Fossil SCM

Merge in trunk for fossil_exe_id() and use it, instead of md5, as the builtin/*.js cache-buster value.

stephan 2020-05-10 14:50 fileedit-ajaxify merge
Commit 7e43119a91c167a8a6fa6768954b381f8f64b76ff14eaaa11b4256df2b3dc9eb
+43 -14
--- src/browse.c
+++ src/browse.c
@@ -133,21 +133,18 @@
133133
Manifest *pM = 0;
134134
const char *zSubdirLink;
135135
int linkTrunk = 1;
136136
int linkTip = 1;
137137
HQuery sURI;
138
+ int isSymbolicCI = 0; /* ci= is symbolic name, not a hash prefix */
139
+ char *zHeader = 0;
138140
141
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
139142
if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
140143
login_check_credentials();
141144
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
142145
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);
149146
150147
/* If the name= parameter is an empty string, make it a NULL pointer */
151148
if( zD && strlen(zD)==0 ){ zD = 0; }
152149
153150
/* If a specific check-in is requested, fetch and parse it. If the
@@ -159,14 +156,31 @@
159156
if( pM ){
160157
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
161158
linkTrunk = trunkRid && rid != trunkRid;
162159
linkTip = rid != symbolic_name_to_rid("tip", "ci");
163160
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
161
+ isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
164162
}else{
165163
zCI = 0;
166164
}
167165
}
166
+
167
+ assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
168
+ if( isSymbolicCI ) {
169
+ zHeader = mprintf("%s at %s", (zD ? zD : "Files"), zCI);
170
+ }else if( zUuid && strlen(zUuid) ){
171
+ zHeader = mprintf("%s at [%S]", (zD ? zD : "Files"), zUuid);
172
+ }else{
173
+ zHeader = mprintf("%s", (zD ? zD : "All Files"));
174
+ }
175
+ style_header("%s", zHeader);
176
+ fossil_free(zHeader);
177
+ style_adunit_config(ADUNIT_RIGHT_OK);
178
+ sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
179
+ pathelementFunc, 0, 0);
180
+ url_initialize(&sURI, "dir");
181
+ cgi_query_parameters_to_url(&sURI);
168182
169183
/* Compute the title of the page */
170184
blob_zero(&dirname);
171185
if( zD ){
172186
blob_append(&dirname, "in directory ", -1);
@@ -184,11 +198,11 @@
184198
}
185199
if( linkTip ){
186200
style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0));
187201
}
188202
if( zCI ){
189
- @ <h2>Files of check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>]
203
+ @ <h2>Files at check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>]
190204
@ %s(blob_str(&dirname))
191205
if( zD ){
192206
@ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
193207
}
194208
@ </h2>
@@ -195,11 +209,11 @@
195209
zSubdirLink = mprintf("%R/dir?ci=%!S&name=%T", zUuid, zPrefix);
196210
if( nD==0 ){
197211
style_submenu_element("File Ages", "%R/fileage?name=%!S", zUuid);
198212
}
199213
}else{
200
- @ <h2>The union of all files from all check-ins
214
+ @ <h2>All files known in the repository
201215
@ %s(blob_str(&dirname))
202216
if( zD ){
203217
@ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
204218
}
205219
@ </h2>
@@ -282,12 +296,11 @@
282296
zFN++;
283297
@ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
284298
}else{
285299
const char *zLink;
286300
if( zCI ){
287
- const char *zUuid = db_column_text(&q, 1);
288
- zLink = href("%R/artifact/%!S",zUuid);
301
+ zLink = href("%R/file?name=%T%T&ci=%!S",zPrefix,zFN,zCI);
289302
}else{
290303
zLink = href("%R/finfo?name=%T%T",zPrefix,zFN);
291304
}
292305
@ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li>
293306
}
@@ -612,11 +625,14 @@
612625
HQuery sURI; /* Hyperlink */
613626
int startExpanded; /* True to start out with the tree expanded */
614627
int showDirOnly; /* Show directories only. Omit files */
615628
int nDir = 0; /* Number of directories. Used for ID attributes */
616629
char *zProjectName = db_get("project-name", 0);
630
+ int isSymbolicCI = 0; /* ci= is a symbolic name, not a hash prefix */
631
+ char *zHeader = 0;
617632
633
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
618634
if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; }
619635
memset(&sTree, 0, sizeof(sTree));
620636
login_check_credentials();
621637
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
622638
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
@@ -624,14 +640,12 @@
624640
pathelementFunc, 0, 0);
625641
url_initialize(&sURI, "tree");
626642
cgi_query_parameters_to_url(&sURI);
627643
if( PB("nofiles") ){
628644
showDirOnly = 1;
629
- style_header("Folder Hierarchy");
630645
}else{
631646
showDirOnly = 0;
632
- style_header("File Tree");
633647
}
634648
style_adunit_config(ADUNIT_RIGHT_OK);
635649
if( PB("expand") ){
636650
startExpanded = 1;
637651
}else{
@@ -660,18 +674,33 @@
660674
linkTip = rid != symbolic_name_to_rid("tip", "ci");
661675
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
662676
rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
663677
zNow = db_text("", "SELECT datetime(mtime,toLocal())"
664678
" FROM event WHERE objid=%d", rid);
679
+ isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI)) != 0);
665680
}else{
666681
zCI = 0;
667682
}
668683
}
669684
if( zCI==0 ){
670685
rNow = db_double(0.0, "SELECT max(mtime) FROM event");
671686
zNow = db_text("", "SELECT datetime(max(mtime),toLocal()) FROM event");
672687
}
688
+
689
+ assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
690
+ if( isSymbolicCI ) {
691
+ zHeader = mprintf("%s at %s",
692
+ (zD ? zD : (showDirOnly ? "Folder Hierarchy" : "Tree-View")), zCI);
693
+ }else if( zUuid && strlen(zUuid) ){
694
+ zHeader = mprintf("%s at [%S]",
695
+ (zD ? zD : (showDirOnly ? "Folder Hierarchy" : "Tree-View")), zUuid);
696
+ }else{
697
+ zHeader = mprintf("%s",
698
+ (zD ? zD : (showDirOnly ?"All Folders Hierarchy":"All Files Tree-View")));
699
+ }
700
+ style_header("%s", zHeader);
701
+ fossil_free(zHeader);
673702
674703
/* Compute the title of the page */
675704
blob_zero(&dirname);
676705
if( zD ){
677706
blob_append(&dirname, "within directory ", -1);
@@ -758,11 +787,11 @@
758787
}
759788
760789
style_submenu_checkbox("nofiles", "Folders Only", 0, 0);
761790
762791
if( zCI ){
763
- @ <h2>%s(zObjType) from
792
+ @ <h2>%s(zObjType) at check-in
764793
if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
765794
@ "%h(zCI)"
766795
}
767796
@ [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))
768797
}else{
@@ -824,11 +853,11 @@
824853
nDir++;
825854
}else if( !showDirOnly ){
826855
const char *zFileClass = fileext_class(p->zName);
827856
char *zLink;
828857
if( zCI ){
829
- zLink = href("%R/artifact/%!S",p->zUuid);
858
+ zLink = href("%R/file?name=%T&ci=%!S",p->zFullName,zCI);
830859
}else{
831860
zLink = href("%R/finfo?name=%T",p->zFullName);
832861
}
833862
@ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline">
834863
@ %z(zLink)%h(p->zName)</a>
835864
--- src/browse.c
+++ src/browse.c
@@ -133,21 +133,18 @@
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,14 +156,31 @@
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);
@@ -184,11 +198,11 @@
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,11 +209,11 @@
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>
@@ -282,12 +296,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 +625,14 @@
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 +640,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,18 +674,33 @@
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);
@@ -758,11 +787,11 @@
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{
@@ -824,11 +853,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>
835
--- src/browse.c
+++ src/browse.c
@@ -133,21 +133,18 @@
133 Manifest *pM = 0;
134 const char *zSubdirLink;
135 int linkTrunk = 1;
136 int linkTip = 1;
137 HQuery sURI;
138 int isSymbolicCI = 0; /* ci= is symbolic name, not a hash prefix */
139 char *zHeader = 0;
140
141 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
142 if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
143 login_check_credentials();
144 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
145 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
 
 
 
 
 
 
146
147 /* If the name= parameter is an empty string, make it a NULL pointer */
148 if( zD && strlen(zD)==0 ){ zD = 0; }
149
150 /* If a specific check-in is requested, fetch and parse it. If the
@@ -159,14 +156,31 @@
156 if( pM ){
157 int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
158 linkTrunk = trunkRid && rid != trunkRid;
159 linkTip = rid != symbolic_name_to_rid("tip", "ci");
160 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
161 isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
162 }else{
163 zCI = 0;
164 }
165 }
166
167 assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
168 if( isSymbolicCI ) {
169 zHeader = mprintf("%s at %s", (zD ? zD : "Files"), zCI);
170 }else if( zUuid && strlen(zUuid) ){
171 zHeader = mprintf("%s at [%S]", (zD ? zD : "Files"), zUuid);
172 }else{
173 zHeader = mprintf("%s", (zD ? zD : "All Files"));
174 }
175 style_header("%s", zHeader);
176 fossil_free(zHeader);
177 style_adunit_config(ADUNIT_RIGHT_OK);
178 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
179 pathelementFunc, 0, 0);
180 url_initialize(&sURI, "dir");
181 cgi_query_parameters_to_url(&sURI);
182
183 /* Compute the title of the page */
184 blob_zero(&dirname);
185 if( zD ){
186 blob_append(&dirname, "in directory ", -1);
@@ -184,11 +198,11 @@
198 }
199 if( linkTip ){
200 style_submenu_element("Tip", "%s", url_render(&sURI, "ci", "tip", 0, 0));
201 }
202 if( zCI ){
203 @ <h2>Files at check-in [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>]
204 @ %s(blob_str(&dirname))
205 if( zD ){
206 @ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
207 }
208 @ </h2>
@@ -195,11 +209,11 @@
209 zSubdirLink = mprintf("%R/dir?ci=%!S&name=%T", zUuid, zPrefix);
210 if( nD==0 ){
211 style_submenu_element("File Ages", "%R/fileage?name=%!S", zUuid);
212 }
213 }else{
214 @ <h2>All files known in the repository
215 @ %s(blob_str(&dirname))
216 if( zD ){
217 @ &nbsp;&nbsp;%z(href("%R/timeline?chng=%T/*", zD))[history]</a>
218 }
219 @ </h2>
@@ -282,12 +296,11 @@
296 zFN++;
297 @ <li class="dir">%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
298 }else{
299 const char *zLink;
300 if( zCI ){
301 zLink = href("%R/file?name=%T%T&ci=%!S",zPrefix,zFN,zCI);
 
302 }else{
303 zLink = href("%R/finfo?name=%T%T",zPrefix,zFN);
304 }
305 @ <li class="%z(fileext_class(zFN))">%z(zLink)%h(zFN)</a></li>
306 }
@@ -612,11 +625,14 @@
625 HQuery sURI; /* Hyperlink */
626 int startExpanded; /* True to start out with the tree expanded */
627 int showDirOnly; /* Show directories only. Omit files */
628 int nDir = 0; /* Number of directories. Used for ID attributes */
629 char *zProjectName = db_get("project-name", 0);
630 int isSymbolicCI = 0; /* ci= is a symbolic name, not a hash prefix */
631 char *zHeader = 0;
632
633 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
634 if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; }
635 memset(&sTree, 0, sizeof(sTree));
636 login_check_credentials();
637 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
638 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
@@ -624,14 +640,12 @@
640 pathelementFunc, 0, 0);
641 url_initialize(&sURI, "tree");
642 cgi_query_parameters_to_url(&sURI);
643 if( PB("nofiles") ){
644 showDirOnly = 1;
 
645 }else{
646 showDirOnly = 0;
 
647 }
648 style_adunit_config(ADUNIT_RIGHT_OK);
649 if( PB("expand") ){
650 startExpanded = 1;
651 }else{
@@ -660,18 +674,33 @@
674 linkTip = rid != symbolic_name_to_rid("tip", "ci");
675 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
676 rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
677 zNow = db_text("", "SELECT datetime(mtime,toLocal())"
678 " FROM event WHERE objid=%d", rid);
679 isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI)) != 0);
680 }else{
681 zCI = 0;
682 }
683 }
684 if( zCI==0 ){
685 rNow = db_double(0.0, "SELECT max(mtime) FROM event");
686 zNow = db_text("", "SELECT datetime(max(mtime),toLocal()) FROM event");
687 }
688
689 assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
690 if( isSymbolicCI ) {
691 zHeader = mprintf("%s at %s",
692 (zD ? zD : (showDirOnly ? "Folder Hierarchy" : "Tree-View")), zCI);
693 }else if( zUuid && strlen(zUuid) ){
694 zHeader = mprintf("%s at [%S]",
695 (zD ? zD : (showDirOnly ? "Folder Hierarchy" : "Tree-View")), zUuid);
696 }else{
697 zHeader = mprintf("%s",
698 (zD ? zD : (showDirOnly ?"All Folders Hierarchy":"All Files Tree-View")));
699 }
700 style_header("%s", zHeader);
701 fossil_free(zHeader);
702
703 /* Compute the title of the page */
704 blob_zero(&dirname);
705 if( zD ){
706 blob_append(&dirname, "within directory ", -1);
@@ -758,11 +787,11 @@
787 }
788
789 style_submenu_checkbox("nofiles", "Folders Only", 0, 0);
790
791 if( zCI ){
792 @ <h2>%s(zObjType) at check-in
793 if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
794 @ "%h(zCI)"
795 }
796 @ [%z(href("vinfo?name=%!S",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))
797 }else{
@@ -824,11 +853,11 @@
853 nDir++;
854 }else if( !showDirOnly ){
855 const char *zFileClass = fileext_class(p->zName);
856 char *zLink;
857 if( zCI ){
858 zLink = href("%R/file?name=%T&ci=%!S",p->zFullName,zCI);
859 }else{
860 zLink = href("%R/finfo?name=%T",p->zFullName);
861 }
862 @ <li class="%z(zFileClass)%s(zLastClass)"><div class="filetreeline">
863 @ %z(zLink)%h(p->zName)</a>
864
+11 -10
--- src/cgi.c
+++ src/cgi.c
@@ -185,12 +185,12 @@
185185
}
186186
187187
/*
188188
** Additional information used to form the HTTP reply
189189
*/
190
-static const char *zContentType = "text/html"; /* Content type of the reply */
191
-static const char *zReplyStatus = "OK"; /* Reply status description */
190
+static const char *zContentType = "text/html"; /* Content type of the reply */
191
+static const char *zReplyStatus = "OK"; /* Reply status description */
192192
static int iReplyStatus = 200; /* Reply status code */
193193
static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
194194
static int rangeStart = 0; /* Start of Range: */
195195
static int rangeEnd = 0; /* End of Range: plus 1 */
196196
@@ -304,11 +304,11 @@
304304
}
305305
if( g.isConst ){
306306
/* isConst means that the reply is guaranteed to be invariant, even
307307
** after configuration changes and/or Fossil binary recompiles. */
308308
fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
309
- }else if( etag_tag()!=0 ){
309
+ }else if( etag_tag()[0]!=0 ){
310310
fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
311311
fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
312312
}else{
313313
fprintf(g.httpOut, "Cache-control: no-cache\r\n");
314314
}
@@ -340,17 +340,17 @@
340340
*/
341341
342342
/* Content intended for logged in users should only be cached in
343343
** the browser, not some shared location.
344344
*/
345
- fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
346
- if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
347
- cgi_combine_header_and_body();
348
- blob_compress(&cgiContent[0], &cgiContent[0]);
349
- }
350
-
351345
if( iReplyStatus!=304 ) {
346
+ fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
347
+ if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
348
+ cgi_combine_header_and_body();
349
+ blob_compress(&cgiContent[0], &cgiContent[0]);
350
+ }
351
+
352352
if( is_gzippable() && iReplyStatus!=206 ){
353353
int i;
354354
gzip_begin(0);
355355
for( i=0; i<2; i++ ){
356356
int size = blob_size(&cgiContent[i]);
@@ -370,11 +370,12 @@
370370
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
371371
}else{
372372
total_size = 0;
373373
}
374374
fprintf(g.httpOut, "\r\n");
375
- if( total_size>0 && iReplyStatus != 304
375
+ if( total_size>0
376
+ && iReplyStatus!=304
376377
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
377378
){
378379
int i, size;
379380
for(i=0; i<2; i++){
380381
size = blob_size(&cgiContent[i]);
381382
--- src/cgi.c
+++ src/cgi.c
@@ -185,12 +185,12 @@
185 }
186
187 /*
188 ** Additional information used to form the HTTP reply
189 */
190 static const char *zContentType = "text/html"; /* Content type of the reply */
191 static const char *zReplyStatus = "OK"; /* Reply status description */
192 static int iReplyStatus = 200; /* Reply status code */
193 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
194 static int rangeStart = 0; /* Start of Range: */
195 static int rangeEnd = 0; /* End of Range: plus 1 */
196
@@ -304,11 +304,11 @@
304 }
305 if( g.isConst ){
306 /* isConst means that the reply is guaranteed to be invariant, even
307 ** after configuration changes and/or Fossil binary recompiles. */
308 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
309 }else if( etag_tag()!=0 ){
310 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
311 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
312 }else{
313 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
314 }
@@ -340,17 +340,17 @@
340 */
341
342 /* Content intended for logged in users should only be cached in
343 ** the browser, not some shared location.
344 */
345 fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
346 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
347 cgi_combine_header_and_body();
348 blob_compress(&cgiContent[0], &cgiContent[0]);
349 }
350
351 if( iReplyStatus!=304 ) {
 
 
 
 
 
 
352 if( is_gzippable() && iReplyStatus!=206 ){
353 int i;
354 gzip_begin(0);
355 for( i=0; i<2; i++ ){
356 int size = blob_size(&cgiContent[i]);
@@ -370,11 +370,12 @@
370 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
371 }else{
372 total_size = 0;
373 }
374 fprintf(g.httpOut, "\r\n");
375 if( total_size>0 && iReplyStatus != 304
 
376 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
377 ){
378 int i, size;
379 for(i=0; i<2; i++){
380 size = blob_size(&cgiContent[i]);
381
--- src/cgi.c
+++ src/cgi.c
@@ -185,12 +185,12 @@
185 }
186
187 /*
188 ** Additional information used to form the HTTP reply
189 */
190 static const char *zContentType = "text/html"; /* Content type of the reply */
191 static const char *zReplyStatus = "OK"; /* Reply status description */
192 static int iReplyStatus = 200; /* Reply status code */
193 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
194 static int rangeStart = 0; /* Start of Range: */
195 static int rangeEnd = 0; /* End of Range: plus 1 */
196
@@ -304,11 +304,11 @@
304 }
305 if( g.isConst ){
306 /* isConst means that the reply is guaranteed to be invariant, even
307 ** after configuration changes and/or Fossil binary recompiles. */
308 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
309 }else if( etag_tag()[0]!=0 ){
310 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
311 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
312 }else{
313 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
314 }
@@ -340,17 +340,17 @@
340 */
341
342 /* Content intended for logged in users should only be cached in
343 ** the browser, not some shared location.
344 */
 
 
 
 
 
 
345 if( iReplyStatus!=304 ) {
346 fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
347 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
348 cgi_combine_header_and_body();
349 blob_compress(&cgiContent[0], &cgiContent[0]);
350 }
351
352 if( is_gzippable() && iReplyStatus!=206 ){
353 int i;
354 gzip_begin(0);
355 for( i=0; i<2; i++ ){
356 int size = blob_size(&cgiContent[i]);
@@ -370,11 +370,12 @@
370 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
371 }else{
372 total_size = 0;
373 }
374 fprintf(g.httpOut, "\r\n");
375 if( total_size>0
376 && iReplyStatus!=304
377 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
378 ){
379 int i, size;
380 for(i=0; i<2; i++){
381 size = blob_size(&cgiContent[i]);
382
+11 -10
--- src/cgi.c
+++ src/cgi.c
@@ -185,12 +185,12 @@
185185
}
186186
187187
/*
188188
** Additional information used to form the HTTP reply
189189
*/
190
-static const char *zContentType = "text/html"; /* Content type of the reply */
191
-static const char *zReplyStatus = "OK"; /* Reply status description */
190
+static const char *zContentType = "text/html"; /* Content type of the reply */
191
+static const char *zReplyStatus = "OK"; /* Reply status description */
192192
static int iReplyStatus = 200; /* Reply status code */
193193
static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
194194
static int rangeStart = 0; /* Start of Range: */
195195
static int rangeEnd = 0; /* End of Range: plus 1 */
196196
@@ -304,11 +304,11 @@
304304
}
305305
if( g.isConst ){
306306
/* isConst means that the reply is guaranteed to be invariant, even
307307
** after configuration changes and/or Fossil binary recompiles. */
308308
fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
309
- }else if( etag_tag()!=0 ){
309
+ }else if( etag_tag()[0]!=0 ){
310310
fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
311311
fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
312312
}else{
313313
fprintf(g.httpOut, "Cache-control: no-cache\r\n");
314314
}
@@ -340,17 +340,17 @@
340340
*/
341341
342342
/* Content intended for logged in users should only be cached in
343343
** the browser, not some shared location.
344344
*/
345
- fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
346
- if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
347
- cgi_combine_header_and_body();
348
- blob_compress(&cgiContent[0], &cgiContent[0]);
349
- }
350
-
351345
if( iReplyStatus!=304 ) {
346
+ fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
347
+ if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
348
+ cgi_combine_header_and_body();
349
+ blob_compress(&cgiContent[0], &cgiContent[0]);
350
+ }
351
+
352352
if( is_gzippable() && iReplyStatus!=206 ){
353353
int i;
354354
gzip_begin(0);
355355
for( i=0; i<2; i++ ){
356356
int size = blob_size(&cgiContent[i]);
@@ -370,11 +370,12 @@
370370
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
371371
}else{
372372
total_size = 0;
373373
}
374374
fprintf(g.httpOut, "\r\n");
375
- if( total_size>0 && iReplyStatus != 304
375
+ if( total_size>0
376
+ && iReplyStatus!=304
376377
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
377378
){
378379
int i, size;
379380
for(i=0; i<2; i++){
380381
size = blob_size(&cgiContent[i]);
381382
--- src/cgi.c
+++ src/cgi.c
@@ -185,12 +185,12 @@
185 }
186
187 /*
188 ** Additional information used to form the HTTP reply
189 */
190 static const char *zContentType = "text/html"; /* Content type of the reply */
191 static const char *zReplyStatus = "OK"; /* Reply status description */
192 static int iReplyStatus = 200; /* Reply status code */
193 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
194 static int rangeStart = 0; /* Start of Range: */
195 static int rangeEnd = 0; /* End of Range: plus 1 */
196
@@ -304,11 +304,11 @@
304 }
305 if( g.isConst ){
306 /* isConst means that the reply is guaranteed to be invariant, even
307 ** after configuration changes and/or Fossil binary recompiles. */
308 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
309 }else if( etag_tag()!=0 ){
310 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
311 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
312 }else{
313 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
314 }
@@ -340,17 +340,17 @@
340 */
341
342 /* Content intended for logged in users should only be cached in
343 ** the browser, not some shared location.
344 */
345 fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
346 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
347 cgi_combine_header_and_body();
348 blob_compress(&cgiContent[0], &cgiContent[0]);
349 }
350
351 if( iReplyStatus!=304 ) {
 
 
 
 
 
 
352 if( is_gzippable() && iReplyStatus!=206 ){
353 int i;
354 gzip_begin(0);
355 for( i=0; i<2; i++ ){
356 int size = blob_size(&cgiContent[i]);
@@ -370,11 +370,12 @@
370 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
371 }else{
372 total_size = 0;
373 }
374 fprintf(g.httpOut, "\r\n");
375 if( total_size>0 && iReplyStatus != 304
 
376 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
377 ){
378 int i, size;
379 for(i=0; i<2; i++){
380 size = blob_size(&cgiContent[i]);
381
--- src/cgi.c
+++ src/cgi.c
@@ -185,12 +185,12 @@
185 }
186
187 /*
188 ** Additional information used to form the HTTP reply
189 */
190 static const char *zContentType = "text/html"; /* Content type of the reply */
191 static const char *zReplyStatus = "OK"; /* Reply status description */
192 static int iReplyStatus = 200; /* Reply status code */
193 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
194 static int rangeStart = 0; /* Start of Range: */
195 static int rangeEnd = 0; /* End of Range: plus 1 */
196
@@ -304,11 +304,11 @@
304 }
305 if( g.isConst ){
306 /* isConst means that the reply is guaranteed to be invariant, even
307 ** after configuration changes and/or Fossil binary recompiles. */
308 fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
309 }else if( etag_tag()[0]!=0 ){
310 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
311 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
312 }else{
313 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
314 }
@@ -340,17 +340,17 @@
340 */
341
342 /* Content intended for logged in users should only be cached in
343 ** the browser, not some shared location.
344 */
 
 
 
 
 
 
345 if( iReplyStatus!=304 ) {
346 fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
347 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
348 cgi_combine_header_and_body();
349 blob_compress(&cgiContent[0], &cgiContent[0]);
350 }
351
352 if( is_gzippable() && iReplyStatus!=206 ){
353 int i;
354 gzip_begin(0);
355 for( i=0; i<2; i++ ){
356 int size = blob_size(&cgiContent[i]);
@@ -370,11 +370,12 @@
370 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
371 }else{
372 total_size = 0;
373 }
374 fprintf(g.httpOut, "\r\n");
375 if( total_size>0
376 && iReplyStatus!=304
377 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
378 ){
379 int i, size;
380 for(i=0; i<2; i++){
381 size = blob_size(&cgiContent[i]);
382
+37 -6
--- src/etag.c
+++ src/etag.c
@@ -60,32 +60,51 @@
6060
*/
6161
#define ETAG_CONFIG 0x01 /* Output depends on the CONFIG table */
6262
#define ETAG_DATA 0x02 /* Output depends on the EVENT table */
6363
#define ETAG_COOKIE 0x04 /* Output depends on a display cookie value */
6464
#define ETAG_HASH 0x08 /* Output depends on a hash */
65
+#define ETAG_QUERY 0x10 /* Output depends on PATH_INFO and QUERY_STRING */
6566
#endif
6667
6768
static char zETag[33]; /* The generated ETag */
6869
static int iMaxAge = 0; /* The max-age parameter in the reply */
6970
static sqlite3_int64 iEtagMtime = 0; /* Last-Modified time */
71
+
72
+/*
73
+** Return a hash that changes every time the Fossil source code is
74
+** rebuilt.
75
+**
76
+** The current implementation is a hash of MANIFEST_UUID, __DATE__, and
77
+** __TIME__. But this might change in the future if we think of a better
78
+** way to compute an identifier that changes with each build.
79
+*/
80
+const char *fossil_exe_id(void){
81
+ static char zExecId[33];
82
+ if( zExecId[0]==0 ){
83
+ Blob x;
84
+ blob_init(&x, MANIFEST_UUID "," __DATE__ "," __TIME__, -1);
85
+ md5sum_blob(&x, &x);
86
+ memcpy(zExecId, x.aData, 32);
87
+ }
88
+ return zExecId;
89
+}
7090
7191
/*
7292
** Generate an ETag
7393
*/
7494
void etag_check(unsigned eFlags, const char *zHash){
75
- sqlite3_int64 mtime;
7695
const char *zIfNoneMatch;
7796
char zBuf[50];
7897
assert( zETag[0]==0 ); /* Only call this routine once! */
7998
8099
iMaxAge = 86400;
81100
md5sum_init();
82101
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);
102
+ /* Always include the executable ID as part of the hash */
103
+ md5sum_step_text("exe-id: ", -1);
104
+ md5sum_step_text(fossil_exe_id(), -1);
105
+ md5sum_step_text("\n", 1);
87106
88107
if( (eFlags & ETAG_HASH)!=0 && zHash ){
89108
md5sum_step_text("hash: ", -1);
90109
md5sum_step_text(zHash, -1);
91110
md5sum_step_text("\n", 1);
@@ -98,11 +117,11 @@
98117
md5sum_step_text("\n", 1);
99118
iMaxAge = 60;
100119
}else if( eFlags & ETAG_CONFIG ){
101120
int iKey = db_int(0, "SELECT value FROM config WHERE name='cfgcnt'");
102121
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey);
103
- md5sum_step_text("data: ", -1);
122
+ md5sum_step_text("config: ", -1);
104123
md5sum_step_text(zBuf, -1);
105124
md5sum_step_text("\n", 1);
106125
iMaxAge = 3600;
107126
}
108127
@@ -111,10 +130,22 @@
111130
md5sum_step_text("display-cookie: ", -1);
112131
md5sum_step_text(PD(DISPLAY_SETTINGS_COOKIE,""), -1);
113132
md5sum_step_text("\n", 1);
114133
iMaxAge = 0;
115134
}
135
+
136
+ /* Output depends on PATH_INFO and QUERY_STRING */
137
+ if( eFlags & ETAG_QUERY ){
138
+ const char *zQS = P("QUERY_STRING");
139
+ md5sum_step_text("query: ", -1);
140
+ md5sum_step_text(PD("PATH_INFO",""), -1);
141
+ if( zQS ){
142
+ md5sum_step_text("?", 1);
143
+ md5sum_step_text(zQS, -1);
144
+ }
145
+ md5sum_step_text("\n",1);
146
+ }
116147
117148
/* Generate the ETag */
118149
memcpy(zETag, md5sum_finish(0), 33);
119150
120151
/* Check to see if the generated ETag matches If-None-Match and
121152
--- src/etag.c
+++ src/etag.c
@@ -60,32 +60,51 @@
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 +117,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 +130,22 @@
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
@@ -60,32 +60,51 @@
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 #define ETAG_QUERY 0x10 /* Output depends on PATH_INFO and QUERY_STRING */
66 #endif
67
68 static char zETag[33]; /* The generated ETag */
69 static int iMaxAge = 0; /* The max-age parameter in the reply */
70 static sqlite3_int64 iEtagMtime = 0; /* Last-Modified time */
71
72 /*
73 ** Return a hash that changes every time the Fossil source code is
74 ** rebuilt.
75 **
76 ** The current implementation is a hash of MANIFEST_UUID, __DATE__, and
77 ** __TIME__. But this might change in the future if we think of a better
78 ** way to compute an identifier that changes with each build.
79 */
80 const char *fossil_exe_id(void){
81 static char zExecId[33];
82 if( zExecId[0]==0 ){
83 Blob x;
84 blob_init(&x, MANIFEST_UUID "," __DATE__ "," __TIME__, -1);
85 md5sum_blob(&x, &x);
86 memcpy(zExecId, x.aData, 32);
87 }
88 return zExecId;
89 }
90
91 /*
92 ** Generate an ETag
93 */
94 void etag_check(unsigned eFlags, const char *zHash){
 
95 const char *zIfNoneMatch;
96 char zBuf[50];
97 assert( zETag[0]==0 ); /* Only call this routine once! */
98
99 iMaxAge = 86400;
100 md5sum_init();
101
102 /* Always include the executable ID as part of the hash */
103 md5sum_step_text("exe-id: ", -1);
104 md5sum_step_text(fossil_exe_id(), -1);
105 md5sum_step_text("\n", 1);
106
107 if( (eFlags & ETAG_HASH)!=0 && zHash ){
108 md5sum_step_text("hash: ", -1);
109 md5sum_step_text(zHash, -1);
110 md5sum_step_text("\n", 1);
@@ -98,11 +117,11 @@
117 md5sum_step_text("\n", 1);
118 iMaxAge = 60;
119 }else if( eFlags & ETAG_CONFIG ){
120 int iKey = db_int(0, "SELECT value FROM config WHERE name='cfgcnt'");
121 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",iKey);
122 md5sum_step_text("config: ", -1);
123 md5sum_step_text(zBuf, -1);
124 md5sum_step_text("\n", 1);
125 iMaxAge = 3600;
126 }
127
@@ -111,10 +130,22 @@
130 md5sum_step_text("display-cookie: ", -1);
131 md5sum_step_text(PD(DISPLAY_SETTINGS_COOKIE,""), -1);
132 md5sum_step_text("\n", 1);
133 iMaxAge = 0;
134 }
135
136 /* Output depends on PATH_INFO and QUERY_STRING */
137 if( eFlags & ETAG_QUERY ){
138 const char *zQS = P("QUERY_STRING");
139 md5sum_step_text("query: ", -1);
140 md5sum_step_text(PD("PATH_INFO",""), -1);
141 if( zQS ){
142 md5sum_step_text("?", 1);
143 md5sum_step_text(zQS, -1);
144 }
145 md5sum_step_text("\n",1);
146 }
147
148 /* Generate the ETag */
149 memcpy(zETag, md5sum_finish(0), 33);
150
151 /* Check to see if the generated ETag matches If-None-Match and
152
+11 -8
--- 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
}
@@ -449,11 +452,11 @@
449452
zLink = href("%R/info/%!S", zUuid);
450453
blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
451454
fossil_free(zUuid);
452455
}
453456
}else{
454
- blob_appendf(&title, "History of ");
457
+ blob_appendf(&title, "History for ");
455458
hyperlinked_path(zFilename, &title, 0, "tree", "");
456459
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
457460
}
458461
if( uBg ){
459462
blob_append(&title, " (color-coded by user)", -1);
@@ -524,11 +527,11 @@
524527
@ <tr class='timelineSelected'>
525528
}else{
526529
@ <tr>
527530
}
528531
@ <td class="timelineTime">\
529
- @ %z(href("%R/artifact/%!S",zUuid))%s(zTime)</a></td>
532
+ @ %z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))%s(zTime)</a></td>
530533
@ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div>
531534
@ </td>
532535
if( zBgClr && zBgClr[0] ){
533536
@ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
534537
}else{
@@ -561,11 +564,11 @@
561564
cgi_printf("<span class='clutter' id='detail-%d'>",frid);
562565
}
563566
cgi_printf("<span class='timeline%sDetail'>", zStyle);
564567
if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
565568
if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
566
- @ file:&nbsp;%z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
569
+ @ file:&nbsp;%z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))[%S(zUuid)]</a>
567570
if( fShowId ){
568571
int srcId = delta_source_rid(frid);
569572
if( srcId>0 ){
570573
@ id:&nbsp;%d(frid)&larr;%d(srcId)
571574
}else{
572575
--- 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 }
@@ -449,11 +452,11 @@
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);
@@ -524,11 +527,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 +564,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 }
@@ -449,11 +452,11 @@
452 zLink = href("%R/info/%!S", zUuid);
453 blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
454 fossil_free(zUuid);
455 }
456 }else{
457 blob_appendf(&title, "History for ");
458 hyperlinked_path(zFilename, &title, 0, "tree", "");
459 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
460 }
461 if( uBg ){
462 blob_append(&title, " (color-coded by user)", -1);
@@ -524,11 +527,11 @@
527 @ <tr class='timelineSelected'>
528 }else{
529 @ <tr>
530 }
531 @ <td class="timelineTime">\
532 @ %z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))%s(zTime)</a></td>
533 @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div>
534 @ </td>
535 if( zBgClr && zBgClr[0] ){
536 @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
537 }else{
@@ -561,11 +564,11 @@
564 cgi_printf("<span class='clutter' id='detail-%d'>",frid);
565 }
566 cgi_printf("<span class='timeline%sDetail'>", zStyle);
567 if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
568 if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
569 @ file:&nbsp;%z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))[%S(zUuid)]</a>
570 if( fShowId ){
571 int srcId = delta_source_rid(frid);
572 if( srcId>0 ){
573 @ id:&nbsp;%d(frid)&larr;%d(srcId)
574 }else{
575
+11 -8
--- 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
}
@@ -449,11 +452,11 @@
449452
zLink = href("%R/info/%!S", zUuid);
450453
blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
451454
fossil_free(zUuid);
452455
}
453456
}else{
454
- blob_appendf(&title, "History of ");
457
+ blob_appendf(&title, "History for ");
455458
hyperlinked_path(zFilename, &title, 0, "tree", "");
456459
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
457460
}
458461
if( uBg ){
459462
blob_append(&title, " (color-coded by user)", -1);
@@ -524,11 +527,11 @@
524527
@ <tr class='timelineSelected'>
525528
}else{
526529
@ <tr>
527530
}
528531
@ <td class="timelineTime">\
529
- @ %z(href("%R/artifact/%!S",zUuid))%s(zTime)</a></td>
532
+ @ %z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))%s(zTime)</a></td>
530533
@ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div>
531534
@ </td>
532535
if( zBgClr && zBgClr[0] ){
533536
@ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
534537
}else{
@@ -561,11 +564,11 @@
561564
cgi_printf("<span class='clutter' id='detail-%d'>",frid);
562565
}
563566
cgi_printf("<span class='timeline%sDetail'>", zStyle);
564567
if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
565568
if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
566
- @ file:&nbsp;%z(href("%R/artifact/%!S",zUuid))[%S(zUuid)]</a>
569
+ @ file:&nbsp;%z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))[%S(zUuid)]</a>
567570
if( fShowId ){
568571
int srcId = delta_source_rid(frid);
569572
if( srcId>0 ){
570573
@ id:&nbsp;%d(frid)&larr;%d(srcId)
571574
}else{
572575
--- 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 }
@@ -449,11 +452,11 @@
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);
@@ -524,11 +527,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 +564,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 }
@@ -449,11 +452,11 @@
452 zLink = href("%R/info/%!S", zUuid);
453 blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
454 fossil_free(zUuid);
455 }
456 }else{
457 blob_appendf(&title, "History for ");
458 hyperlinked_path(zFilename, &title, 0, "tree", "");
459 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
460 }
461 if( uBg ){
462 blob_append(&title, " (color-coded by user)", -1);
@@ -524,11 +527,11 @@
527 @ <tr class='timelineSelected'>
528 }else{
529 @ <tr>
530 }
531 @ <td class="timelineTime">\
532 @ %z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))%s(zTime)</a></td>
533 @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div>
534 @ </td>
535 if( zBgClr && zBgClr[0] ){
536 @ <td class="timeline%s(zStyle)Cell" id='mc%d(gidx)'>
537 }else{
@@ -561,11 +564,11 @@
564 cgi_printf("<span class='clutter' id='detail-%d'>",frid);
565 }
566 cgi_printf("<span class='timeline%sDetail'>", zStyle);
567 if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("(");
568 if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){
569 @ file:&nbsp;%z(href("%R/file?name=%T&ci=%!S",zFilename,zCkin))[%S(zUuid)]</a>
570 if( fShowId ){
571 int srcId = delta_source_rid(frid);
572 if( srcId>0 ){
573 @ id:&nbsp;%d(frid)&larr;%d(srcId)
574 }else{
575
+85 -28
--- src/info.c
+++ src/info.c
@@ -1340,33 +1340,22 @@
13401340
13411341
/*
13421342
** Possible flags for the second parameter to
13431343
** object_description()
13441344
*/
1345
-#define OBJDESC_DETAIL 0x0001 /* more detail */
1345
+#define OBJDESC_DETAIL 0x0001 /* Show more detail */
13461346
#define OBJDESC_BASE 0x0002 /* Set <base> using this object */
13471347
#endif
13481348
13491349
/*
13501350
** 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
13631351
*/
13641352
int object_description(
1365
- int rid, /* The artifact ID */
1353
+ int rid, /* The artifact ID for the object to describe */
13661354
u32 objdescFlags, /* Flags to control display */
1367
- Blob *pDownloadName /* Fill with an appropriate download name */
1355
+ const char *zFileName, /* For file objects, use this name. Can be NULL */
1356
+ Blob *pDownloadName /* Fill with a good download name. Can be NULL */
13681357
){
13691358
Stmt q;
13701359
int cnt = 0;
13711360
int nWiki = 0;
13721361
int objType = 0;
@@ -1401,10 +1390,11 @@
14011390
const char *zVers = db_column_text(&q, 4);
14021391
int mPerm = db_column_int(&q, 5);
14031392
const char *zBr = db_column_text(&q, 6);
14041393
int szFile = db_column_int(&q,7);
14051394
int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1395
+ if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
14061396
if( sameFilename && !showDetail ){
14071397
if( cnt==1 ){
14081398
@ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
14091399
}
14101400
cnt++;
@@ -1750,13 +1740,13 @@
17501740
@ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
17511741
@ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
17521742
}else{
17531743
@ <h2>Differences From
17541744
@ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1755
- object_description(v1, objdescFlags, 0);
1745
+ object_description(v1, objdescFlags,0, 0);
17561746
@ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1757
- object_description(v2, objdescFlags, 0);
1747
+ object_description(v2, objdescFlags,0, 0);
17581748
}
17591749
if( pRe ){
17601750
@ <b>Only differences that match regular expression "%h(zRe)"
17611751
@ are shown.</b>
17621752
}
@@ -1940,11 +1930,11 @@
19401930
}else{
19411931
@ :</h2>
19421932
}
19431933
blob_zero(&downloadName);
19441934
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1945
- object_description(rid, objdescFlags, &downloadName);
1935
+ object_description(rid, objdescFlags, 0, &downloadName);
19461936
style_submenu_element("Download", "%s/raw/%T?name=%s",
19471937
g.zTop, blob_str(&downloadName), zUuid);
19481938
@ <hr />
19491939
content_get(rid, &content);
19501940
@ <blockquote><pre>
@@ -2130,23 +2120,46 @@
21302120
Blob downloadName;
21312121
int renderAsWiki = 0;
21322122
int renderAsHtml = 0;
21332123
int objType;
21342124
int asText;
2135
- const char *zUuid;
2125
+ const char *zUuid = 0;
21362126
u32 objdescFlags = OBJDESC_BASE;
21372127
int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
21382128
int isFile = fossil_strcmp(g.zPath,"file")==0;
21392129
const char *zLn = P("ln");
21402130
const char *zName = P("name");
2131
+ const char *zCI = P("ci");
21412132
HQuery url;
2133
+ Blob dirname;
2134
+ char *zCIUuid = 0;
2135
+ int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2136
+ char *zHeader = 0;
21422137
2138
+ login_check_credentials();
2139
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
21432140
url_initialize(&url, g.zPath);
2144
- rid = artifact_from_ci_and_filename(&url, 0);
2141
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2142
+ if( zCI ){
2143
+ blob_zero(&dirname);
2144
+ hyperlinked_path(zName, &dirname, zCI, "dir", "");
2145
+ blob_reset(&dirname);
2146
+
2147
+ if( name_to_uuid2(zCI, "ci", &zCIUuid) ){
2148
+ isSymbolicCI = (sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI)) != 0);
2149
+ }
2150
+ }
2151
+ if( isFile && zName ) {
2152
+ rid = artifact_from_ci_and_filename(0, "name");
2153
+ }else{
2154
+ rid = artifact_from_ci_and_filename(&url, 0);
2155
+ }
21452156
if( rid==0 ){
21462157
url_add_parameter(&url, "name", zName);
21472158
if( isFile ){
2159
+ int isUnknownAtCI = 0;
2160
+
21482161
/* Do a top-level directory listing in /file mode if no argument
21492162
** specified */
21502163
if( zName==0 || zName[0]==0 ){
21512164
if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
21522165
page_tree();
@@ -2159,10 +2172,17 @@
21592172
" AND mlink.fnid=filename.fnid"
21602173
" AND event.objid=mlink.mid"
21612174
" ORDER BY event.mtime DESC LIMIT 1",
21622175
zName
21632176
);
2177
+ /* If found only by the name, then the file is unknown in the check-in.
2178
+ ** Possibly, the file was renamed/deleted.
2179
+ */
2180
+ if( rid && zCIUuid ){
2181
+ rid = 0;
2182
+ isUnknownAtCI = 1;
2183
+ }
21642184
/* If no file called NAME exists, instead look for a directory
21652185
** with that name, and do a directory listing */
21662186
if( rid==0 ){
21672187
int nName = (int)strlen(zName);
21682188
if( nName && zName[nName-1]=='/' ) nName--;
@@ -2176,22 +2196,32 @@
21762196
return;
21772197
}
21782198
}
21792199
/* If no file or directory called NAME: issue an error */
21802200
if( rid==0 ){
2181
- style_header("No such file");
2182
- @ File '%h(zName)' does not exist in this repository.
2201
+ if( isUnknownAtCI ){
2202
+ if( isSymbolicCI ){
2203
+ zHeader = mprintf("No such file at %s", zCI);
2204
+ }else{
2205
+ zHeader = mprintf("No such file at [%S]", zCIUuid);
2206
+ }
2207
+ style_header("%s", zHeader);
2208
+ fossil_free(zHeader);
2209
+ @ File %z(href("%R/finfo?name=%T",zName))%h(zName)</a> is not known
2210
+ @ at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>].
2211
+ }else{
2212
+ style_header("No such file");
2213
+ @ File '%h(zName)' is not known in this repository.
2214
+ }
21832215
style_footer();
21842216
return;
21852217
}
21862218
}else{
21872219
rid = name_to_rid_www("name");
21882220
}
21892221
}
21902222
2191
- login_check_credentials();
2192
- if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
21932223
if( rid==0 ){
21942224
style_header("No such artifact");
21952225
@ Artifact '%h(zName)' does not exist in this repository.
21962226
style_footer();
21972227
return;
@@ -2199,12 +2229,24 @@
21992229
if( descOnly || P("verbose")!=0 ){
22002230
url_add_parameter(&url, "verbose", "1");
22012231
objdescFlags |= OBJDESC_DETAIL;
22022232
}
22032233
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2234
+
22042235
if( isFile ){
2205
- @ <h2>Latest version of file '%h(zName)':</h2>
2236
+ if( zCI ){
2237
+ const char *zPath;
2238
+ Blob path;
2239
+ blob_zero(&path);
2240
+ hyperlinked_path(zName, &path, zCI, "dir", "");
2241
+ zPath = blob_str(&path);
2242
+ @ <h2>File %s(zPath) at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]
2243
+ @ </h2>
2244
+ blob_reset(&path);
2245
+ }else{
2246
+ @ <h2>Latest version of file '%h(zName)':</h2>
2247
+ }
22062248
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
22072249
}else{
22082250
@ <h2>Artifact
22092251
style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
22102252
if( g.perm.Setup ){
@@ -2214,11 +2256,11 @@
22142256
}
22152257
}
22162258
blob_zero(&downloadName);
22172259
asText = P("txt")!=0;
22182260
if( asText ) objdescFlags &= ~OBJDESC_BASE;
2219
- objType = object_description(rid, objdescFlags, &downloadName);
2261
+ objType = object_description(rid, objdescFlags, (isFile ? zName : 0),&downloadName);
22202262
if( !descOnly && P("download")!=0 ){
22212263
cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
22222264
db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
22232265
/*NOTREACHED*/
22242266
}
@@ -2229,12 +2271,27 @@
22292271
g.zTop, zUuid);
22302272
}else{
22312273
style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
22322274
}
22332275
}
2234
- style_header("%s", isFile ? "File Content" :
2235
- descOnly ? "Artifact Description" : "Artifact Content");
2276
+
2277
+ if( isFile ){
2278
+ if( isSymbolicCI ){
2279
+ zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2280
+ }else if( zCI ){
2281
+ zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2282
+ }else{
2283
+ zHeader = mprintf("%s", file_tail(zName));
2284
+ }
2285
+ }else if( descOnly ){
2286
+ zHeader = mprintf("Artifact Description [%S]", zUuid);
2287
+ }else{
2288
+ zHeader = mprintf("Artifact [%S]", zUuid);
2289
+ }
2290
+ style_header("%s", zHeader);
2291
+ fossil_free(zCIUuid);
2292
+ fossil_free(zHeader);
22362293
if( g.perm.Admin ){
22372294
Stmt q;
22382295
db_prepare(&q,
22392296
"SELECT coalesce(user.login,rcvfrom.uid),"
22402297
" datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
22412298
--- src/info.c
+++ src/info.c
@@ -1340,33 +1340,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 +1390,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++;
@@ -1750,13 +1740,13 @@
1750 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1751 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1752 }else{
1753 @ <h2>Differences From
1754 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1755 object_description(v1, objdescFlags, 0);
1756 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1757 object_description(v2, objdescFlags, 0);
1758 }
1759 if( pRe ){
1760 @ <b>Only differences that match regular expression "%h(zRe)"
1761 @ are shown.</b>
1762 }
@@ -1940,11 +1930,11 @@
1940 }else{
1941 @ :</h2>
1942 }
1943 blob_zero(&downloadName);
1944 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1945 object_description(rid, objdescFlags, &downloadName);
1946 style_submenu_element("Download", "%s/raw/%T?name=%s",
1947 g.zTop, blob_str(&downloadName), zUuid);
1948 @ <hr />
1949 content_get(rid, &content);
1950 @ <blockquote><pre>
@@ -2130,23 +2120,46 @@
2130 Blob downloadName;
2131 int renderAsWiki = 0;
2132 int renderAsHtml = 0;
2133 int objType;
2134 int asText;
2135 const char *zUuid;
2136 u32 objdescFlags = OBJDESC_BASE;
2137 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2138 int isFile = fossil_strcmp(g.zPath,"file")==0;
2139 const char *zLn = P("ln");
2140 const char *zName = P("name");
 
2141 HQuery url;
 
 
 
 
2142
 
 
2143 url_initialize(&url, g.zPath);
2144 rid = artifact_from_ci_and_filename(&url, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2145 if( rid==0 ){
2146 url_add_parameter(&url, "name", zName);
2147 if( isFile ){
 
 
2148 /* Do a top-level directory listing in /file mode if no argument
2149 ** specified */
2150 if( zName==0 || zName[0]==0 ){
2151 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2152 page_tree();
@@ -2159,10 +2172,17 @@
2159 " AND mlink.fnid=filename.fnid"
2160 " AND event.objid=mlink.mid"
2161 " ORDER BY event.mtime DESC LIMIT 1",
2162 zName
2163 );
 
 
 
 
 
 
 
2164 /* If no file called NAME exists, instead look for a directory
2165 ** with that name, and do a directory listing */
2166 if( rid==0 ){
2167 int nName = (int)strlen(zName);
2168 if( nName && zName[nName-1]=='/' ) nName--;
@@ -2176,22 +2196,32 @@
2176 return;
2177 }
2178 }
2179 /* If no file or directory called NAME: issue an error */
2180 if( rid==0 ){
2181 style_header("No such file");
2182 @ File '%h(zName)' does not exist in this repository.
 
 
 
 
 
 
 
 
 
 
 
 
2183 style_footer();
2184 return;
2185 }
2186 }else{
2187 rid = name_to_rid_www("name");
2188 }
2189 }
2190
2191 login_check_credentials();
2192 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2193 if( rid==0 ){
2194 style_header("No such artifact");
2195 @ Artifact '%h(zName)' does not exist in this repository.
2196 style_footer();
2197 return;
@@ -2199,12 +2229,24 @@
2199 if( descOnly || P("verbose")!=0 ){
2200 url_add_parameter(&url, "verbose", "1");
2201 objdescFlags |= OBJDESC_DETAIL;
2202 }
2203 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
 
2204 if( isFile ){
2205 @ <h2>Latest version of file '%h(zName)':</h2>
 
 
 
 
 
 
 
 
 
 
 
2206 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2207 }else{
2208 @ <h2>Artifact
2209 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2210 if( g.perm.Setup ){
@@ -2214,11 +2256,11 @@
2214 }
2215 }
2216 blob_zero(&downloadName);
2217 asText = P("txt")!=0;
2218 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2219 objType = object_description(rid, objdescFlags, &downloadName);
2220 if( !descOnly && P("download")!=0 ){
2221 cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2222 db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
2223 /*NOTREACHED*/
2224 }
@@ -2229,12 +2271,27 @@
2229 g.zTop, zUuid);
2230 }else{
2231 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2232 }
2233 }
2234 style_header("%s", isFile ? "File Content" :
2235 descOnly ? "Artifact Description" : "Artifact Content");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2236 if( g.perm.Admin ){
2237 Stmt q;
2238 db_prepare(&q,
2239 "SELECT coalesce(user.login,rcvfrom.uid),"
2240 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2241
--- src/info.c
+++ src/info.c
@@ -1340,33 +1340,22 @@
1340
1341 /*
1342 ** Possible flags for the second parameter to
1343 ** object_description()
1344 */
1345 #define OBJDESC_DETAIL 0x0001 /* Show 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 int object_description(
1353 int rid, /* The artifact ID for the object to describe */
1354 u32 objdescFlags, /* Flags to control display */
1355 const char *zFileName, /* For file objects, use this name. Can be NULL */
1356 Blob *pDownloadName /* Fill with a good download name. Can be NULL */
1357 ){
1358 Stmt q;
1359 int cnt = 0;
1360 int nWiki = 0;
1361 int objType = 0;
@@ -1401,10 +1390,11 @@
1390 const char *zVers = db_column_text(&q, 4);
1391 int mPerm = db_column_int(&q, 5);
1392 const char *zBr = db_column_text(&q, 6);
1393 int szFile = db_column_int(&q,7);
1394 int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1395 if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
1396 if( sameFilename && !showDetail ){
1397 if( cnt==1 ){
1398 @ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
1399 }
1400 cnt++;
@@ -1750,13 +1740,13 @@
1740 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1741 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1742 }else{
1743 @ <h2>Differences From
1744 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1745 object_description(v1, objdescFlags,0, 0);
1746 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1747 object_description(v2, objdescFlags,0, 0);
1748 }
1749 if( pRe ){
1750 @ <b>Only differences that match regular expression "%h(zRe)"
1751 @ are shown.</b>
1752 }
@@ -1940,11 +1930,11 @@
1930 }else{
1931 @ :</h2>
1932 }
1933 blob_zero(&downloadName);
1934 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1935 object_description(rid, objdescFlags, 0, &downloadName);
1936 style_submenu_element("Download", "%s/raw/%T?name=%s",
1937 g.zTop, blob_str(&downloadName), zUuid);
1938 @ <hr />
1939 content_get(rid, &content);
1940 @ <blockquote><pre>
@@ -2130,23 +2120,46 @@
2120 Blob downloadName;
2121 int renderAsWiki = 0;
2122 int renderAsHtml = 0;
2123 int objType;
2124 int asText;
2125 const char *zUuid = 0;
2126 u32 objdescFlags = OBJDESC_BASE;
2127 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2128 int isFile = fossil_strcmp(g.zPath,"file")==0;
2129 const char *zLn = P("ln");
2130 const char *zName = P("name");
2131 const char *zCI = P("ci");
2132 HQuery url;
2133 Blob dirname;
2134 char *zCIUuid = 0;
2135 int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2136 char *zHeader = 0;
2137
2138 login_check_credentials();
2139 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2140 url_initialize(&url, g.zPath);
2141 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2142 if( zCI ){
2143 blob_zero(&dirname);
2144 hyperlinked_path(zName, &dirname, zCI, "dir", "");
2145 blob_reset(&dirname);
2146
2147 if( name_to_uuid2(zCI, "ci", &zCIUuid) ){
2148 isSymbolicCI = (sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI)) != 0);
2149 }
2150 }
2151 if( isFile && zName ) {
2152 rid = artifact_from_ci_and_filename(0, "name");
2153 }else{
2154 rid = artifact_from_ci_and_filename(&url, 0);
2155 }
2156 if( rid==0 ){
2157 url_add_parameter(&url, "name", zName);
2158 if( isFile ){
2159 int isUnknownAtCI = 0;
2160
2161 /* Do a top-level directory listing in /file mode if no argument
2162 ** specified */
2163 if( zName==0 || zName[0]==0 ){
2164 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2165 page_tree();
@@ -2159,10 +2172,17 @@
2172 " AND mlink.fnid=filename.fnid"
2173 " AND event.objid=mlink.mid"
2174 " ORDER BY event.mtime DESC LIMIT 1",
2175 zName
2176 );
2177 /* If found only by the name, then the file is unknown in the check-in.
2178 ** Possibly, the file was renamed/deleted.
2179 */
2180 if( rid && zCIUuid ){
2181 rid = 0;
2182 isUnknownAtCI = 1;
2183 }
2184 /* If no file called NAME exists, instead look for a directory
2185 ** with that name, and do a directory listing */
2186 if( rid==0 ){
2187 int nName = (int)strlen(zName);
2188 if( nName && zName[nName-1]=='/' ) nName--;
@@ -2176,22 +2196,32 @@
2196 return;
2197 }
2198 }
2199 /* If no file or directory called NAME: issue an error */
2200 if( rid==0 ){
2201 if( isUnknownAtCI ){
2202 if( isSymbolicCI ){
2203 zHeader = mprintf("No such file at %s", zCI);
2204 }else{
2205 zHeader = mprintf("No such file at [%S]", zCIUuid);
2206 }
2207 style_header("%s", zHeader);
2208 fossil_free(zHeader);
2209 @ File %z(href("%R/finfo?name=%T",zName))%h(zName)</a> is not known
2210 @ at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>].
2211 }else{
2212 style_header("No such file");
2213 @ File '%h(zName)' is not known in this repository.
2214 }
2215 style_footer();
2216 return;
2217 }
2218 }else{
2219 rid = name_to_rid_www("name");
2220 }
2221 }
2222
 
 
2223 if( rid==0 ){
2224 style_header("No such artifact");
2225 @ Artifact '%h(zName)' does not exist in this repository.
2226 style_footer();
2227 return;
@@ -2199,12 +2229,24 @@
2229 if( descOnly || P("verbose")!=0 ){
2230 url_add_parameter(&url, "verbose", "1");
2231 objdescFlags |= OBJDESC_DETAIL;
2232 }
2233 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2234
2235 if( isFile ){
2236 if( zCI ){
2237 const char *zPath;
2238 Blob path;
2239 blob_zero(&path);
2240 hyperlinked_path(zName, &path, zCI, "dir", "");
2241 zPath = blob_str(&path);
2242 @ <h2>File %s(zPath) at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]
2243 @ </h2>
2244 blob_reset(&path);
2245 }else{
2246 @ <h2>Latest version of file '%h(zName)':</h2>
2247 }
2248 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2249 }else{
2250 @ <h2>Artifact
2251 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2252 if( g.perm.Setup ){
@@ -2214,11 +2256,11 @@
2256 }
2257 }
2258 blob_zero(&downloadName);
2259 asText = P("txt")!=0;
2260 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2261 objType = object_description(rid, objdescFlags, (isFile ? zName : 0),&downloadName);
2262 if( !descOnly && P("download")!=0 ){
2263 cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2264 db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
2265 /*NOTREACHED*/
2266 }
@@ -2229,12 +2271,27 @@
2271 g.zTop, zUuid);
2272 }else{
2273 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2274 }
2275 }
2276
2277 if( isFile ){
2278 if( isSymbolicCI ){
2279 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2280 }else if( zCI ){
2281 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2282 }else{
2283 zHeader = mprintf("%s", file_tail(zName));
2284 }
2285 }else if( descOnly ){
2286 zHeader = mprintf("Artifact Description [%S]", zUuid);
2287 }else{
2288 zHeader = mprintf("Artifact [%S]", zUuid);
2289 }
2290 style_header("%s", zHeader);
2291 fossil_free(zCIUuid);
2292 fossil_free(zHeader);
2293 if( g.perm.Admin ){
2294 Stmt q;
2295 db_prepare(&q,
2296 "SELECT coalesce(user.login,rcvfrom.uid),"
2297 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2298
+85 -28
--- src/info.c
+++ src/info.c
@@ -1340,33 +1340,22 @@
13401340
13411341
/*
13421342
** Possible flags for the second parameter to
13431343
** object_description()
13441344
*/
1345
-#define OBJDESC_DETAIL 0x0001 /* more detail */
1345
+#define OBJDESC_DETAIL 0x0001 /* Show more detail */
13461346
#define OBJDESC_BASE 0x0002 /* Set <base> using this object */
13471347
#endif
13481348
13491349
/*
13501350
** 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
13631351
*/
13641352
int object_description(
1365
- int rid, /* The artifact ID */
1353
+ int rid, /* The artifact ID for the object to describe */
13661354
u32 objdescFlags, /* Flags to control display */
1367
- Blob *pDownloadName /* Fill with an appropriate download name */
1355
+ const char *zFileName, /* For file objects, use this name. Can be NULL */
1356
+ Blob *pDownloadName /* Fill with a good download name. Can be NULL */
13681357
){
13691358
Stmt q;
13701359
int cnt = 0;
13711360
int nWiki = 0;
13721361
int objType = 0;
@@ -1401,10 +1390,11 @@
14011390
const char *zVers = db_column_text(&q, 4);
14021391
int mPerm = db_column_int(&q, 5);
14031392
const char *zBr = db_column_text(&q, 6);
14041393
int szFile = db_column_int(&q,7);
14051394
int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1395
+ if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
14061396
if( sameFilename && !showDetail ){
14071397
if( cnt==1 ){
14081398
@ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
14091399
}
14101400
cnt++;
@@ -1750,13 +1740,13 @@
17501740
@ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
17511741
@ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
17521742
}else{
17531743
@ <h2>Differences From
17541744
@ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1755
- object_description(v1, objdescFlags, 0);
1745
+ object_description(v1, objdescFlags,0, 0);
17561746
@ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1757
- object_description(v2, objdescFlags, 0);
1747
+ object_description(v2, objdescFlags,0, 0);
17581748
}
17591749
if( pRe ){
17601750
@ <b>Only differences that match regular expression "%h(zRe)"
17611751
@ are shown.</b>
17621752
}
@@ -1940,11 +1930,11 @@
19401930
}else{
19411931
@ :</h2>
19421932
}
19431933
blob_zero(&downloadName);
19441934
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1945
- object_description(rid, objdescFlags, &downloadName);
1935
+ object_description(rid, objdescFlags, 0, &downloadName);
19461936
style_submenu_element("Download", "%s/raw/%T?name=%s",
19471937
g.zTop, blob_str(&downloadName), zUuid);
19481938
@ <hr />
19491939
content_get(rid, &content);
19501940
@ <blockquote><pre>
@@ -2130,23 +2120,46 @@
21302120
Blob downloadName;
21312121
int renderAsWiki = 0;
21322122
int renderAsHtml = 0;
21332123
int objType;
21342124
int asText;
2135
- const char *zUuid;
2125
+ const char *zUuid = 0;
21362126
u32 objdescFlags = OBJDESC_BASE;
21372127
int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
21382128
int isFile = fossil_strcmp(g.zPath,"file")==0;
21392129
const char *zLn = P("ln");
21402130
const char *zName = P("name");
2131
+ const char *zCI = P("ci");
21412132
HQuery url;
2133
+ Blob dirname;
2134
+ char *zCIUuid = 0;
2135
+ int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2136
+ char *zHeader = 0;
21422137
2138
+ login_check_credentials();
2139
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
21432140
url_initialize(&url, g.zPath);
2144
- rid = artifact_from_ci_and_filename(&url, 0);
2141
+ if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2142
+ if( zCI ){
2143
+ blob_zero(&dirname);
2144
+ hyperlinked_path(zName, &dirname, zCI, "dir", "");
2145
+ blob_reset(&dirname);
2146
+
2147
+ if( name_to_uuid2(zCI, "ci", &zCIUuid) ){
2148
+ isSymbolicCI = (sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI)) != 0);
2149
+ }
2150
+ }
2151
+ if( isFile && zName ) {
2152
+ rid = artifact_from_ci_and_filename(0, "name");
2153
+ }else{
2154
+ rid = artifact_from_ci_and_filename(&url, 0);
2155
+ }
21452156
if( rid==0 ){
21462157
url_add_parameter(&url, "name", zName);
21472158
if( isFile ){
2159
+ int isUnknownAtCI = 0;
2160
+
21482161
/* Do a top-level directory listing in /file mode if no argument
21492162
** specified */
21502163
if( zName==0 || zName[0]==0 ){
21512164
if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
21522165
page_tree();
@@ -2159,10 +2172,17 @@
21592172
" AND mlink.fnid=filename.fnid"
21602173
" AND event.objid=mlink.mid"
21612174
" ORDER BY event.mtime DESC LIMIT 1",
21622175
zName
21632176
);
2177
+ /* If found only by the name, then the file is unknown in the check-in.
2178
+ ** Possibly, the file was renamed/deleted.
2179
+ */
2180
+ if( rid && zCIUuid ){
2181
+ rid = 0;
2182
+ isUnknownAtCI = 1;
2183
+ }
21642184
/* If no file called NAME exists, instead look for a directory
21652185
** with that name, and do a directory listing */
21662186
if( rid==0 ){
21672187
int nName = (int)strlen(zName);
21682188
if( nName && zName[nName-1]=='/' ) nName--;
@@ -2176,22 +2196,32 @@
21762196
return;
21772197
}
21782198
}
21792199
/* If no file or directory called NAME: issue an error */
21802200
if( rid==0 ){
2181
- style_header("No such file");
2182
- @ File '%h(zName)' does not exist in this repository.
2201
+ if( isUnknownAtCI ){
2202
+ if( isSymbolicCI ){
2203
+ zHeader = mprintf("No such file at %s", zCI);
2204
+ }else{
2205
+ zHeader = mprintf("No such file at [%S]", zCIUuid);
2206
+ }
2207
+ style_header("%s", zHeader);
2208
+ fossil_free(zHeader);
2209
+ @ File %z(href("%R/finfo?name=%T",zName))%h(zName)</a> is not known
2210
+ @ at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>].
2211
+ }else{
2212
+ style_header("No such file");
2213
+ @ File '%h(zName)' is not known in this repository.
2214
+ }
21832215
style_footer();
21842216
return;
21852217
}
21862218
}else{
21872219
rid = name_to_rid_www("name");
21882220
}
21892221
}
21902222
2191
- login_check_credentials();
2192
- if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
21932223
if( rid==0 ){
21942224
style_header("No such artifact");
21952225
@ Artifact '%h(zName)' does not exist in this repository.
21962226
style_footer();
21972227
return;
@@ -2199,12 +2229,24 @@
21992229
if( descOnly || P("verbose")!=0 ){
22002230
url_add_parameter(&url, "verbose", "1");
22012231
objdescFlags |= OBJDESC_DETAIL;
22022232
}
22032233
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2234
+
22042235
if( isFile ){
2205
- @ <h2>Latest version of file '%h(zName)':</h2>
2236
+ if( zCI ){
2237
+ const char *zPath;
2238
+ Blob path;
2239
+ blob_zero(&path);
2240
+ hyperlinked_path(zName, &path, zCI, "dir", "");
2241
+ zPath = blob_str(&path);
2242
+ @ <h2>File %s(zPath) at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]
2243
+ @ </h2>
2244
+ blob_reset(&path);
2245
+ }else{
2246
+ @ <h2>Latest version of file '%h(zName)':</h2>
2247
+ }
22062248
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
22072249
}else{
22082250
@ <h2>Artifact
22092251
style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
22102252
if( g.perm.Setup ){
@@ -2214,11 +2256,11 @@
22142256
}
22152257
}
22162258
blob_zero(&downloadName);
22172259
asText = P("txt")!=0;
22182260
if( asText ) objdescFlags &= ~OBJDESC_BASE;
2219
- objType = object_description(rid, objdescFlags, &downloadName);
2261
+ objType = object_description(rid, objdescFlags, (isFile ? zName : 0),&downloadName);
22202262
if( !descOnly && P("download")!=0 ){
22212263
cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
22222264
db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
22232265
/*NOTREACHED*/
22242266
}
@@ -2229,12 +2271,27 @@
22292271
g.zTop, zUuid);
22302272
}else{
22312273
style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
22322274
}
22332275
}
2234
- style_header("%s", isFile ? "File Content" :
2235
- descOnly ? "Artifact Description" : "Artifact Content");
2276
+
2277
+ if( isFile ){
2278
+ if( isSymbolicCI ){
2279
+ zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2280
+ }else if( zCI ){
2281
+ zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2282
+ }else{
2283
+ zHeader = mprintf("%s", file_tail(zName));
2284
+ }
2285
+ }else if( descOnly ){
2286
+ zHeader = mprintf("Artifact Description [%S]", zUuid);
2287
+ }else{
2288
+ zHeader = mprintf("Artifact [%S]", zUuid);
2289
+ }
2290
+ style_header("%s", zHeader);
2291
+ fossil_free(zCIUuid);
2292
+ fossil_free(zHeader);
22362293
if( g.perm.Admin ){
22372294
Stmt q;
22382295
db_prepare(&q,
22392296
"SELECT coalesce(user.login,rcvfrom.uid),"
22402297
" datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
22412298
--- src/info.c
+++ src/info.c
@@ -1340,33 +1340,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 +1390,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++;
@@ -1750,13 +1740,13 @@
1750 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1751 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1752 }else{
1753 @ <h2>Differences From
1754 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1755 object_description(v1, objdescFlags, 0);
1756 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1757 object_description(v2, objdescFlags, 0);
1758 }
1759 if( pRe ){
1760 @ <b>Only differences that match regular expression "%h(zRe)"
1761 @ are shown.</b>
1762 }
@@ -1940,11 +1930,11 @@
1940 }else{
1941 @ :</h2>
1942 }
1943 blob_zero(&downloadName);
1944 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1945 object_description(rid, objdescFlags, &downloadName);
1946 style_submenu_element("Download", "%s/raw/%T?name=%s",
1947 g.zTop, blob_str(&downloadName), zUuid);
1948 @ <hr />
1949 content_get(rid, &content);
1950 @ <blockquote><pre>
@@ -2130,23 +2120,46 @@
2130 Blob downloadName;
2131 int renderAsWiki = 0;
2132 int renderAsHtml = 0;
2133 int objType;
2134 int asText;
2135 const char *zUuid;
2136 u32 objdescFlags = OBJDESC_BASE;
2137 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2138 int isFile = fossil_strcmp(g.zPath,"file")==0;
2139 const char *zLn = P("ln");
2140 const char *zName = P("name");
 
2141 HQuery url;
 
 
 
 
2142
 
 
2143 url_initialize(&url, g.zPath);
2144 rid = artifact_from_ci_and_filename(&url, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2145 if( rid==0 ){
2146 url_add_parameter(&url, "name", zName);
2147 if( isFile ){
 
 
2148 /* Do a top-level directory listing in /file mode if no argument
2149 ** specified */
2150 if( zName==0 || zName[0]==0 ){
2151 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2152 page_tree();
@@ -2159,10 +2172,17 @@
2159 " AND mlink.fnid=filename.fnid"
2160 " AND event.objid=mlink.mid"
2161 " ORDER BY event.mtime DESC LIMIT 1",
2162 zName
2163 );
 
 
 
 
 
 
 
2164 /* If no file called NAME exists, instead look for a directory
2165 ** with that name, and do a directory listing */
2166 if( rid==0 ){
2167 int nName = (int)strlen(zName);
2168 if( nName && zName[nName-1]=='/' ) nName--;
@@ -2176,22 +2196,32 @@
2176 return;
2177 }
2178 }
2179 /* If no file or directory called NAME: issue an error */
2180 if( rid==0 ){
2181 style_header("No such file");
2182 @ File '%h(zName)' does not exist in this repository.
 
 
 
 
 
 
 
 
 
 
 
 
2183 style_footer();
2184 return;
2185 }
2186 }else{
2187 rid = name_to_rid_www("name");
2188 }
2189 }
2190
2191 login_check_credentials();
2192 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2193 if( rid==0 ){
2194 style_header("No such artifact");
2195 @ Artifact '%h(zName)' does not exist in this repository.
2196 style_footer();
2197 return;
@@ -2199,12 +2229,24 @@
2199 if( descOnly || P("verbose")!=0 ){
2200 url_add_parameter(&url, "verbose", "1");
2201 objdescFlags |= OBJDESC_DETAIL;
2202 }
2203 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
 
2204 if( isFile ){
2205 @ <h2>Latest version of file '%h(zName)':</h2>
 
 
 
 
 
 
 
 
 
 
 
2206 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2207 }else{
2208 @ <h2>Artifact
2209 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2210 if( g.perm.Setup ){
@@ -2214,11 +2256,11 @@
2214 }
2215 }
2216 blob_zero(&downloadName);
2217 asText = P("txt")!=0;
2218 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2219 objType = object_description(rid, objdescFlags, &downloadName);
2220 if( !descOnly && P("download")!=0 ){
2221 cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2222 db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
2223 /*NOTREACHED*/
2224 }
@@ -2229,12 +2271,27 @@
2229 g.zTop, zUuid);
2230 }else{
2231 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2232 }
2233 }
2234 style_header("%s", isFile ? "File Content" :
2235 descOnly ? "Artifact Description" : "Artifact Content");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2236 if( g.perm.Admin ){
2237 Stmt q;
2238 db_prepare(&q,
2239 "SELECT coalesce(user.login,rcvfrom.uid),"
2240 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2241
--- src/info.c
+++ src/info.c
@@ -1340,33 +1340,22 @@
1340
1341 /*
1342 ** Possible flags for the second parameter to
1343 ** object_description()
1344 */
1345 #define OBJDESC_DETAIL 0x0001 /* Show 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 int object_description(
1353 int rid, /* The artifact ID for the object to describe */
1354 u32 objdescFlags, /* Flags to control display */
1355 const char *zFileName, /* For file objects, use this name. Can be NULL */
1356 Blob *pDownloadName /* Fill with a good download name. Can be NULL */
1357 ){
1358 Stmt q;
1359 int cnt = 0;
1360 int nWiki = 0;
1361 int objType = 0;
@@ -1401,10 +1390,11 @@
1390 const char *zVers = db_column_text(&q, 4);
1391 int mPerm = db_column_int(&q, 5);
1392 const char *zBr = db_column_text(&q, 6);
1393 int szFile = db_column_int(&q,7);
1394 int sameFilename = prevName!=0 && fossil_strcmp(zName,prevName)==0;
1395 if( zFileName && fossil_strcmp(zName,zFileName)!=0 ) continue;
1396 if( sameFilename && !showDetail ){
1397 if( cnt==1 ){
1398 @ %z(href("%R/whatis/%!S",zUuid))[more...]</a>
1399 }
1400 cnt++;
@@ -1750,13 +1740,13 @@
1740 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1741 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1742 }else{
1743 @ <h2>Differences From
1744 @ Artifact %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a>:</h2>
1745 object_description(v1, objdescFlags,0, 0);
1746 @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
1747 object_description(v2, objdescFlags,0, 0);
1748 }
1749 if( pRe ){
1750 @ <b>Only differences that match regular expression "%h(zRe)"
1751 @ are shown.</b>
1752 }
@@ -1940,11 +1930,11 @@
1930 }else{
1931 @ :</h2>
1932 }
1933 blob_zero(&downloadName);
1934 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1935 object_description(rid, objdescFlags, 0, &downloadName);
1936 style_submenu_element("Download", "%s/raw/%T?name=%s",
1937 g.zTop, blob_str(&downloadName), zUuid);
1938 @ <hr />
1939 content_get(rid, &content);
1940 @ <blockquote><pre>
@@ -2130,23 +2120,46 @@
2120 Blob downloadName;
2121 int renderAsWiki = 0;
2122 int renderAsHtml = 0;
2123 int objType;
2124 int asText;
2125 const char *zUuid = 0;
2126 u32 objdescFlags = OBJDESC_BASE;
2127 int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
2128 int isFile = fossil_strcmp(g.zPath,"file")==0;
2129 const char *zLn = P("ln");
2130 const char *zName = P("name");
2131 const char *zCI = P("ci");
2132 HQuery url;
2133 Blob dirname;
2134 char *zCIUuid = 0;
2135 int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
2136 char *zHeader = 0;
2137
2138 login_check_credentials();
2139 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2140 url_initialize(&url, g.zPath);
2141 if( zCI && strlen(zCI)==0 ){ zCI = 0; }
2142 if( zCI ){
2143 blob_zero(&dirname);
2144 hyperlinked_path(zName, &dirname, zCI, "dir", "");
2145 blob_reset(&dirname);
2146
2147 if( name_to_uuid2(zCI, "ci", &zCIUuid) ){
2148 isSymbolicCI = (sqlite3_strnicmp(zCIUuid, zCI, strlen(zCI)) != 0);
2149 }
2150 }
2151 if( isFile && zName ) {
2152 rid = artifact_from_ci_and_filename(0, "name");
2153 }else{
2154 rid = artifact_from_ci_and_filename(&url, 0);
2155 }
2156 if( rid==0 ){
2157 url_add_parameter(&url, "name", zName);
2158 if( isFile ){
2159 int isUnknownAtCI = 0;
2160
2161 /* Do a top-level directory listing in /file mode if no argument
2162 ** specified */
2163 if( zName==0 || zName[0]==0 ){
2164 if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
2165 page_tree();
@@ -2159,10 +2172,17 @@
2172 " AND mlink.fnid=filename.fnid"
2173 " AND event.objid=mlink.mid"
2174 " ORDER BY event.mtime DESC LIMIT 1",
2175 zName
2176 );
2177 /* If found only by the name, then the file is unknown in the check-in.
2178 ** Possibly, the file was renamed/deleted.
2179 */
2180 if( rid && zCIUuid ){
2181 rid = 0;
2182 isUnknownAtCI = 1;
2183 }
2184 /* If no file called NAME exists, instead look for a directory
2185 ** with that name, and do a directory listing */
2186 if( rid==0 ){
2187 int nName = (int)strlen(zName);
2188 if( nName && zName[nName-1]=='/' ) nName--;
@@ -2176,22 +2196,32 @@
2196 return;
2197 }
2198 }
2199 /* If no file or directory called NAME: issue an error */
2200 if( rid==0 ){
2201 if( isUnknownAtCI ){
2202 if( isSymbolicCI ){
2203 zHeader = mprintf("No such file at %s", zCI);
2204 }else{
2205 zHeader = mprintf("No such file at [%S]", zCIUuid);
2206 }
2207 style_header("%s", zHeader);
2208 fossil_free(zHeader);
2209 @ File %z(href("%R/finfo?name=%T",zName))%h(zName)</a> is not known
2210 @ at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>].
2211 }else{
2212 style_header("No such file");
2213 @ File '%h(zName)' is not known in this repository.
2214 }
2215 style_footer();
2216 return;
2217 }
2218 }else{
2219 rid = name_to_rid_www("name");
2220 }
2221 }
2222
 
 
2223 if( rid==0 ){
2224 style_header("No such artifact");
2225 @ Artifact '%h(zName)' does not exist in this repository.
2226 style_footer();
2227 return;
@@ -2199,12 +2229,24 @@
2229 if( descOnly || P("verbose")!=0 ){
2230 url_add_parameter(&url, "verbose", "1");
2231 objdescFlags |= OBJDESC_DETAIL;
2232 }
2233 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
2234
2235 if( isFile ){
2236 if( zCI ){
2237 const char *zPath;
2238 Blob path;
2239 blob_zero(&path);
2240 hyperlinked_path(zName, &path, zCI, "dir", "");
2241 zPath = blob_str(&path);
2242 @ <h2>File %s(zPath) at check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]
2243 @ </h2>
2244 blob_reset(&path);
2245 }else{
2246 @ <h2>Latest version of file '%h(zName)':</h2>
2247 }
2248 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2249 }else{
2250 @ <h2>Artifact
2251 style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
2252 if( g.perm.Setup ){
@@ -2214,11 +2256,11 @@
2256 }
2257 }
2258 blob_zero(&downloadName);
2259 asText = P("txt")!=0;
2260 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2261 objType = object_description(rid, objdescFlags, (isFile ? zName : 0),&downloadName);
2262 if( !descOnly && P("download")!=0 ){
2263 cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
2264 db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
2265 /*NOTREACHED*/
2266 }
@@ -2229,12 +2271,27 @@
2271 g.zTop, zUuid);
2272 }else{
2273 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
2274 }
2275 }
2276
2277 if( isFile ){
2278 if( isSymbolicCI ){
2279 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2280 }else if( zCI ){
2281 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2282 }else{
2283 zHeader = mprintf("%s", file_tail(zName));
2284 }
2285 }else if( descOnly ){
2286 zHeader = mprintf("Artifact Description [%S]", zUuid);
2287 }else{
2288 zHeader = mprintf("Artifact [%S]", zUuid);
2289 }
2290 style_header("%s", zHeader);
2291 fossil_free(zCIUuid);
2292 fossil_free(zHeader);
2293 if( g.perm.Admin ){
2294 Stmt q;
2295 db_prepare(&q,
2296 "SELECT coalesce(user.login,rcvfrom.uid),"
2297 " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
2298
+1 -1
--- src/login.c
+++ src/login.c
@@ -1736,11 +1736,11 @@
17361736
if( iErrLine==5 ){
17371737
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
17381738
}
17391739
@ <tr>
17401740
@ <td class="form_label" align="right">Captcha:</td>
1741
- @ <td><input type="text" name="captcha" size="30"\
1741
+ @ <td><input type="text" name="captcha" \
17421742
@ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
17431743
captcha_speakit_button(uSeed, "Speak the captcha text");
17441744
@ </td>
17451745
@ </tr>
17461746
if( iErrLine==6 ){
17471747
--- src/login.c
+++ src/login.c
@@ -1736,11 +1736,11 @@
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
@@ -1736,11 +1736,11 @@
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" \
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
+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
+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
+402 -243
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1162,11 +1162,11 @@
11621162
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
11631163
** [sqlite_version()] and [sqlite_source_id()].
11641164
*/
11651165
#define SQLITE_VERSION "3.32.0"
11661166
#define SQLITE_VERSION_NUMBER 3032000
1167
-#define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda"
1167
+#define SQLITE_SOURCE_ID "2020-05-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f9654ff"
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))
@@ -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);
@@ -19935,11 +19939,11 @@
1993519939
SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
1993619940
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
1993719941
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
1993819942
SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
1993919943
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
19940
-SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*);
19944
+SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
1994119945
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
1994219946
SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
1994319947
SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
1994419948
SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
1994519949
SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
@@ -27730,14 +27734,16 @@
2773027734
if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
2773127735
mem0.alarmThreshold-nDiff ){
2773227736
sqlite3MallocAlarm(nDiff);
2773327737
}
2773427738
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27739
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
2773527740
if( pNew==0 && mem0.alarmThreshold>0 ){
2773627741
sqlite3MallocAlarm((int)nBytes);
2773727742
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
2773827743
}
27744
+#endif
2773927745
if( pNew ){
2774027746
nNew = sqlite3MallocSize(pNew);
2774127747
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
2774227748
}
2774327749
sqlite3_mutex_leave(mem0.mutex);
@@ -34971,20 +34977,21 @@
3497134977
static int osSetPosixAdvisoryLock(
3497234978
int h, /* The file descriptor on which to take the lock */
3497334979
struct flock *pLock, /* The description of the lock */
3497434980
unixFile *pFile /* Structure holding timeout value */
3497534981
){
34982
+ int tm = pFile->iBusyTimeout;
3497634983
int rc = osFcntl(h,F_SETLK,pLock);
34977
- while( rc<0 && pFile->iBusyTimeout>0 ){
34984
+ while( rc<0 && tm>0 ){
3497834985
/* On systems that support some kind of blocking file lock with a timeout,
3497934986
** make appropriate changes here to invoke that blocking file lock. On
3498034987
** generic posix, however, there is no such API. So we simply try the
3498134988
** lock once every millisecond until either the timeout expires, or until
3498234989
** the lock is obtained. */
3498334990
usleep(1000);
3498434991
rc = osFcntl(h,F_SETLK,pLock);
34985
- pFile->iBusyTimeout--;
34992
+ tm--;
3498634993
}
3498734994
return rc;
3498834995
}
3498934996
#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
3499034997
@@ -37722,17 +37729,24 @@
3772237729
3772337730
/* Locks are within range */
3772437731
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
3772537732
3772637733
if( pShmNode->hShm>=0 ){
37734
+ int res;
3772737735
/* Initialize the locking parameters */
3772837736
f.l_type = lockType;
3772937737
f.l_whence = SEEK_SET;
3773037738
f.l_start = ofst;
3773137739
f.l_len = n;
37732
- rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
37733
- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
37740
+ res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
37741
+ if( res==-1 ){
37742
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
37743
+ rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
37744
+#else
37745
+ rc = SQLITE_BUSY;
37746
+#endif
37747
+ }
3773437748
}
3773537749
3773637750
/* Update the global lock state and do debug tracing */
3773737751
#ifdef SQLITE_DEBUG
3773837752
{ u16 mask;
@@ -38225,26 +38239,27 @@
3822538239
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
3822638240
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
3822738241
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
3822838242
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
3822938243
38230
- /* Check that, if this to be a blocking lock, that locks have been
38231
- ** obtained in the following order.
38244
+ /* Check that, if this to be a blocking lock, no locks that occur later
38245
+ ** in the following list than the lock being obtained are already held:
3823238246
**
3823338247
** 1. Checkpointer lock (ofst==1).
38234
- ** 2. Recover lock (ofst==2).
38248
+ ** 2. Write lock (ofst==0).
3823538249
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
38236
- ** 4. Write lock (ofst==0).
3823738250
**
3823838251
** In other words, if this is a blocking lock, none of the locks that
3823938252
** occur later in the above list than the lock being obtained may be
3824038253
** held. */
3824138254
#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
- );
38255
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
38256
+ (ofst!=2) /* not RECOVER */
38257
+ && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
38258
+ && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
38259
+ && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
38260
+ ));
3824638261
#endif
3824738262
3824838263
mask = (1<<(ofst+n)) - (1<<ofst);
3824938264
assert( n>1 || mask==(1<<ofst) );
3825038265
sqlite3_mutex_enter(pShmNode->pShmMutex);
@@ -51548,10 +51563,15 @@
5154851563
SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
5154951564
#endif
5155051565
5155151566
/* Return the sqlite3_file object for the WAL file */
5155251567
SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
51568
+
51569
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
51570
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock);
51571
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db);
51572
+#endif
5155351573
5155451574
#endif /* ifndef SQLITE_OMIT_WAL */
5155551575
#endif /* SQLITE_WAL_H */
5155651576
5155751577
/************** End of wal.h *************************************************/
@@ -57238,11 +57258,10 @@
5723857258
Pager *pPager;
5723957259
assert( pPg!=0 );
5724057260
assert( pPg->pgno==1 );
5724157261
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
5724257262
pPager = pPg->pPager;
57243
- sqlite3PagerResetLockTimeout(pPager);
5724457263
sqlite3PcacheRelease(pPg);
5724557264
pagerUnlockIfUnused(pPager);
5724657265
}
5724757266
5724857267
/*
@@ -58531,20 +58550,10 @@
5853158550
*/
5853258551
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
5853358552
return pPager->fd;
5853458553
}
5853558554
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
-
5854658555
/*
5854758556
** Return the file handle for the journal file (if it exists).
5854858557
** This will be either the rollback journal or the WAL file.
5854958558
*/
5855058559
SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
@@ -58954,11 +58963,10 @@
5895458963
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
5895558964
pPager->pBusyHandlerArg,
5895658965
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
5895758966
pnLog, pnCkpt
5895858967
);
58959
- sqlite3PagerResetLockTimeout(pPager);
5896058968
}
5896158969
return rc;
5896258970
}
5896358971
5896458972
SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
@@ -59119,11 +59127,35 @@
5911959127
}
5912059128
}
5912159129
return rc;
5912259130
}
5912359131
59132
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59133
+/*
59134
+** If pager pPager is a wal-mode database not in exclusive locking mode,
59135
+** invoke the sqlite3WalWriteLock() function on the associated Wal object
59136
+** with the same db and bLock parameters as were passed to this function.
59137
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
59138
+*/
59139
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
59140
+ int rc = SQLITE_OK;
59141
+ if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
59142
+ rc = sqlite3WalWriteLock(pPager->pWal, bLock);
59143
+ }
59144
+ return rc;
59145
+}
5912459146
59147
+/*
59148
+** Set the database handle used by the wal layer to determine if
59149
+** blocking locks are required.
59150
+*/
59151
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
59152
+ if( pagerUseWal(pPager) ){
59153
+ sqlite3WalDb(pPager->pWal, db);
59154
+ }
59155
+}
59156
+#endif
5912559157
5912659158
#ifdef SQLITE_ENABLE_SNAPSHOT
5912759159
/*
5912859160
** If this is a WAL database, obtain a snapshot handle for the snapshot
5912959161
** currently open. Otherwise, return an error.
@@ -59139,11 +59171,14 @@
5913959171
/*
5914059172
** If this is a WAL database, store a pointer to pSnapshot. Next time a
5914159173
** read transaction is opened, attempt to read from the snapshot it
5914259174
** identifies. If this is not a WAL database, return an error.
5914359175
*/
59144
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
59176
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
59177
+ Pager *pPager,
59178
+ sqlite3_snapshot *pSnapshot
59179
+){
5914559180
int rc = SQLITE_OK;
5914659181
if( pPager->pWal ){
5914759182
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
5914859183
}else{
5914959184
rc = SQLITE_ERROR;
@@ -59684,10 +59719,13 @@
5968459719
u8 lockError; /* True if a locking error has occurred */
5968559720
#endif
5968659721
#ifdef SQLITE_ENABLE_SNAPSHOT
5968759722
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
5968859723
#endif
59724
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59725
+ sqlite3 *db;
59726
+#endif
5968959727
};
5969059728
5969159729
/*
5969259730
** Candidate values for Wal.exclusiveMode.
5969359731
*/
@@ -60057,11 +60095,11 @@
6005760095
if( pWal->exclusiveMode ) return SQLITE_OK;
6005860096
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
6005960097
SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
6006060098
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
6006160099
walLockName(lockIdx), rc ? "failed" : "ok"));
60062
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
60100
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
6006360101
return rc;
6006460102
}
6006560103
static void walUnlockShared(Wal *pWal, int lockIdx){
6006660104
if( pWal->exclusiveMode ) return;
6006760105
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
@@ -60073,11 +60111,11 @@
6007360111
if( pWal->exclusiveMode ) return SQLITE_OK;
6007460112
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
6007560113
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
6007660114
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
6007760115
walLockName(lockIdx), n, rc ? "failed" : "ok"));
60078
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
60116
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
6007960117
return rc;
6008060118
}
6008160119
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
6008260120
if( pWal->exclusiveMode ) return;
6008360121
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
@@ -60345,15 +60383,10 @@
6034560383
int rc; /* Return Code */
6034660384
i64 nSize; /* Size of log file */
6034760385
u32 aFrameCksum[2] = {0, 0};
6034860386
int iLock; /* Lock offset to lock for checkpoint */
6034960387
60350
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
60351
- int tmout = 0;
60352
- sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
60353
-#endif
60354
-
6035560388
/* Obtain an exclusive lock on all byte in the locking range not already
6035660389
** locked by the caller. The caller is guaranteed to have locked the
6035760390
** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
6035860391
** If successful, the same bytes that are locked here are unlocked before
6035960392
** this function returns.
@@ -60897,10 +60930,93 @@
6089760930
p = 0;
6089860931
}
6089960932
*pp = p;
6090060933
return rc;
6090160934
}
60935
+
60936
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
60937
+/*
60938
+** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
60939
+** they are supported by the VFS, and (b) the database handle is configured
60940
+** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
60941
+** or 0 otherwise.
60942
+*/
60943
+static int walEnableBlocking(Wal *pWal){
60944
+ int res = 0;
60945
+ if( pWal->db ){
60946
+ int tmout = pWal->db->busyTimeout;
60947
+ if( tmout ){
60948
+ int rc;
60949
+ rc = sqlite3OsFileControl(
60950
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
60951
+ );
60952
+ res = (rc==SQLITE_OK);
60953
+ }
60954
+ }
60955
+ return res;
60956
+}
60957
+
60958
+/*
60959
+** Disable blocking locks.
60960
+*/
60961
+static void walDisableBlocking(Wal *pWal){
60962
+ int tmout = 0;
60963
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
60964
+}
60965
+
60966
+/*
60967
+** If parameter bLock is true, attempt to enable blocking locks, take
60968
+** the WRITER lock, and then disable blocking locks. If blocking locks
60969
+** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
60970
+** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
60971
+** an error if blocking locks can not be enabled.
60972
+**
60973
+** If the bLock parameter is false and the WRITER lock is held, release it.
60974
+*/
60975
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){
60976
+ int rc = SQLITE_OK;
60977
+ assert( pWal->readLock<0 || bLock==0 );
60978
+ if( bLock ){
60979
+ assert( pWal->db );
60980
+ if( walEnableBlocking(pWal) ){
60981
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
60982
+ if( rc==SQLITE_OK ){
60983
+ pWal->writeLock = 1;
60984
+ }
60985
+ walDisableBlocking(pWal);
60986
+ }
60987
+ }else if( pWal->writeLock ){
60988
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
60989
+ pWal->writeLock = 0;
60990
+ }
60991
+ return rc;
60992
+}
60993
+
60994
+/*
60995
+** Set the database handle used to determine if blocking locks are required.
60996
+*/
60997
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){
60998
+ pWal->db = db;
60999
+}
61000
+
61001
+/*
61002
+** Take an exclusive WRITE lock. Blocking if so configured.
61003
+*/
61004
+static int walLockWriter(Wal *pWal){
61005
+ int rc;
61006
+ walEnableBlocking(pWal);
61007
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
61008
+ walDisableBlocking(pWal);
61009
+ return rc;
61010
+}
61011
+#else
61012
+# define walEnableBlocking(x) 0
61013
+# define walDisableBlocking(x)
61014
+# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
61015
+# define sqlite3WalDb(pWal, db)
61016
+#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
61017
+
6090261018
6090361019
/*
6090461020
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
6090561021
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
6090661022
** busy-handler function. Invoke it and retry the lock until either the
@@ -60915,10 +61031,16 @@
6091561031
){
6091661032
int rc;
6091761033
do {
6091861034
rc = walLockExclusive(pWal, lockIdx, n);
6091961035
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
61036
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61037
+ if( rc==SQLITE_BUSY_TIMEOUT ){
61038
+ walDisableBlocking(pWal);
61039
+ rc = SQLITE_BUSY;
61040
+ }
61041
+#endif
6092061042
return rc;
6092161043
}
6092261044
6092361045
/*
6092461046
** The cache of the wal-index header must be valid to call this function.
@@ -61394,32 +61516,36 @@
6139461516
badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
6139561517
6139661518
/* If the first attempt failed, it might have been due to a race
6139761519
** with a writer. So get a WRITE lock and try again.
6139861520
*/
61399
- assert( badHdr==0 || pWal->writeLock==0 );
6140061521
if( badHdr ){
6140161522
if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
6140261523
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
6140361524
walUnlockShared(pWal, WAL_WRITE_LOCK);
6140461525
rc = SQLITE_READONLY_RECOVERY;
6140561526
}
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);
61527
+ }else{
61528
+ int bWriteLock = pWal->writeLock;
61529
+ if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
61530
+ pWal->writeLock = 1;
61531
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
61532
+ badHdr = walIndexTryHdr(pWal, pChanged);
61533
+ if( badHdr ){
61534
+ /* If the wal-index header is still malformed even while holding
61535
+ ** a WRITE lock, it can only mean that the header is corrupted and
61536
+ ** needs to be reconstructed. So run recovery to do exactly that.
61537
+ */
61538
+ rc = walIndexRecover(pWal);
61539
+ *pChanged = 1;
61540
+ }
61541
+ }
61542
+ if( bWriteLock==0 ){
61543
+ pWal->writeLock = 0;
61544
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
61545
+ }
61546
+ }
6142161547
}
6142261548
}
6142361549
6142461550
/* If the header is read successfully, check the version number to make
6142561551
** sure the wal-index was not constructed with some future format that
@@ -61967,26 +62093,38 @@
6196762093
** needs to be flushed.
6196862094
*/
6196962095
SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
6197062096
int rc; /* Return code */
6197162097
int cnt = 0; /* Number of TryBeginRead attempts */
61972
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61973
- int tmout = 0;
61974
-#endif
62098
+
62099
+ assert( pWal->ckptLock==0 );
6197562100
6197662101
#ifdef SQLITE_ENABLE_SNAPSHOT
6197762102
int bChanged = 0;
6197862103
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);
62104
+ if( pSnapshot ){
62105
+ if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
62106
+ bChanged = 1;
62107
+ }
62108
+
62109
+ /* It is possible that there is a checkpointer thread running
62110
+ ** concurrent with this code. If this is the case, it may be that the
62111
+ ** checkpointer has already determined that it will checkpoint
62112
+ ** snapshot X, where X is later in the wal file than pSnapshot, but
62113
+ ** has not yet set the pInfo->nBackfillAttempted variable to indicate
62114
+ ** its intent. To avoid the race condition this leads to, ensure that
62115
+ ** there is no checkpointer process by taking a shared CKPT lock
62116
+ ** before checking pInfo->nBackfillAttempted. */
62117
+ (void)walEnableBlocking(pWal);
62118
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
62119
+ walDisableBlocking(pWal);
62120
+
62121
+ if( rc!=SQLITE_OK ){
62122
+ return rc;
62123
+ }
62124
+ pWal->ckptLock = 1;
62125
+ }
6198862126
#endif
6198962127
6199062128
do{
6199162129
rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
6199262130
}while( rc==WAL_RETRY );
@@ -61993,20 +62131,10 @@
6199362131
testcase( (rc&0xff)==SQLITE_BUSY );
6199462132
testcase( (rc&0xff)==SQLITE_IOERR );
6199562133
testcase( rc==SQLITE_PROTOCOL );
6199662134
testcase( rc==SQLITE_OK );
6199762135
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
-
6200862136
#ifdef SQLITE_ENABLE_SNAPSHOT
6200962137
if( rc==SQLITE_OK ){
6201062138
if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
6201162139
/* At this point the client has a lock on an aReadMark[] slot holding
6201262140
** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
@@ -62024,52 +62152,46 @@
6202462152
volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
6202562153
6202662154
assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
6202762155
assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
6202862156
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
-
62157
+ /* Check that the wal file has not been wrapped. Assuming that it has
62158
+ ** not, also check that no checkpointer has attempted to checkpoint any
62159
+ ** frames beyond pSnapshot->mxFrame. If either of these conditions are
62160
+ ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
62161
+ ** with *pSnapshot and set *pChanged as appropriate for opening the
62162
+ ** snapshot. */
62163
+ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
62164
+ && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
62165
+ ){
62166
+ assert( pWal->readLock>0 );
62167
+ memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
62168
+ *pChanged = bChanged;
62169
+ }else{
62170
+ rc = SQLITE_ERROR_SNAPSHOT;
62171
+ }
62172
+
62173
+ /* A client using a non-current snapshot may not ignore any frames
62174
+ ** from the start of the wal file. This is because, for a system
62175
+ ** where (minFrame < iSnapshot < maxFrame), a checkpointer may
62176
+ ** have omitted to checkpoint a frame earlier than minFrame in
62177
+ ** the file because there exists a frame after iSnapshot that
62178
+ ** is the same database page. */
62179
+ pWal->minFrame = 1;
6206562180
6206662181
if( rc!=SQLITE_OK ){
6206762182
sqlite3WalEndReadTransaction(pWal);
6206862183
}
6206962184
}
6207062185
}
62186
+
62187
+ /* Release the shared CKPT lock obtained above. */
62188
+ if( pWal->ckptLock ){
62189
+ assert( pSnapshot );
62190
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
62191
+ pWal->ckptLock = 0;
62192
+ }
6207162193
#endif
6207262194
return rc;
6207362195
}
6207462196
6207562197
/*
@@ -62235,10 +62357,20 @@
6223562357
**
6223662358
** There can only be a single writer active at a time.
6223762359
*/
6223862360
SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
6223962361
int rc;
62362
+
62363
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
62364
+ /* If the write-lock is already held, then it was obtained before the
62365
+ ** read-transaction was even opened, making this call a no-op.
62366
+ ** Return early. */
62367
+ if( pWal->writeLock ){
62368
+ assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
62369
+ return SQLITE_OK;
62370
+ }
62371
+#endif
6224062372
6224162373
/* Cannot start a write transaction without first holding a read
6224262374
** transaction. */
6224362375
assert( pWal->readLock>=0 );
6224462376
assert( pWal->writeLock==0 && pWal->iReCksum==0 );
@@ -62811,50 +62943,57 @@
6281162943
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
6281262944
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
6281362945
6281462946
if( pWal->readOnly ) return SQLITE_READONLY;
6281562947
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
62948
+
62949
+ /* Enable blocking locks, if possible. If blocking locks are successfully
62950
+ ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
62951
+ sqlite3WalDb(pWal, db);
62952
+ (void)walEnableBlocking(pWal);
6281662953
6281762954
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
62818
- ** "checkpoint" lock on the database file. */
62955
+ ** "checkpoint" lock on the database file.
62956
+ ** EVIDENCE-OF: R-10421-19736 If any other process is running a
62957
+ ** checkpoint operation at the same time, the lock cannot be obtained and
62958
+ ** SQLITE_BUSY is returned.
62959
+ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
62960
+ ** it will not be invoked in this case.
62961
+ */
6281962962
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
- }
62963
+ testcase( rc==SQLITE_BUSY );
62964
+ testcase( rc!=SQLITE_OK && xBusy2!=0 );
62965
+ if( rc==SQLITE_OK ){
62966
+ pWal->ckptLock = 1;
62967
+
62968
+ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
62969
+ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
62970
+ ** file.
62971
+ **
62972
+ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
62973
+ ** immediately, and a busy-handler is configured, it is invoked and the
62974
+ ** writer lock retried until either the busy-handler returns 0 or the
62975
+ ** lock is successfully obtained.
62976
+ */
62977
+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
62978
+ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
62979
+ if( rc==SQLITE_OK ){
62980
+ pWal->writeLock = 1;
62981
+ }else if( rc==SQLITE_BUSY ){
62982
+ eMode2 = SQLITE_CHECKPOINT_PASSIVE;
62983
+ xBusy2 = 0;
62984
+ rc = SQLITE_OK;
62985
+ }
62986
+ }
62987
+ }
62988
+
6285262989
6285362990
/* Read the wal-index header. */
6285462991
if( rc==SQLITE_OK ){
62992
+ walDisableBlocking(pWal);
6285562993
rc = walIndexReadHdr(pWal, &isChanged);
62994
+ (void)walEnableBlocking(pWal);
6285662995
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
6285762996
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
6285862997
}
6285962998
}
6286062999
@@ -62881,16 +63020,24 @@
6288163020
** next time the pager opens a snapshot on this database it knows that
6288263021
** the cache needs to be reset.
6288363022
*/
6288463023
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
6288563024
}
63025
+
63026
+ walDisableBlocking(pWal);
63027
+ sqlite3WalDb(pWal, 0);
6288663028
6288763029
/* Release the locks. */
6288863030
sqlite3WalEndWriteTransaction(pWal);
62889
- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
62890
- pWal->ckptLock = 0;
63031
+ if( pWal->ckptLock ){
63032
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
63033
+ pWal->ckptLock = 0;
63034
+ }
6289163035
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
63036
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
63037
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
63038
+#endif
6289263039
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
6289363040
}
6289463041
6289563042
/* Return the value to pass to a sqlite3_wal_hook callback, the
6289663043
** number of frames in the WAL at the point of the last commit since
@@ -63003,11 +63150,14 @@
6300363150
return rc;
6300463151
}
6300563152
6300663153
/* Try to open on pSnapshot when the next read-transaction starts
6300763154
*/
63008
-SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
63155
+SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
63156
+ Wal *pWal,
63157
+ sqlite3_snapshot *pSnapshot
63158
+){
6300963159
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
6301063160
}
6301163161
6301263162
/*
6301363163
** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
@@ -63522,11 +63672,11 @@
6352263672
u8 incrVacuum; /* True if incr-vacuum is enabled */
6352363673
u8 bDoTruncate; /* True to truncate db on commit */
6352463674
#endif
6352563675
u8 inTransaction; /* Transaction state */
6352663676
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 */
63677
+ u8 nReserveWanted; /* Desired number of extra bytes per page */
6352863678
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
6352963679
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
6353063680
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
6353163681
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
6353263682
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
@@ -66416,12 +66566,11 @@
6641666566
*/
6641766567
static int btreeInvokeBusyHandler(void *pArg){
6641866568
BtShared *pBt = (BtShared*)pArg;
6641966569
assert( pBt->db );
6642066570
assert( sqlite3_mutex_held(pBt->db->mutex) );
66421
- return sqlite3InvokeBusyHandler(&pBt->db->busyHandler,
66422
- sqlite3PagerFile(pBt->pPager));
66571
+ return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
6642366572
}
6642466573
6642566574
/*
6642666575
** Open a database file.
6642766576
**
@@ -66968,23 +67117,21 @@
6696867117
** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
6696967118
** and autovacuum mode can no longer be changed.
6697067119
*/
6697167120
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
6697267121
int rc = SQLITE_OK;
67122
+ int x;
6697367123
BtShared *pBt = p->pBt;
66974
- assert( nReserve>=-1 && nReserve<=254 );
67124
+ assert( nReserve>=0 && nReserve<=255 );
6697567125
sqlite3BtreeEnter(p);
66976
- if( nReserve>=0 ){
66977
- pBt->nReserveWanted = nReserve + 1;
66978
- }
67126
+ pBt->nReserveWanted = nReserve;
67127
+ x = pBt->pageSize - pBt->usableSize;
67128
+ if( nReserve<x ) nReserve = x;
6697967129
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
6698067130
sqlite3BtreeLeave(p);
6698167131
return SQLITE_READONLY;
6698267132
}
66983
- if( nReserve<0 ){
66984
- nReserve = pBt->pageSize - pBt->usableSize;
66985
- }
6698667133
assert( nReserve>=0 && nReserve<=255 );
6698767134
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
6698867135
((pageSize-1)&pageSize)==0 ){
6698967136
assert( (pageSize & 7)==0 );
6699067137
assert( !pBt->pCursor );
@@ -67031,16 +67178,16 @@
6703167178
** The value returned is the larger of the current reserve size and
6703267179
** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
6703367180
** The amount of reserve can only grow - never shrink.
6703467181
*/
6703567182
SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
67036
- int n;
67183
+ int n1, n2;
6703767184
sqlite3BtreeEnter(p);
67038
- n = ((int)p->pBt->nReserveWanted) - 1;
67039
- if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);
67185
+ n1 = (int)p->pBt->nReserveWanted;
67186
+ n2 = sqlite3BtreeGetReserveNoMutex(p);
6704067187
sqlite3BtreeLeave(p);
67041
- return n;
67188
+ return n1>n2 ? n1 : n2;
6704267189
}
6704367190
6704467191
6704567192
/*
6704667193
** Set the maximum page count for a database if mxPage is positive.
@@ -67486,10 +67633,11 @@
6748667633
** when A already has a read lock, we encourage A to give up and let B
6748767634
** proceed.
6748867635
*/
6748967636
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
6749067637
BtShared *pBt = p->pBt;
67638
+ Pager *pPager = pBt->pPager;
6749167639
int rc = SQLITE_OK;
6749267640
6749367641
sqlite3BtreeEnter(p);
6749467642
btreeIntegrity(p);
6749567643
@@ -67501,11 +67649,11 @@
6750167649
goto trans_begun;
6750267650
}
6750367651
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
6750467652
6750567653
if( (p->db->flags & SQLITE_ResetDatabase)
67506
- && sqlite3PagerIsreadonly(pBt->pPager)==0
67654
+ && sqlite3PagerIsreadonly(pPager)==0
6750767655
){
6750867656
pBt->btsFlags &= ~BTS_READ_ONLY;
6750967657
}
6751067658
6751167659
/* Write transactions are not possible on a read-only database */
@@ -67549,10 +67697,22 @@
6754967697
if( SQLITE_OK!=rc ) goto trans_begun;
6755067698
6755167699
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
6755267700
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
6755367701
do {
67702
+ sqlite3PagerWalDb(pPager, p->db);
67703
+
67704
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67705
+ /* If transitioning from no transaction directly to a write transaction,
67706
+ ** block for the WRITER lock first if possible. */
67707
+ if( pBt->pPage1==0 && wrflag ){
67708
+ assert( pBt->inTransaction==TRANS_NONE );
67709
+ rc = sqlite3PagerWalWriteLock(pPager, 1);
67710
+ if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
67711
+ }
67712
+#endif
67713
+
6755467714
/* Call lockBtree() until either pBt->pPage1 is populated or
6755567715
** lockBtree() returns something other than SQLITE_OK. lockBtree()
6755667716
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
6755767717
** reading page 1 it discovers that the page-size of the database
6755867718
** file is not pBt->pageSize. In this case lockBtree() will update
@@ -67562,11 +67722,11 @@
6756267722
6756367723
if( rc==SQLITE_OK && wrflag ){
6756467724
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
6756567725
rc = SQLITE_READONLY;
6756667726
}else{
67567
- rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
67727
+ rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
6756867728
if( rc==SQLITE_OK ){
6756967729
rc = newDatabase(pBt);
6757067730
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
6757167731
/* if there was no transaction opened when this function was
6757267732
** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
@@ -67575,15 +67735,19 @@
6757567735
}
6757667736
}
6757767737
}
6757867738
6757967739
if( rc!=SQLITE_OK ){
67740
+ (void)sqlite3PagerWalWriteLock(pPager, 0);
6758067741
unlockBtreeIfUnused(pBt);
6758167742
}
6758267743
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
6758367744
btreeInvokeBusyHandler(pBt) );
67584
- sqlite3PagerResetLockTimeout(pBt->pPager);
67745
+ sqlite3PagerWalDb(pPager, 0);
67746
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67747
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
67748
+#endif
6758567749
6758667750
if( rc==SQLITE_OK ){
6758767751
if( p->inTrans==TRANS_NONE ){
6758867752
pBt->nTransaction++;
6758967753
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -67631,11 +67795,11 @@
6763167795
if( wrflag ){
6763267796
/* This call makes sure that the pager has the correct number of
6763367797
** open savepoints. If the second parameter is greater than 0 and
6763467798
** the sub-journal is not already open, then it will be opened here.
6763567799
*/
67636
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
67800
+ rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
6763767801
}
6763867802
}
6763967803
6764067804
btreeIntegrity(p);
6764167805
sqlite3BtreeLeave(p);
@@ -71267,11 +71431,11 @@
7126771431
7126871432
/* Remove cells from the start and end of the page */
7126971433
assert( nCell>=0 );
7127071434
if( iOld<iNew ){
7127171435
int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
71272
- if( nShift>nCell ) return SQLITE_CORRUPT_BKPT;
71436
+ if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
7127371437
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
7127471438
nCell -= nShift;
7127571439
}
7127671440
if( iNewEnd < iOldEnd ){
7127771441
int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
@@ -74746,11 +74910,11 @@
7474674910
** Attempt to set the page size of the destination to match the page size
7474774911
** of the source.
7474874912
*/
7474974913
static int setDestPgsz(sqlite3_backup *p){
7475074914
int rc;
74751
- rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
74915
+ rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
7475274916
return rc;
7475374917
}
7475474918
7475574919
/*
7475674920
** Check that there is no open read-transaction on the b-tree passed as the
@@ -90540,16 +90704,23 @@
9054090704
rc = sqlite3VdbeSorterWrite(pC, pIn2);
9054190705
if( rc) goto abort_due_to_error;
9054290706
break;
9054390707
}
9054490708
90545
-/* Opcode: IdxDelete P1 P2 P3 * *
90709
+/* Opcode: IdxDelete P1 P2 P3 * P5
9054690710
** Synopsis: key=r[P2@P3]
9054790711
**
9054890712
** The content of P3 registers starting at register P2 form
9054990713
** an unpacked index key. This opcode removes that entry from the
9055090714
** index opened by cursor P1.
90715
+**
90716
+** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
90717
+** if no matching index entry is found. This happens when running
90718
+** an UPDATE or DELETE statement and the index entry to be updated
90719
+** or deleted is not found. For some uses of IdxDelete
90720
+** (example: the EXCEPT operator) it does not matter that no matching
90721
+** entry is found. For those cases, P5 is zero.
9055190722
*/
9055290723
case OP_IdxDelete: {
9055390724
VdbeCursor *pC;
9055490725
BtCursor *pCrsr;
9055590726
int res;
@@ -90562,20 +90733,22 @@
9056290733
assert( pC!=0 );
9056390734
assert( pC->eCurType==CURTYPE_BTREE );
9056490735
sqlite3VdbeIncrWriteCounter(p, pC);
9056590736
pCrsr = pC->uc.pCursor;
9056690737
assert( pCrsr!=0 );
90567
- assert( pOp->p5==0 );
9056890738
r.pKeyInfo = pC->pKeyInfo;
9056990739
r.nField = (u16)pOp->p3;
9057090740
r.default_rc = 0;
9057190741
r.aMem = &aMem[pOp->p2];
9057290742
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
9057390743
if( rc ) goto abort_due_to_error;
9057490744
if( res==0 ){
9057590745
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
9057690746
if( rc ) goto abort_due_to_error;
90747
+ }else if( pOp->p5 ){
90748
+ rc = SQLITE_CORRUPT_INDEX;
90749
+ goto abort_due_to_error;
9057790750
}
9057890751
assert( pC->deferredMoveto==0 );
9057990752
pC->cacheStatus = CACHE_STALE;
9058090753
pC->seekResult = 0;
9058190754
break;
@@ -103684,11 +103857,11 @@
103684103857
assert( pExpr->affExpr==OE_Rollback
103685103858
|| pExpr->affExpr==OE_Abort
103686103859
|| pExpr->affExpr==OE_Fail
103687103860
|| pExpr->affExpr==OE_Ignore
103688103861
);
103689
- if( !pParse->pTriggerTab ){
103862
+ if( !pParse->pTriggerTab && !pParse->nested ){
103690103863
sqlite3ErrorMsg(pParse,
103691103864
"RAISE() may only be used within a trigger-program");
103692103865
return 0;
103693103866
}
103694103867
if( pExpr->affExpr==OE_Abort ){
@@ -103698,12 +103871,13 @@
103698103871
if( pExpr->affExpr==OE_Ignore ){
103699103872
sqlite3VdbeAddOp4(
103700103873
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
103701103874
VdbeCoverage(v);
103702103875
}else{
103703
- sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
103704
- pExpr->affExpr, pExpr->u.zToken, 0, 0);
103876
+ sqlite3HaltConstraint(pParse,
103877
+ pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
103878
+ pExpr->affExpr, pExpr->u.zToken, 0, 0);
103705103879
}
103706103880
103707103881
break;
103708103882
}
103709103883
#endif
@@ -105454,10 +105628,26 @@
105454105628
exit_rename_table:
105455105629
sqlite3SrcListDelete(db, pSrc);
105456105630
sqlite3DbFree(db, zName);
105457105631
db->mDbFlags = savedDbFlags;
105458105632
}
105633
+
105634
+/*
105635
+** Write code that will raise an error if the table described by
105636
+** zDb and zTab is not empty.
105637
+*/
105638
+static void sqlite3ErrorIfNotEmpty(
105639
+ Parse *pParse, /* Parsing context */
105640
+ const char *zDb, /* Schema holding the table */
105641
+ const char *zTab, /* Table to check for empty */
105642
+ const char *zErr /* Error message text */
105643
+){
105644
+ sqlite3NestedParse(pParse,
105645
+ "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
105646
+ zErr, zDb, zTab
105647
+ );
105648
+}
105459105649
105460105650
/*
105461105651
** This function is called after an "ALTER TABLE ... ADD" statement
105462105652
** has been parsed. Argument pColDef contains the text of the new
105463105653
** column definition.
@@ -105507,11 +105697,12 @@
105507105697
if( pCol->colFlags & COLFLAG_PRIMKEY ){
105508105698
sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
105509105699
return;
105510105700
}
105511105701
if( pNew->pIndex ){
105512
- sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
105702
+ sqlite3ErrorMsg(pParse,
105703
+ "Cannot add a UNIQUE column");
105513105704
return;
105514105705
}
105515105706
if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
105516105707
/* If the default value for the new column was specified with a
105517105708
** literal NULL, then set pDflt to 0. This simplifies checking
@@ -105520,19 +105711,18 @@
105520105711
assert( pDflt==0 || pDflt->op==TK_SPAN );
105521105712
if( pDflt && pDflt->pLeft->op==TK_NULL ){
105522105713
pDflt = 0;
105523105714
}
105524105715
if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
105525
- sqlite3ErrorMsg(pParse,
105716
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105526105717
"Cannot add a REFERENCES column with non-NULL default value");
105527
- return;
105528105718
}
105529105719
if( pCol->notNull && !pDflt ){
105530
- sqlite3ErrorMsg(pParse,
105720
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105531105721
"Cannot add a NOT NULL column with default value NULL");
105532
- return;
105533105722
}
105723
+
105534105724
105535105725
/* Ensure the default expression is something that sqlite3ValueFromExpr()
105536105726
** can handle (i.e. not CURRENT_TIME etc.)
105537105727
*/
105538105728
if( pDflt ){
@@ -105543,18 +105733,17 @@
105543105733
if( rc!=SQLITE_OK ){
105544105734
assert( db->mallocFailed == 1 );
105545105735
return;
105546105736
}
105547105737
if( !pVal ){
105548
- sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
105549
- return;
105738
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105739
+ "Cannot add a column with non-constant default");
105550105740
}
105551105741
sqlite3ValueFree(pVal);
105552105742
}
105553105743
}else if( pCol->colFlags & COLFLAG_STORED ){
105554
- sqlite3ErrorMsg(pParse, "cannot add a STORED column");
105555
- return;
105744
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
105556105745
}
105557105746
105558105747
105559105748
/* Modify the CREATE TABLE statement. */
105560105749
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
@@ -114373,11 +114562,11 @@
114373114562
pParse->rc = rc;
114374114563
return 1;
114375114564
}
114376114565
db->aDb[1].pBt = pBt;
114377114566
assert( db->aDb[1].pSchema );
114378
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
114567
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
114379114568
sqlite3OomFault(db);
114380114569
return 1;
114381114570
}
114382114571
}
114383114572
return 0;
@@ -114484,11 +114673,11 @@
114484114673
char *p4, /* Error message */
114485114674
i8 p4type, /* P4_STATIC or P4_TRANSIENT */
114486114675
u8 p5Errmsg /* P5_ErrMsg type */
114487114676
){
114488114677
Vdbe *v = sqlite3GetVdbe(pParse);
114489
- assert( (errCode&0xff)==SQLITE_CONSTRAINT );
114678
+ assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
114490114679
if( onError==OE_Abort ){
114491114680
sqlite3MayAbort(pParse);
114492114681
}
114493114682
sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
114494114683
sqlite3VdbeChangeP5(v, p5Errmsg);
@@ -116197,10 +116386,11 @@
116197116386
VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
116198116387
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
116199116388
&iPartIdxLabel, pPrior, r1);
116200116389
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
116201116390
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
116391
+ sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
116202116392
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
116203116393
pPrior = pIdx;
116204116394
}
116205116395
}
116206116396
@@ -125555,11 +125745,11 @@
125555125745
}else{
125556125746
/* Malloc may fail when setting the page-size, as there is an internal
125557125747
** buffer that the pager module resizes using sqlite3_realloc().
125558125748
*/
125559125749
db->nextPagesize = sqlite3Atoi(zRight);
125560
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
125750
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
125561125751
sqlite3OomFault(db);
125562125752
}
125563125753
}
125564125754
break;
125565125755
}
@@ -135193,17 +135383,19 @@
135193135383
**
135194135384
** In practice the KeyInfo structure will not be used. It is only
135195135385
** passed to keep OP_OpenRead happy.
135196135386
*/
135197135387
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;
135388
+ if( !p->pSrc->a[0].fg.notIndexed ){
135389
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
135390
+ if( pIdx->bUnordered==0
135391
+ && pIdx->szIdxRow<pTab->szTabRow
135392
+ && pIdx->pPartIdxWhere==0
135393
+ && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
135394
+ ){
135395
+ pBest = pIdx;
135396
+ }
135205135397
}
135206135398
}
135207135399
if( pBest ){
135208135400
iRoot = pBest->tnum;
135209135401
pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
@@ -138439,11 +138631,11 @@
138439138631
db->mDbFlags = saved_mDbFlags;
138440138632
db->flags = saved_flags;
138441138633
db->nChange = saved_nChange;
138442138634
db->nTotalChange = saved_nTotalChange;
138443138635
db->mTrace = saved_mTrace;
138444
- sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
138636
+ sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
138445138637
138446138638
/* Currently there is an SQL level transaction open on the vacuum
138447138639
** database. No locks are held on any other files (since the main file
138448138640
** was committed at the btree level). So it safe to end the transaction
138449138641
** by manually setting the autoCommit flag to true and detaching the
@@ -161431,12 +161623,11 @@
161431161623
** Return non-zero to retry the lock. Return zero to stop trying
161432161624
** and cause SQLite to return SQLITE_BUSY.
161433161625
*/
161434161626
static int sqliteDefaultBusyCallback(
161435161627
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 */
161628
+ int count /* Number of times table has been busy */
161438161629
){
161439161630
#if SQLITE_OS_WIN || HAVE_USLEEP
161440161631
/* This case is for systems that have support for sleeping for fractions of
161441161632
** a second. Examples: All windows systems, unix systems with usleep() */
161442161633
static const u8 delays[] =
@@ -161446,35 +161637,10 @@
161446161637
# define NDELAY ArraySize(delays)
161447161638
sqlite3 *db = (sqlite3 *)ptr;
161448161639
int tmout = db->busyTimeout;
161449161640
int delay, prior;
161450161641
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
161476161642
assert( count>=0 );
161477161643
if( count < NDELAY ){
161478161644
delay = delays[count];
161479161645
prior = totals[count];
161480161646
}else{
@@ -161490,11 +161656,10 @@
161490161656
#else
161491161657
/* This case for unix systems that lack usleep() support. Sleeping
161492161658
** must be done in increments of whole seconds */
161493161659
sqlite3 *db = (sqlite3 *)ptr;
161494161660
int tmout = ((sqlite3 *)ptr)->busyTimeout;
161495
- UNUSED_PARAMETER(pFile);
161496161661
if( (count+1)*1000 > tmout ){
161497161662
return 0;
161498161663
}
161499161664
sqlite3OsSleep(db->pVfs, 1000000);
161500161665
return 1;
@@ -161508,23 +161673,14 @@
161508161673
** lock on VFS file pFile.
161509161674
**
161510161675
** If this routine returns non-zero, the lock is retried. If it
161511161676
** returns 0, the operation aborts with an SQLITE_BUSY error.
161512161677
*/
161513
-SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
161678
+SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
161514161679
int rc;
161515161680
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
- }
161681
+ rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
161526161682
if( rc==0 ){
161527161683
p->nBusy = -1;
161528161684
}else{
161529161685
p->nBusy++;
161530161686
}
@@ -161545,11 +161701,10 @@
161545161701
#endif
161546161702
sqlite3_mutex_enter(db->mutex);
161547161703
db->busyHandler.xBusyHandler = xBusy;
161548161704
db->busyHandler.pBusyArg = pArg;
161549161705
db->busyHandler.nBusy = 0;
161550
- db->busyHandler.bExtraFileArg = 0;
161551161706
db->busyTimeout = 0;
161552161707
sqlite3_mutex_leave(db->mutex);
161553161708
return SQLITE_OK;
161554161709
}
161555161710
@@ -161596,11 +161751,10 @@
161596161751
#endif
161597161752
if( ms>0 ){
161598161753
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
161599161754
(void*)db);
161600161755
db->busyTimeout = ms;
161601
- db->busyHandler.bExtraFileArg = 1;
161602161756
}else{
161603161757
sqlite3_busy_handler(db, 0, 0);
161604161758
}
161605161759
return SQLITE_OK;
161606161760
}
@@ -163071,10 +163225,13 @@
163071163225
| SQLITE_EnableQPSG
163072163226
#endif
163073163227
#if defined(SQLITE_DEFAULT_DEFENSIVE)
163074163228
| SQLITE_Defensive
163075163229
#endif
163230
+#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
163231
+ | SQLITE_LegacyAlter
163232
+#endif
163076163233
;
163077163234
sqlite3HashInit(&db->aCollSeq);
163078163235
#ifndef SQLITE_OMIT_VIRTUALTABLE
163079163236
sqlite3HashInit(&db->aModule);
163080163237
#endif
@@ -163668,11 +163825,11 @@
163668163825
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
163669163826
rc = SQLITE_OK;
163670163827
}else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
163671163828
int iNew = *(int*)pArg;
163672163829
*(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
163673
- if( iNew>=0 && iNew<=254 ){
163830
+ if( iNew>=0 && iNew<=255 ){
163674163831
sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
163675163832
}
163676163833
rc = SQLITE_OK;
163677163834
}else{
163678163835
rc = sqlite3OsFileControl(fd, op, pArg);
@@ -167905,11 +168062,13 @@
167905168062
static void fts3ReadNextPos(
167906168063
char **pp, /* IN/OUT: Pointer into position-list buffer */
167907168064
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
167908168065
){
167909168066
if( (**pp)&0xFE ){
167910
- fts3GetDeltaVarint(pp, pi);
168067
+ int iVal;
168068
+ *pp += fts3GetVarint32((*pp), &iVal);
168069
+ *pi += iVal;
167911168070
*pi -= 2;
167912168071
}else{
167913168072
*pi = POSITION_LIST_END;
167914168073
}
167915168074
}
@@ -224505,11 +224664,11 @@
224505224664
int nArg, /* Number of args */
224506224665
sqlite3_value **apUnused /* Function arguments */
224507224666
){
224508224667
assert( nArg==0 );
224509224668
UNUSED_PARAM2(nArg, apUnused);
224510
- sqlite3_result_text(pCtx, "fts5: 2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda", -1, SQLITE_TRANSIENT);
224669
+ sqlite3_result_text(pCtx, "fts5: 2020-05-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f9654ff", -1, SQLITE_TRANSIENT);
224511224670
}
224512224671
224513224672
/*
224514224673
** Return true if zName is the extension on one of the shadow tables used
224515224674
** by this module.
@@ -229288,12 +229447,12 @@
229288229447
}
229289229448
#endif /* SQLITE_CORE */
229290229449
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
229291229450
229292229451
/************** End of stmt.c ************************************************/
229293
-#if __LINE__!=229293
229452
+#if __LINE__!=229452
229294229453
#undef SQLITE_SOURCE_ID
229295
-#define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb21alt2"
229454
+#define SQLITE_SOURCE_ID "2020-05-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f96alt2"
229296229455
#endif
229297229456
/* Return the source-id for this library */
229298229457
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
229299229458
/************************** End of sqlite3.c ******************************/
229300229459
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1162,11 +1162,11 @@
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))
@@ -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);
@@ -19935,11 +19939,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*);
@@ -27730,14 +27734,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);
@@ -34971,20 +34977,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 +37729,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 +38239,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);
@@ -51548,10 +51563,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 +57258,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 +58550,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 +58963,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 +59127,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 +59171,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 +59719,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 */
@@ -60057,11 +60095,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 +60111,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 +60383,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 +60930,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 +61031,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.
@@ -61394,32 +61516,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
@@ -61967,26 +62093,38 @@
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 +62131,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 +62152,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 /*
@@ -62235,10 +62357,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 +62943,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 +63020,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 +63150,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 +63672,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 +66566,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 +67117,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 +67178,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 +67633,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 +67649,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 +67697,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 +67722,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 +67735,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 +67795,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 +71431,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 +74910,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
@@ -90540,16 +90704,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 +90733,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;
@@ -103684,11 +103857,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 +103871,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
@@ -105454,10 +105628,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 +105697,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 +105711,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 +105733,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);
@@ -114373,11 +114562,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 +114673,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 +116386,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
@@ -125555,11 +125745,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 }
@@ -135193,17 +135383,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);
@@ -138439,11 +138631,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
@@ -161431,12 +161623,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 +161637,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 +161656,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 +161673,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 +161701,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 +161751,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 +163225,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
@@ -163668,11 +163825,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 +168062,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 }
@@ -224505,11 +224664,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 +229447,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
@@ -1162,11 +1162,11 @@
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-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f9654ff"
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))
@@ -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);
@@ -19935,11 +19939,11 @@
19939 SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
19940 SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
19941 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
19942 SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
19943 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
19944 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
19945 SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
19946 SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
19947 SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
19948 SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
19949 SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
@@ -27730,14 +27734,16 @@
27734 if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
27735 mem0.alarmThreshold-nDiff ){
27736 sqlite3MallocAlarm(nDiff);
27737 }
27738 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27739 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
27740 if( pNew==0 && mem0.alarmThreshold>0 ){
27741 sqlite3MallocAlarm((int)nBytes);
27742 pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
27743 }
27744 #endif
27745 if( pNew ){
27746 nNew = sqlite3MallocSize(pNew);
27747 sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
27748 }
27749 sqlite3_mutex_leave(mem0.mutex);
@@ -34971,20 +34977,21 @@
34977 static int osSetPosixAdvisoryLock(
34978 int h, /* The file descriptor on which to take the lock */
34979 struct flock *pLock, /* The description of the lock */
34980 unixFile *pFile /* Structure holding timeout value */
34981 ){
34982 int tm = pFile->iBusyTimeout;
34983 int rc = osFcntl(h,F_SETLK,pLock);
34984 while( rc<0 && tm>0 ){
34985 /* On systems that support some kind of blocking file lock with a timeout,
34986 ** make appropriate changes here to invoke that blocking file lock. On
34987 ** generic posix, however, there is no such API. So we simply try the
34988 ** lock once every millisecond until either the timeout expires, or until
34989 ** the lock is obtained. */
34990 usleep(1000);
34991 rc = osFcntl(h,F_SETLK,pLock);
34992 tm--;
34993 }
34994 return rc;
34995 }
34996 #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
34997
@@ -37722,17 +37729,24 @@
37729
37730 /* Locks are within range */
37731 assert( n>=1 && n<=SQLITE_SHM_NLOCK );
37732
37733 if( pShmNode->hShm>=0 ){
37734 int res;
37735 /* Initialize the locking parameters */
37736 f.l_type = lockType;
37737 f.l_whence = SEEK_SET;
37738 f.l_start = ofst;
37739 f.l_len = n;
37740 res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
37741 if( res==-1 ){
37742 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
37743 rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
37744 #else
37745 rc = SQLITE_BUSY;
37746 #endif
37747 }
37748 }
37749
37750 /* Update the global lock state and do debug tracing */
37751 #ifdef SQLITE_DEBUG
37752 { u16 mask;
@@ -38225,26 +38239,27 @@
38239 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
38240 assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
38241 assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
38242 assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
38243
38244 /* Check that, if this to be a blocking lock, no locks that occur later
38245 ** in the following list than the lock being obtained are already held:
38246 **
38247 ** 1. Checkpointer lock (ofst==1).
38248 ** 2. Write lock (ofst==0).
38249 ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
 
38250 **
38251 ** In other words, if this is a blocking lock, none of the locks that
38252 ** occur later in the above list than the lock being obtained may be
38253 ** held. */
38254 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
38255 assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
38256 (ofst!=2) /* not RECOVER */
38257 && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
38258 && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
38259 && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
38260 ));
38261 #endif
38262
38263 mask = (1<<(ofst+n)) - (1<<ofst);
38264 assert( n>1 || mask==(1<<ofst) );
38265 sqlite3_mutex_enter(pShmNode->pShmMutex);
@@ -51548,10 +51563,15 @@
51563 SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
51564 #endif
51565
51566 /* Return the sqlite3_file object for the WAL file */
51567 SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
51568
51569 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
51570 SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock);
51571 SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db);
51572 #endif
51573
51574 #endif /* ifndef SQLITE_OMIT_WAL */
51575 #endif /* SQLITE_WAL_H */
51576
51577 /************** End of wal.h *************************************************/
@@ -57238,11 +57258,10 @@
57258 Pager *pPager;
57259 assert( pPg!=0 );
57260 assert( pPg->pgno==1 );
57261 assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
57262 pPager = pPg->pPager;
 
57263 sqlite3PcacheRelease(pPg);
57264 pagerUnlockIfUnused(pPager);
57265 }
57266
57267 /*
@@ -58531,20 +58550,10 @@
58550 */
58551 SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
58552 return pPager->fd;
58553 }
58554
 
 
 
 
 
 
 
 
 
 
58555 /*
58556 ** Return the file handle for the journal file (if it exists).
58557 ** This will be either the rollback journal or the WAL file.
58558 */
58559 SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
@@ -58954,11 +58963,10 @@
58963 (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
58964 pPager->pBusyHandlerArg,
58965 pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
58966 pnLog, pnCkpt
58967 );
 
58968 }
58969 return rc;
58970 }
58971
58972 SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
@@ -59119,11 +59127,35 @@
59127 }
59128 }
59129 return rc;
59130 }
59131
59132 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59133 /*
59134 ** If pager pPager is a wal-mode database not in exclusive locking mode,
59135 ** invoke the sqlite3WalWriteLock() function on the associated Wal object
59136 ** with the same db and bLock parameters as were passed to this function.
59137 ** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
59138 */
59139 SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
59140 int rc = SQLITE_OK;
59141 if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
59142 rc = sqlite3WalWriteLock(pPager->pWal, bLock);
59143 }
59144 return rc;
59145 }
59146
59147 /*
59148 ** Set the database handle used by the wal layer to determine if
59149 ** blocking locks are required.
59150 */
59151 SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
59152 if( pagerUseWal(pPager) ){
59153 sqlite3WalDb(pPager->pWal, db);
59154 }
59155 }
59156 #endif
59157
59158 #ifdef SQLITE_ENABLE_SNAPSHOT
59159 /*
59160 ** If this is a WAL database, obtain a snapshot handle for the snapshot
59161 ** currently open. Otherwise, return an error.
@@ -59139,11 +59171,14 @@
59171 /*
59172 ** If this is a WAL database, store a pointer to pSnapshot. Next time a
59173 ** read transaction is opened, attempt to read from the snapshot it
59174 ** identifies. If this is not a WAL database, return an error.
59175 */
59176 SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
59177 Pager *pPager,
59178 sqlite3_snapshot *pSnapshot
59179 ){
59180 int rc = SQLITE_OK;
59181 if( pPager->pWal ){
59182 sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
59183 }else{
59184 rc = SQLITE_ERROR;
@@ -59684,10 +59719,13 @@
59719 u8 lockError; /* True if a locking error has occurred */
59720 #endif
59721 #ifdef SQLITE_ENABLE_SNAPSHOT
59722 WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
59723 #endif
59724 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
59725 sqlite3 *db;
59726 #endif
59727 };
59728
59729 /*
59730 ** Candidate values for Wal.exclusiveMode.
59731 */
@@ -60057,11 +60095,11 @@
60095 if( pWal->exclusiveMode ) return SQLITE_OK;
60096 rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
60097 SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
60098 WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
60099 walLockName(lockIdx), rc ? "failed" : "ok"));
60100 VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
60101 return rc;
60102 }
60103 static void walUnlockShared(Wal *pWal, int lockIdx){
60104 if( pWal->exclusiveMode ) return;
60105 (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
@@ -60073,11 +60111,11 @@
60111 if( pWal->exclusiveMode ) return SQLITE_OK;
60112 rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
60113 SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
60114 WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
60115 walLockName(lockIdx), n, rc ? "failed" : "ok"));
60116 VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
60117 return rc;
60118 }
60119 static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
60120 if( pWal->exclusiveMode ) return;
60121 (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
@@ -60345,15 +60383,10 @@
60383 int rc; /* Return Code */
60384 i64 nSize; /* Size of log file */
60385 u32 aFrameCksum[2] = {0, 0};
60386 int iLock; /* Lock offset to lock for checkpoint */
60387
 
 
 
 
 
60388 /* Obtain an exclusive lock on all byte in the locking range not already
60389 ** locked by the caller. The caller is guaranteed to have locked the
60390 ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
60391 ** If successful, the same bytes that are locked here are unlocked before
60392 ** this function returns.
@@ -60897,10 +60930,93 @@
60930 p = 0;
60931 }
60932 *pp = p;
60933 return rc;
60934 }
60935
60936 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
60937 /*
60938 ** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
60939 ** they are supported by the VFS, and (b) the database handle is configured
60940 ** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
60941 ** or 0 otherwise.
60942 */
60943 static int walEnableBlocking(Wal *pWal){
60944 int res = 0;
60945 if( pWal->db ){
60946 int tmout = pWal->db->busyTimeout;
60947 if( tmout ){
60948 int rc;
60949 rc = sqlite3OsFileControl(
60950 pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
60951 );
60952 res = (rc==SQLITE_OK);
60953 }
60954 }
60955 return res;
60956 }
60957
60958 /*
60959 ** Disable blocking locks.
60960 */
60961 static void walDisableBlocking(Wal *pWal){
60962 int tmout = 0;
60963 sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
60964 }
60965
60966 /*
60967 ** If parameter bLock is true, attempt to enable blocking locks, take
60968 ** the WRITER lock, and then disable blocking locks. If blocking locks
60969 ** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
60970 ** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
60971 ** an error if blocking locks can not be enabled.
60972 **
60973 ** If the bLock parameter is false and the WRITER lock is held, release it.
60974 */
60975 SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){
60976 int rc = SQLITE_OK;
60977 assert( pWal->readLock<0 || bLock==0 );
60978 if( bLock ){
60979 assert( pWal->db );
60980 if( walEnableBlocking(pWal) ){
60981 rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
60982 if( rc==SQLITE_OK ){
60983 pWal->writeLock = 1;
60984 }
60985 walDisableBlocking(pWal);
60986 }
60987 }else if( pWal->writeLock ){
60988 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
60989 pWal->writeLock = 0;
60990 }
60991 return rc;
60992 }
60993
60994 /*
60995 ** Set the database handle used to determine if blocking locks are required.
60996 */
60997 SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){
60998 pWal->db = db;
60999 }
61000
61001 /*
61002 ** Take an exclusive WRITE lock. Blocking if so configured.
61003 */
61004 static int walLockWriter(Wal *pWal){
61005 int rc;
61006 walEnableBlocking(pWal);
61007 rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
61008 walDisableBlocking(pWal);
61009 return rc;
61010 }
61011 #else
61012 # define walEnableBlocking(x) 0
61013 # define walDisableBlocking(x)
61014 # define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
61015 # define sqlite3WalDb(pWal, db)
61016 #endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
61017
61018
61019 /*
61020 ** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
61021 ** n. If the attempt fails and parameter xBusy is not NULL, then it is a
61022 ** busy-handler function. Invoke it and retry the lock until either the
@@ -60915,10 +61031,16 @@
61031 ){
61032 int rc;
61033 do {
61034 rc = walLockExclusive(pWal, lockIdx, n);
61035 }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
61036 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
61037 if( rc==SQLITE_BUSY_TIMEOUT ){
61038 walDisableBlocking(pWal);
61039 rc = SQLITE_BUSY;
61040 }
61041 #endif
61042 return rc;
61043 }
61044
61045 /*
61046 ** The cache of the wal-index header must be valid to call this function.
@@ -61394,32 +61516,36 @@
61516 badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
61517
61518 /* If the first attempt failed, it might have been due to a race
61519 ** with a writer. So get a WRITE lock and try again.
61520 */
 
61521 if( badHdr ){
61522 if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
61523 if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
61524 walUnlockShared(pWal, WAL_WRITE_LOCK);
61525 rc = SQLITE_READONLY_RECOVERY;
61526 }
61527 }else{
61528 int bWriteLock = pWal->writeLock;
61529 if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
61530 pWal->writeLock = 1;
61531 if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
61532 badHdr = walIndexTryHdr(pWal, pChanged);
61533 if( badHdr ){
61534 /* If the wal-index header is still malformed even while holding
61535 ** a WRITE lock, it can only mean that the header is corrupted and
61536 ** needs to be reconstructed. So run recovery to do exactly that.
61537 */
61538 rc = walIndexRecover(pWal);
61539 *pChanged = 1;
61540 }
61541 }
61542 if( bWriteLock==0 ){
61543 pWal->writeLock = 0;
61544 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
61545 }
61546 }
61547 }
61548 }
61549
61550 /* If the header is read successfully, check the version number to make
61551 ** sure the wal-index was not constructed with some future format that
@@ -61967,26 +62093,38 @@
62093 ** needs to be flushed.
62094 */
62095 SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
62096 int rc; /* Return code */
62097 int cnt = 0; /* Number of TryBeginRead attempts */
62098
62099 assert( pWal->ckptLock==0 );
 
62100
62101 #ifdef SQLITE_ENABLE_SNAPSHOT
62102 int bChanged = 0;
62103 WalIndexHdr *pSnapshot = pWal->pSnapshot;
62104 if( pSnapshot ){
62105 if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
62106 bChanged = 1;
62107 }
62108
62109 /* It is possible that there is a checkpointer thread running
62110 ** concurrent with this code. If this is the case, it may be that the
62111 ** checkpointer has already determined that it will checkpoint
62112 ** snapshot X, where X is later in the wal file than pSnapshot, but
62113 ** has not yet set the pInfo->nBackfillAttempted variable to indicate
62114 ** its intent. To avoid the race condition this leads to, ensure that
62115 ** there is no checkpointer process by taking a shared CKPT lock
62116 ** before checking pInfo->nBackfillAttempted. */
62117 (void)walEnableBlocking(pWal);
62118 rc = walLockShared(pWal, WAL_CKPT_LOCK);
62119 walDisableBlocking(pWal);
62120
62121 if( rc!=SQLITE_OK ){
62122 return rc;
62123 }
62124 pWal->ckptLock = 1;
62125 }
62126 #endif
62127
62128 do{
62129 rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
62130 }while( rc==WAL_RETRY );
@@ -61993,20 +62131,10 @@
62131 testcase( (rc&0xff)==SQLITE_BUSY );
62132 testcase( (rc&0xff)==SQLITE_IOERR );
62133 testcase( rc==SQLITE_PROTOCOL );
62134 testcase( rc==SQLITE_OK );
62135
 
 
 
 
 
 
 
 
 
 
62136 #ifdef SQLITE_ENABLE_SNAPSHOT
62137 if( rc==SQLITE_OK ){
62138 if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
62139 /* At this point the client has a lock on an aReadMark[] slot holding
62140 ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
@@ -62024,52 +62152,46 @@
62152 volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
62153
62154 assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
62155 assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
62156
62157 /* Check that the wal file has not been wrapped. Assuming that it has
62158 ** not, also check that no checkpointer has attempted to checkpoint any
62159 ** frames beyond pSnapshot->mxFrame. If either of these conditions are
62160 ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
62161 ** with *pSnapshot and set *pChanged as appropriate for opening the
62162 ** snapshot. */
62163 if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
62164 && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
62165 ){
62166 assert( pWal->readLock>0 );
62167 memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
62168 *pChanged = bChanged;
62169 }else{
62170 rc = SQLITE_ERROR_SNAPSHOT;
62171 }
62172
62173 /* A client using a non-current snapshot may not ignore any frames
62174 ** from the start of the wal file. This is because, for a system
62175 ** where (minFrame < iSnapshot < maxFrame), a checkpointer may
62176 ** have omitted to checkpoint a frame earlier than minFrame in
62177 ** the file because there exists a frame after iSnapshot that
62178 ** is the same database page. */
62179 pWal->minFrame = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
62180
62181 if( rc!=SQLITE_OK ){
62182 sqlite3WalEndReadTransaction(pWal);
62183 }
62184 }
62185 }
62186
62187 /* Release the shared CKPT lock obtained above. */
62188 if( pWal->ckptLock ){
62189 assert( pSnapshot );
62190 walUnlockShared(pWal, WAL_CKPT_LOCK);
62191 pWal->ckptLock = 0;
62192 }
62193 #endif
62194 return rc;
62195 }
62196
62197 /*
@@ -62235,10 +62357,20 @@
62357 **
62358 ** There can only be a single writer active at a time.
62359 */
62360 SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
62361 int rc;
62362
62363 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
62364 /* If the write-lock is already held, then it was obtained before the
62365 ** read-transaction was even opened, making this call a no-op.
62366 ** Return early. */
62367 if( pWal->writeLock ){
62368 assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
62369 return SQLITE_OK;
62370 }
62371 #endif
62372
62373 /* Cannot start a write transaction without first holding a read
62374 ** transaction. */
62375 assert( pWal->readLock>=0 );
62376 assert( pWal->writeLock==0 && pWal->iReCksum==0 );
@@ -62811,50 +62943,57 @@
62943 ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
62944 assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
62945
62946 if( pWal->readOnly ) return SQLITE_READONLY;
62947 WALTRACE(("WAL%p: checkpoint begins\n", pWal));
62948
62949 /* Enable blocking locks, if possible. If blocking locks are successfully
62950 ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
62951 sqlite3WalDb(pWal, db);
62952 (void)walEnableBlocking(pWal);
62953
62954 /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
62955 ** "checkpoint" lock on the database file.
62956 ** EVIDENCE-OF: R-10421-19736 If any other process is running a
62957 ** checkpoint operation at the same time, the lock cannot be obtained and
62958 ** SQLITE_BUSY is returned.
62959 ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
62960 ** it will not be invoked in this case.
62961 */
62962 rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
62963 testcase( rc==SQLITE_BUSY );
62964 testcase( rc!=SQLITE_OK && xBusy2!=0 );
62965 if( rc==SQLITE_OK ){
62966 pWal->ckptLock = 1;
62967
62968 /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
62969 ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
62970 ** file.
62971 **
62972 ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
62973 ** immediately, and a busy-handler is configured, it is invoked and the
62974 ** writer lock retried until either the busy-handler returns 0 or the
62975 ** lock is successfully obtained.
62976 */
62977 if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
62978 rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
62979 if( rc==SQLITE_OK ){
62980 pWal->writeLock = 1;
62981 }else if( rc==SQLITE_BUSY ){
62982 eMode2 = SQLITE_CHECKPOINT_PASSIVE;
62983 xBusy2 = 0;
62984 rc = SQLITE_OK;
62985 }
62986 }
62987 }
62988
 
 
 
 
 
 
62989
62990 /* Read the wal-index header. */
62991 if( rc==SQLITE_OK ){
62992 walDisableBlocking(pWal);
62993 rc = walIndexReadHdr(pWal, &isChanged);
62994 (void)walEnableBlocking(pWal);
62995 if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
62996 sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
62997 }
62998 }
62999
@@ -62881,16 +63020,24 @@
63020 ** next time the pager opens a snapshot on this database it knows that
63021 ** the cache needs to be reset.
63022 */
63023 memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
63024 }
63025
63026 walDisableBlocking(pWal);
63027 sqlite3WalDb(pWal, 0);
63028
63029 /* Release the locks. */
63030 sqlite3WalEndWriteTransaction(pWal);
63031 if( pWal->ckptLock ){
63032 walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
63033 pWal->ckptLock = 0;
63034 }
63035 WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
63036 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
63037 if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
63038 #endif
63039 return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
63040 }
63041
63042 /* Return the value to pass to a sqlite3_wal_hook callback, the
63043 ** number of frames in the WAL at the point of the last commit since
@@ -63003,11 +63150,14 @@
63150 return rc;
63151 }
63152
63153 /* Try to open on pSnapshot when the next read-transaction starts
63154 */
63155 SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
63156 Wal *pWal,
63157 sqlite3_snapshot *pSnapshot
63158 ){
63159 pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
63160 }
63161
63162 /*
63163 ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
@@ -63522,11 +63672,11 @@
63672 u8 incrVacuum; /* True if incr-vacuum is enabled */
63673 u8 bDoTruncate; /* True to truncate db on commit */
63674 #endif
63675 u8 inTransaction; /* Transaction state */
63676 u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
63677 u8 nReserveWanted; /* Desired number of extra bytes per page */
63678 u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
63679 u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
63680 u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
63681 u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
63682 u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
@@ -66416,12 +66566,11 @@
66566 */
66567 static int btreeInvokeBusyHandler(void *pArg){
66568 BtShared *pBt = (BtShared*)pArg;
66569 assert( pBt->db );
66570 assert( sqlite3_mutex_held(pBt->db->mutex) );
66571 return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
 
66572 }
66573
66574 /*
66575 ** Open a database file.
66576 **
@@ -66968,23 +67117,21 @@
67117 ** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
67118 ** and autovacuum mode can no longer be changed.
67119 */
67120 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
67121 int rc = SQLITE_OK;
67122 int x;
67123 BtShared *pBt = p->pBt;
67124 assert( nReserve>=0 && nReserve<=255 );
67125 sqlite3BtreeEnter(p);
67126 pBt->nReserveWanted = nReserve;
67127 x = pBt->pageSize - pBt->usableSize;
67128 if( nReserve<x ) nReserve = x;
67129 if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
67130 sqlite3BtreeLeave(p);
67131 return SQLITE_READONLY;
67132 }
 
 
 
67133 assert( nReserve>=0 && nReserve<=255 );
67134 if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
67135 ((pageSize-1)&pageSize)==0 ){
67136 assert( (pageSize & 7)==0 );
67137 assert( !pBt->pCursor );
@@ -67031,16 +67178,16 @@
67178 ** The value returned is the larger of the current reserve size and
67179 ** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
67180 ** The amount of reserve can only grow - never shrink.
67181 */
67182 SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
67183 int n1, n2;
67184 sqlite3BtreeEnter(p);
67185 n1 = (int)p->pBt->nReserveWanted;
67186 n2 = sqlite3BtreeGetReserveNoMutex(p);
67187 sqlite3BtreeLeave(p);
67188 return n1>n2 ? n1 : n2;
67189 }
67190
67191
67192 /*
67193 ** Set the maximum page count for a database if mxPage is positive.
@@ -67486,10 +67633,11 @@
67633 ** when A already has a read lock, we encourage A to give up and let B
67634 ** proceed.
67635 */
67636 SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
67637 BtShared *pBt = p->pBt;
67638 Pager *pPager = pBt->pPager;
67639 int rc = SQLITE_OK;
67640
67641 sqlite3BtreeEnter(p);
67642 btreeIntegrity(p);
67643
@@ -67501,11 +67649,11 @@
67649 goto trans_begun;
67650 }
67651 assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
67652
67653 if( (p->db->flags & SQLITE_ResetDatabase)
67654 && sqlite3PagerIsreadonly(pPager)==0
67655 ){
67656 pBt->btsFlags &= ~BTS_READ_ONLY;
67657 }
67658
67659 /* Write transactions are not possible on a read-only database */
@@ -67549,10 +67697,22 @@
67697 if( SQLITE_OK!=rc ) goto trans_begun;
67698
67699 pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
67700 if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
67701 do {
67702 sqlite3PagerWalDb(pPager, p->db);
67703
67704 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67705 /* If transitioning from no transaction directly to a write transaction,
67706 ** block for the WRITER lock first if possible. */
67707 if( pBt->pPage1==0 && wrflag ){
67708 assert( pBt->inTransaction==TRANS_NONE );
67709 rc = sqlite3PagerWalWriteLock(pPager, 1);
67710 if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
67711 }
67712 #endif
67713
67714 /* Call lockBtree() until either pBt->pPage1 is populated or
67715 ** lockBtree() returns something other than SQLITE_OK. lockBtree()
67716 ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
67717 ** reading page 1 it discovers that the page-size of the database
67718 ** file is not pBt->pageSize. In this case lockBtree() will update
@@ -67562,11 +67722,11 @@
67722
67723 if( rc==SQLITE_OK && wrflag ){
67724 if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
67725 rc = SQLITE_READONLY;
67726 }else{
67727 rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
67728 if( rc==SQLITE_OK ){
67729 rc = newDatabase(pBt);
67730 }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
67731 /* if there was no transaction opened when this function was
67732 ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
@@ -67575,15 +67735,19 @@
67735 }
67736 }
67737 }
67738
67739 if( rc!=SQLITE_OK ){
67740 (void)sqlite3PagerWalWriteLock(pPager, 0);
67741 unlockBtreeIfUnused(pBt);
67742 }
67743 }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
67744 btreeInvokeBusyHandler(pBt) );
67745 sqlite3PagerWalDb(pPager, 0);
67746 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
67747 if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
67748 #endif
67749
67750 if( rc==SQLITE_OK ){
67751 if( p->inTrans==TRANS_NONE ){
67752 pBt->nTransaction++;
67753 #ifndef SQLITE_OMIT_SHARED_CACHE
@@ -67631,11 +67795,11 @@
67795 if( wrflag ){
67796 /* This call makes sure that the pager has the correct number of
67797 ** open savepoints. If the second parameter is greater than 0 and
67798 ** the sub-journal is not already open, then it will be opened here.
67799 */
67800 rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
67801 }
67802 }
67803
67804 btreeIntegrity(p);
67805 sqlite3BtreeLeave(p);
@@ -71267,11 +71431,11 @@
71431
71432 /* Remove cells from the start and end of the page */
71433 assert( nCell>=0 );
71434 if( iOld<iNew ){
71435 int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
71436 if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
71437 memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
71438 nCell -= nShift;
71439 }
71440 if( iNewEnd < iOldEnd ){
71441 int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
@@ -74746,11 +74910,11 @@
74910 ** Attempt to set the page size of the destination to match the page size
74911 ** of the source.
74912 */
74913 static int setDestPgsz(sqlite3_backup *p){
74914 int rc;
74915 rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
74916 return rc;
74917 }
74918
74919 /*
74920 ** Check that there is no open read-transaction on the b-tree passed as the
@@ -90540,16 +90704,23 @@
90704 rc = sqlite3VdbeSorterWrite(pC, pIn2);
90705 if( rc) goto abort_due_to_error;
90706 break;
90707 }
90708
90709 /* Opcode: IdxDelete P1 P2 P3 * P5
90710 ** Synopsis: key=r[P2@P3]
90711 **
90712 ** The content of P3 registers starting at register P2 form
90713 ** an unpacked index key. This opcode removes that entry from the
90714 ** index opened by cursor P1.
90715 **
90716 ** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
90717 ** if no matching index entry is found. This happens when running
90718 ** an UPDATE or DELETE statement and the index entry to be updated
90719 ** or deleted is not found. For some uses of IdxDelete
90720 ** (example: the EXCEPT operator) it does not matter that no matching
90721 ** entry is found. For those cases, P5 is zero.
90722 */
90723 case OP_IdxDelete: {
90724 VdbeCursor *pC;
90725 BtCursor *pCrsr;
90726 int res;
@@ -90562,20 +90733,22 @@
90733 assert( pC!=0 );
90734 assert( pC->eCurType==CURTYPE_BTREE );
90735 sqlite3VdbeIncrWriteCounter(p, pC);
90736 pCrsr = pC->uc.pCursor;
90737 assert( pCrsr!=0 );
 
90738 r.pKeyInfo = pC->pKeyInfo;
90739 r.nField = (u16)pOp->p3;
90740 r.default_rc = 0;
90741 r.aMem = &aMem[pOp->p2];
90742 rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
90743 if( rc ) goto abort_due_to_error;
90744 if( res==0 ){
90745 rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
90746 if( rc ) goto abort_due_to_error;
90747 }else if( pOp->p5 ){
90748 rc = SQLITE_CORRUPT_INDEX;
90749 goto abort_due_to_error;
90750 }
90751 assert( pC->deferredMoveto==0 );
90752 pC->cacheStatus = CACHE_STALE;
90753 pC->seekResult = 0;
90754 break;
@@ -103684,11 +103857,11 @@
103857 assert( pExpr->affExpr==OE_Rollback
103858 || pExpr->affExpr==OE_Abort
103859 || pExpr->affExpr==OE_Fail
103860 || pExpr->affExpr==OE_Ignore
103861 );
103862 if( !pParse->pTriggerTab && !pParse->nested ){
103863 sqlite3ErrorMsg(pParse,
103864 "RAISE() may only be used within a trigger-program");
103865 return 0;
103866 }
103867 if( pExpr->affExpr==OE_Abort ){
@@ -103698,12 +103871,13 @@
103871 if( pExpr->affExpr==OE_Ignore ){
103872 sqlite3VdbeAddOp4(
103873 v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
103874 VdbeCoverage(v);
103875 }else{
103876 sqlite3HaltConstraint(pParse,
103877 pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
103878 pExpr->affExpr, pExpr->u.zToken, 0, 0);
103879 }
103880
103881 break;
103882 }
103883 #endif
@@ -105454,10 +105628,26 @@
105628 exit_rename_table:
105629 sqlite3SrcListDelete(db, pSrc);
105630 sqlite3DbFree(db, zName);
105631 db->mDbFlags = savedDbFlags;
105632 }
105633
105634 /*
105635 ** Write code that will raise an error if the table described by
105636 ** zDb and zTab is not empty.
105637 */
105638 static void sqlite3ErrorIfNotEmpty(
105639 Parse *pParse, /* Parsing context */
105640 const char *zDb, /* Schema holding the table */
105641 const char *zTab, /* Table to check for empty */
105642 const char *zErr /* Error message text */
105643 ){
105644 sqlite3NestedParse(pParse,
105645 "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
105646 zErr, zDb, zTab
105647 );
105648 }
105649
105650 /*
105651 ** This function is called after an "ALTER TABLE ... ADD" statement
105652 ** has been parsed. Argument pColDef contains the text of the new
105653 ** column definition.
@@ -105507,11 +105697,12 @@
105697 if( pCol->colFlags & COLFLAG_PRIMKEY ){
105698 sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
105699 return;
105700 }
105701 if( pNew->pIndex ){
105702 sqlite3ErrorMsg(pParse,
105703 "Cannot add a UNIQUE column");
105704 return;
105705 }
105706 if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
105707 /* If the default value for the new column was specified with a
105708 ** literal NULL, then set pDflt to 0. This simplifies checking
@@ -105520,19 +105711,18 @@
105711 assert( pDflt==0 || pDflt->op==TK_SPAN );
105712 if( pDflt && pDflt->pLeft->op==TK_NULL ){
105713 pDflt = 0;
105714 }
105715 if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
105716 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105717 "Cannot add a REFERENCES column with non-NULL default value");
 
105718 }
105719 if( pCol->notNull && !pDflt ){
105720 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105721 "Cannot add a NOT NULL column with default value NULL");
 
105722 }
105723
105724
105725 /* Ensure the default expression is something that sqlite3ValueFromExpr()
105726 ** can handle (i.e. not CURRENT_TIME etc.)
105727 */
105728 if( pDflt ){
@@ -105543,18 +105733,17 @@
105733 if( rc!=SQLITE_OK ){
105734 assert( db->mallocFailed == 1 );
105735 return;
105736 }
105737 if( !pVal ){
105738 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
105739 "Cannot add a column with non-constant default");
105740 }
105741 sqlite3ValueFree(pVal);
105742 }
105743 }else if( pCol->colFlags & COLFLAG_STORED ){
105744 sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
 
105745 }
105746
105747
105748 /* Modify the CREATE TABLE statement. */
105749 zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
@@ -114373,11 +114562,11 @@
114562 pParse->rc = rc;
114563 return 1;
114564 }
114565 db->aDb[1].pBt = pBt;
114566 assert( db->aDb[1].pSchema );
114567 if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
114568 sqlite3OomFault(db);
114569 return 1;
114570 }
114571 }
114572 return 0;
@@ -114484,11 +114673,11 @@
114673 char *p4, /* Error message */
114674 i8 p4type, /* P4_STATIC or P4_TRANSIENT */
114675 u8 p5Errmsg /* P5_ErrMsg type */
114676 ){
114677 Vdbe *v = sqlite3GetVdbe(pParse);
114678 assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
114679 if( onError==OE_Abort ){
114680 sqlite3MayAbort(pParse);
114681 }
114682 sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
114683 sqlite3VdbeChangeP5(v, p5Errmsg);
@@ -116197,10 +116386,11 @@
116386 VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
116387 r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
116388 &iPartIdxLabel, pPrior, r1);
116389 sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
116390 pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
116391 sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
116392 sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
116393 pPrior = pIdx;
116394 }
116395 }
116396
@@ -125555,11 +125745,11 @@
125745 }else{
125746 /* Malloc may fail when setting the page-size, as there is an internal
125747 ** buffer that the pager module resizes using sqlite3_realloc().
125748 */
125749 db->nextPagesize = sqlite3Atoi(zRight);
125750 if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
125751 sqlite3OomFault(db);
125752 }
125753 }
125754 break;
125755 }
@@ -135193,17 +135383,19 @@
135383 **
135384 ** In practice the KeyInfo structure will not be used. It is only
135385 ** passed to keep OP_OpenRead happy.
135386 */
135387 if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
135388 if( !p->pSrc->a[0].fg.notIndexed ){
135389 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
135390 if( pIdx->bUnordered==0
135391 && pIdx->szIdxRow<pTab->szTabRow
135392 && pIdx->pPartIdxWhere==0
135393 && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
135394 ){
135395 pBest = pIdx;
135396 }
135397 }
135398 }
135399 if( pBest ){
135400 iRoot = pBest->tnum;
135401 pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest);
@@ -138439,11 +138631,11 @@
138631 db->mDbFlags = saved_mDbFlags;
138632 db->flags = saved_flags;
138633 db->nChange = saved_nChange;
138634 db->nTotalChange = saved_nTotalChange;
138635 db->mTrace = saved_mTrace;
138636 sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
138637
138638 /* Currently there is an SQL level transaction open on the vacuum
138639 ** database. No locks are held on any other files (since the main file
138640 ** was committed at the btree level). So it safe to end the transaction
138641 ** by manually setting the autoCommit flag to true and detaching the
@@ -161431,12 +161623,11 @@
161623 ** Return non-zero to retry the lock. Return zero to stop trying
161624 ** and cause SQLite to return SQLITE_BUSY.
161625 */
161626 static int sqliteDefaultBusyCallback(
161627 void *ptr, /* Database connection */
161628 int count /* Number of times table has been busy */
 
161629 ){
161630 #if SQLITE_OS_WIN || HAVE_USLEEP
161631 /* This case is for systems that have support for sleeping for fractions of
161632 ** a second. Examples: All windows systems, unix systems with usleep() */
161633 static const u8 delays[] =
@@ -161446,35 +161637,10 @@
161637 # define NDELAY ArraySize(delays)
161638 sqlite3 *db = (sqlite3 *)ptr;
161639 int tmout = db->busyTimeout;
161640 int delay, prior;
161641
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161642 assert( count>=0 );
161643 if( count < NDELAY ){
161644 delay = delays[count];
161645 prior = totals[count];
161646 }else{
@@ -161490,11 +161656,10 @@
161656 #else
161657 /* This case for unix systems that lack usleep() support. Sleeping
161658 ** must be done in increments of whole seconds */
161659 sqlite3 *db = (sqlite3 *)ptr;
161660 int tmout = ((sqlite3 *)ptr)->busyTimeout;
 
161661 if( (count+1)*1000 > tmout ){
161662 return 0;
161663 }
161664 sqlite3OsSleep(db->pVfs, 1000000);
161665 return 1;
@@ -161508,23 +161673,14 @@
161673 ** lock on VFS file pFile.
161674 **
161675 ** If this routine returns non-zero, the lock is retried. If it
161676 ** returns 0, the operation aborts with an SQLITE_BUSY error.
161677 */
161678 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
161679 int rc;
161680 if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
161681 rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
 
 
 
 
 
 
 
 
 
161682 if( rc==0 ){
161683 p->nBusy = -1;
161684 }else{
161685 p->nBusy++;
161686 }
@@ -161545,11 +161701,10 @@
161701 #endif
161702 sqlite3_mutex_enter(db->mutex);
161703 db->busyHandler.xBusyHandler = xBusy;
161704 db->busyHandler.pBusyArg = pArg;
161705 db->busyHandler.nBusy = 0;
 
161706 db->busyTimeout = 0;
161707 sqlite3_mutex_leave(db->mutex);
161708 return SQLITE_OK;
161709 }
161710
@@ -161596,11 +161751,10 @@
161751 #endif
161752 if( ms>0 ){
161753 sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
161754 (void*)db);
161755 db->busyTimeout = ms;
 
161756 }else{
161757 sqlite3_busy_handler(db, 0, 0);
161758 }
161759 return SQLITE_OK;
161760 }
@@ -163071,10 +163225,13 @@
163225 | SQLITE_EnableQPSG
163226 #endif
163227 #if defined(SQLITE_DEFAULT_DEFENSIVE)
163228 | SQLITE_Defensive
163229 #endif
163230 #if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
163231 | SQLITE_LegacyAlter
163232 #endif
163233 ;
163234 sqlite3HashInit(&db->aCollSeq);
163235 #ifndef SQLITE_OMIT_VIRTUALTABLE
163236 sqlite3HashInit(&db->aModule);
163237 #endif
@@ -163668,11 +163825,11 @@
163825 *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
163826 rc = SQLITE_OK;
163827 }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
163828 int iNew = *(int*)pArg;
163829 *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
163830 if( iNew>=0 && iNew<=255 ){
163831 sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
163832 }
163833 rc = SQLITE_OK;
163834 }else{
163835 rc = sqlite3OsFileControl(fd, op, pArg);
@@ -167905,11 +168062,13 @@
168062 static void fts3ReadNextPos(
168063 char **pp, /* IN/OUT: Pointer into position-list buffer */
168064 sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
168065 ){
168066 if( (**pp)&0xFE ){
168067 int iVal;
168068 *pp += fts3GetVarint32((*pp), &iVal);
168069 *pi += iVal;
168070 *pi -= 2;
168071 }else{
168072 *pi = POSITION_LIST_END;
168073 }
168074 }
@@ -224505,11 +224664,11 @@
224664 int nArg, /* Number of args */
224665 sqlite3_value **apUnused /* Function arguments */
224666 ){
224667 assert( nArg==0 );
224668 UNUSED_PARAM2(nArg, apUnused);
224669 sqlite3_result_text(pCtx, "fts5: 2020-05-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f9654ff", -1, SQLITE_TRANSIENT);
224670 }
224671
224672 /*
224673 ** Return true if zName is the extension on one of the shadow tables used
224674 ** by this module.
@@ -229288,12 +229447,12 @@
229447 }
229448 #endif /* SQLITE_CORE */
229449 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
229450
229451 /************** End of stmt.c ************************************************/
229452 #if __LINE__!=229452
229453 #undef SQLITE_SOURCE_ID
229454 #define SQLITE_SOURCE_ID "2020-05-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f96alt2"
229455 #endif
229456 /* Return the source-id for this library */
229457 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
229458 /************************** End of sqlite3.c ******************************/
229459
+3 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123123
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124124
** [sqlite_version()] and [sqlite_source_id()].
125125
*/
126126
#define SQLITE_VERSION "3.32.0"
127127
#define SQLITE_VERSION_NUMBER 3032000
128
-#define SQLITE_SOURCE_ID "2020-05-04 19:52:00 8eee591d3cb9fadfd5cac5543bd66ef9cb371a72d3ad3241fb3bfd67fb216eda"
128
+#define SQLITE_SOURCE_ID "2020-05-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f9654ff"
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))
524526
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.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))
524
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -123,11 +123,11 @@
123 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
124 ** [sqlite_version()] and [sqlite_source_id()].
125 */
126 #define SQLITE_VERSION "3.32.0"
127 #define SQLITE_VERSION_NUMBER 3032000
128 #define SQLITE_SOURCE_ID "2020-05-08 19:02:21 3a16c0ce4d8851f79f670d94786032c8007619154ece44647dc9cc5b1f9654ff"
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))
526
+7 -13
--- 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 />
@@ -1577,30 +1578,23 @@
15771578
**
15781579
** If asInline is true, it is emitted directly as an opening tag, the
15791580
** content of the zName builtin file, and a closing tag.
15801581
**
15811582
** If it is false, a script tag loading it via
1582
-** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a prefix
1583
-** of the builtin content's md5 hash.
1583
+** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a
1584
+** build-time-dependent cache-buster value.
15841585
*/
15851586
void style_emit_script_builtin(int asInline, char const * zName){
15861587
if(asInline){
15871588
style_emit_script_tag(0,0);
15881589
CX("%s", builtin_text(zName));
15891590
style_emit_script_tag(1,0);
15901591
}else{
15911592
char * zFullName = mprintf("builtin/%s",zName);
1592
- int nLen = 0;
1593
- const char * zBuiltin = (const char *)builtin_file(zName, &nLen);
1594
- const char * zHash = 0;
1595
- if(zBuiltin!=0){
1596
- md5sum_init();
1597
- md5sum_step_text(zBuiltin,nLen);
1598
- zHash = md5sum_finish(0);
1599
- }
1600
- CX("<script src='%R/%T?cache=%.8s'></script>\n",zFullName,
1601
- zHash ? zHash : "MISSING");
1593
+ const char * zHash = fossil_exe_id();
1594
+ CX("<script src='%R/%T?cache=%.8s'></script>\n",
1595
+ zFullName, zHash);
16021596
fossil_free(zFullName);
16031597
}
16041598
}
16051599
16061600
/*
16071601
--- 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 />
@@ -1577,30 +1578,23 @@
1577 **
1578 ** If asInline is true, it is emitted directly as an opening tag, the
1579 ** content of the zName builtin file, and a closing tag.
1580 **
1581 ** If it is false, a script tag loading it via
1582 ** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a prefix
1583 ** of the builtin content's md5 hash.
1584 */
1585 void style_emit_script_builtin(int asInline, char const * zName){
1586 if(asInline){
1587 style_emit_script_tag(0,0);
1588 CX("%s", builtin_text(zName));
1589 style_emit_script_tag(1,0);
1590 }else{
1591 char * zFullName = mprintf("builtin/%s",zName);
1592 int nLen = 0;
1593 const char * zBuiltin = (const char *)builtin_file(zName, &nLen);
1594 const char * zHash = 0;
1595 if(zBuiltin!=0){
1596 md5sum_init();
1597 md5sum_step_text(zBuiltin,nLen);
1598 zHash = md5sum_finish(0);
1599 }
1600 CX("<script src='%R/%T?cache=%.8s'></script>\n",zFullName,
1601 zHash ? zHash : "MISSING");
1602 fossil_free(zFullName);
1603 }
1604 }
1605
1606 /*
1607
--- 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 />
@@ -1577,30 +1578,23 @@
1578 **
1579 ** If asInline is true, it is emitted directly as an opening tag, the
1580 ** content of the zName builtin file, and a closing tag.
1581 **
1582 ** If it is false, a script tag loading it via
1583 ** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a
1584 ** build-time-dependent cache-buster value.
1585 */
1586 void style_emit_script_builtin(int asInline, char const * zName){
1587 if(asInline){
1588 style_emit_script_tag(0,0);
1589 CX("%s", builtin_text(zName));
1590 style_emit_script_tag(1,0);
1591 }else{
1592 char * zFullName = mprintf("builtin/%s",zName);
1593 const char * zHash = fossil_exe_id();
1594 CX("<script src='%R/%T?cache=%.8s'></script>\n",
1595 zFullName, zHash);
 
 
 
 
 
 
 
1596 fossil_free(zFullName);
1597 }
1598 }
1599
1600 /*
1601
+7 -13
--- 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 />
@@ -1577,30 +1578,23 @@
15771578
**
15781579
** If asInline is true, it is emitted directly as an opening tag, the
15791580
** content of the zName builtin file, and a closing tag.
15801581
**
15811582
** If it is false, a script tag loading it via
1582
-** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a prefix
1583
-** of the builtin content's md5 hash.
1583
+** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a
1584
+** build-time-dependent cache-buster value.
15841585
*/
15851586
void style_emit_script_builtin(int asInline, char const * zName){
15861587
if(asInline){
15871588
style_emit_script_tag(0,0);
15881589
CX("%s", builtin_text(zName));
15891590
style_emit_script_tag(1,0);
15901591
}else{
15911592
char * zFullName = mprintf("builtin/%s",zName);
1592
- int nLen = 0;
1593
- const char * zBuiltin = (const char *)builtin_file(zName, &nLen);
1594
- const char * zHash = 0;
1595
- if(zBuiltin!=0){
1596
- md5sum_init();
1597
- md5sum_step_text(zBuiltin,nLen);
1598
- zHash = md5sum_finish(0);
1599
- }
1600
- CX("<script src='%R/%T?cache=%.8s'></script>\n",zFullName,
1601
- zHash ? zHash : "MISSING");
1593
+ const char * zHash = fossil_exe_id();
1594
+ CX("<script src='%R/%T?cache=%.8s'></script>\n",
1595
+ zFullName, zHash);
16021596
fossil_free(zFullName);
16031597
}
16041598
}
16051599
16061600
/*
16071601
--- 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 />
@@ -1577,30 +1578,23 @@
1577 **
1578 ** If asInline is true, it is emitted directly as an opening tag, the
1579 ** content of the zName builtin file, and a closing tag.
1580 **
1581 ** If it is false, a script tag loading it via
1582 ** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a prefix
1583 ** of the builtin content's md5 hash.
1584 */
1585 void style_emit_script_builtin(int asInline, char const * zName){
1586 if(asInline){
1587 style_emit_script_tag(0,0);
1588 CX("%s", builtin_text(zName));
1589 style_emit_script_tag(1,0);
1590 }else{
1591 char * zFullName = mprintf("builtin/%s",zName);
1592 int nLen = 0;
1593 const char * zBuiltin = (const char *)builtin_file(zName, &nLen);
1594 const char * zHash = 0;
1595 if(zBuiltin!=0){
1596 md5sum_init();
1597 md5sum_step_text(zBuiltin,nLen);
1598 zHash = md5sum_finish(0);
1599 }
1600 CX("<script src='%R/%T?cache=%.8s'></script>\n",zFullName,
1601 zHash ? zHash : "MISSING");
1602 fossil_free(zFullName);
1603 }
1604 }
1605
1606 /*
1607
--- 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 />
@@ -1577,30 +1578,23 @@
1578 **
1579 ** If asInline is true, it is emitted directly as an opening tag, the
1580 ** content of the zName builtin file, and a closing tag.
1581 **
1582 ** If it is false, a script tag loading it via
1583 ** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a
1584 ** build-time-dependent cache-buster value.
1585 */
1586 void style_emit_script_builtin(int asInline, char const * zName){
1587 if(asInline){
1588 style_emit_script_tag(0,0);
1589 CX("%s", builtin_text(zName));
1590 style_emit_script_tag(1,0);
1591 }else{
1592 char * zFullName = mprintf("builtin/%s",zName);
1593 const char * zHash = fossil_exe_id();
1594 CX("<script src='%R/%T?cache=%.8s'></script>\n",
1595 zFullName, zHash);
 
 
 
 
 
 
 
1596 fossil_free(zFullName);
1597 }
1598 }
1599
1600 /*
1601
+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
+2 -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);
17521753
--- 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);
1752
--- 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);
1753
--- src/unversioned.c
+++ src/unversioned.c
@@ -524,10 +524,11 @@
524524
int showDel = 0;
525525
char zSzName[100];
526526
527527
login_check_credentials();
528528
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
529
+ etag_check(ETAG_DATA,0);
529530
style_header("Unversioned Files");
530531
if( !db_table_exists("repository","unversioned") ){
531532
@ No unversioned files on this server
532533
style_footer();
533534
return;
@@ -636,10 +637,11 @@
636637
Blob json;
637638
638639
login_check_credentials();
639640
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
640641
cgi_set_content_type("text/json");
642
+ etag_check(ETAG_DATA,0);
641643
if( !db_table_exists("repository","unversioned") ){
642644
blob_init(&json, "[]", -1);
643645
cgi_set_content(&json);
644646
return;
645647
}
646648
647649
ADDED test/subdir with spaces/filename with spaces.txt
--- src/unversioned.c
+++ src/unversioned.c
@@ -524,10 +524,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 +637,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
@@ -524,10 +524,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 etag_check(ETAG_DATA,0);
530 style_header("Unversioned Files");
531 if( !db_table_exists("repository","unversioned") ){
532 @ No unversioned files on this server
533 style_footer();
534 return;
@@ -636,10 +637,11 @@
637 Blob json;
638
639 login_check_credentials();
640 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
641 cgi_set_content_type("text/json");
642 etag_check(ETAG_DATA,0);
643 if( !db_table_exists("repository","unversioned") ){
644 blob_init(&json, "[]", -1);
645 cgi_set_content(&json);
646 return;
647 }
648
649 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.
--- www/changes.wiki
+++ www/changes.wiki
@@ -55,10 +55,12 @@
5555
* Security: Fossil now puts the Content-Security-Policy in the
5656
HTTP reply header, in addition to also leaving it in the
5757
HTML &lt;head&gt; section, so that it is always available, even
5858
if a custom skin overrides the HTML &lt;head&gt; and omits
5959
the CSP in the process.
60
+ * Output of the [/help?cmd=diff|fossil diff -y] command automatically
61
+ adjusts according to the terminal width.
6062
* The Content-Security-Policy is now set using the
6163
[/help?cmd=default-csp|default-csp setting].
6264
* Merge conflicts caused via the [/help?cmd=merge|merge] and
6365
[/help?cmd=update|update] commands no longer leave temporary
6466
files behind unless the new <tt>--keep-merge-files</tt> flag
6567
--- www/changes.wiki
+++ www/changes.wiki
@@ -55,10 +55,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
@@ -55,10 +55,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 * Output of the [/help?cmd=diff|fossil diff -y] command automatically
61 adjusts according to the terminal width.
62 * The Content-Security-Policy is now set using the
63 [/help?cmd=default-csp|default-csp setting].
64 * Merge conflicts caused via the [/help?cmd=merge|merge] and
65 [/help?cmd=update|update] commands no longer leave temporary
66 files behind unless the new <tt>--keep-merge-files</tt> flag
67

Keyboard Shortcuts

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