Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From 1374d581423a1ee2 To c8b46764b6a913f8
2017-10-21
| ||
19:37 | Update the built-in SQLite to the second 3.21.0 beta. ... (check-in: 7ac19afa user: drh tags: trunk) | |
2017-10-19
| ||
20:39 | Initial changes for adding attachments to check-ins. ... (Closed-Leaf check-in: cb385ba0 user: drh tags: checkin-attachment) | |
08:47 | typo fix reported on the ML. ... (check-in: 1374d581 user: stephan tags: trunk) | |
04:09 | Adjust help text wording for /download page ... (check-in: eecb721e user: andygoth tags: trunk) | |
2017-10-02
| ||
03:46 | Update the build-in SQLite to the latest 3.21.0 beta that includes the enhance use of co-routines for subqueries. ... (check-in: 75fffb49 user: drh tags: trunk) | |
02:30 | Fix the computation of the percentage of the repo taken up by unversioned files on the /stat page. ... (check-in: c8b46764 user: drh tags: trunk) | |
2017-09-30
| ||
01:09 | Add [string index] TH1 command ... (check-in: 0c57ba3e user: andygoth tags: trunk) | |
Changes to Makefile.in.
︙ | ︙ | |||
47 48 49 50 51 52 53 | USE_SEE = @USE_SEE@ FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile | < < < < < < < < < < < < < < < < < < < < < | 47 48 49 50 51 52 53 | USE_SEE = @USE_SEE@ FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile |
Changes to autosetup/system.tcl.
︙ | ︙ | |||
203 204 205 206 207 208 209 | set cond [expr {!$cond}] } } continue } lappend result $line } | | < | > | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | set cond [expr {!$cond}] } } continue } lappend result $line } writefile $out [string map $mapping [join $result \n]]\n msg-result "Created [relative-path $out] from [relative-path $template]" } # build/host tuples and cross-compilation prefix set build [opt-val build] define build_alias $build if {$build eq ""} { define build [config_guess] |
︙ | ︙ |
Changes to src/clone.c.
︙ | ︙ | |||
291 292 293 294 295 296 297 | ** options). */ void clone_ssh_db_set_options(void){ if( g.zSshCmd && g.zSshCmd[0] ){ db_set("ssh-command", g.zSshCmd, 0); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 291 292 293 294 295 296 297 | ** options). */ void clone_ssh_db_set_options(void){ if( g.zSshCmd && g.zSshCmd[0] ){ db_set("ssh-command", g.zSshCmd, 0); } } |
Changes to src/db.c.
︙ | ︙ | |||
2924 2925 2926 2927 2928 2929 2930 | /* ** SETTING: exec-rel-paths boolean default=off ** When executing certain external commands (e.g. diff and ** gdiff), use relative paths. */ #endif /* | | | 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 | /* ** SETTING: exec-rel-paths boolean default=off ** When executing certain external commands (e.g. diff and ** gdiff), use relative paths. */ #endif /* ** SETTING; gdiff-command width=40 default=gdiff ** The value is an external command to run when performing a graphical ** diff. If undefined, text diff will be used. */ /* ** SETTING: gmerge-command width=40 ** The value is a graphical merge conflict resolver command operating ** on four files. Examples: |
︙ | ︙ | |||
3014 3015 3016 3017 3018 3019 3020 | ** If enabled, the "mv" and "rename" commands will also move ** the associated files within the checkout -AND- the "rm" ** and "delete" commands will also remove the associated ** files from within the checkout. */ #endif /* | | > > < | 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 | ** If enabled, the "mv" and "rename" commands will also move ** the associated files within the checkout -AND- the "rm" ** and "delete" commands will also remove the associated ** files from within the checkout. */ #endif /* ** SETTING; pgp-command width=40 ** DEFAULT: gpg --clearsign -o ** ** Command used to clear-sign manifests at check-in. */ /* ** SETTING: proxy width=32 default=off ** URL of the HTTP proxy. If undefined or "off" then ** the "http_proxy" environment variable is consulted. ** If the http_proxy environment variable is undefined ** then a direct HTTP connection is used. |
︙ | ︙ |
Changes to src/delta.c.
︙ | ︙ | |||
569 570 571 572 573 574 575 | int lenSrc, /* Length of the source file */ const char *zDelta, /* Delta to apply to the pattern */ int lenDelta, /* Length of the delta */ char *zOut /* Write the output into this preallocated buffer */ ){ unsigned int limit; unsigned int total = 0; | | | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | int lenSrc, /* Length of the source file */ const char *zDelta, /* Delta to apply to the pattern */ int lenDelta, /* Length of the delta */ char *zOut /* Write the output into this preallocated buffer */ ){ unsigned int limit; unsigned int total = 0; #ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST char *zOrigOut = zOut; #endif limit = getInt(&zDelta, &lenDelta); if( *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; |
︙ | ︙ | |||
626 627 628 629 630 631 632 | zDelta += cnt; lenDelta -= cnt; break; } case ';': { zDelta++; lenDelta--; zOut[0] = 0; | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | zDelta += cnt; lenDelta -= cnt; break; } case ';': { zDelta++; lenDelta--; zOut[0] = 0; #ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST if( cnt!=checksum(zOrigOut, total) ){ /* ERROR: bad checksum */ return -1; } #endif if( total!=limit ){ /* ERROR: generated size does not match predicted size */ |
︙ | ︙ |
Changes to src/diff.c.
︙ | ︙ | |||
2257 2258 2259 2260 2261 2262 2263 | /* Get filename ID */ file_tree_name(zFilename, &treename, 0, 1); zFilename = blob_str(&treename); fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); db_prepare(&q, | | | 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 | /* Get filename ID */ file_tree_name(zFilename, &treename, 0, 1); zFilename = blob_str(&treename); fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); db_prepare(&q, "SELECT" " (SELECT uuid FROM blob WHERE rid=mlink.fid)," " (SELECT uuid FROM blob WHERE rid=mlink.mid)," " date(event.mtime)," " coalesce(event.euser,event.user)," " mlink.fid" " FROM mlink, event, ancestor" " WHERE mlink.fnid=%d" |
︙ | ︙ |
Changes to src/finfo.c.
︙ | ︙ | |||
594 595 596 597 598 599 600 | /* ** WEBPAGE: mlink ** URL: /mlink?name=FILENAME ** URL: /mlink?ci=NAME ** ** Show all MLINK table entries for a particular file, or for | | < < | < < < < | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 | /* ** WEBPAGE: mlink ** URL: /mlink?name=FILENAME ** URL: /mlink?ci=NAME ** ** Show all MLINK table entries for a particular file, or for ** a particular check-in. This screen is intended for use by developers ** in debugging Fossil. */ void mlink_page(void){ const char *zFName = P("name"); const char *zCI = P("ci"); Stmt q; login_check_credentials(); |
︙ | ︙ | |||
642 643 644 645 646 647 648 | @ <h1>MLINK table for file @ <a href='%R/finfo?name=%t(zFName)'>%h(zFName)</a></h1> @ <div class='brlist'> @ <table id='mlinktable'> @ <thead><tr> @ <th>Date</th> @ <th>Check-in</th> | | | | | | 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 | @ <h1>MLINK table for file @ <a href='%R/finfo?name=%t(zFName)'>%h(zFName)</a></h1> @ <div class='brlist'> @ <table id='mlinktable'> @ <thead><tr> @ <th>Date</th> @ <th>Check-in</th> @ <th>Parent Check-in</th> @ <th>Merge?</th> @ <th>New</th> @ <th>Old</th> @ <th>Exe Bit?</th> @ <th>Prior Name</th> @ </tr></thead> @ <tbody> while( db_step(&q)==SQLITE_ROW ){ const char *zDate = db_column_text(&q,0); const char *zCkin = db_column_text(&q,1); const char *zParent = db_column_text(&q,2); int isMerge = db_column_int(&q,3); const char *zFid = db_column_text(&q,4); const char *zPid = db_column_text(&q,5); int isExe = db_column_int(&q,7); const char *zPrior = db_column_text(&q,8); @ <tr> @ <td><a href='%R/timeline?c=%!S(zCkin)'>%s(zDate)</a></td> @ <td><a href='%R/info/%!S(zCkin)'>%S(zCkin)</a></td> if( zParent ){ @ <td><a href='%R/info/%!S(zPid)'>%S(zParent)</a></td> }else{ @ <td><i>(New)</i></td> } @ <td align='center'>%s(isMerge?"✓":"")</td> if( zFid ){ @ <td><a href='%R/info/%!S(zFid)'>%S(zFid)</a></td> }else{ |
︙ | ︙ | |||
715 716 717 718 719 720 721 | @ <h1>MLINK table for check-in %h(zCI)</h1> render_checkin_context(mid, 1); @ <hr /> @ <div class='brlist'> @ <table id='mlinktable'> @ <thead><tr> @ <th>File</th> | | | | | 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 | @ <h1>MLINK table for check-in %h(zCI)</h1> render_checkin_context(mid, 1); @ <hr /> @ <div class='brlist'> @ <table id='mlinktable'> @ <thead><tr> @ <th>File</th> @ <th>From</th> @ <th>Merge?</th> @ <th>New</th> @ <th>Old</th> @ <th>Exe Bit?</th> @ <th>Prior Name</th> @ </tr></thead> @ <tbody> while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q,0); const char *zFid = db_column_text(&q,1); const char *zPid = db_column_text(&q,3); const char *zPrior = db_column_text(&q,4); |
︙ | ︙ |
Changes to src/info.c.
︙ | ︙ | |||
762 763 764 765 766 767 768 | @ </td></tr> @ <tr><th>Other Links:</th> @ <td> @ %z(href("%R/tree?ci=%!S",zUuid))files</a> @ | %z(href("%R/fileage?name=%!S",zUuid))file ages</a> @ | %z(href("%R/tree?nofiles&type=tree&ci=%!S",zUuid))folders</a> @ | %z(href("%R/artifact/%!S",zUuid))manifest</a> | < < < | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 | @ </td></tr> @ <tr><th>Other Links:</th> @ <td> @ %z(href("%R/tree?ci=%!S",zUuid))files</a> @ | %z(href("%R/fileage?name=%!S",zUuid))file ages</a> @ | %z(href("%R/tree?nofiles&type=tree&ci=%!S",zUuid))folders</a> @ | %z(href("%R/artifact/%!S",zUuid))manifest</a> if( g.anon.Write ){ @ | %z(href("%R/ci_edit?r=%!S",zUuid))edit</a> } @ </td> @ </tr> blob_reset(&projName); } |
︙ | ︙ | |||
1573 1574 1575 1576 1577 1578 1579 | /* If the two file versions being compared both have the same ** filename, then offer an "Annotate" link that constructs an ** annotation between those version. */ db_prepare(&q, "SELECT (SELECT substr(uuid,1,20) FROM blob WHERE rid=a.mid)," " (SELECT substr(uuid,1,20) FROM blob WHERE rid=b.mid)," " (SELECT name FROM filename WHERE filename.fnid=a.fnid)" | | | < < < | | | 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 | /* If the two file versions being compared both have the same ** filename, then offer an "Annotate" link that constructs an ** annotation between those version. */ db_prepare(&q, "SELECT (SELECT substr(uuid,1,20) FROM blob WHERE rid=a.mid)," " (SELECT substr(uuid,1,20) FROM blob WHERE rid=b.mid)," " (SELECT name FROM filename WHERE filename.fnid=a.fnid)" " FROM mlink a, mlink b" " WHERE a.fid=%d" " AND b.fid=%d" " AND a.fnid=b.fnid" " AND a.fid!=a.pid" " AND b.fid!=b.pid", v1, v2 ); if( db_step(&q)==SQLITE_ROW ){ const char *zOrig = db_column_text(&q, 0); const char *zCkin = db_column_text(&q, 1); const char *zFN = db_column_text(&q, 2); style_submenu_element("Annotate", "%R/annotate?origin=%s&checkin=%s&filename=%T", zOrig, zCkin, zFN); } db_finalize(&q); } |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
733 734 735 736 737 738 739 | atexit( fossil_atexit ); #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** The TH1 return codes from the hook will be handled as follows: ** ** TH_OK: The xFunc() and the TH1 notification will both be executed. ** | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | atexit( fossil_atexit ); #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** The TH1 return codes from the hook will be handled as follows: ** ** TH_OK: The xFunc() and the TH1 notification will both be executed. ** ** TH_ERROR: The xFunc() will be executed, the TH1 notification will be ** skipped. If the xFunc() is being hooked, the error message ** will be emitted. ** ** TH_BREAK: The xFunc() and the TH1 notification will both be skipped. ** ** TH_RETURN: The xFunc() will be executed, the TH1 notification will be ** skipped. |
︙ | ︙ | |||
947 948 949 950 951 952 953 | #if defined(FOSSIL_HAVE_FUSEFS) blob_appendf(pOut, "libfuse %s, loaded %s\n", fusefs_inc_version(), fusefs_lib_version()); #endif #if defined(FOSSIL_DEBUG) blob_append(pOut, "FOSSIL_DEBUG\n", -1); #endif | | | | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 | #if defined(FOSSIL_HAVE_FUSEFS) blob_appendf(pOut, "libfuse %s, loaded %s\n", fusefs_inc_version(), fusefs_lib_version()); #endif #if defined(FOSSIL_DEBUG) blob_append(pOut, "FOSSIL_DEBUG\n", -1); #endif #if defined(FOSSIL_OMIT_DELTA_CKSUM_TEST) blob_append(pOut, "FOSSIL_OMIT_DELTA_CKSUM_TEST\n", -1); #endif #if defined(FOSSIL_ENABLE_LEGACY_MV_RM) blob_append(pOut, "FOSSIL_ENABLE_LEGACY_MV_RM\n", -1); #endif #if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) blob_append(pOut, "FOSSIL_ENABLE_EXEC_REL_PATHS\n", -1); #endif |
︙ | ︙ | |||
1289 1290 1291 1292 1293 1294 1295 | if( nName<7 ) continue; zUrl = sqlite3_mprintf("%.*s", nName-7, zName); if( sqlite3_strglob("*.fossil", zName)!=0 ){ /* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands ** do not work for repositories whose names do not end in ".fossil". ** So do not hyperlink those cases. */ @ <li>%h(zName)</li> | < < < | 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 | if( nName<7 ) continue; zUrl = sqlite3_mprintf("%.*s", nName-7, zName); if( sqlite3_strglob("*.fossil", zName)!=0 ){ /* The "fossil server DIRECTORY" and "fossil ui DIRECTORY" commands ** do not work for repositories whose names do not end in ".fossil". ** So do not hyperlink those cases. */ @ <li>%h(zName)</li> } else if( allRepo && sqlite3_strglob("[a-zA-Z]:/?*", zName)!=0 ){ @ <li><a href="%R/%T(zUrl)/home" target="_blank">/%h(zName)</a></li> }else{ @ <li><a href="%R/%T(zUrl)/home" target="_blank">%h(zName)</a></li> } sqlite3_free(zUrl); } |
︙ | ︙ | |||
1665 1666 1667 1668 1669 1670 1671 | }else{ #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** The TH1 return codes from the hook will be handled as follows: ** ** TH_OK: The xFunc() and the TH1 notification will both be executed. ** | | | 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 | }else{ #ifdef FOSSIL_ENABLE_TH1_HOOKS /* ** The TH1 return codes from the hook will be handled as follows: ** ** TH_OK: The xFunc() and the TH1 notification will both be executed. ** ** TH_ERROR: The xFunc() will be executed, the TH1 notification will be ** skipped. If the xFunc() is being hooked, the error message ** will be emitted. ** ** TH_BREAK: The xFunc() and the TH1 notification will both be skipped. ** ** TH_RETURN: The xFunc() will be executed, the TH1 notification will be ** skipped. |
︙ | ︙ |
Changes to src/path.c.
︙ | ︙ | |||
201 202 203 204 205 206 207 208 | ** both /annotate and /finfo. See also: compute_direct_ancestors(). */ void path_shortest_stored_in_ancestor_table( int origid, /* RID for check-in at start of the path */ int cid /* RID for check-in at the end of the path */ ){ PathNode *pPath; int gen = 0; | > < > | | < | < < > > | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | ** both /annotate and /finfo. See also: compute_direct_ancestors(). */ void path_shortest_stored_in_ancestor_table( int origid, /* RID for check-in at start of the path */ int cid /* RID for check-in at the end of the path */ ){ PathNode *pPath; Blob sql; int gen = 0; char *zSep = "VALUES"; pPath = path_shortest(cid, origid, 1, 0); db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ancestor(" " rid INT UNIQUE," " generation INTEGER PRIMARY KEY" ");" "DELETE FROM ancestor;" ); blob_init(&sql, "INSERT INTO ancestor(rid, generation)", -1); while( pPath ){ blob_append_sql(&sql, "%s(%d,%d)", zSep/*safe-for-%s*/, pPath->rid,++gen); zSep = ","; pPath = pPath->u.pTo; } path_reset(); db_multi_exec("%s", blob_sql_text(&sql)); blob_reset(&sql); } /* ** COMMAND: test-shortest-path ** ** Usage: %fossil test-shortest-path ?--no-merge? VERSION1 VERSION2 ** |
︙ | ︙ |
Changes to src/setup.c.
︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 | @ might not work inside a chroot() jail. @ (Property: "max-loadavg")</p> @ <hr /> onoff_attribute( "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", "auto-hyperlink", "autohyperlink", 1, 0); | | | < < | | > > | | < < | > > > | > | < > > | | 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 | @ might not work inside a chroot() jail. @ (Property: "max-loadavg")</p> @ <hr /> onoff_attribute( "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", "auto-hyperlink", "autohyperlink", 1, 0); @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users @ including user "nobody", as long as (1) the User-Agent string in the @ HTTP header indicates that the request is coming from an actual human @ being and not a robot or spider and (2) the user agent is able to @ run Javascript in order to set the href= attribute of hyperlinks. Bots @ and spiders can forge a User-Agent string that makes them seem to be a @ normal browser and they can run javascript just like browsers. But most @ bots do not go to that much trouble so this is normally an effective @ defense.<p> @ @ <p>You do not normally want a bot to walk your entire repository because @ if it does, your server will end up computing diffs and annotations for @ every historical version of every file and creating ZIPs and tarballs of @ every historical check-in, which can use a lot of CPU and bandwidth @ even for relatively small projects.</p> @ @ <p>Additional parameters that control this behavior:</p> @ <blockquote> onoff_attribute("Enable hyperlinks for humans as deduced from the UserAgent " "string", "auto-hyperlink-ishuman", "ahis", 0, 0); @ <br /> onoff_attribute("Require mouse movement before enabling hyperlinks", "auto-hyperlink-mouseover", "ahmo", 0, 0); @ <br /> entry_attribute("Delay in milliseconds before enabling hyperlinks", 5, "auto-hyperlink-delay", "ah-delay", "10", 0); @ </blockquote> @ <p>Hyperlinks for user "nobody" are normally enabled as soon as the page @ finishes loading. But the first check-box below can be set to require mouse @ movement before enabling the links. One can also set a delay prior to enabling @ links by enter a positive number of milliseconds in the entry box above.</p> @ (Properties: "auto-hyperlink", "auto-hyperlink-ishuman", @ "auto-hyperlink-mouseover", and "auto-hyperlink-delay")</p> @ <hr /> onoff_attribute("Require a CAPTCHA if not logged in", "require-captcha", "reqcapt", 1, 0); @ <p>Require a CAPTCHA for edit operations (appending, creating, or @ editing wiki or tickets or adding attachments to wiki or tickets) |
︙ | ︙ | |||
1648 1649 1650 1651 1652 1653 1654 | @ <hr /> textarea_attribute("Project Description", 3, 80, "project-description", "pd", "", 0); @ <p>Describe your project. This will be used in page headers for search @ engines as well as a short RSS description. @ (Property: "project-description")</p> @ <hr /> | | < < < < < < < < < < | 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 | @ <hr /> textarea_attribute("Project Description", 3, 80, "project-description", "pd", "", 0); @ <p>Describe your project. This will be used in page headers for search @ engines as well as a short RSS description. @ (Property: "project-description")</p> @ <hr /> entry_attribute("Tarball and ZIP-archive Prefix", 20, "short-project-name", "spn", "", 0); @ <p>This is used as a prefix on the names of generated tarballs and ZIP archive. @ For best results, keep this prefix brief and avoid special characters such @ as "/" and "\". @ If no tarball prefix is specified, then the full Project Name above is used. @ (Property: "short-project-name") @ </p> @ <hr /> onoff_attribute("Enable WYSIWYG Wiki Editing", "wysiwyg-wiki", "wysiwyg-wiki", 0, 0); @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages. @ The WYSIWYG editor generates HTML instead of markup, which makes @ subsequent manual editing more difficult. @ (Property: "wysiwyg-wiki")</p> |
︙ | ︙ |
Changes to src/sqlite3.c.
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.21.0" #define SQLITE_VERSION_NUMBER 3021000 | | | 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.21.0" #define SQLITE_VERSION_NUMBER 3021000 #define SQLITE_SOURCE_ID "2017-09-21 20:43:48 5d03c738e93d36815248991d9ed3d62297ba1bb966e602e7874410076c144f43" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
︙ | ︙ | |||
15277 15278 15279 15280 15281 15282 15283 | ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ #define SQLITE_ColumnCache 0x0002 /* Column cache */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ | > | | | > | | < < | > | 15277 15278 15279 15280 15281 15282 15283 15284 15285 15286 15287 15288 15289 15290 15291 15292 15293 15294 15295 15296 15297 15298 15299 15300 | ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ #define SQLITE_ColumnCache 0x0002 /* Column cache */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ /* not used 0x0010 // Was: SQLITE_IdxRealAsInt */ #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ #define SQLITE_CountOfView 0x1000 /* The count-of-view optimization */ #define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) |
︙ | ︙ | |||
17774 17775 17776 17777 17778 17779 17780 | #endif SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); | < < | 17775 17776 17777 17778 17779 17780 17781 17782 17783 17784 17785 17786 17787 17788 | #endif SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); |
︙ | ︙ | |||
43281 43282 43283 43284 43285 43286 43287 | extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); extendedParameters.dwFileAttributes = dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; extendedParameters.lpSecurityAttributes = NULL; extendedParameters.hTemplateFile = NULL; | < | | | | | > | < < < < | < < | | | | | < | < < < < > > | < | 43280 43281 43282 43283 43284 43285 43286 43287 43288 43289 43290 43291 43292 43293 43294 43295 43296 43297 43298 43299 43300 43301 43302 43303 43304 43305 43306 43307 43308 43309 43310 43311 43312 43313 43314 43315 43316 43317 43318 43319 43320 43321 43322 43323 43324 43325 43326 43327 43328 43329 | extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); extendedParameters.dwFileAttributes = dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; extendedParameters.lpSecurityAttributes = NULL; extendedParameters.hTemplateFile = NULL; while( (h = osCreateFile2((LPCWSTR)zConverted, dwDesiredAccess, dwShareMode, dwCreationDisposition, &extendedParameters))==INVALID_HANDLE_VALUE && winRetryIoerr(&cnt, &lastErrno) ){ /* Noop */ } #else do{ h = osCreateFileW((LPCWSTR)zConverted, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); if( h!=INVALID_HANDLE_VALUE ) break; if( isReadWrite ){ int isRO = 0; int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); if( rc2==SQLITE_OK && isRO ) break; } }while( winRetryIoerr(&cnt, &lastErrno) ); #endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ while( (h = osCreateFileA((LPCSTR)zConverted, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL))==INVALID_HANDLE_VALUE && winRetryIoerr(&cnt, &lastErrno) ){ /* Noop */ } } #endif winLogIoerr(cnt, __LINE__); OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name, dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); |
︙ | ︙ | |||
61040 61041 61042 61043 61044 61045 61046 | if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; int sz2 = 0; int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); | < < < | 61029 61030 61031 61032 61033 61034 61035 61036 61037 61038 61039 61040 61041 61042 | if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; int sz2 = 0; int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); if( iFree2 ){ assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */ sz2 = get2byte(&data[iFree2+2]); assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize ); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; } |
︙ | ︙ | |||
71395 71396 71397 71398 71399 71400 71401 | BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ int rc; pMem->flags = MEM_Null; | | < | 71381 71382 71383 71384 71385 71386 71387 71388 71389 71390 71391 71392 71393 71394 71395 71396 71397 | BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ int rc; pMem->flags = MEM_Null; if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt)) ){ rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z); if( rc==SQLITE_OK ){ pMem->flags = MEM_Blob; pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); } } return rc; |
︙ | ︙ | |||
91895 91896 91897 91898 91899 91900 91901 | return pExpr; } /* ** Return the collation sequence for the expression pExpr. If ** there is no defined collating sequence, return NULL. ** | < < < < < | 91880 91881 91882 91883 91884 91885 91886 91887 91888 91889 91890 91891 91892 91893 | return pExpr; } /* ** Return the collation sequence for the expression pExpr. If ** there is no defined collating sequence, return NULL. ** ** The collating sequence might be determined by a COLLATE operator ** or by the presence of a column with a defined collating sequence. ** COLLATE operators take first precedence. Left operands take ** precedence over right operands. */ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ sqlite3 *db = pParse->db; |
︙ | ︙ | |||
91964 91965 91966 91967 91968 91969 91970 | } if( sqlite3CheckCollSeq(pParse, pColl) ){ pColl = 0; } return pColl; } | < < < < < < < < < < < < < < < < < < < < < < < < < < | 91944 91945 91946 91947 91948 91949 91950 91951 91952 91953 91954 91955 91956 91957 | } if( sqlite3CheckCollSeq(pParse, pColl) ){ pColl = 0; } return pColl; } /* ** pExpr is an operand of a comparison operator. aff2 is the ** type affinity of the other operand. This routine returns the ** type affinity that should be used for the comparison operator. */ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); |
︙ | ︙ | |||
93483 93484 93485 93486 93487 93488 93489 | /* ** Return the bitwise-OR of all Expr.flags fields in the given ** ExprList. */ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ int i; u32 m = 0; | | | | | | > | 93437 93438 93439 93440 93441 93442 93443 93444 93445 93446 93447 93448 93449 93450 93451 93452 93453 93454 93455 93456 | /* ** Return the bitwise-OR of all Expr.flags fields in the given ** ExprList. */ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ int i; u32 m = 0; if( pList ){ for(i=0; i<pList->nExpr; i++){ Expr *pExpr = pList->a[i].pExpr; assert( pExpr!=0 ); m |= pExpr->flags; } } return m; } /* ** This is a SELECT-node callback for the expression walker that ** always "fails". By "fail" in this case, we mean set |
︙ | ︙ | |||
93644 93645 93646 93647 93648 93649 93650 | int i; /* Check if pExpr is identical to any GROUP BY term. If so, consider ** it constant. */ for(i=0; i<pGroupBy->nExpr; i++){ Expr *p = pGroupBy->a[i].pExpr; if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ | | | | 93599 93600 93601 93602 93603 93604 93605 93606 93607 93608 93609 93610 93611 93612 93613 93614 | int i; /* Check if pExpr is identical to any GROUP BY term. If so, consider ** it constant. */ for(i=0; i<pGroupBy->nExpr; i++){ Expr *p = pGroupBy->a[i].pExpr; if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p); if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){ return WRC_Prune; } } } /* Check if pExpr is a sub-select. If so, consider it variable. */ if( ExprHasProperty(pExpr, EP_xIsSelect) ){ |
︙ | ︙ | |||
117789 117790 117791 117792 117793 117794 117795 | Select standin; pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) ); if( pNew==0 ){ assert( pParse->db->mallocFailed ); pNew = &standin; } if( pEList==0 ){ | | < | 117744 117745 117746 117747 117748 117749 117750 117751 117752 117753 117754 117755 117756 117757 117758 | Select standin; pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) ); if( pNew==0 ){ assert( pParse->db->mallocFailed ); pNew = &standin; } if( pEList==0 ){ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0)); } pNew->pEList = pEList; pNew->op = TK_SELECT; pNew->selFlags = selFlags; pNew->iLimit = 0; pNew->iOffset = 0; #if SELECTTRACE_ENABLED |
︙ | ︙ | |||
117814 117815 117816 117817 117818 117819 117820 | pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; pNew->pPrior = 0; pNew->pNext = 0; pNew->pLimit = pLimit; pNew->pOffset = pOffset; pNew->pWith = 0; | | < | 117768 117769 117770 117771 117772 117773 117774 117775 117776 117777 117778 117779 117780 117781 117782 | pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; pNew->pPrior = 0; pNew->pNext = 0; pNew->pLimit = pLimit; pNew->pOffset = pOffset; pNew->pWith = 0; assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 ); if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); pNew = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); } assert( pNew!=&standin ); |
︙ | ︙ | |||
118432 118433 118434 118435 118436 118437 118438 | p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; } } regOrig = 0; assert( eDest==SRT_Set || eDest==SRT_Mem || eDest==SRT_Coroutine || eDest==SRT_Output ); } | | < | 118385 118386 118387 118388 118389 118390 118391 118392 118393 118394 118395 118396 118397 118398 118399 | p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; } } regOrig = 0; assert( eDest==SRT_Set || eDest==SRT_Mem || eDest==SRT_Coroutine || eDest==SRT_Output ); } nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult,0,ecelFlags); } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ |
︙ | ︙ | |||
118783 118784 118785 118786 118787 118788 118789 | int i; nExpr = pList->nExpr; pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){ | > > > | | 118735 118736 118737 118738 118739 118740 118741 118742 118743 118744 118745 118746 118747 118748 118749 118750 118751 118752 | int i; nExpr = pList->nExpr; pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){ CollSeq *pColl; pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); if( !pColl ) pColl = db->pDfltColl; pInfo->aColl[i-iStart] = pColl; pInfo->aSortOrder[i-iStart] = pItem->sortOrder; } } return pInfo; } /* |
︙ | ︙ | |||
119244 119245 119246 119247 119248 119249 119250 | ** other modes for legacy: ** ** short=OFF, full=OFF: Column name is the text of the expression has it ** originally appears in the SELECT statement. In ** other words, the zSpan of the result expression. ** ** short=ON, full=OFF: (This is the default setting). If the result | | | | | 119199 119200 119201 119202 119203 119204 119205 119206 119207 119208 119209 119210 119211 119212 119213 119214 119215 | ** other modes for legacy: ** ** short=OFF, full=OFF: Column name is the text of the expression has it ** originally appears in the SELECT statement. In ** other words, the zSpan of the result expression. ** ** short=ON, full=OFF: (This is the default setting). If the result ** refers directly to a table column, then the result ** column name is just the table column name: COLUMN. ** Otherwise use zSpan. ** ** full=ON, short=ANY: If the result refers directly to a table column, ** then the result column name with the table name ** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ static void generateColumnNames( Parse *pParse, /* Parser context */ |
︙ | ︙ | |||
119288 119289 119290 119291 119292 119293 119294 | srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; i<pEList->nExpr; i++){ Expr *p = pEList->a[i].pExpr; assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ | | | 119243 119244 119245 119246 119247 119248 119249 119250 119251 119252 119253 119254 119255 119256 119257 | srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; i<pEList->nExpr; i++){ Expr *p = pEList->a[i].pExpr; assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering indexes not yet coded */ if( pEList->a[i].zName ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zName; sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; |
︙ | ︙ | |||
120852 120853 120854 120855 120856 120857 120858 | ** of the subquery rather the result set of the subquery. */ static Expr *substExpr( SubstContext *pSubst, /* Description of the substitution */ Expr *pExpr /* Expr in which substitution occurs */ ){ if( pExpr==0 ) return 0; | | < < | 120807 120808 120809 120810 120811 120812 120813 120814 120815 120816 120817 120818 120819 120820 120821 | ** of the subquery rather the result set of the subquery. */ static Expr *substExpr( SubstContext *pSubst, /* Description of the substitution */ Expr *pExpr /* Expr in which substitution occurs */ ){ if( pExpr==0 ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){ pExpr->iRightJoinTable = pSubst->iNewTable; } if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){ if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ Expr *pNew; |
︙ | ︙ | |||
120967 120968 120969 120970 120971 120972 120973 | ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 ** ** The code generated for this simplification gives the same result ** but only has to scan the data once. And because indices might ** exist on the table t1, a complete scan of the data might be ** avoided. ** | | < | < | < | | | < | | | | < | | | | | > | | | | | | | | | | | | < | < < > | | | | | | | | | < | | | > | > > > > > > > > > > | > > > > > | | | < | | | < | | | < | | | | | | | | 120920 120921 120922 120923 120924 120925 120926 120927 120928 120929 120930 120931 120932 120933 120934 120935 120936 120937 120938 120939 120940 120941 120942 120943 120944 120945 120946 120947 120948 120949 120950 120951 120952 120953 120954 120955 120956 120957 120958 120959 120960 120961 120962 120963 120964 120965 120966 120967 120968 120969 120970 120971 120972 120973 120974 120975 120976 120977 120978 120979 120980 120981 120982 120983 120984 120985 120986 120987 120988 120989 120990 120991 120992 120993 120994 120995 120996 120997 120998 120999 121000 121001 121002 121003 121004 121005 121006 121007 121008 121009 121010 121011 121012 121013 121014 121015 121016 121017 121018 121019 121020 121021 121022 121023 121024 121025 121026 121027 121028 121029 121030 121031 121032 121033 121034 121035 121036 121037 121038 121039 121040 121041 121042 121043 121044 121045 121046 121047 121048 121049 121050 121051 121052 121053 121054 121055 121056 121057 121058 121059 121060 121061 121062 121063 121064 121065 121066 121067 121068 121069 121070 121071 121072 121073 121074 121075 121076 121077 121078 121079 121080 121081 121082 121083 121084 121085 121086 121087 121088 121089 121090 121091 121092 121093 121094 121095 121096 121097 121098 121099 121100 121101 121102 121103 121104 121105 121106 121107 121108 121109 121110 121111 121112 121113 121114 121115 121116 121117 121118 121119 121120 121121 121122 121123 121124 121125 121126 121127 121128 121129 121130 121131 121132 121133 121134 121135 121136 121137 121138 121139 121140 121141 121142 121143 121144 121145 121146 121147 121148 121149 121150 121151 121152 121153 121154 121155 121156 121157 121158 121159 121160 121161 121162 121163 121164 121165 121166 121167 121168 121169 121170 121171 121172 121173 121174 121175 121176 121177 121178 121179 121180 121181 121182 121183 121184 121185 121186 121187 121188 121189 | ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 ** ** The code generated for this simplification gives the same result ** but only has to scan the data once. And because indices might ** exist on the table t1, a complete scan of the data might be ** avoided. ** ** Flattening is only attempted if all of the following are true: ** ** (1) The subquery and the outer query do not both use aggregates. ** ** (2) The subquery is not an aggregate or (2a) the outer query is not a join ** and (2b) the outer query does not use subqueries other than the one ** FROM-clause subquery that is a candidate for flattening. (2b is ** due to ticket [2f7170d73bf9abf80] from 2015-02-09.) ** ** (3) The subquery is not the right operand of a LEFT JOIN ** or (a) the subquery is not itself a join and (b) the FROM clause ** of the subquery does not contain a virtual table and (c) the ** outer query is not an aggregate. ** ** (4) The subquery is not DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT ** sub-queries that were excluded from this optimization. Restriction ** (4) has since been expanded to exclude all DISTINCT subqueries. ** ** (6) The subquery does not use aggregates or the outer query is not ** DISTINCT. ** ** (7) The subquery has a FROM clause. TODO: For subqueries without ** A FROM clause, consider adding a FROM clause with the special ** table sqlite_once that consists of a single row containing a ** single NULL. ** ** (8) The subquery does not use LIMIT or the outer query is not a join. ** ** (9) The subquery does not use LIMIT or the outer query does not use ** aggregates. ** ** (**) Restriction (10) was removed from the code on 2005-02-05 but we ** accidently carried the comment forward until 2014-09-15. Original ** text: "The subquery does not use aggregates or the outer query ** does not use LIMIT." ** ** (11) The subquery and the outer query do not both have ORDER BY clauses. ** ** (**) Not implemented. Subsumed into restriction (3). Was previously ** a separate restriction deriving from ticket #350. ** ** (13) The subquery and outer query do not both use LIMIT. ** ** (14) The subquery does not use OFFSET. ** ** (15) The outer query is not part of a compound select or the ** subquery does not have a LIMIT clause. ** (See ticket #2339 and ticket [02a8e81d44]). ** ** (16) The outer query is not an aggregate or the subquery does ** not contain ORDER BY. (Ticket #2942) This used to not matter ** until we introduced the group_concat() function. ** ** (17) The sub-query is not a compound select, or it is a UNION ALL ** compound clause made up entirely of non-aggregate queries, and ** the parent query: ** ** * is not itself part of a compound select, ** * is not an aggregate or DISTINCT query, and ** * is not a join ** ** The parent and sub-query may contain WHERE clauses. Subject to ** rules (11), (13) and (14), they may also contain ORDER BY, ** LIMIT and OFFSET clauses. The subquery cannot use any compound ** operator other than UNION ALL because all the other compound ** operators have an implied DISTINCT which is disallowed by ** restriction (4). ** ** Also, each component of the sub-query must return the same number ** of result columns. This is actually a requirement for any compound ** SELECT statement, but all the code here does is make sure that no ** such (illegal) sub-query is flattened. The caller will detect the ** syntax error and return a detailed message. ** ** (18) If the sub-query is a compound select, then all terms of the ** ORDER by clause of the parent must be simple references to ** columns of the sub-query. ** ** (19) The subquery does not use LIMIT or the outer query does not ** have a WHERE clause. ** ** (20) If the sub-query is a compound select, then it must not use ** an ORDER BY clause. Ticket #3773. We could relax this constraint ** somewhat by saying that the terms of the ORDER BY clause must ** appear as unmodified result columns in the outer query. But we ** have other optimizations in mind to deal with that case. ** ** (21) The subquery does not use LIMIT or the outer query is not ** DISTINCT. (See ticket [752e1646fc]). ** ** (22) The subquery is not a recursive CTE. ** ** (23) The parent is not a recursive CTE, or the sub-query is not a ** compound query. This restriction is because transforming the ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** ** (24) The subquery is not an aggregate that uses the built-in min() or ** or max() functions. (Without this restriction, a query like: ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily ** return the value X for which Y was maximal.) ** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. ** ** All of the expression analysis must occur on both the outer query and ** the subquery before this routine runs. */ static int flattenSubquery( Parse *pParse, /* Parsing context */ Select *p, /* The parent or outer SELECT statement */ int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ int isAgg, /* True if outer SELECT uses aggregate functions */ int subqueryIsAgg /* True if the subquery uses aggregate functions */ ){ const char *zSavedAuthContext = pParse->zAuthContext; Select *pParent; /* Current UNION ALL term of the other query */ Select *pSub; /* The inner query or "subquery" */ Select *pSub1; /* Pointer to the rightmost select in sub-query */ SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ int iParent; /* VDBE cursor number of the pSub result set temp table */ int iNewParent = -1;/* Replacement table for iParent */ int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ int i; /* Loop counter */ Expr *pWhere; /* The WHERE clause */ struct SrcList_item *pSubitem; /* The subquery */ sqlite3 *db = pParse->db; /* Check to see if flattening is permitted. Return 0 if not. */ assert( p!=0 ); assert( p->pPrior==0 ); /* Unable to flatten compound queries */ if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; pSrc = p->pSrc; assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc ); pSubitem = &pSrc->a[iFrom]; iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; assert( pSub!=0 ); if( subqueryIsAgg ){ if( isAgg ) return 0; /* Restriction (1) */ if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */ if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery)) || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0 || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0 ){ return 0; /* Restriction (2b) */ } } pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET ** because they could be computed at compile-time. But when LIMIT and OFFSET ** became arbitrary expressions, we were forced to add restrictions (13) ** and (14). */ if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */ if( pSub->pOffset ) return 0; /* Restriction (14) */ if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){ return 0; /* Restriction (15) */ } if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */ if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){ return 0; /* Restrictions (8)(9) */ } if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){ return 0; /* Restriction (6) */ } if( p->pOrderBy && pSub->pOrderBy ){ return 0; /* Restriction (11) */ } if( isAgg && pSub->pOrderBy ) return 0; /* Restriction (16) */ if( pSub->pLimit && p->pWhere ) return 0; /* Restriction (19) */ if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ return 0; /* Restriction (21) */ } testcase( pSub->selFlags & SF_Recursive ); testcase( pSub->selFlags & SF_MinMaxAgg ); if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){ return 0; /* Restrictions (22) and (24) */ } if( (p->selFlags & SF_Recursive) && pSub->pPrior ){ return 0; /* Restriction (23) */ } /* ** If the subquery is the right operand of a LEFT JOIN, then the ** subquery may not be a join itself. Example of why this is not allowed: ** ** t1 LEFT OUTER JOIN (t2 JOIN t3) ** ** If we flatten the above, we would get ** ** (t1 LEFT OUTER JOIN t2) JOIN t3 ** ** which is not at all the same thing. ** ** If the subquery is the right operand of a LEFT JOIN, then the outer ** query cannot be an aggregate. This is an artifact of the way aggregates ** are processed - there is no mechanism to determine if the LEFT JOIN ** table should be all-NULL. ** ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ isLeftJoin = 1; if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){ return 0; /* Restriction (3) */ } } #ifdef SQLITE_EXTRA_IFNULLROW else if( iFrom>0 && !isAgg ){ /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for ** every reference to any result column from subquery in a join, even though ** they are not necessary. This will stress-test the OP_IfNullRow opcode. */ isLeftJoin = -1; } #endif /* Restriction 17: If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ if( pSub->pPrior ){ if( pSub->pOrderBy ){ return 0; /* Restriction 20 */ } if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){ return 0; } for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){ testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); assert( pSub->pSrc!=0 ); assert( pSub->pEList->nExpr==pSub1->pEList->nExpr ); if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 || (pSub1->pPrior && pSub1->op!=TK_ALL) || pSub1->pSrc->nSrc<1 ){ return 0; } testcase( pSub1->pSrc->nSrc>1 ); } /* Restriction 18. */ if( p->pOrderBy ){ int ii; for(ii=0; ii<p->pOrderBy->nExpr; ii++){ if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0; } } } |
︙ | ︙ | |||
121437 121438 121439 121440 121441 121442 121443 | pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } pWhere = sqlite3ExprDup(db, pSub->pWhere, 0); if( isLeftJoin>0 ){ setJoinExpr(pWhere, iNewParent); } | > > > > > > > > > > | > | 121396 121397 121398 121399 121400 121401 121402 121403 121404 121405 121406 121407 121408 121409 121410 121411 121412 121413 121414 121415 121416 121417 121418 121419 121420 121421 | pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } pWhere = sqlite3ExprDup(db, pSub->pWhere, 0); if( isLeftJoin>0 ){ setJoinExpr(pWhere, iNewParent); } if( subqueryIsAgg ){ assert( pParent->pHaving==0 ); pParent->pHaving = pParent->pWhere; pParent->pWhere = pWhere; pParent->pHaving = sqlite3ExprAnd(db, sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving ); assert( pParent->pGroupBy==0 ); pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0); }else{ pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); } if( db->mallocFailed==0 ){ SubstContext x; x.pParse = pParse; x.iTable = iParent; x.iNewTable = iNewParent; x.isLeftJoin = isLeftJoin; x.pEList = pSub->pEList; |
︙ | ︙ | |||
121500 121501 121502 121503 121504 121505 121506 | ** WHERE x=5 AND y=10; ** ** The hope is that the terms added to the inner query will make it more ** efficient. ** ** Do not attempt this optimization if: ** | | < < | < < | | 121470 121471 121472 121473 121474 121475 121476 121477 121478 121479 121480 121481 121482 121483 121484 121485 121486 | ** WHERE x=5 AND y=10; ** ** The hope is that the terms added to the inner query will make it more ** efficient. ** ** Do not attempt this optimization if: ** ** (1) The inner query is an aggregate. (In that case, we'd really want ** to copy the outer WHERE-clause terms onto the HAVING clause of the ** inner query. But they probably won't help there so do not bother.) ** ** (2) The inner query is the recursive part of a common table expression. ** ** (3) The inner query has a LIMIT clause (since the changes to the WHERE ** close would change the meaning of the LIMIT). ** ** (4) The inner query is the right operand of a LEFT JOIN. (The caller |
︙ | ︙ | |||
121531 121532 121533 121534 121535 121536 121537 121538 | Parse *pParse, /* Parse context (for malloc() and error reporting) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ Expr *pWhere, /* The WHERE clause of the outer query */ int iCursor /* Cursor number of the subquery */ ){ Expr *pNew; int nChng = 0; if( pWhere==0 ) return 0; | > < < < < < < < < < | | > > > > < < | < < < | < | 121497 121498 121499 121500 121501 121502 121503 121504 121505 121506 121507 121508 121509 121510 121511 121512 121513 121514 121515 121516 121517 121518 121519 121520 121521 121522 121523 121524 121525 121526 121527 121528 121529 121530 121531 121532 121533 121534 121535 121536 121537 121538 121539 121540 | Parse *pParse, /* Parse context (for malloc() and error reporting) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ Expr *pWhere, /* The WHERE clause of the outer query */ int iCursor /* Cursor number of the subquery */ ){ Expr *pNew; int nChng = 0; Select *pX; /* For looping over compound SELECTs in pSubq */ if( pWhere==0 ) return 0; for(pX=pSubq; pX; pX=pX->pPrior){ if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){ testcase( pX->selFlags & SF_Aggregate ); testcase( pX->selFlags & SF_Recursive ); testcase( pX!=pSubq ); return 0; /* restrictions (1) and (2) */ } } if( pSubq->pLimit!=0 ){ return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor); pWhere = pWhere->pLeft; } if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */ if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; while( pSubq ){ SubstContext x; pNew = sqlite3ExprDup(pParse->db, pWhere, 0); x.pParse = pParse; x.iTable = iCursor; x.iNewTable = iCursor; x.isLeftJoin = 0; x.pEList = pSubq->pEList; pNew = substExpr(&x, pNew); pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); pSubq = pSubq->pPrior; } } return nChng; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ |
︙ | ︙ | |||
121898 121899 121900 121901 121902 121903 121904 | /* Only one recursive reference is permitted. */ if( pTab->nTabRef>2 ){ sqlite3ErrorMsg( pParse, "multiple references to recursive table: %s", pCte->zName ); return SQLITE_ERROR; } | < | | 121854 121855 121856 121857 121858 121859 121860 121861 121862 121863 121864 121865 121866 121867 121868 | /* Only one recursive reference is permitted. */ if( pTab->nTabRef>2 ){ sqlite3ErrorMsg( pParse, "multiple references to recursive table: %s", pCte->zName ); return SQLITE_ERROR; } assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; if( bMayRecursive ){ Select *pPrior = pSel->pPrior; assert( pPrior->pWith==0 ); |
︙ | ︙ | |||
122043 122044 122045 122046 122047 122048 122049 | /* A sub-query in the FROM clause of a SELECT */ assert( pSel!=0 ); assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nTabRef = 1; | < < < | < | 121998 121999 122000 122001 122002 122003 122004 122005 122006 122007 122008 122009 122010 122011 122012 | /* A sub-query in the FROM clause of a SELECT */ assert( pSel!=0 ); assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nTabRef = 1; pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab); while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; #endif }else{ |
︙ | ︙ | |||
122707 122708 122709 122710 122711 122712 122713 | ** Return TRUE if the optimization is undertaken. */ static int countOfViewOptimization(Parse *pParse, Select *p){ Select *pSub, *pPrior; Expr *pExpr; Expr *pCount; sqlite3 *db; | | | | | | | | 122658 122659 122660 122661 122662 122663 122664 122665 122666 122667 122668 122669 122670 122671 122672 122673 122674 122675 122676 122677 122678 122679 122680 122681 122682 122683 122684 122685 122686 122687 122688 122689 | ** Return TRUE if the optimization is undertaken. */ static int countOfViewOptimization(Parse *pParse, Select *p){ Select *pSub, *pPrior; Expr *pExpr; Expr *pCount; sqlite3 *db; if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate query */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ pExpr = p->pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Must be count() */ if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ if( p->pSrc->nSrc!=1 ) return 0; /* One table in the FROM clause */ pSub = p->pSrc->a[0].pSelect; if( pSub==0 ) return 0; /* The FROM is a subquery */ if( pSub->pPrior==0 ) return 0; /* Must be a compound subquery */ do{ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ pSub = pSub->pPrior; /* Repeat over compound terms */ }while( pSub ); /* If we reach this point, that means it is OK to perform the transformation */ db = pParse->db; pCount = pExpr; pExpr = 0; pSub = p->pSrc->a[0].pSelect; p->pSrc->a[0].pSelect = 0; sqlite3SrcListDelete(db, p->pSrc); |
︙ | ︙ | |||
122864 122865 122866 122867 122868 122869 122870 122871 122872 122873 122874 122875 122876 122877 122878 122879 122880 122881 | /* Try to flatten subqueries in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; Table *pTab = pItem->pTab; if( pSub==0 ) continue; /* Catch mismatch in the declared columns of a view and the number of ** columns in the SELECT on the RHS */ if( pTab->nCol!=pSub->pEList->nExpr ){ sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d", pTab->nCol, pTab->zName, pSub->pEList->nExpr); goto select_end; } | > < < < < < < < | < < < < < < < < < < < < < < < < < < < < | > > > > | 122815 122816 122817 122818 122819 122820 122821 122822 122823 122824 122825 122826 122827 122828 122829 122830 122831 122832 122833 122834 122835 122836 122837 122838 122839 122840 122841 122842 122843 122844 122845 122846 122847 | /* Try to flatten subqueries in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; int isAggSub; Table *pTab = pItem->pTab; if( pSub==0 ) continue; /* Catch mismatch in the declared columns of a view and the number of ** columns in the SELECT on the RHS */ if( pTab->nCol!=pSub->pEList->nExpr ){ sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d", pTab->nCol, pTab->zName, pSub->pEList->nExpr); goto select_end; } isAggSub = (pSub->selFlags & SF_Aggregate)!=0; if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ /* This subquery can be absorbed into its parent. */ if( isAggSub ){ isAgg = 1; p->selFlags |= SF_Aggregate; } i = -1; } pTabList = p->pSrc; if( db->mallocFailed ) goto select_end; if( !IgnorableOrderby(pDest) ){ sSort.pOrderBy = p->pOrderBy; } |
︙ | ︙ | |||
122938 122939 122940 122941 122942 122943 122944 | ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries */ for(i=0; i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; SelectDest dest; Select *pSub; | < < < | | | < | | | | 122867 122868 122869 122870 122871 122872 122873 122874 122875 122876 122877 122878 122879 122880 122881 122882 122883 122884 122885 122886 122887 122888 122889 122890 122891 122892 122893 122894 122895 | ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries */ for(i=0; i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; SelectDest dest; Select *pSub; /* Issue SQLITE_READ authorizations with a fake column name for any tables that ** are referenced but from which no values are extracted. Examples of where these ** kinds of null SQLITE_READ authorizations would occur: ** ** SELECT count(*) FROM t1; -- SQLITE_READ t1."" ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2."" ** ** The fake column name is an empty string. It is possible for a table to ** have a column named by the empty string, in which case there is no way to ** distinguish between an unreferenced table and an actual reference to the ** "" column. The original design was for the fake column name to be a NULL, ** which would be unambiguous. But legacy authorization callbacks might ** assume the column name is non-NULL and segfault. The use of an empty string ** for the fake column name seems safer. */ if( pItem->colUsed==0 ){ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* Generate code for all sub-queries in the FROM clause |
︙ | ︙ | |||
123008 123009 123010 123011 123012 123013 123014 | if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } | < < < | | | > > > > > > > < | 122933 122934 122935 122936 122937 122938 122939 122940 122941 122942 122943 122944 122945 122946 122947 122948 122949 122950 122951 122952 122953 122954 122955 122956 122957 122958 122959 122960 122961 122962 122963 122964 122965 122966 122967 122968 122969 122970 | if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* Generate code to implement the subquery ** ** The subquery is implemented as a co-routine if all of these are true: ** (1) The subquery is guaranteed to be the outer loop (so that it ** does not need to be computed more than once) ** (2) The ALL keyword after SELECT is omitted. (Applications are ** allowed to say "SELECT ALL" instead of just "SELECT" to disable ** the use of co-routines.) ** (3) Co-routines are not disabled using sqlite3_test_control() ** with SQLITE_TESTCTRL_OPTIMIZATIONS. ** ** TODO: Are there other reasons beside (1) to use a co-routine ** implementation? */ if( i==0 && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ && (p->selFlags & SF_All)==0 /* (2) */ && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */ ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); |
︙ | ︙ | |||
123086 123087 123088 123089 123090 123091 123092 | retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); | < | 123014 123015 123016 123017 123018 123019 123020 123021 123022 123023 123024 123025 123026 123027 | retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); #endif } /* Various elements of the SELECT copied into local variables for ** convenience */ pEList = p->pEList; pWhere = p->pWhere; |
︙ | ︙ | |||
131092 131093 131094 131095 131096 131097 131098 131099 131100 131101 131102 131103 131104 131105 131106 131107 131108 131109 131110 | ** for the LHS anyplace else in the WHERE clause where the LHS column occurs. ** This is an optimization. No harm comes from returning 0. But if 1 is ** returned when it should not be, then incorrect answers might result. */ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; | > | > > > > | 131019 131020 131021 131022 131023 131024 131025 131026 131027 131028 131029 131030 131031 131032 131033 131034 131035 131036 131037 131038 131039 131040 131041 131042 131043 131044 131045 131046 131047 131048 131049 131050 | ** for the LHS anyplace else in the WHERE clause where the LHS column occurs. ** This is an optimization. No harm comes from returning 0. But if 1 is ** returned when it should not be, then incorrect answers might result. */ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; const char *zColl1, *zColl2; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); zColl1 = pColl ? pColl->zName : 0; pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); zColl2 = pColl ? pColl->zName : 0; return sqlite3_stricmp(zColl1, zColl2)==0; } /* ** Recursively walk the expressions of a SELECT statement and generate ** a bitmask indicating which tables are used in that expression ** tree. */ |
︙ | ︙ | |||
132185 132186 132187 132188 132189 132190 132191 | for(i=0; i<pList->nExpr; i++){ Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); if( p->op==TK_COLUMN && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ | | | | 132117 132118 132119 132120 132121 132122 132123 132124 132125 132126 132127 132128 132129 132130 132131 132132 | for(i=0; i<pList->nExpr; i++){ Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); if( p->op==TK_COLUMN && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } } } return -1; } |
︙ | ︙ | |||
134451 134452 134453 134454 134455 134456 134457 | if( pExpr->iColumn<0 ) return 1; for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; | | | 134383 134384 134385 134386 134387 134388 134389 134390 134391 134392 134393 134394 134395 134396 134397 | if( pExpr->iColumn<0 ) return 1; for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; if( sqlite3ExprCompare(0, pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ return 1; } } } } return 0; } |
︙ | ︙ | |||
135361 135362 135363 135364 135365 135366 135367 | ** optimization, and then only if they are actually used ** by the query plan */ assert( wctrlFlags & WHERE_ORDERBY_LIMIT ); for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){} if( j>=pLoop->nLTerm ) continue; } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ | > | > > | > > | < | 135293 135294 135295 135296 135297 135298 135299 135300 135301 135302 135303 135304 135305 135306 135307 135308 135309 135310 135311 135312 135313 135314 | ** optimization, and then only if they are actually used ** by the query plan */ assert( wctrlFlags & WHERE_ORDERBY_LIMIT ); for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){} if( j>=pLoop->nLTerm ) continue; } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ const char *z1, *z2; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; z1 = pColl->zName; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr); if( !pColl ) pColl = db->pDfltColl; z2 = pColl->zName; if( sqlite3StrICmp(z1, z2)!=0 ) continue; testcase( pTerm->pExpr->op==TK_IS ); } obSat |= MASKBIT(i); } if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ if( pLoop->wsFlags & WHERE_IPK ){ |
︙ | ︙ | |||
135436 135437 135438 135439 135440 135441 135442 | /* Get the column number in the table (iColumn) and sort order ** (revIdx) for the j-th column of the index. */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j]; | | | 135372 135373 135374 135375 135376 135377 135378 135379 135380 135381 135382 135383 135384 135385 135386 | /* Get the column number in the table (iColumn) and sort order ** (revIdx) for the j-th column of the index. */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j]; if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; }else{ iColumn = XN_ROWID; revIdx = 0; } /* An unconstrained column that might be NULL means that this ** WhereLoop is not well-ordered |
︙ | ︙ | |||
135463 135464 135465 135466 135467 135468 135469 | isMatch = 0; for(i=0; bOnce && i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; | | < | > | > | 135399 135400 135401 135402 135403 135404 135405 135406 135407 135408 135409 135410 135411 135412 135413 135414 135415 135416 135417 135418 135419 135420 135421 135422 135423 135424 135425 | isMatch = 0; for(i=0; bOnce && i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( iColumn>=(-1) ){ if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ if( sqlite3ExprCompare(0, pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){ continue; } } if( iColumn!=XN_ROWID ){ pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } pLoop->u.btree.nIdxCol = j+1; isMatch = 1; break; } if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ |
︙ | ︙ | |||
137156 137157 137158 137159 137160 137161 137162 | ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YY_MAX_SHIFT Maximum value for shift actions ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions | < | | 137093 137094 137095 137096 137097 137098 137099 137100 137101 137102 137103 137104 137105 137106 137107 | ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YY_MAX_SHIFT Maximum value for shift actions ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions ** YY_MIN_REDUCE Maximum value for reduce actions ** YY_ERROR_ACTION The yy_action[] code for syntax error ** YY_ACCEPT_ACTION The yy_action[] code for accept ** YY_NO_ACTION The yy_action[] code for no-op */ #ifndef INTERFACE # define INTERFACE 1 #endif |
︙ | ︙ | |||
184954 184955 184956 184957 184958 184959 184960 | ** fts5YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** fts5YYNSTATE the combined number of states. ** fts5YYNRULE the number of rules in the grammar ** fts5YY_MAX_SHIFT Maximum value for shift actions ** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions | < | | 184890 184891 184892 184893 184894 184895 184896 184897 184898 184899 184900 184901 184902 184903 184904 | ** fts5YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** fts5YYNSTATE the combined number of states. ** fts5YYNRULE the number of rules in the grammar ** fts5YY_MAX_SHIFT Maximum value for shift actions ** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions ** fts5YY_MIN_REDUCE Maximum value for reduce actions ** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error ** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept ** fts5YY_NO_ACTION The fts5yy_action[] code for no-op */ #ifndef INTERFACE # define INTERFACE 1 #endif |
︙ | ︙ | |||
200695 200696 200697 200698 200699 200700 200701 | static void fts5SourceIdFunc( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ sqlite3_value **apUnused /* Function arguments */ ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); | | | 200630 200631 200632 200633 200634 200635 200636 200637 200638 200639 200640 200641 200642 200643 200644 | static void fts5SourceIdFunc( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ sqlite3_value **apUnused /* Function arguments */ ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); sqlite3_result_text(pCtx, "fts5: 2017-09-21 20:43:48 5d03c738e93d36815248991d9ed3d62297ba1bb966e602e7874410076c144f43", -1, SQLITE_TRANSIENT); } static int fts5Init(sqlite3 *db){ static const sqlite3_module fts5Mod = { /* iVersion */ 2, /* xCreate */ fts5CreateMethod, /* xConnect */ fts5ConnectMethod, |
︙ | ︙ | |||
204964 204965 204966 204967 204968 204969 204970 | #endif return rc; } #endif /* SQLITE_CORE */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ | | | | 204899 204900 204901 204902 204903 204904 204905 204906 204907 204908 204909 204910 204911 204912 | #endif return rc; } #endif /* SQLITE_CORE */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ #if __LINE__!=204906 #undef SQLITE_SOURCE_ID #define SQLITE_SOURCE_ID "2017-09-21 20:43:48 5d03c738e93d36815248991d9ed3d62297ba1bb966e602e7874410076c14alt2" #endif /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } /************************** End of sqlite3.c ******************************/ |
Changes to src/sqlite3.h.
︙ | ︙ | |||
121 122 123 124 125 126 127 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.21.0" #define SQLITE_VERSION_NUMBER 3021000 | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.21.0" #define SQLITE_VERSION_NUMBER 3021000 #define SQLITE_SOURCE_ID "2017-09-21 20:43:48 5d03c738e93d36815248991d9ed3d62297ba1bb966e602e7874410076c144f43" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
︙ | ︙ |
Changes to src/style.c.
︙ | ︙ | |||
1423 1424 1425 1426 1427 1428 1429 | }, { ".brlist table", "The list of branches", @ border-spacing: 0; }, { ".brlist table th", "Branch list table headers", @ text-align: left; @ padding: 0px 1em 0.5ex 0px; | < | 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 | }, { ".brlist table", "The list of branches", @ border-spacing: 0; }, { ".brlist table th", "Branch list table headers", @ text-align: left; @ padding: 0px 1em 0.5ex 0px; }, { ".brlist table td", "Branch list table headers", @ padding: 0px 2em 0px 0px; @ white-space: nowrap; }, { "th.sort:after", "General styles for sortable column marker", |
︙ | ︙ |
Changes to src/th.h.
︙ | ︙ | |||
100 101 102 103 104 105 106 | ** Valid return codes for xProc callbacks. */ #define TH_OK 0 #define TH_ERROR 1 #define TH_BREAK 2 #define TH_RETURN 3 #define TH_CONTINUE 4 | < | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | ** Valid return codes for xProc callbacks. */ #define TH_OK 0 #define TH_ERROR 1 #define TH_BREAK 2 #define TH_RETURN 3 #define TH_CONTINUE 4 /* ** Set and get the interpreter result. */ int Th_SetResult(Th_Interp *, const char *, int); const char *Th_GetResult(Th_Interp *, int *); char *Th_TakeResult(Th_Interp *, int *); |
︙ | ︙ |
Changes to src/th_lang.c.
︙ | ︙ | |||
431 432 433 434 435 436 437 | procargs.argv = argv; procargs.argl = argl; rc = Th_InFrame(interp, proc_call2, (void *)p, (void *)&procargs); if( rc==TH_RETURN ){ rc = TH_OK; } | < < < | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | procargs.argv = argv; procargs.argl = argl; rc = Th_InFrame(interp, proc_call2, (void *)p, (void *)&procargs); if( rc==TH_RETURN ){ rc = TH_OK; } return rc; } /* ** This function is registered as the delete callback for all commands ** created using the built-in [proc] command. It is called automatically ** when a command created using [proc] is deleted. |
︙ | ︙ | |||
732 733 734 735 736 737 738 | int iIndex; if( argc!=4 ){ return Th_WrongNumArgs(interp, "string index string index"); } if( argl[3]==3 && 0==memcmp("end", argv[3], 3) ){ | | | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | int iIndex; if( argc!=4 ){ return Th_WrongNumArgs(interp, "string index string index"); } if( argl[3]==3 && 0==memcmp("end", argv[3], 3) ){ iIndex = argl[2]; }else if( Th_ToInt(interp, argv[3], argl[3], &iIndex) ){ Th_ErrorMessage( interp, "Expected \"end\" or integer, got:", argv[3], argl[3]); return TH_ERROR; } if( iIndex>=0 && iIndex<argl[2] ){ |
︙ | ︙ |
Changes to src/th_main.c.
︙ | ︙ | |||
297 298 299 300 301 302 303 | switch( rc ){ case TH_OK: return nullIfOk ? 0 : "TH_OK"; case TH_ERROR: return "TH_ERROR"; case TH_BREAK: return "TH_BREAK"; case TH_RETURN: return "TH_RETURN"; case TH_CONTINUE: return "TH_CONTINUE"; | < | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | switch( rc ){ case TH_OK: return nullIfOk ? 0 : "TH_OK"; case TH_ERROR: return "TH_ERROR"; case TH_BREAK: return "TH_BREAK"; case TH_RETURN: return "TH_RETURN"; case TH_CONTINUE: return "TH_CONTINUE"; default: { sqlite3_snprintf(sizeof(zRc), zRc, "TH1 return code %d", rc); } } return zRc; } |
︙ | ︙ |
Changes to src/unversioned.c.
︙ | ︙ | |||
482 483 484 485 486 487 488 | @ No unversioned files on this server style_footer(); return; } if( PB("byage") ) zOrderBy = "mtime DESC"; if( PB("showdel") ) showDel = 1; db_prepare(&q, | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | | | | | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | @ No unversioned files on this server style_footer(); return; } if( PB("byage") ) zOrderBy = "mtime DESC"; if( PB("showdel") ) showDel = 1; db_prepare(&q, "SELECT" " name," " mtime," " hash," " sz," " (SELECT login FROM rcvfrom, user" " WHERE user.uid=rcvfrom.uid AND rcvfrom.rcvid=unversioned.rcvid)," " rcvid" " FROM unversioned %s ORDER BY %s", showDel ? "" : "WHERE hash IS NOT NULL" /*safe-for-%s*/, zOrderBy/*safe-for-%s*/ ); iNow = db_int64(0, "SELECT strftime('%%s','now');"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); sqlite3_int64 mtime = db_column_int(&q, 1); const char *zHash = db_column_text(&q, 2); int isDeleted = zHash==0; int fullSize = db_column_int(&q, 3); char *zAge = human_readable_age((iNow - mtime)/86400.0); const char *zLogin = db_column_text(&q, 4); int rcvid = db_column_int(&q,5); if( zLogin==0 ) zLogin = ""; if( (n++)==0 ){ @ <div class="uvlist"> @ <table cellpadding="2" cellspacing="0" border="1" id="uvtab"> @ <thead><tr> @ <th> Name @ <th> Age @ <th> Size @ <th> User @ <th> SHA1 if( g.perm.Admin ){ @ <th> rcvid } @ </tr></thead> @ <tbody> } @ <tr> if( isDeleted ){ sqlite3_snprintf(sizeof(zSzName), zSzName, "<i>Deleted</i>"); zHash = ""; fullSize = 0; @ <td> %h(zName) </td> }else{ approxSizeName(sizeof(zSzName), zSzName, fullSize); iTotalSz += fullSize; cnt++; @ <td> <a href='%R/uv/%T(zName)'>%h(zName)</a> </td> } @ <td data-sortkey='%016llx(-mtime)'> %s(zAge) </td> @ <td data-sortkey='%08x(fullSize)'> %s(zSzName) </td> @ <td> %h(zLogin) </td> @ <td> %h(zHash) </td> if( g.perm.Admin ){ if( rcvid ){ @ <td> <a href="%R/rcvfrom?rcvid=%d(rcvid)">%d(rcvid)</a> }else{ @ <td> } } @ </tr> fossil_free(zAge); } db_finalize(&q); if( n ){ approxSizeName(sizeof(zSzName), zSzName, iTotalSz); @ </tbody> @ <tfoot><tr><td><b>Total over %d(cnt) files</b><td><td>%s(zSzName) @ <td><td><td></tfoot> @ </table></div> output_table_sorting_javascript("uvtab","tkKttN",1); }else{ @ No unversioned files on this server. } style_footer(); } /* ** WEBPAGE: juvlist ** ** Return a complete list of unversioned files as JSON. The JSON ** looks like this: |
︙ | ︙ |
Changes to test/th1-hooks.test.
︙ | ︙ | |||
68 69 70 71 72 73 74 | } elseif {$::cmd_name eq "test2"} { error "unsupported command" } elseif {$::cmd_name eq "test3"} { emit_hook_log break "TH_BREAK return code" } elseif {$::cmd_name eq "test4"} { emit_hook_log | | < < < | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | } elseif {$::cmd_name eq "test2"} { error "unsupported command" } elseif {$::cmd_name eq "test3"} { emit_hook_log break "TH_BREAK return code" } elseif {$::cmd_name eq "test4"} { emit_hook_log return -code 2 "TH_RETURN return code" } elseif {$::cmd_name eq "timeline"} { set length [llength $::cmd_args] set length [expr {$length - 1}] if {[lindex $::cmd_args $length] eq "custom"} { append_hook_log "CUSTOM TIMELINE" emit_hook_log return "custom timeline" } elseif {[lindex $::cmd_args $length] eq "custom2"} { emit_hook_log puts "+++ some stuff here +++" continue "custom2 timeline" } elseif {[lindex $::cmd_args $length] eq "now"} { emit_hook_log return "now timeline" } else { emit_hook_log error "unsupported timeline" } |
︙ | ︙ | |||
143 144 145 146 147 148 149 | test th1-cmd-hooks-1b {[normalize_result] eq \ {<h1><b>command_hook timeline</b></h1> +++ some stuff here +++ <h1><b>command_hook timeline command_notify timeline</b></h1>}} ############################################################################### | < < < < < < < < | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | test th1-cmd-hooks-1b {[normalize_result] eq \ {<h1><b>command_hook timeline</b></h1> +++ some stuff here +++ <h1><b>command_hook timeline command_notify timeline</b></h1>}} ############################################################################### fossil timeline test th1-cmd-hooks-2a {[first_data_line] eq \ {<h1><b>command_hook timeline</b></h1>}} test th1-cmd-hooks-2b {[second_data_line] eq {ERROR: unsupported timeline}} ############################################################################### |
︙ | ︙ | |||
194 195 196 197 198 199 200 | fossil test3 test th1-custom-cmd-3a {[string trim $RESULT] eq \ {<h1><b>command_hook test3</b></h1>}} ############################################################################### fossil test4 | < | < < < < < < | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | fossil test3 test th1-custom-cmd-3a {[string trim $RESULT] eq \ {<h1><b>command_hook test3</b></h1>}} ############################################################################### fossil test4 test th1-custom-cmd-4a {[string trim $RESULT] eq \ {<h1><b>command_hook test4</b></h1>}} ############################################################################### set RESULT [test_fossil_http $repository $dataFileName /timeline] test th1-web-hooks-1a {[regexp \ {<title>Unnamed Fossil Project: Timeline</title>} $RESULT]} |
︙ | ︙ |
Changes to test/th1.test.
︙ | ︙ | |||
1432 1433 1434 1435 1436 1437 1438 | test th1-string-is-30 {$RESULT eq "1"} ############################################################################### fossil test-th-eval {string is integer 0xC0DEF00Z} test th1-string-is-31 {$RESULT eq "0"} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 | test th1-string-is-30 {$RESULT eq "1"} ############################################################################### fossil test-th-eval {string is integer 0xC0DEF00Z} test th1-string-is-31 {$RESULT eq "0"} ############################################################################### fossil test-th-eval {markdown} test th1-markdown-1 {$RESULT eq \ {TH_ERROR: wrong # args: should be "markdown STRING"}} ############################################################################### |
︙ | ︙ |
Changes to www/index.wiki.
︙ | ︙ | |||
125 126 127 128 129 130 131 | * On-line [/help | help]. * Documentation on the [http://www.sqliteconcepts.org/THManual.pdf | TH1 scripting language], used to customize [./custom_ticket.wiki | ticketing], and several other subsystems, including [./customskin.md | theming]. * List of [./th1.md | TH1 commands provided by Fossil itself] that expose its key functionality to TH1 scripts. | < < | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | * On-line [/help | help]. * Documentation on the [http://www.sqliteconcepts.org/THManual.pdf | TH1 scripting language], used to customize [./custom_ticket.wiki | ticketing], and several other subsystems, including [./customskin.md | theming]. * List of [./th1.md | TH1 commands provided by Fossil itself] that expose its key functionality to TH1 scripts. * A free hosting server for Fossil repositories is available at [http://chiselapp.com/]. * How to [./server.wiki | set up a server] for your repository. * Customizing the [./custom_ticket.wiki | ticket system]. * Methods to [./checkin_names.wiki | identify a specific check-in]. * [./inout.wiki | Import and export] from and to Git. * [./fossil-v-git.wiki | Fossil versus Git]. |
︙ | ︙ |
Deleted www/th1-hooks.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/th1.md.
︙ | ︙ | |||
103 104 105 106 107 108 109 | * lsearch LIST STRING * proc NAME ARG-LIST BODY-SCRIPT * rename OLD NEW * return ?-code CODE? ?VALUE? * set VARNAME VALUE * string compare STR1 STR2 * string first NEEDLE HAYSTACK ?START-INDEX? | < | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | * lsearch LIST STRING * proc NAME ARG-LIST BODY-SCRIPT * rename OLD NEW * return ?-code CODE? ?VALUE? * set VARNAME VALUE * string compare STR1 STR2 * string first NEEDLE HAYSTACK ?START-INDEX? * string is CLASS STRING * string last NEEDLE HAYSTACK ?START-INDEX? * string length STRING * string range STRING FIRST LAST * string repeat STRING COUNT * unset VARNAME * uplevel ?LEVEL? SCRIPT |
︙ | ︙ |