Fossil SCM

Merging from trunk. I still have merge conflicts since my previous merge.

viriketo 2013-02-11 19:30 annotate_links merge
Commit bdeb633a6ca008ae67823e6e88ea2f5d08179fb1
107 files changed +2 -1 +2 -1 +1 +1 +1 +1 +1 +10 -15 +10 -15 +36 -19 +36 -19 +36 -19 +1 -1 +1 -1 +3 +3 +61 -62 +61 -62 +61 -62 +33 -2 +33 -2 +10 -47 +10 -47 +10 -47 +7 -3 +7 -3 +7 -3 +2 -3 +2 -3 +52 -34 +52 -34 +6 -2 +6 -2 +4 -10 +4 -10 +51 -6 +51 -6 +3 -2 +3 -2 +3 -2 +1 -3 +1 -3 +1 -1 +1 -1 +1 -1 +1 -1 +17 -28 +17 -28 +1 -1 +1 -1 +34 -15 +34 -15 +71 -8 +71 -8 +71 -8 +16 -1 +16 -1 +8 +8 +38 -24 +38 -24 +2 +2 +9 +9 +6 +6 +381 -172 +381 -172 +1 -1 +1 -1 +104 -6 +104 -6 +20 -35 +20 -35 +20 -35 +73 -16 +73 -16 +2 +2 +1 -1 +35 -11 +35 -11 +10 -1 +10 -1 +19 -3 +19 -3 +26 +26 +5 -5 +5 -5 +29 -5 +29 -5 +30 -7 +30 -7 +3 -3 +3 -3 +2 -2 +2 -2 +40 +40 +2 +2 +1 +1 +7 +7
~ auto.def ~ auto.def ~ compat/zlib/configure ~ compat/zlib/configure ~ compat/zlib/configure ~ src/allrepo.c ~ src/allrepo.c ~ src/blob.c ~ src/blob.c ~ src/checkin.c ~ src/checkin.c ~ src/checkin.c ~ src/configure.c ~ src/configure.c ~ src/cson_amalgamation.h ~ src/cson_amalgamation.h ~ src/db.c ~ src/db.c ~ src/db.c ~ src/descendants.c ~ src/descendants.c ~ src/diff.c ~ src/diff.c ~ src/diff.c ~ src/doc.c ~ src/doc.c ~ src/doc.c ~ src/encode.c ~ src/encode.c ~ src/file.c ~ src/file.c ~ src/http.c ~ src/http.c ~ src/http_ssl.c ~ src/http_ssl.c ~ src/http_transport.c ~ src/http_transport.c ~ src/info.c ~ src/info.c ~ src/info.c ~ src/json.c ~ src/json.c ~ src/json_detail.h ~ src/json_detail.h ~ src/login.c ~ src/login.c ~ src/main.c ~ src/main.c ~ src/main.mk ~ src/main.mk ~ src/makemake.tcl ~ src/makemake.tcl ~ src/merge.c ~ src/merge.c ~ src/merge.c ~ src/printf.c ~ src/printf.c ~ src/rebuild.c ~ src/rebuild.c ~ src/regexp.c ~ src/regexp.c ~ src/schema.c ~ src/schema.c ~ src/setup.c ~ src/setup.c ~ src/shell.c ~ src/shell.c ~ src/sqlite3.c ~ src/sqlite3.c ~ src/sqlite3.h ~ src/sqlite3.h ~ src/stat.c ~ src/stat.c ~ src/timeline.c ~ src/timeline.c ~ src/timeline.c ~ src/tkt.c ~ src/tkt.c ~ src/tktsetup.c ~ src/tktsetup.c ~ src/unicode.c ~ src/update.c ~ src/update.c ~ src/url.c ~ src/url.c ~ src/xfer.c ~ src/xfer.c ~ test/revert.test ~ test/revert.test ~ win/Makefile.mingw ~ win/Makefile.mingw ~ win/Makefile.mingw.mistachkin ~ win/Makefile.mingw.mistachkin ~ win/Makefile.msc ~ win/Makefile.msc ~ win/include/dirent.h ~ win/include/dirent.h ~ www/build.wiki ~ www/build.wiki ~ www/fiveminutes.wiki ~ www/fiveminutes.wiki ~ www/index.wiki ~ www/index.wiki ~ www/mkindex.tcl ~ www/mkindex.tcl ~ www/permutedindex.wiki ~ www/permutedindex.wiki
+2 -1
--- auto.def
+++ auto.def
@@ -193,11 +193,11 @@
193193
if {$found} {
194194
define FOSSIL_ENABLE_SSL
195195
define-append EXTRA_CFLAGS $cflags
196196
define-append EXTRA_LDFLAGS $ldflags
197197
define-append LIBS -lssl -lcrypto
198
- msg-result "HTTP support enabled"
198
+ msg-result "HTTPS support enabled"
199199
200200
# Silence OpenSSL deprecation warnings on Mac OS X 10.7.
201201
if {[string match *-darwin* [get-define host]]} {
202202
if {[cctest -cflags {-Wdeprecated-declarations}]} {
203203
define-append EXTRA_CFLAGS -Wdeprecated-declarations
@@ -233,8 +233,9 @@
233233
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
234234
if {![cc-check-functions getpassphrase]} {
235235
# Haiku needs this
236236
cc-check-function-in-lib getpass bsd
237237
}
238
+cc-check-function-in-lib dlopen dl
238239
239240
make-template Makefile.in
240241
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
241242
--- auto.def
+++ auto.def
@@ -193,11 +193,11 @@
193 if {$found} {
194 define FOSSIL_ENABLE_SSL
195 define-append EXTRA_CFLAGS $cflags
196 define-append EXTRA_LDFLAGS $ldflags
197 define-append LIBS -lssl -lcrypto
198 msg-result "HTTP support enabled"
199
200 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
201 if {[string match *-darwin* [get-define host]]} {
202 if {[cctest -cflags {-Wdeprecated-declarations}]} {
203 define-append EXTRA_CFLAGS -Wdeprecated-declarations
@@ -233,8 +233,9 @@
233 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
234 if {![cc-check-functions getpassphrase]} {
235 # Haiku needs this
236 cc-check-function-in-lib getpass bsd
237 }
 
238
239 make-template Makefile.in
240 make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
241
--- auto.def
+++ auto.def
@@ -193,11 +193,11 @@
193 if {$found} {
194 define FOSSIL_ENABLE_SSL
195 define-append EXTRA_CFLAGS $cflags
196 define-append EXTRA_LDFLAGS $ldflags
197 define-append LIBS -lssl -lcrypto
198 msg-result "HTTPS support enabled"
199
200 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
201 if {[string match *-darwin* [get-define host]]} {
202 if {[cctest -cflags {-Wdeprecated-declarations}]} {
203 define-append EXTRA_CFLAGS -Wdeprecated-declarations
@@ -233,8 +233,9 @@
233 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
234 if {![cc-check-functions getpassphrase]} {
235 # Haiku needs this
236 cc-check-function-in-lib getpass bsd
237 }
238 cc-check-function-in-lib dlopen dl
239
240 make-template Makefile.in
241 make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
242
+2 -1
--- auto.def
+++ auto.def
@@ -193,11 +193,11 @@
193193
if {$found} {
194194
define FOSSIL_ENABLE_SSL
195195
define-append EXTRA_CFLAGS $cflags
196196
define-append EXTRA_LDFLAGS $ldflags
197197
define-append LIBS -lssl -lcrypto
198
- msg-result "HTTP support enabled"
198
+ msg-result "HTTPS support enabled"
199199
200200
# Silence OpenSSL deprecation warnings on Mac OS X 10.7.
201201
if {[string match *-darwin* [get-define host]]} {
202202
if {[cctest -cflags {-Wdeprecated-declarations}]} {
203203
define-append EXTRA_CFLAGS -Wdeprecated-declarations
@@ -233,8 +233,9 @@
233233
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
234234
if {![cc-check-functions getpassphrase]} {
235235
# Haiku needs this
236236
cc-check-function-in-lib getpass bsd
237237
}
238
+cc-check-function-in-lib dlopen dl
238239
239240
make-template Makefile.in
240241
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
241242
--- auto.def
+++ auto.def
@@ -193,11 +193,11 @@
193 if {$found} {
194 define FOSSIL_ENABLE_SSL
195 define-append EXTRA_CFLAGS $cflags
196 define-append EXTRA_LDFLAGS $ldflags
197 define-append LIBS -lssl -lcrypto
198 msg-result "HTTP support enabled"
199
200 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
201 if {[string match *-darwin* [get-define host]]} {
202 if {[cctest -cflags {-Wdeprecated-declarations}]} {
203 define-append EXTRA_CFLAGS -Wdeprecated-declarations
@@ -233,8 +233,9 @@
233 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
234 if {![cc-check-functions getpassphrase]} {
235 # Haiku needs this
236 cc-check-function-in-lib getpass bsd
237 }
 
238
239 make-template Makefile.in
240 make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
241
--- auto.def
+++ auto.def
@@ -193,11 +193,11 @@
193 if {$found} {
194 define FOSSIL_ENABLE_SSL
195 define-append EXTRA_CFLAGS $cflags
196 define-append EXTRA_LDFLAGS $ldflags
197 define-append LIBS -lssl -lcrypto
198 msg-result "HTTPS support enabled"
199
200 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
201 if {[string match *-darwin* [get-define host]]} {
202 if {[cctest -cflags {-Wdeprecated-declarations}]} {
203 define-append EXTRA_CFLAGS -Wdeprecated-declarations
@@ -233,8 +233,9 @@
233 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
234 if {![cc-check-functions getpassphrase]} {
235 # Haiku needs this
236 cc-check-function-in-lib getpass bsd
237 }
238 cc-check-function-in-lib dlopen dl
239
240 make-template Makefile.in
241 make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
242
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814814
/^mandir *=/s#=.*#=$mandir#
815815
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
816816
" | sed -e "
817817
s/\@VERSION\@/$VER/g;
818818
" > zlib.pc
819
+#
819820
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814 /^mandir *=/s#=.*#=$mandir#
815 /^LDFLAGS *=/s#=.*#=$LDFLAGS#
816 " | sed -e "
817 s/\@VERSION\@/$VER/g;
818 " > zlib.pc
 
819
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814 /^mandir *=/s#=.*#=$mandir#
815 /^LDFLAGS *=/s#=.*#=$LDFLAGS#
816 " | sed -e "
817 s/\@VERSION\@/$VER/g;
818 " > zlib.pc
819 #
820
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814814
/^mandir *=/s#=.*#=$mandir#
815815
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
816816
" | sed -e "
817817
s/\@VERSION\@/$VER/g;
818818
" > zlib.pc
819
+#
819820
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814 /^mandir *=/s#=.*#=$mandir#
815 /^LDFLAGS *=/s#=.*#=$LDFLAGS#
816 " | sed -e "
817 s/\@VERSION\@/$VER/g;
818 " > zlib.pc
 
819
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814 /^mandir *=/s#=.*#=$mandir#
815 /^LDFLAGS *=/s#=.*#=$LDFLAGS#
816 " | sed -e "
817 s/\@VERSION\@/$VER/g;
818 " > zlib.pc
819 #
820
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814814
/^mandir *=/s#=.*#=$mandir#
815815
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
816816
" | sed -e "
817817
s/\@VERSION\@/$VER/g;
818818
" > zlib.pc
819
+#
819820
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814 /^mandir *=/s#=.*#=$mandir#
815 /^LDFLAGS *=/s#=.*#=$LDFLAGS#
816 " | sed -e "
817 s/\@VERSION\@/$VER/g;
818 " > zlib.pc
 
819
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -814,5 +814,6 @@
814 /^mandir *=/s#=.*#=$mandir#
815 /^LDFLAGS *=/s#=.*#=$LDFLAGS#
816 " | sed -e "
817 s/\@VERSION\@/$VER/g;
818 " > zlib.pc
819 #
820
--- src/allrepo.c
+++ src/allrepo.c
@@ -144,10 +144,11 @@
144144
collect_argument(&extra, "compress");
145145
collect_argument(&extra, "noverify");
146146
collect_argument_value(&extra, "pagesize");
147147
collect_argument(&extra, "vacuum");
148148
collect_argument(&extra, "deanalyze");
149
+ collect_argument(&extra, "analyze");
149150
collect_argument(&extra, "wal");
150151
collect_argument(&extra, "stat");
151152
}else if( strncmp(zCmd, "sync", n)==0 ){
152153
zCmd = "sync -autourl -R";
153154
collect_argument(&extra, "verbose");
154155
--- src/allrepo.c
+++ src/allrepo.c
@@ -144,10 +144,11 @@
144 collect_argument(&extra, "compress");
145 collect_argument(&extra, "noverify");
146 collect_argument_value(&extra, "pagesize");
147 collect_argument(&extra, "vacuum");
148 collect_argument(&extra, "deanalyze");
 
149 collect_argument(&extra, "wal");
150 collect_argument(&extra, "stat");
151 }else if( strncmp(zCmd, "sync", n)==0 ){
152 zCmd = "sync -autourl -R";
153 collect_argument(&extra, "verbose");
154
--- src/allrepo.c
+++ src/allrepo.c
@@ -144,10 +144,11 @@
144 collect_argument(&extra, "compress");
145 collect_argument(&extra, "noverify");
146 collect_argument_value(&extra, "pagesize");
147 collect_argument(&extra, "vacuum");
148 collect_argument(&extra, "deanalyze");
149 collect_argument(&extra, "analyze");
150 collect_argument(&extra, "wal");
151 collect_argument(&extra, "stat");
152 }else if( strncmp(zCmd, "sync", n)==0 ){
153 zCmd = "sync -autourl -R";
154 collect_argument(&extra, "verbose");
155
--- src/allrepo.c
+++ src/allrepo.c
@@ -144,10 +144,11 @@
144144
collect_argument(&extra, "compress");
145145
collect_argument(&extra, "noverify");
146146
collect_argument_value(&extra, "pagesize");
147147
collect_argument(&extra, "vacuum");
148148
collect_argument(&extra, "deanalyze");
149
+ collect_argument(&extra, "analyze");
149150
collect_argument(&extra, "wal");
150151
collect_argument(&extra, "stat");
151152
}else if( strncmp(zCmd, "sync", n)==0 ){
152153
zCmd = "sync -autourl -R";
153154
collect_argument(&extra, "verbose");
154155
--- src/allrepo.c
+++ src/allrepo.c
@@ -144,10 +144,11 @@
144 collect_argument(&extra, "compress");
145 collect_argument(&extra, "noverify");
146 collect_argument_value(&extra, "pagesize");
147 collect_argument(&extra, "vacuum");
148 collect_argument(&extra, "deanalyze");
 
149 collect_argument(&extra, "wal");
150 collect_argument(&extra, "stat");
151 }else if( strncmp(zCmd, "sync", n)==0 ){
152 zCmd = "sync -autourl -R";
153 collect_argument(&extra, "verbose");
154
--- src/allrepo.c
+++ src/allrepo.c
@@ -144,10 +144,11 @@
144 collect_argument(&extra, "compress");
145 collect_argument(&extra, "noverify");
146 collect_argument_value(&extra, "pagesize");
147 collect_argument(&extra, "vacuum");
148 collect_argument(&extra, "deanalyze");
149 collect_argument(&extra, "analyze");
150 collect_argument(&extra, "wal");
151 collect_argument(&extra, "stat");
152 }else if( strncmp(zCmd, "sync", n)==0 ){
153 zCmd = "sync -autourl -R";
154 collect_argument(&extra, "verbose");
155
+10 -15
--- src/blob.c
+++ src/blob.c
@@ -1104,26 +1104,21 @@
11041104
blob_zero(&temp);
11051105
blob_append(&temp, zUtf8, -1);
11061106
blob_swap(pBlob, &temp);
11071107
blob_reset(&temp);
11081108
#ifdef _WIN32
1109
- }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){
1110
- /* Make sure the blob contains two terminating 0-bytes */
1111
- blob_append(pBlob, "", 1);
1112
- zUtf8 = blob_str(pBlob) + bomSize;
1113
- zUtf8 = fossil_unicode_to_utf8(zUtf8);
1114
- blob_zero(pBlob);
1115
- blob_append(pBlob, zUtf8, -1);
1116
- fossil_unicode_free(zUtf8);
1117
- }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){
1118
- unsigned int i = blob_size(pBlob);
1109
+ }else if( starts_with_utf16_bom(pBlob, &bomSize) ){
11191110
zUtf8 = blob_buffer(pBlob);
1120
- while( i > 0 ){
1121
- /* swap bytes of unicode representation */
1122
- char zTemp = zUtf8[--i];
1123
- zUtf8[i] = zUtf8[i-1];
1124
- zUtf8[--i] = zTemp;
1111
+ if (*((unsigned short *)zUtf8) == 0xfffe) {
1112
+ /* Found BOM, but with reversed bytes */
1113
+ unsigned int i = blob_size(pBlob);
1114
+ while( i > 0 ){
1115
+ /* swap bytes of unicode representation */
1116
+ char zTemp = zUtf8[--i];
1117
+ zUtf8[i] = zUtf8[i-1];
1118
+ zUtf8[--i] = zTemp;
1119
+ }
11251120
}
11261121
/* Make sure the blob contains two terminating 0-bytes */
11271122
blob_append(pBlob, "", 1);
11281123
zUtf8 = blob_str(pBlob) + bomSize;
11291124
zUtf8 = fossil_unicode_to_utf8(zUtf8);
11301125
--- src/blob.c
+++ src/blob.c
@@ -1104,26 +1104,21 @@
1104 blob_zero(&temp);
1105 blob_append(&temp, zUtf8, -1);
1106 blob_swap(pBlob, &temp);
1107 blob_reset(&temp);
1108 #ifdef _WIN32
1109 }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){
1110 /* Make sure the blob contains two terminating 0-bytes */
1111 blob_append(pBlob, "", 1);
1112 zUtf8 = blob_str(pBlob) + bomSize;
1113 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1114 blob_zero(pBlob);
1115 blob_append(pBlob, zUtf8, -1);
1116 fossil_unicode_free(zUtf8);
1117 }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){
1118 unsigned int i = blob_size(pBlob);
1119 zUtf8 = blob_buffer(pBlob);
1120 while( i > 0 ){
1121 /* swap bytes of unicode representation */
1122 char zTemp = zUtf8[--i];
1123 zUtf8[i] = zUtf8[i-1];
1124 zUtf8[--i] = zTemp;
 
 
 
 
1125 }
1126 /* Make sure the blob contains two terminating 0-bytes */
1127 blob_append(pBlob, "", 1);
1128 zUtf8 = blob_str(pBlob) + bomSize;
1129 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1130
--- src/blob.c
+++ src/blob.c
@@ -1104,26 +1104,21 @@
1104 blob_zero(&temp);
1105 blob_append(&temp, zUtf8, -1);
1106 blob_swap(pBlob, &temp);
1107 blob_reset(&temp);
1108 #ifdef _WIN32
1109 }else if( starts_with_utf16_bom(pBlob, &bomSize) ){
 
 
 
 
 
 
 
 
 
1110 zUtf8 = blob_buffer(pBlob);
1111 if (*((unsigned short *)zUtf8) == 0xfffe) {
1112 /* Found BOM, but with reversed bytes */
1113 unsigned int i = blob_size(pBlob);
1114 while( i > 0 ){
1115 /* swap bytes of unicode representation */
1116 char zTemp = zUtf8[--i];
1117 zUtf8[i] = zUtf8[i-1];
1118 zUtf8[--i] = zTemp;
1119 }
1120 }
1121 /* Make sure the blob contains two terminating 0-bytes */
1122 blob_append(pBlob, "", 1);
1123 zUtf8 = blob_str(pBlob) + bomSize;
1124 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1125
+10 -15
--- src/blob.c
+++ src/blob.c
@@ -1104,26 +1104,21 @@
11041104
blob_zero(&temp);
11051105
blob_append(&temp, zUtf8, -1);
11061106
blob_swap(pBlob, &temp);
11071107
blob_reset(&temp);
11081108
#ifdef _WIN32
1109
- }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){
1110
- /* Make sure the blob contains two terminating 0-bytes */
1111
- blob_append(pBlob, "", 1);
1112
- zUtf8 = blob_str(pBlob) + bomSize;
1113
- zUtf8 = fossil_unicode_to_utf8(zUtf8);
1114
- blob_zero(pBlob);
1115
- blob_append(pBlob, zUtf8, -1);
1116
- fossil_unicode_free(zUtf8);
1117
- }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){
1118
- unsigned int i = blob_size(pBlob);
1109
+ }else if( starts_with_utf16_bom(pBlob, &bomSize) ){
11191110
zUtf8 = blob_buffer(pBlob);
1120
- while( i > 0 ){
1121
- /* swap bytes of unicode representation */
1122
- char zTemp = zUtf8[--i];
1123
- zUtf8[i] = zUtf8[i-1];
1124
- zUtf8[--i] = zTemp;
1111
+ if (*((unsigned short *)zUtf8) == 0xfffe) {
1112
+ /* Found BOM, but with reversed bytes */
1113
+ unsigned int i = blob_size(pBlob);
1114
+ while( i > 0 ){
1115
+ /* swap bytes of unicode representation */
1116
+ char zTemp = zUtf8[--i];
1117
+ zUtf8[i] = zUtf8[i-1];
1118
+ zUtf8[--i] = zTemp;
1119
+ }
11251120
}
11261121
/* Make sure the blob contains two terminating 0-bytes */
11271122
blob_append(pBlob, "", 1);
11281123
zUtf8 = blob_str(pBlob) + bomSize;
11291124
zUtf8 = fossil_unicode_to_utf8(zUtf8);
11301125
--- src/blob.c
+++ src/blob.c
@@ -1104,26 +1104,21 @@
1104 blob_zero(&temp);
1105 blob_append(&temp, zUtf8, -1);
1106 blob_swap(pBlob, &temp);
1107 blob_reset(&temp);
1108 #ifdef _WIN32
1109 }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){
1110 /* Make sure the blob contains two terminating 0-bytes */
1111 blob_append(pBlob, "", 1);
1112 zUtf8 = blob_str(pBlob) + bomSize;
1113 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1114 blob_zero(pBlob);
1115 blob_append(pBlob, zUtf8, -1);
1116 fossil_unicode_free(zUtf8);
1117 }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){
1118 unsigned int i = blob_size(pBlob);
1119 zUtf8 = blob_buffer(pBlob);
1120 while( i > 0 ){
1121 /* swap bytes of unicode representation */
1122 char zTemp = zUtf8[--i];
1123 zUtf8[i] = zUtf8[i-1];
1124 zUtf8[--i] = zTemp;
 
 
 
 
1125 }
1126 /* Make sure the blob contains two terminating 0-bytes */
1127 blob_append(pBlob, "", 1);
1128 zUtf8 = blob_str(pBlob) + bomSize;
1129 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1130
--- src/blob.c
+++ src/blob.c
@@ -1104,26 +1104,21 @@
1104 blob_zero(&temp);
1105 blob_append(&temp, zUtf8, -1);
1106 blob_swap(pBlob, &temp);
1107 blob_reset(&temp);
1108 #ifdef _WIN32
1109 }else if( starts_with_utf16_bom(pBlob, &bomSize) ){
 
 
 
 
 
 
 
 
 
1110 zUtf8 = blob_buffer(pBlob);
1111 if (*((unsigned short *)zUtf8) == 0xfffe) {
1112 /* Found BOM, but with reversed bytes */
1113 unsigned int i = blob_size(pBlob);
1114 while( i > 0 ){
1115 /* swap bytes of unicode representation */
1116 char zTemp = zUtf8[--i];
1117 zUtf8[i] = zUtf8[i-1];
1118 zUtf8[--i] = zTemp;
1119 }
1120 }
1121 /* Make sure the blob contains two terminating 0-bytes */
1122 blob_append(pBlob, "", 1);
1123 zUtf8 = blob_str(pBlob) + bomSize;
1124 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1125
+36 -19
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619619
** of the array.
620620
**
621621
** If there were no arguments passed to [commit], aCommitFile is not
622622
** allocated and remains NULL. Other parts of the code interpret this
623623
** to mean "all files".
624
+**
625
+** Returns 1 if there was a warning, 0 otherwise.
624626
*/
625
-void select_commit_files(void){
627
+int select_commit_files(void){
628
+ int result = 0;
626629
if( g.argc>2 ){
627
- int ii;
630
+ int ii, jj=0;
628631
Blob b;
629632
blob_zero(&b);
630633
g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
631634
632635
for(ii=2; ii<g.argc; ii++){
633636
int iId;
634637
file_tree_name(g.argv[ii], &b, 1);
635638
iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
636639
if( iId<0 ){
637
- fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
640
+ fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
641
+ result = 1;
642
+ } else {
643
+ g.aCommitFile[jj++] = iId;
638644
}
639
- g.aCommitFile[ii-2] = iId;
640645
blob_reset(&b);
641646
}
642
- g.aCommitFile[ii-2] = 0;
647
+ g.aCommitFile[jj] = 0;
643648
}
649
+ return result;
644650
}
645651
646652
/*
647653
** Make sure the current check-in with timestamp zDate is younger than its
648654
** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
898904
*/
899905
static int commit_warning(
900906
Blob *p, /* The content of the file being committed. */
901907
int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
902908
int binOk, /* Non-zero if binary warnings should be disabled. */
903
- int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
909
+ int encodingOk, /* Non-zero if encoding warnings should be disabled. */
904910
const char *zFilename /* The full name of the file being committed. */
905911
){
906912
int eType; /* return value of looks_like_utf8/utf16() */
907913
int fUnicode; /* return value of starts_with_utf16_bom() */
908914
char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
912918
if( allOk ) return 0;
913919
fUnicode = starts_with_utf16_bom(p, 0);
914920
eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
915921
if( eType==0 || eType==-1 || fUnicode ){
916922
const char *zWarning;
923
+ const char *zDisable;
917924
const char *zConvert = "c=convert/";
918925
Blob ans;
919926
char cReply;
920927
921928
if( eType==-1 && fUnicode ){
922
- if ( crnlOk && unicodeOk ){
923
- return 0; /* We don't want Unicode/CR/NL warnings for this file. */
929
+ if ( crnlOk && encodingOk ){
930
+ return 0; /* We don't want CR/NL and Unicode warnings for this file. */
924931
}
925
- zWarning = "Unicode and CR/NL line endings";
932
+ zWarning = "CR/NL line endings and Unicode";
933
+ zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
926934
}else if( eType==-1 ){
927935
if( crnlOk ){
928936
return 0; /* We don't want CR/NL warnings for this file. */
929937
}
930938
zWarning = "CR/NL line endings";
939
+ zDisable = "\"crnl-glob\" setting";
931940
}else if( eType==0 ){
932941
if( binOk ){
933942
return 0; /* We don't want binary warnings for this file. */
934943
}
935944
zWarning = "binary data";
945
+ zDisable = "\"binary-glob\" setting";
936946
zConvert = ""; /* We cannot convert binary files. */
937947
}else{
938
- if ( unicodeOk ){
939
- return 0; /* We don't want unicode warnings for this file. */
948
+ if ( encodingOk ){
949
+ return 0; /* We don't want encoding warnings for this file. */
940950
}
941951
zWarning = "Unicode";
952
+ zDisable = "\"encoding-glob\" setting";
942953
#ifndef _WIN32
943954
zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
944955
#endif
945956
}
946957
file_relative_name(zFilename, &fname, 0);
947958
blob_zero(&ans);
948959
zMsg = mprintf(
949
- "%s contains %s. commit anyhow (a=all/%sy/N)? ",
950
- blob_str(&fname), zWarning, zConvert);
960
+ "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961
+ "Commit anyhow (a=all/%sy/N)? ",
962
+ blob_str(&fname), zWarning, zDisable, zConvert);
951963
prompt_user(zMsg, &ans);
952964
fossil_free(zMsg);
953965
cReply = blob_str(&ans)[0];
954966
if( cReply=='a' || cReply=='A' ){
955967
allOk = 1;
@@ -1196,11 +1208,16 @@
11961208
** After the following function call has returned, the Global.aCommitFile[]
11971209
** array is allocated to contain the "id" field from the vfile table
11981210
** for each file to be committed. Or, if aCommitFile is NULL, all files
11991211
** should be committed.
12001212
*/
1201
- select_commit_files();
1213
+ if ( select_commit_files() ){
1214
+ blob_zero(&ans);
1215
+ prompt_user("continue (y/N)? ", &ans);
1216
+ cReply = blob_str(&ans)[0];
1217
+ if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218
+ }
12021219
/* id=0 means that it introduces a new parent */
12031220
isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
12041221
if( g.aCommitFile && isAMerge ){
12051222
fossil_fatal("cannot do a partial commit of a graph merge");
12061223
}
@@ -1318,25 +1335,25 @@
13181335
"SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
13191336
"WHERE chnged==1 AND NOT deleted AND is_selected(id)",
13201337
g.zLocalRoot,
13211338
glob_expr("pathname", db_get("crnl-glob","")),
13221339
glob_expr("pathname", db_get("binary-glob","")),
1323
- glob_expr("pathname", db_get("unicode-glob",""))
1340
+ glob_expr("pathname", db_get("encoding-glob",""))
13241341
);
13251342
while( db_step(&q)==SQLITE_ROW ){
13261343
int id, rid;
13271344
const char *zFullname;
13281345
Blob content;
1329
- int crnlOk, binOk, unicodeOk, chnged;
1346
+ int crnlOk, binOk, encodingOk, chnged;
13301347
13311348
id = db_column_int(&q, 0);
13321349
zFullname = db_column_text(&q, 1);
13331350
rid = db_column_int(&q, 2);
13341351
crnlOk = db_column_int(&q, 3);
13351352
chnged = db_column_int(&q, 4);
13361353
binOk = db_column_int(&q, 5);
1337
- unicodeOk = db_column_int(&q, 6);
1354
+ encodingOk = db_column_int(&q, 6);
13381355
13391356
blob_zero(&content);
13401357
if( file_wd_islink(zFullname) ){
13411358
/* Instead of file content, put link destination path */
13421359
blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
13441361
blob_read_from_file(&content, zFullname);
13451362
}
13461363
/* Do not emit any warnings when they are disabled. */
13471364
if( !noWarningFlag ){
13481365
abortCommit |= commit_warning(&content, crnlOk, binOk,
1349
- unicodeOk, zFullname);
1366
+ encodingOk, zFullname);
13501367
}
13511368
if( chnged==1 && contains_merge_marker(&content) ){
13521369
Blob fname; /* Relative pathname of the file */
13531370
13541371
nConflict++;
@@ -1531,11 +1548,11 @@
15311548
exit(1);
15321549
}
15331550
db_end_transaction(0);
15341551
15351552
if( !g.markPrivate ){
1536
- autosync(SYNC_PUSH);
1553
+ autosync(SYNC_PUSH|SYNC_PULL);
15371554
}
15381555
if( count_nonbranch_children(vid)>1 ){
15391556
fossil_print("**** warning: a fork has occurred *****\n");
15401557
}
15411558
}
15421559
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619 ** of the array.
620 **
621 ** If there were no arguments passed to [commit], aCommitFile is not
622 ** allocated and remains NULL. Other parts of the code interpret this
623 ** to mean "all files".
 
 
624 */
625 void select_commit_files(void){
 
626 if( g.argc>2 ){
627 int ii;
628 Blob b;
629 blob_zero(&b);
630 g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
631
632 for(ii=2; ii<g.argc; ii++){
633 int iId;
634 file_tree_name(g.argv[ii], &b, 1);
635 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
636 if( iId<0 ){
637 fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
 
 
 
638 }
639 g.aCommitFile[ii-2] = iId;
640 blob_reset(&b);
641 }
642 g.aCommitFile[ii-2] = 0;
643 }
 
644 }
645
646 /*
647 ** Make sure the current check-in with timestamp zDate is younger than its
648 ** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
898 */
899 static int commit_warning(
900 Blob *p, /* The content of the file being committed. */
901 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
902 int binOk, /* Non-zero if binary warnings should be disabled. */
903 int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
904 const char *zFilename /* The full name of the file being committed. */
905 ){
906 int eType; /* return value of looks_like_utf8/utf16() */
907 int fUnicode; /* return value of starts_with_utf16_bom() */
908 char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
912 if( allOk ) return 0;
913 fUnicode = starts_with_utf16_bom(p, 0);
914 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
915 if( eType==0 || eType==-1 || fUnicode ){
916 const char *zWarning;
 
917 const char *zConvert = "c=convert/";
918 Blob ans;
919 char cReply;
920
921 if( eType==-1 && fUnicode ){
922 if ( crnlOk && unicodeOk ){
923 return 0; /* We don't want Unicode/CR/NL warnings for this file. */
924 }
925 zWarning = "Unicode and CR/NL line endings";
 
926 }else if( eType==-1 ){
927 if( crnlOk ){
928 return 0; /* We don't want CR/NL warnings for this file. */
929 }
930 zWarning = "CR/NL line endings";
 
931 }else if( eType==0 ){
932 if( binOk ){
933 return 0; /* We don't want binary warnings for this file. */
934 }
935 zWarning = "binary data";
 
936 zConvert = ""; /* We cannot convert binary files. */
937 }else{
938 if ( unicodeOk ){
939 return 0; /* We don't want unicode warnings for this file. */
940 }
941 zWarning = "Unicode";
 
942 #ifndef _WIN32
943 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
944 #endif
945 }
946 file_relative_name(zFilename, &fname, 0);
947 blob_zero(&ans);
948 zMsg = mprintf(
949 "%s contains %s. commit anyhow (a=all/%sy/N)? ",
950 blob_str(&fname), zWarning, zConvert);
 
951 prompt_user(zMsg, &ans);
952 fossil_free(zMsg);
953 cReply = blob_str(&ans)[0];
954 if( cReply=='a' || cReply=='A' ){
955 allOk = 1;
@@ -1196,11 +1208,16 @@
1196 ** After the following function call has returned, the Global.aCommitFile[]
1197 ** array is allocated to contain the "id" field from the vfile table
1198 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1199 ** should be committed.
1200 */
1201 select_commit_files();
 
 
 
 
 
1202 /* id=0 means that it introduces a new parent */
1203 isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
1204 if( g.aCommitFile && isAMerge ){
1205 fossil_fatal("cannot do a partial commit of a graph merge");
1206 }
@@ -1318,25 +1335,25 @@
1318 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1319 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1320 g.zLocalRoot,
1321 glob_expr("pathname", db_get("crnl-glob","")),
1322 glob_expr("pathname", db_get("binary-glob","")),
1323 glob_expr("pathname", db_get("unicode-glob",""))
1324 );
1325 while( db_step(&q)==SQLITE_ROW ){
1326 int id, rid;
1327 const char *zFullname;
1328 Blob content;
1329 int crnlOk, binOk, unicodeOk, chnged;
1330
1331 id = db_column_int(&q, 0);
1332 zFullname = db_column_text(&q, 1);
1333 rid = db_column_int(&q, 2);
1334 crnlOk = db_column_int(&q, 3);
1335 chnged = db_column_int(&q, 4);
1336 binOk = db_column_int(&q, 5);
1337 unicodeOk = db_column_int(&q, 6);
1338
1339 blob_zero(&content);
1340 if( file_wd_islink(zFullname) ){
1341 /* Instead of file content, put link destination path */
1342 blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
1344 blob_read_from_file(&content, zFullname);
1345 }
1346 /* Do not emit any warnings when they are disabled. */
1347 if( !noWarningFlag ){
1348 abortCommit |= commit_warning(&content, crnlOk, binOk,
1349 unicodeOk, zFullname);
1350 }
1351 if( chnged==1 && contains_merge_marker(&content) ){
1352 Blob fname; /* Relative pathname of the file */
1353
1354 nConflict++;
@@ -1531,11 +1548,11 @@
1531 exit(1);
1532 }
1533 db_end_transaction(0);
1534
1535 if( !g.markPrivate ){
1536 autosync(SYNC_PUSH);
1537 }
1538 if( count_nonbranch_children(vid)>1 ){
1539 fossil_print("**** warning: a fork has occurred *****\n");
1540 }
1541 }
1542
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619 ** of the array.
620 **
621 ** If there were no arguments passed to [commit], aCommitFile is not
622 ** allocated and remains NULL. Other parts of the code interpret this
623 ** to mean "all files".
624 **
625 ** Returns 1 if there was a warning, 0 otherwise.
626 */
627 int select_commit_files(void){
628 int result = 0;
629 if( g.argc>2 ){
630 int ii, jj=0;
631 Blob b;
632 blob_zero(&b);
633 g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
634
635 for(ii=2; ii<g.argc; ii++){
636 int iId;
637 file_tree_name(g.argv[ii], &b, 1);
638 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
639 if( iId<0 ){
640 fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
641 result = 1;
642 } else {
643 g.aCommitFile[jj++] = iId;
644 }
 
645 blob_reset(&b);
646 }
647 g.aCommitFile[jj] = 0;
648 }
649 return result;
650 }
651
652 /*
653 ** Make sure the current check-in with timestamp zDate is younger than its
654 ** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
904 */
905 static int commit_warning(
906 Blob *p, /* The content of the file being committed. */
907 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
908 int binOk, /* Non-zero if binary warnings should be disabled. */
909 int encodingOk, /* Non-zero if encoding warnings should be disabled. */
910 const char *zFilename /* The full name of the file being committed. */
911 ){
912 int eType; /* return value of looks_like_utf8/utf16() */
913 int fUnicode; /* return value of starts_with_utf16_bom() */
914 char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
918 if( allOk ) return 0;
919 fUnicode = starts_with_utf16_bom(p, 0);
920 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
921 if( eType==0 || eType==-1 || fUnicode ){
922 const char *zWarning;
923 const char *zDisable;
924 const char *zConvert = "c=convert/";
925 Blob ans;
926 char cReply;
927
928 if( eType==-1 && fUnicode ){
929 if ( crnlOk && encodingOk ){
930 return 0; /* We don't want CR/NL and Unicode warnings for this file. */
931 }
932 zWarning = "CR/NL line endings and Unicode";
933 zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
934 }else if( eType==-1 ){
935 if( crnlOk ){
936 return 0; /* We don't want CR/NL warnings for this file. */
937 }
938 zWarning = "CR/NL line endings";
939 zDisable = "\"crnl-glob\" setting";
940 }else if( eType==0 ){
941 if( binOk ){
942 return 0; /* We don't want binary warnings for this file. */
943 }
944 zWarning = "binary data";
945 zDisable = "\"binary-glob\" setting";
946 zConvert = ""; /* We cannot convert binary files. */
947 }else{
948 if ( encodingOk ){
949 return 0; /* We don't want encoding warnings for this file. */
950 }
951 zWarning = "Unicode";
952 zDisable = "\"encoding-glob\" setting";
953 #ifndef _WIN32
954 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
955 #endif
956 }
957 file_relative_name(zFilename, &fname, 0);
958 blob_zero(&ans);
959 zMsg = mprintf(
960 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961 "Commit anyhow (a=all/%sy/N)? ",
962 blob_str(&fname), zWarning, zDisable, zConvert);
963 prompt_user(zMsg, &ans);
964 fossil_free(zMsg);
965 cReply = blob_str(&ans)[0];
966 if( cReply=='a' || cReply=='A' ){
967 allOk = 1;
@@ -1196,11 +1208,16 @@
1208 ** After the following function call has returned, the Global.aCommitFile[]
1209 ** array is allocated to contain the "id" field from the vfile table
1210 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1211 ** should be committed.
1212 */
1213 if ( select_commit_files() ){
1214 blob_zero(&ans);
1215 prompt_user("continue (y/N)? ", &ans);
1216 cReply = blob_str(&ans)[0];
1217 if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218 }
1219 /* id=0 means that it introduces a new parent */
1220 isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
1221 if( g.aCommitFile && isAMerge ){
1222 fossil_fatal("cannot do a partial commit of a graph merge");
1223 }
@@ -1318,25 +1335,25 @@
1335 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1336 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1337 g.zLocalRoot,
1338 glob_expr("pathname", db_get("crnl-glob","")),
1339 glob_expr("pathname", db_get("binary-glob","")),
1340 glob_expr("pathname", db_get("encoding-glob",""))
1341 );
1342 while( db_step(&q)==SQLITE_ROW ){
1343 int id, rid;
1344 const char *zFullname;
1345 Blob content;
1346 int crnlOk, binOk, encodingOk, chnged;
1347
1348 id = db_column_int(&q, 0);
1349 zFullname = db_column_text(&q, 1);
1350 rid = db_column_int(&q, 2);
1351 crnlOk = db_column_int(&q, 3);
1352 chnged = db_column_int(&q, 4);
1353 binOk = db_column_int(&q, 5);
1354 encodingOk = db_column_int(&q, 6);
1355
1356 blob_zero(&content);
1357 if( file_wd_islink(zFullname) ){
1358 /* Instead of file content, put link destination path */
1359 blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
1361 blob_read_from_file(&content, zFullname);
1362 }
1363 /* Do not emit any warnings when they are disabled. */
1364 if( !noWarningFlag ){
1365 abortCommit |= commit_warning(&content, crnlOk, binOk,
1366 encodingOk, zFullname);
1367 }
1368 if( chnged==1 && contains_merge_marker(&content) ){
1369 Blob fname; /* Relative pathname of the file */
1370
1371 nConflict++;
@@ -1531,11 +1548,11 @@
1548 exit(1);
1549 }
1550 db_end_transaction(0);
1551
1552 if( !g.markPrivate ){
1553 autosync(SYNC_PUSH|SYNC_PULL);
1554 }
1555 if( count_nonbranch_children(vid)>1 ){
1556 fossil_print("**** warning: a fork has occurred *****\n");
1557 }
1558 }
1559
+36 -19
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619619
** of the array.
620620
**
621621
** If there were no arguments passed to [commit], aCommitFile is not
622622
** allocated and remains NULL. Other parts of the code interpret this
623623
** to mean "all files".
624
+**
625
+** Returns 1 if there was a warning, 0 otherwise.
624626
*/
625
-void select_commit_files(void){
627
+int select_commit_files(void){
628
+ int result = 0;
626629
if( g.argc>2 ){
627
- int ii;
630
+ int ii, jj=0;
628631
Blob b;
629632
blob_zero(&b);
630633
g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
631634
632635
for(ii=2; ii<g.argc; ii++){
633636
int iId;
634637
file_tree_name(g.argv[ii], &b, 1);
635638
iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
636639
if( iId<0 ){
637
- fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
640
+ fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
641
+ result = 1;
642
+ } else {
643
+ g.aCommitFile[jj++] = iId;
638644
}
639
- g.aCommitFile[ii-2] = iId;
640645
blob_reset(&b);
641646
}
642
- g.aCommitFile[ii-2] = 0;
647
+ g.aCommitFile[jj] = 0;
643648
}
649
+ return result;
644650
}
645651
646652
/*
647653
** Make sure the current check-in with timestamp zDate is younger than its
648654
** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
898904
*/
899905
static int commit_warning(
900906
Blob *p, /* The content of the file being committed. */
901907
int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
902908
int binOk, /* Non-zero if binary warnings should be disabled. */
903
- int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
909
+ int encodingOk, /* Non-zero if encoding warnings should be disabled. */
904910
const char *zFilename /* The full name of the file being committed. */
905911
){
906912
int eType; /* return value of looks_like_utf8/utf16() */
907913
int fUnicode; /* return value of starts_with_utf16_bom() */
908914
char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
912918
if( allOk ) return 0;
913919
fUnicode = starts_with_utf16_bom(p, 0);
914920
eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
915921
if( eType==0 || eType==-1 || fUnicode ){
916922
const char *zWarning;
923
+ const char *zDisable;
917924
const char *zConvert = "c=convert/";
918925
Blob ans;
919926
char cReply;
920927
921928
if( eType==-1 && fUnicode ){
922
- if ( crnlOk && unicodeOk ){
923
- return 0; /* We don't want Unicode/CR/NL warnings for this file. */
929
+ if ( crnlOk && encodingOk ){
930
+ return 0; /* We don't want CR/NL and Unicode warnings for this file. */
924931
}
925
- zWarning = "Unicode and CR/NL line endings";
932
+ zWarning = "CR/NL line endings and Unicode";
933
+ zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
926934
}else if( eType==-1 ){
927935
if( crnlOk ){
928936
return 0; /* We don't want CR/NL warnings for this file. */
929937
}
930938
zWarning = "CR/NL line endings";
939
+ zDisable = "\"crnl-glob\" setting";
931940
}else if( eType==0 ){
932941
if( binOk ){
933942
return 0; /* We don't want binary warnings for this file. */
934943
}
935944
zWarning = "binary data";
945
+ zDisable = "\"binary-glob\" setting";
936946
zConvert = ""; /* We cannot convert binary files. */
937947
}else{
938
- if ( unicodeOk ){
939
- return 0; /* We don't want unicode warnings for this file. */
948
+ if ( encodingOk ){
949
+ return 0; /* We don't want encoding warnings for this file. */
940950
}
941951
zWarning = "Unicode";
952
+ zDisable = "\"encoding-glob\" setting";
942953
#ifndef _WIN32
943954
zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
944955
#endif
945956
}
946957
file_relative_name(zFilename, &fname, 0);
947958
blob_zero(&ans);
948959
zMsg = mprintf(
949
- "%s contains %s. commit anyhow (a=all/%sy/N)? ",
950
- blob_str(&fname), zWarning, zConvert);
960
+ "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961
+ "Commit anyhow (a=all/%sy/N)? ",
962
+ blob_str(&fname), zWarning, zDisable, zConvert);
951963
prompt_user(zMsg, &ans);
952964
fossil_free(zMsg);
953965
cReply = blob_str(&ans)[0];
954966
if( cReply=='a' || cReply=='A' ){
955967
allOk = 1;
@@ -1196,11 +1208,16 @@
11961208
** After the following function call has returned, the Global.aCommitFile[]
11971209
** array is allocated to contain the "id" field from the vfile table
11981210
** for each file to be committed. Or, if aCommitFile is NULL, all files
11991211
** should be committed.
12001212
*/
1201
- select_commit_files();
1213
+ if ( select_commit_files() ){
1214
+ blob_zero(&ans);
1215
+ prompt_user("continue (y/N)? ", &ans);
1216
+ cReply = blob_str(&ans)[0];
1217
+ if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218
+ }
12021219
/* id=0 means that it introduces a new parent */
12031220
isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
12041221
if( g.aCommitFile && isAMerge ){
12051222
fossil_fatal("cannot do a partial commit of a graph merge");
12061223
}
@@ -1318,25 +1335,25 @@
13181335
"SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
13191336
"WHERE chnged==1 AND NOT deleted AND is_selected(id)",
13201337
g.zLocalRoot,
13211338
glob_expr("pathname", db_get("crnl-glob","")),
13221339
glob_expr("pathname", db_get("binary-glob","")),
1323
- glob_expr("pathname", db_get("unicode-glob",""))
1340
+ glob_expr("pathname", db_get("encoding-glob",""))
13241341
);
13251342
while( db_step(&q)==SQLITE_ROW ){
13261343
int id, rid;
13271344
const char *zFullname;
13281345
Blob content;
1329
- int crnlOk, binOk, unicodeOk, chnged;
1346
+ int crnlOk, binOk, encodingOk, chnged;
13301347
13311348
id = db_column_int(&q, 0);
13321349
zFullname = db_column_text(&q, 1);
13331350
rid = db_column_int(&q, 2);
13341351
crnlOk = db_column_int(&q, 3);
13351352
chnged = db_column_int(&q, 4);
13361353
binOk = db_column_int(&q, 5);
1337
- unicodeOk = db_column_int(&q, 6);
1354
+ encodingOk = db_column_int(&q, 6);
13381355
13391356
blob_zero(&content);
13401357
if( file_wd_islink(zFullname) ){
13411358
/* Instead of file content, put link destination path */
13421359
blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
13441361
blob_read_from_file(&content, zFullname);
13451362
}
13461363
/* Do not emit any warnings when they are disabled. */
13471364
if( !noWarningFlag ){
13481365
abortCommit |= commit_warning(&content, crnlOk, binOk,
1349
- unicodeOk, zFullname);
1366
+ encodingOk, zFullname);
13501367
}
13511368
if( chnged==1 && contains_merge_marker(&content) ){
13521369
Blob fname; /* Relative pathname of the file */
13531370
13541371
nConflict++;
@@ -1531,11 +1548,11 @@
15311548
exit(1);
15321549
}
15331550
db_end_transaction(0);
15341551
15351552
if( !g.markPrivate ){
1536
- autosync(SYNC_PUSH);
1553
+ autosync(SYNC_PUSH|SYNC_PULL);
15371554
}
15381555
if( count_nonbranch_children(vid)>1 ){
15391556
fossil_print("**** warning: a fork has occurred *****\n");
15401557
}
15411558
}
15421559
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619 ** of the array.
620 **
621 ** If there were no arguments passed to [commit], aCommitFile is not
622 ** allocated and remains NULL. Other parts of the code interpret this
623 ** to mean "all files".
 
 
624 */
625 void select_commit_files(void){
 
626 if( g.argc>2 ){
627 int ii;
628 Blob b;
629 blob_zero(&b);
630 g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
631
632 for(ii=2; ii<g.argc; ii++){
633 int iId;
634 file_tree_name(g.argv[ii], &b, 1);
635 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
636 if( iId<0 ){
637 fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
 
 
 
638 }
639 g.aCommitFile[ii-2] = iId;
640 blob_reset(&b);
641 }
642 g.aCommitFile[ii-2] = 0;
643 }
 
644 }
645
646 /*
647 ** Make sure the current check-in with timestamp zDate is younger than its
648 ** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
898 */
899 static int commit_warning(
900 Blob *p, /* The content of the file being committed. */
901 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
902 int binOk, /* Non-zero if binary warnings should be disabled. */
903 int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
904 const char *zFilename /* The full name of the file being committed. */
905 ){
906 int eType; /* return value of looks_like_utf8/utf16() */
907 int fUnicode; /* return value of starts_with_utf16_bom() */
908 char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
912 if( allOk ) return 0;
913 fUnicode = starts_with_utf16_bom(p, 0);
914 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
915 if( eType==0 || eType==-1 || fUnicode ){
916 const char *zWarning;
 
917 const char *zConvert = "c=convert/";
918 Blob ans;
919 char cReply;
920
921 if( eType==-1 && fUnicode ){
922 if ( crnlOk && unicodeOk ){
923 return 0; /* We don't want Unicode/CR/NL warnings for this file. */
924 }
925 zWarning = "Unicode and CR/NL line endings";
 
926 }else if( eType==-1 ){
927 if( crnlOk ){
928 return 0; /* We don't want CR/NL warnings for this file. */
929 }
930 zWarning = "CR/NL line endings";
 
931 }else if( eType==0 ){
932 if( binOk ){
933 return 0; /* We don't want binary warnings for this file. */
934 }
935 zWarning = "binary data";
 
936 zConvert = ""; /* We cannot convert binary files. */
937 }else{
938 if ( unicodeOk ){
939 return 0; /* We don't want unicode warnings for this file. */
940 }
941 zWarning = "Unicode";
 
942 #ifndef _WIN32
943 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
944 #endif
945 }
946 file_relative_name(zFilename, &fname, 0);
947 blob_zero(&ans);
948 zMsg = mprintf(
949 "%s contains %s. commit anyhow (a=all/%sy/N)? ",
950 blob_str(&fname), zWarning, zConvert);
 
951 prompt_user(zMsg, &ans);
952 fossil_free(zMsg);
953 cReply = blob_str(&ans)[0];
954 if( cReply=='a' || cReply=='A' ){
955 allOk = 1;
@@ -1196,11 +1208,16 @@
1196 ** After the following function call has returned, the Global.aCommitFile[]
1197 ** array is allocated to contain the "id" field from the vfile table
1198 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1199 ** should be committed.
1200 */
1201 select_commit_files();
 
 
 
 
 
1202 /* id=0 means that it introduces a new parent */
1203 isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
1204 if( g.aCommitFile && isAMerge ){
1205 fossil_fatal("cannot do a partial commit of a graph merge");
1206 }
@@ -1318,25 +1335,25 @@
1318 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1319 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1320 g.zLocalRoot,
1321 glob_expr("pathname", db_get("crnl-glob","")),
1322 glob_expr("pathname", db_get("binary-glob","")),
1323 glob_expr("pathname", db_get("unicode-glob",""))
1324 );
1325 while( db_step(&q)==SQLITE_ROW ){
1326 int id, rid;
1327 const char *zFullname;
1328 Blob content;
1329 int crnlOk, binOk, unicodeOk, chnged;
1330
1331 id = db_column_int(&q, 0);
1332 zFullname = db_column_text(&q, 1);
1333 rid = db_column_int(&q, 2);
1334 crnlOk = db_column_int(&q, 3);
1335 chnged = db_column_int(&q, 4);
1336 binOk = db_column_int(&q, 5);
1337 unicodeOk = db_column_int(&q, 6);
1338
1339 blob_zero(&content);
1340 if( file_wd_islink(zFullname) ){
1341 /* Instead of file content, put link destination path */
1342 blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
1344 blob_read_from_file(&content, zFullname);
1345 }
1346 /* Do not emit any warnings when they are disabled. */
1347 if( !noWarningFlag ){
1348 abortCommit |= commit_warning(&content, crnlOk, binOk,
1349 unicodeOk, zFullname);
1350 }
1351 if( chnged==1 && contains_merge_marker(&content) ){
1352 Blob fname; /* Relative pathname of the file */
1353
1354 nConflict++;
@@ -1531,11 +1548,11 @@
1531 exit(1);
1532 }
1533 db_end_transaction(0);
1534
1535 if( !g.markPrivate ){
1536 autosync(SYNC_PUSH);
1537 }
1538 if( count_nonbranch_children(vid)>1 ){
1539 fossil_print("**** warning: a fork has occurred *****\n");
1540 }
1541 }
1542
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619 ** of the array.
620 **
621 ** If there were no arguments passed to [commit], aCommitFile is not
622 ** allocated and remains NULL. Other parts of the code interpret this
623 ** to mean "all files".
624 **
625 ** Returns 1 if there was a warning, 0 otherwise.
626 */
627 int select_commit_files(void){
628 int result = 0;
629 if( g.argc>2 ){
630 int ii, jj=0;
631 Blob b;
632 blob_zero(&b);
633 g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
634
635 for(ii=2; ii<g.argc; ii++){
636 int iId;
637 file_tree_name(g.argv[ii], &b, 1);
638 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
639 if( iId<0 ){
640 fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
641 result = 1;
642 } else {
643 g.aCommitFile[jj++] = iId;
644 }
 
645 blob_reset(&b);
646 }
647 g.aCommitFile[jj] = 0;
648 }
649 return result;
650 }
651
652 /*
653 ** Make sure the current check-in with timestamp zDate is younger than its
654 ** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
904 */
905 static int commit_warning(
906 Blob *p, /* The content of the file being committed. */
907 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
908 int binOk, /* Non-zero if binary warnings should be disabled. */
909 int encodingOk, /* Non-zero if encoding warnings should be disabled. */
910 const char *zFilename /* The full name of the file being committed. */
911 ){
912 int eType; /* return value of looks_like_utf8/utf16() */
913 int fUnicode; /* return value of starts_with_utf16_bom() */
914 char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
918 if( allOk ) return 0;
919 fUnicode = starts_with_utf16_bom(p, 0);
920 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
921 if( eType==0 || eType==-1 || fUnicode ){
922 const char *zWarning;
923 const char *zDisable;
924 const char *zConvert = "c=convert/";
925 Blob ans;
926 char cReply;
927
928 if( eType==-1 && fUnicode ){
929 if ( crnlOk && encodingOk ){
930 return 0; /* We don't want CR/NL and Unicode warnings for this file. */
931 }
932 zWarning = "CR/NL line endings and Unicode";
933 zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
934 }else if( eType==-1 ){
935 if( crnlOk ){
936 return 0; /* We don't want CR/NL warnings for this file. */
937 }
938 zWarning = "CR/NL line endings";
939 zDisable = "\"crnl-glob\" setting";
940 }else if( eType==0 ){
941 if( binOk ){
942 return 0; /* We don't want binary warnings for this file. */
943 }
944 zWarning = "binary data";
945 zDisable = "\"binary-glob\" setting";
946 zConvert = ""; /* We cannot convert binary files. */
947 }else{
948 if ( encodingOk ){
949 return 0; /* We don't want encoding warnings for this file. */
950 }
951 zWarning = "Unicode";
952 zDisable = "\"encoding-glob\" setting";
953 #ifndef _WIN32
954 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
955 #endif
956 }
957 file_relative_name(zFilename, &fname, 0);
958 blob_zero(&ans);
959 zMsg = mprintf(
960 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961 "Commit anyhow (a=all/%sy/N)? ",
962 blob_str(&fname), zWarning, zDisable, zConvert);
963 prompt_user(zMsg, &ans);
964 fossil_free(zMsg);
965 cReply = blob_str(&ans)[0];
966 if( cReply=='a' || cReply=='A' ){
967 allOk = 1;
@@ -1196,11 +1208,16 @@
1208 ** After the following function call has returned, the Global.aCommitFile[]
1209 ** array is allocated to contain the "id" field from the vfile table
1210 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1211 ** should be committed.
1212 */
1213 if ( select_commit_files() ){
1214 blob_zero(&ans);
1215 prompt_user("continue (y/N)? ", &ans);
1216 cReply = blob_str(&ans)[0];
1217 if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218 }
1219 /* id=0 means that it introduces a new parent */
1220 isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
1221 if( g.aCommitFile && isAMerge ){
1222 fossil_fatal("cannot do a partial commit of a graph merge");
1223 }
@@ -1318,25 +1335,25 @@
1335 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1336 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1337 g.zLocalRoot,
1338 glob_expr("pathname", db_get("crnl-glob","")),
1339 glob_expr("pathname", db_get("binary-glob","")),
1340 glob_expr("pathname", db_get("encoding-glob",""))
1341 );
1342 while( db_step(&q)==SQLITE_ROW ){
1343 int id, rid;
1344 const char *zFullname;
1345 Blob content;
1346 int crnlOk, binOk, encodingOk, chnged;
1347
1348 id = db_column_int(&q, 0);
1349 zFullname = db_column_text(&q, 1);
1350 rid = db_column_int(&q, 2);
1351 crnlOk = db_column_int(&q, 3);
1352 chnged = db_column_int(&q, 4);
1353 binOk = db_column_int(&q, 5);
1354 encodingOk = db_column_int(&q, 6);
1355
1356 blob_zero(&content);
1357 if( file_wd_islink(zFullname) ){
1358 /* Instead of file content, put link destination path */
1359 blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
1361 blob_read_from_file(&content, zFullname);
1362 }
1363 /* Do not emit any warnings when they are disabled. */
1364 if( !noWarningFlag ){
1365 abortCommit |= commit_warning(&content, crnlOk, binOk,
1366 encodingOk, zFullname);
1367 }
1368 if( chnged==1 && contains_merge_marker(&content) ){
1369 Blob fname; /* Relative pathname of the file */
1370
1371 nConflict++;
@@ -1531,11 +1548,11 @@
1548 exit(1);
1549 }
1550 db_end_transaction(0);
1551
1552 if( !g.markPrivate ){
1553 autosync(SYNC_PUSH|SYNC_PULL);
1554 }
1555 if( count_nonbranch_children(vid)>1 ){
1556 fossil_print("**** warning: a fork has occurred *****\n");
1557 }
1558 }
1559
+36 -19
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619619
** of the array.
620620
**
621621
** If there were no arguments passed to [commit], aCommitFile is not
622622
** allocated and remains NULL. Other parts of the code interpret this
623623
** to mean "all files".
624
+**
625
+** Returns 1 if there was a warning, 0 otherwise.
624626
*/
625
-void select_commit_files(void){
627
+int select_commit_files(void){
628
+ int result = 0;
626629
if( g.argc>2 ){
627
- int ii;
630
+ int ii, jj=0;
628631
Blob b;
629632
blob_zero(&b);
630633
g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
631634
632635
for(ii=2; ii<g.argc; ii++){
633636
int iId;
634637
file_tree_name(g.argv[ii], &b, 1);
635638
iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
636639
if( iId<0 ){
637
- fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
640
+ fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
641
+ result = 1;
642
+ } else {
643
+ g.aCommitFile[jj++] = iId;
638644
}
639
- g.aCommitFile[ii-2] = iId;
640645
blob_reset(&b);
641646
}
642
- g.aCommitFile[ii-2] = 0;
647
+ g.aCommitFile[jj] = 0;
643648
}
649
+ return result;
644650
}
645651
646652
/*
647653
** Make sure the current check-in with timestamp zDate is younger than its
648654
** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
898904
*/
899905
static int commit_warning(
900906
Blob *p, /* The content of the file being committed. */
901907
int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
902908
int binOk, /* Non-zero if binary warnings should be disabled. */
903
- int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
909
+ int encodingOk, /* Non-zero if encoding warnings should be disabled. */
904910
const char *zFilename /* The full name of the file being committed. */
905911
){
906912
int eType; /* return value of looks_like_utf8/utf16() */
907913
int fUnicode; /* return value of starts_with_utf16_bom() */
908914
char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
912918
if( allOk ) return 0;
913919
fUnicode = starts_with_utf16_bom(p, 0);
914920
eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
915921
if( eType==0 || eType==-1 || fUnicode ){
916922
const char *zWarning;
923
+ const char *zDisable;
917924
const char *zConvert = "c=convert/";
918925
Blob ans;
919926
char cReply;
920927
921928
if( eType==-1 && fUnicode ){
922
- if ( crnlOk && unicodeOk ){
923
- return 0; /* We don't want Unicode/CR/NL warnings for this file. */
929
+ if ( crnlOk && encodingOk ){
930
+ return 0; /* We don't want CR/NL and Unicode warnings for this file. */
924931
}
925
- zWarning = "Unicode and CR/NL line endings";
932
+ zWarning = "CR/NL line endings and Unicode";
933
+ zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
926934
}else if( eType==-1 ){
927935
if( crnlOk ){
928936
return 0; /* We don't want CR/NL warnings for this file. */
929937
}
930938
zWarning = "CR/NL line endings";
939
+ zDisable = "\"crnl-glob\" setting";
931940
}else if( eType==0 ){
932941
if( binOk ){
933942
return 0; /* We don't want binary warnings for this file. */
934943
}
935944
zWarning = "binary data";
945
+ zDisable = "\"binary-glob\" setting";
936946
zConvert = ""; /* We cannot convert binary files. */
937947
}else{
938
- if ( unicodeOk ){
939
- return 0; /* We don't want unicode warnings for this file. */
948
+ if ( encodingOk ){
949
+ return 0; /* We don't want encoding warnings for this file. */
940950
}
941951
zWarning = "Unicode";
952
+ zDisable = "\"encoding-glob\" setting";
942953
#ifndef _WIN32
943954
zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
944955
#endif
945956
}
946957
file_relative_name(zFilename, &fname, 0);
947958
blob_zero(&ans);
948959
zMsg = mprintf(
949
- "%s contains %s. commit anyhow (a=all/%sy/N)? ",
950
- blob_str(&fname), zWarning, zConvert);
960
+ "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961
+ "Commit anyhow (a=all/%sy/N)? ",
962
+ blob_str(&fname), zWarning, zDisable, zConvert);
951963
prompt_user(zMsg, &ans);
952964
fossil_free(zMsg);
953965
cReply = blob_str(&ans)[0];
954966
if( cReply=='a' || cReply=='A' ){
955967
allOk = 1;
@@ -1196,11 +1208,16 @@
11961208
** After the following function call has returned, the Global.aCommitFile[]
11971209
** array is allocated to contain the "id" field from the vfile table
11981210
** for each file to be committed. Or, if aCommitFile is NULL, all files
11991211
** should be committed.
12001212
*/
1201
- select_commit_files();
1213
+ if ( select_commit_files() ){
1214
+ blob_zero(&ans);
1215
+ prompt_user("continue (y/N)? ", &ans);
1216
+ cReply = blob_str(&ans)[0];
1217
+ if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218
+ }
12021219
/* id=0 means that it introduces a new parent */
12031220
isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
12041221
if( g.aCommitFile && isAMerge ){
12051222
fossil_fatal("cannot do a partial commit of a graph merge");
12061223
}
@@ -1318,25 +1335,25 @@
13181335
"SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
13191336
"WHERE chnged==1 AND NOT deleted AND is_selected(id)",
13201337
g.zLocalRoot,
13211338
glob_expr("pathname", db_get("crnl-glob","")),
13221339
glob_expr("pathname", db_get("binary-glob","")),
1323
- glob_expr("pathname", db_get("unicode-glob",""))
1340
+ glob_expr("pathname", db_get("encoding-glob",""))
13241341
);
13251342
while( db_step(&q)==SQLITE_ROW ){
13261343
int id, rid;
13271344
const char *zFullname;
13281345
Blob content;
1329
- int crnlOk, binOk, unicodeOk, chnged;
1346
+ int crnlOk, binOk, encodingOk, chnged;
13301347
13311348
id = db_column_int(&q, 0);
13321349
zFullname = db_column_text(&q, 1);
13331350
rid = db_column_int(&q, 2);
13341351
crnlOk = db_column_int(&q, 3);
13351352
chnged = db_column_int(&q, 4);
13361353
binOk = db_column_int(&q, 5);
1337
- unicodeOk = db_column_int(&q, 6);
1354
+ encodingOk = db_column_int(&q, 6);
13381355
13391356
blob_zero(&content);
13401357
if( file_wd_islink(zFullname) ){
13411358
/* Instead of file content, put link destination path */
13421359
blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
13441361
blob_read_from_file(&content, zFullname);
13451362
}
13461363
/* Do not emit any warnings when they are disabled. */
13471364
if( !noWarningFlag ){
13481365
abortCommit |= commit_warning(&content, crnlOk, binOk,
1349
- unicodeOk, zFullname);
1366
+ encodingOk, zFullname);
13501367
}
13511368
if( chnged==1 && contains_merge_marker(&content) ){
13521369
Blob fname; /* Relative pathname of the file */
13531370
13541371
nConflict++;
@@ -1531,11 +1548,11 @@
15311548
exit(1);
15321549
}
15331550
db_end_transaction(0);
15341551
15351552
if( !g.markPrivate ){
1536
- autosync(SYNC_PUSH);
1553
+ autosync(SYNC_PUSH|SYNC_PULL);
15371554
}
15381555
if( count_nonbranch_children(vid)>1 ){
15391556
fossil_print("**** warning: a fork has occurred *****\n");
15401557
}
15411558
}
15421559
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619 ** of the array.
620 **
621 ** If there were no arguments passed to [commit], aCommitFile is not
622 ** allocated and remains NULL. Other parts of the code interpret this
623 ** to mean "all files".
 
 
624 */
625 void select_commit_files(void){
 
626 if( g.argc>2 ){
627 int ii;
628 Blob b;
629 blob_zero(&b);
630 g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
631
632 for(ii=2; ii<g.argc; ii++){
633 int iId;
634 file_tree_name(g.argv[ii], &b, 1);
635 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
636 if( iId<0 ){
637 fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
 
 
 
638 }
639 g.aCommitFile[ii-2] = iId;
640 blob_reset(&b);
641 }
642 g.aCommitFile[ii-2] = 0;
643 }
 
644 }
645
646 /*
647 ** Make sure the current check-in with timestamp zDate is younger than its
648 ** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
898 */
899 static int commit_warning(
900 Blob *p, /* The content of the file being committed. */
901 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
902 int binOk, /* Non-zero if binary warnings should be disabled. */
903 int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
904 const char *zFilename /* The full name of the file being committed. */
905 ){
906 int eType; /* return value of looks_like_utf8/utf16() */
907 int fUnicode; /* return value of starts_with_utf16_bom() */
908 char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
912 if( allOk ) return 0;
913 fUnicode = starts_with_utf16_bom(p, 0);
914 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
915 if( eType==0 || eType==-1 || fUnicode ){
916 const char *zWarning;
 
917 const char *zConvert = "c=convert/";
918 Blob ans;
919 char cReply;
920
921 if( eType==-1 && fUnicode ){
922 if ( crnlOk && unicodeOk ){
923 return 0; /* We don't want Unicode/CR/NL warnings for this file. */
924 }
925 zWarning = "Unicode and CR/NL line endings";
 
926 }else if( eType==-1 ){
927 if( crnlOk ){
928 return 0; /* We don't want CR/NL warnings for this file. */
929 }
930 zWarning = "CR/NL line endings";
 
931 }else if( eType==0 ){
932 if( binOk ){
933 return 0; /* We don't want binary warnings for this file. */
934 }
935 zWarning = "binary data";
 
936 zConvert = ""; /* We cannot convert binary files. */
937 }else{
938 if ( unicodeOk ){
939 return 0; /* We don't want unicode warnings for this file. */
940 }
941 zWarning = "Unicode";
 
942 #ifndef _WIN32
943 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
944 #endif
945 }
946 file_relative_name(zFilename, &fname, 0);
947 blob_zero(&ans);
948 zMsg = mprintf(
949 "%s contains %s. commit anyhow (a=all/%sy/N)? ",
950 blob_str(&fname), zWarning, zConvert);
 
951 prompt_user(zMsg, &ans);
952 fossil_free(zMsg);
953 cReply = blob_str(&ans)[0];
954 if( cReply=='a' || cReply=='A' ){
955 allOk = 1;
@@ -1196,11 +1208,16 @@
1196 ** After the following function call has returned, the Global.aCommitFile[]
1197 ** array is allocated to contain the "id" field from the vfile table
1198 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1199 ** should be committed.
1200 */
1201 select_commit_files();
 
 
 
 
 
1202 /* id=0 means that it introduces a new parent */
1203 isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
1204 if( g.aCommitFile && isAMerge ){
1205 fossil_fatal("cannot do a partial commit of a graph merge");
1206 }
@@ -1318,25 +1335,25 @@
1318 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1319 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1320 g.zLocalRoot,
1321 glob_expr("pathname", db_get("crnl-glob","")),
1322 glob_expr("pathname", db_get("binary-glob","")),
1323 glob_expr("pathname", db_get("unicode-glob",""))
1324 );
1325 while( db_step(&q)==SQLITE_ROW ){
1326 int id, rid;
1327 const char *zFullname;
1328 Blob content;
1329 int crnlOk, binOk, unicodeOk, chnged;
1330
1331 id = db_column_int(&q, 0);
1332 zFullname = db_column_text(&q, 1);
1333 rid = db_column_int(&q, 2);
1334 crnlOk = db_column_int(&q, 3);
1335 chnged = db_column_int(&q, 4);
1336 binOk = db_column_int(&q, 5);
1337 unicodeOk = db_column_int(&q, 6);
1338
1339 blob_zero(&content);
1340 if( file_wd_islink(zFullname) ){
1341 /* Instead of file content, put link destination path */
1342 blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
1344 blob_read_from_file(&content, zFullname);
1345 }
1346 /* Do not emit any warnings when they are disabled. */
1347 if( !noWarningFlag ){
1348 abortCommit |= commit_warning(&content, crnlOk, binOk,
1349 unicodeOk, zFullname);
1350 }
1351 if( chnged==1 && contains_merge_marker(&content) ){
1352 Blob fname; /* Relative pathname of the file */
1353
1354 nConflict++;
@@ -1531,11 +1548,11 @@
1531 exit(1);
1532 }
1533 db_end_transaction(0);
1534
1535 if( !g.markPrivate ){
1536 autosync(SYNC_PUSH);
1537 }
1538 if( count_nonbranch_children(vid)>1 ){
1539 fossil_print("**** warning: a fork has occurred *****\n");
1540 }
1541 }
1542
--- src/checkin.c
+++ src/checkin.c
@@ -619,30 +619,36 @@
619 ** of the array.
620 **
621 ** If there were no arguments passed to [commit], aCommitFile is not
622 ** allocated and remains NULL. Other parts of the code interpret this
623 ** to mean "all files".
624 **
625 ** Returns 1 if there was a warning, 0 otherwise.
626 */
627 int select_commit_files(void){
628 int result = 0;
629 if( g.argc>2 ){
630 int ii, jj=0;
631 Blob b;
632 blob_zero(&b);
633 g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));
634
635 for(ii=2; ii<g.argc; ii++){
636 int iId;
637 file_tree_name(g.argv[ii], &b, 1);
638 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
639 if( iId<0 ){
640 fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
641 result = 1;
642 } else {
643 g.aCommitFile[jj++] = iId;
644 }
 
645 blob_reset(&b);
646 }
647 g.aCommitFile[jj] = 0;
648 }
649 return result;
650 }
651
652 /*
653 ** Make sure the current check-in with timestamp zDate is younger than its
654 ** ancestor identified rid and zUuid. Throw a fatal error if not.
@@ -898,11 +904,11 @@
904 */
905 static int commit_warning(
906 Blob *p, /* The content of the file being committed. */
907 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
908 int binOk, /* Non-zero if binary warnings should be disabled. */
909 int encodingOk, /* Non-zero if encoding warnings should be disabled. */
910 const char *zFilename /* The full name of the file being committed. */
911 ){
912 int eType; /* return value of looks_like_utf8/utf16() */
913 int fUnicode; /* return value of starts_with_utf16_bom() */
914 char *zMsg; /* Warning message */
@@ -912,44 +918,50 @@
918 if( allOk ) return 0;
919 fUnicode = starts_with_utf16_bom(p, 0);
920 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
921 if( eType==0 || eType==-1 || fUnicode ){
922 const char *zWarning;
923 const char *zDisable;
924 const char *zConvert = "c=convert/";
925 Blob ans;
926 char cReply;
927
928 if( eType==-1 && fUnicode ){
929 if ( crnlOk && encodingOk ){
930 return 0; /* We don't want CR/NL and Unicode warnings for this file. */
931 }
932 zWarning = "CR/NL line endings and Unicode";
933 zDisable = "\"crnl-glob\" and \"encoding-glob\" settings";
934 }else if( eType==-1 ){
935 if( crnlOk ){
936 return 0; /* We don't want CR/NL warnings for this file. */
937 }
938 zWarning = "CR/NL line endings";
939 zDisable = "\"crnl-glob\" setting";
940 }else if( eType==0 ){
941 if( binOk ){
942 return 0; /* We don't want binary warnings for this file. */
943 }
944 zWarning = "binary data";
945 zDisable = "\"binary-glob\" setting";
946 zConvert = ""; /* We cannot convert binary files. */
947 }else{
948 if ( encodingOk ){
949 return 0; /* We don't want encoding warnings for this file. */
950 }
951 zWarning = "Unicode";
952 zDisable = "\"encoding-glob\" setting";
953 #ifndef _WIN32
954 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
955 #endif
956 }
957 file_relative_name(zFilename, &fname, 0);
958 blob_zero(&ans);
959 zMsg = mprintf(
960 "%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
961 "Commit anyhow (a=all/%sy/N)? ",
962 blob_str(&fname), zWarning, zDisable, zConvert);
963 prompt_user(zMsg, &ans);
964 fossil_free(zMsg);
965 cReply = blob_str(&ans)[0];
966 if( cReply=='a' || cReply=='A' ){
967 allOk = 1;
@@ -1196,11 +1208,16 @@
1208 ** After the following function call has returned, the Global.aCommitFile[]
1209 ** array is allocated to contain the "id" field from the vfile table
1210 ** for each file to be committed. Or, if aCommitFile is NULL, all files
1211 ** should be committed.
1212 */
1213 if ( select_commit_files() ){
1214 blob_zero(&ans);
1215 prompt_user("continue (y/N)? ", &ans);
1216 cReply = blob_str(&ans)[0];
1217 if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
1218 }
1219 /* id=0 means that it introduces a new parent */
1220 isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
1221 if( g.aCommitFile && isAMerge ){
1222 fossil_fatal("cannot do a partial commit of a graph merge");
1223 }
@@ -1318,25 +1335,25 @@
1335 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1336 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1337 g.zLocalRoot,
1338 glob_expr("pathname", db_get("crnl-glob","")),
1339 glob_expr("pathname", db_get("binary-glob","")),
1340 glob_expr("pathname", db_get("encoding-glob",""))
1341 );
1342 while( db_step(&q)==SQLITE_ROW ){
1343 int id, rid;
1344 const char *zFullname;
1345 Blob content;
1346 int crnlOk, binOk, encodingOk, chnged;
1347
1348 id = db_column_int(&q, 0);
1349 zFullname = db_column_text(&q, 1);
1350 rid = db_column_int(&q, 2);
1351 crnlOk = db_column_int(&q, 3);
1352 chnged = db_column_int(&q, 4);
1353 binOk = db_column_int(&q, 5);
1354 encodingOk = db_column_int(&q, 6);
1355
1356 blob_zero(&content);
1357 if( file_wd_islink(zFullname) ){
1358 /* Instead of file content, put link destination path */
1359 blob_read_link(&content, zFullname);
@@ -1344,11 +1361,11 @@
1361 blob_read_from_file(&content, zFullname);
1362 }
1363 /* Do not emit any warnings when they are disabled. */
1364 if( !noWarningFlag ){
1365 abortCommit |= commit_warning(&content, crnlOk, binOk,
1366 encodingOk, zFullname);
1367 }
1368 if( chnged==1 && contains_merge_marker(&content) ){
1369 Blob fname; /* Relative pathname of the file */
1370
1371 nConflict++;
@@ -1531,11 +1548,11 @@
1548 exit(1);
1549 }
1550 db_end_transaction(0);
1551
1552 if( !g.markPrivate ){
1553 autosync(SYNC_PUSH|SYNC_PULL);
1554 }
1555 if( count_nonbranch_children(vid)>1 ){
1556 fossil_print("**** warning: a fork has occurred *****\n");
1557 }
1558 }
1559
+1 -1
--- src/configure.c
+++ src/configure.c
@@ -103,11 +103,11 @@
103103
{ "project-description", CONFIGSET_PROJ },
104104
{ "manifest", CONFIGSET_PROJ },
105105
{ "binary-glob", CONFIGSET_PROJ },
106106
{ "ignore-glob", CONFIGSET_PROJ },
107107
{ "crnl-glob", CONFIGSET_PROJ },
108
- { "unicode-glob", CONFIGSET_PROJ },
108
+ { "encoding-glob", CONFIGSET_PROJ },
109109
{ "empty-dirs", CONFIGSET_PROJ },
110110
{ "allow-symlinks", CONFIGSET_PROJ },
111111
112112
{ "ticket-table", CONFIGSET_TKT },
113113
{ "ticket-common", CONFIGSET_TKT },
114114
--- src/configure.c
+++ src/configure.c
@@ -103,11 +103,11 @@
103 { "project-description", CONFIGSET_PROJ },
104 { "manifest", CONFIGSET_PROJ },
105 { "binary-glob", CONFIGSET_PROJ },
106 { "ignore-glob", CONFIGSET_PROJ },
107 { "crnl-glob", CONFIGSET_PROJ },
108 { "unicode-glob", CONFIGSET_PROJ },
109 { "empty-dirs", CONFIGSET_PROJ },
110 { "allow-symlinks", CONFIGSET_PROJ },
111
112 { "ticket-table", CONFIGSET_TKT },
113 { "ticket-common", CONFIGSET_TKT },
114
--- src/configure.c
+++ src/configure.c
@@ -103,11 +103,11 @@
103 { "project-description", CONFIGSET_PROJ },
104 { "manifest", CONFIGSET_PROJ },
105 { "binary-glob", CONFIGSET_PROJ },
106 { "ignore-glob", CONFIGSET_PROJ },
107 { "crnl-glob", CONFIGSET_PROJ },
108 { "encoding-glob", CONFIGSET_PROJ },
109 { "empty-dirs", CONFIGSET_PROJ },
110 { "allow-symlinks", CONFIGSET_PROJ },
111
112 { "ticket-table", CONFIGSET_TKT },
113 { "ticket-common", CONFIGSET_TKT },
114
+1 -1
--- src/configure.c
+++ src/configure.c
@@ -103,11 +103,11 @@
103103
{ "project-description", CONFIGSET_PROJ },
104104
{ "manifest", CONFIGSET_PROJ },
105105
{ "binary-glob", CONFIGSET_PROJ },
106106
{ "ignore-glob", CONFIGSET_PROJ },
107107
{ "crnl-glob", CONFIGSET_PROJ },
108
- { "unicode-glob", CONFIGSET_PROJ },
108
+ { "encoding-glob", CONFIGSET_PROJ },
109109
{ "empty-dirs", CONFIGSET_PROJ },
110110
{ "allow-symlinks", CONFIGSET_PROJ },
111111
112112
{ "ticket-table", CONFIGSET_TKT },
113113
{ "ticket-common", CONFIGSET_TKT },
114114
--- src/configure.c
+++ src/configure.c
@@ -103,11 +103,11 @@
103 { "project-description", CONFIGSET_PROJ },
104 { "manifest", CONFIGSET_PROJ },
105 { "binary-glob", CONFIGSET_PROJ },
106 { "ignore-glob", CONFIGSET_PROJ },
107 { "crnl-glob", CONFIGSET_PROJ },
108 { "unicode-glob", CONFIGSET_PROJ },
109 { "empty-dirs", CONFIGSET_PROJ },
110 { "allow-symlinks", CONFIGSET_PROJ },
111
112 { "ticket-table", CONFIGSET_TKT },
113 { "ticket-common", CONFIGSET_TKT },
114
--- src/configure.c
+++ src/configure.c
@@ -103,11 +103,11 @@
103 { "project-description", CONFIGSET_PROJ },
104 { "manifest", CONFIGSET_PROJ },
105 { "binary-glob", CONFIGSET_PROJ },
106 { "ignore-glob", CONFIGSET_PROJ },
107 { "crnl-glob", CONFIGSET_PROJ },
108 { "encoding-glob", CONFIGSET_PROJ },
109 { "empty-dirs", CONFIGSET_PROJ },
110 { "allow-symlinks", CONFIGSET_PROJ },
111
112 { "ticket-table", CONFIGSET_TKT },
113 { "ticket-common", CONFIGSET_TKT },
114
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -1,6 +1,9 @@
11
#ifdef FOSSIL_ENABLE_JSON
2
+#ifndef CSON_FOSSIL_MODE
3
+#define CSON_FOSSIL_MODE
4
+#endif
25
/* auto-generated! Do not edit! */
36
/* begin file include/wh/cson/cson.h */
47
#if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
58
#define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
69
710
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -1,6 +1,9 @@
1 #ifdef FOSSIL_ENABLE_JSON
 
 
 
2 /* auto-generated! Do not edit! */
3 /* begin file include/wh/cson/cson.h */
4 #if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
5 #define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
6
7
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -1,6 +1,9 @@
1 #ifdef FOSSIL_ENABLE_JSON
2 #ifndef CSON_FOSSIL_MODE
3 #define CSON_FOSSIL_MODE
4 #endif
5 /* auto-generated! Do not edit! */
6 /* begin file include/wh/cson/cson.h */
7 #if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
8 #define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
9
10
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -1,6 +1,9 @@
11
#ifdef FOSSIL_ENABLE_JSON
2
+#ifndef CSON_FOSSIL_MODE
3
+#define CSON_FOSSIL_MODE
4
+#endif
25
/* auto-generated! Do not edit! */
36
/* begin file include/wh/cson/cson.h */
47
#if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
58
#define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
69
710
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -1,6 +1,9 @@
1 #ifdef FOSSIL_ENABLE_JSON
 
 
 
2 /* auto-generated! Do not edit! */
3 /* begin file include/wh/cson/cson.h */
4 #if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
5 #define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
6
7
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -1,6 +1,9 @@
1 #ifdef FOSSIL_ENABLE_JSON
2 #ifndef CSON_FOSSIL_MODE
3 #define CSON_FOSSIL_MODE
4 #endif
5 /* auto-generated! Do not edit! */
6 /* begin file include/wh/cson/cson.h */
7 #if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
8 #define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
9
10
+61 -62
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
2222
**
2323
** (1) The "user" database in ~/.fossil
2424
**
2525
** (2) The "repository" database
2626
**
27
-** (3) A local checkout database named "_FOSSIL_" or ".fos"
27
+** (3) A local checkout database named "_FOSSIL_" or ".fslckout"
2828
** and located at the root of the local copy of the source tree.
2929
**
3030
*/
3131
#include "config.h"
3232
#if ! defined(_WIN32)
@@ -89,11 +89,11 @@
8989
cgi_reply();
9090
}
9191
else if( g.cgiOutput ){
9292
g.cgiOutput = 0;
9393
cgi_printf("<h1>Database Error</h1>\n"
94
- "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
94
+ "<pre>%h</pre>\n<p>%s</p>\n", z, zRebuildMsg);
9595
cgi_reply();
9696
}else{
9797
fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
9898
}
9999
free(z);
@@ -484,20 +484,30 @@
484484
/*
485485
** Execute multiple SQL statements.
486486
*/
487487
int db_multi_exec(const char *zSql, ...){
488488
Blob sql;
489
- int rc;
489
+ int rc = SQLITE_OK;
490490
va_list ap;
491
- char *zErr = 0;
491
+ const char *z, *zEnd;
492
+ sqlite3_stmt *pStmt;
492493
blob_init(&sql, 0, 0);
493494
va_start(ap, zSql);
494495
blob_vappendf(&sql, zSql, ap);
495496
va_end(ap);
496
- rc = sqlite3_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
497
- if( rc!=SQLITE_OK ){
498
- db_err("%s\n%s", zErr, blob_buffer(&sql));
497
+ z = blob_str(&sql);
498
+ while( rc==SQLITE_OK && z[0] ){
499
+ pStmt = 0;
500
+ rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
501
+ if( rc!=SQLITE_OK ) break;
502
+ if( pStmt ){
503
+ db.nPrepare++;
504
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){}
505
+ rc = sqlite3_finalize(pStmt);
506
+ if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
507
+ }
508
+ z = zEnd;
499509
}
500510
blob_reset(&sql);
501511
return rc;
502512
}
503513
@@ -642,15 +652,11 @@
642652
sqlite3 *db;
643653
int rc;
644654
const char *zSql;
645655
va_list ap;
646656
647
- rc = sqlite3_open(zFileName, &db);
648
- if( rc!=SQLITE_OK ){
649
- db_err(sqlite3_errmsg(db));
650
- }
651
- sqlite3_busy_timeout(db, 5000);
657
+ db = db_open(zFileName);
652658
sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
653659
rc = sqlite3_exec(db, zSchema, 0, 0, 0);
654660
if( rc!=SQLITE_OK ){
655661
db_err(sqlite3_errmsg(db));
656662
}
@@ -697,29 +703,43 @@
697703
698704
/*
699705
** Open a database file. Return a pointer to the new database
700706
** connection. An error results in process abort.
701707
*/
702
-static sqlite3 *openDatabase(const char *zDbName){
708
+LOCAL sqlite3 *db_open(const char *zDbName){
703709
int rc;
704710
const char *zVfs;
705711
sqlite3 *db;
706712
713
+ if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
707714
zVfs = fossil_getenv("FOSSIL_VFS");
708715
rc = sqlite3_open_v2(
709716
zDbName, &db,
710717
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
711718
zVfs
712719
);
713720
if( rc!=SQLITE_OK ){
714
- db_err(sqlite3_errmsg(db));
721
+ db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
715722
}
716723
sqlite3_busy_timeout(db, 5000);
717724
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718725
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719726
sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720727
db_checkin_mtime_function, 0, 0);
728
+ sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
729
+ sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
730
+ sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
731
+ sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
732
+ sqlite3_create_function(
733
+ db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
734
+ );
735
+ sqlite3_create_function(
736
+ db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
737
+ );
738
+ if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
739
+ re_add_sql_func(db);
740
+ sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
721741
return db;
722742
}
723743
724744
725745
/*
@@ -747,13 +767,12 @@
747767
const char *zLabel,
748768
int *pWasAttached
749769
){
750770
if( !g.db ){
751771
assert( g.zMainDbType==0 );
752
- g.db = openDatabase(zDbName);
772
+ g.db = db_open(zDbName);
753773
g.zMainDbType = zLabel;
754
- db_connection_init();
755774
if ( pWasAttached ) *pWasAttached = 0;
756775
}else{
757776
assert( g.zMainDbType!=0 );
758777
db_attach(zDbName, zLabel);
759778
if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
820839
db_open_or_attach(zDbName, "configdb", &g.useAttach);
821840
g.dbConfig = 0;
822841
g.zConfigDbType = 0;
823842
}else{
824843
g.useAttach = 0;
825
- g.dbConfig = openDatabase(zDbName);
844
+ g.dbConfig = db_open(zDbName);
826845
g.zConfigDbType = "configdb";
827846
}
828847
g.configOpen = 1;
829848
free(zDbName);
830849
}
@@ -1221,10 +1240,13 @@
12211240
void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
12221241
const char *zUser = zDefaultUser;
12231242
if( zUser==0 ){
12241243
zUser = db_get("default-user", 0);
12251244
}
1245
+ if( zUser==0 ){
1246
+ zUser = fossil_getenv("FOSSIL_USER");
1247
+ }
12261248
if( zUser==0 ){
12271249
#if defined(_WIN32)
12281250
zUser = fossil_getenv("USERNAME");
12291251
#else
12301252
zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
14411463
** SQL functions for debugging.
14421464
**
14431465
** The print() function writes its arguments on stdout, but only
14441466
** if the -sqlprint command-line option is turned on.
14451467
*/
1446
-static void db_sql_print(
1468
+LOCAL void db_sql_print(
14471469
sqlite3_context *context,
14481470
int argc,
14491471
sqlite3_value **argv
14501472
){
14511473
int i;
@@ -1454,22 +1476,20 @@
14541476
char c = i==argc-1 ? '\n' : ' ';
14551477
fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
14561478
}
14571479
}
14581480
}
1459
-static void db_sql_trace(void *notUsed, const char *zSql){
1481
+LOCAL void db_sql_trace(void *notUsed, const char *zSql){
14601482
int n = strlen(zSql);
1461
- char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
1462
- fossil_puts(zMsg, 1);
1463
- fossil_free(zMsg);
1483
+ fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
14641484
}
14651485
14661486
/*
14671487
** Implement the user() SQL function. user() takes no arguments and
14681488
** returns the user ID of the current user.
14691489
*/
1470
-static void db_sql_user(
1490
+LOCAL void db_sql_user(
14711491
sqlite3_context *context,
14721492
int argc,
14731493
sqlite3_value **argv
14741494
){
14751495
if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
14811501
** Implement the cgi() SQL function. cgi() takes an argument which is
14821502
** a name of CGI query parameter. The value of that parameter is returned,
14831503
** if available. Optional second argument will be returned if the first
14841504
** doesn't exist as a CGI parameter.
14851505
*/
1486
-static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1506
+LOCAL void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
14871507
const char* zP;
14881508
if( argc!=1 && argc!=2 ) return;
14891509
zP = P((const char*)sqlite3_value_text(argv[0]));
14901510
if( zP ){
14911511
sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
15121532
** (meaning that id was named on the command-line).
15131533
**
15141534
** In the second form (3 arguments) return argument X if true and Y
15151535
** if false. Except if Y is NULL then always return X.
15161536
*/
1517
-static void file_is_selected(
1537
+LOCAL void file_is_selected(
15181538
sqlite3_context *context,
15191539
int argc,
15201540
sqlite3_value **argv
15211541
){
15221542
int rc = 0;
@@ -1600,32 +1620,10 @@
16001620
zOut = mprintf("%s", zKey);
16011621
}
16021622
return zOut;
16031623
}
16041624
1605
-/*
1606
-** This function registers auxiliary functions when the SQLite
1607
-** database connection is first established.
1608
-*/
1609
-void db_connection_init(void){
1610
- sqlite3_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1611
- sqlite3_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
1612
- sqlite3_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1613
- sqlite3_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1614
- sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1615
- sqlite3_create_function(
1616
- g.db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1617
- );
1618
- sqlite3_create_function(
1619
- g.db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
1620
- );
1621
- if( g.fSqlTrace ){
1622
- sqlite3_trace(g.db, db_sql_trace, 0);
1623
- }
1624
- re_add_sql_func(g.db);
1625
-}
1626
-
16271625
/*
16281626
** Return true if the string zVal represents "true" (or "false").
16291627
*/
16301628
int is_truth(const char *zVal){
16311629
static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
20662064
{ "default-perms", 0, 16, 0, "u" },
20672065
{ "diff-binary", 0, 0, 0, "on" },
20682066
{ "diff-command", 0, 40, 0, "" },
20692067
{ "dont-push", 0, 0, 0, "off" },
20702068
{ "editor", 0, 32, 0, "" },
2069
+ { "empty-dirs", 0, 40, 1, "" },
2070
+ { "encoding-glob", 0, 40, 1, "" },
20712071
{ "gdiff-command", 0, 40, 0, "gdiff" },
20722072
{ "gmerge-command",0, 40, 0, "" },
2073
+ { "http-port", 0, 16, 0, "8080" },
20732074
{ "https-login", 0, 0, 0, "off" },
2074
- { "ignore-glob", 0, 40, 1, "" },
2075
- { "empty-dirs", 0, 40, 1, "" },
20762075
{ "href-targets", 0, 0, 0, "on" },
2077
- { "http-port", 0, 16, 0, "8080" },
2076
+ { "ignore-glob", 0, 40, 1, "" },
20782077
{ "localauth", 0, 0, 0, "off" },
20792078
{ "main-branch", 0, 40, 0, "trunk" },
20802079
{ "manifest", 0, 0, 1, "off" },
20812080
#ifdef FOSSIL_ENABLE_MARKDOWN
20822081
{ "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
20862085
{ "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
20872086
{ "proxy", 0, 32, 0, "off" },
20882087
{ "relative-paths",0, 0, 0, "on" },
20892088
{ "repo-cksum", 0, 0, 0, "on" },
20902089
{ "self-register", 0, 0, 0, "off" },
2090
+ { "ssh-command", 0, 40, 0, "" },
20912091
{ "ssl-ca-location",0, 40, 0, "" },
20922092
{ "ssl-identity", 0, 40, 0, "" },
2093
- { "ssh-command", 0, 40, 0, "" },
2094
- { "th1-setup", 0, 40, 0, "" },
20952093
#ifdef FOSSIL_ENABLE_TCL
20962094
{ "tcl", 0, 0, 0, "off" },
20972095
{ "tcl-setup", 0, 40, 0, "" },
20982096
#endif
2099
- { "unicode-glob", 0, 40, 1, "" },
2097
+ { "th1-setup", 0, 40, 0, "" },
21002098
{ "web-browser", 0, 32, 0, "" },
21012099
{ "white-foreground", 0, 0, 0, "off" },
21022100
{ 0,0,0,0,0 }
21032101
};
21042102
@@ -2175,17 +2173,23 @@
21752173
** diff-command External command to run when performing a diff.
21762174
** If undefined, the internal text diff will be used.
21772175
**
21782176
** dont-push Prevent this repository from pushing from client to
21792177
** server. Useful when setting up a private branch.
2178
+**
2179
+** editor Text editor command used for check-in comments.
21802180
**
21812181
** empty-dirs A comma or newline-separated list of pathnames. On
21822182
** (versionable) update and checkout commands, if no file or directory
21832183
** exists with that name, an empty directory will be
21842184
** created.
21852185
**
2186
-** editor Text editor command used for check-in comments.
2186
+** encoding-glob The VALUE is a comma or newline-separated list of GLOB
2187
+** (versionable) patterns specifying files that the "commit" command will
2188
+** ignore when issuing warnings about text files that may
2189
+** use another encoding than ASCII or UTF-8. Set to "*"
2190
+** to disable encoding checking.
21872191
**
21882192
** gdiff-command External command to run when performing a graphical
21892193
** diff. If undefined, text diff will be used.
21902194
**
21912195
** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
22442248
**
22452249
** self-register Allow users to register themselves through the HTTP UI.
22462250
** This is useful if you want to see other names than
22472251
** "Anonymous" in e.g. ticketing system. On the other hand
22482252
** users can not be deleted. Default: off.
2253
+**
2254
+** ssh-command Command used to talk to a remote machine with
2255
+** the "ssh://" protocol.
22492256
**
22502257
** ssl-ca-location The full pathname to a file containing PEM encoded
22512258
** CA root certificates, or a directory of certificates
22522259
** with filenames formed from the certificate hashes as
22532260
** required by OpenSSL.
@@ -2263,13 +2270,10 @@
22632270
** the certificate and private key files.
22642271
** This identity will be presented to SSL servers to
22652272
** authenticate this client, in addition to the normal
22662273
** password authentication.
22672274
**
2268
-** ssh-command Command used to talk to a remote machine with
2269
-** the "ssh://" protocol.
2270
-**
22712275
** tcl If enabled (and Fossil was compiled with Tcl support),
22722276
** Tcl integration commands will be added to the TH1
22732277
** interpreter, allowing arbitrary Tcl expressions and
22742278
** scripts to be evaluated from TH1. Additionally, the Tcl
22752279
** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
22812285
**
22822286
** th1-setup This is the setup script to be evaluated after creating
22832287
** and initializing the TH1 interpreter. By default, this
22842288
** is empty and no extra setup is performed.
22852289
**
2286
-** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2287
-** (versionable) patterns specifying files that the "commit" command will
2288
-** ignore when issuing warnings about text files that may
2289
-** contain Unicode. Set to "*" to disable Unicode checking.
2290
-**
22912290
** web-browser A shell command used to launch your preferred
22922291
** web browser when given a URL as an argument.
22932292
** Defaults to "start" on windows, "open" on Mac,
22942293
** and "firefox" on Unix.
22952294
**
22962295
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
22 **
23 ** (1) The "user" database in ~/.fossil
24 **
25 ** (2) The "repository" database
26 **
27 ** (3) A local checkout database named "_FOSSIL_" or ".fos"
28 ** and located at the root of the local copy of the source tree.
29 **
30 */
31 #include "config.h"
32 #if ! defined(_WIN32)
@@ -89,11 +89,11 @@
89 cgi_reply();
90 }
91 else if( g.cgiOutput ){
92 g.cgiOutput = 0;
93 cgi_printf("<h1>Database Error</h1>\n"
94 "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
95 cgi_reply();
96 }else{
97 fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
98 }
99 free(z);
@@ -484,20 +484,30 @@
484 /*
485 ** Execute multiple SQL statements.
486 */
487 int db_multi_exec(const char *zSql, ...){
488 Blob sql;
489 int rc;
490 va_list ap;
491 char *zErr = 0;
 
492 blob_init(&sql, 0, 0);
493 va_start(ap, zSql);
494 blob_vappendf(&sql, zSql, ap);
495 va_end(ap);
496 rc = sqlite3_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
497 if( rc!=SQLITE_OK ){
498 db_err("%s\n%s", zErr, blob_buffer(&sql));
 
 
 
 
 
 
 
 
 
499 }
500 blob_reset(&sql);
501 return rc;
502 }
503
@@ -642,15 +652,11 @@
642 sqlite3 *db;
643 int rc;
644 const char *zSql;
645 va_list ap;
646
647 rc = sqlite3_open(zFileName, &db);
648 if( rc!=SQLITE_OK ){
649 db_err(sqlite3_errmsg(db));
650 }
651 sqlite3_busy_timeout(db, 5000);
652 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
653 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
654 if( rc!=SQLITE_OK ){
655 db_err(sqlite3_errmsg(db));
656 }
@@ -697,29 +703,43 @@
697
698 /*
699 ** Open a database file. Return a pointer to the new database
700 ** connection. An error results in process abort.
701 */
702 static sqlite3 *openDatabase(const char *zDbName){
703 int rc;
704 const char *zVfs;
705 sqlite3 *db;
706
 
707 zVfs = fossil_getenv("FOSSIL_VFS");
708 rc = sqlite3_open_v2(
709 zDbName, &db,
710 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
711 zVfs
712 );
713 if( rc!=SQLITE_OK ){
714 db_err(sqlite3_errmsg(db));
715 }
716 sqlite3_busy_timeout(db, 5000);
717 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720 db_checkin_mtime_function, 0, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
721 return db;
722 }
723
724
725 /*
@@ -747,13 +767,12 @@
747 const char *zLabel,
748 int *pWasAttached
749 ){
750 if( !g.db ){
751 assert( g.zMainDbType==0 );
752 g.db = openDatabase(zDbName);
753 g.zMainDbType = zLabel;
754 db_connection_init();
755 if ( pWasAttached ) *pWasAttached = 0;
756 }else{
757 assert( g.zMainDbType!=0 );
758 db_attach(zDbName, zLabel);
759 if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
820 db_open_or_attach(zDbName, "configdb", &g.useAttach);
821 g.dbConfig = 0;
822 g.zConfigDbType = 0;
823 }else{
824 g.useAttach = 0;
825 g.dbConfig = openDatabase(zDbName);
826 g.zConfigDbType = "configdb";
827 }
828 g.configOpen = 1;
829 free(zDbName);
830 }
@@ -1221,10 +1240,13 @@
1221 void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
1222 const char *zUser = zDefaultUser;
1223 if( zUser==0 ){
1224 zUser = db_get("default-user", 0);
1225 }
 
 
 
1226 if( zUser==0 ){
1227 #if defined(_WIN32)
1228 zUser = fossil_getenv("USERNAME");
1229 #else
1230 zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
1441 ** SQL functions for debugging.
1442 **
1443 ** The print() function writes its arguments on stdout, but only
1444 ** if the -sqlprint command-line option is turned on.
1445 */
1446 static void db_sql_print(
1447 sqlite3_context *context,
1448 int argc,
1449 sqlite3_value **argv
1450 ){
1451 int i;
@@ -1454,22 +1476,20 @@
1454 char c = i==argc-1 ? '\n' : ' ';
1455 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
1456 }
1457 }
1458 }
1459 static void db_sql_trace(void *notUsed, const char *zSql){
1460 int n = strlen(zSql);
1461 char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
1462 fossil_puts(zMsg, 1);
1463 fossil_free(zMsg);
1464 }
1465
1466 /*
1467 ** Implement the user() SQL function. user() takes no arguments and
1468 ** returns the user ID of the current user.
1469 */
1470 static void db_sql_user(
1471 sqlite3_context *context,
1472 int argc,
1473 sqlite3_value **argv
1474 ){
1475 if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
1481 ** Implement the cgi() SQL function. cgi() takes an argument which is
1482 ** a name of CGI query parameter. The value of that parameter is returned,
1483 ** if available. Optional second argument will be returned if the first
1484 ** doesn't exist as a CGI parameter.
1485 */
1486 static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1487 const char* zP;
1488 if( argc!=1 && argc!=2 ) return;
1489 zP = P((const char*)sqlite3_value_text(argv[0]));
1490 if( zP ){
1491 sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
1512 ** (meaning that id was named on the command-line).
1513 **
1514 ** In the second form (3 arguments) return argument X if true and Y
1515 ** if false. Except if Y is NULL then always return X.
1516 */
1517 static void file_is_selected(
1518 sqlite3_context *context,
1519 int argc,
1520 sqlite3_value **argv
1521 ){
1522 int rc = 0;
@@ -1600,32 +1620,10 @@
1600 zOut = mprintf("%s", zKey);
1601 }
1602 return zOut;
1603 }
1604
1605 /*
1606 ** This function registers auxiliary functions when the SQLite
1607 ** database connection is first established.
1608 */
1609 void db_connection_init(void){
1610 sqlite3_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1611 sqlite3_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
1612 sqlite3_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1613 sqlite3_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1614 sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1615 sqlite3_create_function(
1616 g.db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1617 );
1618 sqlite3_create_function(
1619 g.db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
1620 );
1621 if( g.fSqlTrace ){
1622 sqlite3_trace(g.db, db_sql_trace, 0);
1623 }
1624 re_add_sql_func(g.db);
1625 }
1626
1627 /*
1628 ** Return true if the string zVal represents "true" (or "false").
1629 */
1630 int is_truth(const char *zVal){
1631 static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
2066 { "default-perms", 0, 16, 0, "u" },
2067 { "diff-binary", 0, 0, 0, "on" },
2068 { "diff-command", 0, 40, 0, "" },
2069 { "dont-push", 0, 0, 0, "off" },
2070 { "editor", 0, 32, 0, "" },
 
 
2071 { "gdiff-command", 0, 40, 0, "gdiff" },
2072 { "gmerge-command",0, 40, 0, "" },
 
2073 { "https-login", 0, 0, 0, "off" },
2074 { "ignore-glob", 0, 40, 1, "" },
2075 { "empty-dirs", 0, 40, 1, "" },
2076 { "href-targets", 0, 0, 0, "on" },
2077 { "http-port", 0, 16, 0, "8080" },
2078 { "localauth", 0, 0, 0, "off" },
2079 { "main-branch", 0, 40, 0, "trunk" },
2080 { "manifest", 0, 0, 1, "off" },
2081 #ifdef FOSSIL_ENABLE_MARKDOWN
2082 { "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
2086 { "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
2087 { "proxy", 0, 32, 0, "off" },
2088 { "relative-paths",0, 0, 0, "on" },
2089 { "repo-cksum", 0, 0, 0, "on" },
2090 { "self-register", 0, 0, 0, "off" },
 
2091 { "ssl-ca-location",0, 40, 0, "" },
2092 { "ssl-identity", 0, 40, 0, "" },
2093 { "ssh-command", 0, 40, 0, "" },
2094 { "th1-setup", 0, 40, 0, "" },
2095 #ifdef FOSSIL_ENABLE_TCL
2096 { "tcl", 0, 0, 0, "off" },
2097 { "tcl-setup", 0, 40, 0, "" },
2098 #endif
2099 { "unicode-glob", 0, 40, 1, "" },
2100 { "web-browser", 0, 32, 0, "" },
2101 { "white-foreground", 0, 0, 0, "off" },
2102 { 0,0,0,0,0 }
2103 };
2104
@@ -2175,17 +2173,23 @@
2175 ** diff-command External command to run when performing a diff.
2176 ** If undefined, the internal text diff will be used.
2177 **
2178 ** dont-push Prevent this repository from pushing from client to
2179 ** server. Useful when setting up a private branch.
 
 
2180 **
2181 ** empty-dirs A comma or newline-separated list of pathnames. On
2182 ** (versionable) update and checkout commands, if no file or directory
2183 ** exists with that name, an empty directory will be
2184 ** created.
2185 **
2186 ** editor Text editor command used for check-in comments.
 
 
 
 
2187 **
2188 ** gdiff-command External command to run when performing a graphical
2189 ** diff. If undefined, text diff will be used.
2190 **
2191 ** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
2244 **
2245 ** self-register Allow users to register themselves through the HTTP UI.
2246 ** This is useful if you want to see other names than
2247 ** "Anonymous" in e.g. ticketing system. On the other hand
2248 ** users can not be deleted. Default: off.
 
 
 
2249 **
2250 ** ssl-ca-location The full pathname to a file containing PEM encoded
2251 ** CA root certificates, or a directory of certificates
2252 ** with filenames formed from the certificate hashes as
2253 ** required by OpenSSL.
@@ -2263,13 +2270,10 @@
2263 ** the certificate and private key files.
2264 ** This identity will be presented to SSL servers to
2265 ** authenticate this client, in addition to the normal
2266 ** password authentication.
2267 **
2268 ** ssh-command Command used to talk to a remote machine with
2269 ** the "ssh://" protocol.
2270 **
2271 ** tcl If enabled (and Fossil was compiled with Tcl support),
2272 ** Tcl integration commands will be added to the TH1
2273 ** interpreter, allowing arbitrary Tcl expressions and
2274 ** scripts to be evaluated from TH1. Additionally, the Tcl
2275 ** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
2281 **
2282 ** th1-setup This is the setup script to be evaluated after creating
2283 ** and initializing the TH1 interpreter. By default, this
2284 ** is empty and no extra setup is performed.
2285 **
2286 ** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2287 ** (versionable) patterns specifying files that the "commit" command will
2288 ** ignore when issuing warnings about text files that may
2289 ** contain Unicode. Set to "*" to disable Unicode checking.
2290 **
2291 ** web-browser A shell command used to launch your preferred
2292 ** web browser when given a URL as an argument.
2293 ** Defaults to "start" on windows, "open" on Mac,
2294 ** and "firefox" on Unix.
2295 **
2296
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
22 **
23 ** (1) The "user" database in ~/.fossil
24 **
25 ** (2) The "repository" database
26 **
27 ** (3) A local checkout database named "_FOSSIL_" or ".fslckout"
28 ** and located at the root of the local copy of the source tree.
29 **
30 */
31 #include "config.h"
32 #if ! defined(_WIN32)
@@ -89,11 +89,11 @@
89 cgi_reply();
90 }
91 else if( g.cgiOutput ){
92 g.cgiOutput = 0;
93 cgi_printf("<h1>Database Error</h1>\n"
94 "<pre>%h</pre>\n<p>%s</p>\n", z, zRebuildMsg);
95 cgi_reply();
96 }else{
97 fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
98 }
99 free(z);
@@ -484,20 +484,30 @@
484 /*
485 ** Execute multiple SQL statements.
486 */
487 int db_multi_exec(const char *zSql, ...){
488 Blob sql;
489 int rc = SQLITE_OK;
490 va_list ap;
491 const char *z, *zEnd;
492 sqlite3_stmt *pStmt;
493 blob_init(&sql, 0, 0);
494 va_start(ap, zSql);
495 blob_vappendf(&sql, zSql, ap);
496 va_end(ap);
497 z = blob_str(&sql);
498 while( rc==SQLITE_OK && z[0] ){
499 pStmt = 0;
500 rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
501 if( rc!=SQLITE_OK ) break;
502 if( pStmt ){
503 db.nPrepare++;
504 while( sqlite3_step(pStmt)==SQLITE_ROW ){}
505 rc = sqlite3_finalize(pStmt);
506 if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
507 }
508 z = zEnd;
509 }
510 blob_reset(&sql);
511 return rc;
512 }
513
@@ -642,15 +652,11 @@
652 sqlite3 *db;
653 int rc;
654 const char *zSql;
655 va_list ap;
656
657 db = db_open(zFileName);
 
 
 
 
658 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
659 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
660 if( rc!=SQLITE_OK ){
661 db_err(sqlite3_errmsg(db));
662 }
@@ -697,29 +703,43 @@
703
704 /*
705 ** Open a database file. Return a pointer to the new database
706 ** connection. An error results in process abort.
707 */
708 LOCAL sqlite3 *db_open(const char *zDbName){
709 int rc;
710 const char *zVfs;
711 sqlite3 *db;
712
713 if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
714 zVfs = fossil_getenv("FOSSIL_VFS");
715 rc = sqlite3_open_v2(
716 zDbName, &db,
717 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
718 zVfs
719 );
720 if( rc!=SQLITE_OK ){
721 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
722 }
723 sqlite3_busy_timeout(db, 5000);
724 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
725 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
726 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
727 db_checkin_mtime_function, 0, 0);
728 sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
729 sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
730 sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
731 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
732 sqlite3_create_function(
733 db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
734 );
735 sqlite3_create_function(
736 db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
737 );
738 if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
739 re_add_sql_func(db);
740 sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
741 return db;
742 }
743
744
745 /*
@@ -747,13 +767,12 @@
767 const char *zLabel,
768 int *pWasAttached
769 ){
770 if( !g.db ){
771 assert( g.zMainDbType==0 );
772 g.db = db_open(zDbName);
773 g.zMainDbType = zLabel;
 
774 if ( pWasAttached ) *pWasAttached = 0;
775 }else{
776 assert( g.zMainDbType!=0 );
777 db_attach(zDbName, zLabel);
778 if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
839 db_open_or_attach(zDbName, "configdb", &g.useAttach);
840 g.dbConfig = 0;
841 g.zConfigDbType = 0;
842 }else{
843 g.useAttach = 0;
844 g.dbConfig = db_open(zDbName);
845 g.zConfigDbType = "configdb";
846 }
847 g.configOpen = 1;
848 free(zDbName);
849 }
@@ -1221,10 +1240,13 @@
1240 void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
1241 const char *zUser = zDefaultUser;
1242 if( zUser==0 ){
1243 zUser = db_get("default-user", 0);
1244 }
1245 if( zUser==0 ){
1246 zUser = fossil_getenv("FOSSIL_USER");
1247 }
1248 if( zUser==0 ){
1249 #if defined(_WIN32)
1250 zUser = fossil_getenv("USERNAME");
1251 #else
1252 zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
1463 ** SQL functions for debugging.
1464 **
1465 ** The print() function writes its arguments on stdout, but only
1466 ** if the -sqlprint command-line option is turned on.
1467 */
1468 LOCAL void db_sql_print(
1469 sqlite3_context *context,
1470 int argc,
1471 sqlite3_value **argv
1472 ){
1473 int i;
@@ -1454,22 +1476,20 @@
1476 char c = i==argc-1 ? '\n' : ' ';
1477 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
1478 }
1479 }
1480 }
1481 LOCAL void db_sql_trace(void *notUsed, const char *zSql){
1482 int n = strlen(zSql);
1483 fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
 
 
1484 }
1485
1486 /*
1487 ** Implement the user() SQL function. user() takes no arguments and
1488 ** returns the user ID of the current user.
1489 */
1490 LOCAL void db_sql_user(
1491 sqlite3_context *context,
1492 int argc,
1493 sqlite3_value **argv
1494 ){
1495 if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
1501 ** Implement the cgi() SQL function. cgi() takes an argument which is
1502 ** a name of CGI query parameter. The value of that parameter is returned,
1503 ** if available. Optional second argument will be returned if the first
1504 ** doesn't exist as a CGI parameter.
1505 */
1506 LOCAL void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1507 const char* zP;
1508 if( argc!=1 && argc!=2 ) return;
1509 zP = P((const char*)sqlite3_value_text(argv[0]));
1510 if( zP ){
1511 sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
1532 ** (meaning that id was named on the command-line).
1533 **
1534 ** In the second form (3 arguments) return argument X if true and Y
1535 ** if false. Except if Y is NULL then always return X.
1536 */
1537 LOCAL void file_is_selected(
1538 sqlite3_context *context,
1539 int argc,
1540 sqlite3_value **argv
1541 ){
1542 int rc = 0;
@@ -1600,32 +1620,10 @@
1620 zOut = mprintf("%s", zKey);
1621 }
1622 return zOut;
1623 }
1624
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1625 /*
1626 ** Return true if the string zVal represents "true" (or "false").
1627 */
1628 int is_truth(const char *zVal){
1629 static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
2064 { "default-perms", 0, 16, 0, "u" },
2065 { "diff-binary", 0, 0, 0, "on" },
2066 { "diff-command", 0, 40, 0, "" },
2067 { "dont-push", 0, 0, 0, "off" },
2068 { "editor", 0, 32, 0, "" },
2069 { "empty-dirs", 0, 40, 1, "" },
2070 { "encoding-glob", 0, 40, 1, "" },
2071 { "gdiff-command", 0, 40, 0, "gdiff" },
2072 { "gmerge-command",0, 40, 0, "" },
2073 { "http-port", 0, 16, 0, "8080" },
2074 { "https-login", 0, 0, 0, "off" },
 
 
2075 { "href-targets", 0, 0, 0, "on" },
2076 { "ignore-glob", 0, 40, 1, "" },
2077 { "localauth", 0, 0, 0, "off" },
2078 { "main-branch", 0, 40, 0, "trunk" },
2079 { "manifest", 0, 0, 1, "off" },
2080 #ifdef FOSSIL_ENABLE_MARKDOWN
2081 { "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
2085 { "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
2086 { "proxy", 0, 32, 0, "off" },
2087 { "relative-paths",0, 0, 0, "on" },
2088 { "repo-cksum", 0, 0, 0, "on" },
2089 { "self-register", 0, 0, 0, "off" },
2090 { "ssh-command", 0, 40, 0, "" },
2091 { "ssl-ca-location",0, 40, 0, "" },
2092 { "ssl-identity", 0, 40, 0, "" },
 
 
2093 #ifdef FOSSIL_ENABLE_TCL
2094 { "tcl", 0, 0, 0, "off" },
2095 { "tcl-setup", 0, 40, 0, "" },
2096 #endif
2097 { "th1-setup", 0, 40, 0, "" },
2098 { "web-browser", 0, 32, 0, "" },
2099 { "white-foreground", 0, 0, 0, "off" },
2100 { 0,0,0,0,0 }
2101 };
2102
@@ -2175,17 +2173,23 @@
2173 ** diff-command External command to run when performing a diff.
2174 ** If undefined, the internal text diff will be used.
2175 **
2176 ** dont-push Prevent this repository from pushing from client to
2177 ** server. Useful when setting up a private branch.
2178 **
2179 ** editor Text editor command used for check-in comments.
2180 **
2181 ** empty-dirs A comma or newline-separated list of pathnames. On
2182 ** (versionable) update and checkout commands, if no file or directory
2183 ** exists with that name, an empty directory will be
2184 ** created.
2185 **
2186 ** encoding-glob The VALUE is a comma or newline-separated list of GLOB
2187 ** (versionable) patterns specifying files that the "commit" command will
2188 ** ignore when issuing warnings about text files that may
2189 ** use another encoding than ASCII or UTF-8. Set to "*"
2190 ** to disable encoding checking.
2191 **
2192 ** gdiff-command External command to run when performing a graphical
2193 ** diff. If undefined, text diff will be used.
2194 **
2195 ** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
2248 **
2249 ** self-register Allow users to register themselves through the HTTP UI.
2250 ** This is useful if you want to see other names than
2251 ** "Anonymous" in e.g. ticketing system. On the other hand
2252 ** users can not be deleted. Default: off.
2253 **
2254 ** ssh-command Command used to talk to a remote machine with
2255 ** the "ssh://" protocol.
2256 **
2257 ** ssl-ca-location The full pathname to a file containing PEM encoded
2258 ** CA root certificates, or a directory of certificates
2259 ** with filenames formed from the certificate hashes as
2260 ** required by OpenSSL.
@@ -2263,13 +2270,10 @@
2270 ** the certificate and private key files.
2271 ** This identity will be presented to SSL servers to
2272 ** authenticate this client, in addition to the normal
2273 ** password authentication.
2274 **
 
 
 
2275 ** tcl If enabled (and Fossil was compiled with Tcl support),
2276 ** Tcl integration commands will be added to the TH1
2277 ** interpreter, allowing arbitrary Tcl expressions and
2278 ** scripts to be evaluated from TH1. Additionally, the Tcl
2279 ** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
2285 **
2286 ** th1-setup This is the setup script to be evaluated after creating
2287 ** and initializing the TH1 interpreter. By default, this
2288 ** is empty and no extra setup is performed.
2289 **
 
 
 
 
 
2290 ** web-browser A shell command used to launch your preferred
2291 ** web browser when given a URL as an argument.
2292 ** Defaults to "start" on windows, "open" on Mac,
2293 ** and "firefox" on Unix.
2294 **
2295
+61 -62
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
2222
**
2323
** (1) The "user" database in ~/.fossil
2424
**
2525
** (2) The "repository" database
2626
**
27
-** (3) A local checkout database named "_FOSSIL_" or ".fos"
27
+** (3) A local checkout database named "_FOSSIL_" or ".fslckout"
2828
** and located at the root of the local copy of the source tree.
2929
**
3030
*/
3131
#include "config.h"
3232
#if ! defined(_WIN32)
@@ -89,11 +89,11 @@
8989
cgi_reply();
9090
}
9191
else if( g.cgiOutput ){
9292
g.cgiOutput = 0;
9393
cgi_printf("<h1>Database Error</h1>\n"
94
- "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
94
+ "<pre>%h</pre>\n<p>%s</p>\n", z, zRebuildMsg);
9595
cgi_reply();
9696
}else{
9797
fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
9898
}
9999
free(z);
@@ -484,20 +484,30 @@
484484
/*
485485
** Execute multiple SQL statements.
486486
*/
487487
int db_multi_exec(const char *zSql, ...){
488488
Blob sql;
489
- int rc;
489
+ int rc = SQLITE_OK;
490490
va_list ap;
491
- char *zErr = 0;
491
+ const char *z, *zEnd;
492
+ sqlite3_stmt *pStmt;
492493
blob_init(&sql, 0, 0);
493494
va_start(ap, zSql);
494495
blob_vappendf(&sql, zSql, ap);
495496
va_end(ap);
496
- rc = sqlite3_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
497
- if( rc!=SQLITE_OK ){
498
- db_err("%s\n%s", zErr, blob_buffer(&sql));
497
+ z = blob_str(&sql);
498
+ while( rc==SQLITE_OK && z[0] ){
499
+ pStmt = 0;
500
+ rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
501
+ if( rc!=SQLITE_OK ) break;
502
+ if( pStmt ){
503
+ db.nPrepare++;
504
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){}
505
+ rc = sqlite3_finalize(pStmt);
506
+ if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
507
+ }
508
+ z = zEnd;
499509
}
500510
blob_reset(&sql);
501511
return rc;
502512
}
503513
@@ -642,15 +652,11 @@
642652
sqlite3 *db;
643653
int rc;
644654
const char *zSql;
645655
va_list ap;
646656
647
- rc = sqlite3_open(zFileName, &db);
648
- if( rc!=SQLITE_OK ){
649
- db_err(sqlite3_errmsg(db));
650
- }
651
- sqlite3_busy_timeout(db, 5000);
657
+ db = db_open(zFileName);
652658
sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
653659
rc = sqlite3_exec(db, zSchema, 0, 0, 0);
654660
if( rc!=SQLITE_OK ){
655661
db_err(sqlite3_errmsg(db));
656662
}
@@ -697,29 +703,43 @@
697703
698704
/*
699705
** Open a database file. Return a pointer to the new database
700706
** connection. An error results in process abort.
701707
*/
702
-static sqlite3 *openDatabase(const char *zDbName){
708
+LOCAL sqlite3 *db_open(const char *zDbName){
703709
int rc;
704710
const char *zVfs;
705711
sqlite3 *db;
706712
713
+ if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
707714
zVfs = fossil_getenv("FOSSIL_VFS");
708715
rc = sqlite3_open_v2(
709716
zDbName, &db,
710717
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
711718
zVfs
712719
);
713720
if( rc!=SQLITE_OK ){
714
- db_err(sqlite3_errmsg(db));
721
+ db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
715722
}
716723
sqlite3_busy_timeout(db, 5000);
717724
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718725
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719726
sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720727
db_checkin_mtime_function, 0, 0);
728
+ sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
729
+ sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
730
+ sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
731
+ sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
732
+ sqlite3_create_function(
733
+ db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
734
+ );
735
+ sqlite3_create_function(
736
+ db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
737
+ );
738
+ if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
739
+ re_add_sql_func(db);
740
+ sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
721741
return db;
722742
}
723743
724744
725745
/*
@@ -747,13 +767,12 @@
747767
const char *zLabel,
748768
int *pWasAttached
749769
){
750770
if( !g.db ){
751771
assert( g.zMainDbType==0 );
752
- g.db = openDatabase(zDbName);
772
+ g.db = db_open(zDbName);
753773
g.zMainDbType = zLabel;
754
- db_connection_init();
755774
if ( pWasAttached ) *pWasAttached = 0;
756775
}else{
757776
assert( g.zMainDbType!=0 );
758777
db_attach(zDbName, zLabel);
759778
if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
820839
db_open_or_attach(zDbName, "configdb", &g.useAttach);
821840
g.dbConfig = 0;
822841
g.zConfigDbType = 0;
823842
}else{
824843
g.useAttach = 0;
825
- g.dbConfig = openDatabase(zDbName);
844
+ g.dbConfig = db_open(zDbName);
826845
g.zConfigDbType = "configdb";
827846
}
828847
g.configOpen = 1;
829848
free(zDbName);
830849
}
@@ -1221,10 +1240,13 @@
12211240
void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
12221241
const char *zUser = zDefaultUser;
12231242
if( zUser==0 ){
12241243
zUser = db_get("default-user", 0);
12251244
}
1245
+ if( zUser==0 ){
1246
+ zUser = fossil_getenv("FOSSIL_USER");
1247
+ }
12261248
if( zUser==0 ){
12271249
#if defined(_WIN32)
12281250
zUser = fossil_getenv("USERNAME");
12291251
#else
12301252
zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
14411463
** SQL functions for debugging.
14421464
**
14431465
** The print() function writes its arguments on stdout, but only
14441466
** if the -sqlprint command-line option is turned on.
14451467
*/
1446
-static void db_sql_print(
1468
+LOCAL void db_sql_print(
14471469
sqlite3_context *context,
14481470
int argc,
14491471
sqlite3_value **argv
14501472
){
14511473
int i;
@@ -1454,22 +1476,20 @@
14541476
char c = i==argc-1 ? '\n' : ' ';
14551477
fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
14561478
}
14571479
}
14581480
}
1459
-static void db_sql_trace(void *notUsed, const char *zSql){
1481
+LOCAL void db_sql_trace(void *notUsed, const char *zSql){
14601482
int n = strlen(zSql);
1461
- char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
1462
- fossil_puts(zMsg, 1);
1463
- fossil_free(zMsg);
1483
+ fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
14641484
}
14651485
14661486
/*
14671487
** Implement the user() SQL function. user() takes no arguments and
14681488
** returns the user ID of the current user.
14691489
*/
1470
-static void db_sql_user(
1490
+LOCAL void db_sql_user(
14711491
sqlite3_context *context,
14721492
int argc,
14731493
sqlite3_value **argv
14741494
){
14751495
if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
14811501
** Implement the cgi() SQL function. cgi() takes an argument which is
14821502
** a name of CGI query parameter. The value of that parameter is returned,
14831503
** if available. Optional second argument will be returned if the first
14841504
** doesn't exist as a CGI parameter.
14851505
*/
1486
-static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1506
+LOCAL void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
14871507
const char* zP;
14881508
if( argc!=1 && argc!=2 ) return;
14891509
zP = P((const char*)sqlite3_value_text(argv[0]));
14901510
if( zP ){
14911511
sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
15121532
** (meaning that id was named on the command-line).
15131533
**
15141534
** In the second form (3 arguments) return argument X if true and Y
15151535
** if false. Except if Y is NULL then always return X.
15161536
*/
1517
-static void file_is_selected(
1537
+LOCAL void file_is_selected(
15181538
sqlite3_context *context,
15191539
int argc,
15201540
sqlite3_value **argv
15211541
){
15221542
int rc = 0;
@@ -1600,32 +1620,10 @@
16001620
zOut = mprintf("%s", zKey);
16011621
}
16021622
return zOut;
16031623
}
16041624
1605
-/*
1606
-** This function registers auxiliary functions when the SQLite
1607
-** database connection is first established.
1608
-*/
1609
-void db_connection_init(void){
1610
- sqlite3_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1611
- sqlite3_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
1612
- sqlite3_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1613
- sqlite3_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1614
- sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1615
- sqlite3_create_function(
1616
- g.db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1617
- );
1618
- sqlite3_create_function(
1619
- g.db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
1620
- );
1621
- if( g.fSqlTrace ){
1622
- sqlite3_trace(g.db, db_sql_trace, 0);
1623
- }
1624
- re_add_sql_func(g.db);
1625
-}
1626
-
16271625
/*
16281626
** Return true if the string zVal represents "true" (or "false").
16291627
*/
16301628
int is_truth(const char *zVal){
16311629
static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
20662064
{ "default-perms", 0, 16, 0, "u" },
20672065
{ "diff-binary", 0, 0, 0, "on" },
20682066
{ "diff-command", 0, 40, 0, "" },
20692067
{ "dont-push", 0, 0, 0, "off" },
20702068
{ "editor", 0, 32, 0, "" },
2069
+ { "empty-dirs", 0, 40, 1, "" },
2070
+ { "encoding-glob", 0, 40, 1, "" },
20712071
{ "gdiff-command", 0, 40, 0, "gdiff" },
20722072
{ "gmerge-command",0, 40, 0, "" },
2073
+ { "http-port", 0, 16, 0, "8080" },
20732074
{ "https-login", 0, 0, 0, "off" },
2074
- { "ignore-glob", 0, 40, 1, "" },
2075
- { "empty-dirs", 0, 40, 1, "" },
20762075
{ "href-targets", 0, 0, 0, "on" },
2077
- { "http-port", 0, 16, 0, "8080" },
2076
+ { "ignore-glob", 0, 40, 1, "" },
20782077
{ "localauth", 0, 0, 0, "off" },
20792078
{ "main-branch", 0, 40, 0, "trunk" },
20802079
{ "manifest", 0, 0, 1, "off" },
20812080
#ifdef FOSSIL_ENABLE_MARKDOWN
20822081
{ "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
20862085
{ "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
20872086
{ "proxy", 0, 32, 0, "off" },
20882087
{ "relative-paths",0, 0, 0, "on" },
20892088
{ "repo-cksum", 0, 0, 0, "on" },
20902089
{ "self-register", 0, 0, 0, "off" },
2090
+ { "ssh-command", 0, 40, 0, "" },
20912091
{ "ssl-ca-location",0, 40, 0, "" },
20922092
{ "ssl-identity", 0, 40, 0, "" },
2093
- { "ssh-command", 0, 40, 0, "" },
2094
- { "th1-setup", 0, 40, 0, "" },
20952093
#ifdef FOSSIL_ENABLE_TCL
20962094
{ "tcl", 0, 0, 0, "off" },
20972095
{ "tcl-setup", 0, 40, 0, "" },
20982096
#endif
2099
- { "unicode-glob", 0, 40, 1, "" },
2097
+ { "th1-setup", 0, 40, 0, "" },
21002098
{ "web-browser", 0, 32, 0, "" },
21012099
{ "white-foreground", 0, 0, 0, "off" },
21022100
{ 0,0,0,0,0 }
21032101
};
21042102
@@ -2175,17 +2173,23 @@
21752173
** diff-command External command to run when performing a diff.
21762174
** If undefined, the internal text diff will be used.
21772175
**
21782176
** dont-push Prevent this repository from pushing from client to
21792177
** server. Useful when setting up a private branch.
2178
+**
2179
+** editor Text editor command used for check-in comments.
21802180
**
21812181
** empty-dirs A comma or newline-separated list of pathnames. On
21822182
** (versionable) update and checkout commands, if no file or directory
21832183
** exists with that name, an empty directory will be
21842184
** created.
21852185
**
2186
-** editor Text editor command used for check-in comments.
2186
+** encoding-glob The VALUE is a comma or newline-separated list of GLOB
2187
+** (versionable) patterns specifying files that the "commit" command will
2188
+** ignore when issuing warnings about text files that may
2189
+** use another encoding than ASCII or UTF-8. Set to "*"
2190
+** to disable encoding checking.
21872191
**
21882192
** gdiff-command External command to run when performing a graphical
21892193
** diff. If undefined, text diff will be used.
21902194
**
21912195
** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
22442248
**
22452249
** self-register Allow users to register themselves through the HTTP UI.
22462250
** This is useful if you want to see other names than
22472251
** "Anonymous" in e.g. ticketing system. On the other hand
22482252
** users can not be deleted. Default: off.
2253
+**
2254
+** ssh-command Command used to talk to a remote machine with
2255
+** the "ssh://" protocol.
22492256
**
22502257
** ssl-ca-location The full pathname to a file containing PEM encoded
22512258
** CA root certificates, or a directory of certificates
22522259
** with filenames formed from the certificate hashes as
22532260
** required by OpenSSL.
@@ -2263,13 +2270,10 @@
22632270
** the certificate and private key files.
22642271
** This identity will be presented to SSL servers to
22652272
** authenticate this client, in addition to the normal
22662273
** password authentication.
22672274
**
2268
-** ssh-command Command used to talk to a remote machine with
2269
-** the "ssh://" protocol.
2270
-**
22712275
** tcl If enabled (and Fossil was compiled with Tcl support),
22722276
** Tcl integration commands will be added to the TH1
22732277
** interpreter, allowing arbitrary Tcl expressions and
22742278
** scripts to be evaluated from TH1. Additionally, the Tcl
22752279
** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
22812285
**
22822286
** th1-setup This is the setup script to be evaluated after creating
22832287
** and initializing the TH1 interpreter. By default, this
22842288
** is empty and no extra setup is performed.
22852289
**
2286
-** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2287
-** (versionable) patterns specifying files that the "commit" command will
2288
-** ignore when issuing warnings about text files that may
2289
-** contain Unicode. Set to "*" to disable Unicode checking.
2290
-**
22912290
** web-browser A shell command used to launch your preferred
22922291
** web browser when given a URL as an argument.
22932292
** Defaults to "start" on windows, "open" on Mac,
22942293
** and "firefox" on Unix.
22952294
**
22962295
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
22 **
23 ** (1) The "user" database in ~/.fossil
24 **
25 ** (2) The "repository" database
26 **
27 ** (3) A local checkout database named "_FOSSIL_" or ".fos"
28 ** and located at the root of the local copy of the source tree.
29 **
30 */
31 #include "config.h"
32 #if ! defined(_WIN32)
@@ -89,11 +89,11 @@
89 cgi_reply();
90 }
91 else if( g.cgiOutput ){
92 g.cgiOutput = 0;
93 cgi_printf("<h1>Database Error</h1>\n"
94 "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
95 cgi_reply();
96 }else{
97 fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
98 }
99 free(z);
@@ -484,20 +484,30 @@
484 /*
485 ** Execute multiple SQL statements.
486 */
487 int db_multi_exec(const char *zSql, ...){
488 Blob sql;
489 int rc;
490 va_list ap;
491 char *zErr = 0;
 
492 blob_init(&sql, 0, 0);
493 va_start(ap, zSql);
494 blob_vappendf(&sql, zSql, ap);
495 va_end(ap);
496 rc = sqlite3_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
497 if( rc!=SQLITE_OK ){
498 db_err("%s\n%s", zErr, blob_buffer(&sql));
 
 
 
 
 
 
 
 
 
499 }
500 blob_reset(&sql);
501 return rc;
502 }
503
@@ -642,15 +652,11 @@
642 sqlite3 *db;
643 int rc;
644 const char *zSql;
645 va_list ap;
646
647 rc = sqlite3_open(zFileName, &db);
648 if( rc!=SQLITE_OK ){
649 db_err(sqlite3_errmsg(db));
650 }
651 sqlite3_busy_timeout(db, 5000);
652 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
653 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
654 if( rc!=SQLITE_OK ){
655 db_err(sqlite3_errmsg(db));
656 }
@@ -697,29 +703,43 @@
697
698 /*
699 ** Open a database file. Return a pointer to the new database
700 ** connection. An error results in process abort.
701 */
702 static sqlite3 *openDatabase(const char *zDbName){
703 int rc;
704 const char *zVfs;
705 sqlite3 *db;
706
 
707 zVfs = fossil_getenv("FOSSIL_VFS");
708 rc = sqlite3_open_v2(
709 zDbName, &db,
710 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
711 zVfs
712 );
713 if( rc!=SQLITE_OK ){
714 db_err(sqlite3_errmsg(db));
715 }
716 sqlite3_busy_timeout(db, 5000);
717 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720 db_checkin_mtime_function, 0, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
721 return db;
722 }
723
724
725 /*
@@ -747,13 +767,12 @@
747 const char *zLabel,
748 int *pWasAttached
749 ){
750 if( !g.db ){
751 assert( g.zMainDbType==0 );
752 g.db = openDatabase(zDbName);
753 g.zMainDbType = zLabel;
754 db_connection_init();
755 if ( pWasAttached ) *pWasAttached = 0;
756 }else{
757 assert( g.zMainDbType!=0 );
758 db_attach(zDbName, zLabel);
759 if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
820 db_open_or_attach(zDbName, "configdb", &g.useAttach);
821 g.dbConfig = 0;
822 g.zConfigDbType = 0;
823 }else{
824 g.useAttach = 0;
825 g.dbConfig = openDatabase(zDbName);
826 g.zConfigDbType = "configdb";
827 }
828 g.configOpen = 1;
829 free(zDbName);
830 }
@@ -1221,10 +1240,13 @@
1221 void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
1222 const char *zUser = zDefaultUser;
1223 if( zUser==0 ){
1224 zUser = db_get("default-user", 0);
1225 }
 
 
 
1226 if( zUser==0 ){
1227 #if defined(_WIN32)
1228 zUser = fossil_getenv("USERNAME");
1229 #else
1230 zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
1441 ** SQL functions for debugging.
1442 **
1443 ** The print() function writes its arguments on stdout, but only
1444 ** if the -sqlprint command-line option is turned on.
1445 */
1446 static void db_sql_print(
1447 sqlite3_context *context,
1448 int argc,
1449 sqlite3_value **argv
1450 ){
1451 int i;
@@ -1454,22 +1476,20 @@
1454 char c = i==argc-1 ? '\n' : ' ';
1455 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
1456 }
1457 }
1458 }
1459 static void db_sql_trace(void *notUsed, const char *zSql){
1460 int n = strlen(zSql);
1461 char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
1462 fossil_puts(zMsg, 1);
1463 fossil_free(zMsg);
1464 }
1465
1466 /*
1467 ** Implement the user() SQL function. user() takes no arguments and
1468 ** returns the user ID of the current user.
1469 */
1470 static void db_sql_user(
1471 sqlite3_context *context,
1472 int argc,
1473 sqlite3_value **argv
1474 ){
1475 if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
1481 ** Implement the cgi() SQL function. cgi() takes an argument which is
1482 ** a name of CGI query parameter. The value of that parameter is returned,
1483 ** if available. Optional second argument will be returned if the first
1484 ** doesn't exist as a CGI parameter.
1485 */
1486 static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1487 const char* zP;
1488 if( argc!=1 && argc!=2 ) return;
1489 zP = P((const char*)sqlite3_value_text(argv[0]));
1490 if( zP ){
1491 sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
1512 ** (meaning that id was named on the command-line).
1513 **
1514 ** In the second form (3 arguments) return argument X if true and Y
1515 ** if false. Except if Y is NULL then always return X.
1516 */
1517 static void file_is_selected(
1518 sqlite3_context *context,
1519 int argc,
1520 sqlite3_value **argv
1521 ){
1522 int rc = 0;
@@ -1600,32 +1620,10 @@
1600 zOut = mprintf("%s", zKey);
1601 }
1602 return zOut;
1603 }
1604
1605 /*
1606 ** This function registers auxiliary functions when the SQLite
1607 ** database connection is first established.
1608 */
1609 void db_connection_init(void){
1610 sqlite3_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1611 sqlite3_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
1612 sqlite3_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1613 sqlite3_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1614 sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1615 sqlite3_create_function(
1616 g.db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1617 );
1618 sqlite3_create_function(
1619 g.db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
1620 );
1621 if( g.fSqlTrace ){
1622 sqlite3_trace(g.db, db_sql_trace, 0);
1623 }
1624 re_add_sql_func(g.db);
1625 }
1626
1627 /*
1628 ** Return true if the string zVal represents "true" (or "false").
1629 */
1630 int is_truth(const char *zVal){
1631 static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
2066 { "default-perms", 0, 16, 0, "u" },
2067 { "diff-binary", 0, 0, 0, "on" },
2068 { "diff-command", 0, 40, 0, "" },
2069 { "dont-push", 0, 0, 0, "off" },
2070 { "editor", 0, 32, 0, "" },
 
 
2071 { "gdiff-command", 0, 40, 0, "gdiff" },
2072 { "gmerge-command",0, 40, 0, "" },
 
2073 { "https-login", 0, 0, 0, "off" },
2074 { "ignore-glob", 0, 40, 1, "" },
2075 { "empty-dirs", 0, 40, 1, "" },
2076 { "href-targets", 0, 0, 0, "on" },
2077 { "http-port", 0, 16, 0, "8080" },
2078 { "localauth", 0, 0, 0, "off" },
2079 { "main-branch", 0, 40, 0, "trunk" },
2080 { "manifest", 0, 0, 1, "off" },
2081 #ifdef FOSSIL_ENABLE_MARKDOWN
2082 { "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
2086 { "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
2087 { "proxy", 0, 32, 0, "off" },
2088 { "relative-paths",0, 0, 0, "on" },
2089 { "repo-cksum", 0, 0, 0, "on" },
2090 { "self-register", 0, 0, 0, "off" },
 
2091 { "ssl-ca-location",0, 40, 0, "" },
2092 { "ssl-identity", 0, 40, 0, "" },
2093 { "ssh-command", 0, 40, 0, "" },
2094 { "th1-setup", 0, 40, 0, "" },
2095 #ifdef FOSSIL_ENABLE_TCL
2096 { "tcl", 0, 0, 0, "off" },
2097 { "tcl-setup", 0, 40, 0, "" },
2098 #endif
2099 { "unicode-glob", 0, 40, 1, "" },
2100 { "web-browser", 0, 32, 0, "" },
2101 { "white-foreground", 0, 0, 0, "off" },
2102 { 0,0,0,0,0 }
2103 };
2104
@@ -2175,17 +2173,23 @@
2175 ** diff-command External command to run when performing a diff.
2176 ** If undefined, the internal text diff will be used.
2177 **
2178 ** dont-push Prevent this repository from pushing from client to
2179 ** server. Useful when setting up a private branch.
 
 
2180 **
2181 ** empty-dirs A comma or newline-separated list of pathnames. On
2182 ** (versionable) update and checkout commands, if no file or directory
2183 ** exists with that name, an empty directory will be
2184 ** created.
2185 **
2186 ** editor Text editor command used for check-in comments.
 
 
 
 
2187 **
2188 ** gdiff-command External command to run when performing a graphical
2189 ** diff. If undefined, text diff will be used.
2190 **
2191 ** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
2244 **
2245 ** self-register Allow users to register themselves through the HTTP UI.
2246 ** This is useful if you want to see other names than
2247 ** "Anonymous" in e.g. ticketing system. On the other hand
2248 ** users can not be deleted. Default: off.
 
 
 
2249 **
2250 ** ssl-ca-location The full pathname to a file containing PEM encoded
2251 ** CA root certificates, or a directory of certificates
2252 ** with filenames formed from the certificate hashes as
2253 ** required by OpenSSL.
@@ -2263,13 +2270,10 @@
2263 ** the certificate and private key files.
2264 ** This identity will be presented to SSL servers to
2265 ** authenticate this client, in addition to the normal
2266 ** password authentication.
2267 **
2268 ** ssh-command Command used to talk to a remote machine with
2269 ** the "ssh://" protocol.
2270 **
2271 ** tcl If enabled (and Fossil was compiled with Tcl support),
2272 ** Tcl integration commands will be added to the TH1
2273 ** interpreter, allowing arbitrary Tcl expressions and
2274 ** scripts to be evaluated from TH1. Additionally, the Tcl
2275 ** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
2281 **
2282 ** th1-setup This is the setup script to be evaluated after creating
2283 ** and initializing the TH1 interpreter. By default, this
2284 ** is empty and no extra setup is performed.
2285 **
2286 ** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2287 ** (versionable) patterns specifying files that the "commit" command will
2288 ** ignore when issuing warnings about text files that may
2289 ** contain Unicode. Set to "*" to disable Unicode checking.
2290 **
2291 ** web-browser A shell command used to launch your preferred
2292 ** web browser when given a URL as an argument.
2293 ** Defaults to "start" on windows, "open" on Mac,
2294 ** and "firefox" on Unix.
2295 **
2296
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
22 **
23 ** (1) The "user" database in ~/.fossil
24 **
25 ** (2) The "repository" database
26 **
27 ** (3) A local checkout database named "_FOSSIL_" or ".fslckout"
28 ** and located at the root of the local copy of the source tree.
29 **
30 */
31 #include "config.h"
32 #if ! defined(_WIN32)
@@ -89,11 +89,11 @@
89 cgi_reply();
90 }
91 else if( g.cgiOutput ){
92 g.cgiOutput = 0;
93 cgi_printf("<h1>Database Error</h1>\n"
94 "<pre>%h</pre>\n<p>%s</p>\n", z, zRebuildMsg);
95 cgi_reply();
96 }else{
97 fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
98 }
99 free(z);
@@ -484,20 +484,30 @@
484 /*
485 ** Execute multiple SQL statements.
486 */
487 int db_multi_exec(const char *zSql, ...){
488 Blob sql;
489 int rc = SQLITE_OK;
490 va_list ap;
491 const char *z, *zEnd;
492 sqlite3_stmt *pStmt;
493 blob_init(&sql, 0, 0);
494 va_start(ap, zSql);
495 blob_vappendf(&sql, zSql, ap);
496 va_end(ap);
497 z = blob_str(&sql);
498 while( rc==SQLITE_OK && z[0] ){
499 pStmt = 0;
500 rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
501 if( rc!=SQLITE_OK ) break;
502 if( pStmt ){
503 db.nPrepare++;
504 while( sqlite3_step(pStmt)==SQLITE_ROW ){}
505 rc = sqlite3_finalize(pStmt);
506 if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
507 }
508 z = zEnd;
509 }
510 blob_reset(&sql);
511 return rc;
512 }
513
@@ -642,15 +652,11 @@
652 sqlite3 *db;
653 int rc;
654 const char *zSql;
655 va_list ap;
656
657 db = db_open(zFileName);
 
 
 
 
658 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
659 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
660 if( rc!=SQLITE_OK ){
661 db_err(sqlite3_errmsg(db));
662 }
@@ -697,29 +703,43 @@
703
704 /*
705 ** Open a database file. Return a pointer to the new database
706 ** connection. An error results in process abort.
707 */
708 LOCAL sqlite3 *db_open(const char *zDbName){
709 int rc;
710 const char *zVfs;
711 sqlite3 *db;
712
713 if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
714 zVfs = fossil_getenv("FOSSIL_VFS");
715 rc = sqlite3_open_v2(
716 zDbName, &db,
717 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
718 zVfs
719 );
720 if( rc!=SQLITE_OK ){
721 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
722 }
723 sqlite3_busy_timeout(db, 5000);
724 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
725 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
726 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
727 db_checkin_mtime_function, 0, 0);
728 sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
729 sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
730 sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
731 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
732 sqlite3_create_function(
733 db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
734 );
735 sqlite3_create_function(
736 db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
737 );
738 if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
739 re_add_sql_func(db);
740 sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
741 return db;
742 }
743
744
745 /*
@@ -747,13 +767,12 @@
767 const char *zLabel,
768 int *pWasAttached
769 ){
770 if( !g.db ){
771 assert( g.zMainDbType==0 );
772 g.db = db_open(zDbName);
773 g.zMainDbType = zLabel;
 
774 if ( pWasAttached ) *pWasAttached = 0;
775 }else{
776 assert( g.zMainDbType!=0 );
777 db_attach(zDbName, zLabel);
778 if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
839 db_open_or_attach(zDbName, "configdb", &g.useAttach);
840 g.dbConfig = 0;
841 g.zConfigDbType = 0;
842 }else{
843 g.useAttach = 0;
844 g.dbConfig = db_open(zDbName);
845 g.zConfigDbType = "configdb";
846 }
847 g.configOpen = 1;
848 free(zDbName);
849 }
@@ -1221,10 +1240,13 @@
1240 void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
1241 const char *zUser = zDefaultUser;
1242 if( zUser==0 ){
1243 zUser = db_get("default-user", 0);
1244 }
1245 if( zUser==0 ){
1246 zUser = fossil_getenv("FOSSIL_USER");
1247 }
1248 if( zUser==0 ){
1249 #if defined(_WIN32)
1250 zUser = fossil_getenv("USERNAME");
1251 #else
1252 zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
1463 ** SQL functions for debugging.
1464 **
1465 ** The print() function writes its arguments on stdout, but only
1466 ** if the -sqlprint command-line option is turned on.
1467 */
1468 LOCAL void db_sql_print(
1469 sqlite3_context *context,
1470 int argc,
1471 sqlite3_value **argv
1472 ){
1473 int i;
@@ -1454,22 +1476,20 @@
1476 char c = i==argc-1 ? '\n' : ' ';
1477 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
1478 }
1479 }
1480 }
1481 LOCAL void db_sql_trace(void *notUsed, const char *zSql){
1482 int n = strlen(zSql);
1483 fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
 
 
1484 }
1485
1486 /*
1487 ** Implement the user() SQL function. user() takes no arguments and
1488 ** returns the user ID of the current user.
1489 */
1490 LOCAL void db_sql_user(
1491 sqlite3_context *context,
1492 int argc,
1493 sqlite3_value **argv
1494 ){
1495 if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
1501 ** Implement the cgi() SQL function. cgi() takes an argument which is
1502 ** a name of CGI query parameter. The value of that parameter is returned,
1503 ** if available. Optional second argument will be returned if the first
1504 ** doesn't exist as a CGI parameter.
1505 */
1506 LOCAL void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1507 const char* zP;
1508 if( argc!=1 && argc!=2 ) return;
1509 zP = P((const char*)sqlite3_value_text(argv[0]));
1510 if( zP ){
1511 sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
1532 ** (meaning that id was named on the command-line).
1533 **
1534 ** In the second form (3 arguments) return argument X if true and Y
1535 ** if false. Except if Y is NULL then always return X.
1536 */
1537 LOCAL void file_is_selected(
1538 sqlite3_context *context,
1539 int argc,
1540 sqlite3_value **argv
1541 ){
1542 int rc = 0;
@@ -1600,32 +1620,10 @@
1620 zOut = mprintf("%s", zKey);
1621 }
1622 return zOut;
1623 }
1624
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1625 /*
1626 ** Return true if the string zVal represents "true" (or "false").
1627 */
1628 int is_truth(const char *zVal){
1629 static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
2064 { "default-perms", 0, 16, 0, "u" },
2065 { "diff-binary", 0, 0, 0, "on" },
2066 { "diff-command", 0, 40, 0, "" },
2067 { "dont-push", 0, 0, 0, "off" },
2068 { "editor", 0, 32, 0, "" },
2069 { "empty-dirs", 0, 40, 1, "" },
2070 { "encoding-glob", 0, 40, 1, "" },
2071 { "gdiff-command", 0, 40, 0, "gdiff" },
2072 { "gmerge-command",0, 40, 0, "" },
2073 { "http-port", 0, 16, 0, "8080" },
2074 { "https-login", 0, 0, 0, "off" },
 
 
2075 { "href-targets", 0, 0, 0, "on" },
2076 { "ignore-glob", 0, 40, 1, "" },
2077 { "localauth", 0, 0, 0, "off" },
2078 { "main-branch", 0, 40, 0, "trunk" },
2079 { "manifest", 0, 0, 1, "off" },
2080 #ifdef FOSSIL_ENABLE_MARKDOWN
2081 { "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
2085 { "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
2086 { "proxy", 0, 32, 0, "off" },
2087 { "relative-paths",0, 0, 0, "on" },
2088 { "repo-cksum", 0, 0, 0, "on" },
2089 { "self-register", 0, 0, 0, "off" },
2090 { "ssh-command", 0, 40, 0, "" },
2091 { "ssl-ca-location",0, 40, 0, "" },
2092 { "ssl-identity", 0, 40, 0, "" },
 
 
2093 #ifdef FOSSIL_ENABLE_TCL
2094 { "tcl", 0, 0, 0, "off" },
2095 { "tcl-setup", 0, 40, 0, "" },
2096 #endif
2097 { "th1-setup", 0, 40, 0, "" },
2098 { "web-browser", 0, 32, 0, "" },
2099 { "white-foreground", 0, 0, 0, "off" },
2100 { 0,0,0,0,0 }
2101 };
2102
@@ -2175,17 +2173,23 @@
2173 ** diff-command External command to run when performing a diff.
2174 ** If undefined, the internal text diff will be used.
2175 **
2176 ** dont-push Prevent this repository from pushing from client to
2177 ** server. Useful when setting up a private branch.
2178 **
2179 ** editor Text editor command used for check-in comments.
2180 **
2181 ** empty-dirs A comma or newline-separated list of pathnames. On
2182 ** (versionable) update and checkout commands, if no file or directory
2183 ** exists with that name, an empty directory will be
2184 ** created.
2185 **
2186 ** encoding-glob The VALUE is a comma or newline-separated list of GLOB
2187 ** (versionable) patterns specifying files that the "commit" command will
2188 ** ignore when issuing warnings about text files that may
2189 ** use another encoding than ASCII or UTF-8. Set to "*"
2190 ** to disable encoding checking.
2191 **
2192 ** gdiff-command External command to run when performing a graphical
2193 ** diff. If undefined, text diff will be used.
2194 **
2195 ** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
2248 **
2249 ** self-register Allow users to register themselves through the HTTP UI.
2250 ** This is useful if you want to see other names than
2251 ** "Anonymous" in e.g. ticketing system. On the other hand
2252 ** users can not be deleted. Default: off.
2253 **
2254 ** ssh-command Command used to talk to a remote machine with
2255 ** the "ssh://" protocol.
2256 **
2257 ** ssl-ca-location The full pathname to a file containing PEM encoded
2258 ** CA root certificates, or a directory of certificates
2259 ** with filenames formed from the certificate hashes as
2260 ** required by OpenSSL.
@@ -2263,13 +2270,10 @@
2270 ** the certificate and private key files.
2271 ** This identity will be presented to SSL servers to
2272 ** authenticate this client, in addition to the normal
2273 ** password authentication.
2274 **
 
 
 
2275 ** tcl If enabled (and Fossil was compiled with Tcl support),
2276 ** Tcl integration commands will be added to the TH1
2277 ** interpreter, allowing arbitrary Tcl expressions and
2278 ** scripts to be evaluated from TH1. Additionally, the Tcl
2279 ** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
2285 **
2286 ** th1-setup This is the setup script to be evaluated after creating
2287 ** and initializing the TH1 interpreter. By default, this
2288 ** is empty and no extra setup is performed.
2289 **
 
 
 
 
 
2290 ** web-browser A shell command used to launch your preferred
2291 ** web browser when given a URL as an argument.
2292 ** Defaults to "start" on windows, "open" on Mac,
2293 ** and "firefox" on Unix.
2294 **
2295
+61 -62
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
2222
**
2323
** (1) The "user" database in ~/.fossil
2424
**
2525
** (2) The "repository" database
2626
**
27
-** (3) A local checkout database named "_FOSSIL_" or ".fos"
27
+** (3) A local checkout database named "_FOSSIL_" or ".fslckout"
2828
** and located at the root of the local copy of the source tree.
2929
**
3030
*/
3131
#include "config.h"
3232
#if ! defined(_WIN32)
@@ -89,11 +89,11 @@
8989
cgi_reply();
9090
}
9191
else if( g.cgiOutput ){
9292
g.cgiOutput = 0;
9393
cgi_printf("<h1>Database Error</h1>\n"
94
- "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
94
+ "<pre>%h</pre>\n<p>%s</p>\n", z, zRebuildMsg);
9595
cgi_reply();
9696
}else{
9797
fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
9898
}
9999
free(z);
@@ -484,20 +484,30 @@
484484
/*
485485
** Execute multiple SQL statements.
486486
*/
487487
int db_multi_exec(const char *zSql, ...){
488488
Blob sql;
489
- int rc;
489
+ int rc = SQLITE_OK;
490490
va_list ap;
491
- char *zErr = 0;
491
+ const char *z, *zEnd;
492
+ sqlite3_stmt *pStmt;
492493
blob_init(&sql, 0, 0);
493494
va_start(ap, zSql);
494495
blob_vappendf(&sql, zSql, ap);
495496
va_end(ap);
496
- rc = sqlite3_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
497
- if( rc!=SQLITE_OK ){
498
- db_err("%s\n%s", zErr, blob_buffer(&sql));
497
+ z = blob_str(&sql);
498
+ while( rc==SQLITE_OK && z[0] ){
499
+ pStmt = 0;
500
+ rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
501
+ if( rc!=SQLITE_OK ) break;
502
+ if( pStmt ){
503
+ db.nPrepare++;
504
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){}
505
+ rc = sqlite3_finalize(pStmt);
506
+ if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
507
+ }
508
+ z = zEnd;
499509
}
500510
blob_reset(&sql);
501511
return rc;
502512
}
503513
@@ -642,15 +652,11 @@
642652
sqlite3 *db;
643653
int rc;
644654
const char *zSql;
645655
va_list ap;
646656
647
- rc = sqlite3_open(zFileName, &db);
648
- if( rc!=SQLITE_OK ){
649
- db_err(sqlite3_errmsg(db));
650
- }
651
- sqlite3_busy_timeout(db, 5000);
657
+ db = db_open(zFileName);
652658
sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
653659
rc = sqlite3_exec(db, zSchema, 0, 0, 0);
654660
if( rc!=SQLITE_OK ){
655661
db_err(sqlite3_errmsg(db));
656662
}
@@ -697,29 +703,43 @@
697703
698704
/*
699705
** Open a database file. Return a pointer to the new database
700706
** connection. An error results in process abort.
701707
*/
702
-static sqlite3 *openDatabase(const char *zDbName){
708
+LOCAL sqlite3 *db_open(const char *zDbName){
703709
int rc;
704710
const char *zVfs;
705711
sqlite3 *db;
706712
713
+ if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
707714
zVfs = fossil_getenv("FOSSIL_VFS");
708715
rc = sqlite3_open_v2(
709716
zDbName, &db,
710717
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
711718
zVfs
712719
);
713720
if( rc!=SQLITE_OK ){
714
- db_err(sqlite3_errmsg(db));
721
+ db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
715722
}
716723
sqlite3_busy_timeout(db, 5000);
717724
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718725
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719726
sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720727
db_checkin_mtime_function, 0, 0);
728
+ sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
729
+ sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
730
+ sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
731
+ sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
732
+ sqlite3_create_function(
733
+ db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
734
+ );
735
+ sqlite3_create_function(
736
+ db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
737
+ );
738
+ if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
739
+ re_add_sql_func(db);
740
+ sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
721741
return db;
722742
}
723743
724744
725745
/*
@@ -747,13 +767,12 @@
747767
const char *zLabel,
748768
int *pWasAttached
749769
){
750770
if( !g.db ){
751771
assert( g.zMainDbType==0 );
752
- g.db = openDatabase(zDbName);
772
+ g.db = db_open(zDbName);
753773
g.zMainDbType = zLabel;
754
- db_connection_init();
755774
if ( pWasAttached ) *pWasAttached = 0;
756775
}else{
757776
assert( g.zMainDbType!=0 );
758777
db_attach(zDbName, zLabel);
759778
if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
820839
db_open_or_attach(zDbName, "configdb", &g.useAttach);
821840
g.dbConfig = 0;
822841
g.zConfigDbType = 0;
823842
}else{
824843
g.useAttach = 0;
825
- g.dbConfig = openDatabase(zDbName);
844
+ g.dbConfig = db_open(zDbName);
826845
g.zConfigDbType = "configdb";
827846
}
828847
g.configOpen = 1;
829848
free(zDbName);
830849
}
@@ -1221,10 +1240,13 @@
12211240
void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
12221241
const char *zUser = zDefaultUser;
12231242
if( zUser==0 ){
12241243
zUser = db_get("default-user", 0);
12251244
}
1245
+ if( zUser==0 ){
1246
+ zUser = fossil_getenv("FOSSIL_USER");
1247
+ }
12261248
if( zUser==0 ){
12271249
#if defined(_WIN32)
12281250
zUser = fossil_getenv("USERNAME");
12291251
#else
12301252
zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
14411463
** SQL functions for debugging.
14421464
**
14431465
** The print() function writes its arguments on stdout, but only
14441466
** if the -sqlprint command-line option is turned on.
14451467
*/
1446
-static void db_sql_print(
1468
+LOCAL void db_sql_print(
14471469
sqlite3_context *context,
14481470
int argc,
14491471
sqlite3_value **argv
14501472
){
14511473
int i;
@@ -1454,22 +1476,20 @@
14541476
char c = i==argc-1 ? '\n' : ' ';
14551477
fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
14561478
}
14571479
}
14581480
}
1459
-static void db_sql_trace(void *notUsed, const char *zSql){
1481
+LOCAL void db_sql_trace(void *notUsed, const char *zSql){
14601482
int n = strlen(zSql);
1461
- char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
1462
- fossil_puts(zMsg, 1);
1463
- fossil_free(zMsg);
1483
+ fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
14641484
}
14651485
14661486
/*
14671487
** Implement the user() SQL function. user() takes no arguments and
14681488
** returns the user ID of the current user.
14691489
*/
1470
-static void db_sql_user(
1490
+LOCAL void db_sql_user(
14711491
sqlite3_context *context,
14721492
int argc,
14731493
sqlite3_value **argv
14741494
){
14751495
if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
14811501
** Implement the cgi() SQL function. cgi() takes an argument which is
14821502
** a name of CGI query parameter. The value of that parameter is returned,
14831503
** if available. Optional second argument will be returned if the first
14841504
** doesn't exist as a CGI parameter.
14851505
*/
1486
-static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1506
+LOCAL void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
14871507
const char* zP;
14881508
if( argc!=1 && argc!=2 ) return;
14891509
zP = P((const char*)sqlite3_value_text(argv[0]));
14901510
if( zP ){
14911511
sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
15121532
** (meaning that id was named on the command-line).
15131533
**
15141534
** In the second form (3 arguments) return argument X if true and Y
15151535
** if false. Except if Y is NULL then always return X.
15161536
*/
1517
-static void file_is_selected(
1537
+LOCAL void file_is_selected(
15181538
sqlite3_context *context,
15191539
int argc,
15201540
sqlite3_value **argv
15211541
){
15221542
int rc = 0;
@@ -1600,32 +1620,10 @@
16001620
zOut = mprintf("%s", zKey);
16011621
}
16021622
return zOut;
16031623
}
16041624
1605
-/*
1606
-** This function registers auxiliary functions when the SQLite
1607
-** database connection is first established.
1608
-*/
1609
-void db_connection_init(void){
1610
- sqlite3_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1611
- sqlite3_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
1612
- sqlite3_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1613
- sqlite3_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1614
- sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1615
- sqlite3_create_function(
1616
- g.db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1617
- );
1618
- sqlite3_create_function(
1619
- g.db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
1620
- );
1621
- if( g.fSqlTrace ){
1622
- sqlite3_trace(g.db, db_sql_trace, 0);
1623
- }
1624
- re_add_sql_func(g.db);
1625
-}
1626
-
16271625
/*
16281626
** Return true if the string zVal represents "true" (or "false").
16291627
*/
16301628
int is_truth(const char *zVal){
16311629
static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
20662064
{ "default-perms", 0, 16, 0, "u" },
20672065
{ "diff-binary", 0, 0, 0, "on" },
20682066
{ "diff-command", 0, 40, 0, "" },
20692067
{ "dont-push", 0, 0, 0, "off" },
20702068
{ "editor", 0, 32, 0, "" },
2069
+ { "empty-dirs", 0, 40, 1, "" },
2070
+ { "encoding-glob", 0, 40, 1, "" },
20712071
{ "gdiff-command", 0, 40, 0, "gdiff" },
20722072
{ "gmerge-command",0, 40, 0, "" },
2073
+ { "http-port", 0, 16, 0, "8080" },
20732074
{ "https-login", 0, 0, 0, "off" },
2074
- { "ignore-glob", 0, 40, 1, "" },
2075
- { "empty-dirs", 0, 40, 1, "" },
20762075
{ "href-targets", 0, 0, 0, "on" },
2077
- { "http-port", 0, 16, 0, "8080" },
2076
+ { "ignore-glob", 0, 40, 1, "" },
20782077
{ "localauth", 0, 0, 0, "off" },
20792078
{ "main-branch", 0, 40, 0, "trunk" },
20802079
{ "manifest", 0, 0, 1, "off" },
20812080
#ifdef FOSSIL_ENABLE_MARKDOWN
20822081
{ "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
20862085
{ "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
20872086
{ "proxy", 0, 32, 0, "off" },
20882087
{ "relative-paths",0, 0, 0, "on" },
20892088
{ "repo-cksum", 0, 0, 0, "on" },
20902089
{ "self-register", 0, 0, 0, "off" },
2090
+ { "ssh-command", 0, 40, 0, "" },
20912091
{ "ssl-ca-location",0, 40, 0, "" },
20922092
{ "ssl-identity", 0, 40, 0, "" },
2093
- { "ssh-command", 0, 40, 0, "" },
2094
- { "th1-setup", 0, 40, 0, "" },
20952093
#ifdef FOSSIL_ENABLE_TCL
20962094
{ "tcl", 0, 0, 0, "off" },
20972095
{ "tcl-setup", 0, 40, 0, "" },
20982096
#endif
2099
- { "unicode-glob", 0, 40, 1, "" },
2097
+ { "th1-setup", 0, 40, 0, "" },
21002098
{ "web-browser", 0, 32, 0, "" },
21012099
{ "white-foreground", 0, 0, 0, "off" },
21022100
{ 0,0,0,0,0 }
21032101
};
21042102
@@ -2175,17 +2173,23 @@
21752173
** diff-command External command to run when performing a diff.
21762174
** If undefined, the internal text diff will be used.
21772175
**
21782176
** dont-push Prevent this repository from pushing from client to
21792177
** server. Useful when setting up a private branch.
2178
+**
2179
+** editor Text editor command used for check-in comments.
21802180
**
21812181
** empty-dirs A comma or newline-separated list of pathnames. On
21822182
** (versionable) update and checkout commands, if no file or directory
21832183
** exists with that name, an empty directory will be
21842184
** created.
21852185
**
2186
-** editor Text editor command used for check-in comments.
2186
+** encoding-glob The VALUE is a comma or newline-separated list of GLOB
2187
+** (versionable) patterns specifying files that the "commit" command will
2188
+** ignore when issuing warnings about text files that may
2189
+** use another encoding than ASCII or UTF-8. Set to "*"
2190
+** to disable encoding checking.
21872191
**
21882192
** gdiff-command External command to run when performing a graphical
21892193
** diff. If undefined, text diff will be used.
21902194
**
21912195
** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
22442248
**
22452249
** self-register Allow users to register themselves through the HTTP UI.
22462250
** This is useful if you want to see other names than
22472251
** "Anonymous" in e.g. ticketing system. On the other hand
22482252
** users can not be deleted. Default: off.
2253
+**
2254
+** ssh-command Command used to talk to a remote machine with
2255
+** the "ssh://" protocol.
22492256
**
22502257
** ssl-ca-location The full pathname to a file containing PEM encoded
22512258
** CA root certificates, or a directory of certificates
22522259
** with filenames formed from the certificate hashes as
22532260
** required by OpenSSL.
@@ -2263,13 +2270,10 @@
22632270
** the certificate and private key files.
22642271
** This identity will be presented to SSL servers to
22652272
** authenticate this client, in addition to the normal
22662273
** password authentication.
22672274
**
2268
-** ssh-command Command used to talk to a remote machine with
2269
-** the "ssh://" protocol.
2270
-**
22712275
** tcl If enabled (and Fossil was compiled with Tcl support),
22722276
** Tcl integration commands will be added to the TH1
22732277
** interpreter, allowing arbitrary Tcl expressions and
22742278
** scripts to be evaluated from TH1. Additionally, the Tcl
22752279
** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
22812285
**
22822286
** th1-setup This is the setup script to be evaluated after creating
22832287
** and initializing the TH1 interpreter. By default, this
22842288
** is empty and no extra setup is performed.
22852289
**
2286
-** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2287
-** (versionable) patterns specifying files that the "commit" command will
2288
-** ignore when issuing warnings about text files that may
2289
-** contain Unicode. Set to "*" to disable Unicode checking.
2290
-**
22912290
** web-browser A shell command used to launch your preferred
22922291
** web browser when given a URL as an argument.
22932292
** Defaults to "start" on windows, "open" on Mac,
22942293
** and "firefox" on Unix.
22952294
**
22962295
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
22 **
23 ** (1) The "user" database in ~/.fossil
24 **
25 ** (2) The "repository" database
26 **
27 ** (3) A local checkout database named "_FOSSIL_" or ".fos"
28 ** and located at the root of the local copy of the source tree.
29 **
30 */
31 #include "config.h"
32 #if ! defined(_WIN32)
@@ -89,11 +89,11 @@
89 cgi_reply();
90 }
91 else if( g.cgiOutput ){
92 g.cgiOutput = 0;
93 cgi_printf("<h1>Database Error</h1>\n"
94 "<pre>%h</pre><p>%s</p>", z, zRebuildMsg);
95 cgi_reply();
96 }else{
97 fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
98 }
99 free(z);
@@ -484,20 +484,30 @@
484 /*
485 ** Execute multiple SQL statements.
486 */
487 int db_multi_exec(const char *zSql, ...){
488 Blob sql;
489 int rc;
490 va_list ap;
491 char *zErr = 0;
 
492 blob_init(&sql, 0, 0);
493 va_start(ap, zSql);
494 blob_vappendf(&sql, zSql, ap);
495 va_end(ap);
496 rc = sqlite3_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
497 if( rc!=SQLITE_OK ){
498 db_err("%s\n%s", zErr, blob_buffer(&sql));
 
 
 
 
 
 
 
 
 
499 }
500 blob_reset(&sql);
501 return rc;
502 }
503
@@ -642,15 +652,11 @@
642 sqlite3 *db;
643 int rc;
644 const char *zSql;
645 va_list ap;
646
647 rc = sqlite3_open(zFileName, &db);
648 if( rc!=SQLITE_OK ){
649 db_err(sqlite3_errmsg(db));
650 }
651 sqlite3_busy_timeout(db, 5000);
652 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
653 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
654 if( rc!=SQLITE_OK ){
655 db_err(sqlite3_errmsg(db));
656 }
@@ -697,29 +703,43 @@
697
698 /*
699 ** Open a database file. Return a pointer to the new database
700 ** connection. An error results in process abort.
701 */
702 static sqlite3 *openDatabase(const char *zDbName){
703 int rc;
704 const char *zVfs;
705 sqlite3 *db;
706
 
707 zVfs = fossil_getenv("FOSSIL_VFS");
708 rc = sqlite3_open_v2(
709 zDbName, &db,
710 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
711 zVfs
712 );
713 if( rc!=SQLITE_OK ){
714 db_err(sqlite3_errmsg(db));
715 }
716 sqlite3_busy_timeout(db, 5000);
717 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720 db_checkin_mtime_function, 0, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
721 return db;
722 }
723
724
725 /*
@@ -747,13 +767,12 @@
747 const char *zLabel,
748 int *pWasAttached
749 ){
750 if( !g.db ){
751 assert( g.zMainDbType==0 );
752 g.db = openDatabase(zDbName);
753 g.zMainDbType = zLabel;
754 db_connection_init();
755 if ( pWasAttached ) *pWasAttached = 0;
756 }else{
757 assert( g.zMainDbType!=0 );
758 db_attach(zDbName, zLabel);
759 if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
820 db_open_or_attach(zDbName, "configdb", &g.useAttach);
821 g.dbConfig = 0;
822 g.zConfigDbType = 0;
823 }else{
824 g.useAttach = 0;
825 g.dbConfig = openDatabase(zDbName);
826 g.zConfigDbType = "configdb";
827 }
828 g.configOpen = 1;
829 free(zDbName);
830 }
@@ -1221,10 +1240,13 @@
1221 void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
1222 const char *zUser = zDefaultUser;
1223 if( zUser==0 ){
1224 zUser = db_get("default-user", 0);
1225 }
 
 
 
1226 if( zUser==0 ){
1227 #if defined(_WIN32)
1228 zUser = fossil_getenv("USERNAME");
1229 #else
1230 zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
1441 ** SQL functions for debugging.
1442 **
1443 ** The print() function writes its arguments on stdout, but only
1444 ** if the -sqlprint command-line option is turned on.
1445 */
1446 static void db_sql_print(
1447 sqlite3_context *context,
1448 int argc,
1449 sqlite3_value **argv
1450 ){
1451 int i;
@@ -1454,22 +1476,20 @@
1454 char c = i==argc-1 ? '\n' : ' ';
1455 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
1456 }
1457 }
1458 }
1459 static void db_sql_trace(void *notUsed, const char *zSql){
1460 int n = strlen(zSql);
1461 char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
1462 fossil_puts(zMsg, 1);
1463 fossil_free(zMsg);
1464 }
1465
1466 /*
1467 ** Implement the user() SQL function. user() takes no arguments and
1468 ** returns the user ID of the current user.
1469 */
1470 static void db_sql_user(
1471 sqlite3_context *context,
1472 int argc,
1473 sqlite3_value **argv
1474 ){
1475 if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
1481 ** Implement the cgi() SQL function. cgi() takes an argument which is
1482 ** a name of CGI query parameter. The value of that parameter is returned,
1483 ** if available. Optional second argument will be returned if the first
1484 ** doesn't exist as a CGI parameter.
1485 */
1486 static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1487 const char* zP;
1488 if( argc!=1 && argc!=2 ) return;
1489 zP = P((const char*)sqlite3_value_text(argv[0]));
1490 if( zP ){
1491 sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
1512 ** (meaning that id was named on the command-line).
1513 **
1514 ** In the second form (3 arguments) return argument X if true and Y
1515 ** if false. Except if Y is NULL then always return X.
1516 */
1517 static void file_is_selected(
1518 sqlite3_context *context,
1519 int argc,
1520 sqlite3_value **argv
1521 ){
1522 int rc = 0;
@@ -1600,32 +1620,10 @@
1600 zOut = mprintf("%s", zKey);
1601 }
1602 return zOut;
1603 }
1604
1605 /*
1606 ** This function registers auxiliary functions when the SQLite
1607 ** database connection is first established.
1608 */
1609 void db_connection_init(void){
1610 sqlite3_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
1611 sqlite3_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
1612 sqlite3_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1613 sqlite3_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
1614 sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
1615 sqlite3_create_function(
1616 g.db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
1617 );
1618 sqlite3_create_function(
1619 g.db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
1620 );
1621 if( g.fSqlTrace ){
1622 sqlite3_trace(g.db, db_sql_trace, 0);
1623 }
1624 re_add_sql_func(g.db);
1625 }
1626
1627 /*
1628 ** Return true if the string zVal represents "true" (or "false").
1629 */
1630 int is_truth(const char *zVal){
1631 static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
2066 { "default-perms", 0, 16, 0, "u" },
2067 { "diff-binary", 0, 0, 0, "on" },
2068 { "diff-command", 0, 40, 0, "" },
2069 { "dont-push", 0, 0, 0, "off" },
2070 { "editor", 0, 32, 0, "" },
 
 
2071 { "gdiff-command", 0, 40, 0, "gdiff" },
2072 { "gmerge-command",0, 40, 0, "" },
 
2073 { "https-login", 0, 0, 0, "off" },
2074 { "ignore-glob", 0, 40, 1, "" },
2075 { "empty-dirs", 0, 40, 1, "" },
2076 { "href-targets", 0, 0, 0, "on" },
2077 { "http-port", 0, 16, 0, "8080" },
2078 { "localauth", 0, 0, 0, "off" },
2079 { "main-branch", 0, 40, 0, "trunk" },
2080 { "manifest", 0, 0, 1, "off" },
2081 #ifdef FOSSIL_ENABLE_MARKDOWN
2082 { "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
2086 { "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
2087 { "proxy", 0, 32, 0, "off" },
2088 { "relative-paths",0, 0, 0, "on" },
2089 { "repo-cksum", 0, 0, 0, "on" },
2090 { "self-register", 0, 0, 0, "off" },
 
2091 { "ssl-ca-location",0, 40, 0, "" },
2092 { "ssl-identity", 0, 40, 0, "" },
2093 { "ssh-command", 0, 40, 0, "" },
2094 { "th1-setup", 0, 40, 0, "" },
2095 #ifdef FOSSIL_ENABLE_TCL
2096 { "tcl", 0, 0, 0, "off" },
2097 { "tcl-setup", 0, 40, 0, "" },
2098 #endif
2099 { "unicode-glob", 0, 40, 1, "" },
2100 { "web-browser", 0, 32, 0, "" },
2101 { "white-foreground", 0, 0, 0, "off" },
2102 { 0,0,0,0,0 }
2103 };
2104
@@ -2175,17 +2173,23 @@
2175 ** diff-command External command to run when performing a diff.
2176 ** If undefined, the internal text diff will be used.
2177 **
2178 ** dont-push Prevent this repository from pushing from client to
2179 ** server. Useful when setting up a private branch.
 
 
2180 **
2181 ** empty-dirs A comma or newline-separated list of pathnames. On
2182 ** (versionable) update and checkout commands, if no file or directory
2183 ** exists with that name, an empty directory will be
2184 ** created.
2185 **
2186 ** editor Text editor command used for check-in comments.
 
 
 
 
2187 **
2188 ** gdiff-command External command to run when performing a graphical
2189 ** diff. If undefined, text diff will be used.
2190 **
2191 ** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
2244 **
2245 ** self-register Allow users to register themselves through the HTTP UI.
2246 ** This is useful if you want to see other names than
2247 ** "Anonymous" in e.g. ticketing system. On the other hand
2248 ** users can not be deleted. Default: off.
 
 
 
2249 **
2250 ** ssl-ca-location The full pathname to a file containing PEM encoded
2251 ** CA root certificates, or a directory of certificates
2252 ** with filenames formed from the certificate hashes as
2253 ** required by OpenSSL.
@@ -2263,13 +2270,10 @@
2263 ** the certificate and private key files.
2264 ** This identity will be presented to SSL servers to
2265 ** authenticate this client, in addition to the normal
2266 ** password authentication.
2267 **
2268 ** ssh-command Command used to talk to a remote machine with
2269 ** the "ssh://" protocol.
2270 **
2271 ** tcl If enabled (and Fossil was compiled with Tcl support),
2272 ** Tcl integration commands will be added to the TH1
2273 ** interpreter, allowing arbitrary Tcl expressions and
2274 ** scripts to be evaluated from TH1. Additionally, the Tcl
2275 ** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
2281 **
2282 ** th1-setup This is the setup script to be evaluated after creating
2283 ** and initializing the TH1 interpreter. By default, this
2284 ** is empty and no extra setup is performed.
2285 **
2286 ** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2287 ** (versionable) patterns specifying files that the "commit" command will
2288 ** ignore when issuing warnings about text files that may
2289 ** contain Unicode. Set to "*" to disable Unicode checking.
2290 **
2291 ** web-browser A shell command used to launch your preferred
2292 ** web browser when given a URL as an argument.
2293 ** Defaults to "start" on windows, "open" on Mac,
2294 ** and "firefox" on Unix.
2295 **
2296
--- src/db.c
+++ src/db.c
@@ -22,11 +22,11 @@
22 **
23 ** (1) The "user" database in ~/.fossil
24 **
25 ** (2) The "repository" database
26 **
27 ** (3) A local checkout database named "_FOSSIL_" or ".fslckout"
28 ** and located at the root of the local copy of the source tree.
29 **
30 */
31 #include "config.h"
32 #if ! defined(_WIN32)
@@ -89,11 +89,11 @@
89 cgi_reply();
90 }
91 else if( g.cgiOutput ){
92 g.cgiOutput = 0;
93 cgi_printf("<h1>Database Error</h1>\n"
94 "<pre>%h</pre>\n<p>%s</p>\n", z, zRebuildMsg);
95 cgi_reply();
96 }else{
97 fprintf(stderr, "%s: %s\n\n%s", g.argv[0], z, zRebuildMsg);
98 }
99 free(z);
@@ -484,20 +484,30 @@
484 /*
485 ** Execute multiple SQL statements.
486 */
487 int db_multi_exec(const char *zSql, ...){
488 Blob sql;
489 int rc = SQLITE_OK;
490 va_list ap;
491 const char *z, *zEnd;
492 sqlite3_stmt *pStmt;
493 blob_init(&sql, 0, 0);
494 va_start(ap, zSql);
495 blob_vappendf(&sql, zSql, ap);
496 va_end(ap);
497 z = blob_str(&sql);
498 while( rc==SQLITE_OK && z[0] ){
499 pStmt = 0;
500 rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
501 if( rc!=SQLITE_OK ) break;
502 if( pStmt ){
503 db.nPrepare++;
504 while( sqlite3_step(pStmt)==SQLITE_ROW ){}
505 rc = sqlite3_finalize(pStmt);
506 if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
507 }
508 z = zEnd;
509 }
510 blob_reset(&sql);
511 return rc;
512 }
513
@@ -642,15 +652,11 @@
652 sqlite3 *db;
653 int rc;
654 const char *zSql;
655 va_list ap;
656
657 db = db_open(zFileName);
 
 
 
 
658 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
659 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
660 if( rc!=SQLITE_OK ){
661 db_err(sqlite3_errmsg(db));
662 }
@@ -697,29 +703,43 @@
703
704 /*
705 ** Open a database file. Return a pointer to the new database
706 ** connection. An error results in process abort.
707 */
708 LOCAL sqlite3 *db_open(const char *zDbName){
709 int rc;
710 const char *zVfs;
711 sqlite3 *db;
712
713 if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
714 zVfs = fossil_getenv("FOSSIL_VFS");
715 rc = sqlite3_open_v2(
716 zDbName, &db,
717 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
718 zVfs
719 );
720 if( rc!=SQLITE_OK ){
721 db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
722 }
723 sqlite3_busy_timeout(db, 5000);
724 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
725 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
726 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
727 db_checkin_mtime_function, 0, 0);
728 sqlite3_create_function(db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
729 sqlite3_create_function(db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
730 sqlite3_create_function(db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
731 sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
732 sqlite3_create_function(
733 db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
734 );
735 sqlite3_create_function(
736 db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
737 );
738 if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
739 re_add_sql_func(db);
740 sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
741 return db;
742 }
743
744
745 /*
@@ -747,13 +767,12 @@
767 const char *zLabel,
768 int *pWasAttached
769 ){
770 if( !g.db ){
771 assert( g.zMainDbType==0 );
772 g.db = db_open(zDbName);
773 g.zMainDbType = zLabel;
 
774 if ( pWasAttached ) *pWasAttached = 0;
775 }else{
776 assert( g.zMainDbType!=0 );
777 db_attach(zDbName, zLabel);
778 if ( pWasAttached ) *pWasAttached = 1;
@@ -820,11 +839,11 @@
839 db_open_or_attach(zDbName, "configdb", &g.useAttach);
840 g.dbConfig = 0;
841 g.zConfigDbType = 0;
842 }else{
843 g.useAttach = 0;
844 g.dbConfig = db_open(zDbName);
845 g.zConfigDbType = "configdb";
846 }
847 g.configOpen = 1;
848 free(zDbName);
849 }
@@ -1221,10 +1240,13 @@
1240 void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
1241 const char *zUser = zDefaultUser;
1242 if( zUser==0 ){
1243 zUser = db_get("default-user", 0);
1244 }
1245 if( zUser==0 ){
1246 zUser = fossil_getenv("FOSSIL_USER");
1247 }
1248 if( zUser==0 ){
1249 #if defined(_WIN32)
1250 zUser = fossil_getenv("USERNAME");
1251 #else
1252 zUser = fossil_getenv("USER");
@@ -1441,11 +1463,11 @@
1463 ** SQL functions for debugging.
1464 **
1465 ** The print() function writes its arguments on stdout, but only
1466 ** if the -sqlprint command-line option is turned on.
1467 */
1468 LOCAL void db_sql_print(
1469 sqlite3_context *context,
1470 int argc,
1471 sqlite3_value **argv
1472 ){
1473 int i;
@@ -1454,22 +1476,20 @@
1476 char c = i==argc-1 ? '\n' : ' ';
1477 fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
1478 }
1479 }
1480 }
1481 LOCAL void db_sql_trace(void *notUsed, const char *zSql){
1482 int n = strlen(zSql);
1483 fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
 
 
1484 }
1485
1486 /*
1487 ** Implement the user() SQL function. user() takes no arguments and
1488 ** returns the user ID of the current user.
1489 */
1490 LOCAL void db_sql_user(
1491 sqlite3_context *context,
1492 int argc,
1493 sqlite3_value **argv
1494 ){
1495 if( g.zLogin!=0 ){
@@ -1481,11 +1501,11 @@
1501 ** Implement the cgi() SQL function. cgi() takes an argument which is
1502 ** a name of CGI query parameter. The value of that parameter is returned,
1503 ** if available. Optional second argument will be returned if the first
1504 ** doesn't exist as a CGI parameter.
1505 */
1506 LOCAL void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
1507 const char* zP;
1508 if( argc!=1 && argc!=2 ) return;
1509 zP = P((const char*)sqlite3_value_text(argv[0]));
1510 if( zP ){
1511 sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
@@ -1512,11 +1532,11 @@
1532 ** (meaning that id was named on the command-line).
1533 **
1534 ** In the second form (3 arguments) return argument X if true and Y
1535 ** if false. Except if Y is NULL then always return X.
1536 */
1537 LOCAL void file_is_selected(
1538 sqlite3_context *context,
1539 int argc,
1540 sqlite3_value **argv
1541 ){
1542 int rc = 0;
@@ -1600,32 +1620,10 @@
1620 zOut = mprintf("%s", zKey);
1621 }
1622 return zOut;
1623 }
1624
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1625 /*
1626 ** Return true if the string zVal represents "true" (or "false").
1627 */
1628 int is_truth(const char *zVal){
1629 static const char *const azOn[] = { "on", "yes", "true", "1" };
@@ -2066,17 +2064,18 @@
2064 { "default-perms", 0, 16, 0, "u" },
2065 { "diff-binary", 0, 0, 0, "on" },
2066 { "diff-command", 0, 40, 0, "" },
2067 { "dont-push", 0, 0, 0, "off" },
2068 { "editor", 0, 32, 0, "" },
2069 { "empty-dirs", 0, 40, 1, "" },
2070 { "encoding-glob", 0, 40, 1, "" },
2071 { "gdiff-command", 0, 40, 0, "gdiff" },
2072 { "gmerge-command",0, 40, 0, "" },
2073 { "http-port", 0, 16, 0, "8080" },
2074 { "https-login", 0, 0, 0, "off" },
 
 
2075 { "href-targets", 0, 0, 0, "on" },
2076 { "ignore-glob", 0, 40, 1, "" },
2077 { "localauth", 0, 0, 0, "off" },
2078 { "main-branch", 0, 40, 0, "trunk" },
2079 { "manifest", 0, 0, 1, "off" },
2080 #ifdef FOSSIL_ENABLE_MARKDOWN
2081 { "markdown", 0, 0, 0, "off" },
@@ -2086,19 +2085,18 @@
2085 { "pgp-command", 0, 40, 0, "gpg --clearsign -o " },
2086 { "proxy", 0, 32, 0, "off" },
2087 { "relative-paths",0, 0, 0, "on" },
2088 { "repo-cksum", 0, 0, 0, "on" },
2089 { "self-register", 0, 0, 0, "off" },
2090 { "ssh-command", 0, 40, 0, "" },
2091 { "ssl-ca-location",0, 40, 0, "" },
2092 { "ssl-identity", 0, 40, 0, "" },
 
 
2093 #ifdef FOSSIL_ENABLE_TCL
2094 { "tcl", 0, 0, 0, "off" },
2095 { "tcl-setup", 0, 40, 0, "" },
2096 #endif
2097 { "th1-setup", 0, 40, 0, "" },
2098 { "web-browser", 0, 32, 0, "" },
2099 { "white-foreground", 0, 0, 0, "off" },
2100 { 0,0,0,0,0 }
2101 };
2102
@@ -2175,17 +2173,23 @@
2173 ** diff-command External command to run when performing a diff.
2174 ** If undefined, the internal text diff will be used.
2175 **
2176 ** dont-push Prevent this repository from pushing from client to
2177 ** server. Useful when setting up a private branch.
2178 **
2179 ** editor Text editor command used for check-in comments.
2180 **
2181 ** empty-dirs A comma or newline-separated list of pathnames. On
2182 ** (versionable) update and checkout commands, if no file or directory
2183 ** exists with that name, an empty directory will be
2184 ** created.
2185 **
2186 ** encoding-glob The VALUE is a comma or newline-separated list of GLOB
2187 ** (versionable) patterns specifying files that the "commit" command will
2188 ** ignore when issuing warnings about text files that may
2189 ** use another encoding than ASCII or UTF-8. Set to "*"
2190 ** to disable encoding checking.
2191 **
2192 ** gdiff-command External command to run when performing a graphical
2193 ** diff. If undefined, text diff will be used.
2194 **
2195 ** gmerge-command A graphical merge conflict resolver command operating
@@ -2244,10 +2248,13 @@
2248 **
2249 ** self-register Allow users to register themselves through the HTTP UI.
2250 ** This is useful if you want to see other names than
2251 ** "Anonymous" in e.g. ticketing system. On the other hand
2252 ** users can not be deleted. Default: off.
2253 **
2254 ** ssh-command Command used to talk to a remote machine with
2255 ** the "ssh://" protocol.
2256 **
2257 ** ssl-ca-location The full pathname to a file containing PEM encoded
2258 ** CA root certificates, or a directory of certificates
2259 ** with filenames formed from the certificate hashes as
2260 ** required by OpenSSL.
@@ -2263,13 +2270,10 @@
2270 ** the certificate and private key files.
2271 ** This identity will be presented to SSL servers to
2272 ** authenticate this client, in addition to the normal
2273 ** password authentication.
2274 **
 
 
 
2275 ** tcl If enabled (and Fossil was compiled with Tcl support),
2276 ** Tcl integration commands will be added to the TH1
2277 ** interpreter, allowing arbitrary Tcl expressions and
2278 ** scripts to be evaluated from TH1. Additionally, the Tcl
2279 ** interpreter will be able to evaluate arbitrary TH1
@@ -2281,15 +2285,10 @@
2285 **
2286 ** th1-setup This is the setup script to be evaluated after creating
2287 ** and initializing the TH1 interpreter. By default, this
2288 ** is empty and no extra setup is performed.
2289 **
 
 
 
 
 
2290 ** web-browser A shell command used to launch your preferred
2291 ** web browser when given a URL as an argument.
2292 ** Defaults to "start" on windows, "open" on Mac,
2293 ** and "firefox" on Unix.
2294 **
2295
--- src/descendants.c
+++ src/descendants.c
@@ -348,10 +348,11 @@
348348
** repository database to be recomputed.
349349
**
350350
** Options:
351351
** --all show ALL leaves
352352
** --closed show only closed leaves
353
+** --bybranch order output by branch name
353354
** --recompute recompute the "leaf" table in the repository DB
354355
**
355356
** See also: descendants, finfo, info, branch
356357
*/
357358
void leaves_cmd(void){
@@ -358,10 +359,14 @@
358359
Stmt q;
359360
Blob sql;
360361
int showAll = find_option("all", 0, 0)!=0;
361362
int showClosed = find_option("closed", 0, 0)!=0;
362363
int recomputeFlag = find_option("recompute",0,0)!=0;
364
+ int byBranch = find_option("bybranch",0,0)!=0;
365
+ char *zLastBr = 0;
366
+ int n;
367
+ char zLineNo[10];
363368
364369
db_find_and_open_repository(0,0);
365370
if( recomputeFlag ) leaf_rebuild();
366371
blob_zero(&sql);
367372
blob_append(&sql, timeline_query_for_tty(), -1);
@@ -369,13 +374,39 @@
369374
if( showClosed ){
370375
blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
371376
}else if( !showAll ){
372377
blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
373378
}
374
- db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
379
+ if( byBranch ){
380
+ db_prepare(&q, "%s ORDER BY nullif(branch,'trunk') COLLATE nocase,"
381
+ " event.mtime DESC",
382
+ blob_str(&sql));
383
+ }else{
384
+ db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
385
+ }
375386
blob_reset(&sql);
376
- print_timeline(&q, 2000, 0);
387
+ n = 0;
388
+ while( db_step(&q)==SQLITE_ROW ){
389
+ const char *zId = db_column_text(&q, 1);
390
+ const char *zDate = db_column_text(&q, 2);
391
+ const char *zCom = db_column_text(&q, 3);
392
+ const char *zBr = db_column_text(&q, 7);
393
+ char *z;
394
+
395
+ if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
396
+ fossil_print("*** %s ***\n", zBr);
397
+ fossil_free(zLastBr);
398
+ zLastBr = fossil_strdup(zBr);
399
+ }
400
+ n++;
401
+ sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
402
+ fossil_print("%6s ", zLineNo);
403
+ z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
404
+ comment_print(z, 7, 79);
405
+ fossil_free(z);
406
+ }
407
+ fossil_free(zLastBr);
377408
db_finalize(&q);
378409
}
379410
380411
/*
381412
** WEBPAGE: leaves
382413
--- src/descendants.c
+++ src/descendants.c
@@ -348,10 +348,11 @@
348 ** repository database to be recomputed.
349 **
350 ** Options:
351 ** --all show ALL leaves
352 ** --closed show only closed leaves
 
353 ** --recompute recompute the "leaf" table in the repository DB
354 **
355 ** See also: descendants, finfo, info, branch
356 */
357 void leaves_cmd(void){
@@ -358,10 +359,14 @@
358 Stmt q;
359 Blob sql;
360 int showAll = find_option("all", 0, 0)!=0;
361 int showClosed = find_option("closed", 0, 0)!=0;
362 int recomputeFlag = find_option("recompute",0,0)!=0;
 
 
 
 
363
364 db_find_and_open_repository(0,0);
365 if( recomputeFlag ) leaf_rebuild();
366 blob_zero(&sql);
367 blob_append(&sql, timeline_query_for_tty(), -1);
@@ -369,13 +374,39 @@
369 if( showClosed ){
370 blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
371 }else if( !showAll ){
372 blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
373 }
374 db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
 
 
 
 
 
 
375 blob_reset(&sql);
376 print_timeline(&q, 2000, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377 db_finalize(&q);
378 }
379
380 /*
381 ** WEBPAGE: leaves
382
--- src/descendants.c
+++ src/descendants.c
@@ -348,10 +348,11 @@
348 ** repository database to be recomputed.
349 **
350 ** Options:
351 ** --all show ALL leaves
352 ** --closed show only closed leaves
353 ** --bybranch order output by branch name
354 ** --recompute recompute the "leaf" table in the repository DB
355 **
356 ** See also: descendants, finfo, info, branch
357 */
358 void leaves_cmd(void){
@@ -358,10 +359,14 @@
359 Stmt q;
360 Blob sql;
361 int showAll = find_option("all", 0, 0)!=0;
362 int showClosed = find_option("closed", 0, 0)!=0;
363 int recomputeFlag = find_option("recompute",0,0)!=0;
364 int byBranch = find_option("bybranch",0,0)!=0;
365 char *zLastBr = 0;
366 int n;
367 char zLineNo[10];
368
369 db_find_and_open_repository(0,0);
370 if( recomputeFlag ) leaf_rebuild();
371 blob_zero(&sql);
372 blob_append(&sql, timeline_query_for_tty(), -1);
@@ -369,13 +374,39 @@
374 if( showClosed ){
375 blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
376 }else if( !showAll ){
377 blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
378 }
379 if( byBranch ){
380 db_prepare(&q, "%s ORDER BY nullif(branch,'trunk') COLLATE nocase,"
381 " event.mtime DESC",
382 blob_str(&sql));
383 }else{
384 db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
385 }
386 blob_reset(&sql);
387 n = 0;
388 while( db_step(&q)==SQLITE_ROW ){
389 const char *zId = db_column_text(&q, 1);
390 const char *zDate = db_column_text(&q, 2);
391 const char *zCom = db_column_text(&q, 3);
392 const char *zBr = db_column_text(&q, 7);
393 char *z;
394
395 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
396 fossil_print("*** %s ***\n", zBr);
397 fossil_free(zLastBr);
398 zLastBr = fossil_strdup(zBr);
399 }
400 n++;
401 sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
402 fossil_print("%6s ", zLineNo);
403 z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
404 comment_print(z, 7, 79);
405 fossil_free(z);
406 }
407 fossil_free(zLastBr);
408 db_finalize(&q);
409 }
410
411 /*
412 ** WEBPAGE: leaves
413
--- src/descendants.c
+++ src/descendants.c
@@ -348,10 +348,11 @@
348348
** repository database to be recomputed.
349349
**
350350
** Options:
351351
** --all show ALL leaves
352352
** --closed show only closed leaves
353
+** --bybranch order output by branch name
353354
** --recompute recompute the "leaf" table in the repository DB
354355
**
355356
** See also: descendants, finfo, info, branch
356357
*/
357358
void leaves_cmd(void){
@@ -358,10 +359,14 @@
358359
Stmt q;
359360
Blob sql;
360361
int showAll = find_option("all", 0, 0)!=0;
361362
int showClosed = find_option("closed", 0, 0)!=0;
362363
int recomputeFlag = find_option("recompute",0,0)!=0;
364
+ int byBranch = find_option("bybranch",0,0)!=0;
365
+ char *zLastBr = 0;
366
+ int n;
367
+ char zLineNo[10];
363368
364369
db_find_and_open_repository(0,0);
365370
if( recomputeFlag ) leaf_rebuild();
366371
blob_zero(&sql);
367372
blob_append(&sql, timeline_query_for_tty(), -1);
@@ -369,13 +374,39 @@
369374
if( showClosed ){
370375
blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
371376
}else if( !showAll ){
372377
blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
373378
}
374
- db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
379
+ if( byBranch ){
380
+ db_prepare(&q, "%s ORDER BY nullif(branch,'trunk') COLLATE nocase,"
381
+ " event.mtime DESC",
382
+ blob_str(&sql));
383
+ }else{
384
+ db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
385
+ }
375386
blob_reset(&sql);
376
- print_timeline(&q, 2000, 0);
387
+ n = 0;
388
+ while( db_step(&q)==SQLITE_ROW ){
389
+ const char *zId = db_column_text(&q, 1);
390
+ const char *zDate = db_column_text(&q, 2);
391
+ const char *zCom = db_column_text(&q, 3);
392
+ const char *zBr = db_column_text(&q, 7);
393
+ char *z;
394
+
395
+ if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
396
+ fossil_print("*** %s ***\n", zBr);
397
+ fossil_free(zLastBr);
398
+ zLastBr = fossil_strdup(zBr);
399
+ }
400
+ n++;
401
+ sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
402
+ fossil_print("%6s ", zLineNo);
403
+ z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
404
+ comment_print(z, 7, 79);
405
+ fossil_free(z);
406
+ }
407
+ fossil_free(zLastBr);
377408
db_finalize(&q);
378409
}
379410
380411
/*
381412
** WEBPAGE: leaves
382413
--- src/descendants.c
+++ src/descendants.c
@@ -348,10 +348,11 @@
348 ** repository database to be recomputed.
349 **
350 ** Options:
351 ** --all show ALL leaves
352 ** --closed show only closed leaves
 
353 ** --recompute recompute the "leaf" table in the repository DB
354 **
355 ** See also: descendants, finfo, info, branch
356 */
357 void leaves_cmd(void){
@@ -358,10 +359,14 @@
358 Stmt q;
359 Blob sql;
360 int showAll = find_option("all", 0, 0)!=0;
361 int showClosed = find_option("closed", 0, 0)!=0;
362 int recomputeFlag = find_option("recompute",0,0)!=0;
 
 
 
 
363
364 db_find_and_open_repository(0,0);
365 if( recomputeFlag ) leaf_rebuild();
366 blob_zero(&sql);
367 blob_append(&sql, timeline_query_for_tty(), -1);
@@ -369,13 +374,39 @@
369 if( showClosed ){
370 blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
371 }else if( !showAll ){
372 blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
373 }
374 db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
 
 
 
 
 
 
375 blob_reset(&sql);
376 print_timeline(&q, 2000, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377 db_finalize(&q);
378 }
379
380 /*
381 ** WEBPAGE: leaves
382
--- src/descendants.c
+++ src/descendants.c
@@ -348,10 +348,11 @@
348 ** repository database to be recomputed.
349 **
350 ** Options:
351 ** --all show ALL leaves
352 ** --closed show only closed leaves
353 ** --bybranch order output by branch name
354 ** --recompute recompute the "leaf" table in the repository DB
355 **
356 ** See also: descendants, finfo, info, branch
357 */
358 void leaves_cmd(void){
@@ -358,10 +359,14 @@
359 Stmt q;
360 Blob sql;
361 int showAll = find_option("all", 0, 0)!=0;
362 int showClosed = find_option("closed", 0, 0)!=0;
363 int recomputeFlag = find_option("recompute",0,0)!=0;
364 int byBranch = find_option("bybranch",0,0)!=0;
365 char *zLastBr = 0;
366 int n;
367 char zLineNo[10];
368
369 db_find_and_open_repository(0,0);
370 if( recomputeFlag ) leaf_rebuild();
371 blob_zero(&sql);
372 blob_append(&sql, timeline_query_for_tty(), -1);
@@ -369,13 +374,39 @@
374 if( showClosed ){
375 blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
376 }else if( !showAll ){
377 blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid"));
378 }
379 if( byBranch ){
380 db_prepare(&q, "%s ORDER BY nullif(branch,'trunk') COLLATE nocase,"
381 " event.mtime DESC",
382 blob_str(&sql));
383 }else{
384 db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql));
385 }
386 blob_reset(&sql);
387 n = 0;
388 while( db_step(&q)==SQLITE_ROW ){
389 const char *zId = db_column_text(&q, 1);
390 const char *zDate = db_column_text(&q, 2);
391 const char *zCom = db_column_text(&q, 3);
392 const char *zBr = db_column_text(&q, 7);
393 char *z;
394
395 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
396 fossil_print("*** %s ***\n", zBr);
397 fossil_free(zLastBr);
398 zLastBr = fossil_strdup(zBr);
399 }
400 n++;
401 sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
402 fossil_print("%6s ", zLineNo);
403 z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
404 comment_print(z, 7, 79);
405 fossil_free(z);
406 }
407 fossil_free(zLastBr);
408 db_finalize(&q);
409 }
410
411 /*
412 ** WEBPAGE: leaves
413
+10 -47
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360360
** This function returns non-zero if the blob starts with a UTF-16le or
361361
** UTF-16be byte-order-mark (BOM).
362362
*/
363363
int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364364
const char *z = blob_buffer(pContent);
365
- int c1, c2;
366
-
367
- if( pnByte ) *pnByte = 2;
368
- if( blob_size(pContent)<2 ) return 0;
369
- c1 = z[0]; c2 = z[1];
370
- if( (c1==(char)0xff) && (c2==(char)0xfe) ){
371
- return 1;
372
- }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
373
- return 1;
374
- }
375
- return 0;
376
-}
377
-
378
-/*
379
-** This function returns non-zero if the blob starts with a UTF-16le
380
-** byte-order-mark (BOM).
381
-*/
382
-int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
383
- const char *z = blob_buffer(pContent);
384
- int c1, c2;
385
-
386
- if( pnByte ) *pnByte = 2;
387
- if( blob_size(pContent)<2 ) return 0;
388
- c1 = z[0]; c2 = z[1];
389
- if( (c1==(char)0xff) && (c2==(char)0xfe) ){
390
- return 1;
391
- }
392
- return 0;
393
-}
394
-
395
-/*
396
-** This function returns non-zero if the blob starts with a UTF-16be
397
-** byte-order-mark (BOM).
398
-*/
399
-int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
400
- const char *z = blob_buffer(pContent);
401
- int c1, c2;
402
-
403
- if( pnByte ) *pnByte = 2;
404
- if( blob_size(pContent)<2 ) return 0;
405
- c1 = z[0]; c2 = z[1];
406
- if( (c1==(char)0xfe) && (c2==(char)0xff) ){
407
- return 1;
365
+ int c1;
366
+
367
+ if( pnByte ) *pnByte = 2;
368
+ if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369
+ c1 = ((unsigned short *)z)[0];
370
+ if( (c1==0xfeff) || (c1==0xfffe) ){
371
+ if( blob_size(pContent) < 4 ) return 1;
372
+ c1 = ((unsigned short *)z)[1];
373
+ if( c1 != 0 ) return 1;
408374
}
409375
return 0;
410376
}
411377
412378
/*
@@ -424,11 +390,11 @@
424390
ReCompiled *pRe, /* The regular expression to be matched */
425391
DLine *aDLine, /* First of N DLines to compare against */
426392
int N /* Number of DLines to check */
427393
){
428394
while( N-- ){
429
- if( re_execute(pRe, aDLine->z, LENGTH(aDLine)) ){
395
+ if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
430396
return 1;
431397
}
432398
aDLine++;
433399
}
434400
return 0;
@@ -621,13 +587,11 @@
621587
622588
/* Show the differences */
623589
for(i=0; i<nr; i++){
624590
m = R[r+i*3+1];
625591
for(j=0; j<m; j++){
626
- char cMark = '-';
627592
if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
628
- if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' ';
629593
appendDiffLine(pOut, '-', &A[a+j], html, pRe);
630594
}
631595
a += m;
632596
m = R[r+i*3+2];
633597
for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
19651929
Blob *pOut, /* Write diff here if not NULL */
19661930
ReCompiled *pRe, /* Only output changes where this Regexp matches */
19671931
u64 diffFlags /* DIFF_* flags defined above */
19681932
){
19691933
int ignoreEolWs; /* Ignore whitespace at the end of lines */
1970
- int nContext; /* Amount of context to display */
19711934
DContext c;
19721935
19731936
if( diffFlags & DIFF_INVERT ){
19741937
Blob *pTemp = pA_Blob;
19751938
pA_Blob = pB_Blob;
19761939
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1, c2;
366
367 if( pnByte ) *pnByte = 2;
368 if( blob_size(pContent)<2 ) return 0;
369 c1 = z[0]; c2 = z[1];
370 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
371 return 1;
372 }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
373 return 1;
374 }
375 return 0;
376 }
377
378 /*
379 ** This function returns non-zero if the blob starts with a UTF-16le
380 ** byte-order-mark (BOM).
381 */
382 int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
383 const char *z = blob_buffer(pContent);
384 int c1, c2;
385
386 if( pnByte ) *pnByte = 2;
387 if( blob_size(pContent)<2 ) return 0;
388 c1 = z[0]; c2 = z[1];
389 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
390 return 1;
391 }
392 return 0;
393 }
394
395 /*
396 ** This function returns non-zero if the blob starts with a UTF-16be
397 ** byte-order-mark (BOM).
398 */
399 int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
400 const char *z = blob_buffer(pContent);
401 int c1, c2;
402
403 if( pnByte ) *pnByte = 2;
404 if( blob_size(pContent)<2 ) return 0;
405 c1 = z[0]; c2 = z[1];
406 if( (c1==(char)0xfe) && (c2==(char)0xff) ){
407 return 1;
408 }
409 return 0;
410 }
411
412 /*
@@ -424,11 +390,11 @@
424 ReCompiled *pRe, /* The regular expression to be matched */
425 DLine *aDLine, /* First of N DLines to compare against */
426 int N /* Number of DLines to check */
427 ){
428 while( N-- ){
429 if( re_execute(pRe, aDLine->z, LENGTH(aDLine)) ){
430 return 1;
431 }
432 aDLine++;
433 }
434 return 0;
@@ -621,13 +587,11 @@
621
622 /* Show the differences */
623 for(i=0; i<nr; i++){
624 m = R[r+i*3+1];
625 for(j=0; j<m; j++){
626 char cMark = '-';
627 if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
628 if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' ';
629 appendDiffLine(pOut, '-', &A[a+j], html, pRe);
630 }
631 a += m;
632 m = R[r+i*3+2];
633 for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
1965 Blob *pOut, /* Write diff here if not NULL */
1966 ReCompiled *pRe, /* Only output changes where this Regexp matches */
1967 u64 diffFlags /* DIFF_* flags defined above */
1968 ){
1969 int ignoreEolWs; /* Ignore whitespace at the end of lines */
1970 int nContext; /* Amount of context to display */
1971 DContext c;
1972
1973 if( diffFlags & DIFF_INVERT ){
1974 Blob *pTemp = pA_Blob;
1975 pA_Blob = pB_Blob;
1976
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1;
366
367 if( pnByte ) *pnByte = 2;
368 if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369 c1 = ((unsigned short *)z)[0];
370 if( (c1==0xfeff) || (c1==0xfffe) ){
371 if( blob_size(pContent) < 4 ) return 1;
372 c1 = ((unsigned short *)z)[1];
373 if( c1 != 0 ) return 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374 }
375 return 0;
376 }
377
378 /*
@@ -424,11 +390,11 @@
390 ReCompiled *pRe, /* The regular expression to be matched */
391 DLine *aDLine, /* First of N DLines to compare against */
392 int N /* Number of DLines to check */
393 ){
394 while( N-- ){
395 if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
396 return 1;
397 }
398 aDLine++;
399 }
400 return 0;
@@ -621,13 +587,11 @@
587
588 /* Show the differences */
589 for(i=0; i<nr; i++){
590 m = R[r+i*3+1];
591 for(j=0; j<m; j++){
 
592 if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
 
593 appendDiffLine(pOut, '-', &A[a+j], html, pRe);
594 }
595 a += m;
596 m = R[r+i*3+2];
597 for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
1929 Blob *pOut, /* Write diff here if not NULL */
1930 ReCompiled *pRe, /* Only output changes where this Regexp matches */
1931 u64 diffFlags /* DIFF_* flags defined above */
1932 ){
1933 int ignoreEolWs; /* Ignore whitespace at the end of lines */
 
1934 DContext c;
1935
1936 if( diffFlags & DIFF_INVERT ){
1937 Blob *pTemp = pA_Blob;
1938 pA_Blob = pB_Blob;
1939
+10 -47
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360360
** This function returns non-zero if the blob starts with a UTF-16le or
361361
** UTF-16be byte-order-mark (BOM).
362362
*/
363363
int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364364
const char *z = blob_buffer(pContent);
365
- int c1, c2;
366
-
367
- if( pnByte ) *pnByte = 2;
368
- if( blob_size(pContent)<2 ) return 0;
369
- c1 = z[0]; c2 = z[1];
370
- if( (c1==(char)0xff) && (c2==(char)0xfe) ){
371
- return 1;
372
- }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
373
- return 1;
374
- }
375
- return 0;
376
-}
377
-
378
-/*
379
-** This function returns non-zero if the blob starts with a UTF-16le
380
-** byte-order-mark (BOM).
381
-*/
382
-int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
383
- const char *z = blob_buffer(pContent);
384
- int c1, c2;
385
-
386
- if( pnByte ) *pnByte = 2;
387
- if( blob_size(pContent)<2 ) return 0;
388
- c1 = z[0]; c2 = z[1];
389
- if( (c1==(char)0xff) && (c2==(char)0xfe) ){
390
- return 1;
391
- }
392
- return 0;
393
-}
394
-
395
-/*
396
-** This function returns non-zero if the blob starts with a UTF-16be
397
-** byte-order-mark (BOM).
398
-*/
399
-int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
400
- const char *z = blob_buffer(pContent);
401
- int c1, c2;
402
-
403
- if( pnByte ) *pnByte = 2;
404
- if( blob_size(pContent)<2 ) return 0;
405
- c1 = z[0]; c2 = z[1];
406
- if( (c1==(char)0xfe) && (c2==(char)0xff) ){
407
- return 1;
365
+ int c1;
366
+
367
+ if( pnByte ) *pnByte = 2;
368
+ if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369
+ c1 = ((unsigned short *)z)[0];
370
+ if( (c1==0xfeff) || (c1==0xfffe) ){
371
+ if( blob_size(pContent) < 4 ) return 1;
372
+ c1 = ((unsigned short *)z)[1];
373
+ if( c1 != 0 ) return 1;
408374
}
409375
return 0;
410376
}
411377
412378
/*
@@ -424,11 +390,11 @@
424390
ReCompiled *pRe, /* The regular expression to be matched */
425391
DLine *aDLine, /* First of N DLines to compare against */
426392
int N /* Number of DLines to check */
427393
){
428394
while( N-- ){
429
- if( re_execute(pRe, aDLine->z, LENGTH(aDLine)) ){
395
+ if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
430396
return 1;
431397
}
432398
aDLine++;
433399
}
434400
return 0;
@@ -621,13 +587,11 @@
621587
622588
/* Show the differences */
623589
for(i=0; i<nr; i++){
624590
m = R[r+i*3+1];
625591
for(j=0; j<m; j++){
626
- char cMark = '-';
627592
if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
628
- if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' ';
629593
appendDiffLine(pOut, '-', &A[a+j], html, pRe);
630594
}
631595
a += m;
632596
m = R[r+i*3+2];
633597
for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
19651929
Blob *pOut, /* Write diff here if not NULL */
19661930
ReCompiled *pRe, /* Only output changes where this Regexp matches */
19671931
u64 diffFlags /* DIFF_* flags defined above */
19681932
){
19691933
int ignoreEolWs; /* Ignore whitespace at the end of lines */
1970
- int nContext; /* Amount of context to display */
19711934
DContext c;
19721935
19731936
if( diffFlags & DIFF_INVERT ){
19741937
Blob *pTemp = pA_Blob;
19751938
pA_Blob = pB_Blob;
19761939
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1, c2;
366
367 if( pnByte ) *pnByte = 2;
368 if( blob_size(pContent)<2 ) return 0;
369 c1 = z[0]; c2 = z[1];
370 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
371 return 1;
372 }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
373 return 1;
374 }
375 return 0;
376 }
377
378 /*
379 ** This function returns non-zero if the blob starts with a UTF-16le
380 ** byte-order-mark (BOM).
381 */
382 int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
383 const char *z = blob_buffer(pContent);
384 int c1, c2;
385
386 if( pnByte ) *pnByte = 2;
387 if( blob_size(pContent)<2 ) return 0;
388 c1 = z[0]; c2 = z[1];
389 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
390 return 1;
391 }
392 return 0;
393 }
394
395 /*
396 ** This function returns non-zero if the blob starts with a UTF-16be
397 ** byte-order-mark (BOM).
398 */
399 int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
400 const char *z = blob_buffer(pContent);
401 int c1, c2;
402
403 if( pnByte ) *pnByte = 2;
404 if( blob_size(pContent)<2 ) return 0;
405 c1 = z[0]; c2 = z[1];
406 if( (c1==(char)0xfe) && (c2==(char)0xff) ){
407 return 1;
408 }
409 return 0;
410 }
411
412 /*
@@ -424,11 +390,11 @@
424 ReCompiled *pRe, /* The regular expression to be matched */
425 DLine *aDLine, /* First of N DLines to compare against */
426 int N /* Number of DLines to check */
427 ){
428 while( N-- ){
429 if( re_execute(pRe, aDLine->z, LENGTH(aDLine)) ){
430 return 1;
431 }
432 aDLine++;
433 }
434 return 0;
@@ -621,13 +587,11 @@
621
622 /* Show the differences */
623 for(i=0; i<nr; i++){
624 m = R[r+i*3+1];
625 for(j=0; j<m; j++){
626 char cMark = '-';
627 if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
628 if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' ';
629 appendDiffLine(pOut, '-', &A[a+j], html, pRe);
630 }
631 a += m;
632 m = R[r+i*3+2];
633 for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
1965 Blob *pOut, /* Write diff here if not NULL */
1966 ReCompiled *pRe, /* Only output changes where this Regexp matches */
1967 u64 diffFlags /* DIFF_* flags defined above */
1968 ){
1969 int ignoreEolWs; /* Ignore whitespace at the end of lines */
1970 int nContext; /* Amount of context to display */
1971 DContext c;
1972
1973 if( diffFlags & DIFF_INVERT ){
1974 Blob *pTemp = pA_Blob;
1975 pA_Blob = pB_Blob;
1976
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1;
366
367 if( pnByte ) *pnByte = 2;
368 if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369 c1 = ((unsigned short *)z)[0];
370 if( (c1==0xfeff) || (c1==0xfffe) ){
371 if( blob_size(pContent) < 4 ) return 1;
372 c1 = ((unsigned short *)z)[1];
373 if( c1 != 0 ) return 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374 }
375 return 0;
376 }
377
378 /*
@@ -424,11 +390,11 @@
390 ReCompiled *pRe, /* The regular expression to be matched */
391 DLine *aDLine, /* First of N DLines to compare against */
392 int N /* Number of DLines to check */
393 ){
394 while( N-- ){
395 if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
396 return 1;
397 }
398 aDLine++;
399 }
400 return 0;
@@ -621,13 +587,11 @@
587
588 /* Show the differences */
589 for(i=0; i<nr; i++){
590 m = R[r+i*3+1];
591 for(j=0; j<m; j++){
 
592 if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
 
593 appendDiffLine(pOut, '-', &A[a+j], html, pRe);
594 }
595 a += m;
596 m = R[r+i*3+2];
597 for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
1929 Blob *pOut, /* Write diff here if not NULL */
1930 ReCompiled *pRe, /* Only output changes where this Regexp matches */
1931 u64 diffFlags /* DIFF_* flags defined above */
1932 ){
1933 int ignoreEolWs; /* Ignore whitespace at the end of lines */
 
1934 DContext c;
1935
1936 if( diffFlags & DIFF_INVERT ){
1937 Blob *pTemp = pA_Blob;
1938 pA_Blob = pB_Blob;
1939
+10 -47
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360360
** This function returns non-zero if the blob starts with a UTF-16le or
361361
** UTF-16be byte-order-mark (BOM).
362362
*/
363363
int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364364
const char *z = blob_buffer(pContent);
365
- int c1, c2;
366
-
367
- if( pnByte ) *pnByte = 2;
368
- if( blob_size(pContent)<2 ) return 0;
369
- c1 = z[0]; c2 = z[1];
370
- if( (c1==(char)0xff) && (c2==(char)0xfe) ){
371
- return 1;
372
- }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
373
- return 1;
374
- }
375
- return 0;
376
-}
377
-
378
-/*
379
-** This function returns non-zero if the blob starts with a UTF-16le
380
-** byte-order-mark (BOM).
381
-*/
382
-int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
383
- const char *z = blob_buffer(pContent);
384
- int c1, c2;
385
-
386
- if( pnByte ) *pnByte = 2;
387
- if( blob_size(pContent)<2 ) return 0;
388
- c1 = z[0]; c2 = z[1];
389
- if( (c1==(char)0xff) && (c2==(char)0xfe) ){
390
- return 1;
391
- }
392
- return 0;
393
-}
394
-
395
-/*
396
-** This function returns non-zero if the blob starts with a UTF-16be
397
-** byte-order-mark (BOM).
398
-*/
399
-int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
400
- const char *z = blob_buffer(pContent);
401
- int c1, c2;
402
-
403
- if( pnByte ) *pnByte = 2;
404
- if( blob_size(pContent)<2 ) return 0;
405
- c1 = z[0]; c2 = z[1];
406
- if( (c1==(char)0xfe) && (c2==(char)0xff) ){
407
- return 1;
365
+ int c1;
366
+
367
+ if( pnByte ) *pnByte = 2;
368
+ if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369
+ c1 = ((unsigned short *)z)[0];
370
+ if( (c1==0xfeff) || (c1==0xfffe) ){
371
+ if( blob_size(pContent) < 4 ) return 1;
372
+ c1 = ((unsigned short *)z)[1];
373
+ if( c1 != 0 ) return 1;
408374
}
409375
return 0;
410376
}
411377
412378
/*
@@ -424,11 +390,11 @@
424390
ReCompiled *pRe, /* The regular expression to be matched */
425391
DLine *aDLine, /* First of N DLines to compare against */
426392
int N /* Number of DLines to check */
427393
){
428394
while( N-- ){
429
- if( re_execute(pRe, aDLine->z, LENGTH(aDLine)) ){
395
+ if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
430396
return 1;
431397
}
432398
aDLine++;
433399
}
434400
return 0;
@@ -621,13 +587,11 @@
621587
622588
/* Show the differences */
623589
for(i=0; i<nr; i++){
624590
m = R[r+i*3+1];
625591
for(j=0; j<m; j++){
626
- char cMark = '-';
627592
if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
628
- if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' ';
629593
appendDiffLine(pOut, '-', &A[a+j], html, pRe);
630594
}
631595
a += m;
632596
m = R[r+i*3+2];
633597
for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
19651929
Blob *pOut, /* Write diff here if not NULL */
19661930
ReCompiled *pRe, /* Only output changes where this Regexp matches */
19671931
u64 diffFlags /* DIFF_* flags defined above */
19681932
){
19691933
int ignoreEolWs; /* Ignore whitespace at the end of lines */
1970
- int nContext; /* Amount of context to display */
19711934
DContext c;
19721935
19731936
if( diffFlags & DIFF_INVERT ){
19741937
Blob *pTemp = pA_Blob;
19751938
pA_Blob = pB_Blob;
19761939
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1, c2;
366
367 if( pnByte ) *pnByte = 2;
368 if( blob_size(pContent)<2 ) return 0;
369 c1 = z[0]; c2 = z[1];
370 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
371 return 1;
372 }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
373 return 1;
374 }
375 return 0;
376 }
377
378 /*
379 ** This function returns non-zero if the blob starts with a UTF-16le
380 ** byte-order-mark (BOM).
381 */
382 int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
383 const char *z = blob_buffer(pContent);
384 int c1, c2;
385
386 if( pnByte ) *pnByte = 2;
387 if( blob_size(pContent)<2 ) return 0;
388 c1 = z[0]; c2 = z[1];
389 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
390 return 1;
391 }
392 return 0;
393 }
394
395 /*
396 ** This function returns non-zero if the blob starts with a UTF-16be
397 ** byte-order-mark (BOM).
398 */
399 int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
400 const char *z = blob_buffer(pContent);
401 int c1, c2;
402
403 if( pnByte ) *pnByte = 2;
404 if( blob_size(pContent)<2 ) return 0;
405 c1 = z[0]; c2 = z[1];
406 if( (c1==(char)0xfe) && (c2==(char)0xff) ){
407 return 1;
408 }
409 return 0;
410 }
411
412 /*
@@ -424,11 +390,11 @@
424 ReCompiled *pRe, /* The regular expression to be matched */
425 DLine *aDLine, /* First of N DLines to compare against */
426 int N /* Number of DLines to check */
427 ){
428 while( N-- ){
429 if( re_execute(pRe, aDLine->z, LENGTH(aDLine)) ){
430 return 1;
431 }
432 aDLine++;
433 }
434 return 0;
@@ -621,13 +587,11 @@
621
622 /* Show the differences */
623 for(i=0; i<nr; i++){
624 m = R[r+i*3+1];
625 for(j=0; j<m; j++){
626 char cMark = '-';
627 if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
628 if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' ';
629 appendDiffLine(pOut, '-', &A[a+j], html, pRe);
630 }
631 a += m;
632 m = R[r+i*3+2];
633 for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
1965 Blob *pOut, /* Write diff here if not NULL */
1966 ReCompiled *pRe, /* Only output changes where this Regexp matches */
1967 u64 diffFlags /* DIFF_* flags defined above */
1968 ){
1969 int ignoreEolWs; /* Ignore whitespace at the end of lines */
1970 int nContext; /* Amount of context to display */
1971 DContext c;
1972
1973 if( diffFlags & DIFF_INVERT ){
1974 Blob *pTemp = pA_Blob;
1975 pA_Blob = pB_Blob;
1976
--- src/diff.c
+++ src/diff.c
@@ -360,53 +360,19 @@
360 ** This function returns non-zero if the blob starts with a UTF-16le or
361 ** UTF-16be byte-order-mark (BOM).
362 */
363 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
364 const char *z = blob_buffer(pContent);
365 int c1;
366
367 if( pnByte ) *pnByte = 2;
368 if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
369 c1 = ((unsigned short *)z)[0];
370 if( (c1==0xfeff) || (c1==0xfffe) ){
371 if( blob_size(pContent) < 4 ) return 1;
372 c1 = ((unsigned short *)z)[1];
373 if( c1 != 0 ) return 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374 }
375 return 0;
376 }
377
378 /*
@@ -424,11 +390,11 @@
390 ReCompiled *pRe, /* The regular expression to be matched */
391 DLine *aDLine, /* First of N DLines to compare against */
392 int N /* Number of DLines to check */
393 ){
394 while( N-- ){
395 if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
396 return 1;
397 }
398 aDLine++;
399 }
400 return 0;
@@ -621,13 +587,11 @@
587
588 /* Show the differences */
589 for(i=0; i<nr; i++){
590 m = R[r+i*3+1];
591 for(j=0; j<m; j++){
 
592 if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
 
593 appendDiffLine(pOut, '-', &A[a+j], html, pRe);
594 }
595 a += m;
596 m = R[r+i*3+2];
597 for(j=0; j<m; j++){
@@ -1965,11 +1929,10 @@
1929 Blob *pOut, /* Write diff here if not NULL */
1930 ReCompiled *pRe, /* Only output changes where this Regexp matches */
1931 u64 diffFlags /* DIFF_* flags defined above */
1932 ){
1933 int ignoreEolWs; /* Ignore whitespace at the end of lines */
 
1934 DContext c;
1935
1936 if( diffFlags & DIFF_INVERT ){
1937 Blob *pTemp = pA_Blob;
1938 pA_Blob = pB_Blob;
1939
+7 -3
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122122
{ "deb", 3, "application/x-debian-package" },
123123
{ "dir", 3, "application/x-director" },
124124
{ "dl", 2, "video/dl" },
125125
{ "dms", 3, "application/octet-stream" },
126126
{ "doc", 3, "application/msword" },
127
- { "docx", 4, "application/msword" },
127
+ { "docx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
128
+ { "dot", 3, "application/msword" },
129
+ { "dotx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
128130
{ "drw", 3, "application/drafting" },
129131
{ "dvi", 3, "application/x-dvi" },
130132
{ "dwg", 3, "application/acad" },
131133
{ "dxf", 3, "application/dxf" },
132134
{ "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
202204
{ "pl", 2, "application/x-perl" },
203205
{ "pm", 2, "application/x-perl" },
204206
{ "png", 3, "image/png" },
205207
{ "pnm", 3, "image/x-portable-anymap" },
206208
{ "pot", 3, "application/mspowerpoint" },
209
+ { "potx", 4, "application/vnd.openxmlformats-officedocument.presentationml.template"},
207210
{ "ppm", 3, "image/x-portable-pixmap" },
208211
{ "pps", 3, "application/mspowerpoint" },
212
+ { "ppsx", 4, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
209213
{ "ppt", 3, "application/mspowerpoint" },
210
- { "pptx", 4, "application/mspowerpoint" },
214
+ { "pptx", 4, "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
211215
{ "ppz", 3, "application/mspowerpoint" },
212216
{ "pre", 3, "application/x-freelance" },
213217
{ "prt", 3, "application/pro_eng" },
214218
{ "ps", 2, "application/postscript" },
215219
{ "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
280284
{ "xbm", 3, "image/x-xbitmap" },
281285
{ "xlc", 3, "application/vnd.ms-excel" },
282286
{ "xll", 3, "application/vnd.ms-excel" },
283287
{ "xlm", 3, "application/vnd.ms-excel" },
284288
{ "xls", 3, "application/vnd.ms-excel" },
285
- { "xlsx", 4, "application/vnd.ms-excel" },
289
+ { "xlsx", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
286290
{ "xlw", 3, "application/vnd.ms-excel" },
287291
{ "xml", 3, "text/xml" },
288292
{ "xpm", 3, "image/x-xpixmap" },
289293
{ "xwd", 3, "image/x-xwindowdump" },
290294
{ "xyz", 3, "chemical/x-pdb" },
291295
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122 { "deb", 3, "application/x-debian-package" },
123 { "dir", 3, "application/x-director" },
124 { "dl", 2, "video/dl" },
125 { "dms", 3, "application/octet-stream" },
126 { "doc", 3, "application/msword" },
127 { "docx", 4, "application/msword" },
 
 
128 { "drw", 3, "application/drafting" },
129 { "dvi", 3, "application/x-dvi" },
130 { "dwg", 3, "application/acad" },
131 { "dxf", 3, "application/dxf" },
132 { "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
202 { "pl", 2, "application/x-perl" },
203 { "pm", 2, "application/x-perl" },
204 { "png", 3, "image/png" },
205 { "pnm", 3, "image/x-portable-anymap" },
206 { "pot", 3, "application/mspowerpoint" },
 
207 { "ppm", 3, "image/x-portable-pixmap" },
208 { "pps", 3, "application/mspowerpoint" },
 
209 { "ppt", 3, "application/mspowerpoint" },
210 { "pptx", 4, "application/mspowerpoint" },
211 { "ppz", 3, "application/mspowerpoint" },
212 { "pre", 3, "application/x-freelance" },
213 { "prt", 3, "application/pro_eng" },
214 { "ps", 2, "application/postscript" },
215 { "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
280 { "xbm", 3, "image/x-xbitmap" },
281 { "xlc", 3, "application/vnd.ms-excel" },
282 { "xll", 3, "application/vnd.ms-excel" },
283 { "xlm", 3, "application/vnd.ms-excel" },
284 { "xls", 3, "application/vnd.ms-excel" },
285 { "xlsx", 4, "application/vnd.ms-excel" },
286 { "xlw", 3, "application/vnd.ms-excel" },
287 { "xml", 3, "text/xml" },
288 { "xpm", 3, "image/x-xpixmap" },
289 { "xwd", 3, "image/x-xwindowdump" },
290 { "xyz", 3, "chemical/x-pdb" },
291
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122 { "deb", 3, "application/x-debian-package" },
123 { "dir", 3, "application/x-director" },
124 { "dl", 2, "video/dl" },
125 { "dms", 3, "application/octet-stream" },
126 { "doc", 3, "application/msword" },
127 { "docx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
128 { "dot", 3, "application/msword" },
129 { "dotx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
130 { "drw", 3, "application/drafting" },
131 { "dvi", 3, "application/x-dvi" },
132 { "dwg", 3, "application/acad" },
133 { "dxf", 3, "application/dxf" },
134 { "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
204 { "pl", 2, "application/x-perl" },
205 { "pm", 2, "application/x-perl" },
206 { "png", 3, "image/png" },
207 { "pnm", 3, "image/x-portable-anymap" },
208 { "pot", 3, "application/mspowerpoint" },
209 { "potx", 4, "application/vnd.openxmlformats-officedocument.presentationml.template"},
210 { "ppm", 3, "image/x-portable-pixmap" },
211 { "pps", 3, "application/mspowerpoint" },
212 { "ppsx", 4, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
213 { "ppt", 3, "application/mspowerpoint" },
214 { "pptx", 4, "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
215 { "ppz", 3, "application/mspowerpoint" },
216 { "pre", 3, "application/x-freelance" },
217 { "prt", 3, "application/pro_eng" },
218 { "ps", 2, "application/postscript" },
219 { "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
284 { "xbm", 3, "image/x-xbitmap" },
285 { "xlc", 3, "application/vnd.ms-excel" },
286 { "xll", 3, "application/vnd.ms-excel" },
287 { "xlm", 3, "application/vnd.ms-excel" },
288 { "xls", 3, "application/vnd.ms-excel" },
289 { "xlsx", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
290 { "xlw", 3, "application/vnd.ms-excel" },
291 { "xml", 3, "text/xml" },
292 { "xpm", 3, "image/x-xpixmap" },
293 { "xwd", 3, "image/x-xwindowdump" },
294 { "xyz", 3, "chemical/x-pdb" },
295
+7 -3
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122122
{ "deb", 3, "application/x-debian-package" },
123123
{ "dir", 3, "application/x-director" },
124124
{ "dl", 2, "video/dl" },
125125
{ "dms", 3, "application/octet-stream" },
126126
{ "doc", 3, "application/msword" },
127
- { "docx", 4, "application/msword" },
127
+ { "docx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
128
+ { "dot", 3, "application/msword" },
129
+ { "dotx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
128130
{ "drw", 3, "application/drafting" },
129131
{ "dvi", 3, "application/x-dvi" },
130132
{ "dwg", 3, "application/acad" },
131133
{ "dxf", 3, "application/dxf" },
132134
{ "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
202204
{ "pl", 2, "application/x-perl" },
203205
{ "pm", 2, "application/x-perl" },
204206
{ "png", 3, "image/png" },
205207
{ "pnm", 3, "image/x-portable-anymap" },
206208
{ "pot", 3, "application/mspowerpoint" },
209
+ { "potx", 4, "application/vnd.openxmlformats-officedocument.presentationml.template"},
207210
{ "ppm", 3, "image/x-portable-pixmap" },
208211
{ "pps", 3, "application/mspowerpoint" },
212
+ { "ppsx", 4, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
209213
{ "ppt", 3, "application/mspowerpoint" },
210
- { "pptx", 4, "application/mspowerpoint" },
214
+ { "pptx", 4, "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
211215
{ "ppz", 3, "application/mspowerpoint" },
212216
{ "pre", 3, "application/x-freelance" },
213217
{ "prt", 3, "application/pro_eng" },
214218
{ "ps", 2, "application/postscript" },
215219
{ "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
280284
{ "xbm", 3, "image/x-xbitmap" },
281285
{ "xlc", 3, "application/vnd.ms-excel" },
282286
{ "xll", 3, "application/vnd.ms-excel" },
283287
{ "xlm", 3, "application/vnd.ms-excel" },
284288
{ "xls", 3, "application/vnd.ms-excel" },
285
- { "xlsx", 4, "application/vnd.ms-excel" },
289
+ { "xlsx", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
286290
{ "xlw", 3, "application/vnd.ms-excel" },
287291
{ "xml", 3, "text/xml" },
288292
{ "xpm", 3, "image/x-xpixmap" },
289293
{ "xwd", 3, "image/x-xwindowdump" },
290294
{ "xyz", 3, "chemical/x-pdb" },
291295
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122 { "deb", 3, "application/x-debian-package" },
123 { "dir", 3, "application/x-director" },
124 { "dl", 2, "video/dl" },
125 { "dms", 3, "application/octet-stream" },
126 { "doc", 3, "application/msword" },
127 { "docx", 4, "application/msword" },
 
 
128 { "drw", 3, "application/drafting" },
129 { "dvi", 3, "application/x-dvi" },
130 { "dwg", 3, "application/acad" },
131 { "dxf", 3, "application/dxf" },
132 { "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
202 { "pl", 2, "application/x-perl" },
203 { "pm", 2, "application/x-perl" },
204 { "png", 3, "image/png" },
205 { "pnm", 3, "image/x-portable-anymap" },
206 { "pot", 3, "application/mspowerpoint" },
 
207 { "ppm", 3, "image/x-portable-pixmap" },
208 { "pps", 3, "application/mspowerpoint" },
 
209 { "ppt", 3, "application/mspowerpoint" },
210 { "pptx", 4, "application/mspowerpoint" },
211 { "ppz", 3, "application/mspowerpoint" },
212 { "pre", 3, "application/x-freelance" },
213 { "prt", 3, "application/pro_eng" },
214 { "ps", 2, "application/postscript" },
215 { "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
280 { "xbm", 3, "image/x-xbitmap" },
281 { "xlc", 3, "application/vnd.ms-excel" },
282 { "xll", 3, "application/vnd.ms-excel" },
283 { "xlm", 3, "application/vnd.ms-excel" },
284 { "xls", 3, "application/vnd.ms-excel" },
285 { "xlsx", 4, "application/vnd.ms-excel" },
286 { "xlw", 3, "application/vnd.ms-excel" },
287 { "xml", 3, "text/xml" },
288 { "xpm", 3, "image/x-xpixmap" },
289 { "xwd", 3, "image/x-xwindowdump" },
290 { "xyz", 3, "chemical/x-pdb" },
291
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122 { "deb", 3, "application/x-debian-package" },
123 { "dir", 3, "application/x-director" },
124 { "dl", 2, "video/dl" },
125 { "dms", 3, "application/octet-stream" },
126 { "doc", 3, "application/msword" },
127 { "docx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
128 { "dot", 3, "application/msword" },
129 { "dotx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
130 { "drw", 3, "application/drafting" },
131 { "dvi", 3, "application/x-dvi" },
132 { "dwg", 3, "application/acad" },
133 { "dxf", 3, "application/dxf" },
134 { "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
204 { "pl", 2, "application/x-perl" },
205 { "pm", 2, "application/x-perl" },
206 { "png", 3, "image/png" },
207 { "pnm", 3, "image/x-portable-anymap" },
208 { "pot", 3, "application/mspowerpoint" },
209 { "potx", 4, "application/vnd.openxmlformats-officedocument.presentationml.template"},
210 { "ppm", 3, "image/x-portable-pixmap" },
211 { "pps", 3, "application/mspowerpoint" },
212 { "ppsx", 4, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
213 { "ppt", 3, "application/mspowerpoint" },
214 { "pptx", 4, "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
215 { "ppz", 3, "application/mspowerpoint" },
216 { "pre", 3, "application/x-freelance" },
217 { "prt", 3, "application/pro_eng" },
218 { "ps", 2, "application/postscript" },
219 { "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
284 { "xbm", 3, "image/x-xbitmap" },
285 { "xlc", 3, "application/vnd.ms-excel" },
286 { "xll", 3, "application/vnd.ms-excel" },
287 { "xlm", 3, "application/vnd.ms-excel" },
288 { "xls", 3, "application/vnd.ms-excel" },
289 { "xlsx", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
290 { "xlw", 3, "application/vnd.ms-excel" },
291 { "xml", 3, "text/xml" },
292 { "xpm", 3, "image/x-xpixmap" },
293 { "xwd", 3, "image/x-xwindowdump" },
294 { "xyz", 3, "chemical/x-pdb" },
295
+7 -3
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122122
{ "deb", 3, "application/x-debian-package" },
123123
{ "dir", 3, "application/x-director" },
124124
{ "dl", 2, "video/dl" },
125125
{ "dms", 3, "application/octet-stream" },
126126
{ "doc", 3, "application/msword" },
127
- { "docx", 4, "application/msword" },
127
+ { "docx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
128
+ { "dot", 3, "application/msword" },
129
+ { "dotx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
128130
{ "drw", 3, "application/drafting" },
129131
{ "dvi", 3, "application/x-dvi" },
130132
{ "dwg", 3, "application/acad" },
131133
{ "dxf", 3, "application/dxf" },
132134
{ "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
202204
{ "pl", 2, "application/x-perl" },
203205
{ "pm", 2, "application/x-perl" },
204206
{ "png", 3, "image/png" },
205207
{ "pnm", 3, "image/x-portable-anymap" },
206208
{ "pot", 3, "application/mspowerpoint" },
209
+ { "potx", 4, "application/vnd.openxmlformats-officedocument.presentationml.template"},
207210
{ "ppm", 3, "image/x-portable-pixmap" },
208211
{ "pps", 3, "application/mspowerpoint" },
212
+ { "ppsx", 4, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
209213
{ "ppt", 3, "application/mspowerpoint" },
210
- { "pptx", 4, "application/mspowerpoint" },
214
+ { "pptx", 4, "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
211215
{ "ppz", 3, "application/mspowerpoint" },
212216
{ "pre", 3, "application/x-freelance" },
213217
{ "prt", 3, "application/pro_eng" },
214218
{ "ps", 2, "application/postscript" },
215219
{ "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
280284
{ "xbm", 3, "image/x-xbitmap" },
281285
{ "xlc", 3, "application/vnd.ms-excel" },
282286
{ "xll", 3, "application/vnd.ms-excel" },
283287
{ "xlm", 3, "application/vnd.ms-excel" },
284288
{ "xls", 3, "application/vnd.ms-excel" },
285
- { "xlsx", 4, "application/vnd.ms-excel" },
289
+ { "xlsx", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
286290
{ "xlw", 3, "application/vnd.ms-excel" },
287291
{ "xml", 3, "text/xml" },
288292
{ "xpm", 3, "image/x-xpixmap" },
289293
{ "xwd", 3, "image/x-xwindowdump" },
290294
{ "xyz", 3, "chemical/x-pdb" },
291295
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122 { "deb", 3, "application/x-debian-package" },
123 { "dir", 3, "application/x-director" },
124 { "dl", 2, "video/dl" },
125 { "dms", 3, "application/octet-stream" },
126 { "doc", 3, "application/msword" },
127 { "docx", 4, "application/msword" },
 
 
128 { "drw", 3, "application/drafting" },
129 { "dvi", 3, "application/x-dvi" },
130 { "dwg", 3, "application/acad" },
131 { "dxf", 3, "application/dxf" },
132 { "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
202 { "pl", 2, "application/x-perl" },
203 { "pm", 2, "application/x-perl" },
204 { "png", 3, "image/png" },
205 { "pnm", 3, "image/x-portable-anymap" },
206 { "pot", 3, "application/mspowerpoint" },
 
207 { "ppm", 3, "image/x-portable-pixmap" },
208 { "pps", 3, "application/mspowerpoint" },
 
209 { "ppt", 3, "application/mspowerpoint" },
210 { "pptx", 4, "application/mspowerpoint" },
211 { "ppz", 3, "application/mspowerpoint" },
212 { "pre", 3, "application/x-freelance" },
213 { "prt", 3, "application/pro_eng" },
214 { "ps", 2, "application/postscript" },
215 { "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
280 { "xbm", 3, "image/x-xbitmap" },
281 { "xlc", 3, "application/vnd.ms-excel" },
282 { "xll", 3, "application/vnd.ms-excel" },
283 { "xlm", 3, "application/vnd.ms-excel" },
284 { "xls", 3, "application/vnd.ms-excel" },
285 { "xlsx", 4, "application/vnd.ms-excel" },
286 { "xlw", 3, "application/vnd.ms-excel" },
287 { "xml", 3, "text/xml" },
288 { "xpm", 3, "image/x-xpixmap" },
289 { "xwd", 3, "image/x-xwindowdump" },
290 { "xyz", 3, "chemical/x-pdb" },
291
--- src/doc.c
+++ src/doc.c
@@ -122,11 +122,13 @@
122 { "deb", 3, "application/x-debian-package" },
123 { "dir", 3, "application/x-director" },
124 { "dl", 2, "video/dl" },
125 { "dms", 3, "application/octet-stream" },
126 { "doc", 3, "application/msword" },
127 { "docx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
128 { "dot", 3, "application/msword" },
129 { "dotx", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
130 { "drw", 3, "application/drafting" },
131 { "dvi", 3, "application/x-dvi" },
132 { "dwg", 3, "application/acad" },
133 { "dxf", 3, "application/dxf" },
134 { "dxr", 3, "application/x-director" },
@@ -202,14 +204,16 @@
204 { "pl", 2, "application/x-perl" },
205 { "pm", 2, "application/x-perl" },
206 { "png", 3, "image/png" },
207 { "pnm", 3, "image/x-portable-anymap" },
208 { "pot", 3, "application/mspowerpoint" },
209 { "potx", 4, "application/vnd.openxmlformats-officedocument.presentationml.template"},
210 { "ppm", 3, "image/x-portable-pixmap" },
211 { "pps", 3, "application/mspowerpoint" },
212 { "ppsx", 4, "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
213 { "ppt", 3, "application/mspowerpoint" },
214 { "pptx", 4, "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
215 { "ppz", 3, "application/mspowerpoint" },
216 { "pre", 3, "application/x-freelance" },
217 { "prt", 3, "application/pro_eng" },
218 { "ps", 2, "application/postscript" },
219 { "qt", 2, "video/quicktime" },
@@ -280,11 +284,11 @@
284 { "xbm", 3, "image/x-xbitmap" },
285 { "xlc", 3, "application/vnd.ms-excel" },
286 { "xll", 3, "application/vnd.ms-excel" },
287 { "xlm", 3, "application/vnd.ms-excel" },
288 { "xls", 3, "application/vnd.ms-excel" },
289 { "xlsx", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
290 { "xlw", 3, "application/vnd.ms-excel" },
291 { "xml", 3, "text/xml" },
292 { "xpm", 3, "image/x-xpixmap" },
293 { "xwd", 3, "image/x-xwindowdump" },
294 { "xyz", 3, "chemical/x-pdb" },
295
+2 -3
--- src/encode.c
+++ src/encode.c
@@ -131,18 +131,17 @@
131131
static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
132132
int c;
133133
int i = 0;
134134
int count = 0;
135135
char *zOut;
136
- int other;
137136
# define IsSafeChar(X) \
138137
(fossil_isalnum(X) || (X)=='.' || (X)=='$' \
139
- || (X)=='~' || (X)=='-' || (X)=='_' || (X)==other)
138
+ || (X)=='~' || (X)=='-' || (X)=='_' \
139
+ || (!encodeSlash && ((X)=='/' || (X)==':')))
140140
141141
if( zIn==0 ) return 0;
142142
if( n<0 ) n = strlen(zIn);
143
- other = encodeSlash ? 'a' : '/';
144143
while( i<n && (c = zIn[i])!=0 ){
145144
if( IsSafeChar(c) || c==' ' ){
146145
count++;
147146
}else{
148147
count += 3;
149148
--- src/encode.c
+++ src/encode.c
@@ -131,18 +131,17 @@
131 static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
132 int c;
133 int i = 0;
134 int count = 0;
135 char *zOut;
136 int other;
137 # define IsSafeChar(X) \
138 (fossil_isalnum(X) || (X)=='.' || (X)=='$' \
139 || (X)=='~' || (X)=='-' || (X)=='_' || (X)==other)
 
140
141 if( zIn==0 ) return 0;
142 if( n<0 ) n = strlen(zIn);
143 other = encodeSlash ? 'a' : '/';
144 while( i<n && (c = zIn[i])!=0 ){
145 if( IsSafeChar(c) || c==' ' ){
146 count++;
147 }else{
148 count += 3;
149
--- src/encode.c
+++ src/encode.c
@@ -131,18 +131,17 @@
131 static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
132 int c;
133 int i = 0;
134 int count = 0;
135 char *zOut;
 
136 # define IsSafeChar(X) \
137 (fossil_isalnum(X) || (X)=='.' || (X)=='$' \
138 || (X)=='~' || (X)=='-' || (X)=='_' \
139 || (!encodeSlash && ((X)=='/' || (X)==':')))
140
141 if( zIn==0 ) return 0;
142 if( n<0 ) n = strlen(zIn);
 
143 while( i<n && (c = zIn[i])!=0 ){
144 if( IsSafeChar(c) || c==' ' ){
145 count++;
146 }else{
147 count += 3;
148
+2 -3
--- src/encode.c
+++ src/encode.c
@@ -131,18 +131,17 @@
131131
static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
132132
int c;
133133
int i = 0;
134134
int count = 0;
135135
char *zOut;
136
- int other;
137136
# define IsSafeChar(X) \
138137
(fossil_isalnum(X) || (X)=='.' || (X)=='$' \
139
- || (X)=='~' || (X)=='-' || (X)=='_' || (X)==other)
138
+ || (X)=='~' || (X)=='-' || (X)=='_' \
139
+ || (!encodeSlash && ((X)=='/' || (X)==':')))
140140
141141
if( zIn==0 ) return 0;
142142
if( n<0 ) n = strlen(zIn);
143
- other = encodeSlash ? 'a' : '/';
144143
while( i<n && (c = zIn[i])!=0 ){
145144
if( IsSafeChar(c) || c==' ' ){
146145
count++;
147146
}else{
148147
count += 3;
149148
--- src/encode.c
+++ src/encode.c
@@ -131,18 +131,17 @@
131 static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
132 int c;
133 int i = 0;
134 int count = 0;
135 char *zOut;
136 int other;
137 # define IsSafeChar(X) \
138 (fossil_isalnum(X) || (X)=='.' || (X)=='$' \
139 || (X)=='~' || (X)=='-' || (X)=='_' || (X)==other)
 
140
141 if( zIn==0 ) return 0;
142 if( n<0 ) n = strlen(zIn);
143 other = encodeSlash ? 'a' : '/';
144 while( i<n && (c = zIn[i])!=0 ){
145 if( IsSafeChar(c) || c==' ' ){
146 count++;
147 }else{
148 count += 3;
149
--- src/encode.c
+++ src/encode.c
@@ -131,18 +131,17 @@
131 static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
132 int c;
133 int i = 0;
134 int count = 0;
135 char *zOut;
 
136 # define IsSafeChar(X) \
137 (fossil_isalnum(X) || (X)=='.' || (X)=='$' \
138 || (X)=='~' || (X)=='-' || (X)=='_' \
139 || (!encodeSlash && ((X)=='/' || (X)==':')))
140
141 if( zIn==0 ) return 0;
142 if( n<0 ) n = strlen(zIn);
 
143 while( i<n && (c = zIn[i])!=0 ){
144 if( IsSafeChar(c) || c==' ' ){
145 count++;
146 }else{
147 count += 3;
148
+52 -34
--- src/file.c
+++ src/file.c
@@ -490,50 +490,68 @@
490490
** * Does not contain two or more "/" characters in a row.
491491
** * Contains at least one character
492492
**
493493
** Invalid UTF8 characters result in a false return if bStrictUtf8 is
494494
** true. If bStrictUtf8 is false, invalid UTF8 characters are silently
495
-** ignored.
495
+** ignored. See http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
496
+** and http://en.wikipedia.org/wiki/Unicode (for the noncharacters)
497
+**
498
+** The bStrictUtf8 flag is true for new inputs, but is false when parsing
499
+** legacy manifests, for backwards compatibility.
496500
*/
497501
int file_is_simple_pathname(const char *z, int bStrictUtf8){
498502
int i;
499
- char c = z[0];
503
+ unsigned char c = (unsigned char) z[0];
500504
char maskNonAscii = bStrictUtf8 ? 0x80 : 0x00;
501505
if( c=='/' || c==0 ) return 0;
502506
if( c=='.' ){
503507
if( z[1]=='/' || z[1]==0 ) return 0;
504508
if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
505509
}
506
- for(i=0; (c=z[i])!=0; i++){
507
- if( c & maskNonAscii ){
508
- if( (c & 0xf0) == 0xf0 ) {
509
- /* Unicode characters > U+FFFF are not supported.
510
- * Windows XP and earlier cannot handle them.
511
- */
512
- return 0;
513
- }
514
- if( (c & 0xf0) == 0xe0 ) {
515
- /* This is a 3-byte UTF-8 character */
516
- if ( (c & 0xfe) == 0xee ){
517
- /* Range U+E000 - U+FFFF (Starting with 0xee or 0xef in UTF-8 ) */
518
- if ( (c & 1) && ((z[i+1] & 0xff) >= 0xa4) ){
519
- /* But exclude U+F900 - U+FFFF (0xef followed by byte >= 0xa4),
520
- * which contain valid characters. */
521
- continue;
522
- }
523
- /* Unicode character in the range U+E000 - U+F8FF are for
524
- * private use, they shouldn't occur in filenames. */
525
- return 0;
526
- }
527
- if( ((c & 0xff) == 0xed) && ((z[i+1] & 0xe0) == 0xa0) ){
528
- /* Unicode character in the range U+D800 - U+DFFF are for
529
- * surrogate pairs, they shouldn't occur in filenames. */
530
- return 0;
531
- }
532
- }
533
- }
534
- if( c=='\\' ){
510
+ for(i=0; (c=(unsigned char)z[i])!=0; i++){
511
+ if( c & maskNonAscii ){
512
+ if( (z[++i]&0xc0)!=0x80 ){
513
+ /* Invalid first continuation byte */
514
+ return 0;
515
+ }
516
+ if( c<0xc2 ){
517
+ /* Invalid 1-byte UTF-8 sequence, or 2-byte overlong form. */
518
+ return 0;
519
+ }else if( (c&0xe0)==0xe0 ){
520
+ /* 3-byte or more */
521
+ int unicode;
522
+ if( c&0x10 ){
523
+ /* Unicode characters > U+FFFF are not supported.
524
+ * Windows XP and earlier cannot handle them.
525
+ */
526
+ return 0;
527
+ }
528
+ /* This is a 3-byte UTF-8 character */
529
+ unicode = ((c&0x0f)<<12) + ((z[i]&0x3f)<<6) + (z[i+1]&0x3f);
530
+ if( unicode <= 0x07ff ){
531
+ /* overlong form */
532
+ return 0;
533
+ }else if( unicode>=0xe000 ){
534
+ /* U+E000..U+FFFF */
535
+ if( (unicode<=0xf8ff) || (unicode>=0xfffe) ){
536
+ /* U+E000..U+F8FF are for private use.
537
+ * U+FFFE..U+FFFF are noncharacters. */
538
+ return 0;
539
+ } else if( (unicode>=0xfdd0) && (unicode<=0xfdef) ){
540
+ /* U+FDD0..U+FDEF are noncharacters. */
541
+ return 0;
542
+ }
543
+ }else if( (unicode>=0xd800) && (unicode<=0xdfff) ){
544
+ /* U+D800..U+DFFF are for surrogate pairs. */
545
+ return 0;
546
+ }
547
+ if( (z[++i]&0xc0)!=0x80 ){
548
+ /* Invalid second continuation byte */
549
+ return 0;
550
+ }
551
+ }
552
+ }else if( bStrictUtf8 && (c=='\\') ){
535553
return 0;
536554
}
537555
if( c=='/' ){
538556
if( z[i+1]=='/' ) return 0;
539557
if( z[i+1]=='.' ){
@@ -583,11 +601,11 @@
583601
if( z[i]=='\\' ) z[i] = '/';
584602
}
585603
#endif
586604
587605
/* Removing trailing "/" characters */
588
- if ( !slash ){
606
+ if( !slash ){
589607
while( n>1 && z[n-1]=='/' ){ n--; }
590608
}
591609
592610
/* Remove duplicate '/' characters. Except, two // at the beginning
593611
** of a pathname is allowed since this is important on windows. */
@@ -840,11 +858,11 @@
840858
if( zPwd[i]==0 ){
841859
blob_append(pOut, ".", 1);
842860
}else{
843861
blob_append(pOut, "..", 2);
844862
for(j=i+1; zPwd[j]; j++){
845
- if( zPwd[j]=='/' ) {
863
+ if( zPwd[j]=='/' ){
846864
blob_append(pOut, "/..", 3);
847865
}
848866
}
849867
}
850868
return;
@@ -857,11 +875,11 @@
857875
return;
858876
}
859877
while( zPath[i-1]!='/' ){ i--; }
860878
blob_set(&tmp, "../");
861879
for(j=i; zPwd[j]; j++){
862
- if( zPwd[j]=='/' ) {
880
+ if( zPwd[j]=='/' ){
863881
blob_append(&tmp, "../", 3);
864882
}
865883
}
866884
blob_append(&tmp, &zPath[i], -1);
867885
blob_reset(pOut);
868886
--- src/file.c
+++ src/file.c
@@ -490,50 +490,68 @@
490 ** * Does not contain two or more "/" characters in a row.
491 ** * Contains at least one character
492 **
493 ** Invalid UTF8 characters result in a false return if bStrictUtf8 is
494 ** true. If bStrictUtf8 is false, invalid UTF8 characters are silently
495 ** ignored.
 
 
 
 
496 */
497 int file_is_simple_pathname(const char *z, int bStrictUtf8){
498 int i;
499 char c = z[0];
500 char maskNonAscii = bStrictUtf8 ? 0x80 : 0x00;
501 if( c=='/' || c==0 ) return 0;
502 if( c=='.' ){
503 if( z[1]=='/' || z[1]==0 ) return 0;
504 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
505 }
506 for(i=0; (c=z[i])!=0; i++){
507 if( c & maskNonAscii ){
508 if( (c & 0xf0) == 0xf0 ) {
509 /* Unicode characters > U+FFFF are not supported.
510 * Windows XP and earlier cannot handle them.
511 */
512 return 0;
513 }
514 if( (c & 0xf0) == 0xe0 ) {
515 /* This is a 3-byte UTF-8 character */
516 if ( (c & 0xfe) == 0xee ){
517 /* Range U+E000 - U+FFFF (Starting with 0xee or 0xef in UTF-8 ) */
518 if ( (c & 1) && ((z[i+1] & 0xff) >= 0xa4) ){
519 /* But exclude U+F900 - U+FFFF (0xef followed by byte >= 0xa4),
520 * which contain valid characters. */
521 continue;
522 }
523 /* Unicode character in the range U+E000 - U+F8FF are for
524 * private use, they shouldn't occur in filenames. */
525 return 0;
526 }
527 if( ((c & 0xff) == 0xed) && ((z[i+1] & 0xe0) == 0xa0) ){
528 /* Unicode character in the range U+D800 - U+DFFF are for
529 * surrogate pairs, they shouldn't occur in filenames. */
530 return 0;
531 }
532 }
533 }
534 if( c=='\\' ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535 return 0;
536 }
537 if( c=='/' ){
538 if( z[i+1]=='/' ) return 0;
539 if( z[i+1]=='.' ){
@@ -583,11 +601,11 @@
583 if( z[i]=='\\' ) z[i] = '/';
584 }
585 #endif
586
587 /* Removing trailing "/" characters */
588 if ( !slash ){
589 while( n>1 && z[n-1]=='/' ){ n--; }
590 }
591
592 /* Remove duplicate '/' characters. Except, two // at the beginning
593 ** of a pathname is allowed since this is important on windows. */
@@ -840,11 +858,11 @@
840 if( zPwd[i]==0 ){
841 blob_append(pOut, ".", 1);
842 }else{
843 blob_append(pOut, "..", 2);
844 for(j=i+1; zPwd[j]; j++){
845 if( zPwd[j]=='/' ) {
846 blob_append(pOut, "/..", 3);
847 }
848 }
849 }
850 return;
@@ -857,11 +875,11 @@
857 return;
858 }
859 while( zPath[i-1]!='/' ){ i--; }
860 blob_set(&tmp, "../");
861 for(j=i; zPwd[j]; j++){
862 if( zPwd[j]=='/' ) {
863 blob_append(&tmp, "../", 3);
864 }
865 }
866 blob_append(&tmp, &zPath[i], -1);
867 blob_reset(pOut);
868
--- src/file.c
+++ src/file.c
@@ -490,50 +490,68 @@
490 ** * Does not contain two or more "/" characters in a row.
491 ** * Contains at least one character
492 **
493 ** Invalid UTF8 characters result in a false return if bStrictUtf8 is
494 ** true. If bStrictUtf8 is false, invalid UTF8 characters are silently
495 ** ignored. See http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
496 ** and http://en.wikipedia.org/wiki/Unicode (for the noncharacters)
497 **
498 ** The bStrictUtf8 flag is true for new inputs, but is false when parsing
499 ** legacy manifests, for backwards compatibility.
500 */
501 int file_is_simple_pathname(const char *z, int bStrictUtf8){
502 int i;
503 unsigned char c = (unsigned char) z[0];
504 char maskNonAscii = bStrictUtf8 ? 0x80 : 0x00;
505 if( c=='/' || c==0 ) return 0;
506 if( c=='.' ){
507 if( z[1]=='/' || z[1]==0 ) return 0;
508 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
509 }
510 for(i=0; (c=(unsigned char)z[i])!=0; i++){
511 if( c & maskNonAscii ){
512 if( (z[++i]&0xc0)!=0x80 ){
513 /* Invalid first continuation byte */
514 return 0;
515 }
516 if( c<0xc2 ){
517 /* Invalid 1-byte UTF-8 sequence, or 2-byte overlong form. */
518 return 0;
519 }else if( (c&0xe0)==0xe0 ){
520 /* 3-byte or more */
521 int unicode;
522 if( c&0x10 ){
523 /* Unicode characters > U+FFFF are not supported.
524 * Windows XP and earlier cannot handle them.
525 */
526 return 0;
527 }
528 /* This is a 3-byte UTF-8 character */
529 unicode = ((c&0x0f)<<12) + ((z[i]&0x3f)<<6) + (z[i+1]&0x3f);
530 if( unicode <= 0x07ff ){
531 /* overlong form */
532 return 0;
533 }else if( unicode>=0xe000 ){
534 /* U+E000..U+FFFF */
535 if( (unicode<=0xf8ff) || (unicode>=0xfffe) ){
536 /* U+E000..U+F8FF are for private use.
537 * U+FFFE..U+FFFF are noncharacters. */
538 return 0;
539 } else if( (unicode>=0xfdd0) && (unicode<=0xfdef) ){
540 /* U+FDD0..U+FDEF are noncharacters. */
541 return 0;
542 }
543 }else if( (unicode>=0xd800) && (unicode<=0xdfff) ){
544 /* U+D800..U+DFFF are for surrogate pairs. */
545 return 0;
546 }
547 if( (z[++i]&0xc0)!=0x80 ){
548 /* Invalid second continuation byte */
549 return 0;
550 }
551 }
552 }else if( bStrictUtf8 && (c=='\\') ){
553 return 0;
554 }
555 if( c=='/' ){
556 if( z[i+1]=='/' ) return 0;
557 if( z[i+1]=='.' ){
@@ -583,11 +601,11 @@
601 if( z[i]=='\\' ) z[i] = '/';
602 }
603 #endif
604
605 /* Removing trailing "/" characters */
606 if( !slash ){
607 while( n>1 && z[n-1]=='/' ){ n--; }
608 }
609
610 /* Remove duplicate '/' characters. Except, two // at the beginning
611 ** of a pathname is allowed since this is important on windows. */
@@ -840,11 +858,11 @@
858 if( zPwd[i]==0 ){
859 blob_append(pOut, ".", 1);
860 }else{
861 blob_append(pOut, "..", 2);
862 for(j=i+1; zPwd[j]; j++){
863 if( zPwd[j]=='/' ){
864 blob_append(pOut, "/..", 3);
865 }
866 }
867 }
868 return;
@@ -857,11 +875,11 @@
875 return;
876 }
877 while( zPath[i-1]!='/' ){ i--; }
878 blob_set(&tmp, "../");
879 for(j=i; zPwd[j]; j++){
880 if( zPwd[j]=='/' ){
881 blob_append(&tmp, "../", 3);
882 }
883 }
884 blob_append(&tmp, &zPath[i], -1);
885 blob_reset(pOut);
886
+52 -34
--- src/file.c
+++ src/file.c
@@ -490,50 +490,68 @@
490490
** * Does not contain two or more "/" characters in a row.
491491
** * Contains at least one character
492492
**
493493
** Invalid UTF8 characters result in a false return if bStrictUtf8 is
494494
** true. If bStrictUtf8 is false, invalid UTF8 characters are silently
495
-** ignored.
495
+** ignored. See http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
496
+** and http://en.wikipedia.org/wiki/Unicode (for the noncharacters)
497
+**
498
+** The bStrictUtf8 flag is true for new inputs, but is false when parsing
499
+** legacy manifests, for backwards compatibility.
496500
*/
497501
int file_is_simple_pathname(const char *z, int bStrictUtf8){
498502
int i;
499
- char c = z[0];
503
+ unsigned char c = (unsigned char) z[0];
500504
char maskNonAscii = bStrictUtf8 ? 0x80 : 0x00;
501505
if( c=='/' || c==0 ) return 0;
502506
if( c=='.' ){
503507
if( z[1]=='/' || z[1]==0 ) return 0;
504508
if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
505509
}
506
- for(i=0; (c=z[i])!=0; i++){
507
- if( c & maskNonAscii ){
508
- if( (c & 0xf0) == 0xf0 ) {
509
- /* Unicode characters > U+FFFF are not supported.
510
- * Windows XP and earlier cannot handle them.
511
- */
512
- return 0;
513
- }
514
- if( (c & 0xf0) == 0xe0 ) {
515
- /* This is a 3-byte UTF-8 character */
516
- if ( (c & 0xfe) == 0xee ){
517
- /* Range U+E000 - U+FFFF (Starting with 0xee or 0xef in UTF-8 ) */
518
- if ( (c & 1) && ((z[i+1] & 0xff) >= 0xa4) ){
519
- /* But exclude U+F900 - U+FFFF (0xef followed by byte >= 0xa4),
520
- * which contain valid characters. */
521
- continue;
522
- }
523
- /* Unicode character in the range U+E000 - U+F8FF are for
524
- * private use, they shouldn't occur in filenames. */
525
- return 0;
526
- }
527
- if( ((c & 0xff) == 0xed) && ((z[i+1] & 0xe0) == 0xa0) ){
528
- /* Unicode character in the range U+D800 - U+DFFF are for
529
- * surrogate pairs, they shouldn't occur in filenames. */
530
- return 0;
531
- }
532
- }
533
- }
534
- if( c=='\\' ){
510
+ for(i=0; (c=(unsigned char)z[i])!=0; i++){
511
+ if( c & maskNonAscii ){
512
+ if( (z[++i]&0xc0)!=0x80 ){
513
+ /* Invalid first continuation byte */
514
+ return 0;
515
+ }
516
+ if( c<0xc2 ){
517
+ /* Invalid 1-byte UTF-8 sequence, or 2-byte overlong form. */
518
+ return 0;
519
+ }else if( (c&0xe0)==0xe0 ){
520
+ /* 3-byte or more */
521
+ int unicode;
522
+ if( c&0x10 ){
523
+ /* Unicode characters > U+FFFF are not supported.
524
+ * Windows XP and earlier cannot handle them.
525
+ */
526
+ return 0;
527
+ }
528
+ /* This is a 3-byte UTF-8 character */
529
+ unicode = ((c&0x0f)<<12) + ((z[i]&0x3f)<<6) + (z[i+1]&0x3f);
530
+ if( unicode <= 0x07ff ){
531
+ /* overlong form */
532
+ return 0;
533
+ }else if( unicode>=0xe000 ){
534
+ /* U+E000..U+FFFF */
535
+ if( (unicode<=0xf8ff) || (unicode>=0xfffe) ){
536
+ /* U+E000..U+F8FF are for private use.
537
+ * U+FFFE..U+FFFF are noncharacters. */
538
+ return 0;
539
+ } else if( (unicode>=0xfdd0) && (unicode<=0xfdef) ){
540
+ /* U+FDD0..U+FDEF are noncharacters. */
541
+ return 0;
542
+ }
543
+ }else if( (unicode>=0xd800) && (unicode<=0xdfff) ){
544
+ /* U+D800..U+DFFF are for surrogate pairs. */
545
+ return 0;
546
+ }
547
+ if( (z[++i]&0xc0)!=0x80 ){
548
+ /* Invalid second continuation byte */
549
+ return 0;
550
+ }
551
+ }
552
+ }else if( bStrictUtf8 && (c=='\\') ){
535553
return 0;
536554
}
537555
if( c=='/' ){
538556
if( z[i+1]=='/' ) return 0;
539557
if( z[i+1]=='.' ){
@@ -583,11 +601,11 @@
583601
if( z[i]=='\\' ) z[i] = '/';
584602
}
585603
#endif
586604
587605
/* Removing trailing "/" characters */
588
- if ( !slash ){
606
+ if( !slash ){
589607
while( n>1 && z[n-1]=='/' ){ n--; }
590608
}
591609
592610
/* Remove duplicate '/' characters. Except, two // at the beginning
593611
** of a pathname is allowed since this is important on windows. */
@@ -840,11 +858,11 @@
840858
if( zPwd[i]==0 ){
841859
blob_append(pOut, ".", 1);
842860
}else{
843861
blob_append(pOut, "..", 2);
844862
for(j=i+1; zPwd[j]; j++){
845
- if( zPwd[j]=='/' ) {
863
+ if( zPwd[j]=='/' ){
846864
blob_append(pOut, "/..", 3);
847865
}
848866
}
849867
}
850868
return;
@@ -857,11 +875,11 @@
857875
return;
858876
}
859877
while( zPath[i-1]!='/' ){ i--; }
860878
blob_set(&tmp, "../");
861879
for(j=i; zPwd[j]; j++){
862
- if( zPwd[j]=='/' ) {
880
+ if( zPwd[j]=='/' ){
863881
blob_append(&tmp, "../", 3);
864882
}
865883
}
866884
blob_append(&tmp, &zPath[i], -1);
867885
blob_reset(pOut);
868886
--- src/file.c
+++ src/file.c
@@ -490,50 +490,68 @@
490 ** * Does not contain two or more "/" characters in a row.
491 ** * Contains at least one character
492 **
493 ** Invalid UTF8 characters result in a false return if bStrictUtf8 is
494 ** true. If bStrictUtf8 is false, invalid UTF8 characters are silently
495 ** ignored.
 
 
 
 
496 */
497 int file_is_simple_pathname(const char *z, int bStrictUtf8){
498 int i;
499 char c = z[0];
500 char maskNonAscii = bStrictUtf8 ? 0x80 : 0x00;
501 if( c=='/' || c==0 ) return 0;
502 if( c=='.' ){
503 if( z[1]=='/' || z[1]==0 ) return 0;
504 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
505 }
506 for(i=0; (c=z[i])!=0; i++){
507 if( c & maskNonAscii ){
508 if( (c & 0xf0) == 0xf0 ) {
509 /* Unicode characters > U+FFFF are not supported.
510 * Windows XP and earlier cannot handle them.
511 */
512 return 0;
513 }
514 if( (c & 0xf0) == 0xe0 ) {
515 /* This is a 3-byte UTF-8 character */
516 if ( (c & 0xfe) == 0xee ){
517 /* Range U+E000 - U+FFFF (Starting with 0xee or 0xef in UTF-8 ) */
518 if ( (c & 1) && ((z[i+1] & 0xff) >= 0xa4) ){
519 /* But exclude U+F900 - U+FFFF (0xef followed by byte >= 0xa4),
520 * which contain valid characters. */
521 continue;
522 }
523 /* Unicode character in the range U+E000 - U+F8FF are for
524 * private use, they shouldn't occur in filenames. */
525 return 0;
526 }
527 if( ((c & 0xff) == 0xed) && ((z[i+1] & 0xe0) == 0xa0) ){
528 /* Unicode character in the range U+D800 - U+DFFF are for
529 * surrogate pairs, they shouldn't occur in filenames. */
530 return 0;
531 }
532 }
533 }
534 if( c=='\\' ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535 return 0;
536 }
537 if( c=='/' ){
538 if( z[i+1]=='/' ) return 0;
539 if( z[i+1]=='.' ){
@@ -583,11 +601,11 @@
583 if( z[i]=='\\' ) z[i] = '/';
584 }
585 #endif
586
587 /* Removing trailing "/" characters */
588 if ( !slash ){
589 while( n>1 && z[n-1]=='/' ){ n--; }
590 }
591
592 /* Remove duplicate '/' characters. Except, two // at the beginning
593 ** of a pathname is allowed since this is important on windows. */
@@ -840,11 +858,11 @@
840 if( zPwd[i]==0 ){
841 blob_append(pOut, ".", 1);
842 }else{
843 blob_append(pOut, "..", 2);
844 for(j=i+1; zPwd[j]; j++){
845 if( zPwd[j]=='/' ) {
846 blob_append(pOut, "/..", 3);
847 }
848 }
849 }
850 return;
@@ -857,11 +875,11 @@
857 return;
858 }
859 while( zPath[i-1]!='/' ){ i--; }
860 blob_set(&tmp, "../");
861 for(j=i; zPwd[j]; j++){
862 if( zPwd[j]=='/' ) {
863 blob_append(&tmp, "../", 3);
864 }
865 }
866 blob_append(&tmp, &zPath[i], -1);
867 blob_reset(pOut);
868
--- src/file.c
+++ src/file.c
@@ -490,50 +490,68 @@
490 ** * Does not contain two or more "/" characters in a row.
491 ** * Contains at least one character
492 **
493 ** Invalid UTF8 characters result in a false return if bStrictUtf8 is
494 ** true. If bStrictUtf8 is false, invalid UTF8 characters are silently
495 ** ignored. See http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
496 ** and http://en.wikipedia.org/wiki/Unicode (for the noncharacters)
497 **
498 ** The bStrictUtf8 flag is true for new inputs, but is false when parsing
499 ** legacy manifests, for backwards compatibility.
500 */
501 int file_is_simple_pathname(const char *z, int bStrictUtf8){
502 int i;
503 unsigned char c = (unsigned char) z[0];
504 char maskNonAscii = bStrictUtf8 ? 0x80 : 0x00;
505 if( c=='/' || c==0 ) return 0;
506 if( c=='.' ){
507 if( z[1]=='/' || z[1]==0 ) return 0;
508 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
509 }
510 for(i=0; (c=(unsigned char)z[i])!=0; i++){
511 if( c & maskNonAscii ){
512 if( (z[++i]&0xc0)!=0x80 ){
513 /* Invalid first continuation byte */
514 return 0;
515 }
516 if( c<0xc2 ){
517 /* Invalid 1-byte UTF-8 sequence, or 2-byte overlong form. */
518 return 0;
519 }else if( (c&0xe0)==0xe0 ){
520 /* 3-byte or more */
521 int unicode;
522 if( c&0x10 ){
523 /* Unicode characters > U+FFFF are not supported.
524 * Windows XP and earlier cannot handle them.
525 */
526 return 0;
527 }
528 /* This is a 3-byte UTF-8 character */
529 unicode = ((c&0x0f)<<12) + ((z[i]&0x3f)<<6) + (z[i+1]&0x3f);
530 if( unicode <= 0x07ff ){
531 /* overlong form */
532 return 0;
533 }else if( unicode>=0xe000 ){
534 /* U+E000..U+FFFF */
535 if( (unicode<=0xf8ff) || (unicode>=0xfffe) ){
536 /* U+E000..U+F8FF are for private use.
537 * U+FFFE..U+FFFF are noncharacters. */
538 return 0;
539 } else if( (unicode>=0xfdd0) && (unicode<=0xfdef) ){
540 /* U+FDD0..U+FDEF are noncharacters. */
541 return 0;
542 }
543 }else if( (unicode>=0xd800) && (unicode<=0xdfff) ){
544 /* U+D800..U+DFFF are for surrogate pairs. */
545 return 0;
546 }
547 if( (z[++i]&0xc0)!=0x80 ){
548 /* Invalid second continuation byte */
549 return 0;
550 }
551 }
552 }else if( bStrictUtf8 && (c=='\\') ){
553 return 0;
554 }
555 if( c=='/' ){
556 if( z[i+1]=='/' ) return 0;
557 if( z[i+1]=='.' ){
@@ -583,11 +601,11 @@
601 if( z[i]=='\\' ) z[i] = '/';
602 }
603 #endif
604
605 /* Removing trailing "/" characters */
606 if( !slash ){
607 while( n>1 && z[n-1]=='/' ){ n--; }
608 }
609
610 /* Remove duplicate '/' characters. Except, two // at the beginning
611 ** of a pathname is allowed since this is important on windows. */
@@ -840,11 +858,11 @@
858 if( zPwd[i]==0 ){
859 blob_append(pOut, ".", 1);
860 }else{
861 blob_append(pOut, "..", 2);
862 for(j=i+1; zPwd[j]; j++){
863 if( zPwd[j]=='/' ){
864 blob_append(pOut, "/..", 3);
865 }
866 }
867 }
868 return;
@@ -857,11 +875,11 @@
875 return;
876 }
877 while( zPath[i-1]!='/' ){ i--; }
878 blob_set(&tmp, "../");
879 for(j=i; zPwd[j]; j++){
880 if( zPwd[j]=='/' ){
881 blob_append(&tmp, "../", 3);
882 }
883 }
884 blob_append(&tmp, &zPath[i], -1);
885 blob_reset(pOut);
886
+6 -2
--- src/http.c
+++ src/http.c
@@ -130,11 +130,11 @@
130130
**
131131
** The server address is contain in the "g" global structure. The
132132
** url_parse() routine should have been called prior to this routine
133133
** in order to fill this structure appropriately.
134134
*/
135
-int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
135
+int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
136136
Blob login; /* The login card */
137137
Blob payload; /* The complete payload including login card */
138138
Blob hdr; /* The HTTP request header */
139139
int closeConnection; /* True to close the connection when done */
140140
int iLength; /* Length of the reply payload */
@@ -231,10 +231,14 @@
231231
}else if( c=='k' || c=='K' ){
232232
closeConnection = 0;
233233
}
234234
}else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
235235
int i, j;
236
+
237
+ if ( --maxRedirect == 0){
238
+ fossil_fatal("redirect limit exceeded");
239
+ }
236240
for(i=9; zLine[i] && zLine[i]==' '; i++){}
237241
if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
238242
j = strlen(zLine) - 1;
239243
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
240244
j -= 4;
@@ -241,11 +245,11 @@
241245
zLine[j] = 0;
242246
}
243247
fossil_print("redirect to %s\n", &zLine[i]);
244248
url_parse(&zLine[i]);
245249
transport_close();
246
- return http_exchange(pSend, pReply, useLogin);
250
+ return http_exchange(pSend, pReply, useLogin, maxRedirect);
247251
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
248252
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
249253
isCompressed = 0;
250254
}else if( fossil_strnicmp(&zLine[14],
251255
"application/x-fossil-uncompressed", -1)==0 ){
252256
--- src/http.c
+++ src/http.c
@@ -130,11 +130,11 @@
130 **
131 ** The server address is contain in the "g" global structure. The
132 ** url_parse() routine should have been called prior to this routine
133 ** in order to fill this structure appropriately.
134 */
135 int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
136 Blob login; /* The login card */
137 Blob payload; /* The complete payload including login card */
138 Blob hdr; /* The HTTP request header */
139 int closeConnection; /* True to close the connection when done */
140 int iLength; /* Length of the reply payload */
@@ -231,10 +231,14 @@
231 }else if( c=='k' || c=='K' ){
232 closeConnection = 0;
233 }
234 }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
235 int i, j;
 
 
 
 
236 for(i=9; zLine[i] && zLine[i]==' '; i++){}
237 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
238 j = strlen(zLine) - 1;
239 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
240 j -= 4;
@@ -241,11 +245,11 @@
241 zLine[j] = 0;
242 }
243 fossil_print("redirect to %s\n", &zLine[i]);
244 url_parse(&zLine[i]);
245 transport_close();
246 return http_exchange(pSend, pReply, useLogin);
247 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
248 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
249 isCompressed = 0;
250 }else if( fossil_strnicmp(&zLine[14],
251 "application/x-fossil-uncompressed", -1)==0 ){
252
--- src/http.c
+++ src/http.c
@@ -130,11 +130,11 @@
130 **
131 ** The server address is contain in the "g" global structure. The
132 ** url_parse() routine should have been called prior to this routine
133 ** in order to fill this structure appropriately.
134 */
135 int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
136 Blob login; /* The login card */
137 Blob payload; /* The complete payload including login card */
138 Blob hdr; /* The HTTP request header */
139 int closeConnection; /* True to close the connection when done */
140 int iLength; /* Length of the reply payload */
@@ -231,10 +231,14 @@
231 }else if( c=='k' || c=='K' ){
232 closeConnection = 0;
233 }
234 }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
235 int i, j;
236
237 if ( --maxRedirect == 0){
238 fossil_fatal("redirect limit exceeded");
239 }
240 for(i=9; zLine[i] && zLine[i]==' '; i++){}
241 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
242 j = strlen(zLine) - 1;
243 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
244 j -= 4;
@@ -241,11 +245,11 @@
245 zLine[j] = 0;
246 }
247 fossil_print("redirect to %s\n", &zLine[i]);
248 url_parse(&zLine[i]);
249 transport_close();
250 return http_exchange(pSend, pReply, useLogin, maxRedirect);
251 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
252 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
253 isCompressed = 0;
254 }else if( fossil_strnicmp(&zLine[14],
255 "application/x-fossil-uncompressed", -1)==0 ){
256
+6 -2
--- src/http.c
+++ src/http.c
@@ -130,11 +130,11 @@
130130
**
131131
** The server address is contain in the "g" global structure. The
132132
** url_parse() routine should have been called prior to this routine
133133
** in order to fill this structure appropriately.
134134
*/
135
-int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
135
+int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
136136
Blob login; /* The login card */
137137
Blob payload; /* The complete payload including login card */
138138
Blob hdr; /* The HTTP request header */
139139
int closeConnection; /* True to close the connection when done */
140140
int iLength; /* Length of the reply payload */
@@ -231,10 +231,14 @@
231231
}else if( c=='k' || c=='K' ){
232232
closeConnection = 0;
233233
}
234234
}else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
235235
int i, j;
236
+
237
+ if ( --maxRedirect == 0){
238
+ fossil_fatal("redirect limit exceeded");
239
+ }
236240
for(i=9; zLine[i] && zLine[i]==' '; i++){}
237241
if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
238242
j = strlen(zLine) - 1;
239243
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
240244
j -= 4;
@@ -241,11 +245,11 @@
241245
zLine[j] = 0;
242246
}
243247
fossil_print("redirect to %s\n", &zLine[i]);
244248
url_parse(&zLine[i]);
245249
transport_close();
246
- return http_exchange(pSend, pReply, useLogin);
250
+ return http_exchange(pSend, pReply, useLogin, maxRedirect);
247251
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
248252
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
249253
isCompressed = 0;
250254
}else if( fossil_strnicmp(&zLine[14],
251255
"application/x-fossil-uncompressed", -1)==0 ){
252256
--- src/http.c
+++ src/http.c
@@ -130,11 +130,11 @@
130 **
131 ** The server address is contain in the "g" global structure. The
132 ** url_parse() routine should have been called prior to this routine
133 ** in order to fill this structure appropriately.
134 */
135 int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
136 Blob login; /* The login card */
137 Blob payload; /* The complete payload including login card */
138 Blob hdr; /* The HTTP request header */
139 int closeConnection; /* True to close the connection when done */
140 int iLength; /* Length of the reply payload */
@@ -231,10 +231,14 @@
231 }else if( c=='k' || c=='K' ){
232 closeConnection = 0;
233 }
234 }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
235 int i, j;
 
 
 
 
236 for(i=9; zLine[i] && zLine[i]==' '; i++){}
237 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
238 j = strlen(zLine) - 1;
239 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
240 j -= 4;
@@ -241,11 +245,11 @@
241 zLine[j] = 0;
242 }
243 fossil_print("redirect to %s\n", &zLine[i]);
244 url_parse(&zLine[i]);
245 transport_close();
246 return http_exchange(pSend, pReply, useLogin);
247 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
248 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
249 isCompressed = 0;
250 }else if( fossil_strnicmp(&zLine[14],
251 "application/x-fossil-uncompressed", -1)==0 ){
252
--- src/http.c
+++ src/http.c
@@ -130,11 +130,11 @@
130 **
131 ** The server address is contain in the "g" global structure. The
132 ** url_parse() routine should have been called prior to this routine
133 ** in order to fill this structure appropriately.
134 */
135 int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
136 Blob login; /* The login card */
137 Blob payload; /* The complete payload including login card */
138 Blob hdr; /* The HTTP request header */
139 int closeConnection; /* True to close the connection when done */
140 int iLength; /* Length of the reply payload */
@@ -231,10 +231,14 @@
231 }else if( c=='k' || c=='K' ){
232 closeConnection = 0;
233 }
234 }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
235 int i, j;
236
237 if ( --maxRedirect == 0){
238 fossil_fatal("redirect limit exceeded");
239 }
240 for(i=9; zLine[i] && zLine[i]==' '; i++){}
241 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
242 j = strlen(zLine) - 1;
243 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
244 j -= 4;
@@ -241,11 +245,11 @@
245 zLine[j] = 0;
246 }
247 fossil_print("redirect to %s\n", &zLine[i]);
248 url_parse(&zLine[i]);
249 transport_close();
250 return http_exchange(pSend, pReply, useLogin, maxRedirect);
251 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
252 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
253 isCompressed = 0;
254 }else if( fossil_strnicmp(&zLine[14],
255 "application/x-fossil-uncompressed", -1)==0 ){
256
+4 -10
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -1,21 +1,15 @@
11
/*
22
** Copyright (c) 2009 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
5
-** modify it under the terms of the GNU General Public
6
-** License version 2 as published by the Free Software Foundation.
5
+** modify it under the terms of the Simplified BSD License (also
6
+** known as the "2-Clause License" or "FreeBSD License".)
77
**
88
** This program is distributed in the hope that it will be useful,
9
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
10
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
-** General Public License for more details.
12
-**
13
-** You should have received a copy of the GNU General Public
14
-** License along with this library; if not, write to the
15
-** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16
-** Boston, MA 02111-1307, USA.
9
+** but without any warranty; without even the implied warranty of
10
+** merchantability or fitness for a particular purpose.
1711
**
1812
** Author contact information:
1913
** [email protected]
2014
** http://www.hwaci.com/drh/
2115
**
2216
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -1,21 +1,15 @@
1 /*
2 ** Copyright (c) 2009 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public
6 ** License version 2 as published by the Free Software Foundation.
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 ** General Public License for more details.
12 **
13 ** You should have received a copy of the GNU General Public
14 ** License along with this library; if not, write to the
15 ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 ** Boston, MA 02111-1307, USA.
17 **
18 ** Author contact information:
19 ** [email protected]
20 ** http://www.hwaci.com/drh/
21 **
22
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -1,21 +1,15 @@
1 /*
2 ** Copyright (c) 2009 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
 
 
 
 
 
 
11 **
12 ** Author contact information:
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16
+4 -10
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -1,21 +1,15 @@
11
/*
22
** Copyright (c) 2009 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
5
-** modify it under the terms of the GNU General Public
6
-** License version 2 as published by the Free Software Foundation.
5
+** modify it under the terms of the Simplified BSD License (also
6
+** known as the "2-Clause License" or "FreeBSD License".)
77
**
88
** This program is distributed in the hope that it will be useful,
9
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
10
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
-** General Public License for more details.
12
-**
13
-** You should have received a copy of the GNU General Public
14
-** License along with this library; if not, write to the
15
-** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16
-** Boston, MA 02111-1307, USA.
9
+** but without any warranty; without even the implied warranty of
10
+** merchantability or fitness for a particular purpose.
1711
**
1812
** Author contact information:
1913
** [email protected]
2014
** http://www.hwaci.com/drh/
2115
**
2216
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -1,21 +1,15 @@
1 /*
2 ** Copyright (c) 2009 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public
6 ** License version 2 as published by the Free Software Foundation.
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 ** General Public License for more details.
12 **
13 ** You should have received a copy of the GNU General Public
14 ** License along with this library; if not, write to the
15 ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 ** Boston, MA 02111-1307, USA.
17 **
18 ** Author contact information:
19 ** [email protected]
20 ** http://www.hwaci.com/drh/
21 **
22
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -1,21 +1,15 @@
1 /*
2 ** Copyright (c) 2009 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
 
 
 
 
 
 
11 **
12 ** Author contact information:
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16
--- src/http_transport.c
+++ src/http_transport.c
@@ -183,10 +183,11 @@
183183
** and run an SSH command to talk to the remote machine.
184184
*/
185185
const char *zSsh; /* The base SSH command */
186186
Blob zCmd; /* The SSH command */
187187
char *zHost; /* The host name to contact */
188
+ int n; /* Size of prefix string */
188189
189190
zSsh = db_get("ssh-command", zDefaultSshCmd);
190191
blob_init(&zCmd, zSsh, -1);
191192
if( g.urlPort!=g.urlDfltPort ){
192193
#ifdef __MINGW32__
@@ -219,22 +220,63 @@
219220
}
220221
#endif
221222
}else{
222223
zHost = mprintf("%s", g.urlName);
223224
}
225
+ n = blob_size(&zCmd);
224226
blob_append(&zCmd, " ", 1);
225227
shell_escape(&zCmd, zHost);
226
- fossil_print(" %s\n", zHost); /* Show the conclusion of the SSH command */
228
+ if( g.urlShell ){
229
+ blob_appendf(&zCmd, " %s", g.urlShell);
230
+ }else{
231
+#if defined(FOSSIL_ENABLE_SSH_FAR_SIDE)
232
+ /* The following works. But only if the fossil on the remote side
233
+ ** is recent enough to support the test-ssh-far-side command. That
234
+ ** command was added on 2013-02-06. We will leave this turned off
235
+ ** until most fossil servers have upgraded to that version or a later
236
+ ** version. The sync will still work as long as the shell on the far
237
+ ** side is bash and not tcsh. And if the default far side shell is
238
+ ** tcsh, then the shell=/bin/bash query parameter can be used as a
239
+ ** work-around. Enable this code after about a year...
240
+ */
241
+ blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil);
242
+#endif
243
+ }
244
+ fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
227245
free(zHost);
228246
popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
229247
if( sshPid==0 ){
230248
fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
231249
}
232250
blob_reset(&zCmd);
233251
transport_ssh_startup();
234252
}
235253
}
254
+
255
+/*
256
+** COMMAND: test-ssh-far-side
257
+**
258
+** Read lines of input text, one by one, and evaluate each line using
259
+** system(). The ssh: sync protocol uses this on the far side of the
260
+** SSH link.
261
+*/
262
+void test_ssh_far_side_cmd(void){
263
+ int i = 0;
264
+ int got;
265
+ char zLine[5000];
266
+ while( i<sizeof(zLine) ){
267
+ got = read(0, zLine+i, 1);
268
+ if( got==0 ) return;
269
+ if( zLine[i]=='\n' ){
270
+ zLine[i] = 0;
271
+ system(zLine);
272
+ i = 0;
273
+ }else{
274
+ i++;
275
+ }
276
+ }
277
+}
236278
237279
/*
238280
** Open a connection to the server. The server is defined by the following
239281
** global variables:
240282
**
@@ -251,13 +293,13 @@
251293
Blob cmd;
252294
blob_zero(&cmd);
253295
shell_escape(&cmd, g.urlFossil);
254296
blob_append(&cmd, " test-http ", -1);
255297
shell_escape(&cmd, g.urlPath);
256
- /* printf("%s\n", blob_str(&cmd)); fflush(stdout); */
257
- fprintf(sshOut, "%s\n", blob_str(&cmd));
298
+ fprintf(sshOut, "%s || true\n", blob_str(&cmd));
258299
fflush(sshOut);
300
+ if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd));
259301
blob_reset(&cmd);
260302
}else if( g.urlIsHttps ){
261303
#ifdef FOSSIL_ENABLE_SSL
262304
rc = ssl_open();
263305
if( rc==0 ) transport.isOpen = 1;
@@ -403,11 +445,10 @@
403445
int got;
404446
if( sshIn ){
405447
int x;
406448
int wanted = N;
407449
got = 0;
408
- /* printf("want %d bytes...\n", wanted); fflush(stdout); */
409450
while( wanted>0 ){
410451
x = read(sshIn, &zBuf[got], wanted);
411452
if( x<=0 ) break;
412453
got += x;
413454
wanted -= x;
@@ -438,11 +479,14 @@
438479
int transport_receive(char *zBuf, int N){
439480
int onHand; /* Bytes current held in the transport buffer */
440481
int nByte = 0; /* Bytes of content received */
441482
442483
onHand = transport.nUsed - transport.iCursor;
443
- /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */
484
+ if( g.fSshTrace){
485
+ printf("Reading %d bytes with %d on hand... ", N, onHand);
486
+ fflush(stdout);
487
+ }
444488
if( onHand>0 ){
445489
int toMove = onHand;
446490
if( toMove>N ) toMove = N;
447491
/* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
448492
memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -460,10 +504,11 @@
460504
if( got>0 ){
461505
nByte += got;
462506
transport.nRcvd += got;
463507
}
464508
}
509
+ if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
465510
return nByte;
466511
}
467512
468513
/*
469514
** Load up to N new bytes of content into the transport.pBuf buffer.
@@ -532,11 +577,11 @@
532577
}
533578
break;
534579
}
535580
i++;
536581
}
537
- /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
582
+ if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
538583
return &transport.pBuf[iStart];
539584
}
540585
541586
void transport_global_shutdown(void){
542587
if( g.urlIsSsh && sshPid ){
543588
--- src/http_transport.c
+++ src/http_transport.c
@@ -183,10 +183,11 @@
183 ** and run an SSH command to talk to the remote machine.
184 */
185 const char *zSsh; /* The base SSH command */
186 Blob zCmd; /* The SSH command */
187 char *zHost; /* The host name to contact */
 
188
189 zSsh = db_get("ssh-command", zDefaultSshCmd);
190 blob_init(&zCmd, zSsh, -1);
191 if( g.urlPort!=g.urlDfltPort ){
192 #ifdef __MINGW32__
@@ -219,22 +220,63 @@
219 }
220 #endif
221 }else{
222 zHost = mprintf("%s", g.urlName);
223 }
 
224 blob_append(&zCmd, " ", 1);
225 shell_escape(&zCmd, zHost);
226 fossil_print(" %s\n", zHost); /* Show the conclusion of the SSH command */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227 free(zHost);
228 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
229 if( sshPid==0 ){
230 fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
231 }
232 blob_reset(&zCmd);
233 transport_ssh_startup();
234 }
235 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
237 /*
238 ** Open a connection to the server. The server is defined by the following
239 ** global variables:
240 **
@@ -251,13 +293,13 @@
251 Blob cmd;
252 blob_zero(&cmd);
253 shell_escape(&cmd, g.urlFossil);
254 blob_append(&cmd, " test-http ", -1);
255 shell_escape(&cmd, g.urlPath);
256 /* printf("%s\n", blob_str(&cmd)); fflush(stdout); */
257 fprintf(sshOut, "%s\n", blob_str(&cmd));
258 fflush(sshOut);
 
259 blob_reset(&cmd);
260 }else if( g.urlIsHttps ){
261 #ifdef FOSSIL_ENABLE_SSL
262 rc = ssl_open();
263 if( rc==0 ) transport.isOpen = 1;
@@ -403,11 +445,10 @@
403 int got;
404 if( sshIn ){
405 int x;
406 int wanted = N;
407 got = 0;
408 /* printf("want %d bytes...\n", wanted); fflush(stdout); */
409 while( wanted>0 ){
410 x = read(sshIn, &zBuf[got], wanted);
411 if( x<=0 ) break;
412 got += x;
413 wanted -= x;
@@ -438,11 +479,14 @@
438 int transport_receive(char *zBuf, int N){
439 int onHand; /* Bytes current held in the transport buffer */
440 int nByte = 0; /* Bytes of content received */
441
442 onHand = transport.nUsed - transport.iCursor;
443 /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */
 
 
 
444 if( onHand>0 ){
445 int toMove = onHand;
446 if( toMove>N ) toMove = N;
447 /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
448 memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -460,10 +504,11 @@
460 if( got>0 ){
461 nByte += got;
462 transport.nRcvd += got;
463 }
464 }
 
465 return nByte;
466 }
467
468 /*
469 ** Load up to N new bytes of content into the transport.pBuf buffer.
@@ -532,11 +577,11 @@
532 }
533 break;
534 }
535 i++;
536 }
537 /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
538 return &transport.pBuf[iStart];
539 }
540
541 void transport_global_shutdown(void){
542 if( g.urlIsSsh && sshPid ){
543
--- src/http_transport.c
+++ src/http_transport.c
@@ -183,10 +183,11 @@
183 ** and run an SSH command to talk to the remote machine.
184 */
185 const char *zSsh; /* The base SSH command */
186 Blob zCmd; /* The SSH command */
187 char *zHost; /* The host name to contact */
188 int n; /* Size of prefix string */
189
190 zSsh = db_get("ssh-command", zDefaultSshCmd);
191 blob_init(&zCmd, zSsh, -1);
192 if( g.urlPort!=g.urlDfltPort ){
193 #ifdef __MINGW32__
@@ -219,22 +220,63 @@
220 }
221 #endif
222 }else{
223 zHost = mprintf("%s", g.urlName);
224 }
225 n = blob_size(&zCmd);
226 blob_append(&zCmd, " ", 1);
227 shell_escape(&zCmd, zHost);
228 if( g.urlShell ){
229 blob_appendf(&zCmd, " %s", g.urlShell);
230 }else{
231 #if defined(FOSSIL_ENABLE_SSH_FAR_SIDE)
232 /* The following works. But only if the fossil on the remote side
233 ** is recent enough to support the test-ssh-far-side command. That
234 ** command was added on 2013-02-06. We will leave this turned off
235 ** until most fossil servers have upgraded to that version or a later
236 ** version. The sync will still work as long as the shell on the far
237 ** side is bash and not tcsh. And if the default far side shell is
238 ** tcsh, then the shell=/bin/bash query parameter can be used as a
239 ** work-around. Enable this code after about a year...
240 */
241 blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil);
242 #endif
243 }
244 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
245 free(zHost);
246 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
247 if( sshPid==0 ){
248 fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
249 }
250 blob_reset(&zCmd);
251 transport_ssh_startup();
252 }
253 }
254
255 /*
256 ** COMMAND: test-ssh-far-side
257 **
258 ** Read lines of input text, one by one, and evaluate each line using
259 ** system(). The ssh: sync protocol uses this on the far side of the
260 ** SSH link.
261 */
262 void test_ssh_far_side_cmd(void){
263 int i = 0;
264 int got;
265 char zLine[5000];
266 while( i<sizeof(zLine) ){
267 got = read(0, zLine+i, 1);
268 if( got==0 ) return;
269 if( zLine[i]=='\n' ){
270 zLine[i] = 0;
271 system(zLine);
272 i = 0;
273 }else{
274 i++;
275 }
276 }
277 }
278
279 /*
280 ** Open a connection to the server. The server is defined by the following
281 ** global variables:
282 **
@@ -251,13 +293,13 @@
293 Blob cmd;
294 blob_zero(&cmd);
295 shell_escape(&cmd, g.urlFossil);
296 blob_append(&cmd, " test-http ", -1);
297 shell_escape(&cmd, g.urlPath);
298 fprintf(sshOut, "%s || true\n", blob_str(&cmd));
 
299 fflush(sshOut);
300 if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd));
301 blob_reset(&cmd);
302 }else if( g.urlIsHttps ){
303 #ifdef FOSSIL_ENABLE_SSL
304 rc = ssl_open();
305 if( rc==0 ) transport.isOpen = 1;
@@ -403,11 +445,10 @@
445 int got;
446 if( sshIn ){
447 int x;
448 int wanted = N;
449 got = 0;
 
450 while( wanted>0 ){
451 x = read(sshIn, &zBuf[got], wanted);
452 if( x<=0 ) break;
453 got += x;
454 wanted -= x;
@@ -438,11 +479,14 @@
479 int transport_receive(char *zBuf, int N){
480 int onHand; /* Bytes current held in the transport buffer */
481 int nByte = 0; /* Bytes of content received */
482
483 onHand = transport.nUsed - transport.iCursor;
484 if( g.fSshTrace){
485 printf("Reading %d bytes with %d on hand... ", N, onHand);
486 fflush(stdout);
487 }
488 if( onHand>0 ){
489 int toMove = onHand;
490 if( toMove>N ) toMove = N;
491 /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
492 memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -460,10 +504,11 @@
504 if( got>0 ){
505 nByte += got;
506 transport.nRcvd += got;
507 }
508 }
509 if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
510 return nByte;
511 }
512
513 /*
514 ** Load up to N new bytes of content into the transport.pBuf buffer.
@@ -532,11 +577,11 @@
577 }
578 break;
579 }
580 i++;
581 }
582 if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
583 return &transport.pBuf[iStart];
584 }
585
586 void transport_global_shutdown(void){
587 if( g.urlIsSsh && sshPid ){
588
--- src/http_transport.c
+++ src/http_transport.c
@@ -183,10 +183,11 @@
183183
** and run an SSH command to talk to the remote machine.
184184
*/
185185
const char *zSsh; /* The base SSH command */
186186
Blob zCmd; /* The SSH command */
187187
char *zHost; /* The host name to contact */
188
+ int n; /* Size of prefix string */
188189
189190
zSsh = db_get("ssh-command", zDefaultSshCmd);
190191
blob_init(&zCmd, zSsh, -1);
191192
if( g.urlPort!=g.urlDfltPort ){
192193
#ifdef __MINGW32__
@@ -219,22 +220,63 @@
219220
}
220221
#endif
221222
}else{
222223
zHost = mprintf("%s", g.urlName);
223224
}
225
+ n = blob_size(&zCmd);
224226
blob_append(&zCmd, " ", 1);
225227
shell_escape(&zCmd, zHost);
226
- fossil_print(" %s\n", zHost); /* Show the conclusion of the SSH command */
228
+ if( g.urlShell ){
229
+ blob_appendf(&zCmd, " %s", g.urlShell);
230
+ }else{
231
+#if defined(FOSSIL_ENABLE_SSH_FAR_SIDE)
232
+ /* The following works. But only if the fossil on the remote side
233
+ ** is recent enough to support the test-ssh-far-side command. That
234
+ ** command was added on 2013-02-06. We will leave this turned off
235
+ ** until most fossil servers have upgraded to that version or a later
236
+ ** version. The sync will still work as long as the shell on the far
237
+ ** side is bash and not tcsh. And if the default far side shell is
238
+ ** tcsh, then the shell=/bin/bash query parameter can be used as a
239
+ ** work-around. Enable this code after about a year...
240
+ */
241
+ blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil);
242
+#endif
243
+ }
244
+ fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
227245
free(zHost);
228246
popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
229247
if( sshPid==0 ){
230248
fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
231249
}
232250
blob_reset(&zCmd);
233251
transport_ssh_startup();
234252
}
235253
}
254
+
255
+/*
256
+** COMMAND: test-ssh-far-side
257
+**
258
+** Read lines of input text, one by one, and evaluate each line using
259
+** system(). The ssh: sync protocol uses this on the far side of the
260
+** SSH link.
261
+*/
262
+void test_ssh_far_side_cmd(void){
263
+ int i = 0;
264
+ int got;
265
+ char zLine[5000];
266
+ while( i<sizeof(zLine) ){
267
+ got = read(0, zLine+i, 1);
268
+ if( got==0 ) return;
269
+ if( zLine[i]=='\n' ){
270
+ zLine[i] = 0;
271
+ system(zLine);
272
+ i = 0;
273
+ }else{
274
+ i++;
275
+ }
276
+ }
277
+}
236278
237279
/*
238280
** Open a connection to the server. The server is defined by the following
239281
** global variables:
240282
**
@@ -251,13 +293,13 @@
251293
Blob cmd;
252294
blob_zero(&cmd);
253295
shell_escape(&cmd, g.urlFossil);
254296
blob_append(&cmd, " test-http ", -1);
255297
shell_escape(&cmd, g.urlPath);
256
- /* printf("%s\n", blob_str(&cmd)); fflush(stdout); */
257
- fprintf(sshOut, "%s\n", blob_str(&cmd));
298
+ fprintf(sshOut, "%s || true\n", blob_str(&cmd));
258299
fflush(sshOut);
300
+ if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd));
259301
blob_reset(&cmd);
260302
}else if( g.urlIsHttps ){
261303
#ifdef FOSSIL_ENABLE_SSL
262304
rc = ssl_open();
263305
if( rc==0 ) transport.isOpen = 1;
@@ -403,11 +445,10 @@
403445
int got;
404446
if( sshIn ){
405447
int x;
406448
int wanted = N;
407449
got = 0;
408
- /* printf("want %d bytes...\n", wanted); fflush(stdout); */
409450
while( wanted>0 ){
410451
x = read(sshIn, &zBuf[got], wanted);
411452
if( x<=0 ) break;
412453
got += x;
413454
wanted -= x;
@@ -438,11 +479,14 @@
438479
int transport_receive(char *zBuf, int N){
439480
int onHand; /* Bytes current held in the transport buffer */
440481
int nByte = 0; /* Bytes of content received */
441482
442483
onHand = transport.nUsed - transport.iCursor;
443
- /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */
484
+ if( g.fSshTrace){
485
+ printf("Reading %d bytes with %d on hand... ", N, onHand);
486
+ fflush(stdout);
487
+ }
444488
if( onHand>0 ){
445489
int toMove = onHand;
446490
if( toMove>N ) toMove = N;
447491
/* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
448492
memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -460,10 +504,11 @@
460504
if( got>0 ){
461505
nByte += got;
462506
transport.nRcvd += got;
463507
}
464508
}
509
+ if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
465510
return nByte;
466511
}
467512
468513
/*
469514
** Load up to N new bytes of content into the transport.pBuf buffer.
@@ -532,11 +577,11 @@
532577
}
533578
break;
534579
}
535580
i++;
536581
}
537
- /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
582
+ if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
538583
return &transport.pBuf[iStart];
539584
}
540585
541586
void transport_global_shutdown(void){
542587
if( g.urlIsSsh && sshPid ){
543588
--- src/http_transport.c
+++ src/http_transport.c
@@ -183,10 +183,11 @@
183 ** and run an SSH command to talk to the remote machine.
184 */
185 const char *zSsh; /* The base SSH command */
186 Blob zCmd; /* The SSH command */
187 char *zHost; /* The host name to contact */
 
188
189 zSsh = db_get("ssh-command", zDefaultSshCmd);
190 blob_init(&zCmd, zSsh, -1);
191 if( g.urlPort!=g.urlDfltPort ){
192 #ifdef __MINGW32__
@@ -219,22 +220,63 @@
219 }
220 #endif
221 }else{
222 zHost = mprintf("%s", g.urlName);
223 }
 
224 blob_append(&zCmd, " ", 1);
225 shell_escape(&zCmd, zHost);
226 fossil_print(" %s\n", zHost); /* Show the conclusion of the SSH command */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227 free(zHost);
228 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
229 if( sshPid==0 ){
230 fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
231 }
232 blob_reset(&zCmd);
233 transport_ssh_startup();
234 }
235 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
237 /*
238 ** Open a connection to the server. The server is defined by the following
239 ** global variables:
240 **
@@ -251,13 +293,13 @@
251 Blob cmd;
252 blob_zero(&cmd);
253 shell_escape(&cmd, g.urlFossil);
254 blob_append(&cmd, " test-http ", -1);
255 shell_escape(&cmd, g.urlPath);
256 /* printf("%s\n", blob_str(&cmd)); fflush(stdout); */
257 fprintf(sshOut, "%s\n", blob_str(&cmd));
258 fflush(sshOut);
 
259 blob_reset(&cmd);
260 }else if( g.urlIsHttps ){
261 #ifdef FOSSIL_ENABLE_SSL
262 rc = ssl_open();
263 if( rc==0 ) transport.isOpen = 1;
@@ -403,11 +445,10 @@
403 int got;
404 if( sshIn ){
405 int x;
406 int wanted = N;
407 got = 0;
408 /* printf("want %d bytes...\n", wanted); fflush(stdout); */
409 while( wanted>0 ){
410 x = read(sshIn, &zBuf[got], wanted);
411 if( x<=0 ) break;
412 got += x;
413 wanted -= x;
@@ -438,11 +479,14 @@
438 int transport_receive(char *zBuf, int N){
439 int onHand; /* Bytes current held in the transport buffer */
440 int nByte = 0; /* Bytes of content received */
441
442 onHand = transport.nUsed - transport.iCursor;
443 /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */
 
 
 
444 if( onHand>0 ){
445 int toMove = onHand;
446 if( toMove>N ) toMove = N;
447 /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
448 memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -460,10 +504,11 @@
460 if( got>0 ){
461 nByte += got;
462 transport.nRcvd += got;
463 }
464 }
 
465 return nByte;
466 }
467
468 /*
469 ** Load up to N new bytes of content into the transport.pBuf buffer.
@@ -532,11 +577,11 @@
532 }
533 break;
534 }
535 i++;
536 }
537 /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
538 return &transport.pBuf[iStart];
539 }
540
541 void transport_global_shutdown(void){
542 if( g.urlIsSsh && sshPid ){
543
--- src/http_transport.c
+++ src/http_transport.c
@@ -183,10 +183,11 @@
183 ** and run an SSH command to talk to the remote machine.
184 */
185 const char *zSsh; /* The base SSH command */
186 Blob zCmd; /* The SSH command */
187 char *zHost; /* The host name to contact */
188 int n; /* Size of prefix string */
189
190 zSsh = db_get("ssh-command", zDefaultSshCmd);
191 blob_init(&zCmd, zSsh, -1);
192 if( g.urlPort!=g.urlDfltPort ){
193 #ifdef __MINGW32__
@@ -219,22 +220,63 @@
220 }
221 #endif
222 }else{
223 zHost = mprintf("%s", g.urlName);
224 }
225 n = blob_size(&zCmd);
226 blob_append(&zCmd, " ", 1);
227 shell_escape(&zCmd, zHost);
228 if( g.urlShell ){
229 blob_appendf(&zCmd, " %s", g.urlShell);
230 }else{
231 #if defined(FOSSIL_ENABLE_SSH_FAR_SIDE)
232 /* The following works. But only if the fossil on the remote side
233 ** is recent enough to support the test-ssh-far-side command. That
234 ** command was added on 2013-02-06. We will leave this turned off
235 ** until most fossil servers have upgraded to that version or a later
236 ** version. The sync will still work as long as the shell on the far
237 ** side is bash and not tcsh. And if the default far side shell is
238 ** tcsh, then the shell=/bin/bash query parameter can be used as a
239 ** work-around. Enable this code after about a year...
240 */
241 blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil);
242 #endif
243 }
244 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
245 free(zHost);
246 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
247 if( sshPid==0 ){
248 fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
249 }
250 blob_reset(&zCmd);
251 transport_ssh_startup();
252 }
253 }
254
255 /*
256 ** COMMAND: test-ssh-far-side
257 **
258 ** Read lines of input text, one by one, and evaluate each line using
259 ** system(). The ssh: sync protocol uses this on the far side of the
260 ** SSH link.
261 */
262 void test_ssh_far_side_cmd(void){
263 int i = 0;
264 int got;
265 char zLine[5000];
266 while( i<sizeof(zLine) ){
267 got = read(0, zLine+i, 1);
268 if( got==0 ) return;
269 if( zLine[i]=='\n' ){
270 zLine[i] = 0;
271 system(zLine);
272 i = 0;
273 }else{
274 i++;
275 }
276 }
277 }
278
279 /*
280 ** Open a connection to the server. The server is defined by the following
281 ** global variables:
282 **
@@ -251,13 +293,13 @@
293 Blob cmd;
294 blob_zero(&cmd);
295 shell_escape(&cmd, g.urlFossil);
296 blob_append(&cmd, " test-http ", -1);
297 shell_escape(&cmd, g.urlPath);
298 fprintf(sshOut, "%s || true\n", blob_str(&cmd));
 
299 fflush(sshOut);
300 if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd));
301 blob_reset(&cmd);
302 }else if( g.urlIsHttps ){
303 #ifdef FOSSIL_ENABLE_SSL
304 rc = ssl_open();
305 if( rc==0 ) transport.isOpen = 1;
@@ -403,11 +445,10 @@
445 int got;
446 if( sshIn ){
447 int x;
448 int wanted = N;
449 got = 0;
 
450 while( wanted>0 ){
451 x = read(sshIn, &zBuf[got], wanted);
452 if( x<=0 ) break;
453 got += x;
454 wanted -= x;
@@ -438,11 +479,14 @@
479 int transport_receive(char *zBuf, int N){
480 int onHand; /* Bytes current held in the transport buffer */
481 int nByte = 0; /* Bytes of content received */
482
483 onHand = transport.nUsed - transport.iCursor;
484 if( g.fSshTrace){
485 printf("Reading %d bytes with %d on hand... ", N, onHand);
486 fflush(stdout);
487 }
488 if( onHand>0 ){
489 int toMove = onHand;
490 if( toMove>N ) toMove = N;
491 /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
492 memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -460,10 +504,11 @@
504 if( got>0 ){
505 nByte += got;
506 transport.nRcvd += got;
507 }
508 }
509 if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
510 return nByte;
511 }
512
513 /*
514 ** Load up to N new bytes of content into the transport.pBuf buffer.
@@ -532,11 +577,11 @@
577 }
578 break;
579 }
580 i++;
581 }
582 if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
583 return &transport.pBuf[iStart];
584 }
585
586 void transport_global_shutdown(void){
587 if( g.urlIsSsh && sshPid ){
588
+3 -2
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208208
fossil_print("project-code: %s\n", db_get("project-code", ""));
209209
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210210
if( vid ){
211211
show_common_info(vid, "checkout:", 1, 1);
212212
}
213
+ fossil_print("checkins: %d\n",
214
+ db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
213215
}else{
214216
int rid;
215217
rid = name_to_rid(g.argv[2]);
216218
if( rid==0 ){
217219
fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
13131315
char *zV2;
13141316
const char *zRe;
13151317
ReCompiled *pRe = 0;
13161318
u64 diffFlags;
13171319
const char *zStyle = "sbsdiff";
1318
- const char *zReErr = 0;
13191320
13201321
login_check_credentials();
13211322
if( !g.perm.Read ){ login_needed(); return; }
13221323
v1 = name_to_rid_www("v1");
13231324
v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
13401341
diffFlags |= DIFF_LINENO;
13411342
zStyle = "udiff";
13421343
}
13431344
}
13441345
zRe = P("regex");
1345
- if( zRe ) zReErr = re_compile(&pRe, zRe, 0);
1346
+ if( zRe ) re_compile(&pRe, zRe, 0);
13461347
content_get(v1, &c1);
13471348
content_get(v2, &c2);
13481349
text_diff(&c1, &c2, pOut, pRe, diffFlags);
13491350
blob_reset(&c1);
13501351
blob_reset(&c2);
13511352
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
 
 
213 }else{
214 int rid;
215 rid = name_to_rid(g.argv[2]);
216 if( rid==0 ){
217 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
1313 char *zV2;
1314 const char *zRe;
1315 ReCompiled *pRe = 0;
1316 u64 diffFlags;
1317 const char *zStyle = "sbsdiff";
1318 const char *zReErr = 0;
1319
1320 login_check_credentials();
1321 if( !g.perm.Read ){ login_needed(); return; }
1322 v1 = name_to_rid_www("v1");
1323 v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
1340 diffFlags |= DIFF_LINENO;
1341 zStyle = "udiff";
1342 }
1343 }
1344 zRe = P("regex");
1345 if( zRe ) zReErr = re_compile(&pRe, zRe, 0);
1346 content_get(v1, &c1);
1347 content_get(v2, &c2);
1348 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1349 blob_reset(&c1);
1350 blob_reset(&c2);
1351
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
213 fossil_print("checkins: %d\n",
214 db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
215 }else{
216 int rid;
217 rid = name_to_rid(g.argv[2]);
218 if( rid==0 ){
219 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
1315 char *zV2;
1316 const char *zRe;
1317 ReCompiled *pRe = 0;
1318 u64 diffFlags;
1319 const char *zStyle = "sbsdiff";
 
1320
1321 login_check_credentials();
1322 if( !g.perm.Read ){ login_needed(); return; }
1323 v1 = name_to_rid_www("v1");
1324 v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
1341 diffFlags |= DIFF_LINENO;
1342 zStyle = "udiff";
1343 }
1344 }
1345 zRe = P("regex");
1346 if( zRe ) re_compile(&pRe, zRe, 0);
1347 content_get(v1, &c1);
1348 content_get(v2, &c2);
1349 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1350 blob_reset(&c1);
1351 blob_reset(&c2);
1352
+3 -2
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208208
fossil_print("project-code: %s\n", db_get("project-code", ""));
209209
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210210
if( vid ){
211211
show_common_info(vid, "checkout:", 1, 1);
212212
}
213
+ fossil_print("checkins: %d\n",
214
+ db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
213215
}else{
214216
int rid;
215217
rid = name_to_rid(g.argv[2]);
216218
if( rid==0 ){
217219
fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
13131315
char *zV2;
13141316
const char *zRe;
13151317
ReCompiled *pRe = 0;
13161318
u64 diffFlags;
13171319
const char *zStyle = "sbsdiff";
1318
- const char *zReErr = 0;
13191320
13201321
login_check_credentials();
13211322
if( !g.perm.Read ){ login_needed(); return; }
13221323
v1 = name_to_rid_www("v1");
13231324
v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
13401341
diffFlags |= DIFF_LINENO;
13411342
zStyle = "udiff";
13421343
}
13431344
}
13441345
zRe = P("regex");
1345
- if( zRe ) zReErr = re_compile(&pRe, zRe, 0);
1346
+ if( zRe ) re_compile(&pRe, zRe, 0);
13461347
content_get(v1, &c1);
13471348
content_get(v2, &c2);
13481349
text_diff(&c1, &c2, pOut, pRe, diffFlags);
13491350
blob_reset(&c1);
13501351
blob_reset(&c2);
13511352
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
 
 
213 }else{
214 int rid;
215 rid = name_to_rid(g.argv[2]);
216 if( rid==0 ){
217 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
1313 char *zV2;
1314 const char *zRe;
1315 ReCompiled *pRe = 0;
1316 u64 diffFlags;
1317 const char *zStyle = "sbsdiff";
1318 const char *zReErr = 0;
1319
1320 login_check_credentials();
1321 if( !g.perm.Read ){ login_needed(); return; }
1322 v1 = name_to_rid_www("v1");
1323 v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
1340 diffFlags |= DIFF_LINENO;
1341 zStyle = "udiff";
1342 }
1343 }
1344 zRe = P("regex");
1345 if( zRe ) zReErr = re_compile(&pRe, zRe, 0);
1346 content_get(v1, &c1);
1347 content_get(v2, &c2);
1348 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1349 blob_reset(&c1);
1350 blob_reset(&c2);
1351
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
213 fossil_print("checkins: %d\n",
214 db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
215 }else{
216 int rid;
217 rid = name_to_rid(g.argv[2]);
218 if( rid==0 ){
219 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
1315 char *zV2;
1316 const char *zRe;
1317 ReCompiled *pRe = 0;
1318 u64 diffFlags;
1319 const char *zStyle = "sbsdiff";
 
1320
1321 login_check_credentials();
1322 if( !g.perm.Read ){ login_needed(); return; }
1323 v1 = name_to_rid_www("v1");
1324 v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
1341 diffFlags |= DIFF_LINENO;
1342 zStyle = "udiff";
1343 }
1344 }
1345 zRe = P("regex");
1346 if( zRe ) re_compile(&pRe, zRe, 0);
1347 content_get(v1, &c1);
1348 content_get(v2, &c2);
1349 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1350 blob_reset(&c1);
1351 blob_reset(&c2);
1352
+3 -2
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208208
fossil_print("project-code: %s\n", db_get("project-code", ""));
209209
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210210
if( vid ){
211211
show_common_info(vid, "checkout:", 1, 1);
212212
}
213
+ fossil_print("checkins: %d\n",
214
+ db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
213215
}else{
214216
int rid;
215217
rid = name_to_rid(g.argv[2]);
216218
if( rid==0 ){
217219
fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
13131315
char *zV2;
13141316
const char *zRe;
13151317
ReCompiled *pRe = 0;
13161318
u64 diffFlags;
13171319
const char *zStyle = "sbsdiff";
1318
- const char *zReErr = 0;
13191320
13201321
login_check_credentials();
13211322
if( !g.perm.Read ){ login_needed(); return; }
13221323
v1 = name_to_rid_www("v1");
13231324
v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
13401341
diffFlags |= DIFF_LINENO;
13411342
zStyle = "udiff";
13421343
}
13431344
}
13441345
zRe = P("regex");
1345
- if( zRe ) zReErr = re_compile(&pRe, zRe, 0);
1346
+ if( zRe ) re_compile(&pRe, zRe, 0);
13461347
content_get(v1, &c1);
13471348
content_get(v2, &c2);
13481349
text_diff(&c1, &c2, pOut, pRe, diffFlags);
13491350
blob_reset(&c1);
13501351
blob_reset(&c2);
13511352
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
 
 
213 }else{
214 int rid;
215 rid = name_to_rid(g.argv[2]);
216 if( rid==0 ){
217 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
1313 char *zV2;
1314 const char *zRe;
1315 ReCompiled *pRe = 0;
1316 u64 diffFlags;
1317 const char *zStyle = "sbsdiff";
1318 const char *zReErr = 0;
1319
1320 login_check_credentials();
1321 if( !g.perm.Read ){ login_needed(); return; }
1322 v1 = name_to_rid_www("v1");
1323 v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
1340 diffFlags |= DIFF_LINENO;
1341 zStyle = "udiff";
1342 }
1343 }
1344 zRe = P("regex");
1345 if( zRe ) zReErr = re_compile(&pRe, zRe, 0);
1346 content_get(v1, &c1);
1347 content_get(v2, &c2);
1348 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1349 blob_reset(&c1);
1350 blob_reset(&c2);
1351
--- src/info.c
+++ src/info.c
@@ -208,10 +208,12 @@
208 fossil_print("project-code: %s\n", db_get("project-code", ""));
209 vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
210 if( vid ){
211 show_common_info(vid, "checkout:", 1, 1);
212 }
213 fossil_print("checkins: %d\n",
214 db_int(-1, "SELECT count(distinct mid) FROM mlink /*scan*/"));
215 }else{
216 int rid;
217 rid = name_to_rid(g.argv[2]);
218 if( rid==0 ){
219 fossil_panic("no such object: %s\n", g.argv[2]);
@@ -1313,11 +1315,10 @@
1315 char *zV2;
1316 const char *zRe;
1317 ReCompiled *pRe = 0;
1318 u64 diffFlags;
1319 const char *zStyle = "sbsdiff";
 
1320
1321 login_check_credentials();
1322 if( !g.perm.Read ){ login_needed(); return; }
1323 v1 = name_to_rid_www("v1");
1324 v2 = name_to_rid_www("v2");
@@ -1340,11 +1341,11 @@
1341 diffFlags |= DIFF_LINENO;
1342 zStyle = "udiff";
1343 }
1344 }
1345 zRe = P("regex");
1346 if( zRe ) re_compile(&pRe, zRe, 0);
1347 content_get(v1, &c1);
1348 content_get(v2, &c2);
1349 text_diff(&c1, &c2, pOut, pRe, diffFlags);
1350 blob_reset(&c1);
1351 blob_reset(&c2);
1352
+1 -3
--- src/json.c
+++ src/json.c
@@ -2085,15 +2085,13 @@
20852085
cson_object_set(jo, "ticketCount", cson_value_new_integer((cson_int_t)n));
20862086
}/*full*/
20872087
n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
20882088
" + 0.99");
20892089
cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n));
2090
- cson_object_set(jo, "ageYears", cson_value_new_double(n/365.24));
2090
+ cson_object_set(jo, "ageYears", cson_value_new_double(n/365.2425));
20912091
sqlite3_snprintf(BufLen, zBuf, db_get("project-code",""));
20922092
SETBUF(jo, "projectCode");
2093
- sqlite3_snprintf(BufLen, zBuf, db_get("server-code",""));
2094
- SETBUF(jo, "serverCode");
20952093
cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
20962094
20972095
jv2 = cson_value_new_object();
20982096
jo2 = cson_value_get_object(jv2);
20992097
cson_object_set(jo, "sqlite", jv2);
21002098
--- src/json.c
+++ src/json.c
@@ -2085,15 +2085,13 @@
2085 cson_object_set(jo, "ticketCount", cson_value_new_integer((cson_int_t)n));
2086 }/*full*/
2087 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
2088 " + 0.99");
2089 cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n));
2090 cson_object_set(jo, "ageYears", cson_value_new_double(n/365.24));
2091 sqlite3_snprintf(BufLen, zBuf, db_get("project-code",""));
2092 SETBUF(jo, "projectCode");
2093 sqlite3_snprintf(BufLen, zBuf, db_get("server-code",""));
2094 SETBUF(jo, "serverCode");
2095 cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
2096
2097 jv2 = cson_value_new_object();
2098 jo2 = cson_value_get_object(jv2);
2099 cson_object_set(jo, "sqlite", jv2);
2100
--- src/json.c
+++ src/json.c
@@ -2085,15 +2085,13 @@
2085 cson_object_set(jo, "ticketCount", cson_value_new_integer((cson_int_t)n));
2086 }/*full*/
2087 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
2088 " + 0.99");
2089 cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n));
2090 cson_object_set(jo, "ageYears", cson_value_new_double(n/365.2425));
2091 sqlite3_snprintf(BufLen, zBuf, db_get("project-code",""));
2092 SETBUF(jo, "projectCode");
 
 
2093 cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
2094
2095 jv2 = cson_value_new_object();
2096 jo2 = cson_value_get_object(jv2);
2097 cson_object_set(jo, "sqlite", jv2);
2098
+1 -3
--- src/json.c
+++ src/json.c
@@ -2085,15 +2085,13 @@
20852085
cson_object_set(jo, "ticketCount", cson_value_new_integer((cson_int_t)n));
20862086
}/*full*/
20872087
n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
20882088
" + 0.99");
20892089
cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n));
2090
- cson_object_set(jo, "ageYears", cson_value_new_double(n/365.24));
2090
+ cson_object_set(jo, "ageYears", cson_value_new_double(n/365.2425));
20912091
sqlite3_snprintf(BufLen, zBuf, db_get("project-code",""));
20922092
SETBUF(jo, "projectCode");
2093
- sqlite3_snprintf(BufLen, zBuf, db_get("server-code",""));
2094
- SETBUF(jo, "serverCode");
20952093
cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
20962094
20972095
jv2 = cson_value_new_object();
20982096
jo2 = cson_value_get_object(jv2);
20992097
cson_object_set(jo, "sqlite", jv2);
21002098
--- src/json.c
+++ src/json.c
@@ -2085,15 +2085,13 @@
2085 cson_object_set(jo, "ticketCount", cson_value_new_integer((cson_int_t)n));
2086 }/*full*/
2087 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
2088 " + 0.99");
2089 cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n));
2090 cson_object_set(jo, "ageYears", cson_value_new_double(n/365.24));
2091 sqlite3_snprintf(BufLen, zBuf, db_get("project-code",""));
2092 SETBUF(jo, "projectCode");
2093 sqlite3_snprintf(BufLen, zBuf, db_get("server-code",""));
2094 SETBUF(jo, "serverCode");
2095 cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
2096
2097 jv2 = cson_value_new_object();
2098 jo2 = cson_value_get_object(jv2);
2099 cson_object_set(jo, "sqlite", jv2);
2100
--- src/json.c
+++ src/json.c
@@ -2085,15 +2085,13 @@
2085 cson_object_set(jo, "ticketCount", cson_value_new_integer((cson_int_t)n));
2086 }/*full*/
2087 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
2088 " + 0.99");
2089 cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n));
2090 cson_object_set(jo, "ageYears", cson_value_new_double(n/365.2425));
2091 sqlite3_snprintf(BufLen, zBuf, db_get("project-code",""));
2092 SETBUF(jo, "projectCode");
 
 
2093 cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
2094
2095 jv2 = cson_value_new_object();
2096 jo2 = cson_value_get_object(jv2);
2097 cson_object_set(jo, "sqlite", jv2);
2098
--- src/json_detail.h
+++ src/json_detail.h
@@ -199,11 +199,11 @@
199199
char const * requestId;
200200
char const * resultCode;
201201
char const * resultText;
202202
char const * timestamp;
203203
} FossilJsonKeys_;
204
-const FossilJsonKeys_ FossilJsonKeys;
204
+extern const FossilJsonKeys_ FossilJsonKeys;
205205
206206
/*
207207
** A page/command dispatch helper for fossil_json_f() implementations.
208208
** pages must be an array of JsonPageDef commands which we can
209209
** dispatch. The final item in the array MUST have a NULL name
210210
--- src/json_detail.h
+++ src/json_detail.h
@@ -199,11 +199,11 @@
199 char const * requestId;
200 char const * resultCode;
201 char const * resultText;
202 char const * timestamp;
203 } FossilJsonKeys_;
204 const FossilJsonKeys_ FossilJsonKeys;
205
206 /*
207 ** A page/command dispatch helper for fossil_json_f() implementations.
208 ** pages must be an array of JsonPageDef commands which we can
209 ** dispatch. The final item in the array MUST have a NULL name
210
--- src/json_detail.h
+++ src/json_detail.h
@@ -199,11 +199,11 @@
199 char const * requestId;
200 char const * resultCode;
201 char const * resultText;
202 char const * timestamp;
203 } FossilJsonKeys_;
204 extern const FossilJsonKeys_ FossilJsonKeys;
205
206 /*
207 ** A page/command dispatch helper for fossil_json_f() implementations.
208 ** pages must be an array of JsonPageDef commands which we can
209 ** dispatch. The final item in the array MUST have a NULL name
210
--- src/json_detail.h
+++ src/json_detail.h
@@ -199,11 +199,11 @@
199199
char const * requestId;
200200
char const * resultCode;
201201
char const * resultText;
202202
char const * timestamp;
203203
} FossilJsonKeys_;
204
-const FossilJsonKeys_ FossilJsonKeys;
204
+extern const FossilJsonKeys_ FossilJsonKeys;
205205
206206
/*
207207
** A page/command dispatch helper for fossil_json_f() implementations.
208208
** pages must be an array of JsonPageDef commands which we can
209209
** dispatch. The final item in the array MUST have a NULL name
210210
--- src/json_detail.h
+++ src/json_detail.h
@@ -199,11 +199,11 @@
199 char const * requestId;
200 char const * resultCode;
201 char const * resultText;
202 char const * timestamp;
203 } FossilJsonKeys_;
204 const FossilJsonKeys_ FossilJsonKeys;
205
206 /*
207 ** A page/command dispatch helper for fossil_json_f() implementations.
208 ** pages must be an array of JsonPageDef commands which we can
209 ** dispatch. The final item in the array MUST have a NULL name
210
--- src/json_detail.h
+++ src/json_detail.h
@@ -199,11 +199,11 @@
199 char const * requestId;
200 char const * resultCode;
201 char const * resultText;
202 char const * timestamp;
203 } FossilJsonKeys_;
204 extern const FossilJsonKeys_ FossilJsonKeys;
205
206 /*
207 ** A page/command dispatch helper for fossil_json_f() implementations.
208 ** pages must be an array of JsonPageDef commands which we can
209 ** dispatch. The final item in the array MUST have a NULL name
210
+1 -1
--- src/login.c
+++ src/login.c
@@ -625,11 +625,11 @@
625625
@ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
626626
}
627627
if( zAnonPw ){
628628
unsigned int uSeed = captcha_seed();
629629
char const *zDecoded = captcha_decode(uSeed);
630
- int bAutoCaptcha = db_get_boolean("auto-captcha", 1);
630
+ int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
631631
char *zCaptcha = captcha_render(zDecoded);
632632
633633
@ <p><input type="hidden" name="cs" value="%u(uSeed)" />
634634
@ Visitors may enter <b>anonymous</b> as the user-ID with
635635
@ the 8-character hexadecimal password shown below:</p>
636636
--- src/login.c
+++ src/login.c
@@ -625,11 +625,11 @@
625 @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
626 }
627 if( zAnonPw ){
628 unsigned int uSeed = captcha_seed();
629 char const *zDecoded = captcha_decode(uSeed);
630 int bAutoCaptcha = db_get_boolean("auto-captcha", 1);
631 char *zCaptcha = captcha_render(zDecoded);
632
633 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
634 @ Visitors may enter <b>anonymous</b> as the user-ID with
635 @ the 8-character hexadecimal password shown below:</p>
636
--- src/login.c
+++ src/login.c
@@ -625,11 +625,11 @@
625 @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
626 }
627 if( zAnonPw ){
628 unsigned int uSeed = captcha_seed();
629 char const *zDecoded = captcha_decode(uSeed);
630 int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
631 char *zCaptcha = captcha_render(zDecoded);
632
633 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
634 @ Visitors may enter <b>anonymous</b> as the user-ID with
635 @ the 8-character hexadecimal password shown below:</p>
636
+1 -1
--- src/login.c
+++ src/login.c
@@ -625,11 +625,11 @@
625625
@ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
626626
}
627627
if( zAnonPw ){
628628
unsigned int uSeed = captcha_seed();
629629
char const *zDecoded = captcha_decode(uSeed);
630
- int bAutoCaptcha = db_get_boolean("auto-captcha", 1);
630
+ int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
631631
char *zCaptcha = captcha_render(zDecoded);
632632
633633
@ <p><input type="hidden" name="cs" value="%u(uSeed)" />
634634
@ Visitors may enter <b>anonymous</b> as the user-ID with
635635
@ the 8-character hexadecimal password shown below:</p>
636636
--- src/login.c
+++ src/login.c
@@ -625,11 +625,11 @@
625 @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
626 }
627 if( zAnonPw ){
628 unsigned int uSeed = captcha_seed();
629 char const *zDecoded = captcha_decode(uSeed);
630 int bAutoCaptcha = db_get_boolean("auto-captcha", 1);
631 char *zCaptcha = captcha_render(zDecoded);
632
633 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
634 @ Visitors may enter <b>anonymous</b> as the user-ID with
635 @ the 8-character hexadecimal password shown below:</p>
636
--- src/login.c
+++ src/login.c
@@ -625,11 +625,11 @@
625 @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
626 }
627 if( zAnonPw ){
628 unsigned int uSeed = captcha_seed();
629 char const *zDecoded = captcha_decode(uSeed);
630 int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
631 char *zCaptcha = captcha_render(zDecoded);
632
633 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
634 @ Visitors may enter <b>anonymous</b> as the user-ID with
635 @ the 8-character hexadecimal password shown below:</p>
636
+17 -28
--- src/main.c
+++ src/main.c
@@ -170,11 +170,12 @@
170170
char *urlPath; /* Pathname for http: */
171171
char *urlUser; /* User id for http: */
172172
char *urlPasswd; /* Password for http: */
173173
char *urlCanonical; /* Canonical representation of the URL */
174174
char *urlProxyAuth; /* Proxy-Authorizer: string */
175
- char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */
175
+ char *urlFossil; /* The fossil query parameter on ssh: */
176
+ char *urlShell; /* The shell query parameter on ssh: */
176177
int dontKeepUrl; /* Do not persist the URL */
177178
178179
const char *zLogin; /* Login name. "" if not logged in. */
179180
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
180181
int useLocalauth; /* No login required if from 127.0.0.1 */
@@ -605,14 +606,11 @@
605606
if( g.cgiOutput && once ){
606607
once = 0;
607608
cgi_printf("<p class=\"generalError\">%h</p>", z);
608609
cgi_reply();
609610
}else if( !g.fQuiet ){
610
- char *zOut = mprintf("%s: %s\n", g.argv[0], z);
611
- fossil_force_newline();
612
- fossil_puts(zOut, 1);
613
- fossil_free(zOut);
611
+ fossil_trace("%s: %s\n", g.argv[0], z);
614612
}
615613
}
616614
free(z);
617615
db_force_rollback();
618616
fossil_exit(rc);
@@ -636,17 +634,14 @@
636634
else
637635
#endif
638636
{
639637
if( g.cgiOutput ){
640638
g.cgiOutput = 0;
641
- cgi_printf("<p class=\"generalError\">%h</p>", z);
639
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
642640
cgi_reply();
643641
}else if( !g.fQuiet ){
644
- char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
645
- fossil_force_newline();
646
- fossil_puts(zOut, 1);
647
- fossil_free(zOut);
642
+ fossil_trace("%s: %s\n", g.argv[0], z);
648643
}
649644
}
650645
free(z);
651646
db_force_rollback();
652647
fossil_exit(rc);
@@ -679,17 +674,14 @@
679674
} else
680675
#endif
681676
{
682677
if( g.cgiOutput ){
683678
g.cgiOutput = 0;
684
- cgi_printf("<p class=\"generalError\">%h</p>", z);
679
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
685680
cgi_reply();
686681
}else{
687
- char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
688
- fossil_force_newline();
689
- fossil_puts(zOut, 1);
690
- fossil_free(zOut);
682
+ fossil_trace("%s: %s\n", g.argv[0], z);
691683
}
692684
}
693685
db_force_rollback();
694686
fossil_exit(rc);
695687
}
@@ -707,16 +699,13 @@
707699
json_warn( FSL_JSON_W_UNKNOWN, z );
708700
}else
709701
#endif
710702
{
711703
if( g.cgiOutput ){
712
- cgi_printf("<p class=\"generalError\">%h</p>", z);
704
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
713705
}else{
714
- char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
715
- fossil_force_newline();
716
- fossil_puts(zOut, 1);
717
- fossil_free(zOut);
706
+ fossil_trace("%s: %s\n", g.argv[0], z);
718707
}
719708
}
720709
free(z);
721710
}
722711
@@ -747,13 +736,11 @@
747736
** Who knows why - this is just the way windows works.
748737
*/
749738
char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
750739
WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
751740
if( g.fSystemTrace ) {
752
- char *zOut = mprintf("SYSTEM: %s\n", zNewCmd);
753
- fossil_puts(zOut, 1);
754
- fossil_free(zOut);
741
+ fossil_trace("SYSTEM: %s\n", zNewCmd);
755742
}
756743
rc = _wsystem(zUnicode);
757744
fossil_unicode_free(zUnicode);
758745
free(zNewCmd);
759746
#else
@@ -977,11 +964,11 @@
977964
**
978965
** Display information on how to use COMMAND. To display a list of
979966
** available commands one of:
980967
**
981968
** %fossil help Show common commands
982
-** %fossil help --all Show both command and auxiliary commands
969
+** %fossil help --all Show both common and auxiliary commands
983970
** %fossil help --test Show test commands only
984971
** %fossil help --aux Show auxiliary commands only
985972
*/
986973
void help_cmd(void){
987974
int rc, idx;
@@ -1225,15 +1212,17 @@
12251212
}
12261213
zRepo = "/";
12271214
}else{
12281215
for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
12291216
if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
1230
- zDir[i] = 0;
1231
- if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1232
- fossil_fatal("unable to chroot into %s", zDir);
1217
+ if( i>0 ){
1218
+ zDir[i] = 0;
1219
+ if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1220
+ fossil_fatal("unable to chroot into %s", zDir);
1221
+ }
1222
+ zDir[i] = '/';
12331223
}
1234
- zDir[i] = '/';
12351224
zRepo = &zDir[i];
12361225
}
12371226
if( stat(zRepo, &sStat)!=0 ){
12381227
fossil_fatal("cannot stat() repository: %s", zRepo);
12391228
}
12401229
--- src/main.c
+++ src/main.c
@@ -170,11 +170,12 @@
170 char *urlPath; /* Pathname for http: */
171 char *urlUser; /* User id for http: */
172 char *urlPasswd; /* Password for http: */
173 char *urlCanonical; /* Canonical representation of the URL */
174 char *urlProxyAuth; /* Proxy-Authorizer: string */
175 char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */
 
176 int dontKeepUrl; /* Do not persist the URL */
177
178 const char *zLogin; /* Login name. "" if not logged in. */
179 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
180 int useLocalauth; /* No login required if from 127.0.0.1 */
@@ -605,14 +606,11 @@
605 if( g.cgiOutput && once ){
606 once = 0;
607 cgi_printf("<p class=\"generalError\">%h</p>", z);
608 cgi_reply();
609 }else if( !g.fQuiet ){
610 char *zOut = mprintf("%s: %s\n", g.argv[0], z);
611 fossil_force_newline();
612 fossil_puts(zOut, 1);
613 fossil_free(zOut);
614 }
615 }
616 free(z);
617 db_force_rollback();
618 fossil_exit(rc);
@@ -636,17 +634,14 @@
636 else
637 #endif
638 {
639 if( g.cgiOutput ){
640 g.cgiOutput = 0;
641 cgi_printf("<p class=\"generalError\">%h</p>", z);
642 cgi_reply();
643 }else if( !g.fQuiet ){
644 char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
645 fossil_force_newline();
646 fossil_puts(zOut, 1);
647 fossil_free(zOut);
648 }
649 }
650 free(z);
651 db_force_rollback();
652 fossil_exit(rc);
@@ -679,17 +674,14 @@
679 } else
680 #endif
681 {
682 if( g.cgiOutput ){
683 g.cgiOutput = 0;
684 cgi_printf("<p class=\"generalError\">%h</p>", z);
685 cgi_reply();
686 }else{
687 char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
688 fossil_force_newline();
689 fossil_puts(zOut, 1);
690 fossil_free(zOut);
691 }
692 }
693 db_force_rollback();
694 fossil_exit(rc);
695 }
@@ -707,16 +699,13 @@
707 json_warn( FSL_JSON_W_UNKNOWN, z );
708 }else
709 #endif
710 {
711 if( g.cgiOutput ){
712 cgi_printf("<p class=\"generalError\">%h</p>", z);
713 }else{
714 char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
715 fossil_force_newline();
716 fossil_puts(zOut, 1);
717 fossil_free(zOut);
718 }
719 }
720 free(z);
721 }
722
@@ -747,13 +736,11 @@
747 ** Who knows why - this is just the way windows works.
748 */
749 char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
750 WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
751 if( g.fSystemTrace ) {
752 char *zOut = mprintf("SYSTEM: %s\n", zNewCmd);
753 fossil_puts(zOut, 1);
754 fossil_free(zOut);
755 }
756 rc = _wsystem(zUnicode);
757 fossil_unicode_free(zUnicode);
758 free(zNewCmd);
759 #else
@@ -977,11 +964,11 @@
977 **
978 ** Display information on how to use COMMAND. To display a list of
979 ** available commands one of:
980 **
981 ** %fossil help Show common commands
982 ** %fossil help --all Show both command and auxiliary commands
983 ** %fossil help --test Show test commands only
984 ** %fossil help --aux Show auxiliary commands only
985 */
986 void help_cmd(void){
987 int rc, idx;
@@ -1225,15 +1212,17 @@
1225 }
1226 zRepo = "/";
1227 }else{
1228 for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
1229 if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
1230 zDir[i] = 0;
1231 if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1232 fossil_fatal("unable to chroot into %s", zDir);
 
 
 
1233 }
1234 zDir[i] = '/';
1235 zRepo = &zDir[i];
1236 }
1237 if( stat(zRepo, &sStat)!=0 ){
1238 fossil_fatal("cannot stat() repository: %s", zRepo);
1239 }
1240
--- src/main.c
+++ src/main.c
@@ -170,11 +170,12 @@
170 char *urlPath; /* Pathname for http: */
171 char *urlUser; /* User id for http: */
172 char *urlPasswd; /* Password for http: */
173 char *urlCanonical; /* Canonical representation of the URL */
174 char *urlProxyAuth; /* Proxy-Authorizer: string */
175 char *urlFossil; /* The fossil query parameter on ssh: */
176 char *urlShell; /* The shell query parameter on ssh: */
177 int dontKeepUrl; /* Do not persist the URL */
178
179 const char *zLogin; /* Login name. "" if not logged in. */
180 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
181 int useLocalauth; /* No login required if from 127.0.0.1 */
@@ -605,14 +606,11 @@
606 if( g.cgiOutput && once ){
607 once = 0;
608 cgi_printf("<p class=\"generalError\">%h</p>", z);
609 cgi_reply();
610 }else if( !g.fQuiet ){
611 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
612 }
613 }
614 free(z);
615 db_force_rollback();
616 fossil_exit(rc);
@@ -636,17 +634,14 @@
634 else
635 #endif
636 {
637 if( g.cgiOutput ){
638 g.cgiOutput = 0;
639 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
640 cgi_reply();
641 }else if( !g.fQuiet ){
642 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
643 }
644 }
645 free(z);
646 db_force_rollback();
647 fossil_exit(rc);
@@ -679,17 +674,14 @@
674 } else
675 #endif
676 {
677 if( g.cgiOutput ){
678 g.cgiOutput = 0;
679 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
680 cgi_reply();
681 }else{
682 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
683 }
684 }
685 db_force_rollback();
686 fossil_exit(rc);
687 }
@@ -707,16 +699,13 @@
699 json_warn( FSL_JSON_W_UNKNOWN, z );
700 }else
701 #endif
702 {
703 if( g.cgiOutput ){
704 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
705 }else{
706 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
707 }
708 }
709 free(z);
710 }
711
@@ -747,13 +736,11 @@
736 ** Who knows why - this is just the way windows works.
737 */
738 char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
739 WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
740 if( g.fSystemTrace ) {
741 fossil_trace("SYSTEM: %s\n", zNewCmd);
 
 
742 }
743 rc = _wsystem(zUnicode);
744 fossil_unicode_free(zUnicode);
745 free(zNewCmd);
746 #else
@@ -977,11 +964,11 @@
964 **
965 ** Display information on how to use COMMAND. To display a list of
966 ** available commands one of:
967 **
968 ** %fossil help Show common commands
969 ** %fossil help --all Show both common and auxiliary commands
970 ** %fossil help --test Show test commands only
971 ** %fossil help --aux Show auxiliary commands only
972 */
973 void help_cmd(void){
974 int rc, idx;
@@ -1225,15 +1212,17 @@
1212 }
1213 zRepo = "/";
1214 }else{
1215 for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
1216 if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
1217 if( i>0 ){
1218 zDir[i] = 0;
1219 if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1220 fossil_fatal("unable to chroot into %s", zDir);
1221 }
1222 zDir[i] = '/';
1223 }
 
1224 zRepo = &zDir[i];
1225 }
1226 if( stat(zRepo, &sStat)!=0 ){
1227 fossil_fatal("cannot stat() repository: %s", zRepo);
1228 }
1229
+17 -28
--- src/main.c
+++ src/main.c
@@ -170,11 +170,12 @@
170170
char *urlPath; /* Pathname for http: */
171171
char *urlUser; /* User id for http: */
172172
char *urlPasswd; /* Password for http: */
173173
char *urlCanonical; /* Canonical representation of the URL */
174174
char *urlProxyAuth; /* Proxy-Authorizer: string */
175
- char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */
175
+ char *urlFossil; /* The fossil query parameter on ssh: */
176
+ char *urlShell; /* The shell query parameter on ssh: */
176177
int dontKeepUrl; /* Do not persist the URL */
177178
178179
const char *zLogin; /* Login name. "" if not logged in. */
179180
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
180181
int useLocalauth; /* No login required if from 127.0.0.1 */
@@ -605,14 +606,11 @@
605606
if( g.cgiOutput && once ){
606607
once = 0;
607608
cgi_printf("<p class=\"generalError\">%h</p>", z);
608609
cgi_reply();
609610
}else if( !g.fQuiet ){
610
- char *zOut = mprintf("%s: %s\n", g.argv[0], z);
611
- fossil_force_newline();
612
- fossil_puts(zOut, 1);
613
- fossil_free(zOut);
611
+ fossil_trace("%s: %s\n", g.argv[0], z);
614612
}
615613
}
616614
free(z);
617615
db_force_rollback();
618616
fossil_exit(rc);
@@ -636,17 +634,14 @@
636634
else
637635
#endif
638636
{
639637
if( g.cgiOutput ){
640638
g.cgiOutput = 0;
641
- cgi_printf("<p class=\"generalError\">%h</p>", z);
639
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
642640
cgi_reply();
643641
}else if( !g.fQuiet ){
644
- char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
645
- fossil_force_newline();
646
- fossil_puts(zOut, 1);
647
- fossil_free(zOut);
642
+ fossil_trace("%s: %s\n", g.argv[0], z);
648643
}
649644
}
650645
free(z);
651646
db_force_rollback();
652647
fossil_exit(rc);
@@ -679,17 +674,14 @@
679674
} else
680675
#endif
681676
{
682677
if( g.cgiOutput ){
683678
g.cgiOutput = 0;
684
- cgi_printf("<p class=\"generalError\">%h</p>", z);
679
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
685680
cgi_reply();
686681
}else{
687
- char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
688
- fossil_force_newline();
689
- fossil_puts(zOut, 1);
690
- fossil_free(zOut);
682
+ fossil_trace("%s: %s\n", g.argv[0], z);
691683
}
692684
}
693685
db_force_rollback();
694686
fossil_exit(rc);
695687
}
@@ -707,16 +699,13 @@
707699
json_warn( FSL_JSON_W_UNKNOWN, z );
708700
}else
709701
#endif
710702
{
711703
if( g.cgiOutput ){
712
- cgi_printf("<p class=\"generalError\">%h</p>", z);
704
+ cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
713705
}else{
714
- char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
715
- fossil_force_newline();
716
- fossil_puts(zOut, 1);
717
- fossil_free(zOut);
706
+ fossil_trace("%s: %s\n", g.argv[0], z);
718707
}
719708
}
720709
free(z);
721710
}
722711
@@ -747,13 +736,11 @@
747736
** Who knows why - this is just the way windows works.
748737
*/
749738
char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
750739
WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
751740
if( g.fSystemTrace ) {
752
- char *zOut = mprintf("SYSTEM: %s\n", zNewCmd);
753
- fossil_puts(zOut, 1);
754
- fossil_free(zOut);
741
+ fossil_trace("SYSTEM: %s\n", zNewCmd);
755742
}
756743
rc = _wsystem(zUnicode);
757744
fossil_unicode_free(zUnicode);
758745
free(zNewCmd);
759746
#else
@@ -977,11 +964,11 @@
977964
**
978965
** Display information on how to use COMMAND. To display a list of
979966
** available commands one of:
980967
**
981968
** %fossil help Show common commands
982
-** %fossil help --all Show both command and auxiliary commands
969
+** %fossil help --all Show both common and auxiliary commands
983970
** %fossil help --test Show test commands only
984971
** %fossil help --aux Show auxiliary commands only
985972
*/
986973
void help_cmd(void){
987974
int rc, idx;
@@ -1225,15 +1212,17 @@
12251212
}
12261213
zRepo = "/";
12271214
}else{
12281215
for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
12291216
if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
1230
- zDir[i] = 0;
1231
- if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1232
- fossil_fatal("unable to chroot into %s", zDir);
1217
+ if( i>0 ){
1218
+ zDir[i] = 0;
1219
+ if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1220
+ fossil_fatal("unable to chroot into %s", zDir);
1221
+ }
1222
+ zDir[i] = '/';
12331223
}
1234
- zDir[i] = '/';
12351224
zRepo = &zDir[i];
12361225
}
12371226
if( stat(zRepo, &sStat)!=0 ){
12381227
fossil_fatal("cannot stat() repository: %s", zRepo);
12391228
}
12401229
--- src/main.c
+++ src/main.c
@@ -170,11 +170,12 @@
170 char *urlPath; /* Pathname for http: */
171 char *urlUser; /* User id for http: */
172 char *urlPasswd; /* Password for http: */
173 char *urlCanonical; /* Canonical representation of the URL */
174 char *urlProxyAuth; /* Proxy-Authorizer: string */
175 char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */
 
176 int dontKeepUrl; /* Do not persist the URL */
177
178 const char *zLogin; /* Login name. "" if not logged in. */
179 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
180 int useLocalauth; /* No login required if from 127.0.0.1 */
@@ -605,14 +606,11 @@
605 if( g.cgiOutput && once ){
606 once = 0;
607 cgi_printf("<p class=\"generalError\">%h</p>", z);
608 cgi_reply();
609 }else if( !g.fQuiet ){
610 char *zOut = mprintf("%s: %s\n", g.argv[0], z);
611 fossil_force_newline();
612 fossil_puts(zOut, 1);
613 fossil_free(zOut);
614 }
615 }
616 free(z);
617 db_force_rollback();
618 fossil_exit(rc);
@@ -636,17 +634,14 @@
636 else
637 #endif
638 {
639 if( g.cgiOutput ){
640 g.cgiOutput = 0;
641 cgi_printf("<p class=\"generalError\">%h</p>", z);
642 cgi_reply();
643 }else if( !g.fQuiet ){
644 char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
645 fossil_force_newline();
646 fossil_puts(zOut, 1);
647 fossil_free(zOut);
648 }
649 }
650 free(z);
651 db_force_rollback();
652 fossil_exit(rc);
@@ -679,17 +674,14 @@
679 } else
680 #endif
681 {
682 if( g.cgiOutput ){
683 g.cgiOutput = 0;
684 cgi_printf("<p class=\"generalError\">%h</p>", z);
685 cgi_reply();
686 }else{
687 char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
688 fossil_force_newline();
689 fossil_puts(zOut, 1);
690 fossil_free(zOut);
691 }
692 }
693 db_force_rollback();
694 fossil_exit(rc);
695 }
@@ -707,16 +699,13 @@
707 json_warn( FSL_JSON_W_UNKNOWN, z );
708 }else
709 #endif
710 {
711 if( g.cgiOutput ){
712 cgi_printf("<p class=\"generalError\">%h</p>", z);
713 }else{
714 char *zOut = mprintf("\r%s: %s\n", g.argv[0], z);
715 fossil_force_newline();
716 fossil_puts(zOut, 1);
717 fossil_free(zOut);
718 }
719 }
720 free(z);
721 }
722
@@ -747,13 +736,11 @@
747 ** Who knows why - this is just the way windows works.
748 */
749 char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
750 WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
751 if( g.fSystemTrace ) {
752 char *zOut = mprintf("SYSTEM: %s\n", zNewCmd);
753 fossil_puts(zOut, 1);
754 fossil_free(zOut);
755 }
756 rc = _wsystem(zUnicode);
757 fossil_unicode_free(zUnicode);
758 free(zNewCmd);
759 #else
@@ -977,11 +964,11 @@
977 **
978 ** Display information on how to use COMMAND. To display a list of
979 ** available commands one of:
980 **
981 ** %fossil help Show common commands
982 ** %fossil help --all Show both command and auxiliary commands
983 ** %fossil help --test Show test commands only
984 ** %fossil help --aux Show auxiliary commands only
985 */
986 void help_cmd(void){
987 int rc, idx;
@@ -1225,15 +1212,17 @@
1225 }
1226 zRepo = "/";
1227 }else{
1228 for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
1229 if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
1230 zDir[i] = 0;
1231 if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1232 fossil_fatal("unable to chroot into %s", zDir);
 
 
 
1233 }
1234 zDir[i] = '/';
1235 zRepo = &zDir[i];
1236 }
1237 if( stat(zRepo, &sStat)!=0 ){
1238 fossil_fatal("cannot stat() repository: %s", zRepo);
1239 }
1240
--- src/main.c
+++ src/main.c
@@ -170,11 +170,12 @@
170 char *urlPath; /* Pathname for http: */
171 char *urlUser; /* User id for http: */
172 char *urlPasswd; /* Password for http: */
173 char *urlCanonical; /* Canonical representation of the URL */
174 char *urlProxyAuth; /* Proxy-Authorizer: string */
175 char *urlFossil; /* The fossil query parameter on ssh: */
176 char *urlShell; /* The shell query parameter on ssh: */
177 int dontKeepUrl; /* Do not persist the URL */
178
179 const char *zLogin; /* Login name. "" if not logged in. */
180 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */
181 int useLocalauth; /* No login required if from 127.0.0.1 */
@@ -605,14 +606,11 @@
606 if( g.cgiOutput && once ){
607 once = 0;
608 cgi_printf("<p class=\"generalError\">%h</p>", z);
609 cgi_reply();
610 }else if( !g.fQuiet ){
611 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
612 }
613 }
614 free(z);
615 db_force_rollback();
616 fossil_exit(rc);
@@ -636,17 +634,14 @@
634 else
635 #endif
636 {
637 if( g.cgiOutput ){
638 g.cgiOutput = 0;
639 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
640 cgi_reply();
641 }else if( !g.fQuiet ){
642 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
643 }
644 }
645 free(z);
646 db_force_rollback();
647 fossil_exit(rc);
@@ -679,17 +674,14 @@
674 } else
675 #endif
676 {
677 if( g.cgiOutput ){
678 g.cgiOutput = 0;
679 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
680 cgi_reply();
681 }else{
682 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
683 }
684 }
685 db_force_rollback();
686 fossil_exit(rc);
687 }
@@ -707,16 +699,13 @@
699 json_warn( FSL_JSON_W_UNKNOWN, z );
700 }else
701 #endif
702 {
703 if( g.cgiOutput ){
704 cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
705 }else{
706 fossil_trace("%s: %s\n", g.argv[0], z);
 
 
 
707 }
708 }
709 free(z);
710 }
711
@@ -747,13 +736,11 @@
736 ** Who knows why - this is just the way windows works.
737 */
738 char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
739 WCHAR *zUnicode = fossil_utf8_to_unicode(zNewCmd);
740 if( g.fSystemTrace ) {
741 fossil_trace("SYSTEM: %s\n", zNewCmd);
 
 
742 }
743 rc = _wsystem(zUnicode);
744 fossil_unicode_free(zUnicode);
745 free(zNewCmd);
746 #else
@@ -977,11 +964,11 @@
964 **
965 ** Display information on how to use COMMAND. To display a list of
966 ** available commands one of:
967 **
968 ** %fossil help Show common commands
969 ** %fossil help --all Show both common and auxiliary commands
970 ** %fossil help --test Show test commands only
971 ** %fossil help --aux Show auxiliary commands only
972 */
973 void help_cmd(void){
974 int rc, idx;
@@ -1225,15 +1212,17 @@
1212 }
1213 zRepo = "/";
1214 }else{
1215 for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
1216 if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
1217 if( i>0 ){
1218 zDir[i] = 0;
1219 if( chdir(zDir) || chroot(zDir) || chdir("/") ){
1220 fossil_fatal("unable to chroot into %s", zDir);
1221 }
1222 zDir[i] = '/';
1223 }
 
1224 zRepo = &zDir[i];
1225 }
1226 if( stat(zRepo, &sStat)!=0 ){
1227 fossil_fatal("cannot stat() repository: %s", zRepo);
1228 }
1229
+1 -1
--- src/main.mk
+++ src/main.mk
@@ -1146,11 +1146,11 @@
11461146
$(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
11471147
$(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
11481148
11491149
11501150
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1151
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1151
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
11521152
11531153
#
11541154
# The list of all the targets that do not correspond to real files. This stops
11551155
# 'make' from getting confused when someone makes an error in a rule.
11561156
#
11571157
--- src/main.mk
+++ src/main.mk
@@ -1146,11 +1146,11 @@
1146 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1147 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1148
1149
1150 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1151 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1152
1153 #
1154 # The list of all the targets that do not correspond to real files. This stops
1155 # 'make' from getting confused when someone makes an error in a rule.
1156 #
1157
--- src/main.mk
+++ src/main.mk
@@ -1146,11 +1146,11 @@
1146 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1147 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1148
1149
1150 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1151 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1152
1153 #
1154 # The list of all the targets that do not correspond to real files. This stops
1155 # 'make' from getting confused when someone makes an error in a rule.
1156 #
1157
+1 -1
--- src/main.mk
+++ src/main.mk
@@ -1146,11 +1146,11 @@
11461146
$(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
11471147
$(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
11481148
11491149
11501150
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1151
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1151
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
11521152
11531153
#
11541154
# The list of all the targets that do not correspond to real files. This stops
11551155
# 'make' from getting confused when someone makes an error in a rule.
11561156
#
11571157
--- src/main.mk
+++ src/main.mk
@@ -1146,11 +1146,11 @@
1146 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1147 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1148
1149
1150 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1151 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1152
1153 #
1154 # The list of all the targets that do not correspond to real files. This stops
1155 # 'make' from getting confused when someone makes an error in a rule.
1156 #
1157
--- src/main.mk
+++ src/main.mk
@@ -1146,11 +1146,11 @@
1146 $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
1147 $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
1148
1149
1150 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1151 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1152
1153 #
1154 # The list of all the targets that do not correspond to real files. This stops
1155 # 'make' from getting confused when someone makes an error in a rule.
1156 #
1157
+34 -15
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -308,11 +308,11 @@
308308
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
309309
310310
set opt {}
311311
writeln {
312312
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
313
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
313
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
314314
315315
#
316316
# The list of all the targets that do not correspond to real files. This stops
317317
# 'make' from getting confused when someone makes an error in a rule.
318318
#
@@ -340,15 +340,15 @@
340340
#
341341
# This file is automatically generated. Instead of editing this
342342
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
343343
# to regenerate this file.
344344
#
345
-# This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
346
-# MinGW-w64.
345
+# This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
346
+# MinGW or MinGW-w64.
347347
#
348348
349
-#### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
349
+#### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
350350
# By default, this is an empty string (i.e. use the native compiler).
351351
#
352352
PREFIX =
353353
# PREFIX = mingw32-
354354
# PREFIX = i686-pc-mingw32-
@@ -694,11 +694,11 @@
694694
ifdef FOSSIL_ENABLE_TCL
695695
EXTRAOBJ += $(OBJDIR)/th_tcl.o
696696
endif
697697
698698
zlib:
699
- make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
699
+ $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
700700
701701
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
702702
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
703703
704704
# This rule prevents make from using its default rules to try build
@@ -751,11 +751,11 @@
751751
set opt $SQLITE_OPTIONS
752752
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753753
754754
set opt {}
755755
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756
-writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
756
+writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
757757
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758758
759759
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760760
set opt {-Dmain=sqlite3_shell}
761761
append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
@@ -959,18 +959,35 @@
959959
960960
# zlib options
961961
ZINCDIR = $(B)\compat\zlib
962962
ZLIBDIR = $(B)\compat\zlib
963963
ZLIB = zlib.lib
964
+
965
+# Uncomment to enable JSON API
966
+# FOSSIL_ENABLE_JSON = 1
967
+
968
+# Uncomment to enable markdown support
969
+# FOSSIL_ENABLE_MARKDOWN = 1
964970
965971
INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
966972
967973
CFLAGS = -nologo -MT -O2
968974
BCC = $(CC) $(CFLAGS)
969975
TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
976
+RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
970977
LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
971978
LIBDIR = -LIBPATH:$(ZLIBDIR)
979
+
980
+!ifdef FOSSIL_ENABLE_JSON
981
+TCC = $(TCC) -DFOSSIL_ENABLE_JSON
982
+RCC = $(RCC) -DFOSSIL_ENABLE_JSON
983
+!endif
984
+
985
+!ifdef FOSSIL_ENABLE_MARKDOWN
986
+TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
987
+RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
988
+!endif
972989
}
973990
regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS
974991
set j " \\\n "
975992
writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n"
976993
writeln -nonewline "SRC = "
@@ -981,24 +998,22 @@
981998
writeln -nonewline " "
982999
}
9831000
writeln -nonewline "${s}_.c"; incr i
9841001
}
9851002
writeln "\n"
1003
+set AdditionalObj [list shell sqlite3 th th_lang cson_amalgamation]
9861004
writeln -nonewline "OBJ = "
9871005
set i 0
988
-foreach s [lsort $src] {
1006
+foreach s [lsort [concat $src $AdditionalObj]] {
9891007
if {$i > 0} {
9901008
writeln " \\"
9911009
writeln -nonewline " "
9921010
}
9931011
writeln -nonewline "\$(OX)\\$s\$O"; incr i
9941012
}
9951013
writeln " \\"
996
-writeln " \$(OX)\\shell\$O \\"
997
-writeln " \$(OX)\\sqlite3\$O \\"
998
-writeln " \$(OX)\\th\$O \\"
999
-writeln " \$(OX)\\th_lang\$O"
1014
+writeln -nonewline " \$(OX)\\fossil.res\n"
10001015
writeln {
10011016
APPNAME = $(OX)\fossil$(E)
10021017
10031018
all: $(OX) $(APPNAME)
10041019
@@ -1006,15 +1021,15 @@
10061021
@echo Building zlib from "$(ZLIBDIR)"...
10071022
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
10081023
10091024
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
10101025
cd $(OX)
1011
- link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
1026
+ link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
10121027
10131028
$(OX)\linkopts: $B\win\Makefile.msc}
10141029
set redir {>}
1015
-foreach s [lsort [concat $src {shell sqlite3 th th_lang}]] {
1030
+foreach s [lsort [concat $src $AdditionalObj]] {
10161031
writeln "\techo \$(OX)\\$s.obj $redir \$@"
10171032
set redir {>>}
10181033
}
10191034
writeln "\techo \$(LIBS) >> \$@\n\n"
10201035
@@ -1047,12 +1062,12 @@
10471062
$(OX)\th_lang$O : $(SRCDIR)\th_lang.c
10481063
$(TCC) /Fo$@ -c $**
10491064
10501065
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
10511066
$** > $@
1052
-$(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
1053
- cp $(SRCDIR)\cson_amalgamation.h $@
1067
+$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
1068
+ $(TCC) /Fo$@ -c $**
10541069
10551070
page_index.h: mkindex$E $(SRC)
10561071
$** > $@
10571072
10581073
clean:
@@ -1062,10 +1077,11 @@
10621077
-del *.h
10631078
-del *.map
10641079
-del *.manifest
10651080
-del headers
10661081
-del linkopts
1082
+ -del *.res
10671083
10681084
realclean: clean
10691085
-del $(APPNAME)
10701086
-del translate$E
10711087
-del mkindex$E
@@ -1092,10 +1108,13 @@
10921108
writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h"
10931109
writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n"
10941110
writeln "${s}_.c : \$(SRCDIR)\\$s.c"
10951111
writeln "\ttranslate\$E \$** > \$@\n"
10961112
}
1113
+
1114
+writeln "fossil.res : \$B\\win\\fossil.rc"
1115
+writeln "\t\$(RCC) -fo \$@ \$**"
10971116
10981117
writeln "headers: makeheaders\$E page_index.h VERSION.h"
10991118
writeln -nonewline "\tmakeheaders\$E "
11001119
set i 0
11011120
foreach s [lsort $src] {
11021121
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -308,11 +308,11 @@
308 writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
309
310 set opt {}
311 writeln {
312 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
313 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
314
315 #
316 # The list of all the targets that do not correspond to real files. This stops
317 # 'make' from getting confused when someone makes an error in a rule.
318 #
@@ -340,15 +340,15 @@
340 #
341 # This file is automatically generated. Instead of editing this
342 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
343 # to regenerate this file.
344 #
345 # This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
346 # MinGW-w64.
347 #
348
349 #### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
350 # By default, this is an empty string (i.e. use the native compiler).
351 #
352 PREFIX =
353 # PREFIX = mingw32-
354 # PREFIX = i686-pc-mingw32-
@@ -694,11 +694,11 @@
694 ifdef FOSSIL_ENABLE_TCL
695 EXTRAOBJ += $(OBJDIR)/th_tcl.o
696 endif
697
698 zlib:
699 make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
700
701 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
702 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
703
704 # This rule prevents make from using its default rules to try build
@@ -751,11 +751,11 @@
751 set opt $SQLITE_OPTIONS
752 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753
754 set opt {}
755 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
757 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758
759 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760 set opt {-Dmain=sqlite3_shell}
761 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
@@ -959,18 +959,35 @@
959
960 # zlib options
961 ZINCDIR = $(B)\compat\zlib
962 ZLIBDIR = $(B)\compat\zlib
963 ZLIB = zlib.lib
 
 
 
 
 
 
964
965 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
966
967 CFLAGS = -nologo -MT -O2
968 BCC = $(CC) $(CFLAGS)
969 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
 
970 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
971 LIBDIR = -LIBPATH:$(ZLIBDIR)
 
 
 
 
 
 
 
 
 
 
972 }
973 regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS
974 set j " \\\n "
975 writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n"
976 writeln -nonewline "SRC = "
@@ -981,24 +998,22 @@
981 writeln -nonewline " "
982 }
983 writeln -nonewline "${s}_.c"; incr i
984 }
985 writeln "\n"
 
986 writeln -nonewline "OBJ = "
987 set i 0
988 foreach s [lsort $src] {
989 if {$i > 0} {
990 writeln " \\"
991 writeln -nonewline " "
992 }
993 writeln -nonewline "\$(OX)\\$s\$O"; incr i
994 }
995 writeln " \\"
996 writeln " \$(OX)\\shell\$O \\"
997 writeln " \$(OX)\\sqlite3\$O \\"
998 writeln " \$(OX)\\th\$O \\"
999 writeln " \$(OX)\\th_lang\$O"
1000 writeln {
1001 APPNAME = $(OX)\fossil$(E)
1002
1003 all: $(OX) $(APPNAME)
1004
@@ -1006,15 +1021,15 @@
1006 @echo Building zlib from "$(ZLIBDIR)"...
1007 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
1008
1009 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
1010 cd $(OX)
1011 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
1012
1013 $(OX)\linkopts: $B\win\Makefile.msc}
1014 set redir {>}
1015 foreach s [lsort [concat $src {shell sqlite3 th th_lang}]] {
1016 writeln "\techo \$(OX)\\$s.obj $redir \$@"
1017 set redir {>>}
1018 }
1019 writeln "\techo \$(LIBS) >> \$@\n\n"
1020
@@ -1047,12 +1062,12 @@
1047 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
1048 $(TCC) /Fo$@ -c $**
1049
1050 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
1051 $** > $@
1052 $(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
1053 cp $(SRCDIR)\cson_amalgamation.h $@
1054
1055 page_index.h: mkindex$E $(SRC)
1056 $** > $@
1057
1058 clean:
@@ -1062,10 +1077,11 @@
1062 -del *.h
1063 -del *.map
1064 -del *.manifest
1065 -del headers
1066 -del linkopts
 
1067
1068 realclean: clean
1069 -del $(APPNAME)
1070 -del translate$E
1071 -del mkindex$E
@@ -1092,10 +1108,13 @@
1092 writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h"
1093 writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n"
1094 writeln "${s}_.c : \$(SRCDIR)\\$s.c"
1095 writeln "\ttranslate\$E \$** > \$@\n"
1096 }
 
 
 
1097
1098 writeln "headers: makeheaders\$E page_index.h VERSION.h"
1099 writeln -nonewline "\tmakeheaders\$E "
1100 set i 0
1101 foreach s [lsort $src] {
1102
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -308,11 +308,11 @@
308 writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
309
310 set opt {}
311 writeln {
312 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
313 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
314
315 #
316 # The list of all the targets that do not correspond to real files. This stops
317 # 'make' from getting confused when someone makes an error in a rule.
318 #
@@ -340,15 +340,15 @@
340 #
341 # This file is automatically generated. Instead of editing this
342 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
343 # to regenerate this file.
344 #
345 # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
346 # MinGW or MinGW-w64.
347 #
348
349 #### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
350 # By default, this is an empty string (i.e. use the native compiler).
351 #
352 PREFIX =
353 # PREFIX = mingw32-
354 # PREFIX = i686-pc-mingw32-
@@ -694,11 +694,11 @@
694 ifdef FOSSIL_ENABLE_TCL
695 EXTRAOBJ += $(OBJDIR)/th_tcl.o
696 endif
697
698 zlib:
699 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
700
701 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
702 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
703
704 # This rule prevents make from using its default rules to try build
@@ -751,11 +751,11 @@
751 set opt $SQLITE_OPTIONS
752 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753
754 set opt {}
755 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
757 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758
759 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760 set opt {-Dmain=sqlite3_shell}
761 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
@@ -959,18 +959,35 @@
959
960 # zlib options
961 ZINCDIR = $(B)\compat\zlib
962 ZLIBDIR = $(B)\compat\zlib
963 ZLIB = zlib.lib
964
965 # Uncomment to enable JSON API
966 # FOSSIL_ENABLE_JSON = 1
967
968 # Uncomment to enable markdown support
969 # FOSSIL_ENABLE_MARKDOWN = 1
970
971 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
972
973 CFLAGS = -nologo -MT -O2
974 BCC = $(CC) $(CFLAGS)
975 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
976 RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
977 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
978 LIBDIR = -LIBPATH:$(ZLIBDIR)
979
980 !ifdef FOSSIL_ENABLE_JSON
981 TCC = $(TCC) -DFOSSIL_ENABLE_JSON
982 RCC = $(RCC) -DFOSSIL_ENABLE_JSON
983 !endif
984
985 !ifdef FOSSIL_ENABLE_MARKDOWN
986 TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
987 RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
988 !endif
989 }
990 regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS
991 set j " \\\n "
992 writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n"
993 writeln -nonewline "SRC = "
@@ -981,24 +998,22 @@
998 writeln -nonewline " "
999 }
1000 writeln -nonewline "${s}_.c"; incr i
1001 }
1002 writeln "\n"
1003 set AdditionalObj [list shell sqlite3 th th_lang cson_amalgamation]
1004 writeln -nonewline "OBJ = "
1005 set i 0
1006 foreach s [lsort [concat $src $AdditionalObj]] {
1007 if {$i > 0} {
1008 writeln " \\"
1009 writeln -nonewline " "
1010 }
1011 writeln -nonewline "\$(OX)\\$s\$O"; incr i
1012 }
1013 writeln " \\"
1014 writeln -nonewline " \$(OX)\\fossil.res\n"
 
 
 
1015 writeln {
1016 APPNAME = $(OX)\fossil$(E)
1017
1018 all: $(OX) $(APPNAME)
1019
@@ -1006,15 +1021,15 @@
1021 @echo Building zlib from "$(ZLIBDIR)"...
1022 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
1023
1024 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
1025 cd $(OX)
1026 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
1027
1028 $(OX)\linkopts: $B\win\Makefile.msc}
1029 set redir {>}
1030 foreach s [lsort [concat $src $AdditionalObj]] {
1031 writeln "\techo \$(OX)\\$s.obj $redir \$@"
1032 set redir {>>}
1033 }
1034 writeln "\techo \$(LIBS) >> \$@\n\n"
1035
@@ -1047,12 +1062,12 @@
1062 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
1063 $(TCC) /Fo$@ -c $**
1064
1065 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
1066 $** > $@
1067 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
1068 $(TCC) /Fo$@ -c $**
1069
1070 page_index.h: mkindex$E $(SRC)
1071 $** > $@
1072
1073 clean:
@@ -1062,10 +1077,11 @@
1077 -del *.h
1078 -del *.map
1079 -del *.manifest
1080 -del headers
1081 -del linkopts
1082 -del *.res
1083
1084 realclean: clean
1085 -del $(APPNAME)
1086 -del translate$E
1087 -del mkindex$E
@@ -1092,10 +1108,13 @@
1108 writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h"
1109 writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n"
1110 writeln "${s}_.c : \$(SRCDIR)\\$s.c"
1111 writeln "\ttranslate\$E \$** > \$@\n"
1112 }
1113
1114 writeln "fossil.res : \$B\\win\\fossil.rc"
1115 writeln "\t\$(RCC) -fo \$@ \$**"
1116
1117 writeln "headers: makeheaders\$E page_index.h VERSION.h"
1118 writeln -nonewline "\tmakeheaders\$E "
1119 set i 0
1120 foreach s [lsort $src] {
1121
+34 -15
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -308,11 +308,11 @@
308308
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
309309
310310
set opt {}
311311
writeln {
312312
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
313
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
313
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
314314
315315
#
316316
# The list of all the targets that do not correspond to real files. This stops
317317
# 'make' from getting confused when someone makes an error in a rule.
318318
#
@@ -340,15 +340,15 @@
340340
#
341341
# This file is automatically generated. Instead of editing this
342342
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
343343
# to regenerate this file.
344344
#
345
-# This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
346
-# MinGW-w64.
345
+# This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
346
+# MinGW or MinGW-w64.
347347
#
348348
349
-#### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
349
+#### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
350350
# By default, this is an empty string (i.e. use the native compiler).
351351
#
352352
PREFIX =
353353
# PREFIX = mingw32-
354354
# PREFIX = i686-pc-mingw32-
@@ -694,11 +694,11 @@
694694
ifdef FOSSIL_ENABLE_TCL
695695
EXTRAOBJ += $(OBJDIR)/th_tcl.o
696696
endif
697697
698698
zlib:
699
- make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
699
+ $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
700700
701701
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
702702
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
703703
704704
# This rule prevents make from using its default rules to try build
@@ -751,11 +751,11 @@
751751
set opt $SQLITE_OPTIONS
752752
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753753
754754
set opt {}
755755
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756
-writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
756
+writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
757757
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758758
759759
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760760
set opt {-Dmain=sqlite3_shell}
761761
append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
@@ -959,18 +959,35 @@
959959
960960
# zlib options
961961
ZINCDIR = $(B)\compat\zlib
962962
ZLIBDIR = $(B)\compat\zlib
963963
ZLIB = zlib.lib
964
+
965
+# Uncomment to enable JSON API
966
+# FOSSIL_ENABLE_JSON = 1
967
+
968
+# Uncomment to enable markdown support
969
+# FOSSIL_ENABLE_MARKDOWN = 1
964970
965971
INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
966972
967973
CFLAGS = -nologo -MT -O2
968974
BCC = $(CC) $(CFLAGS)
969975
TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
976
+RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
970977
LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
971978
LIBDIR = -LIBPATH:$(ZLIBDIR)
979
+
980
+!ifdef FOSSIL_ENABLE_JSON
981
+TCC = $(TCC) -DFOSSIL_ENABLE_JSON
982
+RCC = $(RCC) -DFOSSIL_ENABLE_JSON
983
+!endif
984
+
985
+!ifdef FOSSIL_ENABLE_MARKDOWN
986
+TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
987
+RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
988
+!endif
972989
}
973990
regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS
974991
set j " \\\n "
975992
writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n"
976993
writeln -nonewline "SRC = "
@@ -981,24 +998,22 @@
981998
writeln -nonewline " "
982999
}
9831000
writeln -nonewline "${s}_.c"; incr i
9841001
}
9851002
writeln "\n"
1003
+set AdditionalObj [list shell sqlite3 th th_lang cson_amalgamation]
9861004
writeln -nonewline "OBJ = "
9871005
set i 0
988
-foreach s [lsort $src] {
1006
+foreach s [lsort [concat $src $AdditionalObj]] {
9891007
if {$i > 0} {
9901008
writeln " \\"
9911009
writeln -nonewline " "
9921010
}
9931011
writeln -nonewline "\$(OX)\\$s\$O"; incr i
9941012
}
9951013
writeln " \\"
996
-writeln " \$(OX)\\shell\$O \\"
997
-writeln " \$(OX)\\sqlite3\$O \\"
998
-writeln " \$(OX)\\th\$O \\"
999
-writeln " \$(OX)\\th_lang\$O"
1014
+writeln -nonewline " \$(OX)\\fossil.res\n"
10001015
writeln {
10011016
APPNAME = $(OX)\fossil$(E)
10021017
10031018
all: $(OX) $(APPNAME)
10041019
@@ -1006,15 +1021,15 @@
10061021
@echo Building zlib from "$(ZLIBDIR)"...
10071022
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
10081023
10091024
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
10101025
cd $(OX)
1011
- link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
1026
+ link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
10121027
10131028
$(OX)\linkopts: $B\win\Makefile.msc}
10141029
set redir {>}
1015
-foreach s [lsort [concat $src {shell sqlite3 th th_lang}]] {
1030
+foreach s [lsort [concat $src $AdditionalObj]] {
10161031
writeln "\techo \$(OX)\\$s.obj $redir \$@"
10171032
set redir {>>}
10181033
}
10191034
writeln "\techo \$(LIBS) >> \$@\n\n"
10201035
@@ -1047,12 +1062,12 @@
10471062
$(OX)\th_lang$O : $(SRCDIR)\th_lang.c
10481063
$(TCC) /Fo$@ -c $**
10491064
10501065
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
10511066
$** > $@
1052
-$(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
1053
- cp $(SRCDIR)\cson_amalgamation.h $@
1067
+$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
1068
+ $(TCC) /Fo$@ -c $**
10541069
10551070
page_index.h: mkindex$E $(SRC)
10561071
$** > $@
10571072
10581073
clean:
@@ -1062,10 +1077,11 @@
10621077
-del *.h
10631078
-del *.map
10641079
-del *.manifest
10651080
-del headers
10661081
-del linkopts
1082
+ -del *.res
10671083
10681084
realclean: clean
10691085
-del $(APPNAME)
10701086
-del translate$E
10711087
-del mkindex$E
@@ -1092,10 +1108,13 @@
10921108
writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h"
10931109
writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n"
10941110
writeln "${s}_.c : \$(SRCDIR)\\$s.c"
10951111
writeln "\ttranslate\$E \$** > \$@\n"
10961112
}
1113
+
1114
+writeln "fossil.res : \$B\\win\\fossil.rc"
1115
+writeln "\t\$(RCC) -fo \$@ \$**"
10971116
10981117
writeln "headers: makeheaders\$E page_index.h VERSION.h"
10991118
writeln -nonewline "\tmakeheaders\$E "
11001119
set i 0
11011120
foreach s [lsort $src] {
11021121
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -308,11 +308,11 @@
308 writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
309
310 set opt {}
311 writeln {
312 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
313 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
314
315 #
316 # The list of all the targets that do not correspond to real files. This stops
317 # 'make' from getting confused when someone makes an error in a rule.
318 #
@@ -340,15 +340,15 @@
340 #
341 # This file is automatically generated. Instead of editing this
342 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
343 # to regenerate this file.
344 #
345 # This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
346 # MinGW-w64.
347 #
348
349 #### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
350 # By default, this is an empty string (i.e. use the native compiler).
351 #
352 PREFIX =
353 # PREFIX = mingw32-
354 # PREFIX = i686-pc-mingw32-
@@ -694,11 +694,11 @@
694 ifdef FOSSIL_ENABLE_TCL
695 EXTRAOBJ += $(OBJDIR)/th_tcl.o
696 endif
697
698 zlib:
699 make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
700
701 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
702 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
703
704 # This rule prevents make from using its default rules to try build
@@ -751,11 +751,11 @@
751 set opt $SQLITE_OPTIONS
752 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753
754 set opt {}
755 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
757 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758
759 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760 set opt {-Dmain=sqlite3_shell}
761 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
@@ -959,18 +959,35 @@
959
960 # zlib options
961 ZINCDIR = $(B)\compat\zlib
962 ZLIBDIR = $(B)\compat\zlib
963 ZLIB = zlib.lib
 
 
 
 
 
 
964
965 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
966
967 CFLAGS = -nologo -MT -O2
968 BCC = $(CC) $(CFLAGS)
969 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
 
970 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
971 LIBDIR = -LIBPATH:$(ZLIBDIR)
 
 
 
 
 
 
 
 
 
 
972 }
973 regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS
974 set j " \\\n "
975 writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n"
976 writeln -nonewline "SRC = "
@@ -981,24 +998,22 @@
981 writeln -nonewline " "
982 }
983 writeln -nonewline "${s}_.c"; incr i
984 }
985 writeln "\n"
 
986 writeln -nonewline "OBJ = "
987 set i 0
988 foreach s [lsort $src] {
989 if {$i > 0} {
990 writeln " \\"
991 writeln -nonewline " "
992 }
993 writeln -nonewline "\$(OX)\\$s\$O"; incr i
994 }
995 writeln " \\"
996 writeln " \$(OX)\\shell\$O \\"
997 writeln " \$(OX)\\sqlite3\$O \\"
998 writeln " \$(OX)\\th\$O \\"
999 writeln " \$(OX)\\th_lang\$O"
1000 writeln {
1001 APPNAME = $(OX)\fossil$(E)
1002
1003 all: $(OX) $(APPNAME)
1004
@@ -1006,15 +1021,15 @@
1006 @echo Building zlib from "$(ZLIBDIR)"...
1007 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
1008
1009 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
1010 cd $(OX)
1011 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
1012
1013 $(OX)\linkopts: $B\win\Makefile.msc}
1014 set redir {>}
1015 foreach s [lsort [concat $src {shell sqlite3 th th_lang}]] {
1016 writeln "\techo \$(OX)\\$s.obj $redir \$@"
1017 set redir {>>}
1018 }
1019 writeln "\techo \$(LIBS) >> \$@\n\n"
1020
@@ -1047,12 +1062,12 @@
1047 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
1048 $(TCC) /Fo$@ -c $**
1049
1050 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
1051 $** > $@
1052 $(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
1053 cp $(SRCDIR)\cson_amalgamation.h $@
1054
1055 page_index.h: mkindex$E $(SRC)
1056 $** > $@
1057
1058 clean:
@@ -1062,10 +1077,11 @@
1062 -del *.h
1063 -del *.map
1064 -del *.manifest
1065 -del headers
1066 -del linkopts
 
1067
1068 realclean: clean
1069 -del $(APPNAME)
1070 -del translate$E
1071 -del mkindex$E
@@ -1092,10 +1108,13 @@
1092 writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h"
1093 writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n"
1094 writeln "${s}_.c : \$(SRCDIR)\\$s.c"
1095 writeln "\ttranslate\$E \$** > \$@\n"
1096 }
 
 
 
1097
1098 writeln "headers: makeheaders\$E page_index.h VERSION.h"
1099 writeln -nonewline "\tmakeheaders\$E "
1100 set i 0
1101 foreach s [lsort $src] {
1102
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -308,11 +308,11 @@
308 writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
309
310 set opt {}
311 writeln {
312 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
313 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
314
315 #
316 # The list of all the targets that do not correspond to real files. This stops
317 # 'make' from getting confused when someone makes an error in a rule.
318 #
@@ -340,15 +340,15 @@
340 #
341 # This file is automatically generated. Instead of editing this
342 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
343 # to regenerate this file.
344 #
345 # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
346 # MinGW or MinGW-w64.
347 #
348
349 #### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
350 # By default, this is an empty string (i.e. use the native compiler).
351 #
352 PREFIX =
353 # PREFIX = mingw32-
354 # PREFIX = i686-pc-mingw32-
@@ -694,11 +694,11 @@
694 ifdef FOSSIL_ENABLE_TCL
695 EXTRAOBJ += $(OBJDIR)/th_tcl.o
696 endif
697
698 zlib:
699 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
700
701 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
702 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
703
704 # This rule prevents make from using its default rules to try build
@@ -751,11 +751,11 @@
751 set opt $SQLITE_OPTIONS
752 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
753
754 set opt {}
755 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
756 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
757 writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
758
759 writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
760 set opt {-Dmain=sqlite3_shell}
761 append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
@@ -959,18 +959,35 @@
959
960 # zlib options
961 ZINCDIR = $(B)\compat\zlib
962 ZLIBDIR = $(B)\compat\zlib
963 ZLIB = zlib.lib
964
965 # Uncomment to enable JSON API
966 # FOSSIL_ENABLE_JSON = 1
967
968 # Uncomment to enable markdown support
969 # FOSSIL_ENABLE_MARKDOWN = 1
970
971 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
972
973 CFLAGS = -nologo -MT -O2
974 BCC = $(CC) $(CFLAGS)
975 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
976 RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
977 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
978 LIBDIR = -LIBPATH:$(ZLIBDIR)
979
980 !ifdef FOSSIL_ENABLE_JSON
981 TCC = $(TCC) -DFOSSIL_ENABLE_JSON
982 RCC = $(RCC) -DFOSSIL_ENABLE_JSON
983 !endif
984
985 !ifdef FOSSIL_ENABLE_MARKDOWN
986 TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
987 RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
988 !endif
989 }
990 regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS
991 set j " \\\n "
992 writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n"
993 writeln -nonewline "SRC = "
@@ -981,24 +998,22 @@
998 writeln -nonewline " "
999 }
1000 writeln -nonewline "${s}_.c"; incr i
1001 }
1002 writeln "\n"
1003 set AdditionalObj [list shell sqlite3 th th_lang cson_amalgamation]
1004 writeln -nonewline "OBJ = "
1005 set i 0
1006 foreach s [lsort [concat $src $AdditionalObj]] {
1007 if {$i > 0} {
1008 writeln " \\"
1009 writeln -nonewline " "
1010 }
1011 writeln -nonewline "\$(OX)\\$s\$O"; incr i
1012 }
1013 writeln " \\"
1014 writeln -nonewline " \$(OX)\\fossil.res\n"
 
 
 
1015 writeln {
1016 APPNAME = $(OX)\fossil$(E)
1017
1018 all: $(OX) $(APPNAME)
1019
@@ -1006,15 +1021,15 @@
1021 @echo Building zlib from "$(ZLIBDIR)"...
1022 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
1023
1024 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
1025 cd $(OX)
1026 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
1027
1028 $(OX)\linkopts: $B\win\Makefile.msc}
1029 set redir {>}
1030 foreach s [lsort [concat $src $AdditionalObj]] {
1031 writeln "\techo \$(OX)\\$s.obj $redir \$@"
1032 set redir {>>}
1033 }
1034 writeln "\techo \$(LIBS) >> \$@\n\n"
1035
@@ -1047,12 +1062,12 @@
1062 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
1063 $(TCC) /Fo$@ -c $**
1064
1065 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
1066 $** > $@
1067 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
1068 $(TCC) /Fo$@ -c $**
1069
1070 page_index.h: mkindex$E $(SRC)
1071 $** > $@
1072
1073 clean:
@@ -1062,10 +1077,11 @@
1077 -del *.h
1078 -del *.map
1079 -del *.manifest
1080 -del headers
1081 -del linkopts
1082 -del *.res
1083
1084 realclean: clean
1085 -del $(APPNAME)
1086 -del translate$E
1087 -del mkindex$E
@@ -1092,10 +1108,13 @@
1108 writeln "\$(OX)\\$s\$O : ${s}_.c ${s}.h"
1109 writeln "\t\$(TCC) /Fo\$@ -c ${s}_.c\n"
1110 writeln "${s}_.c : \$(SRCDIR)\\$s.c"
1111 writeln "\ttranslate\$E \$** > \$@\n"
1112 }
1113
1114 writeln "fossil.res : \$B\\win\\fossil.rc"
1115 writeln "\t\$(RCC) -fo \$@ \$**"
1116
1117 writeln "headers: makeheaders\$E page_index.h VERSION.h"
1118 writeln -nonewline "\tmakeheaders\$E "
1119 set i 0
1120 foreach s [lsort $src] {
1121
+71 -8
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
5757
5858
5959
/*
6060
** COMMAND: merge
6161
**
62
-** Usage: %fossil merge ?OPTIONS? VERSION
62
+** Usage: %fossil merge ?OPTIONS? ?VERSION?
6363
**
6464
** The argument VERSION is a version that should be merged into the
6565
** current checkout. All changes from VERSION back to the nearest
6666
** common ancestor are merged. Except, if either of the --cherrypick or
6767
** --backout options are used only the changes associated with the
6868
** single check-in VERSION are merged. The --backout option causes
6969
** the changes associated with VERSION to be removed from the current
7070
** checkout rather than added.
71
+**
72
+** If the VERSION argument is omitted, then Fossil attempts to find
73
+** a recent fork on the current branch to merge.
7174
**
7275
** Only file content is merged. The result continues to use the
7376
** file and directory names from the current checkout even if those
7477
** names might have been changed in the branch being merged in.
7578
**
@@ -131,24 +134,84 @@
131134
zBinGlob = find_option("binary",0,1);
132135
nochangeFlag = find_option("nochange","n",0)!=0;
133136
forceFlag = find_option("force","f",0)!=0;
134137
zPivot = find_option("baseline",0,1);
135138
capture_case_sensitive_option();
136
- if( g.argc!=3 ){
137
- usage("VERSION");
138
- }
139
+ verify_all_options();
139140
db_must_be_within_tree();
140141
caseSensitive = filenames_are_case_sensitive();
141142
if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
142143
vid = db_lget_int("checkout", 0);
143144
if( vid==0 ){
144145
fossil_fatal("nothing is checked out");
145146
}
146
- mid = name_to_typed_rid(g.argv[2], "ci");
147
- if( mid==0 || !is_a_version(mid) ){
148
- fossil_fatal("not a version: %s", g.argv[2]);
147
+
148
+ /* Find mid, the artifactID of the version to be merged into the current
149
+ ** check-out */
150
+ if( g.argc==3 ){
151
+ /* Mid is specified as an argument on the command-line */
152
+ mid = name_to_typed_rid(g.argv[2], "ci");
153
+ if( mid==0 || !is_a_version(mid) ){
154
+ fossil_fatal("not a version: %s", g.argv[2]);
155
+ }
156
+ }else if( g.argc==2 ){
157
+ /* No version specified on the command-line so pick the most recent
158
+ ** leaf that is (1) not the version currently checked out and (2)
159
+ ** has not already been merged into the current checkout and (3)
160
+ ** the leaf is not closed and (4) the leaf is in the same branch
161
+ ** as the current checkout.
162
+ */
163
+ Stmt q;
164
+ if( pickFlag || backoutFlag ){
165
+ fossil_fatal("cannot use --cherrypick or --backout with a fork merge");
166
+ }
167
+ mid = db_int(0,
168
+ "SELECT leaf.rid"
169
+ " FROM leaf, event"
170
+ " WHERE leaf.rid=event.objid"
171
+ " AND leaf.rid!=%d" /* Constraint (1) */
172
+ " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
173
+ " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
174
+ " WHERE rid=leaf.rid"
175
+ " AND tagid=%d"
176
+ " AND tagtype>0)"
177
+ " AND (SELECT value FROM tagxref" /* Constraint (4) */
178
+ " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
179
+ " (SELECT value FROM tagxref"
180
+ " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
181
+ " ORDER BY event.mtime DESC LIMIT 1",
182
+ vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
183
+ );
184
+ if( mid==0 ){
185
+ fossil_fatal("no unmerged forks of branch \"%s\"",
186
+ db_text(0, "SELECT value FROM tagxref"
187
+ " WHERE tagid=%d AND rid=%d AND tagtype>0",
188
+ TAG_BRANCH, vid)
189
+ );
190
+ }
191
+ db_prepare(&q,
192
+ "SELECT blob.uuid,"
193
+ " datetime(event.mtime,'localtime'),"
194
+ " coalesce(ecomment, comment),"
195
+ " coalesce(euser, user)"
196
+ " FROM event, blob"
197
+ " WHERE event.objid=%d AND blob.rid=%d",
198
+ mid, mid
199
+ );
200
+ if( db_step(&q)==SQLITE_ROW ){
201
+ char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
202
+ db_column_text(&q, 0), db_column_text(&q, 1),
203
+ db_column_text(&q, 3), db_column_text(&q, 2));
204
+ comment_print(zCom, 0, 79);
205
+ fossil_free(zCom);
206
+ }
207
+ db_finalize(&q);
208
+ }else{
209
+ usage("?OPTIONS? ?VERSION?");
210
+ return;
149211
}
212
+
150213
if( zPivot ){
151214
pid = name_to_typed_rid(zPivot, "ci");
152215
if( pid==0 || !is_a_version(pid) ){
153216
fossil_fatal("not a version: %s", zPivot);
154217
}
@@ -347,11 +410,11 @@
347410
"SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
348411
);
349412
while( db_step(&q)==SQLITE_ROW ){
350413
int idm = db_column_int(&q, 0);
351414
char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
352
- fossil_warning("WARNING - no common ancestor: %s\n", zName);
415
+ fossil_warning("WARNING - no common ancestor: %s", zName);
353416
free(zName);
354417
db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
355418
}
356419
db_finalize(&q);
357420
358421
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
57
58
59 /*
60 ** COMMAND: merge
61 **
62 ** Usage: %fossil merge ?OPTIONS? VERSION
63 **
64 ** The argument VERSION is a version that should be merged into the
65 ** current checkout. All changes from VERSION back to the nearest
66 ** common ancestor are merged. Except, if either of the --cherrypick or
67 ** --backout options are used only the changes associated with the
68 ** single check-in VERSION are merged. The --backout option causes
69 ** the changes associated with VERSION to be removed from the current
70 ** checkout rather than added.
 
 
 
71 **
72 ** Only file content is merged. The result continues to use the
73 ** file and directory names from the current checkout even if those
74 ** names might have been changed in the branch being merged in.
75 **
@@ -131,24 +134,84 @@
131 zBinGlob = find_option("binary",0,1);
132 nochangeFlag = find_option("nochange","n",0)!=0;
133 forceFlag = find_option("force","f",0)!=0;
134 zPivot = find_option("baseline",0,1);
135 capture_case_sensitive_option();
136 if( g.argc!=3 ){
137 usage("VERSION");
138 }
139 db_must_be_within_tree();
140 caseSensitive = filenames_are_case_sensitive();
141 if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
142 vid = db_lget_int("checkout", 0);
143 if( vid==0 ){
144 fossil_fatal("nothing is checked out");
145 }
146 mid = name_to_typed_rid(g.argv[2], "ci");
147 if( mid==0 || !is_a_version(mid) ){
148 fossil_fatal("not a version: %s", g.argv[2]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149 }
 
150 if( zPivot ){
151 pid = name_to_typed_rid(zPivot, "ci");
152 if( pid==0 || !is_a_version(pid) ){
153 fossil_fatal("not a version: %s", zPivot);
154 }
@@ -347,11 +410,11 @@
347 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
348 );
349 while( db_step(&q)==SQLITE_ROW ){
350 int idm = db_column_int(&q, 0);
351 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
352 fossil_warning("WARNING - no common ancestor: %s\n", zName);
353 free(zName);
354 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
355 }
356 db_finalize(&q);
357
358
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
57
58
59 /*
60 ** COMMAND: merge
61 **
62 ** Usage: %fossil merge ?OPTIONS? ?VERSION?
63 **
64 ** The argument VERSION is a version that should be merged into the
65 ** current checkout. All changes from VERSION back to the nearest
66 ** common ancestor are merged. Except, if either of the --cherrypick or
67 ** --backout options are used only the changes associated with the
68 ** single check-in VERSION are merged. The --backout option causes
69 ** the changes associated with VERSION to be removed from the current
70 ** checkout rather than added.
71 **
72 ** If the VERSION argument is omitted, then Fossil attempts to find
73 ** a recent fork on the current branch to merge.
74 **
75 ** Only file content is merged. The result continues to use the
76 ** file and directory names from the current checkout even if those
77 ** names might have been changed in the branch being merged in.
78 **
@@ -131,24 +134,84 @@
134 zBinGlob = find_option("binary",0,1);
135 nochangeFlag = find_option("nochange","n",0)!=0;
136 forceFlag = find_option("force","f",0)!=0;
137 zPivot = find_option("baseline",0,1);
138 capture_case_sensitive_option();
139 verify_all_options();
 
 
140 db_must_be_within_tree();
141 caseSensitive = filenames_are_case_sensitive();
142 if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
143 vid = db_lget_int("checkout", 0);
144 if( vid==0 ){
145 fossil_fatal("nothing is checked out");
146 }
147
148 /* Find mid, the artifactID of the version to be merged into the current
149 ** check-out */
150 if( g.argc==3 ){
151 /* Mid is specified as an argument on the command-line */
152 mid = name_to_typed_rid(g.argv[2], "ci");
153 if( mid==0 || !is_a_version(mid) ){
154 fossil_fatal("not a version: %s", g.argv[2]);
155 }
156 }else if( g.argc==2 ){
157 /* No version specified on the command-line so pick the most recent
158 ** leaf that is (1) not the version currently checked out and (2)
159 ** has not already been merged into the current checkout and (3)
160 ** the leaf is not closed and (4) the leaf is in the same branch
161 ** as the current checkout.
162 */
163 Stmt q;
164 if( pickFlag || backoutFlag ){
165 fossil_fatal("cannot use --cherrypick or --backout with a fork merge");
166 }
167 mid = db_int(0,
168 "SELECT leaf.rid"
169 " FROM leaf, event"
170 " WHERE leaf.rid=event.objid"
171 " AND leaf.rid!=%d" /* Constraint (1) */
172 " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
173 " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
174 " WHERE rid=leaf.rid"
175 " AND tagid=%d"
176 " AND tagtype>0)"
177 " AND (SELECT value FROM tagxref" /* Constraint (4) */
178 " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
179 " (SELECT value FROM tagxref"
180 " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
181 " ORDER BY event.mtime DESC LIMIT 1",
182 vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
183 );
184 if( mid==0 ){
185 fossil_fatal("no unmerged forks of branch \"%s\"",
186 db_text(0, "SELECT value FROM tagxref"
187 " WHERE tagid=%d AND rid=%d AND tagtype>0",
188 TAG_BRANCH, vid)
189 );
190 }
191 db_prepare(&q,
192 "SELECT blob.uuid,"
193 " datetime(event.mtime,'localtime'),"
194 " coalesce(ecomment, comment),"
195 " coalesce(euser, user)"
196 " FROM event, blob"
197 " WHERE event.objid=%d AND blob.rid=%d",
198 mid, mid
199 );
200 if( db_step(&q)==SQLITE_ROW ){
201 char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
202 db_column_text(&q, 0), db_column_text(&q, 1),
203 db_column_text(&q, 3), db_column_text(&q, 2));
204 comment_print(zCom, 0, 79);
205 fossil_free(zCom);
206 }
207 db_finalize(&q);
208 }else{
209 usage("?OPTIONS? ?VERSION?");
210 return;
211 }
212
213 if( zPivot ){
214 pid = name_to_typed_rid(zPivot, "ci");
215 if( pid==0 || !is_a_version(pid) ){
216 fossil_fatal("not a version: %s", zPivot);
217 }
@@ -347,11 +410,11 @@
410 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
411 );
412 while( db_step(&q)==SQLITE_ROW ){
413 int idm = db_column_int(&q, 0);
414 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
415 fossil_warning("WARNING - no common ancestor: %s", zName);
416 free(zName);
417 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
418 }
419 db_finalize(&q);
420
421
+71 -8
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
5757
5858
5959
/*
6060
** COMMAND: merge
6161
**
62
-** Usage: %fossil merge ?OPTIONS? VERSION
62
+** Usage: %fossil merge ?OPTIONS? ?VERSION?
6363
**
6464
** The argument VERSION is a version that should be merged into the
6565
** current checkout. All changes from VERSION back to the nearest
6666
** common ancestor are merged. Except, if either of the --cherrypick or
6767
** --backout options are used only the changes associated with the
6868
** single check-in VERSION are merged. The --backout option causes
6969
** the changes associated with VERSION to be removed from the current
7070
** checkout rather than added.
71
+**
72
+** If the VERSION argument is omitted, then Fossil attempts to find
73
+** a recent fork on the current branch to merge.
7174
**
7275
** Only file content is merged. The result continues to use the
7376
** file and directory names from the current checkout even if those
7477
** names might have been changed in the branch being merged in.
7578
**
@@ -131,24 +134,84 @@
131134
zBinGlob = find_option("binary",0,1);
132135
nochangeFlag = find_option("nochange","n",0)!=0;
133136
forceFlag = find_option("force","f",0)!=0;
134137
zPivot = find_option("baseline",0,1);
135138
capture_case_sensitive_option();
136
- if( g.argc!=3 ){
137
- usage("VERSION");
138
- }
139
+ verify_all_options();
139140
db_must_be_within_tree();
140141
caseSensitive = filenames_are_case_sensitive();
141142
if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
142143
vid = db_lget_int("checkout", 0);
143144
if( vid==0 ){
144145
fossil_fatal("nothing is checked out");
145146
}
146
- mid = name_to_typed_rid(g.argv[2], "ci");
147
- if( mid==0 || !is_a_version(mid) ){
148
- fossil_fatal("not a version: %s", g.argv[2]);
147
+
148
+ /* Find mid, the artifactID of the version to be merged into the current
149
+ ** check-out */
150
+ if( g.argc==3 ){
151
+ /* Mid is specified as an argument on the command-line */
152
+ mid = name_to_typed_rid(g.argv[2], "ci");
153
+ if( mid==0 || !is_a_version(mid) ){
154
+ fossil_fatal("not a version: %s", g.argv[2]);
155
+ }
156
+ }else if( g.argc==2 ){
157
+ /* No version specified on the command-line so pick the most recent
158
+ ** leaf that is (1) not the version currently checked out and (2)
159
+ ** has not already been merged into the current checkout and (3)
160
+ ** the leaf is not closed and (4) the leaf is in the same branch
161
+ ** as the current checkout.
162
+ */
163
+ Stmt q;
164
+ if( pickFlag || backoutFlag ){
165
+ fossil_fatal("cannot use --cherrypick or --backout with a fork merge");
166
+ }
167
+ mid = db_int(0,
168
+ "SELECT leaf.rid"
169
+ " FROM leaf, event"
170
+ " WHERE leaf.rid=event.objid"
171
+ " AND leaf.rid!=%d" /* Constraint (1) */
172
+ " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
173
+ " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
174
+ " WHERE rid=leaf.rid"
175
+ " AND tagid=%d"
176
+ " AND tagtype>0)"
177
+ " AND (SELECT value FROM tagxref" /* Constraint (4) */
178
+ " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
179
+ " (SELECT value FROM tagxref"
180
+ " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
181
+ " ORDER BY event.mtime DESC LIMIT 1",
182
+ vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
183
+ );
184
+ if( mid==0 ){
185
+ fossil_fatal("no unmerged forks of branch \"%s\"",
186
+ db_text(0, "SELECT value FROM tagxref"
187
+ " WHERE tagid=%d AND rid=%d AND tagtype>0",
188
+ TAG_BRANCH, vid)
189
+ );
190
+ }
191
+ db_prepare(&q,
192
+ "SELECT blob.uuid,"
193
+ " datetime(event.mtime,'localtime'),"
194
+ " coalesce(ecomment, comment),"
195
+ " coalesce(euser, user)"
196
+ " FROM event, blob"
197
+ " WHERE event.objid=%d AND blob.rid=%d",
198
+ mid, mid
199
+ );
200
+ if( db_step(&q)==SQLITE_ROW ){
201
+ char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
202
+ db_column_text(&q, 0), db_column_text(&q, 1),
203
+ db_column_text(&q, 3), db_column_text(&q, 2));
204
+ comment_print(zCom, 0, 79);
205
+ fossil_free(zCom);
206
+ }
207
+ db_finalize(&q);
208
+ }else{
209
+ usage("?OPTIONS? ?VERSION?");
210
+ return;
149211
}
212
+
150213
if( zPivot ){
151214
pid = name_to_typed_rid(zPivot, "ci");
152215
if( pid==0 || !is_a_version(pid) ){
153216
fossil_fatal("not a version: %s", zPivot);
154217
}
@@ -347,11 +410,11 @@
347410
"SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
348411
);
349412
while( db_step(&q)==SQLITE_ROW ){
350413
int idm = db_column_int(&q, 0);
351414
char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
352
- fossil_warning("WARNING - no common ancestor: %s\n", zName);
415
+ fossil_warning("WARNING - no common ancestor: %s", zName);
353416
free(zName);
354417
db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
355418
}
356419
db_finalize(&q);
357420
358421
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
57
58
59 /*
60 ** COMMAND: merge
61 **
62 ** Usage: %fossil merge ?OPTIONS? VERSION
63 **
64 ** The argument VERSION is a version that should be merged into the
65 ** current checkout. All changes from VERSION back to the nearest
66 ** common ancestor are merged. Except, if either of the --cherrypick or
67 ** --backout options are used only the changes associated with the
68 ** single check-in VERSION are merged. The --backout option causes
69 ** the changes associated with VERSION to be removed from the current
70 ** checkout rather than added.
 
 
 
71 **
72 ** Only file content is merged. The result continues to use the
73 ** file and directory names from the current checkout even if those
74 ** names might have been changed in the branch being merged in.
75 **
@@ -131,24 +134,84 @@
131 zBinGlob = find_option("binary",0,1);
132 nochangeFlag = find_option("nochange","n",0)!=0;
133 forceFlag = find_option("force","f",0)!=0;
134 zPivot = find_option("baseline",0,1);
135 capture_case_sensitive_option();
136 if( g.argc!=3 ){
137 usage("VERSION");
138 }
139 db_must_be_within_tree();
140 caseSensitive = filenames_are_case_sensitive();
141 if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
142 vid = db_lget_int("checkout", 0);
143 if( vid==0 ){
144 fossil_fatal("nothing is checked out");
145 }
146 mid = name_to_typed_rid(g.argv[2], "ci");
147 if( mid==0 || !is_a_version(mid) ){
148 fossil_fatal("not a version: %s", g.argv[2]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149 }
 
150 if( zPivot ){
151 pid = name_to_typed_rid(zPivot, "ci");
152 if( pid==0 || !is_a_version(pid) ){
153 fossil_fatal("not a version: %s", zPivot);
154 }
@@ -347,11 +410,11 @@
347 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
348 );
349 while( db_step(&q)==SQLITE_ROW ){
350 int idm = db_column_int(&q, 0);
351 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
352 fossil_warning("WARNING - no common ancestor: %s\n", zName);
353 free(zName);
354 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
355 }
356 db_finalize(&q);
357
358
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
57
58
59 /*
60 ** COMMAND: merge
61 **
62 ** Usage: %fossil merge ?OPTIONS? ?VERSION?
63 **
64 ** The argument VERSION is a version that should be merged into the
65 ** current checkout. All changes from VERSION back to the nearest
66 ** common ancestor are merged. Except, if either of the --cherrypick or
67 ** --backout options are used only the changes associated with the
68 ** single check-in VERSION are merged. The --backout option causes
69 ** the changes associated with VERSION to be removed from the current
70 ** checkout rather than added.
71 **
72 ** If the VERSION argument is omitted, then Fossil attempts to find
73 ** a recent fork on the current branch to merge.
74 **
75 ** Only file content is merged. The result continues to use the
76 ** file and directory names from the current checkout even if those
77 ** names might have been changed in the branch being merged in.
78 **
@@ -131,24 +134,84 @@
134 zBinGlob = find_option("binary",0,1);
135 nochangeFlag = find_option("nochange","n",0)!=0;
136 forceFlag = find_option("force","f",0)!=0;
137 zPivot = find_option("baseline",0,1);
138 capture_case_sensitive_option();
139 verify_all_options();
 
 
140 db_must_be_within_tree();
141 caseSensitive = filenames_are_case_sensitive();
142 if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
143 vid = db_lget_int("checkout", 0);
144 if( vid==0 ){
145 fossil_fatal("nothing is checked out");
146 }
147
148 /* Find mid, the artifactID of the version to be merged into the current
149 ** check-out */
150 if( g.argc==3 ){
151 /* Mid is specified as an argument on the command-line */
152 mid = name_to_typed_rid(g.argv[2], "ci");
153 if( mid==0 || !is_a_version(mid) ){
154 fossil_fatal("not a version: %s", g.argv[2]);
155 }
156 }else if( g.argc==2 ){
157 /* No version specified on the command-line so pick the most recent
158 ** leaf that is (1) not the version currently checked out and (2)
159 ** has not already been merged into the current checkout and (3)
160 ** the leaf is not closed and (4) the leaf is in the same branch
161 ** as the current checkout.
162 */
163 Stmt q;
164 if( pickFlag || backoutFlag ){
165 fossil_fatal("cannot use --cherrypick or --backout with a fork merge");
166 }
167 mid = db_int(0,
168 "SELECT leaf.rid"
169 " FROM leaf, event"
170 " WHERE leaf.rid=event.objid"
171 " AND leaf.rid!=%d" /* Constraint (1) */
172 " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
173 " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
174 " WHERE rid=leaf.rid"
175 " AND tagid=%d"
176 " AND tagtype>0)"
177 " AND (SELECT value FROM tagxref" /* Constraint (4) */
178 " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
179 " (SELECT value FROM tagxref"
180 " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
181 " ORDER BY event.mtime DESC LIMIT 1",
182 vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
183 );
184 if( mid==0 ){
185 fossil_fatal("no unmerged forks of branch \"%s\"",
186 db_text(0, "SELECT value FROM tagxref"
187 " WHERE tagid=%d AND rid=%d AND tagtype>0",
188 TAG_BRANCH, vid)
189 );
190 }
191 db_prepare(&q,
192 "SELECT blob.uuid,"
193 " datetime(event.mtime,'localtime'),"
194 " coalesce(ecomment, comment),"
195 " coalesce(euser, user)"
196 " FROM event, blob"
197 " WHERE event.objid=%d AND blob.rid=%d",
198 mid, mid
199 );
200 if( db_step(&q)==SQLITE_ROW ){
201 char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
202 db_column_text(&q, 0), db_column_text(&q, 1),
203 db_column_text(&q, 3), db_column_text(&q, 2));
204 comment_print(zCom, 0, 79);
205 fossil_free(zCom);
206 }
207 db_finalize(&q);
208 }else{
209 usage("?OPTIONS? ?VERSION?");
210 return;
211 }
212
213 if( zPivot ){
214 pid = name_to_typed_rid(zPivot, "ci");
215 if( pid==0 || !is_a_version(pid) ){
216 fossil_fatal("not a version: %s", zPivot);
217 }
@@ -347,11 +410,11 @@
410 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
411 );
412 while( db_step(&q)==SQLITE_ROW ){
413 int idm = db_column_int(&q, 0);
414 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
415 fossil_warning("WARNING - no common ancestor: %s", zName);
416 free(zName);
417 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
418 }
419 db_finalize(&q);
420
421
+71 -8
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
5757
5858
5959
/*
6060
** COMMAND: merge
6161
**
62
-** Usage: %fossil merge ?OPTIONS? VERSION
62
+** Usage: %fossil merge ?OPTIONS? ?VERSION?
6363
**
6464
** The argument VERSION is a version that should be merged into the
6565
** current checkout. All changes from VERSION back to the nearest
6666
** common ancestor are merged. Except, if either of the --cherrypick or
6767
** --backout options are used only the changes associated with the
6868
** single check-in VERSION are merged. The --backout option causes
6969
** the changes associated with VERSION to be removed from the current
7070
** checkout rather than added.
71
+**
72
+** If the VERSION argument is omitted, then Fossil attempts to find
73
+** a recent fork on the current branch to merge.
7174
**
7275
** Only file content is merged. The result continues to use the
7376
** file and directory names from the current checkout even if those
7477
** names might have been changed in the branch being merged in.
7578
**
@@ -131,24 +134,84 @@
131134
zBinGlob = find_option("binary",0,1);
132135
nochangeFlag = find_option("nochange","n",0)!=0;
133136
forceFlag = find_option("force","f",0)!=0;
134137
zPivot = find_option("baseline",0,1);
135138
capture_case_sensitive_option();
136
- if( g.argc!=3 ){
137
- usage("VERSION");
138
- }
139
+ verify_all_options();
139140
db_must_be_within_tree();
140141
caseSensitive = filenames_are_case_sensitive();
141142
if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
142143
vid = db_lget_int("checkout", 0);
143144
if( vid==0 ){
144145
fossil_fatal("nothing is checked out");
145146
}
146
- mid = name_to_typed_rid(g.argv[2], "ci");
147
- if( mid==0 || !is_a_version(mid) ){
148
- fossil_fatal("not a version: %s", g.argv[2]);
147
+
148
+ /* Find mid, the artifactID of the version to be merged into the current
149
+ ** check-out */
150
+ if( g.argc==3 ){
151
+ /* Mid is specified as an argument on the command-line */
152
+ mid = name_to_typed_rid(g.argv[2], "ci");
153
+ if( mid==0 || !is_a_version(mid) ){
154
+ fossil_fatal("not a version: %s", g.argv[2]);
155
+ }
156
+ }else if( g.argc==2 ){
157
+ /* No version specified on the command-line so pick the most recent
158
+ ** leaf that is (1) not the version currently checked out and (2)
159
+ ** has not already been merged into the current checkout and (3)
160
+ ** the leaf is not closed and (4) the leaf is in the same branch
161
+ ** as the current checkout.
162
+ */
163
+ Stmt q;
164
+ if( pickFlag || backoutFlag ){
165
+ fossil_fatal("cannot use --cherrypick or --backout with a fork merge");
166
+ }
167
+ mid = db_int(0,
168
+ "SELECT leaf.rid"
169
+ " FROM leaf, event"
170
+ " WHERE leaf.rid=event.objid"
171
+ " AND leaf.rid!=%d" /* Constraint (1) */
172
+ " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
173
+ " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
174
+ " WHERE rid=leaf.rid"
175
+ " AND tagid=%d"
176
+ " AND tagtype>0)"
177
+ " AND (SELECT value FROM tagxref" /* Constraint (4) */
178
+ " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
179
+ " (SELECT value FROM tagxref"
180
+ " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
181
+ " ORDER BY event.mtime DESC LIMIT 1",
182
+ vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
183
+ );
184
+ if( mid==0 ){
185
+ fossil_fatal("no unmerged forks of branch \"%s\"",
186
+ db_text(0, "SELECT value FROM tagxref"
187
+ " WHERE tagid=%d AND rid=%d AND tagtype>0",
188
+ TAG_BRANCH, vid)
189
+ );
190
+ }
191
+ db_prepare(&q,
192
+ "SELECT blob.uuid,"
193
+ " datetime(event.mtime,'localtime'),"
194
+ " coalesce(ecomment, comment),"
195
+ " coalesce(euser, user)"
196
+ " FROM event, blob"
197
+ " WHERE event.objid=%d AND blob.rid=%d",
198
+ mid, mid
199
+ );
200
+ if( db_step(&q)==SQLITE_ROW ){
201
+ char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
202
+ db_column_text(&q, 0), db_column_text(&q, 1),
203
+ db_column_text(&q, 3), db_column_text(&q, 2));
204
+ comment_print(zCom, 0, 79);
205
+ fossil_free(zCom);
206
+ }
207
+ db_finalize(&q);
208
+ }else{
209
+ usage("?OPTIONS? ?VERSION?");
210
+ return;
149211
}
212
+
150213
if( zPivot ){
151214
pid = name_to_typed_rid(zPivot, "ci");
152215
if( pid==0 || !is_a_version(pid) ){
153216
fossil_fatal("not a version: %s", zPivot);
154217
}
@@ -347,11 +410,11 @@
347410
"SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
348411
);
349412
while( db_step(&q)==SQLITE_ROW ){
350413
int idm = db_column_int(&q, 0);
351414
char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
352
- fossil_warning("WARNING - no common ancestor: %s\n", zName);
415
+ fossil_warning("WARNING - no common ancestor: %s", zName);
353416
free(zName);
354417
db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
355418
}
356419
db_finalize(&q);
357420
358421
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
57
58
59 /*
60 ** COMMAND: merge
61 **
62 ** Usage: %fossil merge ?OPTIONS? VERSION
63 **
64 ** The argument VERSION is a version that should be merged into the
65 ** current checkout. All changes from VERSION back to the nearest
66 ** common ancestor are merged. Except, if either of the --cherrypick or
67 ** --backout options are used only the changes associated with the
68 ** single check-in VERSION are merged. The --backout option causes
69 ** the changes associated with VERSION to be removed from the current
70 ** checkout rather than added.
 
 
 
71 **
72 ** Only file content is merged. The result continues to use the
73 ** file and directory names from the current checkout even if those
74 ** names might have been changed in the branch being merged in.
75 **
@@ -131,24 +134,84 @@
131 zBinGlob = find_option("binary",0,1);
132 nochangeFlag = find_option("nochange","n",0)!=0;
133 forceFlag = find_option("force","f",0)!=0;
134 zPivot = find_option("baseline",0,1);
135 capture_case_sensitive_option();
136 if( g.argc!=3 ){
137 usage("VERSION");
138 }
139 db_must_be_within_tree();
140 caseSensitive = filenames_are_case_sensitive();
141 if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
142 vid = db_lget_int("checkout", 0);
143 if( vid==0 ){
144 fossil_fatal("nothing is checked out");
145 }
146 mid = name_to_typed_rid(g.argv[2], "ci");
147 if( mid==0 || !is_a_version(mid) ){
148 fossil_fatal("not a version: %s", g.argv[2]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149 }
 
150 if( zPivot ){
151 pid = name_to_typed_rid(zPivot, "ci");
152 if( pid==0 || !is_a_version(pid) ){
153 fossil_fatal("not a version: %s", zPivot);
154 }
@@ -347,11 +410,11 @@
347 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
348 );
349 while( db_step(&q)==SQLITE_ROW ){
350 int idm = db_column_int(&q, 0);
351 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
352 fossil_warning("WARNING - no common ancestor: %s\n", zName);
353 free(zName);
354 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
355 }
356 db_finalize(&q);
357
358
--- src/merge.c
+++ src/merge.c
@@ -57,19 +57,22 @@
57
58
59 /*
60 ** COMMAND: merge
61 **
62 ** Usage: %fossil merge ?OPTIONS? ?VERSION?
63 **
64 ** The argument VERSION is a version that should be merged into the
65 ** current checkout. All changes from VERSION back to the nearest
66 ** common ancestor are merged. Except, if either of the --cherrypick or
67 ** --backout options are used only the changes associated with the
68 ** single check-in VERSION are merged. The --backout option causes
69 ** the changes associated with VERSION to be removed from the current
70 ** checkout rather than added.
71 **
72 ** If the VERSION argument is omitted, then Fossil attempts to find
73 ** a recent fork on the current branch to merge.
74 **
75 ** Only file content is merged. The result continues to use the
76 ** file and directory names from the current checkout even if those
77 ** names might have been changed in the branch being merged in.
78 **
@@ -131,24 +134,84 @@
134 zBinGlob = find_option("binary",0,1);
135 nochangeFlag = find_option("nochange","n",0)!=0;
136 forceFlag = find_option("force","f",0)!=0;
137 zPivot = find_option("baseline",0,1);
138 capture_case_sensitive_option();
139 verify_all_options();
 
 
140 db_must_be_within_tree();
141 caseSensitive = filenames_are_case_sensitive();
142 if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
143 vid = db_lget_int("checkout", 0);
144 if( vid==0 ){
145 fossil_fatal("nothing is checked out");
146 }
147
148 /* Find mid, the artifactID of the version to be merged into the current
149 ** check-out */
150 if( g.argc==3 ){
151 /* Mid is specified as an argument on the command-line */
152 mid = name_to_typed_rid(g.argv[2], "ci");
153 if( mid==0 || !is_a_version(mid) ){
154 fossil_fatal("not a version: %s", g.argv[2]);
155 }
156 }else if( g.argc==2 ){
157 /* No version specified on the command-line so pick the most recent
158 ** leaf that is (1) not the version currently checked out and (2)
159 ** has not already been merged into the current checkout and (3)
160 ** the leaf is not closed and (4) the leaf is in the same branch
161 ** as the current checkout.
162 */
163 Stmt q;
164 if( pickFlag || backoutFlag ){
165 fossil_fatal("cannot use --cherrypick or --backout with a fork merge");
166 }
167 mid = db_int(0,
168 "SELECT leaf.rid"
169 " FROM leaf, event"
170 " WHERE leaf.rid=event.objid"
171 " AND leaf.rid!=%d" /* Constraint (1) */
172 " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
173 " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */
174 " WHERE rid=leaf.rid"
175 " AND tagid=%d"
176 " AND tagtype>0)"
177 " AND (SELECT value FROM tagxref" /* Constraint (4) */
178 " WHERE tagid=%d AND rid=%d AND tagtype>0) ="
179 " (SELECT value FROM tagxref"
180 " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)"
181 " ORDER BY event.mtime DESC LIMIT 1",
182 vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH
183 );
184 if( mid==0 ){
185 fossil_fatal("no unmerged forks of branch \"%s\"",
186 db_text(0, "SELECT value FROM tagxref"
187 " WHERE tagid=%d AND rid=%d AND tagtype>0",
188 TAG_BRANCH, vid)
189 );
190 }
191 db_prepare(&q,
192 "SELECT blob.uuid,"
193 " datetime(event.mtime,'localtime'),"
194 " coalesce(ecomment, comment),"
195 " coalesce(euser, user)"
196 " FROM event, blob"
197 " WHERE event.objid=%d AND blob.rid=%d",
198 mid, mid
199 );
200 if( db_step(&q)==SQLITE_ROW ){
201 char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
202 db_column_text(&q, 0), db_column_text(&q, 1),
203 db_column_text(&q, 3), db_column_text(&q, 2));
204 comment_print(zCom, 0, 79);
205 fossil_free(zCom);
206 }
207 db_finalize(&q);
208 }else{
209 usage("?OPTIONS? ?VERSION?");
210 return;
211 }
212
213 if( zPivot ){
214 pid = name_to_typed_rid(zPivot, "ci");
215 if( pid==0 || !is_a_version(pid) ){
216 fossil_fatal("not a version: %s", zPivot);
217 }
@@ -347,11 +410,11 @@
410 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
411 );
412 while( db_step(&q)==SQLITE_ROW ){
413 int idm = db_column_int(&q, 0);
414 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
415 fossil_warning("WARNING - no common ancestor: %s", zName);
416 free(zName);
417 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
418 }
419 db_finalize(&q);
420
421
+16 -1
--- src/printf.c
+++ src/printf.c
@@ -848,11 +848,11 @@
848848
fwrite(z, 1, n, toStdErr ? stderr : stdout);
849849
fflush(toStdErr ? stderr : stdout);
850850
}
851851
852852
/*
853
-** Force the the standard output cursor to move to the beginning
853
+** Force the standard output cursor to move to the beginning
854854
** of a line, if it is not there already.
855855
*/
856856
void fossil_force_newline(void){
857857
if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0);
858858
}
@@ -871,10 +871,25 @@
871871
Blob b = empty_blob;
872872
vxprintf(&b, zFormat, ap);
873873
fossil_puts(blob_str(&b), 0);
874874
blob_reset(&b);
875875
}
876
+ va_end(ap);
877
+}
878
+
879
+/*
880
+** Print a trace message on standard error.
881
+*/
882
+void fossil_trace(const char *zFormat, ...){
883
+ va_list ap;
884
+ Blob b;
885
+ va_start(ap, zFormat);
886
+ b = empty_blob;
887
+ vxprintf(&b, zFormat, ap);
888
+ fossil_puts(blob_str(&b), 1);
889
+ blob_reset(&b);
890
+ va_end(ap);
876891
}
877892
878893
/*
879894
** Like strcmp() except that it accepts NULL pointers. NULL sorts before
880895
** all non-NULL string pointers. Also, this strcmp() is a binary comparison
881896
--- src/printf.c
+++ src/printf.c
@@ -848,11 +848,11 @@
848 fwrite(z, 1, n, toStdErr ? stderr : stdout);
849 fflush(toStdErr ? stderr : stdout);
850 }
851
852 /*
853 ** Force the the standard output cursor to move to the beginning
854 ** of a line, if it is not there already.
855 */
856 void fossil_force_newline(void){
857 if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0);
858 }
@@ -871,10 +871,25 @@
871 Blob b = empty_blob;
872 vxprintf(&b, zFormat, ap);
873 fossil_puts(blob_str(&b), 0);
874 blob_reset(&b);
875 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
876 }
877
878 /*
879 ** Like strcmp() except that it accepts NULL pointers. NULL sorts before
880 ** all non-NULL string pointers. Also, this strcmp() is a binary comparison
881
--- src/printf.c
+++ src/printf.c
@@ -848,11 +848,11 @@
848 fwrite(z, 1, n, toStdErr ? stderr : stdout);
849 fflush(toStdErr ? stderr : stdout);
850 }
851
852 /*
853 ** Force the standard output cursor to move to the beginning
854 ** of a line, if it is not there already.
855 */
856 void fossil_force_newline(void){
857 if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0);
858 }
@@ -871,10 +871,25 @@
871 Blob b = empty_blob;
872 vxprintf(&b, zFormat, ap);
873 fossil_puts(blob_str(&b), 0);
874 blob_reset(&b);
875 }
876 va_end(ap);
877 }
878
879 /*
880 ** Print a trace message on standard error.
881 */
882 void fossil_trace(const char *zFormat, ...){
883 va_list ap;
884 Blob b;
885 va_start(ap, zFormat);
886 b = empty_blob;
887 vxprintf(&b, zFormat, ap);
888 fossil_puts(blob_str(&b), 1);
889 blob_reset(&b);
890 va_end(ap);
891 }
892
893 /*
894 ** Like strcmp() except that it accepts NULL pointers. NULL sorts before
895 ** all non-NULL string pointers. Also, this strcmp() is a binary comparison
896
+16 -1
--- src/printf.c
+++ src/printf.c
@@ -848,11 +848,11 @@
848848
fwrite(z, 1, n, toStdErr ? stderr : stdout);
849849
fflush(toStdErr ? stderr : stdout);
850850
}
851851
852852
/*
853
-** Force the the standard output cursor to move to the beginning
853
+** Force the standard output cursor to move to the beginning
854854
** of a line, if it is not there already.
855855
*/
856856
void fossil_force_newline(void){
857857
if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0);
858858
}
@@ -871,10 +871,25 @@
871871
Blob b = empty_blob;
872872
vxprintf(&b, zFormat, ap);
873873
fossil_puts(blob_str(&b), 0);
874874
blob_reset(&b);
875875
}
876
+ va_end(ap);
877
+}
878
+
879
+/*
880
+** Print a trace message on standard error.
881
+*/
882
+void fossil_trace(const char *zFormat, ...){
883
+ va_list ap;
884
+ Blob b;
885
+ va_start(ap, zFormat);
886
+ b = empty_blob;
887
+ vxprintf(&b, zFormat, ap);
888
+ fossil_puts(blob_str(&b), 1);
889
+ blob_reset(&b);
890
+ va_end(ap);
876891
}
877892
878893
/*
879894
** Like strcmp() except that it accepts NULL pointers. NULL sorts before
880895
** all non-NULL string pointers. Also, this strcmp() is a binary comparison
881896
--- src/printf.c
+++ src/printf.c
@@ -848,11 +848,11 @@
848 fwrite(z, 1, n, toStdErr ? stderr : stdout);
849 fflush(toStdErr ? stderr : stdout);
850 }
851
852 /*
853 ** Force the the standard output cursor to move to the beginning
854 ** of a line, if it is not there already.
855 */
856 void fossil_force_newline(void){
857 if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0);
858 }
@@ -871,10 +871,25 @@
871 Blob b = empty_blob;
872 vxprintf(&b, zFormat, ap);
873 fossil_puts(blob_str(&b), 0);
874 blob_reset(&b);
875 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
876 }
877
878 /*
879 ** Like strcmp() except that it accepts NULL pointers. NULL sorts before
880 ** all non-NULL string pointers. Also, this strcmp() is a binary comparison
881
--- src/printf.c
+++ src/printf.c
@@ -848,11 +848,11 @@
848 fwrite(z, 1, n, toStdErr ? stderr : stdout);
849 fflush(toStdErr ? stderr : stdout);
850 }
851
852 /*
853 ** Force the standard output cursor to move to the beginning
854 ** of a line, if it is not there already.
855 */
856 void fossil_force_newline(void){
857 if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0);
858 }
@@ -871,10 +871,25 @@
871 Blob b = empty_blob;
872 vxprintf(&b, zFormat, ap);
873 fossil_puts(blob_str(&b), 0);
874 blob_reset(&b);
875 }
876 va_end(ap);
877 }
878
879 /*
880 ** Print a trace message on standard error.
881 */
882 void fossil_trace(const char *zFormat, ...){
883 va_list ap;
884 Blob b;
885 va_start(ap, zFormat);
886 b = empty_blob;
887 vxprintf(&b, zFormat, ap);
888 fossil_puts(blob_str(&b), 1);
889 blob_reset(&b);
890 va_end(ap);
891 }
892
893 /*
894 ** Like strcmp() except that it accepts NULL pointers. NULL sorts before
895 ** all non-NULL string pointers. Also, this strcmp() is a binary comparison
896
--- src/rebuild.c
+++ src/rebuild.c
@@ -524,10 +524,11 @@
524524
** --noverify Skip the verification of changes to the BLOB table
525525
** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
526526
** --randomize Scan artifacts in a random order
527527
** --vacuum Run VACUUM on the database after rebuilding
528528
** --deanalyze Remove ANALYZE tables from the database
529
+** --analyze Run ANALYZE on the database after rebuilding
529530
** --wal Set Write-Ahead-Log journalling mode on the database
530531
** --stats Show artifact statistics after rebuilding
531532
**
532533
** See also: deconstruct, reconstruct
533534
*/
@@ -540,19 +541,21 @@
540541
const char *zPagesize;
541542
int newPagesize = 0;
542543
int activateWal;
543544
int runVacuum;
544545
int runDeanalyze;
546
+ int runAnalyze;
545547
int runCompress;
546548
int showStats;
547549
548550
omitVerify = find_option("noverify",0,0)!=0;
549551
forceFlag = find_option("force","f",0)!=0;
550552
randomizeFlag = find_option("randomize", 0, 0)!=0;
551553
doClustering = find_option("cluster", 0, 0)!=0;
552554
runVacuum = find_option("vacuum",0,0)!=0;
553555
runDeanalyze = find_option("deanalyze",0,0)!=0;
556
+ runAnalyze = find_option("analyze",0,0)!=0;
554557
runCompress = find_option("compress",0,0)!=0;
555558
zPagesize = find_option("pagesize",0,1);
556559
showStats = find_option("stats",0,0)!=0;
557560
if( zPagesize ){
558561
newPagesize = atoi(zPagesize);
@@ -605,10 +608,15 @@
605608
}
606609
if( runDeanalyze ){
607610
db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
608611
"DROP TABLE IF EXISTS sqlite_stat3;");
609612
}
613
+ if( runAnalyze ){
614
+ fossil_print("Analyzing the database... "); fflush(stdout);
615
+ db_multi_exec("ANALYZE;");
616
+ fossil_print("done\n");
617
+ }
610618
if( runVacuum ){
611619
fossil_print("Vacuuming the database... "); fflush(stdout);
612620
db_multi_exec("VACUUM");
613621
fossil_print("done\n");
614622
}
615623
--- src/rebuild.c
+++ src/rebuild.c
@@ -524,10 +524,11 @@
524 ** --noverify Skip the verification of changes to the BLOB table
525 ** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
526 ** --randomize Scan artifacts in a random order
527 ** --vacuum Run VACUUM on the database after rebuilding
528 ** --deanalyze Remove ANALYZE tables from the database
 
529 ** --wal Set Write-Ahead-Log journalling mode on the database
530 ** --stats Show artifact statistics after rebuilding
531 **
532 ** See also: deconstruct, reconstruct
533 */
@@ -540,19 +541,21 @@
540 const char *zPagesize;
541 int newPagesize = 0;
542 int activateWal;
543 int runVacuum;
544 int runDeanalyze;
 
545 int runCompress;
546 int showStats;
547
548 omitVerify = find_option("noverify",0,0)!=0;
549 forceFlag = find_option("force","f",0)!=0;
550 randomizeFlag = find_option("randomize", 0, 0)!=0;
551 doClustering = find_option("cluster", 0, 0)!=0;
552 runVacuum = find_option("vacuum",0,0)!=0;
553 runDeanalyze = find_option("deanalyze",0,0)!=0;
 
554 runCompress = find_option("compress",0,0)!=0;
555 zPagesize = find_option("pagesize",0,1);
556 showStats = find_option("stats",0,0)!=0;
557 if( zPagesize ){
558 newPagesize = atoi(zPagesize);
@@ -605,10 +608,15 @@
605 }
606 if( runDeanalyze ){
607 db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
608 "DROP TABLE IF EXISTS sqlite_stat3;");
609 }
 
 
 
 
 
610 if( runVacuum ){
611 fossil_print("Vacuuming the database... "); fflush(stdout);
612 db_multi_exec("VACUUM");
613 fossil_print("done\n");
614 }
615
--- src/rebuild.c
+++ src/rebuild.c
@@ -524,10 +524,11 @@
524 ** --noverify Skip the verification of changes to the BLOB table
525 ** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
526 ** --randomize Scan artifacts in a random order
527 ** --vacuum Run VACUUM on the database after rebuilding
528 ** --deanalyze Remove ANALYZE tables from the database
529 ** --analyze Run ANALYZE on the database after rebuilding
530 ** --wal Set Write-Ahead-Log journalling mode on the database
531 ** --stats Show artifact statistics after rebuilding
532 **
533 ** See also: deconstruct, reconstruct
534 */
@@ -540,19 +541,21 @@
541 const char *zPagesize;
542 int newPagesize = 0;
543 int activateWal;
544 int runVacuum;
545 int runDeanalyze;
546 int runAnalyze;
547 int runCompress;
548 int showStats;
549
550 omitVerify = find_option("noverify",0,0)!=0;
551 forceFlag = find_option("force","f",0)!=0;
552 randomizeFlag = find_option("randomize", 0, 0)!=0;
553 doClustering = find_option("cluster", 0, 0)!=0;
554 runVacuum = find_option("vacuum",0,0)!=0;
555 runDeanalyze = find_option("deanalyze",0,0)!=0;
556 runAnalyze = find_option("analyze",0,0)!=0;
557 runCompress = find_option("compress",0,0)!=0;
558 zPagesize = find_option("pagesize",0,1);
559 showStats = find_option("stats",0,0)!=0;
560 if( zPagesize ){
561 newPagesize = atoi(zPagesize);
@@ -605,10 +608,15 @@
608 }
609 if( runDeanalyze ){
610 db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
611 "DROP TABLE IF EXISTS sqlite_stat3;");
612 }
613 if( runAnalyze ){
614 fossil_print("Analyzing the database... "); fflush(stdout);
615 db_multi_exec("ANALYZE;");
616 fossil_print("done\n");
617 }
618 if( runVacuum ){
619 fossil_print("Vacuuming the database... "); fflush(stdout);
620 db_multi_exec("VACUUM");
621 fossil_print("done\n");
622 }
623
--- src/rebuild.c
+++ src/rebuild.c
@@ -524,10 +524,11 @@
524524
** --noverify Skip the verification of changes to the BLOB table
525525
** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
526526
** --randomize Scan artifacts in a random order
527527
** --vacuum Run VACUUM on the database after rebuilding
528528
** --deanalyze Remove ANALYZE tables from the database
529
+** --analyze Run ANALYZE on the database after rebuilding
529530
** --wal Set Write-Ahead-Log journalling mode on the database
530531
** --stats Show artifact statistics after rebuilding
531532
**
532533
** See also: deconstruct, reconstruct
533534
*/
@@ -540,19 +541,21 @@
540541
const char *zPagesize;
541542
int newPagesize = 0;
542543
int activateWal;
543544
int runVacuum;
544545
int runDeanalyze;
546
+ int runAnalyze;
545547
int runCompress;
546548
int showStats;
547549
548550
omitVerify = find_option("noverify",0,0)!=0;
549551
forceFlag = find_option("force","f",0)!=0;
550552
randomizeFlag = find_option("randomize", 0, 0)!=0;
551553
doClustering = find_option("cluster", 0, 0)!=0;
552554
runVacuum = find_option("vacuum",0,0)!=0;
553555
runDeanalyze = find_option("deanalyze",0,0)!=0;
556
+ runAnalyze = find_option("analyze",0,0)!=0;
554557
runCompress = find_option("compress",0,0)!=0;
555558
zPagesize = find_option("pagesize",0,1);
556559
showStats = find_option("stats",0,0)!=0;
557560
if( zPagesize ){
558561
newPagesize = atoi(zPagesize);
@@ -605,10 +608,15 @@
605608
}
606609
if( runDeanalyze ){
607610
db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
608611
"DROP TABLE IF EXISTS sqlite_stat3;");
609612
}
613
+ if( runAnalyze ){
614
+ fossil_print("Analyzing the database... "); fflush(stdout);
615
+ db_multi_exec("ANALYZE;");
616
+ fossil_print("done\n");
617
+ }
610618
if( runVacuum ){
611619
fossil_print("Vacuuming the database... "); fflush(stdout);
612620
db_multi_exec("VACUUM");
613621
fossil_print("done\n");
614622
}
615623
--- src/rebuild.c
+++ src/rebuild.c
@@ -524,10 +524,11 @@
524 ** --noverify Skip the verification of changes to the BLOB table
525 ** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
526 ** --randomize Scan artifacts in a random order
527 ** --vacuum Run VACUUM on the database after rebuilding
528 ** --deanalyze Remove ANALYZE tables from the database
 
529 ** --wal Set Write-Ahead-Log journalling mode on the database
530 ** --stats Show artifact statistics after rebuilding
531 **
532 ** See also: deconstruct, reconstruct
533 */
@@ -540,19 +541,21 @@
540 const char *zPagesize;
541 int newPagesize = 0;
542 int activateWal;
543 int runVacuum;
544 int runDeanalyze;
 
545 int runCompress;
546 int showStats;
547
548 omitVerify = find_option("noverify",0,0)!=0;
549 forceFlag = find_option("force","f",0)!=0;
550 randomizeFlag = find_option("randomize", 0, 0)!=0;
551 doClustering = find_option("cluster", 0, 0)!=0;
552 runVacuum = find_option("vacuum",0,0)!=0;
553 runDeanalyze = find_option("deanalyze",0,0)!=0;
 
554 runCompress = find_option("compress",0,0)!=0;
555 zPagesize = find_option("pagesize",0,1);
556 showStats = find_option("stats",0,0)!=0;
557 if( zPagesize ){
558 newPagesize = atoi(zPagesize);
@@ -605,10 +608,15 @@
605 }
606 if( runDeanalyze ){
607 db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
608 "DROP TABLE IF EXISTS sqlite_stat3;");
609 }
 
 
 
 
 
610 if( runVacuum ){
611 fossil_print("Vacuuming the database... "); fflush(stdout);
612 db_multi_exec("VACUUM");
613 fossil_print("done\n");
614 }
615
--- src/rebuild.c
+++ src/rebuild.c
@@ -524,10 +524,11 @@
524 ** --noverify Skip the verification of changes to the BLOB table
525 ** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
526 ** --randomize Scan artifacts in a random order
527 ** --vacuum Run VACUUM on the database after rebuilding
528 ** --deanalyze Remove ANALYZE tables from the database
529 ** --analyze Run ANALYZE on the database after rebuilding
530 ** --wal Set Write-Ahead-Log journalling mode on the database
531 ** --stats Show artifact statistics after rebuilding
532 **
533 ** See also: deconstruct, reconstruct
534 */
@@ -540,19 +541,21 @@
541 const char *zPagesize;
542 int newPagesize = 0;
543 int activateWal;
544 int runVacuum;
545 int runDeanalyze;
546 int runAnalyze;
547 int runCompress;
548 int showStats;
549
550 omitVerify = find_option("noverify",0,0)!=0;
551 forceFlag = find_option("force","f",0)!=0;
552 randomizeFlag = find_option("randomize", 0, 0)!=0;
553 doClustering = find_option("cluster", 0, 0)!=0;
554 runVacuum = find_option("vacuum",0,0)!=0;
555 runDeanalyze = find_option("deanalyze",0,0)!=0;
556 runAnalyze = find_option("analyze",0,0)!=0;
557 runCompress = find_option("compress",0,0)!=0;
558 zPagesize = find_option("pagesize",0,1);
559 showStats = find_option("stats",0,0)!=0;
560 if( zPagesize ){
561 newPagesize = atoi(zPagesize);
@@ -605,10 +608,15 @@
608 }
609 if( runDeanalyze ){
610 db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
611 "DROP TABLE IF EXISTS sqlite_stat3;");
612 }
613 if( runAnalyze ){
614 fossil_print("Analyzing the database... "); fflush(stdout);
615 db_multi_exec("ANALYZE;");
616 fossil_print("done\n");
617 }
618 if( runVacuum ){
619 fossil_print("Vacuuming the database... "); fflush(stdout);
620 db_multi_exec("VACUUM");
621 fossil_print("done\n");
622 }
623
+38 -24
--- src/regexp.c
+++ src/regexp.c
@@ -32,11 +32,11 @@
3232
** X$ X occurring at the end of the string
3333
** . Match any single character
3434
** \c Character c where c is one of \{}()[]|*+?.
3535
** \c C-language escapes for c in afnrtv. ex: \t or \n
3636
** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
37
-** \xXXX Where XXX is any number of hex digits, unicode value XXX
37
+** \xXX Where XX is exactly 2 hex digits, unicode value XX
3838
** [abc] Any single character from the set abc
3939
** [^abc] Any single character not in the set abc
4040
** [a-z] Any single character in the range a-z
4141
** [^a-z] Any single character not in the range a-z
4242
** \b Word boundary
@@ -134,25 +134,25 @@
134134
*/
135135
static unsigned re_next_char(ReInput *p){
136136
unsigned c;
137137
if( p->i>=p->mx ) return 0;
138138
c = p->z[p->i++];
139
- if( c>0x80 ){
139
+ if( c>=0x80 ){
140140
if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
141141
c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
142142
if( c<0x80 ) c = 0xfffd;
143143
}else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
144144
&& (p->z[p->i+1]&0xc0)==0x80 ){
145145
c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
146146
p->i += 2;
147
- if( c<0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
147
+ if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
148148
}else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
149149
&& (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
150150
c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
151151
| (p->z[p->i+2]&0x3f);
152152
p->i += 3;
153
- if( c<0xffff ) c = 0xfffd;
153
+ if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
154154
}else{
155155
c = 0xfffd;
156156
}
157157
}
158158
return c;
@@ -172,17 +172,17 @@
172172
return (c>='0' && c<='9');
173173
}
174174
175175
/* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
176176
static int re_space_char(int c){
177
- return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f' ;
177
+ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
178178
}
179179
180180
/* Run a compiled regular expression on the zero-terminated input
181181
** string zIn[]. Return true on a match and false if there is no match.
182182
*/
183
-int re_execute(ReCompiled *pRe, const unsigned char *zIn, int nIn){
183
+int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
184184
ReStateSet aStateSet[2], *pThis, *pNext;
185185
ReStateNumber aSpace[100];
186186
ReStateNumber *pToFree;
187187
unsigned int i = 0;
188188
unsigned int iSwap = 0;
@@ -192,19 +192,22 @@
192192
ReInput in;
193193
194194
in.z = zIn;
195195
in.i = 0;
196196
in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
197
+
198
+ /* Look for the initial prefix match, if there is one. */
197199
if( pRe->nInit ){
198200
unsigned char x = pRe->zInit[0];
199
- while( in.i+pRe->nInit<in.mx
201
+ while( in.i+pRe->nInit<=in.mx
200202
&& (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
201203
){
202204
in.i++;
203205
}
204
- if( in.i+pRe->nInit>=in.mx ) return 0;
206
+ if( in.i+pRe->nInit>in.mx ) return 0;
205207
}
208
+
206209
if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
207210
pToFree = 0;
208211
aStateSet[0].aState = aSpace;
209212
}else{
210213
pToFree = fossil_malloc( sizeof(ReStateNumber)*2*pRe->nState );
@@ -275,11 +278,11 @@
275278
re_add_state(pThis, x+pRe->aArg[x]);
276279
break;
277280
}
278281
case RE_OP_ACCEPT: {
279282
rc = 1;
280
- goto re_execute_end;
283
+ goto re_match_end;
281284
}
282285
case RE_OP_CC_INC:
283286
case RE_OP_CC_EXC: {
284287
int j = 1;
285288
int n = pRe->aArg[x];
@@ -307,11 +310,11 @@
307310
}
308311
}
309312
for(i=0; i<pNext->nState; i++){
310313
if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
311314
}
312
-re_execute_end:
315
+re_match_end:
313316
fossil_free(pToFree);
314317
return rc;
315318
}
316319
317320
/* Resize the opcode and argument arrays for an RE under construction.
@@ -378,21 +381,20 @@
378381
*pV = (*pV)*16 + (c & 0xff);
379382
return 1;
380383
}
381384
382385
/* A backslash character has been seen, read the next character and
383
-** return its intepretation.
386
+** return its interpretation.
384387
*/
385388
static unsigned re_esc_char(ReCompiled *p){
386389
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
387390
static const char zTrans[] = "\a\f\n\r\t\v";
388391
int i, v = 0;
389392
char c;
390393
if( p->sIn.i>=p->sIn.mx ) return 0;
391
- c = p->sIn.z[0];
392
- if( c=='u' && p->sIn.i+5<p->sIn.mx ){
393
- v = 0;
394
+ c = p->sIn.z[p->sIn.i];
395
+ if( c=='u' && p->sIn.i+4<p->sIn.mx ){
394396
const unsigned char *zIn = p->sIn.z + p->sIn.i;
395397
if( re_hex(zIn[1],&v)
396398
&& re_hex(zIn[2],&v)
397399
&& re_hex(zIn[3],&v)
398400
&& re_hex(zIn[4],&v)
@@ -399,15 +401,16 @@
399401
){
400402
p->sIn.i += 5;
401403
return v;
402404
}
403405
}
404
- if( c=='x' ){
405
- v = 0;
406
- for(i=1; p->sIn.i<p->sIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){}
407
- if( i>1 ){
408
- p->sIn.i += i;
406
+ if( c=='x' && p->sIn.i+2<p->sIn.mx ){
407
+ const unsigned char *zIn = p->sIn.z + p->sIn.i;
408
+ if( re_hex(zIn[1],&v)
409
+ && re_hex(zIn[2],&v)
410
+ ){
411
+ p->sIn.i += 3;
409412
return v;
410413
}
411414
}
412415
for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
413416
if( zEsc[i] ){
@@ -594,16 +597,17 @@
594597
*/
595598
void re_free(ReCompiled *pRe){
596599
if( pRe ){
597600
fossil_free(pRe->aOp);
598601
fossil_free(pRe->aArg);
602
+ fossil_free(pRe);
599603
}
600604
}
601605
602606
/*
603607
** Compile a textual regular expression in zIn[] into a compiled regular
604
-** expression suitable for us by re_execute() and return a pointer to the
608
+** expression suitable for us by re_match() and return a pointer to the
605609
** compiled regular expression in *ppRe. Return NULL on success or an
606610
** error message if something goes wrong.
607611
*/
608612
const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
609613
ReCompiled *pRe;
@@ -632,11 +636,11 @@
632636
zErr = re_subcompile_re(pRe);
633637
if( zErr ){
634638
re_free(pRe);
635639
return zErr;
636640
}
637
- if( rePeek(pRe)=='$' && pRe->sIn.i+1==pRe->sIn.mx ){
641
+ if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
638642
re_append(pRe, RE_OP_MATCH, RE_EOF);
639643
re_append(pRe, RE_OP_ACCEPT, 0);
640644
*ppRe = pRe;
641645
}else if( pRe->sIn.i>=pRe->sIn.mx ){
642646
re_append(pRe, RE_OP_ACCEPT, 0);
@@ -643,10 +647,19 @@
643647
*ppRe = pRe;
644648
}else{
645649
re_free(pRe);
646650
return "unrecognized character";
647651
}
652
+
653
+ /* The following is a performance optimization. If the regex begins with
654
+ ** ".*" (if the input regex lacks an initial "^") and afterwards there are
655
+ ** one or more matching characters, enter those matching characters into
656
+ ** zInit[]. The re_match() routine can then search ahead in the input
657
+ ** string looking for the initial match without having to run the whole
658
+ ** regex engine over the string. Do not worry able trying to match
659
+ ** unicode characters beyond plane 0 - those are very rare and this is
660
+ ** just an optimization. */
648661
if( pRe->aOp[0]==RE_OP_ANYSTAR ){
649662
for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
650663
unsigned x = pRe->aArg[i];
651664
if( x<=127 ){
652665
pRe->zInit[j++] = x;
@@ -654,15 +667,16 @@
654667
pRe->zInit[j++] = 0xc0 | (x>>6);
655668
pRe->zInit[j++] = 0x80 | (x&0x3f);
656669
}else if( x<=0xffff ){
657670
pRe->zInit[j++] = 0xd0 | (x>>12);
658671
pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
659
- pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
672
+ pRe->zInit[j++] = 0x80 | (x&0x3f);
660673
}else{
661674
break;
662675
}
663676
}
677
+ if( j>0 && pRe->zInit[j-1]==0 ) j--;
664678
pRe->nInit = j;
665679
}
666680
return pRe->zErr;
667681
}
668682
@@ -700,11 +714,11 @@
700714
}
701715
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
702716
}
703717
zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
704718
if( zStr!=0 ){
705
- sqlite3_result_int(context, re_execute(pRe, zStr, -1));
719
+ sqlite3_result_int(context, re_match(pRe, zStr, -1));
706720
}
707721
}
708722
709723
/*
710724
** Invoke this routine in order to install the REGEXP function in an
@@ -731,11 +745,11 @@
731745
char zLine[2000];
732746
while( fgets(zLine, sizeof(zLine), in) ){
733747
ln++;
734748
n = (int)strlen(zLine);
735749
while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--;
736
- if( re_execute(pRe, (const unsigned char*)zLine, n) ){
750
+ if( re_match(pRe, (const unsigned char*)zLine, n) ){
737751
printf("%s:%d:%.*s\n", zFile, ln, n, zLine);
738752
}
739753
}
740754
}
741755
742756
--- src/regexp.c
+++ src/regexp.c
@@ -32,11 +32,11 @@
32 ** X$ X occurring at the end of the string
33 ** . Match any single character
34 ** \c Character c where c is one of \{}()[]|*+?.
35 ** \c C-language escapes for c in afnrtv. ex: \t or \n
36 ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
37 ** \xXXX Where XXX is any number of hex digits, unicode value XXX
38 ** [abc] Any single character from the set abc
39 ** [^abc] Any single character not in the set abc
40 ** [a-z] Any single character in the range a-z
41 ** [^a-z] Any single character not in the range a-z
42 ** \b Word boundary
@@ -134,25 +134,25 @@
134 */
135 static unsigned re_next_char(ReInput *p){
136 unsigned c;
137 if( p->i>=p->mx ) return 0;
138 c = p->z[p->i++];
139 if( c>0x80 ){
140 if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
141 c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
142 if( c<0x80 ) c = 0xfffd;
143 }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
144 && (p->z[p->i+1]&0xc0)==0x80 ){
145 c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
146 p->i += 2;
147 if( c<0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
148 }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
149 && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
150 c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
151 | (p->z[p->i+2]&0x3f);
152 p->i += 3;
153 if( c<0xffff ) c = 0xfffd;
154 }else{
155 c = 0xfffd;
156 }
157 }
158 return c;
@@ -172,17 +172,17 @@
172 return (c>='0' && c<='9');
173 }
174
175 /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
176 static int re_space_char(int c){
177 return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f' ;
178 }
179
180 /* Run a compiled regular expression on the zero-terminated input
181 ** string zIn[]. Return true on a match and false if there is no match.
182 */
183 int re_execute(ReCompiled *pRe, const unsigned char *zIn, int nIn){
184 ReStateSet aStateSet[2], *pThis, *pNext;
185 ReStateNumber aSpace[100];
186 ReStateNumber *pToFree;
187 unsigned int i = 0;
188 unsigned int iSwap = 0;
@@ -192,19 +192,22 @@
192 ReInput in;
193
194 in.z = zIn;
195 in.i = 0;
196 in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
 
 
197 if( pRe->nInit ){
198 unsigned char x = pRe->zInit[0];
199 while( in.i+pRe->nInit<in.mx
200 && (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
201 ){
202 in.i++;
203 }
204 if( in.i+pRe->nInit>=in.mx ) return 0;
205 }
 
206 if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
207 pToFree = 0;
208 aStateSet[0].aState = aSpace;
209 }else{
210 pToFree = fossil_malloc( sizeof(ReStateNumber)*2*pRe->nState );
@@ -275,11 +278,11 @@
275 re_add_state(pThis, x+pRe->aArg[x]);
276 break;
277 }
278 case RE_OP_ACCEPT: {
279 rc = 1;
280 goto re_execute_end;
281 }
282 case RE_OP_CC_INC:
283 case RE_OP_CC_EXC: {
284 int j = 1;
285 int n = pRe->aArg[x];
@@ -307,11 +310,11 @@
307 }
308 }
309 for(i=0; i<pNext->nState; i++){
310 if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
311 }
312 re_execute_end:
313 fossil_free(pToFree);
314 return rc;
315 }
316
317 /* Resize the opcode and argument arrays for an RE under construction.
@@ -378,21 +381,20 @@
378 *pV = (*pV)*16 + (c & 0xff);
379 return 1;
380 }
381
382 /* A backslash character has been seen, read the next character and
383 ** return its intepretation.
384 */
385 static unsigned re_esc_char(ReCompiled *p){
386 static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
387 static const char zTrans[] = "\a\f\n\r\t\v";
388 int i, v = 0;
389 char c;
390 if( p->sIn.i>=p->sIn.mx ) return 0;
391 c = p->sIn.z[0];
392 if( c=='u' && p->sIn.i+5<p->sIn.mx ){
393 v = 0;
394 const unsigned char *zIn = p->sIn.z + p->sIn.i;
395 if( re_hex(zIn[1],&v)
396 && re_hex(zIn[2],&v)
397 && re_hex(zIn[3],&v)
398 && re_hex(zIn[4],&v)
@@ -399,15 +401,16 @@
399 ){
400 p->sIn.i += 5;
401 return v;
402 }
403 }
404 if( c=='x' ){
405 v = 0;
406 for(i=1; p->sIn.i<p->sIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){}
407 if( i>1 ){
408 p->sIn.i += i;
 
409 return v;
410 }
411 }
412 for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
413 if( zEsc[i] ){
@@ -594,16 +597,17 @@
594 */
595 void re_free(ReCompiled *pRe){
596 if( pRe ){
597 fossil_free(pRe->aOp);
598 fossil_free(pRe->aArg);
 
599 }
600 }
601
602 /*
603 ** Compile a textual regular expression in zIn[] into a compiled regular
604 ** expression suitable for us by re_execute() and return a pointer to the
605 ** compiled regular expression in *ppRe. Return NULL on success or an
606 ** error message if something goes wrong.
607 */
608 const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
609 ReCompiled *pRe;
@@ -632,11 +636,11 @@
632 zErr = re_subcompile_re(pRe);
633 if( zErr ){
634 re_free(pRe);
635 return zErr;
636 }
637 if( rePeek(pRe)=='$' && pRe->sIn.i+1==pRe->sIn.mx ){
638 re_append(pRe, RE_OP_MATCH, RE_EOF);
639 re_append(pRe, RE_OP_ACCEPT, 0);
640 *ppRe = pRe;
641 }else if( pRe->sIn.i>=pRe->sIn.mx ){
642 re_append(pRe, RE_OP_ACCEPT, 0);
@@ -643,10 +647,19 @@
643 *ppRe = pRe;
644 }else{
645 re_free(pRe);
646 return "unrecognized character";
647 }
 
 
 
 
 
 
 
 
 
648 if( pRe->aOp[0]==RE_OP_ANYSTAR ){
649 for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
650 unsigned x = pRe->aArg[i];
651 if( x<=127 ){
652 pRe->zInit[j++] = x;
@@ -654,15 +667,16 @@
654 pRe->zInit[j++] = 0xc0 | (x>>6);
655 pRe->zInit[j++] = 0x80 | (x&0x3f);
656 }else if( x<=0xffff ){
657 pRe->zInit[j++] = 0xd0 | (x>>12);
658 pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
659 pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
660 }else{
661 break;
662 }
663 }
 
664 pRe->nInit = j;
665 }
666 return pRe->zErr;
667 }
668
@@ -700,11 +714,11 @@
700 }
701 sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
702 }
703 zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
704 if( zStr!=0 ){
705 sqlite3_result_int(context, re_execute(pRe, zStr, -1));
706 }
707 }
708
709 /*
710 ** Invoke this routine in order to install the REGEXP function in an
@@ -731,11 +745,11 @@
731 char zLine[2000];
732 while( fgets(zLine, sizeof(zLine), in) ){
733 ln++;
734 n = (int)strlen(zLine);
735 while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--;
736 if( re_execute(pRe, (const unsigned char*)zLine, n) ){
737 printf("%s:%d:%.*s\n", zFile, ln, n, zLine);
738 }
739 }
740 }
741
742
--- src/regexp.c
+++ src/regexp.c
@@ -32,11 +32,11 @@
32 ** X$ X occurring at the end of the string
33 ** . Match any single character
34 ** \c Character c where c is one of \{}()[]|*+?.
35 ** \c C-language escapes for c in afnrtv. ex: \t or \n
36 ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
37 ** \xXX Where XX is exactly 2 hex digits, unicode value XX
38 ** [abc] Any single character from the set abc
39 ** [^abc] Any single character not in the set abc
40 ** [a-z] Any single character in the range a-z
41 ** [^a-z] Any single character not in the range a-z
42 ** \b Word boundary
@@ -134,25 +134,25 @@
134 */
135 static unsigned re_next_char(ReInput *p){
136 unsigned c;
137 if( p->i>=p->mx ) return 0;
138 c = p->z[p->i++];
139 if( c>=0x80 ){
140 if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
141 c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
142 if( c<0x80 ) c = 0xfffd;
143 }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
144 && (p->z[p->i+1]&0xc0)==0x80 ){
145 c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
146 p->i += 2;
147 if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
148 }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
149 && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
150 c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
151 | (p->z[p->i+2]&0x3f);
152 p->i += 3;
153 if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
154 }else{
155 c = 0xfffd;
156 }
157 }
158 return c;
@@ -172,17 +172,17 @@
172 return (c>='0' && c<='9');
173 }
174
175 /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
176 static int re_space_char(int c){
177 return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
178 }
179
180 /* Run a compiled regular expression on the zero-terminated input
181 ** string zIn[]. Return true on a match and false if there is no match.
182 */
183 int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
184 ReStateSet aStateSet[2], *pThis, *pNext;
185 ReStateNumber aSpace[100];
186 ReStateNumber *pToFree;
187 unsigned int i = 0;
188 unsigned int iSwap = 0;
@@ -192,19 +192,22 @@
192 ReInput in;
193
194 in.z = zIn;
195 in.i = 0;
196 in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
197
198 /* Look for the initial prefix match, if there is one. */
199 if( pRe->nInit ){
200 unsigned char x = pRe->zInit[0];
201 while( in.i+pRe->nInit<=in.mx
202 && (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
203 ){
204 in.i++;
205 }
206 if( in.i+pRe->nInit>in.mx ) return 0;
207 }
208
209 if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
210 pToFree = 0;
211 aStateSet[0].aState = aSpace;
212 }else{
213 pToFree = fossil_malloc( sizeof(ReStateNumber)*2*pRe->nState );
@@ -275,11 +278,11 @@
278 re_add_state(pThis, x+pRe->aArg[x]);
279 break;
280 }
281 case RE_OP_ACCEPT: {
282 rc = 1;
283 goto re_match_end;
284 }
285 case RE_OP_CC_INC:
286 case RE_OP_CC_EXC: {
287 int j = 1;
288 int n = pRe->aArg[x];
@@ -307,11 +310,11 @@
310 }
311 }
312 for(i=0; i<pNext->nState; i++){
313 if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
314 }
315 re_match_end:
316 fossil_free(pToFree);
317 return rc;
318 }
319
320 /* Resize the opcode and argument arrays for an RE under construction.
@@ -378,21 +381,20 @@
381 *pV = (*pV)*16 + (c & 0xff);
382 return 1;
383 }
384
385 /* A backslash character has been seen, read the next character and
386 ** return its interpretation.
387 */
388 static unsigned re_esc_char(ReCompiled *p){
389 static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
390 static const char zTrans[] = "\a\f\n\r\t\v";
391 int i, v = 0;
392 char c;
393 if( p->sIn.i>=p->sIn.mx ) return 0;
394 c = p->sIn.z[p->sIn.i];
395 if( c=='u' && p->sIn.i+4<p->sIn.mx ){
 
396 const unsigned char *zIn = p->sIn.z + p->sIn.i;
397 if( re_hex(zIn[1],&v)
398 && re_hex(zIn[2],&v)
399 && re_hex(zIn[3],&v)
400 && re_hex(zIn[4],&v)
@@ -399,15 +401,16 @@
401 ){
402 p->sIn.i += 5;
403 return v;
404 }
405 }
406 if( c=='x' && p->sIn.i+2<p->sIn.mx ){
407 const unsigned char *zIn = p->sIn.z + p->sIn.i;
408 if( re_hex(zIn[1],&v)
409 && re_hex(zIn[2],&v)
410 ){
411 p->sIn.i += 3;
412 return v;
413 }
414 }
415 for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
416 if( zEsc[i] ){
@@ -594,16 +597,17 @@
597 */
598 void re_free(ReCompiled *pRe){
599 if( pRe ){
600 fossil_free(pRe->aOp);
601 fossil_free(pRe->aArg);
602 fossil_free(pRe);
603 }
604 }
605
606 /*
607 ** Compile a textual regular expression in zIn[] into a compiled regular
608 ** expression suitable for us by re_match() and return a pointer to the
609 ** compiled regular expression in *ppRe. Return NULL on success or an
610 ** error message if something goes wrong.
611 */
612 const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
613 ReCompiled *pRe;
@@ -632,11 +636,11 @@
636 zErr = re_subcompile_re(pRe);
637 if( zErr ){
638 re_free(pRe);
639 return zErr;
640 }
641 if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
642 re_append(pRe, RE_OP_MATCH, RE_EOF);
643 re_append(pRe, RE_OP_ACCEPT, 0);
644 *ppRe = pRe;
645 }else if( pRe->sIn.i>=pRe->sIn.mx ){
646 re_append(pRe, RE_OP_ACCEPT, 0);
@@ -643,10 +647,19 @@
647 *ppRe = pRe;
648 }else{
649 re_free(pRe);
650 return "unrecognized character";
651 }
652
653 /* The following is a performance optimization. If the regex begins with
654 ** ".*" (if the input regex lacks an initial "^") and afterwards there are
655 ** one or more matching characters, enter those matching characters into
656 ** zInit[]. The re_match() routine can then search ahead in the input
657 ** string looking for the initial match without having to run the whole
658 ** regex engine over the string. Do not worry able trying to match
659 ** unicode characters beyond plane 0 - those are very rare and this is
660 ** just an optimization. */
661 if( pRe->aOp[0]==RE_OP_ANYSTAR ){
662 for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
663 unsigned x = pRe->aArg[i];
664 if( x<=127 ){
665 pRe->zInit[j++] = x;
@@ -654,15 +667,16 @@
667 pRe->zInit[j++] = 0xc0 | (x>>6);
668 pRe->zInit[j++] = 0x80 | (x&0x3f);
669 }else if( x<=0xffff ){
670 pRe->zInit[j++] = 0xd0 | (x>>12);
671 pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
672 pRe->zInit[j++] = 0x80 | (x&0x3f);
673 }else{
674 break;
675 }
676 }
677 if( j>0 && pRe->zInit[j-1]==0 ) j--;
678 pRe->nInit = j;
679 }
680 return pRe->zErr;
681 }
682
@@ -700,11 +714,11 @@
714 }
715 sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
716 }
717 zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
718 if( zStr!=0 ){
719 sqlite3_result_int(context, re_match(pRe, zStr, -1));
720 }
721 }
722
723 /*
724 ** Invoke this routine in order to install the REGEXP function in an
@@ -731,11 +745,11 @@
745 char zLine[2000];
746 while( fgets(zLine, sizeof(zLine), in) ){
747 ln++;
748 n = (int)strlen(zLine);
749 while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--;
750 if( re_match(pRe, (const unsigned char*)zLine, n) ){
751 printf("%s:%d:%.*s\n", zFile, ln, n, zLine);
752 }
753 }
754 }
755
756
+38 -24
--- src/regexp.c
+++ src/regexp.c
@@ -32,11 +32,11 @@
3232
** X$ X occurring at the end of the string
3333
** . Match any single character
3434
** \c Character c where c is one of \{}()[]|*+?.
3535
** \c C-language escapes for c in afnrtv. ex: \t or \n
3636
** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
37
-** \xXXX Where XXX is any number of hex digits, unicode value XXX
37
+** \xXX Where XX is exactly 2 hex digits, unicode value XX
3838
** [abc] Any single character from the set abc
3939
** [^abc] Any single character not in the set abc
4040
** [a-z] Any single character in the range a-z
4141
** [^a-z] Any single character not in the range a-z
4242
** \b Word boundary
@@ -134,25 +134,25 @@
134134
*/
135135
static unsigned re_next_char(ReInput *p){
136136
unsigned c;
137137
if( p->i>=p->mx ) return 0;
138138
c = p->z[p->i++];
139
- if( c>0x80 ){
139
+ if( c>=0x80 ){
140140
if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
141141
c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
142142
if( c<0x80 ) c = 0xfffd;
143143
}else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
144144
&& (p->z[p->i+1]&0xc0)==0x80 ){
145145
c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
146146
p->i += 2;
147
- if( c<0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
147
+ if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
148148
}else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
149149
&& (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
150150
c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
151151
| (p->z[p->i+2]&0x3f);
152152
p->i += 3;
153
- if( c<0xffff ) c = 0xfffd;
153
+ if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
154154
}else{
155155
c = 0xfffd;
156156
}
157157
}
158158
return c;
@@ -172,17 +172,17 @@
172172
return (c>='0' && c<='9');
173173
}
174174
175175
/* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
176176
static int re_space_char(int c){
177
- return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f' ;
177
+ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
178178
}
179179
180180
/* Run a compiled regular expression on the zero-terminated input
181181
** string zIn[]. Return true on a match and false if there is no match.
182182
*/
183
-int re_execute(ReCompiled *pRe, const unsigned char *zIn, int nIn){
183
+int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
184184
ReStateSet aStateSet[2], *pThis, *pNext;
185185
ReStateNumber aSpace[100];
186186
ReStateNumber *pToFree;
187187
unsigned int i = 0;
188188
unsigned int iSwap = 0;
@@ -192,19 +192,22 @@
192192
ReInput in;
193193
194194
in.z = zIn;
195195
in.i = 0;
196196
in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
197
+
198
+ /* Look for the initial prefix match, if there is one. */
197199
if( pRe->nInit ){
198200
unsigned char x = pRe->zInit[0];
199
- while( in.i+pRe->nInit<in.mx
201
+ while( in.i+pRe->nInit<=in.mx
200202
&& (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
201203
){
202204
in.i++;
203205
}
204
- if( in.i+pRe->nInit>=in.mx ) return 0;
206
+ if( in.i+pRe->nInit>in.mx ) return 0;
205207
}
208
+
206209
if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
207210
pToFree = 0;
208211
aStateSet[0].aState = aSpace;
209212
}else{
210213
pToFree = fossil_malloc( sizeof(ReStateNumber)*2*pRe->nState );
@@ -275,11 +278,11 @@
275278
re_add_state(pThis, x+pRe->aArg[x]);
276279
break;
277280
}
278281
case RE_OP_ACCEPT: {
279282
rc = 1;
280
- goto re_execute_end;
283
+ goto re_match_end;
281284
}
282285
case RE_OP_CC_INC:
283286
case RE_OP_CC_EXC: {
284287
int j = 1;
285288
int n = pRe->aArg[x];
@@ -307,11 +310,11 @@
307310
}
308311
}
309312
for(i=0; i<pNext->nState; i++){
310313
if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
311314
}
312
-re_execute_end:
315
+re_match_end:
313316
fossil_free(pToFree);
314317
return rc;
315318
}
316319
317320
/* Resize the opcode and argument arrays for an RE under construction.
@@ -378,21 +381,20 @@
378381
*pV = (*pV)*16 + (c & 0xff);
379382
return 1;
380383
}
381384
382385
/* A backslash character has been seen, read the next character and
383
-** return its intepretation.
386
+** return its interpretation.
384387
*/
385388
static unsigned re_esc_char(ReCompiled *p){
386389
static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
387390
static const char zTrans[] = "\a\f\n\r\t\v";
388391
int i, v = 0;
389392
char c;
390393
if( p->sIn.i>=p->sIn.mx ) return 0;
391
- c = p->sIn.z[0];
392
- if( c=='u' && p->sIn.i+5<p->sIn.mx ){
393
- v = 0;
394
+ c = p->sIn.z[p->sIn.i];
395
+ if( c=='u' && p->sIn.i+4<p->sIn.mx ){
394396
const unsigned char *zIn = p->sIn.z + p->sIn.i;
395397
if( re_hex(zIn[1],&v)
396398
&& re_hex(zIn[2],&v)
397399
&& re_hex(zIn[3],&v)
398400
&& re_hex(zIn[4],&v)
@@ -399,15 +401,16 @@
399401
){
400402
p->sIn.i += 5;
401403
return v;
402404
}
403405
}
404
- if( c=='x' ){
405
- v = 0;
406
- for(i=1; p->sIn.i<p->sIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){}
407
- if( i>1 ){
408
- p->sIn.i += i;
406
+ if( c=='x' && p->sIn.i+2<p->sIn.mx ){
407
+ const unsigned char *zIn = p->sIn.z + p->sIn.i;
408
+ if( re_hex(zIn[1],&v)
409
+ && re_hex(zIn[2],&v)
410
+ ){
411
+ p->sIn.i += 3;
409412
return v;
410413
}
411414
}
412415
for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
413416
if( zEsc[i] ){
@@ -594,16 +597,17 @@
594597
*/
595598
void re_free(ReCompiled *pRe){
596599
if( pRe ){
597600
fossil_free(pRe->aOp);
598601
fossil_free(pRe->aArg);
602
+ fossil_free(pRe);
599603
}
600604
}
601605
602606
/*
603607
** Compile a textual regular expression in zIn[] into a compiled regular
604
-** expression suitable for us by re_execute() and return a pointer to the
608
+** expression suitable for us by re_match() and return a pointer to the
605609
** compiled regular expression in *ppRe. Return NULL on success or an
606610
** error message if something goes wrong.
607611
*/
608612
const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
609613
ReCompiled *pRe;
@@ -632,11 +636,11 @@
632636
zErr = re_subcompile_re(pRe);
633637
if( zErr ){
634638
re_free(pRe);
635639
return zErr;
636640
}
637
- if( rePeek(pRe)=='$' && pRe->sIn.i+1==pRe->sIn.mx ){
641
+ if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
638642
re_append(pRe, RE_OP_MATCH, RE_EOF);
639643
re_append(pRe, RE_OP_ACCEPT, 0);
640644
*ppRe = pRe;
641645
}else if( pRe->sIn.i>=pRe->sIn.mx ){
642646
re_append(pRe, RE_OP_ACCEPT, 0);
@@ -643,10 +647,19 @@
643647
*ppRe = pRe;
644648
}else{
645649
re_free(pRe);
646650
return "unrecognized character";
647651
}
652
+
653
+ /* The following is a performance optimization. If the regex begins with
654
+ ** ".*" (if the input regex lacks an initial "^") and afterwards there are
655
+ ** one or more matching characters, enter those matching characters into
656
+ ** zInit[]. The re_match() routine can then search ahead in the input
657
+ ** string looking for the initial match without having to run the whole
658
+ ** regex engine over the string. Do not worry able trying to match
659
+ ** unicode characters beyond plane 0 - those are very rare and this is
660
+ ** just an optimization. */
648661
if( pRe->aOp[0]==RE_OP_ANYSTAR ){
649662
for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
650663
unsigned x = pRe->aArg[i];
651664
if( x<=127 ){
652665
pRe->zInit[j++] = x;
@@ -654,15 +667,16 @@
654667
pRe->zInit[j++] = 0xc0 | (x>>6);
655668
pRe->zInit[j++] = 0x80 | (x&0x3f);
656669
}else if( x<=0xffff ){
657670
pRe->zInit[j++] = 0xd0 | (x>>12);
658671
pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
659
- pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
672
+ pRe->zInit[j++] = 0x80 | (x&0x3f);
660673
}else{
661674
break;
662675
}
663676
}
677
+ if( j>0 && pRe->zInit[j-1]==0 ) j--;
664678
pRe->nInit = j;
665679
}
666680
return pRe->zErr;
667681
}
668682
@@ -700,11 +714,11 @@
700714
}
701715
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
702716
}
703717
zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
704718
if( zStr!=0 ){
705
- sqlite3_result_int(context, re_execute(pRe, zStr, -1));
719
+ sqlite3_result_int(context, re_match(pRe, zStr, -1));
706720
}
707721
}
708722
709723
/*
710724
** Invoke this routine in order to install the REGEXP function in an
@@ -731,11 +745,11 @@
731745
char zLine[2000];
732746
while( fgets(zLine, sizeof(zLine), in) ){
733747
ln++;
734748
n = (int)strlen(zLine);
735749
while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--;
736
- if( re_execute(pRe, (const unsigned char*)zLine, n) ){
750
+ if( re_match(pRe, (const unsigned char*)zLine, n) ){
737751
printf("%s:%d:%.*s\n", zFile, ln, n, zLine);
738752
}
739753
}
740754
}
741755
742756
--- src/regexp.c
+++ src/regexp.c
@@ -32,11 +32,11 @@
32 ** X$ X occurring at the end of the string
33 ** . Match any single character
34 ** \c Character c where c is one of \{}()[]|*+?.
35 ** \c C-language escapes for c in afnrtv. ex: \t or \n
36 ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
37 ** \xXXX Where XXX is any number of hex digits, unicode value XXX
38 ** [abc] Any single character from the set abc
39 ** [^abc] Any single character not in the set abc
40 ** [a-z] Any single character in the range a-z
41 ** [^a-z] Any single character not in the range a-z
42 ** \b Word boundary
@@ -134,25 +134,25 @@
134 */
135 static unsigned re_next_char(ReInput *p){
136 unsigned c;
137 if( p->i>=p->mx ) return 0;
138 c = p->z[p->i++];
139 if( c>0x80 ){
140 if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
141 c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
142 if( c<0x80 ) c = 0xfffd;
143 }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
144 && (p->z[p->i+1]&0xc0)==0x80 ){
145 c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
146 p->i += 2;
147 if( c<0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
148 }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
149 && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
150 c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
151 | (p->z[p->i+2]&0x3f);
152 p->i += 3;
153 if( c<0xffff ) c = 0xfffd;
154 }else{
155 c = 0xfffd;
156 }
157 }
158 return c;
@@ -172,17 +172,17 @@
172 return (c>='0' && c<='9');
173 }
174
175 /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
176 static int re_space_char(int c){
177 return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f' ;
178 }
179
180 /* Run a compiled regular expression on the zero-terminated input
181 ** string zIn[]. Return true on a match and false if there is no match.
182 */
183 int re_execute(ReCompiled *pRe, const unsigned char *zIn, int nIn){
184 ReStateSet aStateSet[2], *pThis, *pNext;
185 ReStateNumber aSpace[100];
186 ReStateNumber *pToFree;
187 unsigned int i = 0;
188 unsigned int iSwap = 0;
@@ -192,19 +192,22 @@
192 ReInput in;
193
194 in.z = zIn;
195 in.i = 0;
196 in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
 
 
197 if( pRe->nInit ){
198 unsigned char x = pRe->zInit[0];
199 while( in.i+pRe->nInit<in.mx
200 && (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
201 ){
202 in.i++;
203 }
204 if( in.i+pRe->nInit>=in.mx ) return 0;
205 }
 
206 if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
207 pToFree = 0;
208 aStateSet[0].aState = aSpace;
209 }else{
210 pToFree = fossil_malloc( sizeof(ReStateNumber)*2*pRe->nState );
@@ -275,11 +278,11 @@
275 re_add_state(pThis, x+pRe->aArg[x]);
276 break;
277 }
278 case RE_OP_ACCEPT: {
279 rc = 1;
280 goto re_execute_end;
281 }
282 case RE_OP_CC_INC:
283 case RE_OP_CC_EXC: {
284 int j = 1;
285 int n = pRe->aArg[x];
@@ -307,11 +310,11 @@
307 }
308 }
309 for(i=0; i<pNext->nState; i++){
310 if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
311 }
312 re_execute_end:
313 fossil_free(pToFree);
314 return rc;
315 }
316
317 /* Resize the opcode and argument arrays for an RE under construction.
@@ -378,21 +381,20 @@
378 *pV = (*pV)*16 + (c & 0xff);
379 return 1;
380 }
381
382 /* A backslash character has been seen, read the next character and
383 ** return its intepretation.
384 */
385 static unsigned re_esc_char(ReCompiled *p){
386 static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
387 static const char zTrans[] = "\a\f\n\r\t\v";
388 int i, v = 0;
389 char c;
390 if( p->sIn.i>=p->sIn.mx ) return 0;
391 c = p->sIn.z[0];
392 if( c=='u' && p->sIn.i+5<p->sIn.mx ){
393 v = 0;
394 const unsigned char *zIn = p->sIn.z + p->sIn.i;
395 if( re_hex(zIn[1],&v)
396 && re_hex(zIn[2],&v)
397 && re_hex(zIn[3],&v)
398 && re_hex(zIn[4],&v)
@@ -399,15 +401,16 @@
399 ){
400 p->sIn.i += 5;
401 return v;
402 }
403 }
404 if( c=='x' ){
405 v = 0;
406 for(i=1; p->sIn.i<p->sIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){}
407 if( i>1 ){
408 p->sIn.i += i;
 
409 return v;
410 }
411 }
412 for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
413 if( zEsc[i] ){
@@ -594,16 +597,17 @@
594 */
595 void re_free(ReCompiled *pRe){
596 if( pRe ){
597 fossil_free(pRe->aOp);
598 fossil_free(pRe->aArg);
 
599 }
600 }
601
602 /*
603 ** Compile a textual regular expression in zIn[] into a compiled regular
604 ** expression suitable for us by re_execute() and return a pointer to the
605 ** compiled regular expression in *ppRe. Return NULL on success or an
606 ** error message if something goes wrong.
607 */
608 const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
609 ReCompiled *pRe;
@@ -632,11 +636,11 @@
632 zErr = re_subcompile_re(pRe);
633 if( zErr ){
634 re_free(pRe);
635 return zErr;
636 }
637 if( rePeek(pRe)=='$' && pRe->sIn.i+1==pRe->sIn.mx ){
638 re_append(pRe, RE_OP_MATCH, RE_EOF);
639 re_append(pRe, RE_OP_ACCEPT, 0);
640 *ppRe = pRe;
641 }else if( pRe->sIn.i>=pRe->sIn.mx ){
642 re_append(pRe, RE_OP_ACCEPT, 0);
@@ -643,10 +647,19 @@
643 *ppRe = pRe;
644 }else{
645 re_free(pRe);
646 return "unrecognized character";
647 }
 
 
 
 
 
 
 
 
 
648 if( pRe->aOp[0]==RE_OP_ANYSTAR ){
649 for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
650 unsigned x = pRe->aArg[i];
651 if( x<=127 ){
652 pRe->zInit[j++] = x;
@@ -654,15 +667,16 @@
654 pRe->zInit[j++] = 0xc0 | (x>>6);
655 pRe->zInit[j++] = 0x80 | (x&0x3f);
656 }else if( x<=0xffff ){
657 pRe->zInit[j++] = 0xd0 | (x>>12);
658 pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
659 pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
660 }else{
661 break;
662 }
663 }
 
664 pRe->nInit = j;
665 }
666 return pRe->zErr;
667 }
668
@@ -700,11 +714,11 @@
700 }
701 sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
702 }
703 zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
704 if( zStr!=0 ){
705 sqlite3_result_int(context, re_execute(pRe, zStr, -1));
706 }
707 }
708
709 /*
710 ** Invoke this routine in order to install the REGEXP function in an
@@ -731,11 +745,11 @@
731 char zLine[2000];
732 while( fgets(zLine, sizeof(zLine), in) ){
733 ln++;
734 n = (int)strlen(zLine);
735 while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--;
736 if( re_execute(pRe, (const unsigned char*)zLine, n) ){
737 printf("%s:%d:%.*s\n", zFile, ln, n, zLine);
738 }
739 }
740 }
741
742
--- src/regexp.c
+++ src/regexp.c
@@ -32,11 +32,11 @@
32 ** X$ X occurring at the end of the string
33 ** . Match any single character
34 ** \c Character c where c is one of \{}()[]|*+?.
35 ** \c C-language escapes for c in afnrtv. ex: \t or \n
36 ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX
37 ** \xXX Where XX is exactly 2 hex digits, unicode value XX
38 ** [abc] Any single character from the set abc
39 ** [^abc] Any single character not in the set abc
40 ** [a-z] Any single character in the range a-z
41 ** [^a-z] Any single character not in the range a-z
42 ** \b Word boundary
@@ -134,25 +134,25 @@
134 */
135 static unsigned re_next_char(ReInput *p){
136 unsigned c;
137 if( p->i>=p->mx ) return 0;
138 c = p->z[p->i++];
139 if( c>=0x80 ){
140 if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
141 c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
142 if( c<0x80 ) c = 0xfffd;
143 }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80
144 && (p->z[p->i+1]&0xc0)==0x80 ){
145 c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
146 p->i += 2;
147 if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
148 }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
149 && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
150 c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
151 | (p->z[p->i+2]&0x3f);
152 p->i += 3;
153 if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
154 }else{
155 c = 0xfffd;
156 }
157 }
158 return c;
@@ -172,17 +172,17 @@
172 return (c>='0' && c<='9');
173 }
174
175 /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */
176 static int re_space_char(int c){
177 return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
178 }
179
180 /* Run a compiled regular expression on the zero-terminated input
181 ** string zIn[]. Return true on a match and false if there is no match.
182 */
183 int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
184 ReStateSet aStateSet[2], *pThis, *pNext;
185 ReStateNumber aSpace[100];
186 ReStateNumber *pToFree;
187 unsigned int i = 0;
188 unsigned int iSwap = 0;
@@ -192,19 +192,22 @@
192 ReInput in;
193
194 in.z = zIn;
195 in.i = 0;
196 in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);
197
198 /* Look for the initial prefix match, if there is one. */
199 if( pRe->nInit ){
200 unsigned char x = pRe->zInit[0];
201 while( in.i+pRe->nInit<=in.mx
202 && (zIn[in.i]!=x || memcmp(zIn+in.i, pRe->zInit, pRe->nInit)!=0)
203 ){
204 in.i++;
205 }
206 if( in.i+pRe->nInit>in.mx ) return 0;
207 }
208
209 if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
210 pToFree = 0;
211 aStateSet[0].aState = aSpace;
212 }else{
213 pToFree = fossil_malloc( sizeof(ReStateNumber)*2*pRe->nState );
@@ -275,11 +278,11 @@
278 re_add_state(pThis, x+pRe->aArg[x]);
279 break;
280 }
281 case RE_OP_ACCEPT: {
282 rc = 1;
283 goto re_match_end;
284 }
285 case RE_OP_CC_INC:
286 case RE_OP_CC_EXC: {
287 int j = 1;
288 int n = pRe->aArg[x];
@@ -307,11 +310,11 @@
310 }
311 }
312 for(i=0; i<pNext->nState; i++){
313 if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
314 }
315 re_match_end:
316 fossil_free(pToFree);
317 return rc;
318 }
319
320 /* Resize the opcode and argument arrays for an RE under construction.
@@ -378,21 +381,20 @@
381 *pV = (*pV)*16 + (c & 0xff);
382 return 1;
383 }
384
385 /* A backslash character has been seen, read the next character and
386 ** return its interpretation.
387 */
388 static unsigned re_esc_char(ReCompiled *p){
389 static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
390 static const char zTrans[] = "\a\f\n\r\t\v";
391 int i, v = 0;
392 char c;
393 if( p->sIn.i>=p->sIn.mx ) return 0;
394 c = p->sIn.z[p->sIn.i];
395 if( c=='u' && p->sIn.i+4<p->sIn.mx ){
 
396 const unsigned char *zIn = p->sIn.z + p->sIn.i;
397 if( re_hex(zIn[1],&v)
398 && re_hex(zIn[2],&v)
399 && re_hex(zIn[3],&v)
400 && re_hex(zIn[4],&v)
@@ -399,15 +401,16 @@
401 ){
402 p->sIn.i += 5;
403 return v;
404 }
405 }
406 if( c=='x' && p->sIn.i+2<p->sIn.mx ){
407 const unsigned char *zIn = p->sIn.z + p->sIn.i;
408 if( re_hex(zIn[1],&v)
409 && re_hex(zIn[2],&v)
410 ){
411 p->sIn.i += 3;
412 return v;
413 }
414 }
415 for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
416 if( zEsc[i] ){
@@ -594,16 +597,17 @@
597 */
598 void re_free(ReCompiled *pRe){
599 if( pRe ){
600 fossil_free(pRe->aOp);
601 fossil_free(pRe->aArg);
602 fossil_free(pRe);
603 }
604 }
605
606 /*
607 ** Compile a textual regular expression in zIn[] into a compiled regular
608 ** expression suitable for us by re_match() and return a pointer to the
609 ** compiled regular expression in *ppRe. Return NULL on success or an
610 ** error message if something goes wrong.
611 */
612 const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
613 ReCompiled *pRe;
@@ -632,11 +636,11 @@
636 zErr = re_subcompile_re(pRe);
637 if( zErr ){
638 re_free(pRe);
639 return zErr;
640 }
641 if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
642 re_append(pRe, RE_OP_MATCH, RE_EOF);
643 re_append(pRe, RE_OP_ACCEPT, 0);
644 *ppRe = pRe;
645 }else if( pRe->sIn.i>=pRe->sIn.mx ){
646 re_append(pRe, RE_OP_ACCEPT, 0);
@@ -643,10 +647,19 @@
647 *ppRe = pRe;
648 }else{
649 re_free(pRe);
650 return "unrecognized character";
651 }
652
653 /* The following is a performance optimization. If the regex begins with
654 ** ".*" (if the input regex lacks an initial "^") and afterwards there are
655 ** one or more matching characters, enter those matching characters into
656 ** zInit[]. The re_match() routine can then search ahead in the input
657 ** string looking for the initial match without having to run the whole
658 ** regex engine over the string. Do not worry able trying to match
659 ** unicode characters beyond plane 0 - those are very rare and this is
660 ** just an optimization. */
661 if( pRe->aOp[0]==RE_OP_ANYSTAR ){
662 for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
663 unsigned x = pRe->aArg[i];
664 if( x<=127 ){
665 pRe->zInit[j++] = x;
@@ -654,15 +667,16 @@
667 pRe->zInit[j++] = 0xc0 | (x>>6);
668 pRe->zInit[j++] = 0x80 | (x&0x3f);
669 }else if( x<=0xffff ){
670 pRe->zInit[j++] = 0xd0 | (x>>12);
671 pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f);
672 pRe->zInit[j++] = 0x80 | (x&0x3f);
673 }else{
674 break;
675 }
676 }
677 if( j>0 && pRe->zInit[j-1]==0 ) j--;
678 pRe->nInit = j;
679 }
680 return pRe->zErr;
681 }
682
@@ -700,11 +714,11 @@
714 }
715 sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
716 }
717 zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
718 if( zStr!=0 ){
719 sqlite3_result_int(context, re_match(pRe, zStr, -1));
720 }
721 }
722
723 /*
724 ** Invoke this routine in order to install the REGEXP function in an
@@ -731,11 +745,11 @@
745 char zLine[2000];
746 while( fgets(zLine, sizeof(zLine), in) ){
747 ln++;
748 n = (int)strlen(zLine);
749 while( n && (zLine[n-1]=='\n' || zLine[n-1]=='\r') ) n--;
750 if( re_match(pRe, (const unsigned char*)zLine, n) ){
751 printf("%s:%d:%.*s\n", zFile, ln, n, zLine);
752 }
753 }
754 }
755
756
--- src/schema.c
+++ src/schema.c
@@ -385,10 +385,11 @@
385385
@ CREATE TABLE ticket(
386386
@ -- Do not change any column that begins with tkt_
387387
@ tkt_id INTEGER PRIMARY KEY,
388388
@ tkt_uuid TEXT UNIQUE,
389389
@ tkt_mtime DATE,
390
+@ tkt_ctime DATE,
390391
@ -- Add as many field as required below this line
391392
@ type TEXT,
392393
@ status TEXT,
393394
@ subsystem TEXT,
394395
@ priority TEXT,
@@ -400,10 +401,11 @@
400401
@ comment TEXT
401402
@ );
402403
@ CREATE TABLE ticketchng(
403404
@ -- Do not change any column that begins with tkt_
404405
@ tkt_id INTEGER REFERENCES ticket,
406
+@ tkt_rid INTEGER REFERENCES blob,
405407
@ tkt_mtime DATE,
406408
@ -- Add as many fields as required below this line
407409
@ login TEXT,
408410
@ username TEXT,
409411
@ mimetype TEXT,
410412
--- src/schema.c
+++ src/schema.c
@@ -385,10 +385,11 @@
385 @ CREATE TABLE ticket(
386 @ -- Do not change any column that begins with tkt_
387 @ tkt_id INTEGER PRIMARY KEY,
388 @ tkt_uuid TEXT UNIQUE,
389 @ tkt_mtime DATE,
 
390 @ -- Add as many field as required below this line
391 @ type TEXT,
392 @ status TEXT,
393 @ subsystem TEXT,
394 @ priority TEXT,
@@ -400,10 +401,11 @@
400 @ comment TEXT
401 @ );
402 @ CREATE TABLE ticketchng(
403 @ -- Do not change any column that begins with tkt_
404 @ tkt_id INTEGER REFERENCES ticket,
 
405 @ tkt_mtime DATE,
406 @ -- Add as many fields as required below this line
407 @ login TEXT,
408 @ username TEXT,
409 @ mimetype TEXT,
410
--- src/schema.c
+++ src/schema.c
@@ -385,10 +385,11 @@
385 @ CREATE TABLE ticket(
386 @ -- Do not change any column that begins with tkt_
387 @ tkt_id INTEGER PRIMARY KEY,
388 @ tkt_uuid TEXT UNIQUE,
389 @ tkt_mtime DATE,
390 @ tkt_ctime DATE,
391 @ -- Add as many field as required below this line
392 @ type TEXT,
393 @ status TEXT,
394 @ subsystem TEXT,
395 @ priority TEXT,
@@ -400,10 +401,11 @@
401 @ comment TEXT
402 @ );
403 @ CREATE TABLE ticketchng(
404 @ -- Do not change any column that begins with tkt_
405 @ tkt_id INTEGER REFERENCES ticket,
406 @ tkt_rid INTEGER REFERENCES blob,
407 @ tkt_mtime DATE,
408 @ -- Add as many fields as required below this line
409 @ login TEXT,
410 @ username TEXT,
411 @ mimetype TEXT,
412
--- src/schema.c
+++ src/schema.c
@@ -385,10 +385,11 @@
385385
@ CREATE TABLE ticket(
386386
@ -- Do not change any column that begins with tkt_
387387
@ tkt_id INTEGER PRIMARY KEY,
388388
@ tkt_uuid TEXT UNIQUE,
389389
@ tkt_mtime DATE,
390
+@ tkt_ctime DATE,
390391
@ -- Add as many field as required below this line
391392
@ type TEXT,
392393
@ status TEXT,
393394
@ subsystem TEXT,
394395
@ priority TEXT,
@@ -400,10 +401,11 @@
400401
@ comment TEXT
401402
@ );
402403
@ CREATE TABLE ticketchng(
403404
@ -- Do not change any column that begins with tkt_
404405
@ tkt_id INTEGER REFERENCES ticket,
406
+@ tkt_rid INTEGER REFERENCES blob,
405407
@ tkt_mtime DATE,
406408
@ -- Add as many fields as required below this line
407409
@ login TEXT,
408410
@ username TEXT,
409411
@ mimetype TEXT,
410412
--- src/schema.c
+++ src/schema.c
@@ -385,10 +385,11 @@
385 @ CREATE TABLE ticket(
386 @ -- Do not change any column that begins with tkt_
387 @ tkt_id INTEGER PRIMARY KEY,
388 @ tkt_uuid TEXT UNIQUE,
389 @ tkt_mtime DATE,
 
390 @ -- Add as many field as required below this line
391 @ type TEXT,
392 @ status TEXT,
393 @ subsystem TEXT,
394 @ priority TEXT,
@@ -400,10 +401,11 @@
400 @ comment TEXT
401 @ );
402 @ CREATE TABLE ticketchng(
403 @ -- Do not change any column that begins with tkt_
404 @ tkt_id INTEGER REFERENCES ticket,
 
405 @ tkt_mtime DATE,
406 @ -- Add as many fields as required below this line
407 @ login TEXT,
408 @ username TEXT,
409 @ mimetype TEXT,
410
--- src/schema.c
+++ src/schema.c
@@ -385,10 +385,11 @@
385 @ CREATE TABLE ticket(
386 @ -- Do not change any column that begins with tkt_
387 @ tkt_id INTEGER PRIMARY KEY,
388 @ tkt_uuid TEXT UNIQUE,
389 @ tkt_mtime DATE,
390 @ tkt_ctime DATE,
391 @ -- Add as many field as required below this line
392 @ type TEXT,
393 @ status TEXT,
394 @ subsystem TEXT,
395 @ priority TEXT,
@@ -400,10 +401,11 @@
401 @ comment TEXT
402 @ );
403 @ CREATE TABLE ticketchng(
404 @ -- Do not change any column that begins with tkt_
405 @ tkt_id INTEGER REFERENCES ticket,
406 @ tkt_rid INTEGER REFERENCES blob,
407 @ tkt_mtime DATE,
408 @ -- Add as many fields as required below this line
409 @ login TEXT,
410 @ username TEXT,
411 @ mimetype TEXT,
412
--- src/setup.c
+++ src/setup.c
@@ -917,10 +917,19 @@
917917
@ to this many bytes, uncompressed. If the client requires more data
918918
@ than this, then the client will issue multiple HTTP requests.
919919
@ Values below 1 million are not recommended. 5 million is a
920920
@ reasonable number.</p>
921921
922
+ @ <hr />
923
+ entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt",
924
+ "30");
925
+
926
+ @ <p>Fossil tries to spend less than this many seconds gathering
927
+ @ the out-bound data of sync, clone, and pull packets.
928
+ @ If the client request takes longer, a partial reply is given similar
929
+ @ to the download packet limit. 30s is a reasonable default.</p>
930
+
922931
@ <hr />
923932
onoff_attribute(
924933
"Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
925934
"auto-hyperlink", "autohyperlink", 1);
926935
@ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
927936
--- src/setup.c
+++ src/setup.c
@@ -917,10 +917,19 @@
917 @ to this many bytes, uncompressed. If the client requires more data
918 @ than this, then the client will issue multiple HTTP requests.
919 @ Values below 1 million are not recommended. 5 million is a
920 @ reasonable number.</p>
921
 
 
 
 
 
 
 
 
 
922 @ <hr />
923 onoff_attribute(
924 "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
925 "auto-hyperlink", "autohyperlink", 1);
926 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
927
--- src/setup.c
+++ src/setup.c
@@ -917,10 +917,19 @@
917 @ to this many bytes, uncompressed. If the client requires more data
918 @ than this, then the client will issue multiple HTTP requests.
919 @ Values below 1 million are not recommended. 5 million is a
920 @ reasonable number.</p>
921
922 @ <hr />
923 entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt",
924 "30");
925
926 @ <p>Fossil tries to spend less than this many seconds gathering
927 @ the out-bound data of sync, clone, and pull packets.
928 @ If the client request takes longer, a partial reply is given similar
929 @ to the download packet limit. 30s is a reasonable default.</p>
930
931 @ <hr />
932 onoff_attribute(
933 "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
934 "auto-hyperlink", "autohyperlink", 1);
935 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
936
--- src/setup.c
+++ src/setup.c
@@ -917,10 +917,19 @@
917917
@ to this many bytes, uncompressed. If the client requires more data
918918
@ than this, then the client will issue multiple HTTP requests.
919919
@ Values below 1 million are not recommended. 5 million is a
920920
@ reasonable number.</p>
921921
922
+ @ <hr />
923
+ entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt",
924
+ "30");
925
+
926
+ @ <p>Fossil tries to spend less than this many seconds gathering
927
+ @ the out-bound data of sync, clone, and pull packets.
928
+ @ If the client request takes longer, a partial reply is given similar
929
+ @ to the download packet limit. 30s is a reasonable default.</p>
930
+
922931
@ <hr />
923932
onoff_attribute(
924933
"Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
925934
"auto-hyperlink", "autohyperlink", 1);
926935
@ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
927936
--- src/setup.c
+++ src/setup.c
@@ -917,10 +917,19 @@
917 @ to this many bytes, uncompressed. If the client requires more data
918 @ than this, then the client will issue multiple HTTP requests.
919 @ Values below 1 million are not recommended. 5 million is a
920 @ reasonable number.</p>
921
 
 
 
 
 
 
 
 
 
922 @ <hr />
923 onoff_attribute(
924 "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
925 "auto-hyperlink", "autohyperlink", 1);
926 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
927
--- src/setup.c
+++ src/setup.c
@@ -917,10 +917,19 @@
917 @ to this many bytes, uncompressed. If the client requires more data
918 @ than this, then the client will issue multiple HTTP requests.
919 @ Values below 1 million are not recommended. 5 million is a
920 @ reasonable number.</p>
921
922 @ <hr />
923 entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt",
924 "30");
925
926 @ <p>Fossil tries to spend less than this many seconds gathering
927 @ the out-bound data of sync, clone, and pull packets.
928 @ If the client request takes longer, a partial reply is given similar
929 @ to the download packet limit. 30s is a reasonable default.</p>
930
931 @ <hr />
932 onoff_attribute(
933 "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
934 "auto-hyperlink", "autohyperlink", 1);
935 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
936
--- src/shell.c
+++ src/shell.c
@@ -1477,10 +1477,16 @@
14771477
p->zDbFilename, sqlite3_errmsg(db));
14781478
exit(1);
14791479
}
14801480
#ifndef SQLITE_OMIT_LOAD_EXTENSION
14811481
sqlite3_enable_load_extension(p->db, 1);
1482
+#endif
1483
+#ifdef SQLITE_ENABLE_REGEXP
1484
+ {
1485
+ extern int sqlite3_add_regexp_func(sqlite3*);
1486
+ sqlite3_add_regexp_func(db);
1487
+ }
14821488
#endif
14831489
}
14841490
}
14851491
14861492
/*
14871493
--- src/shell.c
+++ src/shell.c
@@ -1477,10 +1477,16 @@
1477 p->zDbFilename, sqlite3_errmsg(db));
1478 exit(1);
1479 }
1480 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1481 sqlite3_enable_load_extension(p->db, 1);
 
 
 
 
 
 
1482 #endif
1483 }
1484 }
1485
1486 /*
1487
--- src/shell.c
+++ src/shell.c
@@ -1477,10 +1477,16 @@
1477 p->zDbFilename, sqlite3_errmsg(db));
1478 exit(1);
1479 }
1480 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1481 sqlite3_enable_load_extension(p->db, 1);
1482 #endif
1483 #ifdef SQLITE_ENABLE_REGEXP
1484 {
1485 extern int sqlite3_add_regexp_func(sqlite3*);
1486 sqlite3_add_regexp_func(db);
1487 }
1488 #endif
1489 }
1490 }
1491
1492 /*
1493
--- src/shell.c
+++ src/shell.c
@@ -1477,10 +1477,16 @@
14771477
p->zDbFilename, sqlite3_errmsg(db));
14781478
exit(1);
14791479
}
14801480
#ifndef SQLITE_OMIT_LOAD_EXTENSION
14811481
sqlite3_enable_load_extension(p->db, 1);
1482
+#endif
1483
+#ifdef SQLITE_ENABLE_REGEXP
1484
+ {
1485
+ extern int sqlite3_add_regexp_func(sqlite3*);
1486
+ sqlite3_add_regexp_func(db);
1487
+ }
14821488
#endif
14831489
}
14841490
}
14851491
14861492
/*
14871493
--- src/shell.c
+++ src/shell.c
@@ -1477,10 +1477,16 @@
1477 p->zDbFilename, sqlite3_errmsg(db));
1478 exit(1);
1479 }
1480 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1481 sqlite3_enable_load_extension(p->db, 1);
 
 
 
 
 
 
1482 #endif
1483 }
1484 }
1485
1486 /*
1487
--- src/shell.c
+++ src/shell.c
@@ -1477,10 +1477,16 @@
1477 p->zDbFilename, sqlite3_errmsg(db));
1478 exit(1);
1479 }
1480 #ifndef SQLITE_OMIT_LOAD_EXTENSION
1481 sqlite3_enable_load_extension(p->db, 1);
1482 #endif
1483 #ifdef SQLITE_ENABLE_REGEXP
1484 {
1485 extern int sqlite3_add_regexp_func(sqlite3*);
1486 sqlite3_add_regexp_func(db);
1487 }
1488 #endif
1489 }
1490 }
1491
1492 /*
1493
+381 -172
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673673
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674674
** [sqlite_version()] and [sqlite_source_id()].
675675
*/
676676
#define SQLITE_VERSION "3.7.16"
677677
#define SQLITE_VERSION_NUMBER 3007016
678
-#define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
678
+#define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
679679
680680
/*
681681
** CAPI3REF: Run-Time Library Version Numbers
682682
** KEYWORDS: sqlite3_version, sqlite3_sourceid
683683
**
@@ -8238,10 +8238,15 @@
82388238
** A convenience macro that returns the number of elements in
82398239
** an array.
82408240
*/
82418241
#define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
82428242
8243
+/*
8244
+** Determine if the argument is a power of two
8245
+*/
8246
+#define IsPowerOfTwo(X) (((X)&((X)-1))==0)
8247
+
82438248
/*
82448249
** The following value as a destructor means to use sqlite3DbFree().
82458250
** The sqlite3DbFree() routine requires two parameters instead of the
82468251
** one parameter that destructors normally want. So we have to introduce
82478252
** this magic value that the code knows to handle differently. Any
@@ -10042,10 +10047,11 @@
1004210047
#define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
1004310048
#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
1004410049
#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
1004510050
#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
1004610051
#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
10052
+#define SQLITE_Transitive 0x0200 /* Transitive constraints */
1004710053
#define SQLITE_AllOpts 0xffff /* All optimizations */
1004810054
1004910055
/*
1005010056
** Macros for testing whether or not optimizations are enabled or disabled.
1005110057
*/
@@ -10553,24 +10559,24 @@
1055310559
** and the value of Index.onError indicate the which conflict resolution
1055410560
** algorithm to employ whenever an attempt is made to insert a non-unique
1055510561
** element.
1055610562
*/
1055710563
struct Index {
10558
- char *zName; /* Name of this index */
10559
- int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10560
- tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
10561
- Table *pTable; /* The SQL table being indexed */
10562
- char *zColAff; /* String defining the affinity of each column */
10563
- Index *pNext; /* The next index associated with the same table */
10564
- Schema *pSchema; /* Schema containing this index */
10565
- u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
10566
- char **azColl; /* Array of collation sequence names for index */
10567
- int nColumn; /* Number of columns in the table used by this index */
10568
- int tnum; /* Page containing root of this index in database file */
10569
- u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10570
- u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
10571
- u8 bUnordered; /* Use this index for == or IN queries only */
10564
+ char *zName; /* Name of this index */
10565
+ int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10566
+ tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
10567
+ Table *pTable; /* The SQL table being indexed */
10568
+ char *zColAff; /* String defining the affinity of each column */
10569
+ Index *pNext; /* The next index associated with the same table */
10570
+ Schema *pSchema; /* Schema containing this index */
10571
+ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
10572
+ char **azColl; /* Array of collation sequence names for index */
10573
+ int tnum; /* DB Page containing root of this index */
10574
+ u16 nColumn; /* Number of columns in table used by this index */
10575
+ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10576
+ unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
10577
+ unsigned bUnordered:1; /* Use this index for == or IN queries only */
1057210578
#ifdef SQLITE_ENABLE_STAT3
1057310579
int nSample; /* Number of elements in aSample[] */
1057410580
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
1057510581
IndexSample *aSample; /* Samples of the left-most key */
1057610582
#endif
@@ -10840,22 +10846,31 @@
1084010846
** name. An expr/name combination can be used in several ways, such
1084110847
** as the list of "expr AS ID" fields following a "SELECT" or in the
1084210848
** list of "ID = expr" items in an UPDATE. A list of expressions can
1084310849
** also be used as the argument to a function, in which case the a.zName
1084410850
** field is not used.
10851
+**
10852
+** By default the Expr.zSpan field holds a human-readable description of
10853
+** the expression that is used in the generation of error messages and
10854
+** column labels. In this case, Expr.zSpan is typically the text of a
10855
+** column expression as it exists in a SELECT statement. However, if
10856
+** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
10857
+** of the result column in the form: DATABASE.TABLE.COLUMN. This later
10858
+** form is used for name resolution with nested FROM clauses.
1084510859
*/
1084610860
struct ExprList {
1084710861
int nExpr; /* Number of expressions on the list */
1084810862
int iECursor; /* VDBE Cursor associated with this ExprList */
1084910863
struct ExprList_item { /* For each expression in the list */
10850
- Expr *pExpr; /* The list of expressions */
10851
- char *zName; /* Token associated with this expression */
10852
- char *zSpan; /* Original text of the expression */
10853
- u8 sortOrder; /* 1 for DESC or 0 for ASC */
10854
- u8 done; /* A flag to indicate when processing is finished */
10855
- u16 iOrderByCol; /* For ORDER BY, column number in result set */
10856
- u16 iAlias; /* Index into Parse.aAlias[] for zName */
10864
+ Expr *pExpr; /* The list of expressions */
10865
+ char *zName; /* Token associated with this expression */
10866
+ char *zSpan; /* Original text of the expression */
10867
+ u8 sortOrder; /* 1 for DESC or 0 for ASC */
10868
+ unsigned done :1; /* A flag to indicate when processing is finished */
10869
+ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
10870
+ u16 iOrderByCol; /* For ORDER BY, column number in result set */
10871
+ u16 iAlias; /* Index into Parse.aAlias[] for zName */
1085710872
} *a; /* Alloc a power of two greater or equal to nExpr */
1085810873
};
1085910874
1086010875
/*
1086110876
** An instance of this structure is used by the parser to record both
@@ -12141,10 +12156,11 @@
1214112156
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
1214212157
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
1214312158
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
1214412159
SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
1214512160
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
12161
+SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
1214612162
SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
1214712163
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
1214812164
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
1214912165
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
1215012166
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
@@ -23289,15 +23305,11 @@
2328923305
{ "pwrite64", (sqlite3_syscall_ptr)0, 0 },
2329023306
#endif
2329123307
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
2329223308
aSyscall[13].pCurrent)
2329323309
23294
-#if SQLITE_ENABLE_LOCKING_STYLE
2329523310
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
23296
-#else
23297
- { "fchmod", (sqlite3_syscall_ptr)0, 0 },
23298
-#endif
2329923311
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
2330023312
2330123313
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
2330223314
{ "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
2330323315
#else
@@ -23318,13 +23330,10 @@
2331823330
#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
2331923331
2332023332
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
2332123333
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
2332223334
23323
- { "umask", (sqlite3_syscall_ptr)umask, 0 },
23324
-#define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
23325
-
2332623335
}; /* End of the overrideable system calls */
2332723336
2332823337
/*
2332923338
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
2333023339
** "unix" VFSes. Return SQLITE_OK opon successfully updating the
@@ -23425,31 +23434,29 @@
2342523434
** process that is able to write to the database will also be able to
2342623435
** recover the hot journals.
2342723436
*/
2342823437
static int robust_open(const char *z, int f, mode_t m){
2342923438
int fd;
23430
- mode_t m2;
23431
- mode_t origM = 0;
23432
- if( m==0 ){
23433
- m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
23434
- }else{
23435
- m2 = m;
23436
- origM = osUmask(0);
23437
- }
23439
+ mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
2343823440
do{
2343923441
#if defined(O_CLOEXEC)
2344023442
fd = osOpen(z,f|O_CLOEXEC,m2);
2344123443
#else
2344223444
fd = osOpen(z,f,m2);
2344323445
#endif
2344423446
}while( fd<0 && errno==EINTR );
23445
- if( m ){
23446
- osUmask(origM);
23447
- }
23447
+ if( fd>=0 ){
23448
+ if( m!=0 ){
23449
+ struct stat statbuf;
23450
+ if( osFstat(fd, &statbuf)==0 && (statbuf.st_mode&0777)!=m ){
23451
+ osFchmod(fd, m);
23452
+ }
23453
+ }
2344823454
#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23449
- if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
23455
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
2345023456
#endif
23457
+ }
2345123458
return fd;
2345223459
}
2345323460
2345423461
/*
2345523462
** Helper functions to obtain and relinquish the global mutex. The
@@ -29871,11 +29878,11 @@
2987129878
};
2987229879
unsigned int i; /* Loop counter */
2987329880
2987429881
/* Double-check that the aSyscall[] array has been constructed
2987529882
** correctly. See ticket [bb3a86e890c8e96ab] */
29876
- assert( ArraySize(aSyscall)==22 );
29883
+ assert( ArraySize(aSyscall)==21 );
2987729884
2987829885
/* Register all VFSes defined in the aVfs[] array */
2987929886
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
2988029887
sqlite3_vfs_register(&aVfs[i], i==0);
2988129888
}
@@ -72655,10 +72662,39 @@
7265572662
}
7265672663
}
7265772664
return 0;
7265872665
}
7265972666
72667
+/*
72668
+** Subqueries stores the original database, table and column names for their
72669
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
72670
+** Check to see if the zSpan given to this routine matches the zDb, zTab,
72671
+** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
72672
+** match anything.
72673
+*/
72674
+SQLITE_PRIVATE int sqlite3MatchSpanName(
72675
+ const char *zSpan,
72676
+ const char *zCol,
72677
+ const char *zTab,
72678
+ const char *zDb
72679
+){
72680
+ int n;
72681
+ for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72682
+ if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
72683
+ return 0;
72684
+ }
72685
+ zSpan += n+1;
72686
+ for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72687
+ if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
72688
+ return 0;
72689
+ }
72690
+ zSpan += n+1;
72691
+ if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
72692
+ return 0;
72693
+ }
72694
+ return 1;
72695
+}
7266072696
7266172697
/*
7266272698
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
7266372699
** that name in the set of source tables in pSrcList and make the pExpr
7266472700
** expression node refer back to that source column. The following changes
@@ -72710,44 +72746,63 @@
7271072746
7271172747
/* Initialize the node to no-match */
7271272748
pExpr->iTable = -1;
7271372749
pExpr->pTab = 0;
7271472750
ExprSetIrreducible(pExpr);
72751
+
72752
+ /* Translate the schema name in zDb into a pointer to the corresponding
72753
+ ** schema. If not found, pSchema will remain NULL and nothing will match
72754
+ ** resulting in an appropriate error message toward the end of this routine
72755
+ */
72756
+ if( zDb ){
72757
+ for(i=0; i<db->nDb; i++){
72758
+ assert( db->aDb[i].zName );
72759
+ if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
72760
+ pSchema = db->aDb[i].pSchema;
72761
+ break;
72762
+ }
72763
+ }
72764
+ }
7271572765
7271672766
/* Start at the inner-most context and move outward until a match is found */
7271772767
while( pNC && cnt==0 ){
7271872768
ExprList *pEList;
7271972769
SrcList *pSrcList = pNC->pSrcList;
7272072770
7272172771
if( pSrcList ){
7272272772
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
7272372773
Table *pTab;
72724
- int iDb;
7272572774
Column *pCol;
7272672775
7272772776
pTab = pItem->pTab;
7272872777
assert( pTab!=0 && pTab->zName!=0 );
72729
- iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
7273072778
assert( pTab->nCol>0 );
72779
+ if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
72780
+ ExprList *pEList = pItem->pSelect->pEList;
72781
+ int hit = 0;
72782
+ for(j=0; j<pEList->nExpr; j++){
72783
+ if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
72784
+ cnt++;
72785
+ cntTab = 2;
72786
+ pMatch = pItem;
72787
+ pExpr->iColumn = j;
72788
+ hit = 1;
72789
+ }
72790
+ }
72791
+ if( hit || zTab==0 ) continue;
72792
+ }
72793
+ if( zDb && pTab->pSchema!=pSchema ){
72794
+ continue;
72795
+ }
7273172796
if( zTab ){
72732
- if( pItem->zAlias ){
72733
- char *zTabName = pItem->zAlias;
72734
- if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
72735
- }else{
72736
- char *zTabName = pTab->zName;
72737
- if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
72738
- continue;
72739
- }
72740
- if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
72741
- continue;
72742
- }
72797
+ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
72798
+ assert( zTabName!=0 );
72799
+ if( sqlite3StrICmp(zTabName, zTab)!=0 ){
72800
+ continue;
7274372801
}
7274472802
}
7274572803
if( 0==(cntTab++) ){
72746
- pExpr->iTable = pItem->iCursor;
72747
- pExpr->pTab = pTab;
72748
- pSchema = pTab->pSchema;
7274972804
pMatch = pItem;
7275072805
}
7275172806
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
7275272807
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
7275372808
/* If there has been exactly one prior match and this match
@@ -72757,21 +72812,23 @@
7275772812
if( cnt==1 ){
7275872813
if( pItem->jointype & JT_NATURAL ) continue;
7275972814
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
7276072815
}
7276172816
cnt++;
72762
- pExpr->iTable = pItem->iCursor;
72763
- pExpr->pTab = pTab;
7276472817
pMatch = pItem;
72765
- pSchema = pTab->pSchema;
7276672818
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
7276772819
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
7276872820
break;
7276972821
}
7277072822
}
7277172823
}
72772
- }
72824
+ if( pMatch ){
72825
+ pExpr->iTable = pMatch->iCursor;
72826
+ pExpr->pTab = pMatch->pTab;
72827
+ pSchema = pExpr->pTab->pSchema;
72828
+ }
72829
+ } /* if( pSrcList ) */
7277372830
7277472831
#ifndef SQLITE_OMIT_TRIGGER
7277572832
/* If we have not already resolved the name, then maybe
7277672833
** it is a new.* or old.* trigger argument reference
7277772834
*/
@@ -73102,11 +73159,11 @@
7310273159
#endif
7310373160
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
7310473161
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
7310573162
pNC->nErr++;
7310673163
is_agg = 0;
73107
- }else if( no_such_func ){
73164
+ }else if( no_such_func && pParse->db->init.busy==0 ){
7310873165
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
7310973166
pNC->nErr++;
7311073167
}else if( wrong_num_args ){
7311173168
sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
7311273169
nId, zId);
@@ -77065,10 +77122,16 @@
7706577122
for(i=0; i<pList->nExpr; i++){
7706677123
sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
7706777124
sqlite3ExplainPush(pOut);
7706877125
sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
7706977126
sqlite3ExplainPop(pOut);
77127
+ if( pList->a[i].zName ){
77128
+ sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
77129
+ }
77130
+ if( pList->a[i].bSpanIsTab ){
77131
+ sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
77132
+ }
7707077133
if( i<pList->nExpr-1 ){
7707177134
sqlite3ExplainNL(pOut);
7707277135
}
7707377136
}
7707477137
sqlite3ExplainPop(pOut);
@@ -92739,13 +92802,15 @@
9273992802
if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
9274092803
Table *pTab;
9274192804
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9274292805
pTab = sqlite3FindTable(db, zRight, zDb);
9274392806
if( pTab ){
92744
- int i;
92807
+ int i, k;
9274592808
int nHidden = 0;
9274692809
Column *pCol;
92810
+ Index *pPk;
92811
+ for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
9274792812
sqlite3VdbeSetNumCols(v, 6);
9274892813
pParse->nMem = 6;
9274992814
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
9275092815
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
9275192816
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
@@ -92766,12 +92831,18 @@
9276692831
if( pCol->zDflt ){
9276792832
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
9276892833
}else{
9276992834
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
9277092835
}
92771
- sqlite3VdbeAddOp2(v, OP_Integer,
92772
- (pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6);
92836
+ if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
92837
+ k = 0;
92838
+ }else if( pPk==0 ){
92839
+ k = 1;
92840
+ }else{
92841
+ for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
92842
+ }
92843
+ sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
9277392844
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
9277492845
}
9277592846
}
9277692847
}else
9277792848
@@ -93516,11 +93587,11 @@
9351693587
sqlite3_rekey(db, zKey, i/2);
9351793588
}
9351893589
}else
9351993590
#endif
9352093591
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
93521
- if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
93592
+ if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){
9352293593
#ifdef SQLITE_HAS_CODEC
9352393594
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
9352493595
sqlite3_activate_see(&zRight[4]);
9352593596
}
9352693597
#endif
@@ -95756,12 +95827,10 @@
9575695827
9575795828
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
9575895829
/* Get an appropriate name for the column
9575995830
*/
9576095831
p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
95761
- assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
95762
- || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
9576395832
if( (zName = pEList->a[i].zName)!=0 ){
9576495833
/* If the column contains an "AS <name>" phrase, use <name> as the name */
9576595834
zName = sqlite3DbStrDup(db, zName);
9576695835
}else{
9576795836
Expr *pColExpr = p; /* The expression that is the result column name */
@@ -95795,10 +95864,13 @@
9579595864
*/
9579695865
nName = sqlite3Strlen30(zName);
9579795866
for(j=cnt=0; j<i; j++){
9579895867
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
9579995868
char *zNewName;
95869
+ int k;
95870
+ for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
95871
+ if( zName[k]==':' ) nName = k;
9580095872
zName[nName] = 0;
9580195873
zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
9580295874
sqlite3DbFree(db, zName);
9580395875
zName = zNewName;
9580495876
j = -1;
@@ -97711,10 +97783,11 @@
9771197783
int i, j, k;
9771297784
SrcList *pTabList;
9771397785
ExprList *pEList;
9771497786
struct SrcList_item *pFrom;
9771597787
sqlite3 *db = pParse->db;
97788
+ Expr *pE, *pRight, *pExpr;
9771697789
9771797790
if( db->mallocFailed ){
9771897791
return WRC_Abort;
9771997792
}
9772097793
if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
@@ -97796,11 +97869,11 @@
9779697869
**
9779797870
** The first loop just checks to see if there are any "*" operators
9779897871
** that need expanding.
9779997872
*/
9780097873
for(k=0; k<pEList->nExpr; k++){
97801
- Expr *pE = pEList->a[k].pExpr;
97874
+ pE = pEList->a[k].pExpr;
9780297875
if( pE->op==TK_ALL ) break;
9780397876
assert( pE->op!=TK_DOT || pE->pRight!=0 );
9780497877
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
9780597878
if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
9780697879
}
@@ -97814,14 +97887,22 @@
9781497887
ExprList *pNew = 0;
9781597888
int flags = pParse->db->flags;
9781697889
int longNames = (flags & SQLITE_FullColNames)!=0
9781797890
&& (flags & SQLITE_ShortColNames)==0;
9781897891
97892
+ /* When processing FROM-clause subqueries, it is always the case
97893
+ ** that full_column_names=OFF and short_column_names=ON. The
97894
+ ** sqlite3ResultSetOfSelect() routine makes it so. */
97895
+ assert( (p->selFlags & SF_NestedFrom)==0
97896
+ || ((flags & SQLITE_FullColNames)==0 &&
97897
+ (flags & SQLITE_ShortColNames)!=0) );
97898
+
9781997899
for(k=0; k<pEList->nExpr; k++){
97820
- Expr *pE = a[k].pExpr;
97821
- assert( pE->op!=TK_DOT || pE->pRight!=0 );
97822
- if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
97900
+ pE = a[k].pExpr;
97901
+ pRight = pE->pRight;
97902
+ assert( pE->op!=TK_DOT || pRight!=0 );
97903
+ if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
9782397904
/* This particular expression does not need to be expanded.
9782497905
*/
9782597906
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
9782697907
if( pNew ){
9782797908
pNew->a[pNew->nExpr-1].zName = a[k].zName;
@@ -97832,44 +97913,56 @@
9783297913
a[k].pExpr = 0;
9783397914
}else{
9783497915
/* This expression is a "*" or a "TABLE.*" and needs to be
9783597916
** expanded. */
9783697917
int tableSeen = 0; /* Set to 1 when TABLE matches */
97837
- char *zTName; /* text of name of TABLE */
97918
+ char *zTName = 0; /* text of name of TABLE */
9783897919
if( pE->op==TK_DOT ){
9783997920
assert( pE->pLeft!=0 );
9784097921
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
9784197922
zTName = pE->pLeft->u.zToken;
97842
- }else{
97843
- zTName = 0;
9784497923
}
9784597924
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
9784697925
Table *pTab = pFrom->pTab;
97926
+ Select *pSub = pFrom->pSelect;
9784797927
char *zTabName = pFrom->zAlias;
97928
+ const char *zSchemaName = 0;
97929
+ int iDb;
9784897930
if( zTabName==0 ){
9784997931
zTabName = pTab->zName;
9785097932
}
9785197933
if( db->mallocFailed ) break;
97852
- if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97853
- continue;
97934
+ if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
97935
+ pSub = 0;
97936
+ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97937
+ continue;
97938
+ }
97939
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
97940
+ zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
9785497941
}
97855
- tableSeen = 1;
9785697942
for(j=0; j<pTab->nCol; j++){
97857
- Expr *pExpr, *pRight;
9785897943
char *zName = pTab->aCol[j].zName;
9785997944
char *zColname; /* The computed column name */
9786097945
char *zToFree; /* Malloced string that needs to be freed */
9786197946
Token sColname; /* Computed column name as a token */
97947
+
97948
+ assert( zName );
97949
+ if( zTName && pSub
97950
+ && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
97951
+ ){
97952
+ continue;
97953
+ }
9786297954
9786397955
/* If a column is marked as 'hidden' (currently only possible
9786497956
** for virtual tables), do not include it in the expanded
9786597957
** result-set list.
9786697958
*/
9786797959
if( IsHiddenColumn(&pTab->aCol[j]) ){
9786897960
assert(IsVirtual(pTab));
9786997961
continue;
9787097962
}
97963
+ tableSeen = 1;
9787197964
9787297965
if( i>0 && zTName==0 ){
9787397966
if( (pFrom->jointype & JT_NATURAL)!=0
9787497967
&& tableAndColumnIndex(pTabList, i, zName, 0, 0)
9787597968
){
@@ -97888,10 +97981,14 @@
9788897981
zToFree = 0;
9788997982
if( longNames || pTabList->nSrc>1 ){
9789097983
Expr *pLeft;
9789197984
pLeft = sqlite3Expr(db, TK_ID, zTabName);
9789297985
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
97986
+ if( zSchemaName ){
97987
+ pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
97988
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
97989
+ }
9789397990
if( longNames ){
9789497991
zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
9789597992
zToFree = zColname;
9789697993
}
9789797994
}else{
@@ -97899,10 +97996,22 @@
9789997996
}
9790097997
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
9790197998
sColname.z = zColname;
9790297999
sColname.n = sqlite3Strlen30(zColname);
9790398000
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
98001
+ if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
98002
+ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
98003
+ if( pSub ){
98004
+ pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
98005
+ testcase( pX->zSpan==0 );
98006
+ }else{
98007
+ pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
98008
+ zSchemaName, zTabName, zColname);
98009
+ testcase( pX->zSpan==0 );
98010
+ }
98011
+ pX->bSpanIsTab = 1;
98012
+ }
9790498013
sqlite3DbFree(db, zToFree);
9790598014
}
9790698015
}
9790798016
if( !tableSeen ){
9790898017
if( zTName ){
@@ -102699,12 +102808,12 @@
102699102808
Expr *pExpr; /* Pointer to the subexpression that is this term */
102700102809
int iParent; /* Disable pWC->a[iParent] when this term disabled */
102701102810
int leftCursor; /* Cursor number of X in "X <op> <expr>" */
102702102811
union {
102703102812
int leftColumn; /* Column number of X in "X <op> <expr>" */
102704
- WhereOrInfo *pOrInfo; /* Extra information if eOperator==WO_OR */
102705
- WhereAndInfo *pAndInfo; /* Extra information if eOperator==WO_AND */
102813
+ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
102814
+ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
102706102815
} u;
102707102816
u16 eOperator; /* A WO_xx value describing <op> */
102708102817
u8 wtFlags; /* TERM_xxx bit flags. See below */
102709102818
u8 nChild; /* Number of children that must disable us */
102710102819
WhereClause *pWC; /* The clause this term is part of */
@@ -102828,10 +102937,11 @@
102828102937
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
102829102938
#define WO_MATCH 0x040
102830102939
#define WO_ISNULL 0x080
102831102940
#define WO_OR 0x100 /* Two or more OR-connected terms */
102832102941
#define WO_AND 0x200 /* Two or more AND-connected terms */
102942
+#define WO_EQUIV 0x400 /* Of the form A==B, both columns */
102833102943
#define WO_NOOP 0x800 /* This term does not restrict search space */
102834102944
102835102945
#define WO_ALL 0xfff /* Mask of all possible WO_* values */
102836102946
#define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
102837102947
@@ -103230,58 +103340,112 @@
103230103340
/*
103231103341
** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
103232103342
** where X is a reference to the iColumn of table iCur and <op> is one of
103233103343
** the WO_xx operator codes specified by the op parameter.
103234103344
** Return a pointer to the term. Return 0 if not found.
103345
+**
103346
+** The term returned might by Y=<expr> if there is another constraint in
103347
+** the WHERE clause that specifies that X=Y. Any such constraints will be
103348
+** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
103349
+** aEquiv[] array holds X and all its equivalents, with each SQL variable
103350
+** taking up two slots in aEquiv[]. The first slot is for the cursor number
103351
+** and the second is for the column number. There are 22 slots in aEquiv[]
103352
+** so that means we can look for X plus up to 10 other equivalent values.
103353
+** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3
103354
+** and ... and A9=A10 and A10=<expr>.
103355
+**
103356
+** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
103357
+** then try for the one with no dependencies on <expr> - in other words where
103358
+** <expr> is a constant expression of some kind. Only return entries of
103359
+** the form "X <op> Y" where Y is a column in another table if no terms of
103360
+** the form "X <op> <const-expr>" exist. Other than this priority, if there
103361
+** are two or more terms that match, then the choice of which term to return
103362
+** is arbitrary.
103235103363
*/
103236103364
static WhereTerm *findTerm(
103237103365
WhereClause *pWC, /* The WHERE clause to be searched */
103238103366
int iCur, /* Cursor number of LHS */
103239103367
int iColumn, /* Column number of LHS */
103240103368
Bitmask notReady, /* RHS must not overlap with this mask */
103241103369
u32 op, /* Mask of WO_xx values describing operator */
103242103370
Index *pIdx /* Must be compatible with this index, if not NULL */
103243103371
){
103244
- WhereTerm *pTerm;
103245
- int k;
103372
+ WhereTerm *pTerm; /* Term being examined as possible result */
103373
+ WhereTerm *pResult = 0; /* The answer to return */
103374
+ WhereClause *pWCOrig = pWC; /* Original pWC value */
103375
+ int j, k; /* Loop counters */
103376
+ Expr *pX; /* Pointer to an expression */
103377
+ Parse *pParse; /* Parsing context */
103378
+ int iOrigCol = iColumn; /* Original value of iColumn */
103379
+ int nEquiv = 2; /* Number of entires in aEquiv[] */
103380
+ int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */
103381
+ int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */
103382
+
103246103383
assert( iCur>=0 );
103247
- op &= WO_ALL;
103248
- for(; pWC; pWC=pWC->pOuter){
103249
- for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103250
- if( pTerm->leftCursor==iCur
103251
- && (pTerm->prereqRight & notReady)==0
103252
- && pTerm->u.leftColumn==iColumn
103253
- && (pTerm->eOperator & op)!=0
103254
- ){
103255
- if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
103256
- Expr *pX = pTerm->pExpr;
103257
- CollSeq *pColl;
103258
- char idxaff;
103259
- int j;
103260
- Parse *pParse = pWC->pParse;
103261
-
103262
- idxaff = pIdx->pTable->aCol[iColumn].affinity;
103263
- if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
103264
-
103265
- /* Figure out the collation sequence required from an index for
103266
- ** it to be useful for optimising expression pX. Store this
103267
- ** value in variable pColl.
103268
- */
103269
- assert(pX->pLeft);
103270
- pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
103271
- if( pColl==0 ) pColl = pParse->db->pDfltColl;
103272
-
103273
- for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
103274
- if( NEVER(j>=pIdx->nColumn) ) return 0;
103275
- }
103276
- if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
103277
- }
103278
- return pTerm;
103279
- }
103280
- }
103281
- }
103282
- return 0;
103384
+ aEquiv[0] = iCur;
103385
+ aEquiv[1] = iColumn;
103386
+ for(;;){
103387
+ for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){
103388
+ for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103389
+ if( pTerm->leftCursor==iCur
103390
+ && pTerm->u.leftColumn==iColumn
103391
+ ){
103392
+ if( (pTerm->prereqRight & notReady)==0
103393
+ && (pTerm->eOperator & op & WO_ALL)!=0
103394
+ ){
103395
+ if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){
103396
+ CollSeq *pColl;
103397
+ char idxaff;
103398
+
103399
+ pX = pTerm->pExpr;
103400
+ pParse = pWC->pParse;
103401
+ idxaff = pIdx->pTable->aCol[iOrigCol].affinity;
103402
+ if( !sqlite3IndexAffinityOk(pX, idxaff) ){
103403
+ continue;
103404
+ }
103405
+
103406
+ /* Figure out the collation sequence required from an index for
103407
+ ** it to be useful for optimising expression pX. Store this
103408
+ ** value in variable pColl.
103409
+ */
103410
+ assert(pX->pLeft);
103411
+ pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight);
103412
+ if( pColl==0 ) pColl = pParse->db->pDfltColl;
103413
+
103414
+ for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){
103415
+ if( NEVER(j>=pIdx->nColumn) ) return 0;
103416
+ }
103417
+ if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
103418
+ continue;
103419
+ }
103420
+ }
103421
+ pResult = pTerm;
103422
+ if( pTerm->prereqRight==0 ) goto findTerm_success;
103423
+ }
103424
+ if( (pTerm->eOperator & WO_EQUIV)!=0
103425
+ && nEquiv<ArraySize(aEquiv)
103426
+ ){
103427
+ pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
103428
+ assert( pX->op==TK_COLUMN );
103429
+ for(j=0; j<nEquiv; j+=2){
103430
+ if( aEquiv[j]==pX->iTable && aEquiv[j+1]==pX->iColumn ) break;
103431
+ }
103432
+ if( j==nEquiv ){
103433
+ aEquiv[j] = pX->iTable;
103434
+ aEquiv[j+1] = pX->iColumn;
103435
+ nEquiv += 2;
103436
+ }
103437
+ }
103438
+ }
103439
+ }
103440
+ }
103441
+ if( iEquiv>=nEquiv ) break;
103442
+ iCur = aEquiv[iEquiv++];
103443
+ iColumn = aEquiv[iEquiv++];
103444
+ }
103445
+findTerm_success:
103446
+ return pResult;
103283103447
}
103284103448
103285103449
/* Forward reference */
103286103450
static void exprAnalyze(SrcList*, WhereClause*, int);
103287103451
@@ -103555,11 +103719,10 @@
103555103719
indexable = ~(Bitmask)0;
103556103720
chngToIN = ~(pWC->vmask);
103557103721
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103558103722
if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103559103723
WhereAndInfo *pAndInfo;
103560
- assert( pOrTerm->eOperator==0 );
103561103724
assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103562103725
chngToIN = 0;
103563103726
pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
103564103727
if( pAndInfo ){
103565103728
WhereClause *pAndWC;
@@ -103594,11 +103757,11 @@
103594103757
if( pOrTerm->wtFlags & TERM_VIRTUAL ){
103595103758
WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent];
103596103759
b |= getMask(pMaskSet, pOther->leftCursor);
103597103760
}
103598103761
indexable &= b;
103599
- if( pOrTerm->eOperator!=WO_EQ ){
103762
+ if( (pOrTerm->eOperator & WO_EQ)==0 ){
103600103763
chngToIN = 0;
103601103764
}else{
103602103765
chngToIN &= b;
103603103766
}
103604103767
}
@@ -103645,11 +103808,11 @@
103645103808
** and column is found but leave okToChngToIN false if not found.
103646103809
*/
103647103810
for(j=0; j<2 && !okToChngToIN; j++){
103648103811
pOrTerm = pOrWc->a;
103649103812
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
103650
- assert( pOrTerm->eOperator==WO_EQ );
103813
+ assert( pOrTerm->eOperator & WO_EQ );
103651103814
pOrTerm->wtFlags &= ~TERM_OR_OK;
103652103815
if( pOrTerm->leftCursor==iCursor ){
103653103816
/* This is the 2-bit case and we are on the second iteration and
103654103817
** current term is from the first iteration. So skip this term. */
103655103818
assert( j==1 );
@@ -103671,21 +103834,21 @@
103671103834
}
103672103835
if( i<0 ){
103673103836
/* No candidate table+column was found. This can only occur
103674103837
** on the second iteration */
103675103838
assert( j==1 );
103676
- assert( (chngToIN&(chngToIN-1))==0 );
103839
+ assert( IsPowerOfTwo(chngToIN) );
103677103840
assert( chngToIN==getMask(pMaskSet, iCursor) );
103678103841
break;
103679103842
}
103680103843
testcase( j==1 );
103681103844
103682103845
/* We have found a candidate table and column. Check to see if that
103683103846
** table and column is common to every term in the OR clause */
103684103847
okToChngToIN = 1;
103685103848
for(; i>=0 && okToChngToIN; i--, pOrTerm++){
103686
- assert( pOrTerm->eOperator==WO_EQ );
103849
+ assert( pOrTerm->eOperator & WO_EQ );
103687103850
if( pOrTerm->leftCursor!=iCursor ){
103688103851
pOrTerm->wtFlags &= ~TERM_OR_OK;
103689103852
}else if( pOrTerm->u.leftColumn!=iColumn ){
103690103853
okToChngToIN = 0;
103691103854
}else{
@@ -103717,11 +103880,11 @@
103717103880
Expr *pLeft = 0; /* The LHS of the IN operator */
103718103881
Expr *pNew; /* The complete IN operator */
103719103882
103720103883
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
103721103884
if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
103722
- assert( pOrTerm->eOperator==WO_EQ );
103885
+ assert( pOrTerm->eOperator & WO_EQ );
103723103886
assert( pOrTerm->leftCursor==iCursor );
103724103887
assert( pOrTerm->u.leftColumn==iColumn );
103725103888
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
103726103889
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup);
103727103890
pLeft = pOrTerm->pExpr->pLeft;
@@ -103746,11 +103909,10 @@
103746103909
pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
103747103910
}
103748103911
}
103749103912
}
103750103913
#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
103751
-
103752103914
103753103915
/*
103754103916
** The input to this routine is an WhereTerm structure with only the
103755103917
** "pExpr" field filled in. The job of this routine is to analyze the
103756103918
** subexpression and populate all the other fields of the WhereTerm
@@ -103816,21 +103978,23 @@
103816103978
}
103817103979
pTerm->prereqAll = prereqAll;
103818103980
pTerm->leftCursor = -1;
103819103981
pTerm->iParent = -1;
103820103982
pTerm->eOperator = 0;
103821
- if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
103983
+ if( allowedOp(op) ){
103822103984
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
103823103985
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
103986
+ u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
103824103987
if( pLeft->op==TK_COLUMN ){
103825103988
pTerm->leftCursor = pLeft->iTable;
103826103989
pTerm->u.leftColumn = pLeft->iColumn;
103827
- pTerm->eOperator = operatorMask(op);
103990
+ pTerm->eOperator = operatorMask(op) & opMask;
103828103991
}
103829103992
if( pRight && pRight->op==TK_COLUMN ){
103830103993
WhereTerm *pNew;
103831103994
Expr *pDup;
103995
+ u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
103832103996
if( pTerm->leftCursor>=0 ){
103833103997
int idxNew;
103834103998
pDup = sqlite3ExprDup(db, pExpr, 0);
103835103999
if( db->mallocFailed ){
103836104000
sqlite3ExprDelete(db, pDup);
@@ -103841,10 +104005,17 @@
103841104005
pNew = &pWC->a[idxNew];
103842104006
pNew->iParent = idxTerm;
103843104007
pTerm = &pWC->a[idxTerm];
103844104008
pTerm->nChild = 1;
103845104009
pTerm->wtFlags |= TERM_COPIED;
104010
+ if( pExpr->op==TK_EQ
104011
+ && !ExprHasProperty(pExpr, EP_FromJoin)
104012
+ && OptimizationEnabled(db, SQLITE_Transitive)
104013
+ ){
104014
+ pTerm->eOperator |= WO_EQUIV;
104015
+ eExtraOp = WO_EQUIV;
104016
+ }
103846104017
}else{
103847104018
pDup = pExpr;
103848104019
pNew = pTerm;
103849104020
}
103850104021
exprCommute(pParse, pDup);
@@ -103852,11 +104023,11 @@
103852104023
pNew->leftCursor = pLeft->iTable;
103853104024
pNew->u.leftColumn = pLeft->iColumn;
103854104025
testcase( (prereqLeft | extraRight) != prereqLeft );
103855104026
pNew->prereqRight = prereqLeft | extraRight;
103856104027
pNew->prereqAll = prereqAll;
103857
- pNew->eOperator = operatorMask(pDup->op);
104028
+ pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
103858104029
}
103859104030
}
103860104031
103861104032
#ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION
103862104033
/* If a term is the BETWEEN operator, create two new virtual terms
@@ -104311,11 +104482,11 @@
104311104482
return;
104312104483
}
104313104484
104314104485
/* Search the WHERE clause terms for a usable WO_OR term. */
104315104486
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
104316
- if( pTerm->eOperator==WO_OR
104487
+ if( (pTerm->eOperator & WO_OR)!=0
104317104488
&& ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
104318104489
&& (pTerm->u.pOrInfo->indexable & maskSrc)!=0
104319104490
){
104320104491
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
104321104492
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
@@ -104332,11 +104503,11 @@
104332104503
sBOI.ppIdxInfo = 0;
104333104504
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
104334104505
WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
104335104506
(pOrTerm - pOrWC->a), (pTerm - pWC->a)
104336104507
));
104337
- if( pOrTerm->eOperator==WO_AND ){
104508
+ if( (pOrTerm->eOperator& WO_AND)!=0 ){
104338104509
sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
104339104510
bestIndex(&sBOI);
104340104511
}else if( pOrTerm->leftCursor==iCur ){
104341104512
WhereClause tempWC;
104342104513
tempWC.pParse = pWC->pParse;
@@ -104393,11 +104564,11 @@
104393104564
struct SrcList_item *pSrc, /* Table we are trying to access */
104394104565
Bitmask notReady /* Tables in outer loops of the join */
104395104566
){
104396104567
char aff;
104397104568
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
104398
- if( pTerm->eOperator!=WO_EQ ) return 0;
104569
+ if( (pTerm->eOperator & WO_EQ)==0 ) return 0;
104399104570
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
104400104571
aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
104401104572
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
104402104573
return 1;
104403104574
}
@@ -104655,13 +104826,13 @@
104655104826
104656104827
/* Count the number of possible WHERE clause constraints referring
104657104828
** to this virtual table */
104658104829
for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104659104830
if( pTerm->leftCursor != pSrc->iCursor ) continue;
104660
- assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104661
- testcase( pTerm->eOperator==WO_IN );
104662
- testcase( pTerm->eOperator==WO_ISNULL );
104831
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104832
+ testcase( pTerm->eOperator & WO_IN );
104833
+ testcase( pTerm->eOperator & WO_ISNULL );
104663104834
if( pTerm->eOperator & (WO_ISNULL) ) continue;
104664104835
if( pTerm->wtFlags & TERM_VNULL ) continue;
104665104836
nTerm++;
104666104837
}
104667104838
@@ -104708,18 +104879,18 @@
104708104879
pUsage;
104709104880
104710104881
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104711104882
u8 op;
104712104883
if( pTerm->leftCursor != pSrc->iCursor ) continue;
104713
- assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104714
- testcase( pTerm->eOperator==WO_IN );
104715
- testcase( pTerm->eOperator==WO_ISNULL );
104884
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104885
+ testcase( pTerm->eOperator & WO_IN );
104886
+ testcase( pTerm->eOperator & WO_ISNULL );
104716104887
if( pTerm->eOperator & (WO_ISNULL) ) continue;
104717104888
if( pTerm->wtFlags & TERM_VNULL ) continue;
104718104889
pIdxCons[j].iColumn = pTerm->u.leftColumn;
104719104890
pIdxCons[j].iTermOffset = i;
104720
- op = (u8)pTerm->eOperator;
104891
+ op = (u8)pTerm->eOperator & WO_ALL;
104721104892
if( op==WO_IN ) op = WO_EQ;
104722104893
pIdxCons[j].op = op;
104723104894
/* The direct assignment in the previous line is possible only because
104724104895
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
104725104896
** following asserts verify this fact. */
@@ -104885,11 +105056,11 @@
104885105056
pUsage = pIdxInfo->aConstraintUsage;
104886105057
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104887105058
j = pIdxCons->iTermOffset;
104888105059
pTerm = &pWC->a[j];
104889105060
if( (pTerm->prereqRight&p->notReady)==0
104890
- && (bAllowIN || pTerm->eOperator!=WO_IN)
105061
+ && (bAllowIN || (pTerm->eOperator & WO_IN)==0)
104891105062
){
104892105063
pIdxCons->usable = 1;
104893105064
}else{
104894105065
pIdxCons->usable = 0;
104895105066
}
@@ -104917,11 +105088,11 @@
104917105088
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104918105089
if( pUsage[i].argvIndex>0 ){
104919105090
j = pIdxCons->iTermOffset;
104920105091
pTerm = &pWC->a[j];
104921105092
p->cost.used |= pTerm->prereqRight;
104922
- if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){
105093
+ if( (pTerm->eOperator & WO_IN)!=0 && pUsage[i].omit==0 ){
104923105094
/* Do not attempt to use an IN constraint if the virtual table
104924105095
** says that the equivalent EQ constraint cannot be safely omitted.
104925105096
** If we do attempt to use such a constraint, some rows might be
104926105097
** repeated in the output. */
104927105098
break;
@@ -105223,28 +105394,28 @@
105223105394
u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
105224105395
105225105396
if( pLower ){
105226105397
Expr *pExpr = pLower->pExpr->pRight;
105227105398
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105228
- assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE );
105399
+ assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
105229105400
if( rc==SQLITE_OK
105230105401
&& whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
105231105402
){
105232105403
iLower = a[0];
105233
- if( pLower->eOperator==WO_GT ) iLower += a[1];
105404
+ if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
105234105405
}
105235105406
sqlite3ValueFree(pRangeVal);
105236105407
}
105237105408
if( rc==SQLITE_OK && pUpper ){
105238105409
Expr *pExpr = pUpper->pExpr->pRight;
105239105410
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105240
- assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE );
105411
+ assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
105241105412
if( rc==SQLITE_OK
105242105413
&& whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
105243105414
){
105244105415
iUpper = a[0];
105245
- if( pUpper->eOperator==WO_LE ) iUpper += a[1];
105416
+ if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
105246105417
}
105247105418
sqlite3ValueFree(pRangeVal);
105248105419
}
105249105420
if( rc==SQLITE_OK ){
105250105421
if( iUpper<=iLower ){
@@ -105548,16 +105719,16 @@
105548105719
** if there are any X= or X IS NULL constraints in the WHERE clause. */
105549105720
pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105550105721
WO_EQ|WO_ISNULL|WO_IN, pIdx);
105551105722
if( pConstraint==0 ){
105552105723
isEq = 0;
105553
- }else if( pConstraint->eOperator==WO_IN ){
105724
+ }else if( (pConstraint->eOperator & WO_IN)!=0 ){
105554105725
/* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105555105726
** because we do not know in what order the values on the RHS of the IN
105556105727
** operator will occur. */
105557105728
break;
105558
- }else if( pConstraint->eOperator==WO_ISNULL ){
105729
+ }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
105559105730
uniqueNotNull = 0;
105560105731
isEq = 1; /* "X IS NULL" means X has only a single value */
105561105732
}else if( pConstraint->prereqRight==0 ){
105562105733
isEq = 1; /* Constraint "X=constant" means X has only a single value */
105563105734
}else{
@@ -105903,11 +106074,11 @@
105903106074
int bRev = 2;
105904106075
WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
105905106076
pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
105906106077
WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
105907106078
bRev, pc.plan.nOBSat));
105908
- if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
106079
+ if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
105909106080
pc.plan.wsFlags |= WHERE_ORDERED;
105910106081
}
105911106082
if( nOrderBy==pc.plan.nOBSat ){
105912106083
bSort = 0;
105913106084
pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
@@ -105966,16 +106137,17 @@
105966106137
*/
105967106138
if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
105968106139
&& pFirstTerm!=0 && aiRowEst[1]>1 ){
105969106140
assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
105970106141
if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
105971
- testcase( pFirstTerm->eOperator==WO_EQ );
105972
- testcase( pFirstTerm->eOperator==WO_ISNULL );
106142
+ testcase( pFirstTerm->eOperator & WO_EQ );
106143
+ testcase( pFirstTerm->eOperator & WO_EQUIV );
106144
+ testcase( pFirstTerm->eOperator & WO_ISNULL );
105973106145
whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
105974106146
&pc.plan.nRow);
105975106147
}else if( bInEst==0 ){
105976
- assert( pFirstTerm->eOperator==WO_IN );
106148
+ assert( pFirstTerm->eOperator & WO_IN );
105977106149
whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
105978106150
&pc.plan.nRow);
105979106151
}
105980106152
}
105981106153
#endif /* SQLITE_ENABLE_STAT3 */
@@ -106118,11 +106290,11 @@
106118106290
** more selective intentionally because of the subjective
106119106291
** observation that indexed range constraints really are more
106120106292
** selective in practice, on average. */
106121106293
pc.plan.nRow /= 3;
106122106294
}
106123
- }else if( pTerm->eOperator!=WO_NOOP ){
106295
+ }else if( (pTerm->eOperator & WO_NOOP)==0 ){
106124106296
/* Any other expression lowers the output row count by half */
106125106297
pc.plan.nRow /= 2;
106126106298
}
106127106299
}
106128106300
if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
@@ -106170,12 +106342,13 @@
106170106342
assert( pSrc->pIndex==0
106171106343
|| p->cost.plan.u.pIdx==0
106172106344
|| p->cost.plan.u.pIdx==pSrc->pIndex
106173106345
);
106174106346
106175
- WHERETRACE((" best index is: %s\n",
106176
- p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
106347
+ WHERETRACE((" best index is %s cost=%.1f\n",
106348
+ p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk",
106349
+ p->cost.rCost));
106177106350
106178106351
bestOrClauseIndex(p);
106179106352
bestAutomaticIndex(p);
106180106353
p->cost.plan.wsFlags |= eqTermMask;
106181106354
}
@@ -106753,11 +106926,10 @@
106753106926
*/
106754106927
iReleaseReg = sqlite3GetTempReg(pParse);
106755106928
pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106756106929
assert( pTerm!=0 );
106757106930
assert( pTerm->pExpr!=0 );
106758
- assert( pTerm->leftCursor==iCur );
106759106931
assert( omitTable==0 );
106760106932
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106761106933
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
106762106934
addrNxt = pLevel->addrNxt;
106763106935
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
@@ -107144,11 +107316,11 @@
107144107316
int ii; /* Loop counter */
107145107317
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
107146107318
107147107319
pTerm = pLevel->plan.u.pTerm;
107148107320
assert( pTerm!=0 );
107149
- assert( pTerm->eOperator==WO_OR );
107321
+ assert( pTerm->eOperator & WO_OR );
107150107322
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
107151107323
pOrWc = &pTerm->u.pOrInfo->wc;
107152107324
pLevel->op = OP_Return;
107153107325
pLevel->p1 = regReturn;
107154107326
@@ -107217,11 +107389,11 @@
107217107389
}
107218107390
}
107219107391
107220107392
for(ii=0; ii<pOrWc->nTerm; ii++){
107221107393
WhereTerm *pOrTerm = &pOrWc->a[ii];
107222
- if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
107394
+ if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
107223107395
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
107224107396
Expr *pOrExpr = pOrTerm->pExpr;
107225107397
if( pAndExpr ){
107226107398
pAndExpr->pLeft = pOrExpr;
107227107399
pOrExpr = pAndExpr;
@@ -107672,10 +107844,11 @@
107672107844
Index *pIdx; /* Index for FROM table at pTabItem */
107673107845
int j; /* For looping over FROM tables */
107674107846
int bestJ = -1; /* The value of j */
107675107847
Bitmask m; /* Bitmask value for j or bestJ */
107676107848
int isOptimal; /* Iterator for optimal/non-optimal search */
107849
+ int ckOptimal; /* Do the optimal scan check */
107677107850
int nUnconstrained; /* Number tables without INDEXED BY */
107678107851
Bitmask notIndexed; /* Mask of tables that cannot use an index */
107679107852
107680107853
memset(&bestPlan, 0, sizeof(bestPlan));
107681107854
bestPlan.rCost = SQLITE_BIG_DBL;
@@ -107706,14 +107879,12 @@
107706107879
**
107707107880
** The second loop iteration is only performed if no optimal scan
107708107881
** strategies were found by the first iteration. This second iteration
107709107882
** is used to search for the lowest cost scan overall.
107710107883
**
107711
- ** Previous versions of SQLite performed only the second iteration -
107712
- ** the next outermost loop was always that with the lowest overall
107713
- ** cost. However, this meant that SQLite could select the wrong plan
107714
- ** for scripts such as the following:
107884
+ ** Without the optimal scan step (the first iteration) a suboptimal
107885
+ ** plan might be chosen for queries like this:
107715107886
**
107716107887
** CREATE TABLE t1(a, b);
107717107888
** CREATE TABLE t2(c, d);
107718107889
** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a;
107719107890
**
@@ -107724,20 +107895,44 @@
107724107895
** algorithm may choose to use t2 for the outer loop, which is a much
107725107896
** costlier approach.
107726107897
*/
107727107898
nUnconstrained = 0;
107728107899
notIndexed = 0;
107729
- for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
107900
+
107901
+ /* The optimal scan check only occurs if there are two or more tables
107902
+ ** available to be reordered */
107903
+ if( iFrom==nTabList-1 ){
107904
+ ckOptimal = 0; /* Common case of just one table in the FROM clause */
107905
+ }else{
107906
+ ckOptimal = -1;
107730107907
for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107731
- int doNotReorder; /* True if this table should not be reordered */
107732
-
107733
- doNotReorder = (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0;
107734
- if( j!=iFrom && doNotReorder ) break;
107735107908
m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107736107909
if( (m & sWBI.notValid)==0 ){
107737107910
if( j==iFrom ) iFrom++;
107738107911
continue;
107912
+ }
107913
+ if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break;
107914
+ if( ++ckOptimal ) break;
107915
+ if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
107916
+ }
107917
+ }
107918
+ assert( ckOptimal==0 || ckOptimal==1 );
107919
+
107920
+ for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){
107921
+ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107922
+ if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){
107923
+ /* This break and one like it in the ckOptimal computation loop
107924
+ ** above prevent table reordering across LEFT and CROSS JOINs.
107925
+ ** The LEFT JOIN case is necessary for correctness. The prohibition
107926
+ ** against reordering across a CROSS JOIN is an SQLite feature that
107927
+ ** allows the developer to control table reordering */
107928
+ break;
107929
+ }
107930
+ m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107931
+ if( (m & sWBI.notValid)==0 ){
107932
+ assert( j>iFrom );
107933
+ continue;
107739107934
}
107740107935
sWBI.notReady = (isOptimal ? m : sWBI.notValid);
107741107936
if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
107742107937
107743107938
WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
@@ -107763,12 +107958,12 @@
107763107958
if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
107764107959
notIndexed |= m;
107765107960
}
107766107961
if( isOptimal ){
107767107962
pWInfo->a[j].rOptCost = sWBI.cost.rCost;
107768
- }else if( iFrom<nTabList-1 ){
107769
- /* If two or more tables have nearly the same outer loop cost,
107963
+ }else if( ckOptimal ){
107964
+ /* If two or more tables have nearly the same outer loop cost, but
107770107965
** very different inner loop (optimal) cost, we want to choose
107771107966
** for the outer loop that table which benefits the least from
107772107967
** being in the inner loop. The following code scales the
107773107968
** outer loop cost estimate to accomplish that. */
107774107969
WHERETRACE((" scaling cost from %.1f to %.1f\n",
@@ -107809,15 +108004,23 @@
107809108004
sWBI.cost.rCost, sWBI.cost.plan.nRow,
107810108005
sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
107811108006
bestPlan = sWBI.cost;
107812108007
bestJ = j;
107813108008
}
107814
- if( doNotReorder ) break;
108009
+
108010
+ /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that
108011
+ ** table y (and not table z) is always the next inner loop inside
108012
+ ** of table x. */
108013
+ if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
107815108014
}
107816108015
}
107817108016
assert( bestJ>=0 );
107818108017
assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
108018
+ assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 );
108019
+ testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 );
108020
+ testcase( bestJ>iFrom && bestJ<nTabList-1
108021
+ && (pTabList->a[bestJ+1].jointype & JT_LEFT)!=0 );
107819108022
WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
107820108023
" cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
107821108024
bestJ, pTabList->a[bestJ].pTab->zName,
107822108025
pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
107823108026
bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
@@ -136543,11 +136746,12 @@
136543136746
** would fit in a single node, use a smaller node-size.
136544136747
*/
136545136748
static int getNodeSize(
136546136749
sqlite3 *db, /* Database handle */
136547136750
Rtree *pRtree, /* Rtree handle */
136548
- int isCreate /* True for xCreate, false for xConnect */
136751
+ int isCreate, /* True for xCreate, false for xConnect */
136752
+ char **pzErr /* OUT: Error message, if any */
136549136753
){
136550136754
int rc;
136551136755
char *zSql;
136552136756
if( isCreate ){
136553136757
int iPageSize = 0;
@@ -136556,17 +136760,22 @@
136556136760
if( rc==SQLITE_OK ){
136557136761
pRtree->iNodeSize = iPageSize-64;
136558136762
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
136559136763
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
136560136764
}
136765
+ }else{
136766
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136561136767
}
136562136768
}else{
136563136769
zSql = sqlite3_mprintf(
136564136770
"SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
136565136771
pRtree->zDb, pRtree->zName
136566136772
);
136567136773
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
136774
+ if( rc!=SQLITE_OK ){
136775
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136776
+ }
136568136777
}
136569136778
136570136779
sqlite3_free(zSql);
136571136780
return rc;
136572136781
}
@@ -136626,11 +136835,11 @@
136626136835
pRtree->eCoordType = eCoordType;
136627136836
memcpy(pRtree->zDb, argv[1], nDb);
136628136837
memcpy(pRtree->zName, argv[2], nName);
136629136838
136630136839
/* Figure out the node size to use. */
136631
- rc = getNodeSize(db, pRtree, isCreate);
136840
+ rc = getNodeSize(db, pRtree, isCreate, pzErr);
136632136841
136633136842
/* Create/Connect to the underlying relational database schema. If
136634136843
** that is successful, call sqlite3_declare_vtab() to configure
136635136844
** the r-tree table schema.
136636136845
*/
136637136846
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674 ** [sqlite_version()] and [sqlite_source_id()].
675 */
676 #define SQLITE_VERSION "3.7.16"
677 #define SQLITE_VERSION_NUMBER 3007016
678 #define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
679
680 /*
681 ** CAPI3REF: Run-Time Library Version Numbers
682 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
683 **
@@ -8238,10 +8238,15 @@
8238 ** A convenience macro that returns the number of elements in
8239 ** an array.
8240 */
8241 #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
8242
 
 
 
 
 
8243 /*
8244 ** The following value as a destructor means to use sqlite3DbFree().
8245 ** The sqlite3DbFree() routine requires two parameters instead of the
8246 ** one parameter that destructors normally want. So we have to introduce
8247 ** this magic value that the code knows to handle differently. Any
@@ -10042,10 +10047,11 @@
10042 #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
10043 #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
10044 #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
10045 #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
10046 #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
 
10047 #define SQLITE_AllOpts 0xffff /* All optimizations */
10048
10049 /*
10050 ** Macros for testing whether or not optimizations are enabled or disabled.
10051 */
@@ -10553,24 +10559,24 @@
10553 ** and the value of Index.onError indicate the which conflict resolution
10554 ** algorithm to employ whenever an attempt is made to insert a non-unique
10555 ** element.
10556 */
10557 struct Index {
10558 char *zName; /* Name of this index */
10559 int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10560 tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
10561 Table *pTable; /* The SQL table being indexed */
10562 char *zColAff; /* String defining the affinity of each column */
10563 Index *pNext; /* The next index associated with the same table */
10564 Schema *pSchema; /* Schema containing this index */
10565 u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
10566 char **azColl; /* Array of collation sequence names for index */
10567 int nColumn; /* Number of columns in the table used by this index */
10568 int tnum; /* Page containing root of this index in database file */
10569 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10570 u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
10571 u8 bUnordered; /* Use this index for == or IN queries only */
10572 #ifdef SQLITE_ENABLE_STAT3
10573 int nSample; /* Number of elements in aSample[] */
10574 tRowcnt avgEq; /* Average nEq value for key values not in aSample */
10575 IndexSample *aSample; /* Samples of the left-most key */
10576 #endif
@@ -10840,22 +10846,31 @@
10840 ** name. An expr/name combination can be used in several ways, such
10841 ** as the list of "expr AS ID" fields following a "SELECT" or in the
10842 ** list of "ID = expr" items in an UPDATE. A list of expressions can
10843 ** also be used as the argument to a function, in which case the a.zName
10844 ** field is not used.
 
 
 
 
 
 
 
 
10845 */
10846 struct ExprList {
10847 int nExpr; /* Number of expressions on the list */
10848 int iECursor; /* VDBE Cursor associated with this ExprList */
10849 struct ExprList_item { /* For each expression in the list */
10850 Expr *pExpr; /* The list of expressions */
10851 char *zName; /* Token associated with this expression */
10852 char *zSpan; /* Original text of the expression */
10853 u8 sortOrder; /* 1 for DESC or 0 for ASC */
10854 u8 done; /* A flag to indicate when processing is finished */
10855 u16 iOrderByCol; /* For ORDER BY, column number in result set */
10856 u16 iAlias; /* Index into Parse.aAlias[] for zName */
 
10857 } *a; /* Alloc a power of two greater or equal to nExpr */
10858 };
10859
10860 /*
10861 ** An instance of this structure is used by the parser to record both
@@ -12141,10 +12156,11 @@
12141 SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
12142 SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
12143 SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
12144 SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
12145 SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
 
12146 SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
12147 SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
12148 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12149 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12150 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
@@ -23289,15 +23305,11 @@
23289 { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
23290 #endif
23291 #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
23292 aSyscall[13].pCurrent)
23293
23294 #if SQLITE_ENABLE_LOCKING_STYLE
23295 { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
23296 #else
23297 { "fchmod", (sqlite3_syscall_ptr)0, 0 },
23298 #endif
23299 #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
23300
23301 #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
23302 { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
23303 #else
@@ -23318,13 +23330,10 @@
23318 #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
23319
23320 { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
23321 #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
23322
23323 { "umask", (sqlite3_syscall_ptr)umask, 0 },
23324 #define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
23325
23326 }; /* End of the overrideable system calls */
23327
23328 /*
23329 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
23330 ** "unix" VFSes. Return SQLITE_OK opon successfully updating the
@@ -23425,31 +23434,29 @@
23425 ** process that is able to write to the database will also be able to
23426 ** recover the hot journals.
23427 */
23428 static int robust_open(const char *z, int f, mode_t m){
23429 int fd;
23430 mode_t m2;
23431 mode_t origM = 0;
23432 if( m==0 ){
23433 m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
23434 }else{
23435 m2 = m;
23436 origM = osUmask(0);
23437 }
23438 do{
23439 #if defined(O_CLOEXEC)
23440 fd = osOpen(z,f|O_CLOEXEC,m2);
23441 #else
23442 fd = osOpen(z,f,m2);
23443 #endif
23444 }while( fd<0 && errno==EINTR );
23445 if( m ){
23446 osUmask(origM);
23447 }
 
 
 
 
23448 #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23449 if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
23450 #endif
 
23451 return fd;
23452 }
23453
23454 /*
23455 ** Helper functions to obtain and relinquish the global mutex. The
@@ -29871,11 +29878,11 @@
29871 };
29872 unsigned int i; /* Loop counter */
29873
29874 /* Double-check that the aSyscall[] array has been constructed
29875 ** correctly. See ticket [bb3a86e890c8e96ab] */
29876 assert( ArraySize(aSyscall)==22 );
29877
29878 /* Register all VFSes defined in the aVfs[] array */
29879 for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
29880 sqlite3_vfs_register(&aVfs[i], i==0);
29881 }
@@ -72655,10 +72662,39 @@
72655 }
72656 }
72657 return 0;
72658 }
72659
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72660
72661 /*
72662 ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
72663 ** that name in the set of source tables in pSrcList and make the pExpr
72664 ** expression node refer back to that source column. The following changes
@@ -72710,44 +72746,63 @@
72710
72711 /* Initialize the node to no-match */
72712 pExpr->iTable = -1;
72713 pExpr->pTab = 0;
72714 ExprSetIrreducible(pExpr);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72715
72716 /* Start at the inner-most context and move outward until a match is found */
72717 while( pNC && cnt==0 ){
72718 ExprList *pEList;
72719 SrcList *pSrcList = pNC->pSrcList;
72720
72721 if( pSrcList ){
72722 for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
72723 Table *pTab;
72724 int iDb;
72725 Column *pCol;
72726
72727 pTab = pItem->pTab;
72728 assert( pTab!=0 && pTab->zName!=0 );
72729 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
72730 assert( pTab->nCol>0 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72731 if( zTab ){
72732 if( pItem->zAlias ){
72733 char *zTabName = pItem->zAlias;
72734 if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
72735 }else{
72736 char *zTabName = pTab->zName;
72737 if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
72738 continue;
72739 }
72740 if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
72741 continue;
72742 }
72743 }
72744 }
72745 if( 0==(cntTab++) ){
72746 pExpr->iTable = pItem->iCursor;
72747 pExpr->pTab = pTab;
72748 pSchema = pTab->pSchema;
72749 pMatch = pItem;
72750 }
72751 for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
72752 if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
72753 /* If there has been exactly one prior match and this match
@@ -72757,21 +72812,23 @@
72757 if( cnt==1 ){
72758 if( pItem->jointype & JT_NATURAL ) continue;
72759 if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
72760 }
72761 cnt++;
72762 pExpr->iTable = pItem->iCursor;
72763 pExpr->pTab = pTab;
72764 pMatch = pItem;
72765 pSchema = pTab->pSchema;
72766 /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
72767 pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
72768 break;
72769 }
72770 }
72771 }
72772 }
 
 
 
 
 
72773
72774 #ifndef SQLITE_OMIT_TRIGGER
72775 /* If we have not already resolved the name, then maybe
72776 ** it is a new.* or old.* trigger argument reference
72777 */
@@ -73102,11 +73159,11 @@
73102 #endif
73103 if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
73104 sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
73105 pNC->nErr++;
73106 is_agg = 0;
73107 }else if( no_such_func ){
73108 sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
73109 pNC->nErr++;
73110 }else if( wrong_num_args ){
73111 sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
73112 nId, zId);
@@ -77065,10 +77122,16 @@
77065 for(i=0; i<pList->nExpr; i++){
77066 sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
77067 sqlite3ExplainPush(pOut);
77068 sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
77069 sqlite3ExplainPop(pOut);
 
 
 
 
 
 
77070 if( i<pList->nExpr-1 ){
77071 sqlite3ExplainNL(pOut);
77072 }
77073 }
77074 sqlite3ExplainPop(pOut);
@@ -92739,13 +92802,15 @@
92739 if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
92740 Table *pTab;
92741 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
92742 pTab = sqlite3FindTable(db, zRight, zDb);
92743 if( pTab ){
92744 int i;
92745 int nHidden = 0;
92746 Column *pCol;
 
 
92747 sqlite3VdbeSetNumCols(v, 6);
92748 pParse->nMem = 6;
92749 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
92750 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
92751 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
@@ -92766,12 +92831,18 @@
92766 if( pCol->zDflt ){
92767 sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
92768 }else{
92769 sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
92770 }
92771 sqlite3VdbeAddOp2(v, OP_Integer,
92772 (pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6);
 
 
 
 
 
 
92773 sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
92774 }
92775 }
92776 }else
92777
@@ -93516,11 +93587,11 @@
93516 sqlite3_rekey(db, zKey, i/2);
93517 }
93518 }else
93519 #endif
93520 #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
93521 if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
93522 #ifdef SQLITE_HAS_CODEC
93523 if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
93524 sqlite3_activate_see(&zRight[4]);
93525 }
93526 #endif
@@ -95756,12 +95827,10 @@
95756
95757 for(i=0, pCol=aCol; i<nCol; i++, pCol++){
95758 /* Get an appropriate name for the column
95759 */
95760 p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
95761 assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
95762 || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
95763 if( (zName = pEList->a[i].zName)!=0 ){
95764 /* If the column contains an "AS <name>" phrase, use <name> as the name */
95765 zName = sqlite3DbStrDup(db, zName);
95766 }else{
95767 Expr *pColExpr = p; /* The expression that is the result column name */
@@ -95795,10 +95864,13 @@
95795 */
95796 nName = sqlite3Strlen30(zName);
95797 for(j=cnt=0; j<i; j++){
95798 if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
95799 char *zNewName;
 
 
 
95800 zName[nName] = 0;
95801 zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
95802 sqlite3DbFree(db, zName);
95803 zName = zNewName;
95804 j = -1;
@@ -97711,10 +97783,11 @@
97711 int i, j, k;
97712 SrcList *pTabList;
97713 ExprList *pEList;
97714 struct SrcList_item *pFrom;
97715 sqlite3 *db = pParse->db;
 
97716
97717 if( db->mallocFailed ){
97718 return WRC_Abort;
97719 }
97720 if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
@@ -97796,11 +97869,11 @@
97796 **
97797 ** The first loop just checks to see if there are any "*" operators
97798 ** that need expanding.
97799 */
97800 for(k=0; k<pEList->nExpr; k++){
97801 Expr *pE = pEList->a[k].pExpr;
97802 if( pE->op==TK_ALL ) break;
97803 assert( pE->op!=TK_DOT || pE->pRight!=0 );
97804 assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
97805 if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
97806 }
@@ -97814,14 +97887,22 @@
97814 ExprList *pNew = 0;
97815 int flags = pParse->db->flags;
97816 int longNames = (flags & SQLITE_FullColNames)!=0
97817 && (flags & SQLITE_ShortColNames)==0;
97818
 
 
 
 
 
 
 
97819 for(k=0; k<pEList->nExpr; k++){
97820 Expr *pE = a[k].pExpr;
97821 assert( pE->op!=TK_DOT || pE->pRight!=0 );
97822 if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
 
97823 /* This particular expression does not need to be expanded.
97824 */
97825 pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
97826 if( pNew ){
97827 pNew->a[pNew->nExpr-1].zName = a[k].zName;
@@ -97832,44 +97913,56 @@
97832 a[k].pExpr = 0;
97833 }else{
97834 /* This expression is a "*" or a "TABLE.*" and needs to be
97835 ** expanded. */
97836 int tableSeen = 0; /* Set to 1 when TABLE matches */
97837 char *zTName; /* text of name of TABLE */
97838 if( pE->op==TK_DOT ){
97839 assert( pE->pLeft!=0 );
97840 assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
97841 zTName = pE->pLeft->u.zToken;
97842 }else{
97843 zTName = 0;
97844 }
97845 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
97846 Table *pTab = pFrom->pTab;
 
97847 char *zTabName = pFrom->zAlias;
 
 
97848 if( zTabName==0 ){
97849 zTabName = pTab->zName;
97850 }
97851 if( db->mallocFailed ) break;
97852 if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97853 continue;
 
 
 
 
 
97854 }
97855 tableSeen = 1;
97856 for(j=0; j<pTab->nCol; j++){
97857 Expr *pExpr, *pRight;
97858 char *zName = pTab->aCol[j].zName;
97859 char *zColname; /* The computed column name */
97860 char *zToFree; /* Malloced string that needs to be freed */
97861 Token sColname; /* Computed column name as a token */
 
 
 
 
 
 
 
97862
97863 /* If a column is marked as 'hidden' (currently only possible
97864 ** for virtual tables), do not include it in the expanded
97865 ** result-set list.
97866 */
97867 if( IsHiddenColumn(&pTab->aCol[j]) ){
97868 assert(IsVirtual(pTab));
97869 continue;
97870 }
 
97871
97872 if( i>0 && zTName==0 ){
97873 if( (pFrom->jointype & JT_NATURAL)!=0
97874 && tableAndColumnIndex(pTabList, i, zName, 0, 0)
97875 ){
@@ -97888,10 +97981,14 @@
97888 zToFree = 0;
97889 if( longNames || pTabList->nSrc>1 ){
97890 Expr *pLeft;
97891 pLeft = sqlite3Expr(db, TK_ID, zTabName);
97892 pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
 
 
 
 
97893 if( longNames ){
97894 zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
97895 zToFree = zColname;
97896 }
97897 }else{
@@ -97899,10 +97996,22 @@
97899 }
97900 pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
97901 sColname.z = zColname;
97902 sColname.n = sqlite3Strlen30(zColname);
97903 sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
 
 
 
 
 
 
 
 
 
 
 
 
97904 sqlite3DbFree(db, zToFree);
97905 }
97906 }
97907 if( !tableSeen ){
97908 if( zTName ){
@@ -102699,12 +102808,12 @@
102699 Expr *pExpr; /* Pointer to the subexpression that is this term */
102700 int iParent; /* Disable pWC->a[iParent] when this term disabled */
102701 int leftCursor; /* Cursor number of X in "X <op> <expr>" */
102702 union {
102703 int leftColumn; /* Column number of X in "X <op> <expr>" */
102704 WhereOrInfo *pOrInfo; /* Extra information if eOperator==WO_OR */
102705 WhereAndInfo *pAndInfo; /* Extra information if eOperator==WO_AND */
102706 } u;
102707 u16 eOperator; /* A WO_xx value describing <op> */
102708 u8 wtFlags; /* TERM_xxx bit flags. See below */
102709 u8 nChild; /* Number of children that must disable us */
102710 WhereClause *pWC; /* The clause this term is part of */
@@ -102828,10 +102937,11 @@
102828 #define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
102829 #define WO_MATCH 0x040
102830 #define WO_ISNULL 0x080
102831 #define WO_OR 0x100 /* Two or more OR-connected terms */
102832 #define WO_AND 0x200 /* Two or more AND-connected terms */
 
102833 #define WO_NOOP 0x800 /* This term does not restrict search space */
102834
102835 #define WO_ALL 0xfff /* Mask of all possible WO_* values */
102836 #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
102837
@@ -103230,58 +103340,112 @@
103230 /*
103231 ** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
103232 ** where X is a reference to the iColumn of table iCur and <op> is one of
103233 ** the WO_xx operator codes specified by the op parameter.
103234 ** Return a pointer to the term. Return 0 if not found.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103235 */
103236 static WhereTerm *findTerm(
103237 WhereClause *pWC, /* The WHERE clause to be searched */
103238 int iCur, /* Cursor number of LHS */
103239 int iColumn, /* Column number of LHS */
103240 Bitmask notReady, /* RHS must not overlap with this mask */
103241 u32 op, /* Mask of WO_xx values describing operator */
103242 Index *pIdx /* Must be compatible with this index, if not NULL */
103243 ){
103244 WhereTerm *pTerm;
103245 int k;
 
 
 
 
 
 
 
 
 
103246 assert( iCur>=0 );
103247 op &= WO_ALL;
103248 for(; pWC; pWC=pWC->pOuter){
103249 for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103250 if( pTerm->leftCursor==iCur
103251 && (pTerm->prereqRight & notReady)==0
103252 && pTerm->u.leftColumn==iColumn
103253 && (pTerm->eOperator & op)!=0
103254 ){
103255 if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
103256 Expr *pX = pTerm->pExpr;
103257 CollSeq *pColl;
103258 char idxaff;
103259 int j;
103260 Parse *pParse = pWC->pParse;
103261
103262 idxaff = pIdx->pTable->aCol[iColumn].affinity;
103263 if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
103264
103265 /* Figure out the collation sequence required from an index for
103266 ** it to be useful for optimising expression pX. Store this
103267 ** value in variable pColl.
103268 */
103269 assert(pX->pLeft);
103270 pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
103271 if( pColl==0 ) pColl = pParse->db->pDfltColl;
103272
103273 for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
103274 if( NEVER(j>=pIdx->nColumn) ) return 0;
103275 }
103276 if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
103277 }
103278 return pTerm;
103279 }
103280 }
103281 }
103282 return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103283 }
103284
103285 /* Forward reference */
103286 static void exprAnalyze(SrcList*, WhereClause*, int);
103287
@@ -103555,11 +103719,10 @@
103555 indexable = ~(Bitmask)0;
103556 chngToIN = ~(pWC->vmask);
103557 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103558 if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103559 WhereAndInfo *pAndInfo;
103560 assert( pOrTerm->eOperator==0 );
103561 assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103562 chngToIN = 0;
103563 pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
103564 if( pAndInfo ){
103565 WhereClause *pAndWC;
@@ -103594,11 +103757,11 @@
103594 if( pOrTerm->wtFlags & TERM_VIRTUAL ){
103595 WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent];
103596 b |= getMask(pMaskSet, pOther->leftCursor);
103597 }
103598 indexable &= b;
103599 if( pOrTerm->eOperator!=WO_EQ ){
103600 chngToIN = 0;
103601 }else{
103602 chngToIN &= b;
103603 }
103604 }
@@ -103645,11 +103808,11 @@
103645 ** and column is found but leave okToChngToIN false if not found.
103646 */
103647 for(j=0; j<2 && !okToChngToIN; j++){
103648 pOrTerm = pOrWc->a;
103649 for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
103650 assert( pOrTerm->eOperator==WO_EQ );
103651 pOrTerm->wtFlags &= ~TERM_OR_OK;
103652 if( pOrTerm->leftCursor==iCursor ){
103653 /* This is the 2-bit case and we are on the second iteration and
103654 ** current term is from the first iteration. So skip this term. */
103655 assert( j==1 );
@@ -103671,21 +103834,21 @@
103671 }
103672 if( i<0 ){
103673 /* No candidate table+column was found. This can only occur
103674 ** on the second iteration */
103675 assert( j==1 );
103676 assert( (chngToIN&(chngToIN-1))==0 );
103677 assert( chngToIN==getMask(pMaskSet, iCursor) );
103678 break;
103679 }
103680 testcase( j==1 );
103681
103682 /* We have found a candidate table and column. Check to see if that
103683 ** table and column is common to every term in the OR clause */
103684 okToChngToIN = 1;
103685 for(; i>=0 && okToChngToIN; i--, pOrTerm++){
103686 assert( pOrTerm->eOperator==WO_EQ );
103687 if( pOrTerm->leftCursor!=iCursor ){
103688 pOrTerm->wtFlags &= ~TERM_OR_OK;
103689 }else if( pOrTerm->u.leftColumn!=iColumn ){
103690 okToChngToIN = 0;
103691 }else{
@@ -103717,11 +103880,11 @@
103717 Expr *pLeft = 0; /* The LHS of the IN operator */
103718 Expr *pNew; /* The complete IN operator */
103719
103720 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
103721 if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
103722 assert( pOrTerm->eOperator==WO_EQ );
103723 assert( pOrTerm->leftCursor==iCursor );
103724 assert( pOrTerm->u.leftColumn==iColumn );
103725 pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
103726 pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup);
103727 pLeft = pOrTerm->pExpr->pLeft;
@@ -103746,11 +103909,10 @@
103746 pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
103747 }
103748 }
103749 }
103750 #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
103751
103752
103753 /*
103754 ** The input to this routine is an WhereTerm structure with only the
103755 ** "pExpr" field filled in. The job of this routine is to analyze the
103756 ** subexpression and populate all the other fields of the WhereTerm
@@ -103816,21 +103978,23 @@
103816 }
103817 pTerm->prereqAll = prereqAll;
103818 pTerm->leftCursor = -1;
103819 pTerm->iParent = -1;
103820 pTerm->eOperator = 0;
103821 if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
103822 Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
103823 Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
 
103824 if( pLeft->op==TK_COLUMN ){
103825 pTerm->leftCursor = pLeft->iTable;
103826 pTerm->u.leftColumn = pLeft->iColumn;
103827 pTerm->eOperator = operatorMask(op);
103828 }
103829 if( pRight && pRight->op==TK_COLUMN ){
103830 WhereTerm *pNew;
103831 Expr *pDup;
 
103832 if( pTerm->leftCursor>=0 ){
103833 int idxNew;
103834 pDup = sqlite3ExprDup(db, pExpr, 0);
103835 if( db->mallocFailed ){
103836 sqlite3ExprDelete(db, pDup);
@@ -103841,10 +104005,17 @@
103841 pNew = &pWC->a[idxNew];
103842 pNew->iParent = idxTerm;
103843 pTerm = &pWC->a[idxTerm];
103844 pTerm->nChild = 1;
103845 pTerm->wtFlags |= TERM_COPIED;
 
 
 
 
 
 
 
103846 }else{
103847 pDup = pExpr;
103848 pNew = pTerm;
103849 }
103850 exprCommute(pParse, pDup);
@@ -103852,11 +104023,11 @@
103852 pNew->leftCursor = pLeft->iTable;
103853 pNew->u.leftColumn = pLeft->iColumn;
103854 testcase( (prereqLeft | extraRight) != prereqLeft );
103855 pNew->prereqRight = prereqLeft | extraRight;
103856 pNew->prereqAll = prereqAll;
103857 pNew->eOperator = operatorMask(pDup->op);
103858 }
103859 }
103860
103861 #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION
103862 /* If a term is the BETWEEN operator, create two new virtual terms
@@ -104311,11 +104482,11 @@
104311 return;
104312 }
104313
104314 /* Search the WHERE clause terms for a usable WO_OR term. */
104315 for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
104316 if( pTerm->eOperator==WO_OR
104317 && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
104318 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0
104319 ){
104320 WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
104321 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
@@ -104332,11 +104503,11 @@
104332 sBOI.ppIdxInfo = 0;
104333 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
104334 WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
104335 (pOrTerm - pOrWC->a), (pTerm - pWC->a)
104336 ));
104337 if( pOrTerm->eOperator==WO_AND ){
104338 sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
104339 bestIndex(&sBOI);
104340 }else if( pOrTerm->leftCursor==iCur ){
104341 WhereClause tempWC;
104342 tempWC.pParse = pWC->pParse;
@@ -104393,11 +104564,11 @@
104393 struct SrcList_item *pSrc, /* Table we are trying to access */
104394 Bitmask notReady /* Tables in outer loops of the join */
104395 ){
104396 char aff;
104397 if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
104398 if( pTerm->eOperator!=WO_EQ ) return 0;
104399 if( (pTerm->prereqRight & notReady)!=0 ) return 0;
104400 aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
104401 if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
104402 return 1;
104403 }
@@ -104655,13 +104826,13 @@
104655
104656 /* Count the number of possible WHERE clause constraints referring
104657 ** to this virtual table */
104658 for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104659 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104660 assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104661 testcase( pTerm->eOperator==WO_IN );
104662 testcase( pTerm->eOperator==WO_ISNULL );
104663 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104664 if( pTerm->wtFlags & TERM_VNULL ) continue;
104665 nTerm++;
104666 }
104667
@@ -104708,18 +104879,18 @@
104708 pUsage;
104709
104710 for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104711 u8 op;
104712 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104713 assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104714 testcase( pTerm->eOperator==WO_IN );
104715 testcase( pTerm->eOperator==WO_ISNULL );
104716 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104717 if( pTerm->wtFlags & TERM_VNULL ) continue;
104718 pIdxCons[j].iColumn = pTerm->u.leftColumn;
104719 pIdxCons[j].iTermOffset = i;
104720 op = (u8)pTerm->eOperator;
104721 if( op==WO_IN ) op = WO_EQ;
104722 pIdxCons[j].op = op;
104723 /* The direct assignment in the previous line is possible only because
104724 ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
104725 ** following asserts verify this fact. */
@@ -104885,11 +105056,11 @@
104885 pUsage = pIdxInfo->aConstraintUsage;
104886 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104887 j = pIdxCons->iTermOffset;
104888 pTerm = &pWC->a[j];
104889 if( (pTerm->prereqRight&p->notReady)==0
104890 && (bAllowIN || pTerm->eOperator!=WO_IN)
104891 ){
104892 pIdxCons->usable = 1;
104893 }else{
104894 pIdxCons->usable = 0;
104895 }
@@ -104917,11 +105088,11 @@
104917 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104918 if( pUsage[i].argvIndex>0 ){
104919 j = pIdxCons->iTermOffset;
104920 pTerm = &pWC->a[j];
104921 p->cost.used |= pTerm->prereqRight;
104922 if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){
104923 /* Do not attempt to use an IN constraint if the virtual table
104924 ** says that the equivalent EQ constraint cannot be safely omitted.
104925 ** If we do attempt to use such a constraint, some rows might be
104926 ** repeated in the output. */
104927 break;
@@ -105223,28 +105394,28 @@
105223 u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
105224
105225 if( pLower ){
105226 Expr *pExpr = pLower->pExpr->pRight;
105227 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105228 assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE );
105229 if( rc==SQLITE_OK
105230 && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
105231 ){
105232 iLower = a[0];
105233 if( pLower->eOperator==WO_GT ) iLower += a[1];
105234 }
105235 sqlite3ValueFree(pRangeVal);
105236 }
105237 if( rc==SQLITE_OK && pUpper ){
105238 Expr *pExpr = pUpper->pExpr->pRight;
105239 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105240 assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE );
105241 if( rc==SQLITE_OK
105242 && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
105243 ){
105244 iUpper = a[0];
105245 if( pUpper->eOperator==WO_LE ) iUpper += a[1];
105246 }
105247 sqlite3ValueFree(pRangeVal);
105248 }
105249 if( rc==SQLITE_OK ){
105250 if( iUpper<=iLower ){
@@ -105548,16 +105719,16 @@
105548 ** if there are any X= or X IS NULL constraints in the WHERE clause. */
105549 pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105550 WO_EQ|WO_ISNULL|WO_IN, pIdx);
105551 if( pConstraint==0 ){
105552 isEq = 0;
105553 }else if( pConstraint->eOperator==WO_IN ){
105554 /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105555 ** because we do not know in what order the values on the RHS of the IN
105556 ** operator will occur. */
105557 break;
105558 }else if( pConstraint->eOperator==WO_ISNULL ){
105559 uniqueNotNull = 0;
105560 isEq = 1; /* "X IS NULL" means X has only a single value */
105561 }else if( pConstraint->prereqRight==0 ){
105562 isEq = 1; /* Constraint "X=constant" means X has only a single value */
105563 }else{
@@ -105903,11 +106074,11 @@
105903 int bRev = 2;
105904 WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
105905 pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
105906 WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
105907 bRev, pc.plan.nOBSat));
105908 if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
105909 pc.plan.wsFlags |= WHERE_ORDERED;
105910 }
105911 if( nOrderBy==pc.plan.nOBSat ){
105912 bSort = 0;
105913 pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
@@ -105966,16 +106137,17 @@
105966 */
105967 if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
105968 && pFirstTerm!=0 && aiRowEst[1]>1 ){
105969 assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
105970 if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
105971 testcase( pFirstTerm->eOperator==WO_EQ );
105972 testcase( pFirstTerm->eOperator==WO_ISNULL );
 
105973 whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
105974 &pc.plan.nRow);
105975 }else if( bInEst==0 ){
105976 assert( pFirstTerm->eOperator==WO_IN );
105977 whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
105978 &pc.plan.nRow);
105979 }
105980 }
105981 #endif /* SQLITE_ENABLE_STAT3 */
@@ -106118,11 +106290,11 @@
106118 ** more selective intentionally because of the subjective
106119 ** observation that indexed range constraints really are more
106120 ** selective in practice, on average. */
106121 pc.plan.nRow /= 3;
106122 }
106123 }else if( pTerm->eOperator!=WO_NOOP ){
106124 /* Any other expression lowers the output row count by half */
106125 pc.plan.nRow /= 2;
106126 }
106127 }
106128 if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
@@ -106170,12 +106342,13 @@
106170 assert( pSrc->pIndex==0
106171 || p->cost.plan.u.pIdx==0
106172 || p->cost.plan.u.pIdx==pSrc->pIndex
106173 );
106174
106175 WHERETRACE((" best index is: %s\n",
106176 p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
 
106177
106178 bestOrClauseIndex(p);
106179 bestAutomaticIndex(p);
106180 p->cost.plan.wsFlags |= eqTermMask;
106181 }
@@ -106753,11 +106926,10 @@
106753 */
106754 iReleaseReg = sqlite3GetTempReg(pParse);
106755 pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106756 assert( pTerm!=0 );
106757 assert( pTerm->pExpr!=0 );
106758 assert( pTerm->leftCursor==iCur );
106759 assert( omitTable==0 );
106760 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106761 iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
106762 addrNxt = pLevel->addrNxt;
106763 sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
@@ -107144,11 +107316,11 @@
107144 int ii; /* Loop counter */
107145 Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
107146
107147 pTerm = pLevel->plan.u.pTerm;
107148 assert( pTerm!=0 );
107149 assert( pTerm->eOperator==WO_OR );
107150 assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
107151 pOrWc = &pTerm->u.pOrInfo->wc;
107152 pLevel->op = OP_Return;
107153 pLevel->p1 = regReturn;
107154
@@ -107217,11 +107389,11 @@
107217 }
107218 }
107219
107220 for(ii=0; ii<pOrWc->nTerm; ii++){
107221 WhereTerm *pOrTerm = &pOrWc->a[ii];
107222 if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
107223 WhereInfo *pSubWInfo; /* Info for single OR-term scan */
107224 Expr *pOrExpr = pOrTerm->pExpr;
107225 if( pAndExpr ){
107226 pAndExpr->pLeft = pOrExpr;
107227 pOrExpr = pAndExpr;
@@ -107672,10 +107844,11 @@
107672 Index *pIdx; /* Index for FROM table at pTabItem */
107673 int j; /* For looping over FROM tables */
107674 int bestJ = -1; /* The value of j */
107675 Bitmask m; /* Bitmask value for j or bestJ */
107676 int isOptimal; /* Iterator for optimal/non-optimal search */
 
107677 int nUnconstrained; /* Number tables without INDEXED BY */
107678 Bitmask notIndexed; /* Mask of tables that cannot use an index */
107679
107680 memset(&bestPlan, 0, sizeof(bestPlan));
107681 bestPlan.rCost = SQLITE_BIG_DBL;
@@ -107706,14 +107879,12 @@
107706 **
107707 ** The second loop iteration is only performed if no optimal scan
107708 ** strategies were found by the first iteration. This second iteration
107709 ** is used to search for the lowest cost scan overall.
107710 **
107711 ** Previous versions of SQLite performed only the second iteration -
107712 ** the next outermost loop was always that with the lowest overall
107713 ** cost. However, this meant that SQLite could select the wrong plan
107714 ** for scripts such as the following:
107715 **
107716 ** CREATE TABLE t1(a, b);
107717 ** CREATE TABLE t2(c, d);
107718 ** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a;
107719 **
@@ -107724,20 +107895,44 @@
107724 ** algorithm may choose to use t2 for the outer loop, which is a much
107725 ** costlier approach.
107726 */
107727 nUnconstrained = 0;
107728 notIndexed = 0;
107729 for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
 
 
 
 
 
 
107730 for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107731 int doNotReorder; /* True if this table should not be reordered */
107732
107733 doNotReorder = (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0;
107734 if( j!=iFrom && doNotReorder ) break;
107735 m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107736 if( (m & sWBI.notValid)==0 ){
107737 if( j==iFrom ) iFrom++;
107738 continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107739 }
107740 sWBI.notReady = (isOptimal ? m : sWBI.notValid);
107741 if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
107742
107743 WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
@@ -107763,12 +107958,12 @@
107763 if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
107764 notIndexed |= m;
107765 }
107766 if( isOptimal ){
107767 pWInfo->a[j].rOptCost = sWBI.cost.rCost;
107768 }else if( iFrom<nTabList-1 ){
107769 /* If two or more tables have nearly the same outer loop cost,
107770 ** very different inner loop (optimal) cost, we want to choose
107771 ** for the outer loop that table which benefits the least from
107772 ** being in the inner loop. The following code scales the
107773 ** outer loop cost estimate to accomplish that. */
107774 WHERETRACE((" scaling cost from %.1f to %.1f\n",
@@ -107809,15 +108004,23 @@
107809 sWBI.cost.rCost, sWBI.cost.plan.nRow,
107810 sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
107811 bestPlan = sWBI.cost;
107812 bestJ = j;
107813 }
107814 if( doNotReorder ) break;
 
 
 
 
107815 }
107816 }
107817 assert( bestJ>=0 );
107818 assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
 
 
 
 
107819 WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
107820 " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
107821 bestJ, pTabList->a[bestJ].pTab->zName,
107822 pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
107823 bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
@@ -136543,11 +136746,12 @@
136543 ** would fit in a single node, use a smaller node-size.
136544 */
136545 static int getNodeSize(
136546 sqlite3 *db, /* Database handle */
136547 Rtree *pRtree, /* Rtree handle */
136548 int isCreate /* True for xCreate, false for xConnect */
 
136549 ){
136550 int rc;
136551 char *zSql;
136552 if( isCreate ){
136553 int iPageSize = 0;
@@ -136556,17 +136760,22 @@
136556 if( rc==SQLITE_OK ){
136557 pRtree->iNodeSize = iPageSize-64;
136558 if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
136559 pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
136560 }
 
 
136561 }
136562 }else{
136563 zSql = sqlite3_mprintf(
136564 "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
136565 pRtree->zDb, pRtree->zName
136566 );
136567 rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
 
 
 
136568 }
136569
136570 sqlite3_free(zSql);
136571 return rc;
136572 }
@@ -136626,11 +136835,11 @@
136626 pRtree->eCoordType = eCoordType;
136627 memcpy(pRtree->zDb, argv[1], nDb);
136628 memcpy(pRtree->zName, argv[2], nName);
136629
136630 /* Figure out the node size to use. */
136631 rc = getNodeSize(db, pRtree, isCreate);
136632
136633 /* Create/Connect to the underlying relational database schema. If
136634 ** that is successful, call sqlite3_declare_vtab() to configure
136635 ** the r-tree table schema.
136636 */
136637
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674 ** [sqlite_version()] and [sqlite_source_id()].
675 */
676 #define SQLITE_VERSION "3.7.16"
677 #define SQLITE_VERSION_NUMBER 3007016
678 #define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
679
680 /*
681 ** CAPI3REF: Run-Time Library Version Numbers
682 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
683 **
@@ -8238,10 +8238,15 @@
8238 ** A convenience macro that returns the number of elements in
8239 ** an array.
8240 */
8241 #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
8242
8243 /*
8244 ** Determine if the argument is a power of two
8245 */
8246 #define IsPowerOfTwo(X) (((X)&((X)-1))==0)
8247
8248 /*
8249 ** The following value as a destructor means to use sqlite3DbFree().
8250 ** The sqlite3DbFree() routine requires two parameters instead of the
8251 ** one parameter that destructors normally want. So we have to introduce
8252 ** this magic value that the code knows to handle differently. Any
@@ -10042,10 +10047,11 @@
10047 #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
10048 #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
10049 #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
10050 #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
10051 #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
10052 #define SQLITE_Transitive 0x0200 /* Transitive constraints */
10053 #define SQLITE_AllOpts 0xffff /* All optimizations */
10054
10055 /*
10056 ** Macros for testing whether or not optimizations are enabled or disabled.
10057 */
@@ -10553,24 +10559,24 @@
10559 ** and the value of Index.onError indicate the which conflict resolution
10560 ** algorithm to employ whenever an attempt is made to insert a non-unique
10561 ** element.
10562 */
10563 struct Index {
10564 char *zName; /* Name of this index */
10565 int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10566 tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
10567 Table *pTable; /* The SQL table being indexed */
10568 char *zColAff; /* String defining the affinity of each column */
10569 Index *pNext; /* The next index associated with the same table */
10570 Schema *pSchema; /* Schema containing this index */
10571 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
10572 char **azColl; /* Array of collation sequence names for index */
10573 int tnum; /* DB Page containing root of this index */
10574 u16 nColumn; /* Number of columns in table used by this index */
10575 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10576 unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
10577 unsigned bUnordered:1; /* Use this index for == or IN queries only */
10578 #ifdef SQLITE_ENABLE_STAT3
10579 int nSample; /* Number of elements in aSample[] */
10580 tRowcnt avgEq; /* Average nEq value for key values not in aSample */
10581 IndexSample *aSample; /* Samples of the left-most key */
10582 #endif
@@ -10840,22 +10846,31 @@
10846 ** name. An expr/name combination can be used in several ways, such
10847 ** as the list of "expr AS ID" fields following a "SELECT" or in the
10848 ** list of "ID = expr" items in an UPDATE. A list of expressions can
10849 ** also be used as the argument to a function, in which case the a.zName
10850 ** field is not used.
10851 **
10852 ** By default the Expr.zSpan field holds a human-readable description of
10853 ** the expression that is used in the generation of error messages and
10854 ** column labels. In this case, Expr.zSpan is typically the text of a
10855 ** column expression as it exists in a SELECT statement. However, if
10856 ** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
10857 ** of the result column in the form: DATABASE.TABLE.COLUMN. This later
10858 ** form is used for name resolution with nested FROM clauses.
10859 */
10860 struct ExprList {
10861 int nExpr; /* Number of expressions on the list */
10862 int iECursor; /* VDBE Cursor associated with this ExprList */
10863 struct ExprList_item { /* For each expression in the list */
10864 Expr *pExpr; /* The list of expressions */
10865 char *zName; /* Token associated with this expression */
10866 char *zSpan; /* Original text of the expression */
10867 u8 sortOrder; /* 1 for DESC or 0 for ASC */
10868 unsigned done :1; /* A flag to indicate when processing is finished */
10869 unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
10870 u16 iOrderByCol; /* For ORDER BY, column number in result set */
10871 u16 iAlias; /* Index into Parse.aAlias[] for zName */
10872 } *a; /* Alloc a power of two greater or equal to nExpr */
10873 };
10874
10875 /*
10876 ** An instance of this structure is used by the parser to record both
@@ -12141,10 +12156,11 @@
12156 SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
12157 SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
12158 SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
12159 SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
12160 SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
12161 SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
12162 SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
12163 SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
12164 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12165 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12166 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
@@ -23289,15 +23305,11 @@
23305 { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
23306 #endif
23307 #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
23308 aSyscall[13].pCurrent)
23309
 
23310 { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
 
 
 
23311 #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
23312
23313 #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
23314 { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
23315 #else
@@ -23318,13 +23330,10 @@
23330 #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
23331
23332 { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
23333 #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
23334
 
 
 
23335 }; /* End of the overrideable system calls */
23336
23337 /*
23338 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
23339 ** "unix" VFSes. Return SQLITE_OK opon successfully updating the
@@ -23425,31 +23434,29 @@
23434 ** process that is able to write to the database will also be able to
23435 ** recover the hot journals.
23436 */
23437 static int robust_open(const char *z, int f, mode_t m){
23438 int fd;
23439 mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
 
 
 
 
 
 
 
23440 do{
23441 #if defined(O_CLOEXEC)
23442 fd = osOpen(z,f|O_CLOEXEC,m2);
23443 #else
23444 fd = osOpen(z,f,m2);
23445 #endif
23446 }while( fd<0 && errno==EINTR );
23447 if( fd>=0 ){
23448 if( m!=0 ){
23449 struct stat statbuf;
23450 if( osFstat(fd, &statbuf)==0 && (statbuf.st_mode&0777)!=m ){
23451 osFchmod(fd, m);
23452 }
23453 }
23454 #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23455 osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
23456 #endif
23457 }
23458 return fd;
23459 }
23460
23461 /*
23462 ** Helper functions to obtain and relinquish the global mutex. The
@@ -29871,11 +29878,11 @@
29878 };
29879 unsigned int i; /* Loop counter */
29880
29881 /* Double-check that the aSyscall[] array has been constructed
29882 ** correctly. See ticket [bb3a86e890c8e96ab] */
29883 assert( ArraySize(aSyscall)==21 );
29884
29885 /* Register all VFSes defined in the aVfs[] array */
29886 for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
29887 sqlite3_vfs_register(&aVfs[i], i==0);
29888 }
@@ -72655,10 +72662,39 @@
72662 }
72663 }
72664 return 0;
72665 }
72666
72667 /*
72668 ** Subqueries stores the original database, table and column names for their
72669 ** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
72670 ** Check to see if the zSpan given to this routine matches the zDb, zTab,
72671 ** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
72672 ** match anything.
72673 */
72674 SQLITE_PRIVATE int sqlite3MatchSpanName(
72675 const char *zSpan,
72676 const char *zCol,
72677 const char *zTab,
72678 const char *zDb
72679 ){
72680 int n;
72681 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72682 if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
72683 return 0;
72684 }
72685 zSpan += n+1;
72686 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72687 if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
72688 return 0;
72689 }
72690 zSpan += n+1;
72691 if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
72692 return 0;
72693 }
72694 return 1;
72695 }
72696
72697 /*
72698 ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
72699 ** that name in the set of source tables in pSrcList and make the pExpr
72700 ** expression node refer back to that source column. The following changes
@@ -72710,44 +72746,63 @@
72746
72747 /* Initialize the node to no-match */
72748 pExpr->iTable = -1;
72749 pExpr->pTab = 0;
72750 ExprSetIrreducible(pExpr);
72751
72752 /* Translate the schema name in zDb into a pointer to the corresponding
72753 ** schema. If not found, pSchema will remain NULL and nothing will match
72754 ** resulting in an appropriate error message toward the end of this routine
72755 */
72756 if( zDb ){
72757 for(i=0; i<db->nDb; i++){
72758 assert( db->aDb[i].zName );
72759 if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
72760 pSchema = db->aDb[i].pSchema;
72761 break;
72762 }
72763 }
72764 }
72765
72766 /* Start at the inner-most context and move outward until a match is found */
72767 while( pNC && cnt==0 ){
72768 ExprList *pEList;
72769 SrcList *pSrcList = pNC->pSrcList;
72770
72771 if( pSrcList ){
72772 for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
72773 Table *pTab;
 
72774 Column *pCol;
72775
72776 pTab = pItem->pTab;
72777 assert( pTab!=0 && pTab->zName!=0 );
 
72778 assert( pTab->nCol>0 );
72779 if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
72780 ExprList *pEList = pItem->pSelect->pEList;
72781 int hit = 0;
72782 for(j=0; j<pEList->nExpr; j++){
72783 if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
72784 cnt++;
72785 cntTab = 2;
72786 pMatch = pItem;
72787 pExpr->iColumn = j;
72788 hit = 1;
72789 }
72790 }
72791 if( hit || zTab==0 ) continue;
72792 }
72793 if( zDb && pTab->pSchema!=pSchema ){
72794 continue;
72795 }
72796 if( zTab ){
72797 const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
72798 assert( zTabName!=0 );
72799 if( sqlite3StrICmp(zTabName, zTab)!=0 ){
72800 continue;
 
 
 
 
 
 
 
72801 }
72802 }
72803 if( 0==(cntTab++) ){
 
 
 
72804 pMatch = pItem;
72805 }
72806 for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
72807 if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
72808 /* If there has been exactly one prior match and this match
@@ -72757,21 +72812,23 @@
72812 if( cnt==1 ){
72813 if( pItem->jointype & JT_NATURAL ) continue;
72814 if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
72815 }
72816 cnt++;
 
 
72817 pMatch = pItem;
 
72818 /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
72819 pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
72820 break;
72821 }
72822 }
72823 }
72824 if( pMatch ){
72825 pExpr->iTable = pMatch->iCursor;
72826 pExpr->pTab = pMatch->pTab;
72827 pSchema = pExpr->pTab->pSchema;
72828 }
72829 } /* if( pSrcList ) */
72830
72831 #ifndef SQLITE_OMIT_TRIGGER
72832 /* If we have not already resolved the name, then maybe
72833 ** it is a new.* or old.* trigger argument reference
72834 */
@@ -73102,11 +73159,11 @@
73159 #endif
73160 if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
73161 sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
73162 pNC->nErr++;
73163 is_agg = 0;
73164 }else if( no_such_func && pParse->db->init.busy==0 ){
73165 sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
73166 pNC->nErr++;
73167 }else if( wrong_num_args ){
73168 sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
73169 nId, zId);
@@ -77065,10 +77122,16 @@
77122 for(i=0; i<pList->nExpr; i++){
77123 sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
77124 sqlite3ExplainPush(pOut);
77125 sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
77126 sqlite3ExplainPop(pOut);
77127 if( pList->a[i].zName ){
77128 sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
77129 }
77130 if( pList->a[i].bSpanIsTab ){
77131 sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
77132 }
77133 if( i<pList->nExpr-1 ){
77134 sqlite3ExplainNL(pOut);
77135 }
77136 }
77137 sqlite3ExplainPop(pOut);
@@ -92739,13 +92802,15 @@
92802 if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
92803 Table *pTab;
92804 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
92805 pTab = sqlite3FindTable(db, zRight, zDb);
92806 if( pTab ){
92807 int i, k;
92808 int nHidden = 0;
92809 Column *pCol;
92810 Index *pPk;
92811 for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
92812 sqlite3VdbeSetNumCols(v, 6);
92813 pParse->nMem = 6;
92814 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
92815 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
92816 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
@@ -92766,12 +92831,18 @@
92831 if( pCol->zDflt ){
92832 sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
92833 }else{
92834 sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
92835 }
92836 if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
92837 k = 0;
92838 }else if( pPk==0 ){
92839 k = 1;
92840 }else{
92841 for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
92842 }
92843 sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
92844 sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
92845 }
92846 }
92847 }else
92848
@@ -93516,11 +93587,11 @@
93587 sqlite3_rekey(db, zKey, i/2);
93588 }
93589 }else
93590 #endif
93591 #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
93592 if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){
93593 #ifdef SQLITE_HAS_CODEC
93594 if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
93595 sqlite3_activate_see(&zRight[4]);
93596 }
93597 #endif
@@ -95756,12 +95827,10 @@
95827
95828 for(i=0, pCol=aCol; i<nCol; i++, pCol++){
95829 /* Get an appropriate name for the column
95830 */
95831 p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
 
 
95832 if( (zName = pEList->a[i].zName)!=0 ){
95833 /* If the column contains an "AS <name>" phrase, use <name> as the name */
95834 zName = sqlite3DbStrDup(db, zName);
95835 }else{
95836 Expr *pColExpr = p; /* The expression that is the result column name */
@@ -95795,10 +95864,13 @@
95864 */
95865 nName = sqlite3Strlen30(zName);
95866 for(j=cnt=0; j<i; j++){
95867 if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
95868 char *zNewName;
95869 int k;
95870 for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
95871 if( zName[k]==':' ) nName = k;
95872 zName[nName] = 0;
95873 zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
95874 sqlite3DbFree(db, zName);
95875 zName = zNewName;
95876 j = -1;
@@ -97711,10 +97783,11 @@
97783 int i, j, k;
97784 SrcList *pTabList;
97785 ExprList *pEList;
97786 struct SrcList_item *pFrom;
97787 sqlite3 *db = pParse->db;
97788 Expr *pE, *pRight, *pExpr;
97789
97790 if( db->mallocFailed ){
97791 return WRC_Abort;
97792 }
97793 if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
@@ -97796,11 +97869,11 @@
97869 **
97870 ** The first loop just checks to see if there are any "*" operators
97871 ** that need expanding.
97872 */
97873 for(k=0; k<pEList->nExpr; k++){
97874 pE = pEList->a[k].pExpr;
97875 if( pE->op==TK_ALL ) break;
97876 assert( pE->op!=TK_DOT || pE->pRight!=0 );
97877 assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
97878 if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
97879 }
@@ -97814,14 +97887,22 @@
97887 ExprList *pNew = 0;
97888 int flags = pParse->db->flags;
97889 int longNames = (flags & SQLITE_FullColNames)!=0
97890 && (flags & SQLITE_ShortColNames)==0;
97891
97892 /* When processing FROM-clause subqueries, it is always the case
97893 ** that full_column_names=OFF and short_column_names=ON. The
97894 ** sqlite3ResultSetOfSelect() routine makes it so. */
97895 assert( (p->selFlags & SF_NestedFrom)==0
97896 || ((flags & SQLITE_FullColNames)==0 &&
97897 (flags & SQLITE_ShortColNames)!=0) );
97898
97899 for(k=0; k<pEList->nExpr; k++){
97900 pE = a[k].pExpr;
97901 pRight = pE->pRight;
97902 assert( pE->op!=TK_DOT || pRight!=0 );
97903 if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
97904 /* This particular expression does not need to be expanded.
97905 */
97906 pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
97907 if( pNew ){
97908 pNew->a[pNew->nExpr-1].zName = a[k].zName;
@@ -97832,44 +97913,56 @@
97913 a[k].pExpr = 0;
97914 }else{
97915 /* This expression is a "*" or a "TABLE.*" and needs to be
97916 ** expanded. */
97917 int tableSeen = 0; /* Set to 1 when TABLE matches */
97918 char *zTName = 0; /* text of name of TABLE */
97919 if( pE->op==TK_DOT ){
97920 assert( pE->pLeft!=0 );
97921 assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
97922 zTName = pE->pLeft->u.zToken;
 
 
97923 }
97924 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
97925 Table *pTab = pFrom->pTab;
97926 Select *pSub = pFrom->pSelect;
97927 char *zTabName = pFrom->zAlias;
97928 const char *zSchemaName = 0;
97929 int iDb;
97930 if( zTabName==0 ){
97931 zTabName = pTab->zName;
97932 }
97933 if( db->mallocFailed ) break;
97934 if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
97935 pSub = 0;
97936 if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97937 continue;
97938 }
97939 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
97940 zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
97941 }
 
97942 for(j=0; j<pTab->nCol; j++){
 
97943 char *zName = pTab->aCol[j].zName;
97944 char *zColname; /* The computed column name */
97945 char *zToFree; /* Malloced string that needs to be freed */
97946 Token sColname; /* Computed column name as a token */
97947
97948 assert( zName );
97949 if( zTName && pSub
97950 && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
97951 ){
97952 continue;
97953 }
97954
97955 /* If a column is marked as 'hidden' (currently only possible
97956 ** for virtual tables), do not include it in the expanded
97957 ** result-set list.
97958 */
97959 if( IsHiddenColumn(&pTab->aCol[j]) ){
97960 assert(IsVirtual(pTab));
97961 continue;
97962 }
97963 tableSeen = 1;
97964
97965 if( i>0 && zTName==0 ){
97966 if( (pFrom->jointype & JT_NATURAL)!=0
97967 && tableAndColumnIndex(pTabList, i, zName, 0, 0)
97968 ){
@@ -97888,10 +97981,14 @@
97981 zToFree = 0;
97982 if( longNames || pTabList->nSrc>1 ){
97983 Expr *pLeft;
97984 pLeft = sqlite3Expr(db, TK_ID, zTabName);
97985 pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
97986 if( zSchemaName ){
97987 pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
97988 pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
97989 }
97990 if( longNames ){
97991 zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
97992 zToFree = zColname;
97993 }
97994 }else{
@@ -97899,10 +97996,22 @@
97996 }
97997 pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
97998 sColname.z = zColname;
97999 sColname.n = sqlite3Strlen30(zColname);
98000 sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
98001 if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
98002 struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
98003 if( pSub ){
98004 pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
98005 testcase( pX->zSpan==0 );
98006 }else{
98007 pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
98008 zSchemaName, zTabName, zColname);
98009 testcase( pX->zSpan==0 );
98010 }
98011 pX->bSpanIsTab = 1;
98012 }
98013 sqlite3DbFree(db, zToFree);
98014 }
98015 }
98016 if( !tableSeen ){
98017 if( zTName ){
@@ -102699,12 +102808,12 @@
102808 Expr *pExpr; /* Pointer to the subexpression that is this term */
102809 int iParent; /* Disable pWC->a[iParent] when this term disabled */
102810 int leftCursor; /* Cursor number of X in "X <op> <expr>" */
102811 union {
102812 int leftColumn; /* Column number of X in "X <op> <expr>" */
102813 WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
102814 WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
102815 } u;
102816 u16 eOperator; /* A WO_xx value describing <op> */
102817 u8 wtFlags; /* TERM_xxx bit flags. See below */
102818 u8 nChild; /* Number of children that must disable us */
102819 WhereClause *pWC; /* The clause this term is part of */
@@ -102828,10 +102937,11 @@
102937 #define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
102938 #define WO_MATCH 0x040
102939 #define WO_ISNULL 0x080
102940 #define WO_OR 0x100 /* Two or more OR-connected terms */
102941 #define WO_AND 0x200 /* Two or more AND-connected terms */
102942 #define WO_EQUIV 0x400 /* Of the form A==B, both columns */
102943 #define WO_NOOP 0x800 /* This term does not restrict search space */
102944
102945 #define WO_ALL 0xfff /* Mask of all possible WO_* values */
102946 #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
102947
@@ -103230,58 +103340,112 @@
103340 /*
103341 ** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
103342 ** where X is a reference to the iColumn of table iCur and <op> is one of
103343 ** the WO_xx operator codes specified by the op parameter.
103344 ** Return a pointer to the term. Return 0 if not found.
103345 **
103346 ** The term returned might by Y=<expr> if there is another constraint in
103347 ** the WHERE clause that specifies that X=Y. Any such constraints will be
103348 ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
103349 ** aEquiv[] array holds X and all its equivalents, with each SQL variable
103350 ** taking up two slots in aEquiv[]. The first slot is for the cursor number
103351 ** and the second is for the column number. There are 22 slots in aEquiv[]
103352 ** so that means we can look for X plus up to 10 other equivalent values.
103353 ** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3
103354 ** and ... and A9=A10 and A10=<expr>.
103355 **
103356 ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
103357 ** then try for the one with no dependencies on <expr> - in other words where
103358 ** <expr> is a constant expression of some kind. Only return entries of
103359 ** the form "X <op> Y" where Y is a column in another table if no terms of
103360 ** the form "X <op> <const-expr>" exist. Other than this priority, if there
103361 ** are two or more terms that match, then the choice of which term to return
103362 ** is arbitrary.
103363 */
103364 static WhereTerm *findTerm(
103365 WhereClause *pWC, /* The WHERE clause to be searched */
103366 int iCur, /* Cursor number of LHS */
103367 int iColumn, /* Column number of LHS */
103368 Bitmask notReady, /* RHS must not overlap with this mask */
103369 u32 op, /* Mask of WO_xx values describing operator */
103370 Index *pIdx /* Must be compatible with this index, if not NULL */
103371 ){
103372 WhereTerm *pTerm; /* Term being examined as possible result */
103373 WhereTerm *pResult = 0; /* The answer to return */
103374 WhereClause *pWCOrig = pWC; /* Original pWC value */
103375 int j, k; /* Loop counters */
103376 Expr *pX; /* Pointer to an expression */
103377 Parse *pParse; /* Parsing context */
103378 int iOrigCol = iColumn; /* Original value of iColumn */
103379 int nEquiv = 2; /* Number of entires in aEquiv[] */
103380 int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */
103381 int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */
103382
103383 assert( iCur>=0 );
103384 aEquiv[0] = iCur;
103385 aEquiv[1] = iColumn;
103386 for(;;){
103387 for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){
103388 for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103389 if( pTerm->leftCursor==iCur
103390 && pTerm->u.leftColumn==iColumn
103391 ){
103392 if( (pTerm->prereqRight & notReady)==0
103393 && (pTerm->eOperator & op & WO_ALL)!=0
103394 ){
103395 if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){
103396 CollSeq *pColl;
103397 char idxaff;
103398
103399 pX = pTerm->pExpr;
103400 pParse = pWC->pParse;
103401 idxaff = pIdx->pTable->aCol[iOrigCol].affinity;
103402 if( !sqlite3IndexAffinityOk(pX, idxaff) ){
103403 continue;
103404 }
103405
103406 /* Figure out the collation sequence required from an index for
103407 ** it to be useful for optimising expression pX. Store this
103408 ** value in variable pColl.
103409 */
103410 assert(pX->pLeft);
103411 pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight);
103412 if( pColl==0 ) pColl = pParse->db->pDfltColl;
103413
103414 for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){
103415 if( NEVER(j>=pIdx->nColumn) ) return 0;
103416 }
103417 if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
103418 continue;
103419 }
103420 }
103421 pResult = pTerm;
103422 if( pTerm->prereqRight==0 ) goto findTerm_success;
103423 }
103424 if( (pTerm->eOperator & WO_EQUIV)!=0
103425 && nEquiv<ArraySize(aEquiv)
103426 ){
103427 pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
103428 assert( pX->op==TK_COLUMN );
103429 for(j=0; j<nEquiv; j+=2){
103430 if( aEquiv[j]==pX->iTable && aEquiv[j+1]==pX->iColumn ) break;
103431 }
103432 if( j==nEquiv ){
103433 aEquiv[j] = pX->iTable;
103434 aEquiv[j+1] = pX->iColumn;
103435 nEquiv += 2;
103436 }
103437 }
103438 }
103439 }
103440 }
103441 if( iEquiv>=nEquiv ) break;
103442 iCur = aEquiv[iEquiv++];
103443 iColumn = aEquiv[iEquiv++];
103444 }
103445 findTerm_success:
103446 return pResult;
103447 }
103448
103449 /* Forward reference */
103450 static void exprAnalyze(SrcList*, WhereClause*, int);
103451
@@ -103555,11 +103719,10 @@
103719 indexable = ~(Bitmask)0;
103720 chngToIN = ~(pWC->vmask);
103721 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103722 if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103723 WhereAndInfo *pAndInfo;
 
103724 assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103725 chngToIN = 0;
103726 pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
103727 if( pAndInfo ){
103728 WhereClause *pAndWC;
@@ -103594,11 +103757,11 @@
103757 if( pOrTerm->wtFlags & TERM_VIRTUAL ){
103758 WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent];
103759 b |= getMask(pMaskSet, pOther->leftCursor);
103760 }
103761 indexable &= b;
103762 if( (pOrTerm->eOperator & WO_EQ)==0 ){
103763 chngToIN = 0;
103764 }else{
103765 chngToIN &= b;
103766 }
103767 }
@@ -103645,11 +103808,11 @@
103808 ** and column is found but leave okToChngToIN false if not found.
103809 */
103810 for(j=0; j<2 && !okToChngToIN; j++){
103811 pOrTerm = pOrWc->a;
103812 for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
103813 assert( pOrTerm->eOperator & WO_EQ );
103814 pOrTerm->wtFlags &= ~TERM_OR_OK;
103815 if( pOrTerm->leftCursor==iCursor ){
103816 /* This is the 2-bit case and we are on the second iteration and
103817 ** current term is from the first iteration. So skip this term. */
103818 assert( j==1 );
@@ -103671,21 +103834,21 @@
103834 }
103835 if( i<0 ){
103836 /* No candidate table+column was found. This can only occur
103837 ** on the second iteration */
103838 assert( j==1 );
103839 assert( IsPowerOfTwo(chngToIN) );
103840 assert( chngToIN==getMask(pMaskSet, iCursor) );
103841 break;
103842 }
103843 testcase( j==1 );
103844
103845 /* We have found a candidate table and column. Check to see if that
103846 ** table and column is common to every term in the OR clause */
103847 okToChngToIN = 1;
103848 for(; i>=0 && okToChngToIN; i--, pOrTerm++){
103849 assert( pOrTerm->eOperator & WO_EQ );
103850 if( pOrTerm->leftCursor!=iCursor ){
103851 pOrTerm->wtFlags &= ~TERM_OR_OK;
103852 }else if( pOrTerm->u.leftColumn!=iColumn ){
103853 okToChngToIN = 0;
103854 }else{
@@ -103717,11 +103880,11 @@
103880 Expr *pLeft = 0; /* The LHS of the IN operator */
103881 Expr *pNew; /* The complete IN operator */
103882
103883 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
103884 if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
103885 assert( pOrTerm->eOperator & WO_EQ );
103886 assert( pOrTerm->leftCursor==iCursor );
103887 assert( pOrTerm->u.leftColumn==iColumn );
103888 pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
103889 pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup);
103890 pLeft = pOrTerm->pExpr->pLeft;
@@ -103746,11 +103909,10 @@
103909 pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
103910 }
103911 }
103912 }
103913 #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
 
103914
103915 /*
103916 ** The input to this routine is an WhereTerm structure with only the
103917 ** "pExpr" field filled in. The job of this routine is to analyze the
103918 ** subexpression and populate all the other fields of the WhereTerm
@@ -103816,21 +103978,23 @@
103978 }
103979 pTerm->prereqAll = prereqAll;
103980 pTerm->leftCursor = -1;
103981 pTerm->iParent = -1;
103982 pTerm->eOperator = 0;
103983 if( allowedOp(op) ){
103984 Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
103985 Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
103986 u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
103987 if( pLeft->op==TK_COLUMN ){
103988 pTerm->leftCursor = pLeft->iTable;
103989 pTerm->u.leftColumn = pLeft->iColumn;
103990 pTerm->eOperator = operatorMask(op) & opMask;
103991 }
103992 if( pRight && pRight->op==TK_COLUMN ){
103993 WhereTerm *pNew;
103994 Expr *pDup;
103995 u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
103996 if( pTerm->leftCursor>=0 ){
103997 int idxNew;
103998 pDup = sqlite3ExprDup(db, pExpr, 0);
103999 if( db->mallocFailed ){
104000 sqlite3ExprDelete(db, pDup);
@@ -103841,10 +104005,17 @@
104005 pNew = &pWC->a[idxNew];
104006 pNew->iParent = idxTerm;
104007 pTerm = &pWC->a[idxTerm];
104008 pTerm->nChild = 1;
104009 pTerm->wtFlags |= TERM_COPIED;
104010 if( pExpr->op==TK_EQ
104011 && !ExprHasProperty(pExpr, EP_FromJoin)
104012 && OptimizationEnabled(db, SQLITE_Transitive)
104013 ){
104014 pTerm->eOperator |= WO_EQUIV;
104015 eExtraOp = WO_EQUIV;
104016 }
104017 }else{
104018 pDup = pExpr;
104019 pNew = pTerm;
104020 }
104021 exprCommute(pParse, pDup);
@@ -103852,11 +104023,11 @@
104023 pNew->leftCursor = pLeft->iTable;
104024 pNew->u.leftColumn = pLeft->iColumn;
104025 testcase( (prereqLeft | extraRight) != prereqLeft );
104026 pNew->prereqRight = prereqLeft | extraRight;
104027 pNew->prereqAll = prereqAll;
104028 pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
104029 }
104030 }
104031
104032 #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION
104033 /* If a term is the BETWEEN operator, create two new virtual terms
@@ -104311,11 +104482,11 @@
104482 return;
104483 }
104484
104485 /* Search the WHERE clause terms for a usable WO_OR term. */
104486 for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
104487 if( (pTerm->eOperator & WO_OR)!=0
104488 && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
104489 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0
104490 ){
104491 WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
104492 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
@@ -104332,11 +104503,11 @@
104503 sBOI.ppIdxInfo = 0;
104504 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
104505 WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
104506 (pOrTerm - pOrWC->a), (pTerm - pWC->a)
104507 ));
104508 if( (pOrTerm->eOperator& WO_AND)!=0 ){
104509 sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
104510 bestIndex(&sBOI);
104511 }else if( pOrTerm->leftCursor==iCur ){
104512 WhereClause tempWC;
104513 tempWC.pParse = pWC->pParse;
@@ -104393,11 +104564,11 @@
104564 struct SrcList_item *pSrc, /* Table we are trying to access */
104565 Bitmask notReady /* Tables in outer loops of the join */
104566 ){
104567 char aff;
104568 if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
104569 if( (pTerm->eOperator & WO_EQ)==0 ) return 0;
104570 if( (pTerm->prereqRight & notReady)!=0 ) return 0;
104571 aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
104572 if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
104573 return 1;
104574 }
@@ -104655,13 +104826,13 @@
104826
104827 /* Count the number of possible WHERE clause constraints referring
104828 ** to this virtual table */
104829 for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104830 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104831 assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104832 testcase( pTerm->eOperator & WO_IN );
104833 testcase( pTerm->eOperator & WO_ISNULL );
104834 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104835 if( pTerm->wtFlags & TERM_VNULL ) continue;
104836 nTerm++;
104837 }
104838
@@ -104708,18 +104879,18 @@
104879 pUsage;
104880
104881 for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104882 u8 op;
104883 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104884 assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104885 testcase( pTerm->eOperator & WO_IN );
104886 testcase( pTerm->eOperator & WO_ISNULL );
104887 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104888 if( pTerm->wtFlags & TERM_VNULL ) continue;
104889 pIdxCons[j].iColumn = pTerm->u.leftColumn;
104890 pIdxCons[j].iTermOffset = i;
104891 op = (u8)pTerm->eOperator & WO_ALL;
104892 if( op==WO_IN ) op = WO_EQ;
104893 pIdxCons[j].op = op;
104894 /* The direct assignment in the previous line is possible only because
104895 ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
104896 ** following asserts verify this fact. */
@@ -104885,11 +105056,11 @@
105056 pUsage = pIdxInfo->aConstraintUsage;
105057 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
105058 j = pIdxCons->iTermOffset;
105059 pTerm = &pWC->a[j];
105060 if( (pTerm->prereqRight&p->notReady)==0
105061 && (bAllowIN || (pTerm->eOperator & WO_IN)==0)
105062 ){
105063 pIdxCons->usable = 1;
105064 }else{
105065 pIdxCons->usable = 0;
105066 }
@@ -104917,11 +105088,11 @@
105088 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
105089 if( pUsage[i].argvIndex>0 ){
105090 j = pIdxCons->iTermOffset;
105091 pTerm = &pWC->a[j];
105092 p->cost.used |= pTerm->prereqRight;
105093 if( (pTerm->eOperator & WO_IN)!=0 && pUsage[i].omit==0 ){
105094 /* Do not attempt to use an IN constraint if the virtual table
105095 ** says that the equivalent EQ constraint cannot be safely omitted.
105096 ** If we do attempt to use such a constraint, some rows might be
105097 ** repeated in the output. */
105098 break;
@@ -105223,28 +105394,28 @@
105394 u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
105395
105396 if( pLower ){
105397 Expr *pExpr = pLower->pExpr->pRight;
105398 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105399 assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
105400 if( rc==SQLITE_OK
105401 && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
105402 ){
105403 iLower = a[0];
105404 if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
105405 }
105406 sqlite3ValueFree(pRangeVal);
105407 }
105408 if( rc==SQLITE_OK && pUpper ){
105409 Expr *pExpr = pUpper->pExpr->pRight;
105410 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105411 assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
105412 if( rc==SQLITE_OK
105413 && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
105414 ){
105415 iUpper = a[0];
105416 if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
105417 }
105418 sqlite3ValueFree(pRangeVal);
105419 }
105420 if( rc==SQLITE_OK ){
105421 if( iUpper<=iLower ){
@@ -105548,16 +105719,16 @@
105719 ** if there are any X= or X IS NULL constraints in the WHERE clause. */
105720 pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105721 WO_EQ|WO_ISNULL|WO_IN, pIdx);
105722 if( pConstraint==0 ){
105723 isEq = 0;
105724 }else if( (pConstraint->eOperator & WO_IN)!=0 ){
105725 /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105726 ** because we do not know in what order the values on the RHS of the IN
105727 ** operator will occur. */
105728 break;
105729 }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
105730 uniqueNotNull = 0;
105731 isEq = 1; /* "X IS NULL" means X has only a single value */
105732 }else if( pConstraint->prereqRight==0 ){
105733 isEq = 1; /* Constraint "X=constant" means X has only a single value */
105734 }else{
@@ -105903,11 +106074,11 @@
106074 int bRev = 2;
106075 WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
106076 pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
106077 WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
106078 bRev, pc.plan.nOBSat));
106079 if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
106080 pc.plan.wsFlags |= WHERE_ORDERED;
106081 }
106082 if( nOrderBy==pc.plan.nOBSat ){
106083 bSort = 0;
106084 pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
@@ -105966,16 +106137,17 @@
106137 */
106138 if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
106139 && pFirstTerm!=0 && aiRowEst[1]>1 ){
106140 assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
106141 if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
106142 testcase( pFirstTerm->eOperator & WO_EQ );
106143 testcase( pFirstTerm->eOperator & WO_EQUIV );
106144 testcase( pFirstTerm->eOperator & WO_ISNULL );
106145 whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
106146 &pc.plan.nRow);
106147 }else if( bInEst==0 ){
106148 assert( pFirstTerm->eOperator & WO_IN );
106149 whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
106150 &pc.plan.nRow);
106151 }
106152 }
106153 #endif /* SQLITE_ENABLE_STAT3 */
@@ -106118,11 +106290,11 @@
106290 ** more selective intentionally because of the subjective
106291 ** observation that indexed range constraints really are more
106292 ** selective in practice, on average. */
106293 pc.plan.nRow /= 3;
106294 }
106295 }else if( (pTerm->eOperator & WO_NOOP)==0 ){
106296 /* Any other expression lowers the output row count by half */
106297 pc.plan.nRow /= 2;
106298 }
106299 }
106300 if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
@@ -106170,12 +106342,13 @@
106342 assert( pSrc->pIndex==0
106343 || p->cost.plan.u.pIdx==0
106344 || p->cost.plan.u.pIdx==pSrc->pIndex
106345 );
106346
106347 WHERETRACE((" best index is %s cost=%.1f\n",
106348 p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk",
106349 p->cost.rCost));
106350
106351 bestOrClauseIndex(p);
106352 bestAutomaticIndex(p);
106353 p->cost.plan.wsFlags |= eqTermMask;
106354 }
@@ -106753,11 +106926,10 @@
106926 */
106927 iReleaseReg = sqlite3GetTempReg(pParse);
106928 pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106929 assert( pTerm!=0 );
106930 assert( pTerm->pExpr!=0 );
 
106931 assert( omitTable==0 );
106932 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106933 iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
106934 addrNxt = pLevel->addrNxt;
106935 sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
@@ -107144,11 +107316,11 @@
107316 int ii; /* Loop counter */
107317 Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
107318
107319 pTerm = pLevel->plan.u.pTerm;
107320 assert( pTerm!=0 );
107321 assert( pTerm->eOperator & WO_OR );
107322 assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
107323 pOrWc = &pTerm->u.pOrInfo->wc;
107324 pLevel->op = OP_Return;
107325 pLevel->p1 = regReturn;
107326
@@ -107217,11 +107389,11 @@
107389 }
107390 }
107391
107392 for(ii=0; ii<pOrWc->nTerm; ii++){
107393 WhereTerm *pOrTerm = &pOrWc->a[ii];
107394 if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
107395 WhereInfo *pSubWInfo; /* Info for single OR-term scan */
107396 Expr *pOrExpr = pOrTerm->pExpr;
107397 if( pAndExpr ){
107398 pAndExpr->pLeft = pOrExpr;
107399 pOrExpr = pAndExpr;
@@ -107672,10 +107844,11 @@
107844 Index *pIdx; /* Index for FROM table at pTabItem */
107845 int j; /* For looping over FROM tables */
107846 int bestJ = -1; /* The value of j */
107847 Bitmask m; /* Bitmask value for j or bestJ */
107848 int isOptimal; /* Iterator for optimal/non-optimal search */
107849 int ckOptimal; /* Do the optimal scan check */
107850 int nUnconstrained; /* Number tables without INDEXED BY */
107851 Bitmask notIndexed; /* Mask of tables that cannot use an index */
107852
107853 memset(&bestPlan, 0, sizeof(bestPlan));
107854 bestPlan.rCost = SQLITE_BIG_DBL;
@@ -107706,14 +107879,12 @@
107879 **
107880 ** The second loop iteration is only performed if no optimal scan
107881 ** strategies were found by the first iteration. This second iteration
107882 ** is used to search for the lowest cost scan overall.
107883 **
107884 ** Without the optimal scan step (the first iteration) a suboptimal
107885 ** plan might be chosen for queries like this:
 
 
107886 **
107887 ** CREATE TABLE t1(a, b);
107888 ** CREATE TABLE t2(c, d);
107889 ** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a;
107890 **
@@ -107724,20 +107895,44 @@
107895 ** algorithm may choose to use t2 for the outer loop, which is a much
107896 ** costlier approach.
107897 */
107898 nUnconstrained = 0;
107899 notIndexed = 0;
107900
107901 /* The optimal scan check only occurs if there are two or more tables
107902 ** available to be reordered */
107903 if( iFrom==nTabList-1 ){
107904 ckOptimal = 0; /* Common case of just one table in the FROM clause */
107905 }else{
107906 ckOptimal = -1;
107907 for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
 
 
 
 
107908 m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107909 if( (m & sWBI.notValid)==0 ){
107910 if( j==iFrom ) iFrom++;
107911 continue;
107912 }
107913 if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break;
107914 if( ++ckOptimal ) break;
107915 if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
107916 }
107917 }
107918 assert( ckOptimal==0 || ckOptimal==1 );
107919
107920 for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){
107921 for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107922 if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){
107923 /* This break and one like it in the ckOptimal computation loop
107924 ** above prevent table reordering across LEFT and CROSS JOINs.
107925 ** The LEFT JOIN case is necessary for correctness. The prohibition
107926 ** against reordering across a CROSS JOIN is an SQLite feature that
107927 ** allows the developer to control table reordering */
107928 break;
107929 }
107930 m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107931 if( (m & sWBI.notValid)==0 ){
107932 assert( j>iFrom );
107933 continue;
107934 }
107935 sWBI.notReady = (isOptimal ? m : sWBI.notValid);
107936 if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
107937
107938 WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
@@ -107763,12 +107958,12 @@
107958 if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
107959 notIndexed |= m;
107960 }
107961 if( isOptimal ){
107962 pWInfo->a[j].rOptCost = sWBI.cost.rCost;
107963 }else if( ckOptimal ){
107964 /* If two or more tables have nearly the same outer loop cost, but
107965 ** very different inner loop (optimal) cost, we want to choose
107966 ** for the outer loop that table which benefits the least from
107967 ** being in the inner loop. The following code scales the
107968 ** outer loop cost estimate to accomplish that. */
107969 WHERETRACE((" scaling cost from %.1f to %.1f\n",
@@ -107809,15 +108004,23 @@
108004 sWBI.cost.rCost, sWBI.cost.plan.nRow,
108005 sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
108006 bestPlan = sWBI.cost;
108007 bestJ = j;
108008 }
108009
108010 /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that
108011 ** table y (and not table z) is always the next inner loop inside
108012 ** of table x. */
108013 if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
108014 }
108015 }
108016 assert( bestJ>=0 );
108017 assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
108018 assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 );
108019 testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 );
108020 testcase( bestJ>iFrom && bestJ<nTabList-1
108021 && (pTabList->a[bestJ+1].jointype & JT_LEFT)!=0 );
108022 WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
108023 " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
108024 bestJ, pTabList->a[bestJ].pTab->zName,
108025 pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
108026 bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
@@ -136543,11 +136746,12 @@
136746 ** would fit in a single node, use a smaller node-size.
136747 */
136748 static int getNodeSize(
136749 sqlite3 *db, /* Database handle */
136750 Rtree *pRtree, /* Rtree handle */
136751 int isCreate, /* True for xCreate, false for xConnect */
136752 char **pzErr /* OUT: Error message, if any */
136753 ){
136754 int rc;
136755 char *zSql;
136756 if( isCreate ){
136757 int iPageSize = 0;
@@ -136556,17 +136760,22 @@
136760 if( rc==SQLITE_OK ){
136761 pRtree->iNodeSize = iPageSize-64;
136762 if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
136763 pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
136764 }
136765 }else{
136766 *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136767 }
136768 }else{
136769 zSql = sqlite3_mprintf(
136770 "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
136771 pRtree->zDb, pRtree->zName
136772 );
136773 rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
136774 if( rc!=SQLITE_OK ){
136775 *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136776 }
136777 }
136778
136779 sqlite3_free(zSql);
136780 return rc;
136781 }
@@ -136626,11 +136835,11 @@
136835 pRtree->eCoordType = eCoordType;
136836 memcpy(pRtree->zDb, argv[1], nDb);
136837 memcpy(pRtree->zName, argv[2], nName);
136838
136839 /* Figure out the node size to use. */
136840 rc = getNodeSize(db, pRtree, isCreate, pzErr);
136841
136842 /* Create/Connect to the underlying relational database schema. If
136843 ** that is successful, call sqlite3_declare_vtab() to configure
136844 ** the r-tree table schema.
136845 */
136846
+381 -172
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673673
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674674
** [sqlite_version()] and [sqlite_source_id()].
675675
*/
676676
#define SQLITE_VERSION "3.7.16"
677677
#define SQLITE_VERSION_NUMBER 3007016
678
-#define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
678
+#define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
679679
680680
/*
681681
** CAPI3REF: Run-Time Library Version Numbers
682682
** KEYWORDS: sqlite3_version, sqlite3_sourceid
683683
**
@@ -8238,10 +8238,15 @@
82388238
** A convenience macro that returns the number of elements in
82398239
** an array.
82408240
*/
82418241
#define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
82428242
8243
+/*
8244
+** Determine if the argument is a power of two
8245
+*/
8246
+#define IsPowerOfTwo(X) (((X)&((X)-1))==0)
8247
+
82438248
/*
82448249
** The following value as a destructor means to use sqlite3DbFree().
82458250
** The sqlite3DbFree() routine requires two parameters instead of the
82468251
** one parameter that destructors normally want. So we have to introduce
82478252
** this magic value that the code knows to handle differently. Any
@@ -10042,10 +10047,11 @@
1004210047
#define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
1004310048
#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
1004410049
#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
1004510050
#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
1004610051
#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
10052
+#define SQLITE_Transitive 0x0200 /* Transitive constraints */
1004710053
#define SQLITE_AllOpts 0xffff /* All optimizations */
1004810054
1004910055
/*
1005010056
** Macros for testing whether or not optimizations are enabled or disabled.
1005110057
*/
@@ -10553,24 +10559,24 @@
1055310559
** and the value of Index.onError indicate the which conflict resolution
1055410560
** algorithm to employ whenever an attempt is made to insert a non-unique
1055510561
** element.
1055610562
*/
1055710563
struct Index {
10558
- char *zName; /* Name of this index */
10559
- int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10560
- tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
10561
- Table *pTable; /* The SQL table being indexed */
10562
- char *zColAff; /* String defining the affinity of each column */
10563
- Index *pNext; /* The next index associated with the same table */
10564
- Schema *pSchema; /* Schema containing this index */
10565
- u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
10566
- char **azColl; /* Array of collation sequence names for index */
10567
- int nColumn; /* Number of columns in the table used by this index */
10568
- int tnum; /* Page containing root of this index in database file */
10569
- u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10570
- u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
10571
- u8 bUnordered; /* Use this index for == or IN queries only */
10564
+ char *zName; /* Name of this index */
10565
+ int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10566
+ tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
10567
+ Table *pTable; /* The SQL table being indexed */
10568
+ char *zColAff; /* String defining the affinity of each column */
10569
+ Index *pNext; /* The next index associated with the same table */
10570
+ Schema *pSchema; /* Schema containing this index */
10571
+ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
10572
+ char **azColl; /* Array of collation sequence names for index */
10573
+ int tnum; /* DB Page containing root of this index */
10574
+ u16 nColumn; /* Number of columns in table used by this index */
10575
+ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10576
+ unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
10577
+ unsigned bUnordered:1; /* Use this index for == or IN queries only */
1057210578
#ifdef SQLITE_ENABLE_STAT3
1057310579
int nSample; /* Number of elements in aSample[] */
1057410580
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
1057510581
IndexSample *aSample; /* Samples of the left-most key */
1057610582
#endif
@@ -10840,22 +10846,31 @@
1084010846
** name. An expr/name combination can be used in several ways, such
1084110847
** as the list of "expr AS ID" fields following a "SELECT" or in the
1084210848
** list of "ID = expr" items in an UPDATE. A list of expressions can
1084310849
** also be used as the argument to a function, in which case the a.zName
1084410850
** field is not used.
10851
+**
10852
+** By default the Expr.zSpan field holds a human-readable description of
10853
+** the expression that is used in the generation of error messages and
10854
+** column labels. In this case, Expr.zSpan is typically the text of a
10855
+** column expression as it exists in a SELECT statement. However, if
10856
+** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
10857
+** of the result column in the form: DATABASE.TABLE.COLUMN. This later
10858
+** form is used for name resolution with nested FROM clauses.
1084510859
*/
1084610860
struct ExprList {
1084710861
int nExpr; /* Number of expressions on the list */
1084810862
int iECursor; /* VDBE Cursor associated with this ExprList */
1084910863
struct ExprList_item { /* For each expression in the list */
10850
- Expr *pExpr; /* The list of expressions */
10851
- char *zName; /* Token associated with this expression */
10852
- char *zSpan; /* Original text of the expression */
10853
- u8 sortOrder; /* 1 for DESC or 0 for ASC */
10854
- u8 done; /* A flag to indicate when processing is finished */
10855
- u16 iOrderByCol; /* For ORDER BY, column number in result set */
10856
- u16 iAlias; /* Index into Parse.aAlias[] for zName */
10864
+ Expr *pExpr; /* The list of expressions */
10865
+ char *zName; /* Token associated with this expression */
10866
+ char *zSpan; /* Original text of the expression */
10867
+ u8 sortOrder; /* 1 for DESC or 0 for ASC */
10868
+ unsigned done :1; /* A flag to indicate when processing is finished */
10869
+ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
10870
+ u16 iOrderByCol; /* For ORDER BY, column number in result set */
10871
+ u16 iAlias; /* Index into Parse.aAlias[] for zName */
1085710872
} *a; /* Alloc a power of two greater or equal to nExpr */
1085810873
};
1085910874
1086010875
/*
1086110876
** An instance of this structure is used by the parser to record both
@@ -12141,10 +12156,11 @@
1214112156
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
1214212157
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
1214312158
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
1214412159
SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
1214512160
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
12161
+SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
1214612162
SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
1214712163
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
1214812164
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
1214912165
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
1215012166
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
@@ -23289,15 +23305,11 @@
2328923305
{ "pwrite64", (sqlite3_syscall_ptr)0, 0 },
2329023306
#endif
2329123307
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
2329223308
aSyscall[13].pCurrent)
2329323309
23294
-#if SQLITE_ENABLE_LOCKING_STYLE
2329523310
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
23296
-#else
23297
- { "fchmod", (sqlite3_syscall_ptr)0, 0 },
23298
-#endif
2329923311
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
2330023312
2330123313
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
2330223314
{ "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
2330323315
#else
@@ -23318,13 +23330,10 @@
2331823330
#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
2331923331
2332023332
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
2332123333
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
2332223334
23323
- { "umask", (sqlite3_syscall_ptr)umask, 0 },
23324
-#define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
23325
-
2332623335
}; /* End of the overrideable system calls */
2332723336
2332823337
/*
2332923338
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
2333023339
** "unix" VFSes. Return SQLITE_OK opon successfully updating the
@@ -23425,31 +23434,29 @@
2342523434
** process that is able to write to the database will also be able to
2342623435
** recover the hot journals.
2342723436
*/
2342823437
static int robust_open(const char *z, int f, mode_t m){
2342923438
int fd;
23430
- mode_t m2;
23431
- mode_t origM = 0;
23432
- if( m==0 ){
23433
- m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
23434
- }else{
23435
- m2 = m;
23436
- origM = osUmask(0);
23437
- }
23439
+ mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
2343823440
do{
2343923441
#if defined(O_CLOEXEC)
2344023442
fd = osOpen(z,f|O_CLOEXEC,m2);
2344123443
#else
2344223444
fd = osOpen(z,f,m2);
2344323445
#endif
2344423446
}while( fd<0 && errno==EINTR );
23445
- if( m ){
23446
- osUmask(origM);
23447
- }
23447
+ if( fd>=0 ){
23448
+ if( m!=0 ){
23449
+ struct stat statbuf;
23450
+ if( osFstat(fd, &statbuf)==0 && (statbuf.st_mode&0777)!=m ){
23451
+ osFchmod(fd, m);
23452
+ }
23453
+ }
2344823454
#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23449
- if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
23455
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
2345023456
#endif
23457
+ }
2345123458
return fd;
2345223459
}
2345323460
2345423461
/*
2345523462
** Helper functions to obtain and relinquish the global mutex. The
@@ -29871,11 +29878,11 @@
2987129878
};
2987229879
unsigned int i; /* Loop counter */
2987329880
2987429881
/* Double-check that the aSyscall[] array has been constructed
2987529882
** correctly. See ticket [bb3a86e890c8e96ab] */
29876
- assert( ArraySize(aSyscall)==22 );
29883
+ assert( ArraySize(aSyscall)==21 );
2987729884
2987829885
/* Register all VFSes defined in the aVfs[] array */
2987929886
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
2988029887
sqlite3_vfs_register(&aVfs[i], i==0);
2988129888
}
@@ -72655,10 +72662,39 @@
7265572662
}
7265672663
}
7265772664
return 0;
7265872665
}
7265972666
72667
+/*
72668
+** Subqueries stores the original database, table and column names for their
72669
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
72670
+** Check to see if the zSpan given to this routine matches the zDb, zTab,
72671
+** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
72672
+** match anything.
72673
+*/
72674
+SQLITE_PRIVATE int sqlite3MatchSpanName(
72675
+ const char *zSpan,
72676
+ const char *zCol,
72677
+ const char *zTab,
72678
+ const char *zDb
72679
+){
72680
+ int n;
72681
+ for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72682
+ if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
72683
+ return 0;
72684
+ }
72685
+ zSpan += n+1;
72686
+ for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72687
+ if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
72688
+ return 0;
72689
+ }
72690
+ zSpan += n+1;
72691
+ if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
72692
+ return 0;
72693
+ }
72694
+ return 1;
72695
+}
7266072696
7266172697
/*
7266272698
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
7266372699
** that name in the set of source tables in pSrcList and make the pExpr
7266472700
** expression node refer back to that source column. The following changes
@@ -72710,44 +72746,63 @@
7271072746
7271172747
/* Initialize the node to no-match */
7271272748
pExpr->iTable = -1;
7271372749
pExpr->pTab = 0;
7271472750
ExprSetIrreducible(pExpr);
72751
+
72752
+ /* Translate the schema name in zDb into a pointer to the corresponding
72753
+ ** schema. If not found, pSchema will remain NULL and nothing will match
72754
+ ** resulting in an appropriate error message toward the end of this routine
72755
+ */
72756
+ if( zDb ){
72757
+ for(i=0; i<db->nDb; i++){
72758
+ assert( db->aDb[i].zName );
72759
+ if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
72760
+ pSchema = db->aDb[i].pSchema;
72761
+ break;
72762
+ }
72763
+ }
72764
+ }
7271572765
7271672766
/* Start at the inner-most context and move outward until a match is found */
7271772767
while( pNC && cnt==0 ){
7271872768
ExprList *pEList;
7271972769
SrcList *pSrcList = pNC->pSrcList;
7272072770
7272172771
if( pSrcList ){
7272272772
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
7272372773
Table *pTab;
72724
- int iDb;
7272572774
Column *pCol;
7272672775
7272772776
pTab = pItem->pTab;
7272872777
assert( pTab!=0 && pTab->zName!=0 );
72729
- iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
7273072778
assert( pTab->nCol>0 );
72779
+ if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
72780
+ ExprList *pEList = pItem->pSelect->pEList;
72781
+ int hit = 0;
72782
+ for(j=0; j<pEList->nExpr; j++){
72783
+ if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
72784
+ cnt++;
72785
+ cntTab = 2;
72786
+ pMatch = pItem;
72787
+ pExpr->iColumn = j;
72788
+ hit = 1;
72789
+ }
72790
+ }
72791
+ if( hit || zTab==0 ) continue;
72792
+ }
72793
+ if( zDb && pTab->pSchema!=pSchema ){
72794
+ continue;
72795
+ }
7273172796
if( zTab ){
72732
- if( pItem->zAlias ){
72733
- char *zTabName = pItem->zAlias;
72734
- if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
72735
- }else{
72736
- char *zTabName = pTab->zName;
72737
- if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
72738
- continue;
72739
- }
72740
- if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
72741
- continue;
72742
- }
72797
+ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
72798
+ assert( zTabName!=0 );
72799
+ if( sqlite3StrICmp(zTabName, zTab)!=0 ){
72800
+ continue;
7274372801
}
7274472802
}
7274572803
if( 0==(cntTab++) ){
72746
- pExpr->iTable = pItem->iCursor;
72747
- pExpr->pTab = pTab;
72748
- pSchema = pTab->pSchema;
7274972804
pMatch = pItem;
7275072805
}
7275172806
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
7275272807
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
7275372808
/* If there has been exactly one prior match and this match
@@ -72757,21 +72812,23 @@
7275772812
if( cnt==1 ){
7275872813
if( pItem->jointype & JT_NATURAL ) continue;
7275972814
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
7276072815
}
7276172816
cnt++;
72762
- pExpr->iTable = pItem->iCursor;
72763
- pExpr->pTab = pTab;
7276472817
pMatch = pItem;
72765
- pSchema = pTab->pSchema;
7276672818
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
7276772819
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
7276872820
break;
7276972821
}
7277072822
}
7277172823
}
72772
- }
72824
+ if( pMatch ){
72825
+ pExpr->iTable = pMatch->iCursor;
72826
+ pExpr->pTab = pMatch->pTab;
72827
+ pSchema = pExpr->pTab->pSchema;
72828
+ }
72829
+ } /* if( pSrcList ) */
7277372830
7277472831
#ifndef SQLITE_OMIT_TRIGGER
7277572832
/* If we have not already resolved the name, then maybe
7277672833
** it is a new.* or old.* trigger argument reference
7277772834
*/
@@ -73102,11 +73159,11 @@
7310273159
#endif
7310373160
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
7310473161
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
7310573162
pNC->nErr++;
7310673163
is_agg = 0;
73107
- }else if( no_such_func ){
73164
+ }else if( no_such_func && pParse->db->init.busy==0 ){
7310873165
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
7310973166
pNC->nErr++;
7311073167
}else if( wrong_num_args ){
7311173168
sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
7311273169
nId, zId);
@@ -77065,10 +77122,16 @@
7706577122
for(i=0; i<pList->nExpr; i++){
7706677123
sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
7706777124
sqlite3ExplainPush(pOut);
7706877125
sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
7706977126
sqlite3ExplainPop(pOut);
77127
+ if( pList->a[i].zName ){
77128
+ sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
77129
+ }
77130
+ if( pList->a[i].bSpanIsTab ){
77131
+ sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
77132
+ }
7707077133
if( i<pList->nExpr-1 ){
7707177134
sqlite3ExplainNL(pOut);
7707277135
}
7707377136
}
7707477137
sqlite3ExplainPop(pOut);
@@ -92739,13 +92802,15 @@
9273992802
if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
9274092803
Table *pTab;
9274192804
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9274292805
pTab = sqlite3FindTable(db, zRight, zDb);
9274392806
if( pTab ){
92744
- int i;
92807
+ int i, k;
9274592808
int nHidden = 0;
9274692809
Column *pCol;
92810
+ Index *pPk;
92811
+ for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
9274792812
sqlite3VdbeSetNumCols(v, 6);
9274892813
pParse->nMem = 6;
9274992814
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
9275092815
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
9275192816
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
@@ -92766,12 +92831,18 @@
9276692831
if( pCol->zDflt ){
9276792832
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
9276892833
}else{
9276992834
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
9277092835
}
92771
- sqlite3VdbeAddOp2(v, OP_Integer,
92772
- (pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6);
92836
+ if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
92837
+ k = 0;
92838
+ }else if( pPk==0 ){
92839
+ k = 1;
92840
+ }else{
92841
+ for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
92842
+ }
92843
+ sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
9277392844
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
9277492845
}
9277592846
}
9277692847
}else
9277792848
@@ -93516,11 +93587,11 @@
9351693587
sqlite3_rekey(db, zKey, i/2);
9351793588
}
9351893589
}else
9351993590
#endif
9352093591
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
93521
- if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
93592
+ if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){
9352293593
#ifdef SQLITE_HAS_CODEC
9352393594
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
9352493595
sqlite3_activate_see(&zRight[4]);
9352593596
}
9352693597
#endif
@@ -95756,12 +95827,10 @@
9575695827
9575795828
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
9575895829
/* Get an appropriate name for the column
9575995830
*/
9576095831
p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
95761
- assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
95762
- || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
9576395832
if( (zName = pEList->a[i].zName)!=0 ){
9576495833
/* If the column contains an "AS <name>" phrase, use <name> as the name */
9576595834
zName = sqlite3DbStrDup(db, zName);
9576695835
}else{
9576795836
Expr *pColExpr = p; /* The expression that is the result column name */
@@ -95795,10 +95864,13 @@
9579595864
*/
9579695865
nName = sqlite3Strlen30(zName);
9579795866
for(j=cnt=0; j<i; j++){
9579895867
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
9579995868
char *zNewName;
95869
+ int k;
95870
+ for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
95871
+ if( zName[k]==':' ) nName = k;
9580095872
zName[nName] = 0;
9580195873
zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
9580295874
sqlite3DbFree(db, zName);
9580395875
zName = zNewName;
9580495876
j = -1;
@@ -97711,10 +97783,11 @@
9771197783
int i, j, k;
9771297784
SrcList *pTabList;
9771397785
ExprList *pEList;
9771497786
struct SrcList_item *pFrom;
9771597787
sqlite3 *db = pParse->db;
97788
+ Expr *pE, *pRight, *pExpr;
9771697789
9771797790
if( db->mallocFailed ){
9771897791
return WRC_Abort;
9771997792
}
9772097793
if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
@@ -97796,11 +97869,11 @@
9779697869
**
9779797870
** The first loop just checks to see if there are any "*" operators
9779897871
** that need expanding.
9779997872
*/
9780097873
for(k=0; k<pEList->nExpr; k++){
97801
- Expr *pE = pEList->a[k].pExpr;
97874
+ pE = pEList->a[k].pExpr;
9780297875
if( pE->op==TK_ALL ) break;
9780397876
assert( pE->op!=TK_DOT || pE->pRight!=0 );
9780497877
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
9780597878
if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
9780697879
}
@@ -97814,14 +97887,22 @@
9781497887
ExprList *pNew = 0;
9781597888
int flags = pParse->db->flags;
9781697889
int longNames = (flags & SQLITE_FullColNames)!=0
9781797890
&& (flags & SQLITE_ShortColNames)==0;
9781897891
97892
+ /* When processing FROM-clause subqueries, it is always the case
97893
+ ** that full_column_names=OFF and short_column_names=ON. The
97894
+ ** sqlite3ResultSetOfSelect() routine makes it so. */
97895
+ assert( (p->selFlags & SF_NestedFrom)==0
97896
+ || ((flags & SQLITE_FullColNames)==0 &&
97897
+ (flags & SQLITE_ShortColNames)!=0) );
97898
+
9781997899
for(k=0; k<pEList->nExpr; k++){
97820
- Expr *pE = a[k].pExpr;
97821
- assert( pE->op!=TK_DOT || pE->pRight!=0 );
97822
- if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
97900
+ pE = a[k].pExpr;
97901
+ pRight = pE->pRight;
97902
+ assert( pE->op!=TK_DOT || pRight!=0 );
97903
+ if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
9782397904
/* This particular expression does not need to be expanded.
9782497905
*/
9782597906
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
9782697907
if( pNew ){
9782797908
pNew->a[pNew->nExpr-1].zName = a[k].zName;
@@ -97832,44 +97913,56 @@
9783297913
a[k].pExpr = 0;
9783397914
}else{
9783497915
/* This expression is a "*" or a "TABLE.*" and needs to be
9783597916
** expanded. */
9783697917
int tableSeen = 0; /* Set to 1 when TABLE matches */
97837
- char *zTName; /* text of name of TABLE */
97918
+ char *zTName = 0; /* text of name of TABLE */
9783897919
if( pE->op==TK_DOT ){
9783997920
assert( pE->pLeft!=0 );
9784097921
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
9784197922
zTName = pE->pLeft->u.zToken;
97842
- }else{
97843
- zTName = 0;
9784497923
}
9784597924
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
9784697925
Table *pTab = pFrom->pTab;
97926
+ Select *pSub = pFrom->pSelect;
9784797927
char *zTabName = pFrom->zAlias;
97928
+ const char *zSchemaName = 0;
97929
+ int iDb;
9784897930
if( zTabName==0 ){
9784997931
zTabName = pTab->zName;
9785097932
}
9785197933
if( db->mallocFailed ) break;
97852
- if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97853
- continue;
97934
+ if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
97935
+ pSub = 0;
97936
+ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97937
+ continue;
97938
+ }
97939
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
97940
+ zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
9785497941
}
97855
- tableSeen = 1;
9785697942
for(j=0; j<pTab->nCol; j++){
97857
- Expr *pExpr, *pRight;
9785897943
char *zName = pTab->aCol[j].zName;
9785997944
char *zColname; /* The computed column name */
9786097945
char *zToFree; /* Malloced string that needs to be freed */
9786197946
Token sColname; /* Computed column name as a token */
97947
+
97948
+ assert( zName );
97949
+ if( zTName && pSub
97950
+ && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
97951
+ ){
97952
+ continue;
97953
+ }
9786297954
9786397955
/* If a column is marked as 'hidden' (currently only possible
9786497956
** for virtual tables), do not include it in the expanded
9786597957
** result-set list.
9786697958
*/
9786797959
if( IsHiddenColumn(&pTab->aCol[j]) ){
9786897960
assert(IsVirtual(pTab));
9786997961
continue;
9787097962
}
97963
+ tableSeen = 1;
9787197964
9787297965
if( i>0 && zTName==0 ){
9787397966
if( (pFrom->jointype & JT_NATURAL)!=0
9787497967
&& tableAndColumnIndex(pTabList, i, zName, 0, 0)
9787597968
){
@@ -97888,10 +97981,14 @@
9788897981
zToFree = 0;
9788997982
if( longNames || pTabList->nSrc>1 ){
9789097983
Expr *pLeft;
9789197984
pLeft = sqlite3Expr(db, TK_ID, zTabName);
9789297985
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
97986
+ if( zSchemaName ){
97987
+ pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
97988
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
97989
+ }
9789397990
if( longNames ){
9789497991
zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
9789597992
zToFree = zColname;
9789697993
}
9789797994
}else{
@@ -97899,10 +97996,22 @@
9789997996
}
9790097997
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
9790197998
sColname.z = zColname;
9790297999
sColname.n = sqlite3Strlen30(zColname);
9790398000
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
98001
+ if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
98002
+ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
98003
+ if( pSub ){
98004
+ pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
98005
+ testcase( pX->zSpan==0 );
98006
+ }else{
98007
+ pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
98008
+ zSchemaName, zTabName, zColname);
98009
+ testcase( pX->zSpan==0 );
98010
+ }
98011
+ pX->bSpanIsTab = 1;
98012
+ }
9790498013
sqlite3DbFree(db, zToFree);
9790598014
}
9790698015
}
9790798016
if( !tableSeen ){
9790898017
if( zTName ){
@@ -102699,12 +102808,12 @@
102699102808
Expr *pExpr; /* Pointer to the subexpression that is this term */
102700102809
int iParent; /* Disable pWC->a[iParent] when this term disabled */
102701102810
int leftCursor; /* Cursor number of X in "X <op> <expr>" */
102702102811
union {
102703102812
int leftColumn; /* Column number of X in "X <op> <expr>" */
102704
- WhereOrInfo *pOrInfo; /* Extra information if eOperator==WO_OR */
102705
- WhereAndInfo *pAndInfo; /* Extra information if eOperator==WO_AND */
102813
+ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
102814
+ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
102706102815
} u;
102707102816
u16 eOperator; /* A WO_xx value describing <op> */
102708102817
u8 wtFlags; /* TERM_xxx bit flags. See below */
102709102818
u8 nChild; /* Number of children that must disable us */
102710102819
WhereClause *pWC; /* The clause this term is part of */
@@ -102828,10 +102937,11 @@
102828102937
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
102829102938
#define WO_MATCH 0x040
102830102939
#define WO_ISNULL 0x080
102831102940
#define WO_OR 0x100 /* Two or more OR-connected terms */
102832102941
#define WO_AND 0x200 /* Two or more AND-connected terms */
102942
+#define WO_EQUIV 0x400 /* Of the form A==B, both columns */
102833102943
#define WO_NOOP 0x800 /* This term does not restrict search space */
102834102944
102835102945
#define WO_ALL 0xfff /* Mask of all possible WO_* values */
102836102946
#define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
102837102947
@@ -103230,58 +103340,112 @@
103230103340
/*
103231103341
** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
103232103342
** where X is a reference to the iColumn of table iCur and <op> is one of
103233103343
** the WO_xx operator codes specified by the op parameter.
103234103344
** Return a pointer to the term. Return 0 if not found.
103345
+**
103346
+** The term returned might by Y=<expr> if there is another constraint in
103347
+** the WHERE clause that specifies that X=Y. Any such constraints will be
103348
+** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
103349
+** aEquiv[] array holds X and all its equivalents, with each SQL variable
103350
+** taking up two slots in aEquiv[]. The first slot is for the cursor number
103351
+** and the second is for the column number. There are 22 slots in aEquiv[]
103352
+** so that means we can look for X plus up to 10 other equivalent values.
103353
+** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3
103354
+** and ... and A9=A10 and A10=<expr>.
103355
+**
103356
+** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
103357
+** then try for the one with no dependencies on <expr> - in other words where
103358
+** <expr> is a constant expression of some kind. Only return entries of
103359
+** the form "X <op> Y" where Y is a column in another table if no terms of
103360
+** the form "X <op> <const-expr>" exist. Other than this priority, if there
103361
+** are two or more terms that match, then the choice of which term to return
103362
+** is arbitrary.
103235103363
*/
103236103364
static WhereTerm *findTerm(
103237103365
WhereClause *pWC, /* The WHERE clause to be searched */
103238103366
int iCur, /* Cursor number of LHS */
103239103367
int iColumn, /* Column number of LHS */
103240103368
Bitmask notReady, /* RHS must not overlap with this mask */
103241103369
u32 op, /* Mask of WO_xx values describing operator */
103242103370
Index *pIdx /* Must be compatible with this index, if not NULL */
103243103371
){
103244
- WhereTerm *pTerm;
103245
- int k;
103372
+ WhereTerm *pTerm; /* Term being examined as possible result */
103373
+ WhereTerm *pResult = 0; /* The answer to return */
103374
+ WhereClause *pWCOrig = pWC; /* Original pWC value */
103375
+ int j, k; /* Loop counters */
103376
+ Expr *pX; /* Pointer to an expression */
103377
+ Parse *pParse; /* Parsing context */
103378
+ int iOrigCol = iColumn; /* Original value of iColumn */
103379
+ int nEquiv = 2; /* Number of entires in aEquiv[] */
103380
+ int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */
103381
+ int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */
103382
+
103246103383
assert( iCur>=0 );
103247
- op &= WO_ALL;
103248
- for(; pWC; pWC=pWC->pOuter){
103249
- for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103250
- if( pTerm->leftCursor==iCur
103251
- && (pTerm->prereqRight & notReady)==0
103252
- && pTerm->u.leftColumn==iColumn
103253
- && (pTerm->eOperator & op)!=0
103254
- ){
103255
- if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
103256
- Expr *pX = pTerm->pExpr;
103257
- CollSeq *pColl;
103258
- char idxaff;
103259
- int j;
103260
- Parse *pParse = pWC->pParse;
103261
-
103262
- idxaff = pIdx->pTable->aCol[iColumn].affinity;
103263
- if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
103264
-
103265
- /* Figure out the collation sequence required from an index for
103266
- ** it to be useful for optimising expression pX. Store this
103267
- ** value in variable pColl.
103268
- */
103269
- assert(pX->pLeft);
103270
- pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
103271
- if( pColl==0 ) pColl = pParse->db->pDfltColl;
103272
-
103273
- for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
103274
- if( NEVER(j>=pIdx->nColumn) ) return 0;
103275
- }
103276
- if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
103277
- }
103278
- return pTerm;
103279
- }
103280
- }
103281
- }
103282
- return 0;
103384
+ aEquiv[0] = iCur;
103385
+ aEquiv[1] = iColumn;
103386
+ for(;;){
103387
+ for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){
103388
+ for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103389
+ if( pTerm->leftCursor==iCur
103390
+ && pTerm->u.leftColumn==iColumn
103391
+ ){
103392
+ if( (pTerm->prereqRight & notReady)==0
103393
+ && (pTerm->eOperator & op & WO_ALL)!=0
103394
+ ){
103395
+ if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){
103396
+ CollSeq *pColl;
103397
+ char idxaff;
103398
+
103399
+ pX = pTerm->pExpr;
103400
+ pParse = pWC->pParse;
103401
+ idxaff = pIdx->pTable->aCol[iOrigCol].affinity;
103402
+ if( !sqlite3IndexAffinityOk(pX, idxaff) ){
103403
+ continue;
103404
+ }
103405
+
103406
+ /* Figure out the collation sequence required from an index for
103407
+ ** it to be useful for optimising expression pX. Store this
103408
+ ** value in variable pColl.
103409
+ */
103410
+ assert(pX->pLeft);
103411
+ pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight);
103412
+ if( pColl==0 ) pColl = pParse->db->pDfltColl;
103413
+
103414
+ for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){
103415
+ if( NEVER(j>=pIdx->nColumn) ) return 0;
103416
+ }
103417
+ if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
103418
+ continue;
103419
+ }
103420
+ }
103421
+ pResult = pTerm;
103422
+ if( pTerm->prereqRight==0 ) goto findTerm_success;
103423
+ }
103424
+ if( (pTerm->eOperator & WO_EQUIV)!=0
103425
+ && nEquiv<ArraySize(aEquiv)
103426
+ ){
103427
+ pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
103428
+ assert( pX->op==TK_COLUMN );
103429
+ for(j=0; j<nEquiv; j+=2){
103430
+ if( aEquiv[j]==pX->iTable && aEquiv[j+1]==pX->iColumn ) break;
103431
+ }
103432
+ if( j==nEquiv ){
103433
+ aEquiv[j] = pX->iTable;
103434
+ aEquiv[j+1] = pX->iColumn;
103435
+ nEquiv += 2;
103436
+ }
103437
+ }
103438
+ }
103439
+ }
103440
+ }
103441
+ if( iEquiv>=nEquiv ) break;
103442
+ iCur = aEquiv[iEquiv++];
103443
+ iColumn = aEquiv[iEquiv++];
103444
+ }
103445
+findTerm_success:
103446
+ return pResult;
103283103447
}
103284103448
103285103449
/* Forward reference */
103286103450
static void exprAnalyze(SrcList*, WhereClause*, int);
103287103451
@@ -103555,11 +103719,10 @@
103555103719
indexable = ~(Bitmask)0;
103556103720
chngToIN = ~(pWC->vmask);
103557103721
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103558103722
if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103559103723
WhereAndInfo *pAndInfo;
103560
- assert( pOrTerm->eOperator==0 );
103561103724
assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103562103725
chngToIN = 0;
103563103726
pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
103564103727
if( pAndInfo ){
103565103728
WhereClause *pAndWC;
@@ -103594,11 +103757,11 @@
103594103757
if( pOrTerm->wtFlags & TERM_VIRTUAL ){
103595103758
WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent];
103596103759
b |= getMask(pMaskSet, pOther->leftCursor);
103597103760
}
103598103761
indexable &= b;
103599
- if( pOrTerm->eOperator!=WO_EQ ){
103762
+ if( (pOrTerm->eOperator & WO_EQ)==0 ){
103600103763
chngToIN = 0;
103601103764
}else{
103602103765
chngToIN &= b;
103603103766
}
103604103767
}
@@ -103645,11 +103808,11 @@
103645103808
** and column is found but leave okToChngToIN false if not found.
103646103809
*/
103647103810
for(j=0; j<2 && !okToChngToIN; j++){
103648103811
pOrTerm = pOrWc->a;
103649103812
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
103650
- assert( pOrTerm->eOperator==WO_EQ );
103813
+ assert( pOrTerm->eOperator & WO_EQ );
103651103814
pOrTerm->wtFlags &= ~TERM_OR_OK;
103652103815
if( pOrTerm->leftCursor==iCursor ){
103653103816
/* This is the 2-bit case and we are on the second iteration and
103654103817
** current term is from the first iteration. So skip this term. */
103655103818
assert( j==1 );
@@ -103671,21 +103834,21 @@
103671103834
}
103672103835
if( i<0 ){
103673103836
/* No candidate table+column was found. This can only occur
103674103837
** on the second iteration */
103675103838
assert( j==1 );
103676
- assert( (chngToIN&(chngToIN-1))==0 );
103839
+ assert( IsPowerOfTwo(chngToIN) );
103677103840
assert( chngToIN==getMask(pMaskSet, iCursor) );
103678103841
break;
103679103842
}
103680103843
testcase( j==1 );
103681103844
103682103845
/* We have found a candidate table and column. Check to see if that
103683103846
** table and column is common to every term in the OR clause */
103684103847
okToChngToIN = 1;
103685103848
for(; i>=0 && okToChngToIN; i--, pOrTerm++){
103686
- assert( pOrTerm->eOperator==WO_EQ );
103849
+ assert( pOrTerm->eOperator & WO_EQ );
103687103850
if( pOrTerm->leftCursor!=iCursor ){
103688103851
pOrTerm->wtFlags &= ~TERM_OR_OK;
103689103852
}else if( pOrTerm->u.leftColumn!=iColumn ){
103690103853
okToChngToIN = 0;
103691103854
}else{
@@ -103717,11 +103880,11 @@
103717103880
Expr *pLeft = 0; /* The LHS of the IN operator */
103718103881
Expr *pNew; /* The complete IN operator */
103719103882
103720103883
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
103721103884
if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
103722
- assert( pOrTerm->eOperator==WO_EQ );
103885
+ assert( pOrTerm->eOperator & WO_EQ );
103723103886
assert( pOrTerm->leftCursor==iCursor );
103724103887
assert( pOrTerm->u.leftColumn==iColumn );
103725103888
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
103726103889
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup);
103727103890
pLeft = pOrTerm->pExpr->pLeft;
@@ -103746,11 +103909,10 @@
103746103909
pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
103747103910
}
103748103911
}
103749103912
}
103750103913
#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
103751
-
103752103914
103753103915
/*
103754103916
** The input to this routine is an WhereTerm structure with only the
103755103917
** "pExpr" field filled in. The job of this routine is to analyze the
103756103918
** subexpression and populate all the other fields of the WhereTerm
@@ -103816,21 +103978,23 @@
103816103978
}
103817103979
pTerm->prereqAll = prereqAll;
103818103980
pTerm->leftCursor = -1;
103819103981
pTerm->iParent = -1;
103820103982
pTerm->eOperator = 0;
103821
- if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
103983
+ if( allowedOp(op) ){
103822103984
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
103823103985
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
103986
+ u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
103824103987
if( pLeft->op==TK_COLUMN ){
103825103988
pTerm->leftCursor = pLeft->iTable;
103826103989
pTerm->u.leftColumn = pLeft->iColumn;
103827
- pTerm->eOperator = operatorMask(op);
103990
+ pTerm->eOperator = operatorMask(op) & opMask;
103828103991
}
103829103992
if( pRight && pRight->op==TK_COLUMN ){
103830103993
WhereTerm *pNew;
103831103994
Expr *pDup;
103995
+ u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
103832103996
if( pTerm->leftCursor>=0 ){
103833103997
int idxNew;
103834103998
pDup = sqlite3ExprDup(db, pExpr, 0);
103835103999
if( db->mallocFailed ){
103836104000
sqlite3ExprDelete(db, pDup);
@@ -103841,10 +104005,17 @@
103841104005
pNew = &pWC->a[idxNew];
103842104006
pNew->iParent = idxTerm;
103843104007
pTerm = &pWC->a[idxTerm];
103844104008
pTerm->nChild = 1;
103845104009
pTerm->wtFlags |= TERM_COPIED;
104010
+ if( pExpr->op==TK_EQ
104011
+ && !ExprHasProperty(pExpr, EP_FromJoin)
104012
+ && OptimizationEnabled(db, SQLITE_Transitive)
104013
+ ){
104014
+ pTerm->eOperator |= WO_EQUIV;
104015
+ eExtraOp = WO_EQUIV;
104016
+ }
103846104017
}else{
103847104018
pDup = pExpr;
103848104019
pNew = pTerm;
103849104020
}
103850104021
exprCommute(pParse, pDup);
@@ -103852,11 +104023,11 @@
103852104023
pNew->leftCursor = pLeft->iTable;
103853104024
pNew->u.leftColumn = pLeft->iColumn;
103854104025
testcase( (prereqLeft | extraRight) != prereqLeft );
103855104026
pNew->prereqRight = prereqLeft | extraRight;
103856104027
pNew->prereqAll = prereqAll;
103857
- pNew->eOperator = operatorMask(pDup->op);
104028
+ pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
103858104029
}
103859104030
}
103860104031
103861104032
#ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION
103862104033
/* If a term is the BETWEEN operator, create two new virtual terms
@@ -104311,11 +104482,11 @@
104311104482
return;
104312104483
}
104313104484
104314104485
/* Search the WHERE clause terms for a usable WO_OR term. */
104315104486
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
104316
- if( pTerm->eOperator==WO_OR
104487
+ if( (pTerm->eOperator & WO_OR)!=0
104317104488
&& ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
104318104489
&& (pTerm->u.pOrInfo->indexable & maskSrc)!=0
104319104490
){
104320104491
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
104321104492
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
@@ -104332,11 +104503,11 @@
104332104503
sBOI.ppIdxInfo = 0;
104333104504
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
104334104505
WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
104335104506
(pOrTerm - pOrWC->a), (pTerm - pWC->a)
104336104507
));
104337
- if( pOrTerm->eOperator==WO_AND ){
104508
+ if( (pOrTerm->eOperator& WO_AND)!=0 ){
104338104509
sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
104339104510
bestIndex(&sBOI);
104340104511
}else if( pOrTerm->leftCursor==iCur ){
104341104512
WhereClause tempWC;
104342104513
tempWC.pParse = pWC->pParse;
@@ -104393,11 +104564,11 @@
104393104564
struct SrcList_item *pSrc, /* Table we are trying to access */
104394104565
Bitmask notReady /* Tables in outer loops of the join */
104395104566
){
104396104567
char aff;
104397104568
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
104398
- if( pTerm->eOperator!=WO_EQ ) return 0;
104569
+ if( (pTerm->eOperator & WO_EQ)==0 ) return 0;
104399104570
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
104400104571
aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
104401104572
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
104402104573
return 1;
104403104574
}
@@ -104655,13 +104826,13 @@
104655104826
104656104827
/* Count the number of possible WHERE clause constraints referring
104657104828
** to this virtual table */
104658104829
for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104659104830
if( pTerm->leftCursor != pSrc->iCursor ) continue;
104660
- assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104661
- testcase( pTerm->eOperator==WO_IN );
104662
- testcase( pTerm->eOperator==WO_ISNULL );
104831
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104832
+ testcase( pTerm->eOperator & WO_IN );
104833
+ testcase( pTerm->eOperator & WO_ISNULL );
104663104834
if( pTerm->eOperator & (WO_ISNULL) ) continue;
104664104835
if( pTerm->wtFlags & TERM_VNULL ) continue;
104665104836
nTerm++;
104666104837
}
104667104838
@@ -104708,18 +104879,18 @@
104708104879
pUsage;
104709104880
104710104881
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104711104882
u8 op;
104712104883
if( pTerm->leftCursor != pSrc->iCursor ) continue;
104713
- assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104714
- testcase( pTerm->eOperator==WO_IN );
104715
- testcase( pTerm->eOperator==WO_ISNULL );
104884
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104885
+ testcase( pTerm->eOperator & WO_IN );
104886
+ testcase( pTerm->eOperator & WO_ISNULL );
104716104887
if( pTerm->eOperator & (WO_ISNULL) ) continue;
104717104888
if( pTerm->wtFlags & TERM_VNULL ) continue;
104718104889
pIdxCons[j].iColumn = pTerm->u.leftColumn;
104719104890
pIdxCons[j].iTermOffset = i;
104720
- op = (u8)pTerm->eOperator;
104891
+ op = (u8)pTerm->eOperator & WO_ALL;
104721104892
if( op==WO_IN ) op = WO_EQ;
104722104893
pIdxCons[j].op = op;
104723104894
/* The direct assignment in the previous line is possible only because
104724104895
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
104725104896
** following asserts verify this fact. */
@@ -104885,11 +105056,11 @@
104885105056
pUsage = pIdxInfo->aConstraintUsage;
104886105057
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104887105058
j = pIdxCons->iTermOffset;
104888105059
pTerm = &pWC->a[j];
104889105060
if( (pTerm->prereqRight&p->notReady)==0
104890
- && (bAllowIN || pTerm->eOperator!=WO_IN)
105061
+ && (bAllowIN || (pTerm->eOperator & WO_IN)==0)
104891105062
){
104892105063
pIdxCons->usable = 1;
104893105064
}else{
104894105065
pIdxCons->usable = 0;
104895105066
}
@@ -104917,11 +105088,11 @@
104917105088
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104918105089
if( pUsage[i].argvIndex>0 ){
104919105090
j = pIdxCons->iTermOffset;
104920105091
pTerm = &pWC->a[j];
104921105092
p->cost.used |= pTerm->prereqRight;
104922
- if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){
105093
+ if( (pTerm->eOperator & WO_IN)!=0 && pUsage[i].omit==0 ){
104923105094
/* Do not attempt to use an IN constraint if the virtual table
104924105095
** says that the equivalent EQ constraint cannot be safely omitted.
104925105096
** If we do attempt to use such a constraint, some rows might be
104926105097
** repeated in the output. */
104927105098
break;
@@ -105223,28 +105394,28 @@
105223105394
u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
105224105395
105225105396
if( pLower ){
105226105397
Expr *pExpr = pLower->pExpr->pRight;
105227105398
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105228
- assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE );
105399
+ assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
105229105400
if( rc==SQLITE_OK
105230105401
&& whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
105231105402
){
105232105403
iLower = a[0];
105233
- if( pLower->eOperator==WO_GT ) iLower += a[1];
105404
+ if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
105234105405
}
105235105406
sqlite3ValueFree(pRangeVal);
105236105407
}
105237105408
if( rc==SQLITE_OK && pUpper ){
105238105409
Expr *pExpr = pUpper->pExpr->pRight;
105239105410
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105240
- assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE );
105411
+ assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
105241105412
if( rc==SQLITE_OK
105242105413
&& whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
105243105414
){
105244105415
iUpper = a[0];
105245
- if( pUpper->eOperator==WO_LE ) iUpper += a[1];
105416
+ if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
105246105417
}
105247105418
sqlite3ValueFree(pRangeVal);
105248105419
}
105249105420
if( rc==SQLITE_OK ){
105250105421
if( iUpper<=iLower ){
@@ -105548,16 +105719,16 @@
105548105719
** if there are any X= or X IS NULL constraints in the WHERE clause. */
105549105720
pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105550105721
WO_EQ|WO_ISNULL|WO_IN, pIdx);
105551105722
if( pConstraint==0 ){
105552105723
isEq = 0;
105553
- }else if( pConstraint->eOperator==WO_IN ){
105724
+ }else if( (pConstraint->eOperator & WO_IN)!=0 ){
105554105725
/* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105555105726
** because we do not know in what order the values on the RHS of the IN
105556105727
** operator will occur. */
105557105728
break;
105558
- }else if( pConstraint->eOperator==WO_ISNULL ){
105729
+ }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
105559105730
uniqueNotNull = 0;
105560105731
isEq = 1; /* "X IS NULL" means X has only a single value */
105561105732
}else if( pConstraint->prereqRight==0 ){
105562105733
isEq = 1; /* Constraint "X=constant" means X has only a single value */
105563105734
}else{
@@ -105903,11 +106074,11 @@
105903106074
int bRev = 2;
105904106075
WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
105905106076
pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
105906106077
WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
105907106078
bRev, pc.plan.nOBSat));
105908
- if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
106079
+ if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
105909106080
pc.plan.wsFlags |= WHERE_ORDERED;
105910106081
}
105911106082
if( nOrderBy==pc.plan.nOBSat ){
105912106083
bSort = 0;
105913106084
pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
@@ -105966,16 +106137,17 @@
105966106137
*/
105967106138
if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
105968106139
&& pFirstTerm!=0 && aiRowEst[1]>1 ){
105969106140
assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
105970106141
if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
105971
- testcase( pFirstTerm->eOperator==WO_EQ );
105972
- testcase( pFirstTerm->eOperator==WO_ISNULL );
106142
+ testcase( pFirstTerm->eOperator & WO_EQ );
106143
+ testcase( pFirstTerm->eOperator & WO_EQUIV );
106144
+ testcase( pFirstTerm->eOperator & WO_ISNULL );
105973106145
whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
105974106146
&pc.plan.nRow);
105975106147
}else if( bInEst==0 ){
105976
- assert( pFirstTerm->eOperator==WO_IN );
106148
+ assert( pFirstTerm->eOperator & WO_IN );
105977106149
whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
105978106150
&pc.plan.nRow);
105979106151
}
105980106152
}
105981106153
#endif /* SQLITE_ENABLE_STAT3 */
@@ -106118,11 +106290,11 @@
106118106290
** more selective intentionally because of the subjective
106119106291
** observation that indexed range constraints really are more
106120106292
** selective in practice, on average. */
106121106293
pc.plan.nRow /= 3;
106122106294
}
106123
- }else if( pTerm->eOperator!=WO_NOOP ){
106295
+ }else if( (pTerm->eOperator & WO_NOOP)==0 ){
106124106296
/* Any other expression lowers the output row count by half */
106125106297
pc.plan.nRow /= 2;
106126106298
}
106127106299
}
106128106300
if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
@@ -106170,12 +106342,13 @@
106170106342
assert( pSrc->pIndex==0
106171106343
|| p->cost.plan.u.pIdx==0
106172106344
|| p->cost.plan.u.pIdx==pSrc->pIndex
106173106345
);
106174106346
106175
- WHERETRACE((" best index is: %s\n",
106176
- p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
106347
+ WHERETRACE((" best index is %s cost=%.1f\n",
106348
+ p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk",
106349
+ p->cost.rCost));
106177106350
106178106351
bestOrClauseIndex(p);
106179106352
bestAutomaticIndex(p);
106180106353
p->cost.plan.wsFlags |= eqTermMask;
106181106354
}
@@ -106753,11 +106926,10 @@
106753106926
*/
106754106927
iReleaseReg = sqlite3GetTempReg(pParse);
106755106928
pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106756106929
assert( pTerm!=0 );
106757106930
assert( pTerm->pExpr!=0 );
106758
- assert( pTerm->leftCursor==iCur );
106759106931
assert( omitTable==0 );
106760106932
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106761106933
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
106762106934
addrNxt = pLevel->addrNxt;
106763106935
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
@@ -107144,11 +107316,11 @@
107144107316
int ii; /* Loop counter */
107145107317
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
107146107318
107147107319
pTerm = pLevel->plan.u.pTerm;
107148107320
assert( pTerm!=0 );
107149
- assert( pTerm->eOperator==WO_OR );
107321
+ assert( pTerm->eOperator & WO_OR );
107150107322
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
107151107323
pOrWc = &pTerm->u.pOrInfo->wc;
107152107324
pLevel->op = OP_Return;
107153107325
pLevel->p1 = regReturn;
107154107326
@@ -107217,11 +107389,11 @@
107217107389
}
107218107390
}
107219107391
107220107392
for(ii=0; ii<pOrWc->nTerm; ii++){
107221107393
WhereTerm *pOrTerm = &pOrWc->a[ii];
107222
- if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
107394
+ if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
107223107395
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
107224107396
Expr *pOrExpr = pOrTerm->pExpr;
107225107397
if( pAndExpr ){
107226107398
pAndExpr->pLeft = pOrExpr;
107227107399
pOrExpr = pAndExpr;
@@ -107672,10 +107844,11 @@
107672107844
Index *pIdx; /* Index for FROM table at pTabItem */
107673107845
int j; /* For looping over FROM tables */
107674107846
int bestJ = -1; /* The value of j */
107675107847
Bitmask m; /* Bitmask value for j or bestJ */
107676107848
int isOptimal; /* Iterator for optimal/non-optimal search */
107849
+ int ckOptimal; /* Do the optimal scan check */
107677107850
int nUnconstrained; /* Number tables without INDEXED BY */
107678107851
Bitmask notIndexed; /* Mask of tables that cannot use an index */
107679107852
107680107853
memset(&bestPlan, 0, sizeof(bestPlan));
107681107854
bestPlan.rCost = SQLITE_BIG_DBL;
@@ -107706,14 +107879,12 @@
107706107879
**
107707107880
** The second loop iteration is only performed if no optimal scan
107708107881
** strategies were found by the first iteration. This second iteration
107709107882
** is used to search for the lowest cost scan overall.
107710107883
**
107711
- ** Previous versions of SQLite performed only the second iteration -
107712
- ** the next outermost loop was always that with the lowest overall
107713
- ** cost. However, this meant that SQLite could select the wrong plan
107714
- ** for scripts such as the following:
107884
+ ** Without the optimal scan step (the first iteration) a suboptimal
107885
+ ** plan might be chosen for queries like this:
107715107886
**
107716107887
** CREATE TABLE t1(a, b);
107717107888
** CREATE TABLE t2(c, d);
107718107889
** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a;
107719107890
**
@@ -107724,20 +107895,44 @@
107724107895
** algorithm may choose to use t2 for the outer loop, which is a much
107725107896
** costlier approach.
107726107897
*/
107727107898
nUnconstrained = 0;
107728107899
notIndexed = 0;
107729
- for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
107900
+
107901
+ /* The optimal scan check only occurs if there are two or more tables
107902
+ ** available to be reordered */
107903
+ if( iFrom==nTabList-1 ){
107904
+ ckOptimal = 0; /* Common case of just one table in the FROM clause */
107905
+ }else{
107906
+ ckOptimal = -1;
107730107907
for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107731
- int doNotReorder; /* True if this table should not be reordered */
107732
-
107733
- doNotReorder = (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0;
107734
- if( j!=iFrom && doNotReorder ) break;
107735107908
m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107736107909
if( (m & sWBI.notValid)==0 ){
107737107910
if( j==iFrom ) iFrom++;
107738107911
continue;
107912
+ }
107913
+ if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break;
107914
+ if( ++ckOptimal ) break;
107915
+ if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
107916
+ }
107917
+ }
107918
+ assert( ckOptimal==0 || ckOptimal==1 );
107919
+
107920
+ for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){
107921
+ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107922
+ if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){
107923
+ /* This break and one like it in the ckOptimal computation loop
107924
+ ** above prevent table reordering across LEFT and CROSS JOINs.
107925
+ ** The LEFT JOIN case is necessary for correctness. The prohibition
107926
+ ** against reordering across a CROSS JOIN is an SQLite feature that
107927
+ ** allows the developer to control table reordering */
107928
+ break;
107929
+ }
107930
+ m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107931
+ if( (m & sWBI.notValid)==0 ){
107932
+ assert( j>iFrom );
107933
+ continue;
107739107934
}
107740107935
sWBI.notReady = (isOptimal ? m : sWBI.notValid);
107741107936
if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
107742107937
107743107938
WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
@@ -107763,12 +107958,12 @@
107763107958
if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
107764107959
notIndexed |= m;
107765107960
}
107766107961
if( isOptimal ){
107767107962
pWInfo->a[j].rOptCost = sWBI.cost.rCost;
107768
- }else if( iFrom<nTabList-1 ){
107769
- /* If two or more tables have nearly the same outer loop cost,
107963
+ }else if( ckOptimal ){
107964
+ /* If two or more tables have nearly the same outer loop cost, but
107770107965
** very different inner loop (optimal) cost, we want to choose
107771107966
** for the outer loop that table which benefits the least from
107772107967
** being in the inner loop. The following code scales the
107773107968
** outer loop cost estimate to accomplish that. */
107774107969
WHERETRACE((" scaling cost from %.1f to %.1f\n",
@@ -107809,15 +108004,23 @@
107809108004
sWBI.cost.rCost, sWBI.cost.plan.nRow,
107810108005
sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
107811108006
bestPlan = sWBI.cost;
107812108007
bestJ = j;
107813108008
}
107814
- if( doNotReorder ) break;
108009
+
108010
+ /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that
108011
+ ** table y (and not table z) is always the next inner loop inside
108012
+ ** of table x. */
108013
+ if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
107815108014
}
107816108015
}
107817108016
assert( bestJ>=0 );
107818108017
assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
108018
+ assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 );
108019
+ testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 );
108020
+ testcase( bestJ>iFrom && bestJ<nTabList-1
108021
+ && (pTabList->a[bestJ+1].jointype & JT_LEFT)!=0 );
107819108022
WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
107820108023
" cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
107821108024
bestJ, pTabList->a[bestJ].pTab->zName,
107822108025
pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
107823108026
bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
@@ -136543,11 +136746,12 @@
136543136746
** would fit in a single node, use a smaller node-size.
136544136747
*/
136545136748
static int getNodeSize(
136546136749
sqlite3 *db, /* Database handle */
136547136750
Rtree *pRtree, /* Rtree handle */
136548
- int isCreate /* True for xCreate, false for xConnect */
136751
+ int isCreate, /* True for xCreate, false for xConnect */
136752
+ char **pzErr /* OUT: Error message, if any */
136549136753
){
136550136754
int rc;
136551136755
char *zSql;
136552136756
if( isCreate ){
136553136757
int iPageSize = 0;
@@ -136556,17 +136760,22 @@
136556136760
if( rc==SQLITE_OK ){
136557136761
pRtree->iNodeSize = iPageSize-64;
136558136762
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
136559136763
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
136560136764
}
136765
+ }else{
136766
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136561136767
}
136562136768
}else{
136563136769
zSql = sqlite3_mprintf(
136564136770
"SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
136565136771
pRtree->zDb, pRtree->zName
136566136772
);
136567136773
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
136774
+ if( rc!=SQLITE_OK ){
136775
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136776
+ }
136568136777
}
136569136778
136570136779
sqlite3_free(zSql);
136571136780
return rc;
136572136781
}
@@ -136626,11 +136835,11 @@
136626136835
pRtree->eCoordType = eCoordType;
136627136836
memcpy(pRtree->zDb, argv[1], nDb);
136628136837
memcpy(pRtree->zName, argv[2], nName);
136629136838
136630136839
/* Figure out the node size to use. */
136631
- rc = getNodeSize(db, pRtree, isCreate);
136840
+ rc = getNodeSize(db, pRtree, isCreate, pzErr);
136632136841
136633136842
/* Create/Connect to the underlying relational database schema. If
136634136843
** that is successful, call sqlite3_declare_vtab() to configure
136635136844
** the r-tree table schema.
136636136845
*/
136637136846
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674 ** [sqlite_version()] and [sqlite_source_id()].
675 */
676 #define SQLITE_VERSION "3.7.16"
677 #define SQLITE_VERSION_NUMBER 3007016
678 #define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
679
680 /*
681 ** CAPI3REF: Run-Time Library Version Numbers
682 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
683 **
@@ -8238,10 +8238,15 @@
8238 ** A convenience macro that returns the number of elements in
8239 ** an array.
8240 */
8241 #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
8242
 
 
 
 
 
8243 /*
8244 ** The following value as a destructor means to use sqlite3DbFree().
8245 ** The sqlite3DbFree() routine requires two parameters instead of the
8246 ** one parameter that destructors normally want. So we have to introduce
8247 ** this magic value that the code knows to handle differently. Any
@@ -10042,10 +10047,11 @@
10042 #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
10043 #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
10044 #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
10045 #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
10046 #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
 
10047 #define SQLITE_AllOpts 0xffff /* All optimizations */
10048
10049 /*
10050 ** Macros for testing whether or not optimizations are enabled or disabled.
10051 */
@@ -10553,24 +10559,24 @@
10553 ** and the value of Index.onError indicate the which conflict resolution
10554 ** algorithm to employ whenever an attempt is made to insert a non-unique
10555 ** element.
10556 */
10557 struct Index {
10558 char *zName; /* Name of this index */
10559 int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10560 tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
10561 Table *pTable; /* The SQL table being indexed */
10562 char *zColAff; /* String defining the affinity of each column */
10563 Index *pNext; /* The next index associated with the same table */
10564 Schema *pSchema; /* Schema containing this index */
10565 u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
10566 char **azColl; /* Array of collation sequence names for index */
10567 int nColumn; /* Number of columns in the table used by this index */
10568 int tnum; /* Page containing root of this index in database file */
10569 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10570 u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
10571 u8 bUnordered; /* Use this index for == or IN queries only */
10572 #ifdef SQLITE_ENABLE_STAT3
10573 int nSample; /* Number of elements in aSample[] */
10574 tRowcnt avgEq; /* Average nEq value for key values not in aSample */
10575 IndexSample *aSample; /* Samples of the left-most key */
10576 #endif
@@ -10840,22 +10846,31 @@
10840 ** name. An expr/name combination can be used in several ways, such
10841 ** as the list of "expr AS ID" fields following a "SELECT" or in the
10842 ** list of "ID = expr" items in an UPDATE. A list of expressions can
10843 ** also be used as the argument to a function, in which case the a.zName
10844 ** field is not used.
 
 
 
 
 
 
 
 
10845 */
10846 struct ExprList {
10847 int nExpr; /* Number of expressions on the list */
10848 int iECursor; /* VDBE Cursor associated with this ExprList */
10849 struct ExprList_item { /* For each expression in the list */
10850 Expr *pExpr; /* The list of expressions */
10851 char *zName; /* Token associated with this expression */
10852 char *zSpan; /* Original text of the expression */
10853 u8 sortOrder; /* 1 for DESC or 0 for ASC */
10854 u8 done; /* A flag to indicate when processing is finished */
10855 u16 iOrderByCol; /* For ORDER BY, column number in result set */
10856 u16 iAlias; /* Index into Parse.aAlias[] for zName */
 
10857 } *a; /* Alloc a power of two greater or equal to nExpr */
10858 };
10859
10860 /*
10861 ** An instance of this structure is used by the parser to record both
@@ -12141,10 +12156,11 @@
12141 SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
12142 SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
12143 SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
12144 SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
12145 SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
 
12146 SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
12147 SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
12148 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12149 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12150 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
@@ -23289,15 +23305,11 @@
23289 { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
23290 #endif
23291 #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
23292 aSyscall[13].pCurrent)
23293
23294 #if SQLITE_ENABLE_LOCKING_STYLE
23295 { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
23296 #else
23297 { "fchmod", (sqlite3_syscall_ptr)0, 0 },
23298 #endif
23299 #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
23300
23301 #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
23302 { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
23303 #else
@@ -23318,13 +23330,10 @@
23318 #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
23319
23320 { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
23321 #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
23322
23323 { "umask", (sqlite3_syscall_ptr)umask, 0 },
23324 #define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
23325
23326 }; /* End of the overrideable system calls */
23327
23328 /*
23329 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
23330 ** "unix" VFSes. Return SQLITE_OK opon successfully updating the
@@ -23425,31 +23434,29 @@
23425 ** process that is able to write to the database will also be able to
23426 ** recover the hot journals.
23427 */
23428 static int robust_open(const char *z, int f, mode_t m){
23429 int fd;
23430 mode_t m2;
23431 mode_t origM = 0;
23432 if( m==0 ){
23433 m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
23434 }else{
23435 m2 = m;
23436 origM = osUmask(0);
23437 }
23438 do{
23439 #if defined(O_CLOEXEC)
23440 fd = osOpen(z,f|O_CLOEXEC,m2);
23441 #else
23442 fd = osOpen(z,f,m2);
23443 #endif
23444 }while( fd<0 && errno==EINTR );
23445 if( m ){
23446 osUmask(origM);
23447 }
 
 
 
 
23448 #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23449 if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
23450 #endif
 
23451 return fd;
23452 }
23453
23454 /*
23455 ** Helper functions to obtain and relinquish the global mutex. The
@@ -29871,11 +29878,11 @@
29871 };
29872 unsigned int i; /* Loop counter */
29873
29874 /* Double-check that the aSyscall[] array has been constructed
29875 ** correctly. See ticket [bb3a86e890c8e96ab] */
29876 assert( ArraySize(aSyscall)==22 );
29877
29878 /* Register all VFSes defined in the aVfs[] array */
29879 for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
29880 sqlite3_vfs_register(&aVfs[i], i==0);
29881 }
@@ -72655,10 +72662,39 @@
72655 }
72656 }
72657 return 0;
72658 }
72659
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72660
72661 /*
72662 ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
72663 ** that name in the set of source tables in pSrcList and make the pExpr
72664 ** expression node refer back to that source column. The following changes
@@ -72710,44 +72746,63 @@
72710
72711 /* Initialize the node to no-match */
72712 pExpr->iTable = -1;
72713 pExpr->pTab = 0;
72714 ExprSetIrreducible(pExpr);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72715
72716 /* Start at the inner-most context and move outward until a match is found */
72717 while( pNC && cnt==0 ){
72718 ExprList *pEList;
72719 SrcList *pSrcList = pNC->pSrcList;
72720
72721 if( pSrcList ){
72722 for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
72723 Table *pTab;
72724 int iDb;
72725 Column *pCol;
72726
72727 pTab = pItem->pTab;
72728 assert( pTab!=0 && pTab->zName!=0 );
72729 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
72730 assert( pTab->nCol>0 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72731 if( zTab ){
72732 if( pItem->zAlias ){
72733 char *zTabName = pItem->zAlias;
72734 if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
72735 }else{
72736 char *zTabName = pTab->zName;
72737 if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
72738 continue;
72739 }
72740 if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
72741 continue;
72742 }
72743 }
72744 }
72745 if( 0==(cntTab++) ){
72746 pExpr->iTable = pItem->iCursor;
72747 pExpr->pTab = pTab;
72748 pSchema = pTab->pSchema;
72749 pMatch = pItem;
72750 }
72751 for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
72752 if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
72753 /* If there has been exactly one prior match and this match
@@ -72757,21 +72812,23 @@
72757 if( cnt==1 ){
72758 if( pItem->jointype & JT_NATURAL ) continue;
72759 if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
72760 }
72761 cnt++;
72762 pExpr->iTable = pItem->iCursor;
72763 pExpr->pTab = pTab;
72764 pMatch = pItem;
72765 pSchema = pTab->pSchema;
72766 /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
72767 pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
72768 break;
72769 }
72770 }
72771 }
72772 }
 
 
 
 
 
72773
72774 #ifndef SQLITE_OMIT_TRIGGER
72775 /* If we have not already resolved the name, then maybe
72776 ** it is a new.* or old.* trigger argument reference
72777 */
@@ -73102,11 +73159,11 @@
73102 #endif
73103 if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
73104 sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
73105 pNC->nErr++;
73106 is_agg = 0;
73107 }else if( no_such_func ){
73108 sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
73109 pNC->nErr++;
73110 }else if( wrong_num_args ){
73111 sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
73112 nId, zId);
@@ -77065,10 +77122,16 @@
77065 for(i=0; i<pList->nExpr; i++){
77066 sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
77067 sqlite3ExplainPush(pOut);
77068 sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
77069 sqlite3ExplainPop(pOut);
 
 
 
 
 
 
77070 if( i<pList->nExpr-1 ){
77071 sqlite3ExplainNL(pOut);
77072 }
77073 }
77074 sqlite3ExplainPop(pOut);
@@ -92739,13 +92802,15 @@
92739 if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
92740 Table *pTab;
92741 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
92742 pTab = sqlite3FindTable(db, zRight, zDb);
92743 if( pTab ){
92744 int i;
92745 int nHidden = 0;
92746 Column *pCol;
 
 
92747 sqlite3VdbeSetNumCols(v, 6);
92748 pParse->nMem = 6;
92749 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
92750 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
92751 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
@@ -92766,12 +92831,18 @@
92766 if( pCol->zDflt ){
92767 sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
92768 }else{
92769 sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
92770 }
92771 sqlite3VdbeAddOp2(v, OP_Integer,
92772 (pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6);
 
 
 
 
 
 
92773 sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
92774 }
92775 }
92776 }else
92777
@@ -93516,11 +93587,11 @@
93516 sqlite3_rekey(db, zKey, i/2);
93517 }
93518 }else
93519 #endif
93520 #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
93521 if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
93522 #ifdef SQLITE_HAS_CODEC
93523 if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
93524 sqlite3_activate_see(&zRight[4]);
93525 }
93526 #endif
@@ -95756,12 +95827,10 @@
95756
95757 for(i=0, pCol=aCol; i<nCol; i++, pCol++){
95758 /* Get an appropriate name for the column
95759 */
95760 p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
95761 assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
95762 || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
95763 if( (zName = pEList->a[i].zName)!=0 ){
95764 /* If the column contains an "AS <name>" phrase, use <name> as the name */
95765 zName = sqlite3DbStrDup(db, zName);
95766 }else{
95767 Expr *pColExpr = p; /* The expression that is the result column name */
@@ -95795,10 +95864,13 @@
95795 */
95796 nName = sqlite3Strlen30(zName);
95797 for(j=cnt=0; j<i; j++){
95798 if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
95799 char *zNewName;
 
 
 
95800 zName[nName] = 0;
95801 zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
95802 sqlite3DbFree(db, zName);
95803 zName = zNewName;
95804 j = -1;
@@ -97711,10 +97783,11 @@
97711 int i, j, k;
97712 SrcList *pTabList;
97713 ExprList *pEList;
97714 struct SrcList_item *pFrom;
97715 sqlite3 *db = pParse->db;
 
97716
97717 if( db->mallocFailed ){
97718 return WRC_Abort;
97719 }
97720 if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
@@ -97796,11 +97869,11 @@
97796 **
97797 ** The first loop just checks to see if there are any "*" operators
97798 ** that need expanding.
97799 */
97800 for(k=0; k<pEList->nExpr; k++){
97801 Expr *pE = pEList->a[k].pExpr;
97802 if( pE->op==TK_ALL ) break;
97803 assert( pE->op!=TK_DOT || pE->pRight!=0 );
97804 assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
97805 if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
97806 }
@@ -97814,14 +97887,22 @@
97814 ExprList *pNew = 0;
97815 int flags = pParse->db->flags;
97816 int longNames = (flags & SQLITE_FullColNames)!=0
97817 && (flags & SQLITE_ShortColNames)==0;
97818
 
 
 
 
 
 
 
97819 for(k=0; k<pEList->nExpr; k++){
97820 Expr *pE = a[k].pExpr;
97821 assert( pE->op!=TK_DOT || pE->pRight!=0 );
97822 if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
 
97823 /* This particular expression does not need to be expanded.
97824 */
97825 pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
97826 if( pNew ){
97827 pNew->a[pNew->nExpr-1].zName = a[k].zName;
@@ -97832,44 +97913,56 @@
97832 a[k].pExpr = 0;
97833 }else{
97834 /* This expression is a "*" or a "TABLE.*" and needs to be
97835 ** expanded. */
97836 int tableSeen = 0; /* Set to 1 when TABLE matches */
97837 char *zTName; /* text of name of TABLE */
97838 if( pE->op==TK_DOT ){
97839 assert( pE->pLeft!=0 );
97840 assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
97841 zTName = pE->pLeft->u.zToken;
97842 }else{
97843 zTName = 0;
97844 }
97845 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
97846 Table *pTab = pFrom->pTab;
 
97847 char *zTabName = pFrom->zAlias;
 
 
97848 if( zTabName==0 ){
97849 zTabName = pTab->zName;
97850 }
97851 if( db->mallocFailed ) break;
97852 if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97853 continue;
 
 
 
 
 
97854 }
97855 tableSeen = 1;
97856 for(j=0; j<pTab->nCol; j++){
97857 Expr *pExpr, *pRight;
97858 char *zName = pTab->aCol[j].zName;
97859 char *zColname; /* The computed column name */
97860 char *zToFree; /* Malloced string that needs to be freed */
97861 Token sColname; /* Computed column name as a token */
 
 
 
 
 
 
 
97862
97863 /* If a column is marked as 'hidden' (currently only possible
97864 ** for virtual tables), do not include it in the expanded
97865 ** result-set list.
97866 */
97867 if( IsHiddenColumn(&pTab->aCol[j]) ){
97868 assert(IsVirtual(pTab));
97869 continue;
97870 }
 
97871
97872 if( i>0 && zTName==0 ){
97873 if( (pFrom->jointype & JT_NATURAL)!=0
97874 && tableAndColumnIndex(pTabList, i, zName, 0, 0)
97875 ){
@@ -97888,10 +97981,14 @@
97888 zToFree = 0;
97889 if( longNames || pTabList->nSrc>1 ){
97890 Expr *pLeft;
97891 pLeft = sqlite3Expr(db, TK_ID, zTabName);
97892 pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
 
 
 
 
97893 if( longNames ){
97894 zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
97895 zToFree = zColname;
97896 }
97897 }else{
@@ -97899,10 +97996,22 @@
97899 }
97900 pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
97901 sColname.z = zColname;
97902 sColname.n = sqlite3Strlen30(zColname);
97903 sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
 
 
 
 
 
 
 
 
 
 
 
 
97904 sqlite3DbFree(db, zToFree);
97905 }
97906 }
97907 if( !tableSeen ){
97908 if( zTName ){
@@ -102699,12 +102808,12 @@
102699 Expr *pExpr; /* Pointer to the subexpression that is this term */
102700 int iParent; /* Disable pWC->a[iParent] when this term disabled */
102701 int leftCursor; /* Cursor number of X in "X <op> <expr>" */
102702 union {
102703 int leftColumn; /* Column number of X in "X <op> <expr>" */
102704 WhereOrInfo *pOrInfo; /* Extra information if eOperator==WO_OR */
102705 WhereAndInfo *pAndInfo; /* Extra information if eOperator==WO_AND */
102706 } u;
102707 u16 eOperator; /* A WO_xx value describing <op> */
102708 u8 wtFlags; /* TERM_xxx bit flags. See below */
102709 u8 nChild; /* Number of children that must disable us */
102710 WhereClause *pWC; /* The clause this term is part of */
@@ -102828,10 +102937,11 @@
102828 #define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
102829 #define WO_MATCH 0x040
102830 #define WO_ISNULL 0x080
102831 #define WO_OR 0x100 /* Two or more OR-connected terms */
102832 #define WO_AND 0x200 /* Two or more AND-connected terms */
 
102833 #define WO_NOOP 0x800 /* This term does not restrict search space */
102834
102835 #define WO_ALL 0xfff /* Mask of all possible WO_* values */
102836 #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
102837
@@ -103230,58 +103340,112 @@
103230 /*
103231 ** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
103232 ** where X is a reference to the iColumn of table iCur and <op> is one of
103233 ** the WO_xx operator codes specified by the op parameter.
103234 ** Return a pointer to the term. Return 0 if not found.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103235 */
103236 static WhereTerm *findTerm(
103237 WhereClause *pWC, /* The WHERE clause to be searched */
103238 int iCur, /* Cursor number of LHS */
103239 int iColumn, /* Column number of LHS */
103240 Bitmask notReady, /* RHS must not overlap with this mask */
103241 u32 op, /* Mask of WO_xx values describing operator */
103242 Index *pIdx /* Must be compatible with this index, if not NULL */
103243 ){
103244 WhereTerm *pTerm;
103245 int k;
 
 
 
 
 
 
 
 
 
103246 assert( iCur>=0 );
103247 op &= WO_ALL;
103248 for(; pWC; pWC=pWC->pOuter){
103249 for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103250 if( pTerm->leftCursor==iCur
103251 && (pTerm->prereqRight & notReady)==0
103252 && pTerm->u.leftColumn==iColumn
103253 && (pTerm->eOperator & op)!=0
103254 ){
103255 if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
103256 Expr *pX = pTerm->pExpr;
103257 CollSeq *pColl;
103258 char idxaff;
103259 int j;
103260 Parse *pParse = pWC->pParse;
103261
103262 idxaff = pIdx->pTable->aCol[iColumn].affinity;
103263 if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
103264
103265 /* Figure out the collation sequence required from an index for
103266 ** it to be useful for optimising expression pX. Store this
103267 ** value in variable pColl.
103268 */
103269 assert(pX->pLeft);
103270 pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
103271 if( pColl==0 ) pColl = pParse->db->pDfltColl;
103272
103273 for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
103274 if( NEVER(j>=pIdx->nColumn) ) return 0;
103275 }
103276 if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
103277 }
103278 return pTerm;
103279 }
103280 }
103281 }
103282 return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103283 }
103284
103285 /* Forward reference */
103286 static void exprAnalyze(SrcList*, WhereClause*, int);
103287
@@ -103555,11 +103719,10 @@
103555 indexable = ~(Bitmask)0;
103556 chngToIN = ~(pWC->vmask);
103557 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103558 if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103559 WhereAndInfo *pAndInfo;
103560 assert( pOrTerm->eOperator==0 );
103561 assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103562 chngToIN = 0;
103563 pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
103564 if( pAndInfo ){
103565 WhereClause *pAndWC;
@@ -103594,11 +103757,11 @@
103594 if( pOrTerm->wtFlags & TERM_VIRTUAL ){
103595 WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent];
103596 b |= getMask(pMaskSet, pOther->leftCursor);
103597 }
103598 indexable &= b;
103599 if( pOrTerm->eOperator!=WO_EQ ){
103600 chngToIN = 0;
103601 }else{
103602 chngToIN &= b;
103603 }
103604 }
@@ -103645,11 +103808,11 @@
103645 ** and column is found but leave okToChngToIN false if not found.
103646 */
103647 for(j=0; j<2 && !okToChngToIN; j++){
103648 pOrTerm = pOrWc->a;
103649 for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
103650 assert( pOrTerm->eOperator==WO_EQ );
103651 pOrTerm->wtFlags &= ~TERM_OR_OK;
103652 if( pOrTerm->leftCursor==iCursor ){
103653 /* This is the 2-bit case and we are on the second iteration and
103654 ** current term is from the first iteration. So skip this term. */
103655 assert( j==1 );
@@ -103671,21 +103834,21 @@
103671 }
103672 if( i<0 ){
103673 /* No candidate table+column was found. This can only occur
103674 ** on the second iteration */
103675 assert( j==1 );
103676 assert( (chngToIN&(chngToIN-1))==0 );
103677 assert( chngToIN==getMask(pMaskSet, iCursor) );
103678 break;
103679 }
103680 testcase( j==1 );
103681
103682 /* We have found a candidate table and column. Check to see if that
103683 ** table and column is common to every term in the OR clause */
103684 okToChngToIN = 1;
103685 for(; i>=0 && okToChngToIN; i--, pOrTerm++){
103686 assert( pOrTerm->eOperator==WO_EQ );
103687 if( pOrTerm->leftCursor!=iCursor ){
103688 pOrTerm->wtFlags &= ~TERM_OR_OK;
103689 }else if( pOrTerm->u.leftColumn!=iColumn ){
103690 okToChngToIN = 0;
103691 }else{
@@ -103717,11 +103880,11 @@
103717 Expr *pLeft = 0; /* The LHS of the IN operator */
103718 Expr *pNew; /* The complete IN operator */
103719
103720 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
103721 if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
103722 assert( pOrTerm->eOperator==WO_EQ );
103723 assert( pOrTerm->leftCursor==iCursor );
103724 assert( pOrTerm->u.leftColumn==iColumn );
103725 pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
103726 pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup);
103727 pLeft = pOrTerm->pExpr->pLeft;
@@ -103746,11 +103909,10 @@
103746 pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
103747 }
103748 }
103749 }
103750 #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
103751
103752
103753 /*
103754 ** The input to this routine is an WhereTerm structure with only the
103755 ** "pExpr" field filled in. The job of this routine is to analyze the
103756 ** subexpression and populate all the other fields of the WhereTerm
@@ -103816,21 +103978,23 @@
103816 }
103817 pTerm->prereqAll = prereqAll;
103818 pTerm->leftCursor = -1;
103819 pTerm->iParent = -1;
103820 pTerm->eOperator = 0;
103821 if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
103822 Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
103823 Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
 
103824 if( pLeft->op==TK_COLUMN ){
103825 pTerm->leftCursor = pLeft->iTable;
103826 pTerm->u.leftColumn = pLeft->iColumn;
103827 pTerm->eOperator = operatorMask(op);
103828 }
103829 if( pRight && pRight->op==TK_COLUMN ){
103830 WhereTerm *pNew;
103831 Expr *pDup;
 
103832 if( pTerm->leftCursor>=0 ){
103833 int idxNew;
103834 pDup = sqlite3ExprDup(db, pExpr, 0);
103835 if( db->mallocFailed ){
103836 sqlite3ExprDelete(db, pDup);
@@ -103841,10 +104005,17 @@
103841 pNew = &pWC->a[idxNew];
103842 pNew->iParent = idxTerm;
103843 pTerm = &pWC->a[idxTerm];
103844 pTerm->nChild = 1;
103845 pTerm->wtFlags |= TERM_COPIED;
 
 
 
 
 
 
 
103846 }else{
103847 pDup = pExpr;
103848 pNew = pTerm;
103849 }
103850 exprCommute(pParse, pDup);
@@ -103852,11 +104023,11 @@
103852 pNew->leftCursor = pLeft->iTable;
103853 pNew->u.leftColumn = pLeft->iColumn;
103854 testcase( (prereqLeft | extraRight) != prereqLeft );
103855 pNew->prereqRight = prereqLeft | extraRight;
103856 pNew->prereqAll = prereqAll;
103857 pNew->eOperator = operatorMask(pDup->op);
103858 }
103859 }
103860
103861 #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION
103862 /* If a term is the BETWEEN operator, create two new virtual terms
@@ -104311,11 +104482,11 @@
104311 return;
104312 }
104313
104314 /* Search the WHERE clause terms for a usable WO_OR term. */
104315 for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
104316 if( pTerm->eOperator==WO_OR
104317 && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
104318 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0
104319 ){
104320 WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
104321 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
@@ -104332,11 +104503,11 @@
104332 sBOI.ppIdxInfo = 0;
104333 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
104334 WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
104335 (pOrTerm - pOrWC->a), (pTerm - pWC->a)
104336 ));
104337 if( pOrTerm->eOperator==WO_AND ){
104338 sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
104339 bestIndex(&sBOI);
104340 }else if( pOrTerm->leftCursor==iCur ){
104341 WhereClause tempWC;
104342 tempWC.pParse = pWC->pParse;
@@ -104393,11 +104564,11 @@
104393 struct SrcList_item *pSrc, /* Table we are trying to access */
104394 Bitmask notReady /* Tables in outer loops of the join */
104395 ){
104396 char aff;
104397 if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
104398 if( pTerm->eOperator!=WO_EQ ) return 0;
104399 if( (pTerm->prereqRight & notReady)!=0 ) return 0;
104400 aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
104401 if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
104402 return 1;
104403 }
@@ -104655,13 +104826,13 @@
104655
104656 /* Count the number of possible WHERE clause constraints referring
104657 ** to this virtual table */
104658 for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104659 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104660 assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104661 testcase( pTerm->eOperator==WO_IN );
104662 testcase( pTerm->eOperator==WO_ISNULL );
104663 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104664 if( pTerm->wtFlags & TERM_VNULL ) continue;
104665 nTerm++;
104666 }
104667
@@ -104708,18 +104879,18 @@
104708 pUsage;
104709
104710 for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104711 u8 op;
104712 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104713 assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 );
104714 testcase( pTerm->eOperator==WO_IN );
104715 testcase( pTerm->eOperator==WO_ISNULL );
104716 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104717 if( pTerm->wtFlags & TERM_VNULL ) continue;
104718 pIdxCons[j].iColumn = pTerm->u.leftColumn;
104719 pIdxCons[j].iTermOffset = i;
104720 op = (u8)pTerm->eOperator;
104721 if( op==WO_IN ) op = WO_EQ;
104722 pIdxCons[j].op = op;
104723 /* The direct assignment in the previous line is possible only because
104724 ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
104725 ** following asserts verify this fact. */
@@ -104885,11 +105056,11 @@
104885 pUsage = pIdxInfo->aConstraintUsage;
104886 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104887 j = pIdxCons->iTermOffset;
104888 pTerm = &pWC->a[j];
104889 if( (pTerm->prereqRight&p->notReady)==0
104890 && (bAllowIN || pTerm->eOperator!=WO_IN)
104891 ){
104892 pIdxCons->usable = 1;
104893 }else{
104894 pIdxCons->usable = 0;
104895 }
@@ -104917,11 +105088,11 @@
104917 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
104918 if( pUsage[i].argvIndex>0 ){
104919 j = pIdxCons->iTermOffset;
104920 pTerm = &pWC->a[j];
104921 p->cost.used |= pTerm->prereqRight;
104922 if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){
104923 /* Do not attempt to use an IN constraint if the virtual table
104924 ** says that the equivalent EQ constraint cannot be safely omitted.
104925 ** If we do attempt to use such a constraint, some rows might be
104926 ** repeated in the output. */
104927 break;
@@ -105223,28 +105394,28 @@
105223 u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
105224
105225 if( pLower ){
105226 Expr *pExpr = pLower->pExpr->pRight;
105227 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105228 assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE );
105229 if( rc==SQLITE_OK
105230 && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
105231 ){
105232 iLower = a[0];
105233 if( pLower->eOperator==WO_GT ) iLower += a[1];
105234 }
105235 sqlite3ValueFree(pRangeVal);
105236 }
105237 if( rc==SQLITE_OK && pUpper ){
105238 Expr *pExpr = pUpper->pExpr->pRight;
105239 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105240 assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE );
105241 if( rc==SQLITE_OK
105242 && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
105243 ){
105244 iUpper = a[0];
105245 if( pUpper->eOperator==WO_LE ) iUpper += a[1];
105246 }
105247 sqlite3ValueFree(pRangeVal);
105248 }
105249 if( rc==SQLITE_OK ){
105250 if( iUpper<=iLower ){
@@ -105548,16 +105719,16 @@
105548 ** if there are any X= or X IS NULL constraints in the WHERE clause. */
105549 pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105550 WO_EQ|WO_ISNULL|WO_IN, pIdx);
105551 if( pConstraint==0 ){
105552 isEq = 0;
105553 }else if( pConstraint->eOperator==WO_IN ){
105554 /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105555 ** because we do not know in what order the values on the RHS of the IN
105556 ** operator will occur. */
105557 break;
105558 }else if( pConstraint->eOperator==WO_ISNULL ){
105559 uniqueNotNull = 0;
105560 isEq = 1; /* "X IS NULL" means X has only a single value */
105561 }else if( pConstraint->prereqRight==0 ){
105562 isEq = 1; /* Constraint "X=constant" means X has only a single value */
105563 }else{
@@ -105903,11 +106074,11 @@
105903 int bRev = 2;
105904 WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
105905 pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
105906 WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
105907 bRev, pc.plan.nOBSat));
105908 if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
105909 pc.plan.wsFlags |= WHERE_ORDERED;
105910 }
105911 if( nOrderBy==pc.plan.nOBSat ){
105912 bSort = 0;
105913 pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
@@ -105966,16 +106137,17 @@
105966 */
105967 if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
105968 && pFirstTerm!=0 && aiRowEst[1]>1 ){
105969 assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
105970 if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
105971 testcase( pFirstTerm->eOperator==WO_EQ );
105972 testcase( pFirstTerm->eOperator==WO_ISNULL );
 
105973 whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
105974 &pc.plan.nRow);
105975 }else if( bInEst==0 ){
105976 assert( pFirstTerm->eOperator==WO_IN );
105977 whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
105978 &pc.plan.nRow);
105979 }
105980 }
105981 #endif /* SQLITE_ENABLE_STAT3 */
@@ -106118,11 +106290,11 @@
106118 ** more selective intentionally because of the subjective
106119 ** observation that indexed range constraints really are more
106120 ** selective in practice, on average. */
106121 pc.plan.nRow /= 3;
106122 }
106123 }else if( pTerm->eOperator!=WO_NOOP ){
106124 /* Any other expression lowers the output row count by half */
106125 pc.plan.nRow /= 2;
106126 }
106127 }
106128 if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
@@ -106170,12 +106342,13 @@
106170 assert( pSrc->pIndex==0
106171 || p->cost.plan.u.pIdx==0
106172 || p->cost.plan.u.pIdx==pSrc->pIndex
106173 );
106174
106175 WHERETRACE((" best index is: %s\n",
106176 p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
 
106177
106178 bestOrClauseIndex(p);
106179 bestAutomaticIndex(p);
106180 p->cost.plan.wsFlags |= eqTermMask;
106181 }
@@ -106753,11 +106926,10 @@
106753 */
106754 iReleaseReg = sqlite3GetTempReg(pParse);
106755 pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106756 assert( pTerm!=0 );
106757 assert( pTerm->pExpr!=0 );
106758 assert( pTerm->leftCursor==iCur );
106759 assert( omitTable==0 );
106760 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106761 iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
106762 addrNxt = pLevel->addrNxt;
106763 sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
@@ -107144,11 +107316,11 @@
107144 int ii; /* Loop counter */
107145 Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
107146
107147 pTerm = pLevel->plan.u.pTerm;
107148 assert( pTerm!=0 );
107149 assert( pTerm->eOperator==WO_OR );
107150 assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
107151 pOrWc = &pTerm->u.pOrInfo->wc;
107152 pLevel->op = OP_Return;
107153 pLevel->p1 = regReturn;
107154
@@ -107217,11 +107389,11 @@
107217 }
107218 }
107219
107220 for(ii=0; ii<pOrWc->nTerm; ii++){
107221 WhereTerm *pOrTerm = &pOrWc->a[ii];
107222 if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
107223 WhereInfo *pSubWInfo; /* Info for single OR-term scan */
107224 Expr *pOrExpr = pOrTerm->pExpr;
107225 if( pAndExpr ){
107226 pAndExpr->pLeft = pOrExpr;
107227 pOrExpr = pAndExpr;
@@ -107672,10 +107844,11 @@
107672 Index *pIdx; /* Index for FROM table at pTabItem */
107673 int j; /* For looping over FROM tables */
107674 int bestJ = -1; /* The value of j */
107675 Bitmask m; /* Bitmask value for j or bestJ */
107676 int isOptimal; /* Iterator for optimal/non-optimal search */
 
107677 int nUnconstrained; /* Number tables without INDEXED BY */
107678 Bitmask notIndexed; /* Mask of tables that cannot use an index */
107679
107680 memset(&bestPlan, 0, sizeof(bestPlan));
107681 bestPlan.rCost = SQLITE_BIG_DBL;
@@ -107706,14 +107879,12 @@
107706 **
107707 ** The second loop iteration is only performed if no optimal scan
107708 ** strategies were found by the first iteration. This second iteration
107709 ** is used to search for the lowest cost scan overall.
107710 **
107711 ** Previous versions of SQLite performed only the second iteration -
107712 ** the next outermost loop was always that with the lowest overall
107713 ** cost. However, this meant that SQLite could select the wrong plan
107714 ** for scripts such as the following:
107715 **
107716 ** CREATE TABLE t1(a, b);
107717 ** CREATE TABLE t2(c, d);
107718 ** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a;
107719 **
@@ -107724,20 +107895,44 @@
107724 ** algorithm may choose to use t2 for the outer loop, which is a much
107725 ** costlier approach.
107726 */
107727 nUnconstrained = 0;
107728 notIndexed = 0;
107729 for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
 
 
 
 
 
 
107730 for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107731 int doNotReorder; /* True if this table should not be reordered */
107732
107733 doNotReorder = (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0;
107734 if( j!=iFrom && doNotReorder ) break;
107735 m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107736 if( (m & sWBI.notValid)==0 ){
107737 if( j==iFrom ) iFrom++;
107738 continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107739 }
107740 sWBI.notReady = (isOptimal ? m : sWBI.notValid);
107741 if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
107742
107743 WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
@@ -107763,12 +107958,12 @@
107763 if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
107764 notIndexed |= m;
107765 }
107766 if( isOptimal ){
107767 pWInfo->a[j].rOptCost = sWBI.cost.rCost;
107768 }else if( iFrom<nTabList-1 ){
107769 /* If two or more tables have nearly the same outer loop cost,
107770 ** very different inner loop (optimal) cost, we want to choose
107771 ** for the outer loop that table which benefits the least from
107772 ** being in the inner loop. The following code scales the
107773 ** outer loop cost estimate to accomplish that. */
107774 WHERETRACE((" scaling cost from %.1f to %.1f\n",
@@ -107809,15 +108004,23 @@
107809 sWBI.cost.rCost, sWBI.cost.plan.nRow,
107810 sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
107811 bestPlan = sWBI.cost;
107812 bestJ = j;
107813 }
107814 if( doNotReorder ) break;
 
 
 
 
107815 }
107816 }
107817 assert( bestJ>=0 );
107818 assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
 
 
 
 
107819 WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
107820 " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
107821 bestJ, pTabList->a[bestJ].pTab->zName,
107822 pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
107823 bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
@@ -136543,11 +136746,12 @@
136543 ** would fit in a single node, use a smaller node-size.
136544 */
136545 static int getNodeSize(
136546 sqlite3 *db, /* Database handle */
136547 Rtree *pRtree, /* Rtree handle */
136548 int isCreate /* True for xCreate, false for xConnect */
 
136549 ){
136550 int rc;
136551 char *zSql;
136552 if( isCreate ){
136553 int iPageSize = 0;
@@ -136556,17 +136760,22 @@
136556 if( rc==SQLITE_OK ){
136557 pRtree->iNodeSize = iPageSize-64;
136558 if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
136559 pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
136560 }
 
 
136561 }
136562 }else{
136563 zSql = sqlite3_mprintf(
136564 "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
136565 pRtree->zDb, pRtree->zName
136566 );
136567 rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
 
 
 
136568 }
136569
136570 sqlite3_free(zSql);
136571 return rc;
136572 }
@@ -136626,11 +136835,11 @@
136626 pRtree->eCoordType = eCoordType;
136627 memcpy(pRtree->zDb, argv[1], nDb);
136628 memcpy(pRtree->zName, argv[2], nName);
136629
136630 /* Figure out the node size to use. */
136631 rc = getNodeSize(db, pRtree, isCreate);
136632
136633 /* Create/Connect to the underlying relational database schema. If
136634 ** that is successful, call sqlite3_declare_vtab() to configure
136635 ** the r-tree table schema.
136636 */
136637
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674 ** [sqlite_version()] and [sqlite_source_id()].
675 */
676 #define SQLITE_VERSION "3.7.16"
677 #define SQLITE_VERSION_NUMBER 3007016
678 #define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
679
680 /*
681 ** CAPI3REF: Run-Time Library Version Numbers
682 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
683 **
@@ -8238,10 +8238,15 @@
8238 ** A convenience macro that returns the number of elements in
8239 ** an array.
8240 */
8241 #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0])))
8242
8243 /*
8244 ** Determine if the argument is a power of two
8245 */
8246 #define IsPowerOfTwo(X) (((X)&((X)-1))==0)
8247
8248 /*
8249 ** The following value as a destructor means to use sqlite3DbFree().
8250 ** The sqlite3DbFree() routine requires two parameters instead of the
8251 ** one parameter that destructors normally want. So we have to introduce
8252 ** this magic value that the code knows to handle differently. Any
@@ -10042,10 +10047,11 @@
10047 #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
10048 #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
10049 #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
10050 #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
10051 #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
10052 #define SQLITE_Transitive 0x0200 /* Transitive constraints */
10053 #define SQLITE_AllOpts 0xffff /* All optimizations */
10054
10055 /*
10056 ** Macros for testing whether or not optimizations are enabled or disabled.
10057 */
@@ -10553,24 +10559,24 @@
10559 ** and the value of Index.onError indicate the which conflict resolution
10560 ** algorithm to employ whenever an attempt is made to insert a non-unique
10561 ** element.
10562 */
10563 struct Index {
10564 char *zName; /* Name of this index */
10565 int *aiColumn; /* Which columns are used by this index. 1st is 0 */
10566 tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
10567 Table *pTable; /* The SQL table being indexed */
10568 char *zColAff; /* String defining the affinity of each column */
10569 Index *pNext; /* The next index associated with the same table */
10570 Schema *pSchema; /* Schema containing this index */
10571 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
10572 char **azColl; /* Array of collation sequence names for index */
10573 int tnum; /* DB Page containing root of this index */
10574 u16 nColumn; /* Number of columns in table used by this index */
10575 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10576 unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
10577 unsigned bUnordered:1; /* Use this index for == or IN queries only */
10578 #ifdef SQLITE_ENABLE_STAT3
10579 int nSample; /* Number of elements in aSample[] */
10580 tRowcnt avgEq; /* Average nEq value for key values not in aSample */
10581 IndexSample *aSample; /* Samples of the left-most key */
10582 #endif
@@ -10840,22 +10846,31 @@
10846 ** name. An expr/name combination can be used in several ways, such
10847 ** as the list of "expr AS ID" fields following a "SELECT" or in the
10848 ** list of "ID = expr" items in an UPDATE. A list of expressions can
10849 ** also be used as the argument to a function, in which case the a.zName
10850 ** field is not used.
10851 **
10852 ** By default the Expr.zSpan field holds a human-readable description of
10853 ** the expression that is used in the generation of error messages and
10854 ** column labels. In this case, Expr.zSpan is typically the text of a
10855 ** column expression as it exists in a SELECT statement. However, if
10856 ** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
10857 ** of the result column in the form: DATABASE.TABLE.COLUMN. This later
10858 ** form is used for name resolution with nested FROM clauses.
10859 */
10860 struct ExprList {
10861 int nExpr; /* Number of expressions on the list */
10862 int iECursor; /* VDBE Cursor associated with this ExprList */
10863 struct ExprList_item { /* For each expression in the list */
10864 Expr *pExpr; /* The list of expressions */
10865 char *zName; /* Token associated with this expression */
10866 char *zSpan; /* Original text of the expression */
10867 u8 sortOrder; /* 1 for DESC or 0 for ASC */
10868 unsigned done :1; /* A flag to indicate when processing is finished */
10869 unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
10870 u16 iOrderByCol; /* For ORDER BY, column number in result set */
10871 u16 iAlias; /* Index into Parse.aAlias[] for zName */
10872 } *a; /* Alloc a power of two greater or equal to nExpr */
10873 };
10874
10875 /*
10876 ** An instance of this structure is used by the parser to record both
@@ -12141,10 +12156,11 @@
12156 SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
12157 SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
12158 SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
12159 SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
12160 SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
12161 SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
12162 SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
12163 SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
12164 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12165 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12166 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
@@ -23289,15 +23305,11 @@
23305 { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
23306 #endif
23307 #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
23308 aSyscall[13].pCurrent)
23309
 
23310 { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
 
 
 
23311 #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
23312
23313 #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
23314 { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
23315 #else
@@ -23318,13 +23330,10 @@
23330 #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
23331
23332 { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
23333 #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
23334
 
 
 
23335 }; /* End of the overrideable system calls */
23336
23337 /*
23338 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
23339 ** "unix" VFSes. Return SQLITE_OK opon successfully updating the
@@ -23425,31 +23434,29 @@
23434 ** process that is able to write to the database will also be able to
23435 ** recover the hot journals.
23436 */
23437 static int robust_open(const char *z, int f, mode_t m){
23438 int fd;
23439 mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
 
 
 
 
 
 
 
23440 do{
23441 #if defined(O_CLOEXEC)
23442 fd = osOpen(z,f|O_CLOEXEC,m2);
23443 #else
23444 fd = osOpen(z,f,m2);
23445 #endif
23446 }while( fd<0 && errno==EINTR );
23447 if( fd>=0 ){
23448 if( m!=0 ){
23449 struct stat statbuf;
23450 if( osFstat(fd, &statbuf)==0 && (statbuf.st_mode&0777)!=m ){
23451 osFchmod(fd, m);
23452 }
23453 }
23454 #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0)
23455 osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
23456 #endif
23457 }
23458 return fd;
23459 }
23460
23461 /*
23462 ** Helper functions to obtain and relinquish the global mutex. The
@@ -29871,11 +29878,11 @@
29878 };
29879 unsigned int i; /* Loop counter */
29880
29881 /* Double-check that the aSyscall[] array has been constructed
29882 ** correctly. See ticket [bb3a86e890c8e96ab] */
29883 assert( ArraySize(aSyscall)==21 );
29884
29885 /* Register all VFSes defined in the aVfs[] array */
29886 for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
29887 sqlite3_vfs_register(&aVfs[i], i==0);
29888 }
@@ -72655,10 +72662,39 @@
72662 }
72663 }
72664 return 0;
72665 }
72666
72667 /*
72668 ** Subqueries stores the original database, table and column names for their
72669 ** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
72670 ** Check to see if the zSpan given to this routine matches the zDb, zTab,
72671 ** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
72672 ** match anything.
72673 */
72674 SQLITE_PRIVATE int sqlite3MatchSpanName(
72675 const char *zSpan,
72676 const char *zCol,
72677 const char *zTab,
72678 const char *zDb
72679 ){
72680 int n;
72681 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72682 if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
72683 return 0;
72684 }
72685 zSpan += n+1;
72686 for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
72687 if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
72688 return 0;
72689 }
72690 zSpan += n+1;
72691 if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
72692 return 0;
72693 }
72694 return 1;
72695 }
72696
72697 /*
72698 ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
72699 ** that name in the set of source tables in pSrcList and make the pExpr
72700 ** expression node refer back to that source column. The following changes
@@ -72710,44 +72746,63 @@
72746
72747 /* Initialize the node to no-match */
72748 pExpr->iTable = -1;
72749 pExpr->pTab = 0;
72750 ExprSetIrreducible(pExpr);
72751
72752 /* Translate the schema name in zDb into a pointer to the corresponding
72753 ** schema. If not found, pSchema will remain NULL and nothing will match
72754 ** resulting in an appropriate error message toward the end of this routine
72755 */
72756 if( zDb ){
72757 for(i=0; i<db->nDb; i++){
72758 assert( db->aDb[i].zName );
72759 if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
72760 pSchema = db->aDb[i].pSchema;
72761 break;
72762 }
72763 }
72764 }
72765
72766 /* Start at the inner-most context and move outward until a match is found */
72767 while( pNC && cnt==0 ){
72768 ExprList *pEList;
72769 SrcList *pSrcList = pNC->pSrcList;
72770
72771 if( pSrcList ){
72772 for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
72773 Table *pTab;
 
72774 Column *pCol;
72775
72776 pTab = pItem->pTab;
72777 assert( pTab!=0 && pTab->zName!=0 );
 
72778 assert( pTab->nCol>0 );
72779 if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
72780 ExprList *pEList = pItem->pSelect->pEList;
72781 int hit = 0;
72782 for(j=0; j<pEList->nExpr; j++){
72783 if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
72784 cnt++;
72785 cntTab = 2;
72786 pMatch = pItem;
72787 pExpr->iColumn = j;
72788 hit = 1;
72789 }
72790 }
72791 if( hit || zTab==0 ) continue;
72792 }
72793 if( zDb && pTab->pSchema!=pSchema ){
72794 continue;
72795 }
72796 if( zTab ){
72797 const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
72798 assert( zTabName!=0 );
72799 if( sqlite3StrICmp(zTabName, zTab)!=0 ){
72800 continue;
 
 
 
 
 
 
 
72801 }
72802 }
72803 if( 0==(cntTab++) ){
 
 
 
72804 pMatch = pItem;
72805 }
72806 for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
72807 if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
72808 /* If there has been exactly one prior match and this match
@@ -72757,21 +72812,23 @@
72812 if( cnt==1 ){
72813 if( pItem->jointype & JT_NATURAL ) continue;
72814 if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
72815 }
72816 cnt++;
 
 
72817 pMatch = pItem;
 
72818 /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
72819 pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
72820 break;
72821 }
72822 }
72823 }
72824 if( pMatch ){
72825 pExpr->iTable = pMatch->iCursor;
72826 pExpr->pTab = pMatch->pTab;
72827 pSchema = pExpr->pTab->pSchema;
72828 }
72829 } /* if( pSrcList ) */
72830
72831 #ifndef SQLITE_OMIT_TRIGGER
72832 /* If we have not already resolved the name, then maybe
72833 ** it is a new.* or old.* trigger argument reference
72834 */
@@ -73102,11 +73159,11 @@
73159 #endif
73160 if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
73161 sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
73162 pNC->nErr++;
73163 is_agg = 0;
73164 }else if( no_such_func && pParse->db->init.busy==0 ){
73165 sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
73166 pNC->nErr++;
73167 }else if( wrong_num_args ){
73168 sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
73169 nId, zId);
@@ -77065,10 +77122,16 @@
77122 for(i=0; i<pList->nExpr; i++){
77123 sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
77124 sqlite3ExplainPush(pOut);
77125 sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
77126 sqlite3ExplainPop(pOut);
77127 if( pList->a[i].zName ){
77128 sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
77129 }
77130 if( pList->a[i].bSpanIsTab ){
77131 sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
77132 }
77133 if( i<pList->nExpr-1 ){
77134 sqlite3ExplainNL(pOut);
77135 }
77136 }
77137 sqlite3ExplainPop(pOut);
@@ -92739,13 +92802,15 @@
92802 if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
92803 Table *pTab;
92804 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
92805 pTab = sqlite3FindTable(db, zRight, zDb);
92806 if( pTab ){
92807 int i, k;
92808 int nHidden = 0;
92809 Column *pCol;
92810 Index *pPk;
92811 for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){}
92812 sqlite3VdbeSetNumCols(v, 6);
92813 pParse->nMem = 6;
92814 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
92815 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
92816 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
@@ -92766,12 +92831,18 @@
92831 if( pCol->zDflt ){
92832 sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
92833 }else{
92834 sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
92835 }
92836 if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
92837 k = 0;
92838 }else if( pPk==0 ){
92839 k = 1;
92840 }else{
92841 for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
92842 }
92843 sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
92844 sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
92845 }
92846 }
92847 }else
92848
@@ -93516,11 +93587,11 @@
93587 sqlite3_rekey(db, zKey, i/2);
93588 }
93589 }else
93590 #endif
93591 #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
93592 if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){
93593 #ifdef SQLITE_HAS_CODEC
93594 if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
93595 sqlite3_activate_see(&zRight[4]);
93596 }
93597 #endif
@@ -95756,12 +95827,10 @@
95827
95828 for(i=0, pCol=aCol; i<nCol; i++, pCol++){
95829 /* Get an appropriate name for the column
95830 */
95831 p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
 
 
95832 if( (zName = pEList->a[i].zName)!=0 ){
95833 /* If the column contains an "AS <name>" phrase, use <name> as the name */
95834 zName = sqlite3DbStrDup(db, zName);
95835 }else{
95836 Expr *pColExpr = p; /* The expression that is the result column name */
@@ -95795,10 +95864,13 @@
95864 */
95865 nName = sqlite3Strlen30(zName);
95866 for(j=cnt=0; j<i; j++){
95867 if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
95868 char *zNewName;
95869 int k;
95870 for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
95871 if( zName[k]==':' ) nName = k;
95872 zName[nName] = 0;
95873 zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
95874 sqlite3DbFree(db, zName);
95875 zName = zNewName;
95876 j = -1;
@@ -97711,10 +97783,11 @@
97783 int i, j, k;
97784 SrcList *pTabList;
97785 ExprList *pEList;
97786 struct SrcList_item *pFrom;
97787 sqlite3 *db = pParse->db;
97788 Expr *pE, *pRight, *pExpr;
97789
97790 if( db->mallocFailed ){
97791 return WRC_Abort;
97792 }
97793 if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){
@@ -97796,11 +97869,11 @@
97869 **
97870 ** The first loop just checks to see if there are any "*" operators
97871 ** that need expanding.
97872 */
97873 for(k=0; k<pEList->nExpr; k++){
97874 pE = pEList->a[k].pExpr;
97875 if( pE->op==TK_ALL ) break;
97876 assert( pE->op!=TK_DOT || pE->pRight!=0 );
97877 assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
97878 if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
97879 }
@@ -97814,14 +97887,22 @@
97887 ExprList *pNew = 0;
97888 int flags = pParse->db->flags;
97889 int longNames = (flags & SQLITE_FullColNames)!=0
97890 && (flags & SQLITE_ShortColNames)==0;
97891
97892 /* When processing FROM-clause subqueries, it is always the case
97893 ** that full_column_names=OFF and short_column_names=ON. The
97894 ** sqlite3ResultSetOfSelect() routine makes it so. */
97895 assert( (p->selFlags & SF_NestedFrom)==0
97896 || ((flags & SQLITE_FullColNames)==0 &&
97897 (flags & SQLITE_ShortColNames)!=0) );
97898
97899 for(k=0; k<pEList->nExpr; k++){
97900 pE = a[k].pExpr;
97901 pRight = pE->pRight;
97902 assert( pE->op!=TK_DOT || pRight!=0 );
97903 if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
97904 /* This particular expression does not need to be expanded.
97905 */
97906 pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
97907 if( pNew ){
97908 pNew->a[pNew->nExpr-1].zName = a[k].zName;
@@ -97832,44 +97913,56 @@
97913 a[k].pExpr = 0;
97914 }else{
97915 /* This expression is a "*" or a "TABLE.*" and needs to be
97916 ** expanded. */
97917 int tableSeen = 0; /* Set to 1 when TABLE matches */
97918 char *zTName = 0; /* text of name of TABLE */
97919 if( pE->op==TK_DOT ){
97920 assert( pE->pLeft!=0 );
97921 assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
97922 zTName = pE->pLeft->u.zToken;
 
 
97923 }
97924 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
97925 Table *pTab = pFrom->pTab;
97926 Select *pSub = pFrom->pSelect;
97927 char *zTabName = pFrom->zAlias;
97928 const char *zSchemaName = 0;
97929 int iDb;
97930 if( zTabName==0 ){
97931 zTabName = pTab->zName;
97932 }
97933 if( db->mallocFailed ) break;
97934 if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
97935 pSub = 0;
97936 if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
97937 continue;
97938 }
97939 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
97940 zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
97941 }
 
97942 for(j=0; j<pTab->nCol; j++){
 
97943 char *zName = pTab->aCol[j].zName;
97944 char *zColname; /* The computed column name */
97945 char *zToFree; /* Malloced string that needs to be freed */
97946 Token sColname; /* Computed column name as a token */
97947
97948 assert( zName );
97949 if( zTName && pSub
97950 && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
97951 ){
97952 continue;
97953 }
97954
97955 /* If a column is marked as 'hidden' (currently only possible
97956 ** for virtual tables), do not include it in the expanded
97957 ** result-set list.
97958 */
97959 if( IsHiddenColumn(&pTab->aCol[j]) ){
97960 assert(IsVirtual(pTab));
97961 continue;
97962 }
97963 tableSeen = 1;
97964
97965 if( i>0 && zTName==0 ){
97966 if( (pFrom->jointype & JT_NATURAL)!=0
97967 && tableAndColumnIndex(pTabList, i, zName, 0, 0)
97968 ){
@@ -97888,10 +97981,14 @@
97981 zToFree = 0;
97982 if( longNames || pTabList->nSrc>1 ){
97983 Expr *pLeft;
97984 pLeft = sqlite3Expr(db, TK_ID, zTabName);
97985 pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
97986 if( zSchemaName ){
97987 pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
97988 pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
97989 }
97990 if( longNames ){
97991 zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
97992 zToFree = zColname;
97993 }
97994 }else{
@@ -97899,10 +97996,22 @@
97996 }
97997 pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
97998 sColname.z = zColname;
97999 sColname.n = sqlite3Strlen30(zColname);
98000 sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
98001 if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
98002 struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
98003 if( pSub ){
98004 pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
98005 testcase( pX->zSpan==0 );
98006 }else{
98007 pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
98008 zSchemaName, zTabName, zColname);
98009 testcase( pX->zSpan==0 );
98010 }
98011 pX->bSpanIsTab = 1;
98012 }
98013 sqlite3DbFree(db, zToFree);
98014 }
98015 }
98016 if( !tableSeen ){
98017 if( zTName ){
@@ -102699,12 +102808,12 @@
102808 Expr *pExpr; /* Pointer to the subexpression that is this term */
102809 int iParent; /* Disable pWC->a[iParent] when this term disabled */
102810 int leftCursor; /* Cursor number of X in "X <op> <expr>" */
102811 union {
102812 int leftColumn; /* Column number of X in "X <op> <expr>" */
102813 WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
102814 WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
102815 } u;
102816 u16 eOperator; /* A WO_xx value describing <op> */
102817 u8 wtFlags; /* TERM_xxx bit flags. See below */
102818 u8 nChild; /* Number of children that must disable us */
102819 WhereClause *pWC; /* The clause this term is part of */
@@ -102828,10 +102937,11 @@
102937 #define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
102938 #define WO_MATCH 0x040
102939 #define WO_ISNULL 0x080
102940 #define WO_OR 0x100 /* Two or more OR-connected terms */
102941 #define WO_AND 0x200 /* Two or more AND-connected terms */
102942 #define WO_EQUIV 0x400 /* Of the form A==B, both columns */
102943 #define WO_NOOP 0x800 /* This term does not restrict search space */
102944
102945 #define WO_ALL 0xfff /* Mask of all possible WO_* values */
102946 #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
102947
@@ -103230,58 +103340,112 @@
103340 /*
103341 ** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
103342 ** where X is a reference to the iColumn of table iCur and <op> is one of
103343 ** the WO_xx operator codes specified by the op parameter.
103344 ** Return a pointer to the term. Return 0 if not found.
103345 **
103346 ** The term returned might by Y=<expr> if there is another constraint in
103347 ** the WHERE clause that specifies that X=Y. Any such constraints will be
103348 ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
103349 ** aEquiv[] array holds X and all its equivalents, with each SQL variable
103350 ** taking up two slots in aEquiv[]. The first slot is for the cursor number
103351 ** and the second is for the column number. There are 22 slots in aEquiv[]
103352 ** so that means we can look for X plus up to 10 other equivalent values.
103353 ** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3
103354 ** and ... and A9=A10 and A10=<expr>.
103355 **
103356 ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
103357 ** then try for the one with no dependencies on <expr> - in other words where
103358 ** <expr> is a constant expression of some kind. Only return entries of
103359 ** the form "X <op> Y" where Y is a column in another table if no terms of
103360 ** the form "X <op> <const-expr>" exist. Other than this priority, if there
103361 ** are two or more terms that match, then the choice of which term to return
103362 ** is arbitrary.
103363 */
103364 static WhereTerm *findTerm(
103365 WhereClause *pWC, /* The WHERE clause to be searched */
103366 int iCur, /* Cursor number of LHS */
103367 int iColumn, /* Column number of LHS */
103368 Bitmask notReady, /* RHS must not overlap with this mask */
103369 u32 op, /* Mask of WO_xx values describing operator */
103370 Index *pIdx /* Must be compatible with this index, if not NULL */
103371 ){
103372 WhereTerm *pTerm; /* Term being examined as possible result */
103373 WhereTerm *pResult = 0; /* The answer to return */
103374 WhereClause *pWCOrig = pWC; /* Original pWC value */
103375 int j, k; /* Loop counters */
103376 Expr *pX; /* Pointer to an expression */
103377 Parse *pParse; /* Parsing context */
103378 int iOrigCol = iColumn; /* Original value of iColumn */
103379 int nEquiv = 2; /* Number of entires in aEquiv[] */
103380 int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */
103381 int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */
103382
103383 assert( iCur>=0 );
103384 aEquiv[0] = iCur;
103385 aEquiv[1] = iColumn;
103386 for(;;){
103387 for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){
103388 for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
103389 if( pTerm->leftCursor==iCur
103390 && pTerm->u.leftColumn==iColumn
103391 ){
103392 if( (pTerm->prereqRight & notReady)==0
103393 && (pTerm->eOperator & op & WO_ALL)!=0
103394 ){
103395 if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){
103396 CollSeq *pColl;
103397 char idxaff;
103398
103399 pX = pTerm->pExpr;
103400 pParse = pWC->pParse;
103401 idxaff = pIdx->pTable->aCol[iOrigCol].affinity;
103402 if( !sqlite3IndexAffinityOk(pX, idxaff) ){
103403 continue;
103404 }
103405
103406 /* Figure out the collation sequence required from an index for
103407 ** it to be useful for optimising expression pX. Store this
103408 ** value in variable pColl.
103409 */
103410 assert(pX->pLeft);
103411 pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight);
103412 if( pColl==0 ) pColl = pParse->db->pDfltColl;
103413
103414 for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){
103415 if( NEVER(j>=pIdx->nColumn) ) return 0;
103416 }
103417 if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){
103418 continue;
103419 }
103420 }
103421 pResult = pTerm;
103422 if( pTerm->prereqRight==0 ) goto findTerm_success;
103423 }
103424 if( (pTerm->eOperator & WO_EQUIV)!=0
103425 && nEquiv<ArraySize(aEquiv)
103426 ){
103427 pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
103428 assert( pX->op==TK_COLUMN );
103429 for(j=0; j<nEquiv; j+=2){
103430 if( aEquiv[j]==pX->iTable && aEquiv[j+1]==pX->iColumn ) break;
103431 }
103432 if( j==nEquiv ){
103433 aEquiv[j] = pX->iTable;
103434 aEquiv[j+1] = pX->iColumn;
103435 nEquiv += 2;
103436 }
103437 }
103438 }
103439 }
103440 }
103441 if( iEquiv>=nEquiv ) break;
103442 iCur = aEquiv[iEquiv++];
103443 iColumn = aEquiv[iEquiv++];
103444 }
103445 findTerm_success:
103446 return pResult;
103447 }
103448
103449 /* Forward reference */
103450 static void exprAnalyze(SrcList*, WhereClause*, int);
103451
@@ -103555,11 +103719,10 @@
103719 indexable = ~(Bitmask)0;
103720 chngToIN = ~(pWC->vmask);
103721 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
103722 if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
103723 WhereAndInfo *pAndInfo;
 
103724 assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
103725 chngToIN = 0;
103726 pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
103727 if( pAndInfo ){
103728 WhereClause *pAndWC;
@@ -103594,11 +103757,11 @@
103757 if( pOrTerm->wtFlags & TERM_VIRTUAL ){
103758 WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent];
103759 b |= getMask(pMaskSet, pOther->leftCursor);
103760 }
103761 indexable &= b;
103762 if( (pOrTerm->eOperator & WO_EQ)==0 ){
103763 chngToIN = 0;
103764 }else{
103765 chngToIN &= b;
103766 }
103767 }
@@ -103645,11 +103808,11 @@
103808 ** and column is found but leave okToChngToIN false if not found.
103809 */
103810 for(j=0; j<2 && !okToChngToIN; j++){
103811 pOrTerm = pOrWc->a;
103812 for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
103813 assert( pOrTerm->eOperator & WO_EQ );
103814 pOrTerm->wtFlags &= ~TERM_OR_OK;
103815 if( pOrTerm->leftCursor==iCursor ){
103816 /* This is the 2-bit case and we are on the second iteration and
103817 ** current term is from the first iteration. So skip this term. */
103818 assert( j==1 );
@@ -103671,21 +103834,21 @@
103834 }
103835 if( i<0 ){
103836 /* No candidate table+column was found. This can only occur
103837 ** on the second iteration */
103838 assert( j==1 );
103839 assert( IsPowerOfTwo(chngToIN) );
103840 assert( chngToIN==getMask(pMaskSet, iCursor) );
103841 break;
103842 }
103843 testcase( j==1 );
103844
103845 /* We have found a candidate table and column. Check to see if that
103846 ** table and column is common to every term in the OR clause */
103847 okToChngToIN = 1;
103848 for(; i>=0 && okToChngToIN; i--, pOrTerm++){
103849 assert( pOrTerm->eOperator & WO_EQ );
103850 if( pOrTerm->leftCursor!=iCursor ){
103851 pOrTerm->wtFlags &= ~TERM_OR_OK;
103852 }else if( pOrTerm->u.leftColumn!=iColumn ){
103853 okToChngToIN = 0;
103854 }else{
@@ -103717,11 +103880,11 @@
103880 Expr *pLeft = 0; /* The LHS of the IN operator */
103881 Expr *pNew; /* The complete IN operator */
103882
103883 for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
103884 if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
103885 assert( pOrTerm->eOperator & WO_EQ );
103886 assert( pOrTerm->leftCursor==iCursor );
103887 assert( pOrTerm->u.leftColumn==iColumn );
103888 pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
103889 pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup);
103890 pLeft = pOrTerm->pExpr->pLeft;
@@ -103746,11 +103909,10 @@
103909 pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
103910 }
103911 }
103912 }
103913 #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
 
103914
103915 /*
103916 ** The input to this routine is an WhereTerm structure with only the
103917 ** "pExpr" field filled in. The job of this routine is to analyze the
103918 ** subexpression and populate all the other fields of the WhereTerm
@@ -103816,21 +103978,23 @@
103978 }
103979 pTerm->prereqAll = prereqAll;
103980 pTerm->leftCursor = -1;
103981 pTerm->iParent = -1;
103982 pTerm->eOperator = 0;
103983 if( allowedOp(op) ){
103984 Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
103985 Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
103986 u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
103987 if( pLeft->op==TK_COLUMN ){
103988 pTerm->leftCursor = pLeft->iTable;
103989 pTerm->u.leftColumn = pLeft->iColumn;
103990 pTerm->eOperator = operatorMask(op) & opMask;
103991 }
103992 if( pRight && pRight->op==TK_COLUMN ){
103993 WhereTerm *pNew;
103994 Expr *pDup;
103995 u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
103996 if( pTerm->leftCursor>=0 ){
103997 int idxNew;
103998 pDup = sqlite3ExprDup(db, pExpr, 0);
103999 if( db->mallocFailed ){
104000 sqlite3ExprDelete(db, pDup);
@@ -103841,10 +104005,17 @@
104005 pNew = &pWC->a[idxNew];
104006 pNew->iParent = idxTerm;
104007 pTerm = &pWC->a[idxTerm];
104008 pTerm->nChild = 1;
104009 pTerm->wtFlags |= TERM_COPIED;
104010 if( pExpr->op==TK_EQ
104011 && !ExprHasProperty(pExpr, EP_FromJoin)
104012 && OptimizationEnabled(db, SQLITE_Transitive)
104013 ){
104014 pTerm->eOperator |= WO_EQUIV;
104015 eExtraOp = WO_EQUIV;
104016 }
104017 }else{
104018 pDup = pExpr;
104019 pNew = pTerm;
104020 }
104021 exprCommute(pParse, pDup);
@@ -103852,11 +104023,11 @@
104023 pNew->leftCursor = pLeft->iTable;
104024 pNew->u.leftColumn = pLeft->iColumn;
104025 testcase( (prereqLeft | extraRight) != prereqLeft );
104026 pNew->prereqRight = prereqLeft | extraRight;
104027 pNew->prereqAll = prereqAll;
104028 pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
104029 }
104030 }
104031
104032 #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION
104033 /* If a term is the BETWEEN operator, create two new virtual terms
@@ -104311,11 +104482,11 @@
104482 return;
104483 }
104484
104485 /* Search the WHERE clause terms for a usable WO_OR term. */
104486 for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
104487 if( (pTerm->eOperator & WO_OR)!=0
104488 && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
104489 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0
104490 ){
104491 WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
104492 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
@@ -104332,11 +104503,11 @@
104503 sBOI.ppIdxInfo = 0;
104504 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
104505 WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
104506 (pOrTerm - pOrWC->a), (pTerm - pWC->a)
104507 ));
104508 if( (pOrTerm->eOperator& WO_AND)!=0 ){
104509 sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
104510 bestIndex(&sBOI);
104511 }else if( pOrTerm->leftCursor==iCur ){
104512 WhereClause tempWC;
104513 tempWC.pParse = pWC->pParse;
@@ -104393,11 +104564,11 @@
104564 struct SrcList_item *pSrc, /* Table we are trying to access */
104565 Bitmask notReady /* Tables in outer loops of the join */
104566 ){
104567 char aff;
104568 if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
104569 if( (pTerm->eOperator & WO_EQ)==0 ) return 0;
104570 if( (pTerm->prereqRight & notReady)!=0 ) return 0;
104571 aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
104572 if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
104573 return 1;
104574 }
@@ -104655,13 +104826,13 @@
104826
104827 /* Count the number of possible WHERE clause constraints referring
104828 ** to this virtual table */
104829 for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104830 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104831 assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104832 testcase( pTerm->eOperator & WO_IN );
104833 testcase( pTerm->eOperator & WO_ISNULL );
104834 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104835 if( pTerm->wtFlags & TERM_VNULL ) continue;
104836 nTerm++;
104837 }
104838
@@ -104708,18 +104879,18 @@
104879 pUsage;
104880
104881 for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
104882 u8 op;
104883 if( pTerm->leftCursor != pSrc->iCursor ) continue;
104884 assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
104885 testcase( pTerm->eOperator & WO_IN );
104886 testcase( pTerm->eOperator & WO_ISNULL );
104887 if( pTerm->eOperator & (WO_ISNULL) ) continue;
104888 if( pTerm->wtFlags & TERM_VNULL ) continue;
104889 pIdxCons[j].iColumn = pTerm->u.leftColumn;
104890 pIdxCons[j].iTermOffset = i;
104891 op = (u8)pTerm->eOperator & WO_ALL;
104892 if( op==WO_IN ) op = WO_EQ;
104893 pIdxCons[j].op = op;
104894 /* The direct assignment in the previous line is possible only because
104895 ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
104896 ** following asserts verify this fact. */
@@ -104885,11 +105056,11 @@
105056 pUsage = pIdxInfo->aConstraintUsage;
105057 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
105058 j = pIdxCons->iTermOffset;
105059 pTerm = &pWC->a[j];
105060 if( (pTerm->prereqRight&p->notReady)==0
105061 && (bAllowIN || (pTerm->eOperator & WO_IN)==0)
105062 ){
105063 pIdxCons->usable = 1;
105064 }else{
105065 pIdxCons->usable = 0;
105066 }
@@ -104917,11 +105088,11 @@
105088 for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
105089 if( pUsage[i].argvIndex>0 ){
105090 j = pIdxCons->iTermOffset;
105091 pTerm = &pWC->a[j];
105092 p->cost.used |= pTerm->prereqRight;
105093 if( (pTerm->eOperator & WO_IN)!=0 && pUsage[i].omit==0 ){
105094 /* Do not attempt to use an IN constraint if the virtual table
105095 ** says that the equivalent EQ constraint cannot be safely omitted.
105096 ** If we do attempt to use such a constraint, some rows might be
105097 ** repeated in the output. */
105098 break;
@@ -105223,28 +105394,28 @@
105394 u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
105395
105396 if( pLower ){
105397 Expr *pExpr = pLower->pExpr->pRight;
105398 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105399 assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
105400 if( rc==SQLITE_OK
105401 && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
105402 ){
105403 iLower = a[0];
105404 if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
105405 }
105406 sqlite3ValueFree(pRangeVal);
105407 }
105408 if( rc==SQLITE_OK && pUpper ){
105409 Expr *pExpr = pUpper->pExpr->pRight;
105410 rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
105411 assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
105412 if( rc==SQLITE_OK
105413 && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
105414 ){
105415 iUpper = a[0];
105416 if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
105417 }
105418 sqlite3ValueFree(pRangeVal);
105419 }
105420 if( rc==SQLITE_OK ){
105421 if( iUpper<=iLower ){
@@ -105548,16 +105719,16 @@
105719 ** if there are any X= or X IS NULL constraints in the WHERE clause. */
105720 pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
105721 WO_EQ|WO_ISNULL|WO_IN, pIdx);
105722 if( pConstraint==0 ){
105723 isEq = 0;
105724 }else if( (pConstraint->eOperator & WO_IN)!=0 ){
105725 /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
105726 ** because we do not know in what order the values on the RHS of the IN
105727 ** operator will occur. */
105728 break;
105729 }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){
105730 uniqueNotNull = 0;
105731 isEq = 1; /* "X IS NULL" means X has only a single value */
105732 }else if( pConstraint->prereqRight==0 ){
105733 isEq = 1; /* Constraint "X=constant" means X has only a single value */
105734 }else{
@@ -105903,11 +106074,11 @@
106074 int bRev = 2;
106075 WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
106076 pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
106077 WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
106078 bRev, pc.plan.nOBSat));
106079 if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
106080 pc.plan.wsFlags |= WHERE_ORDERED;
106081 }
106082 if( nOrderBy==pc.plan.nOBSat ){
106083 bSort = 0;
106084 pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
@@ -105966,16 +106137,17 @@
106137 */
106138 if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
106139 && pFirstTerm!=0 && aiRowEst[1]>1 ){
106140 assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
106141 if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
106142 testcase( pFirstTerm->eOperator & WO_EQ );
106143 testcase( pFirstTerm->eOperator & WO_EQUIV );
106144 testcase( pFirstTerm->eOperator & WO_ISNULL );
106145 whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
106146 &pc.plan.nRow);
106147 }else if( bInEst==0 ){
106148 assert( pFirstTerm->eOperator & WO_IN );
106149 whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
106150 &pc.plan.nRow);
106151 }
106152 }
106153 #endif /* SQLITE_ENABLE_STAT3 */
@@ -106118,11 +106290,11 @@
106290 ** more selective intentionally because of the subjective
106291 ** observation that indexed range constraints really are more
106292 ** selective in practice, on average. */
106293 pc.plan.nRow /= 3;
106294 }
106295 }else if( (pTerm->eOperator & WO_NOOP)==0 ){
106296 /* Any other expression lowers the output row count by half */
106297 pc.plan.nRow /= 2;
106298 }
106299 }
106300 if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
@@ -106170,12 +106342,13 @@
106342 assert( pSrc->pIndex==0
106343 || p->cost.plan.u.pIdx==0
106344 || p->cost.plan.u.pIdx==pSrc->pIndex
106345 );
106346
106347 WHERETRACE((" best index is %s cost=%.1f\n",
106348 p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk",
106349 p->cost.rCost));
106350
106351 bestOrClauseIndex(p);
106352 bestAutomaticIndex(p);
106353 p->cost.plan.wsFlags |= eqTermMask;
106354 }
@@ -106753,11 +106926,10 @@
106926 */
106927 iReleaseReg = sqlite3GetTempReg(pParse);
106928 pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0);
106929 assert( pTerm!=0 );
106930 assert( pTerm->pExpr!=0 );
 
106931 assert( omitTable==0 );
106932 testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
106933 iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
106934 addrNxt = pLevel->addrNxt;
106935 sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
@@ -107144,11 +107316,11 @@
107316 int ii; /* Loop counter */
107317 Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
107318
107319 pTerm = pLevel->plan.u.pTerm;
107320 assert( pTerm!=0 );
107321 assert( pTerm->eOperator & WO_OR );
107322 assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
107323 pOrWc = &pTerm->u.pOrInfo->wc;
107324 pLevel->op = OP_Return;
107325 pLevel->p1 = regReturn;
107326
@@ -107217,11 +107389,11 @@
107389 }
107390 }
107391
107392 for(ii=0; ii<pOrWc->nTerm; ii++){
107393 WhereTerm *pOrTerm = &pOrWc->a[ii];
107394 if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
107395 WhereInfo *pSubWInfo; /* Info for single OR-term scan */
107396 Expr *pOrExpr = pOrTerm->pExpr;
107397 if( pAndExpr ){
107398 pAndExpr->pLeft = pOrExpr;
107399 pOrExpr = pAndExpr;
@@ -107672,10 +107844,11 @@
107844 Index *pIdx; /* Index for FROM table at pTabItem */
107845 int j; /* For looping over FROM tables */
107846 int bestJ = -1; /* The value of j */
107847 Bitmask m; /* Bitmask value for j or bestJ */
107848 int isOptimal; /* Iterator for optimal/non-optimal search */
107849 int ckOptimal; /* Do the optimal scan check */
107850 int nUnconstrained; /* Number tables without INDEXED BY */
107851 Bitmask notIndexed; /* Mask of tables that cannot use an index */
107852
107853 memset(&bestPlan, 0, sizeof(bestPlan));
107854 bestPlan.rCost = SQLITE_BIG_DBL;
@@ -107706,14 +107879,12 @@
107879 **
107880 ** The second loop iteration is only performed if no optimal scan
107881 ** strategies were found by the first iteration. This second iteration
107882 ** is used to search for the lowest cost scan overall.
107883 **
107884 ** Without the optimal scan step (the first iteration) a suboptimal
107885 ** plan might be chosen for queries like this:
 
 
107886 **
107887 ** CREATE TABLE t1(a, b);
107888 ** CREATE TABLE t2(c, d);
107889 ** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a;
107890 **
@@ -107724,20 +107895,44 @@
107895 ** algorithm may choose to use t2 for the outer loop, which is a much
107896 ** costlier approach.
107897 */
107898 nUnconstrained = 0;
107899 notIndexed = 0;
107900
107901 /* The optimal scan check only occurs if there are two or more tables
107902 ** available to be reordered */
107903 if( iFrom==nTabList-1 ){
107904 ckOptimal = 0; /* Common case of just one table in the FROM clause */
107905 }else{
107906 ckOptimal = -1;
107907 for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
 
 
 
 
107908 m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107909 if( (m & sWBI.notValid)==0 ){
107910 if( j==iFrom ) iFrom++;
107911 continue;
107912 }
107913 if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break;
107914 if( ++ckOptimal ) break;
107915 if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
107916 }
107917 }
107918 assert( ckOptimal==0 || ckOptimal==1 );
107919
107920 for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){
107921 for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
107922 if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){
107923 /* This break and one like it in the ckOptimal computation loop
107924 ** above prevent table reordering across LEFT and CROSS JOINs.
107925 ** The LEFT JOIN case is necessary for correctness. The prohibition
107926 ** against reordering across a CROSS JOIN is an SQLite feature that
107927 ** allows the developer to control table reordering */
107928 break;
107929 }
107930 m = getMask(pMaskSet, sWBI.pSrc->iCursor);
107931 if( (m & sWBI.notValid)==0 ){
107932 assert( j>iFrom );
107933 continue;
107934 }
107935 sWBI.notReady = (isOptimal ? m : sWBI.notValid);
107936 if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
107937
107938 WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
@@ -107763,12 +107958,12 @@
107958 if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
107959 notIndexed |= m;
107960 }
107961 if( isOptimal ){
107962 pWInfo->a[j].rOptCost = sWBI.cost.rCost;
107963 }else if( ckOptimal ){
107964 /* If two or more tables have nearly the same outer loop cost, but
107965 ** very different inner loop (optimal) cost, we want to choose
107966 ** for the outer loop that table which benefits the least from
107967 ** being in the inner loop. The following code scales the
107968 ** outer loop cost estimate to accomplish that. */
107969 WHERETRACE((" scaling cost from %.1f to %.1f\n",
@@ -107809,15 +108004,23 @@
108004 sWBI.cost.rCost, sWBI.cost.plan.nRow,
108005 sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
108006 bestPlan = sWBI.cost;
108007 bestJ = j;
108008 }
108009
108010 /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that
108011 ** table y (and not table z) is always the next inner loop inside
108012 ** of table x. */
108013 if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break;
108014 }
108015 }
108016 assert( bestJ>=0 );
108017 assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
108018 assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 );
108019 testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 );
108020 testcase( bestJ>iFrom && bestJ<nTabList-1
108021 && (pTabList->a[bestJ+1].jointype & JT_LEFT)!=0 );
108022 WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
108023 " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
108024 bestJ, pTabList->a[bestJ].pTab->zName,
108025 pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
108026 bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
@@ -136543,11 +136746,12 @@
136746 ** would fit in a single node, use a smaller node-size.
136747 */
136748 static int getNodeSize(
136749 sqlite3 *db, /* Database handle */
136750 Rtree *pRtree, /* Rtree handle */
136751 int isCreate, /* True for xCreate, false for xConnect */
136752 char **pzErr /* OUT: Error message, if any */
136753 ){
136754 int rc;
136755 char *zSql;
136756 if( isCreate ){
136757 int iPageSize = 0;
@@ -136556,17 +136760,22 @@
136760 if( rc==SQLITE_OK ){
136761 pRtree->iNodeSize = iPageSize-64;
136762 if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
136763 pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
136764 }
136765 }else{
136766 *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136767 }
136768 }else{
136769 zSql = sqlite3_mprintf(
136770 "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
136771 pRtree->zDb, pRtree->zName
136772 );
136773 rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
136774 if( rc!=SQLITE_OK ){
136775 *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
136776 }
136777 }
136778
136779 sqlite3_free(zSql);
136780 return rc;
136781 }
@@ -136626,11 +136835,11 @@
136835 pRtree->eCoordType = eCoordType;
136836 memcpy(pRtree->zDb, argv[1], nDb);
136837 memcpy(pRtree->zName, argv[2], nName);
136838
136839 /* Figure out the node size to use. */
136840 rc = getNodeSize(db, pRtree, isCreate, pzErr);
136841
136842 /* Create/Connect to the underlying relational database schema. If
136843 ** that is successful, call sqlite3_declare_vtab() to configure
136844 ** the r-tree table schema.
136845 */
136846
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.7.16"
111111
#define SQLITE_VERSION_NUMBER 3007016
112
-#define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
112
+#define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
118118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.16"
111 #define SQLITE_VERSION_NUMBER 3007016
112 #define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.16"
111 #define SQLITE_VERSION_NUMBER 3007016
112 #define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.7.16"
111111
#define SQLITE_VERSION_NUMBER 3007016
112
-#define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
112
+#define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
118118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.16"
111 #define SQLITE_VERSION_NUMBER 3007016
112 #define SQLITE_SOURCE_ID "2012-12-21 16:15:35 ff6857b6ed6a46671006b75157d8cf853a816ef9"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.16"
111 #define SQLITE_VERSION_NUMBER 3007016
112 #define SQLITE_SOURCE_ID "2013-01-17 17:20:49 38852f158ab20bb4d7b264af987ec1538052bec3"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
+104 -6
--- src/stat.c
+++ src/stat.c
@@ -66,11 +66,11 @@
6666
@ </td></tr>
6767
if( !brief ){
6868
@ <tr><th>Number&nbsp;Of&nbsp;Artifacts:</th><td>
6969
n = db_int(0, "SELECT count(*) FROM blob");
7070
m = db_int(0, "SELECT count(*) FROM delta");
71
- @ %d(n) (stored as %d(n-m) full text and %d(m) delta blobs)
71
+ @ %d(n) (%d(n-m) fulltext and %d(m) deltas)
7272
@ </td></tr>
7373
if( n>0 ){
7474
int a, b;
7575
Stmt q;
7676
@ <tr><th>Uncompressed&nbsp;Artifact&nbsp;Size:</th><td>
@@ -94,11 +94,11 @@
9494
a = t/fsize;
9595
@ %d(a):%d(b)
9696
@ </td></tr>
9797
}
9898
@ <tr><th>Number&nbsp;Of&nbsp;Check-ins:</th><td>
99
- n = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/");
99
+ n = db_int(0, "SELECT count(*) FROM event WHERE type='ci' /*scan*/");
100100
@ %d(n)
101101
@ </td></tr>
102102
@ <tr><th>Number&nbsp;Of&nbsp;Files:</th><td>
103103
n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
104104
@ %d(n)
@@ -115,17 +115,16 @@
115115
@ </td></tr>
116116
}
117117
@ <tr><th>Duration&nbsp;Of&nbsp;Project:</th><td>
118118
n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
119119
" + 0.99");
120
- @ %d(n) days or approximately %.2f(n/365.24) years.
120
+ @ %d(n) days or approximately %.2f(n/365.2425) years.
121121
@ </td></tr>
122122
@ <tr><th>Project&nbsp;ID:</th><td>%h(db_get("project-code",""))</td></tr>
123
- @ <tr><th>Server&nbsp;ID:</th><td>%h(db_get("server-code",""))</td></tr>
124123
@ <tr><th>Fossil&nbsp;Version:</th><td>
125
- @ %h(RELEASE_VERSION) %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
126
- @ (%h(COMPILER_NAME))
124
+ @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
125
+ @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
127126
@ </td></tr>
128127
@ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(SQLITE_SOURCE_ID)
129128
@ [%.10s(&SQLITE_SOURCE_ID[20])] (%s(SQLITE_VERSION))</td></tr>
130129
@ <tr><th>Database&nbsp;Stats:</th><td>
131130
zDb = db_name("repository");
@@ -137,10 +136,109 @@
137136
@ </td></tr>
138137
139138
@ </table>
140139
style_footer();
141140
}
141
+
142
+/*
143
+** COMMAND: dbstat*
144
+**
145
+** Usage: %fossil dbstat ?-brief | -b?
146
+**
147
+** Shows statistics and global information about the repository.
148
+**
149
+** The (-brief|-b) option removes any "long-running" statistics, namely
150
+** those whose calculations are known to slow down as the repository
151
+** grows.
152
+**
153
+*/
154
+void dbstat_cmd(void){
155
+ i64 t, fsize;
156
+ int n, m;
157
+ int szMax, szAvg;
158
+ const char *zDb;
159
+ int brief;
160
+ char zBuf[100];
161
+ const int colWidth = -20 /* printf alignment/width for left column */;
162
+ brief = find_option("brief", "b",0)!=0;
163
+ db_find_and_open_repository(0,0);
164
+ fsize = file_size(g.zRepositoryName);
165
+ bigSizeName(sizeof(zBuf), zBuf, fsize);
166
+ fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
167
+ if( !brief ){
168
+ n = db_int(0, "SELECT count(*) FROM blob");
169
+ m = db_int(0, "SELECT count(*) FROM delta");
170
+ fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n",
171
+ colWidth, "artifact-count:",
172
+ n, n-m, m);
173
+ if( n>0 ){
174
+ int a, b;
175
+ Stmt q;
176
+ db_prepare(&q, "SELECT total(size), avg(size), max(size)"
177
+ " FROM blob WHERE size>0");
178
+ db_step(&q);
179
+ t = db_column_int64(&q, 0);
180
+ szAvg = db_column_int(&q, 1);
181
+ szMax = db_column_int(&q, 2);
182
+ db_finalize(&q);
183
+ bigSizeName(sizeof(zBuf), zBuf, t);
184
+ fossil_print( "%*s%d bytes average, "
185
+ "%d bytes max, %s total\n",
186
+ colWidth, "artifact-sizes:",
187
+ szAvg, szMax, zBuf);
188
+ if( t/fsize < 5 ){
189
+ b = 10;
190
+ fsize /= 10;
191
+ }else{
192
+ b = 1;
193
+ }
194
+ a = t/fsize;
195
+ fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b);
196
+ }
197
+ n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'");
198
+ fossil_print("%*s%d\n", colWidth, "checkins:", n);
199
+ n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
200
+ fossil_print("%*s%d across all branches\n", colWidth, "files:", n);
201
+ n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
202
+ " WHERE tagname GLOB 'wiki-*'");
203
+ m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='w'");
204
+ fossil_print("%*s%d (%d changes)\n", colWidth, "wikipages:", n, m);
205
+ n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
206
+ " WHERE tagname GLOB 'tkt-*'");
207
+ m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='t'");
208
+ fossil_print("%*s%d (%d changes)\n", colWidth, "tickets:", n, m);
209
+ n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='e'");
210
+ fossil_print("%*s%d\n", colWidth, "events:", n);
211
+ n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='g'");
212
+ fossil_print("%*s%d\n", colWidth, "tagchanges:", n);
213
+ }
214
+ n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
215
+ " + 0.99");
216
+ fossil_print("%*s%d days or approximately %.2f years.\n",
217
+ colWidth, "project-age:", n, n/365.2425);
218
+ fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
219
+ fossil_print("%*s%s %s %s (%s)\n",
220
+ colWidth, "fossil-version:",
221
+ RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION,
222
+ COMPILER_NAME);
223
+ fossil_print("%*s%.19s [%.10s] (%s)\n",
224
+ colWidth, "sqlite-version:",
225
+ SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20],
226
+ SQLITE_VERSION);
227
+ zDb = db_name("repository");
228
+ fossil_print("%*s%d pages, %d bytes/page, %d free pages, "
229
+ "%s, %s mode\n",
230
+ colWidth, "database-stats:",
231
+ db_int(0, "PRAGMA %s.page_count", zDb),
232
+ db_int(0, "PRAGMA %s.page_size", zDb),
233
+ db_int(0, "PRAGMA %s.freelist_count", zDb),
234
+ db_text(0, "PRAGMA %s.encoding", zDb),
235
+ db_text(0, "PRAGMA %s.journal_mode", zDb));
236
+
237
+}
238
+
239
+
142240
143241
/*
144242
** WEBPAGE: urllist
145243
**
146244
** Show ways in which this repository has been accessed
147245
--- src/stat.c
+++ src/stat.c
@@ -66,11 +66,11 @@
66 @ </td></tr>
67 if( !brief ){
68 @ <tr><th>Number&nbsp;Of&nbsp;Artifacts:</th><td>
69 n = db_int(0, "SELECT count(*) FROM blob");
70 m = db_int(0, "SELECT count(*) FROM delta");
71 @ %d(n) (stored as %d(n-m) full text and %d(m) delta blobs)
72 @ </td></tr>
73 if( n>0 ){
74 int a, b;
75 Stmt q;
76 @ <tr><th>Uncompressed&nbsp;Artifact&nbsp;Size:</th><td>
@@ -94,11 +94,11 @@
94 a = t/fsize;
95 @ %d(a):%d(b)
96 @ </td></tr>
97 }
98 @ <tr><th>Number&nbsp;Of&nbsp;Check-ins:</th><td>
99 n = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/");
100 @ %d(n)
101 @ </td></tr>
102 @ <tr><th>Number&nbsp;Of&nbsp;Files:</th><td>
103 n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
104 @ %d(n)
@@ -115,17 +115,16 @@
115 @ </td></tr>
116 }
117 @ <tr><th>Duration&nbsp;Of&nbsp;Project:</th><td>
118 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
119 " + 0.99");
120 @ %d(n) days or approximately %.2f(n/365.24) years.
121 @ </td></tr>
122 @ <tr><th>Project&nbsp;ID:</th><td>%h(db_get("project-code",""))</td></tr>
123 @ <tr><th>Server&nbsp;ID:</th><td>%h(db_get("server-code",""))</td></tr>
124 @ <tr><th>Fossil&nbsp;Version:</th><td>
125 @ %h(RELEASE_VERSION) %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
126 @ (%h(COMPILER_NAME))
127 @ </td></tr>
128 @ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(SQLITE_SOURCE_ID)
129 @ [%.10s(&SQLITE_SOURCE_ID[20])] (%s(SQLITE_VERSION))</td></tr>
130 @ <tr><th>Database&nbsp;Stats:</th><td>
131 zDb = db_name("repository");
@@ -137,10 +136,109 @@
137 @ </td></tr>
138
139 @ </table>
140 style_footer();
141 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
143 /*
144 ** WEBPAGE: urllist
145 **
146 ** Show ways in which this repository has been accessed
147
--- src/stat.c
+++ src/stat.c
@@ -66,11 +66,11 @@
66 @ </td></tr>
67 if( !brief ){
68 @ <tr><th>Number&nbsp;Of&nbsp;Artifacts:</th><td>
69 n = db_int(0, "SELECT count(*) FROM blob");
70 m = db_int(0, "SELECT count(*) FROM delta");
71 @ %d(n) (%d(n-m) fulltext and %d(m) deltas)
72 @ </td></tr>
73 if( n>0 ){
74 int a, b;
75 Stmt q;
76 @ <tr><th>Uncompressed&nbsp;Artifact&nbsp;Size:</th><td>
@@ -94,11 +94,11 @@
94 a = t/fsize;
95 @ %d(a):%d(b)
96 @ </td></tr>
97 }
98 @ <tr><th>Number&nbsp;Of&nbsp;Check-ins:</th><td>
99 n = db_int(0, "SELECT count(*) FROM event WHERE type='ci' /*scan*/");
100 @ %d(n)
101 @ </td></tr>
102 @ <tr><th>Number&nbsp;Of&nbsp;Files:</th><td>
103 n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
104 @ %d(n)
@@ -115,17 +115,16 @@
115 @ </td></tr>
116 }
117 @ <tr><th>Duration&nbsp;Of&nbsp;Project:</th><td>
118 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
119 " + 0.99");
120 @ %d(n) days or approximately %.2f(n/365.2425) years.
121 @ </td></tr>
122 @ <tr><th>Project&nbsp;ID:</th><td>%h(db_get("project-code",""))</td></tr>
 
123 @ <tr><th>Fossil&nbsp;Version:</th><td>
124 @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
125 @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
126 @ </td></tr>
127 @ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(SQLITE_SOURCE_ID)
128 @ [%.10s(&SQLITE_SOURCE_ID[20])] (%s(SQLITE_VERSION))</td></tr>
129 @ <tr><th>Database&nbsp;Stats:</th><td>
130 zDb = db_name("repository");
@@ -137,10 +136,109 @@
136 @ </td></tr>
137
138 @ </table>
139 style_footer();
140 }
141
142 /*
143 ** COMMAND: dbstat*
144 **
145 ** Usage: %fossil dbstat ?-brief | -b?
146 **
147 ** Shows statistics and global information about the repository.
148 **
149 ** The (-brief|-b) option removes any "long-running" statistics, namely
150 ** those whose calculations are known to slow down as the repository
151 ** grows.
152 **
153 */
154 void dbstat_cmd(void){
155 i64 t, fsize;
156 int n, m;
157 int szMax, szAvg;
158 const char *zDb;
159 int brief;
160 char zBuf[100];
161 const int colWidth = -20 /* printf alignment/width for left column */;
162 brief = find_option("brief", "b",0)!=0;
163 db_find_and_open_repository(0,0);
164 fsize = file_size(g.zRepositoryName);
165 bigSizeName(sizeof(zBuf), zBuf, fsize);
166 fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
167 if( !brief ){
168 n = db_int(0, "SELECT count(*) FROM blob");
169 m = db_int(0, "SELECT count(*) FROM delta");
170 fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n",
171 colWidth, "artifact-count:",
172 n, n-m, m);
173 if( n>0 ){
174 int a, b;
175 Stmt q;
176 db_prepare(&q, "SELECT total(size), avg(size), max(size)"
177 " FROM blob WHERE size>0");
178 db_step(&q);
179 t = db_column_int64(&q, 0);
180 szAvg = db_column_int(&q, 1);
181 szMax = db_column_int(&q, 2);
182 db_finalize(&q);
183 bigSizeName(sizeof(zBuf), zBuf, t);
184 fossil_print( "%*s%d bytes average, "
185 "%d bytes max, %s total\n",
186 colWidth, "artifact-sizes:",
187 szAvg, szMax, zBuf);
188 if( t/fsize < 5 ){
189 b = 10;
190 fsize /= 10;
191 }else{
192 b = 1;
193 }
194 a = t/fsize;
195 fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b);
196 }
197 n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'");
198 fossil_print("%*s%d\n", colWidth, "checkins:", n);
199 n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
200 fossil_print("%*s%d across all branches\n", colWidth, "files:", n);
201 n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
202 " WHERE tagname GLOB 'wiki-*'");
203 m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='w'");
204 fossil_print("%*s%d (%d changes)\n", colWidth, "wikipages:", n, m);
205 n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
206 " WHERE tagname GLOB 'tkt-*'");
207 m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='t'");
208 fossil_print("%*s%d (%d changes)\n", colWidth, "tickets:", n, m);
209 n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='e'");
210 fossil_print("%*s%d\n", colWidth, "events:", n);
211 n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='g'");
212 fossil_print("%*s%d\n", colWidth, "tagchanges:", n);
213 }
214 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
215 " + 0.99");
216 fossil_print("%*s%d days or approximately %.2f years.\n",
217 colWidth, "project-age:", n, n/365.2425);
218 fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
219 fossil_print("%*s%s %s %s (%s)\n",
220 colWidth, "fossil-version:",
221 RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION,
222 COMPILER_NAME);
223 fossil_print("%*s%.19s [%.10s] (%s)\n",
224 colWidth, "sqlite-version:",
225 SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20],
226 SQLITE_VERSION);
227 zDb = db_name("repository");
228 fossil_print("%*s%d pages, %d bytes/page, %d free pages, "
229 "%s, %s mode\n",
230 colWidth, "database-stats:",
231 db_int(0, "PRAGMA %s.page_count", zDb),
232 db_int(0, "PRAGMA %s.page_size", zDb),
233 db_int(0, "PRAGMA %s.freelist_count", zDb),
234 db_text(0, "PRAGMA %s.encoding", zDb),
235 db_text(0, "PRAGMA %s.journal_mode", zDb));
236
237 }
238
239
240
241 /*
242 ** WEBPAGE: urllist
243 **
244 ** Show ways in which this repository has been accessed
245
+104 -6
--- src/stat.c
+++ src/stat.c
@@ -66,11 +66,11 @@
6666
@ </td></tr>
6767
if( !brief ){
6868
@ <tr><th>Number&nbsp;Of&nbsp;Artifacts:</th><td>
6969
n = db_int(0, "SELECT count(*) FROM blob");
7070
m = db_int(0, "SELECT count(*) FROM delta");
71
- @ %d(n) (stored as %d(n-m) full text and %d(m) delta blobs)
71
+ @ %d(n) (%d(n-m) fulltext and %d(m) deltas)
7272
@ </td></tr>
7373
if( n>0 ){
7474
int a, b;
7575
Stmt q;
7676
@ <tr><th>Uncompressed&nbsp;Artifact&nbsp;Size:</th><td>
@@ -94,11 +94,11 @@
9494
a = t/fsize;
9595
@ %d(a):%d(b)
9696
@ </td></tr>
9797
}
9898
@ <tr><th>Number&nbsp;Of&nbsp;Check-ins:</th><td>
99
- n = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/");
99
+ n = db_int(0, "SELECT count(*) FROM event WHERE type='ci' /*scan*/");
100100
@ %d(n)
101101
@ </td></tr>
102102
@ <tr><th>Number&nbsp;Of&nbsp;Files:</th><td>
103103
n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
104104
@ %d(n)
@@ -115,17 +115,16 @@
115115
@ </td></tr>
116116
}
117117
@ <tr><th>Duration&nbsp;Of&nbsp;Project:</th><td>
118118
n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
119119
" + 0.99");
120
- @ %d(n) days or approximately %.2f(n/365.24) years.
120
+ @ %d(n) days or approximately %.2f(n/365.2425) years.
121121
@ </td></tr>
122122
@ <tr><th>Project&nbsp;ID:</th><td>%h(db_get("project-code",""))</td></tr>
123
- @ <tr><th>Server&nbsp;ID:</th><td>%h(db_get("server-code",""))</td></tr>
124123
@ <tr><th>Fossil&nbsp;Version:</th><td>
125
- @ %h(RELEASE_VERSION) %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
126
- @ (%h(COMPILER_NAME))
124
+ @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
125
+ @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
127126
@ </td></tr>
128127
@ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(SQLITE_SOURCE_ID)
129128
@ [%.10s(&SQLITE_SOURCE_ID[20])] (%s(SQLITE_VERSION))</td></tr>
130129
@ <tr><th>Database&nbsp;Stats:</th><td>
131130
zDb = db_name("repository");
@@ -137,10 +136,109 @@
137136
@ </td></tr>
138137
139138
@ </table>
140139
style_footer();
141140
}
141
+
142
+/*
143
+** COMMAND: dbstat*
144
+**
145
+** Usage: %fossil dbstat ?-brief | -b?
146
+**
147
+** Shows statistics and global information about the repository.
148
+**
149
+** The (-brief|-b) option removes any "long-running" statistics, namely
150
+** those whose calculations are known to slow down as the repository
151
+** grows.
152
+**
153
+*/
154
+void dbstat_cmd(void){
155
+ i64 t, fsize;
156
+ int n, m;
157
+ int szMax, szAvg;
158
+ const char *zDb;
159
+ int brief;
160
+ char zBuf[100];
161
+ const int colWidth = -20 /* printf alignment/width for left column */;
162
+ brief = find_option("brief", "b",0)!=0;
163
+ db_find_and_open_repository(0,0);
164
+ fsize = file_size(g.zRepositoryName);
165
+ bigSizeName(sizeof(zBuf), zBuf, fsize);
166
+ fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
167
+ if( !brief ){
168
+ n = db_int(0, "SELECT count(*) FROM blob");
169
+ m = db_int(0, "SELECT count(*) FROM delta");
170
+ fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n",
171
+ colWidth, "artifact-count:",
172
+ n, n-m, m);
173
+ if( n>0 ){
174
+ int a, b;
175
+ Stmt q;
176
+ db_prepare(&q, "SELECT total(size), avg(size), max(size)"
177
+ " FROM blob WHERE size>0");
178
+ db_step(&q);
179
+ t = db_column_int64(&q, 0);
180
+ szAvg = db_column_int(&q, 1);
181
+ szMax = db_column_int(&q, 2);
182
+ db_finalize(&q);
183
+ bigSizeName(sizeof(zBuf), zBuf, t);
184
+ fossil_print( "%*s%d bytes average, "
185
+ "%d bytes max, %s total\n",
186
+ colWidth, "artifact-sizes:",
187
+ szAvg, szMax, zBuf);
188
+ if( t/fsize < 5 ){
189
+ b = 10;
190
+ fsize /= 10;
191
+ }else{
192
+ b = 1;
193
+ }
194
+ a = t/fsize;
195
+ fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b);
196
+ }
197
+ n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'");
198
+ fossil_print("%*s%d\n", colWidth, "checkins:", n);
199
+ n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
200
+ fossil_print("%*s%d across all branches\n", colWidth, "files:", n);
201
+ n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
202
+ " WHERE tagname GLOB 'wiki-*'");
203
+ m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='w'");
204
+ fossil_print("%*s%d (%d changes)\n", colWidth, "wikipages:", n, m);
205
+ n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
206
+ " WHERE tagname GLOB 'tkt-*'");
207
+ m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='t'");
208
+ fossil_print("%*s%d (%d changes)\n", colWidth, "tickets:", n, m);
209
+ n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='e'");
210
+ fossil_print("%*s%d\n", colWidth, "events:", n);
211
+ n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='g'");
212
+ fossil_print("%*s%d\n", colWidth, "tagchanges:", n);
213
+ }
214
+ n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
215
+ " + 0.99");
216
+ fossil_print("%*s%d days or approximately %.2f years.\n",
217
+ colWidth, "project-age:", n, n/365.2425);
218
+ fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
219
+ fossil_print("%*s%s %s %s (%s)\n",
220
+ colWidth, "fossil-version:",
221
+ RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION,
222
+ COMPILER_NAME);
223
+ fossil_print("%*s%.19s [%.10s] (%s)\n",
224
+ colWidth, "sqlite-version:",
225
+ SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20],
226
+ SQLITE_VERSION);
227
+ zDb = db_name("repository");
228
+ fossil_print("%*s%d pages, %d bytes/page, %d free pages, "
229
+ "%s, %s mode\n",
230
+ colWidth, "database-stats:",
231
+ db_int(0, "PRAGMA %s.page_count", zDb),
232
+ db_int(0, "PRAGMA %s.page_size", zDb),
233
+ db_int(0, "PRAGMA %s.freelist_count", zDb),
234
+ db_text(0, "PRAGMA %s.encoding", zDb),
235
+ db_text(0, "PRAGMA %s.journal_mode", zDb));
236
+
237
+}
238
+
239
+
142240
143241
/*
144242
** WEBPAGE: urllist
145243
**
146244
** Show ways in which this repository has been accessed
147245
--- src/stat.c
+++ src/stat.c
@@ -66,11 +66,11 @@
66 @ </td></tr>
67 if( !brief ){
68 @ <tr><th>Number&nbsp;Of&nbsp;Artifacts:</th><td>
69 n = db_int(0, "SELECT count(*) FROM blob");
70 m = db_int(0, "SELECT count(*) FROM delta");
71 @ %d(n) (stored as %d(n-m) full text and %d(m) delta blobs)
72 @ </td></tr>
73 if( n>0 ){
74 int a, b;
75 Stmt q;
76 @ <tr><th>Uncompressed&nbsp;Artifact&nbsp;Size:</th><td>
@@ -94,11 +94,11 @@
94 a = t/fsize;
95 @ %d(a):%d(b)
96 @ </td></tr>
97 }
98 @ <tr><th>Number&nbsp;Of&nbsp;Check-ins:</th><td>
99 n = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/");
100 @ %d(n)
101 @ </td></tr>
102 @ <tr><th>Number&nbsp;Of&nbsp;Files:</th><td>
103 n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
104 @ %d(n)
@@ -115,17 +115,16 @@
115 @ </td></tr>
116 }
117 @ <tr><th>Duration&nbsp;Of&nbsp;Project:</th><td>
118 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
119 " + 0.99");
120 @ %d(n) days or approximately %.2f(n/365.24) years.
121 @ </td></tr>
122 @ <tr><th>Project&nbsp;ID:</th><td>%h(db_get("project-code",""))</td></tr>
123 @ <tr><th>Server&nbsp;ID:</th><td>%h(db_get("server-code",""))</td></tr>
124 @ <tr><th>Fossil&nbsp;Version:</th><td>
125 @ %h(RELEASE_VERSION) %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
126 @ (%h(COMPILER_NAME))
127 @ </td></tr>
128 @ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(SQLITE_SOURCE_ID)
129 @ [%.10s(&SQLITE_SOURCE_ID[20])] (%s(SQLITE_VERSION))</td></tr>
130 @ <tr><th>Database&nbsp;Stats:</th><td>
131 zDb = db_name("repository");
@@ -137,10 +136,109 @@
137 @ </td></tr>
138
139 @ </table>
140 style_footer();
141 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
143 /*
144 ** WEBPAGE: urllist
145 **
146 ** Show ways in which this repository has been accessed
147
--- src/stat.c
+++ src/stat.c
@@ -66,11 +66,11 @@
66 @ </td></tr>
67 if( !brief ){
68 @ <tr><th>Number&nbsp;Of&nbsp;Artifacts:</th><td>
69 n = db_int(0, "SELECT count(*) FROM blob");
70 m = db_int(0, "SELECT count(*) FROM delta");
71 @ %d(n) (%d(n-m) fulltext and %d(m) deltas)
72 @ </td></tr>
73 if( n>0 ){
74 int a, b;
75 Stmt q;
76 @ <tr><th>Uncompressed&nbsp;Artifact&nbsp;Size:</th><td>
@@ -94,11 +94,11 @@
94 a = t/fsize;
95 @ %d(a):%d(b)
96 @ </td></tr>
97 }
98 @ <tr><th>Number&nbsp;Of&nbsp;Check-ins:</th><td>
99 n = db_int(0, "SELECT count(*) FROM event WHERE type='ci' /*scan*/");
100 @ %d(n)
101 @ </td></tr>
102 @ <tr><th>Number&nbsp;Of&nbsp;Files:</th><td>
103 n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
104 @ %d(n)
@@ -115,17 +115,16 @@
115 @ </td></tr>
116 }
117 @ <tr><th>Duration&nbsp;Of&nbsp;Project:</th><td>
118 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
119 " + 0.99");
120 @ %d(n) days or approximately %.2f(n/365.2425) years.
121 @ </td></tr>
122 @ <tr><th>Project&nbsp;ID:</th><td>%h(db_get("project-code",""))</td></tr>
 
123 @ <tr><th>Fossil&nbsp;Version:</th><td>
124 @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
125 @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
126 @ </td></tr>
127 @ <tr><th>SQLite&nbsp;Version:</th><td>%.19s(SQLITE_SOURCE_ID)
128 @ [%.10s(&SQLITE_SOURCE_ID[20])] (%s(SQLITE_VERSION))</td></tr>
129 @ <tr><th>Database&nbsp;Stats:</th><td>
130 zDb = db_name("repository");
@@ -137,10 +136,109 @@
136 @ </td></tr>
137
138 @ </table>
139 style_footer();
140 }
141
142 /*
143 ** COMMAND: dbstat*
144 **
145 ** Usage: %fossil dbstat ?-brief | -b?
146 **
147 ** Shows statistics and global information about the repository.
148 **
149 ** The (-brief|-b) option removes any "long-running" statistics, namely
150 ** those whose calculations are known to slow down as the repository
151 ** grows.
152 **
153 */
154 void dbstat_cmd(void){
155 i64 t, fsize;
156 int n, m;
157 int szMax, szAvg;
158 const char *zDb;
159 int brief;
160 char zBuf[100];
161 const int colWidth = -20 /* printf alignment/width for left column */;
162 brief = find_option("brief", "b",0)!=0;
163 db_find_and_open_repository(0,0);
164 fsize = file_size(g.zRepositoryName);
165 bigSizeName(sizeof(zBuf), zBuf, fsize);
166 fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf );
167 if( !brief ){
168 n = db_int(0, "SELECT count(*) FROM blob");
169 m = db_int(0, "SELECT count(*) FROM delta");
170 fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n",
171 colWidth, "artifact-count:",
172 n, n-m, m);
173 if( n>0 ){
174 int a, b;
175 Stmt q;
176 db_prepare(&q, "SELECT total(size), avg(size), max(size)"
177 " FROM blob WHERE size>0");
178 db_step(&q);
179 t = db_column_int64(&q, 0);
180 szAvg = db_column_int(&q, 1);
181 szMax = db_column_int(&q, 2);
182 db_finalize(&q);
183 bigSizeName(sizeof(zBuf), zBuf, t);
184 fossil_print( "%*s%d bytes average, "
185 "%d bytes max, %s total\n",
186 colWidth, "artifact-sizes:",
187 szAvg, szMax, zBuf);
188 if( t/fsize < 5 ){
189 b = 10;
190 fsize /= 10;
191 }else{
192 b = 1;
193 }
194 a = t/fsize;
195 fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b);
196 }
197 n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'");
198 fossil_print("%*s%d\n", colWidth, "checkins:", n);
199 n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
200 fossil_print("%*s%d across all branches\n", colWidth, "files:", n);
201 n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
202 " WHERE tagname GLOB 'wiki-*'");
203 m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='w'");
204 fossil_print("%*s%d (%d changes)\n", colWidth, "wikipages:", n, m);
205 n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
206 " WHERE tagname GLOB 'tkt-*'");
207 m = db_int(0, "SELECT COUNT(*) FROM event WHERE type='t'");
208 fossil_print("%*s%d (%d changes)\n", colWidth, "tickets:", n, m);
209 n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='e'");
210 fossil_print("%*s%d\n", colWidth, "events:", n);
211 n = db_int(0, "SELECT COUNT(*) FROM event WHERE type='g'");
212 fossil_print("%*s%d\n", colWidth, "tagchanges:", n);
213 }
214 n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
215 " + 0.99");
216 fossil_print("%*s%d days or approximately %.2f years.\n",
217 colWidth, "project-age:", n, n/365.2425);
218 fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
219 fossil_print("%*s%s %s %s (%s)\n",
220 colWidth, "fossil-version:",
221 RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION,
222 COMPILER_NAME);
223 fossil_print("%*s%.19s [%.10s] (%s)\n",
224 colWidth, "sqlite-version:",
225 SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20],
226 SQLITE_VERSION);
227 zDb = db_name("repository");
228 fossil_print("%*s%d pages, %d bytes/page, %d free pages, "
229 "%s, %s mode\n",
230 colWidth, "database-stats:",
231 db_int(0, "PRAGMA %s.page_count", zDb),
232 db_int(0, "PRAGMA %s.page_size", zDb),
233 db_int(0, "PRAGMA %s.freelist_count", zDb),
234 db_text(0, "PRAGMA %s.encoding", zDb),
235 db_text(0, "PRAGMA %s.journal_mode", zDb));
236
237 }
238
239
240
241 /*
242 ** WEBPAGE: urllist
243 **
244 ** Show ways in which this repository has been accessed
245
+20 -35
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210210
if( tmFlags & TIMELINE_GRAPH ){
211211
pGraph = graph_init();
212212
/* style is not moved to css, because this is
213213
** a technical div for the timeline graph
214214
*/
215
- @ <div id="canvas" style="position:relative;width:1px;height:1px;"
215
+ @ <div id="canvas" style="position:relative;height:0px;width:0px;"
216216
@ onclick="clickOnGraph(event)"></div>
217217
}
218218
db_static_prepare(&qbranch,
219219
"SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220220
TAG_BRANCH
221221
);
222222
223
- @ <table id="timelineTable" class="timelineTable">
223
+ @ <table id="timelineTable" class="timelineTable"
224
+ @ onclick="clickOnGraph(event)">
224225
blob_zero(&comment);
225226
while( db_step(pQuery)==SQLITE_ROW ){
226227
int rid = db_column_int(pQuery, 0);
227228
const char *zUuid = db_column_text(pQuery, 1);
228229
int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
726727
@ for(var i in rowinfo){
727728
@ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
728729
@ rowinfo[i].x = left + rowinfo[i].r*railPitch;
729730
@ }
730731
@ var btm = absoluteY("grbtm") + 10 - canvasY;
731
-#if 0
732
- @ if( btm<32768 ){
733
- @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+
734
- @ 'style="position:absolute;left:'+(left-5)+'px;"' +
735
- @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>';
736
- @ realCanvas = gebi('timeline-canvas');
737
- @ }else{
738
- @ realCanvas = 0;
739
- @ }
740
- @ var context;
741
- @ if( realCanvas && realCanvas.getContext
742
- @ && (context = realCanvas.getContext('2d'))) {
743
- @ drawBox = function(color,x0,y0,x1,y1) {
744
- @ if( y0>32767 || y1>32767 ) return;
745
- @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
746
- @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
747
- @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return;
748
- @ context.fillStyle = color;
749
- @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1);
750
- @ };
751
- @ }
752
-#endif
753732
@ for(var i in rowinfo){
754733
@ drawNode(rowinfo[i], left, btm);
755734
@ }
756735
@ if( selRow!=null ) clickOnRow(selRow);
757736
@ }
758737
@ function clickOnGraph(event){
759
-#ifdef OMIT_IE8_SUPPORT
760
- @ var x=event.clientX-absoluteX("canvas")+window.pageXOffset;
761
- @ var y=event.clientY-absoluteY("canvas")+window.pageYOffset;
762
-#else
763738
@ var x=event.clientX-absoluteX("canvas");
764739
@ var y=event.clientY-absoluteY("canvas");
765740
@ if(window.pageXOffset!=null){
766741
@ x += window.pageXOffset;
767742
@ y += window.pageYOffset;
@@ -769,16 +744,18 @@
769744
@ var d = window.document.documentElement;
770745
@ if(document.compatMode!="CSS1Compat") d = d.body;
771746
@ x += d.scrollLeft;
772747
@ y += d.scrollTop;
773748
@ }
774
-#endif
749
+ if( P("clicktest")!=0 ){
750
+ @ alert("click at "+x+","+y)
751
+ }
775752
@ for(var i in rowinfo){
776753
@ p = rowinfo[i];
777
- @ if( p.y<y-10 ) continue;
778
- @ if( p.y>y+10 ) break;
779
- @ if( p.x>x-10 && p.x<x+10 ){
754
+ @ if( p.y<y-11 ) continue;
755
+ @ if( p.y>y+9 ) break;
756
+ @ if( p.x>x-11 && p.x<x+9 ){
780757
@ clickOnRow(p);
781758
@ break;
782759
@ }
783760
@ }
784761
@ }
@@ -1414,10 +1391,12 @@
14141391
** 1. uuid
14151392
** 2. Date/Time
14161393
** 3. Comment string and user
14171394
** 4. Number of non-merge children
14181395
** 5. Number of parents
1396
+** 6. mtime
1397
+** 7. branch
14191398
*/
14201399
void print_timeline(Stmt *q, int mxLine, int showfiles){
14211400
int nLine = 0;
14221401
char zPrevDate[20];
14231402
const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
15221501
@ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
15231502
@ FROM tag, tagxref
15241503
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
15251504
@ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
15261505
@ || ')' as comment,
1527
- @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount,
1506
+ @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
1507
+ @ AS primPlinkCount,
15281508
@ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1529
- @ event.mtime AS mtime
1530
- @ FROM event, blob
1509
+ @ event.mtime AS mtime,
1510
+ @ tagxref.value AS branch
1511
+ @ FROM tag CROSS JOIN event CROSS JOIN blob
1512
+ @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
1513
+ @ AND tagxref.tagtype>0
1514
+ @ AND tagxref.rid=blob.rid
15311515
@ WHERE blob.rid=event.objid
1516
+ @ AND tag.tagname='branch'
15321517
;
15331518
return zBaseSql;
15341519
}
15351520
15361521
/*
15371522
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210 if( tmFlags & TIMELINE_GRAPH ){
211 pGraph = graph_init();
212 /* style is not moved to css, because this is
213 ** a technical div for the timeline graph
214 */
215 @ <div id="canvas" style="position:relative;width:1px;height:1px;"
216 @ onclick="clickOnGraph(event)"></div>
217 }
218 db_static_prepare(&qbranch,
219 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220 TAG_BRANCH
221 );
222
223 @ <table id="timelineTable" class="timelineTable">
 
224 blob_zero(&comment);
225 while( db_step(pQuery)==SQLITE_ROW ){
226 int rid = db_column_int(pQuery, 0);
227 const char *zUuid = db_column_text(pQuery, 1);
228 int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
726 @ for(var i in rowinfo){
727 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
728 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
729 @ }
730 @ var btm = absoluteY("grbtm") + 10 - canvasY;
731 #if 0
732 @ if( btm<32768 ){
733 @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+
734 @ 'style="position:absolute;left:'+(left-5)+'px;"' +
735 @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>';
736 @ realCanvas = gebi('timeline-canvas');
737 @ }else{
738 @ realCanvas = 0;
739 @ }
740 @ var context;
741 @ if( realCanvas && realCanvas.getContext
742 @ && (context = realCanvas.getContext('2d'))) {
743 @ drawBox = function(color,x0,y0,x1,y1) {
744 @ if( y0>32767 || y1>32767 ) return;
745 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
746 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
747 @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return;
748 @ context.fillStyle = color;
749 @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1);
750 @ };
751 @ }
752 #endif
753 @ for(var i in rowinfo){
754 @ drawNode(rowinfo[i], left, btm);
755 @ }
756 @ if( selRow!=null ) clickOnRow(selRow);
757 @ }
758 @ function clickOnGraph(event){
759 #ifdef OMIT_IE8_SUPPORT
760 @ var x=event.clientX-absoluteX("canvas")+window.pageXOffset;
761 @ var y=event.clientY-absoluteY("canvas")+window.pageYOffset;
762 #else
763 @ var x=event.clientX-absoluteX("canvas");
764 @ var y=event.clientY-absoluteY("canvas");
765 @ if(window.pageXOffset!=null){
766 @ x += window.pageXOffset;
767 @ y += window.pageYOffset;
@@ -769,16 +744,18 @@
769 @ var d = window.document.documentElement;
770 @ if(document.compatMode!="CSS1Compat") d = d.body;
771 @ x += d.scrollLeft;
772 @ y += d.scrollTop;
773 @ }
774 #endif
 
 
775 @ for(var i in rowinfo){
776 @ p = rowinfo[i];
777 @ if( p.y<y-10 ) continue;
778 @ if( p.y>y+10 ) break;
779 @ if( p.x>x-10 && p.x<x+10 ){
780 @ clickOnRow(p);
781 @ break;
782 @ }
783 @ }
784 @ }
@@ -1414,10 +1391,12 @@
1414 ** 1. uuid
1415 ** 2. Date/Time
1416 ** 3. Comment string and user
1417 ** 4. Number of non-merge children
1418 ** 5. Number of parents
 
 
1419 */
1420 void print_timeline(Stmt *q, int mxLine, int showfiles){
1421 int nLine = 0;
1422 char zPrevDate[20];
1423 const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
1522 @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
1523 @ FROM tag, tagxref
1524 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
1525 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
1526 @ || ')' as comment,
1527 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount,
 
1528 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1529 @ event.mtime AS mtime
1530 @ FROM event, blob
 
 
 
 
1531 @ WHERE blob.rid=event.objid
 
1532 ;
1533 return zBaseSql;
1534 }
1535
1536 /*
1537
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210 if( tmFlags & TIMELINE_GRAPH ){
211 pGraph = graph_init();
212 /* style is not moved to css, because this is
213 ** a technical div for the timeline graph
214 */
215 @ <div id="canvas" style="position:relative;height:0px;width:0px;"
216 @ onclick="clickOnGraph(event)"></div>
217 }
218 db_static_prepare(&qbranch,
219 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220 TAG_BRANCH
221 );
222
223 @ <table id="timelineTable" class="timelineTable"
224 @ onclick="clickOnGraph(event)">
225 blob_zero(&comment);
226 while( db_step(pQuery)==SQLITE_ROW ){
227 int rid = db_column_int(pQuery, 0);
228 const char *zUuid = db_column_text(pQuery, 1);
229 int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
727 @ for(var i in rowinfo){
728 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
729 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
730 @ }
731 @ var btm = absoluteY("grbtm") + 10 - canvasY;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
732 @ for(var i in rowinfo){
733 @ drawNode(rowinfo[i], left, btm);
734 @ }
735 @ if( selRow!=null ) clickOnRow(selRow);
736 @ }
737 @ function clickOnGraph(event){
 
 
 
 
738 @ var x=event.clientX-absoluteX("canvas");
739 @ var y=event.clientY-absoluteY("canvas");
740 @ if(window.pageXOffset!=null){
741 @ x += window.pageXOffset;
742 @ y += window.pageYOffset;
@@ -769,16 +744,18 @@
744 @ var d = window.document.documentElement;
745 @ if(document.compatMode!="CSS1Compat") d = d.body;
746 @ x += d.scrollLeft;
747 @ y += d.scrollTop;
748 @ }
749 if( P("clicktest")!=0 ){
750 @ alert("click at "+x+","+y)
751 }
752 @ for(var i in rowinfo){
753 @ p = rowinfo[i];
754 @ if( p.y<y-11 ) continue;
755 @ if( p.y>y+9 ) break;
756 @ if( p.x>x-11 && p.x<x+9 ){
757 @ clickOnRow(p);
758 @ break;
759 @ }
760 @ }
761 @ }
@@ -1414,10 +1391,12 @@
1391 ** 1. uuid
1392 ** 2. Date/Time
1393 ** 3. Comment string and user
1394 ** 4. Number of non-merge children
1395 ** 5. Number of parents
1396 ** 6. mtime
1397 ** 7. branch
1398 */
1399 void print_timeline(Stmt *q, int mxLine, int showfiles){
1400 int nLine = 0;
1401 char zPrevDate[20];
1402 const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
1501 @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
1502 @ FROM tag, tagxref
1503 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
1504 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
1505 @ || ')' as comment,
1506 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
1507 @ AS primPlinkCount,
1508 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1509 @ event.mtime AS mtime,
1510 @ tagxref.value AS branch
1511 @ FROM tag CROSS JOIN event CROSS JOIN blob
1512 @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
1513 @ AND tagxref.tagtype>0
1514 @ AND tagxref.rid=blob.rid
1515 @ WHERE blob.rid=event.objid
1516 @ AND tag.tagname='branch'
1517 ;
1518 return zBaseSql;
1519 }
1520
1521 /*
1522
+20 -35
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210210
if( tmFlags & TIMELINE_GRAPH ){
211211
pGraph = graph_init();
212212
/* style is not moved to css, because this is
213213
** a technical div for the timeline graph
214214
*/
215
- @ <div id="canvas" style="position:relative;width:1px;height:1px;"
215
+ @ <div id="canvas" style="position:relative;height:0px;width:0px;"
216216
@ onclick="clickOnGraph(event)"></div>
217217
}
218218
db_static_prepare(&qbranch,
219219
"SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220220
TAG_BRANCH
221221
);
222222
223
- @ <table id="timelineTable" class="timelineTable">
223
+ @ <table id="timelineTable" class="timelineTable"
224
+ @ onclick="clickOnGraph(event)">
224225
blob_zero(&comment);
225226
while( db_step(pQuery)==SQLITE_ROW ){
226227
int rid = db_column_int(pQuery, 0);
227228
const char *zUuid = db_column_text(pQuery, 1);
228229
int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
726727
@ for(var i in rowinfo){
727728
@ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
728729
@ rowinfo[i].x = left + rowinfo[i].r*railPitch;
729730
@ }
730731
@ var btm = absoluteY("grbtm") + 10 - canvasY;
731
-#if 0
732
- @ if( btm<32768 ){
733
- @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+
734
- @ 'style="position:absolute;left:'+(left-5)+'px;"' +
735
- @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>';
736
- @ realCanvas = gebi('timeline-canvas');
737
- @ }else{
738
- @ realCanvas = 0;
739
- @ }
740
- @ var context;
741
- @ if( realCanvas && realCanvas.getContext
742
- @ && (context = realCanvas.getContext('2d'))) {
743
- @ drawBox = function(color,x0,y0,x1,y1) {
744
- @ if( y0>32767 || y1>32767 ) return;
745
- @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
746
- @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
747
- @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return;
748
- @ context.fillStyle = color;
749
- @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1);
750
- @ };
751
- @ }
752
-#endif
753732
@ for(var i in rowinfo){
754733
@ drawNode(rowinfo[i], left, btm);
755734
@ }
756735
@ if( selRow!=null ) clickOnRow(selRow);
757736
@ }
758737
@ function clickOnGraph(event){
759
-#ifdef OMIT_IE8_SUPPORT
760
- @ var x=event.clientX-absoluteX("canvas")+window.pageXOffset;
761
- @ var y=event.clientY-absoluteY("canvas")+window.pageYOffset;
762
-#else
763738
@ var x=event.clientX-absoluteX("canvas");
764739
@ var y=event.clientY-absoluteY("canvas");
765740
@ if(window.pageXOffset!=null){
766741
@ x += window.pageXOffset;
767742
@ y += window.pageYOffset;
@@ -769,16 +744,18 @@
769744
@ var d = window.document.documentElement;
770745
@ if(document.compatMode!="CSS1Compat") d = d.body;
771746
@ x += d.scrollLeft;
772747
@ y += d.scrollTop;
773748
@ }
774
-#endif
749
+ if( P("clicktest")!=0 ){
750
+ @ alert("click at "+x+","+y)
751
+ }
775752
@ for(var i in rowinfo){
776753
@ p = rowinfo[i];
777
- @ if( p.y<y-10 ) continue;
778
- @ if( p.y>y+10 ) break;
779
- @ if( p.x>x-10 && p.x<x+10 ){
754
+ @ if( p.y<y-11 ) continue;
755
+ @ if( p.y>y+9 ) break;
756
+ @ if( p.x>x-11 && p.x<x+9 ){
780757
@ clickOnRow(p);
781758
@ break;
782759
@ }
783760
@ }
784761
@ }
@@ -1414,10 +1391,12 @@
14141391
** 1. uuid
14151392
** 2. Date/Time
14161393
** 3. Comment string and user
14171394
** 4. Number of non-merge children
14181395
** 5. Number of parents
1396
+** 6. mtime
1397
+** 7. branch
14191398
*/
14201399
void print_timeline(Stmt *q, int mxLine, int showfiles){
14211400
int nLine = 0;
14221401
char zPrevDate[20];
14231402
const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
15221501
@ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
15231502
@ FROM tag, tagxref
15241503
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
15251504
@ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
15261505
@ || ')' as comment,
1527
- @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount,
1506
+ @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
1507
+ @ AS primPlinkCount,
15281508
@ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1529
- @ event.mtime AS mtime
1530
- @ FROM event, blob
1509
+ @ event.mtime AS mtime,
1510
+ @ tagxref.value AS branch
1511
+ @ FROM tag CROSS JOIN event CROSS JOIN blob
1512
+ @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
1513
+ @ AND tagxref.tagtype>0
1514
+ @ AND tagxref.rid=blob.rid
15311515
@ WHERE blob.rid=event.objid
1516
+ @ AND tag.tagname='branch'
15321517
;
15331518
return zBaseSql;
15341519
}
15351520
15361521
/*
15371522
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210 if( tmFlags & TIMELINE_GRAPH ){
211 pGraph = graph_init();
212 /* style is not moved to css, because this is
213 ** a technical div for the timeline graph
214 */
215 @ <div id="canvas" style="position:relative;width:1px;height:1px;"
216 @ onclick="clickOnGraph(event)"></div>
217 }
218 db_static_prepare(&qbranch,
219 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220 TAG_BRANCH
221 );
222
223 @ <table id="timelineTable" class="timelineTable">
 
224 blob_zero(&comment);
225 while( db_step(pQuery)==SQLITE_ROW ){
226 int rid = db_column_int(pQuery, 0);
227 const char *zUuid = db_column_text(pQuery, 1);
228 int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
726 @ for(var i in rowinfo){
727 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
728 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
729 @ }
730 @ var btm = absoluteY("grbtm") + 10 - canvasY;
731 #if 0
732 @ if( btm<32768 ){
733 @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+
734 @ 'style="position:absolute;left:'+(left-5)+'px;"' +
735 @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>';
736 @ realCanvas = gebi('timeline-canvas');
737 @ }else{
738 @ realCanvas = 0;
739 @ }
740 @ var context;
741 @ if( realCanvas && realCanvas.getContext
742 @ && (context = realCanvas.getContext('2d'))) {
743 @ drawBox = function(color,x0,y0,x1,y1) {
744 @ if( y0>32767 || y1>32767 ) return;
745 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
746 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
747 @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return;
748 @ context.fillStyle = color;
749 @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1);
750 @ };
751 @ }
752 #endif
753 @ for(var i in rowinfo){
754 @ drawNode(rowinfo[i], left, btm);
755 @ }
756 @ if( selRow!=null ) clickOnRow(selRow);
757 @ }
758 @ function clickOnGraph(event){
759 #ifdef OMIT_IE8_SUPPORT
760 @ var x=event.clientX-absoluteX("canvas")+window.pageXOffset;
761 @ var y=event.clientY-absoluteY("canvas")+window.pageYOffset;
762 #else
763 @ var x=event.clientX-absoluteX("canvas");
764 @ var y=event.clientY-absoluteY("canvas");
765 @ if(window.pageXOffset!=null){
766 @ x += window.pageXOffset;
767 @ y += window.pageYOffset;
@@ -769,16 +744,18 @@
769 @ var d = window.document.documentElement;
770 @ if(document.compatMode!="CSS1Compat") d = d.body;
771 @ x += d.scrollLeft;
772 @ y += d.scrollTop;
773 @ }
774 #endif
 
 
775 @ for(var i in rowinfo){
776 @ p = rowinfo[i];
777 @ if( p.y<y-10 ) continue;
778 @ if( p.y>y+10 ) break;
779 @ if( p.x>x-10 && p.x<x+10 ){
780 @ clickOnRow(p);
781 @ break;
782 @ }
783 @ }
784 @ }
@@ -1414,10 +1391,12 @@
1414 ** 1. uuid
1415 ** 2. Date/Time
1416 ** 3. Comment string and user
1417 ** 4. Number of non-merge children
1418 ** 5. Number of parents
 
 
1419 */
1420 void print_timeline(Stmt *q, int mxLine, int showfiles){
1421 int nLine = 0;
1422 char zPrevDate[20];
1423 const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
1522 @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
1523 @ FROM tag, tagxref
1524 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
1525 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
1526 @ || ')' as comment,
1527 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount,
 
1528 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1529 @ event.mtime AS mtime
1530 @ FROM event, blob
 
 
 
 
1531 @ WHERE blob.rid=event.objid
 
1532 ;
1533 return zBaseSql;
1534 }
1535
1536 /*
1537
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210 if( tmFlags & TIMELINE_GRAPH ){
211 pGraph = graph_init();
212 /* style is not moved to css, because this is
213 ** a technical div for the timeline graph
214 */
215 @ <div id="canvas" style="position:relative;height:0px;width:0px;"
216 @ onclick="clickOnGraph(event)"></div>
217 }
218 db_static_prepare(&qbranch,
219 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220 TAG_BRANCH
221 );
222
223 @ <table id="timelineTable" class="timelineTable"
224 @ onclick="clickOnGraph(event)">
225 blob_zero(&comment);
226 while( db_step(pQuery)==SQLITE_ROW ){
227 int rid = db_column_int(pQuery, 0);
228 const char *zUuid = db_column_text(pQuery, 1);
229 int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
727 @ for(var i in rowinfo){
728 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
729 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
730 @ }
731 @ var btm = absoluteY("grbtm") + 10 - canvasY;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
732 @ for(var i in rowinfo){
733 @ drawNode(rowinfo[i], left, btm);
734 @ }
735 @ if( selRow!=null ) clickOnRow(selRow);
736 @ }
737 @ function clickOnGraph(event){
 
 
 
 
738 @ var x=event.clientX-absoluteX("canvas");
739 @ var y=event.clientY-absoluteY("canvas");
740 @ if(window.pageXOffset!=null){
741 @ x += window.pageXOffset;
742 @ y += window.pageYOffset;
@@ -769,16 +744,18 @@
744 @ var d = window.document.documentElement;
745 @ if(document.compatMode!="CSS1Compat") d = d.body;
746 @ x += d.scrollLeft;
747 @ y += d.scrollTop;
748 @ }
749 if( P("clicktest")!=0 ){
750 @ alert("click at "+x+","+y)
751 }
752 @ for(var i in rowinfo){
753 @ p = rowinfo[i];
754 @ if( p.y<y-11 ) continue;
755 @ if( p.y>y+9 ) break;
756 @ if( p.x>x-11 && p.x<x+9 ){
757 @ clickOnRow(p);
758 @ break;
759 @ }
760 @ }
761 @ }
@@ -1414,10 +1391,12 @@
1391 ** 1. uuid
1392 ** 2. Date/Time
1393 ** 3. Comment string and user
1394 ** 4. Number of non-merge children
1395 ** 5. Number of parents
1396 ** 6. mtime
1397 ** 7. branch
1398 */
1399 void print_timeline(Stmt *q, int mxLine, int showfiles){
1400 int nLine = 0;
1401 char zPrevDate[20];
1402 const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
1501 @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
1502 @ FROM tag, tagxref
1503 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
1504 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
1505 @ || ')' as comment,
1506 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
1507 @ AS primPlinkCount,
1508 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1509 @ event.mtime AS mtime,
1510 @ tagxref.value AS branch
1511 @ FROM tag CROSS JOIN event CROSS JOIN blob
1512 @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
1513 @ AND tagxref.tagtype>0
1514 @ AND tagxref.rid=blob.rid
1515 @ WHERE blob.rid=event.objid
1516 @ AND tag.tagname='branch'
1517 ;
1518 return zBaseSql;
1519 }
1520
1521 /*
1522
+20 -35
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210210
if( tmFlags & TIMELINE_GRAPH ){
211211
pGraph = graph_init();
212212
/* style is not moved to css, because this is
213213
** a technical div for the timeline graph
214214
*/
215
- @ <div id="canvas" style="position:relative;width:1px;height:1px;"
215
+ @ <div id="canvas" style="position:relative;height:0px;width:0px;"
216216
@ onclick="clickOnGraph(event)"></div>
217217
}
218218
db_static_prepare(&qbranch,
219219
"SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220220
TAG_BRANCH
221221
);
222222
223
- @ <table id="timelineTable" class="timelineTable">
223
+ @ <table id="timelineTable" class="timelineTable"
224
+ @ onclick="clickOnGraph(event)">
224225
blob_zero(&comment);
225226
while( db_step(pQuery)==SQLITE_ROW ){
226227
int rid = db_column_int(pQuery, 0);
227228
const char *zUuid = db_column_text(pQuery, 1);
228229
int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
726727
@ for(var i in rowinfo){
727728
@ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
728729
@ rowinfo[i].x = left + rowinfo[i].r*railPitch;
729730
@ }
730731
@ var btm = absoluteY("grbtm") + 10 - canvasY;
731
-#if 0
732
- @ if( btm<32768 ){
733
- @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+
734
- @ 'style="position:absolute;left:'+(left-5)+'px;"' +
735
- @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>';
736
- @ realCanvas = gebi('timeline-canvas');
737
- @ }else{
738
- @ realCanvas = 0;
739
- @ }
740
- @ var context;
741
- @ if( realCanvas && realCanvas.getContext
742
- @ && (context = realCanvas.getContext('2d'))) {
743
- @ drawBox = function(color,x0,y0,x1,y1) {
744
- @ if( y0>32767 || y1>32767 ) return;
745
- @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
746
- @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
747
- @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return;
748
- @ context.fillStyle = color;
749
- @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1);
750
- @ };
751
- @ }
752
-#endif
753732
@ for(var i in rowinfo){
754733
@ drawNode(rowinfo[i], left, btm);
755734
@ }
756735
@ if( selRow!=null ) clickOnRow(selRow);
757736
@ }
758737
@ function clickOnGraph(event){
759
-#ifdef OMIT_IE8_SUPPORT
760
- @ var x=event.clientX-absoluteX("canvas")+window.pageXOffset;
761
- @ var y=event.clientY-absoluteY("canvas")+window.pageYOffset;
762
-#else
763738
@ var x=event.clientX-absoluteX("canvas");
764739
@ var y=event.clientY-absoluteY("canvas");
765740
@ if(window.pageXOffset!=null){
766741
@ x += window.pageXOffset;
767742
@ y += window.pageYOffset;
@@ -769,16 +744,18 @@
769744
@ var d = window.document.documentElement;
770745
@ if(document.compatMode!="CSS1Compat") d = d.body;
771746
@ x += d.scrollLeft;
772747
@ y += d.scrollTop;
773748
@ }
774
-#endif
749
+ if( P("clicktest")!=0 ){
750
+ @ alert("click at "+x+","+y)
751
+ }
775752
@ for(var i in rowinfo){
776753
@ p = rowinfo[i];
777
- @ if( p.y<y-10 ) continue;
778
- @ if( p.y>y+10 ) break;
779
- @ if( p.x>x-10 && p.x<x+10 ){
754
+ @ if( p.y<y-11 ) continue;
755
+ @ if( p.y>y+9 ) break;
756
+ @ if( p.x>x-11 && p.x<x+9 ){
780757
@ clickOnRow(p);
781758
@ break;
782759
@ }
783760
@ }
784761
@ }
@@ -1414,10 +1391,12 @@
14141391
** 1. uuid
14151392
** 2. Date/Time
14161393
** 3. Comment string and user
14171394
** 4. Number of non-merge children
14181395
** 5. Number of parents
1396
+** 6. mtime
1397
+** 7. branch
14191398
*/
14201399
void print_timeline(Stmt *q, int mxLine, int showfiles){
14211400
int nLine = 0;
14221401
char zPrevDate[20];
14231402
const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
15221501
@ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
15231502
@ FROM tag, tagxref
15241503
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
15251504
@ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
15261505
@ || ')' as comment,
1527
- @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount,
1506
+ @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
1507
+ @ AS primPlinkCount,
15281508
@ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1529
- @ event.mtime AS mtime
1530
- @ FROM event, blob
1509
+ @ event.mtime AS mtime,
1510
+ @ tagxref.value AS branch
1511
+ @ FROM tag CROSS JOIN event CROSS JOIN blob
1512
+ @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
1513
+ @ AND tagxref.tagtype>0
1514
+ @ AND tagxref.rid=blob.rid
15311515
@ WHERE blob.rid=event.objid
1516
+ @ AND tag.tagname='branch'
15321517
;
15331518
return zBaseSql;
15341519
}
15351520
15361521
/*
15371522
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210 if( tmFlags & TIMELINE_GRAPH ){
211 pGraph = graph_init();
212 /* style is not moved to css, because this is
213 ** a technical div for the timeline graph
214 */
215 @ <div id="canvas" style="position:relative;width:1px;height:1px;"
216 @ onclick="clickOnGraph(event)"></div>
217 }
218 db_static_prepare(&qbranch,
219 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220 TAG_BRANCH
221 );
222
223 @ <table id="timelineTable" class="timelineTable">
 
224 blob_zero(&comment);
225 while( db_step(pQuery)==SQLITE_ROW ){
226 int rid = db_column_int(pQuery, 0);
227 const char *zUuid = db_column_text(pQuery, 1);
228 int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
726 @ for(var i in rowinfo){
727 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
728 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
729 @ }
730 @ var btm = absoluteY("grbtm") + 10 - canvasY;
731 #if 0
732 @ if( btm<32768 ){
733 @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+
734 @ 'style="position:absolute;left:'+(left-5)+'px;"' +
735 @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>';
736 @ realCanvas = gebi('timeline-canvas');
737 @ }else{
738 @ realCanvas = 0;
739 @ }
740 @ var context;
741 @ if( realCanvas && realCanvas.getContext
742 @ && (context = realCanvas.getContext('2d'))) {
743 @ drawBox = function(color,x0,y0,x1,y1) {
744 @ if( y0>32767 || y1>32767 ) return;
745 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
746 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
747 @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return;
748 @ context.fillStyle = color;
749 @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1);
750 @ };
751 @ }
752 #endif
753 @ for(var i in rowinfo){
754 @ drawNode(rowinfo[i], left, btm);
755 @ }
756 @ if( selRow!=null ) clickOnRow(selRow);
757 @ }
758 @ function clickOnGraph(event){
759 #ifdef OMIT_IE8_SUPPORT
760 @ var x=event.clientX-absoluteX("canvas")+window.pageXOffset;
761 @ var y=event.clientY-absoluteY("canvas")+window.pageYOffset;
762 #else
763 @ var x=event.clientX-absoluteX("canvas");
764 @ var y=event.clientY-absoluteY("canvas");
765 @ if(window.pageXOffset!=null){
766 @ x += window.pageXOffset;
767 @ y += window.pageYOffset;
@@ -769,16 +744,18 @@
769 @ var d = window.document.documentElement;
770 @ if(document.compatMode!="CSS1Compat") d = d.body;
771 @ x += d.scrollLeft;
772 @ y += d.scrollTop;
773 @ }
774 #endif
 
 
775 @ for(var i in rowinfo){
776 @ p = rowinfo[i];
777 @ if( p.y<y-10 ) continue;
778 @ if( p.y>y+10 ) break;
779 @ if( p.x>x-10 && p.x<x+10 ){
780 @ clickOnRow(p);
781 @ break;
782 @ }
783 @ }
784 @ }
@@ -1414,10 +1391,12 @@
1414 ** 1. uuid
1415 ** 2. Date/Time
1416 ** 3. Comment string and user
1417 ** 4. Number of non-merge children
1418 ** 5. Number of parents
 
 
1419 */
1420 void print_timeline(Stmt *q, int mxLine, int showfiles){
1421 int nLine = 0;
1422 char zPrevDate[20];
1423 const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
1522 @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
1523 @ FROM tag, tagxref
1524 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
1525 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
1526 @ || ')' as comment,
1527 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount,
 
1528 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1529 @ event.mtime AS mtime
1530 @ FROM event, blob
 
 
 
 
1531 @ WHERE blob.rid=event.objid
 
1532 ;
1533 return zBaseSql;
1534 }
1535
1536 /*
1537
--- src/timeline.c
+++ src/timeline.c
@@ -210,19 +210,20 @@
210 if( tmFlags & TIMELINE_GRAPH ){
211 pGraph = graph_init();
212 /* style is not moved to css, because this is
213 ** a technical div for the timeline graph
214 */
215 @ <div id="canvas" style="position:relative;height:0px;width:0px;"
216 @ onclick="clickOnGraph(event)"></div>
217 }
218 db_static_prepare(&qbranch,
219 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
220 TAG_BRANCH
221 );
222
223 @ <table id="timelineTable" class="timelineTable"
224 @ onclick="clickOnGraph(event)">
225 blob_zero(&comment);
226 while( db_step(pQuery)==SQLITE_ROW ){
227 int rid = db_column_int(pQuery, 0);
228 const char *zUuid = db_column_text(pQuery, 1);
229 int isLeaf = db_column_int(pQuery, 5);
@@ -726,42 +727,16 @@
727 @ for(var i in rowinfo){
728 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
729 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
730 @ }
731 @ var btm = absoluteY("grbtm") + 10 - canvasY;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
732 @ for(var i in rowinfo){
733 @ drawNode(rowinfo[i], left, btm);
734 @ }
735 @ if( selRow!=null ) clickOnRow(selRow);
736 @ }
737 @ function clickOnGraph(event){
 
 
 
 
738 @ var x=event.clientX-absoluteX("canvas");
739 @ var y=event.clientY-absoluteY("canvas");
740 @ if(window.pageXOffset!=null){
741 @ x += window.pageXOffset;
742 @ y += window.pageYOffset;
@@ -769,16 +744,18 @@
744 @ var d = window.document.documentElement;
745 @ if(document.compatMode!="CSS1Compat") d = d.body;
746 @ x += d.scrollLeft;
747 @ y += d.scrollTop;
748 @ }
749 if( P("clicktest")!=0 ){
750 @ alert("click at "+x+","+y)
751 }
752 @ for(var i in rowinfo){
753 @ p = rowinfo[i];
754 @ if( p.y<y-11 ) continue;
755 @ if( p.y>y+9 ) break;
756 @ if( p.x>x-11 && p.x<x+9 ){
757 @ clickOnRow(p);
758 @ break;
759 @ }
760 @ }
761 @ }
@@ -1414,10 +1391,12 @@
1391 ** 1. uuid
1392 ** 2. Date/Time
1393 ** 3. Comment string and user
1394 ** 4. Number of non-merge children
1395 ** 5. Number of parents
1396 ** 6. mtime
1397 ** 7. branch
1398 */
1399 void print_timeline(Stmt *q, int mxLine, int showfiles){
1400 int nLine = 0;
1401 char zPrevDate[20];
1402 const char *zCurrentUuid=0;
@@ -1522,15 +1501,21 @@
1501 @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
1502 @ FROM tag, tagxref
1503 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
1504 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
1505 @ || ')' as comment,
1506 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
1507 @ AS primPlinkCount,
1508 @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
1509 @ event.mtime AS mtime,
1510 @ tagxref.value AS branch
1511 @ FROM tag CROSS JOIN event CROSS JOIN blob
1512 @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
1513 @ AND tagxref.tagtype>0
1514 @ AND tagxref.rid=blob.rid
1515 @ WHERE blob.rid=event.objid
1516 @ AND tag.tagname='branch'
1517 ;
1518 return zBaseSql;
1519 }
1520
1521 /*
1522
+73 -16
--- src/tkt.c
+++ src/tkt.c
@@ -34,12 +34,15 @@
3434
char *zAppend; /* Value to append */
3535
unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
3636
} *aField;
3737
#define USEDBY_TICKET 01
3838
#define USEDBY_TICKETCHNG 02
39
-static int haveTicket = 0; /* True if the TICKET table exists */
40
-static int haveTicketChng = 0; /* True if the TICKETCHNG table exists */
39
+#define USEDBY_BOTH 03
40
+static u8 haveTicket = 0; /* True if the TICKET table exists */
41
+static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
42
+static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
43
+static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
4144
4245
/*
4346
** Compare two entries in aField[] for sorting purposes
4447
*/
4548
static int nameCmpr(const void *a, const void *b){
@@ -74,11 +77,14 @@
7477
once = 1;
7578
db_prepare(&q, "PRAGMA table_info(ticket)");
7679
while( db_step(&q)==SQLITE_ROW ){
7780
const char *zFieldName = db_column_text(&q, 1);
7881
haveTicket = 1;
79
- if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
82
+ if( memcmp(zFieldName,"tkt_",4)==0 ){
83
+ if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1;
84
+ continue;
85
+ }
8086
if( nField%10==0 ){
8187
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
8288
}
8389
aField[nField].zName = mprintf("%s", zFieldName);
8490
aField[nField].mUsed = USEDBY_TICKET;
@@ -87,11 +93,14 @@
8793
db_finalize(&q);
8894
db_prepare(&q, "PRAGMA table_info(ticketchng)");
8995
while( db_step(&q)==SQLITE_ROW ){
9096
const char *zFieldName = db_column_text(&q, 1);
9197
haveTicketChng = 1;
92
- if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
98
+ if( memcmp(zFieldName,"tkt_",4)==0 ){
99
+ if( strcmp(zFieldName,"tkt_rid")==0 ) haveTicketChngRid = 1;
100
+ continue;
101
+ }
93102
if( (i = fieldId(zFieldName))>=0 ){
94103
aField[i].mUsed |= USEDBY_TICKETCHNG;
95104
continue;
96105
}
97106
if( nField%10==0 ){
@@ -183,10 +192,11 @@
183192
*/
184193
static int ticket_insert(const Manifest *p, int rid, int tktid){
185194
Blob sql1, sql2, sql3;
186195
Stmt q;
187196
int i, j;
197
+ char *aUsed;
188198
189199
if( tktid==0 ){
190200
db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
191201
"VALUES(%Q, 0)", p->zTicketUuid);
192202
tktid = db_last_insert_rowid();
@@ -193,22 +203,25 @@
193203
}
194204
blob_zero(&sql1);
195205
blob_zero(&sql2);
196206
blob_zero(&sql3);
197207
blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime");
208
+ if( haveTicketCTime ){
209
+ blob_appendf(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)");
210
+ }
211
+ aUsed = fossil_malloc( nField );
212
+ memset(aUsed, 0, nField);
198213
for(i=0; i<p->nField; i++){
199214
const char *zName = p->aField[i].zName;
200
- if( zName[0]=='+' ){
201
- zName++;
202
- if( (j = fieldId(zName))<0 ) continue;
203
- if( aField[j].mUsed & USEDBY_TICKET ){
215
+ if( (j = fieldId(zName))<0 ) continue;
216
+ aUsed[j] = 1;
217
+ if( aField[j].mUsed & USEDBY_TICKET ){
218
+ if( zName[0]=='+' ){
219
+ zName++;
204220
blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q",
205221
zName, zName, p->aField[i].zValue);
206
- }
207
- }else{
208
- if( (j = fieldId(zName))<0 ) continue;
209
- if( aField[j].mUsed & USEDBY_TICKET ){
222
+ }else{
210223
blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue);
211224
}
212225
}
213226
if( aField[j].mUsed & USEDBY_TICKETCHNG ){
214227
blob_appendf(&sql2, ",%s", zName);
@@ -222,20 +235,41 @@
222235
db_prepare(&q, "%s", blob_str(&sql1));
223236
db_bind_double(&q, ":mtime", p->rDate);
224237
db_step(&q);
225238
db_finalize(&q);
226239
blob_reset(&sql1);
227
- if( blob_size(&sql2)>0 ){
228
- db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
229
- "VALUES(%d,:mtime%s)",
230
- blob_str(&sql2), tktid, blob_str(&sql3));
240
+ if( blob_size(&sql2)>0 || haveTicketChngRid ){
241
+ int fromTkt = 0;
242
+ if( haveTicketChngRid ){
243
+ blob_append(&sql2, ",tkt_rid", -1);
244
+ blob_appendf(&sql3, ",%d", rid);
245
+ }
246
+ for(i=0; i<nField; i++){
247
+ if( aUsed[i]==0
248
+ && (aField[i].mUsed & USEDBY_BOTH)==USEDBY_BOTH
249
+ ){
250
+ fromTkt = 1;
251
+ blob_appendf(&sql2, ",%s", aField[i].zName);
252
+ blob_appendf(&sql3, ",%s", aField[i].zName);
253
+ }
254
+ }
255
+ if( fromTkt ){
256
+ db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
257
+ "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d",
258
+ blob_str(&sql2), tktid, blob_str(&sql3), tktid);
259
+ }else{
260
+ db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
261
+ "VALUES(%d,:mtime%s)",
262
+ blob_str(&sql2), tktid, blob_str(&sql3));
263
+ }
231264
db_bind_double(&q, ":mtime", p->rDate);
232265
db_step(&q);
233266
db_finalize(&q);
234267
}
235268
blob_reset(&sql2);
236269
blob_reset(&sql3);
270
+ fossil_free(aUsed);
237271
return tktid;
238272
}
239273
240274
/*
241275
** Rebuild an entire entry in the TICKET table
@@ -268,10 +302,11 @@
268302
}
269303
createFlag = 0;
270304
}
271305
db_finalize(&q);
272306
}
307
+
273308
274309
/*
275310
** Create the TH1 interpreter and load the "common" code.
276311
*/
277312
void ticket_init(void){
@@ -328,10 +363,32 @@
328363
ticket_rebuild_entry(zName);
329364
}
330365
db_finalize(&q);
331366
db_end_transaction(0);
332367
}
368
+
369
+/*
370
+** COMMAND: test-ticket-rebuild
371
+**
372
+** Usage: %fossil test-ticket-rebuild TICKETID|all
373
+**
374
+** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID
375
+** or for ALL.
376
+*/
377
+void test_ticket_rebuild(void){
378
+ db_find_and_open_repository(0, 0);
379
+ if( g.argc!=3 ) usage("TICKETID|all");
380
+ if( fossil_strcmp(g.argv[2], "all")==0 ){
381
+ ticket_rebuild();
382
+ }else{
383
+ const char *zUuid;
384
+ zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag"
385
+ " WHERE tagname GLOB 'tkt-%q*'", g.argv[2]);
386
+ if( zUuid==0 ) fossil_fatal("no such ticket: %s", g.argv[2]);
387
+ ticket_rebuild_entry(zUuid);
388
+ }
389
+}
333390
334391
/*
335392
** For trouble-shooting purposes, render a dump of the aField[] table to
336393
** the webpage currently under construction.
337394
*/
338395
--- src/tkt.c
+++ src/tkt.c
@@ -34,12 +34,15 @@
34 char *zAppend; /* Value to append */
35 unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
36 } *aField;
37 #define USEDBY_TICKET 01
38 #define USEDBY_TICKETCHNG 02
39 static int haveTicket = 0; /* True if the TICKET table exists */
40 static int haveTicketChng = 0; /* True if the TICKETCHNG table exists */
 
 
 
41
42 /*
43 ** Compare two entries in aField[] for sorting purposes
44 */
45 static int nameCmpr(const void *a, const void *b){
@@ -74,11 +77,14 @@
74 once = 1;
75 db_prepare(&q, "PRAGMA table_info(ticket)");
76 while( db_step(&q)==SQLITE_ROW ){
77 const char *zFieldName = db_column_text(&q, 1);
78 haveTicket = 1;
79 if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
 
 
 
80 if( nField%10==0 ){
81 aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
82 }
83 aField[nField].zName = mprintf("%s", zFieldName);
84 aField[nField].mUsed = USEDBY_TICKET;
@@ -87,11 +93,14 @@
87 db_finalize(&q);
88 db_prepare(&q, "PRAGMA table_info(ticketchng)");
89 while( db_step(&q)==SQLITE_ROW ){
90 const char *zFieldName = db_column_text(&q, 1);
91 haveTicketChng = 1;
92 if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
 
 
 
93 if( (i = fieldId(zFieldName))>=0 ){
94 aField[i].mUsed |= USEDBY_TICKETCHNG;
95 continue;
96 }
97 if( nField%10==0 ){
@@ -183,10 +192,11 @@
183 */
184 static int ticket_insert(const Manifest *p, int rid, int tktid){
185 Blob sql1, sql2, sql3;
186 Stmt q;
187 int i, j;
 
188
189 if( tktid==0 ){
190 db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
191 "VALUES(%Q, 0)", p->zTicketUuid);
192 tktid = db_last_insert_rowid();
@@ -193,22 +203,25 @@
193 }
194 blob_zero(&sql1);
195 blob_zero(&sql2);
196 blob_zero(&sql3);
197 blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime");
 
 
 
 
 
198 for(i=0; i<p->nField; i++){
199 const char *zName = p->aField[i].zName;
200 if( zName[0]=='+' ){
201 zName++;
202 if( (j = fieldId(zName))<0 ) continue;
203 if( aField[j].mUsed & USEDBY_TICKET ){
 
204 blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q",
205 zName, zName, p->aField[i].zValue);
206 }
207 }else{
208 if( (j = fieldId(zName))<0 ) continue;
209 if( aField[j].mUsed & USEDBY_TICKET ){
210 blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue);
211 }
212 }
213 if( aField[j].mUsed & USEDBY_TICKETCHNG ){
214 blob_appendf(&sql2, ",%s", zName);
@@ -222,20 +235,41 @@
222 db_prepare(&q, "%s", blob_str(&sql1));
223 db_bind_double(&q, ":mtime", p->rDate);
224 db_step(&q);
225 db_finalize(&q);
226 blob_reset(&sql1);
227 if( blob_size(&sql2)>0 ){
228 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
229 "VALUES(%d,:mtime%s)",
230 blob_str(&sql2), tktid, blob_str(&sql3));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231 db_bind_double(&q, ":mtime", p->rDate);
232 db_step(&q);
233 db_finalize(&q);
234 }
235 blob_reset(&sql2);
236 blob_reset(&sql3);
 
237 return tktid;
238 }
239
240 /*
241 ** Rebuild an entire entry in the TICKET table
@@ -268,10 +302,11 @@
268 }
269 createFlag = 0;
270 }
271 db_finalize(&q);
272 }
 
273
274 /*
275 ** Create the TH1 interpreter and load the "common" code.
276 */
277 void ticket_init(void){
@@ -328,10 +363,32 @@
328 ticket_rebuild_entry(zName);
329 }
330 db_finalize(&q);
331 db_end_transaction(0);
332 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
334 /*
335 ** For trouble-shooting purposes, render a dump of the aField[] table to
336 ** the webpage currently under construction.
337 */
338
--- src/tkt.c
+++ src/tkt.c
@@ -34,12 +34,15 @@
34 char *zAppend; /* Value to append */
35 unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
36 } *aField;
37 #define USEDBY_TICKET 01
38 #define USEDBY_TICKETCHNG 02
39 #define USEDBY_BOTH 03
40 static u8 haveTicket = 0; /* True if the TICKET table exists */
41 static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
42 static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
43 static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
44
45 /*
46 ** Compare two entries in aField[] for sorting purposes
47 */
48 static int nameCmpr(const void *a, const void *b){
@@ -74,11 +77,14 @@
77 once = 1;
78 db_prepare(&q, "PRAGMA table_info(ticket)");
79 while( db_step(&q)==SQLITE_ROW ){
80 const char *zFieldName = db_column_text(&q, 1);
81 haveTicket = 1;
82 if( memcmp(zFieldName,"tkt_",4)==0 ){
83 if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1;
84 continue;
85 }
86 if( nField%10==0 ){
87 aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
88 }
89 aField[nField].zName = mprintf("%s", zFieldName);
90 aField[nField].mUsed = USEDBY_TICKET;
@@ -87,11 +93,14 @@
93 db_finalize(&q);
94 db_prepare(&q, "PRAGMA table_info(ticketchng)");
95 while( db_step(&q)==SQLITE_ROW ){
96 const char *zFieldName = db_column_text(&q, 1);
97 haveTicketChng = 1;
98 if( memcmp(zFieldName,"tkt_",4)==0 ){
99 if( strcmp(zFieldName,"tkt_rid")==0 ) haveTicketChngRid = 1;
100 continue;
101 }
102 if( (i = fieldId(zFieldName))>=0 ){
103 aField[i].mUsed |= USEDBY_TICKETCHNG;
104 continue;
105 }
106 if( nField%10==0 ){
@@ -183,10 +192,11 @@
192 */
193 static int ticket_insert(const Manifest *p, int rid, int tktid){
194 Blob sql1, sql2, sql3;
195 Stmt q;
196 int i, j;
197 char *aUsed;
198
199 if( tktid==0 ){
200 db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
201 "VALUES(%Q, 0)", p->zTicketUuid);
202 tktid = db_last_insert_rowid();
@@ -193,22 +203,25 @@
203 }
204 blob_zero(&sql1);
205 blob_zero(&sql2);
206 blob_zero(&sql3);
207 blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime");
208 if( haveTicketCTime ){
209 blob_appendf(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)");
210 }
211 aUsed = fossil_malloc( nField );
212 memset(aUsed, 0, nField);
213 for(i=0; i<p->nField; i++){
214 const char *zName = p->aField[i].zName;
215 if( (j = fieldId(zName))<0 ) continue;
216 aUsed[j] = 1;
217 if( aField[j].mUsed & USEDBY_TICKET ){
218 if( zName[0]=='+' ){
219 zName++;
220 blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q",
221 zName, zName, p->aField[i].zValue);
222 }else{
 
 
 
223 blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue);
224 }
225 }
226 if( aField[j].mUsed & USEDBY_TICKETCHNG ){
227 blob_appendf(&sql2, ",%s", zName);
@@ -222,20 +235,41 @@
235 db_prepare(&q, "%s", blob_str(&sql1));
236 db_bind_double(&q, ":mtime", p->rDate);
237 db_step(&q);
238 db_finalize(&q);
239 blob_reset(&sql1);
240 if( blob_size(&sql2)>0 || haveTicketChngRid ){
241 int fromTkt = 0;
242 if( haveTicketChngRid ){
243 blob_append(&sql2, ",tkt_rid", -1);
244 blob_appendf(&sql3, ",%d", rid);
245 }
246 for(i=0; i<nField; i++){
247 if( aUsed[i]==0
248 && (aField[i].mUsed & USEDBY_BOTH)==USEDBY_BOTH
249 ){
250 fromTkt = 1;
251 blob_appendf(&sql2, ",%s", aField[i].zName);
252 blob_appendf(&sql3, ",%s", aField[i].zName);
253 }
254 }
255 if( fromTkt ){
256 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
257 "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d",
258 blob_str(&sql2), tktid, blob_str(&sql3), tktid);
259 }else{
260 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
261 "VALUES(%d,:mtime%s)",
262 blob_str(&sql2), tktid, blob_str(&sql3));
263 }
264 db_bind_double(&q, ":mtime", p->rDate);
265 db_step(&q);
266 db_finalize(&q);
267 }
268 blob_reset(&sql2);
269 blob_reset(&sql3);
270 fossil_free(aUsed);
271 return tktid;
272 }
273
274 /*
275 ** Rebuild an entire entry in the TICKET table
@@ -268,10 +302,11 @@
302 }
303 createFlag = 0;
304 }
305 db_finalize(&q);
306 }
307
308
309 /*
310 ** Create the TH1 interpreter and load the "common" code.
311 */
312 void ticket_init(void){
@@ -328,10 +363,32 @@
363 ticket_rebuild_entry(zName);
364 }
365 db_finalize(&q);
366 db_end_transaction(0);
367 }
368
369 /*
370 ** COMMAND: test-ticket-rebuild
371 **
372 ** Usage: %fossil test-ticket-rebuild TICKETID|all
373 **
374 ** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID
375 ** or for ALL.
376 */
377 void test_ticket_rebuild(void){
378 db_find_and_open_repository(0, 0);
379 if( g.argc!=3 ) usage("TICKETID|all");
380 if( fossil_strcmp(g.argv[2], "all")==0 ){
381 ticket_rebuild();
382 }else{
383 const char *zUuid;
384 zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag"
385 " WHERE tagname GLOB 'tkt-%q*'", g.argv[2]);
386 if( zUuid==0 ) fossil_fatal("no such ticket: %s", g.argv[2]);
387 ticket_rebuild_entry(zUuid);
388 }
389 }
390
391 /*
392 ** For trouble-shooting purposes, render a dump of the aField[] table to
393 ** the webpage currently under construction.
394 */
395
+73 -16
--- src/tkt.c
+++ src/tkt.c
@@ -34,12 +34,15 @@
3434
char *zAppend; /* Value to append */
3535
unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
3636
} *aField;
3737
#define USEDBY_TICKET 01
3838
#define USEDBY_TICKETCHNG 02
39
-static int haveTicket = 0; /* True if the TICKET table exists */
40
-static int haveTicketChng = 0; /* True if the TICKETCHNG table exists */
39
+#define USEDBY_BOTH 03
40
+static u8 haveTicket = 0; /* True if the TICKET table exists */
41
+static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
42
+static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
43
+static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
4144
4245
/*
4346
** Compare two entries in aField[] for sorting purposes
4447
*/
4548
static int nameCmpr(const void *a, const void *b){
@@ -74,11 +77,14 @@
7477
once = 1;
7578
db_prepare(&q, "PRAGMA table_info(ticket)");
7679
while( db_step(&q)==SQLITE_ROW ){
7780
const char *zFieldName = db_column_text(&q, 1);
7881
haveTicket = 1;
79
- if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
82
+ if( memcmp(zFieldName,"tkt_",4)==0 ){
83
+ if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1;
84
+ continue;
85
+ }
8086
if( nField%10==0 ){
8187
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
8288
}
8389
aField[nField].zName = mprintf("%s", zFieldName);
8490
aField[nField].mUsed = USEDBY_TICKET;
@@ -87,11 +93,14 @@
8793
db_finalize(&q);
8894
db_prepare(&q, "PRAGMA table_info(ticketchng)");
8995
while( db_step(&q)==SQLITE_ROW ){
9096
const char *zFieldName = db_column_text(&q, 1);
9197
haveTicketChng = 1;
92
- if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
98
+ if( memcmp(zFieldName,"tkt_",4)==0 ){
99
+ if( strcmp(zFieldName,"tkt_rid")==0 ) haveTicketChngRid = 1;
100
+ continue;
101
+ }
93102
if( (i = fieldId(zFieldName))>=0 ){
94103
aField[i].mUsed |= USEDBY_TICKETCHNG;
95104
continue;
96105
}
97106
if( nField%10==0 ){
@@ -183,10 +192,11 @@
183192
*/
184193
static int ticket_insert(const Manifest *p, int rid, int tktid){
185194
Blob sql1, sql2, sql3;
186195
Stmt q;
187196
int i, j;
197
+ char *aUsed;
188198
189199
if( tktid==0 ){
190200
db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
191201
"VALUES(%Q, 0)", p->zTicketUuid);
192202
tktid = db_last_insert_rowid();
@@ -193,22 +203,25 @@
193203
}
194204
blob_zero(&sql1);
195205
blob_zero(&sql2);
196206
blob_zero(&sql3);
197207
blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime");
208
+ if( haveTicketCTime ){
209
+ blob_appendf(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)");
210
+ }
211
+ aUsed = fossil_malloc( nField );
212
+ memset(aUsed, 0, nField);
198213
for(i=0; i<p->nField; i++){
199214
const char *zName = p->aField[i].zName;
200
- if( zName[0]=='+' ){
201
- zName++;
202
- if( (j = fieldId(zName))<0 ) continue;
203
- if( aField[j].mUsed & USEDBY_TICKET ){
215
+ if( (j = fieldId(zName))<0 ) continue;
216
+ aUsed[j] = 1;
217
+ if( aField[j].mUsed & USEDBY_TICKET ){
218
+ if( zName[0]=='+' ){
219
+ zName++;
204220
blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q",
205221
zName, zName, p->aField[i].zValue);
206
- }
207
- }else{
208
- if( (j = fieldId(zName))<0 ) continue;
209
- if( aField[j].mUsed & USEDBY_TICKET ){
222
+ }else{
210223
blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue);
211224
}
212225
}
213226
if( aField[j].mUsed & USEDBY_TICKETCHNG ){
214227
blob_appendf(&sql2, ",%s", zName);
@@ -222,20 +235,41 @@
222235
db_prepare(&q, "%s", blob_str(&sql1));
223236
db_bind_double(&q, ":mtime", p->rDate);
224237
db_step(&q);
225238
db_finalize(&q);
226239
blob_reset(&sql1);
227
- if( blob_size(&sql2)>0 ){
228
- db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
229
- "VALUES(%d,:mtime%s)",
230
- blob_str(&sql2), tktid, blob_str(&sql3));
240
+ if( blob_size(&sql2)>0 || haveTicketChngRid ){
241
+ int fromTkt = 0;
242
+ if( haveTicketChngRid ){
243
+ blob_append(&sql2, ",tkt_rid", -1);
244
+ blob_appendf(&sql3, ",%d", rid);
245
+ }
246
+ for(i=0; i<nField; i++){
247
+ if( aUsed[i]==0
248
+ && (aField[i].mUsed & USEDBY_BOTH)==USEDBY_BOTH
249
+ ){
250
+ fromTkt = 1;
251
+ blob_appendf(&sql2, ",%s", aField[i].zName);
252
+ blob_appendf(&sql3, ",%s", aField[i].zName);
253
+ }
254
+ }
255
+ if( fromTkt ){
256
+ db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
257
+ "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d",
258
+ blob_str(&sql2), tktid, blob_str(&sql3), tktid);
259
+ }else{
260
+ db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
261
+ "VALUES(%d,:mtime%s)",
262
+ blob_str(&sql2), tktid, blob_str(&sql3));
263
+ }
231264
db_bind_double(&q, ":mtime", p->rDate);
232265
db_step(&q);
233266
db_finalize(&q);
234267
}
235268
blob_reset(&sql2);
236269
blob_reset(&sql3);
270
+ fossil_free(aUsed);
237271
return tktid;
238272
}
239273
240274
/*
241275
** Rebuild an entire entry in the TICKET table
@@ -268,10 +302,11 @@
268302
}
269303
createFlag = 0;
270304
}
271305
db_finalize(&q);
272306
}
307
+
273308
274309
/*
275310
** Create the TH1 interpreter and load the "common" code.
276311
*/
277312
void ticket_init(void){
@@ -328,10 +363,32 @@
328363
ticket_rebuild_entry(zName);
329364
}
330365
db_finalize(&q);
331366
db_end_transaction(0);
332367
}
368
+
369
+/*
370
+** COMMAND: test-ticket-rebuild
371
+**
372
+** Usage: %fossil test-ticket-rebuild TICKETID|all
373
+**
374
+** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID
375
+** or for ALL.
376
+*/
377
+void test_ticket_rebuild(void){
378
+ db_find_and_open_repository(0, 0);
379
+ if( g.argc!=3 ) usage("TICKETID|all");
380
+ if( fossil_strcmp(g.argv[2], "all")==0 ){
381
+ ticket_rebuild();
382
+ }else{
383
+ const char *zUuid;
384
+ zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag"
385
+ " WHERE tagname GLOB 'tkt-%q*'", g.argv[2]);
386
+ if( zUuid==0 ) fossil_fatal("no such ticket: %s", g.argv[2]);
387
+ ticket_rebuild_entry(zUuid);
388
+ }
389
+}
333390
334391
/*
335392
** For trouble-shooting purposes, render a dump of the aField[] table to
336393
** the webpage currently under construction.
337394
*/
338395
--- src/tkt.c
+++ src/tkt.c
@@ -34,12 +34,15 @@
34 char *zAppend; /* Value to append */
35 unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
36 } *aField;
37 #define USEDBY_TICKET 01
38 #define USEDBY_TICKETCHNG 02
39 static int haveTicket = 0; /* True if the TICKET table exists */
40 static int haveTicketChng = 0; /* True if the TICKETCHNG table exists */
 
 
 
41
42 /*
43 ** Compare two entries in aField[] for sorting purposes
44 */
45 static int nameCmpr(const void *a, const void *b){
@@ -74,11 +77,14 @@
74 once = 1;
75 db_prepare(&q, "PRAGMA table_info(ticket)");
76 while( db_step(&q)==SQLITE_ROW ){
77 const char *zFieldName = db_column_text(&q, 1);
78 haveTicket = 1;
79 if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
 
 
 
80 if( nField%10==0 ){
81 aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
82 }
83 aField[nField].zName = mprintf("%s", zFieldName);
84 aField[nField].mUsed = USEDBY_TICKET;
@@ -87,11 +93,14 @@
87 db_finalize(&q);
88 db_prepare(&q, "PRAGMA table_info(ticketchng)");
89 while( db_step(&q)==SQLITE_ROW ){
90 const char *zFieldName = db_column_text(&q, 1);
91 haveTicketChng = 1;
92 if( memcmp(zFieldName,"tkt_",4)==0 ) continue;
 
 
 
93 if( (i = fieldId(zFieldName))>=0 ){
94 aField[i].mUsed |= USEDBY_TICKETCHNG;
95 continue;
96 }
97 if( nField%10==0 ){
@@ -183,10 +192,11 @@
183 */
184 static int ticket_insert(const Manifest *p, int rid, int tktid){
185 Blob sql1, sql2, sql3;
186 Stmt q;
187 int i, j;
 
188
189 if( tktid==0 ){
190 db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
191 "VALUES(%Q, 0)", p->zTicketUuid);
192 tktid = db_last_insert_rowid();
@@ -193,22 +203,25 @@
193 }
194 blob_zero(&sql1);
195 blob_zero(&sql2);
196 blob_zero(&sql3);
197 blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime");
 
 
 
 
 
198 for(i=0; i<p->nField; i++){
199 const char *zName = p->aField[i].zName;
200 if( zName[0]=='+' ){
201 zName++;
202 if( (j = fieldId(zName))<0 ) continue;
203 if( aField[j].mUsed & USEDBY_TICKET ){
 
204 blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q",
205 zName, zName, p->aField[i].zValue);
206 }
207 }else{
208 if( (j = fieldId(zName))<0 ) continue;
209 if( aField[j].mUsed & USEDBY_TICKET ){
210 blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue);
211 }
212 }
213 if( aField[j].mUsed & USEDBY_TICKETCHNG ){
214 blob_appendf(&sql2, ",%s", zName);
@@ -222,20 +235,41 @@
222 db_prepare(&q, "%s", blob_str(&sql1));
223 db_bind_double(&q, ":mtime", p->rDate);
224 db_step(&q);
225 db_finalize(&q);
226 blob_reset(&sql1);
227 if( blob_size(&sql2)>0 ){
228 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
229 "VALUES(%d,:mtime%s)",
230 blob_str(&sql2), tktid, blob_str(&sql3));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231 db_bind_double(&q, ":mtime", p->rDate);
232 db_step(&q);
233 db_finalize(&q);
234 }
235 blob_reset(&sql2);
236 blob_reset(&sql3);
 
237 return tktid;
238 }
239
240 /*
241 ** Rebuild an entire entry in the TICKET table
@@ -268,10 +302,11 @@
268 }
269 createFlag = 0;
270 }
271 db_finalize(&q);
272 }
 
273
274 /*
275 ** Create the TH1 interpreter and load the "common" code.
276 */
277 void ticket_init(void){
@@ -328,10 +363,32 @@
328 ticket_rebuild_entry(zName);
329 }
330 db_finalize(&q);
331 db_end_transaction(0);
332 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
334 /*
335 ** For trouble-shooting purposes, render a dump of the aField[] table to
336 ** the webpage currently under construction.
337 */
338
--- src/tkt.c
+++ src/tkt.c
@@ -34,12 +34,15 @@
34 char *zAppend; /* Value to append */
35 unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */
36 } *aField;
37 #define USEDBY_TICKET 01
38 #define USEDBY_TICKETCHNG 02
39 #define USEDBY_BOTH 03
40 static u8 haveTicket = 0; /* True if the TICKET table exists */
41 static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
42 static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
43 static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
44
45 /*
46 ** Compare two entries in aField[] for sorting purposes
47 */
48 static int nameCmpr(const void *a, const void *b){
@@ -74,11 +77,14 @@
77 once = 1;
78 db_prepare(&q, "PRAGMA table_info(ticket)");
79 while( db_step(&q)==SQLITE_ROW ){
80 const char *zFieldName = db_column_text(&q, 1);
81 haveTicket = 1;
82 if( memcmp(zFieldName,"tkt_",4)==0 ){
83 if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1;
84 continue;
85 }
86 if( nField%10==0 ){
87 aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
88 }
89 aField[nField].zName = mprintf("%s", zFieldName);
90 aField[nField].mUsed = USEDBY_TICKET;
@@ -87,11 +93,14 @@
93 db_finalize(&q);
94 db_prepare(&q, "PRAGMA table_info(ticketchng)");
95 while( db_step(&q)==SQLITE_ROW ){
96 const char *zFieldName = db_column_text(&q, 1);
97 haveTicketChng = 1;
98 if( memcmp(zFieldName,"tkt_",4)==0 ){
99 if( strcmp(zFieldName,"tkt_rid")==0 ) haveTicketChngRid = 1;
100 continue;
101 }
102 if( (i = fieldId(zFieldName))>=0 ){
103 aField[i].mUsed |= USEDBY_TICKETCHNG;
104 continue;
105 }
106 if( nField%10==0 ){
@@ -183,10 +192,11 @@
192 */
193 static int ticket_insert(const Manifest *p, int rid, int tktid){
194 Blob sql1, sql2, sql3;
195 Stmt q;
196 int i, j;
197 char *aUsed;
198
199 if( tktid==0 ){
200 db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
201 "VALUES(%Q, 0)", p->zTicketUuid);
202 tktid = db_last_insert_rowid();
@@ -193,22 +203,25 @@
203 }
204 blob_zero(&sql1);
205 blob_zero(&sql2);
206 blob_zero(&sql3);
207 blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime");
208 if( haveTicketCTime ){
209 blob_appendf(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)");
210 }
211 aUsed = fossil_malloc( nField );
212 memset(aUsed, 0, nField);
213 for(i=0; i<p->nField; i++){
214 const char *zName = p->aField[i].zName;
215 if( (j = fieldId(zName))<0 ) continue;
216 aUsed[j] = 1;
217 if( aField[j].mUsed & USEDBY_TICKET ){
218 if( zName[0]=='+' ){
219 zName++;
220 blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q",
221 zName, zName, p->aField[i].zValue);
222 }else{
 
 
 
223 blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue);
224 }
225 }
226 if( aField[j].mUsed & USEDBY_TICKETCHNG ){
227 blob_appendf(&sql2, ",%s", zName);
@@ -222,20 +235,41 @@
235 db_prepare(&q, "%s", blob_str(&sql1));
236 db_bind_double(&q, ":mtime", p->rDate);
237 db_step(&q);
238 db_finalize(&q);
239 blob_reset(&sql1);
240 if( blob_size(&sql2)>0 || haveTicketChngRid ){
241 int fromTkt = 0;
242 if( haveTicketChngRid ){
243 blob_append(&sql2, ",tkt_rid", -1);
244 blob_appendf(&sql3, ",%d", rid);
245 }
246 for(i=0; i<nField; i++){
247 if( aUsed[i]==0
248 && (aField[i].mUsed & USEDBY_BOTH)==USEDBY_BOTH
249 ){
250 fromTkt = 1;
251 blob_appendf(&sql2, ",%s", aField[i].zName);
252 blob_appendf(&sql3, ",%s", aField[i].zName);
253 }
254 }
255 if( fromTkt ){
256 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
257 "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d",
258 blob_str(&sql2), tktid, blob_str(&sql3), tktid);
259 }else{
260 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
261 "VALUES(%d,:mtime%s)",
262 blob_str(&sql2), tktid, blob_str(&sql3));
263 }
264 db_bind_double(&q, ":mtime", p->rDate);
265 db_step(&q);
266 db_finalize(&q);
267 }
268 blob_reset(&sql2);
269 blob_reset(&sql3);
270 fossil_free(aUsed);
271 return tktid;
272 }
273
274 /*
275 ** Rebuild an entire entry in the TICKET table
@@ -268,10 +302,11 @@
302 }
303 createFlag = 0;
304 }
305 db_finalize(&q);
306 }
307
308
309 /*
310 ** Create the TH1 interpreter and load the "common" code.
311 */
312 void ticket_init(void){
@@ -328,10 +363,32 @@
363 ticket_rebuild_entry(zName);
364 }
365 db_finalize(&q);
366 db_end_transaction(0);
367 }
368
369 /*
370 ** COMMAND: test-ticket-rebuild
371 **
372 ** Usage: %fossil test-ticket-rebuild TICKETID|all
373 **
374 ** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID
375 ** or for ALL.
376 */
377 void test_ticket_rebuild(void){
378 db_find_and_open_repository(0, 0);
379 if( g.argc!=3 ) usage("TICKETID|all");
380 if( fossil_strcmp(g.argv[2], "all")==0 ){
381 ticket_rebuild();
382 }else{
383 const char *zUuid;
384 zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag"
385 " WHERE tagname GLOB 'tkt-%q*'", g.argv[2]);
386 if( zUuid==0 ) fossil_fatal("no such ticket: %s", g.argv[2]);
387 ticket_rebuild_entry(zUuid);
388 }
389 }
390
391 /*
392 ** For trouble-shooting purposes, render a dump of the aField[] table to
393 ** the webpage currently under construction.
394 */
395
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -67,10 +67,11 @@
6767
@ CREATE TABLE ticket(
6868
@ -- Do not change any column that begins with tkt_
6969
@ tkt_id INTEGER PRIMARY KEY,
7070
@ tkt_uuid TEXT UNIQUE,
7171
@ tkt_mtime DATE,
72
+@ tkt_ctime DATE,
7273
@ -- Add as many fields as required below this line
7374
@ type TEXT,
7475
@ status TEXT,
7576
@ subsystem TEXT,
7677
@ priority TEXT,
@@ -82,10 +83,11 @@
8283
@ comment TEXT
8384
@ );
8485
@ CREATE TABLE ticketchng(
8586
@ -- Do not change any column that begins with tkt_
8687
@ tkt_id INTEGER REFERENCES ticket,
88
+@ tkt_rid INTEGER REFERENCES blob,
8789
@ tkt_mtime DATE,
8890
@ -- Add as many fields as required below this line
8991
@ login TEXT,
9092
@ username TEXT,
9193
@ mimetype TEXT,
9294
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -67,10 +67,11 @@
67 @ CREATE TABLE ticket(
68 @ -- Do not change any column that begins with tkt_
69 @ tkt_id INTEGER PRIMARY KEY,
70 @ tkt_uuid TEXT UNIQUE,
71 @ tkt_mtime DATE,
 
72 @ -- Add as many fields as required below this line
73 @ type TEXT,
74 @ status TEXT,
75 @ subsystem TEXT,
76 @ priority TEXT,
@@ -82,10 +83,11 @@
82 @ comment TEXT
83 @ );
84 @ CREATE TABLE ticketchng(
85 @ -- Do not change any column that begins with tkt_
86 @ tkt_id INTEGER REFERENCES ticket,
 
87 @ tkt_mtime DATE,
88 @ -- Add as many fields as required below this line
89 @ login TEXT,
90 @ username TEXT,
91 @ mimetype TEXT,
92
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -67,10 +67,11 @@
67 @ CREATE TABLE ticket(
68 @ -- Do not change any column that begins with tkt_
69 @ tkt_id INTEGER PRIMARY KEY,
70 @ tkt_uuid TEXT UNIQUE,
71 @ tkt_mtime DATE,
72 @ tkt_ctime DATE,
73 @ -- Add as many fields as required below this line
74 @ type TEXT,
75 @ status TEXT,
76 @ subsystem TEXT,
77 @ priority TEXT,
@@ -82,10 +83,11 @@
83 @ comment TEXT
84 @ );
85 @ CREATE TABLE ticketchng(
86 @ -- Do not change any column that begins with tkt_
87 @ tkt_id INTEGER REFERENCES ticket,
88 @ tkt_rid INTEGER REFERENCES blob,
89 @ tkt_mtime DATE,
90 @ -- Add as many fields as required below this line
91 @ login TEXT,
92 @ username TEXT,
93 @ mimetype TEXT,
94
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -67,10 +67,11 @@
6767
@ CREATE TABLE ticket(
6868
@ -- Do not change any column that begins with tkt_
6969
@ tkt_id INTEGER PRIMARY KEY,
7070
@ tkt_uuid TEXT UNIQUE,
7171
@ tkt_mtime DATE,
72
+@ tkt_ctime DATE,
7273
@ -- Add as many fields as required below this line
7374
@ type TEXT,
7475
@ status TEXT,
7576
@ subsystem TEXT,
7677
@ priority TEXT,
@@ -82,10 +83,11 @@
8283
@ comment TEXT
8384
@ );
8485
@ CREATE TABLE ticketchng(
8586
@ -- Do not change any column that begins with tkt_
8687
@ tkt_id INTEGER REFERENCES ticket,
88
+@ tkt_rid INTEGER REFERENCES blob,
8789
@ tkt_mtime DATE,
8890
@ -- Add as many fields as required below this line
8991
@ login TEXT,
9092
@ username TEXT,
9193
@ mimetype TEXT,
9294
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -67,10 +67,11 @@
67 @ CREATE TABLE ticket(
68 @ -- Do not change any column that begins with tkt_
69 @ tkt_id INTEGER PRIMARY KEY,
70 @ tkt_uuid TEXT UNIQUE,
71 @ tkt_mtime DATE,
 
72 @ -- Add as many fields as required below this line
73 @ type TEXT,
74 @ status TEXT,
75 @ subsystem TEXT,
76 @ priority TEXT,
@@ -82,10 +83,11 @@
82 @ comment TEXT
83 @ );
84 @ CREATE TABLE ticketchng(
85 @ -- Do not change any column that begins with tkt_
86 @ tkt_id INTEGER REFERENCES ticket,
 
87 @ tkt_mtime DATE,
88 @ -- Add as many fields as required below this line
89 @ login TEXT,
90 @ username TEXT,
91 @ mimetype TEXT,
92
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -67,10 +67,11 @@
67 @ CREATE TABLE ticket(
68 @ -- Do not change any column that begins with tkt_
69 @ tkt_id INTEGER PRIMARY KEY,
70 @ tkt_uuid TEXT UNIQUE,
71 @ tkt_mtime DATE,
72 @ tkt_ctime DATE,
73 @ -- Add as many fields as required below this line
74 @ type TEXT,
75 @ status TEXT,
76 @ subsystem TEXT,
77 @ priority TEXT,
@@ -82,10 +83,11 @@
83 @ comment TEXT
84 @ );
85 @ CREATE TABLE ticketchng(
86 @ -- Do not change any column that begins with tkt_
87 @ tkt_id INTEGER REFERENCES ticket,
88 @ tkt_rid INTEGER REFERENCES blob,
89 @ tkt_mtime DATE,
90 @ -- Add as many fields as required below this line
91 @ login TEXT,
92 @ username TEXT,
93 @ mimetype TEXT,
94
+1 -1
--- src/unicode.c
+++ src/unicode.c
@@ -131,11 +131,11 @@
131131
132132
if( c<128 ){
133133
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
134134
}else if( c<(1<<22) ){
135135
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
136
- int iRes;
136
+ int iRes = 0;
137137
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
138138
int iLo = 0;
139139
while( iHi>=iLo ){
140140
int iTest = (iHi + iLo) / 2;
141141
if( key >= aEntry[iTest] ){
142142
--- src/unicode.c
+++ src/unicode.c
@@ -131,11 +131,11 @@
131
132 if( c<128 ){
133 return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
134 }else if( c<(1<<22) ){
135 unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
136 int iRes;
137 int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
138 int iLo = 0;
139 while( iHi>=iLo ){
140 int iTest = (iHi + iLo) / 2;
141 if( key >= aEntry[iTest] ){
142
--- src/unicode.c
+++ src/unicode.c
@@ -131,11 +131,11 @@
131
132 if( c<128 ){
133 return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
134 }else if( c<(1<<22) ){
135 unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
136 int iRes = 0;
137 int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
138 int iLo = 0;
139 while( iHi>=iLo ){
140 int iTest = (iHi + iLo) / 2;
141 if( key >= aEntry[iTest] ){
142
+35 -11
--- src/update.c
+++ src/update.c
@@ -667,10 +667,13 @@
667667
** Usage: %fossil revert ?-r REVISION? ?FILE ...?
668668
**
669669
** Revert to the current repository version of FILE, or to
670670
** the version associated with baseline REVISION if the -r flag
671671
** appears.
672
+**
673
+** If FILE was part of a rename operation, both the original file
674
+** and the renamed file are reverted.
672675
**
673676
** Revert all files if no file name is provided.
674677
**
675678
** If a file is reverted accidently, it can be restored using
676679
** the "fossil undo" command.
@@ -706,23 +709,38 @@
706709
if( g.argc>2 ){
707710
for(i=2; i<g.argc; i++){
708711
Blob fname;
709712
zFile = mprintf("%/", g.argv[i]);
710713
file_tree_name(zFile, &fname, 1);
711
- db_multi_exec("REPLACE INTO torevert VALUES(%B)", &fname);
714
+ db_multi_exec(
715
+ "REPLACE INTO torevert VALUES(%B);"
716
+ "INSERT OR IGNORE INTO torevert"
717
+ " SELECT pathname"
718
+ " FROM vfile"
719
+ " WHERE origname IN(%B)"
720
+ " UNION ALL"
721
+ " SELECT origname"
722
+ " FROM vfile"
723
+ " WHERE pathname IN(%B) AND origname IS NOT NULL;",
724
+ &fname, &fname, &fname
725
+ );
712726
blob_reset(&fname);
713727
}
714728
}else{
715729
int vid;
716730
vid = db_lget_int("checkout", 0);
717731
vfile_check_signature(vid, 0);
718732
db_multi_exec(
719733
"DELETE FROM vmerge;"
720
- "INSERT INTO torevert "
721
- "SELECT pathname"
722
- " FROM vfile "
723
- " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
734
+ "INSERT OR IGNORE INTO torevert "
735
+ " SELECT pathname"
736
+ " FROM vfile "
737
+ " WHERE chnged OR deleted OR rid=0 OR pathname!=origname "
738
+ " UNION ALL "
739
+ " SELECT origname"
740
+ " FROM vfile"
741
+ " WHERE origname!=pathname;"
724742
);
725743
}
726744
blob_zero(&record);
727745
db_prepare(&q, "SELECT name FROM torevert");
728746
if( zRevision==0 ){
@@ -736,18 +754,25 @@
736754
zFile = db_column_text(&q, 0);
737755
zFull = mprintf("%/%/", g.zLocalRoot, zFile);
738756
errCode = historical_version_of_file(zRevision, zFile, &record,
739757
&isLink, &isExe, 0, 2);
740758
if( errCode==2 ){
741
- if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){
759
+ if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
760
+ zFile, zFile)==0 ){
742761
fossil_print("UNMANAGE: %s\n", zFile);
743762
}else{
744763
undo_save(zFile);
745764
file_delete(zFull);
746765
fossil_print("DELETE: %s\n", zFile);
747766
}
748
- db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile);
767
+ db_multi_exec(
768
+ "UPDATE vfile"
769
+ " SET pathname=origname, origname=NULL"
770
+ " WHERE pathname=%Q AND origname!=pathname AND origname IS NOT NULL;"
771
+ "DELETE FROM vfile WHERE pathname=%Q",
772
+ zFile, zFile
773
+ );
749774
}else{
750775
sqlite3_int64 mtime;
751776
undo_save(zFile);
752777
if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
753778
file_delete(zFull);
@@ -760,18 +785,17 @@
760785
file_wd_setexe(zFull, isExe);
761786
fossil_print("REVERTED: %s\n", zFile);
762787
mtime = file_wd_mtime(zFull);
763788
db_multi_exec(
764789
"UPDATE vfile"
765
- " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid,"
766
- " pathname=coalesce(origname,pathname), origname=NULL"
767
- " WHERE pathname=%Q",
768
- mtime, isExe, isLink, zFile
790
+ " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid"
791
+ " WHERE pathname=%Q OR origname=%Q",
792
+ mtime, isExe, isLink, zFile, zFile
769793
);
770794
}
771795
blob_reset(&record);
772796
free(zFull);
773797
}
774798
db_finalize(&q);
775799
undo_finish();
776800
db_end_transaction(0);
777801
}
778802
--- src/update.c
+++ src/update.c
@@ -667,10 +667,13 @@
667 ** Usage: %fossil revert ?-r REVISION? ?FILE ...?
668 **
669 ** Revert to the current repository version of FILE, or to
670 ** the version associated with baseline REVISION if the -r flag
671 ** appears.
 
 
 
672 **
673 ** Revert all files if no file name is provided.
674 **
675 ** If a file is reverted accidently, it can be restored using
676 ** the "fossil undo" command.
@@ -706,23 +709,38 @@
706 if( g.argc>2 ){
707 for(i=2; i<g.argc; i++){
708 Blob fname;
709 zFile = mprintf("%/", g.argv[i]);
710 file_tree_name(zFile, &fname, 1);
711 db_multi_exec("REPLACE INTO torevert VALUES(%B)", &fname);
 
 
 
 
 
 
 
 
 
 
 
712 blob_reset(&fname);
713 }
714 }else{
715 int vid;
716 vid = db_lget_int("checkout", 0);
717 vfile_check_signature(vid, 0);
718 db_multi_exec(
719 "DELETE FROM vmerge;"
720 "INSERT INTO torevert "
721 "SELECT pathname"
722 " FROM vfile "
723 " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
 
 
 
 
724 );
725 }
726 blob_zero(&record);
727 db_prepare(&q, "SELECT name FROM torevert");
728 if( zRevision==0 ){
@@ -736,18 +754,25 @@
736 zFile = db_column_text(&q, 0);
737 zFull = mprintf("%/%/", g.zLocalRoot, zFile);
738 errCode = historical_version_of_file(zRevision, zFile, &record,
739 &isLink, &isExe, 0, 2);
740 if( errCode==2 ){
741 if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){
 
742 fossil_print("UNMANAGE: %s\n", zFile);
743 }else{
744 undo_save(zFile);
745 file_delete(zFull);
746 fossil_print("DELETE: %s\n", zFile);
747 }
748 db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile);
 
 
 
 
 
 
749 }else{
750 sqlite3_int64 mtime;
751 undo_save(zFile);
752 if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
753 file_delete(zFull);
@@ -760,18 +785,17 @@
760 file_wd_setexe(zFull, isExe);
761 fossil_print("REVERTED: %s\n", zFile);
762 mtime = file_wd_mtime(zFull);
763 db_multi_exec(
764 "UPDATE vfile"
765 " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid,"
766 " pathname=coalesce(origname,pathname), origname=NULL"
767 " WHERE pathname=%Q",
768 mtime, isExe, isLink, zFile
769 );
770 }
771 blob_reset(&record);
772 free(zFull);
773 }
774 db_finalize(&q);
775 undo_finish();
776 db_end_transaction(0);
777 }
778
--- src/update.c
+++ src/update.c
@@ -667,10 +667,13 @@
667 ** Usage: %fossil revert ?-r REVISION? ?FILE ...?
668 **
669 ** Revert to the current repository version of FILE, or to
670 ** the version associated with baseline REVISION if the -r flag
671 ** appears.
672 **
673 ** If FILE was part of a rename operation, both the original file
674 ** and the renamed file are reverted.
675 **
676 ** Revert all files if no file name is provided.
677 **
678 ** If a file is reverted accidently, it can be restored using
679 ** the "fossil undo" command.
@@ -706,23 +709,38 @@
709 if( g.argc>2 ){
710 for(i=2; i<g.argc; i++){
711 Blob fname;
712 zFile = mprintf("%/", g.argv[i]);
713 file_tree_name(zFile, &fname, 1);
714 db_multi_exec(
715 "REPLACE INTO torevert VALUES(%B);"
716 "INSERT OR IGNORE INTO torevert"
717 " SELECT pathname"
718 " FROM vfile"
719 " WHERE origname IN(%B)"
720 " UNION ALL"
721 " SELECT origname"
722 " FROM vfile"
723 " WHERE pathname IN(%B) AND origname IS NOT NULL;",
724 &fname, &fname, &fname
725 );
726 blob_reset(&fname);
727 }
728 }else{
729 int vid;
730 vid = db_lget_int("checkout", 0);
731 vfile_check_signature(vid, 0);
732 db_multi_exec(
733 "DELETE FROM vmerge;"
734 "INSERT OR IGNORE INTO torevert "
735 " SELECT pathname"
736 " FROM vfile "
737 " WHERE chnged OR deleted OR rid=0 OR pathname!=origname "
738 " UNION ALL "
739 " SELECT origname"
740 " FROM vfile"
741 " WHERE origname!=pathname;"
742 );
743 }
744 blob_zero(&record);
745 db_prepare(&q, "SELECT name FROM torevert");
746 if( zRevision==0 ){
@@ -736,18 +754,25 @@
754 zFile = db_column_text(&q, 0);
755 zFull = mprintf("%/%/", g.zLocalRoot, zFile);
756 errCode = historical_version_of_file(zRevision, zFile, &record,
757 &isLink, &isExe, 0, 2);
758 if( errCode==2 ){
759 if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
760 zFile, zFile)==0 ){
761 fossil_print("UNMANAGE: %s\n", zFile);
762 }else{
763 undo_save(zFile);
764 file_delete(zFull);
765 fossil_print("DELETE: %s\n", zFile);
766 }
767 db_multi_exec(
768 "UPDATE vfile"
769 " SET pathname=origname, origname=NULL"
770 " WHERE pathname=%Q AND origname!=pathname AND origname IS NOT NULL;"
771 "DELETE FROM vfile WHERE pathname=%Q",
772 zFile, zFile
773 );
774 }else{
775 sqlite3_int64 mtime;
776 undo_save(zFile);
777 if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
778 file_delete(zFull);
@@ -760,18 +785,17 @@
785 file_wd_setexe(zFull, isExe);
786 fossil_print("REVERTED: %s\n", zFile);
787 mtime = file_wd_mtime(zFull);
788 db_multi_exec(
789 "UPDATE vfile"
790 " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid"
791 " WHERE pathname=%Q OR origname=%Q",
792 mtime, isExe, isLink, zFile, zFile
 
793 );
794 }
795 blob_reset(&record);
796 free(zFull);
797 }
798 db_finalize(&q);
799 undo_finish();
800 db_end_transaction(0);
801 }
802
+35 -11
--- src/update.c
+++ src/update.c
@@ -667,10 +667,13 @@
667667
** Usage: %fossil revert ?-r REVISION? ?FILE ...?
668668
**
669669
** Revert to the current repository version of FILE, or to
670670
** the version associated with baseline REVISION if the -r flag
671671
** appears.
672
+**
673
+** If FILE was part of a rename operation, both the original file
674
+** and the renamed file are reverted.
672675
**
673676
** Revert all files if no file name is provided.
674677
**
675678
** If a file is reverted accidently, it can be restored using
676679
** the "fossil undo" command.
@@ -706,23 +709,38 @@
706709
if( g.argc>2 ){
707710
for(i=2; i<g.argc; i++){
708711
Blob fname;
709712
zFile = mprintf("%/", g.argv[i]);
710713
file_tree_name(zFile, &fname, 1);
711
- db_multi_exec("REPLACE INTO torevert VALUES(%B)", &fname);
714
+ db_multi_exec(
715
+ "REPLACE INTO torevert VALUES(%B);"
716
+ "INSERT OR IGNORE INTO torevert"
717
+ " SELECT pathname"
718
+ " FROM vfile"
719
+ " WHERE origname IN(%B)"
720
+ " UNION ALL"
721
+ " SELECT origname"
722
+ " FROM vfile"
723
+ " WHERE pathname IN(%B) AND origname IS NOT NULL;",
724
+ &fname, &fname, &fname
725
+ );
712726
blob_reset(&fname);
713727
}
714728
}else{
715729
int vid;
716730
vid = db_lget_int("checkout", 0);
717731
vfile_check_signature(vid, 0);
718732
db_multi_exec(
719733
"DELETE FROM vmerge;"
720
- "INSERT INTO torevert "
721
- "SELECT pathname"
722
- " FROM vfile "
723
- " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
734
+ "INSERT OR IGNORE INTO torevert "
735
+ " SELECT pathname"
736
+ " FROM vfile "
737
+ " WHERE chnged OR deleted OR rid=0 OR pathname!=origname "
738
+ " UNION ALL "
739
+ " SELECT origname"
740
+ " FROM vfile"
741
+ " WHERE origname!=pathname;"
724742
);
725743
}
726744
blob_zero(&record);
727745
db_prepare(&q, "SELECT name FROM torevert");
728746
if( zRevision==0 ){
@@ -736,18 +754,25 @@
736754
zFile = db_column_text(&q, 0);
737755
zFull = mprintf("%/%/", g.zLocalRoot, zFile);
738756
errCode = historical_version_of_file(zRevision, zFile, &record,
739757
&isLink, &isExe, 0, 2);
740758
if( errCode==2 ){
741
- if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){
759
+ if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
760
+ zFile, zFile)==0 ){
742761
fossil_print("UNMANAGE: %s\n", zFile);
743762
}else{
744763
undo_save(zFile);
745764
file_delete(zFull);
746765
fossil_print("DELETE: %s\n", zFile);
747766
}
748
- db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile);
767
+ db_multi_exec(
768
+ "UPDATE vfile"
769
+ " SET pathname=origname, origname=NULL"
770
+ " WHERE pathname=%Q AND origname!=pathname AND origname IS NOT NULL;"
771
+ "DELETE FROM vfile WHERE pathname=%Q",
772
+ zFile, zFile
773
+ );
749774
}else{
750775
sqlite3_int64 mtime;
751776
undo_save(zFile);
752777
if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
753778
file_delete(zFull);
@@ -760,18 +785,17 @@
760785
file_wd_setexe(zFull, isExe);
761786
fossil_print("REVERTED: %s\n", zFile);
762787
mtime = file_wd_mtime(zFull);
763788
db_multi_exec(
764789
"UPDATE vfile"
765
- " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid,"
766
- " pathname=coalesce(origname,pathname), origname=NULL"
767
- " WHERE pathname=%Q",
768
- mtime, isExe, isLink, zFile
790
+ " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid"
791
+ " WHERE pathname=%Q OR origname=%Q",
792
+ mtime, isExe, isLink, zFile, zFile
769793
);
770794
}
771795
blob_reset(&record);
772796
free(zFull);
773797
}
774798
db_finalize(&q);
775799
undo_finish();
776800
db_end_transaction(0);
777801
}
778802
--- src/update.c
+++ src/update.c
@@ -667,10 +667,13 @@
667 ** Usage: %fossil revert ?-r REVISION? ?FILE ...?
668 **
669 ** Revert to the current repository version of FILE, or to
670 ** the version associated with baseline REVISION if the -r flag
671 ** appears.
 
 
 
672 **
673 ** Revert all files if no file name is provided.
674 **
675 ** If a file is reverted accidently, it can be restored using
676 ** the "fossil undo" command.
@@ -706,23 +709,38 @@
706 if( g.argc>2 ){
707 for(i=2; i<g.argc; i++){
708 Blob fname;
709 zFile = mprintf("%/", g.argv[i]);
710 file_tree_name(zFile, &fname, 1);
711 db_multi_exec("REPLACE INTO torevert VALUES(%B)", &fname);
 
 
 
 
 
 
 
 
 
 
 
712 blob_reset(&fname);
713 }
714 }else{
715 int vid;
716 vid = db_lget_int("checkout", 0);
717 vfile_check_signature(vid, 0);
718 db_multi_exec(
719 "DELETE FROM vmerge;"
720 "INSERT INTO torevert "
721 "SELECT pathname"
722 " FROM vfile "
723 " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
 
 
 
 
724 );
725 }
726 blob_zero(&record);
727 db_prepare(&q, "SELECT name FROM torevert");
728 if( zRevision==0 ){
@@ -736,18 +754,25 @@
736 zFile = db_column_text(&q, 0);
737 zFull = mprintf("%/%/", g.zLocalRoot, zFile);
738 errCode = historical_version_of_file(zRevision, zFile, &record,
739 &isLink, &isExe, 0, 2);
740 if( errCode==2 ){
741 if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){
 
742 fossil_print("UNMANAGE: %s\n", zFile);
743 }else{
744 undo_save(zFile);
745 file_delete(zFull);
746 fossil_print("DELETE: %s\n", zFile);
747 }
748 db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile);
 
 
 
 
 
 
749 }else{
750 sqlite3_int64 mtime;
751 undo_save(zFile);
752 if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
753 file_delete(zFull);
@@ -760,18 +785,17 @@
760 file_wd_setexe(zFull, isExe);
761 fossil_print("REVERTED: %s\n", zFile);
762 mtime = file_wd_mtime(zFull);
763 db_multi_exec(
764 "UPDATE vfile"
765 " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid,"
766 " pathname=coalesce(origname,pathname), origname=NULL"
767 " WHERE pathname=%Q",
768 mtime, isExe, isLink, zFile
769 );
770 }
771 blob_reset(&record);
772 free(zFull);
773 }
774 db_finalize(&q);
775 undo_finish();
776 db_end_transaction(0);
777 }
778
--- src/update.c
+++ src/update.c
@@ -667,10 +667,13 @@
667 ** Usage: %fossil revert ?-r REVISION? ?FILE ...?
668 **
669 ** Revert to the current repository version of FILE, or to
670 ** the version associated with baseline REVISION if the -r flag
671 ** appears.
672 **
673 ** If FILE was part of a rename operation, both the original file
674 ** and the renamed file are reverted.
675 **
676 ** Revert all files if no file name is provided.
677 **
678 ** If a file is reverted accidently, it can be restored using
679 ** the "fossil undo" command.
@@ -706,23 +709,38 @@
709 if( g.argc>2 ){
710 for(i=2; i<g.argc; i++){
711 Blob fname;
712 zFile = mprintf("%/", g.argv[i]);
713 file_tree_name(zFile, &fname, 1);
714 db_multi_exec(
715 "REPLACE INTO torevert VALUES(%B);"
716 "INSERT OR IGNORE INTO torevert"
717 " SELECT pathname"
718 " FROM vfile"
719 " WHERE origname IN(%B)"
720 " UNION ALL"
721 " SELECT origname"
722 " FROM vfile"
723 " WHERE pathname IN(%B) AND origname IS NOT NULL;",
724 &fname, &fname, &fname
725 );
726 blob_reset(&fname);
727 }
728 }else{
729 int vid;
730 vid = db_lget_int("checkout", 0);
731 vfile_check_signature(vid, 0);
732 db_multi_exec(
733 "DELETE FROM vmerge;"
734 "INSERT OR IGNORE INTO torevert "
735 " SELECT pathname"
736 " FROM vfile "
737 " WHERE chnged OR deleted OR rid=0 OR pathname!=origname "
738 " UNION ALL "
739 " SELECT origname"
740 " FROM vfile"
741 " WHERE origname!=pathname;"
742 );
743 }
744 blob_zero(&record);
745 db_prepare(&q, "SELECT name FROM torevert");
746 if( zRevision==0 ){
@@ -736,18 +754,25 @@
754 zFile = db_column_text(&q, 0);
755 zFull = mprintf("%/%/", g.zLocalRoot, zFile);
756 errCode = historical_version_of_file(zRevision, zFile, &record,
757 &isLink, &isExe, 0, 2);
758 if( errCode==2 ){
759 if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
760 zFile, zFile)==0 ){
761 fossil_print("UNMANAGE: %s\n", zFile);
762 }else{
763 undo_save(zFile);
764 file_delete(zFull);
765 fossil_print("DELETE: %s\n", zFile);
766 }
767 db_multi_exec(
768 "UPDATE vfile"
769 " SET pathname=origname, origname=NULL"
770 " WHERE pathname=%Q AND origname!=pathname AND origname IS NOT NULL;"
771 "DELETE FROM vfile WHERE pathname=%Q",
772 zFile, zFile
773 );
774 }else{
775 sqlite3_int64 mtime;
776 undo_save(zFile);
777 if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
778 file_delete(zFull);
@@ -760,18 +785,17 @@
785 file_wd_setexe(zFull, isExe);
786 fossil_print("REVERTED: %s\n", zFile);
787 mtime = file_wd_mtime(zFull);
788 db_multi_exec(
789 "UPDATE vfile"
790 " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid"
791 " WHERE pathname=%Q OR origname=%Q",
792 mtime, isExe, isLink, zFile, zFile
 
793 );
794 }
795 blob_reset(&record);
796 free(zFull);
797 }
798 db_finalize(&q);
799 undo_finish();
800 db_end_transaction(0);
801 }
802
+10 -1
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
6363
|| strncmp(zUrl, "ssh://", 6)==0
6464
){
6565
int iStart;
6666
char *zLogin;
6767
char *zExe;
68
+ char cQuerySep = '?';
6869
6970
g.urlIsFile = 0;
7071
if( zUrl[4]=='s' ){
7172
g.urlIsHttps = 1;
7273
g.urlProtocol = "https";
@@ -75,10 +76,11 @@
7576
}else if( zUrl[0]=='s' ){
7677
g.urlIsSsh = 1;
7778
g.urlProtocol = "ssh";
7879
g.urlDfltPort = 22;
7980
g.urlFossil = "fossil";
81
+ g.urlShell = 0;
8082
iStart = 6;
8183
}else{
8284
g.urlIsHttps = 0;
8385
g.urlProtocol = "http";
8486
g.urlDfltPort = 80;
@@ -144,11 +146,18 @@
144146
i++;
145147
}
146148
if( fossil_strcmp(zName,"fossil")==0 ){
147149
g.urlFossil = zValue;
148150
dehttpize(g.urlFossil);
149
- zExe = mprintf("?fossil=%T", g.urlFossil);
151
+ zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
152
+ cQuerySep = '&';
153
+ }
154
+ if( fossil_strcmp(zName,"shell")==0 ){
155
+ g.urlShell = zValue;
156
+ dehttpize(g.urlShell);
157
+ zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil);
158
+ cQuerySep = '&';
150159
}
151160
}
152161
153162
dehttpize(g.urlPath);
154163
if( g.urlDfltPort==g.urlPort ){
155164
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
63 || strncmp(zUrl, "ssh://", 6)==0
64 ){
65 int iStart;
66 char *zLogin;
67 char *zExe;
 
68
69 g.urlIsFile = 0;
70 if( zUrl[4]=='s' ){
71 g.urlIsHttps = 1;
72 g.urlProtocol = "https";
@@ -75,10 +76,11 @@
75 }else if( zUrl[0]=='s' ){
76 g.urlIsSsh = 1;
77 g.urlProtocol = "ssh";
78 g.urlDfltPort = 22;
79 g.urlFossil = "fossil";
 
80 iStart = 6;
81 }else{
82 g.urlIsHttps = 0;
83 g.urlProtocol = "http";
84 g.urlDfltPort = 80;
@@ -144,11 +146,18 @@
144 i++;
145 }
146 if( fossil_strcmp(zName,"fossil")==0 ){
147 g.urlFossil = zValue;
148 dehttpize(g.urlFossil);
149 zExe = mprintf("?fossil=%T", g.urlFossil);
 
 
 
 
 
 
 
150 }
151 }
152
153 dehttpize(g.urlPath);
154 if( g.urlDfltPort==g.urlPort ){
155
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
63 || strncmp(zUrl, "ssh://", 6)==0
64 ){
65 int iStart;
66 char *zLogin;
67 char *zExe;
68 char cQuerySep = '?';
69
70 g.urlIsFile = 0;
71 if( zUrl[4]=='s' ){
72 g.urlIsHttps = 1;
73 g.urlProtocol = "https";
@@ -75,10 +76,11 @@
76 }else if( zUrl[0]=='s' ){
77 g.urlIsSsh = 1;
78 g.urlProtocol = "ssh";
79 g.urlDfltPort = 22;
80 g.urlFossil = "fossil";
81 g.urlShell = 0;
82 iStart = 6;
83 }else{
84 g.urlIsHttps = 0;
85 g.urlProtocol = "http";
86 g.urlDfltPort = 80;
@@ -144,11 +146,18 @@
146 i++;
147 }
148 if( fossil_strcmp(zName,"fossil")==0 ){
149 g.urlFossil = zValue;
150 dehttpize(g.urlFossil);
151 zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
152 cQuerySep = '&';
153 }
154 if( fossil_strcmp(zName,"shell")==0 ){
155 g.urlShell = zValue;
156 dehttpize(g.urlShell);
157 zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil);
158 cQuerySep = '&';
159 }
160 }
161
162 dehttpize(g.urlPath);
163 if( g.urlDfltPort==g.urlPort ){
164
+10 -1
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
6363
|| strncmp(zUrl, "ssh://", 6)==0
6464
){
6565
int iStart;
6666
char *zLogin;
6767
char *zExe;
68
+ char cQuerySep = '?';
6869
6970
g.urlIsFile = 0;
7071
if( zUrl[4]=='s' ){
7172
g.urlIsHttps = 1;
7273
g.urlProtocol = "https";
@@ -75,10 +76,11 @@
7576
}else if( zUrl[0]=='s' ){
7677
g.urlIsSsh = 1;
7778
g.urlProtocol = "ssh";
7879
g.urlDfltPort = 22;
7980
g.urlFossil = "fossil";
81
+ g.urlShell = 0;
8082
iStart = 6;
8183
}else{
8284
g.urlIsHttps = 0;
8385
g.urlProtocol = "http";
8486
g.urlDfltPort = 80;
@@ -144,11 +146,18 @@
144146
i++;
145147
}
146148
if( fossil_strcmp(zName,"fossil")==0 ){
147149
g.urlFossil = zValue;
148150
dehttpize(g.urlFossil);
149
- zExe = mprintf("?fossil=%T", g.urlFossil);
151
+ zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
152
+ cQuerySep = '&';
153
+ }
154
+ if( fossil_strcmp(zName,"shell")==0 ){
155
+ g.urlShell = zValue;
156
+ dehttpize(g.urlShell);
157
+ zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil);
158
+ cQuerySep = '&';
150159
}
151160
}
152161
153162
dehttpize(g.urlPath);
154163
if( g.urlDfltPort==g.urlPort ){
155164
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
63 || strncmp(zUrl, "ssh://", 6)==0
64 ){
65 int iStart;
66 char *zLogin;
67 char *zExe;
 
68
69 g.urlIsFile = 0;
70 if( zUrl[4]=='s' ){
71 g.urlIsHttps = 1;
72 g.urlProtocol = "https";
@@ -75,10 +76,11 @@
75 }else if( zUrl[0]=='s' ){
76 g.urlIsSsh = 1;
77 g.urlProtocol = "ssh";
78 g.urlDfltPort = 22;
79 g.urlFossil = "fossil";
 
80 iStart = 6;
81 }else{
82 g.urlIsHttps = 0;
83 g.urlProtocol = "http";
84 g.urlDfltPort = 80;
@@ -144,11 +146,18 @@
144 i++;
145 }
146 if( fossil_strcmp(zName,"fossil")==0 ){
147 g.urlFossil = zValue;
148 dehttpize(g.urlFossil);
149 zExe = mprintf("?fossil=%T", g.urlFossil);
 
 
 
 
 
 
 
150 }
151 }
152
153 dehttpize(g.urlPath);
154 if( g.urlDfltPort==g.urlPort ){
155
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
63 || strncmp(zUrl, "ssh://", 6)==0
64 ){
65 int iStart;
66 char *zLogin;
67 char *zExe;
68 char cQuerySep = '?';
69
70 g.urlIsFile = 0;
71 if( zUrl[4]=='s' ){
72 g.urlIsHttps = 1;
73 g.urlProtocol = "https";
@@ -75,10 +76,11 @@
76 }else if( zUrl[0]=='s' ){
77 g.urlIsSsh = 1;
78 g.urlProtocol = "ssh";
79 g.urlDfltPort = 22;
80 g.urlFossil = "fossil";
81 g.urlShell = 0;
82 iStart = 6;
83 }else{
84 g.urlIsHttps = 0;
85 g.urlProtocol = "http";
86 g.urlDfltPort = 80;
@@ -144,11 +146,18 @@
146 i++;
147 }
148 if( fossil_strcmp(zName,"fossil")==0 ){
149 g.urlFossil = zValue;
150 dehttpize(g.urlFossil);
151 zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
152 cQuerySep = '&';
153 }
154 if( fossil_strcmp(zName,"shell")==0 ){
155 g.urlShell = zValue;
156 dehttpize(g.urlShell);
157 zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil);
158 cQuerySep = '&';
159 }
160 }
161
162 dehttpize(g.urlPath);
163 if( g.urlDfltPort==g.urlPort ){
164
+19 -3
--- src/xfer.c
+++ src/xfer.c
@@ -18,10 +18,18 @@
1818
** This file contains code to implement the file transfer protocol.
1919
*/
2020
#include "config.h"
2121
#include "xfer.h"
2222
23
+#include <time.h>
24
+
25
+/*
26
+** Maximum number of HTTP redirects that any http_exchange() call will
27
+** follow before throwing a fatal error. Most browsers use a limit of 20.
28
+*/
29
+#define MAX_REDIRECTS 20
30
+
2331
/*
2432
** This structure holds information about the current state of either
2533
** a client or a server that is participating in xfer.
2634
*/
2735
typedef struct Xfer Xfer;
@@ -40,10 +48,11 @@
4048
int nDeltaRcvd; /* Number of deltas received */
4149
int nDanglingFile; /* Number of dangling deltas received */
4250
int mxSend; /* Stop sending "file" with pOut reaches this size */
4351
u8 syncPrivate; /* True to enable syncing private content */
4452
u8 nextIsPrivate; /* If true, next "file" received is a private */
53
+ time_t maxTime; /* Time when this transfer should be finished */
4554
};
4655
4756
4857
/*
4958
** The input blob contains a UUID. Convert it into a record ID.
@@ -393,11 +402,12 @@
393402
}
394403
if( uuid_is_shunned(blob_str(pUuid)) ){
395404
blob_reset(&uuid);
396405
return;
397406
}
398
- if( pXfer->mxSend<=blob_size(pXfer->pOut) ){
407
+ if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) ||
408
+ pXfer->mxSend<=blob_size(pXfer->pOut) ){
399409
const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
400410
blob_appendf(pXfer->pOut, zFormat, pUuid);
401411
pXfer->nIGotSent++;
402412
blob_reset(&uuid);
403413
return;
@@ -867,10 +877,13 @@
867877
}
868878
blob_zero(&xfer.err);
869879
xfer.pIn = &g.cgiIn;
870880
xfer.pOut = cgi_output_blob();
871881
xfer.mxSend = db_get_int("max-download", 5000000);
882
+ xfer.maxTime = db_get_int("max-download-time", 30);
883
+ if( xfer.maxTime<1 ) xfer.maxTime = 1;
884
+ xfer.maxTime += time(NULL);
872885
g.xferPanic = 1;
873886
874887
db_begin_transaction();
875888
db_multi_exec(
876889
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
@@ -1034,11 +1047,12 @@
10341047
if( iVers>=3 ){
10351048
cgi_set_content_type("application/x-fossil-uncompressed");
10361049
}
10371050
blob_is_int(&xfer.aToken[2], &seqno);
10381051
max = db_int(0, "SELECT max(rid) FROM blob");
1039
- while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max ){
1052
+ while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max){
1053
+ if( time(NULL) >= xfer.maxTime ) break;
10401054
if( iVers>=3 ){
10411055
send_compressed_file(&xfer, seqno);
10421056
}else{
10431057
send_file(&xfer, seqno, 0, 1);
10441058
}
@@ -1328,10 +1342,11 @@
13281342
socket_global_init();
13291343
memset(&xfer, 0, sizeof(xfer));
13301344
xfer.pIn = &recv;
13311345
xfer.pOut = &send;
13321346
xfer.mxSend = db_get_int("max-upload", 250000);
1347
+ xfer.maxTime = -1;
13331348
if( syncFlags & SYNC_PRIVATE ){
13341349
g.perm.Private = 1;
13351350
xfer.syncPrivate = 1;
13361351
}
13371352
@@ -1471,11 +1486,12 @@
14711486
xfer.nIGotSent = 0;
14721487
if( syncFlags & SYNC_VERBOSE ){
14731488
fossil_print("waiting for server...");
14741489
}
14751490
fflush(stdout);
1476
- if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
1491
+ if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1492
+ MAX_REDIRECTS) ){
14771493
nErr++;
14781494
break;
14791495
}
14801496
lastPctDone = -1;
14811497
blob_reset(&send);
14821498
14831499
ADDED test/revert.test
--- src/xfer.c
+++ src/xfer.c
@@ -18,10 +18,18 @@
18 ** This file contains code to implement the file transfer protocol.
19 */
20 #include "config.h"
21 #include "xfer.h"
22
 
 
 
 
 
 
 
 
23 /*
24 ** This structure holds information about the current state of either
25 ** a client or a server that is participating in xfer.
26 */
27 typedef struct Xfer Xfer;
@@ -40,10 +48,11 @@
40 int nDeltaRcvd; /* Number of deltas received */
41 int nDanglingFile; /* Number of dangling deltas received */
42 int mxSend; /* Stop sending "file" with pOut reaches this size */
43 u8 syncPrivate; /* True to enable syncing private content */
44 u8 nextIsPrivate; /* If true, next "file" received is a private */
 
45 };
46
47
48 /*
49 ** The input blob contains a UUID. Convert it into a record ID.
@@ -393,11 +402,12 @@
393 }
394 if( uuid_is_shunned(blob_str(pUuid)) ){
395 blob_reset(&uuid);
396 return;
397 }
398 if( pXfer->mxSend<=blob_size(pXfer->pOut) ){
 
399 const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
400 blob_appendf(pXfer->pOut, zFormat, pUuid);
401 pXfer->nIGotSent++;
402 blob_reset(&uuid);
403 return;
@@ -867,10 +877,13 @@
867 }
868 blob_zero(&xfer.err);
869 xfer.pIn = &g.cgiIn;
870 xfer.pOut = cgi_output_blob();
871 xfer.mxSend = db_get_int("max-download", 5000000);
 
 
 
872 g.xferPanic = 1;
873
874 db_begin_transaction();
875 db_multi_exec(
876 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
@@ -1034,11 +1047,12 @@
1034 if( iVers>=3 ){
1035 cgi_set_content_type("application/x-fossil-uncompressed");
1036 }
1037 blob_is_int(&xfer.aToken[2], &seqno);
1038 max = db_int(0, "SELECT max(rid) FROM blob");
1039 while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max ){
 
1040 if( iVers>=3 ){
1041 send_compressed_file(&xfer, seqno);
1042 }else{
1043 send_file(&xfer, seqno, 0, 1);
1044 }
@@ -1328,10 +1342,11 @@
1328 socket_global_init();
1329 memset(&xfer, 0, sizeof(xfer));
1330 xfer.pIn = &recv;
1331 xfer.pOut = &send;
1332 xfer.mxSend = db_get_int("max-upload", 250000);
 
1333 if( syncFlags & SYNC_PRIVATE ){
1334 g.perm.Private = 1;
1335 xfer.syncPrivate = 1;
1336 }
1337
@@ -1471,11 +1486,12 @@
1471 xfer.nIGotSent = 0;
1472 if( syncFlags & SYNC_VERBOSE ){
1473 fossil_print("waiting for server...");
1474 }
1475 fflush(stdout);
1476 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
 
1477 nErr++;
1478 break;
1479 }
1480 lastPctDone = -1;
1481 blob_reset(&send);
1482
1483 DDED test/revert.test
--- src/xfer.c
+++ src/xfer.c
@@ -18,10 +18,18 @@
18 ** This file contains code to implement the file transfer protocol.
19 */
20 #include "config.h"
21 #include "xfer.h"
22
23 #include <time.h>
24
25 /*
26 ** Maximum number of HTTP redirects that any http_exchange() call will
27 ** follow before throwing a fatal error. Most browsers use a limit of 20.
28 */
29 #define MAX_REDIRECTS 20
30
31 /*
32 ** This structure holds information about the current state of either
33 ** a client or a server that is participating in xfer.
34 */
35 typedef struct Xfer Xfer;
@@ -40,10 +48,11 @@
48 int nDeltaRcvd; /* Number of deltas received */
49 int nDanglingFile; /* Number of dangling deltas received */
50 int mxSend; /* Stop sending "file" with pOut reaches this size */
51 u8 syncPrivate; /* True to enable syncing private content */
52 u8 nextIsPrivate; /* If true, next "file" received is a private */
53 time_t maxTime; /* Time when this transfer should be finished */
54 };
55
56
57 /*
58 ** The input blob contains a UUID. Convert it into a record ID.
@@ -393,11 +402,12 @@
402 }
403 if( uuid_is_shunned(blob_str(pUuid)) ){
404 blob_reset(&uuid);
405 return;
406 }
407 if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) ||
408 pXfer->mxSend<=blob_size(pXfer->pOut) ){
409 const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
410 blob_appendf(pXfer->pOut, zFormat, pUuid);
411 pXfer->nIGotSent++;
412 blob_reset(&uuid);
413 return;
@@ -867,10 +877,13 @@
877 }
878 blob_zero(&xfer.err);
879 xfer.pIn = &g.cgiIn;
880 xfer.pOut = cgi_output_blob();
881 xfer.mxSend = db_get_int("max-download", 5000000);
882 xfer.maxTime = db_get_int("max-download-time", 30);
883 if( xfer.maxTime<1 ) xfer.maxTime = 1;
884 xfer.maxTime += time(NULL);
885 g.xferPanic = 1;
886
887 db_begin_transaction();
888 db_multi_exec(
889 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
@@ -1034,11 +1047,12 @@
1047 if( iVers>=3 ){
1048 cgi_set_content_type("application/x-fossil-uncompressed");
1049 }
1050 blob_is_int(&xfer.aToken[2], &seqno);
1051 max = db_int(0, "SELECT max(rid) FROM blob");
1052 while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max){
1053 if( time(NULL) >= xfer.maxTime ) break;
1054 if( iVers>=3 ){
1055 send_compressed_file(&xfer, seqno);
1056 }else{
1057 send_file(&xfer, seqno, 0, 1);
1058 }
@@ -1328,10 +1342,11 @@
1342 socket_global_init();
1343 memset(&xfer, 0, sizeof(xfer));
1344 xfer.pIn = &recv;
1345 xfer.pOut = &send;
1346 xfer.mxSend = db_get_int("max-upload", 250000);
1347 xfer.maxTime = -1;
1348 if( syncFlags & SYNC_PRIVATE ){
1349 g.perm.Private = 1;
1350 xfer.syncPrivate = 1;
1351 }
1352
@@ -1471,11 +1486,12 @@
1486 xfer.nIGotSent = 0;
1487 if( syncFlags & SYNC_VERBOSE ){
1488 fossil_print("waiting for server...");
1489 }
1490 fflush(stdout);
1491 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1492 MAX_REDIRECTS) ){
1493 nErr++;
1494 break;
1495 }
1496 lastPctDone = -1;
1497 blob_reset(&send);
1498
1499 DDED test/revert.test
+19 -3
--- src/xfer.c
+++ src/xfer.c
@@ -18,10 +18,18 @@
1818
** This file contains code to implement the file transfer protocol.
1919
*/
2020
#include "config.h"
2121
#include "xfer.h"
2222
23
+#include <time.h>
24
+
25
+/*
26
+** Maximum number of HTTP redirects that any http_exchange() call will
27
+** follow before throwing a fatal error. Most browsers use a limit of 20.
28
+*/
29
+#define MAX_REDIRECTS 20
30
+
2331
/*
2432
** This structure holds information about the current state of either
2533
** a client or a server that is participating in xfer.
2634
*/
2735
typedef struct Xfer Xfer;
@@ -40,10 +48,11 @@
4048
int nDeltaRcvd; /* Number of deltas received */
4149
int nDanglingFile; /* Number of dangling deltas received */
4250
int mxSend; /* Stop sending "file" with pOut reaches this size */
4351
u8 syncPrivate; /* True to enable syncing private content */
4452
u8 nextIsPrivate; /* If true, next "file" received is a private */
53
+ time_t maxTime; /* Time when this transfer should be finished */
4554
};
4655
4756
4857
/*
4958
** The input blob contains a UUID. Convert it into a record ID.
@@ -393,11 +402,12 @@
393402
}
394403
if( uuid_is_shunned(blob_str(pUuid)) ){
395404
blob_reset(&uuid);
396405
return;
397406
}
398
- if( pXfer->mxSend<=blob_size(pXfer->pOut) ){
407
+ if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) ||
408
+ pXfer->mxSend<=blob_size(pXfer->pOut) ){
399409
const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
400410
blob_appendf(pXfer->pOut, zFormat, pUuid);
401411
pXfer->nIGotSent++;
402412
blob_reset(&uuid);
403413
return;
@@ -867,10 +877,13 @@
867877
}
868878
blob_zero(&xfer.err);
869879
xfer.pIn = &g.cgiIn;
870880
xfer.pOut = cgi_output_blob();
871881
xfer.mxSend = db_get_int("max-download", 5000000);
882
+ xfer.maxTime = db_get_int("max-download-time", 30);
883
+ if( xfer.maxTime<1 ) xfer.maxTime = 1;
884
+ xfer.maxTime += time(NULL);
872885
g.xferPanic = 1;
873886
874887
db_begin_transaction();
875888
db_multi_exec(
876889
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
@@ -1034,11 +1047,12 @@
10341047
if( iVers>=3 ){
10351048
cgi_set_content_type("application/x-fossil-uncompressed");
10361049
}
10371050
blob_is_int(&xfer.aToken[2], &seqno);
10381051
max = db_int(0, "SELECT max(rid) FROM blob");
1039
- while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max ){
1052
+ while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max){
1053
+ if( time(NULL) >= xfer.maxTime ) break;
10401054
if( iVers>=3 ){
10411055
send_compressed_file(&xfer, seqno);
10421056
}else{
10431057
send_file(&xfer, seqno, 0, 1);
10441058
}
@@ -1328,10 +1342,11 @@
13281342
socket_global_init();
13291343
memset(&xfer, 0, sizeof(xfer));
13301344
xfer.pIn = &recv;
13311345
xfer.pOut = &send;
13321346
xfer.mxSend = db_get_int("max-upload", 250000);
1347
+ xfer.maxTime = -1;
13331348
if( syncFlags & SYNC_PRIVATE ){
13341349
g.perm.Private = 1;
13351350
xfer.syncPrivate = 1;
13361351
}
13371352
@@ -1471,11 +1486,12 @@
14711486
xfer.nIGotSent = 0;
14721487
if( syncFlags & SYNC_VERBOSE ){
14731488
fossil_print("waiting for server...");
14741489
}
14751490
fflush(stdout);
1476
- if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
1491
+ if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1492
+ MAX_REDIRECTS) ){
14771493
nErr++;
14781494
break;
14791495
}
14801496
lastPctDone = -1;
14811497
blob_reset(&send);
14821498
14831499
ADDED test/revert.test
--- src/xfer.c
+++ src/xfer.c
@@ -18,10 +18,18 @@
18 ** This file contains code to implement the file transfer protocol.
19 */
20 #include "config.h"
21 #include "xfer.h"
22
 
 
 
 
 
 
 
 
23 /*
24 ** This structure holds information about the current state of either
25 ** a client or a server that is participating in xfer.
26 */
27 typedef struct Xfer Xfer;
@@ -40,10 +48,11 @@
40 int nDeltaRcvd; /* Number of deltas received */
41 int nDanglingFile; /* Number of dangling deltas received */
42 int mxSend; /* Stop sending "file" with pOut reaches this size */
43 u8 syncPrivate; /* True to enable syncing private content */
44 u8 nextIsPrivate; /* If true, next "file" received is a private */
 
45 };
46
47
48 /*
49 ** The input blob contains a UUID. Convert it into a record ID.
@@ -393,11 +402,12 @@
393 }
394 if( uuid_is_shunned(blob_str(pUuid)) ){
395 blob_reset(&uuid);
396 return;
397 }
398 if( pXfer->mxSend<=blob_size(pXfer->pOut) ){
 
399 const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
400 blob_appendf(pXfer->pOut, zFormat, pUuid);
401 pXfer->nIGotSent++;
402 blob_reset(&uuid);
403 return;
@@ -867,10 +877,13 @@
867 }
868 blob_zero(&xfer.err);
869 xfer.pIn = &g.cgiIn;
870 xfer.pOut = cgi_output_blob();
871 xfer.mxSend = db_get_int("max-download", 5000000);
 
 
 
872 g.xferPanic = 1;
873
874 db_begin_transaction();
875 db_multi_exec(
876 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
@@ -1034,11 +1047,12 @@
1034 if( iVers>=3 ){
1035 cgi_set_content_type("application/x-fossil-uncompressed");
1036 }
1037 blob_is_int(&xfer.aToken[2], &seqno);
1038 max = db_int(0, "SELECT max(rid) FROM blob");
1039 while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max ){
 
1040 if( iVers>=3 ){
1041 send_compressed_file(&xfer, seqno);
1042 }else{
1043 send_file(&xfer, seqno, 0, 1);
1044 }
@@ -1328,10 +1342,11 @@
1328 socket_global_init();
1329 memset(&xfer, 0, sizeof(xfer));
1330 xfer.pIn = &recv;
1331 xfer.pOut = &send;
1332 xfer.mxSend = db_get_int("max-upload", 250000);
 
1333 if( syncFlags & SYNC_PRIVATE ){
1334 g.perm.Private = 1;
1335 xfer.syncPrivate = 1;
1336 }
1337
@@ -1471,11 +1486,12 @@
1471 xfer.nIGotSent = 0;
1472 if( syncFlags & SYNC_VERBOSE ){
1473 fossil_print("waiting for server...");
1474 }
1475 fflush(stdout);
1476 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
 
1477 nErr++;
1478 break;
1479 }
1480 lastPctDone = -1;
1481 blob_reset(&send);
1482
1483 DDED test/revert.test
--- src/xfer.c
+++ src/xfer.c
@@ -18,10 +18,18 @@
18 ** This file contains code to implement the file transfer protocol.
19 */
20 #include "config.h"
21 #include "xfer.h"
22
23 #include <time.h>
24
25 /*
26 ** Maximum number of HTTP redirects that any http_exchange() call will
27 ** follow before throwing a fatal error. Most browsers use a limit of 20.
28 */
29 #define MAX_REDIRECTS 20
30
31 /*
32 ** This structure holds information about the current state of either
33 ** a client or a server that is participating in xfer.
34 */
35 typedef struct Xfer Xfer;
@@ -40,10 +48,11 @@
48 int nDeltaRcvd; /* Number of deltas received */
49 int nDanglingFile; /* Number of dangling deltas received */
50 int mxSend; /* Stop sending "file" with pOut reaches this size */
51 u8 syncPrivate; /* True to enable syncing private content */
52 u8 nextIsPrivate; /* If true, next "file" received is a private */
53 time_t maxTime; /* Time when this transfer should be finished */
54 };
55
56
57 /*
58 ** The input blob contains a UUID. Convert it into a record ID.
@@ -393,11 +402,12 @@
402 }
403 if( uuid_is_shunned(blob_str(pUuid)) ){
404 blob_reset(&uuid);
405 return;
406 }
407 if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) ||
408 pXfer->mxSend<=blob_size(pXfer->pOut) ){
409 const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
410 blob_appendf(pXfer->pOut, zFormat, pUuid);
411 pXfer->nIGotSent++;
412 blob_reset(&uuid);
413 return;
@@ -867,10 +877,13 @@
877 }
878 blob_zero(&xfer.err);
879 xfer.pIn = &g.cgiIn;
880 xfer.pOut = cgi_output_blob();
881 xfer.mxSend = db_get_int("max-download", 5000000);
882 xfer.maxTime = db_get_int("max-download-time", 30);
883 if( xfer.maxTime<1 ) xfer.maxTime = 1;
884 xfer.maxTime += time(NULL);
885 g.xferPanic = 1;
886
887 db_begin_transaction();
888 db_multi_exec(
889 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
@@ -1034,11 +1047,12 @@
1047 if( iVers>=3 ){
1048 cgi_set_content_type("application/x-fossil-uncompressed");
1049 }
1050 blob_is_int(&xfer.aToken[2], &seqno);
1051 max = db_int(0, "SELECT max(rid) FROM blob");
1052 while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max){
1053 if( time(NULL) >= xfer.maxTime ) break;
1054 if( iVers>=3 ){
1055 send_compressed_file(&xfer, seqno);
1056 }else{
1057 send_file(&xfer, seqno, 0, 1);
1058 }
@@ -1328,10 +1342,11 @@
1342 socket_global_init();
1343 memset(&xfer, 0, sizeof(xfer));
1344 xfer.pIn = &recv;
1345 xfer.pOut = &send;
1346 xfer.mxSend = db_get_int("max-upload", 250000);
1347 xfer.maxTime = -1;
1348 if( syncFlags & SYNC_PRIVATE ){
1349 g.perm.Private = 1;
1350 xfer.syncPrivate = 1;
1351 }
1352
@@ -1471,11 +1486,12 @@
1486 xfer.nIGotSent = 0;
1487 if( syncFlags & SYNC_VERBOSE ){
1488 fossil_print("waiting for server...");
1489 }
1490 fflush(stdout);
1491 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1492 MAX_REDIRECTS) ){
1493 nErr++;
1494 break;
1495 }
1496 lastPctDone = -1;
1497 blob_reset(&send);
1498
1499 DDED test/revert.test
--- a/test/revert.test
+++ b/test/revert.test
@@ -0,0 +1,26 @@
1
+puts res=$# Fossil will write dexec rm f1po_init# Copytcatch {exec $::exec mvitory} $res]} {
2
+ puts stderr "Cannot ris test within anif {[llength $args] % 2} {
3
+ set revertArgs [lindex $args 0]
4
+ set args [lrange $args 1 end]
5
+ } else {
6
+ set revertArgs {}
7
+ }VERTED: f3
8
+ DELETE:j@Uy,1X@Se,4:: f0G@YW,21@UT,3:ED:1w@WW,3:ED:3t@YT,G:ED: f3
9
+ DELETE:K@hF,O@YG:ED: f3
10
+ DELETE:K@hF,O@Yl,1
11
+ DELETE:a@nd,1WvoIq;-testnormalize-status-list]
12
+ set r]
13
+ if {$result ne $expected} {
14
+ set passed 0
15
+ protOut " Expected:\n [join $expected "\n "]"
16
+ protOut " Got:\n [joh {exec $::fossilexe info} res
17
+if {![regexp {use --repository} $res]} {
18
+ puts stderr "Cannot run this test within an open checkout"
19
+ return
20
+}
21
+repo_init# Copytcatch {exec $::fossilexe info} res
22
+if {![regexp {use --repository} $res]} {
23
+ puts stderr "Cannot run this test witt# Copytcatch {exec $::fossilexe info} res
24
+if {![regexp {use --repository} $res]} {
25
+ put12 f03 f1 {exec $::fossilexe info}t# Copytcatch {exec $::foss4 f2 {exec $::ft# Copytcatch {exec $::foss5 f3 {exec $::fossilexe info} res
26
+if {![re
--- a/test/revert.test
+++ b/test/revert.test
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/revert.test
+++ b/test/revert.test
@@ -0,0 +1,26 @@
1 puts res=$# Fossil will write dexec rm f1po_init# Copytcatch {exec $::exec mvitory} $res]} {
2 puts stderr "Cannot ris test within anif {[llength $args] % 2} {
3 set revertArgs [lindex $args 0]
4 set args [lrange $args 1 end]
5 } else {
6 set revertArgs {}
7 }VERTED: f3
8 DELETE:j@Uy,1X@Se,4:: f0G@YW,21@UT,3:ED:1w@WW,3:ED:3t@YT,G:ED: f3
9 DELETE:K@hF,O@YG:ED: f3
10 DELETE:K@hF,O@Yl,1
11 DELETE:a@nd,1WvoIq;-testnormalize-status-list]
12 set r]
13 if {$result ne $expected} {
14 set passed 0
15 protOut " Expected:\n [join $expected "\n "]"
16 protOut " Got:\n [joh {exec $::fossilexe info} res
17 if {![regexp {use --repository} $res]} {
18 puts stderr "Cannot run this test within an open checkout"
19 return
20 }
21 repo_init# Copytcatch {exec $::fossilexe info} res
22 if {![regexp {use --repository} $res]} {
23 puts stderr "Cannot run this test witt# Copytcatch {exec $::fossilexe info} res
24 if {![regexp {use --repository} $res]} {
25 put12 f03 f1 {exec $::fossilexe info}t# Copytcatch {exec $::foss4 f2 {exec $::ft# Copytcatch {exec $::foss5 f3 {exec $::fossilexe info} res
26 if {![re
--- a/test/revert.test
+++ b/test/revert.test
@@ -0,0 +1,26 @@
1
+puts res=$# Fossil will write dexec rm f1po_init# Copytcatch {exec $::exec mvitory} $res]} {
2
+ puts stderr "Cannot ris test within anif {[llength $args] % 2} {
3
+ set revertArgs [lindex $args 0]
4
+ set args [lrange $args 1 end]
5
+ } else {
6
+ set revertArgs {}
7
+ }VERTED: f3
8
+ DELETE:j@Uy,1X@Se,4:: f0G@YW,21@UT,3:ED:1w@WW,3:ED:3t@YT,G:ED: f3
9
+ DELETE:K@hF,O@YG:ED: f3
10
+ DELETE:K@hF,O@Yl,1
11
+ DELETE:a@nd,1WvoIq;-testnormalize-status-list]
12
+ set r]
13
+ if {$result ne $expected} {
14
+ set passed 0
15
+ protOut " Expected:\n [join $expected "\n "]"
16
+ protOut " Got:\n [joh {exec $::fossilexe info} res
17
+if {![regexp {use --repository} $res]} {
18
+ puts stderr "Cannot run this test within an open checkout"
19
+ return
20
+}
21
+repo_init# Copytcatch {exec $::fossilexe info} res
22
+if {![regexp {use --repository} $res]} {
23
+ puts stderr "Cannot run this test witt# Copytcatch {exec $::fossilexe info} res
24
+if {![regexp {use --repository} $res]} {
25
+ put12 f03 f1 {exec $::fossilexe info}t# Copytcatch {exec $::foss4 f2 {exec $::ft# Copytcatch {exec $::foss5 f3 {exec $::fossilexe info} res
26
+if {![re
--- a/test/revert.test
+++ b/test/revert.test
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/revert.test
+++ b/test/revert.test
@@ -0,0 +1,26 @@
1 puts res=$# Fossil will write dexec rm f1po_init# Copytcatch {exec $::exec mvitory} $res]} {
2 puts stderr "Cannot ris test within anif {[llength $args] % 2} {
3 set revertArgs [lindex $args 0]
4 set args [lrange $args 1 end]
5 } else {
6 set revertArgs {}
7 }VERTED: f3
8 DELETE:j@Uy,1X@Se,4:: f0G@YW,21@UT,3:ED:1w@WW,3:ED:3t@YT,G:ED: f3
9 DELETE:K@hF,O@YG:ED: f3
10 DELETE:K@hF,O@Yl,1
11 DELETE:a@nd,1WvoIq;-testnormalize-status-list]
12 set r]
13 if {$result ne $expected} {
14 set passed 0
15 protOut " Expected:\n [join $expected "\n "]"
16 protOut " Got:\n [joh {exec $::fossilexe info} res
17 if {![regexp {use --repository} $res]} {
18 puts stderr "Cannot run this test within an open checkout"
19 return
20 }
21 repo_init# Copytcatch {exec $::fossilexe info} res
22 if {![regexp {use --repository} $res]} {
23 puts stderr "Cannot run this test witt# Copytcatch {exec $::fossilexe info} res
24 if {![regexp {use --repository} $res]} {
25 put12 f03 f1 {exec $::fossilexe info}t# Copytcatch {exec $::foss4 f2 {exec $::ft# Copytcatch {exec $::foss5 f3 {exec $::fossilexe info} res
26 if {![re
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -6,15 +6,15 @@
66
#
77
# This file is automatically generated. Instead of editing this
88
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
99
# to regenerate this file.
1010
#
11
-# This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12
-# MinGW-w64.
11
+# This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12
+# MinGW or MinGW-w64.
1313
#
1414
15
-#### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
15
+#### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
1616
# By default, this is an empty string (i.e. use the native compiler).
1717
#
1818
PREFIX =
1919
# PREFIX = mingw32-
2020
# PREFIX = i686-pc-mingw32-
@@ -657,11 +657,11 @@
657657
ifdef FOSSIL_ENABLE_TCL
658658
EXTRAOBJ += $(OBJDIR)/th_tcl.o
659659
endif
660660
661661
zlib:
662
- make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
662
+ $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663663
664664
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665665
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666666
667667
# This rule prevents make from using its default rules to try build
@@ -1633,11 +1633,11 @@
16331633
16341634
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
16351635
$(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
16361636
16371637
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1638
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16391639
16401640
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16411641
16421642
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
16431643
$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
16441644
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12 # MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -657,11 +657,11 @@
657 ifdef FOSSIL_ENABLE_TCL
658 EXTRAOBJ += $(OBJDIR)/th_tcl.o
659 endif
660
661 zlib:
662 make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663
664 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666
667 # This rule prevents make from using its default rules to try build
@@ -1633,11 +1633,11 @@
1633
1634 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1635 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12 # MinGW or MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -657,11 +657,11 @@
657 ifdef FOSSIL_ENABLE_TCL
658 EXTRAOBJ += $(OBJDIR)/th_tcl.o
659 endif
660
661 zlib:
662 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663
664 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666
667 # This rule prevents make from using its default rules to try build
@@ -1633,11 +1633,11 @@
1633
1634 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1635 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -6,15 +6,15 @@
66
#
77
# This file is automatically generated. Instead of editing this
88
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
99
# to regenerate this file.
1010
#
11
-# This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12
-# MinGW-w64.
11
+# This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12
+# MinGW or MinGW-w64.
1313
#
1414
15
-#### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
15
+#### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
1616
# By default, this is an empty string (i.e. use the native compiler).
1717
#
1818
PREFIX =
1919
# PREFIX = mingw32-
2020
# PREFIX = i686-pc-mingw32-
@@ -657,11 +657,11 @@
657657
ifdef FOSSIL_ENABLE_TCL
658658
EXTRAOBJ += $(OBJDIR)/th_tcl.o
659659
endif
660660
661661
zlib:
662
- make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
662
+ $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663663
664664
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665665
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666666
667667
# This rule prevents make from using its default rules to try build
@@ -1633,11 +1633,11 @@
16331633
16341634
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
16351635
$(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
16361636
16371637
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1638
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16391639
16401640
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16411641
16421642
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
16431643
$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
16441644
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12 # MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -657,11 +657,11 @@
657 ifdef FOSSIL_ENABLE_TCL
658 EXTRAOBJ += $(OBJDIR)/th_tcl.o
659 endif
660
661 zlib:
662 make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663
664 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666
667 # This rule prevents make from using its default rules to try build
@@ -1633,11 +1633,11 @@
1633
1634 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1635 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12 # MinGW or MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -657,11 +657,11 @@
657 ifdef FOSSIL_ENABLE_TCL
658 EXTRAOBJ += $(OBJDIR)/th_tcl.o
659 endif
660
661 zlib:
662 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663
664 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666
667 # This rule prevents make from using its default rules to try build
@@ -1633,11 +1633,11 @@
1633
1634 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1635 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -6,15 +6,15 @@
66
#
77
# This file is automatically generated. Instead of editing this
88
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
99
# to regenerate this file.
1010
#
11
-# This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12
-# MinGW-w64.
11
+# This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12
+# MinGW or MinGW-w64.
1313
#
1414
15
-#### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
15
+#### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
1616
# By default, this is an empty string (i.e. use the native compiler).
1717
#
1818
PREFIX =
1919
# PREFIX = mingw32-
2020
# PREFIX = i686-pc-mingw32-
@@ -322,10 +322,11 @@
322322
$(SRCDIR)/pivot.c \
323323
$(SRCDIR)/popen.c \
324324
$(SRCDIR)/pqueue.c \
325325
$(SRCDIR)/printf.c \
326326
$(SRCDIR)/rebuild.c \
327
+ $(SRCDIR)/regexp.c \
327328
$(SRCDIR)/report.c \
328329
$(SRCDIR)/rss.c \
329330
$(SRCDIR)/schema.c \
330331
$(SRCDIR)/search.c \
331332
$(SRCDIR)/setup.c \
@@ -342,10 +343,11 @@
342343
$(SRCDIR)/th_main.c \
343344
$(SRCDIR)/timeline.c \
344345
$(SRCDIR)/tkt.c \
345346
$(SRCDIR)/tktsetup.c \
346347
$(SRCDIR)/undo.c \
348
+ $(SRCDIR)/unicode.c \
347349
$(SRCDIR)/update.c \
348350
$(SRCDIR)/url.c \
349351
$(SRCDIR)/user.c \
350352
$(SRCDIR)/utf8.c \
351353
$(SRCDIR)/verify.c \
@@ -426,10 +428,11 @@
426428
$(OBJDIR)/pivot_.c \
427429
$(OBJDIR)/popen_.c \
428430
$(OBJDIR)/pqueue_.c \
429431
$(OBJDIR)/printf_.c \
430432
$(OBJDIR)/rebuild_.c \
433
+ $(OBJDIR)/regexp_.c \
431434
$(OBJDIR)/report_.c \
432435
$(OBJDIR)/rss_.c \
433436
$(OBJDIR)/schema_.c \
434437
$(OBJDIR)/search_.c \
435438
$(OBJDIR)/setup_.c \
@@ -446,10 +449,11 @@
446449
$(OBJDIR)/th_main_.c \
447450
$(OBJDIR)/timeline_.c \
448451
$(OBJDIR)/tkt_.c \
449452
$(OBJDIR)/tktsetup_.c \
450453
$(OBJDIR)/undo_.c \
454
+ $(OBJDIR)/unicode_.c \
451455
$(OBJDIR)/update_.c \
452456
$(OBJDIR)/url_.c \
453457
$(OBJDIR)/user_.c \
454458
$(OBJDIR)/utf8_.c \
455459
$(OBJDIR)/verify_.c \
@@ -530,10 +534,11 @@
530534
$(OBJDIR)/pivot.o \
531535
$(OBJDIR)/popen.o \
532536
$(OBJDIR)/pqueue.o \
533537
$(OBJDIR)/printf.o \
534538
$(OBJDIR)/rebuild.o \
539
+ $(OBJDIR)/regexp.o \
535540
$(OBJDIR)/report.o \
536541
$(OBJDIR)/rss.o \
537542
$(OBJDIR)/schema.o \
538543
$(OBJDIR)/search.o \
539544
$(OBJDIR)/setup.o \
@@ -550,10 +555,11 @@
550555
$(OBJDIR)/th_main.o \
551556
$(OBJDIR)/timeline.o \
552557
$(OBJDIR)/tkt.o \
553558
$(OBJDIR)/tktsetup.o \
554559
$(OBJDIR)/undo.o \
560
+ $(OBJDIR)/unicode.o \
555561
$(OBJDIR)/update.o \
556562
$(OBJDIR)/url.o \
557563
$(OBJDIR)/user.o \
558564
$(OBJDIR)/utf8.o \
559565
$(OBJDIR)/verify.o \
@@ -651,11 +657,11 @@
651657
ifdef FOSSIL_ENABLE_TCL
652658
EXTRAOBJ += $(OBJDIR)/th_tcl.o
653659
endif
654660
655661
zlib:
656
- make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
662
+ $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
657663
658664
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
659665
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
660666
661667
# This rule prevents make from using its default rules to try build
@@ -747,10 +753,11 @@
747753
$(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
748754
$(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
749755
$(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
750756
$(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
751757
$(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \
758
+ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \
752759
$(OBJDIR)/report_.c:$(OBJDIR)/report.h \
753760
$(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \
754761
$(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \
755762
$(OBJDIR)/search_.c:$(OBJDIR)/search.h \
756763
$(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \
@@ -767,10 +774,11 @@
767774
$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
768775
$(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
769776
$(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
770777
$(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
771778
$(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
779
+ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
772780
$(OBJDIR)/update_.c:$(OBJDIR)/update.h \
773781
$(OBJDIR)/url_.c:$(OBJDIR)/url.h \
774782
$(OBJDIR)/user_.c:$(OBJDIR)/user.h \
775783
$(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
776784
$(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
@@ -1340,10 +1348,18 @@
13401348
13411349
$(OBJDIR)/rebuild.o: $(OBJDIR)/rebuild_.c $(OBJDIR)/rebuild.h $(SRCDIR)/config.h
13421350
$(XTCC) -o $(OBJDIR)/rebuild.o -c $(OBJDIR)/rebuild_.c
13431351
13441352
$(OBJDIR)/rebuild.h: $(OBJDIR)/headers
1353
+
1354
+$(OBJDIR)/regexp_.c: $(SRCDIR)/regexp.c $(OBJDIR)/translate
1355
+ $(TRANSLATE) $(SRCDIR)/regexp.c >$(OBJDIR)/regexp_.c
1356
+
1357
+$(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h
1358
+ $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c
1359
+
1360
+$(OBJDIR)/regexp.h: $(OBJDIR)/headers
13451361
13461362
$(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate
13471363
$(TRANSLATE) $(SRCDIR)/report.c >$(OBJDIR)/report_.c
13481364
13491365
$(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h
@@ -1500,10 +1516,18 @@
15001516
15011517
$(OBJDIR)/undo.o: $(OBJDIR)/undo_.c $(OBJDIR)/undo.h $(SRCDIR)/config.h
15021518
$(XTCC) -o $(OBJDIR)/undo.o -c $(OBJDIR)/undo_.c
15031519
15041520
$(OBJDIR)/undo.h: $(OBJDIR)/headers
1521
+
1522
+$(OBJDIR)/unicode_.c: $(SRCDIR)/unicode.c $(OBJDIR)/translate
1523
+ $(TRANSLATE) $(SRCDIR)/unicode.c >$(OBJDIR)/unicode_.c
1524
+
1525
+$(OBJDIR)/unicode.o: $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h $(SRCDIR)/config.h
1526
+ $(XTCC) -o $(OBJDIR)/unicode.o -c $(OBJDIR)/unicode_.c
1527
+
1528
+$(OBJDIR)/unicode.h: $(OBJDIR)/headers
15051529
15061530
$(OBJDIR)/update_.c: $(SRCDIR)/update.c $(OBJDIR)/translate
15071531
$(TRANSLATE) $(SRCDIR)/update.c >$(OBJDIR)/update_.c
15081532
15091533
$(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h
@@ -1609,11 +1633,11 @@
16091633
16101634
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
16111635
$(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
16121636
16131637
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1614
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1638
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16151639
16161640
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16171641
16181642
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
16191643
$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
16201644
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12 # MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -322,10 +322,11 @@
322 $(SRCDIR)/pivot.c \
323 $(SRCDIR)/popen.c \
324 $(SRCDIR)/pqueue.c \
325 $(SRCDIR)/printf.c \
326 $(SRCDIR)/rebuild.c \
 
327 $(SRCDIR)/report.c \
328 $(SRCDIR)/rss.c \
329 $(SRCDIR)/schema.c \
330 $(SRCDIR)/search.c \
331 $(SRCDIR)/setup.c \
@@ -342,10 +343,11 @@
342 $(SRCDIR)/th_main.c \
343 $(SRCDIR)/timeline.c \
344 $(SRCDIR)/tkt.c \
345 $(SRCDIR)/tktsetup.c \
346 $(SRCDIR)/undo.c \
 
347 $(SRCDIR)/update.c \
348 $(SRCDIR)/url.c \
349 $(SRCDIR)/user.c \
350 $(SRCDIR)/utf8.c \
351 $(SRCDIR)/verify.c \
@@ -426,10 +428,11 @@
426 $(OBJDIR)/pivot_.c \
427 $(OBJDIR)/popen_.c \
428 $(OBJDIR)/pqueue_.c \
429 $(OBJDIR)/printf_.c \
430 $(OBJDIR)/rebuild_.c \
 
431 $(OBJDIR)/report_.c \
432 $(OBJDIR)/rss_.c \
433 $(OBJDIR)/schema_.c \
434 $(OBJDIR)/search_.c \
435 $(OBJDIR)/setup_.c \
@@ -446,10 +449,11 @@
446 $(OBJDIR)/th_main_.c \
447 $(OBJDIR)/timeline_.c \
448 $(OBJDIR)/tkt_.c \
449 $(OBJDIR)/tktsetup_.c \
450 $(OBJDIR)/undo_.c \
 
451 $(OBJDIR)/update_.c \
452 $(OBJDIR)/url_.c \
453 $(OBJDIR)/user_.c \
454 $(OBJDIR)/utf8_.c \
455 $(OBJDIR)/verify_.c \
@@ -530,10 +534,11 @@
530 $(OBJDIR)/pivot.o \
531 $(OBJDIR)/popen.o \
532 $(OBJDIR)/pqueue.o \
533 $(OBJDIR)/printf.o \
534 $(OBJDIR)/rebuild.o \
 
535 $(OBJDIR)/report.o \
536 $(OBJDIR)/rss.o \
537 $(OBJDIR)/schema.o \
538 $(OBJDIR)/search.o \
539 $(OBJDIR)/setup.o \
@@ -550,10 +555,11 @@
550 $(OBJDIR)/th_main.o \
551 $(OBJDIR)/timeline.o \
552 $(OBJDIR)/tkt.o \
553 $(OBJDIR)/tktsetup.o \
554 $(OBJDIR)/undo.o \
 
555 $(OBJDIR)/update.o \
556 $(OBJDIR)/url.o \
557 $(OBJDIR)/user.o \
558 $(OBJDIR)/utf8.o \
559 $(OBJDIR)/verify.o \
@@ -651,11 +657,11 @@
651 ifdef FOSSIL_ENABLE_TCL
652 EXTRAOBJ += $(OBJDIR)/th_tcl.o
653 endif
654
655 zlib:
656 make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
657
658 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
659 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
660
661 # This rule prevents make from using its default rules to try build
@@ -747,10 +753,11 @@
747 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
748 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
749 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
750 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
751 $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \
 
752 $(OBJDIR)/report_.c:$(OBJDIR)/report.h \
753 $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \
754 $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \
755 $(OBJDIR)/search_.c:$(OBJDIR)/search.h \
756 $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \
@@ -767,10 +774,11 @@
767 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
768 $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
769 $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
770 $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
771 $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
 
772 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
773 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
774 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
775 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
776 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
@@ -1340,10 +1348,18 @@
1340
1341 $(OBJDIR)/rebuild.o: $(OBJDIR)/rebuild_.c $(OBJDIR)/rebuild.h $(SRCDIR)/config.h
1342 $(XTCC) -o $(OBJDIR)/rebuild.o -c $(OBJDIR)/rebuild_.c
1343
1344 $(OBJDIR)/rebuild.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1345
1346 $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate
1347 $(TRANSLATE) $(SRCDIR)/report.c >$(OBJDIR)/report_.c
1348
1349 $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h
@@ -1500,10 +1516,18 @@
1500
1501 $(OBJDIR)/undo.o: $(OBJDIR)/undo_.c $(OBJDIR)/undo.h $(SRCDIR)/config.h
1502 $(XTCC) -o $(OBJDIR)/undo.o -c $(OBJDIR)/undo_.c
1503
1504 $(OBJDIR)/undo.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1505
1506 $(OBJDIR)/update_.c: $(SRCDIR)/update.c $(OBJDIR)/translate
1507 $(TRANSLATE) $(SRCDIR)/update.c >$(OBJDIR)/update_.c
1508
1509 $(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h
@@ -1609,11 +1633,11 @@
1609
1610 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1611 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1612
1613 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1614 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1615
1616 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1617
1618 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1619 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1620
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12 # MinGW or MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -322,10 +322,11 @@
322 $(SRCDIR)/pivot.c \
323 $(SRCDIR)/popen.c \
324 $(SRCDIR)/pqueue.c \
325 $(SRCDIR)/printf.c \
326 $(SRCDIR)/rebuild.c \
327 $(SRCDIR)/regexp.c \
328 $(SRCDIR)/report.c \
329 $(SRCDIR)/rss.c \
330 $(SRCDIR)/schema.c \
331 $(SRCDIR)/search.c \
332 $(SRCDIR)/setup.c \
@@ -342,10 +343,11 @@
343 $(SRCDIR)/th_main.c \
344 $(SRCDIR)/timeline.c \
345 $(SRCDIR)/tkt.c \
346 $(SRCDIR)/tktsetup.c \
347 $(SRCDIR)/undo.c \
348 $(SRCDIR)/unicode.c \
349 $(SRCDIR)/update.c \
350 $(SRCDIR)/url.c \
351 $(SRCDIR)/user.c \
352 $(SRCDIR)/utf8.c \
353 $(SRCDIR)/verify.c \
@@ -426,10 +428,11 @@
428 $(OBJDIR)/pivot_.c \
429 $(OBJDIR)/popen_.c \
430 $(OBJDIR)/pqueue_.c \
431 $(OBJDIR)/printf_.c \
432 $(OBJDIR)/rebuild_.c \
433 $(OBJDIR)/regexp_.c \
434 $(OBJDIR)/report_.c \
435 $(OBJDIR)/rss_.c \
436 $(OBJDIR)/schema_.c \
437 $(OBJDIR)/search_.c \
438 $(OBJDIR)/setup_.c \
@@ -446,10 +449,11 @@
449 $(OBJDIR)/th_main_.c \
450 $(OBJDIR)/timeline_.c \
451 $(OBJDIR)/tkt_.c \
452 $(OBJDIR)/tktsetup_.c \
453 $(OBJDIR)/undo_.c \
454 $(OBJDIR)/unicode_.c \
455 $(OBJDIR)/update_.c \
456 $(OBJDIR)/url_.c \
457 $(OBJDIR)/user_.c \
458 $(OBJDIR)/utf8_.c \
459 $(OBJDIR)/verify_.c \
@@ -530,10 +534,11 @@
534 $(OBJDIR)/pivot.o \
535 $(OBJDIR)/popen.o \
536 $(OBJDIR)/pqueue.o \
537 $(OBJDIR)/printf.o \
538 $(OBJDIR)/rebuild.o \
539 $(OBJDIR)/regexp.o \
540 $(OBJDIR)/report.o \
541 $(OBJDIR)/rss.o \
542 $(OBJDIR)/schema.o \
543 $(OBJDIR)/search.o \
544 $(OBJDIR)/setup.o \
@@ -550,10 +555,11 @@
555 $(OBJDIR)/th_main.o \
556 $(OBJDIR)/timeline.o \
557 $(OBJDIR)/tkt.o \
558 $(OBJDIR)/tktsetup.o \
559 $(OBJDIR)/undo.o \
560 $(OBJDIR)/unicode.o \
561 $(OBJDIR)/update.o \
562 $(OBJDIR)/url.o \
563 $(OBJDIR)/user.o \
564 $(OBJDIR)/utf8.o \
565 $(OBJDIR)/verify.o \
@@ -651,11 +657,11 @@
657 ifdef FOSSIL_ENABLE_TCL
658 EXTRAOBJ += $(OBJDIR)/th_tcl.o
659 endif
660
661 zlib:
662 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663
664 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666
667 # This rule prevents make from using its default rules to try build
@@ -747,10 +753,11 @@
753 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
754 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
755 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
756 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
757 $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \
758 $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \
759 $(OBJDIR)/report_.c:$(OBJDIR)/report.h \
760 $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \
761 $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \
762 $(OBJDIR)/search_.c:$(OBJDIR)/search.h \
763 $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \
@@ -767,10 +774,11 @@
774 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
775 $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
776 $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
777 $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
778 $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
779 $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
780 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
781 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
782 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
783 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
784 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
@@ -1340,10 +1348,18 @@
1348
1349 $(OBJDIR)/rebuild.o: $(OBJDIR)/rebuild_.c $(OBJDIR)/rebuild.h $(SRCDIR)/config.h
1350 $(XTCC) -o $(OBJDIR)/rebuild.o -c $(OBJDIR)/rebuild_.c
1351
1352 $(OBJDIR)/rebuild.h: $(OBJDIR)/headers
1353
1354 $(OBJDIR)/regexp_.c: $(SRCDIR)/regexp.c $(OBJDIR)/translate
1355 $(TRANSLATE) $(SRCDIR)/regexp.c >$(OBJDIR)/regexp_.c
1356
1357 $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h
1358 $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c
1359
1360 $(OBJDIR)/regexp.h: $(OBJDIR)/headers
1361
1362 $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate
1363 $(TRANSLATE) $(SRCDIR)/report.c >$(OBJDIR)/report_.c
1364
1365 $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h
@@ -1500,10 +1516,18 @@
1516
1517 $(OBJDIR)/undo.o: $(OBJDIR)/undo_.c $(OBJDIR)/undo.h $(SRCDIR)/config.h
1518 $(XTCC) -o $(OBJDIR)/undo.o -c $(OBJDIR)/undo_.c
1519
1520 $(OBJDIR)/undo.h: $(OBJDIR)/headers
1521
1522 $(OBJDIR)/unicode_.c: $(SRCDIR)/unicode.c $(OBJDIR)/translate
1523 $(TRANSLATE) $(SRCDIR)/unicode.c >$(OBJDIR)/unicode_.c
1524
1525 $(OBJDIR)/unicode.o: $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h $(SRCDIR)/config.h
1526 $(XTCC) -o $(OBJDIR)/unicode.o -c $(OBJDIR)/unicode_.c
1527
1528 $(OBJDIR)/unicode.h: $(OBJDIR)/headers
1529
1530 $(OBJDIR)/update_.c: $(SRCDIR)/update.c $(OBJDIR)/translate
1531 $(TRANSLATE) $(SRCDIR)/update.c >$(OBJDIR)/update_.c
1532
1533 $(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h
@@ -1609,11 +1633,11 @@
1633
1634 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1635 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -6,15 +6,15 @@
66
#
77
# This file is automatically generated. Instead of editing this
88
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
99
# to regenerate this file.
1010
#
11
-# This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12
-# MinGW-w64.
11
+# This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12
+# MinGW or MinGW-w64.
1313
#
1414
15
-#### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
15
+#### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
1616
# By default, this is an empty string (i.e. use the native compiler).
1717
#
1818
PREFIX =
1919
# PREFIX = mingw32-
2020
# PREFIX = i686-pc-mingw32-
@@ -322,10 +322,11 @@
322322
$(SRCDIR)/pivot.c \
323323
$(SRCDIR)/popen.c \
324324
$(SRCDIR)/pqueue.c \
325325
$(SRCDIR)/printf.c \
326326
$(SRCDIR)/rebuild.c \
327
+ $(SRCDIR)/regexp.c \
327328
$(SRCDIR)/report.c \
328329
$(SRCDIR)/rss.c \
329330
$(SRCDIR)/schema.c \
330331
$(SRCDIR)/search.c \
331332
$(SRCDIR)/setup.c \
@@ -342,10 +343,11 @@
342343
$(SRCDIR)/th_main.c \
343344
$(SRCDIR)/timeline.c \
344345
$(SRCDIR)/tkt.c \
345346
$(SRCDIR)/tktsetup.c \
346347
$(SRCDIR)/undo.c \
348
+ $(SRCDIR)/unicode.c \
347349
$(SRCDIR)/update.c \
348350
$(SRCDIR)/url.c \
349351
$(SRCDIR)/user.c \
350352
$(SRCDIR)/utf8.c \
351353
$(SRCDIR)/verify.c \
@@ -426,10 +428,11 @@
426428
$(OBJDIR)/pivot_.c \
427429
$(OBJDIR)/popen_.c \
428430
$(OBJDIR)/pqueue_.c \
429431
$(OBJDIR)/printf_.c \
430432
$(OBJDIR)/rebuild_.c \
433
+ $(OBJDIR)/regexp_.c \
431434
$(OBJDIR)/report_.c \
432435
$(OBJDIR)/rss_.c \
433436
$(OBJDIR)/schema_.c \
434437
$(OBJDIR)/search_.c \
435438
$(OBJDIR)/setup_.c \
@@ -446,10 +449,11 @@
446449
$(OBJDIR)/th_main_.c \
447450
$(OBJDIR)/timeline_.c \
448451
$(OBJDIR)/tkt_.c \
449452
$(OBJDIR)/tktsetup_.c \
450453
$(OBJDIR)/undo_.c \
454
+ $(OBJDIR)/unicode_.c \
451455
$(OBJDIR)/update_.c \
452456
$(OBJDIR)/url_.c \
453457
$(OBJDIR)/user_.c \
454458
$(OBJDIR)/utf8_.c \
455459
$(OBJDIR)/verify_.c \
@@ -530,10 +534,11 @@
530534
$(OBJDIR)/pivot.o \
531535
$(OBJDIR)/popen.o \
532536
$(OBJDIR)/pqueue.o \
533537
$(OBJDIR)/printf.o \
534538
$(OBJDIR)/rebuild.o \
539
+ $(OBJDIR)/regexp.o \
535540
$(OBJDIR)/report.o \
536541
$(OBJDIR)/rss.o \
537542
$(OBJDIR)/schema.o \
538543
$(OBJDIR)/search.o \
539544
$(OBJDIR)/setup.o \
@@ -550,10 +555,11 @@
550555
$(OBJDIR)/th_main.o \
551556
$(OBJDIR)/timeline.o \
552557
$(OBJDIR)/tkt.o \
553558
$(OBJDIR)/tktsetup.o \
554559
$(OBJDIR)/undo.o \
560
+ $(OBJDIR)/unicode.o \
555561
$(OBJDIR)/update.o \
556562
$(OBJDIR)/url.o \
557563
$(OBJDIR)/user.o \
558564
$(OBJDIR)/utf8.o \
559565
$(OBJDIR)/verify.o \
@@ -651,11 +657,11 @@
651657
ifdef FOSSIL_ENABLE_TCL
652658
EXTRAOBJ += $(OBJDIR)/th_tcl.o
653659
endif
654660
655661
zlib:
656
- make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
662
+ $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
657663
658664
$(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
659665
$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
660666
661667
# This rule prevents make from using its default rules to try build
@@ -747,10 +753,11 @@
747753
$(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
748754
$(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
749755
$(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
750756
$(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
751757
$(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \
758
+ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \
752759
$(OBJDIR)/report_.c:$(OBJDIR)/report.h \
753760
$(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \
754761
$(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \
755762
$(OBJDIR)/search_.c:$(OBJDIR)/search.h \
756763
$(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \
@@ -767,10 +774,11 @@
767774
$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
768775
$(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
769776
$(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
770777
$(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
771778
$(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
779
+ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
772780
$(OBJDIR)/update_.c:$(OBJDIR)/update.h \
773781
$(OBJDIR)/url_.c:$(OBJDIR)/url.h \
774782
$(OBJDIR)/user_.c:$(OBJDIR)/user.h \
775783
$(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
776784
$(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
@@ -1340,10 +1348,18 @@
13401348
13411349
$(OBJDIR)/rebuild.o: $(OBJDIR)/rebuild_.c $(OBJDIR)/rebuild.h $(SRCDIR)/config.h
13421350
$(XTCC) -o $(OBJDIR)/rebuild.o -c $(OBJDIR)/rebuild_.c
13431351
13441352
$(OBJDIR)/rebuild.h: $(OBJDIR)/headers
1353
+
1354
+$(OBJDIR)/regexp_.c: $(SRCDIR)/regexp.c $(OBJDIR)/translate
1355
+ $(TRANSLATE) $(SRCDIR)/regexp.c >$(OBJDIR)/regexp_.c
1356
+
1357
+$(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h
1358
+ $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c
1359
+
1360
+$(OBJDIR)/regexp.h: $(OBJDIR)/headers
13451361
13461362
$(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate
13471363
$(TRANSLATE) $(SRCDIR)/report.c >$(OBJDIR)/report_.c
13481364
13491365
$(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h
@@ -1500,10 +1516,18 @@
15001516
15011517
$(OBJDIR)/undo.o: $(OBJDIR)/undo_.c $(OBJDIR)/undo.h $(SRCDIR)/config.h
15021518
$(XTCC) -o $(OBJDIR)/undo.o -c $(OBJDIR)/undo_.c
15031519
15041520
$(OBJDIR)/undo.h: $(OBJDIR)/headers
1521
+
1522
+$(OBJDIR)/unicode_.c: $(SRCDIR)/unicode.c $(OBJDIR)/translate
1523
+ $(TRANSLATE) $(SRCDIR)/unicode.c >$(OBJDIR)/unicode_.c
1524
+
1525
+$(OBJDIR)/unicode.o: $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h $(SRCDIR)/config.h
1526
+ $(XTCC) -o $(OBJDIR)/unicode.o -c $(OBJDIR)/unicode_.c
1527
+
1528
+$(OBJDIR)/unicode.h: $(OBJDIR)/headers
15051529
15061530
$(OBJDIR)/update_.c: $(SRCDIR)/update.c $(OBJDIR)/translate
15071531
$(TRANSLATE) $(SRCDIR)/update.c >$(OBJDIR)/update_.c
15081532
15091533
$(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h
@@ -1609,11 +1633,11 @@
16091633
16101634
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
16111635
$(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
16121636
16131637
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1614
- $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1638
+ $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16151639
16161640
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16171641
16181642
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
16191643
$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
16201644
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Windows/Linux/Darwin/Cygwin using MinGW or
12 # MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -322,10 +322,11 @@
322 $(SRCDIR)/pivot.c \
323 $(SRCDIR)/popen.c \
324 $(SRCDIR)/pqueue.c \
325 $(SRCDIR)/printf.c \
326 $(SRCDIR)/rebuild.c \
 
327 $(SRCDIR)/report.c \
328 $(SRCDIR)/rss.c \
329 $(SRCDIR)/schema.c \
330 $(SRCDIR)/search.c \
331 $(SRCDIR)/setup.c \
@@ -342,10 +343,11 @@
342 $(SRCDIR)/th_main.c \
343 $(SRCDIR)/timeline.c \
344 $(SRCDIR)/tkt.c \
345 $(SRCDIR)/tktsetup.c \
346 $(SRCDIR)/undo.c \
 
347 $(SRCDIR)/update.c \
348 $(SRCDIR)/url.c \
349 $(SRCDIR)/user.c \
350 $(SRCDIR)/utf8.c \
351 $(SRCDIR)/verify.c \
@@ -426,10 +428,11 @@
426 $(OBJDIR)/pivot_.c \
427 $(OBJDIR)/popen_.c \
428 $(OBJDIR)/pqueue_.c \
429 $(OBJDIR)/printf_.c \
430 $(OBJDIR)/rebuild_.c \
 
431 $(OBJDIR)/report_.c \
432 $(OBJDIR)/rss_.c \
433 $(OBJDIR)/schema_.c \
434 $(OBJDIR)/search_.c \
435 $(OBJDIR)/setup_.c \
@@ -446,10 +449,11 @@
446 $(OBJDIR)/th_main_.c \
447 $(OBJDIR)/timeline_.c \
448 $(OBJDIR)/tkt_.c \
449 $(OBJDIR)/tktsetup_.c \
450 $(OBJDIR)/undo_.c \
 
451 $(OBJDIR)/update_.c \
452 $(OBJDIR)/url_.c \
453 $(OBJDIR)/user_.c \
454 $(OBJDIR)/utf8_.c \
455 $(OBJDIR)/verify_.c \
@@ -530,10 +534,11 @@
530 $(OBJDIR)/pivot.o \
531 $(OBJDIR)/popen.o \
532 $(OBJDIR)/pqueue.o \
533 $(OBJDIR)/printf.o \
534 $(OBJDIR)/rebuild.o \
 
535 $(OBJDIR)/report.o \
536 $(OBJDIR)/rss.o \
537 $(OBJDIR)/schema.o \
538 $(OBJDIR)/search.o \
539 $(OBJDIR)/setup.o \
@@ -550,10 +555,11 @@
550 $(OBJDIR)/th_main.o \
551 $(OBJDIR)/timeline.o \
552 $(OBJDIR)/tkt.o \
553 $(OBJDIR)/tktsetup.o \
554 $(OBJDIR)/undo.o \
 
555 $(OBJDIR)/update.o \
556 $(OBJDIR)/url.o \
557 $(OBJDIR)/user.o \
558 $(OBJDIR)/utf8.o \
559 $(OBJDIR)/verify.o \
@@ -651,11 +657,11 @@
651 ifdef FOSSIL_ENABLE_TCL
652 EXTRAOBJ += $(OBJDIR)/th_tcl.o
653 endif
654
655 zlib:
656 make -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
657
658 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
659 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
660
661 # This rule prevents make from using its default rules to try build
@@ -747,10 +753,11 @@
747 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
748 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
749 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
750 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
751 $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \
 
752 $(OBJDIR)/report_.c:$(OBJDIR)/report.h \
753 $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \
754 $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \
755 $(OBJDIR)/search_.c:$(OBJDIR)/search.h \
756 $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \
@@ -767,10 +774,11 @@
767 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
768 $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
769 $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
770 $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
771 $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
 
772 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
773 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
774 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
775 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
776 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
@@ -1340,10 +1348,18 @@
1340
1341 $(OBJDIR)/rebuild.o: $(OBJDIR)/rebuild_.c $(OBJDIR)/rebuild.h $(SRCDIR)/config.h
1342 $(XTCC) -o $(OBJDIR)/rebuild.o -c $(OBJDIR)/rebuild_.c
1343
1344 $(OBJDIR)/rebuild.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1345
1346 $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate
1347 $(TRANSLATE) $(SRCDIR)/report.c >$(OBJDIR)/report_.c
1348
1349 $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h
@@ -1500,10 +1516,18 @@
1500
1501 $(OBJDIR)/undo.o: $(OBJDIR)/undo_.c $(OBJDIR)/undo.h $(SRCDIR)/config.h
1502 $(XTCC) -o $(OBJDIR)/undo.o -c $(OBJDIR)/undo_.c
1503
1504 $(OBJDIR)/undo.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1505
1506 $(OBJDIR)/update_.c: $(SRCDIR)/update.c $(OBJDIR)/translate
1507 $(TRANSLATE) $(SRCDIR)/update.c >$(OBJDIR)/update_.c
1508
1509 $(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h
@@ -1609,11 +1633,11 @@
1609
1610 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1611 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1612
1613 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1614 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
1615
1616 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1617
1618 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1619 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1620
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -6,15 +6,15 @@
6 #
7 # This file is automatically generated. Instead of editing this
8 # file, edit "makemake.tcl" then run "tclsh makemake.tcl"
9 # to regenerate this file.
10 #
11 # This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
12 # MinGW or MinGW-w64.
13 #
14
15 #### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
16 # By default, this is an empty string (i.e. use the native compiler).
17 #
18 PREFIX =
19 # PREFIX = mingw32-
20 # PREFIX = i686-pc-mingw32-
@@ -322,10 +322,11 @@
322 $(SRCDIR)/pivot.c \
323 $(SRCDIR)/popen.c \
324 $(SRCDIR)/pqueue.c \
325 $(SRCDIR)/printf.c \
326 $(SRCDIR)/rebuild.c \
327 $(SRCDIR)/regexp.c \
328 $(SRCDIR)/report.c \
329 $(SRCDIR)/rss.c \
330 $(SRCDIR)/schema.c \
331 $(SRCDIR)/search.c \
332 $(SRCDIR)/setup.c \
@@ -342,10 +343,11 @@
343 $(SRCDIR)/th_main.c \
344 $(SRCDIR)/timeline.c \
345 $(SRCDIR)/tkt.c \
346 $(SRCDIR)/tktsetup.c \
347 $(SRCDIR)/undo.c \
348 $(SRCDIR)/unicode.c \
349 $(SRCDIR)/update.c \
350 $(SRCDIR)/url.c \
351 $(SRCDIR)/user.c \
352 $(SRCDIR)/utf8.c \
353 $(SRCDIR)/verify.c \
@@ -426,10 +428,11 @@
428 $(OBJDIR)/pivot_.c \
429 $(OBJDIR)/popen_.c \
430 $(OBJDIR)/pqueue_.c \
431 $(OBJDIR)/printf_.c \
432 $(OBJDIR)/rebuild_.c \
433 $(OBJDIR)/regexp_.c \
434 $(OBJDIR)/report_.c \
435 $(OBJDIR)/rss_.c \
436 $(OBJDIR)/schema_.c \
437 $(OBJDIR)/search_.c \
438 $(OBJDIR)/setup_.c \
@@ -446,10 +449,11 @@
449 $(OBJDIR)/th_main_.c \
450 $(OBJDIR)/timeline_.c \
451 $(OBJDIR)/tkt_.c \
452 $(OBJDIR)/tktsetup_.c \
453 $(OBJDIR)/undo_.c \
454 $(OBJDIR)/unicode_.c \
455 $(OBJDIR)/update_.c \
456 $(OBJDIR)/url_.c \
457 $(OBJDIR)/user_.c \
458 $(OBJDIR)/utf8_.c \
459 $(OBJDIR)/verify_.c \
@@ -530,10 +534,11 @@
534 $(OBJDIR)/pivot.o \
535 $(OBJDIR)/popen.o \
536 $(OBJDIR)/pqueue.o \
537 $(OBJDIR)/printf.o \
538 $(OBJDIR)/rebuild.o \
539 $(OBJDIR)/regexp.o \
540 $(OBJDIR)/report.o \
541 $(OBJDIR)/rss.o \
542 $(OBJDIR)/schema.o \
543 $(OBJDIR)/search.o \
544 $(OBJDIR)/setup.o \
@@ -550,10 +555,11 @@
555 $(OBJDIR)/th_main.o \
556 $(OBJDIR)/timeline.o \
557 $(OBJDIR)/tkt.o \
558 $(OBJDIR)/tktsetup.o \
559 $(OBJDIR)/undo.o \
560 $(OBJDIR)/unicode.o \
561 $(OBJDIR)/update.o \
562 $(OBJDIR)/url.o \
563 $(OBJDIR)/user.o \
564 $(OBJDIR)/utf8.o \
565 $(OBJDIR)/verify.o \
@@ -651,11 +657,11 @@
657 ifdef FOSSIL_ENABLE_TCL
658 EXTRAOBJ += $(OBJDIR)/th_tcl.o
659 endif
660
661 zlib:
662 $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a
663
664 $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib
665 $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o
666
667 # This rule prevents make from using its default rules to try build
@@ -747,10 +753,11 @@
753 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
754 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
755 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
756 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
757 $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \
758 $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \
759 $(OBJDIR)/report_.c:$(OBJDIR)/report.h \
760 $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \
761 $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \
762 $(OBJDIR)/search_.c:$(OBJDIR)/search.h \
763 $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \
@@ -767,10 +774,11 @@
774 $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
775 $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
776 $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
777 $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
778 $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
779 $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \
780 $(OBJDIR)/update_.c:$(OBJDIR)/update.h \
781 $(OBJDIR)/url_.c:$(OBJDIR)/url.h \
782 $(OBJDIR)/user_.c:$(OBJDIR)/user.h \
783 $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \
784 $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \
@@ -1340,10 +1348,18 @@
1348
1349 $(OBJDIR)/rebuild.o: $(OBJDIR)/rebuild_.c $(OBJDIR)/rebuild.h $(SRCDIR)/config.h
1350 $(XTCC) -o $(OBJDIR)/rebuild.o -c $(OBJDIR)/rebuild_.c
1351
1352 $(OBJDIR)/rebuild.h: $(OBJDIR)/headers
1353
1354 $(OBJDIR)/regexp_.c: $(SRCDIR)/regexp.c $(OBJDIR)/translate
1355 $(TRANSLATE) $(SRCDIR)/regexp.c >$(OBJDIR)/regexp_.c
1356
1357 $(OBJDIR)/regexp.o: $(OBJDIR)/regexp_.c $(OBJDIR)/regexp.h $(SRCDIR)/config.h
1358 $(XTCC) -o $(OBJDIR)/regexp.o -c $(OBJDIR)/regexp_.c
1359
1360 $(OBJDIR)/regexp.h: $(OBJDIR)/headers
1361
1362 $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate
1363 $(TRANSLATE) $(SRCDIR)/report.c >$(OBJDIR)/report_.c
1364
1365 $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h
@@ -1500,10 +1516,18 @@
1516
1517 $(OBJDIR)/undo.o: $(OBJDIR)/undo_.c $(OBJDIR)/undo.h $(SRCDIR)/config.h
1518 $(XTCC) -o $(OBJDIR)/undo.o -c $(OBJDIR)/undo_.c
1519
1520 $(OBJDIR)/undo.h: $(OBJDIR)/headers
1521
1522 $(OBJDIR)/unicode_.c: $(SRCDIR)/unicode.c $(OBJDIR)/translate
1523 $(TRANSLATE) $(SRCDIR)/unicode.c >$(OBJDIR)/unicode_.c
1524
1525 $(OBJDIR)/unicode.o: $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h $(SRCDIR)/config.h
1526 $(XTCC) -o $(OBJDIR)/unicode.o -c $(OBJDIR)/unicode_.c
1527
1528 $(OBJDIR)/unicode.h: $(OBJDIR)/headers
1529
1530 $(OBJDIR)/update_.c: $(SRCDIR)/update.c $(OBJDIR)/translate
1531 $(TRANSLATE) $(SRCDIR)/update.c >$(OBJDIR)/update_.c
1532
1533 $(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h
@@ -1609,11 +1633,11 @@
1633
1634 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1635 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1636
1637 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1638 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1639
1640 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1641
1642 $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
1643 $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
1644
+30 -7
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -22,18 +22,35 @@
2222
2323
# zlib options
2424
ZINCDIR = $(B)\compat\zlib
2525
ZLIBDIR = $(B)\compat\zlib
2626
ZLIB = zlib.lib
27
+
28
+# Uncomment to enable JSON API
29
+# FOSSIL_ENABLE_JSON = 1
30
+
31
+# Uncomment to enable markdown support
32
+# FOSSIL_ENABLE_MARKDOWN = 1
2733
2834
INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
2935
3036
CFLAGS = -nologo -MT -O2
3137
BCC = $(CC) $(CFLAGS)
3238
TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
39
+RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
3340
LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
3441
LIBDIR = -LIBPATH:$(ZLIBDIR)
42
+
43
+!ifdef FOSSIL_ENABLE_JSON
44
+TCC = $(TCC) -DFOSSIL_ENABLE_JSON
45
+RCC = $(RCC) -DFOSSIL_ENABLE_JSON
46
+!endif
47
+
48
+!ifdef FOSSIL_ENABLE_MARKDOWN
49
+TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
50
+RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
51
+!endif
3552
3653
SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \
3754
/DSQLITE_THREADSAFE=0 \
3855
/DSQLITE_DEFAULT_FILE_FORMAT=4 \
3956
/DSQLITE_ENABLE_STAT3 \
@@ -160,10 +177,11 @@
160177
$(OX)\clearsign$O \
161178
$(OX)\clone$O \
162179
$(OX)\comformat$O \
163180
$(OX)\configure$O \
164181
$(OX)\content$O \
182
+ $(OX)\cson_amalgamation$O \
165183
$(OX)\db$O \
166184
$(OX)\delta$O \
167185
$(OX)\deltacmd$O \
168186
$(OX)\descendants$O \
169187
$(OX)\diff$O \
@@ -219,19 +237,23 @@
219237
$(OX)\rss$O \
220238
$(OX)\schema$O \
221239
$(OX)\search$O \
222240
$(OX)\setup$O \
223241
$(OX)\sha1$O \
242
+ $(OX)\shell$O \
224243
$(OX)\shun$O \
225244
$(OX)\skins$O \
226245
$(OX)\sqlcmd$O \
246
+ $(OX)\sqlite3$O \
227247
$(OX)\stash$O \
228248
$(OX)\stat$O \
229249
$(OX)\style$O \
230250
$(OX)\sync$O \
231251
$(OX)\tag$O \
232252
$(OX)\tar$O \
253
+ $(OX)\th$O \
254
+ $(OX)\th_lang$O \
233255
$(OX)\th_main$O \
234256
$(OX)\timeline$O \
235257
$(OX)\tkt$O \
236258
$(OX)\tktsetup$O \
237259
$(OX)\undo$O \
@@ -247,14 +269,11 @@
247269
$(OX)\winhttp$O \
248270
$(OX)\wysiwyg$O \
249271
$(OX)\xfer$O \
250272
$(OX)\xfersetup$O \
251273
$(OX)\zip$O \
252
- $(OX)\shell$O \
253
- $(OX)\sqlite3$O \
254
- $(OX)\th$O \
255
- $(OX)\th_lang$O
274
+ $(OX)\fossil.res
256275
257276
APPNAME = $(OX)\fossil$(E)
258277
259278
all: $(OX) $(APPNAME)
260279
@@ -262,11 +281,11 @@
262281
@echo Building zlib from "$(ZLIBDIR)"...
263282
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
264283
265284
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
266285
cd $(OX)
267
- link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
286
+ link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
268287
269288
$(OX)\linkopts: $B\win\Makefile.msc
270289
echo $(OX)\add.obj > $@
271290
echo $(OX)\allrepo.obj >> $@
272291
echo $(OX)\attach.obj >> $@
@@ -282,10 +301,11 @@
282301
echo $(OX)\clearsign.obj >> $@
283302
echo $(OX)\clone.obj >> $@
284303
echo $(OX)\comformat.obj >> $@
285304
echo $(OX)\configure.obj >> $@
286305
echo $(OX)\content.obj >> $@
306
+ echo $(OX)\cson_amalgamation.obj >> $@
287307
echo $(OX)\db.obj >> $@
288308
echo $(OX)\delta.obj >> $@
289309
echo $(OX)\deltacmd.obj >> $@
290310
echo $(OX)\descendants.obj >> $@
291311
echo $(OX)\diff.obj >> $@
@@ -407,12 +427,12 @@
407427
$(OX)\th_lang$O : $(SRCDIR)\th_lang.c
408428
$(TCC) /Fo$@ -c $**
409429
410430
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
411431
$** > $@
412
-$(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
413
- cp $(SRCDIR)\cson_amalgamation.h $@
432
+$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
433
+ $(TCC) /Fo$@ -c $**
414434
415435
page_index.h: mkindex$E $(SRC)
416436
$** > $@
417437
418438
clean:
@@ -422,10 +442,11 @@
422442
-del *.h
423443
-del *.map
424444
-del *.manifest
425445
-del headers
426446
-del linkopts
447
+ -del *.res
427448
428449
realclean: clean
429450
-del $(APPNAME)
430451
-del translate$E
431452
-del mkindex$E
@@ -1070,10 +1091,12 @@
10701091
$(TCC) /Fo$@ -c zip_.c
10711092
10721093
zip_.c : $(SRCDIR)\zip.c
10731094
translate$E $** > $@
10741095
1096
+fossil.res : $B\win\fossil.rc
1097
+ $(RCC) -fo $@ $**
10751098
headers: makeheaders$E page_index.h VERSION.h
10761099
makeheaders$E add_.c:add.h \
10771100
allrepo_.c:allrepo.h \
10781101
attach_.c:attach.h \
10791102
bag_.c:bag.h \
10801103
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -22,18 +22,35 @@
22
23 # zlib options
24 ZINCDIR = $(B)\compat\zlib
25 ZLIBDIR = $(B)\compat\zlib
26 ZLIB = zlib.lib
 
 
 
 
 
 
27
28 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
29
30 CFLAGS = -nologo -MT -O2
31 BCC = $(CC) $(CFLAGS)
32 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
 
33 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
34 LIBDIR = -LIBPATH:$(ZLIBDIR)
 
 
 
 
 
 
 
 
 
 
35
36 SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \
37 /DSQLITE_THREADSAFE=0 \
38 /DSQLITE_DEFAULT_FILE_FORMAT=4 \
39 /DSQLITE_ENABLE_STAT3 \
@@ -160,10 +177,11 @@
160 $(OX)\clearsign$O \
161 $(OX)\clone$O \
162 $(OX)\comformat$O \
163 $(OX)\configure$O \
164 $(OX)\content$O \
 
165 $(OX)\db$O \
166 $(OX)\delta$O \
167 $(OX)\deltacmd$O \
168 $(OX)\descendants$O \
169 $(OX)\diff$O \
@@ -219,19 +237,23 @@
219 $(OX)\rss$O \
220 $(OX)\schema$O \
221 $(OX)\search$O \
222 $(OX)\setup$O \
223 $(OX)\sha1$O \
 
224 $(OX)\shun$O \
225 $(OX)\skins$O \
226 $(OX)\sqlcmd$O \
 
227 $(OX)\stash$O \
228 $(OX)\stat$O \
229 $(OX)\style$O \
230 $(OX)\sync$O \
231 $(OX)\tag$O \
232 $(OX)\tar$O \
 
 
233 $(OX)\th_main$O \
234 $(OX)\timeline$O \
235 $(OX)\tkt$O \
236 $(OX)\tktsetup$O \
237 $(OX)\undo$O \
@@ -247,14 +269,11 @@
247 $(OX)\winhttp$O \
248 $(OX)\wysiwyg$O \
249 $(OX)\xfer$O \
250 $(OX)\xfersetup$O \
251 $(OX)\zip$O \
252 $(OX)\shell$O \
253 $(OX)\sqlite3$O \
254 $(OX)\th$O \
255 $(OX)\th_lang$O
256
257 APPNAME = $(OX)\fossil$(E)
258
259 all: $(OX) $(APPNAME)
260
@@ -262,11 +281,11 @@
262 @echo Building zlib from "$(ZLIBDIR)"...
263 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
264
265 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
266 cd $(OX)
267 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
268
269 $(OX)\linkopts: $B\win\Makefile.msc
270 echo $(OX)\add.obj > $@
271 echo $(OX)\allrepo.obj >> $@
272 echo $(OX)\attach.obj >> $@
@@ -282,10 +301,11 @@
282 echo $(OX)\clearsign.obj >> $@
283 echo $(OX)\clone.obj >> $@
284 echo $(OX)\comformat.obj >> $@
285 echo $(OX)\configure.obj >> $@
286 echo $(OX)\content.obj >> $@
 
287 echo $(OX)\db.obj >> $@
288 echo $(OX)\delta.obj >> $@
289 echo $(OX)\deltacmd.obj >> $@
290 echo $(OX)\descendants.obj >> $@
291 echo $(OX)\diff.obj >> $@
@@ -407,12 +427,12 @@
407 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
408 $(TCC) /Fo$@ -c $**
409
410 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
411 $** > $@
412 $(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
413 cp $(SRCDIR)\cson_amalgamation.h $@
414
415 page_index.h: mkindex$E $(SRC)
416 $** > $@
417
418 clean:
@@ -422,10 +442,11 @@
422 -del *.h
423 -del *.map
424 -del *.manifest
425 -del headers
426 -del linkopts
 
427
428 realclean: clean
429 -del $(APPNAME)
430 -del translate$E
431 -del mkindex$E
@@ -1070,10 +1091,12 @@
1070 $(TCC) /Fo$@ -c zip_.c
1071
1072 zip_.c : $(SRCDIR)\zip.c
1073 translate$E $** > $@
1074
 
 
1075 headers: makeheaders$E page_index.h VERSION.h
1076 makeheaders$E add_.c:add.h \
1077 allrepo_.c:allrepo.h \
1078 attach_.c:attach.h \
1079 bag_.c:bag.h \
1080
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -22,18 +22,35 @@
22
23 # zlib options
24 ZINCDIR = $(B)\compat\zlib
25 ZLIBDIR = $(B)\compat\zlib
26 ZLIB = zlib.lib
27
28 # Uncomment to enable JSON API
29 # FOSSIL_ENABLE_JSON = 1
30
31 # Uncomment to enable markdown support
32 # FOSSIL_ENABLE_MARKDOWN = 1
33
34 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
35
36 CFLAGS = -nologo -MT -O2
37 BCC = $(CC) $(CFLAGS)
38 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
39 RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
40 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
41 LIBDIR = -LIBPATH:$(ZLIBDIR)
42
43 !ifdef FOSSIL_ENABLE_JSON
44 TCC = $(TCC) -DFOSSIL_ENABLE_JSON
45 RCC = $(RCC) -DFOSSIL_ENABLE_JSON
46 !endif
47
48 !ifdef FOSSIL_ENABLE_MARKDOWN
49 TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
50 RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
51 !endif
52
53 SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \
54 /DSQLITE_THREADSAFE=0 \
55 /DSQLITE_DEFAULT_FILE_FORMAT=4 \
56 /DSQLITE_ENABLE_STAT3 \
@@ -160,10 +177,11 @@
177 $(OX)\clearsign$O \
178 $(OX)\clone$O \
179 $(OX)\comformat$O \
180 $(OX)\configure$O \
181 $(OX)\content$O \
182 $(OX)\cson_amalgamation$O \
183 $(OX)\db$O \
184 $(OX)\delta$O \
185 $(OX)\deltacmd$O \
186 $(OX)\descendants$O \
187 $(OX)\diff$O \
@@ -219,19 +237,23 @@
237 $(OX)\rss$O \
238 $(OX)\schema$O \
239 $(OX)\search$O \
240 $(OX)\setup$O \
241 $(OX)\sha1$O \
242 $(OX)\shell$O \
243 $(OX)\shun$O \
244 $(OX)\skins$O \
245 $(OX)\sqlcmd$O \
246 $(OX)\sqlite3$O \
247 $(OX)\stash$O \
248 $(OX)\stat$O \
249 $(OX)\style$O \
250 $(OX)\sync$O \
251 $(OX)\tag$O \
252 $(OX)\tar$O \
253 $(OX)\th$O \
254 $(OX)\th_lang$O \
255 $(OX)\th_main$O \
256 $(OX)\timeline$O \
257 $(OX)\tkt$O \
258 $(OX)\tktsetup$O \
259 $(OX)\undo$O \
@@ -247,14 +269,11 @@
269 $(OX)\winhttp$O \
270 $(OX)\wysiwyg$O \
271 $(OX)\xfer$O \
272 $(OX)\xfersetup$O \
273 $(OX)\zip$O \
274 $(OX)\fossil.res
 
 
 
275
276 APPNAME = $(OX)\fossil$(E)
277
278 all: $(OX) $(APPNAME)
279
@@ -262,11 +281,11 @@
281 @echo Building zlib from "$(ZLIBDIR)"...
282 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
283
284 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
285 cd $(OX)
286 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
287
288 $(OX)\linkopts: $B\win\Makefile.msc
289 echo $(OX)\add.obj > $@
290 echo $(OX)\allrepo.obj >> $@
291 echo $(OX)\attach.obj >> $@
@@ -282,10 +301,11 @@
301 echo $(OX)\clearsign.obj >> $@
302 echo $(OX)\clone.obj >> $@
303 echo $(OX)\comformat.obj >> $@
304 echo $(OX)\configure.obj >> $@
305 echo $(OX)\content.obj >> $@
306 echo $(OX)\cson_amalgamation.obj >> $@
307 echo $(OX)\db.obj >> $@
308 echo $(OX)\delta.obj >> $@
309 echo $(OX)\deltacmd.obj >> $@
310 echo $(OX)\descendants.obj >> $@
311 echo $(OX)\diff.obj >> $@
@@ -407,12 +427,12 @@
427 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
428 $(TCC) /Fo$@ -c $**
429
430 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
431 $** > $@
432 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
433 $(TCC) /Fo$@ -c $**
434
435 page_index.h: mkindex$E $(SRC)
436 $** > $@
437
438 clean:
@@ -422,10 +442,11 @@
442 -del *.h
443 -del *.map
444 -del *.manifest
445 -del headers
446 -del linkopts
447 -del *.res
448
449 realclean: clean
450 -del $(APPNAME)
451 -del translate$E
452 -del mkindex$E
@@ -1070,10 +1091,12 @@
1091 $(TCC) /Fo$@ -c zip_.c
1092
1093 zip_.c : $(SRCDIR)\zip.c
1094 translate$E $** > $@
1095
1096 fossil.res : $B\win\fossil.rc
1097 $(RCC) -fo $@ $**
1098 headers: makeheaders$E page_index.h VERSION.h
1099 makeheaders$E add_.c:add.h \
1100 allrepo_.c:allrepo.h \
1101 attach_.c:attach.h \
1102 bag_.c:bag.h \
1103
+30 -7
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -22,18 +22,35 @@
2222
2323
# zlib options
2424
ZINCDIR = $(B)\compat\zlib
2525
ZLIBDIR = $(B)\compat\zlib
2626
ZLIB = zlib.lib
27
+
28
+# Uncomment to enable JSON API
29
+# FOSSIL_ENABLE_JSON = 1
30
+
31
+# Uncomment to enable markdown support
32
+# FOSSIL_ENABLE_MARKDOWN = 1
2733
2834
INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
2935
3036
CFLAGS = -nologo -MT -O2
3137
BCC = $(CC) $(CFLAGS)
3238
TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
39
+RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
3340
LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
3441
LIBDIR = -LIBPATH:$(ZLIBDIR)
42
+
43
+!ifdef FOSSIL_ENABLE_JSON
44
+TCC = $(TCC) -DFOSSIL_ENABLE_JSON
45
+RCC = $(RCC) -DFOSSIL_ENABLE_JSON
46
+!endif
47
+
48
+!ifdef FOSSIL_ENABLE_MARKDOWN
49
+TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
50
+RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
51
+!endif
3552
3653
SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \
3754
/DSQLITE_THREADSAFE=0 \
3855
/DSQLITE_DEFAULT_FILE_FORMAT=4 \
3956
/DSQLITE_ENABLE_STAT3 \
@@ -160,10 +177,11 @@
160177
$(OX)\clearsign$O \
161178
$(OX)\clone$O \
162179
$(OX)\comformat$O \
163180
$(OX)\configure$O \
164181
$(OX)\content$O \
182
+ $(OX)\cson_amalgamation$O \
165183
$(OX)\db$O \
166184
$(OX)\delta$O \
167185
$(OX)\deltacmd$O \
168186
$(OX)\descendants$O \
169187
$(OX)\diff$O \
@@ -219,19 +237,23 @@
219237
$(OX)\rss$O \
220238
$(OX)\schema$O \
221239
$(OX)\search$O \
222240
$(OX)\setup$O \
223241
$(OX)\sha1$O \
242
+ $(OX)\shell$O \
224243
$(OX)\shun$O \
225244
$(OX)\skins$O \
226245
$(OX)\sqlcmd$O \
246
+ $(OX)\sqlite3$O \
227247
$(OX)\stash$O \
228248
$(OX)\stat$O \
229249
$(OX)\style$O \
230250
$(OX)\sync$O \
231251
$(OX)\tag$O \
232252
$(OX)\tar$O \
253
+ $(OX)\th$O \
254
+ $(OX)\th_lang$O \
233255
$(OX)\th_main$O \
234256
$(OX)\timeline$O \
235257
$(OX)\tkt$O \
236258
$(OX)\tktsetup$O \
237259
$(OX)\undo$O \
@@ -247,14 +269,11 @@
247269
$(OX)\winhttp$O \
248270
$(OX)\wysiwyg$O \
249271
$(OX)\xfer$O \
250272
$(OX)\xfersetup$O \
251273
$(OX)\zip$O \
252
- $(OX)\shell$O \
253
- $(OX)\sqlite3$O \
254
- $(OX)\th$O \
255
- $(OX)\th_lang$O
274
+ $(OX)\fossil.res
256275
257276
APPNAME = $(OX)\fossil$(E)
258277
259278
all: $(OX) $(APPNAME)
260279
@@ -262,11 +281,11 @@
262281
@echo Building zlib from "$(ZLIBDIR)"...
263282
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
264283
265284
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
266285
cd $(OX)
267
- link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
286
+ link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
268287
269288
$(OX)\linkopts: $B\win\Makefile.msc
270289
echo $(OX)\add.obj > $@
271290
echo $(OX)\allrepo.obj >> $@
272291
echo $(OX)\attach.obj >> $@
@@ -282,10 +301,11 @@
282301
echo $(OX)\clearsign.obj >> $@
283302
echo $(OX)\clone.obj >> $@
284303
echo $(OX)\comformat.obj >> $@
285304
echo $(OX)\configure.obj >> $@
286305
echo $(OX)\content.obj >> $@
306
+ echo $(OX)\cson_amalgamation.obj >> $@
287307
echo $(OX)\db.obj >> $@
288308
echo $(OX)\delta.obj >> $@
289309
echo $(OX)\deltacmd.obj >> $@
290310
echo $(OX)\descendants.obj >> $@
291311
echo $(OX)\diff.obj >> $@
@@ -407,12 +427,12 @@
407427
$(OX)\th_lang$O : $(SRCDIR)\th_lang.c
408428
$(TCC) /Fo$@ -c $**
409429
410430
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
411431
$** > $@
412
-$(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
413
- cp $(SRCDIR)\cson_amalgamation.h $@
432
+$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
433
+ $(TCC) /Fo$@ -c $**
414434
415435
page_index.h: mkindex$E $(SRC)
416436
$** > $@
417437
418438
clean:
@@ -422,10 +442,11 @@
422442
-del *.h
423443
-del *.map
424444
-del *.manifest
425445
-del headers
426446
-del linkopts
447
+ -del *.res
427448
428449
realclean: clean
429450
-del $(APPNAME)
430451
-del translate$E
431452
-del mkindex$E
@@ -1070,10 +1091,12 @@
10701091
$(TCC) /Fo$@ -c zip_.c
10711092
10721093
zip_.c : $(SRCDIR)\zip.c
10731094
translate$E $** > $@
10741095
1096
+fossil.res : $B\win\fossil.rc
1097
+ $(RCC) -fo $@ $**
10751098
headers: makeheaders$E page_index.h VERSION.h
10761099
makeheaders$E add_.c:add.h \
10771100
allrepo_.c:allrepo.h \
10781101
attach_.c:attach.h \
10791102
bag_.c:bag.h \
10801103
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -22,18 +22,35 @@
22
23 # zlib options
24 ZINCDIR = $(B)\compat\zlib
25 ZLIBDIR = $(B)\compat\zlib
26 ZLIB = zlib.lib
 
 
 
 
 
 
27
28 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
29
30 CFLAGS = -nologo -MT -O2
31 BCC = $(CC) $(CFLAGS)
32 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
 
33 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
34 LIBDIR = -LIBPATH:$(ZLIBDIR)
 
 
 
 
 
 
 
 
 
 
35
36 SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \
37 /DSQLITE_THREADSAFE=0 \
38 /DSQLITE_DEFAULT_FILE_FORMAT=4 \
39 /DSQLITE_ENABLE_STAT3 \
@@ -160,10 +177,11 @@
160 $(OX)\clearsign$O \
161 $(OX)\clone$O \
162 $(OX)\comformat$O \
163 $(OX)\configure$O \
164 $(OX)\content$O \
 
165 $(OX)\db$O \
166 $(OX)\delta$O \
167 $(OX)\deltacmd$O \
168 $(OX)\descendants$O \
169 $(OX)\diff$O \
@@ -219,19 +237,23 @@
219 $(OX)\rss$O \
220 $(OX)\schema$O \
221 $(OX)\search$O \
222 $(OX)\setup$O \
223 $(OX)\sha1$O \
 
224 $(OX)\shun$O \
225 $(OX)\skins$O \
226 $(OX)\sqlcmd$O \
 
227 $(OX)\stash$O \
228 $(OX)\stat$O \
229 $(OX)\style$O \
230 $(OX)\sync$O \
231 $(OX)\tag$O \
232 $(OX)\tar$O \
 
 
233 $(OX)\th_main$O \
234 $(OX)\timeline$O \
235 $(OX)\tkt$O \
236 $(OX)\tktsetup$O \
237 $(OX)\undo$O \
@@ -247,14 +269,11 @@
247 $(OX)\winhttp$O \
248 $(OX)\wysiwyg$O \
249 $(OX)\xfer$O \
250 $(OX)\xfersetup$O \
251 $(OX)\zip$O \
252 $(OX)\shell$O \
253 $(OX)\sqlite3$O \
254 $(OX)\th$O \
255 $(OX)\th_lang$O
256
257 APPNAME = $(OX)\fossil$(E)
258
259 all: $(OX) $(APPNAME)
260
@@ -262,11 +281,11 @@
262 @echo Building zlib from "$(ZLIBDIR)"...
263 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
264
265 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
266 cd $(OX)
267 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj @linkopts
268
269 $(OX)\linkopts: $B\win\Makefile.msc
270 echo $(OX)\add.obj > $@
271 echo $(OX)\allrepo.obj >> $@
272 echo $(OX)\attach.obj >> $@
@@ -282,10 +301,11 @@
282 echo $(OX)\clearsign.obj >> $@
283 echo $(OX)\clone.obj >> $@
284 echo $(OX)\comformat.obj >> $@
285 echo $(OX)\configure.obj >> $@
286 echo $(OX)\content.obj >> $@
 
287 echo $(OX)\db.obj >> $@
288 echo $(OX)\delta.obj >> $@
289 echo $(OX)\deltacmd.obj >> $@
290 echo $(OX)\descendants.obj >> $@
291 echo $(OX)\diff.obj >> $@
@@ -407,12 +427,12 @@
407 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
408 $(TCC) /Fo$@ -c $**
409
410 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
411 $** > $@
412 $(OBJDIR)\cson_amalgamation.h : $(SRCDIR)\cson_amalgamation.h
413 cp $(SRCDIR)\cson_amalgamation.h $@
414
415 page_index.h: mkindex$E $(SRC)
416 $** > $@
417
418 clean:
@@ -422,10 +442,11 @@
422 -del *.h
423 -del *.map
424 -del *.manifest
425 -del headers
426 -del linkopts
 
427
428 realclean: clean
429 -del $(APPNAME)
430 -del translate$E
431 -del mkindex$E
@@ -1070,10 +1091,12 @@
1070 $(TCC) /Fo$@ -c zip_.c
1071
1072 zip_.c : $(SRCDIR)\zip.c
1073 translate$E $** > $@
1074
 
 
1075 headers: makeheaders$E page_index.h VERSION.h
1076 makeheaders$E add_.c:add.h \
1077 allrepo_.c:allrepo.h \
1078 attach_.c:attach.h \
1079 bag_.c:bag.h \
1080
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -22,18 +22,35 @@
22
23 # zlib options
24 ZINCDIR = $(B)\compat\zlib
25 ZLIBDIR = $(B)\compat\zlib
26 ZLIB = zlib.lib
27
28 # Uncomment to enable JSON API
29 # FOSSIL_ENABLE_JSON = 1
30
31 # Uncomment to enable markdown support
32 # FOSSIL_ENABLE_MARKDOWN = 1
33
34 INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
35
36 CFLAGS = -nologo -MT -O2
37 BCC = $(CC) $(CFLAGS)
38 TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL)
39 RCC = rc -D_WIN32 -D_MSC_VER $(INCL)
40 LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB)
41 LIBDIR = -LIBPATH:$(ZLIBDIR)
42
43 !ifdef FOSSIL_ENABLE_JSON
44 TCC = $(TCC) -DFOSSIL_ENABLE_JSON
45 RCC = $(RCC) -DFOSSIL_ENABLE_JSON
46 !endif
47
48 !ifdef FOSSIL_ENABLE_MARKDOWN
49 TCC = $(TCC) -DFOSSIL_ENABLE_MARKDOWN
50 RCC = $(RCC) -DFOSSIL_ENABLE_MARKDOWN
51 !endif
52
53 SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \
54 /DSQLITE_THREADSAFE=0 \
55 /DSQLITE_DEFAULT_FILE_FORMAT=4 \
56 /DSQLITE_ENABLE_STAT3 \
@@ -160,10 +177,11 @@
177 $(OX)\clearsign$O \
178 $(OX)\clone$O \
179 $(OX)\comformat$O \
180 $(OX)\configure$O \
181 $(OX)\content$O \
182 $(OX)\cson_amalgamation$O \
183 $(OX)\db$O \
184 $(OX)\delta$O \
185 $(OX)\deltacmd$O \
186 $(OX)\descendants$O \
187 $(OX)\diff$O \
@@ -219,19 +237,23 @@
237 $(OX)\rss$O \
238 $(OX)\schema$O \
239 $(OX)\search$O \
240 $(OX)\setup$O \
241 $(OX)\sha1$O \
242 $(OX)\shell$O \
243 $(OX)\shun$O \
244 $(OX)\skins$O \
245 $(OX)\sqlcmd$O \
246 $(OX)\sqlite3$O \
247 $(OX)\stash$O \
248 $(OX)\stat$O \
249 $(OX)\style$O \
250 $(OX)\sync$O \
251 $(OX)\tag$O \
252 $(OX)\tar$O \
253 $(OX)\th$O \
254 $(OX)\th_lang$O \
255 $(OX)\th_main$O \
256 $(OX)\timeline$O \
257 $(OX)\tkt$O \
258 $(OX)\tktsetup$O \
259 $(OX)\undo$O \
@@ -247,14 +269,11 @@
269 $(OX)\winhttp$O \
270 $(OX)\wysiwyg$O \
271 $(OX)\xfer$O \
272 $(OX)\xfersetup$O \
273 $(OX)\zip$O \
274 $(OX)\fossil.res
 
 
 
275
276 APPNAME = $(OX)\fossil$(E)
277
278 all: $(OX) $(APPNAME)
279
@@ -262,11 +281,11 @@
281 @echo Building zlib from "$(ZLIBDIR)"...
282 @pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
283
284 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
285 cd $(OX)
286 link /NODEFAULTLIB:msvcrt -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
287
288 $(OX)\linkopts: $B\win\Makefile.msc
289 echo $(OX)\add.obj > $@
290 echo $(OX)\allrepo.obj >> $@
291 echo $(OX)\attach.obj >> $@
@@ -282,10 +301,11 @@
301 echo $(OX)\clearsign.obj >> $@
302 echo $(OX)\clone.obj >> $@
303 echo $(OX)\comformat.obj >> $@
304 echo $(OX)\configure.obj >> $@
305 echo $(OX)\content.obj >> $@
306 echo $(OX)\cson_amalgamation.obj >> $@
307 echo $(OX)\db.obj >> $@
308 echo $(OX)\delta.obj >> $@
309 echo $(OX)\deltacmd.obj >> $@
310 echo $(OX)\descendants.obj >> $@
311 echo $(OX)\diff.obj >> $@
@@ -407,12 +427,12 @@
427 $(OX)\th_lang$O : $(SRCDIR)\th_lang.c
428 $(TCC) /Fo$@ -c $**
429
430 VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
431 $** > $@
432 $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
433 $(TCC) /Fo$@ -c $**
434
435 page_index.h: mkindex$E $(SRC)
436 $** > $@
437
438 clean:
@@ -422,10 +442,11 @@
442 -del *.h
443 -del *.map
444 -del *.manifest
445 -del headers
446 -del linkopts
447 -del *.res
448
449 realclean: clean
450 -del $(APPNAME)
451 -del translate$E
452 -del mkindex$E
@@ -1070,10 +1091,12 @@
1091 $(TCC) /Fo$@ -c zip_.c
1092
1093 zip_.c : $(SRCDIR)\zip.c
1094 translate$E $** > $@
1095
1096 fossil.res : $B\win\fossil.rc
1097 $(RCC) -fo $@ $**
1098 headers: makeheaders$E page_index.h VERSION.h
1099 makeheaders$E add_.c:add.h \
1100 allrepo_.c:allrepo.h \
1101 attach_.c:attach.h \
1102 bag_.c:bag.h \
1103
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -866,18 +866,18 @@
866866
/* Set errno variable */
867867
static void
868868
dirent_set_errno(
869869
int error)
870870
{
871
-#if defined(_MSC_VER)
871
+#if defined(_MSC_VER) && _MSC_VER >= 1400
872872
873
- /* Microsoft Visual Studio */
873
+ /* Microsoft Visual Studio 2005 and later */
874874
_set_errno (error);
875875
876876
#else
877877
878
- /* Non-Microsoft compiler */
878
+ /* Non-Microsoft compiler or older Microsoft compiler */
879879
errno = error;
880880
881881
#endif
882882
}
883883
884884
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -866,18 +866,18 @@
866 /* Set errno variable */
867 static void
868 dirent_set_errno(
869 int error)
870 {
871 #if defined(_MSC_VER)
872
873 /* Microsoft Visual Studio */
874 _set_errno (error);
875
876 #else
877
878 /* Non-Microsoft compiler */
879 errno = error;
880
881 #endif
882 }
883
884
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -866,18 +866,18 @@
866 /* Set errno variable */
867 static void
868 dirent_set_errno(
869 int error)
870 {
871 #if defined(_MSC_VER) && _MSC_VER >= 1400
872
873 /* Microsoft Visual Studio 2005 and later */
874 _set_errno (error);
875
876 #else
877
878 /* Non-Microsoft compiler or older Microsoft compiler */
879 errno = error;
880
881 #endif
882 }
883
884
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -866,18 +866,18 @@
866866
/* Set errno variable */
867867
static void
868868
dirent_set_errno(
869869
int error)
870870
{
871
-#if defined(_MSC_VER)
871
+#if defined(_MSC_VER) && _MSC_VER >= 1400
872872
873
- /* Microsoft Visual Studio */
873
+ /* Microsoft Visual Studio 2005 and later */
874874
_set_errno (error);
875875
876876
#else
877877
878
- /* Non-Microsoft compiler */
878
+ /* Non-Microsoft compiler or older Microsoft compiler */
879879
errno = error;
880880
881881
#endif
882882
}
883883
884884
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -866,18 +866,18 @@
866 /* Set errno variable */
867 static void
868 dirent_set_errno(
869 int error)
870 {
871 #if defined(_MSC_VER)
872
873 /* Microsoft Visual Studio */
874 _set_errno (error);
875
876 #else
877
878 /* Non-Microsoft compiler */
879 errno = error;
880
881 #endif
882 }
883
884
--- win/include/dirent.h
+++ win/include/dirent.h
@@ -866,18 +866,18 @@
866 /* Set errno variable */
867 static void
868 dirent_set_errno(
869 int error)
870 {
871 #if defined(_MSC_VER) && _MSC_VER >= 1400
872
873 /* Microsoft Visual Studio 2005 and later */
874 _set_errno (error);
875
876 #else
877
878 /* Non-Microsoft compiler or older Microsoft compiler */
879 errno = error;
880
881 #endif
882 }
883
884
+2 -2
--- www/build.wiki
+++ www/build.wiki
@@ -54,11 +54,11 @@
5454
</ol>
5555
5656
<h2>2.0 Compiling</h2>
5757
5858
<ol>
59
-<li value="6">
59
+<li value="5">
6060
<p>Unpack the ZIP or tarball you downloaded then
6161
<b>cd</b> into the directory created.</p></li>
6262
6363
<li><i>(Optional, unix only)</i>
6464
Run <b>./configure</b> to construct a makefile.
@@ -101,11 +101,11 @@
101101
</ol>
102102
103103
<h2>3.0 Installing</h2>
104104
105105
<ol>
106
-<li value="9">
106
+<li value="8">
107107
<p>The finished binary is named "fossil" (or "fossil.exe" on windows).
108108
Put this binary in a
109109
directory that is somewhere on your PATH environment variable.
110110
It does not matter where.</p>
111111
112112
113113
ADDED www/fiveminutes.wiki
--- www/build.wiki
+++ www/build.wiki
@@ -54,11 +54,11 @@
54 </ol>
55
56 <h2>2.0 Compiling</h2>
57
58 <ol>
59 <li value="6">
60 <p>Unpack the ZIP or tarball you downloaded then
61 <b>cd</b> into the directory created.</p></li>
62
63 <li><i>(Optional, unix only)</i>
64 Run <b>./configure</b> to construct a makefile.
@@ -101,11 +101,11 @@
101 </ol>
102
103 <h2>3.0 Installing</h2>
104
105 <ol>
106 <li value="9">
107 <p>The finished binary is named "fossil" (or "fossil.exe" on windows).
108 Put this binary in a
109 directory that is somewhere on your PATH environment variable.
110 It does not matter where.</p>
111
112
113 DDED www/fiveminutes.wiki
--- www/build.wiki
+++ www/build.wiki
@@ -54,11 +54,11 @@
54 </ol>
55
56 <h2>2.0 Compiling</h2>
57
58 <ol>
59 <li value="5">
60 <p>Unpack the ZIP or tarball you downloaded then
61 <b>cd</b> into the directory created.</p></li>
62
63 <li><i>(Optional, unix only)</i>
64 Run <b>./configure</b> to construct a makefile.
@@ -101,11 +101,11 @@
101 </ol>
102
103 <h2>3.0 Installing</h2>
104
105 <ol>
106 <li value="8">
107 <p>The finished binary is named "fossil" (or "fossil.exe" on windows).
108 Put this binary in a
109 directory that is somewhere on your PATH environment variable.
110 It does not matter where.</p>
111
112
113 DDED www/fiveminutes.wiki
+2 -2
--- www/build.wiki
+++ www/build.wiki
@@ -54,11 +54,11 @@
5454
</ol>
5555
5656
<h2>2.0 Compiling</h2>
5757
5858
<ol>
59
-<li value="6">
59
+<li value="5">
6060
<p>Unpack the ZIP or tarball you downloaded then
6161
<b>cd</b> into the directory created.</p></li>
6262
6363
<li><i>(Optional, unix only)</i>
6464
Run <b>./configure</b> to construct a makefile.
@@ -101,11 +101,11 @@
101101
</ol>
102102
103103
<h2>3.0 Installing</h2>
104104
105105
<ol>
106
-<li value="9">
106
+<li value="8">
107107
<p>The finished binary is named "fossil" (or "fossil.exe" on windows).
108108
Put this binary in a
109109
directory that is somewhere on your PATH environment variable.
110110
It does not matter where.</p>
111111
112112
113113
ADDED www/fiveminutes.wiki
--- www/build.wiki
+++ www/build.wiki
@@ -54,11 +54,11 @@
54 </ol>
55
56 <h2>2.0 Compiling</h2>
57
58 <ol>
59 <li value="6">
60 <p>Unpack the ZIP or tarball you downloaded then
61 <b>cd</b> into the directory created.</p></li>
62
63 <li><i>(Optional, unix only)</i>
64 Run <b>./configure</b> to construct a makefile.
@@ -101,11 +101,11 @@
101 </ol>
102
103 <h2>3.0 Installing</h2>
104
105 <ol>
106 <li value="9">
107 <p>The finished binary is named "fossil" (or "fossil.exe" on windows).
108 Put this binary in a
109 directory that is somewhere on your PATH environment variable.
110 It does not matter where.</p>
111
112
113 DDED www/fiveminutes.wiki
--- www/build.wiki
+++ www/build.wiki
@@ -54,11 +54,11 @@
54 </ol>
55
56 <h2>2.0 Compiling</h2>
57
58 <ol>
59 <li value="5">
60 <p>Unpack the ZIP or tarball you downloaded then
61 <b>cd</b> into the directory created.</p></li>
62
63 <li><i>(Optional, unix only)</i>
64 Run <b>./configure</b> to construct a makefile.
@@ -101,11 +101,11 @@
101 </ol>
102
103 <h2>3.0 Installing</h2>
104
105 <ol>
106 <li value="8">
107 <p>The finished binary is named "fossil" (or "fossil.exe" on windows).
108 Put this binary in a
109 directory that is somewhere on your PATH environment variable.
110 It does not matter where.</p>
111
112
113 DDED www/fiveminutes.wiki
--- a/www/fiveminutes.wiki
+++ b/www/fiveminutes.wiki
@@ -0,0 +1,40 @@
1
+<title>Up and running in 5 minutes as a single user</title>
2
+
3
+<p align="center"><b><i>
4
+The following document was contributed by Gilles Ganault on 2013-01-08.
5
+</i></b>
6
+</p><hr>
7
+
8
+<h1>Up and running in 5 min<p>tes as a single user</h1>
9
+
10
+This short document explains the main basic F ossil comands for a single
11
+user, i.e. with no additional users, with no need to s
12
+repository, and no </p>need for branching/forking.
13
+
14
+<h2>Cr<p>fossil new c:\test.repo</p>
15
+<p>sil new c:\test.repo</tt>
16
+
17
+This will create the new SQLite binary file that holds the repository, itc. It can be located anywhere, although it's considered
18
+best practice to keep it outside the wse to keep it outside the work directory where you will work on files here you will work on files
19
+after they've been che</p>
20
+
21
+<h2>Open the repository</h2>
22
+<p>cd c:\temp\test.fossil</p>
23
+<p>fossil open c:\test.repo</p>
24
+<p>il open c:\test.repo</tt>
25
+
26
+This will check out the last revision of all t
27
+if any, into the current work directory. In addition, it will create a binary
28
+file _UUIDIL_ to keep track of changes (on</p>called
29
+<tt>.fslckout</tt><p>fossilUUID#1 --to UUIDes to the repository. The files aren't actually
30
+added until you run &quot;commit&quot
31
+
32
+<h2>Close the repository</h2>
33
+<p>fossil c repository</h2>
34
+<p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files aren'es in the repository,
35
+if any, into the current work directory. In addition--to UUIDes to the repository. The files aren't actually
36
+added until you run &quot;commit&quot
37
+
38
+<h2>Close the repository</h2>
39
+<p>fossil c repository</h2>
40
+<p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files ar
--- a/www/fiveminutes.wiki
+++ b/www/fiveminutes.wiki
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/fiveminutes.wiki
+++ b/www/fiveminutes.wiki
@@ -0,0 +1,40 @@
1 <title>Up and running in 5 minutes as a single user</title>
2
3 <p align="center"><b><i>
4 The following document was contributed by Gilles Ganault on 2013-01-08.
5 </i></b>
6 </p><hr>
7
8 <h1>Up and running in 5 min<p>tes as a single user</h1>
9
10 This short document explains the main basic F ossil comands for a single
11 user, i.e. with no additional users, with no need to s
12 repository, and no </p>need for branching/forking.
13
14 <h2>Cr<p>fossil new c:\test.repo</p>
15 <p>sil new c:\test.repo</tt>
16
17 This will create the new SQLite binary file that holds the repository, itc. It can be located anywhere, although it's considered
18 best practice to keep it outside the wse to keep it outside the work directory where you will work on files here you will work on files
19 after they've been che</p>
20
21 <h2>Open the repository</h2>
22 <p>cd c:\temp\test.fossil</p>
23 <p>fossil open c:\test.repo</p>
24 <p>il open c:\test.repo</tt>
25
26 This will check out the last revision of all t
27 if any, into the current work directory. In addition, it will create a binary
28 file _UUIDIL_ to keep track of changes (on</p>called
29 <tt>.fslckout</tt><p>fossilUUID#1 --to UUIDes to the repository. The files aren't actually
30 added until you run &quot;commit&quot
31
32 <h2>Close the repository</h2>
33 <p>fossil c repository</h2>
34 <p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files aren'es in the repository,
35 if any, into the current work directory. In addition--to UUIDes to the repository. The files aren't actually
36 added until you run &quot;commit&quot
37
38 <h2>Close the repository</h2>
39 <p>fossil c repository</h2>
40 <p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files ar
--- a/www/fiveminutes.wiki
+++ b/www/fiveminutes.wiki
@@ -0,0 +1,40 @@
1
+<title>Up and running in 5 minutes as a single user</title>
2
+
3
+<p align="center"><b><i>
4
+The following document was contributed by Gilles Ganault on 2013-01-08.
5
+</i></b>
6
+</p><hr>
7
+
8
+<h1>Up and running in 5 min<p>tes as a single user</h1>
9
+
10
+This short document explains the main basic F ossil comands for a single
11
+user, i.e. with no additional users, with no need to s
12
+repository, and no </p>need for branching/forking.
13
+
14
+<h2>Cr<p>fossil new c:\test.repo</p>
15
+<p>sil new c:\test.repo</tt>
16
+
17
+This will create the new SQLite binary file that holds the repository, itc. It can be located anywhere, although it's considered
18
+best practice to keep it outside the wse to keep it outside the work directory where you will work on files here you will work on files
19
+after they've been che</p>
20
+
21
+<h2>Open the repository</h2>
22
+<p>cd c:\temp\test.fossil</p>
23
+<p>fossil open c:\test.repo</p>
24
+<p>il open c:\test.repo</tt>
25
+
26
+This will check out the last revision of all t
27
+if any, into the current work directory. In addition, it will create a binary
28
+file _UUIDIL_ to keep track of changes (on</p>called
29
+<tt>.fslckout</tt><p>fossilUUID#1 --to UUIDes to the repository. The files aren't actually
30
+added until you run &quot;commit&quot
31
+
32
+<h2>Close the repository</h2>
33
+<p>fossil c repository</h2>
34
+<p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files aren'es in the repository,
35
+if any, into the current work directory. In addition--to UUIDes to the repository. The files aren't actually
36
+added until you run &quot;commit&quot
37
+
38
+<h2>Close the repository</h2>
39
+<p>fossil c repository</h2>
40
+<p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files ar
--- a/www/fiveminutes.wiki
+++ b/www/fiveminutes.wiki
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/fiveminutes.wiki
+++ b/www/fiveminutes.wiki
@@ -0,0 +1,40 @@
1 <title>Up and running in 5 minutes as a single user</title>
2
3 <p align="center"><b><i>
4 The following document was contributed by Gilles Ganault on 2013-01-08.
5 </i></b>
6 </p><hr>
7
8 <h1>Up and running in 5 min<p>tes as a single user</h1>
9
10 This short document explains the main basic F ossil comands for a single
11 user, i.e. with no additional users, with no need to s
12 repository, and no </p>need for branching/forking.
13
14 <h2>Cr<p>fossil new c:\test.repo</p>
15 <p>sil new c:\test.repo</tt>
16
17 This will create the new SQLite binary file that holds the repository, itc. It can be located anywhere, although it's considered
18 best practice to keep it outside the wse to keep it outside the work directory where you will work on files here you will work on files
19 after they've been che</p>
20
21 <h2>Open the repository</h2>
22 <p>cd c:\temp\test.fossil</p>
23 <p>fossil open c:\test.repo</p>
24 <p>il open c:\test.repo</tt>
25
26 This will check out the last revision of all t
27 if any, into the current work directory. In addition, it will create a binary
28 file _UUIDIL_ to keep track of changes (on</p>called
29 <tt>.fslckout</tt><p>fossilUUID#1 --to UUIDes to the repository. The files aren't actually
30 added until you run &quot;commit&quot
31
32 <h2>Close the repository</h2>
33 <p>fossil c repository</h2>
34 <p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files aren'es in the repository,
35 if any, into the current work directory. In addition--to UUIDes to the repository. The files aren't actually
36 added until you run &quot;commit&quot
37
38 <h2>Close the repository</h2>
39 <p>fossil c repository</h2>
40 <p>fossil close_FOSSIL_ at the root of the work di>.fslckout</tt>< to the repository. The files ar
--- www/index.wiki
+++ www/index.wiki
@@ -149,10 +149,12 @@
149149
* How to [./server.wiki | set up a server] for your repository.
150150
* Customizing the [./custom_ticket.wiki | ticket system].
151151
* Methods to [./checkin_names.wiki | identify a specific check-in].
152152
* [./inout.wiki | Import and export] from and to Git.
153153
* [./fossil-v-git.wiki | Fossil versus Git].
154
+ * [./fiveminutes.wiki | Up and running in 5 minutes as a single user]
155
+ (contributed by Gilles Ganault on 2013-01-08).
154156
155157
<h3>Links For Fossil Developer:</h3>
156158
157159
* [./contribute.wiki | Contributing] code or documentation to the
158160
Fossil project.
159161
--- www/index.wiki
+++ www/index.wiki
@@ -149,10 +149,12 @@
149 * How to [./server.wiki | set up a server] for your repository.
150 * Customizing the [./custom_ticket.wiki | ticket system].
151 * Methods to [./checkin_names.wiki | identify a specific check-in].
152 * [./inout.wiki | Import and export] from and to Git.
153 * [./fossil-v-git.wiki | Fossil versus Git].
 
 
154
155 <h3>Links For Fossil Developer:</h3>
156
157 * [./contribute.wiki | Contributing] code or documentation to the
158 Fossil project.
159
--- www/index.wiki
+++ www/index.wiki
@@ -149,10 +149,12 @@
149 * How to [./server.wiki | set up a server] for your repository.
150 * Customizing the [./custom_ticket.wiki | ticket system].
151 * Methods to [./checkin_names.wiki | identify a specific check-in].
152 * [./inout.wiki | Import and export] from and to Git.
153 * [./fossil-v-git.wiki | Fossil versus Git].
154 * [./fiveminutes.wiki | Up and running in 5 minutes as a single user]
155 (contributed by Gilles Ganault on 2013-01-08).
156
157 <h3>Links For Fossil Developer:</h3>
158
159 * [./contribute.wiki | Contributing] code or documentation to the
160 Fossil project.
161
--- www/index.wiki
+++ www/index.wiki
@@ -149,10 +149,12 @@
149149
* How to [./server.wiki | set up a server] for your repository.
150150
* Customizing the [./custom_ticket.wiki | ticket system].
151151
* Methods to [./checkin_names.wiki | identify a specific check-in].
152152
* [./inout.wiki | Import and export] from and to Git.
153153
* [./fossil-v-git.wiki | Fossil versus Git].
154
+ * [./fiveminutes.wiki | Up and running in 5 minutes as a single user]
155
+ (contributed by Gilles Ganault on 2013-01-08).
154156
155157
<h3>Links For Fossil Developer:</h3>
156158
157159
* [./contribute.wiki | Contributing] code or documentation to the
158160
Fossil project.
159161
--- www/index.wiki
+++ www/index.wiki
@@ -149,10 +149,12 @@
149 * How to [./server.wiki | set up a server] for your repository.
150 * Customizing the [./custom_ticket.wiki | ticket system].
151 * Methods to [./checkin_names.wiki | identify a specific check-in].
152 * [./inout.wiki | Import and export] from and to Git.
153 * [./fossil-v-git.wiki | Fossil versus Git].
 
 
154
155 <h3>Links For Fossil Developer:</h3>
156
157 * [./contribute.wiki | Contributing] code or documentation to the
158 Fossil project.
159
--- www/index.wiki
+++ www/index.wiki
@@ -149,10 +149,12 @@
149 * How to [./server.wiki | set up a server] for your repository.
150 * Customizing the [./custom_ticket.wiki | ticket system].
151 * Methods to [./checkin_names.wiki | identify a specific check-in].
152 * [./inout.wiki | Import and export] from and to Git.
153 * [./fossil-v-git.wiki | Fossil versus Git].
154 * [./fiveminutes.wiki | Up and running in 5 minutes as a single user]
155 (contributed by Gilles Ganault on 2013-01-08).
156
157 <h3>Links For Fossil Developer:</h3>
158
159 * [./contribute.wiki | Contributing] code or documentation to the
160 Fossil project.
161
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -21,10 +21,11 @@
2121
delta_format.wiki {Fossil Delta Format}
2222
embeddeddoc.wiki {Embedded Project Documentation}
2323
event.wiki {Events}
2424
faq.wiki {Frequently Asked Questions}
2525
fileformat.wiki {Fossil File Format}
26
+ fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
2627
foss-cklist.wiki {Checklist For Successful Open-Source Projects}
2728
fossil-v-git.wiki {Fossil Versus Git}
2829
index.wiki {Home Page}
2930
inout.wiki {Import And Export To And From Git}
3031
makefile.wiki {The Fossil Build Process}
3132
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -21,10 +21,11 @@
21 delta_format.wiki {Fossil Delta Format}
22 embeddeddoc.wiki {Embedded Project Documentation}
23 event.wiki {Events}
24 faq.wiki {Frequently Asked Questions}
25 fileformat.wiki {Fossil File Format}
 
26 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
27 fossil-v-git.wiki {Fossil Versus Git}
28 index.wiki {Home Page}
29 inout.wiki {Import And Export To And From Git}
30 makefile.wiki {The Fossil Build Process}
31
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -21,10 +21,11 @@
21 delta_format.wiki {Fossil Delta Format}
22 embeddeddoc.wiki {Embedded Project Documentation}
23 event.wiki {Events}
24 faq.wiki {Frequently Asked Questions}
25 fileformat.wiki {Fossil File Format}
26 fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
27 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
28 fossil-v-git.wiki {Fossil Versus Git}
29 index.wiki {Home Page}
30 inout.wiki {Import And Export To And From Git}
31 makefile.wiki {The Fossil Build Process}
32
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -21,10 +21,11 @@
2121
delta_format.wiki {Fossil Delta Format}
2222
embeddeddoc.wiki {Embedded Project Documentation}
2323
event.wiki {Events}
2424
faq.wiki {Frequently Asked Questions}
2525
fileformat.wiki {Fossil File Format}
26
+ fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
2627
foss-cklist.wiki {Checklist For Successful Open-Source Projects}
2728
fossil-v-git.wiki {Fossil Versus Git}
2829
index.wiki {Home Page}
2930
inout.wiki {Import And Export To And From Git}
3031
makefile.wiki {The Fossil Build Process}
3132
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -21,10 +21,11 @@
21 delta_format.wiki {Fossil Delta Format}
22 embeddeddoc.wiki {Embedded Project Documentation}
23 event.wiki {Events}
24 faq.wiki {Frequently Asked Questions}
25 fileformat.wiki {Fossil File Format}
 
26 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
27 fossil-v-git.wiki {Fossil Versus Git}
28 index.wiki {Home Page}
29 inout.wiki {Import And Export To And From Git}
30 makefile.wiki {The Fossil Build Process}
31
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -21,10 +21,11 @@
21 delta_format.wiki {Fossil Delta Format}
22 embeddeddoc.wiki {Embedded Project Documentation}
23 event.wiki {Events}
24 faq.wiki {Frequently Asked Questions}
25 fileformat.wiki {Fossil File Format}
26 fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
27 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
28 fossil-v-git.wiki {Fossil Versus Git}
29 index.wiki {Home Page}
30 inout.wiki {Import And Export To And From Git}
31 makefile.wiki {The Fossil Build Process}
32
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -10,13 +10,15 @@
1010
<li> [/help | Command-line help]
1111
</ul>
1212
<a name="pindex"></a>
1313
<h2>Permuted Index:</h2>
1414
<ul>
15
+<li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Update and Running in</a></li>
1516
<li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
1617
<li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
1718
<li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
19
+<li><a href="fiveminutes.wiki">as a Single User &mdash; Update and Running in 5 Minutes</a></li>
1820
<li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
1921
<li><a href="password.wiki">Authentication &mdash; Password Management And</a></li>
2022
<li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
2123
<li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
2224
<li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
@@ -90,10 +92,11 @@
9092
<li><a href="selfcheck.wiki">Integrity Self Checks &mdash; Fossil Repository</a></li>
9193
<li><a href="webui.wiki">Interface &mdash; The Fossil Web</a></li>
9294
<li><a href="copyright-release.html">License Agreement &mdash; Contributor</a></li>
9395
<li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
9496
<li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
97
+<li><a href="fiveminutes.wiki">Minutes as a Single User &mdash; Update and Running in 5</a></li>
9598
<li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
9699
<li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
97100
<li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
98101
<li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
99102
<li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
@@ -115,16 +118,18 @@
115118
<li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li>
116119
<li><a href="selfhost.wiki">Repositories &mdash; Fossil Self Hosting</a></li>
117120
<li><a href="newrepo.wiki">Repository &mdash; How To Create A New Fossil</a></li>
118121
<li><a href="selfcheck.wiki">Repository Integrity Self Checks &mdash; Fossil</a></li>
119122
<li><a href="reviews.wiki">Reviews</a></li>
123
+<li><a href="fiveminutes.wiki">Running in 5 Minutes as a Single User &mdash; Update and</a></li>
120124
<li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are</a></li>
121125
<li><a href="selfcheck.wiki">Self Checks &mdash; Fossil Repository Integrity</a></li>
122126
<li><a href="selfhost.wiki">Self Hosting Repositories &mdash; Fossil</a></li>
123127
<li><a href="server.wiki">Server &mdash; How To Configure A Fossil</a></li>
124128
<li><a href="settings.wiki">Settings &mdash; Fossil</a></li>
125129
<li><a href="shunning.wiki">Shunning: Deleting Content From Fossil</a></li>
130
+<li><a href="fiveminutes.wiki">Single User &mdash; Update and Running in 5 Minutes as a</a></li>
126131
<li><a href="style.wiki">Source Code Style Guidelines</a></li>
127132
<li><a href="tech_overview.wiki">SQLite Databases Used By Fossil</a></li>
128133
<li><a href="ssl.wiki">SSL with Fossil &mdash; Using</a></li>
129134
<li><a href="quickstart.wiki">Start Guide &mdash; Fossil Quick</a></li>
130135
<li><a href="stats.wiki">Statistics &mdash; Performance</a></li>
@@ -140,13 +145,15 @@
140145
<li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
141146
<li><a href="webui.wiki">The Fossil Web Interface</a></li>
142147
<li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
143148
<li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
144149
<li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
150
+<li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
151
+<li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
145152
<li><a href="ssl.wiki">Using SSL with Fossil</a></li>
146153
<li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
147154
<li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
148155
<li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
149156
<li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
150157
<li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
151158
<li><a href="ssl.wiki">with Fossil &mdash; Using SSL</a></li>
152159
</ul>
153160
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -10,13 +10,15 @@
10 <li> [/help | Command-line help]
11 </ul>
12 <a name="pindex"></a>
13 <h2>Permuted Index:</h2>
14 <ul>
 
15 <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
16 <li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
17 <li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
 
18 <li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
19 <li><a href="password.wiki">Authentication &mdash; Password Management And</a></li>
20 <li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
21 <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
22 <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
@@ -90,10 +92,11 @@
90 <li><a href="selfcheck.wiki">Integrity Self Checks &mdash; Fossil Repository</a></li>
91 <li><a href="webui.wiki">Interface &mdash; The Fossil Web</a></li>
92 <li><a href="copyright-release.html">License Agreement &mdash; Contributor</a></li>
93 <li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
94 <li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
 
95 <li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
96 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
97 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
98 <li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
99 <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
@@ -115,16 +118,18 @@
115 <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li>
116 <li><a href="selfhost.wiki">Repositories &mdash; Fossil Self Hosting</a></li>
117 <li><a href="newrepo.wiki">Repository &mdash; How To Create A New Fossil</a></li>
118 <li><a href="selfcheck.wiki">Repository Integrity Self Checks &mdash; Fossil</a></li>
119 <li><a href="reviews.wiki">Reviews</a></li>
 
120 <li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are</a></li>
121 <li><a href="selfcheck.wiki">Self Checks &mdash; Fossil Repository Integrity</a></li>
122 <li><a href="selfhost.wiki">Self Hosting Repositories &mdash; Fossil</a></li>
123 <li><a href="server.wiki">Server &mdash; How To Configure A Fossil</a></li>
124 <li><a href="settings.wiki">Settings &mdash; Fossil</a></li>
125 <li><a href="shunning.wiki">Shunning: Deleting Content From Fossil</a></li>
 
126 <li><a href="style.wiki">Source Code Style Guidelines</a></li>
127 <li><a href="tech_overview.wiki">SQLite Databases Used By Fossil</a></li>
128 <li><a href="ssl.wiki">SSL with Fossil &mdash; Using</a></li>
129 <li><a href="quickstart.wiki">Start Guide &mdash; Fossil Quick</a></li>
130 <li><a href="stats.wiki">Statistics &mdash; Performance</a></li>
@@ -140,13 +145,15 @@
140 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
141 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
142 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
143 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
144 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
 
 
145 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
146 <li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
147 <li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
148 <li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
149 <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
150 <li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
151 <li><a href="ssl.wiki">with Fossil &mdash; Using SSL</a></li>
152 </ul>
153
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -10,13 +10,15 @@
10 <li> [/help | Command-line help]
11 </ul>
12 <a name="pindex"></a>
13 <h2>Permuted Index:</h2>
14 <ul>
15 <li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Update and Running in</a></li>
16 <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
17 <li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
18 <li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
19 <li><a href="fiveminutes.wiki">as a Single User &mdash; Update and Running in 5 Minutes</a></li>
20 <li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
21 <li><a href="password.wiki">Authentication &mdash; Password Management And</a></li>
22 <li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
23 <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
24 <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
@@ -90,10 +92,11 @@
92 <li><a href="selfcheck.wiki">Integrity Self Checks &mdash; Fossil Repository</a></li>
93 <li><a href="webui.wiki">Interface &mdash; The Fossil Web</a></li>
94 <li><a href="copyright-release.html">License Agreement &mdash; Contributor</a></li>
95 <li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
96 <li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
97 <li><a href="fiveminutes.wiki">Minutes as a Single User &mdash; Update and Running in 5</a></li>
98 <li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
99 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
100 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
101 <li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
102 <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
@@ -115,16 +118,18 @@
118 <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li>
119 <li><a href="selfhost.wiki">Repositories &mdash; Fossil Self Hosting</a></li>
120 <li><a href="newrepo.wiki">Repository &mdash; How To Create A New Fossil</a></li>
121 <li><a href="selfcheck.wiki">Repository Integrity Self Checks &mdash; Fossil</a></li>
122 <li><a href="reviews.wiki">Reviews</a></li>
123 <li><a href="fiveminutes.wiki">Running in 5 Minutes as a Single User &mdash; Update and</a></li>
124 <li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are</a></li>
125 <li><a href="selfcheck.wiki">Self Checks &mdash; Fossil Repository Integrity</a></li>
126 <li><a href="selfhost.wiki">Self Hosting Repositories &mdash; Fossil</a></li>
127 <li><a href="server.wiki">Server &mdash; How To Configure A Fossil</a></li>
128 <li><a href="settings.wiki">Settings &mdash; Fossil</a></li>
129 <li><a href="shunning.wiki">Shunning: Deleting Content From Fossil</a></li>
130 <li><a href="fiveminutes.wiki">Single User &mdash; Update and Running in 5 Minutes as a</a></li>
131 <li><a href="style.wiki">Source Code Style Guidelines</a></li>
132 <li><a href="tech_overview.wiki">SQLite Databases Used By Fossil</a></li>
133 <li><a href="ssl.wiki">SSL with Fossil &mdash; Using</a></li>
134 <li><a href="quickstart.wiki">Start Guide &mdash; Fossil Quick</a></li>
135 <li><a href="stats.wiki">Statistics &mdash; Performance</a></li>
@@ -140,13 +145,15 @@
145 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
146 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
147 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
148 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
149 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
150 <li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
151 <li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
152 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
153 <li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
154 <li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
155 <li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
156 <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
157 <li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
158 <li><a href="ssl.wiki">with Fossil &mdash; Using SSL</a></li>
159 </ul>
160
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -10,13 +10,15 @@
1010
<li> [/help | Command-line help]
1111
</ul>
1212
<a name="pindex"></a>
1313
<h2>Permuted Index:</h2>
1414
<ul>
15
+<li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Update and Running in</a></li>
1516
<li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
1617
<li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
1718
<li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
19
+<li><a href="fiveminutes.wiki">as a Single User &mdash; Update and Running in 5 Minutes</a></li>
1820
<li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
1921
<li><a href="password.wiki">Authentication &mdash; Password Management And</a></li>
2022
<li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
2123
<li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
2224
<li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
@@ -90,10 +92,11 @@
9092
<li><a href="selfcheck.wiki">Integrity Self Checks &mdash; Fossil Repository</a></li>
9193
<li><a href="webui.wiki">Interface &mdash; The Fossil Web</a></li>
9294
<li><a href="copyright-release.html">License Agreement &mdash; Contributor</a></li>
9395
<li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
9496
<li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
97
+<li><a href="fiveminutes.wiki">Minutes as a Single User &mdash; Update and Running in 5</a></li>
9598
<li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
9699
<li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
97100
<li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
98101
<li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
99102
<li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
@@ -115,16 +118,18 @@
115118
<li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li>
116119
<li><a href="selfhost.wiki">Repositories &mdash; Fossil Self Hosting</a></li>
117120
<li><a href="newrepo.wiki">Repository &mdash; How To Create A New Fossil</a></li>
118121
<li><a href="selfcheck.wiki">Repository Integrity Self Checks &mdash; Fossil</a></li>
119122
<li><a href="reviews.wiki">Reviews</a></li>
123
+<li><a href="fiveminutes.wiki">Running in 5 Minutes as a Single User &mdash; Update and</a></li>
120124
<li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are</a></li>
121125
<li><a href="selfcheck.wiki">Self Checks &mdash; Fossil Repository Integrity</a></li>
122126
<li><a href="selfhost.wiki">Self Hosting Repositories &mdash; Fossil</a></li>
123127
<li><a href="server.wiki">Server &mdash; How To Configure A Fossil</a></li>
124128
<li><a href="settings.wiki">Settings &mdash; Fossil</a></li>
125129
<li><a href="shunning.wiki">Shunning: Deleting Content From Fossil</a></li>
130
+<li><a href="fiveminutes.wiki">Single User &mdash; Update and Running in 5 Minutes as a</a></li>
126131
<li><a href="style.wiki">Source Code Style Guidelines</a></li>
127132
<li><a href="tech_overview.wiki">SQLite Databases Used By Fossil</a></li>
128133
<li><a href="ssl.wiki">SSL with Fossil &mdash; Using</a></li>
129134
<li><a href="quickstart.wiki">Start Guide &mdash; Fossil Quick</a></li>
130135
<li><a href="stats.wiki">Statistics &mdash; Performance</a></li>
@@ -140,13 +145,15 @@
140145
<li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
141146
<li><a href="webui.wiki">The Fossil Web Interface</a></li>
142147
<li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
143148
<li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
144149
<li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
150
+<li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
151
+<li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
145152
<li><a href="ssl.wiki">Using SSL with Fossil</a></li>
146153
<li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
147154
<li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
148155
<li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
149156
<li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
150157
<li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
151158
<li><a href="ssl.wiki">with Fossil &mdash; Using SSL</a></li>
152159
</ul>
153160
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -10,13 +10,15 @@
10 <li> [/help | Command-line help]
11 </ul>
12 <a name="pindex"></a>
13 <h2>Permuted Index:</h2>
14 <ul>
 
15 <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
16 <li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
17 <li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
 
18 <li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
19 <li><a href="password.wiki">Authentication &mdash; Password Management And</a></li>
20 <li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
21 <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
22 <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
@@ -90,10 +92,11 @@
90 <li><a href="selfcheck.wiki">Integrity Self Checks &mdash; Fossil Repository</a></li>
91 <li><a href="webui.wiki">Interface &mdash; The Fossil Web</a></li>
92 <li><a href="copyright-release.html">License Agreement &mdash; Contributor</a></li>
93 <li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
94 <li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
 
95 <li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
96 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
97 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
98 <li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
99 <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
@@ -115,16 +118,18 @@
115 <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li>
116 <li><a href="selfhost.wiki">Repositories &mdash; Fossil Self Hosting</a></li>
117 <li><a href="newrepo.wiki">Repository &mdash; How To Create A New Fossil</a></li>
118 <li><a href="selfcheck.wiki">Repository Integrity Self Checks &mdash; Fossil</a></li>
119 <li><a href="reviews.wiki">Reviews</a></li>
 
120 <li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are</a></li>
121 <li><a href="selfcheck.wiki">Self Checks &mdash; Fossil Repository Integrity</a></li>
122 <li><a href="selfhost.wiki">Self Hosting Repositories &mdash; Fossil</a></li>
123 <li><a href="server.wiki">Server &mdash; How To Configure A Fossil</a></li>
124 <li><a href="settings.wiki">Settings &mdash; Fossil</a></li>
125 <li><a href="shunning.wiki">Shunning: Deleting Content From Fossil</a></li>
 
126 <li><a href="style.wiki">Source Code Style Guidelines</a></li>
127 <li><a href="tech_overview.wiki">SQLite Databases Used By Fossil</a></li>
128 <li><a href="ssl.wiki">SSL with Fossil &mdash; Using</a></li>
129 <li><a href="quickstart.wiki">Start Guide &mdash; Fossil Quick</a></li>
130 <li><a href="stats.wiki">Statistics &mdash; Performance</a></li>
@@ -140,13 +145,15 @@
140 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
141 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
142 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
143 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
144 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
 
 
145 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
146 <li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
147 <li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
148 <li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
149 <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
150 <li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
151 <li><a href="ssl.wiki">with Fossil &mdash; Using SSL</a></li>
152 </ul>
153
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -10,13 +10,15 @@
10 <li> [/help | Command-line help]
11 </ul>
12 <a name="pindex"></a>
13 <h2>Permuted Index:</h2>
14 <ul>
15 <li><a href="fiveminutes.wiki">5 Minutes as a Single User &mdash; Update and Running in</a></li>
16 <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
17 <li><a href="copyright-release.html">Agreement &mdash; Contributor License</a></li>
18 <li><a href="delta_encoder_algorithm.wiki">Algorithm &mdash; Fossil Delta Encoding</a></li>
19 <li><a href="fiveminutes.wiki">as a Single User &mdash; Update and Running in 5 Minutes</a></li>
20 <li><a href="faq.wiki">Asked Questions &mdash; Frequently</a></li>
21 <li><a href="password.wiki">Authentication &mdash; Password Management And</a></li>
22 <li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
23 <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
24 <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
@@ -90,10 +92,11 @@
92 <li><a href="selfcheck.wiki">Integrity Self Checks &mdash; Fossil Repository</a></li>
93 <li><a href="webui.wiki">Interface &mdash; The Fossil Web</a></li>
94 <li><a href="copyright-release.html">License Agreement &mdash; Contributor</a></li>
95 <li><a href="password.wiki">Management And Authentication &mdash; Password</a></li>
96 <li><a href="branching.wiki">Merging, and Tagging &mdash; Branching, Forking,</a></li>
97 <li><a href="fiveminutes.wiki">Minutes as a Single User &mdash; Update and Running in 5</a></li>
98 <li><a href="checkin_names.wiki">Names &mdash; Checkin And Version</a></li>
99 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
100 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
101 <li><a href="pop.wiki">Operations &mdash; Principles Of</a></li>
102 <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil &mdash; A Technical</a></li>
@@ -115,16 +118,18 @@
118 <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li>
119 <li><a href="selfhost.wiki">Repositories &mdash; Fossil Self Hosting</a></li>
120 <li><a href="newrepo.wiki">Repository &mdash; How To Create A New Fossil</a></li>
121 <li><a href="selfcheck.wiki">Repository Integrity Self Checks &mdash; Fossil</a></li>
122 <li><a href="reviews.wiki">Reviews</a></li>
123 <li><a href="fiveminutes.wiki">Running in 5 Minutes as a Single User &mdash; Update and</a></li>
124 <li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General &mdash; Quotes: What People Are</a></li>
125 <li><a href="selfcheck.wiki">Self Checks &mdash; Fossil Repository Integrity</a></li>
126 <li><a href="selfhost.wiki">Self Hosting Repositories &mdash; Fossil</a></li>
127 <li><a href="server.wiki">Server &mdash; How To Configure A Fossil</a></li>
128 <li><a href="settings.wiki">Settings &mdash; Fossil</a></li>
129 <li><a href="shunning.wiki">Shunning: Deleting Content From Fossil</a></li>
130 <li><a href="fiveminutes.wiki">Single User &mdash; Update and Running in 5 Minutes as a</a></li>
131 <li><a href="style.wiki">Source Code Style Guidelines</a></li>
132 <li><a href="tech_overview.wiki">SQLite Databases Used By Fossil</a></li>
133 <li><a href="ssl.wiki">SSL with Fossil &mdash; Using</a></li>
134 <li><a href="quickstart.wiki">Start Guide &mdash; Fossil Quick</a></li>
135 <li><a href="stats.wiki">Statistics &mdash; Performance</a></li>
@@ -140,13 +145,15 @@
145 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
146 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
147 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
148 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
149 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
150 <li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
151 <li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
152 <li><a href="ssl.wiki">Using SSL with Fossil</a></li>
153 <li><a href="checkin_names.wiki">Version Names &mdash; Checkin And</a></li>
154 <li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
155 <li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
156 <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &mdash; Quotes:</a></li>
157 <li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
158 <li><a href="ssl.wiki">with Fossil &mdash; Using SSL</a></li>
159 </ul>
160

Keyboard Shortcuts

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