Fossil SCM
Merge updates from trunk.
Commit
78829b7089ac7a065514382c1c75d3e054216fbd
Parent
7b54a4e839c9b07…
44 files changed
+6
-6
+19
-15
+19
-15
-5
-5
+2
+2
+8
+3
+2
-1
+3
-1
+3
-1
+11
-38
+11
-38
+1
-1
+847
-17
+1
+39
-14
+39
-14
+2
-2
+2
-2
+1
-1
+46
-19
+481
-221
+33
-32
+28
-2
+28
-2
+35
-18
+2
+18
-17
+29
+66
+4
+1
+44
-53
+1
-1
+1
-1
+2
-2
+2
-2
+1
-1
+1
-1
+1
-1
+4
+4
-5
~
Dockerfile
~
skins/blitz/css.txt
~
skins/blitz_no_logo/css.txt
~
skins/eagle/header.txt
~
skins/enhanced1/header.txt
~
src/add.c
~
src/add.c
~
src/cache.c
~
src/checkin.c
~
src/clone.c
~
src/configure.c
~
src/configure.c
~
src/db.c
~
src/db.c
~
src/doc.c
~
src/import.c
~
src/json_config.c
~
src/main.c
~
src/main.c
~
src/makemake.tcl
~
src/makemake.tcl
~
src/rebuild.c
~
src/shell.c
~
src/sqlite3.c
~
src/sqlite3.h
~
src/th_main.c
~
src/th_main.c
~
src/timeline.c
~
src/wikiformat.c
~
src/xfersetup.c
~
test/fileStat.th1
~
test/tester.tcl
~
test/th1-docs-input.txt
~
test/th1-docs.test
~
test/th1-hooks.test
~
win/Makefile.mingw
~
win/Makefile.mingw
~
win/Makefile.mingw.mistachkin
~
win/Makefile.mingw.mistachkin
~
win/Makefile.msc
~
win/Makefile.msc
~
www/build.wiki
~
www/changes.wiki
~
www/sync.wiki
+6
-6
| --- Dockerfile | ||
| +++ Dockerfile | ||
| @@ -2,26 +2,26 @@ | ||
| 2 | 2 | # Dockerfile for Fossil |
| 3 | 3 | ### |
| 4 | 4 | FROM fedora:21 |
| 5 | 5 | |
| 6 | 6 | ### Now install some additional parts we will need for the build |
| 7 | -RUN yum update -y && yum install -y gcc make zlib-devel openssl-devel tcl tar && yum clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil | |
| 7 | +RUN yum update -y && yum install -y gcc make zlib-devel openssl-devel tar && yum clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil | |
| 8 | 8 | |
| 9 | 9 | ### If you want to build "release", change the next line accordingly. |
| 10 | 10 | ENV FOSSIL_INSTALL_VERSION trunk |
| 11 | 11 | |
| 12 | +RUN curl "http://core.tcl.tk/tcl/tarball/tcl-src.tar.gz?name=tcl-src&uuid=release" | tar zx | |
| 13 | +RUN cd tcl-src/unix && ./configure --prefix=/usr --disable-shared --disable-threads --disable-load && make && make install | |
| 12 | 14 | RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx |
| 13 | -RUN cd fossil-src && ./configure --disable-lineedit --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl --with-tcl-stubs --with-tcl-private-stubs && make; | |
| 14 | -RUN cp fossil-src/fossil /usr/bin && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil | |
| 15 | +RUN cd fossil-src && ./configure --disable-lineedit --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl | |
| 16 | +RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil | |
| 15 | 17 | |
| 16 | 18 | ### Build is done, remove modules no longer needed |
| 17 | 19 | RUN yum remove -y gcc make zlib-devel openssl-devel tar && yum clean all |
| 18 | 20 | |
| 19 | 21 | USER fossil |
| 20 | 22 | |
| 21 | 23 | ENV HOME /opt/fossil |
| 22 | 24 | |
| 23 | -RUN fossil new --docker -A admin /opt/fossil/repository.fossil && fossil user password -R /opt/fossil/repository.fossil admin admin && fossil cache init -R /opt/fossil/repository.fossil | |
| 24 | - | |
| 25 | 25 | EXPOSE 8080 |
| 26 | 26 | |
| 27 | -CMD ["/usr/bin/fossil", "server", "/opt/fossil/repository.fossil"] | |
| 27 | +CMD ["/usr/bin/fossil", "server", "--create", "--user", "admin", "/opt/fossil/repository.fossil"] | |
| 28 | 28 |
| --- Dockerfile | |
| +++ Dockerfile | |
| @@ -2,26 +2,26 @@ | |
| 2 | # Dockerfile for Fossil |
| 3 | ### |
| 4 | FROM fedora:21 |
| 5 | |
| 6 | ### Now install some additional parts we will need for the build |
| 7 | RUN yum update -y && yum install -y gcc make zlib-devel openssl-devel tcl tar && yum clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil |
| 8 | |
| 9 | ### If you want to build "release", change the next line accordingly. |
| 10 | ENV FOSSIL_INSTALL_VERSION trunk |
| 11 | |
| 12 | RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx |
| 13 | RUN cd fossil-src && ./configure --disable-lineedit --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl --with-tcl-stubs --with-tcl-private-stubs && make; |
| 14 | RUN cp fossil-src/fossil /usr/bin && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil |
| 15 | |
| 16 | ### Build is done, remove modules no longer needed |
| 17 | RUN yum remove -y gcc make zlib-devel openssl-devel tar && yum clean all |
| 18 | |
| 19 | USER fossil |
| 20 | |
| 21 | ENV HOME /opt/fossil |
| 22 | |
| 23 | RUN fossil new --docker -A admin /opt/fossil/repository.fossil && fossil user password -R /opt/fossil/repository.fossil admin admin && fossil cache init -R /opt/fossil/repository.fossil |
| 24 | |
| 25 | EXPOSE 8080 |
| 26 | |
| 27 | CMD ["/usr/bin/fossil", "server", "/opt/fossil/repository.fossil"] |
| 28 |
| --- Dockerfile | |
| +++ Dockerfile | |
| @@ -2,26 +2,26 @@ | |
| 2 | # Dockerfile for Fossil |
| 3 | ### |
| 4 | FROM fedora:21 |
| 5 | |
| 6 | ### Now install some additional parts we will need for the build |
| 7 | RUN yum update -y && yum install -y gcc make zlib-devel openssl-devel tar && yum clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil |
| 8 | |
| 9 | ### If you want to build "release", change the next line accordingly. |
| 10 | ENV FOSSIL_INSTALL_VERSION trunk |
| 11 | |
| 12 | RUN curl "http://core.tcl.tk/tcl/tarball/tcl-src.tar.gz?name=tcl-src&uuid=release" | tar zx |
| 13 | RUN cd tcl-src/unix && ./configure --prefix=/usr --disable-shared --disable-threads --disable-load && make && make install |
| 14 | RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx |
| 15 | RUN cd fossil-src && ./configure --disable-lineedit --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl |
| 16 | RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil |
| 17 | |
| 18 | ### Build is done, remove modules no longer needed |
| 19 | RUN yum remove -y gcc make zlib-devel openssl-devel tar && yum clean all |
| 20 | |
| 21 | USER fossil |
| 22 | |
| 23 | ENV HOME /opt/fossil |
| 24 | |
| 25 | EXPOSE 8080 |
| 26 | |
| 27 | CMD ["/usr/bin/fossil", "server", "--create", "--user", "admin", "/opt/fossil/repository.fossil"] |
| 28 |
+19
-15
| --- skins/blitz/css.txt | ||
| +++ skins/blitz/css.txt | ||
| @@ -464,11 +464,11 @@ | ||
| 464 | 464 | font-weight: 400; |
| 465 | 465 | color: #ccc; |
| 466 | 466 | } |
| 467 | 467 | |
| 468 | 468 | pre, code { |
| 469 | - font-size: 1.3rem; | |
| 469 | + font-size: 1.2rem; | |
| 470 | 470 | } |
| 471 | 471 | |
| 472 | 472 | body { |
| 473 | 473 | font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ |
| 474 | 474 | line-height: 1.5; |
| @@ -599,10 +599,11 @@ | ||
| 599 | 599 | -moz-appearance: none; |
| 600 | 600 | appearance: none; |
| 601 | 601 | } |
| 602 | 602 | |
| 603 | 603 | textarea { |
| 604 | + height: inherit; | |
| 604 | 605 | min-height: 65px; |
| 605 | 606 | padding-top: 6px; |
| 606 | 607 | padding-bottom: 6px; |
| 607 | 608 | } |
| 608 | 609 | |
| @@ -857,11 +858,10 @@ | ||
| 857 | 858 | |
| 858 | 859 | .mainmenu li { |
| 859 | 860 | outline: 0; |
| 860 | 861 | display: block; |
| 861 | 862 | float: left; |
| 862 | - padding: 10px 15px; | |
| 863 | 863 | margin: 0; |
| 864 | 864 | } |
| 865 | 865 | |
| 866 | 866 | .mainmenu li.active { |
| 867 | 867 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); |
| @@ -868,12 +868,13 @@ | ||
| 868 | 868 | background-repeat: no-repeat; |
| 869 | 869 | background-position: center bottom; |
| 870 | 870 | } |
| 871 | 871 | |
| 872 | 872 | .mainmenu li a { |
| 873 | - color: #3b5c6b; | |
| 874 | - display: block; | |
| 873 | + color: #3b5c6b; | |
| 874 | + display: block; | |
| 875 | + padding: 10px 15px; | |
| 875 | 876 | } |
| 876 | 877 | |
| 877 | 878 | .mainmenu li.active a { |
| 878 | 879 | font-weight: bold; |
| 879 | 880 | } |
| @@ -890,11 +891,11 @@ | ||
| 890 | 891 | padding: 10px 0px; |
| 891 | 892 | border-bottom: 1px solid #ddd; |
| 892 | 893 | } |
| 893 | 894 | |
| 894 | 895 | .submenu input, .submenu select { |
| 895 | - margin: 0; | |
| 896 | + margin: 0 0 0 5px; | |
| 896 | 897 | } |
| 897 | 898 | |
| 898 | 899 | .submenu a { |
| 899 | 900 | color: #3b5c6b; |
| 900 | 901 | padding: 5px 15px; |
| @@ -1072,17 +1073,15 @@ | ||
| 1072 | 1073 | font-weight: bold; |
| 1073 | 1074 | white-space: nowrap; |
| 1074 | 1075 | } |
| 1075 | 1076 | |
| 1076 | 1077 | a.timelineHistLink { |
| 1077 | - text-transform: uppercase; | |
| 1078 | + text-transform: lowercase; | |
| 1078 | 1079 | } |
| 1079 | 1080 | |
| 1080 | 1081 | span.timelineComment { |
| 1081 | - /* make the span behave like a div */ | |
| 1082 | - /* padding: 10px 20px;*/ | |
| 1083 | - /* display: block;*/ | |
| 1082 | + padding: 0px 5px; | |
| 1084 | 1083 | } |
| 1085 | 1084 | |
| 1086 | 1085 | |
| 1087 | 1086 | /* Login/Loguot |
| 1088 | 1087 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| @@ -1097,17 +1096,22 @@ | ||
| 1097 | 1096 | table.login_out td { |
| 1098 | 1097 | border: 0; |
| 1099 | 1098 | } |
| 1100 | 1099 | |
| 1101 | 1100 | |
| 1102 | -/* Miscellaneous | |
| 1101 | +/* Diff displays | |
| 1103 | 1102 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1104 | -.udiff, .sbsdiff { | |
| 1105 | - font-size: .85em !important; | |
| 1106 | - overflow: auto; | |
| 1107 | - border: 1px solid #ccc; | |
| 1108 | - border-radius: 5px; | |
| 1103 | +pre.udiff, table.sbsdiffcols { | |
| 1104 | + width: 100%; | |
| 1105 | + overflow: auto; | |
| 1106 | + border: 1px solid #ccc; | |
| 1107 | + padding: 5px; | |
| 1108 | + font-size: 1rem; | |
| 1109 | +} | |
| 1110 | + | |
| 1111 | +pre.udiff:focus, table.sbsdiffcols:focus { | |
| 1112 | + outline: none; | |
| 1109 | 1113 | } |
| 1110 | 1114 | |
| 1111 | 1115 | |
| 1112 | 1116 | /* Ticket Reports |
| 1113 | 1117 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1114 | 1118 |
| --- skins/blitz/css.txt | |
| +++ skins/blitz/css.txt | |
| @@ -464,11 +464,11 @@ | |
| 464 | font-weight: 400; |
| 465 | color: #ccc; |
| 466 | } |
| 467 | |
| 468 | pre, code { |
| 469 | font-size: 1.3rem; |
| 470 | } |
| 471 | |
| 472 | body { |
| 473 | font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ |
| 474 | line-height: 1.5; |
| @@ -599,10 +599,11 @@ | |
| 599 | -moz-appearance: none; |
| 600 | appearance: none; |
| 601 | } |
| 602 | |
| 603 | textarea { |
| 604 | min-height: 65px; |
| 605 | padding-top: 6px; |
| 606 | padding-bottom: 6px; |
| 607 | } |
| 608 | |
| @@ -857,11 +858,10 @@ | |
| 857 | |
| 858 | .mainmenu li { |
| 859 | outline: 0; |
| 860 | display: block; |
| 861 | float: left; |
| 862 | padding: 10px 15px; |
| 863 | margin: 0; |
| 864 | } |
| 865 | |
| 866 | .mainmenu li.active { |
| 867 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); |
| @@ -868,12 +868,13 @@ | |
| 868 | background-repeat: no-repeat; |
| 869 | background-position: center bottom; |
| 870 | } |
| 871 | |
| 872 | .mainmenu li a { |
| 873 | color: #3b5c6b; |
| 874 | display: block; |
| 875 | } |
| 876 | |
| 877 | .mainmenu li.active a { |
| 878 | font-weight: bold; |
| 879 | } |
| @@ -890,11 +891,11 @@ | |
| 890 | padding: 10px 0px; |
| 891 | border-bottom: 1px solid #ddd; |
| 892 | } |
| 893 | |
| 894 | .submenu input, .submenu select { |
| 895 | margin: 0; |
| 896 | } |
| 897 | |
| 898 | .submenu a { |
| 899 | color: #3b5c6b; |
| 900 | padding: 5px 15px; |
| @@ -1072,17 +1073,15 @@ | |
| 1072 | font-weight: bold; |
| 1073 | white-space: nowrap; |
| 1074 | } |
| 1075 | |
| 1076 | a.timelineHistLink { |
| 1077 | text-transform: uppercase; |
| 1078 | } |
| 1079 | |
| 1080 | span.timelineComment { |
| 1081 | /* make the span behave like a div */ |
| 1082 | /* padding: 10px 20px;*/ |
| 1083 | /* display: block;*/ |
| 1084 | } |
| 1085 | |
| 1086 | |
| 1087 | /* Login/Loguot |
| 1088 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| @@ -1097,17 +1096,22 @@ | |
| 1097 | table.login_out td { |
| 1098 | border: 0; |
| 1099 | } |
| 1100 | |
| 1101 | |
| 1102 | /* Miscellaneous |
| 1103 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1104 | .udiff, .sbsdiff { |
| 1105 | font-size: .85em !important; |
| 1106 | overflow: auto; |
| 1107 | border: 1px solid #ccc; |
| 1108 | border-radius: 5px; |
| 1109 | } |
| 1110 | |
| 1111 | |
| 1112 | /* Ticket Reports |
| 1113 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1114 |
| --- skins/blitz/css.txt | |
| +++ skins/blitz/css.txt | |
| @@ -464,11 +464,11 @@ | |
| 464 | font-weight: 400; |
| 465 | color: #ccc; |
| 466 | } |
| 467 | |
| 468 | pre, code { |
| 469 | font-size: 1.2rem; |
| 470 | } |
| 471 | |
| 472 | body { |
| 473 | font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ |
| 474 | line-height: 1.5; |
| @@ -599,10 +599,11 @@ | |
| 599 | -moz-appearance: none; |
| 600 | appearance: none; |
| 601 | } |
| 602 | |
| 603 | textarea { |
| 604 | height: inherit; |
| 605 | min-height: 65px; |
| 606 | padding-top: 6px; |
| 607 | padding-bottom: 6px; |
| 608 | } |
| 609 | |
| @@ -857,11 +858,10 @@ | |
| 858 | |
| 859 | .mainmenu li { |
| 860 | outline: 0; |
| 861 | display: block; |
| 862 | float: left; |
| 863 | margin: 0; |
| 864 | } |
| 865 | |
| 866 | .mainmenu li.active { |
| 867 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); |
| @@ -868,12 +868,13 @@ | |
| 868 | background-repeat: no-repeat; |
| 869 | background-position: center bottom; |
| 870 | } |
| 871 | |
| 872 | .mainmenu li a { |
| 873 | color: #3b5c6b; |
| 874 | display: block; |
| 875 | padding: 10px 15px; |
| 876 | } |
| 877 | |
| 878 | .mainmenu li.active a { |
| 879 | font-weight: bold; |
| 880 | } |
| @@ -890,11 +891,11 @@ | |
| 891 | padding: 10px 0px; |
| 892 | border-bottom: 1px solid #ddd; |
| 893 | } |
| 894 | |
| 895 | .submenu input, .submenu select { |
| 896 | margin: 0 0 0 5px; |
| 897 | } |
| 898 | |
| 899 | .submenu a { |
| 900 | color: #3b5c6b; |
| 901 | padding: 5px 15px; |
| @@ -1072,17 +1073,15 @@ | |
| 1073 | font-weight: bold; |
| 1074 | white-space: nowrap; |
| 1075 | } |
| 1076 | |
| 1077 | a.timelineHistLink { |
| 1078 | text-transform: lowercase; |
| 1079 | } |
| 1080 | |
| 1081 | span.timelineComment { |
| 1082 | padding: 0px 5px; |
| 1083 | } |
| 1084 | |
| 1085 | |
| 1086 | /* Login/Loguot |
| 1087 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| @@ -1097,17 +1096,22 @@ | |
| 1096 | table.login_out td { |
| 1097 | border: 0; |
| 1098 | } |
| 1099 | |
| 1100 | |
| 1101 | /* Diff displays |
| 1102 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1103 | pre.udiff, table.sbsdiffcols { |
| 1104 | width: 100%; |
| 1105 | overflow: auto; |
| 1106 | border: 1px solid #ccc; |
| 1107 | padding: 5px; |
| 1108 | font-size: 1rem; |
| 1109 | } |
| 1110 | |
| 1111 | pre.udiff:focus, table.sbsdiffcols:focus { |
| 1112 | outline: none; |
| 1113 | } |
| 1114 | |
| 1115 | |
| 1116 | /* Ticket Reports |
| 1117 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1118 |
+19
-15
| --- skins/blitz_no_logo/css.txt | ||
| +++ skins/blitz_no_logo/css.txt | ||
| @@ -464,11 +464,11 @@ | ||
| 464 | 464 | font-weight: 400; |
| 465 | 465 | color: #ccc; |
| 466 | 466 | } |
| 467 | 467 | |
| 468 | 468 | pre, code { |
| 469 | - font-size: 1.3rem; | |
| 469 | + font-size: 1.2rem; | |
| 470 | 470 | } |
| 471 | 471 | |
| 472 | 472 | body { |
| 473 | 473 | font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ |
| 474 | 474 | line-height: 1.5; |
| @@ -599,10 +599,11 @@ | ||
| 599 | 599 | -moz-appearance: none; |
| 600 | 600 | appearance: none; |
| 601 | 601 | } |
| 602 | 602 | |
| 603 | 603 | textarea { |
| 604 | + height: inherit; | |
| 604 | 605 | min-height: 65px; |
| 605 | 606 | padding-top: 6px; |
| 606 | 607 | padding-bottom: 6px; |
| 607 | 608 | } |
| 608 | 609 | |
| @@ -857,11 +858,10 @@ | ||
| 857 | 858 | |
| 858 | 859 | .mainmenu li { |
| 859 | 860 | outline: 0; |
| 860 | 861 | display: block; |
| 861 | 862 | float: left; |
| 862 | - padding: 10px 15px; | |
| 863 | 863 | margin: 0; |
| 864 | 864 | } |
| 865 | 865 | |
| 866 | 866 | .mainmenu li.active { |
| 867 | 867 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); |
| @@ -868,12 +868,13 @@ | ||
| 868 | 868 | background-repeat: no-repeat; |
| 869 | 869 | background-position: center bottom; |
| 870 | 870 | } |
| 871 | 871 | |
| 872 | 872 | .mainmenu li a { |
| 873 | - color: #3b5c6b; | |
| 874 | - display: block; | |
| 873 | + color: #3b5c6b; | |
| 874 | + display: block; | |
| 875 | + padding: 10px 15px; | |
| 875 | 876 | } |
| 876 | 877 | |
| 877 | 878 | .mainmenu li.active a { |
| 878 | 879 | font-weight: bold; |
| 879 | 880 | } |
| @@ -890,11 +891,11 @@ | ||
| 890 | 891 | padding: 10px 0px; |
| 891 | 892 | border-bottom: 1px solid #ddd; |
| 892 | 893 | } |
| 893 | 894 | |
| 894 | 895 | .submenu input, .submenu select { |
| 895 | - margin: 0; | |
| 896 | + margin: 0 0 0 5px; | |
| 896 | 897 | } |
| 897 | 898 | |
| 898 | 899 | .submenu a { |
| 899 | 900 | color: #3b5c6b; |
| 900 | 901 | padding: 5px 15px; |
| @@ -1072,17 +1073,15 @@ | ||
| 1072 | 1073 | font-weight: bold; |
| 1073 | 1074 | white-space: nowrap; |
| 1074 | 1075 | } |
| 1075 | 1076 | |
| 1076 | 1077 | a.timelineHistLink { |
| 1077 | - text-transform: uppercase; | |
| 1078 | + text-transform: lowercase; | |
| 1078 | 1079 | } |
| 1079 | 1080 | |
| 1080 | 1081 | span.timelineComment { |
| 1081 | - /* make the span behave like a div */ | |
| 1082 | - /* padding: 10px 20px;*/ | |
| 1083 | - /* display: block;*/ | |
| 1082 | + padding: 0px 5px; | |
| 1084 | 1083 | } |
| 1085 | 1084 | |
| 1086 | 1085 | |
| 1087 | 1086 | /* Login/Loguot |
| 1088 | 1087 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| @@ -1097,17 +1096,22 @@ | ||
| 1097 | 1096 | table.login_out td { |
| 1098 | 1097 | border: 0; |
| 1099 | 1098 | } |
| 1100 | 1099 | |
| 1101 | 1100 | |
| 1102 | -/* Miscellaneous | |
| 1101 | +/* Diff displays | |
| 1103 | 1102 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1104 | -.udiff, .sbsdiff { | |
| 1105 | - font-size: .85em !important; | |
| 1106 | - overflow: auto; | |
| 1107 | - border: 1px solid #ccc; | |
| 1108 | - border-radius: 5px; | |
| 1103 | +pre.udiff, table.sbsdiffcols { | |
| 1104 | + width: 100%; | |
| 1105 | + overflow: auto; | |
| 1106 | + border: 1px solid #ccc; | |
| 1107 | + padding: 0px 5px; | |
| 1108 | + font-size: 1rem; | |
| 1109 | +} | |
| 1110 | + | |
| 1111 | +pre.udiff:focus, table.sbsdiffcols:focus { | |
| 1112 | + outline: none; | |
| 1109 | 1113 | } |
| 1110 | 1114 | |
| 1111 | 1115 | |
| 1112 | 1116 | /* Ticket Reports |
| 1113 | 1117 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1114 | 1118 |
| --- skins/blitz_no_logo/css.txt | |
| +++ skins/blitz_no_logo/css.txt | |
| @@ -464,11 +464,11 @@ | |
| 464 | font-weight: 400; |
| 465 | color: #ccc; |
| 466 | } |
| 467 | |
| 468 | pre, code { |
| 469 | font-size: 1.3rem; |
| 470 | } |
| 471 | |
| 472 | body { |
| 473 | font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ |
| 474 | line-height: 1.5; |
| @@ -599,10 +599,11 @@ | |
| 599 | -moz-appearance: none; |
| 600 | appearance: none; |
| 601 | } |
| 602 | |
| 603 | textarea { |
| 604 | min-height: 65px; |
| 605 | padding-top: 6px; |
| 606 | padding-bottom: 6px; |
| 607 | } |
| 608 | |
| @@ -857,11 +858,10 @@ | |
| 857 | |
| 858 | .mainmenu li { |
| 859 | outline: 0; |
| 860 | display: block; |
| 861 | float: left; |
| 862 | padding: 10px 15px; |
| 863 | margin: 0; |
| 864 | } |
| 865 | |
| 866 | .mainmenu li.active { |
| 867 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); |
| @@ -868,12 +868,13 @@ | |
| 868 | background-repeat: no-repeat; |
| 869 | background-position: center bottom; |
| 870 | } |
| 871 | |
| 872 | .mainmenu li a { |
| 873 | color: #3b5c6b; |
| 874 | display: block; |
| 875 | } |
| 876 | |
| 877 | .mainmenu li.active a { |
| 878 | font-weight: bold; |
| 879 | } |
| @@ -890,11 +891,11 @@ | |
| 890 | padding: 10px 0px; |
| 891 | border-bottom: 1px solid #ddd; |
| 892 | } |
| 893 | |
| 894 | .submenu input, .submenu select { |
| 895 | margin: 0; |
| 896 | } |
| 897 | |
| 898 | .submenu a { |
| 899 | color: #3b5c6b; |
| 900 | padding: 5px 15px; |
| @@ -1072,17 +1073,15 @@ | |
| 1072 | font-weight: bold; |
| 1073 | white-space: nowrap; |
| 1074 | } |
| 1075 | |
| 1076 | a.timelineHistLink { |
| 1077 | text-transform: uppercase; |
| 1078 | } |
| 1079 | |
| 1080 | span.timelineComment { |
| 1081 | /* make the span behave like a div */ |
| 1082 | /* padding: 10px 20px;*/ |
| 1083 | /* display: block;*/ |
| 1084 | } |
| 1085 | |
| 1086 | |
| 1087 | /* Login/Loguot |
| 1088 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| @@ -1097,17 +1096,22 @@ | |
| 1097 | table.login_out td { |
| 1098 | border: 0; |
| 1099 | } |
| 1100 | |
| 1101 | |
| 1102 | /* Miscellaneous |
| 1103 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1104 | .udiff, .sbsdiff { |
| 1105 | font-size: .85em !important; |
| 1106 | overflow: auto; |
| 1107 | border: 1px solid #ccc; |
| 1108 | border-radius: 5px; |
| 1109 | } |
| 1110 | |
| 1111 | |
| 1112 | /* Ticket Reports |
| 1113 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1114 |
| --- skins/blitz_no_logo/css.txt | |
| +++ skins/blitz_no_logo/css.txt | |
| @@ -464,11 +464,11 @@ | |
| 464 | font-weight: 400; |
| 465 | color: #ccc; |
| 466 | } |
| 467 | |
| 468 | pre, code { |
| 469 | font-size: 1.2rem; |
| 470 | } |
| 471 | |
| 472 | body { |
| 473 | font-size: 1.4em; /* currently ems cause chrome bug misinterpreting rems on body element */ |
| 474 | line-height: 1.5; |
| @@ -599,10 +599,11 @@ | |
| 599 | -moz-appearance: none; |
| 600 | appearance: none; |
| 601 | } |
| 602 | |
| 603 | textarea { |
| 604 | height: inherit; |
| 605 | min-height: 65px; |
| 606 | padding-top: 6px; |
| 607 | padding-bottom: 6px; |
| 608 | } |
| 609 | |
| @@ -857,11 +858,10 @@ | |
| 858 | |
| 859 | .mainmenu li { |
| 860 | outline: 0; |
| 861 | display: block; |
| 862 | float: left; |
| 863 | margin: 0; |
| 864 | } |
| 865 | |
| 866 | .mainmenu li.active { |
| 867 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB90FDxEXAZ2XRzAAAABJSURBVCjPY2CgBzhz5sx/QmoYiTXAxMSEkWRDsLkAl0GMpHoBm0EoAlu3bmUQFxcnGAboBjEhc4gxAJtLGUmJBVwuYiTXAGSDAIx5IBObnuVxAAAAAElFTkSuQmCC); |
| @@ -868,12 +868,13 @@ | |
| 868 | background-repeat: no-repeat; |
| 869 | background-position: center bottom; |
| 870 | } |
| 871 | |
| 872 | .mainmenu li a { |
| 873 | color: #3b5c6b; |
| 874 | display: block; |
| 875 | padding: 10px 15px; |
| 876 | } |
| 877 | |
| 878 | .mainmenu li.active a { |
| 879 | font-weight: bold; |
| 880 | } |
| @@ -890,11 +891,11 @@ | |
| 891 | padding: 10px 0px; |
| 892 | border-bottom: 1px solid #ddd; |
| 893 | } |
| 894 | |
| 895 | .submenu input, .submenu select { |
| 896 | margin: 0 0 0 5px; |
| 897 | } |
| 898 | |
| 899 | .submenu a { |
| 900 | color: #3b5c6b; |
| 901 | padding: 5px 15px; |
| @@ -1072,17 +1073,15 @@ | |
| 1073 | font-weight: bold; |
| 1074 | white-space: nowrap; |
| 1075 | } |
| 1076 | |
| 1077 | a.timelineHistLink { |
| 1078 | text-transform: lowercase; |
| 1079 | } |
| 1080 | |
| 1081 | span.timelineComment { |
| 1082 | padding: 0px 5px; |
| 1083 | } |
| 1084 | |
| 1085 | |
| 1086 | /* Login/Loguot |
| 1087 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| @@ -1097,17 +1096,22 @@ | |
| 1096 | table.login_out td { |
| 1097 | border: 0; |
| 1098 | } |
| 1099 | |
| 1100 | |
| 1101 | /* Diff displays |
| 1102 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1103 | pre.udiff, table.sbsdiffcols { |
| 1104 | width: 100%; |
| 1105 | overflow: auto; |
| 1106 | border: 1px solid #ccc; |
| 1107 | padding: 0px 5px; |
| 1108 | font-size: 1rem; |
| 1109 | } |
| 1110 | |
| 1111 | pre.udiff:focus, table.sbsdiffcols:focus { |
| 1112 | outline: none; |
| 1113 | } |
| 1114 | |
| 1115 | |
| 1116 | /* Ticket Reports |
| 1117 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */ |
| 1118 |
| --- skins/eagle/header.txt | ||
| +++ skins/eagle/header.txt | ||
| @@ -70,15 +70,10 @@ | ||
| 70 | 70 | } |
| 71 | 71 | set logourl [getLogoUrl $baseurl] |
| 72 | 72 | </th1> |
| 73 | 73 | <a href="$logourl"> |
| 74 | 74 | <img src="$logo_image_url" border="0" alt="$project_name"> |
| 75 | - <th1> | |
| 76 | - if {[anycap jor]} { | |
| 77 | - html "<a class='rss' href='$home/timeline.rss'></a>" | |
| 78 | - } | |
| 79 | - </th1> | |
| 80 | 75 | </a> |
| 81 | 76 | </div> |
| 82 | 77 | <div class="title">$<title></div> |
| 83 | 78 | <div class="status"><nobr><th1> |
| 84 | 79 | if {[info exists login]} { |
| 85 | 80 |
| --- skins/eagle/header.txt | |
| +++ skins/eagle/header.txt | |
| @@ -70,15 +70,10 @@ | |
| 70 | } |
| 71 | set logourl [getLogoUrl $baseurl] |
| 72 | </th1> |
| 73 | <a href="$logourl"> |
| 74 | <img src="$logo_image_url" border="0" alt="$project_name"> |
| 75 | <th1> |
| 76 | if {[anycap jor]} { |
| 77 | html "<a class='rss' href='$home/timeline.rss'></a>" |
| 78 | } |
| 79 | </th1> |
| 80 | </a> |
| 81 | </div> |
| 82 | <div class="title">$<title></div> |
| 83 | <div class="status"><nobr><th1> |
| 84 | if {[info exists login]} { |
| 85 |
| --- skins/eagle/header.txt | |
| +++ skins/eagle/header.txt | |
| @@ -70,15 +70,10 @@ | |
| 70 | } |
| 71 | set logourl [getLogoUrl $baseurl] |
| 72 | </th1> |
| 73 | <a href="$logourl"> |
| 74 | <img src="$logo_image_url" border="0" alt="$project_name"> |
| 75 | </a> |
| 76 | </div> |
| 77 | <div class="title">$<title></div> |
| 78 | <div class="status"><nobr><th1> |
| 79 | if {[info exists login]} { |
| 80 |
| --- skins/enhanced1/header.txt | ||
| +++ skins/enhanced1/header.txt | ||
| @@ -70,15 +70,10 @@ | ||
| 70 | 70 | } |
| 71 | 71 | set logourl [getLogoUrl $baseurl] |
| 72 | 72 | </th1> |
| 73 | 73 | <a href="$logourl"> |
| 74 | 74 | <img src="$logo_image_url" border="0" alt="$project_name"> |
| 75 | - <th1> | |
| 76 | - if {[anycap jor]} { | |
| 77 | - html "<a class='rss' href='$home/timeline.rss'></a>" | |
| 78 | - } | |
| 79 | - </th1> | |
| 80 | 75 | </a> |
| 81 | 76 | </div> |
| 82 | 77 | <div class="title">$<title></div> |
| 83 | 78 | <div class="status"><th1> |
| 84 | 79 | if {[info exists login]} { |
| 85 | 80 |
| --- skins/enhanced1/header.txt | |
| +++ skins/enhanced1/header.txt | |
| @@ -70,15 +70,10 @@ | |
| 70 | } |
| 71 | set logourl [getLogoUrl $baseurl] |
| 72 | </th1> |
| 73 | <a href="$logourl"> |
| 74 | <img src="$logo_image_url" border="0" alt="$project_name"> |
| 75 | <th1> |
| 76 | if {[anycap jor]} { |
| 77 | html "<a class='rss' href='$home/timeline.rss'></a>" |
| 78 | } |
| 79 | </th1> |
| 80 | </a> |
| 81 | </div> |
| 82 | <div class="title">$<title></div> |
| 83 | <div class="status"><th1> |
| 84 | if {[info exists login]} { |
| 85 |
| --- skins/enhanced1/header.txt | |
| +++ skins/enhanced1/header.txt | |
| @@ -70,15 +70,10 @@ | |
| 70 | } |
| 71 | set logourl [getLogoUrl $baseurl] |
| 72 | </th1> |
| 73 | <a href="$logourl"> |
| 74 | <img src="$logo_image_url" border="0" alt="$project_name"> |
| 75 | </a> |
| 76 | </div> |
| 77 | <div class="title">$<title></div> |
| 78 | <div class="status"><th1> |
| 79 | if {[info exists login]} { |
| 80 |
+2
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -306,10 +306,11 @@ | ||
| 306 | 306 | zCleanFlag = db_get("clean-glob", 0); |
| 307 | 307 | } |
| 308 | 308 | if( zIgnoreFlag==0 ){ |
| 309 | 309 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 310 | 310 | } |
| 311 | + if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; | |
| 311 | 312 | vid = db_lget_int("checkout",0); |
| 312 | 313 | db_begin_transaction(); |
| 313 | 314 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 314 | 315 | filename_collation()); |
| 315 | 316 | pClean = glob_create(zCleanFlag); |
| @@ -646,10 +647,11 @@ | ||
| 646 | 647 | zCleanFlag = db_get("clean-glob", 0); |
| 647 | 648 | } |
| 648 | 649 | if( zIgnoreFlag==0 ){ |
| 649 | 650 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 650 | 651 | } |
| 652 | + if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; | |
| 651 | 653 | vid = db_lget_int("checkout",0); |
| 652 | 654 | db_begin_transaction(); |
| 653 | 655 | |
| 654 | 656 | /* step 1: |
| 655 | 657 | ** Populate the temp table "sfile" with the names of all unmanaged |
| 656 | 658 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -306,10 +306,11 @@ | |
| 306 | zCleanFlag = db_get("clean-glob", 0); |
| 307 | } |
| 308 | if( zIgnoreFlag==0 ){ |
| 309 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 310 | } |
| 311 | vid = db_lget_int("checkout",0); |
| 312 | db_begin_transaction(); |
| 313 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 314 | filename_collation()); |
| 315 | pClean = glob_create(zCleanFlag); |
| @@ -646,10 +647,11 @@ | |
| 646 | zCleanFlag = db_get("clean-glob", 0); |
| 647 | } |
| 648 | if( zIgnoreFlag==0 ){ |
| 649 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 650 | } |
| 651 | vid = db_lget_int("checkout",0); |
| 652 | db_begin_transaction(); |
| 653 | |
| 654 | /* step 1: |
| 655 | ** Populate the temp table "sfile" with the names of all unmanaged |
| 656 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -306,10 +306,11 @@ | |
| 306 | zCleanFlag = db_get("clean-glob", 0); |
| 307 | } |
| 308 | if( zIgnoreFlag==0 ){ |
| 309 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 310 | } |
| 311 | if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; |
| 312 | vid = db_lget_int("checkout",0); |
| 313 | db_begin_transaction(); |
| 314 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 315 | filename_collation()); |
| 316 | pClean = glob_create(zCleanFlag); |
| @@ -646,10 +647,11 @@ | |
| 647 | zCleanFlag = db_get("clean-glob", 0); |
| 648 | } |
| 649 | if( zIgnoreFlag==0 ){ |
| 650 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 651 | } |
| 652 | if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; |
| 653 | vid = db_lget_int("checkout",0); |
| 654 | db_begin_transaction(); |
| 655 | |
| 656 | /* step 1: |
| 657 | ** Populate the temp table "sfile" with the names of all unmanaged |
| 658 |
+2
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -306,10 +306,11 @@ | ||
| 306 | 306 | zCleanFlag = db_get("clean-glob", 0); |
| 307 | 307 | } |
| 308 | 308 | if( zIgnoreFlag==0 ){ |
| 309 | 309 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 310 | 310 | } |
| 311 | + if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; | |
| 311 | 312 | vid = db_lget_int("checkout",0); |
| 312 | 313 | db_begin_transaction(); |
| 313 | 314 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 314 | 315 | filename_collation()); |
| 315 | 316 | pClean = glob_create(zCleanFlag); |
| @@ -646,10 +647,11 @@ | ||
| 646 | 647 | zCleanFlag = db_get("clean-glob", 0); |
| 647 | 648 | } |
| 648 | 649 | if( zIgnoreFlag==0 ){ |
| 649 | 650 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 650 | 651 | } |
| 652 | + if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; | |
| 651 | 653 | vid = db_lget_int("checkout",0); |
| 652 | 654 | db_begin_transaction(); |
| 653 | 655 | |
| 654 | 656 | /* step 1: |
| 655 | 657 | ** Populate the temp table "sfile" with the names of all unmanaged |
| 656 | 658 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -306,10 +306,11 @@ | |
| 306 | zCleanFlag = db_get("clean-glob", 0); |
| 307 | } |
| 308 | if( zIgnoreFlag==0 ){ |
| 309 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 310 | } |
| 311 | vid = db_lget_int("checkout",0); |
| 312 | db_begin_transaction(); |
| 313 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 314 | filename_collation()); |
| 315 | pClean = glob_create(zCleanFlag); |
| @@ -646,10 +647,11 @@ | |
| 646 | zCleanFlag = db_get("clean-glob", 0); |
| 647 | } |
| 648 | if( zIgnoreFlag==0 ){ |
| 649 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 650 | } |
| 651 | vid = db_lget_int("checkout",0); |
| 652 | db_begin_transaction(); |
| 653 | |
| 654 | /* step 1: |
| 655 | ** Populate the temp table "sfile" with the names of all unmanaged |
| 656 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -306,10 +306,11 @@ | |
| 306 | zCleanFlag = db_get("clean-glob", 0); |
| 307 | } |
| 308 | if( zIgnoreFlag==0 ){ |
| 309 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 310 | } |
| 311 | if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; |
| 312 | vid = db_lget_int("checkout",0); |
| 313 | db_begin_transaction(); |
| 314 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)", |
| 315 | filename_collation()); |
| 316 | pClean = glob_create(zCleanFlag); |
| @@ -646,10 +647,11 @@ | |
| 647 | zCleanFlag = db_get("clean-glob", 0); |
| 648 | } |
| 649 | if( zIgnoreFlag==0 ){ |
| 650 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 651 | } |
| 652 | if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; |
| 653 | vid = db_lget_int("checkout",0); |
| 654 | db_begin_transaction(); |
| 655 | |
| 656 | /* step 1: |
| 657 | ** Populate the temp table "sfile" with the names of all unmanaged |
| 658 |
+8
| --- src/cache.c | ||
| +++ src/cache.c | ||
| @@ -226,10 +226,18 @@ | ||
| 226 | 226 | cache_read_done: |
| 227 | 227 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 228 | 228 | sqlite3_close(db); |
| 229 | 229 | return rc; |
| 230 | 230 | } |
| 231 | + | |
| 232 | +/* | |
| 233 | +** Create a cache database for the current repository if no such | |
| 234 | +** database already exists. | |
| 235 | +*/ | |
| 236 | +void cache_initialize(void){ | |
| 237 | + sqlite3_close(cacheOpen(1)); | |
| 238 | +} | |
| 231 | 239 | |
| 232 | 240 | /* |
| 233 | 241 | ** COMMAND: cache* |
| 234 | 242 | ** Usage: %fossil cache SUBCOMMAND |
| 235 | 243 | ** |
| 236 | 244 |
| --- src/cache.c | |
| +++ src/cache.c | |
| @@ -226,10 +226,18 @@ | |
| 226 | cache_read_done: |
| 227 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 228 | sqlite3_close(db); |
| 229 | return rc; |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | ** COMMAND: cache* |
| 234 | ** Usage: %fossil cache SUBCOMMAND |
| 235 | ** |
| 236 |
| --- src/cache.c | |
| +++ src/cache.c | |
| @@ -226,10 +226,18 @@ | |
| 226 | cache_read_done: |
| 227 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 228 | sqlite3_close(db); |
| 229 | return rc; |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | ** Create a cache database for the current repository if no such |
| 234 | ** database already exists. |
| 235 | */ |
| 236 | void cache_initialize(void){ |
| 237 | sqlite3_close(cacheOpen(1)); |
| 238 | } |
| 239 | |
| 240 | /* |
| 241 | ** COMMAND: cache* |
| 242 | ** Usage: %fossil cache SUBCOMMAND |
| 243 | ** |
| 244 |
+3
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -571,10 +571,12 @@ | ||
| 571 | 571 | |
| 572 | 572 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| 573 | 573 | db_must_be_within_tree(); |
| 574 | 574 | cwdRelative = determine_cwd_relative_option(); |
| 575 | 575 | |
| 576 | + if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; | |
| 577 | + | |
| 576 | 578 | /* We should be done with options.. */ |
| 577 | 579 | verify_all_options(); |
| 578 | 580 | |
| 579 | 581 | if( zIgnoreFlag==0 ){ |
| 580 | 582 | zIgnoreFlag = db_get("ignore-glob", 0); |
| @@ -707,10 +709,11 @@ | ||
| 707 | 709 | zKeepFlag = db_get("keep-glob", 0); |
| 708 | 710 | } |
| 709 | 711 | if( zCleanFlag==0 ){ |
| 710 | 712 | zCleanFlag = db_get("clean-glob", 0); |
| 711 | 713 | } |
| 714 | + if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; | |
| 712 | 715 | verify_all_options(); |
| 713 | 716 | pIgnore = glob_create(zIgnoreFlag); |
| 714 | 717 | pKeep = glob_create(zKeepFlag); |
| 715 | 718 | pClean = glob_create(zCleanFlag); |
| 716 | 719 | nRoot = (int)strlen(g.zLocalRoot); |
| 717 | 720 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -571,10 +571,12 @@ | |
| 571 | |
| 572 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| 573 | db_must_be_within_tree(); |
| 574 | cwdRelative = determine_cwd_relative_option(); |
| 575 | |
| 576 | /* We should be done with options.. */ |
| 577 | verify_all_options(); |
| 578 | |
| 579 | if( zIgnoreFlag==0 ){ |
| 580 | zIgnoreFlag = db_get("ignore-glob", 0); |
| @@ -707,10 +709,11 @@ | |
| 707 | zKeepFlag = db_get("keep-glob", 0); |
| 708 | } |
| 709 | if( zCleanFlag==0 ){ |
| 710 | zCleanFlag = db_get("clean-glob", 0); |
| 711 | } |
| 712 | verify_all_options(); |
| 713 | pIgnore = glob_create(zIgnoreFlag); |
| 714 | pKeep = glob_create(zKeepFlag); |
| 715 | pClean = glob_create(zCleanFlag); |
| 716 | nRoot = (int)strlen(g.zLocalRoot); |
| 717 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -571,10 +571,12 @@ | |
| 571 | |
| 572 | if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP; |
| 573 | db_must_be_within_tree(); |
| 574 | cwdRelative = determine_cwd_relative_option(); |
| 575 | |
| 576 | if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; |
| 577 | |
| 578 | /* We should be done with options.. */ |
| 579 | verify_all_options(); |
| 580 | |
| 581 | if( zIgnoreFlag==0 ){ |
| 582 | zIgnoreFlag = db_get("ignore-glob", 0); |
| @@ -707,10 +709,11 @@ | |
| 709 | zKeepFlag = db_get("keep-glob", 0); |
| 710 | } |
| 711 | if( zCleanFlag==0 ){ |
| 712 | zCleanFlag = db_get("clean-glob", 0); |
| 713 | } |
| 714 | if( db_get_boolean("dotfiles", 0) ) scanFlags |= SCAN_ALL; |
| 715 | verify_all_options(); |
| 716 | pIgnore = glob_create(zIgnoreFlag); |
| 717 | pKeep = glob_create(zKeepFlag); |
| 718 | pClean = glob_create(zCleanFlag); |
| 719 | nRoot = (int)strlen(g.zLocalRoot); |
| 720 |
+2
-1
| --- src/clone.c | ||
| +++ src/clone.c | ||
| @@ -164,11 +164,11 @@ | ||
| 164 | 164 | }else{ |
| 165 | 165 | db_create_repository(g.argv[3]); |
| 166 | 166 | db_open_repository(g.argv[3]); |
| 167 | 167 | db_begin_transaction(); |
| 168 | 168 | db_record_repository_filename(g.argv[3]); |
| 169 | - db_initial_setup(0, 0, zDefaultUser, 0); | |
| 169 | + db_initial_setup(0, 0, zDefaultUser); | |
| 170 | 170 | user_select(); |
| 171 | 171 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 172 | 172 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 173 | 173 | db_set("rebuilt", get_version(), 0); |
| 174 | 174 | remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]); |
| @@ -182,10 +182,11 @@ | ||
| 182 | 182 | blob_reset(&fn); |
| 183 | 183 | } |
| 184 | 184 | db_multi_exec( |
| 185 | 185 | "REPLACE INTO config(name,value,mtime)" |
| 186 | 186 | " VALUES('server-code', lower(hex(randomblob(20))), now());" |
| 187 | + "DELETE FROM config WHERE name='project-code';" | |
| 187 | 188 | ); |
| 188 | 189 | url_enable_proxy(0); |
| 189 | 190 | clone_ssh_db_set_options(); |
| 190 | 191 | url_get_password_if_needed(); |
| 191 | 192 | g.xlinkClusterOnly = 1; |
| 192 | 193 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -164,11 +164,11 @@ | |
| 164 | }else{ |
| 165 | db_create_repository(g.argv[3]); |
| 166 | db_open_repository(g.argv[3]); |
| 167 | db_begin_transaction(); |
| 168 | db_record_repository_filename(g.argv[3]); |
| 169 | db_initial_setup(0, 0, zDefaultUser, 0); |
| 170 | user_select(); |
| 171 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 172 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 173 | db_set("rebuilt", get_version(), 0); |
| 174 | remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]); |
| @@ -182,10 +182,11 @@ | |
| 182 | blob_reset(&fn); |
| 183 | } |
| 184 | db_multi_exec( |
| 185 | "REPLACE INTO config(name,value,mtime)" |
| 186 | " VALUES('server-code', lower(hex(randomblob(20))), now());" |
| 187 | ); |
| 188 | url_enable_proxy(0); |
| 189 | clone_ssh_db_set_options(); |
| 190 | url_get_password_if_needed(); |
| 191 | g.xlinkClusterOnly = 1; |
| 192 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -164,11 +164,11 @@ | |
| 164 | }else{ |
| 165 | db_create_repository(g.argv[3]); |
| 166 | db_open_repository(g.argv[3]); |
| 167 | db_begin_transaction(); |
| 168 | db_record_repository_filename(g.argv[3]); |
| 169 | db_initial_setup(0, 0, zDefaultUser); |
| 170 | user_select(); |
| 171 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 172 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 173 | db_set("rebuilt", get_version(), 0); |
| 174 | remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]); |
| @@ -182,10 +182,11 @@ | |
| 182 | blob_reset(&fn); |
| 183 | } |
| 184 | db_multi_exec( |
| 185 | "REPLACE INTO config(name,value,mtime)" |
| 186 | " VALUES('server-code', lower(hex(randomblob(20))), now());" |
| 187 | "DELETE FROM config WHERE name='project-code';" |
| 188 | ); |
| 189 | url_enable_proxy(0); |
| 190 | clone_ssh_db_set_options(); |
| 191 | url_get_password_if_needed(); |
| 192 | g.xlinkClusterOnly = 1; |
| 193 |
+3
-1
| --- src/configure.c | ||
| +++ src/configure.c | ||
| @@ -97,10 +97,11 @@ | ||
| 97 | 97 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 98 | 98 | { "adunit", CONFIGSET_SKIN }, |
| 99 | 99 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 100 | 100 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 101 | 101 | { "white-foreground", CONFIGSET_SKIN }, |
| 102 | + | |
| 102 | 103 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 103 | 104 | { "th1-docs", CONFIGSET_TH1 }, |
| 104 | 105 | #endif |
| 105 | 106 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 106 | 107 | { "th1-hooks", CONFIGSET_TH1 }, |
| @@ -124,10 +125,11 @@ | ||
| 124 | 125 | { "keep-glob", CONFIGSET_PROJ }, |
| 125 | 126 | { "crnl-glob", CONFIGSET_PROJ }, |
| 126 | 127 | { "encoding-glob", CONFIGSET_PROJ }, |
| 127 | 128 | { "empty-dirs", CONFIGSET_PROJ }, |
| 128 | 129 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 130 | + { "dotfiles", CONFIGSET_PROJ }, | |
| 129 | 131 | |
| 130 | 132 | #ifdef FOSSIL_ENABLE_LEGACY_MV_RM |
| 131 | 133 | { "move-files", CONFIGSET_PROJ }, |
| 132 | 134 | { "remove-files", CONFIGSET_PROJ }, |
| 133 | 135 | #endif |
| @@ -862,11 +864,11 @@ | ||
| 862 | 864 | ** |
| 863 | 865 | ** Push the local configuration into the remote server identified |
| 864 | 866 | ** by URL. Admin privilege is required on the remote server for |
| 865 | 867 | ** this to work. When the same record exists both locally and on |
| 866 | 868 | ** the remote end, the one that was most recently changed wins. |
| 867 | -** Use the --legacy flag when talking to holder servers. | |
| 869 | +** Use the --legacy flag when talking to older servers. | |
| 868 | 870 | ** |
| 869 | 871 | ** %fossil configuration reset AREA |
| 870 | 872 | ** |
| 871 | 873 | ** Restore the configuration to the default. AREA as above. |
| 872 | 874 | ** |
| 873 | 875 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -97,10 +97,11 @@ | |
| 97 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 98 | { "adunit", CONFIGSET_SKIN }, |
| 99 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 100 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 101 | { "white-foreground", CONFIGSET_SKIN }, |
| 102 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 103 | { "th1-docs", CONFIGSET_TH1 }, |
| 104 | #endif |
| 105 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 106 | { "th1-hooks", CONFIGSET_TH1 }, |
| @@ -124,10 +125,11 @@ | |
| 124 | { "keep-glob", CONFIGSET_PROJ }, |
| 125 | { "crnl-glob", CONFIGSET_PROJ }, |
| 126 | { "encoding-glob", CONFIGSET_PROJ }, |
| 127 | { "empty-dirs", CONFIGSET_PROJ }, |
| 128 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 129 | |
| 130 | #ifdef FOSSIL_ENABLE_LEGACY_MV_RM |
| 131 | { "move-files", CONFIGSET_PROJ }, |
| 132 | { "remove-files", CONFIGSET_PROJ }, |
| 133 | #endif |
| @@ -862,11 +864,11 @@ | |
| 862 | ** |
| 863 | ** Push the local configuration into the remote server identified |
| 864 | ** by URL. Admin privilege is required on the remote server for |
| 865 | ** this to work. When the same record exists both locally and on |
| 866 | ** the remote end, the one that was most recently changed wins. |
| 867 | ** Use the --legacy flag when talking to holder servers. |
| 868 | ** |
| 869 | ** %fossil configuration reset AREA |
| 870 | ** |
| 871 | ** Restore the configuration to the default. AREA as above. |
| 872 | ** |
| 873 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -97,10 +97,11 @@ | |
| 97 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 98 | { "adunit", CONFIGSET_SKIN }, |
| 99 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 100 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 101 | { "white-foreground", CONFIGSET_SKIN }, |
| 102 | |
| 103 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 104 | { "th1-docs", CONFIGSET_TH1 }, |
| 105 | #endif |
| 106 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 107 | { "th1-hooks", CONFIGSET_TH1 }, |
| @@ -124,10 +125,11 @@ | |
| 125 | { "keep-glob", CONFIGSET_PROJ }, |
| 126 | { "crnl-glob", CONFIGSET_PROJ }, |
| 127 | { "encoding-glob", CONFIGSET_PROJ }, |
| 128 | { "empty-dirs", CONFIGSET_PROJ }, |
| 129 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 130 | { "dotfiles", CONFIGSET_PROJ }, |
| 131 | |
| 132 | #ifdef FOSSIL_ENABLE_LEGACY_MV_RM |
| 133 | { "move-files", CONFIGSET_PROJ }, |
| 134 | { "remove-files", CONFIGSET_PROJ }, |
| 135 | #endif |
| @@ -862,11 +864,11 @@ | |
| 864 | ** |
| 865 | ** Push the local configuration into the remote server identified |
| 866 | ** by URL. Admin privilege is required on the remote server for |
| 867 | ** this to work. When the same record exists both locally and on |
| 868 | ** the remote end, the one that was most recently changed wins. |
| 869 | ** Use the --legacy flag when talking to older servers. |
| 870 | ** |
| 871 | ** %fossil configuration reset AREA |
| 872 | ** |
| 873 | ** Restore the configuration to the default. AREA as above. |
| 874 | ** |
| 875 |
+3
-1
| --- src/configure.c | ||
| +++ src/configure.c | ||
| @@ -97,10 +97,11 @@ | ||
| 97 | 97 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 98 | 98 | { "adunit", CONFIGSET_SKIN }, |
| 99 | 99 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 100 | 100 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 101 | 101 | { "white-foreground", CONFIGSET_SKIN }, |
| 102 | + | |
| 102 | 103 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 103 | 104 | { "th1-docs", CONFIGSET_TH1 }, |
| 104 | 105 | #endif |
| 105 | 106 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 106 | 107 | { "th1-hooks", CONFIGSET_TH1 }, |
| @@ -124,10 +125,11 @@ | ||
| 124 | 125 | { "keep-glob", CONFIGSET_PROJ }, |
| 125 | 126 | { "crnl-glob", CONFIGSET_PROJ }, |
| 126 | 127 | { "encoding-glob", CONFIGSET_PROJ }, |
| 127 | 128 | { "empty-dirs", CONFIGSET_PROJ }, |
| 128 | 129 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 130 | + { "dotfiles", CONFIGSET_PROJ }, | |
| 129 | 131 | |
| 130 | 132 | #ifdef FOSSIL_ENABLE_LEGACY_MV_RM |
| 131 | 133 | { "move-files", CONFIGSET_PROJ }, |
| 132 | 134 | { "remove-files", CONFIGSET_PROJ }, |
| 133 | 135 | #endif |
| @@ -862,11 +864,11 @@ | ||
| 862 | 864 | ** |
| 863 | 865 | ** Push the local configuration into the remote server identified |
| 864 | 866 | ** by URL. Admin privilege is required on the remote server for |
| 865 | 867 | ** this to work. When the same record exists both locally and on |
| 866 | 868 | ** the remote end, the one that was most recently changed wins. |
| 867 | -** Use the --legacy flag when talking to holder servers. | |
| 869 | +** Use the --legacy flag when talking to older servers. | |
| 868 | 870 | ** |
| 869 | 871 | ** %fossil configuration reset AREA |
| 870 | 872 | ** |
| 871 | 873 | ** Restore the configuration to the default. AREA as above. |
| 872 | 874 | ** |
| 873 | 875 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -97,10 +97,11 @@ | |
| 97 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 98 | { "adunit", CONFIGSET_SKIN }, |
| 99 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 100 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 101 | { "white-foreground", CONFIGSET_SKIN }, |
| 102 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 103 | { "th1-docs", CONFIGSET_TH1 }, |
| 104 | #endif |
| 105 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 106 | { "th1-hooks", CONFIGSET_TH1 }, |
| @@ -124,10 +125,11 @@ | |
| 124 | { "keep-glob", CONFIGSET_PROJ }, |
| 125 | { "crnl-glob", CONFIGSET_PROJ }, |
| 126 | { "encoding-glob", CONFIGSET_PROJ }, |
| 127 | { "empty-dirs", CONFIGSET_PROJ }, |
| 128 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 129 | |
| 130 | #ifdef FOSSIL_ENABLE_LEGACY_MV_RM |
| 131 | { "move-files", CONFIGSET_PROJ }, |
| 132 | { "remove-files", CONFIGSET_PROJ }, |
| 133 | #endif |
| @@ -862,11 +864,11 @@ | |
| 862 | ** |
| 863 | ** Push the local configuration into the remote server identified |
| 864 | ** by URL. Admin privilege is required on the remote server for |
| 865 | ** this to work. When the same record exists both locally and on |
| 866 | ** the remote end, the one that was most recently changed wins. |
| 867 | ** Use the --legacy flag when talking to holder servers. |
| 868 | ** |
| 869 | ** %fossil configuration reset AREA |
| 870 | ** |
| 871 | ** Restore the configuration to the default. AREA as above. |
| 872 | ** |
| 873 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -97,10 +97,11 @@ | |
| 97 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 98 | { "adunit", CONFIGSET_SKIN }, |
| 99 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 100 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 101 | { "white-foreground", CONFIGSET_SKIN }, |
| 102 | |
| 103 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 104 | { "th1-docs", CONFIGSET_TH1 }, |
| 105 | #endif |
| 106 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 107 | { "th1-hooks", CONFIGSET_TH1 }, |
| @@ -124,10 +125,11 @@ | |
| 125 | { "keep-glob", CONFIGSET_PROJ }, |
| 126 | { "crnl-glob", CONFIGSET_PROJ }, |
| 127 | { "encoding-glob", CONFIGSET_PROJ }, |
| 128 | { "empty-dirs", CONFIGSET_PROJ }, |
| 129 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 130 | { "dotfiles", CONFIGSET_PROJ }, |
| 131 | |
| 132 | #ifdef FOSSIL_ENABLE_LEGACY_MV_RM |
| 133 | { "move-files", CONFIGSET_PROJ }, |
| 134 | { "remove-files", CONFIGSET_PROJ }, |
| 135 | #endif |
| @@ -862,11 +864,11 @@ | |
| 864 | ** |
| 865 | ** Push the local configuration into the remote server identified |
| 866 | ** by URL. Admin privilege is required on the remote server for |
| 867 | ** this to work. When the same record exists both locally and on |
| 868 | ** the remote end, the one that was most recently changed wins. |
| 869 | ** Use the --legacy flag when talking to older servers. |
| 870 | ** |
| 871 | ** %fossil configuration reset AREA |
| 872 | ** |
| 873 | ** Restore the configuration to the default. AREA as above. |
| 874 | ** |
| 875 |
M
src/db.c
+11
-38
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1475,42 +1475,10 @@ | ||
| 1475 | 1475 | " VALUES('reader','','kptw','Reader');" |
| 1476 | 1476 | ); |
| 1477 | 1477 | } |
| 1478 | 1478 | } |
| 1479 | 1479 | |
| 1480 | -/* | |
| 1481 | -** This function sets the server and project codes if they do not already | |
| 1482 | -** exist. Currently, it should be called only by the db_initial_setup() | |
| 1483 | -** or cmd_webserver() functions, the latter being used to facilitate more | |
| 1484 | -** robust integration with "canned image" environments (e.g. Docker). | |
| 1485 | -*/ | |
| 1486 | -void db_setup_server_and_project_codes( | |
| 1487 | - int optional | |
| 1488 | -){ | |
| 1489 | - if( !optional ){ | |
| 1490 | - db_multi_exec( | |
| 1491 | - "INSERT INTO config(name,value,mtime)" | |
| 1492 | - " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 1493 | - "INSERT INTO config(name,value,mtime)" | |
| 1494 | - " VALUES('project-code', lower(hex(randomblob(20))),now());" | |
| 1495 | - ); | |
| 1496 | - }else if( db_is_writeable("repository") ){ | |
| 1497 | - if( db_get("server-code", 0)==0 ) { | |
| 1498 | - db_multi_exec( | |
| 1499 | - "INSERT INTO config(name,value,mtime)" | |
| 1500 | - " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 1501 | - ); | |
| 1502 | - } | |
| 1503 | - if( db_get("project-code", 0)==0 ) { | |
| 1504 | - db_multi_exec( | |
| 1505 | - "INSERT INTO config(name,value,mtime)" | |
| 1506 | - " VALUES('project-code', lower(hex(randomblob(20))),now());" | |
| 1507 | - ); | |
| 1508 | - } | |
| 1509 | - } | |
| 1510 | -} | |
| 1511 | - | |
| 1512 | 1480 | /* |
| 1513 | 1481 | ** Return a pointer to a string that contains the RHS of an IN operator |
| 1514 | 1482 | ** that will select CONFIG table names that are in the list of control |
| 1515 | 1483 | ** settings. |
| 1516 | 1484 | */ |
| @@ -1548,23 +1516,25 @@ | ||
| 1548 | 1516 | ** not server and project codes are invented for this repository. |
| 1549 | 1517 | */ |
| 1550 | 1518 | void db_initial_setup( |
| 1551 | 1519 | const char *zTemplate, /* Repository from which to copy settings. */ |
| 1552 | 1520 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ |
| 1553 | - const char *zDefaultUser, /* Default user for the repository */ | |
| 1554 | - int makeServerCodes /* True to make new server & project codes */ | |
| 1521 | + const char *zDefaultUser /* Default user for the repository */ | |
| 1555 | 1522 | ){ |
| 1556 | 1523 | char *zDate; |
| 1557 | 1524 | Blob hash; |
| 1558 | 1525 | Blob manifest; |
| 1559 | 1526 | |
| 1560 | 1527 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1561 | 1528 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 1562 | 1529 | db_set("rebuilt", get_version(), 0); |
| 1563 | - if( makeServerCodes ){ | |
| 1564 | - db_setup_server_and_project_codes(0); | |
| 1565 | - } | |
| 1530 | + db_multi_exec( | |
| 1531 | + "INSERT INTO config(name,value,mtime)" | |
| 1532 | + " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 1533 | + "INSERT INTO config(name,value,mtime)" | |
| 1534 | + " VALUES('project-code', lower(hex(randomblob(20))),now());" | |
| 1535 | + ); | |
| 1566 | 1536 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1567 | 1537 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1568 | 1538 | if( !db_is_global("timeline-plaintext") ){ |
| 1569 | 1539 | db_set_int("timeline-plaintext", 1, 0); |
| 1570 | 1540 | } |
| @@ -1687,11 +1657,11 @@ | ||
| 1687 | 1657 | db_open_repository(g.argv[2]); |
| 1688 | 1658 | db_open_config(0); |
| 1689 | 1659 | if( zTemplate ) db_attach(zTemplate, "settingSrc"); |
| 1690 | 1660 | db_begin_transaction(); |
| 1691 | 1661 | if( zDate==0 ) zDate = "now"; |
| 1692 | - db_initial_setup(zTemplate, zDate, zDefaultUser, 1); | |
| 1662 | + db_initial_setup(zTemplate, zDate, zDefaultUser); | |
| 1693 | 1663 | db_end_transaction(0); |
| 1694 | 1664 | if( zTemplate ) db_detach("settingSrc"); |
| 1695 | 1665 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 1696 | 1666 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 1697 | 1667 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| @@ -2375,10 +2345,11 @@ | ||
| 2375 | 2345 | { "crnl-glob", 0, 40, 1, 0, "" }, |
| 2376 | 2346 | { "default-perms", 0, 16, 0, 0, "u" }, |
| 2377 | 2347 | { "diff-binary", 0, 0, 0, 0, "on" }, |
| 2378 | 2348 | { "diff-command", 0, 40, 0, 0, "" }, |
| 2379 | 2349 | { "dont-push", 0, 0, 0, 0, "off" }, |
| 2350 | + { "dotfiles", 0, 0, 0, 0, "off" }, | |
| 2380 | 2351 | { "editor", 0, 32, 0, 0, "" }, |
| 2381 | 2352 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2382 | 2353 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2383 | 2354 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2384 | 2355 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| @@ -2541,10 +2512,12 @@ | ||
| 2541 | 2512 | ** diff-command External command to run when performing a diff. |
| 2542 | 2513 | ** If undefined, the internal text diff will be used. |
| 2543 | 2514 | ** |
| 2544 | 2515 | ** dont-push Prevent this repository from pushing from client to |
| 2545 | 2516 | ** server. Useful when setting up a private branch. |
| 2517 | +** | |
| 2518 | +** dotfiles Include --dotfiles option for all compatible commands. | |
| 2546 | 2519 | ** |
| 2547 | 2520 | ** editor Text editor command used for check-in comments. |
| 2548 | 2521 | ** |
| 2549 | 2522 | ** empty-dirs A comma or newline-separated list of pathnames. On |
| 2550 | 2523 | ** (versionable) update and checkout commands, if no file or directory |
| 2551 | 2524 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1475,42 +1475,10 @@ | |
| 1475 | " VALUES('reader','','kptw','Reader');" |
| 1476 | ); |
| 1477 | } |
| 1478 | } |
| 1479 | |
| 1480 | /* |
| 1481 | ** This function sets the server and project codes if they do not already |
| 1482 | ** exist. Currently, it should be called only by the db_initial_setup() |
| 1483 | ** or cmd_webserver() functions, the latter being used to facilitate more |
| 1484 | ** robust integration with "canned image" environments (e.g. Docker). |
| 1485 | */ |
| 1486 | void db_setup_server_and_project_codes( |
| 1487 | int optional |
| 1488 | ){ |
| 1489 | if( !optional ){ |
| 1490 | db_multi_exec( |
| 1491 | "INSERT INTO config(name,value,mtime)" |
| 1492 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 1493 | "INSERT INTO config(name,value,mtime)" |
| 1494 | " VALUES('project-code', lower(hex(randomblob(20))),now());" |
| 1495 | ); |
| 1496 | }else if( db_is_writeable("repository") ){ |
| 1497 | if( db_get("server-code", 0)==0 ) { |
| 1498 | db_multi_exec( |
| 1499 | "INSERT INTO config(name,value,mtime)" |
| 1500 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 1501 | ); |
| 1502 | } |
| 1503 | if( db_get("project-code", 0)==0 ) { |
| 1504 | db_multi_exec( |
| 1505 | "INSERT INTO config(name,value,mtime)" |
| 1506 | " VALUES('project-code', lower(hex(randomblob(20))),now());" |
| 1507 | ); |
| 1508 | } |
| 1509 | } |
| 1510 | } |
| 1511 | |
| 1512 | /* |
| 1513 | ** Return a pointer to a string that contains the RHS of an IN operator |
| 1514 | ** that will select CONFIG table names that are in the list of control |
| 1515 | ** settings. |
| 1516 | */ |
| @@ -1548,23 +1516,25 @@ | |
| 1548 | ** not server and project codes are invented for this repository. |
| 1549 | */ |
| 1550 | void db_initial_setup( |
| 1551 | const char *zTemplate, /* Repository from which to copy settings. */ |
| 1552 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ |
| 1553 | const char *zDefaultUser, /* Default user for the repository */ |
| 1554 | int makeServerCodes /* True to make new server & project codes */ |
| 1555 | ){ |
| 1556 | char *zDate; |
| 1557 | Blob hash; |
| 1558 | Blob manifest; |
| 1559 | |
| 1560 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1561 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 1562 | db_set("rebuilt", get_version(), 0); |
| 1563 | if( makeServerCodes ){ |
| 1564 | db_setup_server_and_project_codes(0); |
| 1565 | } |
| 1566 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1567 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1568 | if( !db_is_global("timeline-plaintext") ){ |
| 1569 | db_set_int("timeline-plaintext", 1, 0); |
| 1570 | } |
| @@ -1687,11 +1657,11 @@ | |
| 1687 | db_open_repository(g.argv[2]); |
| 1688 | db_open_config(0); |
| 1689 | if( zTemplate ) db_attach(zTemplate, "settingSrc"); |
| 1690 | db_begin_transaction(); |
| 1691 | if( zDate==0 ) zDate = "now"; |
| 1692 | db_initial_setup(zTemplate, zDate, zDefaultUser, 1); |
| 1693 | db_end_transaction(0); |
| 1694 | if( zTemplate ) db_detach("settingSrc"); |
| 1695 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 1696 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 1697 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| @@ -2375,10 +2345,11 @@ | |
| 2375 | { "crnl-glob", 0, 40, 1, 0, "" }, |
| 2376 | { "default-perms", 0, 16, 0, 0, "u" }, |
| 2377 | { "diff-binary", 0, 0, 0, 0, "on" }, |
| 2378 | { "diff-command", 0, 40, 0, 0, "" }, |
| 2379 | { "dont-push", 0, 0, 0, 0, "off" }, |
| 2380 | { "editor", 0, 32, 0, 0, "" }, |
| 2381 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2382 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2383 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2384 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| @@ -2541,10 +2512,12 @@ | |
| 2541 | ** diff-command External command to run when performing a diff. |
| 2542 | ** If undefined, the internal text diff will be used. |
| 2543 | ** |
| 2544 | ** dont-push Prevent this repository from pushing from client to |
| 2545 | ** server. Useful when setting up a private branch. |
| 2546 | ** |
| 2547 | ** editor Text editor command used for check-in comments. |
| 2548 | ** |
| 2549 | ** empty-dirs A comma or newline-separated list of pathnames. On |
| 2550 | ** (versionable) update and checkout commands, if no file or directory |
| 2551 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1475,42 +1475,10 @@ | |
| 1475 | " VALUES('reader','','kptw','Reader');" |
| 1476 | ); |
| 1477 | } |
| 1478 | } |
| 1479 | |
| 1480 | /* |
| 1481 | ** Return a pointer to a string that contains the RHS of an IN operator |
| 1482 | ** that will select CONFIG table names that are in the list of control |
| 1483 | ** settings. |
| 1484 | */ |
| @@ -1548,23 +1516,25 @@ | |
| 1516 | ** not server and project codes are invented for this repository. |
| 1517 | */ |
| 1518 | void db_initial_setup( |
| 1519 | const char *zTemplate, /* Repository from which to copy settings. */ |
| 1520 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ |
| 1521 | const char *zDefaultUser /* Default user for the repository */ |
| 1522 | ){ |
| 1523 | char *zDate; |
| 1524 | Blob hash; |
| 1525 | Blob manifest; |
| 1526 | |
| 1527 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1528 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 1529 | db_set("rebuilt", get_version(), 0); |
| 1530 | db_multi_exec( |
| 1531 | "INSERT INTO config(name,value,mtime)" |
| 1532 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 1533 | "INSERT INTO config(name,value,mtime)" |
| 1534 | " VALUES('project-code', lower(hex(randomblob(20))),now());" |
| 1535 | ); |
| 1536 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1537 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1538 | if( !db_is_global("timeline-plaintext") ){ |
| 1539 | db_set_int("timeline-plaintext", 1, 0); |
| 1540 | } |
| @@ -1687,11 +1657,11 @@ | |
| 1657 | db_open_repository(g.argv[2]); |
| 1658 | db_open_config(0); |
| 1659 | if( zTemplate ) db_attach(zTemplate, "settingSrc"); |
| 1660 | db_begin_transaction(); |
| 1661 | if( zDate==0 ) zDate = "now"; |
| 1662 | db_initial_setup(zTemplate, zDate, zDefaultUser); |
| 1663 | db_end_transaction(0); |
| 1664 | if( zTemplate ) db_detach("settingSrc"); |
| 1665 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 1666 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 1667 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| @@ -2375,10 +2345,11 @@ | |
| 2345 | { "crnl-glob", 0, 40, 1, 0, "" }, |
| 2346 | { "default-perms", 0, 16, 0, 0, "u" }, |
| 2347 | { "diff-binary", 0, 0, 0, 0, "on" }, |
| 2348 | { "diff-command", 0, 40, 0, 0, "" }, |
| 2349 | { "dont-push", 0, 0, 0, 0, "off" }, |
| 2350 | { "dotfiles", 0, 0, 0, 0, "off" }, |
| 2351 | { "editor", 0, 32, 0, 0, "" }, |
| 2352 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2353 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2354 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2355 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| @@ -2541,10 +2512,12 @@ | |
| 2512 | ** diff-command External command to run when performing a diff. |
| 2513 | ** If undefined, the internal text diff will be used. |
| 2514 | ** |
| 2515 | ** dont-push Prevent this repository from pushing from client to |
| 2516 | ** server. Useful when setting up a private branch. |
| 2517 | ** |
| 2518 | ** dotfiles Include --dotfiles option for all compatible commands. |
| 2519 | ** |
| 2520 | ** editor Text editor command used for check-in comments. |
| 2521 | ** |
| 2522 | ** empty-dirs A comma or newline-separated list of pathnames. On |
| 2523 | ** (versionable) update and checkout commands, if no file or directory |
| 2524 |
M
src/db.c
+11
-38
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1475,42 +1475,10 @@ | ||
| 1475 | 1475 | " VALUES('reader','','kptw','Reader');" |
| 1476 | 1476 | ); |
| 1477 | 1477 | } |
| 1478 | 1478 | } |
| 1479 | 1479 | |
| 1480 | -/* | |
| 1481 | -** This function sets the server and project codes if they do not already | |
| 1482 | -** exist. Currently, it should be called only by the db_initial_setup() | |
| 1483 | -** or cmd_webserver() functions, the latter being used to facilitate more | |
| 1484 | -** robust integration with "canned image" environments (e.g. Docker). | |
| 1485 | -*/ | |
| 1486 | -void db_setup_server_and_project_codes( | |
| 1487 | - int optional | |
| 1488 | -){ | |
| 1489 | - if( !optional ){ | |
| 1490 | - db_multi_exec( | |
| 1491 | - "INSERT INTO config(name,value,mtime)" | |
| 1492 | - " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 1493 | - "INSERT INTO config(name,value,mtime)" | |
| 1494 | - " VALUES('project-code', lower(hex(randomblob(20))),now());" | |
| 1495 | - ); | |
| 1496 | - }else if( db_is_writeable("repository") ){ | |
| 1497 | - if( db_get("server-code", 0)==0 ) { | |
| 1498 | - db_multi_exec( | |
| 1499 | - "INSERT INTO config(name,value,mtime)" | |
| 1500 | - " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 1501 | - ); | |
| 1502 | - } | |
| 1503 | - if( db_get("project-code", 0)==0 ) { | |
| 1504 | - db_multi_exec( | |
| 1505 | - "INSERT INTO config(name,value,mtime)" | |
| 1506 | - " VALUES('project-code', lower(hex(randomblob(20))),now());" | |
| 1507 | - ); | |
| 1508 | - } | |
| 1509 | - } | |
| 1510 | -} | |
| 1511 | - | |
| 1512 | 1480 | /* |
| 1513 | 1481 | ** Return a pointer to a string that contains the RHS of an IN operator |
| 1514 | 1482 | ** that will select CONFIG table names that are in the list of control |
| 1515 | 1483 | ** settings. |
| 1516 | 1484 | */ |
| @@ -1548,23 +1516,25 @@ | ||
| 1548 | 1516 | ** not server and project codes are invented for this repository. |
| 1549 | 1517 | */ |
| 1550 | 1518 | void db_initial_setup( |
| 1551 | 1519 | const char *zTemplate, /* Repository from which to copy settings. */ |
| 1552 | 1520 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ |
| 1553 | - const char *zDefaultUser, /* Default user for the repository */ | |
| 1554 | - int makeServerCodes /* True to make new server & project codes */ | |
| 1521 | + const char *zDefaultUser /* Default user for the repository */ | |
| 1555 | 1522 | ){ |
| 1556 | 1523 | char *zDate; |
| 1557 | 1524 | Blob hash; |
| 1558 | 1525 | Blob manifest; |
| 1559 | 1526 | |
| 1560 | 1527 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1561 | 1528 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 1562 | 1529 | db_set("rebuilt", get_version(), 0); |
| 1563 | - if( makeServerCodes ){ | |
| 1564 | - db_setup_server_and_project_codes(0); | |
| 1565 | - } | |
| 1530 | + db_multi_exec( | |
| 1531 | + "INSERT INTO config(name,value,mtime)" | |
| 1532 | + " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 1533 | + "INSERT INTO config(name,value,mtime)" | |
| 1534 | + " VALUES('project-code', lower(hex(randomblob(20))),now());" | |
| 1535 | + ); | |
| 1566 | 1536 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1567 | 1537 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1568 | 1538 | if( !db_is_global("timeline-plaintext") ){ |
| 1569 | 1539 | db_set_int("timeline-plaintext", 1, 0); |
| 1570 | 1540 | } |
| @@ -1687,11 +1657,11 @@ | ||
| 1687 | 1657 | db_open_repository(g.argv[2]); |
| 1688 | 1658 | db_open_config(0); |
| 1689 | 1659 | if( zTemplate ) db_attach(zTemplate, "settingSrc"); |
| 1690 | 1660 | db_begin_transaction(); |
| 1691 | 1661 | if( zDate==0 ) zDate = "now"; |
| 1692 | - db_initial_setup(zTemplate, zDate, zDefaultUser, 1); | |
| 1662 | + db_initial_setup(zTemplate, zDate, zDefaultUser); | |
| 1693 | 1663 | db_end_transaction(0); |
| 1694 | 1664 | if( zTemplate ) db_detach("settingSrc"); |
| 1695 | 1665 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 1696 | 1666 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 1697 | 1667 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| @@ -2375,10 +2345,11 @@ | ||
| 2375 | 2345 | { "crnl-glob", 0, 40, 1, 0, "" }, |
| 2376 | 2346 | { "default-perms", 0, 16, 0, 0, "u" }, |
| 2377 | 2347 | { "diff-binary", 0, 0, 0, 0, "on" }, |
| 2378 | 2348 | { "diff-command", 0, 40, 0, 0, "" }, |
| 2379 | 2349 | { "dont-push", 0, 0, 0, 0, "off" }, |
| 2350 | + { "dotfiles", 0, 0, 0, 0, "off" }, | |
| 2380 | 2351 | { "editor", 0, 32, 0, 0, "" }, |
| 2381 | 2352 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2382 | 2353 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2383 | 2354 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2384 | 2355 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| @@ -2541,10 +2512,12 @@ | ||
| 2541 | 2512 | ** diff-command External command to run when performing a diff. |
| 2542 | 2513 | ** If undefined, the internal text diff will be used. |
| 2543 | 2514 | ** |
| 2544 | 2515 | ** dont-push Prevent this repository from pushing from client to |
| 2545 | 2516 | ** server. Useful when setting up a private branch. |
| 2517 | +** | |
| 2518 | +** dotfiles Include --dotfiles option for all compatible commands. | |
| 2546 | 2519 | ** |
| 2547 | 2520 | ** editor Text editor command used for check-in comments. |
| 2548 | 2521 | ** |
| 2549 | 2522 | ** empty-dirs A comma or newline-separated list of pathnames. On |
| 2550 | 2523 | ** (versionable) update and checkout commands, if no file or directory |
| 2551 | 2524 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1475,42 +1475,10 @@ | |
| 1475 | " VALUES('reader','','kptw','Reader');" |
| 1476 | ); |
| 1477 | } |
| 1478 | } |
| 1479 | |
| 1480 | /* |
| 1481 | ** This function sets the server and project codes if they do not already |
| 1482 | ** exist. Currently, it should be called only by the db_initial_setup() |
| 1483 | ** or cmd_webserver() functions, the latter being used to facilitate more |
| 1484 | ** robust integration with "canned image" environments (e.g. Docker). |
| 1485 | */ |
| 1486 | void db_setup_server_and_project_codes( |
| 1487 | int optional |
| 1488 | ){ |
| 1489 | if( !optional ){ |
| 1490 | db_multi_exec( |
| 1491 | "INSERT INTO config(name,value,mtime)" |
| 1492 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 1493 | "INSERT INTO config(name,value,mtime)" |
| 1494 | " VALUES('project-code', lower(hex(randomblob(20))),now());" |
| 1495 | ); |
| 1496 | }else if( db_is_writeable("repository") ){ |
| 1497 | if( db_get("server-code", 0)==0 ) { |
| 1498 | db_multi_exec( |
| 1499 | "INSERT INTO config(name,value,mtime)" |
| 1500 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 1501 | ); |
| 1502 | } |
| 1503 | if( db_get("project-code", 0)==0 ) { |
| 1504 | db_multi_exec( |
| 1505 | "INSERT INTO config(name,value,mtime)" |
| 1506 | " VALUES('project-code', lower(hex(randomblob(20))),now());" |
| 1507 | ); |
| 1508 | } |
| 1509 | } |
| 1510 | } |
| 1511 | |
| 1512 | /* |
| 1513 | ** Return a pointer to a string that contains the RHS of an IN operator |
| 1514 | ** that will select CONFIG table names that are in the list of control |
| 1515 | ** settings. |
| 1516 | */ |
| @@ -1548,23 +1516,25 @@ | |
| 1548 | ** not server and project codes are invented for this repository. |
| 1549 | */ |
| 1550 | void db_initial_setup( |
| 1551 | const char *zTemplate, /* Repository from which to copy settings. */ |
| 1552 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ |
| 1553 | const char *zDefaultUser, /* Default user for the repository */ |
| 1554 | int makeServerCodes /* True to make new server & project codes */ |
| 1555 | ){ |
| 1556 | char *zDate; |
| 1557 | Blob hash; |
| 1558 | Blob manifest; |
| 1559 | |
| 1560 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1561 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 1562 | db_set("rebuilt", get_version(), 0); |
| 1563 | if( makeServerCodes ){ |
| 1564 | db_setup_server_and_project_codes(0); |
| 1565 | } |
| 1566 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1567 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1568 | if( !db_is_global("timeline-plaintext") ){ |
| 1569 | db_set_int("timeline-plaintext", 1, 0); |
| 1570 | } |
| @@ -1687,11 +1657,11 @@ | |
| 1687 | db_open_repository(g.argv[2]); |
| 1688 | db_open_config(0); |
| 1689 | if( zTemplate ) db_attach(zTemplate, "settingSrc"); |
| 1690 | db_begin_transaction(); |
| 1691 | if( zDate==0 ) zDate = "now"; |
| 1692 | db_initial_setup(zTemplate, zDate, zDefaultUser, 1); |
| 1693 | db_end_transaction(0); |
| 1694 | if( zTemplate ) db_detach("settingSrc"); |
| 1695 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 1696 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 1697 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| @@ -2375,10 +2345,11 @@ | |
| 2375 | { "crnl-glob", 0, 40, 1, 0, "" }, |
| 2376 | { "default-perms", 0, 16, 0, 0, "u" }, |
| 2377 | { "diff-binary", 0, 0, 0, 0, "on" }, |
| 2378 | { "diff-command", 0, 40, 0, 0, "" }, |
| 2379 | { "dont-push", 0, 0, 0, 0, "off" }, |
| 2380 | { "editor", 0, 32, 0, 0, "" }, |
| 2381 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2382 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2383 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2384 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| @@ -2541,10 +2512,12 @@ | |
| 2541 | ** diff-command External command to run when performing a diff. |
| 2542 | ** If undefined, the internal text diff will be used. |
| 2543 | ** |
| 2544 | ** dont-push Prevent this repository from pushing from client to |
| 2545 | ** server. Useful when setting up a private branch. |
| 2546 | ** |
| 2547 | ** editor Text editor command used for check-in comments. |
| 2548 | ** |
| 2549 | ** empty-dirs A comma or newline-separated list of pathnames. On |
| 2550 | ** (versionable) update and checkout commands, if no file or directory |
| 2551 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1475,42 +1475,10 @@ | |
| 1475 | " VALUES('reader','','kptw','Reader');" |
| 1476 | ); |
| 1477 | } |
| 1478 | } |
| 1479 | |
| 1480 | /* |
| 1481 | ** Return a pointer to a string that contains the RHS of an IN operator |
| 1482 | ** that will select CONFIG table names that are in the list of control |
| 1483 | ** settings. |
| 1484 | */ |
| @@ -1548,23 +1516,25 @@ | |
| 1516 | ** not server and project codes are invented for this repository. |
| 1517 | */ |
| 1518 | void db_initial_setup( |
| 1519 | const char *zTemplate, /* Repository from which to copy settings. */ |
| 1520 | const char *zInitialDate, /* Initial date of repository. (ex: "now") */ |
| 1521 | const char *zDefaultUser /* Default user for the repository */ |
| 1522 | ){ |
| 1523 | char *zDate; |
| 1524 | Blob hash; |
| 1525 | Blob manifest; |
| 1526 | |
| 1527 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1528 | db_set("aux-schema", AUX_SCHEMA_MAX, 0); |
| 1529 | db_set("rebuilt", get_version(), 0); |
| 1530 | db_multi_exec( |
| 1531 | "INSERT INTO config(name,value,mtime)" |
| 1532 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 1533 | "INSERT INTO config(name,value,mtime)" |
| 1534 | " VALUES('project-code', lower(hex(randomblob(20))),now());" |
| 1535 | ); |
| 1536 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1537 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1538 | if( !db_is_global("timeline-plaintext") ){ |
| 1539 | db_set_int("timeline-plaintext", 1, 0); |
| 1540 | } |
| @@ -1687,11 +1657,11 @@ | |
| 1657 | db_open_repository(g.argv[2]); |
| 1658 | db_open_config(0); |
| 1659 | if( zTemplate ) db_attach(zTemplate, "settingSrc"); |
| 1660 | db_begin_transaction(); |
| 1661 | if( zDate==0 ) zDate = "now"; |
| 1662 | db_initial_setup(zTemplate, zDate, zDefaultUser); |
| 1663 | db_end_transaction(0); |
| 1664 | if( zTemplate ) db_detach("settingSrc"); |
| 1665 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 1666 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 1667 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| @@ -2375,10 +2345,11 @@ | |
| 2345 | { "crnl-glob", 0, 40, 1, 0, "" }, |
| 2346 | { "default-perms", 0, 16, 0, 0, "u" }, |
| 2347 | { "diff-binary", 0, 0, 0, 0, "on" }, |
| 2348 | { "diff-command", 0, 40, 0, 0, "" }, |
| 2349 | { "dont-push", 0, 0, 0, 0, "off" }, |
| 2350 | { "dotfiles", 0, 0, 0, 0, "off" }, |
| 2351 | { "editor", 0, 32, 0, 0, "" }, |
| 2352 | { "empty-dirs", 0, 40, 1, 0, "" }, |
| 2353 | { "encoding-glob", 0, 40, 1, 0, "" }, |
| 2354 | { "gdiff-command", 0, 40, 0, 0, "gdiff" }, |
| 2355 | { "gmerge-command", 0, 40, 0, 0, "" }, |
| @@ -2541,10 +2512,12 @@ | |
| 2512 | ** diff-command External command to run when performing a diff. |
| 2513 | ** If undefined, the internal text diff will be used. |
| 2514 | ** |
| 2515 | ** dont-push Prevent this repository from pushing from client to |
| 2516 | ** server. Useful when setting up a private branch. |
| 2517 | ** |
| 2518 | ** dotfiles Include --dotfiles option for all compatible commands. |
| 2519 | ** |
| 2520 | ** editor Text editor command used for check-in comments. |
| 2521 | ** |
| 2522 | ** empty-dirs A comma or newline-separated list of pathnames. On |
| 2523 | ** (versionable) update and checkout commands, if no file or directory |
| 2524 |
+1
-1
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -640,11 +640,11 @@ | ||
| 640 | 640 | if( blob_size(&title)==0 ) blob_append(&title,zName,-1); |
| 641 | 641 | style_header("%s", blob_str(&title)); |
| 642 | 642 | blob_append(cgi_output_blob(), blob_buffer(&filebody),blob_size(&filebody)); |
| 643 | 643 | style_footer(); |
| 644 | 644 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 645 | - }else if( db_get_boolean("th1-docs", 0) && | |
| 645 | + }else if( Th_AreDocsEnabled() && | |
| 646 | 646 | fossil_strcmp(zMime, "application/x-th1")==0 ){ |
| 647 | 647 | style_header("%h", zName); |
| 648 | 648 | Th_Render(blob_str(&filebody)); |
| 649 | 649 | style_footer(); |
| 650 | 650 | #endif |
| 651 | 651 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -640,11 +640,11 @@ | |
| 640 | if( blob_size(&title)==0 ) blob_append(&title,zName,-1); |
| 641 | style_header("%s", blob_str(&title)); |
| 642 | blob_append(cgi_output_blob(), blob_buffer(&filebody),blob_size(&filebody)); |
| 643 | style_footer(); |
| 644 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 645 | }else if( db_get_boolean("th1-docs", 0) && |
| 646 | fossil_strcmp(zMime, "application/x-th1")==0 ){ |
| 647 | style_header("%h", zName); |
| 648 | Th_Render(blob_str(&filebody)); |
| 649 | style_footer(); |
| 650 | #endif |
| 651 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -640,11 +640,11 @@ | |
| 640 | if( blob_size(&title)==0 ) blob_append(&title,zName,-1); |
| 641 | style_header("%s", blob_str(&title)); |
| 642 | blob_append(cgi_output_blob(), blob_buffer(&filebody),blob_size(&filebody)); |
| 643 | style_footer(); |
| 644 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 645 | }else if( Th_AreDocsEnabled() && |
| 646 | fossil_strcmp(zMime, "application/x-th1")==0 ){ |
| 647 | style_header("%h", zName); |
| 648 | Th_Render(blob_str(&filebody)); |
| 649 | style_footer(); |
| 650 | #endif |
| 651 |
+847
-17
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -12,12 +12,12 @@ | ||
| 12 | 12 | ** Author contact information: |
| 13 | 13 | ** [email protected] |
| 14 | 14 | ** |
| 15 | 15 | ******************************************************************************* |
| 16 | 16 | ** |
| 17 | -** This file contains code used to import the content of a Git | |
| 18 | -** repository in the git-fast-import format as a new Fossil | |
| 17 | +** This file contains code used to import the content of a Git/SVN | |
| 18 | +** repository in the git-fast-import/svn-dump formats as a new Fossil | |
| 19 | 19 | ** repository. |
| 20 | 20 | */ |
| 21 | 21 | #include "config.h" |
| 22 | 22 | #include "import.h" |
| 23 | 23 | #include <assert.h> |
| @@ -516,12 +516,12 @@ | ||
| 516 | 516 | ** last commit that holds that tag. |
| 517 | 517 | ** |
| 518 | 518 | ** None of the above is explained in the git-fast-export |
| 519 | 519 | ** documentation. We had to figure it out via trial and error. |
| 520 | 520 | */ |
| 521 | - for(i=strlen(z)-1; i>=0 && z[i]!='/'; i--){} | |
| 522 | - gg.tagCommit = strncmp(&z[i-4], "tags", 4)==0; /* True for pattern B */ | |
| 521 | + for(i=5; i<strlen(z) && z[i]!='/'; i++){} | |
| 522 | + gg.tagCommit = strncmp(&z[5], "tags", 4)==0; /* True for pattern B */ | |
| 523 | 523 | if( z[i+1]!=0 ) z += i+1; |
| 524 | 524 | if( fossil_strcmp(z, "master")==0 ) z = "trunk"; |
| 525 | 525 | gg.zBranch = fossil_strdup(z); |
| 526 | 526 | gg.fromLoaded = 0; |
| 527 | 527 | }else |
| @@ -716,46 +716,822 @@ | ||
| 716 | 716 | malformed_line: |
| 717 | 717 | trim_newline(zLine); |
| 718 | 718 | fossil_fatal("bad fast-import line: [%s]", zLine); |
| 719 | 719 | return; |
| 720 | 720 | } |
| 721 | + | |
| 722 | +static struct{ | |
| 723 | + int rev; /* SVN revision number */ | |
| 724 | + char *zDate; /* Date/time stamp */ | |
| 725 | + char *zUser; /* User name */ | |
| 726 | + char *zComment; /* Comment of a commit */ | |
| 727 | + const char *zTrunk; /* Name of trunk folder in repo root */ | |
| 728 | + int lenTrunk; /* String length of zTrunk */ | |
| 729 | + const char *zBranches; /* Name of branches folder in repo root */ | |
| 730 | + int lenBranches; /* String length of zBranches */ | |
| 731 | + const char *zTags; /* Name of tags folder in repo root */ | |
| 732 | + int lenTags; /* String length of zTags */ | |
| 733 | + Bag newBranches; /* Branches that were created in this revision */ | |
| 734 | + int incrFlag; /* Add svn-rev-nn tags on every checkin */ | |
| 735 | +} gsvn; | |
| 736 | +typedef struct { | |
| 737 | + char *zKey; | |
| 738 | + char *zVal; | |
| 739 | +} KeyVal; | |
| 740 | +typedef struct { | |
| 741 | + KeyVal *aHeaders; | |
| 742 | + int nHeaders; | |
| 743 | + char *pRawProps; | |
| 744 | + KeyVal *aProps; | |
| 745 | + int nProps; | |
| 746 | + Blob content; | |
| 747 | + int contentFlag; | |
| 748 | +} SvnRecord; | |
| 749 | + | |
| 750 | +#define svn_find_header(rec, zHeader) \ | |
| 751 | + svn_find_keyval((rec).aHeaders, (rec).nHeaders, (zHeader)) | |
| 752 | +#define svn_find_prop(rec, zProp) \ | |
| 753 | + svn_find_keyval((rec).aProps, (rec).nProps, (zProp)) | |
| 754 | +static char *svn_find_keyval( | |
| 755 | + KeyVal *aKeyVal, | |
| 756 | + int nKeyVal, | |
| 757 | + const char *zKey | |
| 758 | +){ | |
| 759 | + int i; | |
| 760 | + for(i=0; i<nKeyVal; i++){ | |
| 761 | + if( fossil_strcmp(aKeyVal[i].zKey, zKey)==0 ){ | |
| 762 | + return aKeyVal[i].zVal; | |
| 763 | + } | |
| 764 | + } | |
| 765 | + return 0; | |
| 766 | +} | |
| 767 | + | |
| 768 | +static void svn_free_rec(SvnRecord *rec){ | |
| 769 | + int i; | |
| 770 | + for(i=0; i<rec->nHeaders; i++){ | |
| 771 | + fossil_free(rec->aHeaders[i].zKey); | |
| 772 | + } | |
| 773 | + fossil_free(rec->aHeaders); | |
| 774 | + fossil_free(rec->aProps); | |
| 775 | + fossil_free(rec->pRawProps); | |
| 776 | + blob_reset(&rec->content); | |
| 777 | +} | |
| 778 | + | |
| 779 | +static int svn_read_headers(FILE *pIn, SvnRecord *rec){ | |
| 780 | + char zLine[1000]; | |
| 781 | + | |
| 782 | + rec->aHeaders = 0; | |
| 783 | + rec->nHeaders = 0; | |
| 784 | + while( fgets(zLine, sizeof(zLine), pIn) ){ | |
| 785 | + if( zLine[0]!='\n' ) break; | |
| 786 | + } | |
| 787 | + if( feof(pIn) ) return 0; | |
| 788 | + do{ | |
| 789 | + char *sep; | |
| 790 | + if( zLine[0]=='\n' ) break; | |
| 791 | + rec->nHeaders += 1; | |
| 792 | + rec->aHeaders = fossil_realloc(rec->aHeaders, | |
| 793 | + sizeof(rec->aHeaders[0])*rec->nHeaders); | |
| 794 | + rec->aHeaders[rec->nHeaders-1].zKey = mprintf("%s", zLine); | |
| 795 | + sep = strchr(rec->aHeaders[rec->nHeaders-1].zKey, ':'); | |
| 796 | + if( !sep ){ | |
| 797 | + trim_newline(zLine); | |
| 798 | + fossil_fatal("bad header line: [%s]", zLine); | |
| 799 | + } | |
| 800 | + *sep = 0; | |
| 801 | + rec->aHeaders[rec->nHeaders-1].zVal = sep+1; | |
| 802 | + sep = strchr(rec->aHeaders[rec->nHeaders-1].zVal, '\n'); | |
| 803 | + *sep = 0; | |
| 804 | + while(rec->aHeaders[rec->nHeaders-1].zVal | |
| 805 | + && fossil_isspace(*(rec->aHeaders[rec->nHeaders-1].zVal)) ) | |
| 806 | + { | |
| 807 | + rec->aHeaders[rec->nHeaders-1].zVal++; | |
| 808 | + } | |
| 809 | + }while( fgets(zLine, sizeof(zLine), pIn) ); | |
| 810 | + if( zLine[0]!='\n' ){ | |
| 811 | + trim_newline(zLine); | |
| 812 | + fossil_fatal("svn-dump data ended unexpectedly"); | |
| 813 | + } | |
| 814 | + return 1; | |
| 815 | +} | |
| 816 | + | |
| 817 | +static void svn_read_props(FILE *pIn, SvnRecord *rec){ | |
| 818 | + int nRawProps = 0; | |
| 819 | + char *pRawProps; | |
| 820 | + const char *zLen; | |
| 821 | + | |
| 822 | + rec->pRawProps = 0; | |
| 823 | + rec->aProps = 0; | |
| 824 | + rec->nProps = 0; | |
| 825 | + zLen = svn_find_header(*rec, "Prop-content-length"); | |
| 826 | + if( zLen ){ | |
| 827 | + nRawProps = atoi(zLen); | |
| 828 | + } | |
| 829 | + if( nRawProps ){ | |
| 830 | + int got; | |
| 831 | + char *zLine; | |
| 832 | + rec->pRawProps = pRawProps = fossil_malloc( nRawProps ); | |
| 833 | + got = fread(rec->pRawProps, 1, nRawProps, pIn); | |
| 834 | + if( got!=nRawProps ){ | |
| 835 | + fossil_fatal("short read: got %d of %d bytes", got, nRawProps); | |
| 836 | + } | |
| 837 | + if( memcmp(&pRawProps[got-10], "PROPS-END\n", 10)!=0 ){ | |
| 838 | + fossil_fatal("svn-dump data ended unexpectedly"); | |
| 839 | + } | |
| 840 | + zLine = pRawProps; | |
| 841 | + while( zLine<(pRawProps+nRawProps-10) ){ | |
| 842 | + char *eol; | |
| 843 | + int propLen; | |
| 844 | + if( zLine[0]=='D' ){ | |
| 845 | + propLen = atoi(&zLine[2]); | |
| 846 | + eol = strchr(zLine, '\n'); | |
| 847 | + zLine = eol+1+propLen+1; | |
| 848 | + }else{ | |
| 849 | + if( zLine[0]!='K' ){ | |
| 850 | + fossil_fatal("svn-dump data format broken"); | |
| 851 | + } | |
| 852 | + propLen = atoi(&zLine[2]); | |
| 853 | + eol = strchr(zLine, '\n'); | |
| 854 | + zLine = eol+1; | |
| 855 | + eol = zLine+propLen; | |
| 856 | + if( *eol!='\n' ){ | |
| 857 | + fossil_fatal("svn-dump data format broken"); | |
| 858 | + } | |
| 859 | + *eol = 0; | |
| 860 | + rec->nProps += 1; | |
| 861 | + rec->aProps = fossil_realloc(rec->aProps, | |
| 862 | + sizeof(rec->aProps[0])*rec->nProps); | |
| 863 | + rec->aProps[rec->nProps-1].zKey = zLine; | |
| 864 | + zLine = eol+1; | |
| 865 | + if( zLine[0]!='V' ){ | |
| 866 | + fossil_fatal("svn-dump data format broken"); | |
| 867 | + } | |
| 868 | + propLen = atoi(&zLine[2]); | |
| 869 | + eol = strchr(zLine, '\n'); | |
| 870 | + zLine = eol+1; | |
| 871 | + eol = zLine+propLen; | |
| 872 | + if( *eol!='\n' ){ | |
| 873 | + fossil_fatal("svn-dump data format broken"); | |
| 874 | + } | |
| 875 | + *eol = 0; | |
| 876 | + rec->aProps[rec->nProps-1].zVal = zLine; | |
| 877 | + zLine = eol+1; | |
| 878 | + } | |
| 879 | + } | |
| 880 | + } | |
| 881 | +} | |
| 882 | + | |
| 883 | +static int svn_read_rec(FILE *pIn, SvnRecord *rec){ | |
| 884 | + const char *zLen; | |
| 885 | + int nLen = 0; | |
| 886 | + if( svn_read_headers(pIn, rec)==0 ) return 0; | |
| 887 | + svn_read_props(pIn, rec); | |
| 888 | + blob_zero(&rec->content); | |
| 889 | + zLen = svn_find_header(*rec, "Text-content-length"); | |
| 890 | + if( zLen ){ | |
| 891 | + rec->contentFlag = 1; | |
| 892 | + nLen = atoi(zLen); | |
| 893 | + blob_read_from_channel(&rec->content, pIn, nLen); | |
| 894 | + if( blob_size(&rec->content)!=nLen ){ | |
| 895 | + fossil_fatal("short read: got %d of %d bytes", | |
| 896 | + blob_size(&rec->content), nLen | |
| 897 | + ); | |
| 898 | + } | |
| 899 | + }else{ | |
| 900 | + rec->contentFlag = 0; | |
| 901 | + } | |
| 902 | + return 1; | |
| 903 | +} | |
| 904 | + | |
| 905 | +/* | |
| 906 | +** Returns the UUID for the RID, or NULL if not found. | |
| 907 | +** The returned string is allocated via db_text() and must be | |
| 908 | +** free()d by the caller. | |
| 909 | +*/ | |
| 910 | +char * rid_to_uuid(int rid) | |
| 911 | +{ | |
| 912 | + return db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 913 | +} | |
| 914 | + | |
| 915 | +#define SVN_UNKNOWN 0 | |
| 916 | +#define SVN_TRUNK 1 | |
| 917 | +#define SVN_BRANCH 2 | |
| 918 | +#define SVN_TAG 3 | |
| 919 | + | |
| 920 | +#define MAX_INT_32 (0x7FFFFFFFL) | |
| 921 | + | |
| 922 | +static void svn_finish_revision(){ | |
| 923 | + Blob manifest; | |
| 924 | + static Stmt getChanges; | |
| 925 | + static Stmt getFiles; | |
| 926 | + static Stmt setRid; | |
| 927 | + Blob mcksum; | |
| 928 | + | |
| 929 | + blob_zero(&manifest); | |
| 930 | + db_static_prepare(&getChanges, "SELECT tid, tname, ttype, tparent" | |
| 931 | + " FROM xrevisions, xbranches ON (tbranch=tid)" | |
| 932 | + " WHERE trid ISNULL"); | |
| 933 | + db_static_prepare(&getFiles, "SELECT tpath, tuuid, tperm FROM xfiles" | |
| 934 | + " WHERE tbranch=:branch ORDER BY tpath"); | |
| 935 | + db_prepare(&setRid, "UPDATE xrevisions SET trid=:rid" | |
| 936 | + " WHERE trev=%d AND tbranch=:branch", gsvn.rev); | |
| 937 | + while( db_step(&getChanges)==SQLITE_ROW ){ | |
| 938 | + int branchId = db_column_int(&getChanges, 0); | |
| 939 | + const char *zBranch = db_column_text(&getChanges, 1); | |
| 940 | + int branchType = db_column_int(&getChanges, 2); | |
| 941 | + int parentRid = db_column_int(&getChanges, 3); | |
| 942 | + int mergeRid = parentRid; | |
| 943 | + Manifest *pParentManifest = 0; | |
| 944 | + ManifestFile *pParentFile = 0; | |
| 945 | + int sameAsParent = 1; | |
| 946 | + int parentBranch = 0; | |
| 947 | + if( !bag_find(&gsvn.newBranches, branchId) ){ | |
| 948 | + parentRid = db_int(0, "SELECT trid, max(trev) FROM xrevisions" | |
| 949 | + " WHERE trev<%d AND tbranch=%d", | |
| 950 | + gsvn.rev, branchId); | |
| 951 | + } | |
| 952 | + if( parentRid>0 ){ | |
| 953 | + pParentManifest = manifest_get(parentRid, CFTYPE_MANIFEST, 0); | |
| 954 | + pParentFile = manifest_file_next(pParentManifest, 0); | |
| 955 | + parentBranch = db_int(0, "SELECT tbranch FROM xrevisions WHERE trid=%d", | |
| 956 | + parentRid); | |
| 957 | + if( parentBranch!=branchId && branchType!=SVN_TAG ){ | |
| 958 | + sameAsParent = 0; | |
| 959 | + } | |
| 960 | + } | |
| 961 | + if( mergeRid<MAX_INT_32 ){ | |
| 962 | + if( gsvn.zComment ){ | |
| 963 | + blob_appendf(&manifest, "C %F\n", gsvn.zComment); | |
| 964 | + }else{ | |
| 965 | + blob_append(&manifest, "C (no\\scomment)\n", 16); | |
| 966 | + } | |
| 967 | + blob_appendf(&manifest, "D %s\n", gsvn.zDate); | |
| 968 | + db_bind_int(&getFiles, ":branch", branchId); | |
| 969 | + while( db_step(&getFiles)==SQLITE_ROW ){ | |
| 970 | + const char *zFile = db_column_text(&getFiles, 0); | |
| 971 | + const char *zUuid = db_column_text(&getFiles, 1); | |
| 972 | + const char *zPerm = db_column_text(&getFiles, 2); | |
| 973 | + if( zPerm ){ | |
| 974 | + blob_appendf(&manifest, "F %F %s %s\n", zFile, zUuid, zPerm); | |
| 975 | + }else{ | |
| 976 | + blob_appendf(&manifest, "F %F %s\n", zFile, zUuid); | |
| 977 | + } | |
| 978 | + if( sameAsParent ){ | |
| 979 | + if( !pParentFile | |
| 980 | + || fossil_strcmp(pParentFile->zName,zFile)!=0 | |
| 981 | + || fossil_strcmp(pParentFile->zUuid,zUuid)!=0 | |
| 982 | + || fossil_strcmp(pParentFile->zPerm,zPerm)!=0 | |
| 983 | + ){ | |
| 984 | + sameAsParent = 0; | |
| 985 | + }else{ | |
| 986 | + pParentFile = manifest_file_next(pParentManifest, 0); | |
| 987 | + } | |
| 988 | + } | |
| 989 | + } | |
| 990 | + if( pParentFile ){ | |
| 991 | + sameAsParent = 0; | |
| 992 | + } | |
| 993 | + db_reset(&getFiles); | |
| 994 | + if( !sameAsParent ){ | |
| 995 | + if( parentRid>0 ){ | |
| 996 | + char *zParentUuid = rid_to_uuid(parentRid); | |
| 997 | + if( parentRid==mergeRid || mergeRid==0){ | |
| 998 | + char *zParentBranch = | |
| 999 | + db_text(0, "SELECT tname FROM xbranches WHERE tid=%d", | |
| 1000 | + parentBranch | |
| 1001 | + ); | |
| 1002 | + blob_appendf(&manifest, "P %s\n", zParentUuid); | |
| 1003 | + blob_appendf(&manifest, "T *branch * %F\n", zBranch); | |
| 1004 | + blob_appendf(&manifest, "T *sym-%F *\n", zBranch); | |
| 1005 | + if( gsvn.incrFlag ){ | |
| 1006 | + blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); | |
| 1007 | + } | |
| 1008 | + blob_appendf(&manifest, "T -sym-%F *\n", zParentBranch); | |
| 1009 | + fossil_free(zParentBranch); | |
| 1010 | + }else{ | |
| 1011 | + char *zMergeUuid = rid_to_uuid(mergeRid); | |
| 1012 | + blob_appendf(&manifest, "P %s %s\n", zParentUuid, zMergeUuid); | |
| 1013 | + if( gsvn.incrFlag ){ | |
| 1014 | + blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); | |
| 1015 | + } | |
| 1016 | + fossil_free(zMergeUuid); | |
| 1017 | + } | |
| 1018 | + fossil_free(zParentUuid); | |
| 1019 | + }else{ | |
| 1020 | + blob_appendf(&manifest, "T *branch * %F\n", zBranch); | |
| 1021 | + blob_appendf(&manifest, "T *sym-%F *\n", zBranch); | |
| 1022 | + if( gsvn.incrFlag ){ | |
| 1023 | + blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); | |
| 1024 | + } | |
| 1025 | + } | |
| 1026 | + }else if( branchType==SVN_TAG ){ | |
| 1027 | + char *zParentUuid = rid_to_uuid(parentRid); | |
| 1028 | + blob_reset(&manifest); | |
| 1029 | + blob_appendf(&manifest, "D %s\n", gsvn.zDate); | |
| 1030 | + blob_appendf(&manifest, "T +sym-%F %s\n", zBranch, zParentUuid); | |
| 1031 | + fossil_free(zParentUuid); | |
| 1032 | + } | |
| 1033 | + }else{ | |
| 1034 | + char *zParentUuid = rid_to_uuid(parentRid); | |
| 1035 | + blob_appendf(&manifest, "D %s\n", gsvn.zDate); | |
| 1036 | + if( branchType!=SVN_TAG ){ | |
| 1037 | + blob_appendf(&manifest, "T +closed %s\n", zParentUuid); | |
| 1038 | + }else{ | |
| 1039 | + blob_appendf(&manifest, "T -sym-%F %s\n", zBranch, zParentUuid); | |
| 1040 | + } | |
| 1041 | + fossil_free(zParentUuid); | |
| 1042 | + } | |
| 1043 | + if( gsvn.zUser ){ | |
| 1044 | + blob_appendf(&manifest, "U %F\n", gsvn.zUser); | |
| 1045 | + }else{ | |
| 1046 | + const char *zUserOvrd = find_option("user-override",0,1); | |
| 1047 | + blob_appendf(&manifest, "U %F\n", zUserOvrd ? zUserOvrd : login_name()); | |
| 1048 | + } | |
| 1049 | + md5sum_blob(&manifest, &mcksum); | |
| 1050 | + blob_appendf(&manifest, "Z %b\n", &mcksum); | |
| 1051 | + blob_reset(&mcksum); | |
| 1052 | + if( !sameAsParent ){ | |
| 1053 | + int rid = content_put(&manifest); | |
| 1054 | + db_bind_int(&setRid, ":branch", branchId); | |
| 1055 | + db_bind_int(&setRid, ":rid", rid); | |
| 1056 | + db_step(&setRid); | |
| 1057 | + db_reset(&setRid); | |
| 1058 | + }else if( branchType==SVN_TAG ){ | |
| 1059 | + content_put(&manifest); | |
| 1060 | + db_bind_int(&setRid, ":branch", branchId); | |
| 1061 | + db_bind_int(&setRid, ":rid", parentRid); | |
| 1062 | + db_step(&setRid); | |
| 1063 | + db_reset(&setRid); | |
| 1064 | + }else if( mergeRid==MAX_INT_32 ){ | |
| 1065 | + content_put(&manifest); | |
| 1066 | + db_multi_exec("DELETE FROM xrevisions WHERE tbranch=%d AND trev=%d", | |
| 1067 | + branchId, gsvn.rev); | |
| 1068 | + }else{ | |
| 1069 | + db_multi_exec("DELETE FROM xrevisions WHERE tbranch=%d AND trev=%d", | |
| 1070 | + branchId, gsvn.rev); | |
| 1071 | + } | |
| 1072 | + blob_reset(&manifest); | |
| 1073 | + manifest_destroy(pParentManifest); | |
| 1074 | + } | |
| 1075 | + db_reset(&getChanges); | |
| 1076 | + db_finalize(&setRid); | |
| 1077 | +} | |
| 1078 | + | |
| 1079 | +static u64 svn_get_varint(const char **pz){ | |
| 1080 | + unsigned int v = 0; | |
| 1081 | + do{ | |
| 1082 | + v = (v<<7) | ((*pz)[0]&0x7f); | |
| 1083 | + }while( (*pz)++[0]&0x80 ); | |
| 1084 | + return v; | |
| 1085 | +} | |
| 1086 | + | |
| 1087 | +static void svn_apply_svndiff(Blob *pDiff, Blob *pSrc, Blob *pOut){ | |
| 1088 | + const char *zDiff = blob_buffer(pDiff); | |
| 1089 | + char *zOut; | |
| 1090 | + if( blob_size(pDiff)<4 || memcmp(zDiff, "SVN", 4)!=0 ){ | |
| 1091 | + fossil_fatal("Invalid svndiff0 format"); | |
| 1092 | + } | |
| 1093 | + zDiff += 4; | |
| 1094 | + blob_zero(pOut); | |
| 1095 | + while( zDiff<(blob_buffer(pDiff)+blob_size(pDiff)) ){ | |
| 1096 | + u64 lenOut, lenInst, lenData, lenOld; | |
| 1097 | + const char *zInst; | |
| 1098 | + const char *zData; | |
| 1099 | + | |
| 1100 | + u64 offSrc = svn_get_varint(&zDiff); | |
| 1101 | + /*lenSrc =*/ svn_get_varint(&zDiff); | |
| 1102 | + lenOut = svn_get_varint(&zDiff); | |
| 1103 | + lenInst = svn_get_varint(&zDiff); | |
| 1104 | + lenData = svn_get_varint(&zDiff); | |
| 1105 | + zInst = zDiff; | |
| 1106 | + zData = zInst+lenInst; | |
| 1107 | + lenOld = blob_size(pOut); | |
| 1108 | + blob_resize(pOut, lenOut+lenOld); | |
| 1109 | + zOut = blob_buffer(pOut)+lenOld; | |
| 1110 | + while( zDiff<zInst+lenInst ){ | |
| 1111 | + u64 lenCpy = (*zDiff)&0x3f; | |
| 1112 | + const char *zCpy; | |
| 1113 | + switch( (*zDiff)&0xC0 ){ | |
| 1114 | + case 0x00: zCpy = blob_buffer(pSrc)+offSrc; break; | |
| 1115 | + case 0x40: zCpy = blob_buffer(pOut); break; | |
| 1116 | + case 0x80: zCpy = zData; break; | |
| 1117 | + default: fossil_fatal("Invalid svndiff0 instruction"); | |
| 1118 | + } | |
| 1119 | + zDiff++; | |
| 1120 | + if( lenCpy==0 ){ | |
| 1121 | + lenCpy = svn_get_varint(&zDiff); | |
| 1122 | + } | |
| 1123 | + if( zCpy!=zData ){ | |
| 1124 | + zCpy += svn_get_varint(&zDiff); | |
| 1125 | + }else{ | |
| 1126 | + zData += lenCpy; | |
| 1127 | + } | |
| 1128 | + while( lenCpy-- > 0 ){ | |
| 1129 | + *zOut++ = *zCpy++; | |
| 1130 | + } | |
| 1131 | + } | |
| 1132 | + zDiff += lenData; | |
| 1133 | + } | |
| 1134 | +} | |
| 1135 | + | |
| 1136 | +/* | |
| 1137 | +** Extract the branch or tag that the given path is on. Return the branch ID. | |
| 1138 | + */ | |
| 1139 | +static int svn_parse_path(char *zPath, char **zFile, int *type){ | |
| 1140 | + char *zBranch = 0; | |
| 1141 | + int branchId = 0; | |
| 1142 | + *type = SVN_UNKNOWN; | |
| 1143 | + *zFile = 0; | |
| 1144 | + if( gsvn.lenTrunk==0 ){ | |
| 1145 | + zBranch = "trunk"; | |
| 1146 | + *zFile = zPath; | |
| 1147 | + *type = SVN_TRUNK; | |
| 1148 | + }else | |
| 1149 | + if( strncmp(zPath, gsvn.zTrunk, gsvn.lenTrunk-1)==0 ){ | |
| 1150 | + if( zPath[gsvn.lenTrunk-1]=='/' || zPath[gsvn.lenTrunk-1]==0 ){ | |
| 1151 | + zBranch = "trunk"; | |
| 1152 | + *zFile = zPath+gsvn.lenTrunk; | |
| 1153 | + *type = SVN_TRUNK; | |
| 1154 | + }else{ | |
| 1155 | + zBranch = 0; | |
| 1156 | + *type = SVN_UNKNOWN; | |
| 1157 | + } | |
| 1158 | + }else{ | |
| 1159 | + if( strncmp(zPath, gsvn.zBranches, gsvn.lenBranches)==0 ){ | |
| 1160 | + *zFile = zBranch = zPath+gsvn.lenBranches; | |
| 1161 | + *type = SVN_BRANCH; | |
| 1162 | + }else | |
| 1163 | + if( strncmp(zPath, gsvn.zTags, gsvn.lenTags)==0 ){ | |
| 1164 | + *zFile = zBranch = zPath+gsvn.lenTags; | |
| 1165 | + *type = SVN_TAG; | |
| 1166 | + }else{ /* Not a branch, tag or trunk */ | |
| 1167 | + return 0; | |
| 1168 | + } | |
| 1169 | + while( **zFile && **zFile!='/' ){ (*zFile)++; } | |
| 1170 | + if( **zFile ){ | |
| 1171 | + **zFile = '\0'; | |
| 1172 | + (*zFile)++; | |
| 1173 | + } | |
| 1174 | + } | |
| 1175 | + if( *type!=SVN_UNKNOWN ){ | |
| 1176 | + branchId = db_int(0, | |
| 1177 | + "SELECT tid FROM xbranches WHERE tname=%Q AND ttype=%d", | |
| 1178 | + zBranch, *type); | |
| 1179 | + if( branchId==0 ){ | |
| 1180 | + db_multi_exec("INSERT INTO xbranches (tname, ttype) VALUES(%Q, %d)", | |
| 1181 | + zBranch, *type); | |
| 1182 | + branchId = db_last_insert_rowid(); | |
| 1183 | + } | |
| 1184 | + } | |
| 1185 | + return branchId; | |
| 1186 | +} | |
| 1187 | + | |
| 1188 | +/* | |
| 1189 | +** Read the svn-dump format from pIn and insert the corresponding | |
| 1190 | +** content into the database. | |
| 1191 | +*/ | |
| 1192 | +static void svn_dump_import(FILE *pIn){ | |
| 1193 | + SvnRecord rec; | |
| 1194 | + int ver; | |
| 1195 | + char *zTemp; | |
| 1196 | + const char *zUuid; | |
| 1197 | + Stmt addFile; | |
| 1198 | + Stmt delPath; | |
| 1199 | + Stmt addRev; | |
| 1200 | + Stmt cpyPath; | |
| 1201 | + Stmt cpyRoot; | |
| 1202 | + Stmt revSrc; | |
| 1203 | + | |
| 1204 | + /* version */ | |
| 1205 | + if( svn_read_rec(pIn, &rec) | |
| 1206 | + && (zTemp = svn_find_header(rec, "SVN-fs-dump-format-version")) ){ | |
| 1207 | + ver = atoi(zTemp); | |
| 1208 | + if( ver!=2 && ver!=3 ){ | |
| 1209 | + fossil_fatal("Unknown svn-dump format version: %d", ver); | |
| 1210 | + } | |
| 1211 | + }else{ | |
| 1212 | + fossil_fatal("Input is not an svn-dump!"); | |
| 1213 | + } | |
| 1214 | + svn_free_rec(&rec); | |
| 1215 | + /* UUID */ | |
| 1216 | + if( !svn_read_rec(pIn, &rec) || !(zUuid = svn_find_header(rec, "UUID")) ){ | |
| 1217 | + /* Removed the following line since UUID is not actually used | |
| 1218 | + fossil_fatal("Missing UUID!"); */ | |
| 1219 | + } | |
| 1220 | + svn_free_rec(&rec); | |
| 1221 | + | |
| 1222 | + /* content */ | |
| 1223 | + db_prepare(&addFile, | |
| 1224 | + "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" | |
| 1225 | + " VALUES(:path, :branch, (SELECT uuid FROM blob WHERE rid=:rid), :perm)" | |
| 1226 | + ); | |
| 1227 | + db_prepare(&delPath, | |
| 1228 | + "DELETE FROM xfiles" | |
| 1229 | + " WHERE (tpath=:path OR (tpath>:path||'/' AND tpath<:path||'0'))" | |
| 1230 | + " AND tbranch=:branch" | |
| 1231 | + ); | |
| 1232 | + db_prepare(&addRev, | |
| 1233 | + "INSERT OR IGNORE INTO xrevisions (trev, tbranch) VALUES(:rev, :branch)" | |
| 1234 | + ); | |
| 1235 | + db_prepare(&cpyPath, | |
| 1236 | + "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" | |
| 1237 | + " SELECT :path||:sep||substr(filename, length(:srcpath)+2), :branch, uuid, perm" | |
| 1238 | + " FROM xfoci" | |
| 1239 | + " WHERE checkinID=:rid" | |
| 1240 | + " AND filename>:srcpath||'/'" | |
| 1241 | + " AND filename<:srcpath||'0'" | |
| 1242 | + ); | |
| 1243 | + db_prepare(&cpyRoot, | |
| 1244 | + "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" | |
| 1245 | + " SELECT :path||:sep||filename, :branch, uuid, perm" | |
| 1246 | + " FROM xfoci" | |
| 1247 | + " WHERE checkinID=:rid" | |
| 1248 | + ); | |
| 1249 | + db_prepare(&revSrc, | |
| 1250 | + "UPDATE xrevisions SET tparent=:parent" | |
| 1251 | + " WHERE trev=:rev AND tbranch=:branch AND tparent<:parent" | |
| 1252 | + ); | |
| 1253 | + gsvn.rev = -1; | |
| 1254 | + bag_init(&gsvn.newBranches); | |
| 1255 | + while( svn_read_rec(pIn, &rec) ){ | |
| 1256 | + if( (zTemp = svn_find_header(rec, "Revision-number")) ){ /* revision node */ | |
| 1257 | + /* finish previous revision */ | |
| 1258 | + char *zDate = NULL; | |
| 1259 | + if( gsvn.rev>=0 ){ | |
| 1260 | + svn_finish_revision(); | |
| 1261 | + fossil_free(gsvn.zUser); | |
| 1262 | + fossil_free(gsvn.zComment); | |
| 1263 | + fossil_free(gsvn.zDate); | |
| 1264 | + bag_clear(&gsvn.newBranches); | |
| 1265 | + } | |
| 1266 | + /* start new revision */ | |
| 1267 | + gsvn.rev = atoi(zTemp); | |
| 1268 | + gsvn.zUser = mprintf("%s", svn_find_prop(rec, "svn:author")); | |
| 1269 | + gsvn.zComment = mprintf("%s", svn_find_prop(rec, "svn:log")); | |
| 1270 | + zDate = svn_find_prop(rec, "svn:date"); | |
| 1271 | + if( zDate ){ | |
| 1272 | + gsvn.zDate = date_in_standard_format(zDate); | |
| 1273 | + }else{ | |
| 1274 | + gsvn.zDate = date_in_standard_format("now"); | |
| 1275 | + } | |
| 1276 | + db_bind_int(&addRev, ":rev", gsvn.rev); | |
| 1277 | + fossil_print("\rImporting SVN revision: %d", gsvn.rev); | |
| 1278 | + }else | |
| 1279 | + if( (zTemp = svn_find_header(rec, "Node-path")) ){ /* file/dir node */ | |
| 1280 | + char *zFile; | |
| 1281 | + int branchType; | |
| 1282 | + int branchId = svn_parse_path(zTemp, &zFile, &branchType); | |
| 1283 | + char *zAction = svn_find_header(rec, "Node-action"); | |
| 1284 | + char *zKind = svn_find_header(rec, "Node-kind"); | |
| 1285 | + char *zPerm = svn_find_prop(rec, "svn:executable") ? "x" : 0; | |
| 1286 | + int deltaFlag = 0; | |
| 1287 | + int srcRev = 0; | |
| 1288 | + if( branchId==0 ){ | |
| 1289 | + svn_free_rec(&rec); | |
| 1290 | + continue; | |
| 1291 | + } | |
| 1292 | + if( (zTemp = svn_find_header(rec, "Text-delta")) ){ | |
| 1293 | + deltaFlag = strncmp(zTemp, "true", 4)==0; | |
| 1294 | + } | |
| 1295 | + if( strncmp(zAction, "delete", 6)==0 | |
| 1296 | + || strncmp(zAction, "replace", 7)==0 ) | |
| 1297 | + { | |
| 1298 | + db_bind_int(&addRev, ":branch", branchId); | |
| 1299 | + db_step(&addRev); | |
| 1300 | + db_reset(&addRev); | |
| 1301 | + if( zFile[0]!=0 ){ | |
| 1302 | + db_bind_text(&delPath, ":path", zFile); | |
| 1303 | + db_bind_int(&delPath, ":branch", branchId); | |
| 1304 | + db_step(&delPath); | |
| 1305 | + db_reset(&delPath); | |
| 1306 | + }else{ | |
| 1307 | + db_multi_exec("DELETE FROM xfiles WHERE tbranch=%d", branchId); | |
| 1308 | + db_bind_int(&revSrc, ":parent", MAX_INT_32); | |
| 1309 | + db_bind_int(&revSrc, ":rev", gsvn.rev); | |
| 1310 | + db_bind_int(&revSrc, ":branch", branchId); | |
| 1311 | + db_step(&revSrc); | |
| 1312 | + db_reset(&revSrc); | |
| 1313 | + } | |
| 1314 | + } /* no 'else' here since 'replace' does both a 'delete' and an 'add' */ | |
| 1315 | + if( strncmp(zAction, "add", 3)==0 | |
| 1316 | + || strncmp(zAction, "replace", 7)==0 ) | |
| 1317 | + { | |
| 1318 | + char *zSrcPath = svn_find_header(rec, "Node-copyfrom-path"); | |
| 1319 | + char *zSrcFile; | |
| 1320 | + int srcRid = 0; | |
| 1321 | + if( zSrcPath ){ | |
| 1322 | + int srcBranch; | |
| 1323 | + zTemp = svn_find_header(rec, "Node-copyfrom-rev"); | |
| 1324 | + if( zTemp ){ | |
| 1325 | + srcRev = atoi(zTemp); | |
| 1326 | + }else{ | |
| 1327 | + fossil_fatal("Missing copyfrom-rev"); | |
| 1328 | + } | |
| 1329 | + srcBranch = svn_parse_path(zSrcPath, &zSrcFile, &branchType); | |
| 1330 | + if( srcBranch==0 ){ | |
| 1331 | + fossil_fatal("Copy from path outside the import paths"); | |
| 1332 | + } | |
| 1333 | + srcRid = db_int(0, "SELECT trid, max(trev) FROM xrevisions" | |
| 1334 | + " WHERE trev<=%d AND tbranch=%d", | |
| 1335 | + srcRev, srcBranch); | |
| 1336 | + if( srcRid>0 && srcBranch!=branchId ){ | |
| 1337 | + db_bind_int(&addRev, ":branch", branchId); | |
| 1338 | + db_step(&addRev); | |
| 1339 | + db_reset(&addRev); | |
| 1340 | + db_bind_int(&revSrc, ":parent", srcRid); | |
| 1341 | + db_bind_int(&revSrc, ":rev", gsvn.rev); | |
| 1342 | + db_bind_int(&revSrc, ":branch", branchId); | |
| 1343 | + db_step(&revSrc); | |
| 1344 | + db_reset(&revSrc); | |
| 1345 | + } | |
| 1346 | + } | |
| 1347 | + if( zKind==0 ){ | |
| 1348 | + fossil_fatal("Missing Node-kind"); | |
| 1349 | + }else if( strncmp(zKind, "dir", 3)==0 ){ | |
| 1350 | + if( zSrcPath ){ | |
| 1351 | + if( srcRid>0 ){ | |
| 1352 | + if( zSrcFile[0]==0 ){ | |
| 1353 | + db_bind_text(&cpyRoot, ":path", zFile); | |
| 1354 | + if( zFile[0]!=0 ){ | |
| 1355 | + db_bind_text(&cpyRoot, ":sep", "/"); | |
| 1356 | + }else{ | |
| 1357 | + db_bind_text(&cpyRoot, ":sep", ""); | |
| 1358 | + } | |
| 1359 | + db_bind_int(&cpyRoot, ":branch", branchId); | |
| 1360 | + db_bind_int(&cpyRoot, ":rid", srcRid); | |
| 1361 | + db_step(&cpyRoot); | |
| 1362 | + db_reset(&cpyRoot); | |
| 1363 | + }else{ | |
| 1364 | + db_bind_text(&cpyPath, ":path", zFile); | |
| 1365 | + if( zFile[0]!=0 ){ | |
| 1366 | + db_bind_text(&cpyPath, ":sep", "/"); | |
| 1367 | + }else{ | |
| 1368 | + db_bind_text(&cpyPath, ":sep", ""); | |
| 1369 | + } | |
| 1370 | + db_bind_int(&cpyPath, ":branch", branchId); | |
| 1371 | + db_bind_text(&cpyPath, ":srcpath", zSrcFile); | |
| 1372 | + db_bind_int(&cpyPath, ":rid", srcRid); | |
| 1373 | + db_step(&cpyPath); | |
| 1374 | + db_reset(&cpyPath); | |
| 1375 | + } | |
| 1376 | + } | |
| 1377 | + } | |
| 1378 | + if( zFile[0]==0 ){ | |
| 1379 | + bag_insert(&gsvn.newBranches, branchId); | |
| 1380 | + } | |
| 1381 | + }else{ | |
| 1382 | + int rid = 0; | |
| 1383 | + if( zSrcPath ){ | |
| 1384 | + rid = db_int(0, "SELECT rid FROM blob WHERE uuid=(" | |
| 1385 | + " SELECT uuid FROM xfoci" | |
| 1386 | + " WHERE checkinID=%d AND filename=%Q" | |
| 1387 | + ")", | |
| 1388 | + srcRid, zSrcFile); | |
| 1389 | + } | |
| 1390 | + if( deltaFlag ){ | |
| 1391 | + Blob deltaSrc; | |
| 1392 | + Blob target; | |
| 1393 | + if( rid!=0 ){ | |
| 1394 | + content_get(rid, &deltaSrc); | |
| 1395 | + }else{ | |
| 1396 | + blob_zero(&deltaSrc); | |
| 1397 | + } | |
| 1398 | + svn_apply_svndiff(&rec.content, &deltaSrc, &target); | |
| 1399 | + rid = content_put(&target); | |
| 1400 | + }else if( rec.contentFlag ){ | |
| 1401 | + rid = content_put(&rec.content); | |
| 1402 | + } | |
| 1403 | + db_bind_text(&addFile, ":path", zFile); | |
| 1404 | + db_bind_int(&addFile, ":branch", branchId); | |
| 1405 | + db_bind_int(&addFile, ":rid", rid); | |
| 1406 | + db_bind_text(&addFile, ":perm", zPerm); | |
| 1407 | + db_step(&addFile); | |
| 1408 | + db_reset(&addFile); | |
| 1409 | + db_bind_int(&addRev, ":branch", branchId); | |
| 1410 | + db_step(&addRev); | |
| 1411 | + db_reset(&addRev); | |
| 1412 | + } | |
| 1413 | + }else | |
| 1414 | + if( strncmp(zAction, "change", 6)==0 ){ | |
| 1415 | + int rid = 0; | |
| 1416 | + if( zKind==0 ){ | |
| 1417 | + fossil_fatal("Missing Node-kind"); | |
| 1418 | + } | |
| 1419 | + if( strncmp(zKind, "dir", 3)!=0 ){ | |
| 1420 | + if( deltaFlag ){ | |
| 1421 | + Blob deltaSrc; | |
| 1422 | + Blob target; | |
| 1423 | + rid = db_int(0, "SELECT rid FROM blob WHERE uuid=(" | |
| 1424 | + " SELECT uuid FROM xfiles" | |
| 1425 | + " WHERE tpath=%Q AND tbranch=%d" | |
| 1426 | + ")", zFile, branchId); | |
| 1427 | + content_get(rid, &deltaSrc); | |
| 1428 | + svn_apply_svndiff(&rec.content, &deltaSrc, &target); | |
| 1429 | + rid = content_put(&target); | |
| 1430 | + }else{ | |
| 1431 | + rid = content_put(&rec.content); | |
| 1432 | + } | |
| 1433 | + db_bind_text(&addFile, ":path", zFile); | |
| 1434 | + db_bind_int(&addFile, ":branch", branchId); | |
| 1435 | + db_bind_int(&addFile, ":rid", rid); | |
| 1436 | + db_bind_text(&addFile, ":perm", zPerm); | |
| 1437 | + db_step(&addFile); | |
| 1438 | + db_reset(&addFile); | |
| 1439 | + db_bind_int(&addRev, ":branch", branchId); | |
| 1440 | + db_step(&addRev); | |
| 1441 | + db_reset(&addRev); | |
| 1442 | + } | |
| 1443 | + }else | |
| 1444 | + if( strncmp(zAction, "delete", 6)!=0 ){ /* already did this one above */ | |
| 1445 | + fossil_fatal("Unknown Node-action"); | |
| 1446 | + } | |
| 1447 | + }else{ | |
| 1448 | + fossil_fatal("Unknown record type"); | |
| 1449 | + } | |
| 1450 | + svn_free_rec(&rec); | |
| 1451 | + } | |
| 1452 | + svn_finish_revision(); | |
| 1453 | + fossil_free(gsvn.zUser); | |
| 1454 | + fossil_free(gsvn.zComment); | |
| 1455 | + fossil_free(gsvn.zDate); | |
| 1456 | + db_finalize(&addFile); | |
| 1457 | + db_finalize(&delPath); | |
| 1458 | + db_finalize(&addRev); | |
| 1459 | + db_finalize(&cpyPath); | |
| 1460 | + db_finalize(&cpyRoot); | |
| 1461 | + db_finalize(&revSrc); | |
| 1462 | + fossil_print(" Done!\n"); | |
| 1463 | +} | |
| 721 | 1464 | |
| 722 | 1465 | /* |
| 723 | 1466 | ** COMMAND: import |
| 724 | 1467 | ** |
| 725 | -** Usage: %fossil import ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? | |
| 1468 | +** Usage: %fossil import ?--git? ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? | |
| 1469 | +** or: %fossil import --svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? | |
| 726 | 1470 | ** |
| 727 | 1471 | ** Read interchange format generated by another VCS and use it to |
| 728 | 1472 | ** construct a new Fossil repository named by the NEW-REPOSITORY |
| 729 | 1473 | ** argument. If no input file is supplied the interchange format |
| 730 | 1474 | ** data is read from standard input. |
| 731 | 1475 | ** |
| 732 | -** The git-fast-export file format is currently the only VCS interchange | |
| 733 | -** format that is understood, though other interchange formats may be added | |
| 734 | -** in the future. | |
| 1476 | +** The following formats are currently understood by this command | |
| 1477 | +** | |
| 1478 | +** --git Import from the git-fast-export file format (default) | |
| 1479 | +** | |
| 1480 | +** --svn Import from the svnadmin-dump file format. The default | |
| 1481 | +** behaviour (unless overridden by --flat) is to treat 3 | |
| 1482 | +** folders in the SVN root as special, following the | |
| 1483 | +** common layout of SVN repositories. These are (by | |
| 1484 | +** default) trunk/, branches/ and tags/ | |
| 1485 | +** Options: | |
| 1486 | +** --trunk FOLDER Name of trunk folder | |
| 1487 | +** --branches FOLDER Name of branches folder | |
| 1488 | +** --tags FOLDER Name of tags folder | |
| 1489 | +** --base PATH Path to project root in repository | |
| 1490 | +** --flat The whole dump is a single branch | |
| 1491 | +** | |
| 1492 | +** Common Options: | |
| 1493 | +** -i|--incremental allow importing into an existing repository | |
| 1494 | +** -f|--force overwrite repository if already exist | |
| 735 | 1495 | ** |
| 736 | 1496 | ** The --incremental option allows an existing repository to be extended |
| 737 | 1497 | ** with new content. |
| 738 | 1498 | ** |
| 739 | -** Options: | |
| 740 | -** --git import from the git-fast-export file format (default) | |
| 741 | -** --incremental allow importing into an existing repository | |
| 742 | 1499 | ** |
| 743 | 1500 | ** See also: export |
| 744 | 1501 | */ |
| 745 | 1502 | void import_cmd(void){ |
| 746 | 1503 | char *zPassword; |
| 747 | 1504 | FILE *pIn; |
| 748 | 1505 | Stmt q; |
| 749 | 1506 | int forceFlag = find_option("force", "f", 0)!=0; |
| 750 | - int incrFlag = find_option("incremental", "i", 0)!=0; | |
| 751 | 1507 | int svnFlag = find_option("svn", 0, 0)!=0; |
| 752 | 1508 | |
| 753 | - find_option("git",0,0); /* Skip the --git option for now */ | |
| 1509 | + /* Options common to all input formats */ | |
| 1510 | + int incrFlag = find_option("incremental", "i", 0)!=0; | |
| 1511 | + | |
| 1512 | + /* Options for --svn only */ | |
| 1513 | + const char *zBase=""; | |
| 1514 | + int flatFlag=0; | |
| 1515 | + | |
| 1516 | + if( svnFlag ){ | |
| 1517 | + /* Get --svn related options here, so verify_all_options() fail when svn | |
| 1518 | + * only option are specify with --git | |
| 1519 | + */ | |
| 1520 | + zBase = find_option("base", 0, 1); | |
| 1521 | + flatFlag = find_option("flat", 0, 0)!=0; | |
| 1522 | + gsvn.zTrunk = find_option("trunk", 0, 1); | |
| 1523 | + gsvn.zBranches = find_option("branches", 0, 1); | |
| 1524 | + gsvn.zTags = find_option("tags", 0, 1); | |
| 1525 | + gsvn.incrFlag = incrFlag; | |
| 1526 | + }else{ | |
| 1527 | + find_option("git",0,0); /* Skip the --git option for now */ | |
| 1528 | + } | |
| 754 | 1529 | verify_all_options(); |
| 755 | - if( g.argc!=3 && g.argc!=4 ){ | |
| 756 | - usage("NEW-REPOSITORY ?INPUT-FILE?"); | |
| 1530 | + | |
| 1531 | + if( g.argc!=3 && g.argc!=4 ){ | |
| 1532 | + usage("--git|--svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?"); | |
| 757 | 1533 | } |
| 758 | 1534 | if( g.argc==4 ){ |
| 759 | 1535 | pIn = fossil_fopen(g.argv[3], "rb"); |
| 760 | 1536 | }else{ |
| 761 | 1537 | pIn = stdin; |
| @@ -767,14 +1543,66 @@ | ||
| 767 | 1543 | } |
| 768 | 1544 | db_open_repository(g.argv[2]); |
| 769 | 1545 | db_open_config(0); |
| 770 | 1546 | |
| 771 | 1547 | db_begin_transaction(); |
| 772 | - if( !incrFlag ) db_initial_setup(0, 0, 0, 1); | |
| 1548 | + if( !incrFlag ) db_initial_setup(0, 0, 0); | |
| 773 | 1549 | |
| 774 | 1550 | if( svnFlag ){ |
| 775 | - fossil_fatal("--svn format not implemented yet"); | |
| 1551 | + db_multi_exec( | |
| 1552 | + "CREATE TEMP TABLE xrevisions(" | |
| 1553 | + " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," | |
| 1554 | + " UNIQUE(tbranch, trev)" | |
| 1555 | + ");" | |
| 1556 | + "CREATE INDEX temp.i_xrevisions ON xrevisions(trid);" | |
| 1557 | + "CREATE TEMP TABLE xfiles(" | |
| 1558 | + " tpath TEXT, tbranch INT, tuuid TEXT, tperm TEXT," | |
| 1559 | + " UNIQUE (tbranch, tpath) ON CONFLICT REPLACE" | |
| 1560 | + ");" | |
| 1561 | + "CREATE TEMP TABLE xbranches(" | |
| 1562 | + " tid INTEGER PRIMARY KEY, tname TEXT, ttype INT," | |
| 1563 | + " UNIQUE(tname, ttype)" | |
| 1564 | + ");" | |
| 1565 | + "CREATE VIRTUAL TABLE temp.xfoci USING files_of_checkin;" | |
| 1566 | + ); | |
| 1567 | + if( zBase==0 ){ zBase = ""; } | |
| 1568 | + if( strlen(zBase)>0 ){ | |
| 1569 | + if( zBase[strlen(zBase)-1]!='/' ){ | |
| 1570 | + zBase = mprintf("%s/", zBase); | |
| 1571 | + } | |
| 1572 | + } | |
| 1573 | + if( flatFlag ){ | |
| 1574 | + gsvn.zTrunk = zBase; | |
| 1575 | + gsvn.zBranches = 0; | |
| 1576 | + gsvn.zTags = 0; | |
| 1577 | + gsvn.lenTrunk = strlen(zBase); | |
| 1578 | + gsvn.lenBranches = 0; | |
| 1579 | + gsvn.lenTags = 0; | |
| 1580 | + }else{ | |
| 1581 | + if( gsvn.zTrunk==0 ){ gsvn.zTrunk = "trunk/"; } | |
| 1582 | + if( gsvn.zBranches==0 ){ gsvn.zBranches = "branches/"; } | |
| 1583 | + if( gsvn.zTags==0 ){ gsvn.zTags = "tags/"; } | |
| 1584 | + gsvn.zTrunk = mprintf("%s%s", zBase, gsvn.zTrunk); | |
| 1585 | + gsvn.zBranches = mprintf("%s%s", zBase, gsvn.zBranches); | |
| 1586 | + gsvn.zTags = mprintf("%s%s", zBase, gsvn.zTags); | |
| 1587 | + gsvn.lenTrunk = strlen(gsvn.zTrunk); | |
| 1588 | + gsvn.lenBranches = strlen(gsvn.zBranches); | |
| 1589 | + gsvn.lenTags = strlen(gsvn.zTags); | |
| 1590 | + if( gsvn.zTrunk[gsvn.lenTrunk-1]!='/' ){ | |
| 1591 | + gsvn.zTrunk = mprintf("%s/", gsvn.zTrunk); | |
| 1592 | + gsvn.lenTrunk++; | |
| 1593 | + } | |
| 1594 | + if( gsvn.zBranches[gsvn.lenBranches-1]!='/' ){ | |
| 1595 | + gsvn.zBranches = mprintf("%s/", gsvn.zBranches); | |
| 1596 | + gsvn.lenBranches++; | |
| 1597 | + } | |
| 1598 | + if( gsvn.zTags[gsvn.lenTags-1]!='/' ){ | |
| 1599 | + gsvn.zTags = mprintf("%s/", gsvn.zTags); | |
| 1600 | + gsvn.lenTags++; | |
| 1601 | + } | |
| 1602 | + } | |
| 1603 | + svn_dump_import(pIn); | |
| 776 | 1604 | }else{ |
| 777 | 1605 | /* The following temp-tables are used to hold information needed for |
| 778 | 1606 | ** the import. |
| 779 | 1607 | ** |
| 780 | 1608 | ** The XMARK table provides a mapping from fast-import "marks" and symbols |
| @@ -807,10 +1635,12 @@ | ||
| 807 | 1635 | fast_insert_content(&record, 0, 0); |
| 808 | 1636 | import_reset(0); |
| 809 | 1637 | } |
| 810 | 1638 | db_finalize(&q); |
| 811 | 1639 | } |
| 1640 | + | |
| 1641 | + verify_cancel(); | |
| 812 | 1642 | db_end_transaction(0); |
| 813 | 1643 | db_begin_transaction(); |
| 814 | 1644 | fossil_print("Rebuilding repository meta-data...\n"); |
| 815 | 1645 | rebuild_db(0, 1, !incrFlag); |
| 816 | 1646 | verify_cancel(); |
| 817 | 1647 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -12,12 +12,12 @@ | |
| 12 | ** Author contact information: |
| 13 | ** [email protected] |
| 14 | ** |
| 15 | ******************************************************************************* |
| 16 | ** |
| 17 | ** This file contains code used to import the content of a Git |
| 18 | ** repository in the git-fast-import format as a new Fossil |
| 19 | ** repository. |
| 20 | */ |
| 21 | #include "config.h" |
| 22 | #include "import.h" |
| 23 | #include <assert.h> |
| @@ -516,12 +516,12 @@ | |
| 516 | ** last commit that holds that tag. |
| 517 | ** |
| 518 | ** None of the above is explained in the git-fast-export |
| 519 | ** documentation. We had to figure it out via trial and error. |
| 520 | */ |
| 521 | for(i=strlen(z)-1; i>=0 && z[i]!='/'; i--){} |
| 522 | gg.tagCommit = strncmp(&z[i-4], "tags", 4)==0; /* True for pattern B */ |
| 523 | if( z[i+1]!=0 ) z += i+1; |
| 524 | if( fossil_strcmp(z, "master")==0 ) z = "trunk"; |
| 525 | gg.zBranch = fossil_strdup(z); |
| 526 | gg.fromLoaded = 0; |
| 527 | }else |
| @@ -716,46 +716,822 @@ | |
| 716 | malformed_line: |
| 717 | trim_newline(zLine); |
| 718 | fossil_fatal("bad fast-import line: [%s]", zLine); |
| 719 | return; |
| 720 | } |
| 721 | |
| 722 | /* |
| 723 | ** COMMAND: import |
| 724 | ** |
| 725 | ** Usage: %fossil import ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? |
| 726 | ** |
| 727 | ** Read interchange format generated by another VCS and use it to |
| 728 | ** construct a new Fossil repository named by the NEW-REPOSITORY |
| 729 | ** argument. If no input file is supplied the interchange format |
| 730 | ** data is read from standard input. |
| 731 | ** |
| 732 | ** The git-fast-export file format is currently the only VCS interchange |
| 733 | ** format that is understood, though other interchange formats may be added |
| 734 | ** in the future. |
| 735 | ** |
| 736 | ** The --incremental option allows an existing repository to be extended |
| 737 | ** with new content. |
| 738 | ** |
| 739 | ** Options: |
| 740 | ** --git import from the git-fast-export file format (default) |
| 741 | ** --incremental allow importing into an existing repository |
| 742 | ** |
| 743 | ** See also: export |
| 744 | */ |
| 745 | void import_cmd(void){ |
| 746 | char *zPassword; |
| 747 | FILE *pIn; |
| 748 | Stmt q; |
| 749 | int forceFlag = find_option("force", "f", 0)!=0; |
| 750 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 751 | int svnFlag = find_option("svn", 0, 0)!=0; |
| 752 | |
| 753 | find_option("git",0,0); /* Skip the --git option for now */ |
| 754 | verify_all_options(); |
| 755 | if( g.argc!=3 && g.argc!=4 ){ |
| 756 | usage("NEW-REPOSITORY ?INPUT-FILE?"); |
| 757 | } |
| 758 | if( g.argc==4 ){ |
| 759 | pIn = fossil_fopen(g.argv[3], "rb"); |
| 760 | }else{ |
| 761 | pIn = stdin; |
| @@ -767,14 +1543,66 @@ | |
| 767 | } |
| 768 | db_open_repository(g.argv[2]); |
| 769 | db_open_config(0); |
| 770 | |
| 771 | db_begin_transaction(); |
| 772 | if( !incrFlag ) db_initial_setup(0, 0, 0, 1); |
| 773 | |
| 774 | if( svnFlag ){ |
| 775 | fossil_fatal("--svn format not implemented yet"); |
| 776 | }else{ |
| 777 | /* The following temp-tables are used to hold information needed for |
| 778 | ** the import. |
| 779 | ** |
| 780 | ** The XMARK table provides a mapping from fast-import "marks" and symbols |
| @@ -807,10 +1635,12 @@ | |
| 807 | fast_insert_content(&record, 0, 0); |
| 808 | import_reset(0); |
| 809 | } |
| 810 | db_finalize(&q); |
| 811 | } |
| 812 | db_end_transaction(0); |
| 813 | db_begin_transaction(); |
| 814 | fossil_print("Rebuilding repository meta-data...\n"); |
| 815 | rebuild_db(0, 1, !incrFlag); |
| 816 | verify_cancel(); |
| 817 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -12,12 +12,12 @@ | |
| 12 | ** Author contact information: |
| 13 | ** [email protected] |
| 14 | ** |
| 15 | ******************************************************************************* |
| 16 | ** |
| 17 | ** This file contains code used to import the content of a Git/SVN |
| 18 | ** repository in the git-fast-import/svn-dump formats as a new Fossil |
| 19 | ** repository. |
| 20 | */ |
| 21 | #include "config.h" |
| 22 | #include "import.h" |
| 23 | #include <assert.h> |
| @@ -516,12 +516,12 @@ | |
| 516 | ** last commit that holds that tag. |
| 517 | ** |
| 518 | ** None of the above is explained in the git-fast-export |
| 519 | ** documentation. We had to figure it out via trial and error. |
| 520 | */ |
| 521 | for(i=5; i<strlen(z) && z[i]!='/'; i++){} |
| 522 | gg.tagCommit = strncmp(&z[5], "tags", 4)==0; /* True for pattern B */ |
| 523 | if( z[i+1]!=0 ) z += i+1; |
| 524 | if( fossil_strcmp(z, "master")==0 ) z = "trunk"; |
| 525 | gg.zBranch = fossil_strdup(z); |
| 526 | gg.fromLoaded = 0; |
| 527 | }else |
| @@ -716,46 +716,822 @@ | |
| 716 | malformed_line: |
| 717 | trim_newline(zLine); |
| 718 | fossil_fatal("bad fast-import line: [%s]", zLine); |
| 719 | return; |
| 720 | } |
| 721 | |
| 722 | static struct{ |
| 723 | int rev; /* SVN revision number */ |
| 724 | char *zDate; /* Date/time stamp */ |
| 725 | char *zUser; /* User name */ |
| 726 | char *zComment; /* Comment of a commit */ |
| 727 | const char *zTrunk; /* Name of trunk folder in repo root */ |
| 728 | int lenTrunk; /* String length of zTrunk */ |
| 729 | const char *zBranches; /* Name of branches folder in repo root */ |
| 730 | int lenBranches; /* String length of zBranches */ |
| 731 | const char *zTags; /* Name of tags folder in repo root */ |
| 732 | int lenTags; /* String length of zTags */ |
| 733 | Bag newBranches; /* Branches that were created in this revision */ |
| 734 | int incrFlag; /* Add svn-rev-nn tags on every checkin */ |
| 735 | } gsvn; |
| 736 | typedef struct { |
| 737 | char *zKey; |
| 738 | char *zVal; |
| 739 | } KeyVal; |
| 740 | typedef struct { |
| 741 | KeyVal *aHeaders; |
| 742 | int nHeaders; |
| 743 | char *pRawProps; |
| 744 | KeyVal *aProps; |
| 745 | int nProps; |
| 746 | Blob content; |
| 747 | int contentFlag; |
| 748 | } SvnRecord; |
| 749 | |
| 750 | #define svn_find_header(rec, zHeader) \ |
| 751 | svn_find_keyval((rec).aHeaders, (rec).nHeaders, (zHeader)) |
| 752 | #define svn_find_prop(rec, zProp) \ |
| 753 | svn_find_keyval((rec).aProps, (rec).nProps, (zProp)) |
| 754 | static char *svn_find_keyval( |
| 755 | KeyVal *aKeyVal, |
| 756 | int nKeyVal, |
| 757 | const char *zKey |
| 758 | ){ |
| 759 | int i; |
| 760 | for(i=0; i<nKeyVal; i++){ |
| 761 | if( fossil_strcmp(aKeyVal[i].zKey, zKey)==0 ){ |
| 762 | return aKeyVal[i].zVal; |
| 763 | } |
| 764 | } |
| 765 | return 0; |
| 766 | } |
| 767 | |
| 768 | static void svn_free_rec(SvnRecord *rec){ |
| 769 | int i; |
| 770 | for(i=0; i<rec->nHeaders; i++){ |
| 771 | fossil_free(rec->aHeaders[i].zKey); |
| 772 | } |
| 773 | fossil_free(rec->aHeaders); |
| 774 | fossil_free(rec->aProps); |
| 775 | fossil_free(rec->pRawProps); |
| 776 | blob_reset(&rec->content); |
| 777 | } |
| 778 | |
| 779 | static int svn_read_headers(FILE *pIn, SvnRecord *rec){ |
| 780 | char zLine[1000]; |
| 781 | |
| 782 | rec->aHeaders = 0; |
| 783 | rec->nHeaders = 0; |
| 784 | while( fgets(zLine, sizeof(zLine), pIn) ){ |
| 785 | if( zLine[0]!='\n' ) break; |
| 786 | } |
| 787 | if( feof(pIn) ) return 0; |
| 788 | do{ |
| 789 | char *sep; |
| 790 | if( zLine[0]=='\n' ) break; |
| 791 | rec->nHeaders += 1; |
| 792 | rec->aHeaders = fossil_realloc(rec->aHeaders, |
| 793 | sizeof(rec->aHeaders[0])*rec->nHeaders); |
| 794 | rec->aHeaders[rec->nHeaders-1].zKey = mprintf("%s", zLine); |
| 795 | sep = strchr(rec->aHeaders[rec->nHeaders-1].zKey, ':'); |
| 796 | if( !sep ){ |
| 797 | trim_newline(zLine); |
| 798 | fossil_fatal("bad header line: [%s]", zLine); |
| 799 | } |
| 800 | *sep = 0; |
| 801 | rec->aHeaders[rec->nHeaders-1].zVal = sep+1; |
| 802 | sep = strchr(rec->aHeaders[rec->nHeaders-1].zVal, '\n'); |
| 803 | *sep = 0; |
| 804 | while(rec->aHeaders[rec->nHeaders-1].zVal |
| 805 | && fossil_isspace(*(rec->aHeaders[rec->nHeaders-1].zVal)) ) |
| 806 | { |
| 807 | rec->aHeaders[rec->nHeaders-1].zVal++; |
| 808 | } |
| 809 | }while( fgets(zLine, sizeof(zLine), pIn) ); |
| 810 | if( zLine[0]!='\n' ){ |
| 811 | trim_newline(zLine); |
| 812 | fossil_fatal("svn-dump data ended unexpectedly"); |
| 813 | } |
| 814 | return 1; |
| 815 | } |
| 816 | |
| 817 | static void svn_read_props(FILE *pIn, SvnRecord *rec){ |
| 818 | int nRawProps = 0; |
| 819 | char *pRawProps; |
| 820 | const char *zLen; |
| 821 | |
| 822 | rec->pRawProps = 0; |
| 823 | rec->aProps = 0; |
| 824 | rec->nProps = 0; |
| 825 | zLen = svn_find_header(*rec, "Prop-content-length"); |
| 826 | if( zLen ){ |
| 827 | nRawProps = atoi(zLen); |
| 828 | } |
| 829 | if( nRawProps ){ |
| 830 | int got; |
| 831 | char *zLine; |
| 832 | rec->pRawProps = pRawProps = fossil_malloc( nRawProps ); |
| 833 | got = fread(rec->pRawProps, 1, nRawProps, pIn); |
| 834 | if( got!=nRawProps ){ |
| 835 | fossil_fatal("short read: got %d of %d bytes", got, nRawProps); |
| 836 | } |
| 837 | if( memcmp(&pRawProps[got-10], "PROPS-END\n", 10)!=0 ){ |
| 838 | fossil_fatal("svn-dump data ended unexpectedly"); |
| 839 | } |
| 840 | zLine = pRawProps; |
| 841 | while( zLine<(pRawProps+nRawProps-10) ){ |
| 842 | char *eol; |
| 843 | int propLen; |
| 844 | if( zLine[0]=='D' ){ |
| 845 | propLen = atoi(&zLine[2]); |
| 846 | eol = strchr(zLine, '\n'); |
| 847 | zLine = eol+1+propLen+1; |
| 848 | }else{ |
| 849 | if( zLine[0]!='K' ){ |
| 850 | fossil_fatal("svn-dump data format broken"); |
| 851 | } |
| 852 | propLen = atoi(&zLine[2]); |
| 853 | eol = strchr(zLine, '\n'); |
| 854 | zLine = eol+1; |
| 855 | eol = zLine+propLen; |
| 856 | if( *eol!='\n' ){ |
| 857 | fossil_fatal("svn-dump data format broken"); |
| 858 | } |
| 859 | *eol = 0; |
| 860 | rec->nProps += 1; |
| 861 | rec->aProps = fossil_realloc(rec->aProps, |
| 862 | sizeof(rec->aProps[0])*rec->nProps); |
| 863 | rec->aProps[rec->nProps-1].zKey = zLine; |
| 864 | zLine = eol+1; |
| 865 | if( zLine[0]!='V' ){ |
| 866 | fossil_fatal("svn-dump data format broken"); |
| 867 | } |
| 868 | propLen = atoi(&zLine[2]); |
| 869 | eol = strchr(zLine, '\n'); |
| 870 | zLine = eol+1; |
| 871 | eol = zLine+propLen; |
| 872 | if( *eol!='\n' ){ |
| 873 | fossil_fatal("svn-dump data format broken"); |
| 874 | } |
| 875 | *eol = 0; |
| 876 | rec->aProps[rec->nProps-1].zVal = zLine; |
| 877 | zLine = eol+1; |
| 878 | } |
| 879 | } |
| 880 | } |
| 881 | } |
| 882 | |
| 883 | static int svn_read_rec(FILE *pIn, SvnRecord *rec){ |
| 884 | const char *zLen; |
| 885 | int nLen = 0; |
| 886 | if( svn_read_headers(pIn, rec)==0 ) return 0; |
| 887 | svn_read_props(pIn, rec); |
| 888 | blob_zero(&rec->content); |
| 889 | zLen = svn_find_header(*rec, "Text-content-length"); |
| 890 | if( zLen ){ |
| 891 | rec->contentFlag = 1; |
| 892 | nLen = atoi(zLen); |
| 893 | blob_read_from_channel(&rec->content, pIn, nLen); |
| 894 | if( blob_size(&rec->content)!=nLen ){ |
| 895 | fossil_fatal("short read: got %d of %d bytes", |
| 896 | blob_size(&rec->content), nLen |
| 897 | ); |
| 898 | } |
| 899 | }else{ |
| 900 | rec->contentFlag = 0; |
| 901 | } |
| 902 | return 1; |
| 903 | } |
| 904 | |
| 905 | /* |
| 906 | ** Returns the UUID for the RID, or NULL if not found. |
| 907 | ** The returned string is allocated via db_text() and must be |
| 908 | ** free()d by the caller. |
| 909 | */ |
| 910 | char * rid_to_uuid(int rid) |
| 911 | { |
| 912 | return db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 913 | } |
| 914 | |
| 915 | #define SVN_UNKNOWN 0 |
| 916 | #define SVN_TRUNK 1 |
| 917 | #define SVN_BRANCH 2 |
| 918 | #define SVN_TAG 3 |
| 919 | |
| 920 | #define MAX_INT_32 (0x7FFFFFFFL) |
| 921 | |
| 922 | static void svn_finish_revision(){ |
| 923 | Blob manifest; |
| 924 | static Stmt getChanges; |
| 925 | static Stmt getFiles; |
| 926 | static Stmt setRid; |
| 927 | Blob mcksum; |
| 928 | |
| 929 | blob_zero(&manifest); |
| 930 | db_static_prepare(&getChanges, "SELECT tid, tname, ttype, tparent" |
| 931 | " FROM xrevisions, xbranches ON (tbranch=tid)" |
| 932 | " WHERE trid ISNULL"); |
| 933 | db_static_prepare(&getFiles, "SELECT tpath, tuuid, tperm FROM xfiles" |
| 934 | " WHERE tbranch=:branch ORDER BY tpath"); |
| 935 | db_prepare(&setRid, "UPDATE xrevisions SET trid=:rid" |
| 936 | " WHERE trev=%d AND tbranch=:branch", gsvn.rev); |
| 937 | while( db_step(&getChanges)==SQLITE_ROW ){ |
| 938 | int branchId = db_column_int(&getChanges, 0); |
| 939 | const char *zBranch = db_column_text(&getChanges, 1); |
| 940 | int branchType = db_column_int(&getChanges, 2); |
| 941 | int parentRid = db_column_int(&getChanges, 3); |
| 942 | int mergeRid = parentRid; |
| 943 | Manifest *pParentManifest = 0; |
| 944 | ManifestFile *pParentFile = 0; |
| 945 | int sameAsParent = 1; |
| 946 | int parentBranch = 0; |
| 947 | if( !bag_find(&gsvn.newBranches, branchId) ){ |
| 948 | parentRid = db_int(0, "SELECT trid, max(trev) FROM xrevisions" |
| 949 | " WHERE trev<%d AND tbranch=%d", |
| 950 | gsvn.rev, branchId); |
| 951 | } |
| 952 | if( parentRid>0 ){ |
| 953 | pParentManifest = manifest_get(parentRid, CFTYPE_MANIFEST, 0); |
| 954 | pParentFile = manifest_file_next(pParentManifest, 0); |
| 955 | parentBranch = db_int(0, "SELECT tbranch FROM xrevisions WHERE trid=%d", |
| 956 | parentRid); |
| 957 | if( parentBranch!=branchId && branchType!=SVN_TAG ){ |
| 958 | sameAsParent = 0; |
| 959 | } |
| 960 | } |
| 961 | if( mergeRid<MAX_INT_32 ){ |
| 962 | if( gsvn.zComment ){ |
| 963 | blob_appendf(&manifest, "C %F\n", gsvn.zComment); |
| 964 | }else{ |
| 965 | blob_append(&manifest, "C (no\\scomment)\n", 16); |
| 966 | } |
| 967 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 968 | db_bind_int(&getFiles, ":branch", branchId); |
| 969 | while( db_step(&getFiles)==SQLITE_ROW ){ |
| 970 | const char *zFile = db_column_text(&getFiles, 0); |
| 971 | const char *zUuid = db_column_text(&getFiles, 1); |
| 972 | const char *zPerm = db_column_text(&getFiles, 2); |
| 973 | if( zPerm ){ |
| 974 | blob_appendf(&manifest, "F %F %s %s\n", zFile, zUuid, zPerm); |
| 975 | }else{ |
| 976 | blob_appendf(&manifest, "F %F %s\n", zFile, zUuid); |
| 977 | } |
| 978 | if( sameAsParent ){ |
| 979 | if( !pParentFile |
| 980 | || fossil_strcmp(pParentFile->zName,zFile)!=0 |
| 981 | || fossil_strcmp(pParentFile->zUuid,zUuid)!=0 |
| 982 | || fossil_strcmp(pParentFile->zPerm,zPerm)!=0 |
| 983 | ){ |
| 984 | sameAsParent = 0; |
| 985 | }else{ |
| 986 | pParentFile = manifest_file_next(pParentManifest, 0); |
| 987 | } |
| 988 | } |
| 989 | } |
| 990 | if( pParentFile ){ |
| 991 | sameAsParent = 0; |
| 992 | } |
| 993 | db_reset(&getFiles); |
| 994 | if( !sameAsParent ){ |
| 995 | if( parentRid>0 ){ |
| 996 | char *zParentUuid = rid_to_uuid(parentRid); |
| 997 | if( parentRid==mergeRid || mergeRid==0){ |
| 998 | char *zParentBranch = |
| 999 | db_text(0, "SELECT tname FROM xbranches WHERE tid=%d", |
| 1000 | parentBranch |
| 1001 | ); |
| 1002 | blob_appendf(&manifest, "P %s\n", zParentUuid); |
| 1003 | blob_appendf(&manifest, "T *branch * %F\n", zBranch); |
| 1004 | blob_appendf(&manifest, "T *sym-%F *\n", zBranch); |
| 1005 | if( gsvn.incrFlag ){ |
| 1006 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); |
| 1007 | } |
| 1008 | blob_appendf(&manifest, "T -sym-%F *\n", zParentBranch); |
| 1009 | fossil_free(zParentBranch); |
| 1010 | }else{ |
| 1011 | char *zMergeUuid = rid_to_uuid(mergeRid); |
| 1012 | blob_appendf(&manifest, "P %s %s\n", zParentUuid, zMergeUuid); |
| 1013 | if( gsvn.incrFlag ){ |
| 1014 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); |
| 1015 | } |
| 1016 | fossil_free(zMergeUuid); |
| 1017 | } |
| 1018 | fossil_free(zParentUuid); |
| 1019 | }else{ |
| 1020 | blob_appendf(&manifest, "T *branch * %F\n", zBranch); |
| 1021 | blob_appendf(&manifest, "T *sym-%F *\n", zBranch); |
| 1022 | if( gsvn.incrFlag ){ |
| 1023 | blob_appendf(&manifest, "T +sym-svn-rev-%d *\n", gsvn.rev); |
| 1024 | } |
| 1025 | } |
| 1026 | }else if( branchType==SVN_TAG ){ |
| 1027 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1028 | blob_reset(&manifest); |
| 1029 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1030 | blob_appendf(&manifest, "T +sym-%F %s\n", zBranch, zParentUuid); |
| 1031 | fossil_free(zParentUuid); |
| 1032 | } |
| 1033 | }else{ |
| 1034 | char *zParentUuid = rid_to_uuid(parentRid); |
| 1035 | blob_appendf(&manifest, "D %s\n", gsvn.zDate); |
| 1036 | if( branchType!=SVN_TAG ){ |
| 1037 | blob_appendf(&manifest, "T +closed %s\n", zParentUuid); |
| 1038 | }else{ |
| 1039 | blob_appendf(&manifest, "T -sym-%F %s\n", zBranch, zParentUuid); |
| 1040 | } |
| 1041 | fossil_free(zParentUuid); |
| 1042 | } |
| 1043 | if( gsvn.zUser ){ |
| 1044 | blob_appendf(&manifest, "U %F\n", gsvn.zUser); |
| 1045 | }else{ |
| 1046 | const char *zUserOvrd = find_option("user-override",0,1); |
| 1047 | blob_appendf(&manifest, "U %F\n", zUserOvrd ? zUserOvrd : login_name()); |
| 1048 | } |
| 1049 | md5sum_blob(&manifest, &mcksum); |
| 1050 | blob_appendf(&manifest, "Z %b\n", &mcksum); |
| 1051 | blob_reset(&mcksum); |
| 1052 | if( !sameAsParent ){ |
| 1053 | int rid = content_put(&manifest); |
| 1054 | db_bind_int(&setRid, ":branch", branchId); |
| 1055 | db_bind_int(&setRid, ":rid", rid); |
| 1056 | db_step(&setRid); |
| 1057 | db_reset(&setRid); |
| 1058 | }else if( branchType==SVN_TAG ){ |
| 1059 | content_put(&manifest); |
| 1060 | db_bind_int(&setRid, ":branch", branchId); |
| 1061 | db_bind_int(&setRid, ":rid", parentRid); |
| 1062 | db_step(&setRid); |
| 1063 | db_reset(&setRid); |
| 1064 | }else if( mergeRid==MAX_INT_32 ){ |
| 1065 | content_put(&manifest); |
| 1066 | db_multi_exec("DELETE FROM xrevisions WHERE tbranch=%d AND trev=%d", |
| 1067 | branchId, gsvn.rev); |
| 1068 | }else{ |
| 1069 | db_multi_exec("DELETE FROM xrevisions WHERE tbranch=%d AND trev=%d", |
| 1070 | branchId, gsvn.rev); |
| 1071 | } |
| 1072 | blob_reset(&manifest); |
| 1073 | manifest_destroy(pParentManifest); |
| 1074 | } |
| 1075 | db_reset(&getChanges); |
| 1076 | db_finalize(&setRid); |
| 1077 | } |
| 1078 | |
| 1079 | static u64 svn_get_varint(const char **pz){ |
| 1080 | unsigned int v = 0; |
| 1081 | do{ |
| 1082 | v = (v<<7) | ((*pz)[0]&0x7f); |
| 1083 | }while( (*pz)++[0]&0x80 ); |
| 1084 | return v; |
| 1085 | } |
| 1086 | |
| 1087 | static void svn_apply_svndiff(Blob *pDiff, Blob *pSrc, Blob *pOut){ |
| 1088 | const char *zDiff = blob_buffer(pDiff); |
| 1089 | char *zOut; |
| 1090 | if( blob_size(pDiff)<4 || memcmp(zDiff, "SVN", 4)!=0 ){ |
| 1091 | fossil_fatal("Invalid svndiff0 format"); |
| 1092 | } |
| 1093 | zDiff += 4; |
| 1094 | blob_zero(pOut); |
| 1095 | while( zDiff<(blob_buffer(pDiff)+blob_size(pDiff)) ){ |
| 1096 | u64 lenOut, lenInst, lenData, lenOld; |
| 1097 | const char *zInst; |
| 1098 | const char *zData; |
| 1099 | |
| 1100 | u64 offSrc = svn_get_varint(&zDiff); |
| 1101 | /*lenSrc =*/ svn_get_varint(&zDiff); |
| 1102 | lenOut = svn_get_varint(&zDiff); |
| 1103 | lenInst = svn_get_varint(&zDiff); |
| 1104 | lenData = svn_get_varint(&zDiff); |
| 1105 | zInst = zDiff; |
| 1106 | zData = zInst+lenInst; |
| 1107 | lenOld = blob_size(pOut); |
| 1108 | blob_resize(pOut, lenOut+lenOld); |
| 1109 | zOut = blob_buffer(pOut)+lenOld; |
| 1110 | while( zDiff<zInst+lenInst ){ |
| 1111 | u64 lenCpy = (*zDiff)&0x3f; |
| 1112 | const char *zCpy; |
| 1113 | switch( (*zDiff)&0xC0 ){ |
| 1114 | case 0x00: zCpy = blob_buffer(pSrc)+offSrc; break; |
| 1115 | case 0x40: zCpy = blob_buffer(pOut); break; |
| 1116 | case 0x80: zCpy = zData; break; |
| 1117 | default: fossil_fatal("Invalid svndiff0 instruction"); |
| 1118 | } |
| 1119 | zDiff++; |
| 1120 | if( lenCpy==0 ){ |
| 1121 | lenCpy = svn_get_varint(&zDiff); |
| 1122 | } |
| 1123 | if( zCpy!=zData ){ |
| 1124 | zCpy += svn_get_varint(&zDiff); |
| 1125 | }else{ |
| 1126 | zData += lenCpy; |
| 1127 | } |
| 1128 | while( lenCpy-- > 0 ){ |
| 1129 | *zOut++ = *zCpy++; |
| 1130 | } |
| 1131 | } |
| 1132 | zDiff += lenData; |
| 1133 | } |
| 1134 | } |
| 1135 | |
| 1136 | /* |
| 1137 | ** Extract the branch or tag that the given path is on. Return the branch ID. |
| 1138 | */ |
| 1139 | static int svn_parse_path(char *zPath, char **zFile, int *type){ |
| 1140 | char *zBranch = 0; |
| 1141 | int branchId = 0; |
| 1142 | *type = SVN_UNKNOWN; |
| 1143 | *zFile = 0; |
| 1144 | if( gsvn.lenTrunk==0 ){ |
| 1145 | zBranch = "trunk"; |
| 1146 | *zFile = zPath; |
| 1147 | *type = SVN_TRUNK; |
| 1148 | }else |
| 1149 | if( strncmp(zPath, gsvn.zTrunk, gsvn.lenTrunk-1)==0 ){ |
| 1150 | if( zPath[gsvn.lenTrunk-1]=='/' || zPath[gsvn.lenTrunk-1]==0 ){ |
| 1151 | zBranch = "trunk"; |
| 1152 | *zFile = zPath+gsvn.lenTrunk; |
| 1153 | *type = SVN_TRUNK; |
| 1154 | }else{ |
| 1155 | zBranch = 0; |
| 1156 | *type = SVN_UNKNOWN; |
| 1157 | } |
| 1158 | }else{ |
| 1159 | if( strncmp(zPath, gsvn.zBranches, gsvn.lenBranches)==0 ){ |
| 1160 | *zFile = zBranch = zPath+gsvn.lenBranches; |
| 1161 | *type = SVN_BRANCH; |
| 1162 | }else |
| 1163 | if( strncmp(zPath, gsvn.zTags, gsvn.lenTags)==0 ){ |
| 1164 | *zFile = zBranch = zPath+gsvn.lenTags; |
| 1165 | *type = SVN_TAG; |
| 1166 | }else{ /* Not a branch, tag or trunk */ |
| 1167 | return 0; |
| 1168 | } |
| 1169 | while( **zFile && **zFile!='/' ){ (*zFile)++; } |
| 1170 | if( **zFile ){ |
| 1171 | **zFile = '\0'; |
| 1172 | (*zFile)++; |
| 1173 | } |
| 1174 | } |
| 1175 | if( *type!=SVN_UNKNOWN ){ |
| 1176 | branchId = db_int(0, |
| 1177 | "SELECT tid FROM xbranches WHERE tname=%Q AND ttype=%d", |
| 1178 | zBranch, *type); |
| 1179 | if( branchId==0 ){ |
| 1180 | db_multi_exec("INSERT INTO xbranches (tname, ttype) VALUES(%Q, %d)", |
| 1181 | zBranch, *type); |
| 1182 | branchId = db_last_insert_rowid(); |
| 1183 | } |
| 1184 | } |
| 1185 | return branchId; |
| 1186 | } |
| 1187 | |
| 1188 | /* |
| 1189 | ** Read the svn-dump format from pIn and insert the corresponding |
| 1190 | ** content into the database. |
| 1191 | */ |
| 1192 | static void svn_dump_import(FILE *pIn){ |
| 1193 | SvnRecord rec; |
| 1194 | int ver; |
| 1195 | char *zTemp; |
| 1196 | const char *zUuid; |
| 1197 | Stmt addFile; |
| 1198 | Stmt delPath; |
| 1199 | Stmt addRev; |
| 1200 | Stmt cpyPath; |
| 1201 | Stmt cpyRoot; |
| 1202 | Stmt revSrc; |
| 1203 | |
| 1204 | /* version */ |
| 1205 | if( svn_read_rec(pIn, &rec) |
| 1206 | && (zTemp = svn_find_header(rec, "SVN-fs-dump-format-version")) ){ |
| 1207 | ver = atoi(zTemp); |
| 1208 | if( ver!=2 && ver!=3 ){ |
| 1209 | fossil_fatal("Unknown svn-dump format version: %d", ver); |
| 1210 | } |
| 1211 | }else{ |
| 1212 | fossil_fatal("Input is not an svn-dump!"); |
| 1213 | } |
| 1214 | svn_free_rec(&rec); |
| 1215 | /* UUID */ |
| 1216 | if( !svn_read_rec(pIn, &rec) || !(zUuid = svn_find_header(rec, "UUID")) ){ |
| 1217 | /* Removed the following line since UUID is not actually used |
| 1218 | fossil_fatal("Missing UUID!"); */ |
| 1219 | } |
| 1220 | svn_free_rec(&rec); |
| 1221 | |
| 1222 | /* content */ |
| 1223 | db_prepare(&addFile, |
| 1224 | "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" |
| 1225 | " VALUES(:path, :branch, (SELECT uuid FROM blob WHERE rid=:rid), :perm)" |
| 1226 | ); |
| 1227 | db_prepare(&delPath, |
| 1228 | "DELETE FROM xfiles" |
| 1229 | " WHERE (tpath=:path OR (tpath>:path||'/' AND tpath<:path||'0'))" |
| 1230 | " AND tbranch=:branch" |
| 1231 | ); |
| 1232 | db_prepare(&addRev, |
| 1233 | "INSERT OR IGNORE INTO xrevisions (trev, tbranch) VALUES(:rev, :branch)" |
| 1234 | ); |
| 1235 | db_prepare(&cpyPath, |
| 1236 | "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" |
| 1237 | " SELECT :path||:sep||substr(filename, length(:srcpath)+2), :branch, uuid, perm" |
| 1238 | " FROM xfoci" |
| 1239 | " WHERE checkinID=:rid" |
| 1240 | " AND filename>:srcpath||'/'" |
| 1241 | " AND filename<:srcpath||'0'" |
| 1242 | ); |
| 1243 | db_prepare(&cpyRoot, |
| 1244 | "INSERT INTO xfiles (tpath, tbranch, tuuid, tperm)" |
| 1245 | " SELECT :path||:sep||filename, :branch, uuid, perm" |
| 1246 | " FROM xfoci" |
| 1247 | " WHERE checkinID=:rid" |
| 1248 | ); |
| 1249 | db_prepare(&revSrc, |
| 1250 | "UPDATE xrevisions SET tparent=:parent" |
| 1251 | " WHERE trev=:rev AND tbranch=:branch AND tparent<:parent" |
| 1252 | ); |
| 1253 | gsvn.rev = -1; |
| 1254 | bag_init(&gsvn.newBranches); |
| 1255 | while( svn_read_rec(pIn, &rec) ){ |
| 1256 | if( (zTemp = svn_find_header(rec, "Revision-number")) ){ /* revision node */ |
| 1257 | /* finish previous revision */ |
| 1258 | char *zDate = NULL; |
| 1259 | if( gsvn.rev>=0 ){ |
| 1260 | svn_finish_revision(); |
| 1261 | fossil_free(gsvn.zUser); |
| 1262 | fossil_free(gsvn.zComment); |
| 1263 | fossil_free(gsvn.zDate); |
| 1264 | bag_clear(&gsvn.newBranches); |
| 1265 | } |
| 1266 | /* start new revision */ |
| 1267 | gsvn.rev = atoi(zTemp); |
| 1268 | gsvn.zUser = mprintf("%s", svn_find_prop(rec, "svn:author")); |
| 1269 | gsvn.zComment = mprintf("%s", svn_find_prop(rec, "svn:log")); |
| 1270 | zDate = svn_find_prop(rec, "svn:date"); |
| 1271 | if( zDate ){ |
| 1272 | gsvn.zDate = date_in_standard_format(zDate); |
| 1273 | }else{ |
| 1274 | gsvn.zDate = date_in_standard_format("now"); |
| 1275 | } |
| 1276 | db_bind_int(&addRev, ":rev", gsvn.rev); |
| 1277 | fossil_print("\rImporting SVN revision: %d", gsvn.rev); |
| 1278 | }else |
| 1279 | if( (zTemp = svn_find_header(rec, "Node-path")) ){ /* file/dir node */ |
| 1280 | char *zFile; |
| 1281 | int branchType; |
| 1282 | int branchId = svn_parse_path(zTemp, &zFile, &branchType); |
| 1283 | char *zAction = svn_find_header(rec, "Node-action"); |
| 1284 | char *zKind = svn_find_header(rec, "Node-kind"); |
| 1285 | char *zPerm = svn_find_prop(rec, "svn:executable") ? "x" : 0; |
| 1286 | int deltaFlag = 0; |
| 1287 | int srcRev = 0; |
| 1288 | if( branchId==0 ){ |
| 1289 | svn_free_rec(&rec); |
| 1290 | continue; |
| 1291 | } |
| 1292 | if( (zTemp = svn_find_header(rec, "Text-delta")) ){ |
| 1293 | deltaFlag = strncmp(zTemp, "true", 4)==0; |
| 1294 | } |
| 1295 | if( strncmp(zAction, "delete", 6)==0 |
| 1296 | || strncmp(zAction, "replace", 7)==0 ) |
| 1297 | { |
| 1298 | db_bind_int(&addRev, ":branch", branchId); |
| 1299 | db_step(&addRev); |
| 1300 | db_reset(&addRev); |
| 1301 | if( zFile[0]!=0 ){ |
| 1302 | db_bind_text(&delPath, ":path", zFile); |
| 1303 | db_bind_int(&delPath, ":branch", branchId); |
| 1304 | db_step(&delPath); |
| 1305 | db_reset(&delPath); |
| 1306 | }else{ |
| 1307 | db_multi_exec("DELETE FROM xfiles WHERE tbranch=%d", branchId); |
| 1308 | db_bind_int(&revSrc, ":parent", MAX_INT_32); |
| 1309 | db_bind_int(&revSrc, ":rev", gsvn.rev); |
| 1310 | db_bind_int(&revSrc, ":branch", branchId); |
| 1311 | db_step(&revSrc); |
| 1312 | db_reset(&revSrc); |
| 1313 | } |
| 1314 | } /* no 'else' here since 'replace' does both a 'delete' and an 'add' */ |
| 1315 | if( strncmp(zAction, "add", 3)==0 |
| 1316 | || strncmp(zAction, "replace", 7)==0 ) |
| 1317 | { |
| 1318 | char *zSrcPath = svn_find_header(rec, "Node-copyfrom-path"); |
| 1319 | char *zSrcFile; |
| 1320 | int srcRid = 0; |
| 1321 | if( zSrcPath ){ |
| 1322 | int srcBranch; |
| 1323 | zTemp = svn_find_header(rec, "Node-copyfrom-rev"); |
| 1324 | if( zTemp ){ |
| 1325 | srcRev = atoi(zTemp); |
| 1326 | }else{ |
| 1327 | fossil_fatal("Missing copyfrom-rev"); |
| 1328 | } |
| 1329 | srcBranch = svn_parse_path(zSrcPath, &zSrcFile, &branchType); |
| 1330 | if( srcBranch==0 ){ |
| 1331 | fossil_fatal("Copy from path outside the import paths"); |
| 1332 | } |
| 1333 | srcRid = db_int(0, "SELECT trid, max(trev) FROM xrevisions" |
| 1334 | " WHERE trev<=%d AND tbranch=%d", |
| 1335 | srcRev, srcBranch); |
| 1336 | if( srcRid>0 && srcBranch!=branchId ){ |
| 1337 | db_bind_int(&addRev, ":branch", branchId); |
| 1338 | db_step(&addRev); |
| 1339 | db_reset(&addRev); |
| 1340 | db_bind_int(&revSrc, ":parent", srcRid); |
| 1341 | db_bind_int(&revSrc, ":rev", gsvn.rev); |
| 1342 | db_bind_int(&revSrc, ":branch", branchId); |
| 1343 | db_step(&revSrc); |
| 1344 | db_reset(&revSrc); |
| 1345 | } |
| 1346 | } |
| 1347 | if( zKind==0 ){ |
| 1348 | fossil_fatal("Missing Node-kind"); |
| 1349 | }else if( strncmp(zKind, "dir", 3)==0 ){ |
| 1350 | if( zSrcPath ){ |
| 1351 | if( srcRid>0 ){ |
| 1352 | if( zSrcFile[0]==0 ){ |
| 1353 | db_bind_text(&cpyRoot, ":path", zFile); |
| 1354 | if( zFile[0]!=0 ){ |
| 1355 | db_bind_text(&cpyRoot, ":sep", "/"); |
| 1356 | }else{ |
| 1357 | db_bind_text(&cpyRoot, ":sep", ""); |
| 1358 | } |
| 1359 | db_bind_int(&cpyRoot, ":branch", branchId); |
| 1360 | db_bind_int(&cpyRoot, ":rid", srcRid); |
| 1361 | db_step(&cpyRoot); |
| 1362 | db_reset(&cpyRoot); |
| 1363 | }else{ |
| 1364 | db_bind_text(&cpyPath, ":path", zFile); |
| 1365 | if( zFile[0]!=0 ){ |
| 1366 | db_bind_text(&cpyPath, ":sep", "/"); |
| 1367 | }else{ |
| 1368 | db_bind_text(&cpyPath, ":sep", ""); |
| 1369 | } |
| 1370 | db_bind_int(&cpyPath, ":branch", branchId); |
| 1371 | db_bind_text(&cpyPath, ":srcpath", zSrcFile); |
| 1372 | db_bind_int(&cpyPath, ":rid", srcRid); |
| 1373 | db_step(&cpyPath); |
| 1374 | db_reset(&cpyPath); |
| 1375 | } |
| 1376 | } |
| 1377 | } |
| 1378 | if( zFile[0]==0 ){ |
| 1379 | bag_insert(&gsvn.newBranches, branchId); |
| 1380 | } |
| 1381 | }else{ |
| 1382 | int rid = 0; |
| 1383 | if( zSrcPath ){ |
| 1384 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid=(" |
| 1385 | " SELECT uuid FROM xfoci" |
| 1386 | " WHERE checkinID=%d AND filename=%Q" |
| 1387 | ")", |
| 1388 | srcRid, zSrcFile); |
| 1389 | } |
| 1390 | if( deltaFlag ){ |
| 1391 | Blob deltaSrc; |
| 1392 | Blob target; |
| 1393 | if( rid!=0 ){ |
| 1394 | content_get(rid, &deltaSrc); |
| 1395 | }else{ |
| 1396 | blob_zero(&deltaSrc); |
| 1397 | } |
| 1398 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1399 | rid = content_put(&target); |
| 1400 | }else if( rec.contentFlag ){ |
| 1401 | rid = content_put(&rec.content); |
| 1402 | } |
| 1403 | db_bind_text(&addFile, ":path", zFile); |
| 1404 | db_bind_int(&addFile, ":branch", branchId); |
| 1405 | db_bind_int(&addFile, ":rid", rid); |
| 1406 | db_bind_text(&addFile, ":perm", zPerm); |
| 1407 | db_step(&addFile); |
| 1408 | db_reset(&addFile); |
| 1409 | db_bind_int(&addRev, ":branch", branchId); |
| 1410 | db_step(&addRev); |
| 1411 | db_reset(&addRev); |
| 1412 | } |
| 1413 | }else |
| 1414 | if( strncmp(zAction, "change", 6)==0 ){ |
| 1415 | int rid = 0; |
| 1416 | if( zKind==0 ){ |
| 1417 | fossil_fatal("Missing Node-kind"); |
| 1418 | } |
| 1419 | if( strncmp(zKind, "dir", 3)!=0 ){ |
| 1420 | if( deltaFlag ){ |
| 1421 | Blob deltaSrc; |
| 1422 | Blob target; |
| 1423 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid=(" |
| 1424 | " SELECT uuid FROM xfiles" |
| 1425 | " WHERE tpath=%Q AND tbranch=%d" |
| 1426 | ")", zFile, branchId); |
| 1427 | content_get(rid, &deltaSrc); |
| 1428 | svn_apply_svndiff(&rec.content, &deltaSrc, &target); |
| 1429 | rid = content_put(&target); |
| 1430 | }else{ |
| 1431 | rid = content_put(&rec.content); |
| 1432 | } |
| 1433 | db_bind_text(&addFile, ":path", zFile); |
| 1434 | db_bind_int(&addFile, ":branch", branchId); |
| 1435 | db_bind_int(&addFile, ":rid", rid); |
| 1436 | db_bind_text(&addFile, ":perm", zPerm); |
| 1437 | db_step(&addFile); |
| 1438 | db_reset(&addFile); |
| 1439 | db_bind_int(&addRev, ":branch", branchId); |
| 1440 | db_step(&addRev); |
| 1441 | db_reset(&addRev); |
| 1442 | } |
| 1443 | }else |
| 1444 | if( strncmp(zAction, "delete", 6)!=0 ){ /* already did this one above */ |
| 1445 | fossil_fatal("Unknown Node-action"); |
| 1446 | } |
| 1447 | }else{ |
| 1448 | fossil_fatal("Unknown record type"); |
| 1449 | } |
| 1450 | svn_free_rec(&rec); |
| 1451 | } |
| 1452 | svn_finish_revision(); |
| 1453 | fossil_free(gsvn.zUser); |
| 1454 | fossil_free(gsvn.zComment); |
| 1455 | fossil_free(gsvn.zDate); |
| 1456 | db_finalize(&addFile); |
| 1457 | db_finalize(&delPath); |
| 1458 | db_finalize(&addRev); |
| 1459 | db_finalize(&cpyPath); |
| 1460 | db_finalize(&cpyRoot); |
| 1461 | db_finalize(&revSrc); |
| 1462 | fossil_print(" Done!\n"); |
| 1463 | } |
| 1464 | |
| 1465 | /* |
| 1466 | ** COMMAND: import |
| 1467 | ** |
| 1468 | ** Usage: %fossil import ?--git? ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? |
| 1469 | ** or: %fossil import --svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE? |
| 1470 | ** |
| 1471 | ** Read interchange format generated by another VCS and use it to |
| 1472 | ** construct a new Fossil repository named by the NEW-REPOSITORY |
| 1473 | ** argument. If no input file is supplied the interchange format |
| 1474 | ** data is read from standard input. |
| 1475 | ** |
| 1476 | ** The following formats are currently understood by this command |
| 1477 | ** |
| 1478 | ** --git Import from the git-fast-export file format (default) |
| 1479 | ** |
| 1480 | ** --svn Import from the svnadmin-dump file format. The default |
| 1481 | ** behaviour (unless overridden by --flat) is to treat 3 |
| 1482 | ** folders in the SVN root as special, following the |
| 1483 | ** common layout of SVN repositories. These are (by |
| 1484 | ** default) trunk/, branches/ and tags/ |
| 1485 | ** Options: |
| 1486 | ** --trunk FOLDER Name of trunk folder |
| 1487 | ** --branches FOLDER Name of branches folder |
| 1488 | ** --tags FOLDER Name of tags folder |
| 1489 | ** --base PATH Path to project root in repository |
| 1490 | ** --flat The whole dump is a single branch |
| 1491 | ** |
| 1492 | ** Common Options: |
| 1493 | ** -i|--incremental allow importing into an existing repository |
| 1494 | ** -f|--force overwrite repository if already exist |
| 1495 | ** |
| 1496 | ** The --incremental option allows an existing repository to be extended |
| 1497 | ** with new content. |
| 1498 | ** |
| 1499 | ** |
| 1500 | ** See also: export |
| 1501 | */ |
| 1502 | void import_cmd(void){ |
| 1503 | char *zPassword; |
| 1504 | FILE *pIn; |
| 1505 | Stmt q; |
| 1506 | int forceFlag = find_option("force", "f", 0)!=0; |
| 1507 | int svnFlag = find_option("svn", 0, 0)!=0; |
| 1508 | |
| 1509 | /* Options common to all input formats */ |
| 1510 | int incrFlag = find_option("incremental", "i", 0)!=0; |
| 1511 | |
| 1512 | /* Options for --svn only */ |
| 1513 | const char *zBase=""; |
| 1514 | int flatFlag=0; |
| 1515 | |
| 1516 | if( svnFlag ){ |
| 1517 | /* Get --svn related options here, so verify_all_options() fail when svn |
| 1518 | * only option are specify with --git |
| 1519 | */ |
| 1520 | zBase = find_option("base", 0, 1); |
| 1521 | flatFlag = find_option("flat", 0, 0)!=0; |
| 1522 | gsvn.zTrunk = find_option("trunk", 0, 1); |
| 1523 | gsvn.zBranches = find_option("branches", 0, 1); |
| 1524 | gsvn.zTags = find_option("tags", 0, 1); |
| 1525 | gsvn.incrFlag = incrFlag; |
| 1526 | }else{ |
| 1527 | find_option("git",0,0); /* Skip the --git option for now */ |
| 1528 | } |
| 1529 | verify_all_options(); |
| 1530 | |
| 1531 | if( g.argc!=3 && g.argc!=4 ){ |
| 1532 | usage("--git|--svn ?OPTIONS? NEW-REPOSITORY ?INPUT-FILE?"); |
| 1533 | } |
| 1534 | if( g.argc==4 ){ |
| 1535 | pIn = fossil_fopen(g.argv[3], "rb"); |
| 1536 | }else{ |
| 1537 | pIn = stdin; |
| @@ -767,14 +1543,66 @@ | |
| 1543 | } |
| 1544 | db_open_repository(g.argv[2]); |
| 1545 | db_open_config(0); |
| 1546 | |
| 1547 | db_begin_transaction(); |
| 1548 | if( !incrFlag ) db_initial_setup(0, 0, 0); |
| 1549 | |
| 1550 | if( svnFlag ){ |
| 1551 | db_multi_exec( |
| 1552 | "CREATE TEMP TABLE xrevisions(" |
| 1553 | " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," |
| 1554 | " UNIQUE(tbranch, trev)" |
| 1555 | ");" |
| 1556 | "CREATE INDEX temp.i_xrevisions ON xrevisions(trid);" |
| 1557 | "CREATE TEMP TABLE xfiles(" |
| 1558 | " tpath TEXT, tbranch INT, tuuid TEXT, tperm TEXT," |
| 1559 | " UNIQUE (tbranch, tpath) ON CONFLICT REPLACE" |
| 1560 | ");" |
| 1561 | "CREATE TEMP TABLE xbranches(" |
| 1562 | " tid INTEGER PRIMARY KEY, tname TEXT, ttype INT," |
| 1563 | " UNIQUE(tname, ttype)" |
| 1564 | ");" |
| 1565 | "CREATE VIRTUAL TABLE temp.xfoci USING files_of_checkin;" |
| 1566 | ); |
| 1567 | if( zBase==0 ){ zBase = ""; } |
| 1568 | if( strlen(zBase)>0 ){ |
| 1569 | if( zBase[strlen(zBase)-1]!='/' ){ |
| 1570 | zBase = mprintf("%s/", zBase); |
| 1571 | } |
| 1572 | } |
| 1573 | if( flatFlag ){ |
| 1574 | gsvn.zTrunk = zBase; |
| 1575 | gsvn.zBranches = 0; |
| 1576 | gsvn.zTags = 0; |
| 1577 | gsvn.lenTrunk = strlen(zBase); |
| 1578 | gsvn.lenBranches = 0; |
| 1579 | gsvn.lenTags = 0; |
| 1580 | }else{ |
| 1581 | if( gsvn.zTrunk==0 ){ gsvn.zTrunk = "trunk/"; } |
| 1582 | if( gsvn.zBranches==0 ){ gsvn.zBranches = "branches/"; } |
| 1583 | if( gsvn.zTags==0 ){ gsvn.zTags = "tags/"; } |
| 1584 | gsvn.zTrunk = mprintf("%s%s", zBase, gsvn.zTrunk); |
| 1585 | gsvn.zBranches = mprintf("%s%s", zBase, gsvn.zBranches); |
| 1586 | gsvn.zTags = mprintf("%s%s", zBase, gsvn.zTags); |
| 1587 | gsvn.lenTrunk = strlen(gsvn.zTrunk); |
| 1588 | gsvn.lenBranches = strlen(gsvn.zBranches); |
| 1589 | gsvn.lenTags = strlen(gsvn.zTags); |
| 1590 | if( gsvn.zTrunk[gsvn.lenTrunk-1]!='/' ){ |
| 1591 | gsvn.zTrunk = mprintf("%s/", gsvn.zTrunk); |
| 1592 | gsvn.lenTrunk++; |
| 1593 | } |
| 1594 | if( gsvn.zBranches[gsvn.lenBranches-1]!='/' ){ |
| 1595 | gsvn.zBranches = mprintf("%s/", gsvn.zBranches); |
| 1596 | gsvn.lenBranches++; |
| 1597 | } |
| 1598 | if( gsvn.zTags[gsvn.lenTags-1]!='/' ){ |
| 1599 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1600 | gsvn.lenTags++; |
| 1601 | } |
| 1602 | } |
| 1603 | svn_dump_import(pIn); |
| 1604 | }else{ |
| 1605 | /* The following temp-tables are used to hold information needed for |
| 1606 | ** the import. |
| 1607 | ** |
| 1608 | ** The XMARK table provides a mapping from fast-import "marks" and symbols |
| @@ -807,10 +1635,12 @@ | |
| 1635 | fast_insert_content(&record, 0, 0); |
| 1636 | import_reset(0); |
| 1637 | } |
| 1638 | db_finalize(&q); |
| 1639 | } |
| 1640 | |
| 1641 | verify_cancel(); |
| 1642 | db_end_transaction(0); |
| 1643 | db_begin_transaction(); |
| 1644 | fossil_print("Rebuilding repository meta-data...\n"); |
| 1645 | rebuild_db(0, 1, !incrFlag); |
| 1646 | verify_cancel(); |
| 1647 |
+1
| --- src/json_config.c | ||
| +++ src/json_config.c | ||
| @@ -81,10 +81,11 @@ | ||
| 81 | 81 | { "keep-glob", CONFIGSET_PROJ }, |
| 82 | 82 | { "crnl-glob", CONFIGSET_PROJ }, |
| 83 | 83 | { "encoding-glob", CONFIGSET_PROJ }, |
| 84 | 84 | { "empty-dirs", CONFIGSET_PROJ }, |
| 85 | 85 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 86 | +{ "dotfiles", CONFIGSET_PROJ }, | |
| 86 | 87 | |
| 87 | 88 | { "ticket-table", CONFIGSET_TKT }, |
| 88 | 89 | { "ticket-common", CONFIGSET_TKT }, |
| 89 | 90 | { "ticket-change", CONFIGSET_TKT }, |
| 90 | 91 | { "ticket-newpage", CONFIGSET_TKT }, |
| 91 | 92 |
| --- src/json_config.c | |
| +++ src/json_config.c | |
| @@ -81,10 +81,11 @@ | |
| 81 | { "keep-glob", CONFIGSET_PROJ }, |
| 82 | { "crnl-glob", CONFIGSET_PROJ }, |
| 83 | { "encoding-glob", CONFIGSET_PROJ }, |
| 84 | { "empty-dirs", CONFIGSET_PROJ }, |
| 85 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 86 | |
| 87 | { "ticket-table", CONFIGSET_TKT }, |
| 88 | { "ticket-common", CONFIGSET_TKT }, |
| 89 | { "ticket-change", CONFIGSET_TKT }, |
| 90 | { "ticket-newpage", CONFIGSET_TKT }, |
| 91 |
| --- src/json_config.c | |
| +++ src/json_config.c | |
| @@ -81,10 +81,11 @@ | |
| 81 | { "keep-glob", CONFIGSET_PROJ }, |
| 82 | { "crnl-glob", CONFIGSET_PROJ }, |
| 83 | { "encoding-glob", CONFIGSET_PROJ }, |
| 84 | { "empty-dirs", CONFIGSET_PROJ }, |
| 85 | { "allow-symlinks", CONFIGSET_PROJ }, |
| 86 | { "dotfiles", CONFIGSET_PROJ }, |
| 87 | |
| 88 | { "ticket-table", CONFIGSET_TKT }, |
| 89 | { "ticket-common", CONFIGSET_TKT }, |
| 90 | { "ticket-change", CONFIGSET_TKT }, |
| 91 | { "ticket-newpage", CONFIGSET_TKT }, |
| 92 |
+39
-14
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -2034,19 +2034,43 @@ | ||
| 2034 | 2034 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 2035 | 2035 | ** a directory full of repositories, then set g.zRepositoryName to |
| 2036 | 2036 | ** the name of that directory and the specific repository will be |
| 2037 | 2037 | ** opened later by process_one_web_page() based on the content of |
| 2038 | 2038 | ** the PATH_INFO variable. |
| 2039 | +** | |
| 2040 | +** If the fCreate flag is set, then create the repository if it | |
| 2041 | +** does not already exist. | |
| 2039 | 2042 | */ |
| 2040 | -static void find_server_repository(int arg){ | |
| 2043 | +static void find_server_repository(int arg, int fCreate){ | |
| 2041 | 2044 | if( g.argc<=arg ){ |
| 2042 | 2045 | db_must_be_within_tree(); |
| 2043 | - }else if( file_isdir(g.argv[arg])==1 ){ | |
| 2044 | - g.zRepositoryName = mprintf("%s", g.argv[arg]); | |
| 2045 | - file_simplify_name(g.zRepositoryName, -1, 0); | |
| 2046 | 2046 | }else{ |
| 2047 | - db_open_repository(g.argv[arg]); | |
| 2047 | + const char *zRepo = g.argv[arg]; | |
| 2048 | + int isDir = file_isdir(zRepo); | |
| 2049 | + if( isDir==1 ){ | |
| 2050 | + g.zRepositoryName = mprintf("%s", zRepo); | |
| 2051 | + file_simplify_name(g.zRepositoryName, -1, 0); | |
| 2052 | + }else{ | |
| 2053 | + if( isDir==0 && fCreate ){ | |
| 2054 | + const char *zPassword; | |
| 2055 | + db_create_repository(zRepo); | |
| 2056 | + db_open_repository(zRepo); | |
| 2057 | + db_begin_transaction(); | |
| 2058 | + db_initial_setup(0, "now", g.zLogin); | |
| 2059 | + db_end_transaction(0); | |
| 2060 | + fossil_print("project-id: %s\n", db_get("project-code", 0)); | |
| 2061 | + fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 2062 | + zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); | |
| 2063 | + fossil_print("admin-user: %s (initial password is \"%s\")\n", | |
| 2064 | + g.zLogin, zPassword); | |
| 2065 | + cache_initialize(); | |
| 2066 | + g.zLogin = 0; | |
| 2067 | + g.userUid = 0; | |
| 2068 | + }else{ | |
| 2069 | + db_open_repository(zRepo); | |
| 2070 | + } | |
| 2071 | + } | |
| 2048 | 2072 | } |
| 2049 | 2073 | } |
| 2050 | 2074 | |
| 2051 | 2075 | /* |
| 2052 | 2076 | ** undocumented format: |
| @@ -2149,15 +2173,15 @@ | ||
| 2149 | 2173 | g.fullHttpReply = 1; |
| 2150 | 2174 | if( g.argc>=5 ){ |
| 2151 | 2175 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2152 | 2176 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2153 | 2177 | zIpAddr = g.argv[4]; |
| 2154 | - find_server_repository(5); | |
| 2178 | + find_server_repository(5, 0); | |
| 2155 | 2179 | }else{ |
| 2156 | 2180 | g.httpIn = stdin; |
| 2157 | 2181 | g.httpOut = stdout; |
| 2158 | - find_server_repository(2); | |
| 2182 | + find_server_repository(2, 0); | |
| 2159 | 2183 | } |
| 2160 | 2184 | if( zIpAddr==0 ){ |
| 2161 | 2185 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2162 | 2186 | if( zIpAddr && zIpAddr[0] ){ |
| 2163 | 2187 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2200,11 +2224,11 @@ | ||
| 2200 | 2224 | Th_InitTraceLog(); |
| 2201 | 2225 | login_set_capabilities("sx", 0); |
| 2202 | 2226 | g.useLocalauth = 1; |
| 2203 | 2227 | g.httpIn = stdin; |
| 2204 | 2228 | g.httpOut = stdout; |
| 2205 | - find_server_repository(2); | |
| 2229 | + find_server_repository(2, 0); | |
| 2206 | 2230 | g.cgiOutput = 1; |
| 2207 | 2231 | g.fullHttpReply = 1; |
| 2208 | 2232 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2209 | 2233 | if( zIpAddr && zIpAddr[0] ){ |
| 2210 | 2234 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2257,12 +2281,12 @@ | ||
| 2257 | 2281 | ** The "ui" command automatically starts a web browser after initializing |
| 2258 | 2282 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 2259 | 2283 | ** only process HTTP traffic from the local machine. |
| 2260 | 2284 | ** |
| 2261 | 2285 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 2262 | -** more repositories with names ending in ".fossil". In this case, the | |
| 2263 | -** a prefix of the URL pathname is used to search the directory for an | |
| 2286 | +** more repositories with names ending in ".fossil". In this case, a | |
| 2287 | +** prefix of the URL pathname is used to search the directory for an | |
| 2264 | 2288 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 2265 | 2289 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 2266 | 2290 | ** occur after "/", and every "." must be surrounded on both sides by |
| 2267 | 2291 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 2268 | 2292 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| @@ -2279,10 +2303,11 @@ | ||
| 2279 | 2303 | ** connection is from localhost. The "ui" command also enables --repolist |
| 2280 | 2304 | ** by default. |
| 2281 | 2305 | ** |
| 2282 | 2306 | ** Options: |
| 2283 | 2307 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2308 | +** --create Create a new REPOSITORY if it does not already exist | |
| 2284 | 2309 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2285 | 2310 | ** --localauth enable automatic login for requests from localhost |
| 2286 | 2311 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2287 | 2312 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2288 | 2313 | ** --notfound URL Redirect |
| @@ -2308,10 +2333,11 @@ | ||
| 2308 | 2333 | #endif |
| 2309 | 2334 | int allowRepoList; /* List repositories on URL "/" */ |
| 2310 | 2335 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2311 | 2336 | const char *zFileGlob; /* Static content must match this */ |
| 2312 | 2337 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2338 | + int fCreate = 0; | |
| 2313 | 2339 | |
| 2314 | 2340 | #if defined(_WIN32) |
| 2315 | 2341 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 2316 | 2342 | zStopperFile = find_option("stopper", 0, 1); |
| 2317 | 2343 | #endif |
| @@ -2332,10 +2358,11 @@ | ||
| 2332 | 2358 | Th_InitTraceLog(); |
| 2333 | 2359 | zPort = find_option("port", "P", 1); |
| 2334 | 2360 | zNotFound = find_option("notfound", 0, 1); |
| 2335 | 2361 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2336 | 2362 | zAltBase = find_option("baseurl", 0, 1); |
| 2363 | + fCreate = find_option("create",0,0)!=0; | |
| 2337 | 2364 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2338 | 2365 | if( zAltBase ){ |
| 2339 | 2366 | set_base_url(zAltBase); |
| 2340 | 2367 | } |
| 2341 | 2368 | if( find_option("localhost", 0, 0)!=0 ){ |
| @@ -2350,11 +2377,11 @@ | ||
| 2350 | 2377 | if( isUiCmd ){ |
| 2351 | 2378 | flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; |
| 2352 | 2379 | g.useLocalauth = 1; |
| 2353 | 2380 | allowRepoList = 1; |
| 2354 | 2381 | } |
| 2355 | - find_server_repository(2); | |
| 2382 | + find_server_repository(2, fCreate); | |
| 2356 | 2383 | if( zPort ){ |
| 2357 | 2384 | int i; |
| 2358 | 2385 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2359 | 2386 | if( i>0 ){ |
| 2360 | 2387 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2390,12 +2417,10 @@ | ||
| 2390 | 2417 | }else{ |
| 2391 | 2418 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 2392 | 2419 | } |
| 2393 | 2420 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 2394 | 2421 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 2395 | - }else{ | |
| 2396 | - db_setup_server_and_project_codes(1); | |
| 2397 | 2422 | } |
| 2398 | 2423 | db_close(1); |
| 2399 | 2424 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 2400 | 2425 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 2401 | 2426 | } |
| @@ -2404,11 +2429,11 @@ | ||
| 2404 | 2429 | g.httpOut = stdout; |
| 2405 | 2430 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2406 | 2431 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2407 | 2432 | } |
| 2408 | 2433 | g.cgiOutput = 1; |
| 2409 | - find_server_repository(2); | |
| 2434 | + find_server_repository(2, 0); | |
| 2410 | 2435 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2411 | 2436 | if( flags & HTTP_SERVER_SCGI ){ |
| 2412 | 2437 | cgi_handle_scgi_request(); |
| 2413 | 2438 | }else{ |
| 2414 | 2439 | cgi_handle_http_request(0); |
| 2415 | 2440 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2034,19 +2034,43 @@ | |
| 2034 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 2035 | ** a directory full of repositories, then set g.zRepositoryName to |
| 2036 | ** the name of that directory and the specific repository will be |
| 2037 | ** opened later by process_one_web_page() based on the content of |
| 2038 | ** the PATH_INFO variable. |
| 2039 | */ |
| 2040 | static void find_server_repository(int arg){ |
| 2041 | if( g.argc<=arg ){ |
| 2042 | db_must_be_within_tree(); |
| 2043 | }else if( file_isdir(g.argv[arg])==1 ){ |
| 2044 | g.zRepositoryName = mprintf("%s", g.argv[arg]); |
| 2045 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 2046 | }else{ |
| 2047 | db_open_repository(g.argv[arg]); |
| 2048 | } |
| 2049 | } |
| 2050 | |
| 2051 | /* |
| 2052 | ** undocumented format: |
| @@ -2149,15 +2173,15 @@ | |
| 2149 | g.fullHttpReply = 1; |
| 2150 | if( g.argc>=5 ){ |
| 2151 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2152 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2153 | zIpAddr = g.argv[4]; |
| 2154 | find_server_repository(5); |
| 2155 | }else{ |
| 2156 | g.httpIn = stdin; |
| 2157 | g.httpOut = stdout; |
| 2158 | find_server_repository(2); |
| 2159 | } |
| 2160 | if( zIpAddr==0 ){ |
| 2161 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2162 | if( zIpAddr && zIpAddr[0] ){ |
| 2163 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2200,11 +2224,11 @@ | |
| 2200 | Th_InitTraceLog(); |
| 2201 | login_set_capabilities("sx", 0); |
| 2202 | g.useLocalauth = 1; |
| 2203 | g.httpIn = stdin; |
| 2204 | g.httpOut = stdout; |
| 2205 | find_server_repository(2); |
| 2206 | g.cgiOutput = 1; |
| 2207 | g.fullHttpReply = 1; |
| 2208 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2209 | if( zIpAddr && zIpAddr[0] ){ |
| 2210 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2257,12 +2281,12 @@ | |
| 2257 | ** The "ui" command automatically starts a web browser after initializing |
| 2258 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 2259 | ** only process HTTP traffic from the local machine. |
| 2260 | ** |
| 2261 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 2262 | ** more repositories with names ending in ".fossil". In this case, the |
| 2263 | ** a prefix of the URL pathname is used to search the directory for an |
| 2264 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 2265 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 2266 | ** occur after "/", and every "." must be surrounded on both sides by |
| 2267 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 2268 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| @@ -2279,10 +2303,11 @@ | |
| 2279 | ** connection is from localhost. The "ui" command also enables --repolist |
| 2280 | ** by default. |
| 2281 | ** |
| 2282 | ** Options: |
| 2283 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2284 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2285 | ** --localauth enable automatic login for requests from localhost |
| 2286 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2287 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2288 | ** --notfound URL Redirect |
| @@ -2308,10 +2333,11 @@ | |
| 2308 | #endif |
| 2309 | int allowRepoList; /* List repositories on URL "/" */ |
| 2310 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2311 | const char *zFileGlob; /* Static content must match this */ |
| 2312 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2313 | |
| 2314 | #if defined(_WIN32) |
| 2315 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 2316 | zStopperFile = find_option("stopper", 0, 1); |
| 2317 | #endif |
| @@ -2332,10 +2358,11 @@ | |
| 2332 | Th_InitTraceLog(); |
| 2333 | zPort = find_option("port", "P", 1); |
| 2334 | zNotFound = find_option("notfound", 0, 1); |
| 2335 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2336 | zAltBase = find_option("baseurl", 0, 1); |
| 2337 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2338 | if( zAltBase ){ |
| 2339 | set_base_url(zAltBase); |
| 2340 | } |
| 2341 | if( find_option("localhost", 0, 0)!=0 ){ |
| @@ -2350,11 +2377,11 @@ | |
| 2350 | if( isUiCmd ){ |
| 2351 | flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; |
| 2352 | g.useLocalauth = 1; |
| 2353 | allowRepoList = 1; |
| 2354 | } |
| 2355 | find_server_repository(2); |
| 2356 | if( zPort ){ |
| 2357 | int i; |
| 2358 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2359 | if( i>0 ){ |
| 2360 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2390,12 +2417,10 @@ | |
| 2390 | }else{ |
| 2391 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 2392 | } |
| 2393 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 2394 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 2395 | }else{ |
| 2396 | db_setup_server_and_project_codes(1); |
| 2397 | } |
| 2398 | db_close(1); |
| 2399 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 2400 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 2401 | } |
| @@ -2404,11 +2429,11 @@ | |
| 2404 | g.httpOut = stdout; |
| 2405 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2406 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2407 | } |
| 2408 | g.cgiOutput = 1; |
| 2409 | find_server_repository(2); |
| 2410 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2411 | if( flags & HTTP_SERVER_SCGI ){ |
| 2412 | cgi_handle_scgi_request(); |
| 2413 | }else{ |
| 2414 | cgi_handle_http_request(0); |
| 2415 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2034,19 +2034,43 @@ | |
| 2034 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 2035 | ** a directory full of repositories, then set g.zRepositoryName to |
| 2036 | ** the name of that directory and the specific repository will be |
| 2037 | ** opened later by process_one_web_page() based on the content of |
| 2038 | ** the PATH_INFO variable. |
| 2039 | ** |
| 2040 | ** If the fCreate flag is set, then create the repository if it |
| 2041 | ** does not already exist. |
| 2042 | */ |
| 2043 | static void find_server_repository(int arg, int fCreate){ |
| 2044 | if( g.argc<=arg ){ |
| 2045 | db_must_be_within_tree(); |
| 2046 | }else{ |
| 2047 | const char *zRepo = g.argv[arg]; |
| 2048 | int isDir = file_isdir(zRepo); |
| 2049 | if( isDir==1 ){ |
| 2050 | g.zRepositoryName = mprintf("%s", zRepo); |
| 2051 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 2052 | }else{ |
| 2053 | if( isDir==0 && fCreate ){ |
| 2054 | const char *zPassword; |
| 2055 | db_create_repository(zRepo); |
| 2056 | db_open_repository(zRepo); |
| 2057 | db_begin_transaction(); |
| 2058 | db_initial_setup(0, "now", g.zLogin); |
| 2059 | db_end_transaction(0); |
| 2060 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 2061 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 2062 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 2063 | fossil_print("admin-user: %s (initial password is \"%s\")\n", |
| 2064 | g.zLogin, zPassword); |
| 2065 | cache_initialize(); |
| 2066 | g.zLogin = 0; |
| 2067 | g.userUid = 0; |
| 2068 | }else{ |
| 2069 | db_open_repository(zRepo); |
| 2070 | } |
| 2071 | } |
| 2072 | } |
| 2073 | } |
| 2074 | |
| 2075 | /* |
| 2076 | ** undocumented format: |
| @@ -2149,15 +2173,15 @@ | |
| 2173 | g.fullHttpReply = 1; |
| 2174 | if( g.argc>=5 ){ |
| 2175 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2176 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2177 | zIpAddr = g.argv[4]; |
| 2178 | find_server_repository(5, 0); |
| 2179 | }else{ |
| 2180 | g.httpIn = stdin; |
| 2181 | g.httpOut = stdout; |
| 2182 | find_server_repository(2, 0); |
| 2183 | } |
| 2184 | if( zIpAddr==0 ){ |
| 2185 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2186 | if( zIpAddr && zIpAddr[0] ){ |
| 2187 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2200,11 +2224,11 @@ | |
| 2224 | Th_InitTraceLog(); |
| 2225 | login_set_capabilities("sx", 0); |
| 2226 | g.useLocalauth = 1; |
| 2227 | g.httpIn = stdin; |
| 2228 | g.httpOut = stdout; |
| 2229 | find_server_repository(2, 0); |
| 2230 | g.cgiOutput = 1; |
| 2231 | g.fullHttpReply = 1; |
| 2232 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2233 | if( zIpAddr && zIpAddr[0] ){ |
| 2234 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2257,12 +2281,12 @@ | |
| 2281 | ** The "ui" command automatically starts a web browser after initializing |
| 2282 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 2283 | ** only process HTTP traffic from the local machine. |
| 2284 | ** |
| 2285 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 2286 | ** more repositories with names ending in ".fossil". In this case, a |
| 2287 | ** prefix of the URL pathname is used to search the directory for an |
| 2288 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 2289 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 2290 | ** occur after "/", and every "." must be surrounded on both sides by |
| 2291 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 2292 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| @@ -2279,10 +2303,11 @@ | |
| 2303 | ** connection is from localhost. The "ui" command also enables --repolist |
| 2304 | ** by default. |
| 2305 | ** |
| 2306 | ** Options: |
| 2307 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2308 | ** --create Create a new REPOSITORY if it does not already exist |
| 2309 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2310 | ** --localauth enable automatic login for requests from localhost |
| 2311 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2312 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2313 | ** --notfound URL Redirect |
| @@ -2308,10 +2333,11 @@ | |
| 2333 | #endif |
| 2334 | int allowRepoList; /* List repositories on URL "/" */ |
| 2335 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2336 | const char *zFileGlob; /* Static content must match this */ |
| 2337 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2338 | int fCreate = 0; |
| 2339 | |
| 2340 | #if defined(_WIN32) |
| 2341 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 2342 | zStopperFile = find_option("stopper", 0, 1); |
| 2343 | #endif |
| @@ -2332,10 +2358,11 @@ | |
| 2358 | Th_InitTraceLog(); |
| 2359 | zPort = find_option("port", "P", 1); |
| 2360 | zNotFound = find_option("notfound", 0, 1); |
| 2361 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2362 | zAltBase = find_option("baseurl", 0, 1); |
| 2363 | fCreate = find_option("create",0,0)!=0; |
| 2364 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2365 | if( zAltBase ){ |
| 2366 | set_base_url(zAltBase); |
| 2367 | } |
| 2368 | if( find_option("localhost", 0, 0)!=0 ){ |
| @@ -2350,11 +2377,11 @@ | |
| 2377 | if( isUiCmd ){ |
| 2378 | flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; |
| 2379 | g.useLocalauth = 1; |
| 2380 | allowRepoList = 1; |
| 2381 | } |
| 2382 | find_server_repository(2, fCreate); |
| 2383 | if( zPort ){ |
| 2384 | int i; |
| 2385 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2386 | if( i>0 ){ |
| 2387 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2390,12 +2417,10 @@ | |
| 2417 | }else{ |
| 2418 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 2419 | } |
| 2420 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 2421 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 2422 | } |
| 2423 | db_close(1); |
| 2424 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 2425 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 2426 | } |
| @@ -2404,11 +2429,11 @@ | |
| 2429 | g.httpOut = stdout; |
| 2430 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2431 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2432 | } |
| 2433 | g.cgiOutput = 1; |
| 2434 | find_server_repository(2, 0); |
| 2435 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2436 | if( flags & HTTP_SERVER_SCGI ){ |
| 2437 | cgi_handle_scgi_request(); |
| 2438 | }else{ |
| 2439 | cgi_handle_http_request(0); |
| 2440 |
+39
-14
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -2034,19 +2034,43 @@ | ||
| 2034 | 2034 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 2035 | 2035 | ** a directory full of repositories, then set g.zRepositoryName to |
| 2036 | 2036 | ** the name of that directory and the specific repository will be |
| 2037 | 2037 | ** opened later by process_one_web_page() based on the content of |
| 2038 | 2038 | ** the PATH_INFO variable. |
| 2039 | +** | |
| 2040 | +** If the fCreate flag is set, then create the repository if it | |
| 2041 | +** does not already exist. | |
| 2039 | 2042 | */ |
| 2040 | -static void find_server_repository(int arg){ | |
| 2043 | +static void find_server_repository(int arg, int fCreate){ | |
| 2041 | 2044 | if( g.argc<=arg ){ |
| 2042 | 2045 | db_must_be_within_tree(); |
| 2043 | - }else if( file_isdir(g.argv[arg])==1 ){ | |
| 2044 | - g.zRepositoryName = mprintf("%s", g.argv[arg]); | |
| 2045 | - file_simplify_name(g.zRepositoryName, -1, 0); | |
| 2046 | 2046 | }else{ |
| 2047 | - db_open_repository(g.argv[arg]); | |
| 2047 | + const char *zRepo = g.argv[arg]; | |
| 2048 | + int isDir = file_isdir(zRepo); | |
| 2049 | + if( isDir==1 ){ | |
| 2050 | + g.zRepositoryName = mprintf("%s", zRepo); | |
| 2051 | + file_simplify_name(g.zRepositoryName, -1, 0); | |
| 2052 | + }else{ | |
| 2053 | + if( isDir==0 && fCreate ){ | |
| 2054 | + const char *zPassword; | |
| 2055 | + db_create_repository(zRepo); | |
| 2056 | + db_open_repository(zRepo); | |
| 2057 | + db_begin_transaction(); | |
| 2058 | + db_initial_setup(0, "now", g.zLogin); | |
| 2059 | + db_end_transaction(0); | |
| 2060 | + fossil_print("project-id: %s\n", db_get("project-code", 0)); | |
| 2061 | + fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 2062 | + zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); | |
| 2063 | + fossil_print("admin-user: %s (initial password is \"%s\")\n", | |
| 2064 | + g.zLogin, zPassword); | |
| 2065 | + cache_initialize(); | |
| 2066 | + g.zLogin = 0; | |
| 2067 | + g.userUid = 0; | |
| 2068 | + }else{ | |
| 2069 | + db_open_repository(zRepo); | |
| 2070 | + } | |
| 2071 | + } | |
| 2048 | 2072 | } |
| 2049 | 2073 | } |
| 2050 | 2074 | |
| 2051 | 2075 | /* |
| 2052 | 2076 | ** undocumented format: |
| @@ -2149,15 +2173,15 @@ | ||
| 2149 | 2173 | g.fullHttpReply = 1; |
| 2150 | 2174 | if( g.argc>=5 ){ |
| 2151 | 2175 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2152 | 2176 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2153 | 2177 | zIpAddr = g.argv[4]; |
| 2154 | - find_server_repository(5); | |
| 2178 | + find_server_repository(5, 0); | |
| 2155 | 2179 | }else{ |
| 2156 | 2180 | g.httpIn = stdin; |
| 2157 | 2181 | g.httpOut = stdout; |
| 2158 | - find_server_repository(2); | |
| 2182 | + find_server_repository(2, 0); | |
| 2159 | 2183 | } |
| 2160 | 2184 | if( zIpAddr==0 ){ |
| 2161 | 2185 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2162 | 2186 | if( zIpAddr && zIpAddr[0] ){ |
| 2163 | 2187 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2200,11 +2224,11 @@ | ||
| 2200 | 2224 | Th_InitTraceLog(); |
| 2201 | 2225 | login_set_capabilities("sx", 0); |
| 2202 | 2226 | g.useLocalauth = 1; |
| 2203 | 2227 | g.httpIn = stdin; |
| 2204 | 2228 | g.httpOut = stdout; |
| 2205 | - find_server_repository(2); | |
| 2229 | + find_server_repository(2, 0); | |
| 2206 | 2230 | g.cgiOutput = 1; |
| 2207 | 2231 | g.fullHttpReply = 1; |
| 2208 | 2232 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2209 | 2233 | if( zIpAddr && zIpAddr[0] ){ |
| 2210 | 2234 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2257,12 +2281,12 @@ | ||
| 2257 | 2281 | ** The "ui" command automatically starts a web browser after initializing |
| 2258 | 2282 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 2259 | 2283 | ** only process HTTP traffic from the local machine. |
| 2260 | 2284 | ** |
| 2261 | 2285 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 2262 | -** more repositories with names ending in ".fossil". In this case, the | |
| 2263 | -** a prefix of the URL pathname is used to search the directory for an | |
| 2286 | +** more repositories with names ending in ".fossil". In this case, a | |
| 2287 | +** prefix of the URL pathname is used to search the directory for an | |
| 2264 | 2288 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 2265 | 2289 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 2266 | 2290 | ** occur after "/", and every "." must be surrounded on both sides by |
| 2267 | 2291 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 2268 | 2292 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| @@ -2279,10 +2303,11 @@ | ||
| 2279 | 2303 | ** connection is from localhost. The "ui" command also enables --repolist |
| 2280 | 2304 | ** by default. |
| 2281 | 2305 | ** |
| 2282 | 2306 | ** Options: |
| 2283 | 2307 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2308 | +** --create Create a new REPOSITORY if it does not already exist | |
| 2284 | 2309 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2285 | 2310 | ** --localauth enable automatic login for requests from localhost |
| 2286 | 2311 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2287 | 2312 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2288 | 2313 | ** --notfound URL Redirect |
| @@ -2308,10 +2333,11 @@ | ||
| 2308 | 2333 | #endif |
| 2309 | 2334 | int allowRepoList; /* List repositories on URL "/" */ |
| 2310 | 2335 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2311 | 2336 | const char *zFileGlob; /* Static content must match this */ |
| 2312 | 2337 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2338 | + int fCreate = 0; | |
| 2313 | 2339 | |
| 2314 | 2340 | #if defined(_WIN32) |
| 2315 | 2341 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 2316 | 2342 | zStopperFile = find_option("stopper", 0, 1); |
| 2317 | 2343 | #endif |
| @@ -2332,10 +2358,11 @@ | ||
| 2332 | 2358 | Th_InitTraceLog(); |
| 2333 | 2359 | zPort = find_option("port", "P", 1); |
| 2334 | 2360 | zNotFound = find_option("notfound", 0, 1); |
| 2335 | 2361 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2336 | 2362 | zAltBase = find_option("baseurl", 0, 1); |
| 2363 | + fCreate = find_option("create",0,0)!=0; | |
| 2337 | 2364 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2338 | 2365 | if( zAltBase ){ |
| 2339 | 2366 | set_base_url(zAltBase); |
| 2340 | 2367 | } |
| 2341 | 2368 | if( find_option("localhost", 0, 0)!=0 ){ |
| @@ -2350,11 +2377,11 @@ | ||
| 2350 | 2377 | if( isUiCmd ){ |
| 2351 | 2378 | flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; |
| 2352 | 2379 | g.useLocalauth = 1; |
| 2353 | 2380 | allowRepoList = 1; |
| 2354 | 2381 | } |
| 2355 | - find_server_repository(2); | |
| 2382 | + find_server_repository(2, fCreate); | |
| 2356 | 2383 | if( zPort ){ |
| 2357 | 2384 | int i; |
| 2358 | 2385 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2359 | 2386 | if( i>0 ){ |
| 2360 | 2387 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2390,12 +2417,10 @@ | ||
| 2390 | 2417 | }else{ |
| 2391 | 2418 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 2392 | 2419 | } |
| 2393 | 2420 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 2394 | 2421 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 2395 | - }else{ | |
| 2396 | - db_setup_server_and_project_codes(1); | |
| 2397 | 2422 | } |
| 2398 | 2423 | db_close(1); |
| 2399 | 2424 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 2400 | 2425 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 2401 | 2426 | } |
| @@ -2404,11 +2429,11 @@ | ||
| 2404 | 2429 | g.httpOut = stdout; |
| 2405 | 2430 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2406 | 2431 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2407 | 2432 | } |
| 2408 | 2433 | g.cgiOutput = 1; |
| 2409 | - find_server_repository(2); | |
| 2434 | + find_server_repository(2, 0); | |
| 2410 | 2435 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2411 | 2436 | if( flags & HTTP_SERVER_SCGI ){ |
| 2412 | 2437 | cgi_handle_scgi_request(); |
| 2413 | 2438 | }else{ |
| 2414 | 2439 | cgi_handle_http_request(0); |
| 2415 | 2440 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2034,19 +2034,43 @@ | |
| 2034 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 2035 | ** a directory full of repositories, then set g.zRepositoryName to |
| 2036 | ** the name of that directory and the specific repository will be |
| 2037 | ** opened later by process_one_web_page() based on the content of |
| 2038 | ** the PATH_INFO variable. |
| 2039 | */ |
| 2040 | static void find_server_repository(int arg){ |
| 2041 | if( g.argc<=arg ){ |
| 2042 | db_must_be_within_tree(); |
| 2043 | }else if( file_isdir(g.argv[arg])==1 ){ |
| 2044 | g.zRepositoryName = mprintf("%s", g.argv[arg]); |
| 2045 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 2046 | }else{ |
| 2047 | db_open_repository(g.argv[arg]); |
| 2048 | } |
| 2049 | } |
| 2050 | |
| 2051 | /* |
| 2052 | ** undocumented format: |
| @@ -2149,15 +2173,15 @@ | |
| 2149 | g.fullHttpReply = 1; |
| 2150 | if( g.argc>=5 ){ |
| 2151 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2152 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2153 | zIpAddr = g.argv[4]; |
| 2154 | find_server_repository(5); |
| 2155 | }else{ |
| 2156 | g.httpIn = stdin; |
| 2157 | g.httpOut = stdout; |
| 2158 | find_server_repository(2); |
| 2159 | } |
| 2160 | if( zIpAddr==0 ){ |
| 2161 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2162 | if( zIpAddr && zIpAddr[0] ){ |
| 2163 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2200,11 +2224,11 @@ | |
| 2200 | Th_InitTraceLog(); |
| 2201 | login_set_capabilities("sx", 0); |
| 2202 | g.useLocalauth = 1; |
| 2203 | g.httpIn = stdin; |
| 2204 | g.httpOut = stdout; |
| 2205 | find_server_repository(2); |
| 2206 | g.cgiOutput = 1; |
| 2207 | g.fullHttpReply = 1; |
| 2208 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2209 | if( zIpAddr && zIpAddr[0] ){ |
| 2210 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2257,12 +2281,12 @@ | |
| 2257 | ** The "ui" command automatically starts a web browser after initializing |
| 2258 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 2259 | ** only process HTTP traffic from the local machine. |
| 2260 | ** |
| 2261 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 2262 | ** more repositories with names ending in ".fossil". In this case, the |
| 2263 | ** a prefix of the URL pathname is used to search the directory for an |
| 2264 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 2265 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 2266 | ** occur after "/", and every "." must be surrounded on both sides by |
| 2267 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 2268 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| @@ -2279,10 +2303,11 @@ | |
| 2279 | ** connection is from localhost. The "ui" command also enables --repolist |
| 2280 | ** by default. |
| 2281 | ** |
| 2282 | ** Options: |
| 2283 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2284 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2285 | ** --localauth enable automatic login for requests from localhost |
| 2286 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2287 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2288 | ** --notfound URL Redirect |
| @@ -2308,10 +2333,11 @@ | |
| 2308 | #endif |
| 2309 | int allowRepoList; /* List repositories on URL "/" */ |
| 2310 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2311 | const char *zFileGlob; /* Static content must match this */ |
| 2312 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2313 | |
| 2314 | #if defined(_WIN32) |
| 2315 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 2316 | zStopperFile = find_option("stopper", 0, 1); |
| 2317 | #endif |
| @@ -2332,10 +2358,11 @@ | |
| 2332 | Th_InitTraceLog(); |
| 2333 | zPort = find_option("port", "P", 1); |
| 2334 | zNotFound = find_option("notfound", 0, 1); |
| 2335 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2336 | zAltBase = find_option("baseurl", 0, 1); |
| 2337 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2338 | if( zAltBase ){ |
| 2339 | set_base_url(zAltBase); |
| 2340 | } |
| 2341 | if( find_option("localhost", 0, 0)!=0 ){ |
| @@ -2350,11 +2377,11 @@ | |
| 2350 | if( isUiCmd ){ |
| 2351 | flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; |
| 2352 | g.useLocalauth = 1; |
| 2353 | allowRepoList = 1; |
| 2354 | } |
| 2355 | find_server_repository(2); |
| 2356 | if( zPort ){ |
| 2357 | int i; |
| 2358 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2359 | if( i>0 ){ |
| 2360 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2390,12 +2417,10 @@ | |
| 2390 | }else{ |
| 2391 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 2392 | } |
| 2393 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 2394 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 2395 | }else{ |
| 2396 | db_setup_server_and_project_codes(1); |
| 2397 | } |
| 2398 | db_close(1); |
| 2399 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 2400 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 2401 | } |
| @@ -2404,11 +2429,11 @@ | |
| 2404 | g.httpOut = stdout; |
| 2405 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2406 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2407 | } |
| 2408 | g.cgiOutput = 1; |
| 2409 | find_server_repository(2); |
| 2410 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2411 | if( flags & HTTP_SERVER_SCGI ){ |
| 2412 | cgi_handle_scgi_request(); |
| 2413 | }else{ |
| 2414 | cgi_handle_http_request(0); |
| 2415 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2034,19 +2034,43 @@ | |
| 2034 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 2035 | ** a directory full of repositories, then set g.zRepositoryName to |
| 2036 | ** the name of that directory and the specific repository will be |
| 2037 | ** opened later by process_one_web_page() based on the content of |
| 2038 | ** the PATH_INFO variable. |
| 2039 | ** |
| 2040 | ** If the fCreate flag is set, then create the repository if it |
| 2041 | ** does not already exist. |
| 2042 | */ |
| 2043 | static void find_server_repository(int arg, int fCreate){ |
| 2044 | if( g.argc<=arg ){ |
| 2045 | db_must_be_within_tree(); |
| 2046 | }else{ |
| 2047 | const char *zRepo = g.argv[arg]; |
| 2048 | int isDir = file_isdir(zRepo); |
| 2049 | if( isDir==1 ){ |
| 2050 | g.zRepositoryName = mprintf("%s", zRepo); |
| 2051 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 2052 | }else{ |
| 2053 | if( isDir==0 && fCreate ){ |
| 2054 | const char *zPassword; |
| 2055 | db_create_repository(zRepo); |
| 2056 | db_open_repository(zRepo); |
| 2057 | db_begin_transaction(); |
| 2058 | db_initial_setup(0, "now", g.zLogin); |
| 2059 | db_end_transaction(0); |
| 2060 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 2061 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 2062 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 2063 | fossil_print("admin-user: %s (initial password is \"%s\")\n", |
| 2064 | g.zLogin, zPassword); |
| 2065 | cache_initialize(); |
| 2066 | g.zLogin = 0; |
| 2067 | g.userUid = 0; |
| 2068 | }else{ |
| 2069 | db_open_repository(zRepo); |
| 2070 | } |
| 2071 | } |
| 2072 | } |
| 2073 | } |
| 2074 | |
| 2075 | /* |
| 2076 | ** undocumented format: |
| @@ -2149,15 +2173,15 @@ | |
| 2173 | g.fullHttpReply = 1; |
| 2174 | if( g.argc>=5 ){ |
| 2175 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2176 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2177 | zIpAddr = g.argv[4]; |
| 2178 | find_server_repository(5, 0); |
| 2179 | }else{ |
| 2180 | g.httpIn = stdin; |
| 2181 | g.httpOut = stdout; |
| 2182 | find_server_repository(2, 0); |
| 2183 | } |
| 2184 | if( zIpAddr==0 ){ |
| 2185 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2186 | if( zIpAddr && zIpAddr[0] ){ |
| 2187 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2200,11 +2224,11 @@ | |
| 2224 | Th_InitTraceLog(); |
| 2225 | login_set_capabilities("sx", 0); |
| 2226 | g.useLocalauth = 1; |
| 2227 | g.httpIn = stdin; |
| 2228 | g.httpOut = stdout; |
| 2229 | find_server_repository(2, 0); |
| 2230 | g.cgiOutput = 1; |
| 2231 | g.fullHttpReply = 1; |
| 2232 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2233 | if( zIpAddr && zIpAddr[0] ){ |
| 2234 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2257,12 +2281,12 @@ | |
| 2281 | ** The "ui" command automatically starts a web browser after initializing |
| 2282 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 2283 | ** only process HTTP traffic from the local machine. |
| 2284 | ** |
| 2285 | ** The REPOSITORY can be a directory (aka folder) that contains one or |
| 2286 | ** more repositories with names ending in ".fossil". In this case, a |
| 2287 | ** prefix of the URL pathname is used to search the directory for an |
| 2288 | ** appropriate repository. To thwart mischief, the pathname in the URL must |
| 2289 | ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may |
| 2290 | ** occur after "/", and every "." must be surrounded on both sides by |
| 2291 | ** alphanumerics. Any pathname that does not satisfy these constraints |
| 2292 | ** results in a 404 error. Files in REPOSITORY that match the comma-separated |
| @@ -2279,10 +2303,11 @@ | |
| 2303 | ** connection is from localhost. The "ui" command also enables --repolist |
| 2304 | ** by default. |
| 2305 | ** |
| 2306 | ** Options: |
| 2307 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2308 | ** --create Create a new REPOSITORY if it does not already exist |
| 2309 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2310 | ** --localauth enable automatic login for requests from localhost |
| 2311 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2312 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2313 | ** --notfound URL Redirect |
| @@ -2308,10 +2333,11 @@ | |
| 2333 | #endif |
| 2334 | int allowRepoList; /* List repositories on URL "/" */ |
| 2335 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2336 | const char *zFileGlob; /* Static content must match this */ |
| 2337 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2338 | int fCreate = 0; |
| 2339 | |
| 2340 | #if defined(_WIN32) |
| 2341 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 2342 | zStopperFile = find_option("stopper", 0, 1); |
| 2343 | #endif |
| @@ -2332,10 +2358,11 @@ | |
| 2358 | Th_InitTraceLog(); |
| 2359 | zPort = find_option("port", "P", 1); |
| 2360 | zNotFound = find_option("notfound", 0, 1); |
| 2361 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2362 | zAltBase = find_option("baseurl", 0, 1); |
| 2363 | fCreate = find_option("create",0,0)!=0; |
| 2364 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2365 | if( zAltBase ){ |
| 2366 | set_base_url(zAltBase); |
| 2367 | } |
| 2368 | if( find_option("localhost", 0, 0)!=0 ){ |
| @@ -2350,11 +2377,11 @@ | |
| 2377 | if( isUiCmd ){ |
| 2378 | flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; |
| 2379 | g.useLocalauth = 1; |
| 2380 | allowRepoList = 1; |
| 2381 | } |
| 2382 | find_server_repository(2, fCreate); |
| 2383 | if( zPort ){ |
| 2384 | int i; |
| 2385 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2386 | if( i>0 ){ |
| 2387 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2390,12 +2417,10 @@ | |
| 2417 | }else{ |
| 2418 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 2419 | } |
| 2420 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 2421 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 2422 | } |
| 2423 | db_close(1); |
| 2424 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 2425 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 2426 | } |
| @@ -2404,11 +2429,11 @@ | |
| 2429 | g.httpOut = stdout; |
| 2430 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2431 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2432 | } |
| 2433 | g.cgiOutput = 1; |
| 2434 | find_server_repository(2, 0); |
| 2435 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2436 | if( flags & HTTP_SERVER_SCGI ){ |
| 2437 | cgi_handle_scgi_request(); |
| 2438 | }else{ |
| 2439 | cgi_handle_http_request(0); |
| 2440 |
+2
-2
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -591,11 +591,11 @@ | ||
| 591 | 591 | #### The directories where the OpenSSL include and library files are located. |
| 592 | 592 | # The recommended usage here is to use the Sysinternals junction tool |
| 593 | 593 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 594 | 594 | # Fossil source code directory and the target OpenSSL source directory. |
| 595 | 595 | # |
| 596 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 | |
| 596 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a | |
| 597 | 597 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 598 | 598 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 599 | 599 | |
| 600 | 600 | #### Either the directory where the Tcl library is installed or the Tcl |
| 601 | 601 | # source code directory resides (depending on the value of the macro |
| @@ -1333,11 +1333,11 @@ | ||
| 1333 | 1333 | |
| 1334 | 1334 | # Uncomment to enable Tcl support |
| 1335 | 1335 | # FOSSIL_ENABLE_TCL = 1 |
| 1336 | 1336 | |
| 1337 | 1337 | !ifdef FOSSIL_ENABLE_SSL |
| 1338 | -SSLDIR = $(B)\compat\openssl-1.0.2 | |
| 1338 | +SSLDIR = $(B)\compat\openssl-1.0.2a | |
| 1339 | 1339 | SSLINCDIR = $(SSLDIR)\inc32 |
| 1340 | 1340 | SSLLIBDIR = $(SSLDIR)\out32 |
| 1341 | 1341 | SSLLFLAGS = /nologo /opt:ref /debug |
| 1342 | 1342 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1343 | 1343 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 1344 | 1344 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -591,11 +591,11 @@ | |
| 591 | #### The directories where the OpenSSL include and library files are located. |
| 592 | # The recommended usage here is to use the Sysinternals junction tool |
| 593 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 594 | # Fossil source code directory and the target OpenSSL source directory. |
| 595 | # |
| 596 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 |
| 597 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 598 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 599 | |
| 600 | #### Either the directory where the Tcl library is installed or the Tcl |
| 601 | # source code directory resides (depending on the value of the macro |
| @@ -1333,11 +1333,11 @@ | |
| 1333 | |
| 1334 | # Uncomment to enable Tcl support |
| 1335 | # FOSSIL_ENABLE_TCL = 1 |
| 1336 | |
| 1337 | !ifdef FOSSIL_ENABLE_SSL |
| 1338 | SSLDIR = $(B)\compat\openssl-1.0.2 |
| 1339 | SSLINCDIR = $(SSLDIR)\inc32 |
| 1340 | SSLLIBDIR = $(SSLDIR)\out32 |
| 1341 | SSLLFLAGS = /nologo /opt:ref /debug |
| 1342 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1343 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 1344 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -591,11 +591,11 @@ | |
| 591 | #### The directories where the OpenSSL include and library files are located. |
| 592 | # The recommended usage here is to use the Sysinternals junction tool |
| 593 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 594 | # Fossil source code directory and the target OpenSSL source directory. |
| 595 | # |
| 596 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a |
| 597 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 598 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 599 | |
| 600 | #### Either the directory where the Tcl library is installed or the Tcl |
| 601 | # source code directory resides (depending on the value of the macro |
| @@ -1333,11 +1333,11 @@ | |
| 1333 | |
| 1334 | # Uncomment to enable Tcl support |
| 1335 | # FOSSIL_ENABLE_TCL = 1 |
| 1336 | |
| 1337 | !ifdef FOSSIL_ENABLE_SSL |
| 1338 | SSLDIR = $(B)\compat\openssl-1.0.2a |
| 1339 | SSLINCDIR = $(SSLDIR)\inc32 |
| 1340 | SSLLIBDIR = $(SSLDIR)\out32 |
| 1341 | SSLLFLAGS = /nologo /opt:ref /debug |
| 1342 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1343 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 1344 |
+2
-2
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -591,11 +591,11 @@ | ||
| 591 | 591 | #### The directories where the OpenSSL include and library files are located. |
| 592 | 592 | # The recommended usage here is to use the Sysinternals junction tool |
| 593 | 593 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 594 | 594 | # Fossil source code directory and the target OpenSSL source directory. |
| 595 | 595 | # |
| 596 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 | |
| 596 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a | |
| 597 | 597 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 598 | 598 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 599 | 599 | |
| 600 | 600 | #### Either the directory where the Tcl library is installed or the Tcl |
| 601 | 601 | # source code directory resides (depending on the value of the macro |
| @@ -1333,11 +1333,11 @@ | ||
| 1333 | 1333 | |
| 1334 | 1334 | # Uncomment to enable Tcl support |
| 1335 | 1335 | # FOSSIL_ENABLE_TCL = 1 |
| 1336 | 1336 | |
| 1337 | 1337 | !ifdef FOSSIL_ENABLE_SSL |
| 1338 | -SSLDIR = $(B)\compat\openssl-1.0.2 | |
| 1338 | +SSLDIR = $(B)\compat\openssl-1.0.2a | |
| 1339 | 1339 | SSLINCDIR = $(SSLDIR)\inc32 |
| 1340 | 1340 | SSLLIBDIR = $(SSLDIR)\out32 |
| 1341 | 1341 | SSLLFLAGS = /nologo /opt:ref /debug |
| 1342 | 1342 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1343 | 1343 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 1344 | 1344 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -591,11 +591,11 @@ | |
| 591 | #### The directories where the OpenSSL include and library files are located. |
| 592 | # The recommended usage here is to use the Sysinternals junction tool |
| 593 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 594 | # Fossil source code directory and the target OpenSSL source directory. |
| 595 | # |
| 596 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 |
| 597 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 598 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 599 | |
| 600 | #### Either the directory where the Tcl library is installed or the Tcl |
| 601 | # source code directory resides (depending on the value of the macro |
| @@ -1333,11 +1333,11 @@ | |
| 1333 | |
| 1334 | # Uncomment to enable Tcl support |
| 1335 | # FOSSIL_ENABLE_TCL = 1 |
| 1336 | |
| 1337 | !ifdef FOSSIL_ENABLE_SSL |
| 1338 | SSLDIR = $(B)\compat\openssl-1.0.2 |
| 1339 | SSLINCDIR = $(SSLDIR)\inc32 |
| 1340 | SSLLIBDIR = $(SSLDIR)\out32 |
| 1341 | SSLLFLAGS = /nologo /opt:ref /debug |
| 1342 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1343 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 1344 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -591,11 +591,11 @@ | |
| 591 | #### The directories where the OpenSSL include and library files are located. |
| 592 | # The recommended usage here is to use the Sysinternals junction tool |
| 593 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 594 | # Fossil source code directory and the target OpenSSL source directory. |
| 595 | # |
| 596 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a |
| 597 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 598 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 599 | |
| 600 | #### Either the directory where the Tcl library is installed or the Tcl |
| 601 | # source code directory resides (depending on the value of the macro |
| @@ -1333,11 +1333,11 @@ | |
| 1333 | |
| 1334 | # Uncomment to enable Tcl support |
| 1335 | # FOSSIL_ENABLE_TCL = 1 |
| 1336 | |
| 1337 | !ifdef FOSSIL_ENABLE_SSL |
| 1338 | SSLDIR = $(B)\compat\openssl-1.0.2a |
| 1339 | SSLINCDIR = $(SSLDIR)\inc32 |
| 1340 | SSLLIBDIR = $(SSLDIR)\out32 |
| 1341 | SSLLFLAGS = /nologo /opt:ref /debug |
| 1342 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1343 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 1344 |
+1
-1
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -953,11 +953,11 @@ | ||
| 953 | 953 | /* We should be done with options.. */ |
| 954 | 954 | verify_all_options(); |
| 955 | 955 | |
| 956 | 956 | db_open_config(0); |
| 957 | 957 | db_begin_transaction(); |
| 958 | - db_initial_setup(0, 0, 0, 1); | |
| 958 | + db_initial_setup(0, 0, 0); | |
| 959 | 959 | |
| 960 | 960 | fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]); |
| 961 | 961 | recon_read_dir(g.argv[3]); |
| 962 | 962 | fossil_print("\nBuilding the Fossil repository...\n"); |
| 963 | 963 | |
| 964 | 964 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -953,11 +953,11 @@ | |
| 953 | /* We should be done with options.. */ |
| 954 | verify_all_options(); |
| 955 | |
| 956 | db_open_config(0); |
| 957 | db_begin_transaction(); |
| 958 | db_initial_setup(0, 0, 0, 1); |
| 959 | |
| 960 | fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]); |
| 961 | recon_read_dir(g.argv[3]); |
| 962 | fossil_print("\nBuilding the Fossil repository...\n"); |
| 963 | |
| 964 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -953,11 +953,11 @@ | |
| 953 | /* We should be done with options.. */ |
| 954 | verify_all_options(); |
| 955 | |
| 956 | db_open_config(0); |
| 957 | db_begin_transaction(); |
| 958 | db_initial_setup(0, 0, 0); |
| 959 | |
| 960 | fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]); |
| 961 | recon_read_dir(g.argv[3]); |
| 962 | fossil_print("\nBuilding the Fossil repository...\n"); |
| 963 | |
| 964 |
+46
-19
| --- src/shell.c | ||
| +++ src/shell.c | ||
| @@ -22,10 +22,17 @@ | ||
| 22 | 22 | */ |
| 23 | 23 | #if defined(INCLUDE_MSVC_H) |
| 24 | 24 | #include "msvc.h" |
| 25 | 25 | #endif |
| 26 | 26 | |
| 27 | +/* | |
| 28 | +** No support for loadable extensions in VxWorks. | |
| 29 | +*/ | |
| 30 | +#if defined(_WRS_KERNEL) && !SQLITE_OMIT_LOAD_EXTENSION | |
| 31 | +# define SQLITE_OMIT_LOAD_EXTENSION 1 | |
| 32 | +#endif | |
| 33 | + | |
| 27 | 34 | /* |
| 28 | 35 | ** Enable large-file support for fopen() and friends on unix. |
| 29 | 36 | */ |
| 30 | 37 | #ifndef SQLITE_DISABLE_LFS |
| 31 | 38 | # define _LARGE_FILE 1 |
| @@ -105,14 +112,19 @@ | ||
| 105 | 112 | #else |
| 106 | 113 | /* Make sure isatty() has a prototype. |
| 107 | 114 | */ |
| 108 | 115 | extern int isatty(int); |
| 109 | 116 | |
| 110 | -/* popen and pclose are not C89 functions and so are sometimes omitted from | |
| 111 | -** the <stdio.h> header */ | |
| 112 | -extern FILE *popen(const char*,const char*); | |
| 113 | -extern int pclose(FILE*); | |
| 117 | +#if !defined(__RTP__) && !defined(_WRS_KERNEL) | |
| 118 | + /* popen and pclose are not C89 functions and so are sometimes omitted from | |
| 119 | + ** the <stdio.h> header */ | |
| 120 | + extern FILE *popen(const char*,const char*); | |
| 121 | + extern int pclose(FILE*); | |
| 122 | +#else | |
| 123 | +# define SQLITE_OMIT_POPEN 1 | |
| 124 | +#endif | |
| 125 | + | |
| 114 | 126 | #endif |
| 115 | 127 | |
| 116 | 128 | #if defined(_WIN32_WCE) |
| 117 | 129 | /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() |
| 118 | 130 | * thus we always assume that we have a console. That can be |
| @@ -163,14 +175,22 @@ | ||
| 163 | 175 | t = (sqlite3_int64)(r*86400000.0); |
| 164 | 176 | } |
| 165 | 177 | return t; |
| 166 | 178 | } |
| 167 | 179 | |
| 168 | -#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \ | |
| 169 | - && !defined(__minux) | |
| 180 | +#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) | |
| 170 | 181 | #include <sys/time.h> |
| 171 | 182 | #include <sys/resource.h> |
| 183 | + | |
| 184 | +/* VxWorks does not support getrusage() as far as we can determine */ | |
| 185 | +#if defined(_WRS_KERNEL) || defined(__RTP__) | |
| 186 | +struct rusage { | |
| 187 | + struct timeval ru_utime; /* user CPU time used */ | |
| 188 | + struct timeval ru_stime; /* system CPU time used */ | |
| 189 | +}; | |
| 190 | +#define getrusage(A,B) memset(B,0,sizeof(*B)) | |
| 191 | +#endif | |
| 172 | 192 | |
| 173 | 193 | /* Saved resource information for the beginning of an operation */ |
| 174 | 194 | static struct rusage sBegin; /* CPU time at start */ |
| 175 | 195 | static sqlite3_int64 iBegin; /* Wall-clock time at start */ |
| 176 | 196 | |
| @@ -193,12 +213,12 @@ | ||
| 193 | 213 | /* |
| 194 | 214 | ** Print the timing results. |
| 195 | 215 | */ |
| 196 | 216 | static void endTimer(void){ |
| 197 | 217 | if( enableTimer ){ |
| 198 | - struct rusage sEnd; | |
| 199 | 218 | sqlite3_int64 iEnd = timeOfDay(); |
| 219 | + struct rusage sEnd; | |
| 200 | 220 | getrusage(RUSAGE_SELF, &sEnd); |
| 201 | 221 | printf("Run Time: real %.3f user %f sys %f\n", |
| 202 | 222 | (iEnd - iBegin)*0.001, |
| 203 | 223 | timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), |
| 204 | 224 | timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); |
| @@ -2437,11 +2457,13 @@ | ||
| 2437 | 2457 | /* |
| 2438 | 2458 | ** Change the output file back to stdout |
| 2439 | 2459 | */ |
| 2440 | 2460 | static void output_reset(ShellState *p){ |
| 2441 | 2461 | if( p->outfile[0]=='|' ){ |
| 2462 | +#ifndef SQLITE_OMIT_POPEN | |
| 2442 | 2463 | pclose(p->out); |
| 2464 | +#endif | |
| 2443 | 2465 | }else{ |
| 2444 | 2466 | output_file_close(p->out); |
| 2445 | 2467 | } |
| 2446 | 2468 | p->outfile[0] = 0; |
| 2447 | 2469 | p->out = stdout; |
| @@ -2930,13 +2952,18 @@ | ||
| 2930 | 2952 | return 1; |
| 2931 | 2953 | } |
| 2932 | 2954 | sCtx.zFile = zFile; |
| 2933 | 2955 | sCtx.nLine = 1; |
| 2934 | 2956 | if( sCtx.zFile[0]=='|' ){ |
| 2957 | +#ifdef SQLITE_OMIT_POPEN | |
| 2958 | + fprintf(stderr, "Error: pipes are not supporte in this OS\n"); | |
| 2959 | + return 1; | |
| 2960 | +#else | |
| 2935 | 2961 | sCtx.in = popen(sCtx.zFile+1, "r"); |
| 2936 | 2962 | sCtx.zFile = "<pipe>"; |
| 2937 | 2963 | xCloser = pclose; |
| 2964 | +#endif | |
| 2938 | 2965 | }else{ |
| 2939 | 2966 | sCtx.in = fopen(sCtx.zFile, "rb"); |
| 2940 | 2967 | xCloser = fclose; |
| 2941 | 2968 | } |
| 2942 | 2969 | if( p->mode==MODE_Ascii ){ |
| @@ -3255,18 +3282,24 @@ | ||
| 3255 | 3282 | }else{ |
| 3256 | 3283 | p->outCount = 0; |
| 3257 | 3284 | } |
| 3258 | 3285 | output_reset(p); |
| 3259 | 3286 | if( zFile[0]=='|' ){ |
| 3287 | +#ifdef SQLITE_OMIT_POPEN | |
| 3288 | + fprintf(stderr,"Error: pipes are not supported in this OS\n"); | |
| 3289 | + rc = 1; | |
| 3290 | + p->out = stdout; | |
| 3291 | +#else | |
| 3260 | 3292 | p->out = popen(zFile + 1, "w"); |
| 3261 | 3293 | if( p->out==0 ){ |
| 3262 | 3294 | fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); |
| 3263 | 3295 | p->out = stdout; |
| 3264 | 3296 | rc = 1; |
| 3265 | 3297 | }else{ |
| 3266 | 3298 | sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); |
| 3267 | 3299 | } |
| 3300 | +#endif | |
| 3268 | 3301 | }else{ |
| 3269 | 3302 | p->out = output_file_open(zFile); |
| 3270 | 3303 | if( p->out==0 ){ |
| 3271 | 3304 | if( strcmp(zFile,"off")!=0 ){ |
| 3272 | 3305 | fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile); |
| @@ -4187,27 +4220,25 @@ | ||
| 4187 | 4220 | ** Read input from the file given by sqliterc_override. Or if that |
| 4188 | 4221 | ** parameter is NULL, take input from ~/.sqliterc |
| 4189 | 4222 | ** |
| 4190 | 4223 | ** Returns the number of errors. |
| 4191 | 4224 | */ |
| 4192 | -static int process_sqliterc( | |
| 4225 | +static void process_sqliterc( | |
| 4193 | 4226 | ShellState *p, /* Configuration data */ |
| 4194 | 4227 | const char *sqliterc_override /* Name of config file. NULL to use default */ |
| 4195 | 4228 | ){ |
| 4196 | 4229 | char *home_dir = NULL; |
| 4197 | 4230 | const char *sqliterc = sqliterc_override; |
| 4198 | 4231 | char *zBuf = 0; |
| 4199 | 4232 | FILE *in = NULL; |
| 4200 | - int rc = 0; | |
| 4201 | 4233 | |
| 4202 | 4234 | if (sqliterc == NULL) { |
| 4203 | 4235 | home_dir = find_home_dir(); |
| 4204 | 4236 | if( home_dir==0 ){ |
| 4205 | -#if !defined(__RTP__) && !defined(_WRS_KERNEL) | |
| 4206 | - fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0); | |
| 4207 | -#endif | |
| 4208 | - return 1; | |
| 4237 | + fprintf(stderr, "-- warning: cannot find home directory;" | |
| 4238 | + " cannot read ~/.sqliterc\n"); | |
| 4239 | + return; | |
| 4209 | 4240 | } |
| 4210 | 4241 | sqlite3_initialize(); |
| 4211 | 4242 | zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); |
| 4212 | 4243 | sqliterc = zBuf; |
| 4213 | 4244 | } |
| @@ -4214,15 +4245,14 @@ | ||
| 4214 | 4245 | in = fopen(sqliterc,"rb"); |
| 4215 | 4246 | if( in ){ |
| 4216 | 4247 | if( stdin_is_interactive ){ |
| 4217 | 4248 | fprintf(stderr,"-- Loading resources from %s\n",sqliterc); |
| 4218 | 4249 | } |
| 4219 | - rc = process_input(p,in); | |
| 4250 | + process_input(p,in); | |
| 4220 | 4251 | fclose(in); |
| 4221 | 4252 | } |
| 4222 | 4253 | sqlite3_free(zBuf); |
| 4223 | - return rc; | |
| 4224 | 4254 | } |
| 4225 | 4255 | |
| 4226 | 4256 | /* |
| 4227 | 4257 | ** Show available command line options |
| 4228 | 4258 | */ |
| @@ -4494,14 +4524,11 @@ | ||
| 4494 | 4524 | |
| 4495 | 4525 | /* Process the initialization file if there is one. If no -init option |
| 4496 | 4526 | ** is given on the command line, look for a file named ~/.sqliterc and |
| 4497 | 4527 | ** try to process it. |
| 4498 | 4528 | */ |
| 4499 | - rc = process_sqliterc(&data,zInitFile); | |
| 4500 | - if( rc>0 ){ | |
| 4501 | - return rc; | |
| 4502 | - } | |
| 4529 | + process_sqliterc(&data,zInitFile); | |
| 4503 | 4530 | |
| 4504 | 4531 | /* Make a second pass through the command-line argument and set |
| 4505 | 4532 | ** options. This second pass is delayed until after the initialization |
| 4506 | 4533 | ** file is processed so that the command-line arguments will override |
| 4507 | 4534 | ** settings in the initialization file. |
| 4508 | 4535 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -22,10 +22,17 @@ | |
| 22 | */ |
| 23 | #if defined(INCLUDE_MSVC_H) |
| 24 | #include "msvc.h" |
| 25 | #endif |
| 26 | |
| 27 | /* |
| 28 | ** Enable large-file support for fopen() and friends on unix. |
| 29 | */ |
| 30 | #ifndef SQLITE_DISABLE_LFS |
| 31 | # define _LARGE_FILE 1 |
| @@ -105,14 +112,19 @@ | |
| 105 | #else |
| 106 | /* Make sure isatty() has a prototype. |
| 107 | */ |
| 108 | extern int isatty(int); |
| 109 | |
| 110 | /* popen and pclose are not C89 functions and so are sometimes omitted from |
| 111 | ** the <stdio.h> header */ |
| 112 | extern FILE *popen(const char*,const char*); |
| 113 | extern int pclose(FILE*); |
| 114 | #endif |
| 115 | |
| 116 | #if defined(_WIN32_WCE) |
| 117 | /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() |
| 118 | * thus we always assume that we have a console. That can be |
| @@ -163,14 +175,22 @@ | |
| 163 | t = (sqlite3_int64)(r*86400000.0); |
| 164 | } |
| 165 | return t; |
| 166 | } |
| 167 | |
| 168 | #if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \ |
| 169 | && !defined(__minux) |
| 170 | #include <sys/time.h> |
| 171 | #include <sys/resource.h> |
| 172 | |
| 173 | /* Saved resource information for the beginning of an operation */ |
| 174 | static struct rusage sBegin; /* CPU time at start */ |
| 175 | static sqlite3_int64 iBegin; /* Wall-clock time at start */ |
| 176 | |
| @@ -193,12 +213,12 @@ | |
| 193 | /* |
| 194 | ** Print the timing results. |
| 195 | */ |
| 196 | static void endTimer(void){ |
| 197 | if( enableTimer ){ |
| 198 | struct rusage sEnd; |
| 199 | sqlite3_int64 iEnd = timeOfDay(); |
| 200 | getrusage(RUSAGE_SELF, &sEnd); |
| 201 | printf("Run Time: real %.3f user %f sys %f\n", |
| 202 | (iEnd - iBegin)*0.001, |
| 203 | timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), |
| 204 | timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); |
| @@ -2437,11 +2457,13 @@ | |
| 2437 | /* |
| 2438 | ** Change the output file back to stdout |
| 2439 | */ |
| 2440 | static void output_reset(ShellState *p){ |
| 2441 | if( p->outfile[0]=='|' ){ |
| 2442 | pclose(p->out); |
| 2443 | }else{ |
| 2444 | output_file_close(p->out); |
| 2445 | } |
| 2446 | p->outfile[0] = 0; |
| 2447 | p->out = stdout; |
| @@ -2930,13 +2952,18 @@ | |
| 2930 | return 1; |
| 2931 | } |
| 2932 | sCtx.zFile = zFile; |
| 2933 | sCtx.nLine = 1; |
| 2934 | if( sCtx.zFile[0]=='|' ){ |
| 2935 | sCtx.in = popen(sCtx.zFile+1, "r"); |
| 2936 | sCtx.zFile = "<pipe>"; |
| 2937 | xCloser = pclose; |
| 2938 | }else{ |
| 2939 | sCtx.in = fopen(sCtx.zFile, "rb"); |
| 2940 | xCloser = fclose; |
| 2941 | } |
| 2942 | if( p->mode==MODE_Ascii ){ |
| @@ -3255,18 +3282,24 @@ | |
| 3255 | }else{ |
| 3256 | p->outCount = 0; |
| 3257 | } |
| 3258 | output_reset(p); |
| 3259 | if( zFile[0]=='|' ){ |
| 3260 | p->out = popen(zFile + 1, "w"); |
| 3261 | if( p->out==0 ){ |
| 3262 | fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); |
| 3263 | p->out = stdout; |
| 3264 | rc = 1; |
| 3265 | }else{ |
| 3266 | sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); |
| 3267 | } |
| 3268 | }else{ |
| 3269 | p->out = output_file_open(zFile); |
| 3270 | if( p->out==0 ){ |
| 3271 | if( strcmp(zFile,"off")!=0 ){ |
| 3272 | fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile); |
| @@ -4187,27 +4220,25 @@ | |
| 4187 | ** Read input from the file given by sqliterc_override. Or if that |
| 4188 | ** parameter is NULL, take input from ~/.sqliterc |
| 4189 | ** |
| 4190 | ** Returns the number of errors. |
| 4191 | */ |
| 4192 | static int process_sqliterc( |
| 4193 | ShellState *p, /* Configuration data */ |
| 4194 | const char *sqliterc_override /* Name of config file. NULL to use default */ |
| 4195 | ){ |
| 4196 | char *home_dir = NULL; |
| 4197 | const char *sqliterc = sqliterc_override; |
| 4198 | char *zBuf = 0; |
| 4199 | FILE *in = NULL; |
| 4200 | int rc = 0; |
| 4201 | |
| 4202 | if (sqliterc == NULL) { |
| 4203 | home_dir = find_home_dir(); |
| 4204 | if( home_dir==0 ){ |
| 4205 | #if !defined(__RTP__) && !defined(_WRS_KERNEL) |
| 4206 | fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0); |
| 4207 | #endif |
| 4208 | return 1; |
| 4209 | } |
| 4210 | sqlite3_initialize(); |
| 4211 | zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); |
| 4212 | sqliterc = zBuf; |
| 4213 | } |
| @@ -4214,15 +4245,14 @@ | |
| 4214 | in = fopen(sqliterc,"rb"); |
| 4215 | if( in ){ |
| 4216 | if( stdin_is_interactive ){ |
| 4217 | fprintf(stderr,"-- Loading resources from %s\n",sqliterc); |
| 4218 | } |
| 4219 | rc = process_input(p,in); |
| 4220 | fclose(in); |
| 4221 | } |
| 4222 | sqlite3_free(zBuf); |
| 4223 | return rc; |
| 4224 | } |
| 4225 | |
| 4226 | /* |
| 4227 | ** Show available command line options |
| 4228 | */ |
| @@ -4494,14 +4524,11 @@ | |
| 4494 | |
| 4495 | /* Process the initialization file if there is one. If no -init option |
| 4496 | ** is given on the command line, look for a file named ~/.sqliterc and |
| 4497 | ** try to process it. |
| 4498 | */ |
| 4499 | rc = process_sqliterc(&data,zInitFile); |
| 4500 | if( rc>0 ){ |
| 4501 | return rc; |
| 4502 | } |
| 4503 | |
| 4504 | /* Make a second pass through the command-line argument and set |
| 4505 | ** options. This second pass is delayed until after the initialization |
| 4506 | ** file is processed so that the command-line arguments will override |
| 4507 | ** settings in the initialization file. |
| 4508 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -22,10 +22,17 @@ | |
| 22 | */ |
| 23 | #if defined(INCLUDE_MSVC_H) |
| 24 | #include "msvc.h" |
| 25 | #endif |
| 26 | |
| 27 | /* |
| 28 | ** No support for loadable extensions in VxWorks. |
| 29 | */ |
| 30 | #if defined(_WRS_KERNEL) && !SQLITE_OMIT_LOAD_EXTENSION |
| 31 | # define SQLITE_OMIT_LOAD_EXTENSION 1 |
| 32 | #endif |
| 33 | |
| 34 | /* |
| 35 | ** Enable large-file support for fopen() and friends on unix. |
| 36 | */ |
| 37 | #ifndef SQLITE_DISABLE_LFS |
| 38 | # define _LARGE_FILE 1 |
| @@ -105,14 +112,19 @@ | |
| 112 | #else |
| 113 | /* Make sure isatty() has a prototype. |
| 114 | */ |
| 115 | extern int isatty(int); |
| 116 | |
| 117 | #if !defined(__RTP__) && !defined(_WRS_KERNEL) |
| 118 | /* popen and pclose are not C89 functions and so are sometimes omitted from |
| 119 | ** the <stdio.h> header */ |
| 120 | extern FILE *popen(const char*,const char*); |
| 121 | extern int pclose(FILE*); |
| 122 | #else |
| 123 | # define SQLITE_OMIT_POPEN 1 |
| 124 | #endif |
| 125 | |
| 126 | #endif |
| 127 | |
| 128 | #if defined(_WIN32_WCE) |
| 129 | /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() |
| 130 | * thus we always assume that we have a console. That can be |
| @@ -163,14 +175,22 @@ | |
| 175 | t = (sqlite3_int64)(r*86400000.0); |
| 176 | } |
| 177 | return t; |
| 178 | } |
| 179 | |
| 180 | #if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) |
| 181 | #include <sys/time.h> |
| 182 | #include <sys/resource.h> |
| 183 | |
| 184 | /* VxWorks does not support getrusage() as far as we can determine */ |
| 185 | #if defined(_WRS_KERNEL) || defined(__RTP__) |
| 186 | struct rusage { |
| 187 | struct timeval ru_utime; /* user CPU time used */ |
| 188 | struct timeval ru_stime; /* system CPU time used */ |
| 189 | }; |
| 190 | #define getrusage(A,B) memset(B,0,sizeof(*B)) |
| 191 | #endif |
| 192 | |
| 193 | /* Saved resource information for the beginning of an operation */ |
| 194 | static struct rusage sBegin; /* CPU time at start */ |
| 195 | static sqlite3_int64 iBegin; /* Wall-clock time at start */ |
| 196 | |
| @@ -193,12 +213,12 @@ | |
| 213 | /* |
| 214 | ** Print the timing results. |
| 215 | */ |
| 216 | static void endTimer(void){ |
| 217 | if( enableTimer ){ |
| 218 | sqlite3_int64 iEnd = timeOfDay(); |
| 219 | struct rusage sEnd; |
| 220 | getrusage(RUSAGE_SELF, &sEnd); |
| 221 | printf("Run Time: real %.3f user %f sys %f\n", |
| 222 | (iEnd - iBegin)*0.001, |
| 223 | timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), |
| 224 | timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); |
| @@ -2437,11 +2457,13 @@ | |
| 2457 | /* |
| 2458 | ** Change the output file back to stdout |
| 2459 | */ |
| 2460 | static void output_reset(ShellState *p){ |
| 2461 | if( p->outfile[0]=='|' ){ |
| 2462 | #ifndef SQLITE_OMIT_POPEN |
| 2463 | pclose(p->out); |
| 2464 | #endif |
| 2465 | }else{ |
| 2466 | output_file_close(p->out); |
| 2467 | } |
| 2468 | p->outfile[0] = 0; |
| 2469 | p->out = stdout; |
| @@ -2930,13 +2952,18 @@ | |
| 2952 | return 1; |
| 2953 | } |
| 2954 | sCtx.zFile = zFile; |
| 2955 | sCtx.nLine = 1; |
| 2956 | if( sCtx.zFile[0]=='|' ){ |
| 2957 | #ifdef SQLITE_OMIT_POPEN |
| 2958 | fprintf(stderr, "Error: pipes are not supporte in this OS\n"); |
| 2959 | return 1; |
| 2960 | #else |
| 2961 | sCtx.in = popen(sCtx.zFile+1, "r"); |
| 2962 | sCtx.zFile = "<pipe>"; |
| 2963 | xCloser = pclose; |
| 2964 | #endif |
| 2965 | }else{ |
| 2966 | sCtx.in = fopen(sCtx.zFile, "rb"); |
| 2967 | xCloser = fclose; |
| 2968 | } |
| 2969 | if( p->mode==MODE_Ascii ){ |
| @@ -3255,18 +3282,24 @@ | |
| 3282 | }else{ |
| 3283 | p->outCount = 0; |
| 3284 | } |
| 3285 | output_reset(p); |
| 3286 | if( zFile[0]=='|' ){ |
| 3287 | #ifdef SQLITE_OMIT_POPEN |
| 3288 | fprintf(stderr,"Error: pipes are not supported in this OS\n"); |
| 3289 | rc = 1; |
| 3290 | p->out = stdout; |
| 3291 | #else |
| 3292 | p->out = popen(zFile + 1, "w"); |
| 3293 | if( p->out==0 ){ |
| 3294 | fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); |
| 3295 | p->out = stdout; |
| 3296 | rc = 1; |
| 3297 | }else{ |
| 3298 | sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); |
| 3299 | } |
| 3300 | #endif |
| 3301 | }else{ |
| 3302 | p->out = output_file_open(zFile); |
| 3303 | if( p->out==0 ){ |
| 3304 | if( strcmp(zFile,"off")!=0 ){ |
| 3305 | fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile); |
| @@ -4187,27 +4220,25 @@ | |
| 4220 | ** Read input from the file given by sqliterc_override. Or if that |
| 4221 | ** parameter is NULL, take input from ~/.sqliterc |
| 4222 | ** |
| 4223 | ** Returns the number of errors. |
| 4224 | */ |
| 4225 | static void process_sqliterc( |
| 4226 | ShellState *p, /* Configuration data */ |
| 4227 | const char *sqliterc_override /* Name of config file. NULL to use default */ |
| 4228 | ){ |
| 4229 | char *home_dir = NULL; |
| 4230 | const char *sqliterc = sqliterc_override; |
| 4231 | char *zBuf = 0; |
| 4232 | FILE *in = NULL; |
| 4233 | |
| 4234 | if (sqliterc == NULL) { |
| 4235 | home_dir = find_home_dir(); |
| 4236 | if( home_dir==0 ){ |
| 4237 | fprintf(stderr, "-- warning: cannot find home directory;" |
| 4238 | " cannot read ~/.sqliterc\n"); |
| 4239 | return; |
| 4240 | } |
| 4241 | sqlite3_initialize(); |
| 4242 | zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); |
| 4243 | sqliterc = zBuf; |
| 4244 | } |
| @@ -4214,15 +4245,14 @@ | |
| 4245 | in = fopen(sqliterc,"rb"); |
| 4246 | if( in ){ |
| 4247 | if( stdin_is_interactive ){ |
| 4248 | fprintf(stderr,"-- Loading resources from %s\n",sqliterc); |
| 4249 | } |
| 4250 | process_input(p,in); |
| 4251 | fclose(in); |
| 4252 | } |
| 4253 | sqlite3_free(zBuf); |
| 4254 | } |
| 4255 | |
| 4256 | /* |
| 4257 | ** Show available command line options |
| 4258 | */ |
| @@ -4494,14 +4524,11 @@ | |
| 4524 | |
| 4525 | /* Process the initialization file if there is one. If no -init option |
| 4526 | ** is given on the command line, look for a file named ~/.sqliterc and |
| 4527 | ** try to process it. |
| 4528 | */ |
| 4529 | process_sqliterc(&data,zInitFile); |
| 4530 | |
| 4531 | /* Make a second pass through the command-line argument and set |
| 4532 | ** options. This second pass is delayed until after the initialization |
| 4533 | ** file is processed so that the command-line arguments will override |
| 4534 | ** settings in the initialization file. |
| 4535 |
+481
-221
| --- src/sqlite3.c | ||
| +++ src/sqlite3.c | ||
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | /****************************************************************************** |
| 2 | 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | -** version 3.8.8. By combining all the individual C code files into this | |
| 3 | +** version 3.8.9. By combining all the individual C code files into this | |
| 4 | 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | 8 | ** translation unit. |
| @@ -88,10 +88,48 @@ | ||
| 88 | 88 | #endif /* _MSVC_H_ */ |
| 89 | 89 | |
| 90 | 90 | /************** End of msvc.h ************************************************/ |
| 91 | 91 | /************** Continuing where we left off in sqliteInt.h ******************/ |
| 92 | 92 | |
| 93 | +/* | |
| 94 | +** Special setup for VxWorks | |
| 95 | +*/ | |
| 96 | +/************** Include vxworks.h in the middle of sqliteInt.h ***************/ | |
| 97 | +/************** Begin file vxworks.h *****************************************/ | |
| 98 | +/* | |
| 99 | +** 2015-03-02 | |
| 100 | +** | |
| 101 | +** The author disclaims copyright to this source code. In place of | |
| 102 | +** a legal notice, here is a blessing: | |
| 103 | +** | |
| 104 | +** May you do good and not evil. | |
| 105 | +** May you find forgiveness for yourself and forgive others. | |
| 106 | +** May you share freely, never taking more than you give. | |
| 107 | +** | |
| 108 | +****************************************************************************** | |
| 109 | +** | |
| 110 | +** This file contains code that is specific to Wind River's VxWorks | |
| 111 | +*/ | |
| 112 | +#if defined(__RTP__) || defined(_WRS_KERNEL) | |
| 113 | +/* This is VxWorks. Set up things specially for that OS | |
| 114 | +*/ | |
| 115 | +#include <vxWorks.h> | |
| 116 | +#include <pthread.h> /* amalgamator: dontcache */ | |
| 117 | +#define OS_VXWORKS 1 | |
| 118 | +#define SQLITE_OS_OTHER 0 | |
| 119 | +#define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1 | |
| 120 | +#define SQLITE_OMIT_LOAD_EXTENSION 1 | |
| 121 | +#define SQLITE_ENABLE_LOCKING_STYLE 0 | |
| 122 | +#define HAVE_UTIME 1 | |
| 123 | +#else | |
| 124 | +/* This is not VxWorks. */ | |
| 125 | +#define OS_VXWORKS 0 | |
| 126 | +#endif /* defined(_WRS_KERNEL) */ | |
| 127 | + | |
| 128 | +/************** End of vxworks.h *********************************************/ | |
| 129 | +/************** Continuing where we left off in sqliteInt.h ******************/ | |
| 130 | + | |
| 93 | 131 | /* |
| 94 | 132 | ** These #defines should enable >2GB file support on POSIX if the |
| 95 | 133 | ** underlying operating system supports it. If the OS lacks |
| 96 | 134 | ** large file support, or if the OS is windows, these should be no-ops. |
| 97 | 135 | ** |
| @@ -276,13 +314,13 @@ | ||
| 276 | 314 | ** |
| 277 | 315 | ** See also: [sqlite3_libversion()], |
| 278 | 316 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 279 | 317 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 280 | 318 | */ |
| 281 | -#define SQLITE_VERSION "3.8.8" | |
| 282 | -#define SQLITE_VERSION_NUMBER 3008008 | |
| 283 | -#define SQLITE_SOURCE_ID "2015-02-25 14:25:31 6d132e7a224ee68b5cefe9222944aac5760ffc20" | |
| 319 | +#define SQLITE_VERSION "3.8.9" | |
| 320 | +#define SQLITE_VERSION_NUMBER 3008009 | |
| 321 | +#define SQLITE_SOURCE_ID "2015-03-09 10:40:48 e5da5e7d5dc5a3438ced23f1ee83e695abc29c45" | |
| 284 | 322 | |
| 285 | 323 | /* |
| 286 | 324 | ** CAPI3REF: Run-Time Library Version Numbers |
| 287 | 325 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 288 | 326 | ** |
| @@ -925,18 +963,20 @@ | ||
| 925 | 963 | ** |
| 926 | 964 | ** These integer constants are opcodes for the xFileControl method |
| 927 | 965 | ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] |
| 928 | 966 | ** interface. |
| 929 | 967 | ** |
| 968 | +** <ul> | |
| 969 | +** <li>[[SQLITE_FCNTL_LOCKSTATE]] | |
| 930 | 970 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This |
| 931 | 971 | ** opcode causes the xFileControl method to write the current state of |
| 932 | 972 | ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], |
| 933 | 973 | ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) |
| 934 | 974 | ** into an integer that the pArg argument points to. This capability |
| 935 | -** is used during testing and only needs to be supported when SQLITE_TEST | |
| 936 | -** is defined. | |
| 937 | -** <ul> | |
| 975 | +** is used during testing and is only available when the SQLITE_TEST | |
| 976 | +** compile-time option is used. | |
| 977 | +** | |
| 938 | 978 | ** <li>[[SQLITE_FCNTL_SIZE_HINT]] |
| 939 | 979 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS |
| 940 | 980 | ** layer a hint of how large the database file will grow to be during the |
| 941 | 981 | ** current transaction. This hint is not guaranteed to be accurate but it |
| 942 | 982 | ** is often close. The underlying VFS might choose to preallocate database |
| @@ -1057,11 +1097,13 @@ | ||
| 1057 | 1097 | ** the error message if the pragma fails. ^If the |
| 1058 | 1098 | ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal |
| 1059 | 1099 | ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] |
| 1060 | 1100 | ** file control returns [SQLITE_OK], then the parser assumes that the |
| 1061 | 1101 | ** VFS has handled the PRAGMA itself and the parser generates a no-op |
| 1062 | -** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns | |
| 1102 | +** prepared statement if result string is NULL, or that returns a copy | |
| 1103 | +** of the result string if the string is non-NULL. | |
| 1104 | +** ^If the [SQLITE_FCNTL_PRAGMA] file control returns | |
| 1063 | 1105 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means |
| 1064 | 1106 | ** that the VFS encountered an error while handling the [PRAGMA] and the |
| 1065 | 1107 | ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] |
| 1066 | 1108 | ** file control occurs at the beginning of pragma statement analysis and so |
| 1067 | 1109 | ** it is able to override built-in [PRAGMA] statements. |
| @@ -1916,11 +1958,10 @@ | ||
| 1916 | 1958 | ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE |
| 1917 | 1959 | ** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is |
| 1918 | 1960 | ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro |
| 1919 | 1961 | ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value |
| 1920 | 1962 | ** that specifies the maximum size of the created heap. |
| 1921 | -** </dl> | |
| 1922 | 1963 | ** |
| 1923 | 1964 | ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] |
| 1924 | 1965 | ** <dt>SQLITE_CONFIG_PCACHE_HDRSZ |
| 1925 | 1966 | ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which |
| 1926 | 1967 | ** is a pointer to an integer and writes into that integer the number of extra |
| @@ -3356,20 +3397,18 @@ | ||
| 3356 | 3397 | ** The second argument, "zSql", is the statement to be compiled, encoded |
| 3357 | 3398 | ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() |
| 3358 | 3399 | ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() |
| 3359 | 3400 | ** use UTF-16. |
| 3360 | 3401 | ** |
| 3361 | -** ^If the nByte argument is less than zero, then zSql is read up to the | |
| 3362 | -** first zero terminator. ^If nByte is non-negative, then it is the maximum | |
| 3363 | -** number of bytes read from zSql. ^When nByte is non-negative, the | |
| 3364 | -** zSql string ends at either the first '\000' or '\u0000' character or | |
| 3365 | -** the nByte-th byte, whichever comes first. If the caller knows | |
| 3366 | -** that the supplied string is nul-terminated, then there is a small | |
| 3367 | -** performance advantage to be gained by passing an nByte parameter that | |
| 3368 | -** is equal to the number of bytes in the input string <i>including</i> | |
| 3369 | -** the nul-terminator bytes as this saves SQLite from having to | |
| 3370 | -** make a copy of the input string. | |
| 3402 | +** ^If the nByte argument is negative, then zSql is read up to the | |
| 3403 | +** first zero terminator. ^If nByte is positive, then it is the | |
| 3404 | +** number of bytes read from zSql. ^If nByte is zero, then no prepared | |
| 3405 | +** statement is generated. | |
| 3406 | +** If the caller knows that the supplied string is nul-terminated, then | |
| 3407 | +** there is a small performance advantage to passing an nByte parameter that | |
| 3408 | +** is the number of bytes in the input string <i>including</i> | |
| 3409 | +** the nul-terminator. | |
| 3371 | 3410 | ** |
| 3372 | 3411 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 3373 | 3412 | ** past the end of the first SQL statement in zSql. These routines only |
| 3374 | 3413 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| 3375 | 3414 | ** what remains uncompiled. |
| @@ -4394,12 +4433,12 @@ | ||
| 4394 | 4433 | ** DEPRECATED |
| 4395 | 4434 | ** |
| 4396 | 4435 | ** These functions are [deprecated]. In order to maintain |
| 4397 | 4436 | ** backwards compatibility with older code, these functions continue |
| 4398 | 4437 | ** to be supported. However, new applications should avoid |
| 4399 | -** the use of these functions. To help encourage people to avoid | |
| 4400 | -** using these functions, we are not going to tell you what they do. | |
| 4438 | +** the use of these functions. To encourage programmers to avoid | |
| 4439 | +** these functions, we will not explain what they do. | |
| 4401 | 4440 | */ |
| 4402 | 4441 | #ifndef SQLITE_OMIT_DEPRECATED |
| 4403 | 4442 | SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); |
| 4404 | 4443 | SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); |
| 4405 | 4444 | SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); |
| @@ -7157,24 +7196,24 @@ | ||
| 7157 | 7196 | ** |
| 7158 | 7197 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 7159 | 7198 | ** is not a permanent error and does not affect the return value of |
| 7160 | 7199 | ** sqlite3_backup_finish(). |
| 7161 | 7200 | ** |
| 7162 | -** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] | |
| 7201 | +** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] | |
| 7163 | 7202 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 7164 | 7203 | ** |
| 7165 | -** ^Each call to sqlite3_backup_step() sets two values inside | |
| 7166 | -** the [sqlite3_backup] object: the number of pages still to be backed | |
| 7167 | -** up and the total number of pages in the source database file. | |
| 7168 | -** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces | |
| 7169 | -** retrieve these two values, respectively. | |
| 7170 | -** | |
| 7171 | -** ^The values returned by these functions are only updated by | |
| 7172 | -** sqlite3_backup_step(). ^If the source database is modified during a backup | |
| 7173 | -** operation, then the values are not updated to account for any extra | |
| 7174 | -** pages that need to be updated or the size of the source database file | |
| 7175 | -** changing. | |
| 7204 | +** ^The sqlite3_backup_remaining() routine returns the number of pages still | |
| 7205 | +** to be backed up at the conclusion of the most recent sqlite3_backup_step(). | |
| 7206 | +** ^The sqlite3_backup_pagecount() routine returns the total number of pages | |
| 7207 | +** in the source database at the conclusion of the most recent | |
| 7208 | +** sqlite3_backup_step(). | |
| 7209 | +** ^(The values returned by these functions are only updated by | |
| 7210 | +** sqlite3_backup_step(). If the source database is modified in a way that | |
| 7211 | +** changes the size of the source database or the number of pages remaining, | |
| 7212 | +** those changes are not reflected in the output of sqlite3_backup_pagecount() | |
| 7213 | +** and sqlite3_backup_remaining() until after the next | |
| 7214 | +** sqlite3_backup_step().)^ | |
| 7176 | 7215 | ** |
| 7177 | 7216 | ** <b>Concurrent Usage of Database Handles</b> |
| 7178 | 7217 | ** |
| 7179 | 7218 | ** ^The source [database connection] may be used by the application for other |
| 7180 | 7219 | ** purposes while a backup operation is underway or being initialized. |
| @@ -8018,19 +8057,21 @@ | ||
| 8018 | 8057 | #ifndef SQLITE_MAX_FUNCTION_ARG |
| 8019 | 8058 | # define SQLITE_MAX_FUNCTION_ARG 127 |
| 8020 | 8059 | #endif |
| 8021 | 8060 | |
| 8022 | 8061 | /* |
| 8023 | -** The maximum number of in-memory pages to use for the main database | |
| 8024 | -** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE | |
| 8062 | +** The suggested maximum number of in-memory pages to use for | |
| 8063 | +** the main database table and for temporary tables. | |
| 8064 | +** | |
| 8065 | +** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size | |
| 8066 | +** is 2000 pages. | |
| 8067 | +** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be | |
| 8068 | +** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options. | |
| 8025 | 8069 | */ |
| 8026 | 8070 | #ifndef SQLITE_DEFAULT_CACHE_SIZE |
| 8027 | 8071 | # define SQLITE_DEFAULT_CACHE_SIZE 2000 |
| 8028 | 8072 | #endif |
| 8029 | -#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE | |
| 8030 | -# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500 | |
| 8031 | -#endif | |
| 8032 | 8073 | |
| 8033 | 8074 | /* |
| 8034 | 8075 | ** The default number of frames to accumulate in the log file before |
| 8035 | 8076 | ** checkpointing the database in WAL mode. |
| 8036 | 8077 | */ |
| @@ -9733,27 +9774,29 @@ | ||
| 9733 | 9774 | #define OP_FkCounter 134 /* synopsis: fkctr[P1]+=P2 */ |
| 9734 | 9775 | #define OP_FkIfZero 135 /* synopsis: if fkctr[P1]==0 goto P2 */ |
| 9735 | 9776 | #define OP_MemMax 136 /* synopsis: r[P1]=max(r[P1],r[P2]) */ |
| 9736 | 9777 | #define OP_IfPos 137 /* synopsis: if r[P1]>0 goto P2 */ |
| 9737 | 9778 | #define OP_IfNeg 138 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */ |
| 9738 | -#define OP_IfZero 139 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ | |
| 9739 | -#define OP_AggFinal 140 /* synopsis: accum=r[P1] N=P2 */ | |
| 9740 | -#define OP_IncrVacuum 141 | |
| 9741 | -#define OP_Expire 142 | |
| 9742 | -#define OP_TableLock 143 /* synopsis: iDb=P1 root=P2 write=P3 */ | |
| 9743 | -#define OP_VBegin 144 | |
| 9744 | -#define OP_VCreate 145 | |
| 9745 | -#define OP_VDestroy 146 | |
| 9746 | -#define OP_VOpen 147 | |
| 9747 | -#define OP_VColumn 148 /* synopsis: r[P3]=vcolumn(P2) */ | |
| 9748 | -#define OP_VNext 149 | |
| 9749 | -#define OP_VRename 150 | |
| 9750 | -#define OP_Pagecount 151 | |
| 9751 | -#define OP_MaxPgcnt 152 | |
| 9752 | -#define OP_Init 153 /* synopsis: Start at P2 */ | |
| 9753 | -#define OP_Noop 154 | |
| 9754 | -#define OP_Explain 155 | |
| 9779 | +#define OP_IfNotZero 139 /* synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 */ | |
| 9780 | +#define OP_DecrJumpZero 140 /* synopsis: if (--r[P1])==0 goto P2 */ | |
| 9781 | +#define OP_JumpZeroIncr 141 /* synopsis: if (r[P1]++)==0 ) goto P2 */ | |
| 9782 | +#define OP_AggFinal 142 /* synopsis: accum=r[P1] N=P2 */ | |
| 9783 | +#define OP_IncrVacuum 143 | |
| 9784 | +#define OP_Expire 144 | |
| 9785 | +#define OP_TableLock 145 /* synopsis: iDb=P1 root=P2 write=P3 */ | |
| 9786 | +#define OP_VBegin 146 | |
| 9787 | +#define OP_VCreate 147 | |
| 9788 | +#define OP_VDestroy 148 | |
| 9789 | +#define OP_VOpen 149 | |
| 9790 | +#define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */ | |
| 9791 | +#define OP_VNext 151 | |
| 9792 | +#define OP_VRename 152 | |
| 9793 | +#define OP_Pagecount 153 | |
| 9794 | +#define OP_MaxPgcnt 154 | |
| 9795 | +#define OP_Init 155 /* synopsis: Start at P2 */ | |
| 9796 | +#define OP_Noop 156 | |
| 9797 | +#define OP_Explain 157 | |
| 9755 | 9798 | |
| 9756 | 9799 | |
| 9757 | 9800 | /* Properties such as "out2" or "jump" that are specified in |
| 9758 | 9801 | ** comments following the "case" for each opcode in the vdbe.c |
| 9759 | 9802 | ** are encoded into bitvectors as follows: |
| @@ -9781,13 +9824,13 @@ | ||
| 9781 | 9824 | /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\ |
| 9782 | 9825 | /* 104 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x00,\ |
| 9783 | 9826 | /* 112 */ 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,\ |
| 9784 | 9827 | /* 120 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ |
| 9785 | 9828 | /* 128 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x02, 0x00, 0x01,\ |
| 9786 | -/* 136 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00,\ | |
| 9787 | -/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,\ | |
| 9788 | -/* 152 */ 0x02, 0x01, 0x00, 0x00,} | |
| 9829 | +/* 136 */ 0x08, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x01,\ | |
| 9830 | +/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\ | |
| 9831 | +/* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,} | |
| 9789 | 9832 | |
| 9790 | 9833 | /************** End of opcodes.h *********************************************/ |
| 9791 | 9834 | /************** Continuing where we left off in vdbe.h ***********************/ |
| 9792 | 9835 | |
| 9793 | 9836 | /* |
| @@ -12022,11 +12065,11 @@ | ||
| 12022 | 12065 | #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ |
| 12023 | 12066 | #define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */ |
| 12024 | 12067 | #define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ |
| 12025 | 12068 | #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ |
| 12026 | 12069 | #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ |
| 12027 | - /* 0x0080 // not currently used */ | |
| 12070 | +#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */ | |
| 12028 | 12071 | #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ |
| 12029 | 12072 | #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ |
| 12030 | 12073 | #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ |
| 12031 | 12074 | #define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ |
| 12032 | 12075 | #define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ |
| @@ -24969,27 +25012,29 @@ | ||
| 24969 | 25012 | /* 134 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), |
| 24970 | 25013 | /* 135 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), |
| 24971 | 25014 | /* 136 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), |
| 24972 | 25015 | /* 137 */ "IfPos" OpHelp("if r[P1]>0 goto P2"), |
| 24973 | 25016 | /* 138 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"), |
| 24974 | - /* 139 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), | |
| 24975 | - /* 140 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), | |
| 24976 | - /* 141 */ "IncrVacuum" OpHelp(""), | |
| 24977 | - /* 142 */ "Expire" OpHelp(""), | |
| 24978 | - /* 143 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), | |
| 24979 | - /* 144 */ "VBegin" OpHelp(""), | |
| 24980 | - /* 145 */ "VCreate" OpHelp(""), | |
| 24981 | - /* 146 */ "VDestroy" OpHelp(""), | |
| 24982 | - /* 147 */ "VOpen" OpHelp(""), | |
| 24983 | - /* 148 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), | |
| 24984 | - /* 149 */ "VNext" OpHelp(""), | |
| 24985 | - /* 150 */ "VRename" OpHelp(""), | |
| 24986 | - /* 151 */ "Pagecount" OpHelp(""), | |
| 24987 | - /* 152 */ "MaxPgcnt" OpHelp(""), | |
| 24988 | - /* 153 */ "Init" OpHelp("Start at P2"), | |
| 24989 | - /* 154 */ "Noop" OpHelp(""), | |
| 24990 | - /* 155 */ "Explain" OpHelp(""), | |
| 25017 | + /* 139 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]+=P3, goto P2"), | |
| 25018 | + /* 140 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), | |
| 25019 | + /* 141 */ "JumpZeroIncr" OpHelp("if (r[P1]++)==0 ) goto P2"), | |
| 25020 | + /* 142 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), | |
| 25021 | + /* 143 */ "IncrVacuum" OpHelp(""), | |
| 25022 | + /* 144 */ "Expire" OpHelp(""), | |
| 25023 | + /* 145 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), | |
| 25024 | + /* 146 */ "VBegin" OpHelp(""), | |
| 25025 | + /* 147 */ "VCreate" OpHelp(""), | |
| 25026 | + /* 148 */ "VDestroy" OpHelp(""), | |
| 25027 | + /* 149 */ "VOpen" OpHelp(""), | |
| 25028 | + /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), | |
| 25029 | + /* 151 */ "VNext" OpHelp(""), | |
| 25030 | + /* 152 */ "VRename" OpHelp(""), | |
| 25031 | + /* 153 */ "Pagecount" OpHelp(""), | |
| 25032 | + /* 154 */ "MaxPgcnt" OpHelp(""), | |
| 25033 | + /* 155 */ "Init" OpHelp("Start at P2"), | |
| 25034 | + /* 156 */ "Noop" OpHelp(""), | |
| 25035 | + /* 157 */ "Explain" OpHelp(""), | |
| 24991 | 25036 | }; |
| 24992 | 25037 | return azName[i]; |
| 24993 | 25038 | } |
| 24994 | 25039 | #endif |
| 24995 | 25040 | |
| @@ -25065,22 +25110,10 @@ | ||
| 25065 | 25110 | # else |
| 25066 | 25111 | # define SQLITE_ENABLE_LOCKING_STYLE 0 |
| 25067 | 25112 | # endif |
| 25068 | 25113 | #endif |
| 25069 | 25114 | |
| 25070 | -/* | |
| 25071 | -** Define the OS_VXWORKS pre-processor macro to 1 if building on | |
| 25072 | -** vxworks, or 0 otherwise. | |
| 25073 | -*/ | |
| 25074 | -#ifndef OS_VXWORKS | |
| 25075 | -# if defined(__RTP__) || defined(_WRS_KERNEL) | |
| 25076 | -# define OS_VXWORKS 1 | |
| 25077 | -# else | |
| 25078 | -# define OS_VXWORKS 0 | |
| 25079 | -# endif | |
| 25080 | -#endif | |
| 25081 | - | |
| 25082 | 25115 | /* |
| 25083 | 25116 | ** standard include files. |
| 25084 | 25117 | */ |
| 25085 | 25118 | #include <sys/types.h> |
| 25086 | 25119 | #include <sys/stat.h> |
| @@ -25091,22 +25124,23 @@ | ||
| 25091 | 25124 | #include <errno.h> |
| 25092 | 25125 | #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
| 25093 | 25126 | # include <sys/mman.h> |
| 25094 | 25127 | #endif |
| 25095 | 25128 | |
| 25096 | -#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS | |
| 25129 | +#if SQLITE_ENABLE_LOCKING_STYLE | |
| 25097 | 25130 | # include <sys/ioctl.h> |
| 25098 | -# if OS_VXWORKS | |
| 25099 | -# include <semaphore.h> | |
| 25100 | -# include <limits.h> | |
| 25101 | -# else | |
| 25102 | -# include <sys/file.h> | |
| 25103 | -# include <sys/param.h> | |
| 25104 | -# endif | |
| 25131 | +# include <sys/file.h> | |
| 25132 | +# include <sys/param.h> | |
| 25105 | 25133 | #endif /* SQLITE_ENABLE_LOCKING_STYLE */ |
| 25106 | 25134 | |
| 25107 | -#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) | |
| 25135 | +#if OS_VXWORKS | |
| 25136 | +/* # include <sys/ioctl.h> */ | |
| 25137 | +# include <semaphore.h> | |
| 25138 | +# include <limits.h> | |
| 25139 | +#endif /* OS_VXWORKS */ | |
| 25140 | + | |
| 25141 | +#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE | |
| 25108 | 25142 | # include <sys/mount.h> |
| 25109 | 25143 | #endif |
| 25110 | 25144 | |
| 25111 | 25145 | #ifdef HAVE_UTIME |
| 25112 | 25146 | # include <utime.h> |
| @@ -25142,10 +25176,14 @@ | ||
| 25142 | 25176 | |
| 25143 | 25177 | /* |
| 25144 | 25178 | ** Maximum supported path-length. |
| 25145 | 25179 | */ |
| 25146 | 25180 | #define MAX_PATHNAME 512 |
| 25181 | + | |
| 25182 | +/* Always cast the getpid() return type for compatibility with | |
| 25183 | +** kernel modules in VxWorks. */ | |
| 25184 | +#define osGetpid(X) (pid_t)getpid() | |
| 25147 | 25185 | |
| 25148 | 25186 | /* |
| 25149 | 25187 | ** Only set the lastErrno if the error code is a real error and not |
| 25150 | 25188 | ** a normal expected return code of SQLITE_BUSY or SQLITE_OK |
| 25151 | 25189 | */ |
| @@ -25231,11 +25269,11 @@ | ||
| 25231 | 25269 | |
| 25232 | 25270 | /* This variable holds the process id (pid) from when the xRandomness() |
| 25233 | 25271 | ** method was called. If xOpen() is called from a different process id, |
| 25234 | 25272 | ** indicating that a fork() has occurred, the PRNG will be reset. |
| 25235 | 25273 | */ |
| 25236 | -static int randomnessPid = 0; | |
| 25274 | +static pid_t randomnessPid = 0; | |
| 25237 | 25275 | |
| 25238 | 25276 | /* |
| 25239 | 25277 | ** Allowed values for the unixFile.ctrlFlags bitmask: |
| 25240 | 25278 | */ |
| 25241 | 25279 | #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
| @@ -25587,11 +25625,11 @@ | ||
| 25587 | 25625 | #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) |
| 25588 | 25626 | |
| 25589 | 25627 | { "read", (sqlite3_syscall_ptr)read, 0 }, |
| 25590 | 25628 | #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) |
| 25591 | 25629 | |
| 25592 | -#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) | |
| 25630 | +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE | |
| 25593 | 25631 | { "pread", (sqlite3_syscall_ptr)pread, 0 }, |
| 25594 | 25632 | #else |
| 25595 | 25633 | { "pread", (sqlite3_syscall_ptr)0, 0 }, |
| 25596 | 25634 | #endif |
| 25597 | 25635 | #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) |
| @@ -25604,11 +25642,11 @@ | ||
| 25604 | 25642 | #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) |
| 25605 | 25643 | |
| 25606 | 25644 | { "write", (sqlite3_syscall_ptr)write, 0 }, |
| 25607 | 25645 | #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) |
| 25608 | 25646 | |
| 25609 | -#if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) | |
| 25647 | +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE | |
| 25610 | 25648 | { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, |
| 25611 | 25649 | #else |
| 25612 | 25650 | { "pwrite", (sqlite3_syscall_ptr)0, 0 }, |
| 25613 | 25651 | #endif |
| 25614 | 25652 | #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| @@ -26743,11 +26781,12 @@ | ||
| 26743 | 26781 | int tErrno = 0; |
| 26744 | 26782 | |
| 26745 | 26783 | assert( pFile ); |
| 26746 | 26784 | OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, |
| 26747 | 26785 | azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
| 26748 | - azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid())); | |
| 26786 | + azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared, | |
| 26787 | + osGetpid())); | |
| 26749 | 26788 | |
| 26750 | 26789 | /* If there is already a lock of this type or more restrictive on the |
| 26751 | 26790 | ** unixFile, do nothing. Don't use the end_lock: exit path, as |
| 26752 | 26791 | ** unixEnterMutex() hasn't been called yet. |
| 26753 | 26792 | */ |
| @@ -26951,11 +26990,11 @@ | ||
| 26951 | 26990 | int rc = SQLITE_OK; |
| 26952 | 26991 | |
| 26953 | 26992 | assert( pFile ); |
| 26954 | 26993 | OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, |
| 26955 | 26994 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
| 26956 | - getpid())); | |
| 26995 | + osGetpid())); | |
| 26957 | 26996 | |
| 26958 | 26997 | assert( eFileLock<=SHARED_LOCK ); |
| 26959 | 26998 | if( pFile->eFileLock<=eFileLock ){ |
| 26960 | 26999 | return SQLITE_OK; |
| 26961 | 27000 | } |
| @@ -27378,11 +27417,11 @@ | ||
| 27378 | 27417 | char *zLockFile = (char *)pFile->lockingContext; |
| 27379 | 27418 | int rc; |
| 27380 | 27419 | |
| 27381 | 27420 | assert( pFile ); |
| 27382 | 27421 | OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, |
| 27383 | - pFile->eFileLock, getpid())); | |
| 27422 | + pFile->eFileLock, osGetpid())); | |
| 27384 | 27423 | assert( eFileLock<=SHARED_LOCK ); |
| 27385 | 27424 | |
| 27386 | 27425 | /* no-op if possible */ |
| 27387 | 27426 | if( pFile->eFileLock==eFileLock ){ |
| 27388 | 27427 | return SQLITE_OK; |
| @@ -27441,14 +27480,13 @@ | ||
| 27441 | 27480 | ** a single exclusive lock. In other words, SHARED, RESERVED, and |
| 27442 | 27481 | ** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite |
| 27443 | 27482 | ** still works when you do this, but concurrency is reduced since |
| 27444 | 27483 | ** only a single process can be reading the database at a time. |
| 27445 | 27484 | ** |
| 27446 | -** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if | |
| 27447 | -** compiling for VXWORKS. | |
| 27485 | +** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off | |
| 27448 | 27486 | */ |
| 27449 | -#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS | |
| 27487 | +#if SQLITE_ENABLE_LOCKING_STYLE | |
| 27450 | 27488 | |
| 27451 | 27489 | /* |
| 27452 | 27490 | ** Retry flock() calls that fail with EINTR |
| 27453 | 27491 | */ |
| 27454 | 27492 | #ifdef EINTR |
| @@ -27597,11 +27635,11 @@ | ||
| 27597 | 27635 | static int flockUnlock(sqlite3_file *id, int eFileLock) { |
| 27598 | 27636 | unixFile *pFile = (unixFile*)id; |
| 27599 | 27637 | |
| 27600 | 27638 | assert( pFile ); |
| 27601 | 27639 | OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, |
| 27602 | - pFile->eFileLock, getpid())); | |
| 27640 | + pFile->eFileLock, osGetpid())); | |
| 27603 | 27641 | assert( eFileLock<=SHARED_LOCK ); |
| 27604 | 27642 | |
| 27605 | 27643 | /* no-op if possible */ |
| 27606 | 27644 | if( pFile->eFileLock==eFileLock ){ |
| 27607 | 27645 | return SQLITE_OK; |
| @@ -27658,11 +27696,11 @@ | ||
| 27658 | 27696 | ** This routine checks if there is a RESERVED lock held on the specified |
| 27659 | 27697 | ** file by this or any other process. If such a lock is held, set *pResOut |
| 27660 | 27698 | ** to a non-zero value otherwise *pResOut is set to zero. The return value |
| 27661 | 27699 | ** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
| 27662 | 27700 | */ |
| 27663 | -static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { | |
| 27701 | +static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) { | |
| 27664 | 27702 | int rc = SQLITE_OK; |
| 27665 | 27703 | int reserved = 0; |
| 27666 | 27704 | unixFile *pFile = (unixFile*)id; |
| 27667 | 27705 | |
| 27668 | 27706 | SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
| @@ -27725,11 +27763,11 @@ | ||
| 27725 | 27763 | ** access the file. |
| 27726 | 27764 | ** |
| 27727 | 27765 | ** This routine will only increase a lock. Use the sqlite3OsUnlock() |
| 27728 | 27766 | ** routine to lower a locking level. |
| 27729 | 27767 | */ |
| 27730 | -static int semLock(sqlite3_file *id, int eFileLock) { | |
| 27768 | +static int semXLock(sqlite3_file *id, int eFileLock) { | |
| 27731 | 27769 | unixFile *pFile = (unixFile*)id; |
| 27732 | 27770 | sem_t *pSem = pFile->pInode->pSem; |
| 27733 | 27771 | int rc = SQLITE_OK; |
| 27734 | 27772 | |
| 27735 | 27773 | /* if we already have a lock, it is exclusive. |
| @@ -27758,18 +27796,18 @@ | ||
| 27758 | 27796 | ** must be either NO_LOCK or SHARED_LOCK. |
| 27759 | 27797 | ** |
| 27760 | 27798 | ** If the locking level of the file descriptor is already at or below |
| 27761 | 27799 | ** the requested locking level, this routine is a no-op. |
| 27762 | 27800 | */ |
| 27763 | -static int semUnlock(sqlite3_file *id, int eFileLock) { | |
| 27801 | +static int semXUnlock(sqlite3_file *id, int eFileLock) { | |
| 27764 | 27802 | unixFile *pFile = (unixFile*)id; |
| 27765 | 27803 | sem_t *pSem = pFile->pInode->pSem; |
| 27766 | 27804 | |
| 27767 | 27805 | assert( pFile ); |
| 27768 | 27806 | assert( pSem ); |
| 27769 | 27807 | OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, |
| 27770 | - pFile->eFileLock, getpid())); | |
| 27808 | + pFile->eFileLock, osGetpid())); | |
| 27771 | 27809 | assert( eFileLock<=SHARED_LOCK ); |
| 27772 | 27810 | |
| 27773 | 27811 | /* no-op if possible */ |
| 27774 | 27812 | if( pFile->eFileLock==eFileLock ){ |
| 27775 | 27813 | return SQLITE_OK; |
| @@ -27795,14 +27833,14 @@ | ||
| 27795 | 27833 | } |
| 27796 | 27834 | |
| 27797 | 27835 | /* |
| 27798 | 27836 | ** Close a file. |
| 27799 | 27837 | */ |
| 27800 | -static int semClose(sqlite3_file *id) { | |
| 27838 | +static int semXClose(sqlite3_file *id) { | |
| 27801 | 27839 | if( id ){ |
| 27802 | 27840 | unixFile *pFile = (unixFile*)id; |
| 27803 | - semUnlock(id, NO_LOCK); | |
| 27841 | + semXUnlock(id, NO_LOCK); | |
| 27804 | 27842 | assert( pFile ); |
| 27805 | 27843 | unixEnterMutex(); |
| 27806 | 27844 | releaseInodeInfo(pFile); |
| 27807 | 27845 | unixLeaveMutex(); |
| 27808 | 27846 | closeUnixFile(id); |
| @@ -27979,11 +28017,11 @@ | ||
| 27979 | 28017 | afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; |
| 27980 | 28018 | |
| 27981 | 28019 | assert( pFile ); |
| 27982 | 28020 | OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, |
| 27983 | 28021 | azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
| 27984 | - azFileLock(pInode->eFileLock), pInode->nShared , getpid())); | |
| 28022 | + azFileLock(pInode->eFileLock), pInode->nShared , osGetpid())); | |
| 27985 | 28023 | |
| 27986 | 28024 | /* If there is already a lock of this type or more restrictive on the |
| 27987 | 28025 | ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as |
| 27988 | 28026 | ** unixEnterMutex() hasn't been called yet. |
| 27989 | 28027 | */ |
| @@ -28165,11 +28203,11 @@ | ||
| 28165 | 28203 | #endif |
| 28166 | 28204 | |
| 28167 | 28205 | assert( pFile ); |
| 28168 | 28206 | OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, |
| 28169 | 28207 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
| 28170 | - getpid())); | |
| 28208 | + osGetpid())); | |
| 28171 | 28209 | |
| 28172 | 28210 | assert( eFileLock<=SHARED_LOCK ); |
| 28173 | 28211 | if( pFile->eFileLock<=eFileLock ){ |
| 28174 | 28212 | return SQLITE_OK; |
| 28175 | 28213 | } |
| @@ -29204,11 +29242,13 @@ | ||
| 29204 | 29242 | ** |
| 29205 | 29243 | ** This function should not be called directly by other code in this file. |
| 29206 | 29244 | ** Instead, it should be called via macro osGetpagesize(). |
| 29207 | 29245 | */ |
| 29208 | 29246 | static int unixGetpagesize(void){ |
| 29209 | -#if defined(_BSD_SOURCE) | |
| 29247 | +#if OS_VXWORKS | |
| 29248 | + return 1024; | |
| 29249 | +#elif defined(_BSD_SOURCE) | |
| 29210 | 29250 | return getpagesize(); |
| 29211 | 29251 | #else |
| 29212 | 29252 | return (int)sysconf(_SC_PAGESIZE); |
| 29213 | 29253 | #endif |
| 29214 | 29254 | } |
| @@ -29833,11 +29873,11 @@ | ||
| 29833 | 29873 | } |
| 29834 | 29874 | } |
| 29835 | 29875 | } |
| 29836 | 29876 | sqlite3_mutex_leave(pShmNode->mutex); |
| 29837 | 29877 | OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", |
| 29838 | - p->id, getpid(), p->sharedMask, p->exclMask)); | |
| 29878 | + p->id, osGetpid(), p->sharedMask, p->exclMask)); | |
| 29839 | 29879 | return rc; |
| 29840 | 29880 | } |
| 29841 | 29881 | |
| 29842 | 29882 | /* |
| 29843 | 29883 | ** Implement a memory barrier or memory fence on shared memory. |
| @@ -30236,11 +30276,11 @@ | ||
| 30236 | 30276 | dotlockUnlock, /* xUnlock method */ |
| 30237 | 30277 | dotlockCheckReservedLock, /* xCheckReservedLock method */ |
| 30238 | 30278 | 0 /* xShmMap method */ |
| 30239 | 30279 | ) |
| 30240 | 30280 | |
| 30241 | -#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS | |
| 30281 | +#if SQLITE_ENABLE_LOCKING_STYLE | |
| 30242 | 30282 | IOMETHODS( |
| 30243 | 30283 | flockIoFinder, /* Finder function name */ |
| 30244 | 30284 | flockIoMethods, /* sqlite3_io_methods object name */ |
| 30245 | 30285 | 1, /* shared memory is disabled */ |
| 30246 | 30286 | flockClose, /* xClose method */ |
| @@ -30254,14 +30294,14 @@ | ||
| 30254 | 30294 | #if OS_VXWORKS |
| 30255 | 30295 | IOMETHODS( |
| 30256 | 30296 | semIoFinder, /* Finder function name */ |
| 30257 | 30297 | semIoMethods, /* sqlite3_io_methods object name */ |
| 30258 | 30298 | 1, /* shared memory is disabled */ |
| 30259 | - semClose, /* xClose method */ | |
| 30260 | - semLock, /* xLock method */ | |
| 30261 | - semUnlock, /* xUnlock method */ | |
| 30262 | - semCheckReservedLock, /* xCheckReservedLock method */ | |
| 30299 | + semXClose, /* xClose method */ | |
| 30300 | + semXLock, /* xLock method */ | |
| 30301 | + semXUnlock, /* xUnlock method */ | |
| 30302 | + semXCheckReservedLock, /* xCheckReservedLock method */ | |
| 30263 | 30303 | 0 /* xShmMap method */ |
| 30264 | 30304 | ) |
| 30265 | 30305 | #endif |
| 30266 | 30306 | |
| 30267 | 30307 | #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
| @@ -30381,19 +30421,17 @@ | ||
| 30381 | 30421 | static const sqlite3_io_methods |
| 30382 | 30422 | *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; |
| 30383 | 30423 | |
| 30384 | 30424 | #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
| 30385 | 30425 | |
| 30386 | -#if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE | |
| 30387 | -/* | |
| 30388 | -** This "finder" function attempts to determine the best locking strategy | |
| 30389 | -** for the database file "filePath". It then returns the sqlite3_io_methods | |
| 30390 | -** object that implements that strategy. | |
| 30391 | -** | |
| 30392 | -** This is for VXWorks only. | |
| 30426 | +#if OS_VXWORKS | |
| 30427 | +/* | |
| 30428 | +** This "finder" function for VxWorks checks to see if posix advisory | |
| 30429 | +** locking works. If it does, then that is what is used. If it does not | |
| 30430 | +** work, then fallback to named semaphore locking. | |
| 30393 | 30431 | */ |
| 30394 | -static const sqlite3_io_methods *autolockIoFinderImpl( | |
| 30432 | +static const sqlite3_io_methods *vxworksIoFinderImpl( | |
| 30395 | 30433 | const char *filePath, /* name of the database file */ |
| 30396 | 30434 | unixFile *pNew /* the open file object */ |
| 30397 | 30435 | ){ |
| 30398 | 30436 | struct flock lockInfo; |
| 30399 | 30437 | |
| @@ -30415,13 +30453,13 @@ | ||
| 30415 | 30453 | }else{ |
| 30416 | 30454 | return &semIoMethods; |
| 30417 | 30455 | } |
| 30418 | 30456 | } |
| 30419 | 30457 | static const sqlite3_io_methods |
| 30420 | - *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; | |
| 30458 | + *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl; | |
| 30421 | 30459 | |
| 30422 | -#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */ | |
| 30460 | +#endif /* OS_VXWORKS */ | |
| 30423 | 30461 | |
| 30424 | 30462 | /* |
| 30425 | 30463 | ** An abstract type for a pointer to an IO method finder function: |
| 30426 | 30464 | */ |
| 30427 | 30465 | typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); |
| @@ -30930,12 +30968,12 @@ | ||
| 30930 | 30968 | /* Detect a pid change and reset the PRNG. There is a race condition |
| 30931 | 30969 | ** here such that two or more threads all trying to open databases at |
| 30932 | 30970 | ** the same instant might all reset the PRNG. But multiple resets |
| 30933 | 30971 | ** are harmless. |
| 30934 | 30972 | */ |
| 30935 | - if( randomnessPid!=getpid() ){ | |
| 30936 | - randomnessPid = getpid(); | |
| 30973 | + if( randomnessPid!=osGetpid() ){ | |
| 30974 | + randomnessPid = osGetpid(); | |
| 30937 | 30975 | sqlite3_randomness(0,0); |
| 30938 | 30976 | } |
| 30939 | 30977 | |
| 30940 | 30978 | memset(p, 0, sizeof(unixFile)); |
| 30941 | 30979 | |
| @@ -31322,11 +31360,11 @@ | ||
| 31322 | 31360 | ** When testing, initializing zBuf[] to zero is all we do. That means |
| 31323 | 31361 | ** that we always use the same random number sequence. This makes the |
| 31324 | 31362 | ** tests repeatable. |
| 31325 | 31363 | */ |
| 31326 | 31364 | memset(zBuf, 0, nBuf); |
| 31327 | - randomnessPid = getpid(); | |
| 31365 | + randomnessPid = osGetpid(); | |
| 31328 | 31366 | #if !defined(SQLITE_TEST) |
| 31329 | 31367 | { |
| 31330 | 31368 | int fd, got; |
| 31331 | 31369 | fd = robust_open("/dev/urandom", O_RDONLY, 0); |
| 31332 | 31370 | if( fd<0 ){ |
| @@ -31643,11 +31681,11 @@ | ||
| 31643 | 31681 | #else |
| 31644 | 31682 | # ifdef _CS_DARWIN_USER_TEMP_DIR |
| 31645 | 31683 | { |
| 31646 | 31684 | if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ |
| 31647 | 31685 | OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", |
| 31648 | - lPath, errno, getpid())); | |
| 31686 | + lPath, errno, osGetpid())); | |
| 31649 | 31687 | return SQLITE_IOERR_LOCK; |
| 31650 | 31688 | } |
| 31651 | 31689 | len = strlcat(lPath, "sqliteplocks", maxLen); |
| 31652 | 31690 | } |
| 31653 | 31691 | # else |
| @@ -31665,11 +31703,11 @@ | ||
| 31665 | 31703 | char c = dbPath[i]; |
| 31666 | 31704 | lPath[i+len] = (c=='/')?'_':c; |
| 31667 | 31705 | } |
| 31668 | 31706 | lPath[i+len]='\0'; |
| 31669 | 31707 | strlcat(lPath, ":auto:", maxLen); |
| 31670 | - OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid())); | |
| 31708 | + OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, osGetpid())); | |
| 31671 | 31709 | return SQLITE_OK; |
| 31672 | 31710 | } |
| 31673 | 31711 | |
| 31674 | 31712 | /* |
| 31675 | 31713 | ** Creates the lock file and any missing directories in lockPath |
| @@ -31692,20 +31730,20 @@ | ||
| 31692 | 31730 | if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ |
| 31693 | 31731 | int err=errno; |
| 31694 | 31732 | if( err!=EEXIST ) { |
| 31695 | 31733 | OSTRACE(("CREATELOCKPATH FAILED creating %s, " |
| 31696 | 31734 | "'%s' proxy lock path=%s pid=%d\n", |
| 31697 | - buf, strerror(err), lockPath, getpid())); | |
| 31735 | + buf, strerror(err), lockPath, osGetpid())); | |
| 31698 | 31736 | return err; |
| 31699 | 31737 | } |
| 31700 | 31738 | } |
| 31701 | 31739 | } |
| 31702 | 31740 | start=i+1; |
| 31703 | 31741 | } |
| 31704 | 31742 | buf[i] = lockPath[i]; |
| 31705 | 31743 | } |
| 31706 | - OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid())); | |
| 31744 | + OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, osGetpid())); | |
| 31707 | 31745 | return 0; |
| 31708 | 31746 | } |
| 31709 | 31747 | |
| 31710 | 31748 | /* |
| 31711 | 31749 | ** Create a new VFS file descriptor (stored in memory obtained from |
| @@ -32006,11 +32044,12 @@ | ||
| 32006 | 32044 | int readLen = 0; |
| 32007 | 32045 | int tryOldLockPath = 0; |
| 32008 | 32046 | int forceNewLockPath = 0; |
| 32009 | 32047 | |
| 32010 | 32048 | OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, |
| 32011 | - (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid())); | |
| 32049 | + (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), | |
| 32050 | + osGetpid())); | |
| 32012 | 32051 | |
| 32013 | 32052 | rc = proxyGetHostID(myHostID, &pError); |
| 32014 | 32053 | if( (rc&0xff)==SQLITE_IOERR ){ |
| 32015 | 32054 | storeLastErrno(pFile, pError); |
| 32016 | 32055 | goto end_takeconch; |
| @@ -32216,11 +32255,11 @@ | ||
| 32216 | 32255 | |
| 32217 | 32256 | pCtx = (proxyLockingContext *)pFile->lockingContext; |
| 32218 | 32257 | conchFile = pCtx->conchFile; |
| 32219 | 32258 | OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, |
| 32220 | 32259 | (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), |
| 32221 | - getpid())); | |
| 32260 | + osGetpid())); | |
| 32222 | 32261 | if( pCtx->conchHeld>0 ){ |
| 32223 | 32262 | rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); |
| 32224 | 32263 | } |
| 32225 | 32264 | pCtx->conchHeld = 0; |
| 32226 | 32265 | OSTRACE(("RELEASECONCH %d %s\n", conchFile->h, |
| @@ -32358,11 +32397,11 @@ | ||
| 32358 | 32397 | }else{ |
| 32359 | 32398 | lockPath=(char *)path; |
| 32360 | 32399 | } |
| 32361 | 32400 | |
| 32362 | 32401 | OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, |
| 32363 | - (lockPath ? lockPath : ":auto:"), getpid())); | |
| 32402 | + (lockPath ? lockPath : ":auto:"), osGetpid())); | |
| 32364 | 32403 | |
| 32365 | 32404 | pCtx = sqlite3_malloc( sizeof(*pCtx) ); |
| 32366 | 32405 | if( pCtx==0 ){ |
| 32367 | 32406 | return SQLITE_NOMEM; |
| 32368 | 32407 | } |
| @@ -32699,26 +32738,28 @@ | ||
| 32699 | 32738 | ** Note that the sqlite3_vfs.pNext field of the VFS object is modified |
| 32700 | 32739 | ** by the SQLite core when the VFS is registered. So the following |
| 32701 | 32740 | ** array cannot be const. |
| 32702 | 32741 | */ |
| 32703 | 32742 | static sqlite3_vfs aVfs[] = { |
| 32704 | -#if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__)) | |
| 32743 | +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) | |
| 32705 | 32744 | UNIXVFS("unix", autolockIoFinder ), |
| 32745 | +#elif OS_VXWORKS | |
| 32746 | + UNIXVFS("unix", vxworksIoFinder ), | |
| 32706 | 32747 | #else |
| 32707 | 32748 | UNIXVFS("unix", posixIoFinder ), |
| 32708 | 32749 | #endif |
| 32709 | 32750 | UNIXVFS("unix-none", nolockIoFinder ), |
| 32710 | 32751 | UNIXVFS("unix-dotfile", dotlockIoFinder ), |
| 32711 | 32752 | UNIXVFS("unix-excl", posixIoFinder ), |
| 32712 | 32753 | #if OS_VXWORKS |
| 32713 | 32754 | UNIXVFS("unix-namedsem", semIoFinder ), |
| 32714 | 32755 | #endif |
| 32715 | -#if SQLITE_ENABLE_LOCKING_STYLE | |
| 32756 | +#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS | |
| 32716 | 32757 | UNIXVFS("unix-posix", posixIoFinder ), |
| 32717 | -#if !OS_VXWORKS | |
| 32758 | +#endif | |
| 32759 | +#if SQLITE_ENABLE_LOCKING_STYLE | |
| 32718 | 32760 | UNIXVFS("unix-flock", flockIoFinder ), |
| 32719 | -#endif | |
| 32720 | 32761 | #endif |
| 32721 | 32762 | #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
| 32722 | 32763 | UNIXVFS("unix-afp", afpIoFinder ), |
| 32723 | 32764 | UNIXVFS("unix-nfs", nfsIoFinder ), |
| 32724 | 32765 | UNIXVFS("unix-proxy", proxyIoFinder ), |
| @@ -39072,16 +39113,24 @@ | ||
| 39072 | 39113 | sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); |
| 39073 | 39114 | } |
| 39074 | 39115 | } |
| 39075 | 39116 | |
| 39076 | 39117 | /* |
| 39077 | -** Compute the number of pages of cache requested. | |
| 39118 | +** Compute the number of pages of cache requested. p->szCache is the | |
| 39119 | +** cache size requested by the "PRAGMA cache_size" statement. | |
| 39120 | +** | |
| 39121 | +** | |
| 39078 | 39122 | */ |
| 39079 | 39123 | static int numberOfCachePages(PCache *p){ |
| 39080 | 39124 | if( p->szCache>=0 ){ |
| 39125 | + /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the | |
| 39126 | + ** suggested cache size is set to N. */ | |
| 39081 | 39127 | return p->szCache; |
| 39082 | 39128 | }else{ |
| 39129 | + /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then | |
| 39130 | + ** the number of cache pages is adjusted to use approximately abs(N*1024) | |
| 39131 | + ** bytes of memory. */ | |
| 39083 | 39132 | return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); |
| 39084 | 39133 | } |
| 39085 | 39134 | } |
| 39086 | 39135 | |
| 39087 | 39136 | /*************************************************** General Interfaces ****** |
| @@ -68615,10 +68664,14 @@ | ||
| 68615 | 68664 | } |
| 68616 | 68665 | SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ |
| 68617 | 68666 | return sqlite3ValueText(pVal, SQLITE_UTF16LE); |
| 68618 | 68667 | } |
| 68619 | 68668 | #endif /* SQLITE_OMIT_UTF16 */ |
| 68669 | +/* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five | |
| 68670 | +** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating | |
| 68671 | +** point number string BLOB NULL | |
| 68672 | +*/ | |
| 68620 | 68673 | SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ |
| 68621 | 68674 | static const u8 aType[] = { |
| 68622 | 68675 | SQLITE_BLOB, /* 0x00 */ |
| 68623 | 68676 | SQLITE_NULL, /* 0x01 */ |
| 68624 | 68677 | SQLITE_TEXT, /* 0x02 */ |
| @@ -71290,11 +71343,11 @@ | ||
| 71290 | 71343 | |
| 71291 | 71344 | /* Opcode: String8 * P2 * P4 * |
| 71292 | 71345 | ** Synopsis: r[P2]='P4' |
| 71293 | 71346 | ** |
| 71294 | 71347 | ** P4 points to a nul terminated UTF-8 string. This opcode is transformed |
| 71295 | -** into a String before it is executed for the first time. During | |
| 71348 | +** into a String opcode before it is executed for the first time. During | |
| 71296 | 71349 | ** this transformation, the length of string P4 is computed and stored |
| 71297 | 71350 | ** as the P1 parameter. |
| 71298 | 71351 | */ |
| 71299 | 71352 | case OP_String8: { /* same as TK_STRING, out2-prerelease */ |
| 71300 | 71353 | assert( pOp->p4.z!=0 ); |
| @@ -71322,22 +71375,34 @@ | ||
| 71322 | 71375 | goto too_big; |
| 71323 | 71376 | } |
| 71324 | 71377 | /* Fall through to the next case, OP_String */ |
| 71325 | 71378 | } |
| 71326 | 71379 | |
| 71327 | -/* Opcode: String P1 P2 * P4 * | |
| 71380 | +/* Opcode: String P1 P2 P3 P4 P5 | |
| 71328 | 71381 | ** Synopsis: r[P2]='P4' (len=P1) |
| 71329 | 71382 | ** |
| 71330 | 71383 | ** The string value P4 of length P1 (bytes) is stored in register P2. |
| 71384 | +** | |
| 71385 | +** If P5!=0 and the content of register P3 is greater than zero, then | |
| 71386 | +** the datatype of the register P2 is converted to BLOB. The content is | |
| 71387 | +** the same sequence of bytes, it is merely interpreted as a BLOB instead | |
| 71388 | +** of a string, as if it had been CAST. | |
| 71331 | 71389 | */ |
| 71332 | 71390 | case OP_String: { /* out2-prerelease */ |
| 71333 | 71391 | assert( pOp->p4.z!=0 ); |
| 71334 | 71392 | pOut->flags = MEM_Str|MEM_Static|MEM_Term; |
| 71335 | 71393 | pOut->z = pOp->p4.z; |
| 71336 | 71394 | pOut->n = pOp->p1; |
| 71337 | 71395 | pOut->enc = encoding; |
| 71338 | 71396 | UPDATE_MAX_BLOBSIZE(pOut); |
| 71397 | + if( pOp->p5 ){ | |
| 71398 | + assert( pOp->p3>0 ); | |
| 71399 | + assert( pOp->p3<=(p->nMem-p->nCursor) ); | |
| 71400 | + pIn3 = &aMem[pOp->p3]; | |
| 71401 | + assert( pIn3->flags & MEM_Int ); | |
| 71402 | + if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; | |
| 71403 | + } | |
| 71339 | 71404 | break; |
| 71340 | 71405 | } |
| 71341 | 71406 | |
| 71342 | 71407 | /* Opcode: Null P1 P2 P3 * * |
| 71343 | 71408 | ** Synopsis: r[P2..P3]=NULL |
| @@ -73325,11 +73390,16 @@ | ||
| 73325 | 73390 | ** the value of this counter needs to be restored too. */ |
| 73326 | 73391 | p->nStmtDefCons = db->nDeferredCons; |
| 73327 | 73392 | p->nStmtDefImmCons = db->nDeferredImmCons; |
| 73328 | 73393 | } |
| 73329 | 73394 | |
| 73330 | - /* Gather the schema version number for checking */ | |
| 73395 | + /* Gather the schema version number for checking: | |
| 73396 | + ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite | |
| 73397 | + ** each time a query is executed to ensure that the internal cache of the | |
| 73398 | + ** schema used when compiling the SQL query matches the schema of the | |
| 73399 | + ** database against which the compiled query is actually executed. | |
| 73400 | + */ | |
| 73331 | 73401 | sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); |
| 73332 | 73402 | iGen = db->aDb[pOp->p1].pSchema->iGeneration; |
| 73333 | 73403 | }else{ |
| 73334 | 73404 | iGen = iMeta = 0; |
| 73335 | 73405 | } |
| @@ -75843,14 +75913,16 @@ | ||
| 75843 | 75913 | #endif /* SQLITE_OMIT_AUTOINCREMENT */ |
| 75844 | 75914 | |
| 75845 | 75915 | /* Opcode: IfPos P1 P2 * * * |
| 75846 | 75916 | ** Synopsis: if r[P1]>0 goto P2 |
| 75847 | 75917 | ** |
| 75848 | -** If the value of register P1 is 1 or greater, jump to P2. | |
| 75918 | +** Register P1 must contain an integer. | |
| 75919 | +** If the value of register P1 is 1 or greater, jump to P2 and | |
| 75920 | +** add the literal value P3 to register P1. | |
| 75849 | 75921 | ** |
| 75850 | -** It is illegal to use this instruction on a register that does | |
| 75851 | -** not contain an integer. An assertion fault will result if you try. | |
| 75922 | +** If the initial value of register P1 is less than 1, then the | |
| 75923 | +** value is unchanged and control passes through to the next instruction. | |
| 75852 | 75924 | */ |
| 75853 | 75925 | case OP_IfPos: { /* jump, in1 */ |
| 75854 | 75926 | pIn1 = &aMem[pOp->p1]; |
| 75855 | 75927 | assert( pIn1->flags&MEM_Int ); |
| 75856 | 75928 | VdbeBranchTaken( pIn1->u.i>0, 2); |
| @@ -75875,27 +75947,63 @@ | ||
| 75875 | 75947 | pc = pOp->p2 - 1; |
| 75876 | 75948 | } |
| 75877 | 75949 | break; |
| 75878 | 75950 | } |
| 75879 | 75951 | |
| 75880 | -/* Opcode: IfZero P1 P2 P3 * * | |
| 75881 | -** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2 | |
| 75952 | +/* Opcode: IfNotZero P1 P2 P3 * * | |
| 75953 | +** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 | |
| 75882 | 75954 | ** |
| 75883 | -** The register P1 must contain an integer. Add literal P3 to the | |
| 75884 | -** value in register P1. If the result is exactly 0, jump to P2. | |
| 75955 | +** Register P1 must contain an integer. If the content of register P1 is | |
| 75956 | +** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is | |
| 75957 | +** initially zero, leave it unchanged and fall through. | |
| 75885 | 75958 | */ |
| 75886 | -case OP_IfZero: { /* jump, in1 */ | |
| 75959 | +case OP_IfNotZero: { /* jump, in1 */ | |
| 75960 | + pIn1 = &aMem[pOp->p1]; | |
| 75961 | + assert( pIn1->flags&MEM_Int ); | |
| 75962 | + VdbeBranchTaken(pIn1->u.i<0, 2); | |
| 75963 | + if( pIn1->u.i ){ | |
| 75964 | + pIn1->u.i += pOp->p3; | |
| 75965 | + pc = pOp->p2 - 1; | |
| 75966 | + } | |
| 75967 | + break; | |
| 75968 | +} | |
| 75969 | + | |
| 75970 | +/* Opcode: DecrJumpZero P1 P2 * * * | |
| 75971 | +** Synopsis: if (--r[P1])==0 goto P2 | |
| 75972 | +** | |
| 75973 | +** Register P1 must hold an integer. Decrement the value in register P1 | |
| 75974 | +** then jump to P2 if the new value is exactly zero. | |
| 75975 | +*/ | |
| 75976 | +case OP_DecrJumpZero: { /* jump, in1 */ | |
| 75887 | 75977 | pIn1 = &aMem[pOp->p1]; |
| 75888 | 75978 | assert( pIn1->flags&MEM_Int ); |
| 75889 | - pIn1->u.i += pOp->p3; | |
| 75979 | + pIn1->u.i--; | |
| 75890 | 75980 | VdbeBranchTaken(pIn1->u.i==0, 2); |
| 75891 | 75981 | if( pIn1->u.i==0 ){ |
| 75892 | 75982 | pc = pOp->p2 - 1; |
| 75893 | 75983 | } |
| 75894 | 75984 | break; |
| 75895 | 75985 | } |
| 75896 | 75986 | |
| 75987 | + | |
| 75988 | +/* Opcode: JumpZeroIncr P1 P2 * * * | |
| 75989 | +** Synopsis: if (r[P1]++)==0 ) goto P2 | |
| 75990 | +** | |
| 75991 | +** The register P1 must contain an integer. If register P1 is initially | |
| 75992 | +** zero, then jump to P2. Increment register P1 regardless of whether or | |
| 75993 | +** not the jump is taken. | |
| 75994 | +*/ | |
| 75995 | +case OP_JumpZeroIncr: { /* jump, in1 */ | |
| 75996 | + pIn1 = &aMem[pOp->p1]; | |
| 75997 | + assert( pIn1->flags&MEM_Int ); | |
| 75998 | + VdbeBranchTaken(pIn1->u.i==0, 2); | |
| 75999 | + if( (pIn1->u.i++)==0 ){ | |
| 76000 | + pc = pOp->p2 - 1; | |
| 76001 | + } | |
| 76002 | + break; | |
| 76003 | +} | |
| 76004 | + | |
| 75897 | 76005 | /* Opcode: AggStep * P2 P3 P4 P5 |
| 75898 | 76006 | ** Synopsis: accum=r[P3] step(r[P2@P5]) |
| 75899 | 76007 | ** |
| 75900 | 76008 | ** Execute the step function for an aggregate. The |
| 75901 | 76009 | ** function has P5 arguments. P4 is a pointer to the FuncDef |
| @@ -97181,10 +97289,15 @@ | ||
| 97181 | 97289 | ** pExpr points to an expression which implements a function. If |
| 97182 | 97290 | ** it is appropriate to apply the LIKE optimization to that function |
| 97183 | 97291 | ** then set aWc[0] through aWc[2] to the wildcard characters and |
| 97184 | 97292 | ** return TRUE. If the function is not a LIKE-style function then |
| 97185 | 97293 | ** return FALSE. |
| 97294 | +** | |
| 97295 | +** *pIsNocase is set to true if uppercase and lowercase are equivalent for | |
| 97296 | +** the function (default for LIKE). If the function makes the distinction | |
| 97297 | +** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to | |
| 97298 | +** false. | |
| 97186 | 97299 | */ |
| 97187 | 97300 | SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ |
| 97188 | 97301 | FuncDef *pDef; |
| 97189 | 97302 | if( pExpr->op!=TK_FUNCTION |
| 97190 | 97303 | || !pExpr->x.pList |
| @@ -102972,10 +103085,21 @@ | ||
| 102972 | 103085 | } |
| 102973 | 103086 | |
| 102974 | 103087 | /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS |
| 102975 | 103088 | ** connection. If it returns SQLITE_OK, then assume that the VFS |
| 102976 | 103089 | ** handled the pragma and generate a no-op prepared statement. |
| 103090 | + ** | |
| 103091 | + ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed, | |
| 103092 | + ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file | |
| 103093 | + ** object corresponding to the database file to which the pragma | |
| 103094 | + ** statement refers. | |
| 103095 | + ** | |
| 103096 | + ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA | |
| 103097 | + ** file control is an array of pointers to strings (char**) in which the | |
| 103098 | + ** second element of the array is the name of the pragma and the third | |
| 103099 | + ** element is the argument to the pragma or NULL if the pragma has no | |
| 103100 | + ** argument. | |
| 102977 | 103101 | */ |
| 102978 | 103102 | aFcntl[0] = 0; |
| 102979 | 103103 | aFcntl[1] = zLeft; |
| 102980 | 103104 | aFcntl[2] = zRight; |
| 102981 | 103105 | aFcntl[3] = 0; |
| @@ -103732,34 +103856,46 @@ | ||
| 103732 | 103856 | Index *pIdx; |
| 103733 | 103857 | Table *pTab; |
| 103734 | 103858 | pIdx = sqlite3FindIndex(db, zRight, zDb); |
| 103735 | 103859 | if( pIdx ){ |
| 103736 | 103860 | int i; |
| 103737 | - int mx = pPragma->iArg ? pIdx->nColumn : pIdx->nKeyCol; | |
| 103861 | + int mx; | |
| 103862 | + if( pPragma->iArg ){ | |
| 103863 | + /* PRAGMA index_xinfo (newer version with more rows and columns) */ | |
| 103864 | + mx = pIdx->nColumn; | |
| 103865 | + pParse->nMem = 6; | |
| 103866 | + }else{ | |
| 103867 | + /* PRAGMA index_info (legacy version) */ | |
| 103868 | + mx = pIdx->nKeyCol; | |
| 103869 | + pParse->nMem = 3; | |
| 103870 | + } | |
| 103738 | 103871 | pTab = pIdx->pTable; |
| 103739 | - sqlite3VdbeSetNumCols(v, 6); | |
| 103740 | - pParse->nMem = 6; | |
| 103872 | + sqlite3VdbeSetNumCols(v, pParse->nMem); | |
| 103741 | 103873 | sqlite3CodeVerifySchema(pParse, iDb); |
| 103742 | 103874 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); |
| 103743 | 103875 | sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); |
| 103744 | 103876 | sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); |
| 103745 | - sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC); | |
| 103746 | - sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC); | |
| 103747 | - sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC); | |
| 103877 | + if( pPragma->iArg ){ | |
| 103878 | + sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC); | |
| 103879 | + sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC); | |
| 103880 | + sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC); | |
| 103881 | + } | |
| 103748 | 103882 | for(i=0; i<mx; i++){ |
| 103749 | 103883 | i16 cnum = pIdx->aiColumn[i]; |
| 103750 | 103884 | sqlite3VdbeAddOp2(v, OP_Integer, i, 1); |
| 103751 | 103885 | sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2); |
| 103752 | 103886 | if( cnum<0 ){ |
| 103753 | 103887 | sqlite3VdbeAddOp2(v, OP_Null, 0, 3); |
| 103754 | 103888 | }else{ |
| 103755 | 103889 | sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); |
| 103756 | 103890 | } |
| 103757 | - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4); | |
| 103758 | - sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0); | |
| 103759 | - sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6); | |
| 103760 | - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); | |
| 103891 | + if( pPragma->iArg ){ | |
| 103892 | + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4); | |
| 103893 | + sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0); | |
| 103894 | + sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6); | |
| 103895 | + } | |
| 103896 | + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem); | |
| 103761 | 103897 | } |
| 103762 | 103898 | } |
| 103763 | 103899 | } |
| 103764 | 103900 | break; |
| 103765 | 103901 | |
| @@ -104457,12 +104593,13 @@ | ||
| 104457 | 104593 | #endif |
| 104458 | 104594 | |
| 104459 | 104595 | /* |
| 104460 | 104596 | ** PRAGMA shrink_memory |
| 104461 | 104597 | ** |
| 104462 | - ** This pragma attempts to free as much memory as possible from the | |
| 104463 | - ** current database connection. | |
| 104598 | + ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database | |
| 104599 | + ** connection on which it is invoked to free up as much memory as it | |
| 104600 | + ** can, by calling sqlite3_db_release_memory(). | |
| 104464 | 104601 | */ |
| 104465 | 104602 | case PragTyp_SHRINK_MEMORY: { |
| 104466 | 104603 | sqlite3_db_release_memory(db); |
| 104467 | 104604 | break; |
| 104468 | 104605 | } |
| @@ -104487,12 +104624,16 @@ | ||
| 104487 | 104624 | |
| 104488 | 104625 | /* |
| 104489 | 104626 | ** PRAGMA soft_heap_limit |
| 104490 | 104627 | ** PRAGMA soft_heap_limit = N |
| 104491 | 104628 | ** |
| 104492 | - ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted, | |
| 104493 | - ** use -1. | |
| 104629 | + ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the | |
| 104630 | + ** sqlite3_soft_heap_limit64() interface with the argument N, if N is | |
| 104631 | + ** specified and is a non-negative integer. | |
| 104632 | + ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always | |
| 104633 | + ** returns the same integer that would be returned by the | |
| 104634 | + ** sqlite3_soft_heap_limit64(-1) C-language function. | |
| 104494 | 104635 | */ |
| 104495 | 104636 | case PragTyp_SOFT_HEAP_LIMIT: { |
| 104496 | 104637 | sqlite3_int64 N; |
| 104497 | 104638 | if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ |
| 104498 | 104639 | sqlite3_soft_heap_limit64(N); |
| @@ -106065,24 +106206,21 @@ | ||
| 106065 | 106206 | }else{ |
| 106066 | 106207 | op = OP_IdxInsert; |
| 106067 | 106208 | } |
| 106068 | 106209 | sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); |
| 106069 | 106210 | if( pSelect->iLimit ){ |
| 106070 | - int addr1, addr2; | |
| 106211 | + int addr; | |
| 106071 | 106212 | int iLimit; |
| 106072 | 106213 | if( pSelect->iOffset ){ |
| 106073 | 106214 | iLimit = pSelect->iOffset+1; |
| 106074 | 106215 | }else{ |
| 106075 | 106216 | iLimit = pSelect->iLimit; |
| 106076 | 106217 | } |
| 106077 | - addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v); | |
| 106078 | - sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1); | |
| 106079 | - addr2 = sqlite3VdbeAddOp0(v, OP_Goto); | |
| 106080 | - sqlite3VdbeJumpHere(v, addr1); | |
| 106218 | + addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v); | |
| 106081 | 106219 | sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); |
| 106082 | 106220 | sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); |
| 106083 | - sqlite3VdbeJumpHere(v, addr2); | |
| 106221 | + sqlite3VdbeJumpHere(v, addr); | |
| 106084 | 106222 | } |
| 106085 | 106223 | } |
| 106086 | 106224 | |
| 106087 | 106225 | /* |
| 106088 | 106226 | ** Add code to implement the OFFSET |
| @@ -106475,11 +106613,11 @@ | ||
| 106475 | 106613 | /* Jump to the end of the loop if the LIMIT is reached. Except, if |
| 106476 | 106614 | ** there is a sorter, in which case the sorter has already limited |
| 106477 | 106615 | ** the output for us. |
| 106478 | 106616 | */ |
| 106479 | 106617 | if( pSort==0 && p->iLimit ){ |
| 106480 | - sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); | |
| 106618 | + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); | |
| 106481 | 106619 | } |
| 106482 | 106620 | } |
| 106483 | 106621 | |
| 106484 | 106622 | /* |
| 106485 | 106623 | ** Allocate a KeyInfo object sufficient for an index of N key columns and |
| @@ -107328,11 +107466,11 @@ | ||
| 107328 | 107466 | } |
| 107329 | 107467 | }else{ |
| 107330 | 107468 | sqlite3ExprCode(pParse, p->pLimit, iLimit); |
| 107331 | 107469 | sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); |
| 107332 | 107470 | VdbeComment((v, "LIMIT counter")); |
| 107333 | - sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v); | |
| 107471 | + sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); | |
| 107334 | 107472 | } |
| 107335 | 107473 | if( p->pOffset ){ |
| 107336 | 107474 | p->iOffset = iOffset = ++pParse->nMem; |
| 107337 | 107475 | pParse->nMem++; /* Allocate an extra register for limit+offset */ |
| 107338 | 107476 | sqlite3ExprCode(pParse, p->pOffset, iOffset); |
| @@ -107547,11 +107685,11 @@ | ||
| 107547 | 107685 | addrCont = sqlite3VdbeMakeLabel(v); |
| 107548 | 107686 | codeOffset(v, regOffset, addrCont); |
| 107549 | 107687 | selectInnerLoop(pParse, p, p->pEList, iCurrent, |
| 107550 | 107688 | 0, 0, pDest, addrCont, addrBreak); |
| 107551 | 107689 | if( regLimit ){ |
| 107552 | - sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1); | |
| 107690 | + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); | |
| 107553 | 107691 | VdbeCoverage(v); |
| 107554 | 107692 | } |
| 107555 | 107693 | sqlite3VdbeResolveLabel(v, addrCont); |
| 107556 | 107694 | |
| 107557 | 107695 | /* Execute the recursive SELECT taking the single row in Current as |
| @@ -107772,11 +107910,11 @@ | ||
| 107772 | 107910 | } |
| 107773 | 107911 | p->pPrior = 0; |
| 107774 | 107912 | p->iLimit = pPrior->iLimit; |
| 107775 | 107913 | p->iOffset = pPrior->iOffset; |
| 107776 | 107914 | if( p->iLimit ){ |
| 107777 | - addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v); | |
| 107915 | + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); | |
| 107778 | 107916 | VdbeComment((v, "Jump ahead if LIMIT reached")); |
| 107779 | 107917 | } |
| 107780 | 107918 | explainSetInteger(iSub2, pParse->iNextSelectId); |
| 107781 | 107919 | rc = sqlite3Select(pParse, p, &dest); |
| 107782 | 107920 | testcase( rc!=SQLITE_OK ); |
| @@ -108173,11 +108311,11 @@ | ||
| 108173 | 108311 | } |
| 108174 | 108312 | |
| 108175 | 108313 | /* Jump to the end of the loop if the LIMIT is reached. |
| 108176 | 108314 | */ |
| 108177 | 108315 | if( p->iLimit ){ |
| 108178 | - sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); | |
| 108316 | + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); | |
| 108179 | 108317 | } |
| 108180 | 108318 | |
| 108181 | 108319 | /* Generate the subroutine return |
| 108182 | 108320 | */ |
| 108183 | 108321 | sqlite3VdbeResolveLabel(v, iContinue); |
| @@ -114787,10 +114925,12 @@ | ||
| 114787 | 114925 | int addrNxt; /* Jump here to start the next IN combination */ |
| 114788 | 114926 | int addrSkip; /* Jump here for next iteration of skip-scan */ |
| 114789 | 114927 | int addrCont; /* Jump here to continue with the next loop cycle */ |
| 114790 | 114928 | int addrFirst; /* First instruction of interior of the loop */ |
| 114791 | 114929 | int addrBody; /* Beginning of the body of this loop */ |
| 114930 | + int iLikeRepCntr; /* LIKE range processing counter register */ | |
| 114931 | + int addrLikeRep; /* LIKE range processing address */ | |
| 114792 | 114932 | u8 iFrom; /* Which entry in the FROM clause */ |
| 114793 | 114933 | u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ |
| 114794 | 114934 | int p1, p2; /* Operands of the opcode used to ends the loop */ |
| 114795 | 114935 | union { /* Information that depends on pWLoop->wsFlags */ |
| 114796 | 114936 | struct { |
| @@ -114971,11 +115111,11 @@ | ||
| 114971 | 115111 | WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ |
| 114972 | 115112 | WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ |
| 114973 | 115113 | } u; |
| 114974 | 115114 | LogEst truthProb; /* Probability of truth for this expression */ |
| 114975 | 115115 | u16 eOperator; /* A WO_xx value describing <op> */ |
| 114976 | - u8 wtFlags; /* TERM_xxx bit flags. See below */ | |
| 115116 | + u16 wtFlags; /* TERM_xxx bit flags. See below */ | |
| 114977 | 115117 | u8 nChild; /* Number of children that must disable us */ |
| 114978 | 115118 | WhereClause *pWC; /* The clause this term is part of */ |
| 114979 | 115119 | Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ |
| 114980 | 115120 | Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ |
| 114981 | 115121 | }; |
| @@ -114993,10 +115133,13 @@ | ||
| 114993 | 115133 | #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 |
| 114994 | 115134 | # define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ |
| 114995 | 115135 | #else |
| 114996 | 115136 | # define TERM_VNULL 0x00 /* Disabled if not using stat3 */ |
| 114997 | 115137 | #endif |
| 115138 | +#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ | |
| 115139 | +#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ | |
| 115140 | +#define TERM_LIKE 0x400 /* The original LIKE operator */ | |
| 114998 | 115141 | |
| 114999 | 115142 | /* |
| 115000 | 115143 | ** An instance of the WhereScan object is used as an iterator for locating |
| 115001 | 115144 | ** terms in the WHERE clause that are useful to the query planner. |
| 115002 | 115145 | */ |
| @@ -115368,11 +115511,11 @@ | ||
| 115368 | 115511 | ** WARNING: This routine might reallocate the space used to store |
| 115369 | 115512 | ** WhereTerms. All pointers to WhereTerms should be invalidated after |
| 115370 | 115513 | ** calling this routine. Such pointers may be reinitialized by referencing |
| 115371 | 115514 | ** the pWC->a[] array. |
| 115372 | 115515 | */ |
| 115373 | -static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ | |
| 115516 | +static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ | |
| 115374 | 115517 | WhereTerm *pTerm; |
| 115375 | 115518 | int idx; |
| 115376 | 115519 | testcase( wtFlags & TERM_VIRTUAL ); |
| 115377 | 115520 | if( pWC->nTerm>=pWC->nSlot ){ |
| 115378 | 115521 | WhereTerm *pOld = pWC->a; |
| @@ -115793,11 +115936,15 @@ | ||
| 115793 | 115936 | ** Check to see if the given expression is a LIKE or GLOB operator that |
| 115794 | 115937 | ** can be optimized using inequality constraints. Return TRUE if it is |
| 115795 | 115938 | ** so and false if not. |
| 115796 | 115939 | ** |
| 115797 | 115940 | ** In order for the operator to be optimizible, the RHS must be a string |
| 115798 | -** literal that does not begin with a wildcard. | |
| 115941 | +** literal that does not begin with a wildcard. The LHS must be a column | |
| 115942 | +** that may only be NULL, a string, or a BLOB, never a number. (This means | |
| 115943 | +** that virtual tables cannot participate in the LIKE optimization.) If the | |
| 115944 | +** collating sequence for the column on the LHS must be appropriate for | |
| 115945 | +** the operator. | |
| 115799 | 115946 | */ |
| 115800 | 115947 | static int isLikeOrGlob( |
| 115801 | 115948 | Parse *pParse, /* Parsing and code generating context */ |
| 115802 | 115949 | Expr *pExpr, /* Test this expression */ |
| 115803 | 115950 | Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ |
| @@ -115822,11 +115969,11 @@ | ||
| 115822 | 115969 | #endif |
| 115823 | 115970 | pList = pExpr->x.pList; |
| 115824 | 115971 | pLeft = pList->a[1].pExpr; |
| 115825 | 115972 | if( pLeft->op!=TK_COLUMN |
| 115826 | 115973 | || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT |
| 115827 | - || IsVirtual(pLeft->pTab) | |
| 115974 | + || IsVirtual(pLeft->pTab) /* Value might be numeric */ | |
| 115828 | 115975 | ){ |
| 115829 | 115976 | /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must |
| 115830 | 115977 | ** be the name of an indexed column with TEXT affinity. */ |
| 115831 | 115978 | return 0; |
| 115832 | 115979 | } |
| @@ -116271,11 +116418,11 @@ | ||
| 116271 | 116418 | Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ |
| 116272 | 116419 | Bitmask prereqAll; /* Prerequesites of pExpr */ |
| 116273 | 116420 | Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */ |
| 116274 | 116421 | Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ |
| 116275 | 116422 | int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ |
| 116276 | - int noCase = 0; /* LIKE/GLOB distinguishes case */ | |
| 116423 | + int noCase = 0; /* uppercase equivalent to lowercase */ | |
| 116277 | 116424 | int op; /* Top-level operator. pExpr->op */ |
| 116278 | 116425 | Parse *pParse = pWInfo->pParse; /* Parsing context */ |
| 116279 | 116426 | sqlite3 *db = pParse->db; /* Database connection */ |
| 116280 | 116427 | |
| 116281 | 116428 | if( db->mallocFailed ){ |
| @@ -116409,16 +116556,19 @@ | ||
| 116409 | 116556 | |
| 116410 | 116557 | #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION |
| 116411 | 116558 | /* Add constraints to reduce the search space on a LIKE or GLOB |
| 116412 | 116559 | ** operator. |
| 116413 | 116560 | ** |
| 116414 | - ** A like pattern of the form "x LIKE 'abc%'" is changed into constraints | |
| 116561 | + ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints | |
| 116415 | 116562 | ** |
| 116416 | - ** x>='abc' AND x<'abd' AND x LIKE 'abc%' | |
| 116563 | + ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' | |
| 116417 | 116564 | ** |
| 116418 | 116565 | ** The last character of the prefix "abc" is incremented to form the |
| 116419 | - ** termination condition "abd". | |
| 116566 | + ** termination condition "abd". If case is not significant (the default | |
| 116567 | + ** for LIKE) then the lower-bound is made all uppercase and the upper- | |
| 116568 | + ** bound is made all lowercase so that the bounds also work when comparing | |
| 116569 | + ** BLOBs. | |
| 116420 | 116570 | */ |
| 116421 | 116571 | if( pWC->op==TK_AND |
| 116422 | 116572 | && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) |
| 116423 | 116573 | ){ |
| 116424 | 116574 | Expr *pLeft; /* LHS of LIKE/GLOB operator */ |
| @@ -116426,13 +116576,29 @@ | ||
| 116426 | 116576 | Expr *pNewExpr1; |
| 116427 | 116577 | Expr *pNewExpr2; |
| 116428 | 116578 | int idxNew1; |
| 116429 | 116579 | int idxNew2; |
| 116430 | 116580 | Token sCollSeqName; /* Name of collating sequence */ |
| 116581 | + const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; | |
| 116431 | 116582 | |
| 116432 | 116583 | pLeft = pExpr->x.pList->a[1].pExpr; |
| 116433 | 116584 | pStr2 = sqlite3ExprDup(db, pStr1, 0); |
| 116585 | + | |
| 116586 | + /* Convert the lower bound to upper-case and the upper bound to | |
| 116587 | + ** lower-case (upper-case is less than lower-case in ASCII) so that | |
| 116588 | + ** the range constraints also work for BLOBs | |
| 116589 | + */ | |
| 116590 | + if( noCase && !pParse->db->mallocFailed ){ | |
| 116591 | + int i; | |
| 116592 | + char c; | |
| 116593 | + pTerm->wtFlags |= TERM_LIKE; | |
| 116594 | + for(i=0; (c = pStr1->u.zToken[i])!=0; i++){ | |
| 116595 | + pStr1->u.zToken[i] = sqlite3Toupper(c); | |
| 116596 | + pStr2->u.zToken[i] = sqlite3Tolower(c); | |
| 116597 | + } | |
| 116598 | + } | |
| 116599 | + | |
| 116434 | 116600 | if( !db->mallocFailed ){ |
| 116435 | 116601 | u8 c, *pC; /* Last character before the first wildcard */ |
| 116436 | 116602 | pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; |
| 116437 | 116603 | c = *pC; |
| 116438 | 116604 | if( noCase ){ |
| @@ -116448,23 +116614,23 @@ | ||
| 116448 | 116614 | *pC = c + 1; |
| 116449 | 116615 | } |
| 116450 | 116616 | sCollSeqName.z = noCase ? "NOCASE" : "BINARY"; |
| 116451 | 116617 | sCollSeqName.n = 6; |
| 116452 | 116618 | pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); |
| 116453 | - pNewExpr1 = sqlite3PExpr(pParse, TK_GE, | |
| 116619 | + pNewExpr1 = sqlite3PExpr(pParse, TK_GE, | |
| 116454 | 116620 | sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), |
| 116455 | 116621 | pStr1, 0); |
| 116456 | 116622 | transferJoinMarkings(pNewExpr1, pExpr); |
| 116457 | - idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); | |
| 116623 | + idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); | |
| 116458 | 116624 | testcase( idxNew1==0 ); |
| 116459 | 116625 | exprAnalyze(pSrc, pWC, idxNew1); |
| 116460 | 116626 | pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); |
| 116461 | 116627 | pNewExpr2 = sqlite3PExpr(pParse, TK_LT, |
| 116462 | 116628 | sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), |
| 116463 | 116629 | pStr2, 0); |
| 116464 | 116630 | transferJoinMarkings(pNewExpr2, pExpr); |
| 116465 | - idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); | |
| 116631 | + idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); | |
| 116466 | 116632 | testcase( idxNew2==0 ); |
| 116467 | 116633 | exprAnalyze(pSrc, pWC, idxNew2); |
| 116468 | 116634 | pTerm = &pWC->a[idxTerm]; |
| 116469 | 116635 | if( isComplete ){ |
| 116470 | 116636 | markTermAsChild(pWC, idxNew1, idxTerm); |
| @@ -117635,24 +117801,47 @@ | ||
| 117635 | 117801 | ** by indices, we disable them to prevent redundant tests in the inner |
| 117636 | 117802 | ** loop. We would get the correct results if nothing were ever disabled, |
| 117637 | 117803 | ** but joins might run a little slower. The trick is to disable as much |
| 117638 | 117804 | ** as we can without disabling too much. If we disabled in (1), we'd get |
| 117639 | 117805 | ** the wrong answer. See ticket #813. |
| 117806 | +** | |
| 117807 | +** If all the children of a term are disabled, then that term is also | |
| 117808 | +** automatically disabled. In this way, terms get disabled if derived | |
| 117809 | +** virtual terms are tested first. For example: | |
| 117810 | +** | |
| 117811 | +** x GLOB 'abc*' AND x>='abc' AND x<'acd' | |
| 117812 | +** \___________/ \______/ \_____/ | |
| 117813 | +** parent child1 child2 | |
| 117814 | +** | |
| 117815 | +** Only the parent term was in the original WHERE clause. The child1 | |
| 117816 | +** and child2 terms were added by the LIKE optimization. If both of | |
| 117817 | +** the virtual child terms are valid, then testing of the parent can be | |
| 117818 | +** skipped. | |
| 117819 | +** | |
| 117820 | +** Usually the parent term is marked as TERM_CODED. But if the parent | |
| 117821 | +** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead. | |
| 117822 | +** The TERM_LIKECOND marking indicates that the term should be coded inside | |
| 117823 | +** a conditional such that is only evaluated on the second pass of a | |
| 117824 | +** LIKE-optimization loop, when scanning BLOBs instead of strings. | |
| 117640 | 117825 | */ |
| 117641 | 117826 | static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ |
| 117642 | - if( pTerm | |
| 117827 | + int nLoop = 0; | |
| 117828 | + while( pTerm | |
| 117643 | 117829 | && (pTerm->wtFlags & TERM_CODED)==0 |
| 117644 | 117830 | && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) |
| 117645 | 117831 | && (pLevel->notReady & pTerm->prereqAll)==0 |
| 117646 | 117832 | ){ |
| 117647 | - pTerm->wtFlags |= TERM_CODED; | |
| 117648 | - if( pTerm->iParent>=0 ){ | |
| 117649 | - WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent]; | |
| 117650 | - if( (--pOther->nChild)==0 ){ | |
| 117651 | - disableTerm(pLevel, pOther); | |
| 117652 | - } | |
| 117833 | + if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ | |
| 117834 | + pTerm->wtFlags |= TERM_LIKECOND; | |
| 117835 | + }else{ | |
| 117836 | + pTerm->wtFlags |= TERM_CODED; | |
| 117653 | 117837 | } |
| 117838 | + if( pTerm->iParent<0 ) break; | |
| 117839 | + pTerm = &pTerm->pWC->a[pTerm->iParent]; | |
| 117840 | + pTerm->nChild--; | |
| 117841 | + if( pTerm->nChild!=0 ) break; | |
| 117842 | + nLoop++; | |
| 117654 | 117843 | } |
| 117655 | 117844 | } |
| 117656 | 117845 | |
| 117657 | 117846 | /* |
| 117658 | 117847 | ** Code an OP_Affinity opcode to apply the column affinity string zAff |
| @@ -118132,11 +118321,30 @@ | ||
| 118132 | 118321 | } |
| 118133 | 118322 | #else |
| 118134 | 118323 | # define addScanStatus(a, b, c, d) ((void)d) |
| 118135 | 118324 | #endif |
| 118136 | 118325 | |
| 118137 | - | |
| 118326 | +/* | |
| 118327 | +** Look at the last instruction coded. If that instruction is OP_String8 | |
| 118328 | +** and if pLoop->iLikeRepCntr is non-zero, then change the P3 to be | |
| 118329 | +** pLoop->iLikeRepCntr and set P5. | |
| 118330 | +** | |
| 118331 | +** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range | |
| 118332 | +** expression: "x>='ABC' AND x<'abd'". But this requires that the range | |
| 118333 | +** scan loop run twice, once for strings and a second time for BLOBs. | |
| 118334 | +** The OP_String opcodes on the second pass convert the upper and lower | |
| 118335 | +** bound string contants to blobs. This routine makes the necessary changes | |
| 118336 | +** to the OP_String opcodes for that to happen. | |
| 118337 | +*/ | |
| 118338 | +static void whereLikeOptimizationStringFixup(Vdbe *v, WhereLevel *pLevel){ | |
| 118339 | + VdbeOp *pOp; | |
| 118340 | + pOp = sqlite3VdbeGetOp(v, -1); | |
| 118341 | + if( pLevel->iLikeRepCntr && pOp->opcode==OP_String8 ){ | |
| 118342 | + pOp->p3 = pLevel->iLikeRepCntr; | |
| 118343 | + pOp->p5 = 1; | |
| 118344 | + } | |
| 118345 | +} | |
| 118138 | 118346 | |
| 118139 | 118347 | /* |
| 118140 | 118348 | ** Generate code for the start of the iLevel-th loop in the WHERE clause |
| 118141 | 118349 | ** implementation described by pWInfo. |
| 118142 | 118350 | */ |
| @@ -118466,10 +118674,23 @@ | ||
| 118466 | 118674 | nExtraReg = 1; |
| 118467 | 118675 | } |
| 118468 | 118676 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ |
| 118469 | 118677 | pRangeEnd = pLoop->aLTerm[j++]; |
| 118470 | 118678 | nExtraReg = 1; |
| 118679 | + if( pRangeStart | |
| 118680 | + && (pRangeStart->wtFlags & TERM_LIKEOPT)!=0 | |
| 118681 | + && (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 | |
| 118682 | + ){ | |
| 118683 | + pLevel->iLikeRepCntr = ++pParse->nMem; | |
| 118684 | + testcase( bRev ); | |
| 118685 | + testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); | |
| 118686 | + sqlite3VdbeAddOp2(v, OP_Integer, | |
| 118687 | + bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC), | |
| 118688 | + pLevel->iLikeRepCntr); | |
| 118689 | + VdbeComment((v, "LIKE loop counter")); | |
| 118690 | + pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); | |
| 118691 | + } | |
| 118471 | 118692 | if( pRangeStart==0 |
| 118472 | 118693 | && (j = pIdx->aiColumn[nEq])>=0 |
| 118473 | 118694 | && pIdx->pTable->aCol[j].notNull==0 |
| 118474 | 118695 | ){ |
| 118475 | 118696 | bSeekPastNull = 1; |
| @@ -118508,10 +118729,11 @@ | ||
| 118508 | 118729 | /* Seek the index cursor to the start of the range. */ |
| 118509 | 118730 | nConstraint = nEq; |
| 118510 | 118731 | if( pRangeStart ){ |
| 118511 | 118732 | Expr *pRight = pRangeStart->pExpr->pRight; |
| 118512 | 118733 | sqlite3ExprCode(pParse, pRight, regBase+nEq); |
| 118734 | + whereLikeOptimizationStringFixup(v, pLevel); | |
| 118513 | 118735 | if( (pRangeStart->wtFlags & TERM_VNULL)==0 |
| 118514 | 118736 | && sqlite3ExprCanBeNull(pRight) |
| 118515 | 118737 | ){ |
| 118516 | 118738 | sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); |
| 118517 | 118739 | VdbeCoverage(v); |
| @@ -118553,10 +118775,11 @@ | ||
| 118553 | 118775 | nConstraint = nEq; |
| 118554 | 118776 | if( pRangeEnd ){ |
| 118555 | 118777 | Expr *pRight = pRangeEnd->pExpr->pRight; |
| 118556 | 118778 | sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); |
| 118557 | 118779 | sqlite3ExprCode(pParse, pRight, regBase+nEq); |
| 118780 | + whereLikeOptimizationStringFixup(v, pLevel); | |
| 118558 | 118781 | if( (pRangeEnd->wtFlags & TERM_VNULL)==0 |
| 118559 | 118782 | && sqlite3ExprCanBeNull(pRight) |
| 118560 | 118783 | ){ |
| 118561 | 118784 | sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); |
| 118562 | 118785 | VdbeCoverage(v); |
| @@ -118780,11 +119003,12 @@ | ||
| 118780 | 119003 | ** eliminating duplicates from other WHERE clauses, the action for each |
| 118781 | 119004 | ** sub-WHERE clause is to to invoke the main loop body as a subroutine. |
| 118782 | 119005 | */ |
| 118783 | 119006 | wctrlFlags = WHERE_OMIT_OPEN_CLOSE |
| 118784 | 119007 | | WHERE_FORCE_TABLE |
| 118785 | - | WHERE_ONETABLE_ONLY; | |
| 119008 | + | WHERE_ONETABLE_ONLY | |
| 119009 | + | WHERE_NO_AUTOINDEX; | |
| 118786 | 119010 | for(ii=0; ii<pOrWc->nTerm; ii++){ |
| 118787 | 119011 | WhereTerm *pOrTerm = &pOrWc->a[ii]; |
| 118788 | 119012 | if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ |
| 118789 | 119013 | WhereInfo *pSubWInfo; /* Info for single OR-term scan */ |
| 118790 | 119014 | Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ |
| @@ -118942,10 +119166,11 @@ | ||
| 118942 | 119166 | /* Insert code to test every subexpression that can be completely |
| 118943 | 119167 | ** computed using the current set of tables. |
| 118944 | 119168 | */ |
| 118945 | 119169 | for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ |
| 118946 | 119170 | Expr *pE; |
| 119171 | + int skipLikeAddr = 0; | |
| 118947 | 119172 | testcase( pTerm->wtFlags & TERM_VIRTUAL ); |
| 118948 | 119173 | testcase( pTerm->wtFlags & TERM_CODED ); |
| 118949 | 119174 | if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; |
| 118950 | 119175 | if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ |
| 118951 | 119176 | testcase( pWInfo->untestedTerms==0 |
| @@ -118955,12 +119180,18 @@ | ||
| 118955 | 119180 | } |
| 118956 | 119181 | pE = pTerm->pExpr; |
| 118957 | 119182 | assert( pE!=0 ); |
| 118958 | 119183 | if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ |
| 118959 | 119184 | continue; |
| 119185 | + } | |
| 119186 | + if( pTerm->wtFlags & TERM_LIKECOND ){ | |
| 119187 | + assert( pLevel->iLikeRepCntr>0 ); | |
| 119188 | + skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr); | |
| 119189 | + VdbeCoverage(v); | |
| 118960 | 119190 | } |
| 118961 | 119191 | sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); |
| 119192 | + if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); | |
| 118962 | 119193 | pTerm->wtFlags |= TERM_CODED; |
| 118963 | 119194 | } |
| 118964 | 119195 | |
| 118965 | 119196 | /* Insert code to test for implied constraints based on transitivity |
| 118966 | 119197 | ** of the "==" operator. |
| @@ -119974,10 +120205,11 @@ | ||
| 119974 | 120205 | rLogSize = estLog(rSize); |
| 119975 | 120206 | |
| 119976 | 120207 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX |
| 119977 | 120208 | /* Automatic indexes */ |
| 119978 | 120209 | if( !pBuilder->pOrSet |
| 120210 | + && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 | |
| 119979 | 120211 | && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 |
| 119980 | 120212 | && pSrc->pIndex==0 |
| 119981 | 120213 | && !pSrc->viaCoroutine |
| 119982 | 120214 | && !pSrc->notIndexed |
| 119983 | 120215 | && HasRowid(pTab) |
| @@ -121758,10 +121990,20 @@ | ||
| 121758 | 121990 | if( pLevel->addrSkip ){ |
| 121759 | 121991 | sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrSkip); |
| 121760 | 121992 | VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); |
| 121761 | 121993 | sqlite3VdbeJumpHere(v, pLevel->addrSkip); |
| 121762 | 121994 | sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); |
| 121995 | + } | |
| 121996 | + if( pLevel->addrLikeRep ){ | |
| 121997 | + int op; | |
| 121998 | + if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){ | |
| 121999 | + op = OP_DecrJumpZero; | |
| 122000 | + }else{ | |
| 122001 | + op = OP_JumpZeroIncr; | |
| 122002 | + } | |
| 122003 | + sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep); | |
| 122004 | + VdbeCoverage(v); | |
| 121763 | 122005 | } |
| 121764 | 122006 | if( pLevel->iLeftJoin ){ |
| 121765 | 122007 | addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); |
| 121766 | 122008 | assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 |
| 121767 | 122009 | || (pLoop->wsFlags & WHERE_INDEXED)!=0 ); |
| @@ -126982,30 +127224,32 @@ | ||
| 126982 | 127224 | /* Mutex configuration options are only available in a threadsafe |
| 126983 | 127225 | ** compile. |
| 126984 | 127226 | */ |
| 126985 | 127227 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ |
| 126986 | 127228 | case SQLITE_CONFIG_SINGLETHREAD: { |
| 126987 | - /* Disable all mutexing */ | |
| 126988 | - sqlite3GlobalConfig.bCoreMutex = 0; | |
| 126989 | - sqlite3GlobalConfig.bFullMutex = 0; | |
| 127229 | + /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to | |
| 127230 | + ** Single-thread. */ | |
| 127231 | + sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */ | |
| 127232 | + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ | |
| 126990 | 127233 | break; |
| 126991 | 127234 | } |
| 126992 | 127235 | #endif |
| 126993 | 127236 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ |
| 126994 | 127237 | case SQLITE_CONFIG_MULTITHREAD: { |
| 126995 | - /* Disable mutexing of database connections */ | |
| 126996 | - /* Enable mutexing of core data structures */ | |
| 126997 | - sqlite3GlobalConfig.bCoreMutex = 1; | |
| 126998 | - sqlite3GlobalConfig.bFullMutex = 0; | |
| 127238 | + /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to | |
| 127239 | + ** Multi-thread. */ | |
| 127240 | + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ | |
| 127241 | + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ | |
| 126999 | 127242 | break; |
| 127000 | 127243 | } |
| 127001 | 127244 | #endif |
| 127002 | 127245 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ |
| 127003 | 127246 | case SQLITE_CONFIG_SERIALIZED: { |
| 127004 | - /* Enable all mutexing */ | |
| 127005 | - sqlite3GlobalConfig.bCoreMutex = 1; | |
| 127006 | - sqlite3GlobalConfig.bFullMutex = 1; | |
| 127247 | + /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to | |
| 127248 | + ** Serialized. */ | |
| 127249 | + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ | |
| 127250 | + sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */ | |
| 127007 | 127251 | break; |
| 127008 | 127252 | } |
| 127009 | 127253 | #endif |
| 127010 | 127254 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ |
| 127011 | 127255 | case SQLITE_CONFIG_MUTEX: { |
| @@ -127113,11 +127357,12 @@ | ||
| 127113 | 127357 | ** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ |
| 127114 | 127358 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 127115 | 127359 | case SQLITE_CONFIG_HEAP: { |
| 127116 | 127360 | /* EVIDENCE-OF: R-19854-42126 There are three arguments to |
| 127117 | 127361 | ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the |
| 127118 | - ** number of bytes in the memory buffer, and the minimum allocation size. */ | |
| 127362 | + ** number of bytes in the memory buffer, and the minimum allocation size. | |
| 127363 | + */ | |
| 127119 | 127364 | sqlite3GlobalConfig.pHeap = va_arg(ap, void*); |
| 127120 | 127365 | sqlite3GlobalConfig.nHeap = va_arg(ap, int); |
| 127121 | 127366 | sqlite3GlobalConfig.mnReq = va_arg(ap, int); |
| 127122 | 127367 | |
| 127123 | 127368 | if( sqlite3GlobalConfig.mnReq<1 ){ |
| @@ -127218,11 +127463,13 @@ | ||
| 127218 | 127463 | ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be |
| 127219 | 127464 | ** silently truncated if necessary so that it does not exceed the |
| 127220 | 127465 | ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE |
| 127221 | 127466 | ** compile-time option. |
| 127222 | 127467 | */ |
| 127223 | - if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE; | |
| 127468 | + if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ | |
| 127469 | + mxMmap = SQLITE_MAX_MMAP_SIZE; | |
| 127470 | + } | |
| 127224 | 127471 | if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; |
| 127225 | 127472 | if( szMmap>mxMmap) szMmap = mxMmap; |
| 127226 | 127473 | sqlite3GlobalConfig.mxMmap = mxMmap; |
| 127227 | 127474 | sqlite3GlobalConfig.szMmap = szMmap; |
| 127228 | 127475 | break; |
| @@ -129062,11 +129309,23 @@ | ||
| 129062 | 129309 | for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&'); |
| 129063 | 129310 | zFile = sqlite3_malloc(nByte); |
| 129064 | 129311 | if( !zFile ) return SQLITE_NOMEM; |
| 129065 | 129312 | |
| 129066 | 129313 | iIn = 5; |
| 129067 | -#ifndef SQLITE_ALLOW_URI_AUTHORITY | |
| 129314 | +#ifdef SQLITE_ALLOW_URI_AUTHORITY | |
| 129315 | + if( strncmp(zUri+5, "///", 3)==0 ){ | |
| 129316 | + iIn = 7; | |
| 129317 | + /* The following condition causes URIs with five leading / characters | |
| 129318 | + ** like file://///host/path to be converted into UNCs like //host/path. | |
| 129319 | + ** The correct URI for that UNC has only two or four leading / characters | |
| 129320 | + ** file://host/path or file:////host/path. But 5 leading slashes is a | |
| 129321 | + ** common error, we are told, so we handle it as a special case. */ | |
| 129322 | + if( strncmp(zUri+7, "///", 3)==0 ){ iIn++; } | |
| 129323 | + }else if( strncmp(zUri+5, "//localhost/", 12)==0 ){ | |
| 129324 | + iIn = 16; | |
| 129325 | + } | |
| 129326 | +#else | |
| 129068 | 129327 | /* Discard the scheme and authority segments of the URI. */ |
| 129069 | 129328 | if( zUri[5]=='/' && zUri[6]=='/' ){ |
| 129070 | 129329 | iIn = 7; |
| 129071 | 129330 | while( zUri[iIn] && zUri[iIn]!='/' ) iIn++; |
| 129072 | 129331 | if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){ |
| @@ -129505,11 +129764,12 @@ | ||
| 129505 | 129764 | sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); |
| 129506 | 129765 | |
| 129507 | 129766 | opendb_out: |
| 129508 | 129767 | sqlite3_free(zOpen); |
| 129509 | 129768 | if( db ){ |
| 129510 | - assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); | |
| 129769 | + assert( db->mutex!=0 || isThreadsafe==0 | |
| 129770 | + || sqlite3GlobalConfig.bFullMutex==0 ); | |
| 129511 | 129771 | sqlite3_mutex_leave(db->mutex); |
| 129512 | 129772 | } |
| 129513 | 129773 | rc = sqlite3_errcode(db); |
| 129514 | 129774 | assert( db!=0 || rc==SQLITE_NOMEM ); |
| 129515 | 129775 | if( rc==SQLITE_NOMEM ){ |
| @@ -130250,21 +130510,21 @@ | ||
| 130250 | 130510 | case SQLITE_TESTCTRL_ISINIT: { |
| 130251 | 130511 | if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; |
| 130252 | 130512 | break; |
| 130253 | 130513 | } |
| 130254 | 130514 | |
| 130255 | - /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); | |
| 130515 | + /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); | |
| 130256 | 130516 | ** |
| 130257 | 130517 | ** This test control is used to create imposter tables. "db" is a pointer |
| 130258 | 130518 | ** to the database connection. dbName is the database name (ex: "main" or |
| 130259 | 130519 | ** "temp") which will receive the imposter. "onOff" turns imposter mode on |
| 130260 | 130520 | ** or off. "tnum" is the root page of the b-tree to which the imposter |
| 130261 | 130521 | ** table should connect. |
| 130262 | 130522 | ** |
| 130263 | 130523 | ** Enable imposter mode only when the schema has already been parsed. Then |
| 130264 | - ** run a single CREATE TABLE statement to construct the imposter table in the | |
| 130265 | - ** parsed schema. Then turn imposter mode back off again. | |
| 130524 | + ** run a single CREATE TABLE statement to construct the imposter table in | |
| 130525 | + ** the parsed schema. Then turn imposter mode back off again. | |
| 130266 | 130526 | ** |
| 130267 | 130527 | ** If onOff==0 and tnum>0 then reset the schema for all databases, causing |
| 130268 | 130528 | ** the schema to be reparsed the next time it is needed. This has the |
| 130269 | 130529 | ** effect of erasing all imposter tables. |
| 130270 | 130530 | */ |
| 130271 | 130531 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -1,8 +1,8 @@ | |
| 1 | /****************************************************************************** |
| 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | ** version 3.8.8. By combining all the individual C code files into this |
| 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | ** translation unit. |
| @@ -88,10 +88,48 @@ | |
| 88 | #endif /* _MSVC_H_ */ |
| 89 | |
| 90 | /************** End of msvc.h ************************************************/ |
| 91 | /************** Continuing where we left off in sqliteInt.h ******************/ |
| 92 | |
| 93 | /* |
| 94 | ** These #defines should enable >2GB file support on POSIX if the |
| 95 | ** underlying operating system supports it. If the OS lacks |
| 96 | ** large file support, or if the OS is windows, these should be no-ops. |
| 97 | ** |
| @@ -276,13 +314,13 @@ | |
| 276 | ** |
| 277 | ** See also: [sqlite3_libversion()], |
| 278 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 279 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 280 | */ |
| 281 | #define SQLITE_VERSION "3.8.8" |
| 282 | #define SQLITE_VERSION_NUMBER 3008008 |
| 283 | #define SQLITE_SOURCE_ID "2015-02-25 14:25:31 6d132e7a224ee68b5cefe9222944aac5760ffc20" |
| 284 | |
| 285 | /* |
| 286 | ** CAPI3REF: Run-Time Library Version Numbers |
| 287 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 288 | ** |
| @@ -925,18 +963,20 @@ | |
| 925 | ** |
| 926 | ** These integer constants are opcodes for the xFileControl method |
| 927 | ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] |
| 928 | ** interface. |
| 929 | ** |
| 930 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This |
| 931 | ** opcode causes the xFileControl method to write the current state of |
| 932 | ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], |
| 933 | ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) |
| 934 | ** into an integer that the pArg argument points to. This capability |
| 935 | ** is used during testing and only needs to be supported when SQLITE_TEST |
| 936 | ** is defined. |
| 937 | ** <ul> |
| 938 | ** <li>[[SQLITE_FCNTL_SIZE_HINT]] |
| 939 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS |
| 940 | ** layer a hint of how large the database file will grow to be during the |
| 941 | ** current transaction. This hint is not guaranteed to be accurate but it |
| 942 | ** is often close. The underlying VFS might choose to preallocate database |
| @@ -1057,11 +1097,13 @@ | |
| 1057 | ** the error message if the pragma fails. ^If the |
| 1058 | ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal |
| 1059 | ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] |
| 1060 | ** file control returns [SQLITE_OK], then the parser assumes that the |
| 1061 | ** VFS has handled the PRAGMA itself and the parser generates a no-op |
| 1062 | ** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns |
| 1063 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means |
| 1064 | ** that the VFS encountered an error while handling the [PRAGMA] and the |
| 1065 | ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] |
| 1066 | ** file control occurs at the beginning of pragma statement analysis and so |
| 1067 | ** it is able to override built-in [PRAGMA] statements. |
| @@ -1916,11 +1958,10 @@ | |
| 1916 | ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE |
| 1917 | ** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is |
| 1918 | ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro |
| 1919 | ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value |
| 1920 | ** that specifies the maximum size of the created heap. |
| 1921 | ** </dl> |
| 1922 | ** |
| 1923 | ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] |
| 1924 | ** <dt>SQLITE_CONFIG_PCACHE_HDRSZ |
| 1925 | ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which |
| 1926 | ** is a pointer to an integer and writes into that integer the number of extra |
| @@ -3356,20 +3397,18 @@ | |
| 3356 | ** The second argument, "zSql", is the statement to be compiled, encoded |
| 3357 | ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() |
| 3358 | ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() |
| 3359 | ** use UTF-16. |
| 3360 | ** |
| 3361 | ** ^If the nByte argument is less than zero, then zSql is read up to the |
| 3362 | ** first zero terminator. ^If nByte is non-negative, then it is the maximum |
| 3363 | ** number of bytes read from zSql. ^When nByte is non-negative, the |
| 3364 | ** zSql string ends at either the first '\000' or '\u0000' character or |
| 3365 | ** the nByte-th byte, whichever comes first. If the caller knows |
| 3366 | ** that the supplied string is nul-terminated, then there is a small |
| 3367 | ** performance advantage to be gained by passing an nByte parameter that |
| 3368 | ** is equal to the number of bytes in the input string <i>including</i> |
| 3369 | ** the nul-terminator bytes as this saves SQLite from having to |
| 3370 | ** make a copy of the input string. |
| 3371 | ** |
| 3372 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 3373 | ** past the end of the first SQL statement in zSql. These routines only |
| 3374 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| 3375 | ** what remains uncompiled. |
| @@ -4394,12 +4433,12 @@ | |
| 4394 | ** DEPRECATED |
| 4395 | ** |
| 4396 | ** These functions are [deprecated]. In order to maintain |
| 4397 | ** backwards compatibility with older code, these functions continue |
| 4398 | ** to be supported. However, new applications should avoid |
| 4399 | ** the use of these functions. To help encourage people to avoid |
| 4400 | ** using these functions, we are not going to tell you what they do. |
| 4401 | */ |
| 4402 | #ifndef SQLITE_OMIT_DEPRECATED |
| 4403 | SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); |
| 4404 | SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); |
| 4405 | SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); |
| @@ -7157,24 +7196,24 @@ | |
| 7157 | ** |
| 7158 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 7159 | ** is not a permanent error and does not affect the return value of |
| 7160 | ** sqlite3_backup_finish(). |
| 7161 | ** |
| 7162 | ** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] |
| 7163 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 7164 | ** |
| 7165 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 7166 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 7167 | ** up and the total number of pages in the source database file. |
| 7168 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| 7169 | ** retrieve these two values, respectively. |
| 7170 | ** |
| 7171 | ** ^The values returned by these functions are only updated by |
| 7172 | ** sqlite3_backup_step(). ^If the source database is modified during a backup |
| 7173 | ** operation, then the values are not updated to account for any extra |
| 7174 | ** pages that need to be updated or the size of the source database file |
| 7175 | ** changing. |
| 7176 | ** |
| 7177 | ** <b>Concurrent Usage of Database Handles</b> |
| 7178 | ** |
| 7179 | ** ^The source [database connection] may be used by the application for other |
| 7180 | ** purposes while a backup operation is underway or being initialized. |
| @@ -8018,19 +8057,21 @@ | |
| 8018 | #ifndef SQLITE_MAX_FUNCTION_ARG |
| 8019 | # define SQLITE_MAX_FUNCTION_ARG 127 |
| 8020 | #endif |
| 8021 | |
| 8022 | /* |
| 8023 | ** The maximum number of in-memory pages to use for the main database |
| 8024 | ** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE |
| 8025 | */ |
| 8026 | #ifndef SQLITE_DEFAULT_CACHE_SIZE |
| 8027 | # define SQLITE_DEFAULT_CACHE_SIZE 2000 |
| 8028 | #endif |
| 8029 | #ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE |
| 8030 | # define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500 |
| 8031 | #endif |
| 8032 | |
| 8033 | /* |
| 8034 | ** The default number of frames to accumulate in the log file before |
| 8035 | ** checkpointing the database in WAL mode. |
| 8036 | */ |
| @@ -9733,27 +9774,29 @@ | |
| 9733 | #define OP_FkCounter 134 /* synopsis: fkctr[P1]+=P2 */ |
| 9734 | #define OP_FkIfZero 135 /* synopsis: if fkctr[P1]==0 goto P2 */ |
| 9735 | #define OP_MemMax 136 /* synopsis: r[P1]=max(r[P1],r[P2]) */ |
| 9736 | #define OP_IfPos 137 /* synopsis: if r[P1]>0 goto P2 */ |
| 9737 | #define OP_IfNeg 138 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */ |
| 9738 | #define OP_IfZero 139 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ |
| 9739 | #define OP_AggFinal 140 /* synopsis: accum=r[P1] N=P2 */ |
| 9740 | #define OP_IncrVacuum 141 |
| 9741 | #define OP_Expire 142 |
| 9742 | #define OP_TableLock 143 /* synopsis: iDb=P1 root=P2 write=P3 */ |
| 9743 | #define OP_VBegin 144 |
| 9744 | #define OP_VCreate 145 |
| 9745 | #define OP_VDestroy 146 |
| 9746 | #define OP_VOpen 147 |
| 9747 | #define OP_VColumn 148 /* synopsis: r[P3]=vcolumn(P2) */ |
| 9748 | #define OP_VNext 149 |
| 9749 | #define OP_VRename 150 |
| 9750 | #define OP_Pagecount 151 |
| 9751 | #define OP_MaxPgcnt 152 |
| 9752 | #define OP_Init 153 /* synopsis: Start at P2 */ |
| 9753 | #define OP_Noop 154 |
| 9754 | #define OP_Explain 155 |
| 9755 | |
| 9756 | |
| 9757 | /* Properties such as "out2" or "jump" that are specified in |
| 9758 | ** comments following the "case" for each opcode in the vdbe.c |
| 9759 | ** are encoded into bitvectors as follows: |
| @@ -9781,13 +9824,13 @@ | |
| 9781 | /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\ |
| 9782 | /* 104 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x00,\ |
| 9783 | /* 112 */ 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,\ |
| 9784 | /* 120 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ |
| 9785 | /* 128 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x02, 0x00, 0x01,\ |
| 9786 | /* 136 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00,\ |
| 9787 | /* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,\ |
| 9788 | /* 152 */ 0x02, 0x01, 0x00, 0x00,} |
| 9789 | |
| 9790 | /************** End of opcodes.h *********************************************/ |
| 9791 | /************** Continuing where we left off in vdbe.h ***********************/ |
| 9792 | |
| 9793 | /* |
| @@ -12022,11 +12065,11 @@ | |
| 12022 | #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ |
| 12023 | #define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */ |
| 12024 | #define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ |
| 12025 | #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ |
| 12026 | #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ |
| 12027 | /* 0x0080 // not currently used */ |
| 12028 | #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ |
| 12029 | #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ |
| 12030 | #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ |
| 12031 | #define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ |
| 12032 | #define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ |
| @@ -24969,27 +25012,29 @@ | |
| 24969 | /* 134 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), |
| 24970 | /* 135 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), |
| 24971 | /* 136 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), |
| 24972 | /* 137 */ "IfPos" OpHelp("if r[P1]>0 goto P2"), |
| 24973 | /* 138 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"), |
| 24974 | /* 139 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"), |
| 24975 | /* 140 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), |
| 24976 | /* 141 */ "IncrVacuum" OpHelp(""), |
| 24977 | /* 142 */ "Expire" OpHelp(""), |
| 24978 | /* 143 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), |
| 24979 | /* 144 */ "VBegin" OpHelp(""), |
| 24980 | /* 145 */ "VCreate" OpHelp(""), |
| 24981 | /* 146 */ "VDestroy" OpHelp(""), |
| 24982 | /* 147 */ "VOpen" OpHelp(""), |
| 24983 | /* 148 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), |
| 24984 | /* 149 */ "VNext" OpHelp(""), |
| 24985 | /* 150 */ "VRename" OpHelp(""), |
| 24986 | /* 151 */ "Pagecount" OpHelp(""), |
| 24987 | /* 152 */ "MaxPgcnt" OpHelp(""), |
| 24988 | /* 153 */ "Init" OpHelp("Start at P2"), |
| 24989 | /* 154 */ "Noop" OpHelp(""), |
| 24990 | /* 155 */ "Explain" OpHelp(""), |
| 24991 | }; |
| 24992 | return azName[i]; |
| 24993 | } |
| 24994 | #endif |
| 24995 | |
| @@ -25065,22 +25110,10 @@ | |
| 25065 | # else |
| 25066 | # define SQLITE_ENABLE_LOCKING_STYLE 0 |
| 25067 | # endif |
| 25068 | #endif |
| 25069 | |
| 25070 | /* |
| 25071 | ** Define the OS_VXWORKS pre-processor macro to 1 if building on |
| 25072 | ** vxworks, or 0 otherwise. |
| 25073 | */ |
| 25074 | #ifndef OS_VXWORKS |
| 25075 | # if defined(__RTP__) || defined(_WRS_KERNEL) |
| 25076 | # define OS_VXWORKS 1 |
| 25077 | # else |
| 25078 | # define OS_VXWORKS 0 |
| 25079 | # endif |
| 25080 | #endif |
| 25081 | |
| 25082 | /* |
| 25083 | ** standard include files. |
| 25084 | */ |
| 25085 | #include <sys/types.h> |
| 25086 | #include <sys/stat.h> |
| @@ -25091,22 +25124,23 @@ | |
| 25091 | #include <errno.h> |
| 25092 | #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
| 25093 | # include <sys/mman.h> |
| 25094 | #endif |
| 25095 | |
| 25096 | #if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS |
| 25097 | # include <sys/ioctl.h> |
| 25098 | # if OS_VXWORKS |
| 25099 | # include <semaphore.h> |
| 25100 | # include <limits.h> |
| 25101 | # else |
| 25102 | # include <sys/file.h> |
| 25103 | # include <sys/param.h> |
| 25104 | # endif |
| 25105 | #endif /* SQLITE_ENABLE_LOCKING_STYLE */ |
| 25106 | |
| 25107 | #if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) |
| 25108 | # include <sys/mount.h> |
| 25109 | #endif |
| 25110 | |
| 25111 | #ifdef HAVE_UTIME |
| 25112 | # include <utime.h> |
| @@ -25142,10 +25176,14 @@ | |
| 25142 | |
| 25143 | /* |
| 25144 | ** Maximum supported path-length. |
| 25145 | */ |
| 25146 | #define MAX_PATHNAME 512 |
| 25147 | |
| 25148 | /* |
| 25149 | ** Only set the lastErrno if the error code is a real error and not |
| 25150 | ** a normal expected return code of SQLITE_BUSY or SQLITE_OK |
| 25151 | */ |
| @@ -25231,11 +25269,11 @@ | |
| 25231 | |
| 25232 | /* This variable holds the process id (pid) from when the xRandomness() |
| 25233 | ** method was called. If xOpen() is called from a different process id, |
| 25234 | ** indicating that a fork() has occurred, the PRNG will be reset. |
| 25235 | */ |
| 25236 | static int randomnessPid = 0; |
| 25237 | |
| 25238 | /* |
| 25239 | ** Allowed values for the unixFile.ctrlFlags bitmask: |
| 25240 | */ |
| 25241 | #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
| @@ -25587,11 +25625,11 @@ | |
| 25587 | #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) |
| 25588 | |
| 25589 | { "read", (sqlite3_syscall_ptr)read, 0 }, |
| 25590 | #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) |
| 25591 | |
| 25592 | #if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) |
| 25593 | { "pread", (sqlite3_syscall_ptr)pread, 0 }, |
| 25594 | #else |
| 25595 | { "pread", (sqlite3_syscall_ptr)0, 0 }, |
| 25596 | #endif |
| 25597 | #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) |
| @@ -25604,11 +25642,11 @@ | |
| 25604 | #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) |
| 25605 | |
| 25606 | { "write", (sqlite3_syscall_ptr)write, 0 }, |
| 25607 | #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) |
| 25608 | |
| 25609 | #if defined(USE_PREAD) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS) |
| 25610 | { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, |
| 25611 | #else |
| 25612 | { "pwrite", (sqlite3_syscall_ptr)0, 0 }, |
| 25613 | #endif |
| 25614 | #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| @@ -26743,11 +26781,12 @@ | |
| 26743 | int tErrno = 0; |
| 26744 | |
| 26745 | assert( pFile ); |
| 26746 | OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, |
| 26747 | azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
| 26748 | azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared , getpid())); |
| 26749 | |
| 26750 | /* If there is already a lock of this type or more restrictive on the |
| 26751 | ** unixFile, do nothing. Don't use the end_lock: exit path, as |
| 26752 | ** unixEnterMutex() hasn't been called yet. |
| 26753 | */ |
| @@ -26951,11 +26990,11 @@ | |
| 26951 | int rc = SQLITE_OK; |
| 26952 | |
| 26953 | assert( pFile ); |
| 26954 | OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, |
| 26955 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
| 26956 | getpid())); |
| 26957 | |
| 26958 | assert( eFileLock<=SHARED_LOCK ); |
| 26959 | if( pFile->eFileLock<=eFileLock ){ |
| 26960 | return SQLITE_OK; |
| 26961 | } |
| @@ -27378,11 +27417,11 @@ | |
| 27378 | char *zLockFile = (char *)pFile->lockingContext; |
| 27379 | int rc; |
| 27380 | |
| 27381 | assert( pFile ); |
| 27382 | OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, |
| 27383 | pFile->eFileLock, getpid())); |
| 27384 | assert( eFileLock<=SHARED_LOCK ); |
| 27385 | |
| 27386 | /* no-op if possible */ |
| 27387 | if( pFile->eFileLock==eFileLock ){ |
| 27388 | return SQLITE_OK; |
| @@ -27441,14 +27480,13 @@ | |
| 27441 | ** a single exclusive lock. In other words, SHARED, RESERVED, and |
| 27442 | ** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite |
| 27443 | ** still works when you do this, but concurrency is reduced since |
| 27444 | ** only a single process can be reading the database at a time. |
| 27445 | ** |
| 27446 | ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if |
| 27447 | ** compiling for VXWORKS. |
| 27448 | */ |
| 27449 | #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS |
| 27450 | |
| 27451 | /* |
| 27452 | ** Retry flock() calls that fail with EINTR |
| 27453 | */ |
| 27454 | #ifdef EINTR |
| @@ -27597,11 +27635,11 @@ | |
| 27597 | static int flockUnlock(sqlite3_file *id, int eFileLock) { |
| 27598 | unixFile *pFile = (unixFile*)id; |
| 27599 | |
| 27600 | assert( pFile ); |
| 27601 | OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, |
| 27602 | pFile->eFileLock, getpid())); |
| 27603 | assert( eFileLock<=SHARED_LOCK ); |
| 27604 | |
| 27605 | /* no-op if possible */ |
| 27606 | if( pFile->eFileLock==eFileLock ){ |
| 27607 | return SQLITE_OK; |
| @@ -27658,11 +27696,11 @@ | |
| 27658 | ** This routine checks if there is a RESERVED lock held on the specified |
| 27659 | ** file by this or any other process. If such a lock is held, set *pResOut |
| 27660 | ** to a non-zero value otherwise *pResOut is set to zero. The return value |
| 27661 | ** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
| 27662 | */ |
| 27663 | static int semCheckReservedLock(sqlite3_file *id, int *pResOut) { |
| 27664 | int rc = SQLITE_OK; |
| 27665 | int reserved = 0; |
| 27666 | unixFile *pFile = (unixFile*)id; |
| 27667 | |
| 27668 | SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
| @@ -27725,11 +27763,11 @@ | |
| 27725 | ** access the file. |
| 27726 | ** |
| 27727 | ** This routine will only increase a lock. Use the sqlite3OsUnlock() |
| 27728 | ** routine to lower a locking level. |
| 27729 | */ |
| 27730 | static int semLock(sqlite3_file *id, int eFileLock) { |
| 27731 | unixFile *pFile = (unixFile*)id; |
| 27732 | sem_t *pSem = pFile->pInode->pSem; |
| 27733 | int rc = SQLITE_OK; |
| 27734 | |
| 27735 | /* if we already have a lock, it is exclusive. |
| @@ -27758,18 +27796,18 @@ | |
| 27758 | ** must be either NO_LOCK or SHARED_LOCK. |
| 27759 | ** |
| 27760 | ** If the locking level of the file descriptor is already at or below |
| 27761 | ** the requested locking level, this routine is a no-op. |
| 27762 | */ |
| 27763 | static int semUnlock(sqlite3_file *id, int eFileLock) { |
| 27764 | unixFile *pFile = (unixFile*)id; |
| 27765 | sem_t *pSem = pFile->pInode->pSem; |
| 27766 | |
| 27767 | assert( pFile ); |
| 27768 | assert( pSem ); |
| 27769 | OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, |
| 27770 | pFile->eFileLock, getpid())); |
| 27771 | assert( eFileLock<=SHARED_LOCK ); |
| 27772 | |
| 27773 | /* no-op if possible */ |
| 27774 | if( pFile->eFileLock==eFileLock ){ |
| 27775 | return SQLITE_OK; |
| @@ -27795,14 +27833,14 @@ | |
| 27795 | } |
| 27796 | |
| 27797 | /* |
| 27798 | ** Close a file. |
| 27799 | */ |
| 27800 | static int semClose(sqlite3_file *id) { |
| 27801 | if( id ){ |
| 27802 | unixFile *pFile = (unixFile*)id; |
| 27803 | semUnlock(id, NO_LOCK); |
| 27804 | assert( pFile ); |
| 27805 | unixEnterMutex(); |
| 27806 | releaseInodeInfo(pFile); |
| 27807 | unixLeaveMutex(); |
| 27808 | closeUnixFile(id); |
| @@ -27979,11 +28017,11 @@ | |
| 27979 | afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; |
| 27980 | |
| 27981 | assert( pFile ); |
| 27982 | OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, |
| 27983 | azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
| 27984 | azFileLock(pInode->eFileLock), pInode->nShared , getpid())); |
| 27985 | |
| 27986 | /* If there is already a lock of this type or more restrictive on the |
| 27987 | ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as |
| 27988 | ** unixEnterMutex() hasn't been called yet. |
| 27989 | */ |
| @@ -28165,11 +28203,11 @@ | |
| 28165 | #endif |
| 28166 | |
| 28167 | assert( pFile ); |
| 28168 | OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, |
| 28169 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
| 28170 | getpid())); |
| 28171 | |
| 28172 | assert( eFileLock<=SHARED_LOCK ); |
| 28173 | if( pFile->eFileLock<=eFileLock ){ |
| 28174 | return SQLITE_OK; |
| 28175 | } |
| @@ -29204,11 +29242,13 @@ | |
| 29204 | ** |
| 29205 | ** This function should not be called directly by other code in this file. |
| 29206 | ** Instead, it should be called via macro osGetpagesize(). |
| 29207 | */ |
| 29208 | static int unixGetpagesize(void){ |
| 29209 | #if defined(_BSD_SOURCE) |
| 29210 | return getpagesize(); |
| 29211 | #else |
| 29212 | return (int)sysconf(_SC_PAGESIZE); |
| 29213 | #endif |
| 29214 | } |
| @@ -29833,11 +29873,11 @@ | |
| 29833 | } |
| 29834 | } |
| 29835 | } |
| 29836 | sqlite3_mutex_leave(pShmNode->mutex); |
| 29837 | OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", |
| 29838 | p->id, getpid(), p->sharedMask, p->exclMask)); |
| 29839 | return rc; |
| 29840 | } |
| 29841 | |
| 29842 | /* |
| 29843 | ** Implement a memory barrier or memory fence on shared memory. |
| @@ -30236,11 +30276,11 @@ | |
| 30236 | dotlockUnlock, /* xUnlock method */ |
| 30237 | dotlockCheckReservedLock, /* xCheckReservedLock method */ |
| 30238 | 0 /* xShmMap method */ |
| 30239 | ) |
| 30240 | |
| 30241 | #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS |
| 30242 | IOMETHODS( |
| 30243 | flockIoFinder, /* Finder function name */ |
| 30244 | flockIoMethods, /* sqlite3_io_methods object name */ |
| 30245 | 1, /* shared memory is disabled */ |
| 30246 | flockClose, /* xClose method */ |
| @@ -30254,14 +30294,14 @@ | |
| 30254 | #if OS_VXWORKS |
| 30255 | IOMETHODS( |
| 30256 | semIoFinder, /* Finder function name */ |
| 30257 | semIoMethods, /* sqlite3_io_methods object name */ |
| 30258 | 1, /* shared memory is disabled */ |
| 30259 | semClose, /* xClose method */ |
| 30260 | semLock, /* xLock method */ |
| 30261 | semUnlock, /* xUnlock method */ |
| 30262 | semCheckReservedLock, /* xCheckReservedLock method */ |
| 30263 | 0 /* xShmMap method */ |
| 30264 | ) |
| 30265 | #endif |
| 30266 | |
| 30267 | #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
| @@ -30381,19 +30421,17 @@ | |
| 30381 | static const sqlite3_io_methods |
| 30382 | *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; |
| 30383 | |
| 30384 | #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
| 30385 | |
| 30386 | #if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE |
| 30387 | /* |
| 30388 | ** This "finder" function attempts to determine the best locking strategy |
| 30389 | ** for the database file "filePath". It then returns the sqlite3_io_methods |
| 30390 | ** object that implements that strategy. |
| 30391 | ** |
| 30392 | ** This is for VXWorks only. |
| 30393 | */ |
| 30394 | static const sqlite3_io_methods *autolockIoFinderImpl( |
| 30395 | const char *filePath, /* name of the database file */ |
| 30396 | unixFile *pNew /* the open file object */ |
| 30397 | ){ |
| 30398 | struct flock lockInfo; |
| 30399 | |
| @@ -30415,13 +30453,13 @@ | |
| 30415 | }else{ |
| 30416 | return &semIoMethods; |
| 30417 | } |
| 30418 | } |
| 30419 | static const sqlite3_io_methods |
| 30420 | *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; |
| 30421 | |
| 30422 | #endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */ |
| 30423 | |
| 30424 | /* |
| 30425 | ** An abstract type for a pointer to an IO method finder function: |
| 30426 | */ |
| 30427 | typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); |
| @@ -30930,12 +30968,12 @@ | |
| 30930 | /* Detect a pid change and reset the PRNG. There is a race condition |
| 30931 | ** here such that two or more threads all trying to open databases at |
| 30932 | ** the same instant might all reset the PRNG. But multiple resets |
| 30933 | ** are harmless. |
| 30934 | */ |
| 30935 | if( randomnessPid!=getpid() ){ |
| 30936 | randomnessPid = getpid(); |
| 30937 | sqlite3_randomness(0,0); |
| 30938 | } |
| 30939 | |
| 30940 | memset(p, 0, sizeof(unixFile)); |
| 30941 | |
| @@ -31322,11 +31360,11 @@ | |
| 31322 | ** When testing, initializing zBuf[] to zero is all we do. That means |
| 31323 | ** that we always use the same random number sequence. This makes the |
| 31324 | ** tests repeatable. |
| 31325 | */ |
| 31326 | memset(zBuf, 0, nBuf); |
| 31327 | randomnessPid = getpid(); |
| 31328 | #if !defined(SQLITE_TEST) |
| 31329 | { |
| 31330 | int fd, got; |
| 31331 | fd = robust_open("/dev/urandom", O_RDONLY, 0); |
| 31332 | if( fd<0 ){ |
| @@ -31643,11 +31681,11 @@ | |
| 31643 | #else |
| 31644 | # ifdef _CS_DARWIN_USER_TEMP_DIR |
| 31645 | { |
| 31646 | if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ |
| 31647 | OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", |
| 31648 | lPath, errno, getpid())); |
| 31649 | return SQLITE_IOERR_LOCK; |
| 31650 | } |
| 31651 | len = strlcat(lPath, "sqliteplocks", maxLen); |
| 31652 | } |
| 31653 | # else |
| @@ -31665,11 +31703,11 @@ | |
| 31665 | char c = dbPath[i]; |
| 31666 | lPath[i+len] = (c=='/')?'_':c; |
| 31667 | } |
| 31668 | lPath[i+len]='\0'; |
| 31669 | strlcat(lPath, ":auto:", maxLen); |
| 31670 | OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid())); |
| 31671 | return SQLITE_OK; |
| 31672 | } |
| 31673 | |
| 31674 | /* |
| 31675 | ** Creates the lock file and any missing directories in lockPath |
| @@ -31692,20 +31730,20 @@ | |
| 31692 | if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ |
| 31693 | int err=errno; |
| 31694 | if( err!=EEXIST ) { |
| 31695 | OSTRACE(("CREATELOCKPATH FAILED creating %s, " |
| 31696 | "'%s' proxy lock path=%s pid=%d\n", |
| 31697 | buf, strerror(err), lockPath, getpid())); |
| 31698 | return err; |
| 31699 | } |
| 31700 | } |
| 31701 | } |
| 31702 | start=i+1; |
| 31703 | } |
| 31704 | buf[i] = lockPath[i]; |
| 31705 | } |
| 31706 | OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid())); |
| 31707 | return 0; |
| 31708 | } |
| 31709 | |
| 31710 | /* |
| 31711 | ** Create a new VFS file descriptor (stored in memory obtained from |
| @@ -32006,11 +32044,12 @@ | |
| 32006 | int readLen = 0; |
| 32007 | int tryOldLockPath = 0; |
| 32008 | int forceNewLockPath = 0; |
| 32009 | |
| 32010 | OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, |
| 32011 | (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid())); |
| 32012 | |
| 32013 | rc = proxyGetHostID(myHostID, &pError); |
| 32014 | if( (rc&0xff)==SQLITE_IOERR ){ |
| 32015 | storeLastErrno(pFile, pError); |
| 32016 | goto end_takeconch; |
| @@ -32216,11 +32255,11 @@ | |
| 32216 | |
| 32217 | pCtx = (proxyLockingContext *)pFile->lockingContext; |
| 32218 | conchFile = pCtx->conchFile; |
| 32219 | OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, |
| 32220 | (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), |
| 32221 | getpid())); |
| 32222 | if( pCtx->conchHeld>0 ){ |
| 32223 | rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); |
| 32224 | } |
| 32225 | pCtx->conchHeld = 0; |
| 32226 | OSTRACE(("RELEASECONCH %d %s\n", conchFile->h, |
| @@ -32358,11 +32397,11 @@ | |
| 32358 | }else{ |
| 32359 | lockPath=(char *)path; |
| 32360 | } |
| 32361 | |
| 32362 | OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, |
| 32363 | (lockPath ? lockPath : ":auto:"), getpid())); |
| 32364 | |
| 32365 | pCtx = sqlite3_malloc( sizeof(*pCtx) ); |
| 32366 | if( pCtx==0 ){ |
| 32367 | return SQLITE_NOMEM; |
| 32368 | } |
| @@ -32699,26 +32738,28 @@ | |
| 32699 | ** Note that the sqlite3_vfs.pNext field of the VFS object is modified |
| 32700 | ** by the SQLite core when the VFS is registered. So the following |
| 32701 | ** array cannot be const. |
| 32702 | */ |
| 32703 | static sqlite3_vfs aVfs[] = { |
| 32704 | #if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__)) |
| 32705 | UNIXVFS("unix", autolockIoFinder ), |
| 32706 | #else |
| 32707 | UNIXVFS("unix", posixIoFinder ), |
| 32708 | #endif |
| 32709 | UNIXVFS("unix-none", nolockIoFinder ), |
| 32710 | UNIXVFS("unix-dotfile", dotlockIoFinder ), |
| 32711 | UNIXVFS("unix-excl", posixIoFinder ), |
| 32712 | #if OS_VXWORKS |
| 32713 | UNIXVFS("unix-namedsem", semIoFinder ), |
| 32714 | #endif |
| 32715 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 32716 | UNIXVFS("unix-posix", posixIoFinder ), |
| 32717 | #if !OS_VXWORKS |
| 32718 | UNIXVFS("unix-flock", flockIoFinder ), |
| 32719 | #endif |
| 32720 | #endif |
| 32721 | #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
| 32722 | UNIXVFS("unix-afp", afpIoFinder ), |
| 32723 | UNIXVFS("unix-nfs", nfsIoFinder ), |
| 32724 | UNIXVFS("unix-proxy", proxyIoFinder ), |
| @@ -39072,16 +39113,24 @@ | |
| 39072 | sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); |
| 39073 | } |
| 39074 | } |
| 39075 | |
| 39076 | /* |
| 39077 | ** Compute the number of pages of cache requested. |
| 39078 | */ |
| 39079 | static int numberOfCachePages(PCache *p){ |
| 39080 | if( p->szCache>=0 ){ |
| 39081 | return p->szCache; |
| 39082 | }else{ |
| 39083 | return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); |
| 39084 | } |
| 39085 | } |
| 39086 | |
| 39087 | /*************************************************** General Interfaces ****** |
| @@ -68615,10 +68664,14 @@ | |
| 68615 | } |
| 68616 | SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ |
| 68617 | return sqlite3ValueText(pVal, SQLITE_UTF16LE); |
| 68618 | } |
| 68619 | #endif /* SQLITE_OMIT_UTF16 */ |
| 68620 | SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ |
| 68621 | static const u8 aType[] = { |
| 68622 | SQLITE_BLOB, /* 0x00 */ |
| 68623 | SQLITE_NULL, /* 0x01 */ |
| 68624 | SQLITE_TEXT, /* 0x02 */ |
| @@ -71290,11 +71343,11 @@ | |
| 71290 | |
| 71291 | /* Opcode: String8 * P2 * P4 * |
| 71292 | ** Synopsis: r[P2]='P4' |
| 71293 | ** |
| 71294 | ** P4 points to a nul terminated UTF-8 string. This opcode is transformed |
| 71295 | ** into a String before it is executed for the first time. During |
| 71296 | ** this transformation, the length of string P4 is computed and stored |
| 71297 | ** as the P1 parameter. |
| 71298 | */ |
| 71299 | case OP_String8: { /* same as TK_STRING, out2-prerelease */ |
| 71300 | assert( pOp->p4.z!=0 ); |
| @@ -71322,22 +71375,34 @@ | |
| 71322 | goto too_big; |
| 71323 | } |
| 71324 | /* Fall through to the next case, OP_String */ |
| 71325 | } |
| 71326 | |
| 71327 | /* Opcode: String P1 P2 * P4 * |
| 71328 | ** Synopsis: r[P2]='P4' (len=P1) |
| 71329 | ** |
| 71330 | ** The string value P4 of length P1 (bytes) is stored in register P2. |
| 71331 | */ |
| 71332 | case OP_String: { /* out2-prerelease */ |
| 71333 | assert( pOp->p4.z!=0 ); |
| 71334 | pOut->flags = MEM_Str|MEM_Static|MEM_Term; |
| 71335 | pOut->z = pOp->p4.z; |
| 71336 | pOut->n = pOp->p1; |
| 71337 | pOut->enc = encoding; |
| 71338 | UPDATE_MAX_BLOBSIZE(pOut); |
| 71339 | break; |
| 71340 | } |
| 71341 | |
| 71342 | /* Opcode: Null P1 P2 P3 * * |
| 71343 | ** Synopsis: r[P2..P3]=NULL |
| @@ -73325,11 +73390,16 @@ | |
| 73325 | ** the value of this counter needs to be restored too. */ |
| 73326 | p->nStmtDefCons = db->nDeferredCons; |
| 73327 | p->nStmtDefImmCons = db->nDeferredImmCons; |
| 73328 | } |
| 73329 | |
| 73330 | /* Gather the schema version number for checking */ |
| 73331 | sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); |
| 73332 | iGen = db->aDb[pOp->p1].pSchema->iGeneration; |
| 73333 | }else{ |
| 73334 | iGen = iMeta = 0; |
| 73335 | } |
| @@ -75843,14 +75913,16 @@ | |
| 75843 | #endif /* SQLITE_OMIT_AUTOINCREMENT */ |
| 75844 | |
| 75845 | /* Opcode: IfPos P1 P2 * * * |
| 75846 | ** Synopsis: if r[P1]>0 goto P2 |
| 75847 | ** |
| 75848 | ** If the value of register P1 is 1 or greater, jump to P2. |
| 75849 | ** |
| 75850 | ** It is illegal to use this instruction on a register that does |
| 75851 | ** not contain an integer. An assertion fault will result if you try. |
| 75852 | */ |
| 75853 | case OP_IfPos: { /* jump, in1 */ |
| 75854 | pIn1 = &aMem[pOp->p1]; |
| 75855 | assert( pIn1->flags&MEM_Int ); |
| 75856 | VdbeBranchTaken( pIn1->u.i>0, 2); |
| @@ -75875,27 +75947,63 @@ | |
| 75875 | pc = pOp->p2 - 1; |
| 75876 | } |
| 75877 | break; |
| 75878 | } |
| 75879 | |
| 75880 | /* Opcode: IfZero P1 P2 P3 * * |
| 75881 | ** Synopsis: r[P1]+=P3, if r[P1]==0 goto P2 |
| 75882 | ** |
| 75883 | ** The register P1 must contain an integer. Add literal P3 to the |
| 75884 | ** value in register P1. If the result is exactly 0, jump to P2. |
| 75885 | */ |
| 75886 | case OP_IfZero: { /* jump, in1 */ |
| 75887 | pIn1 = &aMem[pOp->p1]; |
| 75888 | assert( pIn1->flags&MEM_Int ); |
| 75889 | pIn1->u.i += pOp->p3; |
| 75890 | VdbeBranchTaken(pIn1->u.i==0, 2); |
| 75891 | if( pIn1->u.i==0 ){ |
| 75892 | pc = pOp->p2 - 1; |
| 75893 | } |
| 75894 | break; |
| 75895 | } |
| 75896 | |
| 75897 | /* Opcode: AggStep * P2 P3 P4 P5 |
| 75898 | ** Synopsis: accum=r[P3] step(r[P2@P5]) |
| 75899 | ** |
| 75900 | ** Execute the step function for an aggregate. The |
| 75901 | ** function has P5 arguments. P4 is a pointer to the FuncDef |
| @@ -97181,10 +97289,15 @@ | |
| 97181 | ** pExpr points to an expression which implements a function. If |
| 97182 | ** it is appropriate to apply the LIKE optimization to that function |
| 97183 | ** then set aWc[0] through aWc[2] to the wildcard characters and |
| 97184 | ** return TRUE. If the function is not a LIKE-style function then |
| 97185 | ** return FALSE. |
| 97186 | */ |
| 97187 | SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ |
| 97188 | FuncDef *pDef; |
| 97189 | if( pExpr->op!=TK_FUNCTION |
| 97190 | || !pExpr->x.pList |
| @@ -102972,10 +103085,21 @@ | |
| 102972 | } |
| 102973 | |
| 102974 | /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS |
| 102975 | ** connection. If it returns SQLITE_OK, then assume that the VFS |
| 102976 | ** handled the pragma and generate a no-op prepared statement. |
| 102977 | */ |
| 102978 | aFcntl[0] = 0; |
| 102979 | aFcntl[1] = zLeft; |
| 102980 | aFcntl[2] = zRight; |
| 102981 | aFcntl[3] = 0; |
| @@ -103732,34 +103856,46 @@ | |
| 103732 | Index *pIdx; |
| 103733 | Table *pTab; |
| 103734 | pIdx = sqlite3FindIndex(db, zRight, zDb); |
| 103735 | if( pIdx ){ |
| 103736 | int i; |
| 103737 | int mx = pPragma->iArg ? pIdx->nColumn : pIdx->nKeyCol; |
| 103738 | pTab = pIdx->pTable; |
| 103739 | sqlite3VdbeSetNumCols(v, 6); |
| 103740 | pParse->nMem = 6; |
| 103741 | sqlite3CodeVerifySchema(pParse, iDb); |
| 103742 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); |
| 103743 | sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); |
| 103744 | sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); |
| 103745 | sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC); |
| 103746 | sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC); |
| 103747 | sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC); |
| 103748 | for(i=0; i<mx; i++){ |
| 103749 | i16 cnum = pIdx->aiColumn[i]; |
| 103750 | sqlite3VdbeAddOp2(v, OP_Integer, i, 1); |
| 103751 | sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2); |
| 103752 | if( cnum<0 ){ |
| 103753 | sqlite3VdbeAddOp2(v, OP_Null, 0, 3); |
| 103754 | }else{ |
| 103755 | sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); |
| 103756 | } |
| 103757 | sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4); |
| 103758 | sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0); |
| 103759 | sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6); |
| 103760 | sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); |
| 103761 | } |
| 103762 | } |
| 103763 | } |
| 103764 | break; |
| 103765 | |
| @@ -104457,12 +104593,13 @@ | |
| 104457 | #endif |
| 104458 | |
| 104459 | /* |
| 104460 | ** PRAGMA shrink_memory |
| 104461 | ** |
| 104462 | ** This pragma attempts to free as much memory as possible from the |
| 104463 | ** current database connection. |
| 104464 | */ |
| 104465 | case PragTyp_SHRINK_MEMORY: { |
| 104466 | sqlite3_db_release_memory(db); |
| 104467 | break; |
| 104468 | } |
| @@ -104487,12 +104624,16 @@ | |
| 104487 | |
| 104488 | /* |
| 104489 | ** PRAGMA soft_heap_limit |
| 104490 | ** PRAGMA soft_heap_limit = N |
| 104491 | ** |
| 104492 | ** Call sqlite3_soft_heap_limit64(N). Return the result. If N is omitted, |
| 104493 | ** use -1. |
| 104494 | */ |
| 104495 | case PragTyp_SOFT_HEAP_LIMIT: { |
| 104496 | sqlite3_int64 N; |
| 104497 | if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ |
| 104498 | sqlite3_soft_heap_limit64(N); |
| @@ -106065,24 +106206,21 @@ | |
| 106065 | }else{ |
| 106066 | op = OP_IdxInsert; |
| 106067 | } |
| 106068 | sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); |
| 106069 | if( pSelect->iLimit ){ |
| 106070 | int addr1, addr2; |
| 106071 | int iLimit; |
| 106072 | if( pSelect->iOffset ){ |
| 106073 | iLimit = pSelect->iOffset+1; |
| 106074 | }else{ |
| 106075 | iLimit = pSelect->iLimit; |
| 106076 | } |
| 106077 | addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v); |
| 106078 | sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1); |
| 106079 | addr2 = sqlite3VdbeAddOp0(v, OP_Goto); |
| 106080 | sqlite3VdbeJumpHere(v, addr1); |
| 106081 | sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); |
| 106082 | sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); |
| 106083 | sqlite3VdbeJumpHere(v, addr2); |
| 106084 | } |
| 106085 | } |
| 106086 | |
| 106087 | /* |
| 106088 | ** Add code to implement the OFFSET |
| @@ -106475,11 +106613,11 @@ | |
| 106475 | /* Jump to the end of the loop if the LIMIT is reached. Except, if |
| 106476 | ** there is a sorter, in which case the sorter has already limited |
| 106477 | ** the output for us. |
| 106478 | */ |
| 106479 | if( pSort==0 && p->iLimit ){ |
| 106480 | sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); |
| 106481 | } |
| 106482 | } |
| 106483 | |
| 106484 | /* |
| 106485 | ** Allocate a KeyInfo object sufficient for an index of N key columns and |
| @@ -107328,11 +107466,11 @@ | |
| 107328 | } |
| 107329 | }else{ |
| 107330 | sqlite3ExprCode(pParse, p->pLimit, iLimit); |
| 107331 | sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); |
| 107332 | VdbeComment((v, "LIMIT counter")); |
| 107333 | sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak); VdbeCoverage(v); |
| 107334 | } |
| 107335 | if( p->pOffset ){ |
| 107336 | p->iOffset = iOffset = ++pParse->nMem; |
| 107337 | pParse->nMem++; /* Allocate an extra register for limit+offset */ |
| 107338 | sqlite3ExprCode(pParse, p->pOffset, iOffset); |
| @@ -107547,11 +107685,11 @@ | |
| 107547 | addrCont = sqlite3VdbeMakeLabel(v); |
| 107548 | codeOffset(v, regOffset, addrCont); |
| 107549 | selectInnerLoop(pParse, p, p->pEList, iCurrent, |
| 107550 | 0, 0, pDest, addrCont, addrBreak); |
| 107551 | if( regLimit ){ |
| 107552 | sqlite3VdbeAddOp3(v, OP_IfZero, regLimit, addrBreak, -1); |
| 107553 | VdbeCoverage(v); |
| 107554 | } |
| 107555 | sqlite3VdbeResolveLabel(v, addrCont); |
| 107556 | |
| 107557 | /* Execute the recursive SELECT taking the single row in Current as |
| @@ -107772,11 +107910,11 @@ | |
| 107772 | } |
| 107773 | p->pPrior = 0; |
| 107774 | p->iLimit = pPrior->iLimit; |
| 107775 | p->iOffset = pPrior->iOffset; |
| 107776 | if( p->iLimit ){ |
| 107777 | addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit); VdbeCoverage(v); |
| 107778 | VdbeComment((v, "Jump ahead if LIMIT reached")); |
| 107779 | } |
| 107780 | explainSetInteger(iSub2, pParse->iNextSelectId); |
| 107781 | rc = sqlite3Select(pParse, p, &dest); |
| 107782 | testcase( rc!=SQLITE_OK ); |
| @@ -108173,11 +108311,11 @@ | |
| 108173 | } |
| 108174 | |
| 108175 | /* Jump to the end of the loop if the LIMIT is reached. |
| 108176 | */ |
| 108177 | if( p->iLimit ){ |
| 108178 | sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v); |
| 108179 | } |
| 108180 | |
| 108181 | /* Generate the subroutine return |
| 108182 | */ |
| 108183 | sqlite3VdbeResolveLabel(v, iContinue); |
| @@ -114787,10 +114925,12 @@ | |
| 114787 | int addrNxt; /* Jump here to start the next IN combination */ |
| 114788 | int addrSkip; /* Jump here for next iteration of skip-scan */ |
| 114789 | int addrCont; /* Jump here to continue with the next loop cycle */ |
| 114790 | int addrFirst; /* First instruction of interior of the loop */ |
| 114791 | int addrBody; /* Beginning of the body of this loop */ |
| 114792 | u8 iFrom; /* Which entry in the FROM clause */ |
| 114793 | u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ |
| 114794 | int p1, p2; /* Operands of the opcode used to ends the loop */ |
| 114795 | union { /* Information that depends on pWLoop->wsFlags */ |
| 114796 | struct { |
| @@ -114971,11 +115111,11 @@ | |
| 114971 | WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ |
| 114972 | WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ |
| 114973 | } u; |
| 114974 | LogEst truthProb; /* Probability of truth for this expression */ |
| 114975 | u16 eOperator; /* A WO_xx value describing <op> */ |
| 114976 | u8 wtFlags; /* TERM_xxx bit flags. See below */ |
| 114977 | u8 nChild; /* Number of children that must disable us */ |
| 114978 | WhereClause *pWC; /* The clause this term is part of */ |
| 114979 | Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ |
| 114980 | Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ |
| 114981 | }; |
| @@ -114993,10 +115133,13 @@ | |
| 114993 | #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 |
| 114994 | # define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ |
| 114995 | #else |
| 114996 | # define TERM_VNULL 0x00 /* Disabled if not using stat3 */ |
| 114997 | #endif |
| 114998 | |
| 114999 | /* |
| 115000 | ** An instance of the WhereScan object is used as an iterator for locating |
| 115001 | ** terms in the WHERE clause that are useful to the query planner. |
| 115002 | */ |
| @@ -115368,11 +115511,11 @@ | |
| 115368 | ** WARNING: This routine might reallocate the space used to store |
| 115369 | ** WhereTerms. All pointers to WhereTerms should be invalidated after |
| 115370 | ** calling this routine. Such pointers may be reinitialized by referencing |
| 115371 | ** the pWC->a[] array. |
| 115372 | */ |
| 115373 | static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){ |
| 115374 | WhereTerm *pTerm; |
| 115375 | int idx; |
| 115376 | testcase( wtFlags & TERM_VIRTUAL ); |
| 115377 | if( pWC->nTerm>=pWC->nSlot ){ |
| 115378 | WhereTerm *pOld = pWC->a; |
| @@ -115793,11 +115936,15 @@ | |
| 115793 | ** Check to see if the given expression is a LIKE or GLOB operator that |
| 115794 | ** can be optimized using inequality constraints. Return TRUE if it is |
| 115795 | ** so and false if not. |
| 115796 | ** |
| 115797 | ** In order for the operator to be optimizible, the RHS must be a string |
| 115798 | ** literal that does not begin with a wildcard. |
| 115799 | */ |
| 115800 | static int isLikeOrGlob( |
| 115801 | Parse *pParse, /* Parsing and code generating context */ |
| 115802 | Expr *pExpr, /* Test this expression */ |
| 115803 | Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ |
| @@ -115822,11 +115969,11 @@ | |
| 115822 | #endif |
| 115823 | pList = pExpr->x.pList; |
| 115824 | pLeft = pList->a[1].pExpr; |
| 115825 | if( pLeft->op!=TK_COLUMN |
| 115826 | || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT |
| 115827 | || IsVirtual(pLeft->pTab) |
| 115828 | ){ |
| 115829 | /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must |
| 115830 | ** be the name of an indexed column with TEXT affinity. */ |
| 115831 | return 0; |
| 115832 | } |
| @@ -116271,11 +116418,11 @@ | |
| 116271 | Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ |
| 116272 | Bitmask prereqAll; /* Prerequesites of pExpr */ |
| 116273 | Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */ |
| 116274 | Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ |
| 116275 | int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ |
| 116276 | int noCase = 0; /* LIKE/GLOB distinguishes case */ |
| 116277 | int op; /* Top-level operator. pExpr->op */ |
| 116278 | Parse *pParse = pWInfo->pParse; /* Parsing context */ |
| 116279 | sqlite3 *db = pParse->db; /* Database connection */ |
| 116280 | |
| 116281 | if( db->mallocFailed ){ |
| @@ -116409,16 +116556,19 @@ | |
| 116409 | |
| 116410 | #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION |
| 116411 | /* Add constraints to reduce the search space on a LIKE or GLOB |
| 116412 | ** operator. |
| 116413 | ** |
| 116414 | ** A like pattern of the form "x LIKE 'abc%'" is changed into constraints |
| 116415 | ** |
| 116416 | ** x>='abc' AND x<'abd' AND x LIKE 'abc%' |
| 116417 | ** |
| 116418 | ** The last character of the prefix "abc" is incremented to form the |
| 116419 | ** termination condition "abd". |
| 116420 | */ |
| 116421 | if( pWC->op==TK_AND |
| 116422 | && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) |
| 116423 | ){ |
| 116424 | Expr *pLeft; /* LHS of LIKE/GLOB operator */ |
| @@ -116426,13 +116576,29 @@ | |
| 116426 | Expr *pNewExpr1; |
| 116427 | Expr *pNewExpr2; |
| 116428 | int idxNew1; |
| 116429 | int idxNew2; |
| 116430 | Token sCollSeqName; /* Name of collating sequence */ |
| 116431 | |
| 116432 | pLeft = pExpr->x.pList->a[1].pExpr; |
| 116433 | pStr2 = sqlite3ExprDup(db, pStr1, 0); |
| 116434 | if( !db->mallocFailed ){ |
| 116435 | u8 c, *pC; /* Last character before the first wildcard */ |
| 116436 | pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; |
| 116437 | c = *pC; |
| 116438 | if( noCase ){ |
| @@ -116448,23 +116614,23 @@ | |
| 116448 | *pC = c + 1; |
| 116449 | } |
| 116450 | sCollSeqName.z = noCase ? "NOCASE" : "BINARY"; |
| 116451 | sCollSeqName.n = 6; |
| 116452 | pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); |
| 116453 | pNewExpr1 = sqlite3PExpr(pParse, TK_GE, |
| 116454 | sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), |
| 116455 | pStr1, 0); |
| 116456 | transferJoinMarkings(pNewExpr1, pExpr); |
| 116457 | idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); |
| 116458 | testcase( idxNew1==0 ); |
| 116459 | exprAnalyze(pSrc, pWC, idxNew1); |
| 116460 | pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); |
| 116461 | pNewExpr2 = sqlite3PExpr(pParse, TK_LT, |
| 116462 | sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), |
| 116463 | pStr2, 0); |
| 116464 | transferJoinMarkings(pNewExpr2, pExpr); |
| 116465 | idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); |
| 116466 | testcase( idxNew2==0 ); |
| 116467 | exprAnalyze(pSrc, pWC, idxNew2); |
| 116468 | pTerm = &pWC->a[idxTerm]; |
| 116469 | if( isComplete ){ |
| 116470 | markTermAsChild(pWC, idxNew1, idxTerm); |
| @@ -117635,24 +117801,47 @@ | |
| 117635 | ** by indices, we disable them to prevent redundant tests in the inner |
| 117636 | ** loop. We would get the correct results if nothing were ever disabled, |
| 117637 | ** but joins might run a little slower. The trick is to disable as much |
| 117638 | ** as we can without disabling too much. If we disabled in (1), we'd get |
| 117639 | ** the wrong answer. See ticket #813. |
| 117640 | */ |
| 117641 | static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ |
| 117642 | if( pTerm |
| 117643 | && (pTerm->wtFlags & TERM_CODED)==0 |
| 117644 | && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) |
| 117645 | && (pLevel->notReady & pTerm->prereqAll)==0 |
| 117646 | ){ |
| 117647 | pTerm->wtFlags |= TERM_CODED; |
| 117648 | if( pTerm->iParent>=0 ){ |
| 117649 | WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent]; |
| 117650 | if( (--pOther->nChild)==0 ){ |
| 117651 | disableTerm(pLevel, pOther); |
| 117652 | } |
| 117653 | } |
| 117654 | } |
| 117655 | } |
| 117656 | |
| 117657 | /* |
| 117658 | ** Code an OP_Affinity opcode to apply the column affinity string zAff |
| @@ -118132,11 +118321,30 @@ | |
| 118132 | } |
| 118133 | #else |
| 118134 | # define addScanStatus(a, b, c, d) ((void)d) |
| 118135 | #endif |
| 118136 | |
| 118137 | |
| 118138 | |
| 118139 | /* |
| 118140 | ** Generate code for the start of the iLevel-th loop in the WHERE clause |
| 118141 | ** implementation described by pWInfo. |
| 118142 | */ |
| @@ -118466,10 +118674,23 @@ | |
| 118466 | nExtraReg = 1; |
| 118467 | } |
| 118468 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ |
| 118469 | pRangeEnd = pLoop->aLTerm[j++]; |
| 118470 | nExtraReg = 1; |
| 118471 | if( pRangeStart==0 |
| 118472 | && (j = pIdx->aiColumn[nEq])>=0 |
| 118473 | && pIdx->pTable->aCol[j].notNull==0 |
| 118474 | ){ |
| 118475 | bSeekPastNull = 1; |
| @@ -118508,10 +118729,11 @@ | |
| 118508 | /* Seek the index cursor to the start of the range. */ |
| 118509 | nConstraint = nEq; |
| 118510 | if( pRangeStart ){ |
| 118511 | Expr *pRight = pRangeStart->pExpr->pRight; |
| 118512 | sqlite3ExprCode(pParse, pRight, regBase+nEq); |
| 118513 | if( (pRangeStart->wtFlags & TERM_VNULL)==0 |
| 118514 | && sqlite3ExprCanBeNull(pRight) |
| 118515 | ){ |
| 118516 | sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); |
| 118517 | VdbeCoverage(v); |
| @@ -118553,10 +118775,11 @@ | |
| 118553 | nConstraint = nEq; |
| 118554 | if( pRangeEnd ){ |
| 118555 | Expr *pRight = pRangeEnd->pExpr->pRight; |
| 118556 | sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); |
| 118557 | sqlite3ExprCode(pParse, pRight, regBase+nEq); |
| 118558 | if( (pRangeEnd->wtFlags & TERM_VNULL)==0 |
| 118559 | && sqlite3ExprCanBeNull(pRight) |
| 118560 | ){ |
| 118561 | sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); |
| 118562 | VdbeCoverage(v); |
| @@ -118780,11 +119003,12 @@ | |
| 118780 | ** eliminating duplicates from other WHERE clauses, the action for each |
| 118781 | ** sub-WHERE clause is to to invoke the main loop body as a subroutine. |
| 118782 | */ |
| 118783 | wctrlFlags = WHERE_OMIT_OPEN_CLOSE |
| 118784 | | WHERE_FORCE_TABLE |
| 118785 | | WHERE_ONETABLE_ONLY; |
| 118786 | for(ii=0; ii<pOrWc->nTerm; ii++){ |
| 118787 | WhereTerm *pOrTerm = &pOrWc->a[ii]; |
| 118788 | if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ |
| 118789 | WhereInfo *pSubWInfo; /* Info for single OR-term scan */ |
| 118790 | Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ |
| @@ -118942,10 +119166,11 @@ | |
| 118942 | /* Insert code to test every subexpression that can be completely |
| 118943 | ** computed using the current set of tables. |
| 118944 | */ |
| 118945 | for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ |
| 118946 | Expr *pE; |
| 118947 | testcase( pTerm->wtFlags & TERM_VIRTUAL ); |
| 118948 | testcase( pTerm->wtFlags & TERM_CODED ); |
| 118949 | if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; |
| 118950 | if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ |
| 118951 | testcase( pWInfo->untestedTerms==0 |
| @@ -118955,12 +119180,18 @@ | |
| 118955 | } |
| 118956 | pE = pTerm->pExpr; |
| 118957 | assert( pE!=0 ); |
| 118958 | if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ |
| 118959 | continue; |
| 118960 | } |
| 118961 | sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); |
| 118962 | pTerm->wtFlags |= TERM_CODED; |
| 118963 | } |
| 118964 | |
| 118965 | /* Insert code to test for implied constraints based on transitivity |
| 118966 | ** of the "==" operator. |
| @@ -119974,10 +120205,11 @@ | |
| 119974 | rLogSize = estLog(rSize); |
| 119975 | |
| 119976 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX |
| 119977 | /* Automatic indexes */ |
| 119978 | if( !pBuilder->pOrSet |
| 119979 | && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 |
| 119980 | && pSrc->pIndex==0 |
| 119981 | && !pSrc->viaCoroutine |
| 119982 | && !pSrc->notIndexed |
| 119983 | && HasRowid(pTab) |
| @@ -121758,10 +121990,20 @@ | |
| 121758 | if( pLevel->addrSkip ){ |
| 121759 | sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrSkip); |
| 121760 | VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); |
| 121761 | sqlite3VdbeJumpHere(v, pLevel->addrSkip); |
| 121762 | sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); |
| 121763 | } |
| 121764 | if( pLevel->iLeftJoin ){ |
| 121765 | addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); |
| 121766 | assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 |
| 121767 | || (pLoop->wsFlags & WHERE_INDEXED)!=0 ); |
| @@ -126982,30 +127224,32 @@ | |
| 126982 | /* Mutex configuration options are only available in a threadsafe |
| 126983 | ** compile. |
| 126984 | */ |
| 126985 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ |
| 126986 | case SQLITE_CONFIG_SINGLETHREAD: { |
| 126987 | /* Disable all mutexing */ |
| 126988 | sqlite3GlobalConfig.bCoreMutex = 0; |
| 126989 | sqlite3GlobalConfig.bFullMutex = 0; |
| 126990 | break; |
| 126991 | } |
| 126992 | #endif |
| 126993 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ |
| 126994 | case SQLITE_CONFIG_MULTITHREAD: { |
| 126995 | /* Disable mutexing of database connections */ |
| 126996 | /* Enable mutexing of core data structures */ |
| 126997 | sqlite3GlobalConfig.bCoreMutex = 1; |
| 126998 | sqlite3GlobalConfig.bFullMutex = 0; |
| 126999 | break; |
| 127000 | } |
| 127001 | #endif |
| 127002 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ |
| 127003 | case SQLITE_CONFIG_SERIALIZED: { |
| 127004 | /* Enable all mutexing */ |
| 127005 | sqlite3GlobalConfig.bCoreMutex = 1; |
| 127006 | sqlite3GlobalConfig.bFullMutex = 1; |
| 127007 | break; |
| 127008 | } |
| 127009 | #endif |
| 127010 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ |
| 127011 | case SQLITE_CONFIG_MUTEX: { |
| @@ -127113,11 +127357,12 @@ | |
| 127113 | ** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ |
| 127114 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 127115 | case SQLITE_CONFIG_HEAP: { |
| 127116 | /* EVIDENCE-OF: R-19854-42126 There are three arguments to |
| 127117 | ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the |
| 127118 | ** number of bytes in the memory buffer, and the minimum allocation size. */ |
| 127119 | sqlite3GlobalConfig.pHeap = va_arg(ap, void*); |
| 127120 | sqlite3GlobalConfig.nHeap = va_arg(ap, int); |
| 127121 | sqlite3GlobalConfig.mnReq = va_arg(ap, int); |
| 127122 | |
| 127123 | if( sqlite3GlobalConfig.mnReq<1 ){ |
| @@ -127218,11 +127463,13 @@ | |
| 127218 | ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be |
| 127219 | ** silently truncated if necessary so that it does not exceed the |
| 127220 | ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE |
| 127221 | ** compile-time option. |
| 127222 | */ |
| 127223 | if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE; |
| 127224 | if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; |
| 127225 | if( szMmap>mxMmap) szMmap = mxMmap; |
| 127226 | sqlite3GlobalConfig.mxMmap = mxMmap; |
| 127227 | sqlite3GlobalConfig.szMmap = szMmap; |
| 127228 | break; |
| @@ -129062,11 +129309,23 @@ | |
| 129062 | for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&'); |
| 129063 | zFile = sqlite3_malloc(nByte); |
| 129064 | if( !zFile ) return SQLITE_NOMEM; |
| 129065 | |
| 129066 | iIn = 5; |
| 129067 | #ifndef SQLITE_ALLOW_URI_AUTHORITY |
| 129068 | /* Discard the scheme and authority segments of the URI. */ |
| 129069 | if( zUri[5]=='/' && zUri[6]=='/' ){ |
| 129070 | iIn = 7; |
| 129071 | while( zUri[iIn] && zUri[iIn]!='/' ) iIn++; |
| 129072 | if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){ |
| @@ -129505,11 +129764,12 @@ | |
| 129505 | sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); |
| 129506 | |
| 129507 | opendb_out: |
| 129508 | sqlite3_free(zOpen); |
| 129509 | if( db ){ |
| 129510 | assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); |
| 129511 | sqlite3_mutex_leave(db->mutex); |
| 129512 | } |
| 129513 | rc = sqlite3_errcode(db); |
| 129514 | assert( db!=0 || rc==SQLITE_NOMEM ); |
| 129515 | if( rc==SQLITE_NOMEM ){ |
| @@ -130250,21 +130510,21 @@ | |
| 130250 | case SQLITE_TESTCTRL_ISINIT: { |
| 130251 | if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; |
| 130252 | break; |
| 130253 | } |
| 130254 | |
| 130255 | /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); |
| 130256 | ** |
| 130257 | ** This test control is used to create imposter tables. "db" is a pointer |
| 130258 | ** to the database connection. dbName is the database name (ex: "main" or |
| 130259 | ** "temp") which will receive the imposter. "onOff" turns imposter mode on |
| 130260 | ** or off. "tnum" is the root page of the b-tree to which the imposter |
| 130261 | ** table should connect. |
| 130262 | ** |
| 130263 | ** Enable imposter mode only when the schema has already been parsed. Then |
| 130264 | ** run a single CREATE TABLE statement to construct the imposter table in the |
| 130265 | ** parsed schema. Then turn imposter mode back off again. |
| 130266 | ** |
| 130267 | ** If onOff==0 and tnum>0 then reset the schema for all databases, causing |
| 130268 | ** the schema to be reparsed the next time it is needed. This has the |
| 130269 | ** effect of erasing all imposter tables. |
| 130270 | */ |
| 130271 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -1,8 +1,8 @@ | |
| 1 | /****************************************************************************** |
| 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | ** version 3.8.9. By combining all the individual C code files into this |
| 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | ** translation unit. |
| @@ -88,10 +88,48 @@ | |
| 88 | #endif /* _MSVC_H_ */ |
| 89 | |
| 90 | /************** End of msvc.h ************************************************/ |
| 91 | /************** Continuing where we left off in sqliteInt.h ******************/ |
| 92 | |
| 93 | /* |
| 94 | ** Special setup for VxWorks |
| 95 | */ |
| 96 | /************** Include vxworks.h in the middle of sqliteInt.h ***************/ |
| 97 | /************** Begin file vxworks.h *****************************************/ |
| 98 | /* |
| 99 | ** 2015-03-02 |
| 100 | ** |
| 101 | ** The author disclaims copyright to this source code. In place of |
| 102 | ** a legal notice, here is a blessing: |
| 103 | ** |
| 104 | ** May you do good and not evil. |
| 105 | ** May you find forgiveness for yourself and forgive others. |
| 106 | ** May you share freely, never taking more than you give. |
| 107 | ** |
| 108 | ****************************************************************************** |
| 109 | ** |
| 110 | ** This file contains code that is specific to Wind River's VxWorks |
| 111 | */ |
| 112 | #if defined(__RTP__) || defined(_WRS_KERNEL) |
| 113 | /* This is VxWorks. Set up things specially for that OS |
| 114 | */ |
| 115 | #include <vxWorks.h> |
| 116 | #include <pthread.h> /* amalgamator: dontcache */ |
| 117 | #define OS_VXWORKS 1 |
| 118 | #define SQLITE_OS_OTHER 0 |
| 119 | #define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1 |
| 120 | #define SQLITE_OMIT_LOAD_EXTENSION 1 |
| 121 | #define SQLITE_ENABLE_LOCKING_STYLE 0 |
| 122 | #define HAVE_UTIME 1 |
| 123 | #else |
| 124 | /* This is not VxWorks. */ |
| 125 | #define OS_VXWORKS 0 |
| 126 | #endif /* defined(_WRS_KERNEL) */ |
| 127 | |
| 128 | /************** End of vxworks.h *********************************************/ |
| 129 | /************** Continuing where we left off in sqliteInt.h ******************/ |
| 130 | |
| 131 | /* |
| 132 | ** These #defines should enable >2GB file support on POSIX if the |
| 133 | ** underlying operating system supports it. If the OS lacks |
| 134 | ** large file support, or if the OS is windows, these should be no-ops. |
| 135 | ** |
| @@ -276,13 +314,13 @@ | |
| 314 | ** |
| 315 | ** See also: [sqlite3_libversion()], |
| 316 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 317 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 318 | */ |
| 319 | #define SQLITE_VERSION "3.8.9" |
| 320 | #define SQLITE_VERSION_NUMBER 3008009 |
| 321 | #define SQLITE_SOURCE_ID "2015-03-09 10:40:48 e5da5e7d5dc5a3438ced23f1ee83e695abc29c45" |
| 322 | |
| 323 | /* |
| 324 | ** CAPI3REF: Run-Time Library Version Numbers |
| 325 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 326 | ** |
| @@ -925,18 +963,20 @@ | |
| 963 | ** |
| 964 | ** These integer constants are opcodes for the xFileControl method |
| 965 | ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] |
| 966 | ** interface. |
| 967 | ** |
| 968 | ** <ul> |
| 969 | ** <li>[[SQLITE_FCNTL_LOCKSTATE]] |
| 970 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This |
| 971 | ** opcode causes the xFileControl method to write the current state of |
| 972 | ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], |
| 973 | ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) |
| 974 | ** into an integer that the pArg argument points to. This capability |
| 975 | ** is used during testing and is only available when the SQLITE_TEST |
| 976 | ** compile-time option is used. |
| 977 | ** |
| 978 | ** <li>[[SQLITE_FCNTL_SIZE_HINT]] |
| 979 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS |
| 980 | ** layer a hint of how large the database file will grow to be during the |
| 981 | ** current transaction. This hint is not guaranteed to be accurate but it |
| 982 | ** is often close. The underlying VFS might choose to preallocate database |
| @@ -1057,11 +1097,13 @@ | |
| 1097 | ** the error message if the pragma fails. ^If the |
| 1098 | ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal |
| 1099 | ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] |
| 1100 | ** file control returns [SQLITE_OK], then the parser assumes that the |
| 1101 | ** VFS has handled the PRAGMA itself and the parser generates a no-op |
| 1102 | ** prepared statement if result string is NULL, or that returns a copy |
| 1103 | ** of the result string if the string is non-NULL. |
| 1104 | ** ^If the [SQLITE_FCNTL_PRAGMA] file control returns |
| 1105 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means |
| 1106 | ** that the VFS encountered an error while handling the [PRAGMA] and the |
| 1107 | ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] |
| 1108 | ** file control occurs at the beginning of pragma statement analysis and so |
| 1109 | ** it is able to override built-in [PRAGMA] statements. |
| @@ -1916,11 +1958,10 @@ | |
| 1958 | ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE |
| 1959 | ** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is |
| 1960 | ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro |
| 1961 | ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value |
| 1962 | ** that specifies the maximum size of the created heap. |
| 1963 | ** |
| 1964 | ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] |
| 1965 | ** <dt>SQLITE_CONFIG_PCACHE_HDRSZ |
| 1966 | ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which |
| 1967 | ** is a pointer to an integer and writes into that integer the number of extra |
| @@ -3356,20 +3397,18 @@ | |
| 3397 | ** The second argument, "zSql", is the statement to be compiled, encoded |
| 3398 | ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() |
| 3399 | ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() |
| 3400 | ** use UTF-16. |
| 3401 | ** |
| 3402 | ** ^If the nByte argument is negative, then zSql is read up to the |
| 3403 | ** first zero terminator. ^If nByte is positive, then it is the |
| 3404 | ** number of bytes read from zSql. ^If nByte is zero, then no prepared |
| 3405 | ** statement is generated. |
| 3406 | ** If the caller knows that the supplied string is nul-terminated, then |
| 3407 | ** there is a small performance advantage to passing an nByte parameter that |
| 3408 | ** is the number of bytes in the input string <i>including</i> |
| 3409 | ** the nul-terminator. |
| 3410 | ** |
| 3411 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 3412 | ** past the end of the first SQL statement in zSql. These routines only |
| 3413 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| 3414 | ** what remains uncompiled. |
| @@ -4394,12 +4433,12 @@ | |
| 4433 | ** DEPRECATED |
| 4434 | ** |
| 4435 | ** These functions are [deprecated]. In order to maintain |
| 4436 | ** backwards compatibility with older code, these functions continue |
| 4437 | ** to be supported. However, new applications should avoid |
| 4438 | ** the use of these functions. To encourage programmers to avoid |
| 4439 | ** these functions, we will not explain what they do. |
| 4440 | */ |
| 4441 | #ifndef SQLITE_OMIT_DEPRECATED |
| 4442 | SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); |
| 4443 | SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); |
| 4444 | SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); |
| @@ -7157,24 +7196,24 @@ | |
| 7196 | ** |
| 7197 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 7198 | ** is not a permanent error and does not affect the return value of |
| 7199 | ** sqlite3_backup_finish(). |
| 7200 | ** |
| 7201 | ** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] |
| 7202 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 7203 | ** |
| 7204 | ** ^The sqlite3_backup_remaining() routine returns the number of pages still |
| 7205 | ** to be backed up at the conclusion of the most recent sqlite3_backup_step(). |
| 7206 | ** ^The sqlite3_backup_pagecount() routine returns the total number of pages |
| 7207 | ** in the source database at the conclusion of the most recent |
| 7208 | ** sqlite3_backup_step(). |
| 7209 | ** ^(The values returned by these functions are only updated by |
| 7210 | ** sqlite3_backup_step(). If the source database is modified in a way that |
| 7211 | ** changes the size of the source database or the number of pages remaining, |
| 7212 | ** those changes are not reflected in the output of sqlite3_backup_pagecount() |
| 7213 | ** and sqlite3_backup_remaining() until after the next |
| 7214 | ** sqlite3_backup_step().)^ |
| 7215 | ** |
| 7216 | ** <b>Concurrent Usage of Database Handles</b> |
| 7217 | ** |
| 7218 | ** ^The source [database connection] may be used by the application for other |
| 7219 | ** purposes while a backup operation is underway or being initialized. |
| @@ -8018,19 +8057,21 @@ | |
| 8057 | #ifndef SQLITE_MAX_FUNCTION_ARG |
| 8058 | # define SQLITE_MAX_FUNCTION_ARG 127 |
| 8059 | #endif |
| 8060 | |
| 8061 | /* |
| 8062 | ** The suggested maximum number of in-memory pages to use for |
| 8063 | ** the main database table and for temporary tables. |
| 8064 | ** |
| 8065 | ** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size |
| 8066 | ** is 2000 pages. |
| 8067 | ** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be |
| 8068 | ** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options. |
| 8069 | */ |
| 8070 | #ifndef SQLITE_DEFAULT_CACHE_SIZE |
| 8071 | # define SQLITE_DEFAULT_CACHE_SIZE 2000 |
| 8072 | #endif |
| 8073 | |
| 8074 | /* |
| 8075 | ** The default number of frames to accumulate in the log file before |
| 8076 | ** checkpointing the database in WAL mode. |
| 8077 | */ |
| @@ -9733,27 +9774,29 @@ | |
| 9774 | #define OP_FkCounter 134 /* synopsis: fkctr[P1]+=P2 */ |
| 9775 | #define OP_FkIfZero 135 /* synopsis: if fkctr[P1]==0 goto P2 */ |
| 9776 | #define OP_MemMax 136 /* synopsis: r[P1]=max(r[P1],r[P2]) */ |
| 9777 | #define OP_IfPos 137 /* synopsis: if r[P1]>0 goto P2 */ |
| 9778 | #define OP_IfNeg 138 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */ |
| 9779 | #define OP_IfNotZero 139 /* synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 */ |
| 9780 | #define OP_DecrJumpZero 140 /* synopsis: if (--r[P1])==0 goto P2 */ |
| 9781 | #define OP_JumpZeroIncr 141 /* synopsis: if (r[P1]++)==0 ) goto P2 */ |
| 9782 | #define OP_AggFinal 142 /* synopsis: accum=r[P1] N=P2 */ |
| 9783 | #define OP_IncrVacuum 143 |
| 9784 | #define OP_Expire 144 |
| 9785 | #define OP_TableLock 145 /* synopsis: iDb=P1 root=P2 write=P3 */ |
| 9786 | #define OP_VBegin 146 |
| 9787 | #define OP_VCreate 147 |
| 9788 | #define OP_VDestroy 148 |
| 9789 | #define OP_VOpen 149 |
| 9790 | #define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */ |
| 9791 | #define OP_VNext 151 |
| 9792 | #define OP_VRename 152 |
| 9793 | #define OP_Pagecount 153 |
| 9794 | #define OP_MaxPgcnt 154 |
| 9795 | #define OP_Init 155 /* synopsis: Start at P2 */ |
| 9796 | #define OP_Noop 156 |
| 9797 | #define OP_Explain 157 |
| 9798 | |
| 9799 | |
| 9800 | /* Properties such as "out2" or "jump" that are specified in |
| 9801 | ** comments following the "case" for each opcode in the vdbe.c |
| 9802 | ** are encoded into bitvectors as follows: |
| @@ -9781,13 +9824,13 @@ | |
| 9824 | /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\ |
| 9825 | /* 104 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x00,\ |
| 9826 | /* 112 */ 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,\ |
| 9827 | /* 120 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ |
| 9828 | /* 128 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x02, 0x00, 0x01,\ |
| 9829 | /* 136 */ 0x08, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x01,\ |
| 9830 | /* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\ |
| 9831 | /* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,} |
| 9832 | |
| 9833 | /************** End of opcodes.h *********************************************/ |
| 9834 | /************** Continuing where we left off in vdbe.h ***********************/ |
| 9835 | |
| 9836 | /* |
| @@ -12022,11 +12065,11 @@ | |
| 12065 | #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ |
| 12066 | #define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */ |
| 12067 | #define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ |
| 12068 | #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ |
| 12069 | #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ |
| 12070 | #define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */ |
| 12071 | #define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ |
| 12072 | #define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ |
| 12073 | #define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ |
| 12074 | #define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ |
| 12075 | #define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ |
| @@ -24969,27 +25012,29 @@ | |
| 25012 | /* 134 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), |
| 25013 | /* 135 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), |
| 25014 | /* 136 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), |
| 25015 | /* 137 */ "IfPos" OpHelp("if r[P1]>0 goto P2"), |
| 25016 | /* 138 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"), |
| 25017 | /* 139 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]+=P3, goto P2"), |
| 25018 | /* 140 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), |
| 25019 | /* 141 */ "JumpZeroIncr" OpHelp("if (r[P1]++)==0 ) goto P2"), |
| 25020 | /* 142 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), |
| 25021 | /* 143 */ "IncrVacuum" OpHelp(""), |
| 25022 | /* 144 */ "Expire" OpHelp(""), |
| 25023 | /* 145 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), |
| 25024 | /* 146 */ "VBegin" OpHelp(""), |
| 25025 | /* 147 */ "VCreate" OpHelp(""), |
| 25026 | /* 148 */ "VDestroy" OpHelp(""), |
| 25027 | /* 149 */ "VOpen" OpHelp(""), |
| 25028 | /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), |
| 25029 | /* 151 */ "VNext" OpHelp(""), |
| 25030 | /* 152 */ "VRename" OpHelp(""), |
| 25031 | /* 153 */ "Pagecount" OpHelp(""), |
| 25032 | /* 154 */ "MaxPgcnt" OpHelp(""), |
| 25033 | /* 155 */ "Init" OpHelp("Start at P2"), |
| 25034 | /* 156 */ "Noop" OpHelp(""), |
| 25035 | /* 157 */ "Explain" OpHelp(""), |
| 25036 | }; |
| 25037 | return azName[i]; |
| 25038 | } |
| 25039 | #endif |
| 25040 | |
| @@ -25065,22 +25110,10 @@ | |
| 25110 | # else |
| 25111 | # define SQLITE_ENABLE_LOCKING_STYLE 0 |
| 25112 | # endif |
| 25113 | #endif |
| 25114 | |
| 25115 | /* |
| 25116 | ** standard include files. |
| 25117 | */ |
| 25118 | #include <sys/types.h> |
| 25119 | #include <sys/stat.h> |
| @@ -25091,22 +25124,23 @@ | |
| 25124 | #include <errno.h> |
| 25125 | #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
| 25126 | # include <sys/mman.h> |
| 25127 | #endif |
| 25128 | |
| 25129 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 25130 | # include <sys/ioctl.h> |
| 25131 | # include <sys/file.h> |
| 25132 | # include <sys/param.h> |
| 25133 | #endif /* SQLITE_ENABLE_LOCKING_STYLE */ |
| 25134 | |
| 25135 | #if OS_VXWORKS |
| 25136 | /* # include <sys/ioctl.h> */ |
| 25137 | # include <semaphore.h> |
| 25138 | # include <limits.h> |
| 25139 | #endif /* OS_VXWORKS */ |
| 25140 | |
| 25141 | #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE |
| 25142 | # include <sys/mount.h> |
| 25143 | #endif |
| 25144 | |
| 25145 | #ifdef HAVE_UTIME |
| 25146 | # include <utime.h> |
| @@ -25142,10 +25176,14 @@ | |
| 25176 | |
| 25177 | /* |
| 25178 | ** Maximum supported path-length. |
| 25179 | */ |
| 25180 | #define MAX_PATHNAME 512 |
| 25181 | |
| 25182 | /* Always cast the getpid() return type for compatibility with |
| 25183 | ** kernel modules in VxWorks. */ |
| 25184 | #define osGetpid(X) (pid_t)getpid() |
| 25185 | |
| 25186 | /* |
| 25187 | ** Only set the lastErrno if the error code is a real error and not |
| 25188 | ** a normal expected return code of SQLITE_BUSY or SQLITE_OK |
| 25189 | */ |
| @@ -25231,11 +25269,11 @@ | |
| 25269 | |
| 25270 | /* This variable holds the process id (pid) from when the xRandomness() |
| 25271 | ** method was called. If xOpen() is called from a different process id, |
| 25272 | ** indicating that a fork() has occurred, the PRNG will be reset. |
| 25273 | */ |
| 25274 | static pid_t randomnessPid = 0; |
| 25275 | |
| 25276 | /* |
| 25277 | ** Allowed values for the unixFile.ctrlFlags bitmask: |
| 25278 | */ |
| 25279 | #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
| @@ -25587,11 +25625,11 @@ | |
| 25625 | #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) |
| 25626 | |
| 25627 | { "read", (sqlite3_syscall_ptr)read, 0 }, |
| 25628 | #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) |
| 25629 | |
| 25630 | #if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE |
| 25631 | { "pread", (sqlite3_syscall_ptr)pread, 0 }, |
| 25632 | #else |
| 25633 | { "pread", (sqlite3_syscall_ptr)0, 0 }, |
| 25634 | #endif |
| 25635 | #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) |
| @@ -25604,11 +25642,11 @@ | |
| 25642 | #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) |
| 25643 | |
| 25644 | { "write", (sqlite3_syscall_ptr)write, 0 }, |
| 25645 | #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) |
| 25646 | |
| 25647 | #if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE |
| 25648 | { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, |
| 25649 | #else |
| 25650 | { "pwrite", (sqlite3_syscall_ptr)0, 0 }, |
| 25651 | #endif |
| 25652 | #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| @@ -26743,11 +26781,12 @@ | |
| 26781 | int tErrno = 0; |
| 26782 | |
| 26783 | assert( pFile ); |
| 26784 | OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, |
| 26785 | azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
| 26786 | azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared, |
| 26787 | osGetpid())); |
| 26788 | |
| 26789 | /* If there is already a lock of this type or more restrictive on the |
| 26790 | ** unixFile, do nothing. Don't use the end_lock: exit path, as |
| 26791 | ** unixEnterMutex() hasn't been called yet. |
| 26792 | */ |
| @@ -26951,11 +26990,11 @@ | |
| 26990 | int rc = SQLITE_OK; |
| 26991 | |
| 26992 | assert( pFile ); |
| 26993 | OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, |
| 26994 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
| 26995 | osGetpid())); |
| 26996 | |
| 26997 | assert( eFileLock<=SHARED_LOCK ); |
| 26998 | if( pFile->eFileLock<=eFileLock ){ |
| 26999 | return SQLITE_OK; |
| 27000 | } |
| @@ -27378,11 +27417,11 @@ | |
| 27417 | char *zLockFile = (char *)pFile->lockingContext; |
| 27418 | int rc; |
| 27419 | |
| 27420 | assert( pFile ); |
| 27421 | OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, |
| 27422 | pFile->eFileLock, osGetpid())); |
| 27423 | assert( eFileLock<=SHARED_LOCK ); |
| 27424 | |
| 27425 | /* no-op if possible */ |
| 27426 | if( pFile->eFileLock==eFileLock ){ |
| 27427 | return SQLITE_OK; |
| @@ -27441,14 +27480,13 @@ | |
| 27480 | ** a single exclusive lock. In other words, SHARED, RESERVED, and |
| 27481 | ** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite |
| 27482 | ** still works when you do this, but concurrency is reduced since |
| 27483 | ** only a single process can be reading the database at a time. |
| 27484 | ** |
| 27485 | ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off |
| 27486 | */ |
| 27487 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 27488 | |
| 27489 | /* |
| 27490 | ** Retry flock() calls that fail with EINTR |
| 27491 | */ |
| 27492 | #ifdef EINTR |
| @@ -27597,11 +27635,11 @@ | |
| 27635 | static int flockUnlock(sqlite3_file *id, int eFileLock) { |
| 27636 | unixFile *pFile = (unixFile*)id; |
| 27637 | |
| 27638 | assert( pFile ); |
| 27639 | OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, |
| 27640 | pFile->eFileLock, osGetpid())); |
| 27641 | assert( eFileLock<=SHARED_LOCK ); |
| 27642 | |
| 27643 | /* no-op if possible */ |
| 27644 | if( pFile->eFileLock==eFileLock ){ |
| 27645 | return SQLITE_OK; |
| @@ -27658,11 +27696,11 @@ | |
| 27696 | ** This routine checks if there is a RESERVED lock held on the specified |
| 27697 | ** file by this or any other process. If such a lock is held, set *pResOut |
| 27698 | ** to a non-zero value otherwise *pResOut is set to zero. The return value |
| 27699 | ** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
| 27700 | */ |
| 27701 | static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) { |
| 27702 | int rc = SQLITE_OK; |
| 27703 | int reserved = 0; |
| 27704 | unixFile *pFile = (unixFile*)id; |
| 27705 | |
| 27706 | SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
| @@ -27725,11 +27763,11 @@ | |
| 27763 | ** access the file. |
| 27764 | ** |
| 27765 | ** This routine will only increase a lock. Use the sqlite3OsUnlock() |
| 27766 | ** routine to lower a locking level. |
| 27767 | */ |
| 27768 | static int semXLock(sqlite3_file *id, int eFileLock) { |
| 27769 | unixFile *pFile = (unixFile*)id; |
| 27770 | sem_t *pSem = pFile->pInode->pSem; |
| 27771 | int rc = SQLITE_OK; |
| 27772 | |
| 27773 | /* if we already have a lock, it is exclusive. |
| @@ -27758,18 +27796,18 @@ | |
| 27796 | ** must be either NO_LOCK or SHARED_LOCK. |
| 27797 | ** |
| 27798 | ** If the locking level of the file descriptor is already at or below |
| 27799 | ** the requested locking level, this routine is a no-op. |
| 27800 | */ |
| 27801 | static int semXUnlock(sqlite3_file *id, int eFileLock) { |
| 27802 | unixFile *pFile = (unixFile*)id; |
| 27803 | sem_t *pSem = pFile->pInode->pSem; |
| 27804 | |
| 27805 | assert( pFile ); |
| 27806 | assert( pSem ); |
| 27807 | OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, |
| 27808 | pFile->eFileLock, osGetpid())); |
| 27809 | assert( eFileLock<=SHARED_LOCK ); |
| 27810 | |
| 27811 | /* no-op if possible */ |
| 27812 | if( pFile->eFileLock==eFileLock ){ |
| 27813 | return SQLITE_OK; |
| @@ -27795,14 +27833,14 @@ | |
| 27833 | } |
| 27834 | |
| 27835 | /* |
| 27836 | ** Close a file. |
| 27837 | */ |
| 27838 | static int semXClose(sqlite3_file *id) { |
| 27839 | if( id ){ |
| 27840 | unixFile *pFile = (unixFile*)id; |
| 27841 | semXUnlock(id, NO_LOCK); |
| 27842 | assert( pFile ); |
| 27843 | unixEnterMutex(); |
| 27844 | releaseInodeInfo(pFile); |
| 27845 | unixLeaveMutex(); |
| 27846 | closeUnixFile(id); |
| @@ -27979,11 +28017,11 @@ | |
| 28017 | afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; |
| 28018 | |
| 28019 | assert( pFile ); |
| 28020 | OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, |
| 28021 | azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
| 28022 | azFileLock(pInode->eFileLock), pInode->nShared , osGetpid())); |
| 28023 | |
| 28024 | /* If there is already a lock of this type or more restrictive on the |
| 28025 | ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as |
| 28026 | ** unixEnterMutex() hasn't been called yet. |
| 28027 | */ |
| @@ -28165,11 +28203,11 @@ | |
| 28203 | #endif |
| 28204 | |
| 28205 | assert( pFile ); |
| 28206 | OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, |
| 28207 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
| 28208 | osGetpid())); |
| 28209 | |
| 28210 | assert( eFileLock<=SHARED_LOCK ); |
| 28211 | if( pFile->eFileLock<=eFileLock ){ |
| 28212 | return SQLITE_OK; |
| 28213 | } |
| @@ -29204,11 +29242,13 @@ | |
| 29242 | ** |
| 29243 | ** This function should not be called directly by other code in this file. |
| 29244 | ** Instead, it should be called via macro osGetpagesize(). |
| 29245 | */ |
| 29246 | static int unixGetpagesize(void){ |
| 29247 | #if OS_VXWORKS |
| 29248 | return 1024; |
| 29249 | #elif defined(_BSD_SOURCE) |
| 29250 | return getpagesize(); |
| 29251 | #else |
| 29252 | return (int)sysconf(_SC_PAGESIZE); |
| 29253 | #endif |
| 29254 | } |
| @@ -29833,11 +29873,11 @@ | |
| 29873 | } |
| 29874 | } |
| 29875 | } |
| 29876 | sqlite3_mutex_leave(pShmNode->mutex); |
| 29877 | OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", |
| 29878 | p->id, osGetpid(), p->sharedMask, p->exclMask)); |
| 29879 | return rc; |
| 29880 | } |
| 29881 | |
| 29882 | /* |
| 29883 | ** Implement a memory barrier or memory fence on shared memory. |
| @@ -30236,11 +30276,11 @@ | |
| 30276 | dotlockUnlock, /* xUnlock method */ |
| 30277 | dotlockCheckReservedLock, /* xCheckReservedLock method */ |
| 30278 | 0 /* xShmMap method */ |
| 30279 | ) |
| 30280 | |
| 30281 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 30282 | IOMETHODS( |
| 30283 | flockIoFinder, /* Finder function name */ |
| 30284 | flockIoMethods, /* sqlite3_io_methods object name */ |
| 30285 | 1, /* shared memory is disabled */ |
| 30286 | flockClose, /* xClose method */ |
| @@ -30254,14 +30294,14 @@ | |
| 30294 | #if OS_VXWORKS |
| 30295 | IOMETHODS( |
| 30296 | semIoFinder, /* Finder function name */ |
| 30297 | semIoMethods, /* sqlite3_io_methods object name */ |
| 30298 | 1, /* shared memory is disabled */ |
| 30299 | semXClose, /* xClose method */ |
| 30300 | semXLock, /* xLock method */ |
| 30301 | semXUnlock, /* xUnlock method */ |
| 30302 | semXCheckReservedLock, /* xCheckReservedLock method */ |
| 30303 | 0 /* xShmMap method */ |
| 30304 | ) |
| 30305 | #endif |
| 30306 | |
| 30307 | #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
| @@ -30381,19 +30421,17 @@ | |
| 30421 | static const sqlite3_io_methods |
| 30422 | *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; |
| 30423 | |
| 30424 | #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
| 30425 | |
| 30426 | #if OS_VXWORKS |
| 30427 | /* |
| 30428 | ** This "finder" function for VxWorks checks to see if posix advisory |
| 30429 | ** locking works. If it does, then that is what is used. If it does not |
| 30430 | ** work, then fallback to named semaphore locking. |
| 30431 | */ |
| 30432 | static const sqlite3_io_methods *vxworksIoFinderImpl( |
| 30433 | const char *filePath, /* name of the database file */ |
| 30434 | unixFile *pNew /* the open file object */ |
| 30435 | ){ |
| 30436 | struct flock lockInfo; |
| 30437 | |
| @@ -30415,13 +30453,13 @@ | |
| 30453 | }else{ |
| 30454 | return &semIoMethods; |
| 30455 | } |
| 30456 | } |
| 30457 | static const sqlite3_io_methods |
| 30458 | *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl; |
| 30459 | |
| 30460 | #endif /* OS_VXWORKS */ |
| 30461 | |
| 30462 | /* |
| 30463 | ** An abstract type for a pointer to an IO method finder function: |
| 30464 | */ |
| 30465 | typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); |
| @@ -30930,12 +30968,12 @@ | |
| 30968 | /* Detect a pid change and reset the PRNG. There is a race condition |
| 30969 | ** here such that two or more threads all trying to open databases at |
| 30970 | ** the same instant might all reset the PRNG. But multiple resets |
| 30971 | ** are harmless. |
| 30972 | */ |
| 30973 | if( randomnessPid!=osGetpid() ){ |
| 30974 | randomnessPid = osGetpid(); |
| 30975 | sqlite3_randomness(0,0); |
| 30976 | } |
| 30977 | |
| 30978 | memset(p, 0, sizeof(unixFile)); |
| 30979 | |
| @@ -31322,11 +31360,11 @@ | |
| 31360 | ** When testing, initializing zBuf[] to zero is all we do. That means |
| 31361 | ** that we always use the same random number sequence. This makes the |
| 31362 | ** tests repeatable. |
| 31363 | */ |
| 31364 | memset(zBuf, 0, nBuf); |
| 31365 | randomnessPid = osGetpid(); |
| 31366 | #if !defined(SQLITE_TEST) |
| 31367 | { |
| 31368 | int fd, got; |
| 31369 | fd = robust_open("/dev/urandom", O_RDONLY, 0); |
| 31370 | if( fd<0 ){ |
| @@ -31643,11 +31681,11 @@ | |
| 31681 | #else |
| 31682 | # ifdef _CS_DARWIN_USER_TEMP_DIR |
| 31683 | { |
| 31684 | if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ |
| 31685 | OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", |
| 31686 | lPath, errno, osGetpid())); |
| 31687 | return SQLITE_IOERR_LOCK; |
| 31688 | } |
| 31689 | len = strlcat(lPath, "sqliteplocks", maxLen); |
| 31690 | } |
| 31691 | # else |
| @@ -31665,11 +31703,11 @@ | |
| 31703 | char c = dbPath[i]; |
| 31704 | lPath[i+len] = (c=='/')?'_':c; |
| 31705 | } |
| 31706 | lPath[i+len]='\0'; |
| 31707 | strlcat(lPath, ":auto:", maxLen); |
| 31708 | OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, osGetpid())); |
| 31709 | return SQLITE_OK; |
| 31710 | } |
| 31711 | |
| 31712 | /* |
| 31713 | ** Creates the lock file and any missing directories in lockPath |
| @@ -31692,20 +31730,20 @@ | |
| 31730 | if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ |
| 31731 | int err=errno; |
| 31732 | if( err!=EEXIST ) { |
| 31733 | OSTRACE(("CREATELOCKPATH FAILED creating %s, " |
| 31734 | "'%s' proxy lock path=%s pid=%d\n", |
| 31735 | buf, strerror(err), lockPath, osGetpid())); |
| 31736 | return err; |
| 31737 | } |
| 31738 | } |
| 31739 | } |
| 31740 | start=i+1; |
| 31741 | } |
| 31742 | buf[i] = lockPath[i]; |
| 31743 | } |
| 31744 | OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, osGetpid())); |
| 31745 | return 0; |
| 31746 | } |
| 31747 | |
| 31748 | /* |
| 31749 | ** Create a new VFS file descriptor (stored in memory obtained from |
| @@ -32006,11 +32044,12 @@ | |
| 32044 | int readLen = 0; |
| 32045 | int tryOldLockPath = 0; |
| 32046 | int forceNewLockPath = 0; |
| 32047 | |
| 32048 | OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, |
| 32049 | (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), |
| 32050 | osGetpid())); |
| 32051 | |
| 32052 | rc = proxyGetHostID(myHostID, &pError); |
| 32053 | if( (rc&0xff)==SQLITE_IOERR ){ |
| 32054 | storeLastErrno(pFile, pError); |
| 32055 | goto end_takeconch; |
| @@ -32216,11 +32255,11 @@ | |
| 32255 | |
| 32256 | pCtx = (proxyLockingContext *)pFile->lockingContext; |
| 32257 | conchFile = pCtx->conchFile; |
| 32258 | OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, |
| 32259 | (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), |
| 32260 | osGetpid())); |
| 32261 | if( pCtx->conchHeld>0 ){ |
| 32262 | rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); |
| 32263 | } |
| 32264 | pCtx->conchHeld = 0; |
| 32265 | OSTRACE(("RELEASECONCH %d %s\n", conchFile->h, |
| @@ -32358,11 +32397,11 @@ | |
| 32397 | }else{ |
| 32398 | lockPath=(char *)path; |
| 32399 | } |
| 32400 | |
| 32401 | OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, |
| 32402 | (lockPath ? lockPath : ":auto:"), osGetpid())); |
| 32403 | |
| 32404 | pCtx = sqlite3_malloc( sizeof(*pCtx) ); |
| 32405 | if( pCtx==0 ){ |
| 32406 | return SQLITE_NOMEM; |
| 32407 | } |
| @@ -32699,26 +32738,28 @@ | |
| 32738 | ** Note that the sqlite3_vfs.pNext field of the VFS object is modified |
| 32739 | ** by the SQLite core when the VFS is registered. So the following |
| 32740 | ** array cannot be const. |
| 32741 | */ |
| 32742 | static sqlite3_vfs aVfs[] = { |
| 32743 | #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
| 32744 | UNIXVFS("unix", autolockIoFinder ), |
| 32745 | #elif OS_VXWORKS |
| 32746 | UNIXVFS("unix", vxworksIoFinder ), |
| 32747 | #else |
| 32748 | UNIXVFS("unix", posixIoFinder ), |
| 32749 | #endif |
| 32750 | UNIXVFS("unix-none", nolockIoFinder ), |
| 32751 | UNIXVFS("unix-dotfile", dotlockIoFinder ), |
| 32752 | UNIXVFS("unix-excl", posixIoFinder ), |
| 32753 | #if OS_VXWORKS |
| 32754 | UNIXVFS("unix-namedsem", semIoFinder ), |
| 32755 | #endif |
| 32756 | #if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS |
| 32757 | UNIXVFS("unix-posix", posixIoFinder ), |
| 32758 | #endif |
| 32759 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 32760 | UNIXVFS("unix-flock", flockIoFinder ), |
| 32761 | #endif |
| 32762 | #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
| 32763 | UNIXVFS("unix-afp", afpIoFinder ), |
| 32764 | UNIXVFS("unix-nfs", nfsIoFinder ), |
| 32765 | UNIXVFS("unix-proxy", proxyIoFinder ), |
| @@ -39072,16 +39113,24 @@ | |
| 39113 | sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); |
| 39114 | } |
| 39115 | } |
| 39116 | |
| 39117 | /* |
| 39118 | ** Compute the number of pages of cache requested. p->szCache is the |
| 39119 | ** cache size requested by the "PRAGMA cache_size" statement. |
| 39120 | ** |
| 39121 | ** |
| 39122 | */ |
| 39123 | static int numberOfCachePages(PCache *p){ |
| 39124 | if( p->szCache>=0 ){ |
| 39125 | /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the |
| 39126 | ** suggested cache size is set to N. */ |
| 39127 | return p->szCache; |
| 39128 | }else{ |
| 39129 | /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then |
| 39130 | ** the number of cache pages is adjusted to use approximately abs(N*1024) |
| 39131 | ** bytes of memory. */ |
| 39132 | return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); |
| 39133 | } |
| 39134 | } |
| 39135 | |
| 39136 | /*************************************************** General Interfaces ****** |
| @@ -68615,10 +68664,14 @@ | |
| 68664 | } |
| 68665 | SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ |
| 68666 | return sqlite3ValueText(pVal, SQLITE_UTF16LE); |
| 68667 | } |
| 68668 | #endif /* SQLITE_OMIT_UTF16 */ |
| 68669 | /* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five |
| 68670 | ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating |
| 68671 | ** point number string BLOB NULL |
| 68672 | */ |
| 68673 | SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ |
| 68674 | static const u8 aType[] = { |
| 68675 | SQLITE_BLOB, /* 0x00 */ |
| 68676 | SQLITE_NULL, /* 0x01 */ |
| 68677 | SQLITE_TEXT, /* 0x02 */ |
| @@ -71290,11 +71343,11 @@ | |
| 71343 | |
| 71344 | /* Opcode: String8 * P2 * P4 * |
| 71345 | ** Synopsis: r[P2]='P4' |
| 71346 | ** |
| 71347 | ** P4 points to a nul terminated UTF-8 string. This opcode is transformed |
| 71348 | ** into a String opcode before it is executed for the first time. During |
| 71349 | ** this transformation, the length of string P4 is computed and stored |
| 71350 | ** as the P1 parameter. |
| 71351 | */ |
| 71352 | case OP_String8: { /* same as TK_STRING, out2-prerelease */ |
| 71353 | assert( pOp->p4.z!=0 ); |
| @@ -71322,22 +71375,34 @@ | |
| 71375 | goto too_big; |
| 71376 | } |
| 71377 | /* Fall through to the next case, OP_String */ |
| 71378 | } |
| 71379 | |
| 71380 | /* Opcode: String P1 P2 P3 P4 P5 |
| 71381 | ** Synopsis: r[P2]='P4' (len=P1) |
| 71382 | ** |
| 71383 | ** The string value P4 of length P1 (bytes) is stored in register P2. |
| 71384 | ** |
| 71385 | ** If P5!=0 and the content of register P3 is greater than zero, then |
| 71386 | ** the datatype of the register P2 is converted to BLOB. The content is |
| 71387 | ** the same sequence of bytes, it is merely interpreted as a BLOB instead |
| 71388 | ** of a string, as if it had been CAST. |
| 71389 | */ |
| 71390 | case OP_String: { /* out2-prerelease */ |
| 71391 | assert( pOp->p4.z!=0 ); |
| 71392 | pOut->flags = MEM_Str|MEM_Static|MEM_Term; |
| 71393 | pOut->z = pOp->p4.z; |
| 71394 | pOut->n = pOp->p1; |
| 71395 | pOut->enc = encoding; |
| 71396 | UPDATE_MAX_BLOBSIZE(pOut); |
| 71397 | if( pOp->p5 ){ |
| 71398 | assert( pOp->p3>0 ); |
| 71399 | assert( pOp->p3<=(p->nMem-p->nCursor) ); |
| 71400 | pIn3 = &aMem[pOp->p3]; |
| 71401 | assert( pIn3->flags & MEM_Int ); |
| 71402 | if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; |
| 71403 | } |
| 71404 | break; |
| 71405 | } |
| 71406 | |
| 71407 | /* Opcode: Null P1 P2 P3 * * |
| 71408 | ** Synopsis: r[P2..P3]=NULL |
| @@ -73325,11 +73390,16 @@ | |
| 73390 | ** the value of this counter needs to be restored too. */ |
| 73391 | p->nStmtDefCons = db->nDeferredCons; |
| 73392 | p->nStmtDefImmCons = db->nDeferredImmCons; |
| 73393 | } |
| 73394 | |
| 73395 | /* Gather the schema version number for checking: |
| 73396 | ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite |
| 73397 | ** each time a query is executed to ensure that the internal cache of the |
| 73398 | ** schema used when compiling the SQL query matches the schema of the |
| 73399 | ** database against which the compiled query is actually executed. |
| 73400 | */ |
| 73401 | sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); |
| 73402 | iGen = db->aDb[pOp->p1].pSchema->iGeneration; |
| 73403 | }else{ |
| 73404 | iGen = iMeta = 0; |
| 73405 | } |
| @@ -75843,14 +75913,16 @@ | |
| 75913 | #endif /* SQLITE_OMIT_AUTOINCREMENT */ |
| 75914 | |
| 75915 | /* Opcode: IfPos P1 P2 * * * |
| 75916 | ** Synopsis: if r[P1]>0 goto P2 |
| 75917 | ** |
| 75918 | ** Register P1 must contain an integer. |
| 75919 | ** If the value of register P1 is 1 or greater, jump to P2 and |
| 75920 | ** add the literal value P3 to register P1. |
| 75921 | ** |
| 75922 | ** If the initial value of register P1 is less than 1, then the |
| 75923 | ** value is unchanged and control passes through to the next instruction. |
| 75924 | */ |
| 75925 | case OP_IfPos: { /* jump, in1 */ |
| 75926 | pIn1 = &aMem[pOp->p1]; |
| 75927 | assert( pIn1->flags&MEM_Int ); |
| 75928 | VdbeBranchTaken( pIn1->u.i>0, 2); |
| @@ -75875,27 +75947,63 @@ | |
| 75947 | pc = pOp->p2 - 1; |
| 75948 | } |
| 75949 | break; |
| 75950 | } |
| 75951 | |
| 75952 | /* Opcode: IfNotZero P1 P2 P3 * * |
| 75953 | ** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 |
| 75954 | ** |
| 75955 | ** Register P1 must contain an integer. If the content of register P1 is |
| 75956 | ** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is |
| 75957 | ** initially zero, leave it unchanged and fall through. |
| 75958 | */ |
| 75959 | case OP_IfNotZero: { /* jump, in1 */ |
| 75960 | pIn1 = &aMem[pOp->p1]; |
| 75961 | assert( pIn1->flags&MEM_Int ); |
| 75962 | VdbeBranchTaken(pIn1->u.i<0, 2); |
| 75963 | if( pIn1->u.i ){ |
| 75964 | pIn1->u.i += pOp->p3; |
| 75965 | pc = pOp->p2 - 1; |
| 75966 | } |
| 75967 | break; |
| 75968 | } |
| 75969 | |
| 75970 | /* Opcode: DecrJumpZero P1 P2 * * * |
| 75971 | ** Synopsis: if (--r[P1])==0 goto P2 |
| 75972 | ** |
| 75973 | ** Register P1 must hold an integer. Decrement the value in register P1 |
| 75974 | ** then jump to P2 if the new value is exactly zero. |
| 75975 | */ |
| 75976 | case OP_DecrJumpZero: { /* jump, in1 */ |
| 75977 | pIn1 = &aMem[pOp->p1]; |
| 75978 | assert( pIn1->flags&MEM_Int ); |
| 75979 | pIn1->u.i--; |
| 75980 | VdbeBranchTaken(pIn1->u.i==0, 2); |
| 75981 | if( pIn1->u.i==0 ){ |
| 75982 | pc = pOp->p2 - 1; |
| 75983 | } |
| 75984 | break; |
| 75985 | } |
| 75986 | |
| 75987 | |
| 75988 | /* Opcode: JumpZeroIncr P1 P2 * * * |
| 75989 | ** Synopsis: if (r[P1]++)==0 ) goto P2 |
| 75990 | ** |
| 75991 | ** The register P1 must contain an integer. If register P1 is initially |
| 75992 | ** zero, then jump to P2. Increment register P1 regardless of whether or |
| 75993 | ** not the jump is taken. |
| 75994 | */ |
| 75995 | case OP_JumpZeroIncr: { /* jump, in1 */ |
| 75996 | pIn1 = &aMem[pOp->p1]; |
| 75997 | assert( pIn1->flags&MEM_Int ); |
| 75998 | VdbeBranchTaken(pIn1->u.i==0, 2); |
| 75999 | if( (pIn1->u.i++)==0 ){ |
| 76000 | pc = pOp->p2 - 1; |
| 76001 | } |
| 76002 | break; |
| 76003 | } |
| 76004 | |
| 76005 | /* Opcode: AggStep * P2 P3 P4 P5 |
| 76006 | ** Synopsis: accum=r[P3] step(r[P2@P5]) |
| 76007 | ** |
| 76008 | ** Execute the step function for an aggregate. The |
| 76009 | ** function has P5 arguments. P4 is a pointer to the FuncDef |
| @@ -97181,10 +97289,15 @@ | |
| 97289 | ** pExpr points to an expression which implements a function. If |
| 97290 | ** it is appropriate to apply the LIKE optimization to that function |
| 97291 | ** then set aWc[0] through aWc[2] to the wildcard characters and |
| 97292 | ** return TRUE. If the function is not a LIKE-style function then |
| 97293 | ** return FALSE. |
| 97294 | ** |
| 97295 | ** *pIsNocase is set to true if uppercase and lowercase are equivalent for |
| 97296 | ** the function (default for LIKE). If the function makes the distinction |
| 97297 | ** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to |
| 97298 | ** false. |
| 97299 | */ |
| 97300 | SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ |
| 97301 | FuncDef *pDef; |
| 97302 | if( pExpr->op!=TK_FUNCTION |
| 97303 | || !pExpr->x.pList |
| @@ -102972,10 +103085,21 @@ | |
| 103085 | } |
| 103086 | |
| 103087 | /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS |
| 103088 | ** connection. If it returns SQLITE_OK, then assume that the VFS |
| 103089 | ** handled the pragma and generate a no-op prepared statement. |
| 103090 | ** |
| 103091 | ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed, |
| 103092 | ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file |
| 103093 | ** object corresponding to the database file to which the pragma |
| 103094 | ** statement refers. |
| 103095 | ** |
| 103096 | ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA |
| 103097 | ** file control is an array of pointers to strings (char**) in which the |
| 103098 | ** second element of the array is the name of the pragma and the third |
| 103099 | ** element is the argument to the pragma or NULL if the pragma has no |
| 103100 | ** argument. |
| 103101 | */ |
| 103102 | aFcntl[0] = 0; |
| 103103 | aFcntl[1] = zLeft; |
| 103104 | aFcntl[2] = zRight; |
| 103105 | aFcntl[3] = 0; |
| @@ -103732,34 +103856,46 @@ | |
| 103856 | Index *pIdx; |
| 103857 | Table *pTab; |
| 103858 | pIdx = sqlite3FindIndex(db, zRight, zDb); |
| 103859 | if( pIdx ){ |
| 103860 | int i; |
| 103861 | int mx; |
| 103862 | if( pPragma->iArg ){ |
| 103863 | /* PRAGMA index_xinfo (newer version with more rows and columns) */ |
| 103864 | mx = pIdx->nColumn; |
| 103865 | pParse->nMem = 6; |
| 103866 | }else{ |
| 103867 | /* PRAGMA index_info (legacy version) */ |
| 103868 | mx = pIdx->nKeyCol; |
| 103869 | pParse->nMem = 3; |
| 103870 | } |
| 103871 | pTab = pIdx->pTable; |
| 103872 | sqlite3VdbeSetNumCols(v, pParse->nMem); |
| 103873 | sqlite3CodeVerifySchema(pParse, iDb); |
| 103874 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); |
| 103875 | sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); |
| 103876 | sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); |
| 103877 | if( pPragma->iArg ){ |
| 103878 | sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC); |
| 103879 | sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC); |
| 103880 | sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC); |
| 103881 | } |
| 103882 | for(i=0; i<mx; i++){ |
| 103883 | i16 cnum = pIdx->aiColumn[i]; |
| 103884 | sqlite3VdbeAddOp2(v, OP_Integer, i, 1); |
| 103885 | sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2); |
| 103886 | if( cnum<0 ){ |
| 103887 | sqlite3VdbeAddOp2(v, OP_Null, 0, 3); |
| 103888 | }else{ |
| 103889 | sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); |
| 103890 | } |
| 103891 | if( pPragma->iArg ){ |
| 103892 | sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4); |
| 103893 | sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0); |
| 103894 | sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6); |
| 103895 | } |
| 103896 | sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem); |
| 103897 | } |
| 103898 | } |
| 103899 | } |
| 103900 | break; |
| 103901 | |
| @@ -104457,12 +104593,13 @@ | |
| 104593 | #endif |
| 104594 | |
| 104595 | /* |
| 104596 | ** PRAGMA shrink_memory |
| 104597 | ** |
| 104598 | ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database |
| 104599 | ** connection on which it is invoked to free up as much memory as it |
| 104600 | ** can, by calling sqlite3_db_release_memory(). |
| 104601 | */ |
| 104602 | case PragTyp_SHRINK_MEMORY: { |
| 104603 | sqlite3_db_release_memory(db); |
| 104604 | break; |
| 104605 | } |
| @@ -104487,12 +104624,16 @@ | |
| 104624 | |
| 104625 | /* |
| 104626 | ** PRAGMA soft_heap_limit |
| 104627 | ** PRAGMA soft_heap_limit = N |
| 104628 | ** |
| 104629 | ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the |
| 104630 | ** sqlite3_soft_heap_limit64() interface with the argument N, if N is |
| 104631 | ** specified and is a non-negative integer. |
| 104632 | ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always |
| 104633 | ** returns the same integer that would be returned by the |
| 104634 | ** sqlite3_soft_heap_limit64(-1) C-language function. |
| 104635 | */ |
| 104636 | case PragTyp_SOFT_HEAP_LIMIT: { |
| 104637 | sqlite3_int64 N; |
| 104638 | if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ |
| 104639 | sqlite3_soft_heap_limit64(N); |
| @@ -106065,24 +106206,21 @@ | |
| 106206 | }else{ |
| 106207 | op = OP_IdxInsert; |
| 106208 | } |
| 106209 | sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); |
| 106210 | if( pSelect->iLimit ){ |
| 106211 | int addr; |
| 106212 | int iLimit; |
| 106213 | if( pSelect->iOffset ){ |
| 106214 | iLimit = pSelect->iOffset+1; |
| 106215 | }else{ |
| 106216 | iLimit = pSelect->iLimit; |
| 106217 | } |
| 106218 | addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v); |
| 106219 | sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); |
| 106220 | sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); |
| 106221 | sqlite3VdbeJumpHere(v, addr); |
| 106222 | } |
| 106223 | } |
| 106224 | |
| 106225 | /* |
| 106226 | ** Add code to implement the OFFSET |
| @@ -106475,11 +106613,11 @@ | |
| 106613 | /* Jump to the end of the loop if the LIMIT is reached. Except, if |
| 106614 | ** there is a sorter, in which case the sorter has already limited |
| 106615 | ** the output for us. |
| 106616 | */ |
| 106617 | if( pSort==0 && p->iLimit ){ |
| 106618 | sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); |
| 106619 | } |
| 106620 | } |
| 106621 | |
| 106622 | /* |
| 106623 | ** Allocate a KeyInfo object sufficient for an index of N key columns and |
| @@ -107328,11 +107466,11 @@ | |
| 107466 | } |
| 107467 | }else{ |
| 107468 | sqlite3ExprCode(pParse, p->pLimit, iLimit); |
| 107469 | sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); |
| 107470 | VdbeComment((v, "LIMIT counter")); |
| 107471 | sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); |
| 107472 | } |
| 107473 | if( p->pOffset ){ |
| 107474 | p->iOffset = iOffset = ++pParse->nMem; |
| 107475 | pParse->nMem++; /* Allocate an extra register for limit+offset */ |
| 107476 | sqlite3ExprCode(pParse, p->pOffset, iOffset); |
| @@ -107547,11 +107685,11 @@ | |
| 107685 | addrCont = sqlite3VdbeMakeLabel(v); |
| 107686 | codeOffset(v, regOffset, addrCont); |
| 107687 | selectInnerLoop(pParse, p, p->pEList, iCurrent, |
| 107688 | 0, 0, pDest, addrCont, addrBreak); |
| 107689 | if( regLimit ){ |
| 107690 | sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); |
| 107691 | VdbeCoverage(v); |
| 107692 | } |
| 107693 | sqlite3VdbeResolveLabel(v, addrCont); |
| 107694 | |
| 107695 | /* Execute the recursive SELECT taking the single row in Current as |
| @@ -107772,11 +107910,11 @@ | |
| 107910 | } |
| 107911 | p->pPrior = 0; |
| 107912 | p->iLimit = pPrior->iLimit; |
| 107913 | p->iOffset = pPrior->iOffset; |
| 107914 | if( p->iLimit ){ |
| 107915 | addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); |
| 107916 | VdbeComment((v, "Jump ahead if LIMIT reached")); |
| 107917 | } |
| 107918 | explainSetInteger(iSub2, pParse->iNextSelectId); |
| 107919 | rc = sqlite3Select(pParse, p, &dest); |
| 107920 | testcase( rc!=SQLITE_OK ); |
| @@ -108173,11 +108311,11 @@ | |
| 108311 | } |
| 108312 | |
| 108313 | /* Jump to the end of the loop if the LIMIT is reached. |
| 108314 | */ |
| 108315 | if( p->iLimit ){ |
| 108316 | sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); |
| 108317 | } |
| 108318 | |
| 108319 | /* Generate the subroutine return |
| 108320 | */ |
| 108321 | sqlite3VdbeResolveLabel(v, iContinue); |
| @@ -114787,10 +114925,12 @@ | |
| 114925 | int addrNxt; /* Jump here to start the next IN combination */ |
| 114926 | int addrSkip; /* Jump here for next iteration of skip-scan */ |
| 114927 | int addrCont; /* Jump here to continue with the next loop cycle */ |
| 114928 | int addrFirst; /* First instruction of interior of the loop */ |
| 114929 | int addrBody; /* Beginning of the body of this loop */ |
| 114930 | int iLikeRepCntr; /* LIKE range processing counter register */ |
| 114931 | int addrLikeRep; /* LIKE range processing address */ |
| 114932 | u8 iFrom; /* Which entry in the FROM clause */ |
| 114933 | u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ |
| 114934 | int p1, p2; /* Operands of the opcode used to ends the loop */ |
| 114935 | union { /* Information that depends on pWLoop->wsFlags */ |
| 114936 | struct { |
| @@ -114971,11 +115111,11 @@ | |
| 115111 | WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ |
| 115112 | WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ |
| 115113 | } u; |
| 115114 | LogEst truthProb; /* Probability of truth for this expression */ |
| 115115 | u16 eOperator; /* A WO_xx value describing <op> */ |
| 115116 | u16 wtFlags; /* TERM_xxx bit flags. See below */ |
| 115117 | u8 nChild; /* Number of children that must disable us */ |
| 115118 | WhereClause *pWC; /* The clause this term is part of */ |
| 115119 | Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ |
| 115120 | Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ |
| 115121 | }; |
| @@ -114993,10 +115133,13 @@ | |
| 115133 | #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 |
| 115134 | # define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ |
| 115135 | #else |
| 115136 | # define TERM_VNULL 0x00 /* Disabled if not using stat3 */ |
| 115137 | #endif |
| 115138 | #define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ |
| 115139 | #define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ |
| 115140 | #define TERM_LIKE 0x400 /* The original LIKE operator */ |
| 115141 | |
| 115142 | /* |
| 115143 | ** An instance of the WhereScan object is used as an iterator for locating |
| 115144 | ** terms in the WHERE clause that are useful to the query planner. |
| 115145 | */ |
| @@ -115368,11 +115511,11 @@ | |
| 115511 | ** WARNING: This routine might reallocate the space used to store |
| 115512 | ** WhereTerms. All pointers to WhereTerms should be invalidated after |
| 115513 | ** calling this routine. Such pointers may be reinitialized by referencing |
| 115514 | ** the pWC->a[] array. |
| 115515 | */ |
| 115516 | static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ |
| 115517 | WhereTerm *pTerm; |
| 115518 | int idx; |
| 115519 | testcase( wtFlags & TERM_VIRTUAL ); |
| 115520 | if( pWC->nTerm>=pWC->nSlot ){ |
| 115521 | WhereTerm *pOld = pWC->a; |
| @@ -115793,11 +115936,15 @@ | |
| 115936 | ** Check to see if the given expression is a LIKE or GLOB operator that |
| 115937 | ** can be optimized using inequality constraints. Return TRUE if it is |
| 115938 | ** so and false if not. |
| 115939 | ** |
| 115940 | ** In order for the operator to be optimizible, the RHS must be a string |
| 115941 | ** literal that does not begin with a wildcard. The LHS must be a column |
| 115942 | ** that may only be NULL, a string, or a BLOB, never a number. (This means |
| 115943 | ** that virtual tables cannot participate in the LIKE optimization.) If the |
| 115944 | ** collating sequence for the column on the LHS must be appropriate for |
| 115945 | ** the operator. |
| 115946 | */ |
| 115947 | static int isLikeOrGlob( |
| 115948 | Parse *pParse, /* Parsing and code generating context */ |
| 115949 | Expr *pExpr, /* Test this expression */ |
| 115950 | Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ |
| @@ -115822,11 +115969,11 @@ | |
| 115969 | #endif |
| 115970 | pList = pExpr->x.pList; |
| 115971 | pLeft = pList->a[1].pExpr; |
| 115972 | if( pLeft->op!=TK_COLUMN |
| 115973 | || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT |
| 115974 | || IsVirtual(pLeft->pTab) /* Value might be numeric */ |
| 115975 | ){ |
| 115976 | /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must |
| 115977 | ** be the name of an indexed column with TEXT affinity. */ |
| 115978 | return 0; |
| 115979 | } |
| @@ -116271,11 +116418,11 @@ | |
| 116418 | Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ |
| 116419 | Bitmask prereqAll; /* Prerequesites of pExpr */ |
| 116420 | Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */ |
| 116421 | Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ |
| 116422 | int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ |
| 116423 | int noCase = 0; /* uppercase equivalent to lowercase */ |
| 116424 | int op; /* Top-level operator. pExpr->op */ |
| 116425 | Parse *pParse = pWInfo->pParse; /* Parsing context */ |
| 116426 | sqlite3 *db = pParse->db; /* Database connection */ |
| 116427 | |
| 116428 | if( db->mallocFailed ){ |
| @@ -116409,16 +116556,19 @@ | |
| 116556 | |
| 116557 | #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION |
| 116558 | /* Add constraints to reduce the search space on a LIKE or GLOB |
| 116559 | ** operator. |
| 116560 | ** |
| 116561 | ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints |
| 116562 | ** |
| 116563 | ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' |
| 116564 | ** |
| 116565 | ** The last character of the prefix "abc" is incremented to form the |
| 116566 | ** termination condition "abd". If case is not significant (the default |
| 116567 | ** for LIKE) then the lower-bound is made all uppercase and the upper- |
| 116568 | ** bound is made all lowercase so that the bounds also work when comparing |
| 116569 | ** BLOBs. |
| 116570 | */ |
| 116571 | if( pWC->op==TK_AND |
| 116572 | && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) |
| 116573 | ){ |
| 116574 | Expr *pLeft; /* LHS of LIKE/GLOB operator */ |
| @@ -116426,13 +116576,29 @@ | |
| 116576 | Expr *pNewExpr1; |
| 116577 | Expr *pNewExpr2; |
| 116578 | int idxNew1; |
| 116579 | int idxNew2; |
| 116580 | Token sCollSeqName; /* Name of collating sequence */ |
| 116581 | const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; |
| 116582 | |
| 116583 | pLeft = pExpr->x.pList->a[1].pExpr; |
| 116584 | pStr2 = sqlite3ExprDup(db, pStr1, 0); |
| 116585 | |
| 116586 | /* Convert the lower bound to upper-case and the upper bound to |
| 116587 | ** lower-case (upper-case is less than lower-case in ASCII) so that |
| 116588 | ** the range constraints also work for BLOBs |
| 116589 | */ |
| 116590 | if( noCase && !pParse->db->mallocFailed ){ |
| 116591 | int i; |
| 116592 | char c; |
| 116593 | pTerm->wtFlags |= TERM_LIKE; |
| 116594 | for(i=0; (c = pStr1->u.zToken[i])!=0; i++){ |
| 116595 | pStr1->u.zToken[i] = sqlite3Toupper(c); |
| 116596 | pStr2->u.zToken[i] = sqlite3Tolower(c); |
| 116597 | } |
| 116598 | } |
| 116599 | |
| 116600 | if( !db->mallocFailed ){ |
| 116601 | u8 c, *pC; /* Last character before the first wildcard */ |
| 116602 | pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; |
| 116603 | c = *pC; |
| 116604 | if( noCase ){ |
| @@ -116448,23 +116614,23 @@ | |
| 116614 | *pC = c + 1; |
| 116615 | } |
| 116616 | sCollSeqName.z = noCase ? "NOCASE" : "BINARY"; |
| 116617 | sCollSeqName.n = 6; |
| 116618 | pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); |
| 116619 | pNewExpr1 = sqlite3PExpr(pParse, TK_GE, |
| 116620 | sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), |
| 116621 | pStr1, 0); |
| 116622 | transferJoinMarkings(pNewExpr1, pExpr); |
| 116623 | idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); |
| 116624 | testcase( idxNew1==0 ); |
| 116625 | exprAnalyze(pSrc, pWC, idxNew1); |
| 116626 | pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); |
| 116627 | pNewExpr2 = sqlite3PExpr(pParse, TK_LT, |
| 116628 | sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), |
| 116629 | pStr2, 0); |
| 116630 | transferJoinMarkings(pNewExpr2, pExpr); |
| 116631 | idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); |
| 116632 | testcase( idxNew2==0 ); |
| 116633 | exprAnalyze(pSrc, pWC, idxNew2); |
| 116634 | pTerm = &pWC->a[idxTerm]; |
| 116635 | if( isComplete ){ |
| 116636 | markTermAsChild(pWC, idxNew1, idxTerm); |
| @@ -117635,24 +117801,47 @@ | |
| 117801 | ** by indices, we disable them to prevent redundant tests in the inner |
| 117802 | ** loop. We would get the correct results if nothing were ever disabled, |
| 117803 | ** but joins might run a little slower. The trick is to disable as much |
| 117804 | ** as we can without disabling too much. If we disabled in (1), we'd get |
| 117805 | ** the wrong answer. See ticket #813. |
| 117806 | ** |
| 117807 | ** If all the children of a term are disabled, then that term is also |
| 117808 | ** automatically disabled. In this way, terms get disabled if derived |
| 117809 | ** virtual terms are tested first. For example: |
| 117810 | ** |
| 117811 | ** x GLOB 'abc*' AND x>='abc' AND x<'acd' |
| 117812 | ** \___________/ \______/ \_____/ |
| 117813 | ** parent child1 child2 |
| 117814 | ** |
| 117815 | ** Only the parent term was in the original WHERE clause. The child1 |
| 117816 | ** and child2 terms were added by the LIKE optimization. If both of |
| 117817 | ** the virtual child terms are valid, then testing of the parent can be |
| 117818 | ** skipped. |
| 117819 | ** |
| 117820 | ** Usually the parent term is marked as TERM_CODED. But if the parent |
| 117821 | ** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead. |
| 117822 | ** The TERM_LIKECOND marking indicates that the term should be coded inside |
| 117823 | ** a conditional such that is only evaluated on the second pass of a |
| 117824 | ** LIKE-optimization loop, when scanning BLOBs instead of strings. |
| 117825 | */ |
| 117826 | static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ |
| 117827 | int nLoop = 0; |
| 117828 | while( pTerm |
| 117829 | && (pTerm->wtFlags & TERM_CODED)==0 |
| 117830 | && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) |
| 117831 | && (pLevel->notReady & pTerm->prereqAll)==0 |
| 117832 | ){ |
| 117833 | if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ |
| 117834 | pTerm->wtFlags |= TERM_LIKECOND; |
| 117835 | }else{ |
| 117836 | pTerm->wtFlags |= TERM_CODED; |
| 117837 | } |
| 117838 | if( pTerm->iParent<0 ) break; |
| 117839 | pTerm = &pTerm->pWC->a[pTerm->iParent]; |
| 117840 | pTerm->nChild--; |
| 117841 | if( pTerm->nChild!=0 ) break; |
| 117842 | nLoop++; |
| 117843 | } |
| 117844 | } |
| 117845 | |
| 117846 | /* |
| 117847 | ** Code an OP_Affinity opcode to apply the column affinity string zAff |
| @@ -118132,11 +118321,30 @@ | |
| 118321 | } |
| 118322 | #else |
| 118323 | # define addScanStatus(a, b, c, d) ((void)d) |
| 118324 | #endif |
| 118325 | |
| 118326 | /* |
| 118327 | ** Look at the last instruction coded. If that instruction is OP_String8 |
| 118328 | ** and if pLoop->iLikeRepCntr is non-zero, then change the P3 to be |
| 118329 | ** pLoop->iLikeRepCntr and set P5. |
| 118330 | ** |
| 118331 | ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range |
| 118332 | ** expression: "x>='ABC' AND x<'abd'". But this requires that the range |
| 118333 | ** scan loop run twice, once for strings and a second time for BLOBs. |
| 118334 | ** The OP_String opcodes on the second pass convert the upper and lower |
| 118335 | ** bound string contants to blobs. This routine makes the necessary changes |
| 118336 | ** to the OP_String opcodes for that to happen. |
| 118337 | */ |
| 118338 | static void whereLikeOptimizationStringFixup(Vdbe *v, WhereLevel *pLevel){ |
| 118339 | VdbeOp *pOp; |
| 118340 | pOp = sqlite3VdbeGetOp(v, -1); |
| 118341 | if( pLevel->iLikeRepCntr && pOp->opcode==OP_String8 ){ |
| 118342 | pOp->p3 = pLevel->iLikeRepCntr; |
| 118343 | pOp->p5 = 1; |
| 118344 | } |
| 118345 | } |
| 118346 | |
| 118347 | /* |
| 118348 | ** Generate code for the start of the iLevel-th loop in the WHERE clause |
| 118349 | ** implementation described by pWInfo. |
| 118350 | */ |
| @@ -118466,10 +118674,23 @@ | |
| 118674 | nExtraReg = 1; |
| 118675 | } |
| 118676 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ |
| 118677 | pRangeEnd = pLoop->aLTerm[j++]; |
| 118678 | nExtraReg = 1; |
| 118679 | if( pRangeStart |
| 118680 | && (pRangeStart->wtFlags & TERM_LIKEOPT)!=0 |
| 118681 | && (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 |
| 118682 | ){ |
| 118683 | pLevel->iLikeRepCntr = ++pParse->nMem; |
| 118684 | testcase( bRev ); |
| 118685 | testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); |
| 118686 | sqlite3VdbeAddOp2(v, OP_Integer, |
| 118687 | bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC), |
| 118688 | pLevel->iLikeRepCntr); |
| 118689 | VdbeComment((v, "LIKE loop counter")); |
| 118690 | pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); |
| 118691 | } |
| 118692 | if( pRangeStart==0 |
| 118693 | && (j = pIdx->aiColumn[nEq])>=0 |
| 118694 | && pIdx->pTable->aCol[j].notNull==0 |
| 118695 | ){ |
| 118696 | bSeekPastNull = 1; |
| @@ -118508,10 +118729,11 @@ | |
| 118729 | /* Seek the index cursor to the start of the range. */ |
| 118730 | nConstraint = nEq; |
| 118731 | if( pRangeStart ){ |
| 118732 | Expr *pRight = pRangeStart->pExpr->pRight; |
| 118733 | sqlite3ExprCode(pParse, pRight, regBase+nEq); |
| 118734 | whereLikeOptimizationStringFixup(v, pLevel); |
| 118735 | if( (pRangeStart->wtFlags & TERM_VNULL)==0 |
| 118736 | && sqlite3ExprCanBeNull(pRight) |
| 118737 | ){ |
| 118738 | sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); |
| 118739 | VdbeCoverage(v); |
| @@ -118553,10 +118775,11 @@ | |
| 118775 | nConstraint = nEq; |
| 118776 | if( pRangeEnd ){ |
| 118777 | Expr *pRight = pRangeEnd->pExpr->pRight; |
| 118778 | sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); |
| 118779 | sqlite3ExprCode(pParse, pRight, regBase+nEq); |
| 118780 | whereLikeOptimizationStringFixup(v, pLevel); |
| 118781 | if( (pRangeEnd->wtFlags & TERM_VNULL)==0 |
| 118782 | && sqlite3ExprCanBeNull(pRight) |
| 118783 | ){ |
| 118784 | sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); |
| 118785 | VdbeCoverage(v); |
| @@ -118780,11 +119003,12 @@ | |
| 119003 | ** eliminating duplicates from other WHERE clauses, the action for each |
| 119004 | ** sub-WHERE clause is to to invoke the main loop body as a subroutine. |
| 119005 | */ |
| 119006 | wctrlFlags = WHERE_OMIT_OPEN_CLOSE |
| 119007 | | WHERE_FORCE_TABLE |
| 119008 | | WHERE_ONETABLE_ONLY |
| 119009 | | WHERE_NO_AUTOINDEX; |
| 119010 | for(ii=0; ii<pOrWc->nTerm; ii++){ |
| 119011 | WhereTerm *pOrTerm = &pOrWc->a[ii]; |
| 119012 | if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ |
| 119013 | WhereInfo *pSubWInfo; /* Info for single OR-term scan */ |
| 119014 | Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ |
| @@ -118942,10 +119166,11 @@ | |
| 119166 | /* Insert code to test every subexpression that can be completely |
| 119167 | ** computed using the current set of tables. |
| 119168 | */ |
| 119169 | for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ |
| 119170 | Expr *pE; |
| 119171 | int skipLikeAddr = 0; |
| 119172 | testcase( pTerm->wtFlags & TERM_VIRTUAL ); |
| 119173 | testcase( pTerm->wtFlags & TERM_CODED ); |
| 119174 | if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; |
| 119175 | if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ |
| 119176 | testcase( pWInfo->untestedTerms==0 |
| @@ -118955,12 +119180,18 @@ | |
| 119180 | } |
| 119181 | pE = pTerm->pExpr; |
| 119182 | assert( pE!=0 ); |
| 119183 | if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ |
| 119184 | continue; |
| 119185 | } |
| 119186 | if( pTerm->wtFlags & TERM_LIKECOND ){ |
| 119187 | assert( pLevel->iLikeRepCntr>0 ); |
| 119188 | skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr); |
| 119189 | VdbeCoverage(v); |
| 119190 | } |
| 119191 | sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); |
| 119192 | if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); |
| 119193 | pTerm->wtFlags |= TERM_CODED; |
| 119194 | } |
| 119195 | |
| 119196 | /* Insert code to test for implied constraints based on transitivity |
| 119197 | ** of the "==" operator. |
| @@ -119974,10 +120205,11 @@ | |
| 120205 | rLogSize = estLog(rSize); |
| 120206 | |
| 120207 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX |
| 120208 | /* Automatic indexes */ |
| 120209 | if( !pBuilder->pOrSet |
| 120210 | && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 |
| 120211 | && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 |
| 120212 | && pSrc->pIndex==0 |
| 120213 | && !pSrc->viaCoroutine |
| 120214 | && !pSrc->notIndexed |
| 120215 | && HasRowid(pTab) |
| @@ -121758,10 +121990,20 @@ | |
| 121990 | if( pLevel->addrSkip ){ |
| 121991 | sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrSkip); |
| 121992 | VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); |
| 121993 | sqlite3VdbeJumpHere(v, pLevel->addrSkip); |
| 121994 | sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); |
| 121995 | } |
| 121996 | if( pLevel->addrLikeRep ){ |
| 121997 | int op; |
| 121998 | if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){ |
| 121999 | op = OP_DecrJumpZero; |
| 122000 | }else{ |
| 122001 | op = OP_JumpZeroIncr; |
| 122002 | } |
| 122003 | sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep); |
| 122004 | VdbeCoverage(v); |
| 122005 | } |
| 122006 | if( pLevel->iLeftJoin ){ |
| 122007 | addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); |
| 122008 | assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 |
| 122009 | || (pLoop->wsFlags & WHERE_INDEXED)!=0 ); |
| @@ -126982,30 +127224,32 @@ | |
| 127224 | /* Mutex configuration options are only available in a threadsafe |
| 127225 | ** compile. |
| 127226 | */ |
| 127227 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ |
| 127228 | case SQLITE_CONFIG_SINGLETHREAD: { |
| 127229 | /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to |
| 127230 | ** Single-thread. */ |
| 127231 | sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */ |
| 127232 | sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ |
| 127233 | break; |
| 127234 | } |
| 127235 | #endif |
| 127236 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ |
| 127237 | case SQLITE_CONFIG_MULTITHREAD: { |
| 127238 | /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to |
| 127239 | ** Multi-thread. */ |
| 127240 | sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ |
| 127241 | sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ |
| 127242 | break; |
| 127243 | } |
| 127244 | #endif |
| 127245 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ |
| 127246 | case SQLITE_CONFIG_SERIALIZED: { |
| 127247 | /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to |
| 127248 | ** Serialized. */ |
| 127249 | sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ |
| 127250 | sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */ |
| 127251 | break; |
| 127252 | } |
| 127253 | #endif |
| 127254 | #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ |
| 127255 | case SQLITE_CONFIG_MUTEX: { |
| @@ -127113,11 +127357,12 @@ | |
| 127357 | ** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ |
| 127358 | #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) |
| 127359 | case SQLITE_CONFIG_HEAP: { |
| 127360 | /* EVIDENCE-OF: R-19854-42126 There are three arguments to |
| 127361 | ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the |
| 127362 | ** number of bytes in the memory buffer, and the minimum allocation size. |
| 127363 | */ |
| 127364 | sqlite3GlobalConfig.pHeap = va_arg(ap, void*); |
| 127365 | sqlite3GlobalConfig.nHeap = va_arg(ap, int); |
| 127366 | sqlite3GlobalConfig.mnReq = va_arg(ap, int); |
| 127367 | |
| 127368 | if( sqlite3GlobalConfig.mnReq<1 ){ |
| @@ -127218,11 +127463,13 @@ | |
| 127463 | ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be |
| 127464 | ** silently truncated if necessary so that it does not exceed the |
| 127465 | ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE |
| 127466 | ** compile-time option. |
| 127467 | */ |
| 127468 | if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ |
| 127469 | mxMmap = SQLITE_MAX_MMAP_SIZE; |
| 127470 | } |
| 127471 | if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; |
| 127472 | if( szMmap>mxMmap) szMmap = mxMmap; |
| 127473 | sqlite3GlobalConfig.mxMmap = mxMmap; |
| 127474 | sqlite3GlobalConfig.szMmap = szMmap; |
| 127475 | break; |
| @@ -129062,11 +129309,23 @@ | |
| 129309 | for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&'); |
| 129310 | zFile = sqlite3_malloc(nByte); |
| 129311 | if( !zFile ) return SQLITE_NOMEM; |
| 129312 | |
| 129313 | iIn = 5; |
| 129314 | #ifdef SQLITE_ALLOW_URI_AUTHORITY |
| 129315 | if( strncmp(zUri+5, "///", 3)==0 ){ |
| 129316 | iIn = 7; |
| 129317 | /* The following condition causes URIs with five leading / characters |
| 129318 | ** like file://///host/path to be converted into UNCs like //host/path. |
| 129319 | ** The correct URI for that UNC has only two or four leading / characters |
| 129320 | ** file://host/path or file:////host/path. But 5 leading slashes is a |
| 129321 | ** common error, we are told, so we handle it as a special case. */ |
| 129322 | if( strncmp(zUri+7, "///", 3)==0 ){ iIn++; } |
| 129323 | }else if( strncmp(zUri+5, "//localhost/", 12)==0 ){ |
| 129324 | iIn = 16; |
| 129325 | } |
| 129326 | #else |
| 129327 | /* Discard the scheme and authority segments of the URI. */ |
| 129328 | if( zUri[5]=='/' && zUri[6]=='/' ){ |
| 129329 | iIn = 7; |
| 129330 | while( zUri[iIn] && zUri[iIn]!='/' ) iIn++; |
| 129331 | if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){ |
| @@ -129505,11 +129764,12 @@ | |
| 129764 | sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); |
| 129765 | |
| 129766 | opendb_out: |
| 129767 | sqlite3_free(zOpen); |
| 129768 | if( db ){ |
| 129769 | assert( db->mutex!=0 || isThreadsafe==0 |
| 129770 | || sqlite3GlobalConfig.bFullMutex==0 ); |
| 129771 | sqlite3_mutex_leave(db->mutex); |
| 129772 | } |
| 129773 | rc = sqlite3_errcode(db); |
| 129774 | assert( db!=0 || rc==SQLITE_NOMEM ); |
| 129775 | if( rc==SQLITE_NOMEM ){ |
| @@ -130250,21 +130510,21 @@ | |
| 130510 | case SQLITE_TESTCTRL_ISINIT: { |
| 130511 | if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; |
| 130512 | break; |
| 130513 | } |
| 130514 | |
| 130515 | /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); |
| 130516 | ** |
| 130517 | ** This test control is used to create imposter tables. "db" is a pointer |
| 130518 | ** to the database connection. dbName is the database name (ex: "main" or |
| 130519 | ** "temp") which will receive the imposter. "onOff" turns imposter mode on |
| 130520 | ** or off. "tnum" is the root page of the b-tree to which the imposter |
| 130521 | ** table should connect. |
| 130522 | ** |
| 130523 | ** Enable imposter mode only when the schema has already been parsed. Then |
| 130524 | ** run a single CREATE TABLE statement to construct the imposter table in |
| 130525 | ** the parsed schema. Then turn imposter mode back off again. |
| 130526 | ** |
| 130527 | ** If onOff==0 and tnum>0 then reset the schema for all databases, causing |
| 130528 | ** the schema to be reparsed the next time it is needed. This has the |
| 130529 | ** effect of erasing all imposter tables. |
| 130530 | */ |
| 130531 |
+33
-32
| --- src/sqlite3.h | ||
| +++ src/sqlite3.h | ||
| @@ -105,13 +105,13 @@ | ||
| 105 | 105 | ** |
| 106 | 106 | ** See also: [sqlite3_libversion()], |
| 107 | 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | 109 | */ |
| 110 | -#define SQLITE_VERSION "3.8.8" | |
| 111 | -#define SQLITE_VERSION_NUMBER 3008008 | |
| 112 | -#define SQLITE_SOURCE_ID "2015-02-25 14:25:31 6d132e7a224ee68b5cefe9222944aac5760ffc20" | |
| 110 | +#define SQLITE_VERSION "3.8.9" | |
| 111 | +#define SQLITE_VERSION_NUMBER 3008009 | |
| 112 | +#define SQLITE_SOURCE_ID "2015-03-09 10:40:48 e5da5e7d5dc5a3438ced23f1ee83e695abc29c45" | |
| 113 | 113 | |
| 114 | 114 | /* |
| 115 | 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | 117 | ** |
| @@ -754,18 +754,20 @@ | ||
| 754 | 754 | ** |
| 755 | 755 | ** These integer constants are opcodes for the xFileControl method |
| 756 | 756 | ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] |
| 757 | 757 | ** interface. |
| 758 | 758 | ** |
| 759 | +** <ul> | |
| 760 | +** <li>[[SQLITE_FCNTL_LOCKSTATE]] | |
| 759 | 761 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This |
| 760 | 762 | ** opcode causes the xFileControl method to write the current state of |
| 761 | 763 | ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], |
| 762 | 764 | ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) |
| 763 | 765 | ** into an integer that the pArg argument points to. This capability |
| 764 | -** is used during testing and only needs to be supported when SQLITE_TEST | |
| 765 | -** is defined. | |
| 766 | -** <ul> | |
| 766 | +** is used during testing and is only available when the SQLITE_TEST | |
| 767 | +** compile-time option is used. | |
| 768 | +** | |
| 767 | 769 | ** <li>[[SQLITE_FCNTL_SIZE_HINT]] |
| 768 | 770 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS |
| 769 | 771 | ** layer a hint of how large the database file will grow to be during the |
| 770 | 772 | ** current transaction. This hint is not guaranteed to be accurate but it |
| 771 | 773 | ** is often close. The underlying VFS might choose to preallocate database |
| @@ -886,11 +888,13 @@ | ||
| 886 | 888 | ** the error message if the pragma fails. ^If the |
| 887 | 889 | ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal |
| 888 | 890 | ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] |
| 889 | 891 | ** file control returns [SQLITE_OK], then the parser assumes that the |
| 890 | 892 | ** VFS has handled the PRAGMA itself and the parser generates a no-op |
| 891 | -** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns | |
| 893 | +** prepared statement if result string is NULL, or that returns a copy | |
| 894 | +** of the result string if the string is non-NULL. | |
| 895 | +** ^If the [SQLITE_FCNTL_PRAGMA] file control returns | |
| 892 | 896 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means |
| 893 | 897 | ** that the VFS encountered an error while handling the [PRAGMA] and the |
| 894 | 898 | ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] |
| 895 | 899 | ** file control occurs at the beginning of pragma statement analysis and so |
| 896 | 900 | ** it is able to override built-in [PRAGMA] statements. |
| @@ -1745,11 +1749,10 @@ | ||
| 1745 | 1749 | ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE |
| 1746 | 1750 | ** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is |
| 1747 | 1751 | ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro |
| 1748 | 1752 | ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value |
| 1749 | 1753 | ** that specifies the maximum size of the created heap. |
| 1750 | -** </dl> | |
| 1751 | 1754 | ** |
| 1752 | 1755 | ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] |
| 1753 | 1756 | ** <dt>SQLITE_CONFIG_PCACHE_HDRSZ |
| 1754 | 1757 | ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which |
| 1755 | 1758 | ** is a pointer to an integer and writes into that integer the number of extra |
| @@ -3185,20 +3188,18 @@ | ||
| 3185 | 3188 | ** The second argument, "zSql", is the statement to be compiled, encoded |
| 3186 | 3189 | ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() |
| 3187 | 3190 | ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() |
| 3188 | 3191 | ** use UTF-16. |
| 3189 | 3192 | ** |
| 3190 | -** ^If the nByte argument is less than zero, then zSql is read up to the | |
| 3191 | -** first zero terminator. ^If nByte is non-negative, then it is the maximum | |
| 3192 | -** number of bytes read from zSql. ^When nByte is non-negative, the | |
| 3193 | -** zSql string ends at either the first '\000' or '\u0000' character or | |
| 3194 | -** the nByte-th byte, whichever comes first. If the caller knows | |
| 3195 | -** that the supplied string is nul-terminated, then there is a small | |
| 3196 | -** performance advantage to be gained by passing an nByte parameter that | |
| 3197 | -** is equal to the number of bytes in the input string <i>including</i> | |
| 3198 | -** the nul-terminator bytes as this saves SQLite from having to | |
| 3199 | -** make a copy of the input string. | |
| 3193 | +** ^If the nByte argument is negative, then zSql is read up to the | |
| 3194 | +** first zero terminator. ^If nByte is positive, then it is the | |
| 3195 | +** number of bytes read from zSql. ^If nByte is zero, then no prepared | |
| 3196 | +** statement is generated. | |
| 3197 | +** If the caller knows that the supplied string is nul-terminated, then | |
| 3198 | +** there is a small performance advantage to passing an nByte parameter that | |
| 3199 | +** is the number of bytes in the input string <i>including</i> | |
| 3200 | +** the nul-terminator. | |
| 3200 | 3201 | ** |
| 3201 | 3202 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 3202 | 3203 | ** past the end of the first SQL statement in zSql. These routines only |
| 3203 | 3204 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| 3204 | 3205 | ** what remains uncompiled. |
| @@ -4223,12 +4224,12 @@ | ||
| 4223 | 4224 | ** DEPRECATED |
| 4224 | 4225 | ** |
| 4225 | 4226 | ** These functions are [deprecated]. In order to maintain |
| 4226 | 4227 | ** backwards compatibility with older code, these functions continue |
| 4227 | 4228 | ** to be supported. However, new applications should avoid |
| 4228 | -** the use of these functions. To help encourage people to avoid | |
| 4229 | -** using these functions, we are not going to tell you what they do. | |
| 4229 | +** the use of these functions. To encourage programmers to avoid | |
| 4230 | +** these functions, we will not explain what they do. | |
| 4230 | 4231 | */ |
| 4231 | 4232 | #ifndef SQLITE_OMIT_DEPRECATED |
| 4232 | 4233 | SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); |
| 4233 | 4234 | SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); |
| 4234 | 4235 | SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); |
| @@ -6986,24 +6987,24 @@ | ||
| 6986 | 6987 | ** |
| 6987 | 6988 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6988 | 6989 | ** is not a permanent error and does not affect the return value of |
| 6989 | 6990 | ** sqlite3_backup_finish(). |
| 6990 | 6991 | ** |
| 6991 | -** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] | |
| 6992 | +** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] | |
| 6992 | 6993 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 6993 | 6994 | ** |
| 6994 | -** ^Each call to sqlite3_backup_step() sets two values inside | |
| 6995 | -** the [sqlite3_backup] object: the number of pages still to be backed | |
| 6996 | -** up and the total number of pages in the source database file. | |
| 6997 | -** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces | |
| 6998 | -** retrieve these two values, respectively. | |
| 6999 | -** | |
| 7000 | -** ^The values returned by these functions are only updated by | |
| 7001 | -** sqlite3_backup_step(). ^If the source database is modified during a backup | |
| 7002 | -** operation, then the values are not updated to account for any extra | |
| 7003 | -** pages that need to be updated or the size of the source database file | |
| 7004 | -** changing. | |
| 6995 | +** ^The sqlite3_backup_remaining() routine returns the number of pages still | |
| 6996 | +** to be backed up at the conclusion of the most recent sqlite3_backup_step(). | |
| 6997 | +** ^The sqlite3_backup_pagecount() routine returns the total number of pages | |
| 6998 | +** in the source database at the conclusion of the most recent | |
| 6999 | +** sqlite3_backup_step(). | |
| 7000 | +** ^(The values returned by these functions are only updated by | |
| 7001 | +** sqlite3_backup_step(). If the source database is modified in a way that | |
| 7002 | +** changes the size of the source database or the number of pages remaining, | |
| 7003 | +** those changes are not reflected in the output of sqlite3_backup_pagecount() | |
| 7004 | +** and sqlite3_backup_remaining() until after the next | |
| 7005 | +** sqlite3_backup_step().)^ | |
| 7005 | 7006 | ** |
| 7006 | 7007 | ** <b>Concurrent Usage of Database Handles</b> |
| 7007 | 7008 | ** |
| 7008 | 7009 | ** ^The source [database connection] may be used by the application for other |
| 7009 | 7010 | ** purposes while a backup operation is underway or being initialized. |
| 7010 | 7011 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -105,13 +105,13 @@ | |
| 105 | ** |
| 106 | ** See also: [sqlite3_libversion()], |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.8.8" |
| 111 | #define SQLITE_VERSION_NUMBER 3008008 |
| 112 | #define SQLITE_SOURCE_ID "2015-02-25 14:25:31 6d132e7a224ee68b5cefe9222944aac5760ffc20" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -754,18 +754,20 @@ | |
| 754 | ** |
| 755 | ** These integer constants are opcodes for the xFileControl method |
| 756 | ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] |
| 757 | ** interface. |
| 758 | ** |
| 759 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This |
| 760 | ** opcode causes the xFileControl method to write the current state of |
| 761 | ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], |
| 762 | ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) |
| 763 | ** into an integer that the pArg argument points to. This capability |
| 764 | ** is used during testing and only needs to be supported when SQLITE_TEST |
| 765 | ** is defined. |
| 766 | ** <ul> |
| 767 | ** <li>[[SQLITE_FCNTL_SIZE_HINT]] |
| 768 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS |
| 769 | ** layer a hint of how large the database file will grow to be during the |
| 770 | ** current transaction. This hint is not guaranteed to be accurate but it |
| 771 | ** is often close. The underlying VFS might choose to preallocate database |
| @@ -886,11 +888,13 @@ | |
| 886 | ** the error message if the pragma fails. ^If the |
| 887 | ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal |
| 888 | ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] |
| 889 | ** file control returns [SQLITE_OK], then the parser assumes that the |
| 890 | ** VFS has handled the PRAGMA itself and the parser generates a no-op |
| 891 | ** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns |
| 892 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means |
| 893 | ** that the VFS encountered an error while handling the [PRAGMA] and the |
| 894 | ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] |
| 895 | ** file control occurs at the beginning of pragma statement analysis and so |
| 896 | ** it is able to override built-in [PRAGMA] statements. |
| @@ -1745,11 +1749,10 @@ | |
| 1745 | ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE |
| 1746 | ** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is |
| 1747 | ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro |
| 1748 | ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value |
| 1749 | ** that specifies the maximum size of the created heap. |
| 1750 | ** </dl> |
| 1751 | ** |
| 1752 | ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] |
| 1753 | ** <dt>SQLITE_CONFIG_PCACHE_HDRSZ |
| 1754 | ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which |
| 1755 | ** is a pointer to an integer and writes into that integer the number of extra |
| @@ -3185,20 +3188,18 @@ | |
| 3185 | ** The second argument, "zSql", is the statement to be compiled, encoded |
| 3186 | ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() |
| 3187 | ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() |
| 3188 | ** use UTF-16. |
| 3189 | ** |
| 3190 | ** ^If the nByte argument is less than zero, then zSql is read up to the |
| 3191 | ** first zero terminator. ^If nByte is non-negative, then it is the maximum |
| 3192 | ** number of bytes read from zSql. ^When nByte is non-negative, the |
| 3193 | ** zSql string ends at either the first '\000' or '\u0000' character or |
| 3194 | ** the nByte-th byte, whichever comes first. If the caller knows |
| 3195 | ** that the supplied string is nul-terminated, then there is a small |
| 3196 | ** performance advantage to be gained by passing an nByte parameter that |
| 3197 | ** is equal to the number of bytes in the input string <i>including</i> |
| 3198 | ** the nul-terminator bytes as this saves SQLite from having to |
| 3199 | ** make a copy of the input string. |
| 3200 | ** |
| 3201 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 3202 | ** past the end of the first SQL statement in zSql. These routines only |
| 3203 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| 3204 | ** what remains uncompiled. |
| @@ -4223,12 +4224,12 @@ | |
| 4223 | ** DEPRECATED |
| 4224 | ** |
| 4225 | ** These functions are [deprecated]. In order to maintain |
| 4226 | ** backwards compatibility with older code, these functions continue |
| 4227 | ** to be supported. However, new applications should avoid |
| 4228 | ** the use of these functions. To help encourage people to avoid |
| 4229 | ** using these functions, we are not going to tell you what they do. |
| 4230 | */ |
| 4231 | #ifndef SQLITE_OMIT_DEPRECATED |
| 4232 | SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); |
| 4233 | SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); |
| 4234 | SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); |
| @@ -6986,24 +6987,24 @@ | |
| 6986 | ** |
| 6987 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6988 | ** is not a permanent error and does not affect the return value of |
| 6989 | ** sqlite3_backup_finish(). |
| 6990 | ** |
| 6991 | ** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] |
| 6992 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 6993 | ** |
| 6994 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 6995 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 6996 | ** up and the total number of pages in the source database file. |
| 6997 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| 6998 | ** retrieve these two values, respectively. |
| 6999 | ** |
| 7000 | ** ^The values returned by these functions are only updated by |
| 7001 | ** sqlite3_backup_step(). ^If the source database is modified during a backup |
| 7002 | ** operation, then the values are not updated to account for any extra |
| 7003 | ** pages that need to be updated or the size of the source database file |
| 7004 | ** changing. |
| 7005 | ** |
| 7006 | ** <b>Concurrent Usage of Database Handles</b> |
| 7007 | ** |
| 7008 | ** ^The source [database connection] may be used by the application for other |
| 7009 | ** purposes while a backup operation is underway or being initialized. |
| 7010 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -105,13 +105,13 @@ | |
| 105 | ** |
| 106 | ** See also: [sqlite3_libversion()], |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.8.9" |
| 111 | #define SQLITE_VERSION_NUMBER 3008009 |
| 112 | #define SQLITE_SOURCE_ID "2015-03-09 10:40:48 e5da5e7d5dc5a3438ced23f1ee83e695abc29c45" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -754,18 +754,20 @@ | |
| 754 | ** |
| 755 | ** These integer constants are opcodes for the xFileControl method |
| 756 | ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] |
| 757 | ** interface. |
| 758 | ** |
| 759 | ** <ul> |
| 760 | ** <li>[[SQLITE_FCNTL_LOCKSTATE]] |
| 761 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This |
| 762 | ** opcode causes the xFileControl method to write the current state of |
| 763 | ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], |
| 764 | ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) |
| 765 | ** into an integer that the pArg argument points to. This capability |
| 766 | ** is used during testing and is only available when the SQLITE_TEST |
| 767 | ** compile-time option is used. |
| 768 | ** |
| 769 | ** <li>[[SQLITE_FCNTL_SIZE_HINT]] |
| 770 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS |
| 771 | ** layer a hint of how large the database file will grow to be during the |
| 772 | ** current transaction. This hint is not guaranteed to be accurate but it |
| 773 | ** is often close. The underlying VFS might choose to preallocate database |
| @@ -886,11 +888,13 @@ | |
| 888 | ** the error message if the pragma fails. ^If the |
| 889 | ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal |
| 890 | ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] |
| 891 | ** file control returns [SQLITE_OK], then the parser assumes that the |
| 892 | ** VFS has handled the PRAGMA itself and the parser generates a no-op |
| 893 | ** prepared statement if result string is NULL, or that returns a copy |
| 894 | ** of the result string if the string is non-NULL. |
| 895 | ** ^If the [SQLITE_FCNTL_PRAGMA] file control returns |
| 896 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means |
| 897 | ** that the VFS encountered an error while handling the [PRAGMA] and the |
| 898 | ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] |
| 899 | ** file control occurs at the beginning of pragma statement analysis and so |
| 900 | ** it is able to override built-in [PRAGMA] statements. |
| @@ -1745,11 +1749,10 @@ | |
| 1749 | ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE |
| 1750 | ** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is |
| 1751 | ** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro |
| 1752 | ** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value |
| 1753 | ** that specifies the maximum size of the created heap. |
| 1754 | ** |
| 1755 | ** [[SQLITE_CONFIG_PCACHE_HDRSZ]] |
| 1756 | ** <dt>SQLITE_CONFIG_PCACHE_HDRSZ |
| 1757 | ** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which |
| 1758 | ** is a pointer to an integer and writes into that integer the number of extra |
| @@ -3185,20 +3188,18 @@ | |
| 3188 | ** The second argument, "zSql", is the statement to be compiled, encoded |
| 3189 | ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() |
| 3190 | ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() |
| 3191 | ** use UTF-16. |
| 3192 | ** |
| 3193 | ** ^If the nByte argument is negative, then zSql is read up to the |
| 3194 | ** first zero terminator. ^If nByte is positive, then it is the |
| 3195 | ** number of bytes read from zSql. ^If nByte is zero, then no prepared |
| 3196 | ** statement is generated. |
| 3197 | ** If the caller knows that the supplied string is nul-terminated, then |
| 3198 | ** there is a small performance advantage to passing an nByte parameter that |
| 3199 | ** is the number of bytes in the input string <i>including</i> |
| 3200 | ** the nul-terminator. |
| 3201 | ** |
| 3202 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 3203 | ** past the end of the first SQL statement in zSql. These routines only |
| 3204 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| 3205 | ** what remains uncompiled. |
| @@ -4223,12 +4224,12 @@ | |
| 4224 | ** DEPRECATED |
| 4225 | ** |
| 4226 | ** These functions are [deprecated]. In order to maintain |
| 4227 | ** backwards compatibility with older code, these functions continue |
| 4228 | ** to be supported. However, new applications should avoid |
| 4229 | ** the use of these functions. To encourage programmers to avoid |
| 4230 | ** these functions, we will not explain what they do. |
| 4231 | */ |
| 4232 | #ifndef SQLITE_OMIT_DEPRECATED |
| 4233 | SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); |
| 4234 | SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); |
| 4235 | SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); |
| @@ -6986,24 +6987,24 @@ | |
| 6987 | ** |
| 6988 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6989 | ** is not a permanent error and does not affect the return value of |
| 6990 | ** sqlite3_backup_finish(). |
| 6991 | ** |
| 6992 | ** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] |
| 6993 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 6994 | ** |
| 6995 | ** ^The sqlite3_backup_remaining() routine returns the number of pages still |
| 6996 | ** to be backed up at the conclusion of the most recent sqlite3_backup_step(). |
| 6997 | ** ^The sqlite3_backup_pagecount() routine returns the total number of pages |
| 6998 | ** in the source database at the conclusion of the most recent |
| 6999 | ** sqlite3_backup_step(). |
| 7000 | ** ^(The values returned by these functions are only updated by |
| 7001 | ** sqlite3_backup_step(). If the source database is modified in a way that |
| 7002 | ** changes the size of the source database or the number of pages remaining, |
| 7003 | ** those changes are not reflected in the output of sqlite3_backup_pagecount() |
| 7004 | ** and sqlite3_backup_remaining() until after the next |
| 7005 | ** sqlite3_backup_step().)^ |
| 7006 | ** |
| 7007 | ** <b>Concurrent Usage of Database Handles</b> |
| 7008 | ** |
| 7009 | ** ^The source [database connection] may be used by the application for other |
| 7010 | ** purposes while a backup operation is underway or being initialized. |
| 7011 |
+28
-2
| --- src/th_main.c | ||
| +++ src/th_main.c | ||
| @@ -1839,10 +1839,16 @@ | ||
| 1839 | 1839 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1840 | 1840 | ** command hook handler as that is not actually an error condition. |
| 1841 | 1841 | */ |
| 1842 | 1842 | if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ |
| 1843 | 1843 | sendError(zResult, nResult, 0); |
| 1844 | + }else{ | |
| 1845 | + /* | |
| 1846 | + ** There is no command hook handler "installed". This situation | |
| 1847 | + ** is NOT actually an error. | |
| 1848 | + */ | |
| 1849 | + rc = TH_OK; | |
| 1844 | 1850 | } |
| 1845 | 1851 | } |
| 1846 | 1852 | /* |
| 1847 | 1853 | ** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does |
| 1848 | 1854 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1859,11 +1865,11 @@ | ||
| 1859 | 1865 | ** clean it up now. This is very important because some commands do not |
| 1860 | 1866 | ** expect the repository and/or the configuration ("user") database to be |
| 1861 | 1867 | ** open prior to their own code doing so. |
| 1862 | 1868 | */ |
| 1863 | 1869 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1864 | - return (rc != TH_ERROR) ? rc : TH_OK; | |
| 1870 | + return rc; | |
| 1865 | 1871 | } |
| 1866 | 1872 | |
| 1867 | 1873 | /* |
| 1868 | 1874 | ** This function is called by Fossil just after dispatching a command. |
| 1869 | 1875 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1920,10 +1926,16 @@ | ||
| 1920 | 1926 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1921 | 1927 | ** webpage hook handler as that is not actually an error condition. |
| 1922 | 1928 | */ |
| 1923 | 1929 | if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ |
| 1924 | 1930 | sendError(zResult, nResult, 1); |
| 1931 | + }else{ | |
| 1932 | + /* | |
| 1933 | + ** There is no webpage hook handler "installed". This situation | |
| 1934 | + ** is NOT actually an error. | |
| 1935 | + */ | |
| 1936 | + rc = TH_OK; | |
| 1925 | 1937 | } |
| 1926 | 1938 | } |
| 1927 | 1939 | /* |
| 1928 | 1940 | ** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does |
| 1929 | 1941 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1940,11 +1952,11 @@ | ||
| 1940 | 1952 | ** clean it up now. This is very important because some commands do not |
| 1941 | 1953 | ** expect the repository and/or the configuration ("user") database to be |
| 1942 | 1954 | ** open prior to their own code doing so. |
| 1943 | 1955 | */ |
| 1944 | 1956 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1945 | - return (rc != TH_ERROR) ? rc : TH_OK; | |
| 1957 | + return rc; | |
| 1946 | 1958 | } |
| 1947 | 1959 | |
| 1948 | 1960 | /* |
| 1949 | 1961 | ** This function is called by Fossil just after processing a web page. |
| 1950 | 1962 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1975,10 +1987,24 @@ | ||
| 1975 | 1987 | */ |
| 1976 | 1988 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1977 | 1989 | return rc; |
| 1978 | 1990 | } |
| 1979 | 1991 | #endif |
| 1992 | + | |
| 1993 | + | |
| 1994 | +#ifdef FOSSIL_ENABLE_TH1_DOCS | |
| 1995 | +/* | |
| 1996 | +** This function determines if TH1 docs are enabled for the repository. | |
| 1997 | +*/ | |
| 1998 | +int Th_AreDocsEnabled(void){ | |
| 1999 | + if( fossil_getenv("TH1_ENABLE_DOCS")!=0 ){ | |
| 2000 | + return 1; | |
| 2001 | + } | |
| 2002 | + return db_get_boolean("th1-docs", 0); | |
| 2003 | +} | |
| 2004 | +#endif | |
| 2005 | + | |
| 1980 | 2006 | |
| 1981 | 2007 | /* |
| 1982 | 2008 | ** The z[] input contains text mixed with TH1 scripts. |
| 1983 | 2009 | ** The TH1 scripts are contained within <th1>...</th1>. |
| 1984 | 2010 | ** TH1 variables are $aaa or $<aaa>. The first form of |
| 1985 | 2011 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -1839,10 +1839,16 @@ | |
| 1839 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1840 | ** command hook handler as that is not actually an error condition. |
| 1841 | */ |
| 1842 | if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ |
| 1843 | sendError(zResult, nResult, 0); |
| 1844 | } |
| 1845 | } |
| 1846 | /* |
| 1847 | ** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does |
| 1848 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1859,11 +1865,11 @@ | |
| 1859 | ** clean it up now. This is very important because some commands do not |
| 1860 | ** expect the repository and/or the configuration ("user") database to be |
| 1861 | ** open prior to their own code doing so. |
| 1862 | */ |
| 1863 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1864 | return (rc != TH_ERROR) ? rc : TH_OK; |
| 1865 | } |
| 1866 | |
| 1867 | /* |
| 1868 | ** This function is called by Fossil just after dispatching a command. |
| 1869 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1920,10 +1926,16 @@ | |
| 1920 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1921 | ** webpage hook handler as that is not actually an error condition. |
| 1922 | */ |
| 1923 | if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ |
| 1924 | sendError(zResult, nResult, 1); |
| 1925 | } |
| 1926 | } |
| 1927 | /* |
| 1928 | ** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does |
| 1929 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1940,11 +1952,11 @@ | |
| 1940 | ** clean it up now. This is very important because some commands do not |
| 1941 | ** expect the repository and/or the configuration ("user") database to be |
| 1942 | ** open prior to their own code doing so. |
| 1943 | */ |
| 1944 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1945 | return (rc != TH_ERROR) ? rc : TH_OK; |
| 1946 | } |
| 1947 | |
| 1948 | /* |
| 1949 | ** This function is called by Fossil just after processing a web page. |
| 1950 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1975,10 +1987,24 @@ | |
| 1975 | */ |
| 1976 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1977 | return rc; |
| 1978 | } |
| 1979 | #endif |
| 1980 | |
| 1981 | /* |
| 1982 | ** The z[] input contains text mixed with TH1 scripts. |
| 1983 | ** The TH1 scripts are contained within <th1>...</th1>. |
| 1984 | ** TH1 variables are $aaa or $<aaa>. The first form of |
| 1985 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -1839,10 +1839,16 @@ | |
| 1839 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1840 | ** command hook handler as that is not actually an error condition. |
| 1841 | */ |
| 1842 | if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ |
| 1843 | sendError(zResult, nResult, 0); |
| 1844 | }else{ |
| 1845 | /* |
| 1846 | ** There is no command hook handler "installed". This situation |
| 1847 | ** is NOT actually an error. |
| 1848 | */ |
| 1849 | rc = TH_OK; |
| 1850 | } |
| 1851 | } |
| 1852 | /* |
| 1853 | ** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does |
| 1854 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1859,11 +1865,11 @@ | |
| 1865 | ** clean it up now. This is very important because some commands do not |
| 1866 | ** expect the repository and/or the configuration ("user") database to be |
| 1867 | ** open prior to their own code doing so. |
| 1868 | */ |
| 1869 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1870 | return rc; |
| 1871 | } |
| 1872 | |
| 1873 | /* |
| 1874 | ** This function is called by Fossil just after dispatching a command. |
| 1875 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1920,10 +1926,16 @@ | |
| 1926 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1927 | ** webpage hook handler as that is not actually an error condition. |
| 1928 | */ |
| 1929 | if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ |
| 1930 | sendError(zResult, nResult, 1); |
| 1931 | }else{ |
| 1932 | /* |
| 1933 | ** There is no webpage hook handler "installed". This situation |
| 1934 | ** is NOT actually an error. |
| 1935 | */ |
| 1936 | rc = TH_OK; |
| 1937 | } |
| 1938 | } |
| 1939 | /* |
| 1940 | ** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does |
| 1941 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1940,11 +1952,11 @@ | |
| 1952 | ** clean it up now. This is very important because some commands do not |
| 1953 | ** expect the repository and/or the configuration ("user") database to be |
| 1954 | ** open prior to their own code doing so. |
| 1955 | */ |
| 1956 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1957 | return rc; |
| 1958 | } |
| 1959 | |
| 1960 | /* |
| 1961 | ** This function is called by Fossil just after processing a web page. |
| 1962 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1975,10 +1987,24 @@ | |
| 1987 | */ |
| 1988 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1989 | return rc; |
| 1990 | } |
| 1991 | #endif |
| 1992 | |
| 1993 | |
| 1994 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 1995 | /* |
| 1996 | ** This function determines if TH1 docs are enabled for the repository. |
| 1997 | */ |
| 1998 | int Th_AreDocsEnabled(void){ |
| 1999 | if( fossil_getenv("TH1_ENABLE_DOCS")!=0 ){ |
| 2000 | return 1; |
| 2001 | } |
| 2002 | return db_get_boolean("th1-docs", 0); |
| 2003 | } |
| 2004 | #endif |
| 2005 | |
| 2006 | |
| 2007 | /* |
| 2008 | ** The z[] input contains text mixed with TH1 scripts. |
| 2009 | ** The TH1 scripts are contained within <th1>...</th1>. |
| 2010 | ** TH1 variables are $aaa or $<aaa>. The first form of |
| 2011 |
+28
-2
| --- src/th_main.c | ||
| +++ src/th_main.c | ||
| @@ -1839,10 +1839,16 @@ | ||
| 1839 | 1839 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1840 | 1840 | ** command hook handler as that is not actually an error condition. |
| 1841 | 1841 | */ |
| 1842 | 1842 | if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ |
| 1843 | 1843 | sendError(zResult, nResult, 0); |
| 1844 | + }else{ | |
| 1845 | + /* | |
| 1846 | + ** There is no command hook handler "installed". This situation | |
| 1847 | + ** is NOT actually an error. | |
| 1848 | + */ | |
| 1849 | + rc = TH_OK; | |
| 1844 | 1850 | } |
| 1845 | 1851 | } |
| 1846 | 1852 | /* |
| 1847 | 1853 | ** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does |
| 1848 | 1854 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1859,11 +1865,11 @@ | ||
| 1859 | 1865 | ** clean it up now. This is very important because some commands do not |
| 1860 | 1866 | ** expect the repository and/or the configuration ("user") database to be |
| 1861 | 1867 | ** open prior to their own code doing so. |
| 1862 | 1868 | */ |
| 1863 | 1869 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1864 | - return (rc != TH_ERROR) ? rc : TH_OK; | |
| 1870 | + return rc; | |
| 1865 | 1871 | } |
| 1866 | 1872 | |
| 1867 | 1873 | /* |
| 1868 | 1874 | ** This function is called by Fossil just after dispatching a command. |
| 1869 | 1875 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1920,10 +1926,16 @@ | ||
| 1920 | 1926 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1921 | 1927 | ** webpage hook handler as that is not actually an error condition. |
| 1922 | 1928 | */ |
| 1923 | 1929 | if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ |
| 1924 | 1930 | sendError(zResult, nResult, 1); |
| 1931 | + }else{ | |
| 1932 | + /* | |
| 1933 | + ** There is no webpage hook handler "installed". This situation | |
| 1934 | + ** is NOT actually an error. | |
| 1935 | + */ | |
| 1936 | + rc = TH_OK; | |
| 1925 | 1937 | } |
| 1926 | 1938 | } |
| 1927 | 1939 | /* |
| 1928 | 1940 | ** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does |
| 1929 | 1941 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1940,11 +1952,11 @@ | ||
| 1940 | 1952 | ** clean it up now. This is very important because some commands do not |
| 1941 | 1953 | ** expect the repository and/or the configuration ("user") database to be |
| 1942 | 1954 | ** open prior to their own code doing so. |
| 1943 | 1955 | */ |
| 1944 | 1956 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1945 | - return (rc != TH_ERROR) ? rc : TH_OK; | |
| 1957 | + return rc; | |
| 1946 | 1958 | } |
| 1947 | 1959 | |
| 1948 | 1960 | /* |
| 1949 | 1961 | ** This function is called by Fossil just after processing a web page. |
| 1950 | 1962 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1975,10 +1987,24 @@ | ||
| 1975 | 1987 | */ |
| 1976 | 1988 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1977 | 1989 | return rc; |
| 1978 | 1990 | } |
| 1979 | 1991 | #endif |
| 1992 | + | |
| 1993 | + | |
| 1994 | +#ifdef FOSSIL_ENABLE_TH1_DOCS | |
| 1995 | +/* | |
| 1996 | +** This function determines if TH1 docs are enabled for the repository. | |
| 1997 | +*/ | |
| 1998 | +int Th_AreDocsEnabled(void){ | |
| 1999 | + if( fossil_getenv("TH1_ENABLE_DOCS")!=0 ){ | |
| 2000 | + return 1; | |
| 2001 | + } | |
| 2002 | + return db_get_boolean("th1-docs", 0); | |
| 2003 | +} | |
| 2004 | +#endif | |
| 2005 | + | |
| 1980 | 2006 | |
| 1981 | 2007 | /* |
| 1982 | 2008 | ** The z[] input contains text mixed with TH1 scripts. |
| 1983 | 2009 | ** The TH1 scripts are contained within <th1>...</th1>. |
| 1984 | 2010 | ** TH1 variables are $aaa or $<aaa>. The first form of |
| 1985 | 2011 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -1839,10 +1839,16 @@ | |
| 1839 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1840 | ** command hook handler as that is not actually an error condition. |
| 1841 | */ |
| 1842 | if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ |
| 1843 | sendError(zResult, nResult, 0); |
| 1844 | } |
| 1845 | } |
| 1846 | /* |
| 1847 | ** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does |
| 1848 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1859,11 +1865,11 @@ | |
| 1859 | ** clean it up now. This is very important because some commands do not |
| 1860 | ** expect the repository and/or the configuration ("user") database to be |
| 1861 | ** open prior to their own code doing so. |
| 1862 | */ |
| 1863 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1864 | return (rc != TH_ERROR) ? rc : TH_OK; |
| 1865 | } |
| 1866 | |
| 1867 | /* |
| 1868 | ** This function is called by Fossil just after dispatching a command. |
| 1869 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1920,10 +1926,16 @@ | |
| 1920 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1921 | ** webpage hook handler as that is not actually an error condition. |
| 1922 | */ |
| 1923 | if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ |
| 1924 | sendError(zResult, nResult, 1); |
| 1925 | } |
| 1926 | } |
| 1927 | /* |
| 1928 | ** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does |
| 1929 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1940,11 +1952,11 @@ | |
| 1940 | ** clean it up now. This is very important because some commands do not |
| 1941 | ** expect the repository and/or the configuration ("user") database to be |
| 1942 | ** open prior to their own code doing so. |
| 1943 | */ |
| 1944 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1945 | return (rc != TH_ERROR) ? rc : TH_OK; |
| 1946 | } |
| 1947 | |
| 1948 | /* |
| 1949 | ** This function is called by Fossil just after processing a web page. |
| 1950 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1975,10 +1987,24 @@ | |
| 1975 | */ |
| 1976 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1977 | return rc; |
| 1978 | } |
| 1979 | #endif |
| 1980 | |
| 1981 | /* |
| 1982 | ** The z[] input contains text mixed with TH1 scripts. |
| 1983 | ** The TH1 scripts are contained within <th1>...</th1>. |
| 1984 | ** TH1 variables are $aaa or $<aaa>. The first form of |
| 1985 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -1839,10 +1839,16 @@ | |
| 1839 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1840 | ** command hook handler as that is not actually an error condition. |
| 1841 | */ |
| 1842 | if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ |
| 1843 | sendError(zResult, nResult, 0); |
| 1844 | }else{ |
| 1845 | /* |
| 1846 | ** There is no command hook handler "installed". This situation |
| 1847 | ** is NOT actually an error. |
| 1848 | */ |
| 1849 | rc = TH_OK; |
| 1850 | } |
| 1851 | } |
| 1852 | /* |
| 1853 | ** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does |
| 1854 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1859,11 +1865,11 @@ | |
| 1865 | ** clean it up now. This is very important because some commands do not |
| 1866 | ** expect the repository and/or the configuration ("user") database to be |
| 1867 | ** open prior to their own code doing so. |
| 1868 | */ |
| 1869 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1870 | return rc; |
| 1871 | } |
| 1872 | |
| 1873 | /* |
| 1874 | ** This function is called by Fossil just after dispatching a command. |
| 1875 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1920,10 +1926,16 @@ | |
| 1926 | ** Make sure that the TH1 script error was not caused by a "missing" |
| 1927 | ** webpage hook handler as that is not actually an error condition. |
| 1928 | */ |
| 1929 | if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ |
| 1930 | sendError(zResult, nResult, 1); |
| 1931 | }else{ |
| 1932 | /* |
| 1933 | ** There is no webpage hook handler "installed". This situation |
| 1934 | ** is NOT actually an error. |
| 1935 | */ |
| 1936 | rc = TH_OK; |
| 1937 | } |
| 1938 | } |
| 1939 | /* |
| 1940 | ** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does |
| 1941 | ** not exist because commands are not being hooked), return TH_OK because we |
| @@ -1940,11 +1952,11 @@ | |
| 1952 | ** clean it up now. This is very important because some commands do not |
| 1953 | ** expect the repository and/or the configuration ("user") database to be |
| 1954 | ** open prior to their own code doing so. |
| 1955 | */ |
| 1956 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1957 | return rc; |
| 1958 | } |
| 1959 | |
| 1960 | /* |
| 1961 | ** This function is called by Fossil just after processing a web page. |
| 1962 | ** Returning a value other than TH_OK from this function (i.e. via an |
| @@ -1975,10 +1987,24 @@ | |
| 1987 | */ |
| 1988 | if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
| 1989 | return rc; |
| 1990 | } |
| 1991 | #endif |
| 1992 | |
| 1993 | |
| 1994 | #ifdef FOSSIL_ENABLE_TH1_DOCS |
| 1995 | /* |
| 1996 | ** This function determines if TH1 docs are enabled for the repository. |
| 1997 | */ |
| 1998 | int Th_AreDocsEnabled(void){ |
| 1999 | if( fossil_getenv("TH1_ENABLE_DOCS")!=0 ){ |
| 2000 | return 1; |
| 2001 | } |
| 2002 | return db_get_boolean("th1-docs", 0); |
| 2003 | } |
| 2004 | #endif |
| 2005 | |
| 2006 | |
| 2007 | /* |
| 2008 | ** The z[] input contains text mixed with TH1 scripts. |
| 2009 | ** The TH1 scripts are contained within <th1>...</th1>. |
| 2010 | ** TH1 variables are $aaa or $<aaa>. The first form of |
| 2011 |
+35
-18
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -752,25 +752,25 @@ | ||
| 752 | 752 | @ }while( obj = obj.offsetParent ); |
| 753 | 753 | @ } |
| 754 | 754 | @ return left; |
| 755 | 755 | @ } |
| 756 | 756 | @ function drawUpArrow(x,y0,y1){ |
| 757 | - @ drawBox(lineClr,x,y0+5,x+1,y1); | |
| 757 | + @ drawBox(lineClr,x,y0+4,x+1,y1); | |
| 758 | 758 | @ var n = document.createElement("div"), |
| 759 | 759 | @ l = x-2, |
| 760 | 760 | @ t = y0; |
| 761 | 761 | @ n.style.position = "absolute"; |
| 762 | 762 | @ n.style.left = l+"px"; |
| 763 | 763 | @ n.style.top = t+"px"; |
| 764 | 764 | @ n.style.width = 0; |
| 765 | 765 | @ n.style.height = 0; |
| 766 | + @ n.style.transform = "scale(.999)"; | |
| 766 | 767 | @ n.style.borderWidth = 0; |
| 767 | 768 | @ n.style.borderStyle = "solid"; |
| 768 | 769 | @ n.style.borderColor = "transparent"; |
| 769 | 770 | @ n.style.borderRightWidth = "3px"; |
| 770 | - @ n.style.borderBottomColor = "#000"; | |
| 771 | - @ n.style.borderBottomStyle = "outset"; | |
| 771 | + @ n.style.borderBottomColor = lineClr; | |
| 772 | 772 | @ n.style.borderLeftWidth = "3px"; |
| 773 | 773 | @ if( y0+10>=y1 ){ |
| 774 | 774 | @ n.style.borderBottomWidth = "5px"; |
| 775 | 775 | @ } else { |
| 776 | 776 | @ n.style.borderBottomWidth = "7px"; |
| @@ -782,27 +782,26 @@ | ||
| 782 | 782 | @ t = y-2; |
| 783 | 783 | @ n.style.position = "absolute"; |
| 784 | 784 | @ n.style.top = t+"px"; |
| 785 | 785 | @ n.style.width = 0; |
| 786 | 786 | @ n.style.height = "1px"; |
| 787 | + @ n.style.transform = "scale(.999)"; | |
| 787 | 788 | @ n.style.borderWidth = 0; |
| 788 | 789 | @ n.style.borderStyle = "solid"; |
| 789 | 790 | @ n.style.borderColor = "transparent"; |
| 790 | 791 | @ n.style.borderTopWidth = "2px"; |
| 791 | 792 | @ n.style.borderBottomWidth = "2px"; |
| 792 | 793 | @ if( xFrom<xTo ){ |
| 793 | 794 | @ drawBox(lineClr,xFrom,y,xTo-3,y); |
| 794 | 795 | @ n.style.left = xTo-3+"px"; |
| 795 | - @ n.style.borderLeftStyle = "inset"; | |
| 796 | 796 | @ n.style.borderLeftWidth = "3px"; |
| 797 | - @ n.style.borderLeftColor = "#000"; | |
| 797 | + @ n.style.borderLeftColor = lineClr; | |
| 798 | 798 | @ }else{ |
| 799 | 799 | @ drawBox(lineClr,xTo+3,y,xFrom,y); |
| 800 | 800 | @ n.style.left = xTo+1+"px"; |
| 801 | - @ n.style.borderRightStyle = "outset"; | |
| 802 | 801 | @ n.style.borderRightWidth = "3px"; |
| 803 | - @ n.style.borderRightColor = "#000"; | |
| 802 | + @ n.style.borderRightColor = lineClr; | |
| 804 | 803 | @ } |
| 805 | 804 | @ cDiv.appendChild(n); |
| 806 | 805 | @ } |
| 807 | 806 | @ function drawThinLine(x0,y0,x1,y1){ |
| 808 | 807 | @ drawBox(lineClr,x0,y0,x1,y1); |
| @@ -851,16 +850,16 @@ | ||
| 851 | 850 | @ n.style.position = "absolute"; |
| 852 | 851 | @ n.style.top = t+"px"; |
| 853 | 852 | @ n.style.left = l+"px"; |
| 854 | 853 | @ n.style.width = 0; |
| 855 | 854 | @ n.style.height = 0; |
| 855 | + @ n.style.transform = "scale(.999)"; | |
| 856 | 856 | @ n.style.borderWidth = 0; |
| 857 | 857 | @ n.style.borderStyle = "solid"; |
| 858 | 858 | @ n.style.borderColor = "transparent"; |
| 859 | 859 | @ n.style.borderTopWidth = "3px"; |
| 860 | 860 | @ n.style.borderBottomWidth = "3px"; |
| 861 | - @ n.style.borderLeftStyle = "inset"; | |
| 862 | 861 | @ n.style.borderLeftWidth = "7px"; |
| 863 | 862 | @ n.style.borderLeftColor = "#600000"; |
| 864 | 863 | @ cDiv.appendChild(n); |
| 865 | 864 | @ } |
| 866 | 865 | @ } |
| @@ -1421,11 +1420,11 @@ | ||
| 1421 | 1420 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1422 | 1421 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1423 | 1422 | } |
| 1424 | 1423 | }else{ |
| 1425 | 1424 | /* Otherwise, a timeline based on a span of time */ |
| 1426 | - int n; | |
| 1425 | + int n, nBefore, nAfter; | |
| 1427 | 1426 | const char *zEType = "timeline item"; |
| 1428 | 1427 | char *zDate; |
| 1429 | 1428 | if( zUses ){ |
| 1430 | 1429 | blob_append_sql(&sql, " AND event.objid IN usesfile "); |
| 1431 | 1430 | } |
| @@ -1629,20 +1628,38 @@ | ||
| 1629 | 1628 | } |
| 1630 | 1629 | if( zSearch ){ |
| 1631 | 1630 | blob_appendf(&desc, " matching \"%h\"", zSearch); |
| 1632 | 1631 | } |
| 1633 | 1632 | if( g.perm.Hyperlink ){ |
| 1634 | - if( zAfter || n==nEntry ){ | |
| 1633 | + if( zCirca && rCirca ){ | |
| 1634 | + nBefore = db_int(0, | |
| 1635 | + "SELECT count(*) FROM timeline WHERE etype!='div'" | |
| 1636 | + " AND sortby<=%f /*scan*/", rCirca); | |
| 1637 | + nAfter = db_int(0, | |
| 1638 | + "SELECT count(*) FROM timeline WHERE etype!='div'" | |
| 1639 | + " AND sortby>=%f /*scan*/", rCirca); | |
| 1635 | 1640 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); |
| 1636 | - timeline_submenu(&url, "Older", "b", zDate, "a"); | |
| 1637 | - zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0)); | |
| 1638 | - free(zDate); | |
| 1639 | - } | |
| 1640 | - if( zBefore || (zAfter && n==nEntry) ){ | |
| 1641 | - zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); | |
| 1642 | - timeline_submenu(&url, "Newer", "a", zDate, "b"); | |
| 1643 | - free(zDate); | |
| 1641 | + if( nBefore>=nEntry ){ | |
| 1642 | + timeline_submenu(&url, "Older", "b", zDate, "c"); | |
| 1643 | + zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "c", 0)); | |
| 1644 | + } | |
| 1645 | + if( nAfter>=nEntry ){ | |
| 1646 | + timeline_submenu(&url, "Newer", "a", zDate, "c"); | |
| 1647 | + } | |
| 1648 | + free(zDate); | |
| 1649 | + }else{ | |
| 1650 | + if( zAfter || n==nEntry ){ | |
| 1651 | + zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); | |
| 1652 | + timeline_submenu(&url, "Older", "b", zDate, "a"); | |
| 1653 | + zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0)); | |
| 1654 | + free(zDate); | |
| 1655 | + } | |
| 1656 | + if( zBefore || (zAfter && n==nEntry) ){ | |
| 1657 | + zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); | |
| 1658 | + timeline_submenu(&url, "Newer", "a", zDate, "b"); | |
| 1659 | + free(zDate); | |
| 1660 | + } | |
| 1644 | 1661 | } |
| 1645 | 1662 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 1646 | 1663 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1647 | 1664 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1648 | 1665 | } |
| 1649 | 1666 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -752,25 +752,25 @@ | |
| 752 | @ }while( obj = obj.offsetParent ); |
| 753 | @ } |
| 754 | @ return left; |
| 755 | @ } |
| 756 | @ function drawUpArrow(x,y0,y1){ |
| 757 | @ drawBox(lineClr,x,y0+5,x+1,y1); |
| 758 | @ var n = document.createElement("div"), |
| 759 | @ l = x-2, |
| 760 | @ t = y0; |
| 761 | @ n.style.position = "absolute"; |
| 762 | @ n.style.left = l+"px"; |
| 763 | @ n.style.top = t+"px"; |
| 764 | @ n.style.width = 0; |
| 765 | @ n.style.height = 0; |
| 766 | @ n.style.borderWidth = 0; |
| 767 | @ n.style.borderStyle = "solid"; |
| 768 | @ n.style.borderColor = "transparent"; |
| 769 | @ n.style.borderRightWidth = "3px"; |
| 770 | @ n.style.borderBottomColor = "#000"; |
| 771 | @ n.style.borderBottomStyle = "outset"; |
| 772 | @ n.style.borderLeftWidth = "3px"; |
| 773 | @ if( y0+10>=y1 ){ |
| 774 | @ n.style.borderBottomWidth = "5px"; |
| 775 | @ } else { |
| 776 | @ n.style.borderBottomWidth = "7px"; |
| @@ -782,27 +782,26 @@ | |
| 782 | @ t = y-2; |
| 783 | @ n.style.position = "absolute"; |
| 784 | @ n.style.top = t+"px"; |
| 785 | @ n.style.width = 0; |
| 786 | @ n.style.height = "1px"; |
| 787 | @ n.style.borderWidth = 0; |
| 788 | @ n.style.borderStyle = "solid"; |
| 789 | @ n.style.borderColor = "transparent"; |
| 790 | @ n.style.borderTopWidth = "2px"; |
| 791 | @ n.style.borderBottomWidth = "2px"; |
| 792 | @ if( xFrom<xTo ){ |
| 793 | @ drawBox(lineClr,xFrom,y,xTo-3,y); |
| 794 | @ n.style.left = xTo-3+"px"; |
| 795 | @ n.style.borderLeftStyle = "inset"; |
| 796 | @ n.style.borderLeftWidth = "3px"; |
| 797 | @ n.style.borderLeftColor = "#000"; |
| 798 | @ }else{ |
| 799 | @ drawBox(lineClr,xTo+3,y,xFrom,y); |
| 800 | @ n.style.left = xTo+1+"px"; |
| 801 | @ n.style.borderRightStyle = "outset"; |
| 802 | @ n.style.borderRightWidth = "3px"; |
| 803 | @ n.style.borderRightColor = "#000"; |
| 804 | @ } |
| 805 | @ cDiv.appendChild(n); |
| 806 | @ } |
| 807 | @ function drawThinLine(x0,y0,x1,y1){ |
| 808 | @ drawBox(lineClr,x0,y0,x1,y1); |
| @@ -851,16 +850,16 @@ | |
| 851 | @ n.style.position = "absolute"; |
| 852 | @ n.style.top = t+"px"; |
| 853 | @ n.style.left = l+"px"; |
| 854 | @ n.style.width = 0; |
| 855 | @ n.style.height = 0; |
| 856 | @ n.style.borderWidth = 0; |
| 857 | @ n.style.borderStyle = "solid"; |
| 858 | @ n.style.borderColor = "transparent"; |
| 859 | @ n.style.borderTopWidth = "3px"; |
| 860 | @ n.style.borderBottomWidth = "3px"; |
| 861 | @ n.style.borderLeftStyle = "inset"; |
| 862 | @ n.style.borderLeftWidth = "7px"; |
| 863 | @ n.style.borderLeftColor = "#600000"; |
| 864 | @ cDiv.appendChild(n); |
| 865 | @ } |
| 866 | @ } |
| @@ -1421,11 +1420,11 @@ | |
| 1421 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1422 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1423 | } |
| 1424 | }else{ |
| 1425 | /* Otherwise, a timeline based on a span of time */ |
| 1426 | int n; |
| 1427 | const char *zEType = "timeline item"; |
| 1428 | char *zDate; |
| 1429 | if( zUses ){ |
| 1430 | blob_append_sql(&sql, " AND event.objid IN usesfile "); |
| 1431 | } |
| @@ -1629,20 +1628,38 @@ | |
| 1629 | } |
| 1630 | if( zSearch ){ |
| 1631 | blob_appendf(&desc, " matching \"%h\"", zSearch); |
| 1632 | } |
| 1633 | if( g.perm.Hyperlink ){ |
| 1634 | if( zAfter || n==nEntry ){ |
| 1635 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); |
| 1636 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| 1637 | zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0)); |
| 1638 | free(zDate); |
| 1639 | } |
| 1640 | if( zBefore || (zAfter && n==nEntry) ){ |
| 1641 | zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); |
| 1642 | timeline_submenu(&url, "Newer", "a", zDate, "b"); |
| 1643 | free(zDate); |
| 1644 | } |
| 1645 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 1646 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1647 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1648 | } |
| 1649 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -752,25 +752,25 @@ | |
| 752 | @ }while( obj = obj.offsetParent ); |
| 753 | @ } |
| 754 | @ return left; |
| 755 | @ } |
| 756 | @ function drawUpArrow(x,y0,y1){ |
| 757 | @ drawBox(lineClr,x,y0+4,x+1,y1); |
| 758 | @ var n = document.createElement("div"), |
| 759 | @ l = x-2, |
| 760 | @ t = y0; |
| 761 | @ n.style.position = "absolute"; |
| 762 | @ n.style.left = l+"px"; |
| 763 | @ n.style.top = t+"px"; |
| 764 | @ n.style.width = 0; |
| 765 | @ n.style.height = 0; |
| 766 | @ n.style.transform = "scale(.999)"; |
| 767 | @ n.style.borderWidth = 0; |
| 768 | @ n.style.borderStyle = "solid"; |
| 769 | @ n.style.borderColor = "transparent"; |
| 770 | @ n.style.borderRightWidth = "3px"; |
| 771 | @ n.style.borderBottomColor = lineClr; |
| 772 | @ n.style.borderLeftWidth = "3px"; |
| 773 | @ if( y0+10>=y1 ){ |
| 774 | @ n.style.borderBottomWidth = "5px"; |
| 775 | @ } else { |
| 776 | @ n.style.borderBottomWidth = "7px"; |
| @@ -782,27 +782,26 @@ | |
| 782 | @ t = y-2; |
| 783 | @ n.style.position = "absolute"; |
| 784 | @ n.style.top = t+"px"; |
| 785 | @ n.style.width = 0; |
| 786 | @ n.style.height = "1px"; |
| 787 | @ n.style.transform = "scale(.999)"; |
| 788 | @ n.style.borderWidth = 0; |
| 789 | @ n.style.borderStyle = "solid"; |
| 790 | @ n.style.borderColor = "transparent"; |
| 791 | @ n.style.borderTopWidth = "2px"; |
| 792 | @ n.style.borderBottomWidth = "2px"; |
| 793 | @ if( xFrom<xTo ){ |
| 794 | @ drawBox(lineClr,xFrom,y,xTo-3,y); |
| 795 | @ n.style.left = xTo-3+"px"; |
| 796 | @ n.style.borderLeftWidth = "3px"; |
| 797 | @ n.style.borderLeftColor = lineClr; |
| 798 | @ }else{ |
| 799 | @ drawBox(lineClr,xTo+3,y,xFrom,y); |
| 800 | @ n.style.left = xTo+1+"px"; |
| 801 | @ n.style.borderRightWidth = "3px"; |
| 802 | @ n.style.borderRightColor = lineClr; |
| 803 | @ } |
| 804 | @ cDiv.appendChild(n); |
| 805 | @ } |
| 806 | @ function drawThinLine(x0,y0,x1,y1){ |
| 807 | @ drawBox(lineClr,x0,y0,x1,y1); |
| @@ -851,16 +850,16 @@ | |
| 850 | @ n.style.position = "absolute"; |
| 851 | @ n.style.top = t+"px"; |
| 852 | @ n.style.left = l+"px"; |
| 853 | @ n.style.width = 0; |
| 854 | @ n.style.height = 0; |
| 855 | @ n.style.transform = "scale(.999)"; |
| 856 | @ n.style.borderWidth = 0; |
| 857 | @ n.style.borderStyle = "solid"; |
| 858 | @ n.style.borderColor = "transparent"; |
| 859 | @ n.style.borderTopWidth = "3px"; |
| 860 | @ n.style.borderBottomWidth = "3px"; |
| 861 | @ n.style.borderLeftWidth = "7px"; |
| 862 | @ n.style.borderLeftColor = "#600000"; |
| 863 | @ cDiv.appendChild(n); |
| 864 | @ } |
| 865 | @ } |
| @@ -1421,11 +1420,11 @@ | |
| 1420 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1421 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1422 | } |
| 1423 | }else{ |
| 1424 | /* Otherwise, a timeline based on a span of time */ |
| 1425 | int n, nBefore, nAfter; |
| 1426 | const char *zEType = "timeline item"; |
| 1427 | char *zDate; |
| 1428 | if( zUses ){ |
| 1429 | blob_append_sql(&sql, " AND event.objid IN usesfile "); |
| 1430 | } |
| @@ -1629,20 +1628,38 @@ | |
| 1628 | } |
| 1629 | if( zSearch ){ |
| 1630 | blob_appendf(&desc, " matching \"%h\"", zSearch); |
| 1631 | } |
| 1632 | if( g.perm.Hyperlink ){ |
| 1633 | if( zCirca && rCirca ){ |
| 1634 | nBefore = db_int(0, |
| 1635 | "SELECT count(*) FROM timeline WHERE etype!='div'" |
| 1636 | " AND sortby<=%f /*scan*/", rCirca); |
| 1637 | nAfter = db_int(0, |
| 1638 | "SELECT count(*) FROM timeline WHERE etype!='div'" |
| 1639 | " AND sortby>=%f /*scan*/", rCirca); |
| 1640 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); |
| 1641 | if( nBefore>=nEntry ){ |
| 1642 | timeline_submenu(&url, "Older", "b", zDate, "c"); |
| 1643 | zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "c", 0)); |
| 1644 | } |
| 1645 | if( nAfter>=nEntry ){ |
| 1646 | timeline_submenu(&url, "Newer", "a", zDate, "c"); |
| 1647 | } |
| 1648 | free(zDate); |
| 1649 | }else{ |
| 1650 | if( zAfter || n==nEntry ){ |
| 1651 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); |
| 1652 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| 1653 | zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0)); |
| 1654 | free(zDate); |
| 1655 | } |
| 1656 | if( zBefore || (zAfter && n==nEntry) ){ |
| 1657 | zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); |
| 1658 | timeline_submenu(&url, "Newer", "a", zDate, "b"); |
| 1659 | free(zDate); |
| 1660 | } |
| 1661 | } |
| 1662 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 1663 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1664 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1665 | } |
| 1666 |
+2
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -1250,10 +1250,12 @@ | ||
| 1250 | 1250 | zTerm = "]</span>"; |
| 1251 | 1251 | } |
| 1252 | 1252 | }else if( g.perm.Hyperlink ){ |
| 1253 | 1253 | blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget)); |
| 1254 | 1254 | zTerm = "]</a>"; |
| 1255 | + }else{ | |
| 1256 | + zTerm = ""; | |
| 1255 | 1257 | } |
| 1256 | 1258 | }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' |
| 1257 | 1259 | && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ |
| 1258 | 1260 | blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget); |
| 1259 | 1261 | }else if( (z = validWikiPageName(p, zTarget))!=0 ){ |
| 1260 | 1262 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -1250,10 +1250,12 @@ | |
| 1250 | zTerm = "]</span>"; |
| 1251 | } |
| 1252 | }else if( g.perm.Hyperlink ){ |
| 1253 | blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget)); |
| 1254 | zTerm = "]</a>"; |
| 1255 | } |
| 1256 | }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' |
| 1257 | && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ |
| 1258 | blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget); |
| 1259 | }else if( (z = validWikiPageName(p, zTarget))!=0 ){ |
| 1260 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -1250,10 +1250,12 @@ | |
| 1250 | zTerm = "]</span>"; |
| 1251 | } |
| 1252 | }else if( g.perm.Hyperlink ){ |
| 1253 | blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget)); |
| 1254 | zTerm = "]</a>"; |
| 1255 | }else{ |
| 1256 | zTerm = ""; |
| 1257 | } |
| 1258 | }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' |
| 1259 | && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ |
| 1260 | blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget); |
| 1261 | }else if( (z = validWikiPageName(p, zTarget))!=0 ){ |
| 1262 |
+18
-17
| --- src/xfersetup.c | ||
| +++ src/xfersetup.c | ||
| @@ -33,11 +33,11 @@ | ||
| 33 | 33 | return; |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | style_header("Transfer Setup"); |
| 37 | 37 | |
| 38 | - @ <table border="0" cellspacing="20"> | |
| 38 | + @ <table class="xfersetup"> | |
| 39 | 39 | setup_menu_entry("Common", "xfersetup_com", |
| 40 | 40 | "Common TH1 code run before all transfer request processing."); |
| 41 | 41 | setup_menu_entry("Push", "xfersetup_push", |
| 42 | 42 | "Specific TH1 code to run after \"push\" transfer requests."); |
| 43 | 43 | setup_menu_entry("Commit", "xfersetup_commit", |
| @@ -60,33 +60,33 @@ | ||
| 60 | 60 | syncFlags = SYNC_PUSH | SYNC_PULL; |
| 61 | 61 | zButton = "Synchronize"; |
| 62 | 62 | zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.", |
| 63 | 63 | g.url.canonical); |
| 64 | 64 | } |
| 65 | - if( P("sync") ){ | |
| 66 | - user_select(); | |
| 67 | - url_enable_proxy(0); | |
| 68 | - client_sync(syncFlags, 0, 0); | |
| 69 | - } | |
| 70 | - @ <p>Press the %h(zButton) button below to synchronize with the | |
| 71 | - @ "%h(g.url.canonical)" repository now. This may be useful when | |
| 72 | - @ testing the various transfer scripts.</p> | |
| 73 | - @ <p>You can use the "http -async" command in your scripts, but | |
| 74 | - @ make sure the "th1-uri-regexp" setting is set first.</p> | |
| 65 | + @ <p>Press the <strong>%h(zButton)</strong> button below to | |
| 66 | + @ synchronize with the <em>%h(g.url.canonical)</em> repository now.<br/> | |
| 67 | + @ This may be useful when testing the various transfer scripts.</p> | |
| 68 | + @ <p>You can use the <code>http -async</code> command in your scripts, but | |
| 69 | + @ make sure the <code>th1-uri-regexp</code> setting is set first.</p> | |
| 75 | 70 | if( zWarning ){ |
| 76 | 71 | @ |
| 77 | 72 | @ <big><b>%h(zWarning)</b></big> |
| 78 | 73 | free(zWarning); |
| 79 | 74 | } |
| 80 | 75 | @ |
| 81 | - @ <blockquote> | |
| 82 | 76 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 83 | 77 | login_insert_csrf_secret(); |
| 84 | 78 | @ <input type="submit" name="sync" value="%h(zButton)" /> |
| 85 | 79 | @ </div></form> |
| 86 | - @ </blockquote> | |
| 87 | 80 | @ |
| 81 | + if( P("sync") ){ | |
| 82 | + user_select(); | |
| 83 | + url_enable_proxy(0); | |
| 84 | + @ <pre class="xfersetup"> | |
| 85 | + client_sync(syncFlags, 0, 0); | |
| 86 | + @ </pre> | |
| 87 | + } | |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | 90 | style_footer(); |
| 91 | 91 | } |
| 92 | 92 | |
| @@ -137,18 +137,18 @@ | ||
| 137 | 137 | } |
| 138 | 138 | @ <form action="%s(g.zTop)/%s(g.zPath)" method="post"><div> |
| 139 | 139 | login_insert_csrf_secret(); |
| 140 | 140 | @ <p>%s(zDesc)</p> |
| 141 | 141 | @ <textarea name="x" rows="%d(height)" cols="80">%h(z)</textarea> |
| 142 | - @ <blockquote><p> | |
| 142 | + @ <p> | |
| 143 | 143 | @ <input type="submit" name="submit" value="Apply Changes" /> |
| 144 | 144 | @ <input type="submit" name="clear" value="Revert To Default" /> |
| 145 | 145 | @ <input type="submit" name="setup" value="Cancel" /> |
| 146 | - @ </p></blockquote> | |
| 146 | + @ </p> | |
| 147 | 147 | @ </div></form> |
| 148 | - @ <hr /> | |
| 149 | 148 | if ( zDfltValue ){ |
| 149 | + @ <hr /> | |
| 150 | 150 | @ <h2>Default %s(zTitle)</h2> |
| 151 | 151 | @ <blockquote><pre> |
| 152 | 152 | @ %h(zDfltValue) |
| 153 | 153 | @ </pre></blockquote> |
| 154 | 154 | } |
| @@ -181,11 +181,12 @@ | ||
| 181 | 181 | /* |
| 182 | 182 | ** WEBPAGE: xfersetup_push |
| 183 | 183 | */ |
| 184 | 184 | void xfersetup_push_page(void){ |
| 185 | 185 | static const char zDesc[] = |
| 186 | - @ Enter TH1 script that runs after processing "push" transfer requests. | |
| 186 | + @ Enter TH1 script that runs after processing <strong>push</strong> | |
| 187 | + @ transfer requests. | |
| 187 | 188 | ; |
| 188 | 189 | xfersetup_generic( |
| 189 | 190 | "Transfer Push Script", |
| 190 | 191 | "xfer-push-script", |
| 191 | 192 | zDefaultXferPush, |
| 192 | 193 | |
| 193 | 194 | ADDED test/fileStat.th1 |
| --- src/xfersetup.c | |
| +++ src/xfersetup.c | |
| @@ -33,11 +33,11 @@ | |
| 33 | return; |
| 34 | } |
| 35 | |
| 36 | style_header("Transfer Setup"); |
| 37 | |
| 38 | @ <table border="0" cellspacing="20"> |
| 39 | setup_menu_entry("Common", "xfersetup_com", |
| 40 | "Common TH1 code run before all transfer request processing."); |
| 41 | setup_menu_entry("Push", "xfersetup_push", |
| 42 | "Specific TH1 code to run after \"push\" transfer requests."); |
| 43 | setup_menu_entry("Commit", "xfersetup_commit", |
| @@ -60,33 +60,33 @@ | |
| 60 | syncFlags = SYNC_PUSH | SYNC_PULL; |
| 61 | zButton = "Synchronize"; |
| 62 | zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.", |
| 63 | g.url.canonical); |
| 64 | } |
| 65 | if( P("sync") ){ |
| 66 | user_select(); |
| 67 | url_enable_proxy(0); |
| 68 | client_sync(syncFlags, 0, 0); |
| 69 | } |
| 70 | @ <p>Press the %h(zButton) button below to synchronize with the |
| 71 | @ "%h(g.url.canonical)" repository now. This may be useful when |
| 72 | @ testing the various transfer scripts.</p> |
| 73 | @ <p>You can use the "http -async" command in your scripts, but |
| 74 | @ make sure the "th1-uri-regexp" setting is set first.</p> |
| 75 | if( zWarning ){ |
| 76 | @ |
| 77 | @ <big><b>%h(zWarning)</b></big> |
| 78 | free(zWarning); |
| 79 | } |
| 80 | @ |
| 81 | @ <blockquote> |
| 82 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 83 | login_insert_csrf_secret(); |
| 84 | @ <input type="submit" name="sync" value="%h(zButton)" /> |
| 85 | @ </div></form> |
| 86 | @ </blockquote> |
| 87 | @ |
| 88 | } |
| 89 | |
| 90 | style_footer(); |
| 91 | } |
| 92 | |
| @@ -137,18 +137,18 @@ | |
| 137 | } |
| 138 | @ <form action="%s(g.zTop)/%s(g.zPath)" method="post"><div> |
| 139 | login_insert_csrf_secret(); |
| 140 | @ <p>%s(zDesc)</p> |
| 141 | @ <textarea name="x" rows="%d(height)" cols="80">%h(z)</textarea> |
| 142 | @ <blockquote><p> |
| 143 | @ <input type="submit" name="submit" value="Apply Changes" /> |
| 144 | @ <input type="submit" name="clear" value="Revert To Default" /> |
| 145 | @ <input type="submit" name="setup" value="Cancel" /> |
| 146 | @ </p></blockquote> |
| 147 | @ </div></form> |
| 148 | @ <hr /> |
| 149 | if ( zDfltValue ){ |
| 150 | @ <h2>Default %s(zTitle)</h2> |
| 151 | @ <blockquote><pre> |
| 152 | @ %h(zDfltValue) |
| 153 | @ </pre></blockquote> |
| 154 | } |
| @@ -181,11 +181,12 @@ | |
| 181 | /* |
| 182 | ** WEBPAGE: xfersetup_push |
| 183 | */ |
| 184 | void xfersetup_push_page(void){ |
| 185 | static const char zDesc[] = |
| 186 | @ Enter TH1 script that runs after processing "push" transfer requests. |
| 187 | ; |
| 188 | xfersetup_generic( |
| 189 | "Transfer Push Script", |
| 190 | "xfer-push-script", |
| 191 | zDefaultXferPush, |
| 192 | |
| 193 | DDED test/fileStat.th1 |
| --- src/xfersetup.c | |
| +++ src/xfersetup.c | |
| @@ -33,11 +33,11 @@ | |
| 33 | return; |
| 34 | } |
| 35 | |
| 36 | style_header("Transfer Setup"); |
| 37 | |
| 38 | @ <table class="xfersetup"> |
| 39 | setup_menu_entry("Common", "xfersetup_com", |
| 40 | "Common TH1 code run before all transfer request processing."); |
| 41 | setup_menu_entry("Push", "xfersetup_push", |
| 42 | "Specific TH1 code to run after \"push\" transfer requests."); |
| 43 | setup_menu_entry("Commit", "xfersetup_commit", |
| @@ -60,33 +60,33 @@ | |
| 60 | syncFlags = SYNC_PUSH | SYNC_PULL; |
| 61 | zButton = "Synchronize"; |
| 62 | zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.", |
| 63 | g.url.canonical); |
| 64 | } |
| 65 | @ <p>Press the <strong>%h(zButton)</strong> button below to |
| 66 | @ synchronize with the <em>%h(g.url.canonical)</em> repository now.<br/> |
| 67 | @ This may be useful when testing the various transfer scripts.</p> |
| 68 | @ <p>You can use the <code>http -async</code> command in your scripts, but |
| 69 | @ make sure the <code>th1-uri-regexp</code> setting is set first.</p> |
| 70 | if( zWarning ){ |
| 71 | @ |
| 72 | @ <big><b>%h(zWarning)</b></big> |
| 73 | free(zWarning); |
| 74 | } |
| 75 | @ |
| 76 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 77 | login_insert_csrf_secret(); |
| 78 | @ <input type="submit" name="sync" value="%h(zButton)" /> |
| 79 | @ </div></form> |
| 80 | @ |
| 81 | if( P("sync") ){ |
| 82 | user_select(); |
| 83 | url_enable_proxy(0); |
| 84 | @ <pre class="xfersetup"> |
| 85 | client_sync(syncFlags, 0, 0); |
| 86 | @ </pre> |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | style_footer(); |
| 91 | } |
| 92 | |
| @@ -137,18 +137,18 @@ | |
| 137 | } |
| 138 | @ <form action="%s(g.zTop)/%s(g.zPath)" method="post"><div> |
| 139 | login_insert_csrf_secret(); |
| 140 | @ <p>%s(zDesc)</p> |
| 141 | @ <textarea name="x" rows="%d(height)" cols="80">%h(z)</textarea> |
| 142 | @ <p> |
| 143 | @ <input type="submit" name="submit" value="Apply Changes" /> |
| 144 | @ <input type="submit" name="clear" value="Revert To Default" /> |
| 145 | @ <input type="submit" name="setup" value="Cancel" /> |
| 146 | @ </p> |
| 147 | @ </div></form> |
| 148 | if ( zDfltValue ){ |
| 149 | @ <hr /> |
| 150 | @ <h2>Default %s(zTitle)</h2> |
| 151 | @ <blockquote><pre> |
| 152 | @ %h(zDfltValue) |
| 153 | @ </pre></blockquote> |
| 154 | } |
| @@ -181,11 +181,12 @@ | |
| 181 | /* |
| 182 | ** WEBPAGE: xfersetup_push |
| 183 | */ |
| 184 | void xfersetup_push_page(void){ |
| 185 | static const char zDesc[] = |
| 186 | @ Enter TH1 script that runs after processing <strong>push</strong> |
| 187 | @ transfer requests. |
| 188 | ; |
| 189 | xfersetup_generic( |
| 190 | "Transfer Push Script", |
| 191 | "xfer-push-script", |
| 192 | zDefaultXferPush, |
| 193 | |
| 194 | DDED test/fileStat.th1 |
+29
| --- a/test/fileStat.th1 | ||
| +++ b/test/fileStat.th1 | ||
| @@ -0,0 +1,29 @@ | ||
| 1 | +<th1> | |
| 2 | + proc doSomeTclSetup {} { | |
| 3 | + # | |
| 4 | + # NOTE: Copy repository file name to the Tcl interpreter. This is | |
| 5 | + # done first (once) because it will be necessary for almost | |
| 6 | + # everything else later on. | |
| 7 | + # | |
| 8 | + tclInvoke set repository [repository] | |
| 9 | + | |
| 10 | + # | |
| 11 | + # NOTE: Create some procedures in the Tcl interpreter to perform | |
| 12 | + # useful operations. This could also do things like load | |
| 13 | + # packages, etc. | |
| 14 | + # | |
| 15 | + tclEval { | |
| 16 | + # | |
| 17 | + # NOTE: Returns an [exec] command for Fossil, using the provided | |
| 18 | + # sub-command and arguments, suitable for use with [eval] | |
| 19 | + # or [catch]. | |
| 20 | + # | |
| 21 | + proc getFossilCommand { repository user args } { | |
| 22 | + global env | |
| 23 | + | |
| 24 | + lappend result exec [info nameofexecutable] | |
| 25 | + | |
| 26 | + if {[info exists env(GATEWAY_INTERFACE)]} then { | |
| 27 | + # | |
| 28 | + # NOTE: This option is required when calling | |
| 29 | + # out to |
| --- a/test/fileStat.th1 | |
| +++ b/test/fileStat.th1 | |
| @@ -0,0 +1,29 @@ | |
| --- a/test/fileStat.th1 | |
| +++ b/test/fileStat.th1 | |
| @@ -0,0 +1,29 @@ | |
| 1 | <th1> |
| 2 | proc doSomeTclSetup {} { |
| 3 | # |
| 4 | # NOTE: Copy repository file name to the Tcl interpreter. This is |
| 5 | # done first (once) because it will be necessary for almost |
| 6 | # everything else later on. |
| 7 | # |
| 8 | tclInvoke set repository [repository] |
| 9 | |
| 10 | # |
| 11 | # NOTE: Create some procedures in the Tcl interpreter to perform |
| 12 | # useful operations. This could also do things like load |
| 13 | # packages, etc. |
| 14 | # |
| 15 | tclEval { |
| 16 | # |
| 17 | # NOTE: Returns an [exec] command for Fossil, using the provided |
| 18 | # sub-command and arguments, suitable for use with [eval] |
| 19 | # or [catch]. |
| 20 | # |
| 21 | proc getFossilCommand { repository user args } { |
| 22 | global env |
| 23 | |
| 24 | lappend result exec [info nameofexecutable] |
| 25 | |
| 26 | if {[info exists env(GATEWAY_INTERFACE)]} then { |
| 27 | # |
| 28 | # NOTE: This option is required when calling |
| 29 | # out to |
+66
| --- test/tester.tcl | ||
| +++ test/tester.tcl | ||
| @@ -328,10 +328,76 @@ | ||
| 328 | 328 | } |
| 329 | 329 | append out \n$line |
| 330 | 330 | } |
| 331 | 331 | return [string range $out 1 end] |
| 332 | 332 | } |
| 333 | + | |
| 334 | +# Executes the "fossil http" command. The entire content of the HTTP request | |
| 335 | +# is read from the data file name, with [subst] being performed on it prior to | |
| 336 | +# submission. Temporary input and output files are created and deleted. The | |
| 337 | +# result will be the contents of the temoprary output file. | |
| 338 | +proc test_fossil_http { repository dataFileName url } { | |
| 339 | + set suffix [appendArgs [pid] - [getSeqNo] - [clock seconds] .txt] | |
| 340 | + set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] | |
| 341 | + set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] | |
| 342 | + set data [subst [read_file $dataFileName]] | |
| 343 | + | |
| 344 | + write_file $inFileName $data | |
| 345 | + fossil http $inFileName $outFileName 127.0.0.1 $repository --localauth | |
| 346 | + set result [expr {[file exists $outFileName] ? [read_file $outFileName] : ""}] | |
| 347 | + | |
| 348 | + if {1} then { | |
| 349 | + catch {file delete $inFileName} | |
| 350 | + catch {file delete $outFileName} | |
| 351 | + } | |
| 352 | + | |
| 353 | + return $result | |
| 354 | +} | |
| 355 | + | |
| 356 | +# obtains and increments a "sequence number" for this test run. | |
| 357 | +proc getSeqNo {} { | |
| 358 | + upvar #0 seqNo seqNo | |
| 359 | + if {![info exists seqNo]} { | |
| 360 | + set seqNo 0 | |
| 361 | + } | |
| 362 | + return [incr seqNo] | |
| 363 | +} | |
| 364 | + | |
| 365 | +# fixup the whitespace in the result to make it easier to compare. | |
| 366 | +proc normalize_result {} { | |
| 367 | + return [string map [list \r\n \n] [string trim $::RESULT]] | |
| 368 | +} | |
| 369 | + | |
| 370 | +# returns the first line of the normalized result. | |
| 371 | +proc first_data_line {} { | |
| 372 | + return [lindex [split [normalize_result] \n] 0] | |
| 373 | +} | |
| 374 | + | |
| 375 | +# returns the second line of the normalized result. | |
| 376 | +proc second_data_line {} { | |
| 377 | + return [lindex [split [normalize_result] \n] 1] | |
| 378 | +} | |
| 379 | + | |
| 380 | +# returns the third line of the normalized result. | |
| 381 | +proc third_data_line {} { | |
| 382 | + return [lindex [split [normalize_result] \n] 2] | |
| 383 | +} | |
| 384 | + | |
| 385 | +# returns the last line of the normalized result. | |
| 386 | +proc last_data_line {} { | |
| 387 | + return [lindex [split [normalize_result] \n] end] | |
| 388 | +} | |
| 389 | + | |
| 390 | +# returns the second to last line of the normalized result. | |
| 391 | +proc next_to_last_data_line {} { | |
| 392 | + return [lindex [split [normalize_result] \n] end-1] | |
| 393 | +} | |
| 394 | + | |
| 395 | +# returns the third to last line of the normalized result. | |
| 396 | +proc third_to_last_data_line {} { | |
| 397 | + return [lindex [split [normalize_result] \n] end-2] | |
| 398 | +} | |
| 333 | 399 | |
| 334 | 400 | protInit $fossilexe |
| 335 | 401 | foreach testfile $argv { |
| 336 | 402 | set dir [file root [file tail $testfile]] |
| 337 | 403 | file delete -force $dir |
| 338 | 404 | |
| 339 | 405 | ADDED test/th1-docs-input.txt |
| 340 | 406 | ADDED test/th1-docs.test |
| --- test/tester.tcl | |
| +++ test/tester.tcl | |
| @@ -328,10 +328,76 @@ | |
| 328 | } |
| 329 | append out \n$line |
| 330 | } |
| 331 | return [string range $out 1 end] |
| 332 | } |
| 333 | |
| 334 | protInit $fossilexe |
| 335 | foreach testfile $argv { |
| 336 | set dir [file root [file tail $testfile]] |
| 337 | file delete -force $dir |
| 338 | |
| 339 | DDED test/th1-docs-input.txt |
| 340 | DDED test/th1-docs.test |
| --- test/tester.tcl | |
| +++ test/tester.tcl | |
| @@ -328,10 +328,76 @@ | |
| 328 | } |
| 329 | append out \n$line |
| 330 | } |
| 331 | return [string range $out 1 end] |
| 332 | } |
| 333 | |
| 334 | # Executes the "fossil http" command. The entire content of the HTTP request |
| 335 | # is read from the data file name, with [subst] being performed on it prior to |
| 336 | # submission. Temporary input and output files are created and deleted. The |
| 337 | # result will be the contents of the temoprary output file. |
| 338 | proc test_fossil_http { repository dataFileName url } { |
| 339 | set suffix [appendArgs [pid] - [getSeqNo] - [clock seconds] .txt] |
| 340 | set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] |
| 341 | set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] |
| 342 | set data [subst [read_file $dataFileName]] |
| 343 | |
| 344 | write_file $inFileName $data |
| 345 | fossil http $inFileName $outFileName 127.0.0.1 $repository --localauth |
| 346 | set result [expr {[file exists $outFileName] ? [read_file $outFileName] : ""}] |
| 347 | |
| 348 | if {1} then { |
| 349 | catch {file delete $inFileName} |
| 350 | catch {file delete $outFileName} |
| 351 | } |
| 352 | |
| 353 | return $result |
| 354 | } |
| 355 | |
| 356 | # obtains and increments a "sequence number" for this test run. |
| 357 | proc getSeqNo {} { |
| 358 | upvar #0 seqNo seqNo |
| 359 | if {![info exists seqNo]} { |
| 360 | set seqNo 0 |
| 361 | } |
| 362 | return [incr seqNo] |
| 363 | } |
| 364 | |
| 365 | # fixup the whitespace in the result to make it easier to compare. |
| 366 | proc normalize_result {} { |
| 367 | return [string map [list \r\n \n] [string trim $::RESULT]] |
| 368 | } |
| 369 | |
| 370 | # returns the first line of the normalized result. |
| 371 | proc first_data_line {} { |
| 372 | return [lindex [split [normalize_result] \n] 0] |
| 373 | } |
| 374 | |
| 375 | # returns the second line of the normalized result. |
| 376 | proc second_data_line {} { |
| 377 | return [lindex [split [normalize_result] \n] 1] |
| 378 | } |
| 379 | |
| 380 | # returns the third line of the normalized result. |
| 381 | proc third_data_line {} { |
| 382 | return [lindex [split [normalize_result] \n] 2] |
| 383 | } |
| 384 | |
| 385 | # returns the last line of the normalized result. |
| 386 | proc last_data_line {} { |
| 387 | return [lindex [split [normalize_result] \n] end] |
| 388 | } |
| 389 | |
| 390 | # returns the second to last line of the normalized result. |
| 391 | proc next_to_last_data_line {} { |
| 392 | return [lindex [split [normalize_result] \n] end-1] |
| 393 | } |
| 394 | |
| 395 | # returns the third to last line of the normalized result. |
| 396 | proc third_to_last_data_line {} { |
| 397 | return [lindex [split [normalize_result] \n] end-2] |
| 398 | } |
| 399 | |
| 400 | protInit $fossilexe |
| 401 | foreach testfile $argv { |
| 402 | set dir [file root [file tail $testfile]] |
| 403 | file delete -force $dir |
| 404 | |
| 405 | DDED test/th1-docs-input.txt |
| 406 | DDED test/th1-docs.test |
| --- a/test/th1-docs-input.txt | ||
| +++ b/test/th1-docs-input.txt | ||
| @@ -0,0 +1,4 @@ | ||
| 1 | +GET ${url} HTTP/1.1 | |
| 2 | +Host: localhost | |
| 3 | +User-Agent: Fossil | |
| 4 | + |
| --- a/test/th1-docs-input.txt | |
| +++ b/test/th1-docs-input.txt | |
| @@ -0,0 +1,4 @@ | |
| --- a/test/th1-docs-input.txt | |
| +++ b/test/th1-docs-input.txt | |
| @@ -0,0 +1,4 @@ | |
| 1 | GET ${url} HTTP/1.1 |
| 2 | Host: localhost |
| 3 | User-Agent: Fossil |
| 4 |
+1
| --- a/test/th1-docs.test | ||
| +++ b/test/th1-docs.test | ||
| @@ -0,0 +1 @@ | ||
| 1 | +thenthenthenset data [fossil info] |
| --- a/test/th1-docs.test | |
| +++ b/test/th1-docs.test | |
| @@ -0,0 +1 @@ | |
| --- a/test/th1-docs.test | |
| +++ b/test/th1-docs.test | |
| @@ -0,0 +1 @@ | |
| 1 | thenthenthenset data [fossil info] |
+44
-53
| --- test/th1-hooks.test | ||
| +++ test/th1-hooks.test | ||
| @@ -28,50 +28,10 @@ | ||
| 28 | 28 | |
| 29 | 29 | set env(TH1_ENABLE_HOOKS) 1; # TH1 hooks must be enabled for this test. |
| 30 | 30 | |
| 31 | 31 | ############################################################################### |
| 32 | 32 | |
| 33 | -proc fossil_th1_hook_http { repository url } { | |
| 34 | - set suffix [appendArgs [pid] - [clock seconds] .txt] | |
| 35 | - set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] | |
| 36 | - set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] | |
| 37 | - set data [subst [read_file [file join $::testdir th1-hooks-input.txt]]] | |
| 38 | - | |
| 39 | - write_file $inFileName $data | |
| 40 | - fossil http $repository $inFileName $outFileName 127.0.0.1 | |
| 41 | - set result [expr {[file exists $outFileName] ? [read_file $outFileName] : ""}] | |
| 42 | - | |
| 43 | - if {1} then { | |
| 44 | - catch {file delete $inFileName} | |
| 45 | - catch {file delete $outFileName} | |
| 46 | - } | |
| 47 | - | |
| 48 | - return $result | |
| 49 | -} | |
| 50 | - | |
| 51 | -proc first_data_line {} { | |
| 52 | - return [lindex [split [string trim $::RESULT] \r\n] 0] | |
| 53 | -} | |
| 54 | - | |
| 55 | -proc second_data_line {} { | |
| 56 | - return [lindex [split [string trim $::RESULT] \r\n] 1] | |
| 57 | -} | |
| 58 | - | |
| 59 | -proc third_data_line {} { | |
| 60 | - return [lindex [split [string trim $::RESULT] \r\n] 2] | |
| 61 | -} | |
| 62 | - | |
| 63 | -proc last_data_line {} { | |
| 64 | - return [lindex [split [string trim $::RESULT] \r\n] end] | |
| 65 | -} | |
| 66 | - | |
| 67 | -proc next_to_last_data_line {} { | |
| 68 | - return [lindex [split [string trim $::RESULT] \r\n] end-1] | |
| 69 | -} | |
| 70 | - | |
| 71 | -############################################################################### | |
| 72 | - | |
| 73 | 33 | set testTh1Setup { |
| 74 | 34 | proc initialize_hook_log {} { |
| 75 | 35 | if {![info exists ::hook_log]} { |
| 76 | 36 | set ::hook_log "" |
| 77 | 37 | } |
| @@ -103,13 +63,18 @@ | ||
| 103 | 63 | break "TH_BREAK return code" |
| 104 | 64 | } elseif {$::cmd_name eq "test4"} { |
| 105 | 65 | emit_hook_log |
| 106 | 66 | return -code 2 "TH_RETURN return code" |
| 107 | 67 | } elseif {$::cmd_name eq "timeline"} { |
| 108 | - if {$::cmd_args eq "custom"} { | |
| 68 | + set length [llength $::cmd_args] | |
| 69 | + set length [expr {$length - 1}] | |
| 70 | + if {[lindex $::cmd_args $length] eq "custom"} { | |
| 109 | 71 | emit_hook_log |
| 110 | 72 | return "custom timeline" |
| 73 | + } elseif {[lindex $::cmd_args $length] eq "now"} { | |
| 74 | + emit_hook_log | |
| 75 | + return "now timeline" | |
| 111 | 76 | } else { |
| 112 | 77 | emit_hook_log |
| 113 | 78 | error "unsupported timeline" |
| 114 | 79 | } |
| 115 | 80 | } |
| @@ -139,63 +104,89 @@ | ||
| 139 | 104 | regexp -line -- {^repository: (.*)$} $data dummy repository |
| 140 | 105 | |
| 141 | 106 | if {[string length $repository] == 0 || ![file exists $repository]} then { |
| 142 | 107 | error "unable to locate repository" |
| 143 | 108 | } |
| 109 | + | |
| 110 | +set dataFileName [file join $::testdir th1-hooks-input.txt] | |
| 144 | 111 | |
| 145 | 112 | ############################################################################### |
| 146 | 113 | |
| 147 | 114 | saveTh1SetupFile; writeTh1SetupFile $testTh1Setup |
| 148 | 115 | |
| 149 | 116 | ############################################################################### |
| 150 | 117 | |
| 151 | 118 | fossil timeline custom; # NOTE: Bad "WHEN" argument. |
| 152 | -test th1-cmd-hooks-1a {[string map [list \r\n \n] [string trim $RESULT]] eq {<h1><b>command_hook timeline</b></h1> | |
| 153 | -ERROR: unsupported timeline | |
| 119 | +test th1-cmd-hooks-1a {[normalize_result] eq \ | |
| 120 | +{<h1><b>command_hook timeline</b></h1> | |
| 154 | 121 | +++ no more data (0) +++ |
| 155 | 122 | |
| 156 | 123 | <h1><b>command_hook timeline command_notify timeline</b></h1>}} |
| 157 | 124 | |
| 158 | 125 | ############################################################################### |
| 159 | 126 | |
| 160 | 127 | fossil timeline |
| 161 | -test th1-cmd-hooks-2a {[first_data_line] eq {<h1><b>command_hook timeline</b></h1>}} | |
| 128 | +test th1-cmd-hooks-2a {[first_data_line] eq \ | |
| 129 | + {<h1><b>command_hook timeline</b></h1>}} | |
| 130 | + | |
| 162 | 131 | test th1-cmd-hooks-2b {[second_data_line] eq {ERROR: unsupported timeline}} |
| 163 | -test th1-cmd-hooks-2c {[regexp -- {=== \d{4}-\d{2}-\d{2} ===} [third_data_line]]} | |
| 164 | -test th1-cmd-hooks-2d {[last_data_line] eq {<h1><b>command_hook timeline command_notify timeline</b></h1>}} | |
| 132 | + | |
| 133 | +############################################################################### | |
| 134 | + | |
| 135 | +fossil timeline now | |
| 136 | +test th1-cmd-hooks-3a {[first_data_line] eq \ | |
| 137 | + {<h1><b>command_hook timeline</b></h1>}} | |
| 138 | + | |
| 139 | +test th1-cmd-hooks-3b \ | |
| 140 | + {[regexp -- {=== \d{4}-\d{2}-\d{2} ===} [second_data_line]]} | |
| 141 | + | |
| 142 | +test th1-cmd-hooks-3c \ | |
| 143 | + {[regexp -- {--- line limit \(\d+\) reached ---} [third_to_last_data_line]]} | |
| 144 | + | |
| 145 | +test th1-cmd-hooks-3d {[last_data_line] eq \ | |
| 146 | + {<h1><b>command_hook timeline command_notify timeline</b></h1>}} | |
| 165 | 147 | |
| 166 | 148 | ############################################################################### |
| 167 | 149 | |
| 168 | 150 | fossil test1 |
| 169 | 151 | test th1-custom-cmd-1a {[next_to_last_data_line] eq $repository} |
| 170 | -test th1-custom-cmd-1b {[last_data_line] eq {<h1><b>command_hook test1 command_notify test1</b></h1>}} | |
| 152 | + | |
| 153 | +test th1-custom-cmd-1b {[last_data_line] eq \ | |
| 154 | + {<h1><b>command_hook test1 command_notify test1</b></h1>}} | |
| 171 | 155 | |
| 172 | 156 | ############################################################################### |
| 173 | 157 | |
| 174 | 158 | fossil test2 |
| 175 | 159 | test th1-custom-cmd-2a {[first_data_line] eq {ERROR: unsupported command}} |
| 176 | 160 | |
| 177 | 161 | ############################################################################### |
| 178 | 162 | |
| 179 | 163 | fossil test3 |
| 180 | -test th1-custom-cmd-3a {[string trim $RESULT] eq {<h1><b>command_hook test3</b></h1>}} | |
| 164 | +test th1-custom-cmd-3a {[string trim $RESULT] eq \ | |
| 165 | + {<h1><b>command_hook test3</b></h1>}} | |
| 181 | 166 | |
| 182 | 167 | ############################################################################### |
| 183 | 168 | |
| 184 | 169 | fossil test4 |
| 185 | -test th1-custom-cmd-4a {[string trim $RESULT] eq {<h1><b>command_hook test4</b></h1>}} | |
| 170 | +test th1-custom-cmd-4a {[string trim $RESULT] eq \ | |
| 171 | + {<h1><b>command_hook test4</b></h1>}} | |
| 186 | 172 | |
| 187 | 173 | ############################################################################### |
| 188 | 174 | |
| 189 | -set RESULT [fossil_th1_hook_http $repository /timeline] | |
| 175 | +set RESULT [test_fossil_http $repository $dataFileName /timeline] | |
| 190 | 176 | test th1-web-hooks-1a {[regexp {<title>Fossil: Timeline</title>} $RESULT]} |
| 191 | -test th1-web-hooks-1b {[regexp {<h1><b>command_hook http webpage_hook timeline webpage_notify timeline</b></h1>} $RESULT]} | |
| 177 | + | |
| 178 | +test th1-web-hooks-1b {[regexp [appendArgs \ | |
| 179 | + {<h1><b>command_hook http webpage_hook timeline} " " \ | |
| 180 | + {webpage_notify timeline</b></h1>}] $RESULT]} | |
| 192 | 181 | |
| 193 | 182 | ############################################################################### |
| 194 | 183 | |
| 195 | -set RESULT [fossil_th1_hook_http $repository /test1] | |
| 184 | +set RESULT [test_fossil_http $repository $dataFileName /test1] | |
| 196 | 185 | test th1-custom-web-1a {[next_to_last_data_line] eq $repository} |
| 197 | -test th1-custom-web-1b {[last_data_line] eq {<h1><b>command_hook http webpage_hook test1 webpage_notify test1</b></h1>}} | |
| 186 | + | |
| 187 | +test th1-custom-web-1b {[last_data_line] eq \ | |
| 188 | + {<h1><b>command_hook http webpage_hook test1 webpage_notify test1</b></h1>}} | |
| 198 | 189 | |
| 199 | 190 | ############################################################################### |
| 200 | 191 | |
| 201 | 192 | restoreTh1SetupFile |
| 202 | 193 |
| --- test/th1-hooks.test | |
| +++ test/th1-hooks.test | |
| @@ -28,50 +28,10 @@ | |
| 28 | |
| 29 | set env(TH1_ENABLE_HOOKS) 1; # TH1 hooks must be enabled for this test. |
| 30 | |
| 31 | ############################################################################### |
| 32 | |
| 33 | proc fossil_th1_hook_http { repository url } { |
| 34 | set suffix [appendArgs [pid] - [clock seconds] .txt] |
| 35 | set inFileName [file join $::tempPath [appendArgs test-http-in- $suffix]] |
| 36 | set outFileName [file join $::tempPath [appendArgs test-http-out- $suffix]] |
| 37 | set data [subst [read_file [file join $::testdir th1-hooks-input.txt]]] |
| 38 | |
| 39 | write_file $inFileName $data |
| 40 | fossil http $repository $inFileName $outFileName 127.0.0.1 |
| 41 | set result [expr {[file exists $outFileName] ? [read_file $outFileName] : ""}] |
| 42 | |
| 43 | if {1} then { |
| 44 | catch {file delete $inFileName} |
| 45 | catch {file delete $outFileName} |
| 46 | } |
| 47 | |
| 48 | return $result |
| 49 | } |
| 50 | |
| 51 | proc first_data_line {} { |
| 52 | return [lindex [split [string trim $::RESULT] \r\n] 0] |
| 53 | } |
| 54 | |
| 55 | proc second_data_line {} { |
| 56 | return [lindex [split [string trim $::RESULT] \r\n] 1] |
| 57 | } |
| 58 | |
| 59 | proc third_data_line {} { |
| 60 | return [lindex [split [string trim $::RESULT] \r\n] 2] |
| 61 | } |
| 62 | |
| 63 | proc last_data_line {} { |
| 64 | return [lindex [split [string trim $::RESULT] \r\n] end] |
| 65 | } |
| 66 | |
| 67 | proc next_to_last_data_line {} { |
| 68 | return [lindex [split [string trim $::RESULT] \r\n] end-1] |
| 69 | } |
| 70 | |
| 71 | ############################################################################### |
| 72 | |
| 73 | set testTh1Setup { |
| 74 | proc initialize_hook_log {} { |
| 75 | if {![info exists ::hook_log]} { |
| 76 | set ::hook_log "" |
| 77 | } |
| @@ -103,13 +63,18 @@ | |
| 103 | break "TH_BREAK return code" |
| 104 | } elseif {$::cmd_name eq "test4"} { |
| 105 | emit_hook_log |
| 106 | return -code 2 "TH_RETURN return code" |
| 107 | } elseif {$::cmd_name eq "timeline"} { |
| 108 | if {$::cmd_args eq "custom"} { |
| 109 | emit_hook_log |
| 110 | return "custom timeline" |
| 111 | } else { |
| 112 | emit_hook_log |
| 113 | error "unsupported timeline" |
| 114 | } |
| 115 | } |
| @@ -139,63 +104,89 @@ | |
| 139 | regexp -line -- {^repository: (.*)$} $data dummy repository |
| 140 | |
| 141 | if {[string length $repository] == 0 || ![file exists $repository]} then { |
| 142 | error "unable to locate repository" |
| 143 | } |
| 144 | |
| 145 | ############################################################################### |
| 146 | |
| 147 | saveTh1SetupFile; writeTh1SetupFile $testTh1Setup |
| 148 | |
| 149 | ############################################################################### |
| 150 | |
| 151 | fossil timeline custom; # NOTE: Bad "WHEN" argument. |
| 152 | test th1-cmd-hooks-1a {[string map [list \r\n \n] [string trim $RESULT]] eq {<h1><b>command_hook timeline</b></h1> |
| 153 | ERROR: unsupported timeline |
| 154 | +++ no more data (0) +++ |
| 155 | |
| 156 | <h1><b>command_hook timeline command_notify timeline</b></h1>}} |
| 157 | |
| 158 | ############################################################################### |
| 159 | |
| 160 | fossil timeline |
| 161 | test th1-cmd-hooks-2a {[first_data_line] eq {<h1><b>command_hook timeline</b></h1>}} |
| 162 | test th1-cmd-hooks-2b {[second_data_line] eq {ERROR: unsupported timeline}} |
| 163 | test th1-cmd-hooks-2c {[regexp -- {=== \d{4}-\d{2}-\d{2} ===} [third_data_line]]} |
| 164 | test th1-cmd-hooks-2d {[last_data_line] eq {<h1><b>command_hook timeline command_notify timeline</b></h1>}} |
| 165 | |
| 166 | ############################################################################### |
| 167 | |
| 168 | fossil test1 |
| 169 | test th1-custom-cmd-1a {[next_to_last_data_line] eq $repository} |
| 170 | test th1-custom-cmd-1b {[last_data_line] eq {<h1><b>command_hook test1 command_notify test1</b></h1>}} |
| 171 | |
| 172 | ############################################################################### |
| 173 | |
| 174 | fossil test2 |
| 175 | test th1-custom-cmd-2a {[first_data_line] eq {ERROR: unsupported command}} |
| 176 | |
| 177 | ############################################################################### |
| 178 | |
| 179 | fossil test3 |
| 180 | test th1-custom-cmd-3a {[string trim $RESULT] eq {<h1><b>command_hook test3</b></h1>}} |
| 181 | |
| 182 | ############################################################################### |
| 183 | |
| 184 | fossil test4 |
| 185 | test th1-custom-cmd-4a {[string trim $RESULT] eq {<h1><b>command_hook test4</b></h1>}} |
| 186 | |
| 187 | ############################################################################### |
| 188 | |
| 189 | set RESULT [fossil_th1_hook_http $repository /timeline] |
| 190 | test th1-web-hooks-1a {[regexp {<title>Fossil: Timeline</title>} $RESULT]} |
| 191 | test th1-web-hooks-1b {[regexp {<h1><b>command_hook http webpage_hook timeline webpage_notify timeline</b></h1>} $RESULT]} |
| 192 | |
| 193 | ############################################################################### |
| 194 | |
| 195 | set RESULT [fossil_th1_hook_http $repository /test1] |
| 196 | test th1-custom-web-1a {[next_to_last_data_line] eq $repository} |
| 197 | test th1-custom-web-1b {[last_data_line] eq {<h1><b>command_hook http webpage_hook test1 webpage_notify test1</b></h1>}} |
| 198 | |
| 199 | ############################################################################### |
| 200 | |
| 201 | restoreTh1SetupFile |
| 202 |
| --- test/th1-hooks.test | |
| +++ test/th1-hooks.test | |
| @@ -28,50 +28,10 @@ | |
| 28 | |
| 29 | set env(TH1_ENABLE_HOOKS) 1; # TH1 hooks must be enabled for this test. |
| 30 | |
| 31 | ############################################################################### |
| 32 | |
| 33 | set testTh1Setup { |
| 34 | proc initialize_hook_log {} { |
| 35 | if {![info exists ::hook_log]} { |
| 36 | set ::hook_log "" |
| 37 | } |
| @@ -103,13 +63,18 @@ | |
| 63 | break "TH_BREAK return code" |
| 64 | } elseif {$::cmd_name eq "test4"} { |
| 65 | emit_hook_log |
| 66 | return -code 2 "TH_RETURN return code" |
| 67 | } elseif {$::cmd_name eq "timeline"} { |
| 68 | set length [llength $::cmd_args] |
| 69 | set length [expr {$length - 1}] |
| 70 | if {[lindex $::cmd_args $length] eq "custom"} { |
| 71 | emit_hook_log |
| 72 | return "custom timeline" |
| 73 | } elseif {[lindex $::cmd_args $length] eq "now"} { |
| 74 | emit_hook_log |
| 75 | return "now timeline" |
| 76 | } else { |
| 77 | emit_hook_log |
| 78 | error "unsupported timeline" |
| 79 | } |
| 80 | } |
| @@ -139,63 +104,89 @@ | |
| 104 | regexp -line -- {^repository: (.*)$} $data dummy repository |
| 105 | |
| 106 | if {[string length $repository] == 0 || ![file exists $repository]} then { |
| 107 | error "unable to locate repository" |
| 108 | } |
| 109 | |
| 110 | set dataFileName [file join $::testdir th1-hooks-input.txt] |
| 111 | |
| 112 | ############################################################################### |
| 113 | |
| 114 | saveTh1SetupFile; writeTh1SetupFile $testTh1Setup |
| 115 | |
| 116 | ############################################################################### |
| 117 | |
| 118 | fossil timeline custom; # NOTE: Bad "WHEN" argument. |
| 119 | test th1-cmd-hooks-1a {[normalize_result] eq \ |
| 120 | {<h1><b>command_hook timeline</b></h1> |
| 121 | +++ no more data (0) +++ |
| 122 | |
| 123 | <h1><b>command_hook timeline command_notify timeline</b></h1>}} |
| 124 | |
| 125 | ############################################################################### |
| 126 | |
| 127 | fossil timeline |
| 128 | test th1-cmd-hooks-2a {[first_data_line] eq \ |
| 129 | {<h1><b>command_hook timeline</b></h1>}} |
| 130 | |
| 131 | test th1-cmd-hooks-2b {[second_data_line] eq {ERROR: unsupported timeline}} |
| 132 | |
| 133 | ############################################################################### |
| 134 | |
| 135 | fossil timeline now |
| 136 | test th1-cmd-hooks-3a {[first_data_line] eq \ |
| 137 | {<h1><b>command_hook timeline</b></h1>}} |
| 138 | |
| 139 | test th1-cmd-hooks-3b \ |
| 140 | {[regexp -- {=== \d{4}-\d{2}-\d{2} ===} [second_data_line]]} |
| 141 | |
| 142 | test th1-cmd-hooks-3c \ |
| 143 | {[regexp -- {--- line limit \(\d+\) reached ---} [third_to_last_data_line]]} |
| 144 | |
| 145 | test th1-cmd-hooks-3d {[last_data_line] eq \ |
| 146 | {<h1><b>command_hook timeline command_notify timeline</b></h1>}} |
| 147 | |
| 148 | ############################################################################### |
| 149 | |
| 150 | fossil test1 |
| 151 | test th1-custom-cmd-1a {[next_to_last_data_line] eq $repository} |
| 152 | |
| 153 | test th1-custom-cmd-1b {[last_data_line] eq \ |
| 154 | {<h1><b>command_hook test1 command_notify test1</b></h1>}} |
| 155 | |
| 156 | ############################################################################### |
| 157 | |
| 158 | fossil test2 |
| 159 | test th1-custom-cmd-2a {[first_data_line] eq {ERROR: unsupported command}} |
| 160 | |
| 161 | ############################################################################### |
| 162 | |
| 163 | fossil test3 |
| 164 | test th1-custom-cmd-3a {[string trim $RESULT] eq \ |
| 165 | {<h1><b>command_hook test3</b></h1>}} |
| 166 | |
| 167 | ############################################################################### |
| 168 | |
| 169 | fossil test4 |
| 170 | test th1-custom-cmd-4a {[string trim $RESULT] eq \ |
| 171 | {<h1><b>command_hook test4</b></h1>}} |
| 172 | |
| 173 | ############################################################################### |
| 174 | |
| 175 | set RESULT [test_fossil_http $repository $dataFileName /timeline] |
| 176 | test th1-web-hooks-1a {[regexp {<title>Fossil: Timeline</title>} $RESULT]} |
| 177 | |
| 178 | test th1-web-hooks-1b {[regexp [appendArgs \ |
| 179 | {<h1><b>command_hook http webpage_hook timeline} " " \ |
| 180 | {webpage_notify timeline</b></h1>}] $RESULT]} |
| 181 | |
| 182 | ############################################################################### |
| 183 | |
| 184 | set RESULT [test_fossil_http $repository $dataFileName /test1] |
| 185 | test th1-custom-web-1a {[next_to_last_data_line] eq $repository} |
| 186 | |
| 187 | test th1-custom-web-1b {[last_data_line] eq \ |
| 188 | {<h1><b>command_hook http webpage_hook test1 webpage_notify test1</b></h1>}} |
| 189 | |
| 190 | ############################################################################### |
| 191 | |
| 192 | restoreTh1SetupFile |
| 193 |
+1
-1
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -150,11 +150,11 @@ | ||
| 150 | 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | 154 | # |
| 155 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 | |
| 155 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a | |
| 156 | 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | 158 | |
| 159 | 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | 160 | # source code directory resides (depending on the value of the macro |
| 161 | 161 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
+1
-1
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -150,11 +150,11 @@ | ||
| 150 | 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | 154 | # |
| 155 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 | |
| 155 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a | |
| 156 | 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | 158 | |
| 159 | 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | 160 | # source code directory resides (depending on the value of the macro |
| 161 | 161 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
+2
-2
| --- win/Makefile.mingw.mistachkin | ||
| +++ win/Makefile.mingw.mistachkin | ||
| @@ -59,11 +59,11 @@ | ||
| 59 | 59 | # |
| 60 | 60 | FOSSIL_ENABLE_LEGACY_MV_RM = 1 |
| 61 | 61 | |
| 62 | 62 | #### Enable TH1 scripts in embedded documentation files |
| 63 | 63 | # |
| 64 | -# FOSSIL_ENABLE_TH1_DOCS = 1 | |
| 64 | +FOSSIL_ENABLE_TH1_DOCS = 1 | |
| 65 | 65 | |
| 66 | 66 | #### Enable hooks for commands and web pages via TH1 |
| 67 | 67 | # |
| 68 | 68 | FOSSIL_ENABLE_TH1_HOOKS = 1 |
| 69 | 69 | |
| @@ -150,11 +150,11 @@ | ||
| 150 | 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | 154 | # |
| 155 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 | |
| 155 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a | |
| 156 | 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | 158 | |
| 159 | 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | 160 | # source code directory resides (depending on the value of the macro |
| 161 | 161 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -59,11 +59,11 @@ | |
| 59 | # |
| 60 | FOSSIL_ENABLE_LEGACY_MV_RM = 1 |
| 61 | |
| 62 | #### Enable TH1 scripts in embedded documentation files |
| 63 | # |
| 64 | # FOSSIL_ENABLE_TH1_DOCS = 1 |
| 65 | |
| 66 | #### Enable hooks for commands and web pages via TH1 |
| 67 | # |
| 68 | FOSSIL_ENABLE_TH1_HOOKS = 1 |
| 69 | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -59,11 +59,11 @@ | |
| 59 | # |
| 60 | FOSSIL_ENABLE_LEGACY_MV_RM = 1 |
| 61 | |
| 62 | #### Enable TH1 scripts in embedded documentation files |
| 63 | # |
| 64 | FOSSIL_ENABLE_TH1_DOCS = 1 |
| 65 | |
| 66 | #### Enable hooks for commands and web pages via TH1 |
| 67 | # |
| 68 | FOSSIL_ENABLE_TH1_HOOKS = 1 |
| 69 | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
+2
-2
| --- win/Makefile.mingw.mistachkin | ||
| +++ win/Makefile.mingw.mistachkin | ||
| @@ -59,11 +59,11 @@ | ||
| 59 | 59 | # |
| 60 | 60 | FOSSIL_ENABLE_LEGACY_MV_RM = 1 |
| 61 | 61 | |
| 62 | 62 | #### Enable TH1 scripts in embedded documentation files |
| 63 | 63 | # |
| 64 | -# FOSSIL_ENABLE_TH1_DOCS = 1 | |
| 64 | +FOSSIL_ENABLE_TH1_DOCS = 1 | |
| 65 | 65 | |
| 66 | 66 | #### Enable hooks for commands and web pages via TH1 |
| 67 | 67 | # |
| 68 | 68 | FOSSIL_ENABLE_TH1_HOOKS = 1 |
| 69 | 69 | |
| @@ -150,11 +150,11 @@ | ||
| 150 | 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | 154 | # |
| 155 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 | |
| 155 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a | |
| 156 | 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | 158 | |
| 159 | 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | 160 | # source code directory resides (depending on the value of the macro |
| 161 | 161 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -59,11 +59,11 @@ | |
| 59 | # |
| 60 | FOSSIL_ENABLE_LEGACY_MV_RM = 1 |
| 61 | |
| 62 | #### Enable TH1 scripts in embedded documentation files |
| 63 | # |
| 64 | # FOSSIL_ENABLE_TH1_DOCS = 1 |
| 65 | |
| 66 | #### Enable hooks for commands and web pages via TH1 |
| 67 | # |
| 68 | FOSSIL_ENABLE_TH1_HOOKS = 1 |
| 69 | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2 |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -59,11 +59,11 @@ | |
| 59 | # |
| 60 | FOSSIL_ENABLE_LEGACY_MV_RM = 1 |
| 61 | |
| 62 | #### Enable TH1 scripts in embedded documentation files |
| 63 | # |
| 64 | FOSSIL_ENABLE_TH1_DOCS = 1 |
| 65 | |
| 66 | #### Enable hooks for commands and web pages via TH1 |
| 67 | # |
| 68 | FOSSIL_ENABLE_TH1_HOOKS = 1 |
| 69 | |
| @@ -150,11 +150,11 @@ | |
| 150 | #### The directories where the OpenSSL include and library files are located. |
| 151 | # The recommended usage here is to use the Sysinternals junction tool |
| 152 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 153 | # Fossil source code directory and the target OpenSSL source directory. |
| 154 | # |
| 155 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2a |
| 156 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 157 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 158 | |
| 159 | #### Either the directory where the Tcl library is installed or the Tcl |
| 160 | # source code directory resides (depending on the value of the macro |
| 161 |
+1
-1
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -58,11 +58,11 @@ | ||
| 58 | 58 | |
| 59 | 59 | # Uncomment to enable Tcl support |
| 60 | 60 | # FOSSIL_ENABLE_TCL = 1 |
| 61 | 61 | |
| 62 | 62 | !ifdef FOSSIL_ENABLE_SSL |
| 63 | -SSLDIR = $(B)\compat\openssl-1.0.2 | |
| 63 | +SSLDIR = $(B)\compat\openssl-1.0.2a | |
| 64 | 64 | SSLINCDIR = $(SSLDIR)\inc32 |
| 65 | 65 | SSLLIBDIR = $(SSLDIR)\out32 |
| 66 | 66 | SSLLFLAGS = /nologo /opt:ref /debug |
| 67 | 67 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 68 | 68 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 69 | 69 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | # Uncomment to enable Tcl support |
| 60 | # FOSSIL_ENABLE_TCL = 1 |
| 61 | |
| 62 | !ifdef FOSSIL_ENABLE_SSL |
| 63 | SSLDIR = $(B)\compat\openssl-1.0.2 |
| 64 | SSLINCDIR = $(SSLDIR)\inc32 |
| 65 | SSLLIBDIR = $(SSLDIR)\out32 |
| 66 | SSLLFLAGS = /nologo /opt:ref /debug |
| 67 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 68 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 69 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | # Uncomment to enable Tcl support |
| 60 | # FOSSIL_ENABLE_TCL = 1 |
| 61 | |
| 62 | !ifdef FOSSIL_ENABLE_SSL |
| 63 | SSLDIR = $(B)\compat\openssl-1.0.2a |
| 64 | SSLINCDIR = $(SSLDIR)\inc32 |
| 65 | SSLLIBDIR = $(SSLDIR)\out32 |
| 66 | SSLLFLAGS = /nologo /opt:ref /debug |
| 67 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 68 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 69 |
+1
-1
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -58,11 +58,11 @@ | ||
| 58 | 58 | |
| 59 | 59 | # Uncomment to enable Tcl support |
| 60 | 60 | # FOSSIL_ENABLE_TCL = 1 |
| 61 | 61 | |
| 62 | 62 | !ifdef FOSSIL_ENABLE_SSL |
| 63 | -SSLDIR = $(B)\compat\openssl-1.0.2 | |
| 63 | +SSLDIR = $(B)\compat\openssl-1.0.2a | |
| 64 | 64 | SSLINCDIR = $(SSLDIR)\inc32 |
| 65 | 65 | SSLLIBDIR = $(SSLDIR)\out32 |
| 66 | 66 | SSLLFLAGS = /nologo /opt:ref /debug |
| 67 | 67 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 68 | 68 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 69 | 69 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | # Uncomment to enable Tcl support |
| 60 | # FOSSIL_ENABLE_TCL = 1 |
| 61 | |
| 62 | !ifdef FOSSIL_ENABLE_SSL |
| 63 | SSLDIR = $(B)\compat\openssl-1.0.2 |
| 64 | SSLINCDIR = $(SSLDIR)\inc32 |
| 65 | SSLLIBDIR = $(SSLDIR)\out32 |
| 66 | SSLLFLAGS = /nologo /opt:ref /debug |
| 67 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 68 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 69 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | # Uncomment to enable Tcl support |
| 60 | # FOSSIL_ENABLE_TCL = 1 |
| 61 | |
| 62 | !ifdef FOSSIL_ENABLE_SSL |
| 63 | SSLDIR = $(B)\compat\openssl-1.0.2a |
| 64 | SSLINCDIR = $(SSLDIR)\inc32 |
| 65 | SSLLIBDIR = $(SSLDIR)\out32 |
| 66 | SSLLFLAGS = /nologo /opt:ref /debug |
| 67 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 68 | !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" |
| 69 |
+1
-1
| --- www/build.wiki | ||
| +++ www/build.wiki | ||
| @@ -125,11 +125,11 @@ | ||
| 125 | 125 | the optional <a href="https://www.openssl.org/">OpenSSL</a> support, |
| 126 | 126 | first <a href="https://www.openssl.org/source/">download the official |
| 127 | 127 | source code for OpenSSL</a> and extract it to an appropriately named |
| 128 | 128 | "<b>openssl-X.Y.ZA</b>" subdirectory within the local |
| 129 | 129 | [/tree?ci=trunk&name=compat | compat] directory (e.g. |
| 130 | -"<b>compat/openssl-1.0.2</b>"), then make sure that some recent | |
| 130 | +"<b>compat/openssl-1.0.2a</b>"), then make sure that some recent | |
| 131 | 131 | <a href="http://www.perl.org/">Perl</a> binaries are installed locally, |
| 132 | 132 | and finally run one of the following commands: |
| 133 | 133 | <blockquote><pre> |
| 134 | 134 | nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin |
| 135 | 135 | </pre></blockquote> |
| 136 | 136 |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -125,11 +125,11 @@ | |
| 125 | the optional <a href="https://www.openssl.org/">OpenSSL</a> support, |
| 126 | first <a href="https://www.openssl.org/source/">download the official |
| 127 | source code for OpenSSL</a> and extract it to an appropriately named |
| 128 | "<b>openssl-X.Y.ZA</b>" subdirectory within the local |
| 129 | [/tree?ci=trunk&name=compat | compat] directory (e.g. |
| 130 | "<b>compat/openssl-1.0.2</b>"), then make sure that some recent |
| 131 | <a href="http://www.perl.org/">Perl</a> binaries are installed locally, |
| 132 | and finally run one of the following commands: |
| 133 | <blockquote><pre> |
| 134 | nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin |
| 135 | </pre></blockquote> |
| 136 |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -125,11 +125,11 @@ | |
| 125 | the optional <a href="https://www.openssl.org/">OpenSSL</a> support, |
| 126 | first <a href="https://www.openssl.org/source/">download the official |
| 127 | source code for OpenSSL</a> and extract it to an appropriately named |
| 128 | "<b>openssl-X.Y.ZA</b>" subdirectory within the local |
| 129 | [/tree?ci=trunk&name=compat | compat] directory (e.g. |
| 130 | "<b>compat/openssl-1.0.2a</b>"), then make sure that some recent |
| 131 | <a href="http://www.perl.org/">Perl</a> binaries are installed locally, |
| 132 | and finally run one of the following commands: |
| 133 | <blockquote><pre> |
| 134 | nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin |
| 135 | </pre></blockquote> |
| 136 |
+4
| --- www/changes.wiki | ||
| +++ www/changes.wiki | ||
| @@ -1,7 +1,11 @@ | ||
| 1 | 1 | <title>Change Log</title> |
| 2 | 2 | |
| 3 | +<h2>Changes for Version 1.33 (not released yet)</h2> | |
| 4 | + * Add [/help?cmd=import|fossil import --svn], for importing a subversion | |
| 5 | + repository into fossil which was exported using "svnadmin dump". | |
| 6 | + | |
| 3 | 7 | <h2>Changes for Version 1.32 (2015-03-14)</h2> |
| 4 | 8 | * When creating a new repository using [/help?cmd=init|fossil init], ensure |
| 5 | 9 | that the new repository is fully compatible with historical versions of |
| 6 | 10 | Fossil by having a valid manifest as RID 1. |
| 7 | 11 | * Anti-aliased rendering of arrowheads on timeline graphs. |
| 8 | 12 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -1,7 +1,11 @@ | |
| 1 | <title>Change Log</title> |
| 2 | |
| 3 | <h2>Changes for Version 1.32 (2015-03-14)</h2> |
| 4 | * When creating a new repository using [/help?cmd=init|fossil init], ensure |
| 5 | that the new repository is fully compatible with historical versions of |
| 6 | Fossil by having a valid manifest as RID 1. |
| 7 | * Anti-aliased rendering of arrowheads on timeline graphs. |
| 8 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -1,7 +1,11 @@ | |
| 1 | <title>Change Log</title> |
| 2 | |
| 3 | <h2>Changes for Version 1.33 (not released yet)</h2> |
| 4 | * Add [/help?cmd=import|fossil import --svn], for importing a subversion |
| 5 | repository into fossil which was exported using "svnadmin dump". |
| 6 | |
| 7 | <h2>Changes for Version 1.32 (2015-03-14)</h2> |
| 8 | * When creating a new repository using [/help?cmd=init|fossil init], ensure |
| 9 | that the new repository is fully compatible with historical versions of |
| 10 | Fossil by having a valid manifest as RID 1. |
| 11 | * Anti-aliased rendering of arrowheads on timeline graphs. |
| 12 |
+4
-5
| --- www/sync.wiki | ||
| +++ www/sync.wiki | ||
| @@ -247,13 +247,11 @@ | ||
| 247 | 247 | <b>push</b> <i>servercode projectcode</i><br> |
| 248 | 248 | <b>pull</b> <i>servercode projectcode</i> |
| 249 | 249 | </blockquote> |
| 250 | 250 | |
| 251 | 251 | <p>The <i>servercode</i> argument is the repository ID for the |
| 252 | -client. The server will only allow the transaction to proceed | |
| 253 | -if the servercode is different from its own servercode. This | |
| 254 | -prevents a sync-loop. The <i>projectcode</i> is the identifier | |
| 252 | +client. The <i>projectcode</i> is the identifier | |
| 255 | 253 | of the software project that the client repository contains. |
| 256 | 254 | The projectcode for the client and server must match in order |
| 257 | 255 | for the transaction to proceed.</p> |
| 258 | 256 | |
| 259 | 257 | <p>The server will also send a push card back to the client |
| @@ -384,11 +382,11 @@ | ||
| 384 | 382 | |
| 385 | 383 | <blockquote> |
| 386 | 384 | <b>reqconfig</b> <i>configuration-name</i> |
| 387 | 385 | </blockquote> |
| 388 | 386 | |
| 389 | -<p>As of [/timeline?r=trunk&c=2015-01-24+00%3A17%3A55&n=20|2015-01-24], the configuration-name must be one of the | |
| 387 | +<p>As of [/timeline?r=trunk&c=2015-03-19+03%3A57%3A46&n=20|2015-03-19], the configuration-name must be one of the | |
| 390 | 388 | following values: |
| 391 | 389 | |
| 392 | 390 | <center><table border=0> |
| 393 | 391 | <tr><td valign="top"> |
| 394 | 392 | <ul> |
| @@ -420,16 +418,17 @@ | ||
| 420 | 418 | <li> keep-glob |
| 421 | 419 | <li> crnl-glob |
| 422 | 420 | <li> encoding-glob |
| 423 | 421 | <li> empty-dirs |
| 424 | 422 | <li> allow-symlinks |
| 423 | +<li> dotfiles | |
| 425 | 424 | <li> ticket-table |
| 426 | 425 | <li> ticket-common |
| 427 | 426 | <li> ticket-change |
| 428 | 427 | <li> ticket-newpage |
| 429 | -<li> ticket-viewpage | |
| 430 | 428 | <ul></td><td valign="top"><ul> |
| 429 | +<li> ticket-viewpage | |
| 431 | 430 | <li> ticket-editpage |
| 432 | 431 | <li> ticket-reportlist |
| 433 | 432 | <li> ticket-report-template |
| 434 | 433 | <li> ticket-key-template |
| 435 | 434 | <li> ticket-title-expr |
| 436 | 435 |
| --- www/sync.wiki | |
| +++ www/sync.wiki | |
| @@ -247,13 +247,11 @@ | |
| 247 | <b>push</b> <i>servercode projectcode</i><br> |
| 248 | <b>pull</b> <i>servercode projectcode</i> |
| 249 | </blockquote> |
| 250 | |
| 251 | <p>The <i>servercode</i> argument is the repository ID for the |
| 252 | client. The server will only allow the transaction to proceed |
| 253 | if the servercode is different from its own servercode. This |
| 254 | prevents a sync-loop. The <i>projectcode</i> is the identifier |
| 255 | of the software project that the client repository contains. |
| 256 | The projectcode for the client and server must match in order |
| 257 | for the transaction to proceed.</p> |
| 258 | |
| 259 | <p>The server will also send a push card back to the client |
| @@ -384,11 +382,11 @@ | |
| 384 | |
| 385 | <blockquote> |
| 386 | <b>reqconfig</b> <i>configuration-name</i> |
| 387 | </blockquote> |
| 388 | |
| 389 | <p>As of [/timeline?r=trunk&c=2015-01-24+00%3A17%3A55&n=20|2015-01-24], the configuration-name must be one of the |
| 390 | following values: |
| 391 | |
| 392 | <center><table border=0> |
| 393 | <tr><td valign="top"> |
| 394 | <ul> |
| @@ -420,16 +418,17 @@ | |
| 420 | <li> keep-glob |
| 421 | <li> crnl-glob |
| 422 | <li> encoding-glob |
| 423 | <li> empty-dirs |
| 424 | <li> allow-symlinks |
| 425 | <li> ticket-table |
| 426 | <li> ticket-common |
| 427 | <li> ticket-change |
| 428 | <li> ticket-newpage |
| 429 | <li> ticket-viewpage |
| 430 | <ul></td><td valign="top"><ul> |
| 431 | <li> ticket-editpage |
| 432 | <li> ticket-reportlist |
| 433 | <li> ticket-report-template |
| 434 | <li> ticket-key-template |
| 435 | <li> ticket-title-expr |
| 436 |
| --- www/sync.wiki | |
| +++ www/sync.wiki | |
| @@ -247,13 +247,11 @@ | |
| 247 | <b>push</b> <i>servercode projectcode</i><br> |
| 248 | <b>pull</b> <i>servercode projectcode</i> |
| 249 | </blockquote> |
| 250 | |
| 251 | <p>The <i>servercode</i> argument is the repository ID for the |
| 252 | client. The <i>projectcode</i> is the identifier |
| 253 | of the software project that the client repository contains. |
| 254 | The projectcode for the client and server must match in order |
| 255 | for the transaction to proceed.</p> |
| 256 | |
| 257 | <p>The server will also send a push card back to the client |
| @@ -384,11 +382,11 @@ | |
| 382 | |
| 383 | <blockquote> |
| 384 | <b>reqconfig</b> <i>configuration-name</i> |
| 385 | </blockquote> |
| 386 | |
| 387 | <p>As of [/timeline?r=trunk&c=2015-03-19+03%3A57%3A46&n=20|2015-03-19], the configuration-name must be one of the |
| 388 | following values: |
| 389 | |
| 390 | <center><table border=0> |
| 391 | <tr><td valign="top"> |
| 392 | <ul> |
| @@ -420,16 +418,17 @@ | |
| 418 | <li> keep-glob |
| 419 | <li> crnl-glob |
| 420 | <li> encoding-glob |
| 421 | <li> empty-dirs |
| 422 | <li> allow-symlinks |
| 423 | <li> dotfiles |
| 424 | <li> ticket-table |
| 425 | <li> ticket-common |
| 426 | <li> ticket-change |
| 427 | <li> ticket-newpage |
| 428 | <ul></td><td valign="top"><ul> |
| 429 | <li> ticket-viewpage |
| 430 | <li> ticket-editpage |
| 431 | <li> ticket-reportlist |
| 432 | <li> ticket-report-template |
| 433 | <li> ticket-key-template |
| 434 | <li> ticket-title-expr |
| 435 |