Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | merge cleanX |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | cleanX-no-clean-glob |
| Files: | files | file ages | folders |
| SHA1: |
f7fd7d0ac8f39f9de2ee94918acf7713 |
| User & Date: | jan.nijtmans 2014-04-24 09:59:01.000 |
Context
|
2014-04-29
| ||
| 08:11 | merge cleanX check-in: 820b10f776 user: jan.nijtmans tags: cleanX-no-clean-glob | |
|
2014-04-24
| ||
| 09:59 | merge cleanX check-in: f7fd7d0ac8 user: jan.nijtmans tags: cleanX-no-clean-glob | |
| 08:12 | merge trunk check-in: 9d969db8a4 user: jan.nijtmans tags: cleanX | |
|
2014-03-23
| ||
| 17:15 | merge cleanX check-in: 1d54c02400 user: jan.nijtmans tags: cleanX-no-clean-glob | |
Changes
Changes to Makefile.Cygwin.in.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 | #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ | | < < < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR =$(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ SQLITE_CFLAGS += -DSQLITE_WIN32_NO_ANSI SQLITE_CFLAGS += -DSQLITE_WIN32_MAX_PATH_BYTES=4096 SQLITE_CFLAGS += -DSQLITE_MAX_MMAP_SIZE=0x7fff0000 include $(SRCDIR)/main.mk distclean: clean |
| ︙ | ︙ |
Changes to Makefile.in.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 | # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ | < < < | 38 39 40 41 42 43 44 45 46 47 48 49 | # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile |
Changes to VERSION.
|
| | | 1 | 1.29 |
Changes to auto.def.
| ︙ | ︙ | |||
246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
if {![cc-check-function-in-lib socket {socket network}]} {
# Last resort, may be Windows
if {[string match *mingw* [get-define host]]} {
define-append LIBS -lwsock32
}
}
cc-check-function-in-lib iconv iconv
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
if {![cc-check-functions getpassphrase]} {
# Haiku needs this
cc-check-function-in-lib getpass bsd
}
cc-check-function-in-lib dlopen dl
| > > > > > | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
if {![cc-check-function-in-lib socket {socket network}]} {
# Last resort, may be Windows
if {[string match *mingw* [get-define host]]} {
define-append LIBS -lwsock32
}
}
cc-check-function-in-lib iconv iconv
# Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
if {![cc-check-functions getloadavg]} {
define FOSSIL_OMIT_LOAD_AVERAGE 1
}
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
if {![cc-check-functions getpassphrase]} {
# Haiku needs this
cc-check-function-in-lib getpass bsd
}
cc-check-function-in-lib dlopen dl
|
| ︙ | ︙ |
Changes to src/add.c.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 | #include <assert.h> #include <dirent.h> #include "cygsup.h" /* ** This routine returns the names of files in a working checkout that ** are created by Fossil itself, and hence should not be added, deleted, | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include <assert.h>
#include <dirent.h>
#include "cygsup.h"
/*
** This routine returns the names of files in a working checkout that
** are created by Fossil itself, and hence should not be added, deleted,
** or merge, and should be omitted from "clean" and "extras" lists.
**
** Return the N-th name. The first name has N==0. When all names have
** been used, return 0.
*/
const char *fossil_reserved_name(int N, int omitRepo){
/* Possible names of the local per-checkout database file and
** its associated journals
|
| ︙ | ︙ | |||
449 450 451 452 453 454 455 | ** ** Usage: %fossil addremove ?OPTIONS? ** ** Do all necessary "add" and "rm" commands to synchronize the repository ** with the content of the working checkout: ** ** * All files in the checkout but not in the repository (that is, | | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | ** ** Usage: %fossil addremove ?OPTIONS? ** ** Do all necessary "add" and "rm" commands to synchronize the repository ** with the content of the working checkout: ** ** * All files in the checkout but not in the repository (that is, ** all files displayed using the "extras" command) are added as ** if by the "add" command. ** ** * All files in the repository but missing from the checkout (that is, ** all files that show as MISSING with the "status" command) are ** removed as if by the "rm" command. ** ** The command does not "commit". You must run the "commit" separately |
| ︙ | ︙ |
Changes to src/allrepo.c.
| ︙ | ︙ | |||
74 75 76 77 78 79 80 | } } /* ** COMMAND: all ** | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | } } /* ** COMMAND: all ** ** Usage: %fossil all (changes|clean|extras|ignore|list|ls|pull|push|rebuild|sync) ** ** The ~/.fossil file records the location of all repositories for a ** user. This command performs certain operations on all repositories ** that can be useful before or after a period of disconnected operation. ** ** On Win32 systems, the file is named "_fossil" and is located in ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. |
| ︙ | ︙ | |||
97 98 99 100 101 102 103 | ** effects cannot be undone. Use of the --dry-run option to ** carefully review the local checkouts to be operated upon ** and the --whatif option to carefully review the files to ** be deleted beforehand is highly recommended. The command ** line options supported by the clean command itself, if any ** are present, are passed along verbatim. ** | | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | ** effects cannot be undone. Use of the --dry-run option to ** carefully review the local checkouts to be operated upon ** and the --whatif option to carefully review the files to ** be deleted beforehand is highly recommended. The command ** line options supported by the clean command itself, if any ** are present, are passed along verbatim. ** ** extras Shows "extra" files from all local checkouts. The command ** line options supported by the extra command itself, if any ** are present, are passed along verbatim. ** ** ignore Arguments are repositories that should be ignored by ** subsequent clean, extras, list, pull, push, rebuild, and ** sync operations. The -c|--ckout option causes the listed ** local checkouts to be ignored instead. ** ** list | ls Display the location of all repositories. The -c|--ckout ** option causes all local checkouts to be listed instead. ** ** pull Run a "pull" operation on all repositories. Only the |
| ︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
**
** Repositories are automatically added to the set of known repositories
** when one of the following commands are run against the repository:
** clone, info, pull, push, or sync. Even previously ignored repositories
** are added back to the list of repositories by these commands.
**
** Options:
** --dontstop Continue with other repositories even after an error.
** --dry-run If given, display instead of run actions.
*/
void all_cmd(void){
int n;
Stmt q;
const char *zCmd;
char *zSyscmd;
char *zFossil;
char *zQFilename;
Blob extra;
int useCheckouts = 0;
int quiet = 0;
int dryRunFlag = 0;
int stopOnError = find_option("dontstop",0,0)==0;
int rc;
int nToDel = 0;
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
if( g.argc<3 ){
| > > | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
**
** Repositories are automatically added to the set of known repositories
** when one of the following commands are run against the repository:
** clone, info, pull, push, or sync. Even previously ignored repositories
** are added back to the list of repositories by these commands.
**
** Options:
** --showfile Show the repository or checkout being operated upon.
** --dontstop Continue with other repositories even after an error.
** --dry-run If given, display instead of run actions.
*/
void all_cmd(void){
int n;
Stmt q;
const char *zCmd;
char *zSyscmd;
char *zFossil;
char *zQFilename;
Blob extra;
int useCheckouts = 0;
int quiet = 0;
int dryRunFlag = 0;
int showFile = find_option("showfile",0,0)!=0;
int stopOnError = find_option("dontstop",0,0)==0;
int rc;
int nToDel = 0;
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
if( g.argc<3 ){
usage("changes|clean|extras|ignore|list|ls|pull|push|rebuild|sync");
}
n = strlen(g.argv[2]);
db_open_config(1);
blob_zero(&extra);
zCmd = g.argv[2];
if( !login_is_nobody() ) blob_appendf(&extra, " -U %s", g.zLogin);
if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){
|
| ︙ | ︙ | |||
183 184 185 186 187 188 189 |
collect_argument(&extra, "force","f");
collect_argument_value(&extra, "ignore");
collect_argument_value(&extra, "keep");
collect_argument(&extra, "temp",0);
collect_argument(&extra, "verbose","v");
collect_argument(&extra, "whatif",0);
useCheckouts = 1;
| | > | > > > | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
collect_argument(&extra, "force","f");
collect_argument_value(&extra, "ignore");
collect_argument_value(&extra, "keep");
collect_argument(&extra, "temp",0);
collect_argument(&extra, "verbose","v");
collect_argument(&extra, "whatif",0);
useCheckouts = 1;
}else if( strncmp(zCmd, "extras", n)==0 ){
if( showFile ){
zCmd = "extras --chdir";
}else{
zCmd = "extras --header --chdir";
}
collect_argument(&extra, "abs-paths",0);
collect_argument_value(&extra, "case-sensitive");
collect_argument(&extra, "dotfiles",0);
collect_argument_value(&extra, "ignore");
collect_argument(&extra, "rel-paths",0);
useCheckouts = 1;
stopOnError = 0;
|
| ︙ | ︙ | |||
252 253 254 255 256 257 258 |
}
fossil_free(zSql);
}
db_end_transaction(0);
return;
}else{
fossil_fatal("\"all\" subcommand should be one of: "
| | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
}
fossil_free(zSql);
}
db_end_transaction(0);
return;
}else{
fossil_fatal("\"all\" subcommand should be one of: "
"changes clean extras ignore list ls push pull rebuild sync");
}
verify_all_options();
zFossil = quoteFilename(g.nameOfExe);
if( useCheckouts ){
db_prepare(&q,
"SELECT DISTINCT substr(name, 7), name COLLATE nocase"
" FROM global_config"
|
| ︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
db_multi_exec("INSERT INTO todel VALUES(%Q)", db_column_text(&q, 1));
nToDel++;
continue;
}
if( zCmd[0]=='l' ){
fossil_print("%s\n", zFilename);
continue;
}
zQFilename = quoteFilename(zFilename);
zSyscmd = mprintf("%s %s %s%s",
zFossil, zCmd, zQFilename, blob_str(&extra));
if( !quiet || dryRunFlag ){
fossil_print("%s\n", zSyscmd);
fflush(stdout);
| > > > | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
db_multi_exec("INSERT INTO todel VALUES(%Q)", db_column_text(&q, 1));
nToDel++;
continue;
}
if( zCmd[0]=='l' ){
fossil_print("%s\n", zFilename);
continue;
}else if( showFile ){
fossil_print("%s: %s\n", useCheckouts ? "checkout" : "repository",
zFilename);
}
zQFilename = quoteFilename(zFilename);
zSyscmd = mprintf("%s %s %s%s",
zFossil, zCmd, zQFilename, blob_str(&extra));
if( !quiet || dryRunFlag ){
fossil_print("%s\n", zSyscmd);
fflush(stdout);
|
| ︙ | ︙ |
Changes to src/attach.c.
| ︙ | ︙ | |||
256 257 258 259 260 261 262 |
if( g.perm.ApndTkt==0 || g.perm.Attach==0 ) login_needed();
if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){
zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag"
" WHERE tagname GLOB 'tkt-%q*'", zTkt);
if( zTkt==0 ) fossil_redirect_home();
}
zTarget = zTkt;
| | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
if( g.perm.ApndTkt==0 || g.perm.Attach==0 ) login_needed();
if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){
zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag"
" WHERE tagname GLOB 'tkt-%q*'", zTkt);
if( zTkt==0 ) fossil_redirect_home();
}
zTarget = zTkt;
zTargetType = mprintf("Ticket <a href=\"%s/tktview/%s\">%S</a>",
g.zTop, zTkt, zTkt);
}
if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
if( P("cancel") ){
cgi_redirect(zFrom);
}
if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){
|
| ︙ | ︙ | |||
461 462 463 464 465 466 467 |
return;
}
if( strcmp(zModAction,"approve")==0 ){
moderation_approve(rid);
}
}
style_header("Attachment Details");
| | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
return;
}
if( strcmp(zModAction,"approve")==0 ){
moderation_approve(rid);
}
}
style_header("Attachment Details");
style_submenu_element("Raw", "Raw", "%R/artifact/%s", zUuid);
@ <div class="section">Overview</div>
@ <p><table class="label-value">
@ <tr><th>Artifact ID:</th>
@ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
if( g.perm.Setup ){
@ (%d(rid))
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 |
output_text_with_line_numbers(z, zLn);
}else{
@ <pre>
@ %h(z)
@ </pre>
}
}else if( strncmp(zMime, "image/", 6)==0 ){
| | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
output_text_with_line_numbers(z, zLn);
}else{
@ <pre>
@ %h(z)
@ </pre>
}
}else if( strncmp(zMime, "image/", 6)==0 ){
@ <img src="%R/raw/%s(zSrc)?m=%s(zMime)"></img>
style_submenu_element("Image", "Image", "%R/raw/%s?m=%s", zSrc, zMime);
}else{
int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc);
@ <i>(file is %d(sz) bytes of binary data)</i>
}
@ </blockquote>
manifest_destroy(pAttach);
blob_reset(&attach);
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
83 84 85 86 87 88 89 |
int i, j;
char *zSep = "";
for(i=0; zPath[i]; i=j){
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
if( zPath[j] && g.perm.Hyperlink ){
if( zCI ){
| | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
int i, j;
char *zSep = "";
for(i=0; zPath[i]; i=j){
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
if( zPath[j] && g.perm.Hyperlink ){
if( zCI ){
char *zLink = href("%R/%s?name=%#T%s&ci=%s", zURI, j, zPath, zREx, zCI);
blob_appendf(pOut, "%s%z%#h</a>",
zSep, zLink, j-i, &zPath[i]);
}else{
char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
blob_appendf(pOut, "%s%z%#h</a>",
zSep, zLink, j-i, &zPath[i]);
}
|
| ︙ | ︙ | |||
177 178 179 180 181 182 183 |
url_render(&sURI, "ci", "trunk", 0, 0));
}
if( linkTip ){
style_submenu_element("Tip", "Tip", "%s",
url_render(&sURI, "ci", "tip", 0, 0));
}
if( zCI ){
| < < < | | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
url_render(&sURI, "ci", "trunk", 0, 0));
}
if( linkTip ){
style_submenu_element("Tip", "Tip", "%s",
url_render(&sURI, "ci", "tip", 0, 0));
}
if( zCI ){
@ <h2>Files of check-in [%z(href("vinfo?name=%s",zUuid))%.10s(zUuid)</a>]
@ %s(blob_str(&dirname))</h2>
zSubdirLink = mprintf("%R/dir?ci=%s&name=%T", zUuid, zPrefix);
if( nD==0 ){
style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s",
zUuid);
}
}else{
@ <h2>The union of all files from all check-ins
@ %s(blob_str(&dirname))</h2>
zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
}
|
| ︙ | ︙ | |||
488 489 490 491 492 493 494 |
blob_appendf(&dirname, "matching \"%s\"", zRE);
}
}
if( zCI ){
style_submenu_element("All", "All", "%s",
url_render(&sURI, "ci", 0, 0, 0));
if( nD==0 && !showDirOnly ){
| | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
blob_appendf(&dirname, "matching \"%s\"", zRE);
}
}
if( zCI ){
style_submenu_element("All", "All", "%s",
url_render(&sURI, "ci", 0, 0, 0));
if( nD==0 && !showDirOnly ){
style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%s",
zUuid);
}
}
if( linkTrunk ){
style_submenu_element("Trunk", "Trunk", "%s",
url_render(&sURI, "ci", "trunk", 0, 0));
}
|
| ︙ | ︙ | |||
572 573 574 575 576 577 578 |
}
if( zCI ){
@ <h2>%d(nFile) %s(zObjType) of check-in
if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
@ "%h(zCI)"
}
| | | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
}
if( zCI ){
@ <h2>%d(nFile) %s(zObjType) of check-in
if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
@ "%h(zCI)"
}
@ [%z(href("vinfo?name=%s",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2>
}else{
int n = db_int(0, "SELECT count(*) FROM plink");
@ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins
@ %s(blob_str(&dirname))</h2>
}
|
| ︙ | ︙ | |||
615 616 617 618 619 620 621 |
@ <ul id="dir%d(nDir)" class="collapsed">
}
nDir++;
}else if( !showDirOnly ){
const char *zFileClass = fileext_class(p->zName);
char *zLink;
if( zCI ){
| | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
@ <ul id="dir%d(nDir)" class="collapsed">
}
nDir++;
}else if( !showDirOnly ){
const char *zFileClass = fileext_class(p->zName);
char *zLink;
if( zCI ){
zLink = href("%R/artifact/%s",p->zUuid);
}else{
zLink = href("%R/finfo?name=%T",p->zFullName);
}
@ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
}
if( p->isLast ){
int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0);
|
| ︙ | ︙ | |||
873 874 875 876 877 878 879 |
}
}else{
zAge[0] = 0;
}
@ <tr>
@ <td>%s(zAge)
@ <td width="25">
| | | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 |
}
}else{
zAge[0] = 0;
}
@ <tr>
@ <td>%s(zAge)
@ <td width="25">
@ <td>%z(href("%R/artifact/%s?ln", zFUuid))%h(db_column_text(&q, 3))</a>
@ </tr>
@
}
@ <tr><td colspan=3><hr></tr>
@ </table>
db_finalize(&q);
style_footer();
}
|
Changes to src/checkin.c.
| ︙ | ︙ | |||
177 178 179 180 181 182 183 | ** --rel-paths Display pathnames relative to the current working ** directory. ** --sha1sum Verify file status using SHA1 hashing rather ** than relying on file mtimes. ** --header Identify the repository if there are changes ** -v|--verbose Say "(none)" if there are no changes ** | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
** --rel-paths Display pathnames relative to the current working
** directory.
** --sha1sum Verify file status using SHA1 hashing rather
** than relying on file mtimes.
** --header Identify the repository if there are changes
** -v|--verbose Say "(none)" if there are no changes
**
** See also: extras, ls, status
*/
void changes_cmd(void){
Blob report;
int vid;
int useSha1sum = find_option("sha1sum", 0, 0)!=0;
int showHdr = find_option("header",0,0)!=0;
int verboseFlag = find_option("verbose","v",0)!=0;
|
| ︙ | ︙ | |||
221 222 223 224 225 226 227 | ** ** --abs-paths Display absolute pathnames. ** --rel-paths Display pathnames relative to the current working ** directory. ** --sha1sum Verify file status using SHA1 hashing rather ** than relying on file mtimes. ** | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
**
** --abs-paths Display absolute pathnames.
** --rel-paths Display pathnames relative to the current working
** directory.
** --sha1sum Verify file status using SHA1 hashing rather
** than relying on file mtimes.
**
** See also: changes, extras, ls
*/
void status_cmd(void){
int vid;
db_must_be_within_tree();
/* 012345678901234 */
fossil_print("repository: %s\n", db_repository_filename());
fossil_print("local-root: %s\n", g.zLocalRoot);
|
| ︙ | ︙ | |||
253 254 255 256 257 258 259 | ** extra information about each file. If FILENAMES are included, only ** the files listed (or their children if they are directories) are shown. ** ** Options: ** --age Show when each file was committed ** -v|--verbose Provide extra information about each file. ** | | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
** extra information about each file. If FILENAMES are included, only
** the files listed (or their children if they are directories) are shown.
**
** Options:
** --age Show when each file was committed
** -v|--verbose Provide extra information about each file.
**
** See also: changes, extras, status
*/
void ls_cmd(void){
int vid;
Stmt q;
int verboseFlag;
int showAge;
char *zOrderBy = "pathname";
|
| ︙ | ︙ | |||
430 431 432 433 434 435 436 437 438 439 440 441 442 |
** Pathnames are displayed according to the "relative-paths" setting,
** unless overridden by the --abs-paths or --rel-paths options.
**
** Options:
** --abs-paths Display absolute pathnames.
** --case-sensitive <BOOL> override case-sensitive setting
** --dotfiles include files beginning with a dot (".")
** --ignore <CSG> ignore files matching patterns from the argument
** --rel-paths Display pathnames relative to the current working
** directory.
**
** See also: changes, clean, status
*/
| > | > | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
** Pathnames are displayed according to the "relative-paths" setting,
** unless overridden by the --abs-paths or --rel-paths options.
**
** Options:
** --abs-paths Display absolute pathnames.
** --case-sensitive <BOOL> override case-sensitive setting
** --dotfiles include files beginning with a dot (".")
** --header Identify the repository if there are extras
** --ignore <CSG> ignore files matching patterns from the argument
** --rel-paths Display pathnames relative to the current working
** directory.
**
** See also: changes, clean, status
*/
void extras_cmd(void){
Stmt q;
const char *zIgnoreFlag = find_option("ignore",0,1);
unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
int showHdr = find_option("header",0,0)!=0;
int cwdRelative = 0;
Glob *pIgnore;
Blob rewrittenPathname;
const char *zPathname, *zDisplayName;
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
capture_case_sensitive_option();
|
| ︙ | ︙ | |||
474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
file_relative_name(zFullName, &rewrittenPathname, 0);
free(zFullName);
zDisplayName = blob_str(&rewrittenPathname);
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
zDisplayName += 2; /* no unnecessary ./ prefix */
}
}
fossil_print("%s\n", zDisplayName);
}
blob_reset(&rewrittenPathname);
db_finalize(&q);
}
/*
| > > > > > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
file_relative_name(zFullName, &rewrittenPathname, 0);
free(zFullName);
zDisplayName = blob_str(&rewrittenPathname);
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
zDisplayName += 2; /* no unnecessary ./ prefix */
}
}
if( showHdr ){
showHdr = 0;
fossil_print("Extras for %s at %s:\n", db_get("project-name","???"),
g.zLocalRoot);
}
fossil_print("%s\n", zDisplayName);
}
blob_reset(&rewrittenPathname);
db_finalize(&q);
}
/*
|
| ︙ | ︙ | |||
536 537 538 539 540 541 542 | ** comma separated list of glob patterns. ** --keep <CSG> Keep files matching this comma separated ** list of glob patterns. ** -n|--dry-run If given, display instead of run actions. ** --temp Remove only Fossil-generated temporary files. ** -v|--verbose Show all files as they are removed. ** -x|--extreme Remove all files not part of the current | | | | | | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
** comma separated list of glob patterns.
** --keep <CSG> Keep files matching this comma separated
** list of glob patterns.
** -n|--dry-run If given, display instead of run actions.
** --temp Remove only Fossil-generated temporary files.
** -v|--verbose Show all files as they are removed.
** -x|--extreme Remove all files not part of the current
** checkout, except the ones matching --keep.
** Files not matching any of --clean/--ignore/-keep,
** will be prompted for.
** Compatibile with "git clean -x".
**
** See also: addremove, extras, status
*/
void clean_cmd(void){
int allFileFlag, allDirFlag, dryRunFlag, verboseFlag, extremeFlag;
int emptyDirsFlag, dirsOnlyFlag;
unsigned scanFlags = 0;
const char *zIgnoreFlag, *zKeepFlag;
Glob *pIgnore, *pKeep;
|
| ︙ | ︙ | |||
617 618 619 620 621 622 623 |
if( file_tree_name(g.zRepositoryName, &repo, 0) ){
db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
}
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
if( glob_match(pKeep, zName+nRoot) ){
| > | > > | 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
if( file_tree_name(g.zRepositoryName, &repo, 0) ){
db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
}
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
if( glob_match(pKeep, zName+nRoot) ){
if( verboseFlag ){
fossil_print("KEPT file \"%s\" not removed (due to --keep"
" or \"keep-glob\")\n", zName+nRoot);
}
continue;
}
if( !allFileFlag && !dryRunFlag && (!extremeFlag || !glob_match(pIgnore, zName+nRoot)) ){
Blob ans;
char cReply;
int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
char *prompt = mprintf("%sRemove %s file \"%s\" (a=all/y/N)? ",
|
| ︙ | ︙ | |||
666 667 668 669 670 671 672 |
" WHERE x NOT IN (%s) AND y = 0"
" ORDER BY 1 DESC",
g.zLocalRoot, fossil_all_reserved_names(0)
);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
if( glob_match(pKeep, zName+nRoot) ){
| > | > > | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
" WHERE x NOT IN (%s) AND y = 0"
" ORDER BY 1 DESC",
g.zLocalRoot, fossil_all_reserved_names(0)
);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
if( glob_match(pKeep, zName+nRoot) ){
if( verboseFlag ){
fossil_print("KEPT directory \"%s\" not removed (due to --keep"
" or \"keep-glob\")\n", zName+nRoot);
}
continue;
}
if( !allDirFlag && !dryRunFlag && (!extremeFlag || !glob_match(pIgnore, zName+nRoot)) ){
Blob ans;
char cReply;
int matchIgnore = extremeFlag && glob_match(pIgnore, zName+nRoot);
int matchEmpty = extremeFlag && glob_match(pEmptyDirs, zName+nRoot);
|
| ︙ | ︙ | |||
836 837 838 839 840 841 842 |
blob_append(&prompt, zInit, -1);
}
#else
blob_init(&prompt, zInit, -1);
#endif
blob_append(&prompt,
"\n"
| | | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 |
blob_append(&prompt, zInit, -1);
}
#else
blob_init(&prompt, zInit, -1);
#endif
blob_append(&prompt,
"\n"
"# Enter a commit message for this check-in. Lines beginning with # are ignored.\n"
"#\n", -1
);
blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : login_name());
if( p->zBranch && p->zBranch[0] ){
blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
}else{
char *zTags = info_tags_of_checkin(parent_rid, 1);
|
| ︙ | ︙ | |||
1339 1340 1341 1342 1343 1344 1345 |
allOk = 1;
}else if( *zConvert && (cReply=='c' || cReply=='C') ){
char *zOrig = file_newname(zFilename, "original", 1);
FILE *f;
blob_write_to_file(p, zOrig);
fossil_free(zOrig);
f = fossil_fopen(zFilename, "wb");
| > > > | | | | | | | | | | | > | 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 |
allOk = 1;
}else if( *zConvert && (cReply=='c' || cReply=='C') ){
char *zOrig = file_newname(zFilename, "original", 1);
FILE *f;
blob_write_to_file(p, zOrig);
fossil_free(zOrig);
f = fossil_fopen(zFilename, "wb");
if( f==0 ){
fossil_warning("cannot open %s for writing", zFilename);
}else{
if( fUnicode ) {
int bomSize;
const unsigned char *bom = get_utf8_bom(&bomSize);
fwrite(bom, 1, bomSize, f);
blob_to_utf8_no_bom(p, 0);
}
if( fHasAnyCr ){
blob_to_lf_only(p);
}
fwrite(blob_buffer(p), 1, blob_size(p), f);
fclose(f);
}
return 1;
}else if( cReply!='y' && cReply!='Y' ){
fossil_fatal("Abandoning commit due to %s in %s",
zWarning, blob_str(&fname));
}
blob_reset(&ans);
blob_reset(&fname);
|
| ︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 | ** check-in process may be aborted if a file contains content that ** appears to be binary, Unicode text, or text with CR/NL line endings ** unless the interactive user chooses to proceed. If there is no ** interactive user or these warnings should be skipped for some other ** reason, the --no-warnings option may be used. A check-in is not ** allowed against a closed leaf. ** ** The --private option creates a private check-in that is never synced. ** Children of private check-ins are automatically private. ** ** The --tag option applies the symbolic tag name to the check-in. ** ** The --sha1sum option detects edited files by computing each file's ** SHA1 hash rather than just checking for changes to its size or mtime. | > > > > | 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 |
** check-in process may be aborted if a file contains content that
** appears to be binary, Unicode text, or text with CR/NL line endings
** unless the interactive user chooses to proceed. If there is no
** interactive user or these warnings should be skipped for some other
** reason, the --no-warnings option may be used. A check-in is not
** allowed against a closed leaf.
**
** If a commit message is blank, you will be prompted:
** ("continue (y/N)?") to confirm you really want to commit with a
** blank commit message. The default value is "N", do not commit.
**
** The --private option creates a private check-in that is never synced.
** Children of private check-ins are automatically private.
**
** The --tag option applies the symbolic tag name to the check-in.
**
** The --sha1sum option detects edited files by computing each file's
** SHA1 hash rather than just checking for changes to its size or mtime.
|
| ︙ | ︙ | |||
1446 1447 1448 1449 1450 1451 1452 | ** --no-warnings omit all warnings about file contents ** --nosign do not attempt to sign this commit with gpg ** --private do not sync changes and their descendants ** --sha1sum verify file status using SHA1 hashing rather ** than relying on file mtimes ** --tag TAG-NAME assign given tag TAG-NAME to the checkin ** | | | 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 |
** --no-warnings omit all warnings about file contents
** --nosign do not attempt to sign this commit with gpg
** --private do not sync changes and their descendants
** --sha1sum verify file status using SHA1 hashing rather
** than relying on file mtimes
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
**
** See also: branch, changes, checkout, extras, sync
*/
void commit_cmd(void){
int hasChanges; /* True if unsaved changes exist */
int vid; /* blob-id of parent version */
int nrid; /* blob-id of a modified file */
int nvid; /* Blob-id of the new check-in */
Blob comment; /* Check-in comment */
|
| ︙ | ︙ |
Changes to src/clone.c.
| ︙ | ︙ | |||
134 135 136 137 138 139 140 |
}
db_open_config(0);
if( file_size(g.argv[3])>0 ){
fossil_fatal("file already exists: %s", g.argv[3]);
}
url_parse(g.argv[2], urlFlags);
| | | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
}
db_open_config(0);
if( file_size(g.argv[3])>0 ){
fossil_fatal("file already exists: %s", g.argv[3]);
}
url_parse(g.argv[2], urlFlags);
if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
if( g.url.isFile ){
file_copy(g.url.name, g.argv[3]);
db_close(1);
db_open_repository(g.argv[3]);
db_record_repository_filename(g.argv[3]);
url_remember();
if( !bPrivate ) delete_private_content();
shun_artifacts();
db_create_default_users(1, zDefaultUser);
|
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
** decision. Set the global preference if the URL is not being changed.
*/
void remember_or_get_http_auth(
const char *zHttpAuth, /* Credentials in the form "user:password" */
int fRemember, /* True to remember credentials for later reuse */
const char *zUrl /* URL for which these credentials apply */
){
| | | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
** decision. Set the global preference if the URL is not being changed.
*/
void remember_or_get_http_auth(
const char *zHttpAuth, /* Credentials in the form "user:password" */
int fRemember, /* True to remember credentials for later reuse */
const char *zUrl /* URL for which these credentials apply */
){
char *zKey = mprintf("http-auth:%s", g.url.canonical);
if( zHttpAuth && zHttpAuth[0] ){
g.zHttpAuth = mprintf("%s", zHttpAuth);
}
if( fRemember ){
if( g.zHttpAuth && g.zHttpAuth[0] ){
set_httpauth(g.zHttpAuth);
}else if( zUrl && zUrl[0] ){
|
| ︙ | ︙ | |||
231 232 233 234 235 236 237 |
free(zKey);
}
/*
** Get the HTTP Authorization preference from db.
*/
char *get_httpauth(void){
| | | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
free(zKey);
}
/*
** Get the HTTP Authorization preference from db.
*/
char *get_httpauth(void){
char *zKey = mprintf("http-auth:%s", g.url.canonical);
return unobscure(db_get(zKey, 0));
free(zKey);
}
/*
** Set the HTTP Authorization preference in db.
*/
void set_httpauth(const char *zHttpAuth){
char *zKey = mprintf("http-auth:%s", g.url.canonical);
db_set(zKey, obscure(zHttpAuth), 0);
free(zKey);
}
/*
** Look for SSH clone command line options and setup in globals.
*/
|
| ︙ | ︙ |
Changes to src/configure.c.
| ︙ | ︙ | |||
922 923 924 925 926 927 928 |
usage(mprintf("%s AREA ?URL?", zMethod));
}
mask = configure_name_to_mask(g.argv[3], 1);
if( g.argc==5 ){
zServer = g.argv[4];
}
url_parse(zServer, URL_PROMPT_PW);
| | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 |
usage(mprintf("%s AREA ?URL?", zMethod));
}
mask = configure_name_to_mask(g.argv[3], 1);
if( g.argc==5 ){
zServer = g.argv[4];
}
url_parse(zServer, URL_PROMPT_PW);
if( g.url.protocol==0 ) fossil_fatal("no server URL specified");
user_select();
url_enable_proxy("via proxy: ");
if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
if( strncmp(zMethod, "push", n)==0 ){
client_sync(0,0,(unsigned)mask);
}else if( strncmp(zMethod, "pull", n)==0 ){
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
727 728 729 730 731 732 733 |
g.zVfsName
);
if( rc!=SQLITE_OK ){
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
}
sqlite3_busy_timeout(db, 5000);
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
| | | | | | | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 |
g.zVfsName
);
if( rc!=SQLITE_OK ){
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
}
sqlite3_busy_timeout(db, 5000);
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, db_now_function, 0, 0);
sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
db_checkin_mtime_function, 0, 0);
sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
sqlite3_create_function(
db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
);
sqlite3_create_function(
db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
);
|
| ︙ | ︙ |
Changes to src/delta.c.
| ︙ | ︙ | |||
465 466 467 468 469 470 471 |
*(zDelta++) = ':';
memcpy(zDelta, &zOut[base], lenOut-base);
zDelta += lenOut-base;
}
/* Output the final checksum record. */
putInt(checksum(zOut, lenOut), &zDelta);
*(zDelta++) = ';';
| | | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
*(zDelta++) = ':';
memcpy(zDelta, &zOut[base], lenOut-base);
zDelta += lenOut-base;
}
/* Output the final checksum record. */
putInt(checksum(zOut, lenOut), &zDelta);
*(zDelta++) = ';';
fossil_free(collide);
return zDelta - zOrigDelta;
}
/*
** Return the size (in bytes) of the output from applying
** a delta.
**
|
| ︙ | ︙ |
Changes to src/descendants.c.
| ︙ | ︙ | |||
327 328 329 330 331 332 333 | ** The -a|--all flag causes all leaves (closed and open) to be shown. ** The -c|--closed flag shows only closed leaves. ** ** The --recompute flag causes the content of the "leaf" table in the ** repository database to be recomputed. ** ** Options: | | | | | > > > | > > > > > > > > | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
** The -a|--all flag causes all leaves (closed and open) to be shown.
** The -c|--closed flag shows only closed leaves.
**
** The --recompute flag causes the content of the "leaf" table in the
** repository database to be recomputed.
**
** Options:
** -a|--all show ALL leaves
** -c|--closed show only closed leaves
** --bybranch order output by branch name
** --recompute recompute the "leaf" table in the repository DB
** -W|--width <num> With of lines (default 79). Must be >39 or 0
** (= no limit, resulting in a single line per entry).
**
** See also: descendants, finfo, info, branch
*/
void leaves_cmd(void){
Stmt q;
Blob sql;
int showAll = find_option("all", "a", 0)!=0;
int showClosed = find_option("closed", "c", 0)!=0;
int recomputeFlag = find_option("recompute",0,0)!=0;
int byBranch = find_option("bybranch",0,0)!=0;
const char *zWidth = find_option("width","W",1);
char *zLastBr = 0;
int n, width;
char zLineNo[10];
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=39) ){
fossil_fatal("-W|--width value must be >39 or 0");
}
}else{
width = 79;
}
db_find_and_open_repository(0,0);
if( recomputeFlag ) leaf_rebuild();
blob_zero(&sql);
blob_append(&sql, timeline_query_for_tty(), -1);
blob_appendf(&sql, " AND blob.rid IN leaf");
if( showClosed ){
blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid"));
|
| ︙ | ︙ | |||
380 381 382 383 384 385 386 |
fossil_free(zLastBr);
zLastBr = fossil_strdup(zBr);
}
n++;
sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
fossil_print("%6s ", zLineNo);
z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
| | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
fossil_free(zLastBr);
zLastBr = fossil_strdup(zBr);
}
n++;
sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n);
fossil_print("%6s ", zLineNo);
z = mprintf("%s [%.10s] %s", zDate, zId, zCom);
comment_print(z, 7, width);
fossil_free(z);
}
fossil_free(zLastBr);
db_finalize(&q);
}
/*
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
223 224 225 226 227 228 229 |
int a = pA->indent, b = pB->indent;
if( pA->h==pB->h ){
while( a<pA->n && b<pB->n ){
if( pA->z[a++] != pB->z[b++] ) return 0;
while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
}
| | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
int a = pA->indent, b = pB->indent;
if( pA->h==pB->h ){
while( a<pA->n && b<pB->n ){
if( pA->z[a++] != pB->z[b++] ) return 0;
while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
}
return pA->n-a == pB->n-b;
}
return 0;
}
/*
** Return true if the regular expression *pRe matches any of the
** N dlines
|
| ︙ | ︙ | |||
764 765 766 767 768 769 770 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ int nRightDiff; /* nRight - nPrefix - nSuffix */ int aLCS[4]; /* Bounds of common middle segment */ static const char zClassRm[] = "<span class=\"diffrm\">"; static const char zClassAdd[] = "<span class=\"diffadd\">"; static const char zClassChng[] = "<span class=\"diffchng\">"; | | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
int nLeftDiff; /* nLeft - nPrefix - nSuffix */
int nRightDiff; /* nRight - nPrefix - nSuffix */
int aLCS[4]; /* Bounds of common middle segment */
static const char zClassRm[] = "<span class=\"diffrm\">";
static const char zClassAdd[] = "<span class=\"diffadd\">";
static const char zClassChng[] = "<span class=\"diffchng\">";
nLeft = pLeft->n;
zLeft = pLeft->z;
nRight = pRight->n;
zRight = pRight->z;
nShort = nLeft<nRight ? nLeft : nRight;
nPrefix = 0;
while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
nPrefix++;
}
|
| ︙ | ︙ | |||
912 913 914 915 916 917 918 | int score; /* Final score. 0..100 */ unsigned char c; /* Character being examined */ unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */ unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */ zA = pA->z; zB = pB->z; | | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
int score; /* Final score. 0..100 */
unsigned char c; /* Character being examined */
unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
zA = pA->z;
zB = pB->z;
nA = pA->n;
nB = pB->n;
while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; }
while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; }
while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; }
while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; }
if( nA>250 ) nA = 250;
if( nB>250 ) nB = 250;
avg = (nA+nB)/2;
|
| ︙ | ︙ | |||
2305 2306 2307 2308 2309 2310 2311 |
}
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
clr = gradient_color(clr1, clr2, ann.nVers-1, i);
ann.aVers[i].zBgColor = mprintf("#%06x", clr);
}
if( showLog ){
| | | | | 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 |
}
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
clr = gradient_color(clr1, clr2, ann.nVers-1, i);
ann.aVers[i].zBgColor = mprintf("#%06x", clr);
}
if( showLog ){
char *zLink = href("%R/finfo?name=%t&ci=%s",zFilename,zCI);
@ <h2>Ancestors of %z(zLink)%h(zFilename)</a> analyzed:</h2>
@ <ol>
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
@ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
@ check-in %z(href("%R/info/%s",p->zMUuid))%.10s(p->zMUuid)</a>
@ artifact %z(href("%R/artifact/%s",p->zFUuid))%.10s(p->zFUuid)</a>
@ </span>
#if 0
if( i>0 ){
char *zLink = xhref("target='infowindow'",
"%R/fdiff?v1=%S&v2=%S&sbs=1",
p->zFUuid,ann.aVers[0].zFUuid);
@ %z(zLink)[diff-to-top]</a>
|
| ︙ | ︙ | |||
2333 2334 2335 2336 2337 2338 2339 |
#endif
}
@ </ol>
@ <hr>
}
if( !ann.bLimit ){
@ <h2>Origin for each line in
| | | | | | | | 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 |
#endif
}
@ </ol>
@ <hr>
}
if( !ann.bLimit ){
@ <h2>Origin for each line in
@ %z(href("%R/finfo?name=%h&ci=%s", zFilename, zCI))%h(zFilename)</a>
@ from check-in %z(href("%R/info/%s",zCI))%S(zCI)</a>:</h2>
iLimit = ann.nVers+10;
}else{
@ <h2>Lines added by the %d(iLimit) most recent ancestors of
@ %z(href("%R/finfo?name=%h&ci=%s", zFilename, zCI))%h(zFilename)</a>
@ from check-in %z(href("%R/info/%s",zCI))%S(zCI)</a>:</h2>
}
@ <pre>
for(i=0; i<ann.nOrig; i++){
int iVers = ann.aOrig[i].iVers;
char *z = (char*)ann.aOrig[i].z;
int n = ann.aOrig[i].n;
char zPrefix[300];
z[n] = 0;
if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
if( bBlame ){
if( iVers>=0 ){
struct AnnVers *p = ann.aVers+iVers;
char *zLink = xhref("target='infowindow'", "%R/info/%s", p->zMUuid);
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
"<span style='background-color:%s'>"
"%s%.10s</a> %s</span> %13.13s:",
p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser);
fossil_free(zLink);
}else{
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
}
}else{
if( iVers>=0 ){
struct AnnVers *p = ann.aVers+iVers;
char *zLink = xhref("target='infowindow'", "%R/info/%s", p->zMUuid);
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
"<span style='background-color:%s'>"
"%s%.10s</a> %s</span> %4d:",
p->zBgColor, zLink, p->zMUuid, p->zDate, i+1);
fossil_free(zLink);
}else{
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1);
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 |
@ tk_messageBox -type ok -title $CFG(TITLE) -message "No changes"
@ exit
@ }
@ update idletasks
@
@ proc saveDiff {} {
@ set fn [tk_getSaveFile]
@ set out [open $fn wb]
@ puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'"
@ puts $out "# to see the graphical diff.\n#"
@ puts $out "set fossilcmd {}"
@ puts $out "set prog [list $::prog]"
@ puts $out "set difftxt \173"
@ foreach e $::difftxt {puts $out [list $e]}
@ puts $out "\175"
@ puts $out "eval \$prog"
@ close $out
@ }
@ ::ttk::button .bb.quit -text {Quit} -command exit
@ ::ttk::button .bb.save -text {Save As...} -command saveDiff
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 |
@ tk_messageBox -type ok -title $CFG(TITLE) -message "No changes"
@ exit
@ }
@ update idletasks
@
@ proc saveDiff {} {
@ set fn [tk_getSaveFile]
@ if {$fn==""} return
@ set out [open $fn wb]
@ puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'"
@ puts $out "# to see the graphical diff.\n#"
@ puts $out "set fossilcmd {}"
@ puts $out "set prog [list $::prog]"
@ puts $out "set difftxt \173"
@ foreach e $::difftxt {puts $out [list $e]}
@ puts $out "\175"
@ puts $out "eval \$prog"
@ close $out
@ }
@ proc invertDiff {} {
@ global CFG
@ array set x [grid info .txtA]
@ if {$x(-column)==1} {
@ grid config .lnB -column 0
@ grid config .txtB -column 1
@ .txtB tag config add -background $CFG(RM_BG)
@ grid config .lnA -column 3
@ grid config .txtA -column 4
@ .txtA tag config rm -background $CFG(ADD_BG)
@ } else {
@ grid config .lnA -column 0
@ grid config .txtA -column 1
@ .txtA tag config rm -background $CFG(RM_BG)
@ grid config .lnB -column 3
@ grid config .txtB -column 4
@ .txtB tag config add -background $CFG(ADD_BG)
@ }
@ .mkr config -state normal
@ set clt [.mkr search -all < 1.0 end]
@ set cgt [.mkr search -all > 1.0 end]
@ foreach c $clt {.mkr replace $c "$c +1 chars" >}
@ foreach c $cgt {.mkr replace $c "$c +1 chars" <}
@ .mkr config -state disabled
@ }
@ ::ttk::button .bb.quit -text {Quit} -command exit
@ ::ttk::button .bb.invert -text {Invert} -command invertDiff
@ ::ttk::button .bb.save -text {Save As...} -command saveDiff
@ pack .bb.quit .bb.invert -side left
@ if {$fossilcmd!=""} {pack .bb.save -side left}
@ pack .bb.files -side left
@ grid rowconfigure . 1 -weight 1
@ grid columnconfigure . 1 -weight 1
@ grid columnconfigure . 4 -weight 1
@ grid .bb -row 0 -columnspan 6
@ eval grid [cols] -row 1 -sticky nsew
|
| ︙ | ︙ | |||
996 997 998 999 1000 1001 1002 |
** for testing and debugging. */
if( strglob("*-script",z) && i<g.argc-1 ){
i++;
zTempFile = g.argv[i];
continue;
}
}
| > > > > | | > | 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 |
** for testing and debugging. */
if( strglob("*-script",z) && i<g.argc-1 ){
i++;
zTempFile = g.argv[i];
continue;
}
}
if( sqlite3_strglob("*}*",z) ){
blob_appendf(&script, " {%/}", z);
}else{
int j;
blob_append(&script, " ", 1);
for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
}
}
blob_appendf(&script, "}\n%s", zDiffScript);
if( zTempFile ){
blob_write_to_file(&script, zTempFile);
fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile);
}else{
#if defined(FOSSIL_ENABLE_TCL)
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
975 976 977 978 979 980 981 982 983 984 985 986 987 988 |
}else{
blob_set(pOut, "..");
for(j=i+1; zPwd[j]; j++){
if( zPwd[j]=='/' ){
blob_append(pOut, "/..", 3);
}
}
}
if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){
blob_append(pOut, "/", 1);
}
blob_reset(&tmp);
return;
}
| > > | 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 |
}else{
blob_set(pOut, "..");
for(j=i+1; zPwd[j]; j++){
if( zPwd[j]=='/' ){
blob_append(pOut, "/..", 3);
}
}
while( i>0 && (zPwd[i]!='/')) --i;
blob_append(pOut, zPath+i, j-i);
}
if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){
blob_append(pOut, "/", 1);
}
blob_reset(&tmp);
return;
}
|
| ︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 | char *zLocalRoot; Blob full; int nFull; char *zFull; int (*xCmp)(const char*,const char*,int); blob_zero(pOut); | > > | > | 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 |
char *zLocalRoot;
Blob full;
int nFull;
char *zFull;
int (*xCmp)(const char*,const char*,int);
blob_zero(pOut);
if( !g.localOpen ){
blob_appendf(pOut, "%s", zOrigName);
return 1;
}
file_canonical_name(g.zLocalRoot, &localRoot, 1);
nLocalRoot = blob_size(&localRoot);
zLocalRoot = blob_buffer(&localRoot);
assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
file_canonical_name(zOrigName, &full, 0);
nFull = blob_size(&full);
zFull = blob_buffer(&full);
|
| ︙ | ︙ | |||
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 |
** Options:
** --case-sensitive B Enable or disable case-sensitive filenames. B is
** a boolean: "yes", "no", "true", "false", etc.
*/
void cmd_test_tree_name(void){
int i;
Blob x;
blob_zero(&x);
capture_case_sensitive_option();
for(i=2; i<g.argc; i++){
if( file_tree_name(g.argv[i], &x, 1) ){
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
| > | 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 |
** Options:
** --case-sensitive B Enable or disable case-sensitive filenames. B is
** a boolean: "yes", "no", "true", "false", etc.
*/
void cmd_test_tree_name(void){
int i;
Blob x;
db_find_and_open_repository(0,0);
blob_zero(&x);
capture_case_sensitive_option();
for(i=2; i<g.argc; i++){
if( file_tree_name(g.argv[i], &x, 1) ){
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
149 150 151 152 153 154 155 |
zWidth = find_option("width","W",1);
iLimit = zLimit ? atoi(zLimit) : -1;
iWidth = zWidth ? atoi(zWidth) : 79;
zOffset = find_option("offset",0,1);
iOffset = zOffset ? atoi(zOffset) : 0;
iBrief = (find_option("brief","b",0) == 0);
if( (iWidth!=0) && (iWidth<=22) ){
| | | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
zWidth = find_option("width","W",1);
iLimit = zLimit ? atoi(zLimit) : -1;
iWidth = zWidth ? atoi(zWidth) : 79;
zOffset = find_option("offset",0,1);
iOffset = zOffset ? atoi(zOffset) : 0;
iBrief = (find_option("brief","b",0) == 0);
if( (iWidth!=0) && (iWidth<=22) ){
fossil_fatal("-W|--width value must be >22 or 0");
}
if( g.argc!=3 ){
usage("?-l|--log? ?-b|--brief? FILENAME");
}
file_tree_name(g.argv[2], &fname, 1);
rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
&fname, filename_collation());
|
| ︙ | ︙ | |||
372 373 374 375 376 377 378 |
if( P("showsql")!=0 ){
@ <p>SQL: %h(blob_str(&sql))</p>
}
blob_reset(&sql);
blob_zero(&title);
if( baseCheckin ){
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
| | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
if( P("showsql")!=0 ){
@ <p>SQL: %h(blob_str(&sql))</p>
}
blob_reset(&sql);
blob_zero(&title);
if( baseCheckin ){
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
char *zLink = href("%R/info/%s", zUuid);
blob_appendf(&title, "Ancestors of file ");
hyperlinked_path(zFilename, &title, zUuid, "tree", "");
blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid);
fossil_free(zUuid);
}else{
blob_appendf(&title, "History of files named ");
hyperlinked_path(zFilename, &title, 0, "tree", "");
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 |
const char *zCkin = db_column_text(&q,7);
const char *zBgClr = db_column_text(&q, 8);
const char *zBr = db_column_text(&q, 9);
int fmid = db_column_int(&q, 10);
int pfnid = db_column_int(&q, 11);
int gidx;
char zTime[10];
| < < | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
const char *zCkin = db_column_text(&q,7);
const char *zBgClr = db_column_text(&q, 8);
const char *zBr = db_column_text(&q, 9);
int fmid = db_column_int(&q, 10);
int pfnid = db_column_int(&q, 11);
int gidx;
char zTime[10];
if( zBr==0 ) zBr = "trunk";
if( uBg ){
zBgClr = hash_color(zUser);
}else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
}
gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr,
|
| ︙ | ︙ | |||
428 429 430 431 432 433 434 |
@ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
@ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
if( zBgClr && zBgClr[0] ){
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
}else{
@ <td class="timelineTableCell">
}
| < < | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
@ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
@ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
if( zBgClr && zBgClr[0] ){
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
}else{
@ <td class="timelineTableCell">
}
if( zUuid ){
if( fpid==0 ){
@ <b>Added</b>
}else if( pfnid ){
char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
pfnid);
@ <b>Renamed</b> from
|
| ︙ | ︙ | |||
456 457 458 459 460 461 462 |
@ <b>Renamed</b> to
@ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in
fossil_free(zNewName);
}else{
@ <b>Deleted</b> by check-in
}
}
| | | | | | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
@ <b>Renamed</b> to
@ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in
fossil_free(zNewName);
}else{
@ <b>Deleted</b> by check-in
}
}
hyperlink_to_uuid(zCkin);
@ %w(zCom) (user:
hyperlink_to_user(zUser, zDate, "");
@ branch: %h(zBr))
if( g.perm.Hyperlink && zUuid ){
const char *z = zFilename;
@ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
@ [annotate]</a>
@ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
@ [blame]</a>
@ %z(href("%R/timeline?n=200&uf=%s",zUuid))[checkins using]</a>
if( fpid ){
@ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
}
}
if( fDebug & FINFO_DEBUG_MLINK ){
int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
@ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid) sz=%d(sz)
if( srcid ){
|
| ︙ | ︙ |
Changes to src/http.c.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | Blob nonce; /* The nonce */ const char *zLogin; /* The user login name */ const char *zPw; /* The user password */ Blob pw; /* The nonce with user password appended */ Blob sig; /* The signature field */ blob_zero(pLogin); | | | | | | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
Blob nonce; /* The nonce */
const char *zLogin; /* The user login name */
const char *zPw; /* The user password */
Blob pw; /* The nonce with user password appended */
Blob sig; /* The signature field */
blob_zero(pLogin);
if( g.url.user==0 || fossil_strcmp(g.url.user, "anonymous")==0 ){
return; /* If no login card for users "nobody" and "anonymous" */
}
if( g.url.isSsh ){
return; /* If no login card for SSH: */
}
blob_zero(&nonce);
blob_zero(&pw);
sha1sum_blob(pPayload, &nonce);
blob_copy(&pw, &nonce);
zLogin = g.url.user;
if( g.url.passwd ){
zPw = g.url.passwd;
}else if( g.cgiOutput ){
/* Password failure while doing a sync from the web interface */
cgi_printf("*** incorrect or missing password for user %h\n", zLogin);
zPw = 0;
}else{
/* Password failure while doing a sync from the command-line interface */
url_prompt_for_password();
zPw = g.url.passwd;
}
/* The login card wants the SHA1 hash of the password, so convert the
** password to its SHA1 hash it it isn't already a SHA1 hash.
*/
/* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */
if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0);
|
| ︙ | ︙ | |||
100 101 102 103 104 105 106 |
** the complete payload (including the login card) already compressed.
*/
static void http_build_header(Blob *pPayload, Blob *pHdr){
int i;
const char *zSep;
blob_zero(pHdr);
| | | | | | | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
** the complete payload (including the login card) already compressed.
*/
static void http_build_header(Blob *pPayload, Blob *pHdr){
int i;
const char *zSep;
blob_zero(pHdr);
i = strlen(g.url.path);
if( i>0 && g.url.path[i-1]=='/' ){
zSep = "";
}else{
zSep = "/";
}
blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.url.path, zSep);
if( g.url.proxyAuth ){
blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
}
if( g.zHttpAuth && g.zHttpAuth[0] ){
const char *zCredentials = g.zHttpAuth;
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
}
blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
if( g.fHttpTrace ){
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
}else{
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
}
blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
}
|
| ︙ | ︙ | |||
145 146 147 148 149 150 151 |
/*
** Prompt to save HTTP Basic Authorization information
*/
static int save_httpauth_prompt(void){
Blob x;
char c;
| | | | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
/*
** Prompt to save HTTP Basic Authorization information
*/
static int save_httpauth_prompt(void){
Blob x;
char c;
if( (g.url.flags & URL_REMEMBER)==0 ) return 0;
prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
c = blob_str(&x)[0];
blob_reset(&x);
return ( c!='n' && c!='N' );
}
/*
** Get the HTTP Basic Authorization credentials from the user
** when 401 is received.
*/
char *prompt_for_httpauth_creds(void){
Blob x;
char *zUser;
char *zPw;
char *zPrompt;
char *zHttpAuth = 0;
if( !isatty(fileno(stdin)) ) return 0;
zPrompt = mprintf("\n%s authorization required by\n%s\n",
g.url.isHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.url.canonical);
fossil_print(zPrompt);
free(zPrompt);
if ( g.url.user && g.url.passwd && use_fossil_creds_for_httpauth_prompt() ){
zHttpAuth = mprintf("%s:%s", g.url.user, g.url.passwd);
}else{
prompt_user("Basic Authorization user: ", &x);
zUser = mprintf("%b", &x);
zPrompt = mprintf("HTTP password for %b: ", &x);
blob_reset(&x);
prompt_for_password(zPrompt, &x, 1);
zPw = mprintf("%b", &x);
|
| ︙ | ︙ | |||
211 212 213 214 215 216 217 | int rc = 0; /* Result code */ int iHttpVersion; /* Which version of HTTP protocol server uses */ char *zLine; /* A single line of the reply header */ int i; /* Loop counter */ int isError = 0; /* True if the reply is an error message */ int isCompressed = 1; /* True if the reply is compressed */ | | | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
int rc = 0; /* Result code */
int iHttpVersion; /* Which version of HTTP protocol server uses */
char *zLine; /* A single line of the reply header */
int i; /* Loop counter */
int isError = 0; /* True if the reply is an error message */
int isCompressed = 1; /* True if the reply is compressed */
if( transport_open(&g.url) ){
fossil_warning(transport_errmsg(&g.url));
return 1;
}
/* Construct the login card and prepare the complete payload */
blob_zero(&login);
if( useLogin ) http_build_login_card(pSend, &login);
if( g.fHttpTrace ){
|
| ︙ | ︙ | |||
258 259 260 261 262 263 264 |
transport_log(out);
free(zOutFile);
}
/*
** Send the request to the server.
*/
| | | | | | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
transport_log(out);
free(zOutFile);
}
/*
** Send the request to the server.
*/
transport_send(&g.url, &hdr);
transport_send(&g.url, &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_flip(&g.url);
/*
** Read and interpret the server reply
*/
closeConnection = 1;
iLength = -1;
while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
/* printf("[%s]\n", zLine); fflush(stdout); */
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
if( rc==401 ){
if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
if( g.zHttpAuth ){
if( g.zHttpAuth ) free(g.zHttpAuth);
}
g.zHttpAuth = prompt_for_httpauth_creds();
transport_close(&g.url);
return http_exchange(pSend, pReply, useLogin, maxRedirect);
}
}
if( rc!=200 && rc!=302 ){
int ii;
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
while( zLine[ii]==' ' ) ii++;
fossil_warning("server says: %s", &zLine[ii]);
goto write_err;
}
if( iHttpVersion==0 ){
closeConnection = 1;
}else{
closeConnection = 0;
}
}else if( g.url.isSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err;
if( rc!=200 && rc!=302 ){
int ii;
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
while( zLine[ii]==' ' ) ii++;
fossil_warning("server says: %s", &zLine[ii]);
goto write_err;
|
| ︙ | ︙ | |||
335 336 337 338 339 340 341 |
zLine[j] = 0;
}
fossil_print("redirect to %s\n", &zLine[i]);
url_parse(&zLine[i], 0);
fSeenHttpAuth = 0;
if( g.zHttpAuth ) free(g.zHttpAuth);
g.zHttpAuth = get_httpauth();
| | | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
zLine[j] = 0;
}
fossil_print("redirect to %s\n", &zLine[i]);
url_parse(&zLine[i], 0);
fSeenHttpAuth = 0;
if( g.zHttpAuth ) free(g.zHttpAuth);
g.zHttpAuth = get_httpauth();
transport_close(&g.url);
return http_exchange(pSend, pReply, useLogin, maxRedirect);
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
isCompressed = 0;
}else if( fossil_strnicmp(&zLine[14],
"application/x-fossil-uncompressed", -1)==0 ){
isCompressed = 0;
|
| ︙ | ︙ | |||
362 363 364 365 366 367 368 | } /* ** Extract the reply payload that follows the header */ blob_zero(pReply); blob_resize(pReply, iLength); | | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
}
/*
** Extract the reply payload that follows the header
*/
blob_zero(pReply);
blob_resize(pReply, iLength);
iLength = transport_receive(&g.url, blob_buffer(pReply), iLength);
blob_resize(pReply, iLength);
if( isError ){
char *z;
int i, j;
z = blob_str(pReply);
for(i=j=0; z[i]; i++, j++){
if( z[i]=='<' ){
|
| ︙ | ︙ | |||
389 390 391 392 393 394 395 | ** ** FIXME: There is some bug in the lower layers that prevents the ** connection from remaining open. The easiest fix for now is to ** simply close and restart the connection for each round-trip. ** ** For SSH we will leave the connection open. */ | | | | | | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
**
** FIXME: There is some bug in the lower layers that prevents the
** connection from remaining open. The easiest fix for now is to
** simply close and restart the connection for each round-trip.
**
** For SSH we will leave the connection open.
*/
if( ! g.url.isSsh ) closeConnection = 1; /* FIX ME */
if( closeConnection ){
transport_close(&g.url);
}else{
transport_rewind(&g.url);
}
return 0;
/*
** Jump to here if an error is seen.
*/
write_err:
transport_close(&g.url);
return 1;
}
|
Changes to src/http_socket.c.
| ︙ | ︙ | |||
122 123 124 125 126 127 128 |
#endif
iSocket = -1;
}
}
/*
** Open a socket connection. The identify of the server is determined
| | | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
#endif
iSocket = -1;
}
}
/*
** Open a socket connection. The identify of the server is determined
** by pUrlData
**
** pUrlDAta->name Name of the server. Ex: www.fossil-scm.org
** pUrlDAta->port TCP/IP port to use. Ex: 80
**
** Return the number of errors.
*/
int socket_open(UrlData *pUrlData){
static struct sockaddr_in addr; /* The server address */
static int addrIsInit = 0; /* True once addr is initialized */
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 |
N -= (size_t)got;
pContent = (void*)&((char*)pContent)[got];
}
return total;
}
/*
| | | | > | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
N -= (size_t)got;
pContent = (void*)&((char*)pContent)[got];
}
return total;
}
/*
** Attempt to resolve pUrlData->name to an IP address and setup g.zIpAddr
** so rcvfrom gets populated. For hostnames with more than one IP (or
** if overridden in ~/.ssh/config) the rcvfrom may not match the host
** to which we connect.
*/
void socket_ssh_resolve_addr(UrlData *pUrlData){
struct hostent *pHost; /* Used to make best effort for rcvfrom */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
pHost = gethostbyname(pUrlData->name);
if( pHost!=0 ){
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
}
}
|
Changes to src/http_ssl.c.
| ︙ | ︙ | |||
222 223 224 225 226 227 228 | sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc); blob_reset(&reply); return rc; } /* ** Open an SSL connection. The identify of the server is determined | | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
blob_reset(&reply);
return rc;
}
/*
** Open an SSL connection. The identify of the server is determined
** as follows:
**
** g.url.name Name of the server. Ex: www.fossil-scm.org
** pUrlData->port TCP/IP port to use. Ex: 80
**
** Return the number of errors.
*/
int ssl_open(UrlData *pUrlData){
X509 *cert;
int hasSavedCertificate = 0;
|
| ︙ | ︙ | |||
251 252 253 254 255 256 257 |
hasSavedCertificate = 1;
}
if( pUrlData->useProxy ){
int rc;
BIO *sBio;
char *connStr;
| | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
hasSavedCertificate = 1;
}
if( pUrlData->useProxy ){
int rc;
BIO *sBio;
char *connStr;
connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
sBio = BIO_new_connect(connStr);
free(connStr);
if( BIO_do_connect(sBio)<=0 ){
ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
|
| ︙ | ︙ | |||
415 416 417 418 419 420 421 |
zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
db_set_int(zHost, trusted, 1);
free(zHost);
BIO_free(mem);
}
/*
| | | > | > | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
db_set_int(zHost, trusted, 1);
free(zHost);
BIO_free(mem);
}
/*
** Get certificate for pUrlData->urlName from global config.
** Return NULL if no certificate found.
*/
X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
char *zHost, *zCert;
BIO *mem;
X509 *cert;
zHost = mprintf("cert:%s",
pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
zCert = db_get(zHost, NULL);
free(zHost);
if ( zCert==NULL )
return NULL;
if ( pTrusted!=0 ){
zHost = mprintf("trusted:%s",
pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
*pTrusted = db_get_int(zHost, 0);
free(zHost);
}
mem = BIO_new(BIO_s_mem());
BIO_puts(mem, zCert);
cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
|
| ︙ | ︙ |
Changes to src/http_transport.c.
| ︙ | ︙ | |||
136 137 138 139 140 141 142 | } blob_reset(&zCmd); return sshPid==0; } /* ** Open a connection to the server. The server is defined by the following | | | | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
}
blob_reset(&zCmd);
return sshPid==0;
}
/*
** Open a connection to the server. The server is defined by the following
** variables:
**
** pUrlData->name Name of the server. Ex: www.fossil-scm.org
** pUrlData->port TCP/IP port. Ex: 80
** pUrlData->isHttps Use TLS for the connection
**
** Return the number of errors.
*/
int transport_open(UrlData *pUrlData){
int rc = 0;
if( transport.isOpen==0 ){
if( pUrlData->isSsh ){
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
397 398 399 400 401 402 403 |
@ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
}
if( diffFlags ){
append_diff(zOld, zNew, diffFlags, pRe);
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
@
| | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
@ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
}
if( diffFlags ){
append_diff(zOld, zNew, diffFlags, pRe);
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
@
@ %z(href("%R/fdiff?v1=%s&v2=%s&sbs=1",zOld,zNew))[diff]</a>
}
}
}
/*
** Generate javascript to enhance HTML diffs.
*/
|
| ︙ | ︙ | |||
610 611 612 613 614 615 616 |
zPJ = blob_str(&projName);
for(jj=0; zPJ[jj]; jj++){
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
zPJ[jj] = '_';
}
}
@ <tr><th>Timelines:</th><td>
| | | | | | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 |
zPJ = blob_str(&projName);
for(jj=0; zPJ[jj]; jj++){
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
zPJ[jj] = '_';
}
}
@ <tr><th>Timelines:</th><td>
@ %z(href("%R/timeline?f=%s&unhide",zUuid))family</a>
if( zParent ){
@ | %z(href("%R/timeline?p=%s&unhide",zUuid))ancestors</a>
}
if( !isLeaf ){
@ | %z(href("%R/timeline?d=%s&unhide",zUuid))descendants</a>
}
if( zParent && !isLeaf ){
@ | %z(href("%R/timeline?dp=%s&unhide",zUuid))both</a>
}
db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
" WHERE rid=%d AND tagtype>0 "
" AND tag.tagid=tagxref.tagid "
" AND +tag.tagname GLOB 'sym-*'", rid);
while( db_step(&q2)==SQLITE_ROW ){
const char *zTagName = db_column_text(&q2, 0);
|
| ︙ | ︙ | |||
645 646 647 648 649 650 651 |
@ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid))
@ ZIP archive</a>
fossil_free(zUrl);
}
@ </td></tr>
@ <tr><th>Other Links:</th>
@ <td>
| | | | | | | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
@ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid))
@ ZIP archive</a>
fossil_free(zUrl);
}
@ </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?ci=%s&nofiles",zUuid))folders</a>
@ | %z(href("%R/artifact/%s",zUuid))manifest</a>
if( g.perm.Write ){
@ | %z(href("%R/ci_edit?r=%s",zUuid))edit</a>
}
@ </td>
@ </tr>
blob_reset(&projName);
}
@ </table>
}else{
|
| ︙ | ︙ | |||
697 698 699 700 701 702 703 |
}else{
@ %z(xhref("class='button'","%R/%s/%T?sbs=0",zPage,zName))
@ Show Unified Diffs</a>
@ %z(xhref("class='button'","%R/%s/%T?sbs=1",zPage,zName))
@ Show Side-by-Side Diffs</a>
}
if( zParent ){
| | | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
}else{
@ %z(xhref("class='button'","%R/%s/%T?sbs=0",zPage,zName))
@ Show Unified Diffs</a>
@ %z(xhref("class='button'","%R/%s/%T?sbs=1",zPage,zName))
@ Show Side-by-Side Diffs</a>
}
if( zParent ){
@ %z(xhref("class='button'","%R/vpatch?from=%s&to=%s",zParent,zUuid))
@ Patch</a>
}
@</div>
if( pRe ){
@ <p><b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b></p>
}
|
| ︙ | ︙ | |||
768 769 770 771 772 773 774 |
if( strcmp(zModAction,"approve")==0 ){
moderation_approve(rid);
}
}
style_header("Update of \"%h\"", pWiki->zWikiTitle);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
| | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 |
if( strcmp(zModAction,"approve")==0 ){
moderation_approve(rid);
}
}
style_header("Update of \"%h\"", pWiki->zWikiTitle);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
style_submenu_element("Raw", "Raw", "artifact/%s", zUuid);
style_submenu_element("History", "History", "whistory?name=%t",
pWiki->zWikiTitle);
style_submenu_element("Page", "Page", "wiki?name=%t",
pWiki->zWikiTitle);
login_anonymous_available();
@ <div class="section">Overview</div>
@ <p><table class="label-value">
|
| ︙ | ︙ | |||
796 797 798 799 800 801 802 |
@ <tr><th>Original User:</th><td>
hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>");
if( pWiki->nParent>0 ){
int i;
@ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td>
for(i=0; i<pWiki->nParent; i++){
char *zParent = pWiki->azParent[i];
| | | 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 |
@ <tr><th>Original User:</th><td>
hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>");
if( pWiki->nParent>0 ){
int i;
@ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td>
for(i=0; i<pWiki->nParent; i++){
char *zParent = pWiki->azParent[i];
@ %z(href("info/%s",zParent))%s(zParent)</a>
}
@ </td></tr>
}
@ </table>
if( g.perm.ModWiki && modPending ){
@ <div class="section">Moderation</div>
|
| ︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 |
hyperlink_to_uuid(zVers);
if( zBr && zBr[0] ){
@ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
}
@ - %!w(zCom) (user:
hyperlink_to_user(zUser,zDate,")");
if( g.perm.Hyperlink ){
| | | | | 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 |
hyperlink_to_uuid(zVers);
if( zBr && zBr[0] ){
@ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
}
@ - %!w(zCom) (user:
hyperlink_to_user(zUser,zDate,")");
if( g.perm.Hyperlink ){
@ %z(href("%R/finfo?name=%T&ci=%s",zName,zVers))[ancestry]</a>
@ %z(href("%R/annotate?filename=%T&checkin=%s",zName,zVers))
@ [annotate]</a>
@ %z(href("%R/blame?filename=%T&checkin=%s",zName,zVers))
@ [blame]</a>
}
cnt++;
if( pDownloadName && blob_size(pDownloadName)==0 ){
blob_append(pDownloadName, zName, -1);
}
}
|
| ︙ | ︙ | |||
1300 1301 1302 1303 1304 1305 1306 |
@ Also attachment "%h(zFilename)" to
}else{
@ Attachment "%h(zFilename)" to
}
objType |= OBJTYPE_ATTACHMENT;
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
if( g.perm.Hyperlink && g.perm.RdTkt ){
| | | 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 |
@ Also attachment "%h(zFilename)" to
}else{
@ Attachment "%h(zFilename)" to
}
objType |= OBJTYPE_ATTACHMENT;
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
if( g.perm.Hyperlink && g.perm.RdTkt ){
@ ticket [%z(href("%R/tktview?name=%s",zTarget))%S(zTarget)</a>]
}else{
@ ticket [%S(zTarget)]
}
}else{
if( g.perm.Hyperlink && g.perm.RdWiki ){
@ wiki page [%z(href("%R/wiki?name=%t",zTarget))%h(zTarget)</a>]
}else{
|
| ︙ | ︙ | |||
1326 1327 1328 1329 1330 1331 1332 |
db_finalize(&q);
if( cnt==0 ){
@ Control artifact.
if( pDownloadName && blob_size(pDownloadName)==0 ){
blob_appendf(pDownloadName, "%.10s.txt", zUuid);
}
}else if( linkToView && g.perm.Hyperlink ){
| | | 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 |
db_finalize(&q);
if( cnt==0 ){
@ Control artifact.
if( pDownloadName && blob_size(pDownloadName)==0 ){
blob_appendf(pDownloadName, "%.10s.txt", zUuid);
}
}else if( linkToView && g.perm.Hyperlink ){
@ %z(href("%R/artifact/%s",zUuid))[view]</a>
}
return objType;
}
/*
** WEBPAGE: fdiff
|
| ︙ | ︙ | |||
1402 1403 1404 1405 1406 1407 1408 |
style_submenu_element("Unified Diff", "udiff",
"%s/fdiff?v1=%T&v2=%T&sbs=0%s",
g.zTop, P("v1"), P("v2"), zW);
}
if( P("smhdr")!=0 ){
@ <h2>Differences From Artifact
| | | | | | 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 |
style_submenu_element("Unified Diff", "udiff",
"%s/fdiff?v1=%T&v2=%T&sbs=0%s",
g.zTop, P("v1"), P("v2"), zW);
}
if( P("smhdr")!=0 ){
@ <h2>Differences From Artifact
@ %z(href("%R/artifact/%s",zV1))[%S(zV1)]</a> To
@ %z(href("%R/artifact/%s",zV2))[%S(zV2)]</a>.</h2>
}else{
@ <h2>Differences From
@ Artifact %z(href("%R/artifact/%s",zV1))[%S(zV1)]</a>:</h2>
object_description(v1, 0, 0);
@ <h2>To Artifact %z(href("%R/artifact/%s",zV2))[%S(zV2)]</a>:</h2>
object_description(v2, 0, 0);
}
if( pRe ){
@ <b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b>
}
@ <hr />
|
| ︙ | ︙ | |||
1759 1760 1761 1762 1763 1764 1765 |
output_text_with_line_numbers(z, zLn);
}else{
@ <pre>
@ %h(z)
@ </pre>
}
}else if( strncmp(zMime, "image/", 6)==0 ){
| | | | 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 |
output_text_with_line_numbers(z, zLn);
}else{
@ <pre>
@ %h(z)
@ </pre>
}
}else if( strncmp(zMime, "image/", 6)==0 ){
@ <img src="%R/raw/%s(zUuid)?m=%s(zMime)" />
style_submenu_element("Image", "Image",
"%R/raw/%s?m=%s", zUuid, zMime);
}else{
@ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
}
@ </blockquote>
}
style_footer();
}
|
| ︙ | ︙ | |||
1817 1818 1819 1820 1821 1822 1823 |
moderation_approve(rid);
}
}
zTktTitle = db_table_has_column( "ticket", "title" )
? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
: 0;
style_header("Ticket Change Details");
| | | | | 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 |
moderation_approve(rid);
}
}
zTktTitle = db_table_has_column( "ticket", "title" )
? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
: 0;
style_header("Ticket Change Details");
style_submenu_element("Raw", "Raw", "%R/artifact/%s", zUuid);
style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
if( P("plaintext") ){
style_submenu_element("Formatted", "Formatted", "%R/info/%s", zUuid);
}else{
style_submenu_element("Plaintext", "Plaintext",
"%R/info/%s?plaintext", zUuid);
}
@ <div class="section">Overview</div>
@ <p><table class="label-value">
@ <tr><th>Artifact ID:</th>
@ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
if( g.perm.Setup ){
|
| ︙ | ︙ | |||
1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 |
** Figure out what the artifact ID is and jump to it.
*/
void info_page(void){
const char *zName;
Blob uuid;
int rid;
int rc;
zName = P("name");
if( zName==0 ) fossil_redirect_home();
| > > > > > > > > > > | | | | | | > | | | | < < < > > > > | 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 |
** Figure out what the artifact ID is and jump to it.
*/
void info_page(void){
const char *zName;
Blob uuid;
int rid;
int rc;
int nLen;
zName = P("name");
if( zName==0 ) fossil_redirect_home();
nLen = strlen(zName);
blob_set(&uuid, zName);
if( name_collisions(zName) ){
cgi_set_parameter("src","info");
ambiguous_page();
return;
}
rc = name_to_uuid(&uuid, -1, "*");
if( rc==1 ){
if( validate16(zName, nLen) ){
if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
tktview_page();
return;
}
if( db_exists("SELECT 1 FROM tag"
" WHERE tagname GLOB 'event-%q*'", zName) ){
event_page();
return;
}
}
style_header("No Such Object");
@ <p>No such object: %h(zName)</p>
if( nLen<4 ){
@ <p>Object name should be no less than 4 characters. Ten or more
@ characters are recommended.</p>
}
style_footer();
return;
}else if( rc==2 ){
cgi_set_parameter("src","info");
ambiguous_page();
return;
}
|
| ︙ | ︙ | |||
2339 2340 2341 2342 2343 2344 2345 |
@ <hr />
blob_reset(&suffix);
}
@ <p>Make changes to attributes of check-in
@ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
form_begin(0, "%R/ci_edit");
login_insert_csrf_secret();
| | | 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 |
@ <hr />
blob_reset(&suffix);
}
@ <p>Make changes to attributes of check-in
@ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
form_begin(0, "%R/ci_edit");
login_insert_csrf_secret();
@ <div><input type="hidden" name="r" value="%s(zUuid)" />
@ <table border="0" cellspacing="10">
@ <tr><th align="right" valign="top">User:</th>
@ <td valign="top">
@ <input type="text" name="u" size="20" value="%h(zNewUser)" />
@ </td></tr>
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
1273 1274 1275 1276 1277 1278 1279 | INT(g, xferPanic); INT(g, fullHttpReply); INT(g, xlinkClusterOnly); INT(g, fTimeFormat); INT(g, markPrivate); INT(g, clockSkewSeen); INT(g, isHTTP); | | | | | | | | | | | | | | | | 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 | INT(g, xferPanic); INT(g, fullHttpReply); INT(g, xlinkClusterOnly); INT(g, fTimeFormat); INT(g, markPrivate); INT(g, clockSkewSeen); INT(g, isHTTP); INT(g.url, isFile); INT(g.url, isHttps); INT(g.url, isSsh); INT(g.url, port); INT(g.url, dfltPort); INT(g, useLocalauth); INT(g, noPswd); INT(g, userUid); INT(g, rcvid); INT(g, okCsrf); INT(g, thTrace); INT(g, isHome); INT(g, nAux); INT(g, allowSymlinks); CSTR(g, zMainDbType); CSTR(g, zConfigDbType); CSTR(g, zLocalRoot); CSTR(g, zPath); CSTR(g, zExtra); CSTR(g, zBaseURL); CSTR(g, zTop); CSTR(g, zContentType); CSTR(g, zErrMsg); CSTR(g.url, name); CSTR(g.url, hostname); CSTR(g.url, protocol); CSTR(g.url, path); CSTR(g.url, user); CSTR(g.url, passwd); CSTR(g.url, canonical); CSTR(g.url, proxyAuth); CSTR(g.url, fossil); CSTR(g, zLogin); CSTR(g, zSSLIdentity); CSTR(g, zIpAddr); CSTR(g, zNonce); CSTR(g, zCsrfToken); o = cson_new_object(); |
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
704 705 706 707 708 709 710 |
rc = sqlite3_open_v2(
zOtherRepo, &pOther,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
if( rc==SQLITE_OK ){
| | | 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 |
rc = sqlite3_open_v2(
zOtherRepo, &pOther,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
if( rc==SQLITE_OK ){
sqlite3_create_function(pOther,"now",0,SQLITE_UTF8,0,db_now_function,0,0);
sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
sqlite3_busy_timeout(pOther, 5000);
zSQL = mprintf(
"SELECT cexpire FROM user"
" WHERE login=%Q"
" AND ipaddr=%Q"
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 |
}
sqlite3_finalize(pStmt);
}
sqlite3_close(pOther);
fossil_free(zOtherRepo);
return nXfer;
}
/*
** Lookup the uid for a non-built-in user with zLogin and zCookie and
** zRemoteAddr. Return 0 if not found.
**
** Note that this only searches for logged-in entries with matching
** zCookie (db: user.cookie) and zRemoteAddr (db: user.ipaddr)
** entries.
*/
static int login_find_user(
const char *zLogin, /* User name */
const char *zCookie, /* Login cookie value */
const char *zRemoteAddr /* Abbreviated IP address for valid login */
){
int uid;
| > > > > > > > > > > > | < < < | 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 |
}
sqlite3_finalize(pStmt);
}
sqlite3_close(pOther);
fossil_free(zOtherRepo);
return nXfer;
}
/*
** Return TRUE if zLogin is one of the special usernames
*/
int login_is_special(const char *zLogin){
if( fossil_strcmp(zLogin, "anonymous")==0 ) return 1;
if( fossil_strcmp(zLogin, "nobody")==0 ) return 1;
if( fossil_strcmp(zLogin, "developer")==0 ) return 1;
if( fossil_strcmp(zLogin, "reader")==0 ) return 1;
return 0;
}
/*
** Lookup the uid for a non-built-in user with zLogin and zCookie and
** zRemoteAddr. Return 0 if not found.
**
** Note that this only searches for logged-in entries with matching
** zCookie (db: user.cookie) and zRemoteAddr (db: user.ipaddr)
** entries.
*/
static int login_find_user(
const char *zLogin, /* User name */
const char *zCookie, /* Login cookie value */
const char *zRemoteAddr /* Abbreviated IP address for valid login */
){
int uid;
if( login_is_special(zLogin) ) return 0;
uid = db_int(0,
"SELECT uid FROM user"
" WHERE login=%Q"
" AND ipaddr=%Q"
" AND cexpire>julianday('now')"
" AND length(cap)>0"
" AND length(pw)>0"
|
| ︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 |
sqlite3_errmsg(pPeer), zSuffix);
nErr++;
sqlite3_close(pPeer);
continue;
}
sqlite3_create_function(pPeer, "shared_secret", 3, SQLITE_UTF8,
0, sha1_shared_secret_sql_function, 0, 0);
| | | 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 |
sqlite3_errmsg(pPeer), zSuffix);
nErr++;
sqlite3_close(pPeer);
continue;
}
sqlite3_create_function(pPeer, "shared_secret", 3, SQLITE_UTF8,
0, sha1_shared_secret_sql_function, 0, 0);
sqlite3_create_function(pPeer, "now", 0,SQLITE_UTF8,0,db_now_function,0,0);
sqlite3_busy_timeout(pPeer, 5000);
zErr = 0;
rc = sqlite3_exec(pPeer, zSql, 0, 0, &zErr);
if( zErr ){
blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName, zErr, zSuffix);
sqlite3_free(zErr);
nErr++;
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
110 111 112 113 114 115 116 | void *xPreEval; /* Optional, called before Tcl_Eval*(). */ void *pPreContext; /* Optional, provided to xPreEval(). */ void *xPostEval; /* Optional, called after Tcl_Eval*(). */ void *pPostContext; /* Optional, provided to xPostEval(). */ }; #endif | < < < < < | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
void *xPreEval; /* Optional, called before Tcl_Eval*(). */
void *pPreContext; /* Optional, provided to xPreEval(). */
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
char *nameOfExe; /* Full path of executable. */
const char *zErrlog; /* Log errors to this file, if not NULL */
int isConst; /* True if the output is unchanging & cacheable */
const char *zVfsName; /* The VFS to use for database connections */
sqlite3 *db; /* The connection to the databases */
|
| ︙ | ︙ | |||
169 170 171 172 173 174 175 | int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %w and %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ | | > | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %w and %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ UrlData url; /* Information about current URL */ #if 0 /* ** NOTE: These members MUST be kept in sync with those in the "UrlData" ** structure defined in "url.c". */ int urlIsFile; /* True if a "file:" url */ int urlIsHttps; /* True if a "https:" url */ int urlIsSsh; /* True if an "ssh:" url */ |
| ︙ | ︙ | |||
192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
char *urlCanonical; /* Canonical representation of the URL */
char *urlProxyAuth; /* Proxy-Authorizer: string */
char *urlFossil; /* The fossil query parameter on ssh: */
unsigned urlFlags; /* Boolean flags controlling URL processing */
int useProxy; /* Used to remember that a proxy is in use */
char *proxyUrlPath;
int proxyOrigPort; /* Tunneled port number for https through proxy */
const char *zLogin; /* Login name. NULL or "" if not logged in. */
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
** SSL client identity */
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
int isHuman; /* True if access by a human, not a spider or bot */
| > > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
char *urlCanonical; /* Canonical representation of the URL */
char *urlProxyAuth; /* Proxy-Authorizer: string */
char *urlFossil; /* The fossil query parameter on ssh: */
unsigned urlFlags; /* Boolean flags controlling URL processing */
int useProxy; /* Used to remember that a proxy is in use */
char *proxyUrlPath;
int proxyOrigPort; /* Tunneled port number for https through proxy */
#endif
const char *zLogin; /* Login name. NULL or "" if not logged in. */
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
** SSL client identity */
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
int isHuman; /* True if access by a human, not a spider or bot */
|
| ︙ | ︙ | |||
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 |
process_one_web_page(zNotFound, glob_create(zFileGlob));
}
/*
** Process all requests in a single SSH connection if possible.
*/
void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
do{
cgi_handle_ssh_http_request(zIpAddr);
process_one_web_page(0, FileGlob);
blob_reset(&g.cgiIn);
} while ( g.fSshClient & CGI_SSH_FOSSIL ||
g.fSshClient & CGI_SSH_COMPAT );
}
| > | 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 |
process_one_web_page(zNotFound, glob_create(zFileGlob));
}
/*
** Process all requests in a single SSH connection if possible.
*/
void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
blob_zero(&g.cgiIn);
do{
cgi_handle_ssh_http_request(zIpAddr);
process_one_web_page(0, FileGlob);
blob_reset(&g.cgiIn);
} while ( g.fSshClient & CGI_SSH_FOSSIL ||
g.fSshClient & CGI_SSH_COMPAT );
}
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
398 399 400 401 402 403 404 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) | < < < < < < < | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # |
| ︙ | ︙ |
Changes to src/makemake.tcl.
| ︙ | ︙ | |||
266 267 268 269 270 271 272 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) | < < < < < < < | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ. = $(SQLITE3_OBJ.0) EXTRAOBJ = \ $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" |
| ︙ | ︙ | |||
449 450 451 452 453 454 455 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # | | | | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
722 723 724 725 726 727 728 729 730 | $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = \ $(OBJDIR)/sqlite3.o \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/cson_amalgamation.o | > < < < < | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 | $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = \ $(OBJDIR)/sqlite3.o \ $(OBJDIR)/shell.o \ $(OBJDIR)/th.o \ $(OBJDIR)/th_lang.o \ $(OBJDIR)/th_tcl.o \ $(OBJDIR)/cson_amalgamation.o zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean openssl: zlib |
| ︙ | ︙ | |||
822 823 824 825 826 827 828 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n" | < | | < | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n" writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c" writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n" close $output_file # # End of the win/Makefile.mingw output ############################################################################## ############################################################################## ############################################################################## |
| ︙ | ︙ | |||
1022 1023 1024 1025 1026 1027 1028 | # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL | | | | 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 | # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL SSLINCDIR = $(B)\compat\openssl-1.0.1g\include SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib !endif !ifdef FOSSIL_ENABLE_TCL TCLDIR = $(B)\compat\tcl-8.6 TCLSRCDIR = $(TCLDIR) TCLINCDIR = $(TCLSRCDIR)\generic |
| ︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 |
if {$i > 0} {
writeln " \\"
writeln -nonewline " "
}
writeln -nonewline "${s}_.c"; incr i
}
writeln "\n"
| | < < < < < < | 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 |
if {$i > 0} {
writeln " \\"
writeln -nonewline " "
}
writeln -nonewline "${s}_.c"; incr i
}
writeln "\n"
set AdditionalObj [list shell sqlite3 th th_lang th_tcl cson_amalgamation]
writeln -nonewline "OBJ = "
set i 0
foreach s [lsort [concat $src $AdditionalObj]] {
if {$i > 0} {
writeln " \\"
writeln -nonewline " "
}
writeln -nonewline "\$(OX)\\$s\$O"; incr i
}
writeln " \\"
writeln -nonewline " \$(OX)\\fossil.res\n\n"
writeln {
APPNAME = $(OX)\fossil$(E)
PDBNAME = $(OX)\fossil$(P)
all: $(OX) $(APPNAME)
zlib:
@echo Building zlib from "$(ZLIBDIR)"...
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
cd $(OX)
link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
$(OX)\linkopts: $B\win\Makefile.msc}
set redir {>}
foreach s [lsort [concat $src $AdditionalObj]] {
writeln "\techo \$(OX)\\$s.obj $redir \$@"
set redir {>>}
}
set redir {>>}
writeln "\techo \$(LIBS) $redir \$@"
writeln {
$(OX):
@-mkdir $@
translate$E: $(SRCDIR)\translate.c
$(BCC) $**
|
| ︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** | < < | 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c $(TCC) /Fo$@ -c $** VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION $** > $@ $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c $(TCC) /Fo$@ /c $** page_index.h: mkindex$E $(SRC) |
| ︙ | ︙ |
Changes to src/manifest.c.
| ︙ | ︙ | |||
133 134 135 136 137 138 139 |
/*
** Clear the memory allocated in a manifest object
*/
void manifest_destroy(Manifest *p){
if( p ){
blob_reset(&p->content);
| | | | | | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
/*
** Clear the memory allocated in a manifest object
*/
void manifest_destroy(Manifest *p){
if( p ){
blob_reset(&p->content);
fossil_free(p->aFile);
fossil_free(p->azParent);
fossil_free(p->azCChild);
fossil_free(p->aTag);
fossil_free(p->aField);
fossil_free(p->aCherrypick);
if( p->pBaseline ) manifest_destroy(p->pBaseline);
memset(p, 0, sizeof(*p));
fossil_free(p);
}
}
/*
|
| ︙ | ︙ | |||
1587 1588 1589 1590 1591 1592 1593 |
if( !isNew ){
for(i=0; i<pManifest->nField; i++){
if( fossil_strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
zNewStatus = pManifest->aField[i].zValue;
}
}
if( zNewStatus ){
| | | | | | | | | | | | | | > | | 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 |
if( !isNew ){
for(i=0; i<pManifest->nField; i++){
if( fossil_strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
zNewStatus = pManifest->aField[i].zValue;
}
}
if( zNewStatus ){
blob_appendf(&comment, "%h ticket [%s|%.10s]: <i>%h</i>",
zNewStatus, pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle
);
if( pManifest->nField>1 ){
blob_appendf(&comment, " plus %d other change%s",
pManifest->nField-1, pManifest->nField==2 ? "" : "s");
}
blob_appendf(&brief, "%h ticket [%s|%.10s].",
zNewStatus, pManifest->zTicketUuid, pManifest->zTicketUuid);
}else{
zNewStatus = db_text("unknown",
"SELECT %s FROM ticket WHERE tkt_uuid='%s'",
zStatusColumn, pManifest->zTicketUuid
);
blob_appendf(&comment, "Ticket [%s|%.10s] <i>%h</i> status still %h with "
"%d other change%s",
pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle, zNewStatus,
pManifest->nField, pManifest->nField==1 ? "" : "s"
);
fossil_free(zNewStatus);
blob_appendf(&brief, "Ticket [%s|%.10s]: %d change%s",
pManifest->zTicketUuid, pManifest->zTicketUuid, pManifest->nField,
pManifest->nField==1 ? "" : "s"
);
}
}else{
blob_appendf(&comment, "New ticket [%s|%.10s] <i>%h</i>.",
pManifest->zTicketUuid, pManifest->zTicketUuid, zTitle
);
blob_appendf(&brief, "New ticket [%s|%.10s].", pManifest->zTicketUuid,
pManifest->zTicketUuid);
}
fossil_free(zTitle);
db_multi_exec(
"REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)"
"VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)",
tktTagId, pManifest->rDate, rid, pManifest->zUser,
blob_str(&comment), blob_str(&brief)
);
blob_reset(&comment);
|
| ︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 |
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid, p->rDate
);
zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
" WHERE rowid=last_insert_rowid()");
wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE);
| | | 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 |
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid, p->rDate
);
zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
" WHERE rowid=last_insert_rowid()");
wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE);
fossil_free(zCom);
/* If this is a delta-manifest, record the fact that this repository
** contains delta manifests, to free the "commit" logic to generate
** new delta manifests.
*/
if( p->zBaseline!=0 ){
static int once = 1;
|
| ︙ | ︙ | |||
1819 1820 1821 1822 1823 1824 1825 |
char *zComment;
int nWiki;
char zLength[40];
while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
nWiki = strlen(p->zWiki);
sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
| | | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 |
char *zComment;
int nWiki;
char zLength[40];
while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
nWiki = strlen(p->zWiki);
sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
fossil_free(zTag);
prior = db_int(0,
"SELECT rid FROM tagxref"
" WHERE tagid=%d AND mtime<%.17g"
" ORDER BY mtime DESC",
tagid, p->rDate
);
if( prior ){
|
| ︙ | ︙ | |||
1847 1848 1849 1850 1851 1852 1853 |
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
p->rDate, rid, p->zUser, zComment,
TAG_BGCOLOR, rid,
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid
);
| | | | 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 |
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
p->rDate, rid, p->zUser, zComment,
TAG_BGCOLOR, rid,
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid
);
fossil_free(zComment);
}
if( p->type==CFTYPE_EVENT ){
char *zTag = mprintf("event-%s", p->zEventId);
int tagid = tag_findid(zTag, 1);
int prior, subsequent;
int nWiki;
char zLength[40];
while( fossil_isspace(p->zWiki[0]) ) p->zWiki++;
nWiki = strlen(p->zWiki);
sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
tag_insert(zTag, 1, zLength, rid, p->rDate, rid);
fossil_free(zTag);
prior = db_int(0,
"SELECT rid FROM tagxref"
" WHERE tagid=%d AND mtime<%.17g AND rid!=%d"
" ORDER BY mtime DESC",
tagid, p->rDate, rid
);
subsequent = db_int(0,
|
| ︙ | ︙ | |||
1898 1899 1900 1901 1902 1903 1904 |
p->rEventDate, rid, tagid, p->zUser, p->zComment,
TAG_BGCOLOR, rid
);
}
}
if( p->type==CFTYPE_TICKET ){
char *zTag;
| < | > > > > > | | < | < < | < < < < < < < | | | | | > | | | | | < | | | | 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 |
p->rEventDate, rid, tagid, p->zUser, p->zComment,
TAG_BGCOLOR, rid
);
}
}
if( p->type==CFTYPE_TICKET ){
char *zTag;
assert( manifest_crosslink_busy==1 );
zTag = mprintf("tkt-%s", p->zTicketUuid);
tag_insert(zTag, 1, 0, rid, p->rDate, rid);
fossil_free(zTag);
db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
p->zTicketUuid);
}
if( p->type==CFTYPE_ATTACHMENT ){
char *zComment = 0;
char const isAdd = (p->zAttachSrc && p->zAttachSrc[0]) ? 1 : 0;
char const attachToType = fossil_is_uuid(p->zAttachTarget)
? 't' /* attach to ticket */
: 'w' /* attach to wiki page */;
db_multi_exec(
"INSERT INTO attachment(attachid, mtime, src, target,"
"filename, comment, user)"
"VALUES(%d,%.17g,%Q,%Q,%Q,%Q,%Q);",
rid, p->rDate, p->zAttachSrc, p->zAttachTarget, p->zAttachName,
(p->zComment ? p->zComment : ""), p->zUser
);
db_multi_exec(
"UPDATE attachment SET isLatest = (mtime=="
"(SELECT max(mtime) FROM attachment"
" WHERE target=%Q AND filename=%Q))"
" WHERE target=%Q AND filename=%Q",
p->zAttachTarget, p->zAttachName,
p->zAttachTarget, p->zAttachName
);
if( 'w' == attachToType ){
if( isAdd ){
zComment = mprintf(
"Add attachment [/artifact/%s|%h] to wiki page [%h]",
p->zAttachSrc, p->zAttachName, p->zAttachTarget);
}else{
zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]",
p->zAttachName, p->zAttachTarget);
}
}else{
if( isAdd ){
zComment = mprintf(
"Add attachment [/artifact/%s|%h] to ticket [%s|%.10s]",
p->zAttachSrc, p->zAttachName, p->zAttachTarget, p->zAttachTarget);
}else{
zComment = mprintf("Delete attachment \"%h\" from ticket [%s|%.10s]",
p->zAttachName, p->zAttachTarget, p->zAttachTarget);
}
}
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('%c',%.17g,%d,%Q,%Q)",
attachToType, p->rDate, rid, p->zUser, zComment
);
fossil_free(zComment);
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
const char *zTagUuid;
int branchMove = 0;
blob_zero(&comment);
if( p->zComment ){
blob_appendf(&comment, " %s.", p->zComment);
}
/* Next loop expects tags to be sorted on UUID, so sort it. */
qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
for(i=0; i<p->nTag; i++){
zTagUuid = p->aTag[i].zUuid;
if( !zTagUuid ) continue;
if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
blob_appendf(&comment,
" Edit [%s|%.10s]:",
zTagUuid, zTagUuid);
branchMove = 0;
if( permitHooks && db_exists("SELECT 1 FROM event, blob"
" WHERE event.type='ci' AND event.objid=blob.rid"
" AND blob.uuid='%s'", zTagUuid) ){
zScript = xfer_commit_code();
zUuid = zTagUuid;
}
}
zName = p->aTag[i].zName;
zValue = p->aTag[i].zValue;
if( strcmp(zName, "*branch")==0 ){
blob_appendf(&comment,
" Move to branch [/timeline?r=%h&nd&dp=%s&unhide | %h].",
zValue, zTagUuid, zValue);
branchMove = 1;
continue;
}else if( strcmp(zName, "*bgcolor")==0 ){
blob_appendf(&comment,
" Change branch background color to \"%h\".", zValue);
continue;
|
| ︙ | ︙ |
Changes to src/name.c.
| ︙ | ︙ | |||
264 265 266 267 268 269 270 |
" AND event.type GLOB '%q'", zTag, zType);
}
}
}
return rid;
}
| < | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
" AND event.type GLOB '%q'", zTag, zType);
}
}
}
return rid;
}
/*
** This routine takes a user-entered UUID which might be in mixed
** case and might only be a prefix of the full UUID and converts it
** into the full-length UUID in canonical form.
**
** If the input is not a UUID or a UUID prefix, then try to resolve
** the name as a tag. If multiple tags match, pick the latest.
|
| ︙ | ︙ | |||
317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
if((rid>0) && pUuid){
*pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
return rid;
}
/*
** COMMAND: test-name-to-id
**
** Convert a name to a full artifact ID.
*/
void test_name_to_id(void){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
if((rid>0) && pUuid){
*pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
return rid;
}
/*
** name_collisions searches through events, blobs, and tickets for
** collisions of a given UUID based on its length on UUIDs no shorter
** than 4 characters in length.
*/
int name_collisions(const char *zName){
Stmt q;
int c = 0; /* count of collisions for zName */
int nLen; /* length of zName */
nLen = strlen(zName);
if( nLen>=4 && nLen<=UUID_SIZE && validate16(zName, nLen) ){
db_prepare(&q,
"SELECT count(uuid) FROM"
" (SELECT substr(tkt_uuid, 1, %d) AS uuid FROM ticket"
" UNION ALL SELECT * FROM"
" (SELECT substr(tagname, 7, %d) FROM"
" tag WHERE tagname GLOB 'event-*')"
" UNION ALL SELECT * FROM"
" (SELECT substr(uuid, 1, %d) FROM blob))"
" WHERE uuid GLOB '%q*'"
" GROUP BY uuid HAVING count(uuid) > 1;",
nLen, nLen, nLen, zName);
if( db_step(&q)==SQLITE_ROW ){
c = db_column_int(&q, 0);
}
db_finalize(&q);
}
return c;
}
/*
** COMMAND: test-name-to-id
**
** Convert a name to a full artifact ID.
*/
void test_name_to_id(void){
|
| ︙ | ︙ | |||
400 401 402 403 404 405 406 |
@ <ol>
z = mprintf("%s", zName);
canonical16(z, strlen(z));
db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
| | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
@ <ol>
z = mprintf("%s", zName);
canonical16(z, strlen(z));
db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
@ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
@ %s(zUuid)</a> -
object_description(rid, 0, 0);
@ </p></li>
}
db_finalize(&q);
db_prepare(&q,
" SELECT tkt_rid, tkt_uuid, title"
" FROM ticket, ticketchng"
" WHERE ticket.tkt_id = ticketchng.tkt_id"
" AND tkt_uuid GLOB '%q*'"
" GROUP BY tkt_uuid"
" ORDER BY tkt_ctime DESC", z);
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
const char *zUuid = db_column_text(&q, 1);
const char *zTitle = db_column_text(&q, 2);
@ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
@ %s(zUuid)</a> -
@ <ul></ul>
@ Ticket
hyperlink_to_uuid(zUuid);
@ - %s(zTitle).
@ <ul><li>
object_description(rid, 0, 0);
@ </li></ul>
@ </p></li>
}
db_finalize(&q);
db_prepare(&q,
"SELECT rid, uuid FROM"
" (SELECT tagxref.rid AS rid, substr(tagname, 7) AS uuid"
" FROM tagxref, tag WHERE tagxref.tagid = tag.tagid"
" AND tagname GLOB 'event-%q*') GROUP BY uuid", z);
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
const char* zUuid = db_column_text(&q, 1);
@ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)">
@ %s(zUuid)</a> -
@ <ul><li>
object_description(rid, 0, 0);
@ </li></ul>
@ </p></li>
}
@ </ol>
db_finalize(&q);
style_footer();
}
/*
** Convert the name in CGI parameter zParamName into a rid and return that
** rid. If the CGI parameter is missing or is not a valid artifact tag,
** return 0. If the CGI parameter is ambiguous, redirect to a page that
|
| ︙ | ︙ | |||
628 629 630 631 632 633 634 |
db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
while( db_step(&q)==SQLITE_ROW ){
if( cnt++ ) fossil_print("%.79c\n", '-');
whatis_rid(db_column_int(&q,0), 1);
}
db_finalize(&q);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
while( db_step(&q)==SQLITE_ROW ){
if( cnt++ ) fossil_print("%.79c\n", '-');
whatis_rid(db_column_int(&q,0), 1);
}
db_finalize(&q);
}
/*
** COMMAND: test-ambiguous
** Usage: %fossil test-ambiguous [--minsize N]
**
** Show a list of ambiguous SHA1-hash abbreviations of N characters or
** more where N defaults to 4. Change N to a different value using
** the "--minsize N" command-line option.
*/
void test_ambiguous_cmd(void){
Stmt q, ins;
int i;
int minSize = 4;
const char *zMinsize;
char zPrev[100];
db_find_and_open_repository(0,0);
zMinsize = find_option("minsize",0,1);
if( zMinsize && atoi(zMinsize)>0 ) minSize = atoi(zMinsize);
db_multi_exec("CREATE TEMP TABLE dups(uuid, cnt)");
db_prepare(&ins,"INSERT INTO dups(uuid) VALUES(substr(:uuid,1,:cnt))");
db_prepare(&q,
"SELECT uuid FROM blob "
"UNION "
"SELECT substr(tagname,7) FROM tag WHERE tagname GLOB 'event-*' "
"UNION "
"SELECT tkt_uuid FROM ticket "
"ORDER BY 1"
);
zPrev[0] = 0;
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
for(i=0; zUuid[i]==zPrev[i] && zUuid[i]!=0; i++){}
if( i>=minSize ){
db_bind_int(&ins, ":cnt", i);
db_bind_text(&ins, ":uuid", zUuid);
db_step(&ins);
db_reset(&ins);
}
sqlite3_snprintf(sizeof(zPrev), zPrev, "%s", zUuid);
}
db_finalize(&ins);
db_finalize(&q);
db_prepare(&q, "SELECT uuid FROM dups ORDER BY length(uuid) DESC, uuid");
while( db_step(&q)==SQLITE_ROW ){
fossil_print("%s\n", db_column_text(&q, 0));
}
db_finalize(&q);
}
|
Changes to src/report.c.
| ︙ | ︙ | |||
300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
rn = atoi(PD("rn","0"));
db_prepare(&q, "SELECT title, sqlcode, owner, cols "
"FROM reportfmt WHERE rn=%d",rn);
style_header("SQL For Report Format Number %d", rn);
if( db_step(&q)!=SQLITE_ROW ){
@ <p>Unknown report number: %d(rn)</p>
style_footer();
return;
}
zTitle = db_column_text(&q, 0);
zSQL = db_column_text(&q, 1);
zOwner = db_column_text(&q, 2);
zClrKey = db_column_text(&q, 3);
@ <table cellpadding=0 cellspacing=0 border=0>
| > | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
rn = atoi(PD("rn","0"));
db_prepare(&q, "SELECT title, sqlcode, owner, cols "
"FROM reportfmt WHERE rn=%d",rn);
style_header("SQL For Report Format Number %d", rn);
if( db_step(&q)!=SQLITE_ROW ){
@ <p>Unknown report number: %d(rn)</p>
style_footer();
db_finalize(&q);
return;
}
zTitle = db_column_text(&q, 0);
zSQL = db_column_text(&q, 1);
zOwner = db_column_text(&q, 2);
zClrKey = db_column_text(&q, 3);
@ <table cellpadding=0 cellspacing=0 border=0>
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
@ </pre></td>
@ <td width=15></td><td valign="top">
output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
@ </td>
@ </tr></table>
report_format_hints();
style_footer();
}
/*
** WEBPAGE: /rptnew
** WEBPAGE: /rptedit
*/
void view_edit(void){
| > | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
@ </pre></td>
@ <td width=15></td><td valign="top">
output_color_key(zClrKey, 0, "border=0 cellspacing=0 cellpadding=3");
@ </td>
@ </tr></table>
report_format_hints();
style_footer();
db_finalize(&q);
}
/*
** WEBPAGE: /rptnew
** WEBPAGE: /rptedit
*/
void view_edit(void){
|
| ︙ | ︙ | |||
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 |
}
tabs = P("tablist")!=0;
/* view_add_functions(tabs); */
db_prepare(&q,
"SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn);
if( db_step(&q)!=SQLITE_ROW ){
cgi_redirect("reportlist");
return;
}
zTitle = db_column_malloc(&q, 0);
zSql = db_column_malloc(&q, 1);
zOwner = db_column_malloc(&q, 2);
zClrKey = db_column_malloc(&q, 3);
db_finalize(&q);
| > | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
}
tabs = P("tablist")!=0;
/* view_add_functions(tabs); */
db_prepare(&q,
"SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn);
if( db_step(&q)!=SQLITE_ROW ){
cgi_redirect("reportlist");
db_finalize(&q);
return;
}
zTitle = db_column_malloc(&q, 0);
zSql = db_column_malloc(&q, 1);
zOwner = db_column_malloc(&q, 2);
zClrKey = db_column_malloc(&q, 3);
db_finalize(&q);
|
| ︙ | ︙ |
Changes to src/search.c.
| ︙ | ︙ | |||
197 198 199 200 201 202 203 |
const char *zWidth = find_option("width","W",1);
int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching
lines/entries to list */
int width;
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
| | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
const char *zWidth = find_option("width","W",1);
int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching
lines/entries to list */
int width;
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("-W|--width value must be >20 or 0");
}
}else{
width = 79;
}
db_must_be_within_tree();
if( g.argc<2 ) return;
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
275 276 277 278 279 280 281 282 283 284 285 286 287 288 | @ <span class="usertype">anonymous</span>, and @ <span class="usertype">nobody</span>. @ </p></li> @ @ </ol> @ </td></tr></table> style_footer(); } /* ** Return true if zPw is a valid password string. A valid ** password string is: ** ** (1) A zero-length string, or | > | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | @ <span class="usertype">anonymous</span>, and @ <span class="usertype">nobody</span>. @ </p></li> @ @ </ol> @ </td></tr></table> style_footer(); db_finalize(&s); } /* ** Return true if zPw is a valid password string. A valid ** password string is: ** ** (1) A zero-length string, or |
| ︙ | ︙ | |||
323 324 325 326 327 328 329 |
if( zId && !g.perm.Setup && uid>0 ){
char *zOldCaps;
zOldCaps = db_text(0, "SELECT cap FROM user WHERE uid=%d",uid);
higherUser = zOldCaps && strchr(zOldCaps,'s');
}
if( P("can") ){
| | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
if( zId && !g.perm.Setup && uid>0 ){
char *zOldCaps;
zOldCaps = db_text(0, "SELECT cap FROM user WHERE uid=%d",uid);
higherUser = zOldCaps && strchr(zOldCaps,'s');
}
if( P("can") ){
cgi_redirect("setup_ulist"); /* User pressed the Cancel button */
return;
}
/* If we have all the necessary information, write the new or
** modified user record. After writing the user record, redirect
** to the page that displays a list of users.
*/
|
| ︙ | ︙ | |||
360 361 362 363 364 365 366 |
}
if( isValidPwString(zPw) ){
zPw = sha1_shared_secret(zPw, zLogin, 0);
}else{
zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
}
zOldLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", uid);
| < | < | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
}
if( isValidPwString(zPw) ){
zPw = sha1_shared_secret(zPw, zLogin, 0);
}else{
zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
}
zOldLogin = db_text(0, "SELECT login FROM user WHERE uid=%d", uid);
if( db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid) ){
style_header("User Creation Error");
@ <span class="loginError">Login "%h(zLogin)" is already used by
@ a different user.</span>
@
@ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
style_footer();
return;
|
| ︙ | ︙ | |||
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
style_header(mprintf("Edit User %h", zLogin));
}else{
style_header("Add A New User");
}
@ <div class="ueditCapBox">
@ <form action="%s(g.zPath)" method="post"><div>
login_insert_csrf_secret();
@ <table>
@ <tr>
@ <td class="usetupEditLabel">User ID:</td>
if( uid ){
@ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" /></td>
}else{
@ <td>(new user)<input type="hidden" name="id" value="0" /></td>
}
@ </tr>
@ <tr>
@ <td class="usetupEditLabel">Login:</td>
| > > > > > > > > | | | | | > | 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 |
style_header(mprintf("Edit User %h", zLogin));
}else{
style_header("Add A New User");
}
@ <div class="ueditCapBox">
@ <form action="%s(g.zPath)" method="post"><div>
login_insert_csrf_secret();
if( login_is_special(zLogin) ){
@ <input type="hidden" name="login" value="%s(zLogin)">
@ <input type="hidden" name="info" value="">
@ <input type="hidden" name="pw" value="*">
}
@ <table>
@ <tr>
@ <td class="usetupEditLabel">User ID:</td>
if( uid ){
@ <td>%d(uid) <input type="hidden" name="id" value="%d(uid)" /></td>
}else{
@ <td>(new user)<input type="hidden" name="id" value="0" /></td>
}
@ </tr>
@ <tr>
@ <td class="usetupEditLabel">Login:</td>
if( login_is_special(zLogin) ){
@ <td><b>%h(zLogin)</b></td>
}else{
@ <td><input type="text" name="login" value="%h(zLogin)" /></td>
@ </tr>
@ <tr>
@ <td class="usetupEditLabel">Contact Info:</td>
@ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
}
@ </tr>
@ <tr>
@ <td class="usetupEditLabel">Capabilities:</td>
@ <td>
#define B(x) inherit[x]
@ <table border=0><tr><td valign="top">
if( g.perm.Setup ){
|
| ︙ | ︙ | |||
562 563 564 565 566 567 568 |
@ <label><input type="checkbox" name="ax"%s(oa['x']) />%s(B('x'))Private
@ </label><br />
@ <label><input type="checkbox" name="az"%s(oa['z']) />%s(B('z'))Download
@ Zip </label>
@ </td></tr></table>
@ </td>
@ </tr>
| > | | | | | | | | | | > | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 |
@ <label><input type="checkbox" name="ax"%s(oa['x']) />%s(B('x'))Private
@ </label><br />
@ <label><input type="checkbox" name="az"%s(oa['z']) />%s(B('z'))Download
@ Zip </label>
@ </td></tr></table>
@ </td>
@ </tr>
if( !login_is_special(zLogin) ){
@ <tr>
@ <td align="right">Password:</td>
if( zPw[0] ){
/* Obscure the password for all users */
@ <td><input type="password" name="pw" value="**********" /></td>
}else{
/* Show an empty password as an empty input field */
@ <td><input type="password" name="pw" value="" /></td>
}
@ </tr>
}
zGroup = login_group_name();
if( zGroup ){
@ <tr>
@ <td valign="top" align="right">Scope:</td>
@ <td valign="top">
@ <input type="radio" name="all" checked value="0">
@ Apply changes to this repository only.<br />
|
| ︙ | ︙ |
Changes to src/shell.c.
| ︙ | ︙ | |||
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 |
return;
}
rc = sqlite3_open(zNewDb, &newDb);
if( rc ){
fprintf(stderr, "Cannot create output database: %s\n",
sqlite3_errmsg(newDb));
}else{
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
tryToCloneSchema(p, newDb, "type!='table'", 0);
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
}
sqlite3_close(newDb);
}
/*
** If an input line begins with "." then invoke this routine to
** process that line.
| > > | 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 |
return;
}
rc = sqlite3_open(zNewDb, &newDb);
if( rc ){
fprintf(stderr, "Cannot create output database: %s\n",
sqlite3_errmsg(newDb));
}else{
sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
tryToCloneSchema(p, newDb, "type!='table'", 0);
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
}
sqlite3_close(newDb);
}
/*
** If an input line begins with "." then invoke this routine to
** process that line.
|
| ︙ | ︙ | |||
3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 |
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
{ "assert", SQLITE_TESTCTRL_ASSERT },
{ "always", SQLITE_TESTCTRL_ALWAYS },
{ "reserve", SQLITE_TESTCTRL_RESERVE },
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
};
int testctrl = -1;
int rc = 0;
int i, n;
open_db(p, 0);
/* convert testctrl text option to value. allow any unique prefix
| > | 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 |
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
{ "assert", SQLITE_TESTCTRL_ASSERT },
{ "always", SQLITE_TESTCTRL_ALWAYS },
{ "reserve", SQLITE_TESTCTRL_RESERVE },
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
};
int testctrl = -1;
int rc = 0;
int i, n;
open_db(p, 0);
/* convert testctrl text option to value. allow any unique prefix
|
| ︙ | ︙ | |||
3061 3062 3063 3064 3065 3066 3067 |
} else {
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
azArg[1]);
}
break;
/* sqlite3_test_control(int) */
| | | > | 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 |
} else {
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
azArg[1]);
}
break;
/* sqlite3_test_control(int) */
case SQLITE_TESTCTRL_PRNG_SAVE:
case SQLITE_TESTCTRL_PRNG_RESTORE:
case SQLITE_TESTCTRL_PRNG_RESET:
case SQLITE_TESTCTRL_BYTEORDER:
if( nArg==2 ){
rc = sqlite3_test_control(testctrl);
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
} else {
fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
}
break;
|
| ︙ | ︙ |
Changes to src/sqlcmd.c.
| ︙ | ︙ | |||
110 111 112 113 114 115 116 |
** database connection to be more useful to the human operator.
*/
static int sqlcmd_autoinit(
sqlite3 *db,
const char **pzErrMsg,
const void *notUsed
){
| | | | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
** database connection to be more useful to the human operator.
*/
static int sqlcmd_autoinit(
sqlite3 *db,
const char **pzErrMsg,
const void *notUsed
){
sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
sqlcmd_content, 0, 0);
sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
sqlcmd_compress, 0, 0);
sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
sqlcmd_decompress, 0, 0);
re_add_sql_func(db);
g.repositoryOpen = 1;
g.db = db;
return SQLITE_OK;
}
|
| ︙ | ︙ |
Changes to src/sqlite3.c.
1 2 | /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite | | | 1 2 3 4 5 6 7 8 9 10 | /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite ** version 3.8.5. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements ** of 5% or more are commonly seen when SQLite is compiled as a single ** translation unit. ** ** This file is all you need to compile SQLite. To use SQLite in other |
| ︙ | ︙ | |||
218 219 220 221 222 223 224 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.5" #define SQLITE_VERSION_NUMBER 3008005 #define SQLITE_SOURCE_ID "2014-04-18 22:20:31 9a5d38c79d2482a23bcfbc3ff35ca4fa269c768d" /* ** 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 |
| ︙ | ︙ | |||
6234 6235 6236 6237 6238 6239 6240 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 | > | | 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_LAST 22 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for |
| ︙ | ︙ | |||
8435 8436 8437 8438 8439 8440 8441 | ** ** 0.5 -> -10 0.1 -> -33 0.0625 -> -40 */ typedef INT16_TYPE LogEst; /* ** Macros to determine whether the machine is big or little endian, | > > > > > | | | > > > | > > > > > > > > > | | 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 |
**
** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
*/
typedef INT16_TYPE LogEst;
/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
**
** For best performance, an attempt is made to guess at the byte-order
** using C-preprocessor macros. If that is unsuccessful, or if
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
** at run-time.
*/
#ifdef SQLITE_AMALGAMATION
SQLITE_PRIVATE const int sqlite3one = 1;
#else
SQLITE_PRIVATE const int sqlite3one;
#endif
#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
# define SQLITE_BYTEORDER 1234
# define SQLITE_BIGENDIAN 0
# define SQLITE_LITTLEENDIAN 1
# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
#endif
#if (defined(sparc) || defined(__ppc__)) \
&& !defined(SQLITE_RUNTIME_BYTEORDER)
# define SQLITE_BYTEORDER 4321
# define SQLITE_BIGENDIAN 1
# define SQLITE_LITTLEENDIAN 0
# define SQLITE_UTF16NATIVE SQLITE_UTF16BE
#endif
#if !defined(SQLITE_BYTEORDER)
# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
#endif
/*
** Constants for the largest and smallest possible 64-bit signed integers.
** These macros are designed to work correctly on both 32-bit and 64-bit
** compilers.
*/
|
| ︙ | ︙ | |||
8765 8766 8767 8768 8769 8770 8771 | #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_MEMORY 2 /* This is an in-memory DB */ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); | > | > | 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 | #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_MEMORY 2 /* This is an in-memory DB */ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); #if SQLITE_MAX_MMAP_SIZE>0 SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); #endif SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned); SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*); SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int); |
| ︙ | ︙ | |||
8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 | ** indices.) */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int); SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); | > | 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 | ** indices.) */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int); SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); |
| ︙ | ︙ | |||
8889 8890 8891 8892 8893 8894 8895 | SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); | | | 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 | SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *); SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *); SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); #endif |
| ︙ | ︙ | |||
9132 9133 9134 9135 9136 9137 9138 | #define OP_NextIfOpen 7 #define OP_Prev 8 #define OP_Next 9 #define OP_AggStep 10 /* synopsis: accum=r[P3] step(r[P2@P5]) */ #define OP_Checkpoint 11 #define OP_JournalMode 12 #define OP_Vacuum 13 | | | 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 | #define OP_NextIfOpen 7 #define OP_Prev 8 #define OP_Next 9 #define OP_AggStep 10 /* synopsis: accum=r[P3] step(r[P2@P5]) */ #define OP_Checkpoint 11 #define OP_JournalMode 12 #define OP_Vacuum 13 #define OP_VFilter 14 /* synopsis: iplan=r[P3] zplan='P4' */ #define OP_VUpdate 15 /* synopsis: data=r[P3@P2] */ #define OP_Goto 16 #define OP_Gosub 17 #define OP_Return 18 #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ #define OP_InitCoroutine 20 #define OP_EndCoroutine 21 |
| ︙ | ︙ | |||
9159 9160 9161 9162 9163 9164 9165 | #define OP_SCopy 34 /* synopsis: r[P2]=r[P1] */ #define OP_ResultRow 35 /* synopsis: output=r[P1@P2] */ #define OP_CollSeq 36 #define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */ #define OP_MustBeInt 38 #define OP_RealAffinity 39 #define OP_Permutation 40 | | | 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 | #define OP_SCopy 34 /* synopsis: r[P2]=r[P1] */ #define OP_ResultRow 35 /* synopsis: output=r[P1@P2] */ #define OP_CollSeq 36 #define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */ #define OP_MustBeInt 38 #define OP_RealAffinity 39 #define OP_Permutation 40 #define OP_Compare 41 /* synopsis: r[P1@P3] <-> r[P2@P3] */ #define OP_Jump 42 #define OP_Once 43 #define OP_If 44 #define OP_IfNot 45 #define OP_Column 46 /* synopsis: r[P3]=PX */ #define OP_Affinity 47 /* synopsis: affinity(r[P1@P2]) */ #define OP_MakeRecord 48 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ |
| ︙ | ︙ | |||
9186 9187 9188 9189 9190 9191 9192 | #define OP_SeekGE 61 #define OP_SeekGT 62 #define OP_Seek 63 /* synopsis: intkey=r[P2] */ #define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */ #define OP_NotFound 65 /* synopsis: key=r[P3@P4] */ #define OP_Found 66 /* synopsis: key=r[P3@P4] */ #define OP_NotExists 67 /* synopsis: intkey=r[P3] */ | | | 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 | #define OP_SeekGE 61 #define OP_SeekGT 62 #define OP_Seek 63 /* synopsis: intkey=r[P2] */ #define OP_NoConflict 64 /* synopsis: key=r[P3@P4] */ #define OP_NotFound 65 /* synopsis: key=r[P3@P4] */ #define OP_Found 66 /* synopsis: key=r[P3@P4] */ #define OP_NotExists 67 /* synopsis: intkey=r[P3] */ #define OP_Sequence 68 /* synopsis: r[P2]=cursor[P1].ctr++ */ #define OP_NewRowid 69 /* synopsis: r[P2]=rowid */ #define OP_Insert 70 /* synopsis: intkey=r[P3] data=r[P2] */ #define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ #define OP_InsertInt 73 /* synopsis: intkey=P3 data=r[P2] */ #define OP_Delete 74 #define OP_ResetCount 75 |
| ︙ | ︙ | |||
9234 9235 9236 9237 9238 9239 9240 | #define OP_IdxRowid 109 /* synopsis: r[P2]=rowid */ #define OP_IdxLE 110 /* synopsis: key=r[P3@P4] */ #define OP_IdxGT 111 /* synopsis: key=r[P3@P4] */ #define OP_IdxLT 112 /* synopsis: key=r[P3@P4] */ #define OP_IdxGE 113 /* synopsis: key=r[P3@P4] */ #define OP_Destroy 114 #define OP_Clear 115 | > | | | | | | | | | | | | | | | | < > | | | | | | | | < > | | | | | | | | | | 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 | #define OP_IdxRowid 109 /* synopsis: r[P2]=rowid */ #define OP_IdxLE 110 /* synopsis: key=r[P3@P4] */ #define OP_IdxGT 111 /* synopsis: key=r[P3@P4] */ #define OP_IdxLT 112 /* synopsis: key=r[P3@P4] */ #define OP_IdxGE 113 /* synopsis: key=r[P3@P4] */ #define OP_Destroy 114 #define OP_Clear 115 #define OP_ResetSorter 116 #define OP_CreateIndex 117 /* synopsis: r[P2]=root iDb=P1 */ #define OP_CreateTable 118 /* synopsis: r[P2]=root iDb=P1 */ #define OP_ParseSchema 119 #define OP_LoadAnalysis 120 #define OP_DropTable 121 #define OP_DropIndex 122 #define OP_DropTrigger 123 #define OP_IntegrityCk 124 #define OP_RowSetAdd 125 /* synopsis: rowset(P1)=r[P2] */ #define OP_RowSetRead 126 /* synopsis: r[P3]=rowset(P1) */ #define OP_RowSetTest 127 /* synopsis: if r[P3] in rowset(P1) goto P2 */ #define OP_Program 128 #define OP_Param 129 #define OP_FkCounter 130 /* synopsis: fkctr[P1]+=P2 */ #define OP_FkIfZero 131 /* synopsis: if fkctr[P1]==0 goto P2 */ #define OP_MemMax 132 /* synopsis: r[P1]=max(r[P1],r[P2]) */ #define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ #define OP_IfPos 134 /* synopsis: if r[P1]>0 goto P2 */ #define OP_IfNeg 135 /* synopsis: if r[P1]<0 goto P2 */ #define OP_IfZero 136 /* synopsis: r[P1]+=P3, if r[P1]==0 goto P2 */ #define OP_AggFinal 137 /* synopsis: accum=r[P1] N=P2 */ #define OP_IncrVacuum 138 #define OP_Expire 139 #define OP_TableLock 140 /* synopsis: iDb=P1 root=P2 write=P3 */ #define OP_VBegin 141 #define OP_VCreate 142 #define OP_ToText 143 /* same as TK_TO_TEXT */ #define OP_ToBlob 144 /* same as TK_TO_BLOB */ #define OP_ToNumeric 145 /* same as TK_TO_NUMERIC */ #define OP_ToInt 146 /* same as TK_TO_INT */ #define OP_ToReal 147 /* same as TK_TO_REAL */ #define OP_VDestroy 148 #define OP_VOpen 149 #define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */ #define OP_VNext 151 #define OP_VRename 152 #define OP_Pagecount 153 #define OP_MaxPgcnt 154 #define OP_Init 155 /* synopsis: Start at P2 */ #define OP_Noop 156 #define OP_Explain 157 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: */ #define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */ |
| ︙ | ︙ | |||
9303 9304 9305 9306 9307 9308 9309 | /* 56 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\ /* 64 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x4c,\ /* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\ /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\ /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\ /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\ /* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\ | | | | | | | | 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 | /* 56 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\ /* 64 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x4c,\ /* 72 */ 0x4c, 0x00, 0x00, 0x00, 0x05, 0x05, 0x15, 0x15,\ /* 80 */ 0x15, 0x15, 0x15, 0x15, 0x00, 0x4c, 0x4c, 0x4c,\ /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x00,\ /* 96 */ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\ /* 104 */ 0x01, 0x01, 0x08, 0x08, 0x00, 0x02, 0x01, 0x01,\ /* 112 */ 0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00,\ /* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x15,\ /* 128 */ 0x01, 0x02, 0x00, 0x01, 0x08, 0x02, 0x05, 0x05,\ /* 136 */ 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,\ /* 144 */ 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x01,\ /* 152 */ 0x00, 0x02, 0x02, 0x01, 0x00, 0x00,} /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. |
| ︙ | ︙ | |||
9365 9366 9367 9368 9369 9370 9371 | SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); | | | | 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 | SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int); SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on |
| ︙ | ︙ | |||
10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 |
** The r1 and r2 member variables are only used by the optimized comparison
** functions vdbeRecordCompareInt() and vdbeRecordCompareString().
*/
struct UnpackedRecord {
KeyInfo *pKeyInfo; /* Collation and sort-order information */
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
Mem *aMem; /* Values */
int r1; /* Value to return if (lhs > rhs) */
int r2; /* Value to return if (rhs < lhs) */
};
/*
| > | 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 |
** The r1 and r2 member variables are only used by the optimized comparison
** functions vdbeRecordCompareInt() and vdbeRecordCompareString().
*/
struct UnpackedRecord {
KeyInfo *pKeyInfo; /* Collation and sort-order information */
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
u8 isCorrupt; /* Corruption detected by xRecordCompare() */
Mem *aMem; /* Values */
int r1; /* Value to return if (lhs > rhs) */
int r2; /* Value to return if (rhs < lhs) */
};
/*
|
| ︙ | ︙ | |||
11260 11261 11262 11263 11264 11265 11266 | #define EP_Agg 0x000002 /* Contains one or more aggregate functions */ #define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ #define EP_Error 0x000008 /* Expression contains one or more errors */ #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ | | | | 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 | #define EP_Agg 0x000002 /* Contains one or more aggregate functions */ #define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ #define EP_Error 0x000008 /* Expression contains one or more errors */ #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ #define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ #define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ #define EP_Static 0x008000 /* Held in memory not obtained from malloc() */ #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ |
| ︙ | ︙ | |||
11325 11326 11327 11328 11329 11330 11331 |
** column expression as it exists in a SELECT statement. However, if
** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
** of the result column in the form: DATABASE.TABLE.COLUMN. This later
** form is used for name resolution with nested FROM clauses.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
| < | 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 |
** column expression as it exists in a SELECT statement. However, if
** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
** of the result column in the form: DATABASE.TABLE.COLUMN. This later
** form is used for name resolution with nested FROM clauses.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
struct ExprList_item { /* For each expression in the list */
Expr *pExpr; /* The list of expressions */
char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */
unsigned done :1; /* A flag to indicate when processing is finished */
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
|
| ︙ | ︙ | |||
11549 11550 11551 11552 11553 11554 11555 |
** sequences for the ORDER BY clause.
*/
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
| | | 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 |
** sequences for the ORDER BY clause.
*/
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
u64 nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */
Select *pPrior; /* Prior select in a compound select statement */
|
| ︙ | ︙ | |||
11573 11574 11575 11576 11577 11578 11579 | */ #define SF_Distinct 0x0001 /* Output should be DISTINCT */ #define SF_Resolved 0x0002 /* Identifiers have been resolved */ #define SF_Aggregate 0x0004 /* Contains aggregate functions */ #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ | | | | 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 |
*/
#define SF_Distinct 0x0001 /* Output should be DISTINCT */
#define SF_Resolved 0x0002 /* Identifiers have been resolved */
#define SF_Aggregate 0x0004 /* Contains aggregate functions */
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
/* 0x0040 NOT USED */
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
/* 0x0100 NOT USED */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
#define SF_Compound 0x1000 /* Part of a compound query */
/*
|
| ︙ | ︙ | |||
11628 11629 11630 11631 11632 11633 11634 | ** SRT_Coroutine Generate a co-routine that returns a new row of ** results each time it is invoked. The entry point ** of the co-routine is stored in register pDest->iSDParm ** and the result row is stored in pDest->nDest registers ** starting with pDest->iSdst. ** ** SRT_Table Store results in temporary table pDest->iSDParm. | | | > > | | > > > > | | | | | | | < < < | 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 |
** SRT_Coroutine Generate a co-routine that returns a new row of
** results each time it is invoked. The entry point
** of the co-routine is stored in register pDest->iSDParm
** and the result row is stored in pDest->nDest registers
** starting with pDest->iSdst.
**
** SRT_Table Store results in temporary table pDest->iSDParm.
** SRT_Fifo This is like SRT_EphemTab except that the table
** is assumed to already be open. SRT_Fifo has
** the additional property of being able to ignore
** the ORDER BY clause.
**
** SRT_DistFifo Store results in a temporary table pDest->iSDParm.
** But also use temporary table pDest->iSDParm+1 as
** a record of all prior results and ignore any duplicate
** rows. Name means: "Distinct Fifo".
**
** SRT_Queue Store results in priority queue pDest->iSDParm (really
** an index). Append a sequence number so that all entries
** are distinct.
**
** SRT_DistQueue Store results in priority queue pDest->iSDParm only if
** the same record has never been stored before. The
** index at pDest->iSDParm+1 hold all prior stores.
*/
#define SRT_Union 1 /* Store result as keys in an index */
#define SRT_Except 2 /* Remove result from a UNION index */
#define SRT_Exists 3 /* Store 1 if the result is not empty */
#define SRT_Discard 4 /* Do not save the results anywhere */
#define SRT_Fifo 5 /* Store result as data with an automatic rowid */
#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
#define SRT_Queue 7 /* Store result in an queue */
#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
/* The ORDER BY clause is ignored for all of the above */
#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
#define SRT_Output 9 /* Output each row of result */
#define SRT_Mem 10 /* Store result in a memory cell */
#define SRT_Set 11 /* Store results as keys in an index */
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
#define SRT_Coroutine 13 /* Generate a single row of result */
#define SRT_Table 14 /* Store result as data with an automatic rowid */
/*
** An instance of this object describes where to put of the results of
** a SELECT statement.
*/
struct SelectDest {
u8 eDest; /* How to dispose of the results. On of SRT_* above. */
|
| ︙ | ︙ | |||
11758 11759 11760 11761 11762 11763 11764 | char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ | < < | 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 | char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ int aTempReg[8]; /* Holding area for temporary registers */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ |
| ︙ | ︙ | |||
12385 12386 12387 12388 12389 12390 12391 | SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*); SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*); SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); | | | 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 | SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*); SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*); SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64); SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*); SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); #else |
| ︙ | ︙ | |||
12449 12450 12451 12452 12453 12454 12455 | SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); | | | 12472 12473 12474 12475 12476 12477 12478 12479 12480 12481 12482 12483 12484 12485 12486 | SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*); SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*); SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); |
| ︙ | ︙ | |||
12501 12502 12503 12504 12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 |
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
u8,u8,int,int*);
SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
| > | 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 |
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int);
SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
u8,u8,int,int*);
SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
|
| ︙ | ︙ | |||
12658 12659 12660 12661 12662 12663 12664 | #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); | | | 12682 12683 12684 12685 12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696 | #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*); 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); SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); |
| ︙ | ︙ | |||
13743 13744 13745 13746 13747 13748 13749 13750 13751 13752 13753 13754 13755 13756 | int pseudoTableReg; /* Register holding pseudotable content. */ i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Rowid being deleted by OP_Delete */ | > | 13767 13768 13769 13770 13771 13772 13773 13774 13775 13776 13777 13778 13779 13780 13781 | int pseudoTableReg; /* Register holding pseudotable content. */ i16 nField; /* Number of fields in the header */ u16 nHdrParsed; /* Number of header fields parsed so far */ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 rowidIsValid; /* True if lastRowid is valid */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Rowid being deleted by OP_Delete */ |
| ︙ | ︙ | |||
14062 14063 14064 14065 14066 14067 14068 | SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int); SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); | | | 14087 14088 14089 14090 14091 14092 14093 14094 14095 14096 14097 14098 14099 14100 14101 | SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int); SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *); SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int); SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*); |
| ︙ | ︙ | |||
14108 14109 14110 14111 14112 14113 14114 14115 14116 14117 14118 14119 14120 14121 | SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); | > | 14133 14134 14135 14136 14137 14138 14139 14140 14141 14142 14143 14144 14145 14146 14147 | SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); |
| ︙ | ︙ | |||
17847 17848 17849 17850 17851 17852 17853 |
/* Round nByte up to the next valid power of two */
for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
** block. If not, then split a block of the next larger power of
** two in order to create a new free block of size iLogsize.
*/
| | | 17873 17874 17875 17876 17877 17878 17879 17880 17881 17882 17883 17884 17885 17886 17887 |
/* Round nByte up to the next valid power of two */
for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
** block. If not, then split a block of the next larger power of
** two in order to create a new free block of size iLogsize.
*/
for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){}
if( iBin>LOGMAX ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
return 0;
}
i = mem5.aiFreelist[iBin];
memsys5Unlink(i, iBin);
|
| ︙ | ︙ | |||
20157 20158 20159 20160 20161 20162 20163 | d = digit; digit += '0'; *val = (*val - d)*10.0; return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ | < < < < < < < < < < < < < < | 20183 20184 20185 20186 20187 20188 20189 20190 20191 20192 20193 20194 20195 20196 |
d = digit;
digit += '0';
*val = (*val - d)*10.0;
return (char)digit;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** Set the StrAccum object to an error mode.
*/
static void setStrAccumError(StrAccum *p, u8 eError){
p->accError = eError;
p->nAlloc = 0;
}
|
| ︙ | ︙ | |||
20260 20261 20262 20263 20264 20265 20266 |
}
useIntern = bFlags & SQLITE_PRINTF_INTERNAL;
}else{
bArgList = useIntern = 0;
}
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
| < < | | | 20272 20273 20274 20275 20276 20277 20278 20279 20280 20281 20282 20283 20284 20285 20286 20287 20288 |
}
useIntern = bFlags & SQLITE_PRINTF_INTERNAL;
}else{
bArgList = useIntern = 0;
}
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
bufpt = (char *)fmt;
while( (c=(*++fmt))!='%' && c!=0 ){};
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
if( c==0 ) break;
}
if( (c=(*++fmt))==0 ){
sqlite3StrAccumAppend(pAccum, "%", 1);
break;
}
/* Find out what flags are present */
|
| ︙ | ︙ | |||
20445 20446 20447 20448 20449 20450 20451 |
if( x>=4 || (longvalue/10)%10==1 ){
x = 0;
}
*(--bufpt) = zOrd[x*2+1];
*(--bufpt) = zOrd[x*2];
}
{
| < < | | | 20455 20456 20457 20458 20459 20460 20461 20462 20463 20464 20465 20466 20467 20468 20469 20470 |
if( x>=4 || (longvalue/10)%10==1 ){
x = 0;
}
*(--bufpt) = zOrd[x*2+1];
*(--bufpt) = zOrd[x*2];
}
{
const char *cset = &aDigits[infop->charset];
u8 base = infop->base;
do{ /* Convert to ascii */
*(--bufpt) = cset[longvalue%base];
longvalue = longvalue/base;
}while( longvalue>0 );
}
length = (int)(&zOut[nOut-1]-bufpt);
for(idx=precision-length; idx>0; idx--){
|
| ︙ | ︙ | |||
20752 20753 20754 20755 20756 20757 20758 |
}
}/* End switch over the format type */
/*
** The text of the conversion is pointed to by "bufpt" and is
** "length" characters long. The field width is "width". Do
** the output.
*/
| < < | < | < < < | < < < < < | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 20760 20761 20762 20763 20764 20765 20766 20767 20768 20769 20770 20771 20772 20773 20774 20775 20776 20777 20778 20779 20780 20781 20782 20783 20784 20785 20786 20787 20788 20789 20790 20791 20792 20793 20794 20795 20796 20797 20798 20799 20800 20801 20802 20803 20804 20805 20806 20807 20808 20809 20810 20811 20812 20813 20814 20815 20816 20817 20818 20819 20820 20821 20822 20823 20824 20825 20826 20827 20828 20829 20830 20831 20832 20833 20834 20835 20836 20837 20838 20839 20840 20841 20842 20843 20844 20845 20846 20847 20848 20849 20850 20851 20852 20853 20854 20855 20856 20857 20858 20859 20860 20861 20862 20863 20864 20865 |
}
}/* End switch over the format type */
/*
** The text of the conversion is pointed to by "bufpt" and is
** "length" characters long. The field width is "width". Do
** the output.
*/
width -= length;
if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
sqlite3StrAccumAppend(pAccum, bufpt, length);
if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
if( zExtra ) sqlite3_free(zExtra);
}/* End for loop over the format string */
} /* End of function */
/*
** Enlarge the memory allocation on a StrAccum object so that it is
** able to accept at least N more bytes of text.
**
** Return the number of bytes of text that StrAccum is able to accept
** after the attempted enlargement. The value returned might be zero.
*/
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
return 0;
}
if( !p->useMalloc ){
N = p->nAlloc - p->nChar - 1;
setStrAccumError(p, STRACCUM_TOOBIG);
return N;
}else{
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
szNew += N + 1;
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_TOOBIG);
return 0;
}else{
p->nAlloc = (int)szNew;
}
if( p->useMalloc==1 ){
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
zNew = sqlite3_realloc(zOld, p->nAlloc);
}
if( zNew ){
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
return 0;
}
}
return N;
}
/*
** Append N space characters to the given string buffer.
*/
SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){
if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
while( (N--)>0 ) p->zText[p->nChar++] = ' ';
}
/*
** The StrAccum "p" is not large enough to accept N new bytes of z[].
** So enlarge if first, then do the append.
**
** This is a helper routine to sqlite3StrAccumAppend() that does special-case
** work (enlarging the buffer) using tail recursion, so that the
** sqlite3StrAccumAppend() routine can use fast calling semantics.
*/
static void enlargeAndAppend(StrAccum *p, const char *z, int N){
N = sqlite3StrAccumEnlarge(p, N);
if( N>0 ){
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
}
/*
** Append N bytes of text from z to the StrAccum object. Increase the
** size of the memory allocation for StrAccum if necessary.
*/
SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( z!=0 );
assert( p->zText!=0 || p->nChar==0 || p->accError );
assert( N>=0 );
assert( p->accError==0 || p->nAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
enlargeAndAppend(p,z,N);
return;
}
assert( p->zText );
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
/*
|
| ︙ | ︙ | |||
23326 23327 23328 23329 23330 23331 23332 |
/* 7 */ "NextIfOpen" OpHelp(""),
/* 8 */ "Prev" OpHelp(""),
/* 9 */ "Next" OpHelp(""),
/* 10 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
/* 11 */ "Checkpoint" OpHelp(""),
/* 12 */ "JournalMode" OpHelp(""),
/* 13 */ "Vacuum" OpHelp(""),
| | | 23359 23360 23361 23362 23363 23364 23365 23366 23367 23368 23369 23370 23371 23372 23373 |
/* 7 */ "NextIfOpen" OpHelp(""),
/* 8 */ "Prev" OpHelp(""),
/* 9 */ "Next" OpHelp(""),
/* 10 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
/* 11 */ "Checkpoint" OpHelp(""),
/* 12 */ "JournalMode" OpHelp(""),
/* 13 */ "Vacuum" OpHelp(""),
/* 14 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
/* 15 */ "VUpdate" OpHelp("data=r[P3@P2]"),
/* 16 */ "Goto" OpHelp(""),
/* 17 */ "Gosub" OpHelp(""),
/* 18 */ "Return" OpHelp(""),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
/* 20 */ "InitCoroutine" OpHelp(""),
/* 21 */ "EndCoroutine" OpHelp(""),
|
| ︙ | ︙ | |||
23353 23354 23355 23356 23357 23358 23359 |
/* 34 */ "SCopy" OpHelp("r[P2]=r[P1]"),
/* 35 */ "ResultRow" OpHelp("output=r[P1@P2]"),
/* 36 */ "CollSeq" OpHelp(""),
/* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
/* 38 */ "MustBeInt" OpHelp(""),
/* 39 */ "RealAffinity" OpHelp(""),
/* 40 */ "Permutation" OpHelp(""),
| | | 23386 23387 23388 23389 23390 23391 23392 23393 23394 23395 23396 23397 23398 23399 23400 |
/* 34 */ "SCopy" OpHelp("r[P2]=r[P1]"),
/* 35 */ "ResultRow" OpHelp("output=r[P1@P2]"),
/* 36 */ "CollSeq" OpHelp(""),
/* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
/* 38 */ "MustBeInt" OpHelp(""),
/* 39 */ "RealAffinity" OpHelp(""),
/* 40 */ "Permutation" OpHelp(""),
/* 41 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
/* 42 */ "Jump" OpHelp(""),
/* 43 */ "Once" OpHelp(""),
/* 44 */ "If" OpHelp(""),
/* 45 */ "IfNot" OpHelp(""),
/* 46 */ "Column" OpHelp("r[P3]=PX"),
/* 47 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
/* 48 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
|
| ︙ | ︙ | |||
23380 23381 23382 23383 23384 23385 23386 |
/* 61 */ "SeekGE" OpHelp(""),
/* 62 */ "SeekGT" OpHelp(""),
/* 63 */ "Seek" OpHelp("intkey=r[P2]"),
/* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"),
/* 65 */ "NotFound" OpHelp("key=r[P3@P4]"),
/* 66 */ "Found" OpHelp("key=r[P3@P4]"),
/* 67 */ "NotExists" OpHelp("intkey=r[P3]"),
| | | 23413 23414 23415 23416 23417 23418 23419 23420 23421 23422 23423 23424 23425 23426 23427 |
/* 61 */ "SeekGE" OpHelp(""),
/* 62 */ "SeekGT" OpHelp(""),
/* 63 */ "Seek" OpHelp("intkey=r[P2]"),
/* 64 */ "NoConflict" OpHelp("key=r[P3@P4]"),
/* 65 */ "NotFound" OpHelp("key=r[P3@P4]"),
/* 66 */ "Found" OpHelp("key=r[P3@P4]"),
/* 67 */ "NotExists" OpHelp("intkey=r[P3]"),
/* 68 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
/* 69 */ "NewRowid" OpHelp("r[P2]=rowid"),
/* 70 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
/* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
/* 73 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
/* 74 */ "Delete" OpHelp(""),
/* 75 */ "ResetCount" OpHelp(""),
|
| ︙ | ︙ | |||
23428 23429 23430 23431 23432 23433 23434 |
/* 109 */ "IdxRowid" OpHelp("r[P2]=rowid"),
/* 110 */ "IdxLE" OpHelp("key=r[P3@P4]"),
/* 111 */ "IdxGT" OpHelp("key=r[P3@P4]"),
/* 112 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 113 */ "IdxGE" OpHelp("key=r[P3@P4]"),
/* 114 */ "Destroy" OpHelp(""),
/* 115 */ "Clear" OpHelp(""),
| > | | | | | | | | | | | | | | | | < > | | | | | | | | < > | | | | | | | | | | 23461 23462 23463 23464 23465 23466 23467 23468 23469 23470 23471 23472 23473 23474 23475 23476 23477 23478 23479 23480 23481 23482 23483 23484 23485 23486 23487 23488 23489 23490 23491 23492 23493 23494 23495 23496 23497 23498 23499 23500 23501 23502 23503 23504 23505 23506 23507 23508 23509 23510 23511 23512 23513 23514 23515 23516 |
/* 109 */ "IdxRowid" OpHelp("r[P2]=rowid"),
/* 110 */ "IdxLE" OpHelp("key=r[P3@P4]"),
/* 111 */ "IdxGT" OpHelp("key=r[P3@P4]"),
/* 112 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 113 */ "IdxGE" OpHelp("key=r[P3@P4]"),
/* 114 */ "Destroy" OpHelp(""),
/* 115 */ "Clear" OpHelp(""),
/* 116 */ "ResetSorter" OpHelp(""),
/* 117 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
/* 118 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
/* 119 */ "ParseSchema" OpHelp(""),
/* 120 */ "LoadAnalysis" OpHelp(""),
/* 121 */ "DropTable" OpHelp(""),
/* 122 */ "DropIndex" OpHelp(""),
/* 123 */ "DropTrigger" OpHelp(""),
/* 124 */ "IntegrityCk" OpHelp(""),
/* 125 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
/* 126 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
/* 127 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
/* 128 */ "Program" OpHelp(""),
/* 129 */ "Param" OpHelp(""),
/* 130 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
/* 131 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 132 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
/* 133 */ "Real" OpHelp("r[P2]=P4"),
/* 134 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
/* 135 */ "IfNeg" OpHelp("if r[P1]<0 goto P2"),
/* 136 */ "IfZero" OpHelp("r[P1]+=P3, if r[P1]==0 goto P2"),
/* 137 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
/* 138 */ "IncrVacuum" OpHelp(""),
/* 139 */ "Expire" OpHelp(""),
/* 140 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
/* 141 */ "VBegin" OpHelp(""),
/* 142 */ "VCreate" OpHelp(""),
/* 143 */ "ToText" OpHelp(""),
/* 144 */ "ToBlob" OpHelp(""),
/* 145 */ "ToNumeric" OpHelp(""),
/* 146 */ "ToInt" OpHelp(""),
/* 147 */ "ToReal" OpHelp(""),
/* 148 */ "VDestroy" OpHelp(""),
/* 149 */ "VOpen" OpHelp(""),
/* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
/* 151 */ "VNext" OpHelp(""),
/* 152 */ "VRename" OpHelp(""),
/* 153 */ "Pagecount" OpHelp(""),
/* 154 */ "MaxPgcnt" OpHelp(""),
/* 155 */ "Init" OpHelp("Start at P2"),
/* 156 */ "Noop" OpHelp(""),
/* 157 */ "Explain" OpHelp(""),
};
return azName[i];
}
#endif
/************** End of opcodes.c *********************************************/
/************** Begin file os_unix.c *****************************************/
|
| ︙ | ︙ | |||
24008 24009 24010 24011 24012 24013 24014 24015 24016 24017 24018 24019 24020 24021 |
*/
static int posixFchown(int fd, uid_t uid, gid_t gid){
return geteuid() ? 0 : fchown(fd,uid,gid);
}
/* Forward reference */
static int openDirectory(const char*, int*);
/*
** Many system calls are accessed through pointer-to-functions so that
** they may be overridden at runtime to facilitate fault injection during
** testing and sandboxing. The following array holds the names and pointers
** to all overrideable system calls.
*/
| > | 24042 24043 24044 24045 24046 24047 24048 24049 24050 24051 24052 24053 24054 24055 24056 |
*/
static int posixFchown(int fd, uid_t uid, gid_t gid){
return geteuid() ? 0 : fchown(fd,uid,gid);
}
/* Forward reference */
static int openDirectory(const char*, int*);
static int unixGetpagesize(void);
/*
** Many system calls are accessed through pointer-to-functions so that
** they may be overridden at runtime to facilitate fault injection during
** testing and sandboxing. The following array holds the names and pointers
** to all overrideable system calls.
*/
|
| ︙ | ︙ | |||
24130 24131 24132 24133 24134 24135 24136 24137 24138 24139 24140 24141 24142 24143 |
#if HAVE_MREMAP
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
#else
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
#endif
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes. Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
| > > > | 24165 24166 24167 24168 24169 24170 24171 24172 24173 24174 24175 24176 24177 24178 24179 24180 24181 |
#if HAVE_MREMAP
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
#else
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
#endif
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes. Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
|
| ︙ | ︙ | |||
27790 27791 27792 27793 27794 27795 27796 27797 27798 27799 27800 27801 27802 27803 27804 27805 27806 27807 27808 27809 27810 |
pShmNode->sharedMask, pShmNode->exclMask));
}
#endif
return rc;
}
/*
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
**
** This is not a VFS shared-memory method; it is a utility function called
** by VFS shared-memory methods.
*/
static void unixShmPurge(unixFile *pFd){
unixShmNode *p = pFd->pInode->pShmNode;
assert( unixMutexHeld() );
if( p && p->nRef==0 ){
int i;
assert( p->pInode==pFd->pInode );
sqlite3_mutex_free(p->mutex);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 27828 27829 27830 27831 27832 27833 27834 27835 27836 27837 27838 27839 27840 27841 27842 27843 27844 27845 27846 27847 27848 27849 27850 27851 27852 27853 27854 27855 27856 27857 27858 27859 27860 27861 27862 27863 27864 27865 27866 27867 27868 27869 27870 27871 27872 27873 27874 27875 27876 27877 27878 27879 27880 27881 27882 27883 27884 27885 27886 27887 |
pShmNode->sharedMask, pShmNode->exclMask));
}
#endif
return rc;
}
/*
** Return the system page size.
**
** This function should not be called directly by other code in this file.
** Instead, it should be called via macro osGetpagesize().
*/
static int unixGetpagesize(void){
#if defined(_BSD_SOURCE)
return getpagesize();
#else
return (int)sysconf(_SC_PAGESIZE);
#endif
}
/*
** Return the minimum number of 32KB shm regions that should be mapped at
** a time, assuming that each mapping must be an integer multiple of the
** current system page-size.
**
** Usually, this is 1. The exception seems to be systems that are configured
** to use 64KB pages - in this case each mapping must cover at least two
** shm regions.
*/
static int unixShmRegionPerMap(void){
int shmsz = 32*1024; /* SHM region size */
int pgsz = osGetpagesize(); /* System page size */
assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */
if( pgsz<shmsz ) return 1;
return pgsz/shmsz;
}
/*
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
**
** This is not a VFS shared-memory method; it is a utility function called
** by VFS shared-memory methods.
*/
static void unixShmPurge(unixFile *pFd){
unixShmNode *p = pFd->pInode->pShmNode;
assert( unixMutexHeld() );
if( p && p->nRef==0 ){
int nShmPerMap = unixShmRegionPerMap();
int i;
assert( p->pInode==pFd->pInode );
sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i+=nShmPerMap){
if( p->h>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
}else{
sqlite3_free(p->apRegion[i]);
}
}
sqlite3_free(p->apRegion);
|
| ︙ | ︙ | |||
28011 28012 28013 28014 28015 28016 28017 28018 28019 28020 28021 28022 28023 28024 28025 28026 28027 28028 28029 28030 28031 28032 |
int bExtend, /* True to extend file if necessary */
void volatile **pp /* OUT: Mapped memory */
){
unixFile *pDbFd = (unixFile*)fd;
unixShm *p;
unixShmNode *pShmNode;
int rc = SQLITE_OK;
/* If the shared-memory file has not yet been opened, open it now. */
if( pDbFd->pShm==0 ){
rc = unixOpenSharedMemory(pDbFd);
if( rc!=SQLITE_OK ) return rc;
}
p = pDbFd->pShm;
pShmNode = p->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
assert( pShmNode->pInode==pDbFd->pInode );
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
| > > > > > | | | 28080 28081 28082 28083 28084 28085 28086 28087 28088 28089 28090 28091 28092 28093 28094 28095 28096 28097 28098 28099 28100 28101 28102 28103 28104 28105 28106 28107 28108 28109 28110 28111 28112 28113 28114 28115 28116 |
int bExtend, /* True to extend file if necessary */
void volatile **pp /* OUT: Mapped memory */
){
unixFile *pDbFd = (unixFile*)fd;
unixShm *p;
unixShmNode *pShmNode;
int rc = SQLITE_OK;
int nShmPerMap = unixShmRegionPerMap();
int nReqRegion;
/* If the shared-memory file has not yet been opened, open it now. */
if( pDbFd->pShm==0 ){
rc = unixOpenSharedMemory(pDbFd);
if( rc!=SQLITE_OK ) return rc;
}
p = pDbFd->pShm;
pShmNode = p->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
assert( pShmNode->pInode==pDbFd->pInode );
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
/* Minimum number of regions required to be mapped. */
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
if( pShmNode->nRegion<nReqRegion ){
char **apNew; /* New apRegion[] array */
int nByte = nReqRegion*szRegion; /* Minimum required file size */
struct stat sStat; /* Used by fstat() */
pShmNode->szRegion = szRegion;
if( pShmNode->h>=0 ){
/* The requested region is not mapped into this processes address space.
** Check to see if it has been allocated (i.e. if the wal-index file is
|
| ︙ | ︙ | |||
28077 28078 28079 28080 28081 28082 28083 |
}
}
}
}
/* Map the requested memory region into this processes address space. */
apNew = (char **)sqlite3_realloc(
| | | > > | > > | > | | 28151 28152 28153 28154 28155 28156 28157 28158 28159 28160 28161 28162 28163 28164 28165 28166 28167 28168 28169 28170 28171 28172 28173 28174 28175 28176 28177 28178 28179 28180 28181 28182 28183 28184 28185 28186 28187 28188 28189 28190 28191 28192 28193 28194 28195 28196 28197 |
}
}
}
}
/* Map the requested memory region into this processes address space. */
apNew = (char **)sqlite3_realloc(
pShmNode->apRegion, nReqRegion*sizeof(char *)
);
if( !apNew ){
rc = SQLITE_IOERR_NOMEM;
goto shmpage_out;
}
pShmNode->apRegion = apNew;
while( pShmNode->nRegion<nReqRegion ){
int nMap = szRegion*nShmPerMap;
int i;
void *pMem;
if( pShmNode->h>=0 ){
pMem = osMmap(0, nMap,
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
);
if( pMem==MAP_FAILED ){
rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
goto shmpage_out;
}
}else{
pMem = sqlite3_malloc(szRegion);
if( pMem==0 ){
rc = SQLITE_NOMEM;
goto shmpage_out;
}
memset(pMem, 0, szRegion);
}
for(i=0; i<nShmPerMap; i++){
pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
}
pShmNode->nRegion += nShmPerMap;
}
}
shmpage_out:
if( pShmNode->nRegion>iRegion ){
*pp = pShmNode->apRegion[iRegion];
}else{
|
| ︙ | ︙ | |||
28318 28319 28320 28321 28322 28323 28324 |
osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
pFd->pMapRegion = 0;
pFd->mmapSize = 0;
pFd->mmapSizeActual = 0;
}
}
| < < < < < < < < < < < < < | 28397 28398 28399 28400 28401 28402 28403 28404 28405 28406 28407 28408 28409 28410 |
osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
pFd->pMapRegion = 0;
pFd->mmapSize = 0;
pFd->mmapSizeActual = 0;
}
}
/*
** Attempt to set the size of the memory mapping maintained by file
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
**
** If successful, this function sets the following variables:
**
** unixFile.pMapRegion
|
| ︙ | ︙ | |||
28367 28368 28369 28370 28371 28372 28373 |
assert( nNew>0 );
assert( pFd->mmapSizeActual>=pFd->mmapSize );
assert( MAP_FAILED!=0 );
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
if( pOrig ){
| > > > | > | 28433 28434 28435 28436 28437 28438 28439 28440 28441 28442 28443 28444 28445 28446 28447 28448 28449 28450 28451 28452 |
assert( nNew>0 );
assert( pFd->mmapSizeActual>=pFd->mmapSize );
assert( MAP_FAILED!=0 );
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
if( pOrig ){
#if HAVE_MREMAP
i64 nReuse = pFd->mmapSize;
#else
const int szSyspage = osGetpagesize();
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
#endif
u8 *pReq = &pOrig[nReuse];
/* Unmap any pages of the existing mapping that cannot be reused. */
if( nReuse!=nOrig ){
osMunmap(pReq, nOrig-nReuse);
}
|
| ︙ | ︙ | |||
31114 31115 31116 31117 31118 31119 31120 |
UNIXVFS("unix-proxy", proxyIoFinder ),
#endif
};
unsigned int i; /* Loop counter */
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
| | | 31184 31185 31186 31187 31188 31189 31190 31191 31192 31193 31194 31195 31196 31197 31198 |
UNIXVFS("unix-proxy", proxyIoFinder ),
#endif
};
unsigned int i; /* Loop counter */
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==25 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
sqlite3_vfs_register(&aVfs[i], i==0);
}
return SQLITE_OK;
}
|
| ︙ | ︙ | |||
38995 38996 38997 38998 38999 39000 39001 | struct RowSetChunk *pChunk; /* List of all chunk allocations */ sqlite3 *db; /* The database connection */ struct RowSetEntry *pEntry; /* List of entries using pRight */ struct RowSetEntry *pLast; /* Last entry on the pEntry list */ struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pForest; /* List of binary trees of entries */ u16 nFresh; /* Number of objects on pFresh */ | | | | 39065 39066 39067 39068 39069 39070 39071 39072 39073 39074 39075 39076 39077 39078 39079 39080 | struct RowSetChunk *pChunk; /* List of all chunk allocations */ sqlite3 *db; /* The database connection */ struct RowSetEntry *pEntry; /* List of entries using pRight */ struct RowSetEntry *pLast; /* Last entry on the pEntry list */ struct RowSetEntry *pFresh; /* Source of new entry objects */ struct RowSetEntry *pForest; /* List of binary trees of entries */ u16 nFresh; /* Number of objects on pFresh */ u16 rsFlags; /* Various flags */ int iBatch; /* Current insert batch */ }; /* ** Allowed values for RowSet.rsFlags */ #define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */ #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ |
| ︙ | ︙ | |||
39330 39331 39332 39333 39334 39335 39336 | ** Check to see if element iRowid was inserted into the rowset as ** part of any insert batch prior to iBatch. Return 1 or 0. ** ** If this is the first test of a new batch and if there exist entires ** on pRowSet->pEntry, then sort those entires into the forest at ** pRowSet->pForest so that they can be tested. */ | | | 39400 39401 39402 39403 39404 39405 39406 39407 39408 39409 39410 39411 39412 39413 39414 |
** Check to see if element iRowid was inserted into the rowset as
** part of any insert batch prior to iBatch. Return 1 or 0.
**
** If this is the first test of a new batch and if there exist entires
** on pRowSet->pEntry, then sort those entires into the forest at
** pRowSet->pForest so that they can be tested.
*/
SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
struct RowSetEntry *p, *pTree;
/* This routine is never called after sqlite3RowSetNext() */
assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
/* Sort entries into the forest on the first test of a new batch
*/
|
| ︙ | ︙ | |||
41157 41158 41159 41160 41161 41162 41163 | u32 cksum = 0; /* Checksum of string zMaster */ assert( pPager->setMaster==0 ); assert( !pagerUseWal(pPager) ); if( !zMaster || pPager->journalMode==PAGER_JOURNALMODE_MEMORY | | < | 41227 41228 41229 41230 41231 41232 41233 41234 41235 41236 41237 41238 41239 41240 41241 41242 41243 41244 41245 |
u32 cksum = 0; /* Checksum of string zMaster */
assert( pPager->setMaster==0 );
assert( !pagerUseWal(pPager) );
if( !zMaster
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| !isOpen(pPager->jfd)
){
return SQLITE_OK;
}
pPager->setMaster = 1;
assert( pPager->journalHdr <= pPager->journalOff );
/* Calculate the length in bytes and the checksum of zMaster */
for(nMaster=0; zMaster[nMaster]; nMaster++){
cksum += zMaster[nMaster];
}
|
| ︙ | ︙ | |||
50369 50370 50371 50372 50373 50374 50375 |
** found at self->pBt->mutex.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
| < < < | | > > | < < < < < > > > > > > > > > | 50438 50439 50440 50441 50442 50443 50444 50445 50446 50447 50448 50449 50450 50451 50452 50453 50454 50455 50456 50457 50458 50459 50460 50461 50462 50463 50464 50465 50466 50467 50468 50469 50470 50471 50472 50473 50474 50475 |
** found at self->pBt->mutex.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
Pgno *aOverflow; /* Cache of overflow page locations */
CellInfo info; /* A parse of the cell we are pointing at */
i64 nKey; /* Size of pKey, or last integer key */
void *pKey; /* Saved key that was cursor last known position */
Pgno pgnoRoot; /* The root page of this tree */
int nOvflAlloc; /* Allocated size of aOverflow[] array */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
u8 curFlags; /* zero or more BTCF_* flags defined below */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
u8 hints; /* As configured by CursorSetHints() */
i16 iPage; /* Index of current page in apPage */
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
};
/*
** Legal values for BtCursor.curFlags
*/
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
/*
** Potential values for BtCursor.eState.
**
** CURSOR_INVALID:
** Cursor does not point to a valid entry. This can happen (for example)
** because the table is empty or because BtreeCursorFirst() has not been
** called.
|
| ︙ | ︙ | |||
51260 51261 51262 51263 51264 51265 51266 |
*/
#ifdef SQLITE_DEBUG
static int cursorHoldsMutex(BtCursor *p){
return sqlite3_mutex_held(p->pBt->mutex);
}
#endif
| < < | > | < < < < > | 51332 51333 51334 51335 51336 51337 51338 51339 51340 51341 51342 51343 51344 51345 51346 51347 51348 51349 51350 51351 51352 51353 51354 51355 51356 51357 51358 51359 51360 51361 51362 51363 51364 |
*/
#ifdef SQLITE_DEBUG
static int cursorHoldsMutex(BtCursor *p){
return sqlite3_mutex_held(p->pBt->mutex);
}
#endif
/*
** Invalidate the overflow cache of the cursor passed as the first argument.
** on the shared btree structure pBt.
*/
#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
/*
** Invalidate the overflow page-list cache for all cursors opened
** on the shared btree structure pBt.
*/
static void invalidateAllOverflowCache(BtShared *pBt){
BtCursor *p;
assert( sqlite3_mutex_held(pBt->mutex) );
for(p=pBt->pCursor; p; p=p->pNext){
invalidateOverflowCache(p);
}
}
#ifndef SQLITE_OMIT_INCRBLOB
/*
** This function is called before modifying the contents of a table
** to invalidate any incrblob cursors that are open on the
** row or one of the rows being modified.
**
** If argument isClearTable is true, then the entire contents of the
** table is about to be deleted. In this case invalidate all incrblob
|
| ︙ | ︙ | |||
51305 51306 51307 51308 51309 51310 51311 |
i64 iRow, /* The rowid that might be changing */
int isClearTable /* True if all rows are being deleted */
){
BtCursor *p;
BtShared *pBt = pBtree->pBt;
assert( sqlite3BtreeHoldsMutex(pBtree) );
for(p=pBt->pCursor; p; p=p->pNext){
| | | < < | 51373 51374 51375 51376 51377 51378 51379 51380 51381 51382 51383 51384 51385 51386 51387 51388 51389 51390 51391 51392 51393 51394 |
i64 iRow, /* The rowid that might be changing */
int isClearTable /* True if all rows are being deleted */
){
BtCursor *p;
BtShared *pBt = pBtree->pBt;
assert( sqlite3BtreeHoldsMutex(pBtree) );
for(p=pBt->pCursor; p; p=p->pNext){
if( (p->curFlags & BTCF_Incrblob)!=0 && (isClearTable || p->info.nKey==iRow) ){
p->eState = CURSOR_INVALID;
}
}
}
#else
/* Stub function when INCRBLOB is omitted */
#define invalidateIncrblobCursors(x,y,z)
#endif /* SQLITE_OMIT_INCRBLOB */
/*
** Set bit pgno of the BtShared.pHasContent bitvec. This is called
** when a page that previously contained data becomes a free-list leaf
** page.
|
| ︙ | ︙ | |||
51560 51561 51562 51563 51564 51565 51566 | /* ** Determine whether or not a cursor has moved from the position it ** was last placed at. Cursors can move when the row they are pointing ** at is deleted out from under them. ** ** This routine returns an error code if something goes wrong. The | | > > > > > > > > > > > > | | | | 51626 51627 51628 51629 51630 51631 51632 51633 51634 51635 51636 51637 51638 51639 51640 51641 51642 51643 51644 51645 51646 51647 51648 51649 51650 51651 51652 51653 51654 51655 51656 51657 51658 51659 51660 51661 51662 51663 51664 51665 |
/*
** Determine whether or not a cursor has moved from the position it
** was last placed at. Cursors can move when the row they are pointing
** at is deleted out from under them.
**
** This routine returns an error code if something goes wrong. The
** integer *pHasMoved is set as follows:
**
** 0: The cursor is unchanged
** 1: The cursor is still pointing at the same row, but the pointers
** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
** might now be invalid because of a balance() or other change to the
** b-tree.
** 2: The cursor is no longer pointing to the row. The row might have
** been deleted out from under the cursor.
*/
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
int rc;
if( pCur->eState==CURSOR_VALID ){
*pHasMoved = 0;
return SQLITE_OK;
}
rc = restoreCursorPosition(pCur);
if( rc ){
*pHasMoved = 2;
return rc;
}
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
*pHasMoved = 2;
}else{
*pHasMoved = 1;
}
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Given a page number of a regular database page, return the page
|
| ︙ | ︙ | |||
52975 52976 52977 52978 52979 52980 52981 52982 52983 52984 52985 52986 52987 52988 52989 52990 52991 52992 52993 52994 52995 52996 52997 52998 52999 53000 |
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
sqlite3PagerSetCachesize(pBt->pPager, mxPage);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
/*
** Change the limit on the amount of the database file that may be
** memory mapped.
*/
SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
/*
** Change the way data is synced to disk in order to increase or decrease
** how well the database resists damage due to OS crashes and power
** failures. Level 1 is the same as asynchronous (no syncs() occur and
** there is a high probability of damage) Level 2 is the default. There
** is a very low but non-zero probability of damage. Level 3 reduces the
| > > | 53053 53054 53055 53056 53057 53058 53059 53060 53061 53062 53063 53064 53065 53066 53067 53068 53069 53070 53071 53072 53073 53074 53075 53076 53077 53078 53079 53080 |
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
sqlite3PagerSetCachesize(pBt->pPager, mxPage);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
#if SQLITE_MAX_MMAP_SIZE>0
/*
** Change the limit on the amount of the database file that may be
** memory mapped.
*/
SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
/*
** Change the way data is synced to disk in order to increase or decrease
** how well the database resists damage due to OS crashes and power
** failures. Level 1 is the same as asynchronous (no syncs() occur and
** there is a high probability of damage) Level 2 is the default. There
** is a very low but non-zero probability of damage. Level 3 reduces the
|
| ︙ | ︙ | |||
53363 53364 53365 53366 53367 53368 53369 |
** is capable of reading or writing to the databse. Cursors that
** have been tripped into the CURSOR_FAULT state are not counted.
*/
static int countValidCursors(BtShared *pBt, int wrOnly){
BtCursor *pCur;
int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
| > | | 53443 53444 53445 53446 53447 53448 53449 53450 53451 53452 53453 53454 53455 53456 53457 53458 |
** is capable of reading or writing to the databse. Cursors that
** have been tripped into the CURSOR_FAULT state are not counted.
*/
static int countValidCursors(BtShared *pBt, int wrOnly){
BtCursor *pCur;
int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
&& pCur->eState!=CURSOR_FAULT ) r++;
}
return r;
}
#endif
/*
** If there are no outstanding cursors and we are not in the middle
|
| ︙ | ︙ | |||
54438 54439 54440 54441 54442 54443 54444 | /* Now that no other errors can occur, finish filling in the BtCursor ** variables and link the cursor into the BtShared list. */ pCur->pgnoRoot = (Pgno)iTable; pCur->iPage = -1; pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; | > | | 54519 54520 54521 54522 54523 54524 54525 54526 54527 54528 54529 54530 54531 54532 54533 54534 |
/* Now that no other errors can occur, finish filling in the BtCursor
** variables and link the cursor into the BtShared list. */
pCur->pgnoRoot = (Pgno)iTable;
pCur->iPage = -1;
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
pCur->pBt = pBt;
assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
pCur->curFlags = wrFlag;
pCur->pNext = pBt->pCursor;
if( pCur->pNext ){
pCur->pNext->pPrev = pCur;
}
pBt->pCursor = pCur;
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
|
| ︙ | ︙ | |||
54508 54509 54510 54511 54512 54513 54514 |
if( pCur->pNext ){
pCur->pNext->pPrev = pCur->pPrev;
}
for(i=0; i<=pCur->iPage; i++){
releasePage(pCur->apPage[i]);
}
unlockBtreeIfUnused(pBt);
| | | 54590 54591 54592 54593 54594 54595 54596 54597 54598 54599 54600 54601 54602 54603 54604 |
if( pCur->pNext ){
pCur->pNext->pPrev = pCur->pPrev;
}
for(i=0; i<=pCur->iPage; i++){
releasePage(pCur->apPage[i]);
}
unlockBtreeIfUnused(pBt);
sqlite3DbFree(pBtree->db, pCur->aOverflow);
/* sqlite3_free(pCur); */
sqlite3BtreeLeave(pBtree);
}
return SQLITE_OK;
}
/*
|
| ︙ | ︙ | |||
54547 54548 54549 54550 54551 54552 54553 |
#endif
#ifdef _MSC_VER
/* Use a real function in MSVC to work around bugs in that compiler. */
static void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
int iPage = pCur->iPage;
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
| | | | | 54629 54630 54631 54632 54633 54634 54635 54636 54637 54638 54639 54640 54641 54642 54643 54644 54645 54646 54647 54648 54649 54650 54651 54652 54653 54654 |
#endif
#ifdef _MSC_VER
/* Use a real function in MSVC to work around bugs in that compiler. */
static void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
int iPage = pCur->iPage;
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
pCur->curFlags |= BTCF_ValidNKey;
}else{
assertCellInfo(pCur);
}
}
#else /* if not _MSC_VER */
/* Use a macro in all other compilers so that the function is inlined */
#define getCellInfo(pCur) \
if( pCur->info.nSize==0 ){ \
int iPage = pCur->iPage; \
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
pCur->curFlags |= BTCF_ValidNKey; \
}else{ \
assertCellInfo(pCur); \
}
#endif /* _MSC_VER */
#ifndef NDEBUG /* The next routine used only within assert() statements */
/*
|
| ︙ | ︙ | |||
54729 54730 54731 54732 54733 54734 54735 |
memcpy(pBuf, pPayload, nByte);
}
return SQLITE_OK;
}
/*
** This function is used to read or overwrite payload information
| | < | | > > > < | > | | | | 54811 54812 54813 54814 54815 54816 54817 54818 54819 54820 54821 54822 54823 54824 54825 54826 54827 54828 54829 54830 54831 54832 54833 54834 54835 54836 54837 54838 54839 54840 54841 54842 |
memcpy(pBuf, pPayload, nByte);
}
return SQLITE_OK;
}
/*
** This function is used to read or overwrite payload information
** for the entry that the pCur cursor is pointing to. The eOp
** argument is interpreted as follows:
**
** 0: The operation is a read. Populate the overflow cache.
** 1: The operation is a write. Populate the overflow cache.
** 2: The operation is a read. Do not populate the overflow cache.
**
** A total of "amt" bytes are read or written beginning at "offset".
** Data is read to or from the buffer pBuf.
**
** The content being read or written might appear on the main page
** or be scattered out on multiple overflow pages.
**
** If the current cursor entry uses one or more overflow pages and the
** eOp argument is not 2, this function may allocate space for and lazily
** popluates the overflow page-list cache array (BtCursor.aOverflow).
** Subsequent calls use this cache to make seeking to the supplied offset
** more efficient.
**
** Once an overflow page-list cache has been allocated, it may be
** invalidated if some other cursor writes to the same table, or if
** the cursor is moved to a different row. Additionally, in auto-vacuum
** mode, the following events may invalidate an overflow page-list cache.
**
** * An incremental vacuum,
|
| ︙ | ︙ | |||
54768 54769 54770 54771 54772 54773 54774 54775 54776 54777 54778 54779 54780 54781 54782 54783 54784 54785 54786 54787 54788 54789 54790 54791 54792 54793 54794 54795 54796 54797 |
){
unsigned char *aPayload;
int rc = SQLITE_OK;
u32 nKey;
int iIdx = 0;
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
assert( pPage );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
assert( cursorHoldsMutex(pCur) );
getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader;
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
if( NEVER(offset+amt > nKey+pCur->info.nData)
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
){
/* Trying to read or write past the end of the data is an error */
return SQLITE_CORRUPT_BKPT;
}
/* Check if data must be read/written to/from the btree page itself. */
if( offset<pCur->info.nLocal ){
int a = amt;
if( a+offset>pCur->info.nLocal ){
a = pCur->info.nLocal - offset;
}
| > > > > > > > | < < | > > | | | | | > | | < > | | > > > > > > > > | < < | < > > > < > > | | < > | 54852 54853 54854 54855 54856 54857 54858 54859 54860 54861 54862 54863 54864 54865 54866 54867 54868 54869 54870 54871 54872 54873 54874 54875 54876 54877 54878 54879 54880 54881 54882 54883 54884 54885 54886 54887 54888 54889 54890 54891 54892 54893 54894 54895 54896 54897 54898 54899 54900 54901 54902 54903 54904 54905 54906 54907 54908 54909 54910 54911 54912 54913 54914 54915 54916 54917 54918 54919 54920 54921 54922 54923 54924 54925 54926 54927 54928 54929 54930 54931 54932 54933 54934 54935 54936 54937 54938 54939 54940 54941 54942 54943 54944 54945 54946 54947 54948 54949 54950 54951 54952 54953 54954 54955 54956 54957 54958 54959 54960 54961 54962 54963 54964 54965 54966 54967 54968 54969 54970 54971 |
){
unsigned char *aPayload;
int rc = SQLITE_OK;
u32 nKey;
int iIdx = 0;
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
int bEnd; /* True if reading to end of data */
#endif
assert( pPage );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
assert( cursorHoldsMutex(pCur) );
assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader;
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
#ifdef SQLITE_DIRECT_OVERFLOW_READ
bEnd = (offset+amt==nKey+pCur->info.nData);
#endif
if( NEVER(offset+amt > nKey+pCur->info.nData)
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
){
/* Trying to read or write past the end of the data is an error */
return SQLITE_CORRUPT_BKPT;
}
/* Check if data must be read/written to/from the btree page itself. */
if( offset<pCur->info.nLocal ){
int a = amt;
if( a+offset>pCur->info.nLocal ){
a = pCur->info.nLocal - offset;
}
rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
offset = 0;
pBuf += a;
amt -= a;
}else{
offset -= pCur->info.nLocal;
}
if( rc==SQLITE_OK && amt>0 ){
const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */
Pgno nextPage;
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
/* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
** Except, do not allocate aOverflow[] for eOp==2.
**
** The aOverflow[] array is sized at one entry for each overflow page
** in the overflow chain. The page number of the first overflow page is
** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
** means "not yet known" (the cache is lazily populated).
*/
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
if( nOvfl>pCur->nOvflAlloc ){
Pgno *aNew = (Pgno*)sqlite3DbRealloc(
pCur->pBtree->db, pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
rc = SQLITE_NOMEM;
}else{
pCur->nOvflAlloc = nOvfl*2;
pCur->aOverflow = aNew;
}
}
if( rc==SQLITE_OK ){
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
pCur->curFlags |= BTCF_ValidOvfl;
}
}
/* If the overflow page-list cache has been allocated and the
** entry for the first required overflow page is valid, skip
** directly to it.
*/
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 && pCur->aOverflow[offset/ovflSize] ){
iIdx = (offset/ovflSize);
nextPage = pCur->aOverflow[iIdx];
offset = (offset%ovflSize);
}
for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
/* If required, populate the overflow page-list cache. */
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
pCur->aOverflow[iIdx] = nextPage;
}
if( offset>=ovflSize ){
/* The only reason to read this page is to obtain the page
** number for the next page in the overflow chain. The page
** data is not required. So first try to lookup the overflow
** page-list cache, if any, then fall back to the getOverflowPage()
** function.
**
** Note that the aOverflow[] array must be allocated because eOp!=2
** here. If eOp==2, then offset==0 and this branch is never taken.
*/
assert( eOp!=2 );
assert( pCur->curFlags & BTCF_ValidOvfl );
if( pCur->aOverflow[iIdx+1] ){
nextPage = pCur->aOverflow[iIdx+1];
}else{
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
}
offset -= ovflSize;
}else{
/* Need to read this page properly. It contains some of the
** range of data that is being read (eOp==0) or written (eOp!=0).
*/
#ifdef SQLITE_DIRECT_OVERFLOW_READ
sqlite3_file *fd;
|
| ︙ | ︙ | |||
54878 54879 54880 54881 54882 54883 54884 54885 54886 54887 54888 54889 |
/* If all the following are true:
**
** 1) this is a read operation, and
** 2) data is required from the start of this overflow page, and
** 3) the database is file-backed, and
** 4) there is no open write-transaction, and
** 5) the database is not a WAL database,
**
** then data can be read directly from the database file into the
** output buffer, bypassing the page-cache altogether. This speeds
** up loading large records that span many overflow pages.
*/
| > | > | | | 54979 54980 54981 54982 54983 54984 54985 54986 54987 54988 54989 54990 54991 54992 54993 54994 54995 54996 54997 54998 54999 55000 55001 55002 55003 55004 55005 55006 55007 55008 55009 55010 55011 55012 55013 55014 55015 55016 55017 55018 55019 55020 55021 55022 55023 |
/* If all the following are true:
**
** 1) this is a read operation, and
** 2) data is required from the start of this overflow page, and
** 3) the database is file-backed, and
** 4) there is no open write-transaction, and
** 5) the database is not a WAL database,
** 6) all data from the page is being read.
**
** then data can be read directly from the database file into the
** output buffer, bypassing the page-cache altogether. This speeds
** up loading large records that span many overflow pages.
*/
if( (eOp&0x01)==0 /* (1) */
&& offset==0 /* (2) */
&& (bEnd || a==ovflSize) /* (6) */
&& pBt->inTransaction==TRANS_READ /* (4) */
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
&& pBt->pPage1->aData[19]==0x01 /* (5) */
){
u8 aSave[4];
u8 *aWrite = &pBuf[-4];
memcpy(aSave, aWrite, 4);
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
nextPage = get4byte(aWrite);
memcpy(aWrite, aSave, 4);
}else
#endif
{
DbPage *pDbPage;
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
);
if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload);
rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
sqlite3PagerUnref(pDbPage);
offset = 0;
}
}
amt -= a;
pBuf += a;
}
|
| ︙ | ︙ | |||
55000 55001 55002 55003 55004 55005 55006 55007 55008 55009 55010 55011 55012 55013 55014 55015 55016 55017 |
u32 *pAmt /* Write the number of available bytes here */
){
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
if( pCur->info.nSize==0 ){
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
&pCur->info);
}
*pAmt = pCur->info.nLocal;
return (void*)(pCur->info.pCell + pCur->info.nHeader);
}
/*
** For the entry that cursor pCur is point to, return as
| > > > | 55103 55104 55105 55106 55107 55108 55109 55110 55111 55112 55113 55114 55115 55116 55117 55118 55119 55120 55121 55122 55123 |
u32 *pAmt /* Write the number of available bytes here */
){
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->info.nSize>0 );
#if 0
if( pCur->info.nSize==0 ){
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
&pCur->info);
}
#endif
*pAmt = pCur->info.nLocal;
return (void*)(pCur->info.pCell + pCur->info.nHeader);
}
/*
** For the entry that cursor pCur is point to, return as
|
| ︙ | ︙ | |||
55054 55055 55056 55057 55058 55059 55060 |
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, newPgno, &pNewPage,
| | | | 55160 55161 55162 55163 55164 55165 55166 55167 55168 55169 55170 55171 55172 55173 55174 55175 55176 55177 55178 55179 55180 55181 |
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, newPgno, &pNewPage,
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc ) return rc;
pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0;
pCur->iPage++;
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
return SQLITE_CORRUPT_BKPT;
}
return SQLITE_OK;
}
#if 0
|
| ︙ | ︙ | |||
55119 55120 55121 55122 55123 55124 55125 | ); #endif testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); releasePage(pCur->apPage[pCur->iPage]); pCur->iPage--; pCur->info.nSize = 0; | | | 55225 55226 55227 55228 55229 55230 55231 55232 55233 55234 55235 55236 55237 55238 55239 | ); #endif testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); releasePage(pCur->apPage[pCur->iPage]); pCur->iPage--; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); } /* ** Move the cursor to point to the root page of its b-tree structure. ** ** If the table has a virtual root page, then the cursor is moved to point ** to the virtual root page instead of the actual root page. A table has a |
| ︙ | ︙ | |||
55166 55167 55168 55169 55170 55171 55172 |
if( pCur->iPage>=0 ){
while( pCur->iPage ) releasePage(pCur->apPage[pCur->iPage--]);
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
| | | 55272 55273 55274 55275 55276 55277 55278 55279 55280 55281 55282 55283 55284 55285 55286 |
if( pCur->iPage>=0 ){
while( pCur->iPage ) releasePage(pCur->apPage[pCur->iPage--]);
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
}
pCur->iPage = 0;
}
pRoot = pCur->apPage[0];
|
| ︙ | ︙ | |||
55193 55194 55195 55196 55197 55198 55199 |
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
return SQLITE_CORRUPT_BKPT;
}
pCur->aiIdx[0] = 0;
pCur->info.nSize = 0;
| | < | 55299 55300 55301 55302 55303 55304 55305 55306 55307 55308 55309 55310 55311 55312 55313 |
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
return SQLITE_CORRUPT_BKPT;
}
pCur->aiIdx[0] = 0;
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
Pgno subpage;
if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT;
subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
|
| ︙ | ︙ | |||
55257 55258 55259 55260 55261 55262 55263 |
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->aiIdx[pCur->iPage] = pPage->nCell;
rc = moveToChild(pCur, pgno);
}
if( rc==SQLITE_OK ){
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
pCur->info.nSize = 0;
| | | 55362 55363 55364 55365 55366 55367 55368 55369 55370 55371 55372 55373 55374 55375 55376 |
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->aiIdx[pCur->iPage] = pPage->nCell;
rc = moveToChild(pCur, pgno);
}
if( rc==SQLITE_OK ){
pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
pCur->info.nSize = 0;
pCur->curFlags &= ~BTCF_ValidNKey;
}
return rc;
}
/* Move the cursor to the first entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
|
| ︙ | ︙ | |||
55296 55297 55298 55299 55300 55301 55302 |
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor already points to the last entry, this is a no-op. */
| | | 55401 55402 55403 55404 55405 55406 55407 55408 55409 55410 55411 55412 55413 55414 55415 |
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor already points to the last entry, this is a no-op. */
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
#ifdef SQLITE_DEBUG
/* This block serves to assert() that the cursor really does point
** to the last entry in the b-tree. */
int ii;
for(ii=0; ii<pCur->iPage; ii++){
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
}
|
| ︙ | ︙ | |||
55319 55320 55321 55322 55323 55324 55325 |
if( CURSOR_INVALID==pCur->eState ){
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
*pRes = 1;
}else{
assert( pCur->eState==CURSOR_VALID );
*pRes = 0;
rc = moveToRightmost(pCur);
| | > > > > > | 55424 55425 55426 55427 55428 55429 55430 55431 55432 55433 55434 55435 55436 55437 55438 55439 55440 55441 55442 55443 |
if( CURSOR_INVALID==pCur->eState ){
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
*pRes = 1;
}else{
assert( pCur->eState==CURSOR_VALID );
*pRes = 0;
rc = moveToRightmost(pCur);
if( rc==SQLITE_OK ){
pCur->curFlags |= BTCF_AtLast;
}else{
pCur->curFlags &= ~BTCF_AtLast;
}
}
}
return rc;
}
/* Move the cursor so that it points to an entry near the key
** specified by pIdxKey or intKey. Return a success code.
|
| ︙ | ︙ | |||
55370 55371 55372 55373 55374 55375 55376 | assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ | | | > | 55480 55481 55482 55483 55484 55485 55486 55487 55488 55489 55490 55491 55492 55493 55494 55495 55496 55497 55498 55499 55500 55501 55502 55503 55504 55505 55506 55507 55508 55509 |
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( pRes );
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
/* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */
if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
&& pCur->apPage[0]->intKey
){
if( pCur->info.nKey==intKey ){
*pRes = 0;
return SQLITE_OK;
}
if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
*pRes = -1;
return SQLITE_OK;
}
}
if( pIdxKey ){
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
pIdxKey->isCorrupt = 0;
assert( pIdxKey->default_rc==1
|| pIdxKey->default_rc==0
|| pIdxKey->default_rc==-1
);
}else{
xRecordCompare = 0; /* All keys are integers */
}
|
| ︙ | ︙ | |||
55443 55444 55445 55446 55447 55448 55449 |
lwr = idx+1;
if( lwr>upr ){ c = -1; break; }
}else if( nCellKey>intKey ){
upr = idx-1;
if( lwr>upr ){ c = +1; break; }
}else{
assert( nCellKey==intKey );
| | | 55554 55555 55556 55557 55558 55559 55560 55561 55562 55563 55564 55565 55566 55567 55568 |
lwr = idx+1;
if( lwr>upr ){ c = -1; break; }
}else if( nCellKey>intKey ){
upr = idx-1;
if( lwr>upr ){ c = +1; break; }
}else{
assert( nCellKey==intKey );
pCur->curFlags |= BTCF_ValidNKey;
pCur->info.nKey = nCellKey;
pCur->aiIdx[pCur->iPage] = (u16)idx;
if( !pPage->leaf ){
lwr = idx;
goto moveto_next_layer;
}else{
*pRes = 0;
|
| ︙ | ︙ | |||
55500 55501 55502 55503 55504 55505 55506 |
nCell = (int)pCur->info.nKey;
pCellKey = sqlite3Malloc( nCell );
if( pCellKey==0 ){
rc = SQLITE_NOMEM;
goto moveto_finish;
}
pCur->aiIdx[pCur->iPage] = (u16)idx;
| | > > | 55611 55612 55613 55614 55615 55616 55617 55618 55619 55620 55621 55622 55623 55624 55625 55626 55627 55628 55629 55630 55631 55632 55633 55634 55635 55636 55637 55638 55639 55640 55641 55642 55643 |
nCell = (int)pCur->info.nKey;
pCellKey = sqlite3Malloc( nCell );
if( pCellKey==0 ){
rc = SQLITE_NOMEM;
goto moveto_finish;
}
pCur->aiIdx[pCur->iPage] = (u16)idx;
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
if( rc ){
sqlite3_free(pCellKey);
goto moveto_finish;
}
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
sqlite3_free(pCellKey);
}
assert( pIdxKey->isCorrupt==0 || c==0 );
if( c<0 ){
lwr = idx+1;
}else if( c>0 ){
upr = idx-1;
}else{
assert( c==0 );
*pRes = 0;
rc = SQLITE_OK;
pCur->aiIdx[pCur->iPage] = (u16)idx;
if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT;
goto moveto_finish;
}
if( lwr>upr ) break;
assert( lwr+upr>=0 );
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
}
}
|
| ︙ | ︙ | |||
55545 55546 55547 55548 55549 55550 55551 |
}
pCur->aiIdx[pCur->iPage] = (u16)lwr;
rc = moveToChild(pCur, chldPg);
if( rc ) break;
}
moveto_finish:
pCur->info.nSize = 0;
| | | 55658 55659 55660 55661 55662 55663 55664 55665 55666 55667 55668 55669 55670 55671 55672 |
}
pCur->aiIdx[pCur->iPage] = (u16)lwr;
rc = moveToChild(pCur, chldPg);
if( rc ) break;
}
moveto_finish:
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
return rc;
}
/*
** Return TRUE if the cursor is not pointing at an entry of the table.
**
|
| ︙ | ︙ | |||
55590 55591 55592 55593 55594 55595 55596 55597 55598 55599 55600 55601 55602 55603 |
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
if( pCur->eState!=CURSOR_VALID ){
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
*pRes = 0;
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
| > | 55703 55704 55705 55706 55707 55708 55709 55710 55711 55712 55713 55714 55715 55716 55717 |
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
if( pCur->eState!=CURSOR_VALID ){
invalidateOverflowCache(pCur);
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
*pRes = 0;
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
|
| ︙ | ︙ | |||
55623 55624 55625 55626 55627 55628 55629 | ** to be invalid here. This can only occur if a second cursor modifies ** the page while cursor pCur is holding a reference to it. Which can ** only happen if the database is corrupt in such a way as to link the ** page into more than one b-tree structure. */ testcase( idx>pPage->nCell ); pCur->info.nSize = 0; | | | 55737 55738 55739 55740 55741 55742 55743 55744 55745 55746 55747 55748 55749 55750 55751 |
** to be invalid here. This can only occur if a second cursor modifies
** the page while cursor pCur is holding a reference to it. Which can
** only happen if the database is corrupt in such a way as to link the
** page into more than one b-tree structure. */
testcase( idx>pPage->nCell );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
if( rc ){
*pRes = 0;
return rc;
}
|
| ︙ | ︙ | |||
55684 55685 55686 55687 55688 55689 55690 | int rc; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); assert( pRes!=0 ); assert( *pRes==0 || *pRes==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); | | | 55798 55799 55800 55801 55802 55803 55804 55805 55806 55807 55808 55809 55810 55811 55812 |
int rc;
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl);
if( pCur->eState!=CURSOR_VALID ){
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
rc = btreeRestoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
*pRes = 0;
return rc;
}
|
| ︙ | ︙ | |||
55729 55730 55731 55732 55733 55734 55735 |
pCur->eState = CURSOR_INVALID;
*pRes = 1;
return SQLITE_OK;
}
moveToParent(pCur);
}
pCur->info.nSize = 0;
| | | 55843 55844 55845 55846 55847 55848 55849 55850 55851 55852 55853 55854 55855 55856 55857 |
pCur->eState = CURSOR_INVALID;
*pRes = 1;
return SQLITE_OK;
}
moveToParent(pCur);
}
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->aiIdx[pCur->iPage]--;
pPage = pCur->apPage[pCur->iPage];
if( pPage->intKey && !pPage->leaf ){
rc = sqlite3BtreePrevious(pCur, pRes);
}else{
rc = SQLITE_OK;
|
| ︙ | ︙ | |||
57754 57755 57756 57757 57758 57759 57760 |
if( pCur->eState==CURSOR_FAULT ){
assert( pCur->skipNext!=SQLITE_OK );
return pCur->skipNext;
}
assert( cursorHoldsMutex(pCur) );
| | | 57868 57869 57870 57871 57872 57873 57874 57875 57876 57877 57878 57879 57880 57881 57882 |
if( pCur->eState==CURSOR_FAULT ){
assert( pCur->skipNext!=SQLITE_OK );
return pCur->skipNext;
}
assert( cursorHoldsMutex(pCur) );
assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
/* Assert that the caller has been consistent. If this cursor was opened
** expecting an index b-tree, then the caller should be inserting blob
** keys with no associated data. If the cursor was opened expecting an
** intkey table, the caller should be inserting integer keys with a
|
| ︙ | ︙ | |||
57787 57788 57789 57790 57791 57792 57793 |
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
invalidateIncrblobCursors(p, nKey, 0);
/* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
** call */
| | | 57901 57902 57903 57904 57905 57906 57907 57908 57909 57910 57911 57912 57913 57914 57915 |
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
invalidateIncrblobCursors(p, nKey, 0);
/* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
** call */
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 && pCur->info.nKey==nKey-1 ){
loc = -1;
}
}
if( !loc ){
rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
if( rc ) return rc;
|
| ︙ | ︙ | |||
57840 57841 57842 57843 57844 57845 57846 |
assert( pPage->leaf );
}
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
/* If no error has occurred and pPage has an overflow cell, call balance()
** to redistribute the cells within the tree. Since balance() may move
| | | | 57954 57955 57956 57957 57958 57959 57960 57961 57962 57963 57964 57965 57966 57967 57968 57969 57970 57971 57972 57973 57974 57975 57976 57977 57978 57979 57980 57981 57982 57983 57984 57985 57986 57987 57988 |
assert( pPage->leaf );
}
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
/* If no error has occurred and pPage has an overflow cell, call balance()
** to redistribute the cells within the tree. Since balance() may move
** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
** variables.
**
** Previous versions of SQLite called moveToRoot() to move the cursor
** back to the root page as balance() used to invalidate the contents
** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that,
** set the cursor state to "invalid". This makes common insert operations
** slightly faster.
**
** There is a subtle but important optimization here too. When inserting
** multiple records into an intkey b-tree using a single cursor (as can
** happen while processing an "INSERT INTO ... SELECT" statement), it
** is advantageous to leave the cursor pointing to the last entry in
** the b-tree if possible. If the cursor is left pointing to the last
** entry in the table, and the next row inserted has an integer key
** larger than the largest existing key, it is possible to insert the
** row without seeking the cursor. This can be a big performance boost.
*/
pCur->info.nSize = 0;
if( rc==SQLITE_OK && pPage->nOverflow ){
pCur->curFlags &= ~(BTCF_ValidNKey);
rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance()
** fails. Internal data structure corruption will result otherwise.
** Also, set the cursor state to invalid. This stops saveCursorPosition()
** from trying to save the current position of the cursor. */
pCur->apPage[pCur->iPage]->nOverflow = 0;
|
| ︙ | ︙ | |||
57892 57893 57894 57895 57896 57897 57898 | unsigned char *pCell; /* Pointer to cell to delete */ int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); | | | 58006 58007 58008 58009 58010 58011 58012 58013 58014 58015 58016 58017 58018 58019 58020 |
unsigned char *pCell; /* Pointer to cell to delete */
int iCellIdx; /* Index of cell to delete */
int iCellDepth; /* Depth of node containing pCell */
assert( cursorHoldsMutex(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
|| NEVER(pCur->eState!=CURSOR_VALID)
){
return SQLITE_ERROR; /* Something has gone awry. */
|
| ︙ | ︙ | |||
58236 58237 58238 58239 58240 58241 58242 58243 58244 58245 58246 58247 58248 58249 |
** a no-op). */
invalidateIncrblobCursors(p, 0, 1);
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
}
sqlite3BtreeLeave(p);
return rc;
}
/*
** Erase all information in a table and add the root of the table to
** the freelist. Except, the root of the principle table (the one on
** page 1) is never added to the freelist.
**
** This routine will fail with SQLITE_LOCKED if there are any open
| > > > > > > > > > | 58350 58351 58352 58353 58354 58355 58356 58357 58358 58359 58360 58361 58362 58363 58364 58365 58366 58367 58368 58369 58370 58371 58372 |
** a no-op). */
invalidateIncrblobCursors(p, 0, 1);
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
}
sqlite3BtreeLeave(p);
return rc;
}
/*
** Delete all information from the single table that pCur is open on.
**
** This routine only work for pCur on an ephemeral table.
*/
SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0);
}
/*
** Erase all information in a table and add the root of the table to
** the freelist. Except, the root of the principle table (the one on
** page 1) is never added to the freelist.
**
** This routine will fail with SQLITE_LOCKED if there are any open
|
| ︙ | ︙ | |||
59196 59197 59198 59199 59200 59201 59202 |
** parameters that attempt to write past the end of the existing data,
** no modifications are made and SQLITE_CORRUPT is returned.
*/
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
int rc;
assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
| | | 59319 59320 59321 59322 59323 59324 59325 59326 59327 59328 59329 59330 59331 59332 59333 |
** parameters that attempt to write past the end of the existing data,
** no modifications are made and SQLITE_CORRUPT is returned.
*/
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
int rc;
assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
assert( pCsr->curFlags & BTCF_Incrblob );
rc = restoreCursorPosition(pCsr);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pCsr->eState!=CURSOR_REQUIRESEEK );
if( pCsr->eState!=CURSOR_VALID ){
|
| ︙ | ︙ | |||
59225 59226 59227 59228 59229 59230 59231 | /* Check some assumptions: ** (a) the cursor is open for writing, ** (b) there is a read/write transaction open, ** (c) the connection holds a write-lock on the table (if required), ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. */ | | < < | < < < < < | < < < | | 59348 59349 59350 59351 59352 59353 59354 59355 59356 59357 59358 59359 59360 59361 59362 59363 59364 59365 59366 59367 59368 59369 59370 59371 59372 59373 59374 59375 59376 59377 59378 |
/* Check some assumptions:
** (a) the cursor is open for writing,
** (b) there is a read/write transaction open,
** (c) the connection holds a write-lock on the table (if required),
** (d) there are no conflicting read-locks, and
** (e) the cursor points at a valid row of an intKey table.
*/
if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){
return SQLITE_READONLY;
}
assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
&& pCsr->pBt->inTransaction==TRANS_WRITE );
assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
assert( pCsr->apPage[pCsr->iPage]->intKey );
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
}
/*
** Mark this cursor as an incremental blob cursor.
*/
SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
pCur->curFlags |= BTCF_Incrblob;
}
#endif
/*
** Set both the "read version" (single byte at byte offset 18) and
** "write version" (single byte at byte offset 19) fields in the database
** header to iVersion.
|
| ︙ | ︙ | |||
61622 61623 61624 61625 61626 61627 61628 |
** a prior call to sqlite3VdbeMakeLabel().
*/
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
Parse *p = v->pParse;
int j = -1-x;
assert( v->magic==VDBE_MAGIC_INIT );
assert( j<p->nLabel );
| | | 61735 61736 61737 61738 61739 61740 61741 61742 61743 61744 61745 61746 61747 61748 61749 |
** a prior call to sqlite3VdbeMakeLabel().
*/
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
Parse *p = v->pParse;
int j = -1-x;
assert( v->magic==VDBE_MAGIC_INIT );
assert( j<p->nLabel );
if( ALWAYS(j>=0) && p->aLabel ){
p->aLabel[j] = v->nOp;
}
p->iFixedOp = v->nOp - 1;
}
/*
** Mark the VDBE as one that can only be run one time.
|
| ︙ | ︙ | |||
62129 62130 62131 62132 62133 62134 62135 |
}
assert( p->nOp>0 );
assert( addr<p->nOp );
if( addr<0 ){
addr = p->nOp - 1;
}
pOp = &p->aOp[addr];
| | > > | 62242 62243 62244 62245 62246 62247 62248 62249 62250 62251 62252 62253 62254 62255 62256 62257 62258 |
}
assert( p->nOp>0 );
assert( addr<p->nOp );
if( addr<0 ){
addr = p->nOp - 1;
}
pOp = &p->aOp[addr];
assert( pOp->p4type==P4_NOTUSED
|| pOp->p4type==P4_INT32
|| pOp->p4type==P4_KEYINFO );
freeP4(db, pOp->p4type, pOp->p4.p);
pOp->p4.p = 0;
if( n==P4_INT32 ){
/* Note: this cast is safe, because the origin data point was an int
** that was cast to a (const char *). */
pOp->p4.i = SQLITE_PTR_TO_INT(zP4);
pOp->p4type = P4_INT32;
|
| ︙ | ︙ | |||
64079 64080 64081 64082 64083 64084 64085 |
p->cacheStatus = CACHE_STALE;
}else if( p->pCursor ){
int hasMoved;
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
if( rc ) return rc;
if( hasMoved ){
p->cacheStatus = CACHE_STALE;
| | | 64194 64195 64196 64197 64198 64199 64200 64201 64202 64203 64204 64205 64206 64207 64208 |
p->cacheStatus = CACHE_STALE;
}else if( p->pCursor ){
int hasMoved;
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
if( rc ) return rc;
if( hasMoved ){
p->cacheStatus = CACHE_STALE;
if( hasMoved==2 ) p->nullRow = 1;
}
}
return SQLITE_OK;
}
/*
** The following functions:
|
| ︙ | ︙ | |||
64749 64750 64751 64752 64753 64754 64755 64756 64757 64758 | ** ** If argument bSkip is non-zero, it is assumed that the caller has already ** determined that the first fields of the keys are equal. ** ** Key1 and Key2 do not have to contain the same number of fields. If all ** fields that appear in both keys are equal, then pPKey2->default_rc is ** returned. */ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ | > > > | | 64864 64865 64866 64867 64868 64869 64870 64871 64872 64873 64874 64875 64876 64877 64878 64879 64880 64881 64882 64883 64884 |
**
** If argument bSkip is non-zero, it is assumed that the caller has already
** determined that the first fields of the keys are equal.
**
** Key1 and Key2 do not have to contain the same number of fields. If all
** fields that appear in both keys are equal, then pPKey2->default_rc is
** returned.
**
** If database corruption is discovered, set pPKey2->isCorrupt to non-zero
** and return 0.
*/
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
int nKey1, const void *pKey1, /* Left key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip /* If true, skip the first field */
){
u32 d1; /* Offset into aKey[] of next data element */
int i; /* Index of next field to compare */
u32 szHdr1; /* Size of record header in bytes */
u32 idx1; /* Offset of first type in header */
int rc = 0; /* Return value */
|
| ︙ | ︙ | |||
64778 64779 64780 64781 64782 64783 64784 64785 64786 64787 64788 64789 64790 64791 |
szHdr1 = aKey1[0];
d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1);
i = 1;
pRhs++;
}else{
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
i = 0;
}
VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
|| CORRUPT_DB );
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
| > > > > | 64896 64897 64898 64899 64900 64901 64902 64903 64904 64905 64906 64907 64908 64909 64910 64911 64912 64913 |
szHdr1 = aKey1[0];
d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1);
i = 1;
pRhs++;
}else{
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
if( d1>(unsigned)nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
i = 0;
}
VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
|| CORRUPT_DB );
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
|
| ︙ | ︙ | |||
64854 64855 64856 64857 64858 64859 64860 |
}else if( !(serial_type & 0x01) ){
rc = +1;
}else{
mem1.n = (serial_type - 12) / 2;
testcase( (d1+mem1.n)==(unsigned)nKey1 );
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
if( (d1+mem1.n) > (unsigned)nKey1 ){
| > | | 64976 64977 64978 64979 64980 64981 64982 64983 64984 64985 64986 64987 64988 64989 64990 64991 |
}else if( !(serial_type & 0x01) ){
rc = +1;
}else{
mem1.n = (serial_type - 12) / 2;
testcase( (d1+mem1.n)==(unsigned)nKey1 );
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
if( (d1+mem1.n) > (unsigned)nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else if( pKeyInfo->aColl[i] ){
mem1.enc = pKeyInfo->enc;
mem1.db = pKeyInfo->db;
mem1.flags = MEM_Str;
mem1.z = (char*)&aKey1[d1];
rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]);
}else{
|
| ︙ | ︙ | |||
64880 64881 64882 64883 64884 64885 64886 |
if( serial_type<12 || (serial_type & 0x01) ){
rc = -1;
}else{
int nStr = (serial_type - 12) / 2;
testcase( (d1+nStr)==(unsigned)nKey1 );
testcase( (d1+nStr+1)==(unsigned)nKey1 );
if( (d1+nStr) > (unsigned)nKey1 ){
| > | | 65003 65004 65005 65006 65007 65008 65009 65010 65011 65012 65013 65014 65015 65016 65017 65018 |
if( serial_type<12 || (serial_type & 0x01) ){
rc = -1;
}else{
int nStr = (serial_type - 12) / 2;
testcase( (d1+nStr)==(unsigned)nKey1 );
testcase( (d1+nStr+1)==(unsigned)nKey1 );
if( (d1+nStr) > (unsigned)nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else{
int nCmp = MIN(nStr, pRhs->n);
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
if( rc==0 ) rc = nStr - pRhs->n;
}
}
}
|
| ︙ | ︙ | |||
64933 64934 64935 64936 64937 64938 64939 64940 64941 64942 | } /* ** This function is an optimized version of sqlite3VdbeRecordCompare() ** that (a) the first field of pPKey2 is an integer, and (b) the ** size-of-header varint at the start of (pKey1/nKey1) fits in a single ** byte (i.e. is less than 128). */ static int vdbeRecordCompareInt( int nKey1, const void *pKey1, /* Left key */ | > > > | > | 65057 65058 65059 65060 65061 65062 65063 65064 65065 65066 65067 65068 65069 65070 65071 65072 65073 65074 65075 65076 65077 65078 65079 65080 65081 65082 65083 65084 65085 65086 65087 65088 65089 65090 |
}
/*
** This function is an optimized version of sqlite3VdbeRecordCompare()
** that (a) the first field of pPKey2 is an integer, and (b) the
** size-of-header varint at the start of (pKey1/nKey1) fits in a single
** byte (i.e. is less than 128).
**
** To avoid concerns about buffer overreads, this routine is only used
** on schemas where the maximum valid header size is 63 bytes or less.
*/
static int vdbeRecordCompareInt(
int nKey1, const void *pKey1, /* Left key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip /* Ignored */
){
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
int serial_type = ((const u8*)pKey1)[1];
int res;
u32 y;
u64 x;
i64 v = pPKey2->aMem[0].u.i;
i64 lhs;
UNUSED_PARAMETER(bSkip);
assert( bSkip==0 );
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
switch( serial_type ){
case 1: { /* 1-byte signed integer */
lhs = ONE_BYTE_INT(aKey);
testcase( lhs<0 );
break;
}
case 2: { /* 2-byte signed integer */
|
| ︙ | ︙ | |||
65033 65034 65035 65036 65037 65038 65039 | ** This function is an optimized version of sqlite3VdbeRecordCompare() ** that (a) the first field of pPKey2 is a string, that (b) the first field ** uses the collation sequence BINARY and (c) that the size-of-header varint ** at the start of (pKey1/nKey1) fits in a single byte. */ static int vdbeRecordCompareString( int nKey1, const void *pKey1, /* Left key */ | | | > > > | 65161 65162 65163 65164 65165 65166 65167 65168 65169 65170 65171 65172 65173 65174 65175 65176 65177 65178 65179 65180 65181 65182 65183 65184 65185 65186 65187 65188 65189 65190 65191 65192 65193 65194 65195 65196 65197 65198 65199 |
** This function is an optimized version of sqlite3VdbeRecordCompare()
** that (a) the first field of pPKey2 is a string, that (b) the first field
** uses the collation sequence BINARY and (c) that the size-of-header varint
** at the start of (pKey1/nKey1) fits in a single byte.
*/
static int vdbeRecordCompareString(
int nKey1, const void *pKey1, /* Left key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip
){
const u8 *aKey1 = (const u8*)pKey1;
int serial_type;
int res;
UNUSED_PARAMETER(bSkip);
assert( bSkip==0 );
getVarint32(&aKey1[1], serial_type);
if( serial_type<12 ){
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
}else if( !(serial_type & 0x01) ){
res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
}else{
int nCmp;
int nStr;
int szHdr = aKey1[0];
nStr = (serial_type-12) / 2;
if( (szHdr + nStr) > nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
nCmp = MIN( pPKey2->aMem[0].n, nStr );
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
if( res==0 ){
res = nStr - pPKey2->aMem[0].n;
if( res==0 ){
if( pPKey2->nField>1 ){
|
| ︙ | ︙ | |||
65219 65220 65221 65222 65223 65224 65225 | ** pUnpacked is either created without a rowid or is truncated so that it ** omits the rowid at the end. The rowid at the end of the index entry ** is ignored as well. Hence, this routine only compares the prefixes ** of the keys prior to the final rowid, not the entire key. */ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( VdbeCursor *pC, /* The cursor to compare against */ | | | 65350 65351 65352 65353 65354 65355 65356 65357 65358 65359 65360 65361 65362 65363 65364 |
** pUnpacked is either created without a rowid or is truncated so that it
** omits the rowid at the end. The rowid at the end of the index entry
** is ignored as well. Hence, this routine only compares the prefixes
** of the keys prior to the final rowid, not the entire key.
*/
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
VdbeCursor *pC, /* The cursor to compare against */
UnpackedRecord *pUnpacked, /* Unpacked version of key */
int *res /* Write the comparison result here */
){
i64 nCellKey = 0;
int rc;
BtCursor *pCur = pC->pCursor;
Mem m;
|
| ︙ | ︙ | |||
67309 67310 67311 67312 67313 67314 67315 67316 67317 67318 67319 67320 67321 67322 |
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(
sqlite3_value *pVal,
u8 affinity,
u8 enc
){
applyAffinity((Mem *)pVal, affinity, enc);
}
#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
*/
SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
| > > > > > > > > > > > > > > > > > > > > > > > | 67440 67441 67442 67443 67444 67445 67446 67447 67448 67449 67450 67451 67452 67453 67454 67455 67456 67457 67458 67459 67460 67461 67462 67463 67464 67465 67466 67467 67468 67469 67470 67471 67472 67473 67474 67475 67476 |
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(
sqlite3_value *pVal,
u8 affinity,
u8 enc
){
applyAffinity((Mem *)pVal, affinity, enc);
}
/*
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
** none.
**
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
** But it does set pMem->r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
if( pMem->flags & (MEM_Int|MEM_Real) ){
return pMem->flags & (MEM_Int|MEM_Real);
}
if( pMem->flags & (MEM_Str|MEM_Blob) ){
if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
return 0;
}
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
return MEM_Int;
}
return MEM_Real;
}
return 0;
}
#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
*/
SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
| ︙ | ︙ | |||
68169 68170 68171 68172 68173 68174 68175 | UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Move P1 P2 P3 * * ** Synopsis: r[P2@P3]=r[P1@P3] ** | | | | > | | 68323 68324 68325 68326 68327 68328 68329 68330 68331 68332 68333 68334 68335 68336 68337 68338 68339 68340 68341 68342 68343 68344 68345 68346 68347 68348 68349 68350 68351 68352 |
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
/* Opcode: Move P1 P2 P3 * *
** Synopsis: r[P2@P3]=r[P1@P3]
**
** Move the P3 values in register P1..P1+P3-1 over into
** registers P2..P2+P3-1. Registers P1..P1+P3-1 are
** left holding a NULL. It is an error for register ranges
** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error
** for P3 to be less than 1.
*/
case OP_Move: {
char *zMalloc; /* Holding variable for allocated memory */
int n; /* Number of registers left to copy */
int p1; /* Register to copy from */
int p2; /* Register to copy to */
n = pOp->p3;
p1 = pOp->p1;
p2 = pOp->p2;
assert( n>0 && p1>0 && p2>0 );
assert( p1+n<=p2 || p2+n<=p1 );
pIn1 = &aMem[p1];
pOut = &aMem[p2];
do{
assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
|
| ︙ | ︙ | |||
68207 68208 68209 68210 68211 68212 68213 |
#endif
pIn1->flags = MEM_Undefined;
pIn1->xDel = 0;
pIn1->zMalloc = zMalloc;
REGISTER_TRACE(p2++, pOut);
pIn1++;
pOut++;
| | | 68362 68363 68364 68365 68366 68367 68368 68369 68370 68371 68372 68373 68374 68375 68376 |
#endif
pIn1->flags = MEM_Undefined;
pIn1->xDel = 0;
pIn1->zMalloc = zMalloc;
REGISTER_TRACE(p2++, pOut);
pIn1++;
pOut++;
}while( --n );
break;
}
/* Opcode: Copy P1 P2 P3 * *
** Synopsis: r[P2@P3+1]=r[P1@P3+1]
**
** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
|
| ︙ | ︙ | |||
68439 68440 68441 68442 68443 68444 68445 |
*/
case OP_Add: /* same as TK_PLUS, in1, in2, out3 */
case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
char bIntint; /* Started out as two integer operands */
| | > > | | | | 68594 68595 68596 68597 68598 68599 68600 68601 68602 68603 68604 68605 68606 68607 68608 68609 68610 68611 68612 68613 68614 68615 68616 68617 68618 68619 68620 68621 68622 68623 |
*/
case OP_Add: /* same as TK_PLUS, in1, in2, out3 */
case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
char bIntint; /* Started out as two integer operands */
u16 flags; /* Combined MEM_* flags from both inputs */
u16 type1; /* Numeric type of left operand */
u16 type2; /* Numeric type of right operand */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
double rA; /* Real value of left operand */
double rB; /* Real value of right operand */
pIn1 = &aMem[pOp->p1];
type1 = numericType(pIn1);
pIn2 = &aMem[pOp->p2];
type2 = numericType(pIn2);
pOut = &aMem[pOp->p3];
flags = pIn1->flags | pIn2->flags;
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
if( (type1 & type2 & MEM_Int)!=0 ){
iA = pIn1->u.i;
iB = pIn2->u.i;
bIntint = 1;
switch( pOp->opcode ){
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
case OP_Multiply: if( sqlite3MulInt64(&iB,iA) ) goto fp_math; break;
|
| ︙ | ︙ | |||
68508 68509 68510 68511 68512 68513 68514 |
MemSetTypeFlag(pOut, MEM_Int);
#else
if( sqlite3IsNaN(rB) ){
goto arithmetic_result_is_null;
}
pOut->r = rB;
MemSetTypeFlag(pOut, MEM_Real);
| | | 68665 68666 68667 68668 68669 68670 68671 68672 68673 68674 68675 68676 68677 68678 68679 |
MemSetTypeFlag(pOut, MEM_Int);
#else
if( sqlite3IsNaN(rB) ){
goto arithmetic_result_is_null;
}
pOut->r = rB;
MemSetTypeFlag(pOut, MEM_Real);
if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
sqlite3VdbeIntegerAffinity(pOut);
}
#endif
}
break;
arithmetic_result_is_null:
|
| ︙ | ︙ | |||
69084 69085 69086 69087 69088 69089 69090 69091 69092 69093 69094 69095 69096 69097 |
assert( pOp->p4type==P4_INTARRAY );
assert( pOp->p4.ai );
aPermute = pOp->p4.ai;
break;
}
/* Opcode: Compare P1 P2 P3 P4 P5
**
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
** the comparison for use by the next OP_Jump instruct.
**
** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is
** determined by the most recent OP_Permutation operator. If the
| > | 69241 69242 69243 69244 69245 69246 69247 69248 69249 69250 69251 69252 69253 69254 69255 |
assert( pOp->p4type==P4_INTARRAY );
assert( pOp->p4.ai );
aPermute = pOp->p4.ai;
break;
}
/* Opcode: Compare P1 P2 P3 P4 P5
** Synopsis: r[P1@P3] <-> r[P2@P3]
**
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
** the comparison for use by the next OP_Jump instruct.
**
** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is
** determined by the most recent OP_Permutation operator. If the
|
| ︙ | ︙ | |||
70419 70420 70421 70422 70423 70424 70425 70426 70427 70428 70429 70430 70431 70432 |
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
assert( pOp->p2>=0 );
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
}
if( rc==SQLITE_OK ){
/* If a transient index is required, create it by calling
| > | 70577 70578 70579 70580 70581 70582 70583 70584 70585 70586 70587 70588 70589 70590 70591 |
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
assert( pOp->p2>=0 );
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->isEphemeral = 1;
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
}
if( rc==SQLITE_OK ){
/* If a transient index is required, create it by calling
|
| ︙ | ︙ | |||
70909 70910 70911 70912 70913 70914 70915 |
assert( pC->rowidIsValid==0 );
}
pC->seekResult = res;
break;
}
/* Opcode: Sequence P1 P2 * * *
| | | 71068 71069 71070 71071 71072 71073 71074 71075 71076 71077 71078 71079 71080 71081 71082 |
assert( pC->rowidIsValid==0 );
}
pC->seekResult = res;
break;
}
/* Opcode: Sequence P1 P2 * * *
** Synopsis: r[P2]=cursor[P1].ctr++
**
** Find the next available sequence number for cursor P1.
** Write the sequence number into register P2.
** The sequence number on the cursor is incremented after this
** instruction.
*/
case OP_Sequence: { /* out2-prerelease */
|
| ︙ | ︙ | |||
71600 71601 71602 71603 71604 71605 71606 71607 71608 71609 71610 71611 71612 71613 |
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
int res;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
rc = sqlite3VdbeSorterNext(db, pC, &res);
goto next_tail;
case OP_PrevIfOpen: /* jump */
case OP_NextIfOpen: /* jump */
if( p->apCsr[pOp->p1]==0 ) break;
/* Fall through */
case OP_Prev: /* jump */
| > | 71759 71760 71761 71762 71763 71764 71765 71766 71767 71768 71769 71770 71771 71772 71773 |
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
int res;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
res = 0;
rc = sqlite3VdbeSorterNext(db, pC, &res);
goto next_tail;
case OP_PrevIfOpen: /* jump */
case OP_NextIfOpen: /* jump */
if( p->apCsr[pOp->p1]==0 ) break;
/* Fall through */
case OP_Prev: /* jump */
|
| ︙ | ︙ | |||
71957 71958 71959 71960 71961 71962 71963 71964 71965 71966 71967 71968 71969 71970 |
assert( memIsValid(&aMem[pOp->p3]) );
memAboutToChange(p, &aMem[pOp->p3]);
aMem[pOp->p3].u.i += nChange;
}
}
break;
}
/* Opcode: CreateTable P1 P2 * * *
** Synopsis: r[P2]=root iDb=P1
**
** Allocate a new table in the main database file if P1==0 or in the
** auxiliary database file if P1==1 or in an attached database if
** P1>1. Write the root page number of the new table into
| > > > > > > > > > > > > > > > > > > > > > > > | 72117 72118 72119 72120 72121 72122 72123 72124 72125 72126 72127 72128 72129 72130 72131 72132 72133 72134 72135 72136 72137 72138 72139 72140 72141 72142 72143 72144 72145 72146 72147 72148 72149 72150 72151 72152 72153 |
assert( memIsValid(&aMem[pOp->p3]) );
memAboutToChange(p, &aMem[pOp->p3]);
aMem[pOp->p3].u.i += nChange;
}
}
break;
}
/* Opcode: ResetSorter P1 * * * *
**
** Delete all contents from the ephemeral table or sorter
** that is open on cursor P1.
**
** This opcode only works for cursors used for sorting and
** opened with OP_OpenEphemeral or OP_SorterOpen.
*/
case OP_ResetSorter: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
if( pC->pSorter ){
sqlite3VdbeSorterReset(db, pC->pSorter);
}else{
assert( pC->isEphemeral );
rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
}
break;
}
/* Opcode: CreateTable P1 P2 * * *
** Synopsis: r[P2]=root iDb=P1
**
** Allocate a new table in the main database file if P1==0 or in the
** auxiliary database file if P1==1 or in an attached database if
** P1>1. Write the root page number of the new table into
|
| ︙ | ︙ | |||
72264 72265 72266 72267 72268 72269 72270 |
sqlite3VdbeMemSetRowSet(pIn1);
if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
}
assert( pOp->p4type==P4_INT32 );
assert( iSet==-1 || iSet>=0 );
if( iSet ){
| | < < | 72447 72448 72449 72450 72451 72452 72453 72454 72455 72456 72457 72458 72459 72460 72461 |
sqlite3VdbeMemSetRowSet(pIn1);
if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
}
assert( pOp->p4type==P4_INT32 );
assert( iSet==-1 || iSet>=0 );
if( iSet ){
exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
VdbeBranchTaken(exists!=0,2);
if( exists ){
pc = pOp->p2 - 1;
break;
}
}
if( iSet>=0 ){
|
| ︙ | ︙ | |||
72966 72967 72968 72969 72970 72971 72972 | } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * | | | 73147 73148 73149 73150 73151 73152 73153 73154 73155 73156 73157 73158 73159 73160 73161 | } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * ** Synopsis: iplan=r[P3] zplan='P4' ** ** P1 is a cursor opened using VOpen. P2 is an address to jump to if ** the filtered result set is empty. ** ** P4 is either NULL or a string that was generated by the xBestIndex ** method of the module. The interpretation of the P4 string is left ** to the module implementation. |
| ︙ | ︙ | |||
73534 73535 73536 73537 73538 73539 73540 |
rc = SQLITE_ERROR;
sqlite3_finalize(p->pStmt);
p->pStmt = 0;
}else{
p->iOffset = pC->aType[p->iCol + pC->nField];
p->nByte = sqlite3VdbeSerialTypeLen(type);
p->pCsr = pC->pCursor;
| | < < | 73715 73716 73717 73718 73719 73720 73721 73722 73723 73724 73725 73726 73727 73728 73729 |
rc = SQLITE_ERROR;
sqlite3_finalize(p->pStmt);
p->pStmt = 0;
}else{
p->iOffset = pC->aType[p->iCol + pC->nField];
p->nByte = sqlite3VdbeSerialTypeLen(type);
p->pCsr = pC->pCursor;
sqlite3BtreeIncrblobCursor(p->pCsr);
}
}
if( rc==SQLITE_ROW ){
rc = SQLITE_OK;
}else if( p->pStmt ){
rc = sqlite3_finalize(p->pStmt);
|
| ︙ | ︙ | |||
74429 74430 74431 74432 74433 74434 74435 74436 74437 74438 74439 74440 74441 74442 |
SorterRecord *p;
SorterRecord *pNext;
for(p=pRecord; p; p=pNext){
pNext = p->pNext;
sqlite3DbFree(db, p);
}
}
/*
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
*/
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
VdbeSorter *pSorter = pCsr->pSorter;
if( pSorter ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < | < < < < < | 74608 74609 74610 74611 74612 74613 74614 74615 74616 74617 74618 74619 74620 74621 74622 74623 74624 74625 74626 74627 74628 74629 74630 74631 74632 74633 74634 74635 74636 74637 74638 74639 74640 74641 74642 74643 74644 74645 74646 74647 74648 74649 74650 74651 74652 74653 74654 74655 74656 |
SorterRecord *p;
SorterRecord *pNext;
for(p=pRecord; p; p=pNext){
pNext = p->pNext;
sqlite3DbFree(db, p);
}
}
/*
** Reset a sorting cursor back to its original empty state.
*/
SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
if( pSorter->aIter ){
int i;
for(i=0; i<pSorter->nTree; i++){
vdbeSorterIterZero(db, &pSorter->aIter[i]);
}
sqlite3DbFree(db, pSorter->aIter);
pSorter->aIter = 0;
}
if( pSorter->pTemp1 ){
sqlite3OsCloseFree(pSorter->pTemp1);
pSorter->pTemp1 = 0;
}
vdbeSorterRecordFree(db, pSorter->pRecord);
pSorter->pRecord = 0;
pSorter->iWriteOff = 0;
pSorter->iReadOff = 0;
pSorter->nInMemory = 0;
pSorter->nTree = 0;
pSorter->nPMA = 0;
pSorter->aTree = 0;
}
/*
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
*/
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
VdbeSorter *pSorter = pCsr->pSorter;
if( pSorter ){
sqlite3VdbeSorterReset(db, pSorter);
sqlite3DbFree(db, pSorter->pUnpacked);
sqlite3DbFree(db, pSorter);
pCsr->pSorter = 0;
}
}
/*
|
| ︙ | ︙ | |||
74882 74883 74884 74885 74886 74887 74888 |
*/
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter;
int rc; /* Return code */
if( pSorter->aTree ){
int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
| > > | > > > > > | > > > | > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > | > | 75078 75079 75080 75081 75082 75083 75084 75085 75086 75087 75088 75089 75090 75091 75092 75093 75094 75095 75096 75097 75098 75099 75100 75101 75102 75103 75104 75105 75106 75107 75108 75109 75110 75111 75112 75113 75114 75115 75116 75117 75118 75119 75120 75121 75122 75123 75124 75125 75126 75127 75128 75129 75130 75131 75132 75133 75134 75135 75136 75137 75138 75139 75140 |
*/
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter;
int rc; /* Return code */
if( pSorter->aTree ){
int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
if( rc==SQLITE_OK ){
int i; /* Index of aTree[] to recalculate */
VdbeSorterIter *pIter1; /* First iterator to compare */
VdbeSorterIter *pIter2; /* Second iterator to compare */
u8 *pKey2; /* To pIter2->aKey, or 0 if record cached */
/* Find the first two iterators to compare. The one that was just
** advanced (iPrev) and the one next to it in the array. */
pIter1 = &pSorter->aIter[(iPrev & 0xFFFE)];
pIter2 = &pSorter->aIter[(iPrev | 0x0001)];
pKey2 = pIter2->aKey;
for(i=(pSorter->nTree+iPrev)/2; i>0; i=i/2){
/* Compare pIter1 and pIter2. Store the result in variable iRes. */
int iRes;
if( pIter1->pFile==0 ){
iRes = +1;
}else if( pIter2->pFile==0 ){
iRes = -1;
}else{
vdbeSorterCompare(pCsr, 0,
pIter1->aKey, pIter1->nKey, pKey2, pIter2->nKey, &iRes
);
}
/* If pIter1 contained the smaller value, set aTree[i] to its index.
** Then set pIter2 to the next iterator to compare to pIter1. In this
** case there is no cache of pIter2 in pSorter->pUnpacked, so set
** pKey2 to point to the record belonging to pIter2.
**
** Alternatively, if pIter2 contains the smaller of the two values,
** set aTree[i] to its index and update pIter1. If vdbeSorterCompare()
** was actually called above, then pSorter->pUnpacked now contains
** a value equivalent to pIter2. So set pKey2 to NULL to prevent
** vdbeSorterCompare() from decoding pIter2 again. */
if( iRes<=0 ){
pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter);
pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
pKey2 = pIter2->aKey;
}else{
if( pIter1->pFile ) pKey2 = 0;
pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter);
pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
}
}
*pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
}
}else{
SorterRecord *pFree = pSorter->pRecord;
pSorter->pRecord = pFree->pNext;
pFree->pNext = 0;
vdbeSorterRecordFree(db, pFree);
*pbEof = !pSorter->pRecord;
rc = SQLITE_OK;
|
| ︙ | ︙ | |||
77125 77126 77127 77128 77129 77130 77131 77132 77133 77134 77135 77136 77137 77138 |
** SELECT * FROM t1 WHERE a;
** SELECT a AS b FROM t1 WHERE b;
** SELECT * FROM t1 WHERE (select a from t1);
*/
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
int op;
pExpr = sqlite3ExprSkipCollate(pExpr);
op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
| > | 77362 77363 77364 77365 77366 77367 77368 77369 77370 77371 77372 77373 77374 77375 77376 |
** SELECT * FROM t1 WHERE a;
** SELECT a AS b FROM t1 WHERE b;
** SELECT * FROM t1 WHERE (select a from t1);
*/
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
int op;
pExpr = sqlite3ExprSkipCollate(pExpr);
if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
|
| ︙ | ︙ | |||
77157 77158 77159 77160 77161 77162 77163 | ** Set the collating sequence for expression pExpr to be the collating ** sequence named by pToken. Return a pointer to a new Expr node that ** implements the COLLATE operator. ** ** If a memory allocation error occurs, that fact is recorded in pParse->db ** and the pExpr parameter is returned unchanged. */ | | > > > > | 77395 77396 77397 77398 77399 77400 77401 77402 77403 77404 77405 77406 77407 77408 77409 77410 77411 77412 77413 |
** Set the collating sequence for expression pExpr to be the collating
** sequence named by pToken. Return a pointer to a new Expr node that
** implements the COLLATE operator.
**
** If a memory allocation error occurs, that fact is recorded in pParse->db
** and the pExpr parameter is returned unchanged.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
const Token *pCollName /* Name of collating sequence */
){
if( pCollName->n>0 ){
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
if( pNew ){
pNew->pLeft = pExpr;
pNew->flags |= EP_Collate|EP_Skip;
pExpr = pNew;
}
|
| ︙ | ︙ | |||
77210 77211 77212 77213 77214 77215 77216 77217 77218 77219 77220 77221 77222 77223 |
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
sqlite3 *db = pParse->db;
CollSeq *pColl = 0;
Expr *p = pExpr;
while( p ){
int op = p->op;
if( op==TK_CAST || op==TK_UPLUS ){
p = p->pLeft;
continue;
}
if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
| > | 77452 77453 77454 77455 77456 77457 77458 77459 77460 77461 77462 77463 77464 77465 77466 |
*/
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
sqlite3 *db = pParse->db;
CollSeq *pColl = 0;
Expr *p = pExpr;
while( p ){
int op = p->op;
if( p->flags & EP_Generic ) break;
if( op==TK_CAST || op==TK_UPLUS ){
p = p->pLeft;
continue;
}
if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
|
| ︙ | ︙ | |||
78041 78042 78043 78044 78045 78046 78047 |
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
| < | 78284 78285 78286 78287 78288 78289 78290 78291 78292 78293 78294 78295 78296 78297 |
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nExpr = i = p->nExpr;
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
if( pItem==0 ){
sqlite3DbFree(db, pNew);
return 0;
}
|
| ︙ | ︙ | |||
78154 78155 78156 78157 78158 78159 78160 | pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags); pNew->iLimit = 0; pNew->iOffset = 0; pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; | < | 78396 78397 78398 78399 78400 78401 78402 78403 78404 78405 78406 78407 78408 78409 |
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
pNew->iLimit = 0;
pNew->iOffset = 0;
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = p->nSelectRow;
pNew->pWith = withDup(db, p->pWith);
return pNew;
}
#else
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
assert( p==0 );
|
| ︙ | ︙ | |||
78722 78723 78724 78725 78726 78727 78728 |
u32 savedNQueryLoop = pParse->nQueryLoop;
int rMayHaveNull = 0;
eType = IN_INDEX_EPH;
if( prNotFound ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
}else{
| < | 78963 78964 78965 78966 78967 78968 78969 78970 78971 78972 78973 78974 78975 78976 |
u32 savedNQueryLoop = pParse->nQueryLoop;
int rMayHaveNull = 0;
eType = IN_INDEX_EPH;
if( prNotFound ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
}else{
pParse->nQueryLoop = 0;
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
}
}
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
pParse->nQueryLoop = savedNQueryLoop;
|
| ︙ | ︙ | |||
78972 78973 78974 78975 78976 78977 78978 |
break;
}
}
if( testAddr>=0 ){
sqlite3VdbeJumpHere(v, testAddr);
}
| | | 79212 79213 79214 79215 79216 79217 79218 79219 79220 79221 79222 79223 79224 79225 79226 |
break;
}
}
if( testAddr>=0 ){
sqlite3VdbeJumpHere(v, testAddr);
}
sqlite3ExprCachePop(pParse);
return rReg;
}
#endif /* SQLITE_OMIT_SUBQUERY */
#ifndef SQLITE_OMIT_SUBQUERY
/*
|
| ︙ | ︙ | |||
79107 79108 79109 79110 79111 79112 79113 |
/* The OP_Found at the top of this branch jumps here when true,
** causing the overall IN expression evaluation to fall through.
*/
sqlite3VdbeJumpHere(v, j1);
}
}
sqlite3ReleaseTempReg(pParse, r1);
| | | 79347 79348 79349 79350 79351 79352 79353 79354 79355 79356 79357 79358 79359 79360 79361 |
/* The OP_Found at the top of this branch jumps here when true,
** causing the overall IN expression evaluation to fall through.
*/
sqlite3VdbeJumpHere(v, j1);
}
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ExprCachePop(pParse);
VdbeComment((v, "end IN expr"));
}
#endif /* SQLITE_OMIT_SUBQUERY */
/*
** Duplicate an 8-byte value
*/
|
| ︙ | ︙ | |||
79290 79291 79292 79293 79294 79295 79296 |
printf("PUSH to %d\n", pParse->iCacheLevel);
}
#endif
}
/*
** Remove from the column cache any entries that were added since the
| | | | < | | | 79530 79531 79532 79533 79534 79535 79536 79537 79538 79539 79540 79541 79542 79543 79544 79545 79546 79547 79548 79549 79550 79551 |
printf("PUSH to %d\n", pParse->iCacheLevel);
}
#endif
}
/*
** Remove from the column cache any entries that were added since the
** the previous sqlite3ExprCachePush operation. In other words, restore
** the cache to the state it was in prior the most recent Push.
*/
SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
int i;
struct yColCache *p;
assert( pParse->iCacheLevel>=1 );
pParse->iCacheLevel--;
#ifdef SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("POP to %d\n", pParse->iCacheLevel);
}
#endif
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
|
| ︙ | ︙ | |||
79427 79428 79429 79430 79431 79432 79433 |
** Generate code to move content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
*/
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
int i;
struct yColCache *p;
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
| | | 79666 79667 79668 79669 79670 79671 79672 79673 79674 79675 79676 79677 79678 79679 79680 |
** Generate code to move content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
*/
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
int i;
struct yColCache *p;
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
int x = p->iReg;
if( x>=iFrom && x<iFrom+nReg ){
p->iReg += iTo-iFrom;
}
}
}
|
| ︙ | ︙ | |||
79776 79777 79778 79779 79780 79781 79782 |
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
for(i=1; i<nFarg; i++){
sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
VdbeCoverage(v);
sqlite3ExprCacheRemove(pParse, target, 1);
sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
| | | 80015 80016 80017 80018 80019 80020 80021 80022 80023 80024 80025 80026 80027 80028 80029 |
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
for(i=1; i<nFarg; i++){
sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
VdbeCoverage(v);
sqlite3ExprCacheRemove(pParse, target, 1);
sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
sqlite3ExprCachePop(pParse);
}
sqlite3VdbeResolveLabel(v, endCoalesce);
break;
}
/* The UNLIKELY() function is a no-op. The result is the value
** of the first argument.
|
| ︙ | ︙ | |||
79828 79829 79830 79831 79832 79833 79834 |
testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
pFarg->a[0].pExpr->op2 =
pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
}
}
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
| | | | 80067 80068 80069 80070 80071 80072 80073 80074 80075 80076 80077 80078 80079 80080 80081 80082 80083 |
testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
pFarg->a[0].pExpr->op2 =
pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
}
}
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
sqlite3ExprCodeExprList(pParse, pFarg, r1,
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
}else{
r1 = 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Possibly overload the function if the first argument is
** a virtual table column.
**
|
| ︙ | ︙ | |||
80050 80051 80052 80053 80054 80055 80056 |
}
nextCase = sqlite3VdbeMakeLabel(v);
testcase( pTest->op==TK_COLUMN );
sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
| | | | 80289 80290 80291 80292 80293 80294 80295 80296 80297 80298 80299 80300 80301 80302 80303 80304 80305 80306 80307 80308 80309 |
}
nextCase = sqlite3VdbeMakeLabel(v);
testcase( pTest->op==TK_COLUMN );
sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
sqlite3ExprCachePop(pParse);
sqlite3VdbeResolveLabel(v, nextCase);
}
if( (nExpr&1)!=0 ){
sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
sqlite3ExprCachePop(pParse);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
}
assert( db->mallocFailed || pParse->nErr>0
|| pParse->iCacheLevel==iCacheLevel );
sqlite3VdbeResolveLabel(v, endLabel);
break;
|
| ︙ | ︙ | |||
80635 80636 80637 80638 80639 80640 80641 |
case TK_AND: {
int d2 = sqlite3VdbeMakeLabel(v);
testcase( jumpIfNull==0 );
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
sqlite3ExprCachePush(pParse);
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3VdbeResolveLabel(v, d2);
| | | | 80874 80875 80876 80877 80878 80879 80880 80881 80882 80883 80884 80885 80886 80887 80888 80889 80890 80891 80892 80893 80894 80895 80896 |
case TK_AND: {
int d2 = sqlite3VdbeMakeLabel(v);
testcase( jumpIfNull==0 );
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
sqlite3ExprCachePush(pParse);
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3VdbeResolveLabel(v, d2);
sqlite3ExprCachePop(pParse);
break;
}
case TK_OR: {
testcase( jumpIfNull==0 );
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
sqlite3ExprCachePush(pParse);
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3ExprCachePop(pParse);
break;
}
case TK_NOT: {
testcase( jumpIfNull==0 );
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
|
| ︙ | ︙ | |||
80789 80790 80791 80792 80793 80794 80795 |
switch( pExpr->op ){
case TK_AND: {
testcase( jumpIfNull==0 );
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
| | | | 81028 81029 81030 81031 81032 81033 81034 81035 81036 81037 81038 81039 81040 81041 81042 81043 81044 81045 81046 81047 81048 81049 81050 81051 81052 |
switch( pExpr->op ){
case TK_AND: {
testcase( jumpIfNull==0 );
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3ExprCachePop(pParse);
break;
}
case TK_OR: {
int d2 = sqlite3VdbeMakeLabel(v);
testcase( jumpIfNull==0 );
sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
sqlite3VdbeResolveLabel(v, d2);
sqlite3ExprCachePop(pParse);
break;
}
case TK_NOT: {
testcase( jumpIfNull==0 );
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
|
| ︙ | ︙ | |||
81463 81464 81465 81466 81467 81468 81469 81470 81471 81472 81473 81474 81475 81476 |
unsigned char const *zNew = sqlite3_value_text(argv[2]);
unsigned const char *z; /* Pointer to token */
int n; /* Length of token z */
int token; /* Type of token */
UNUSED_PARAMETER(NotUsed);
for(z=zInput; *z; z=z+n){
n = sqlite3GetToken(z, &token);
if( token==TK_REFERENCES ){
char *zParent;
do {
z += n;
n = sqlite3GetToken(z, &token);
| > | 81702 81703 81704 81705 81706 81707 81708 81709 81710 81711 81712 81713 81714 81715 81716 |
unsigned char const *zNew = sqlite3_value_text(argv[2]);
unsigned const char *z; /* Pointer to token */
int n; /* Length of token z */
int token; /* Type of token */
UNUSED_PARAMETER(NotUsed);
if( zInput==0 || zOld==0 ) return;
for(z=zInput; *z; z=z+n){
n = sqlite3GetToken(z, &token);
if( token==TK_REFERENCES ){
char *zParent;
do {
z += n;
n = sqlite3GetToken(z, &token);
|
| ︙ | ︙ | |||
87457 87458 87459 87460 87461 87462 87463 | ** records into the sorter. */ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); regRecord = sqlite3GetTempReg(pParse); sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); | | | 87697 87698 87699 87700 87701 87702 87703 87704 87705 87706 87707 87708 87709 87710 87711 |
** records into the sorter. */
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
regRecord = sqlite3GetTempReg(pParse);
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
(char *)pKey, P4_KEYINFO);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
|
| ︙ | ︙ | |||
90234 90235 90236 90237 90238 90239 90240 |
if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
if( pIdx==pPk ) continue;
VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
&iPartIdxLabel, pPrior, r1);
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
| | > | | 90474 90475 90476 90477 90478 90479 90480 90481 90482 90483 90484 90485 90486 90487 90488 90489 90490 90491 90492 90493 90494 90495 90496 90497 90498 90499 90500 90501 90502 90503 90504 90505 90506 90507 90508 90509 90510 90511 |
if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
if( pIdx==pPk ) continue;
VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
&iPartIdxLabel, pPrior, r1);
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
pPrior = pIdx;
}
}
/*
** Generate code that will assemble an index key and stores it in register
** regOut. The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to
** the entry that needs indexing. If pTab is a WITHOUT ROWID table, then
** iCur must be the cursor of the PRIMARY KEY index.
**
** Return a register number which is the first in a block of
** registers that holds the elements of the index key. The
** block of registers has already been deallocated by the time
** this routine returns.
**
** If *piPartIdxLabel is not NULL, fill it in with a label and jump
** to that label if pIdx is a partial index that should be skipped.
** The label should be resolved using sqlite3ResolvePartIdxLabel().
** A partial index should be skipped if its WHERE clause evaluates
** to false or null. If pIdx is not a partial index, *piPartIdxLabel
** will be set to zero which is an empty label that is ignored by
** sqlite3ResolvePartIdxLabel().
**
** The pPrior and regPrior parameters are used to implement a cache to
** avoid unnecessary register loads. If pPrior is not NULL, then it is
** a pointer to a different index for which an index key has just been
** computed into register regPrior. If the current pIdx index is generating
** its key into the same sequence of registers and if pPrior and pIdx share
** a column in common, then the register corresponding to that column already
|
| ︙ | ︙ | |||
90289 90290 90291 90292 90293 90294 90295 90296 90297 90298 90299 90300 90301 90302 |
int regBase;
int nCol;
if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
pParse->iPartIdxTab = iDataCur;
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
}else{
*piPartIdxLabel = 0;
}
}
nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
| > | 90530 90531 90532 90533 90534 90535 90536 90537 90538 90539 90540 90541 90542 90543 90544 |
int regBase;
int nCol;
if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
pParse->iPartIdxTab = iDataCur;
sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
}else{
*piPartIdxLabel = 0;
}
}
nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
|
| ︙ | ︙ | |||
90316 90317 90318 90319 90320 90321 90322 90323 90324 90325 90326 90327 90328 90329 |
}
if( regOut ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
}
sqlite3ReleaseTempRange(pParse, regBase, nCol);
return regBase;
}
/************** End of delete.c **********************************************/
/************** Begin file func.c ********************************************/
/*
** 2002 February 23
**
** The author disclaims copyright to this source code. In place of
| > > > > > > > > > > > > | 90558 90559 90560 90561 90562 90563 90564 90565 90566 90567 90568 90569 90570 90571 90572 90573 90574 90575 90576 90577 90578 90579 90580 90581 90582 90583 |
}
if( regOut ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
}
sqlite3ReleaseTempRange(pParse, regBase, nCol);
return regBase;
}
/*
** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label
** because it was a partial index, then this routine should be called to
** resolve that label.
*/
SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
if( iLabel ){
sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
sqlite3ExprCachePop(pParse);
}
}
/************** End of delete.c **********************************************/
/************** Begin file func.c ********************************************/
/*
** 2002 February 23
**
** The author disclaims copyright to this source code. In place of
|
| ︙ | ︙ | |||
98714 98715 98716 98717 98718 98719 98720 |
/* Do the b-tree integrity checks */
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
P4_DYNAMIC);
| | | 98968 98969 98970 98971 98972 98973 98974 98975 98976 98977 98978 98979 98980 98981 98982 |
/* Do the b-tree integrity checks */
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
P4_DYNAMIC);
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
*/
for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
|
| ︙ | ︙ | |||
98767 98768 98769 98770 98771 98772 98773 |
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
sqlite3VdbeAddOp0(v, OP_Halt);
sqlite3VdbeJumpHere(v, jmp4);
sqlite3VdbeJumpHere(v, jmp2);
| | | 99021 99022 99023 99024 99025 99026 99027 99028 99029 99030 99031 99032 99033 99034 99035 |
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
sqlite3VdbeAddOp0(v, OP_Halt);
sqlite3VdbeJumpHere(v, jmp4);
sqlite3VdbeJumpHere(v, jmp2);
sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
"wrong # of entries in index ", P4_STATIC);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
| ︙ | ︙ | |||
100052 100053 100054 100055 100056 100057 100058 100059 100060 100061 100062 100063 100064 100065 |
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
*/
/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
*/
static void clearSelect(sqlite3 *db, Select *p){
sqlite3ExprListDelete(db, p->pEList);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 100306 100307 100308 100309 100310 100311 100312 100313 100314 100315 100316 100317 100318 100319 100320 100321 100322 100323 100324 100325 100326 100327 100328 100329 100330 100331 100332 100333 100334 100335 100336 100337 100338 100339 100340 100341 100342 100343 100344 100345 100346 100347 |
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
*/
/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
** into the selectInnerLoop() routine.
*/
typedef struct DistinctCtx DistinctCtx;
struct DistinctCtx {
u8 isTnct; /* True if the DISTINCT keyword is present */
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
int tabTnct; /* Ephemeral table used for DISTINCT processing */
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
};
/*
** An instance of the following object is used to record information about
** the ORDER BY (or GROUP BY) clause of query is being coded.
*/
typedef struct SortCtx SortCtx;
struct SortCtx {
ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */
int nOBSat; /* Number of ORDER BY terms satisfied by indices */
int iECursor; /* Cursor number for the sorter */
int regReturn; /* Register holding block-output return address */
int labelBkOut; /* Start label for the block-output subroutine */
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
*/
static void clearSelect(sqlite3 *db, Select *p){
sqlite3ExprListDelete(db, p->pEList);
|
| ︙ | ︙ | |||
100125 100126 100127 100128 100129 100130 100131 | pNew->selFlags = selFlags; pNew->op = TK_SELECT; pNew->pLimit = pLimit; pNew->pOffset = pOffset; assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; | < | 100407 100408 100409 100410 100411 100412 100413 100414 100415 100416 100417 100418 100419 100420 |
pNew->selFlags = selFlags;
pNew->op = TK_SELECT;
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
assert( pOffset==0 || pLimit!=0 );
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
if( db->mallocFailed ) {
clearSelect(db, pNew);
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
pNew = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
}
|
| ︙ | ︙ | |||
100457 100458 100459 100460 100461 100462 100463 100464 |
isOuter, &p->pWhere);
}
}
}
return 0;
}
/*
| > > > > > > > > | | | | > | | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | > | | > | | | | 100738 100739 100740 100741 100742 100743 100744 100745 100746 100747 100748 100749 100750 100751 100752 100753 100754 100755 100756 100757 100758 100759 100760 100761 100762 100763 100764 100765 100766 100767 100768 100769 100770 100771 100772 100773 100774 100775 100776 100777 100778 100779 100780 100781 100782 100783 100784 100785 100786 100787 100788 100789 100790 100791 100792 100793 100794 100795 100796 100797 100798 100799 100800 100801 100802 100803 100804 100805 100806 100807 100808 100809 100810 100811 100812 100813 100814 100815 100816 100817 100818 100819 100820 100821 100822 100823 100824 100825 100826 100827 100828 100829 100830 100831 100832 100833 100834 100835 100836 100837 100838 100839 100840 100841 100842 100843 100844 100845 100846 100847 |
isOuter, &p->pWhere);
}
}
}
return 0;
}
/* Forward reference */
static KeyInfo *keyInfoFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* Form the KeyInfo object from this ExprList */
int iStart, /* Begin with this column of pList */
int nExtra /* Add this many extra columns to the end */
);
/*
** Insert code into "v" that will push the record in register regData
** into the sorter.
*/
static void pushOntoSorter(
Parse *pParse, /* Parser context */
SortCtx *pSort, /* Information about the ORDER BY clause */
Select *pSelect, /* The whole SELECT statement */
int regData /* Register holding data to be sorted */
){
Vdbe *v = pParse->pVdbe;
int nExpr = pSort->pOrderBy->nExpr;
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
int regRecord = sqlite3GetTempReg(pParse);
int nOBSat = pSort->nOBSat;
int op;
sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat, regRecord);
if( nOBSat>0 ){
int regPrevKey; /* The first nOBSat columns of the previous row */
int addrFirst; /* Address of the OP_IfNot opcode */
int addrJmp; /* Address of the OP_Jump opcode */
VdbeOp *pOp; /* Opcode that opens the sorter */
int nKey; /* Number of sorting key columns, including OP_Sequence */
KeyInfo *pKI; /* Original KeyInfo on the sorter table */
regPrevKey = pParse->nMem+1;
pParse->nMem += pSort->nOBSat;
nKey = nExpr - pSort->nOBSat + 1;
addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
if( pParse->db->mallocFailed ) return;
pOp->p2 = nKey + 1;
pKI = pOp->p4.pKeyInfo;
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
pSort->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
sqlite3VdbeJumpHere(v, addrFirst);
sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
sqlite3VdbeJumpHere(v, addrJmp);
}
if( pSort->sortFlags & SORTFLAG_UseSorter ){
op = OP_SorterInsert;
}else{
op = OP_IdxInsert;
}
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( nOBSat==0 ){
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
}
if( pSelect->iLimit ){
int addr1, addr2;
int iLimit;
if( pSelect->iOffset ){
iLimit = pSelect->iOffset+1;
}else{
iLimit = pSelect->iLimit;
}
addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
sqlite3VdbeJumpHere(v, addr2);
}
}
/*
** Add code to implement the OFFSET
*/
static void codeOffset(
Vdbe *v, /* Generate code into this VM */
int iOffset, /* Register holding the offset counter */
int iContinue /* Jump here to skip the current record */
){
if( iOffset>0 ){
int addr;
sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
VdbeComment((v, "skip OFFSET records"));
sqlite3VdbeJumpHere(v, addr);
}
|
| ︙ | ︙ | |||
100572 100573 100574 100575 100576 100577 100578 |
return 1;
}else{
return 0;
}
}
#endif
| < < < < < < < < < < < < < | > | > | 100894 100895 100896 100897 100898 100899 100900 100901 100902 100903 100904 100905 100906 100907 100908 100909 100910 100911 100912 100913 100914 100915 100916 100917 100918 100919 100920 100921 100922 100923 100924 100925 100926 100927 100928 100929 100930 100931 100932 100933 100934 100935 100936 100937 100938 100939 100940 100941 |
return 1;
}else{
return 0;
}
}
#endif
/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
** If srcTab is negative, then the pEList expressions
** are evaluated in order to get the data for this row. If srcTab is
** zero or more, then data is pulled from srcTab and pEList is used only
** to get number columns and the datatype for each column.
*/
static void selectInnerLoop(
Parse *pParse, /* The parser context */
Select *p, /* The complete select statement being coded */
ExprList *pEList, /* List of values being extracted */
int srcTab, /* Pull data from this table */
SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
SelectDest *pDest, /* How to dispose of the results */
int iContinue, /* Jump here to continue with next row */
int iBreak /* Jump here to break out of the inner loop */
){
Vdbe *v = pParse->pVdbe;
int i;
int hasDistinct; /* True if the DISTINCT keyword is present */
int regResult; /* Start of memory holding result set */
int eDest = pDest->eDest; /* How to dispose of results */
int iParm = pDest->iSDParm; /* First argument to disposal method */
int nResultCol; /* Number of result columns */
assert( v );
assert( pEList!=0 );
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
if( pSort && pSort->pOrderBy==0 ) pSort = 0;
if( pSort==0 && !hasDistinct ){
assert( iContinue!=0 );
codeOffset(v, p->iOffset, iContinue);
}
/* Pull the requested columns.
*/
nResultCol = pEList->nExpr;
|
| ︙ | ︙ | |||
100706 100707 100708 100709 100710 100711 100712 |
default: {
assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult);
break;
}
}
| | | 101017 101018 101019 101020 101021 101022 101023 101024 101025 101026 101027 101028 101029 101030 101031 |
default: {
assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult);
break;
}
}
if( pSort==0 ){
codeOffset(v, p->iOffset, iContinue);
}
}
switch( eDest ){
/* In this mode, write each query result to the key of the temporary
** table iParm.
|
| ︙ | ︙ | |||
100737 100738 100739 100740 100741 100742 100743 |
sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol);
break;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
/* Store the result as data using a unique key.
*/
| > | | | | | | | | | 101048 101049 101050 101051 101052 101053 101054 101055 101056 101057 101058 101059 101060 101061 101062 101063 101064 101065 101066 101067 101068 101069 101070 101071 101072 101073 101074 101075 101076 101077 101078 101079 101080 101081 101082 101083 101084 101085 101086 101087 101088 101089 101090 101091 101092 101093 101094 101095 101096 101097 101098 101099 101100 101101 101102 101103 101104 101105 101106 101107 101108 101109 101110 |
sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol);
break;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
/* Store the result as data using a unique key.
*/
case SRT_Fifo:
case SRT_DistFifo:
case SRT_Table:
case SRT_EphemTab: {
int r1 = sqlite3GetTempReg(pParse);
testcase( eDest==SRT_Table );
testcase( eDest==SRT_EphemTab );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
** on an ephemeral index. If the current row is already present
** in the index, do not write it to the output. If not, add the
** current row to the index and proceed with writing it to the
** output table as well. */
int addr = sqlite3VdbeCurrentAddr(v) + 4;
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
assert( pSort==0 );
}
#endif
if( pSort ){
pushOntoSorter(pParse, pSort, p, r1);
}else{
int r2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3ReleaseTempReg(pParse, r2);
}
sqlite3ReleaseTempReg(pParse, r1);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
/* If we are creating a set for an "expr IN (SELECT ...)" construct,
** then there should be a single item on the stack. Write this
** item into the set table with bogus data.
*/
case SRT_Set: {
assert( nResultCol==1 );
pDest->affSdst =
sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
if( pSort ){
/* At first glance you would think we could optimize out the
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
pushOntoSorter(pParse, pSort, p, regResult);
}else{
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
}
|
| ︙ | ︙ | |||
100809 100810 100811 100812 100813 100814 100815 |
/* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
** of the scan loop.
*/
case SRT_Mem: {
assert( nResultCol==1 );
| | | | | | 101121 101122 101123 101124 101125 101126 101127 101128 101129 101130 101131 101132 101133 101134 101135 101136 101137 101138 101139 101140 101141 101142 101143 101144 101145 101146 101147 101148 101149 101150 101151 101152 |
/* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
** of the scan loop.
*/
case SRT_Mem: {
assert( nResultCol==1 );
if( pSort ){
pushOntoSorter(pParse, pSort, p, regResult);
}else{
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
/* The LIMIT clause will jump out of the loop for us */
}
break;
}
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
case SRT_Coroutine: /* Send data to a co-routine */
case SRT_Output: { /* Return the results */
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pSort ){
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
pushOntoSorter(pParse, pSort, p, r1);
sqlite3ReleaseTempReg(pParse, r1);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
}else{
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol);
sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
}
|
| ︙ | ︙ | |||
100903 100904 100905 100906 100907 100908 100909 | #endif } /* Jump to the end of the loop if the LIMIT is reached. Except, if ** there is a sorter, in which case the sorter has already limited ** the output for us. */ | | | 101215 101216 101217 101218 101219 101220 101221 101222 101223 101224 101225 101226 101227 101228 101229 |
#endif
}
/* Jump to the end of the loop if the LIMIT is reached. Except, if
** there is a sorter, in which case the sorter has already limited
** the output for us.
*/
if( pSort==0 && p->iLimit ){
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
}
}
/*
** Allocate a KeyInfo object sufficient for an index of N key columns and
** X extra columns.
|
| ︙ | ︙ | |||
100974 100975 100976 100977 100978 100979 100980 | ** then the KeyInfo structure is appropriate for initializing a virtual ** index to implement a DISTINCT test. ** ** Space to hold the KeyInfo structure is obtain from malloc. The calling ** function is responsible for seeing that this structure is eventually ** freed. */ | | > > > > > | | | | | 101286 101287 101288 101289 101290 101291 101292 101293 101294 101295 101296 101297 101298 101299 101300 101301 101302 101303 101304 101305 101306 101307 101308 101309 101310 101311 101312 101313 101314 101315 101316 101317 101318 101319 101320 101321 |
** then the KeyInfo structure is appropriate for initializing a virtual
** index to implement a DISTINCT test.
**
** Space to hold the KeyInfo structure is obtain from malloc. The calling
** function is responsible for seeing that this structure is eventually
** freed.
*/
static KeyInfo *keyInfoFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* Form the KeyInfo object from this ExprList */
int iStart, /* Begin with this column of pList */
int nExtra /* Add this many extra columns to the end */
){
int nExpr;
KeyInfo *pInfo;
struct ExprList_item *pItem;
sqlite3 *db = pParse->db;
int i;
nExpr = pList->nExpr;
pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 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;
}
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/*
|
| ︙ | ︙ | |||
101092 101093 101094 101095 101096 101097 101098 | ** then the results were placed in a sorter. After the loop is terminated ** we need to run the sorter and output the results. The following ** routine generates the code needed to do that. */ static void generateSortTail( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ | | > > | < < > > > > > > > | > | | > | > | | 101409 101410 101411 101412 101413 101414 101415 101416 101417 101418 101419 101420 101421 101422 101423 101424 101425 101426 101427 101428 101429 101430 101431 101432 101433 101434 101435 101436 101437 101438 101439 101440 101441 101442 101443 101444 101445 101446 101447 101448 101449 101450 101451 101452 101453 101454 101455 101456 101457 101458 101459 101460 101461 101462 101463 101464 101465 101466 101467 101468 101469 101470 101471 101472 |
** then the results were placed in a sorter. After the loop is terminated
** we need to run the sorter and output the results. The following
** routine generates the code needed to do that.
*/
static void generateSortTail(
Parse *pParse, /* Parsing context */
Select *p, /* The SELECT statement */
SortCtx *pSort, /* Information on the ORDER BY clause */
int nColumn, /* Number of columns of data */
SelectDest *pDest /* Write the sorted results here */
){
Vdbe *v = pParse->pVdbe; /* The prepared statement */
int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
int addr;
int addrOnce = 0;
int iTab;
int pseudoTab = 0;
ExprList *pOrderBy = pSort->pOrderBy;
int eDest = pDest->eDest;
int iParm = pDest->iSDParm;
int regRow;
int regRowid;
int nKey;
if( pSort->labelBkOut ){
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
}
iTab = pSort->iECursor;
regRow = sqlite3GetTempReg(pParse);
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
pseudoTab = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
regRowid = 0;
}else{
regRowid = sqlite3GetTempReg(pParse);
}
nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
int ptab2 = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow);
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
}else{
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow);
}
switch( eDest ){
case SRT_Table:
case SRT_EphemTab: {
testcase( eDest==SRT_Table );
testcase( eDest==SRT_EphemTab );
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
|
| ︙ | ︙ | |||
101186 101187 101188 101189 101190 101191 101192 | } sqlite3ReleaseTempReg(pParse, regRow); sqlite3ReleaseTempReg(pParse, regRowid); /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); | | > | 101513 101514 101515 101516 101517 101518 101519 101520 101521 101522 101523 101524 101525 101526 101527 101528 101529 101530 101531 101532 |
}
sqlite3ReleaseTempReg(pParse, regRow);
sqlite3ReleaseTempReg(pParse, regRowid);
/* The bottom of the loop
*/
sqlite3VdbeResolveLabel(v, addrContinue);
if( pSort->sortFlags & SORTFLAG_UseSorter ){
sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
}else{
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
}
if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
sqlite3VdbeResolveLabel(v, addrBreak);
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
}
}
/*
|
| ︙ | ︙ | |||
101872 101873 101874 101875 101876 101877 101878 | Select *pSetup = p->pPrior; /* The setup query */ int addrTop; /* Top of the loop */ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ int iCurrent = 0; /* The Current table */ int regCurrent; /* Register holding Current table */ int iQueue; /* The Queue table */ int iDistinct = 0; /* To ensure unique results if UNION */ | | | 102200 102201 102202 102203 102204 102205 102206 102207 102208 102209 102210 102211 102212 102213 102214 | Select *pSetup = p->pPrior; /* The setup query */ int addrTop; /* Top of the loop */ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ int iCurrent = 0; /* The Current table */ int regCurrent; /* Register holding Current table */ int iQueue; /* The Queue table */ int iDistinct = 0; /* To ensure unique results if UNION */ int eDest = SRT_Fifo; /* How to write to Queue */ SelectDest destQueue; /* SelectDest targetting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ ExprList *pOrderBy; /* The ORDER BY clause */ Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */ int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ |
| ︙ | ︙ | |||
101904 101905 101906 101907 101908 101909 101910 |
iCurrent = pSrc->a[i].iCursor;
break;
}
}
/* Allocate cursors numbers for Queue and Distinct. The cursor number for
** the Distinct table must be exactly one greater than Queue in order
| | | | | 102232 102233 102234 102235 102236 102237 102238 102239 102240 102241 102242 102243 102244 102245 102246 102247 102248 102249 102250 102251 102252 |
iCurrent = pSrc->a[i].iCursor;
break;
}
}
/* Allocate cursors numbers for Queue and Distinct. The cursor number for
** the Distinct table must be exactly one greater than Queue in order
** for the SRT_DistFifo and SRT_DistQueue destinations to work. */
iQueue = pParse->nTab++;
if( p->op==TK_UNION ){
eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo;
iDistinct = pParse->nTab++;
}else{
eDest = pOrderBy ? SRT_Queue : SRT_Fifo;
}
sqlite3SelectDestInit(&destQueue, eDest, iQueue);
/* Allocate cursors for Current, Queue, and Distinct. */
regCurrent = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol);
if( pOrderBy ){
|
| ︙ | ︙ | |||
101976 101977 101978 101979 101980 101981 101982 101983 101984 101985 101986 101987 101988 101989 | p->pPrior = pSetup; /* Keep running the loop until the Queue is empty */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: p->pOrderBy = pOrderBy; p->pLimit = pLimit; p->pOffset = pOffset; return; } #endif /* SQLITE_OMIT_CTE */ | > | 102304 102305 102306 102307 102308 102309 102310 102311 102312 102313 102314 102315 102316 102317 102318 | p->pPrior = pSetup; /* Keep running the loop until the Queue is empty */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: sqlite3ExprListDelete(pParse->db, p->pOrderBy); p->pOrderBy = pOrderBy; p->pLimit = pLimit; p->pOffset = pOffset; return; } #endif /* SQLITE_OMIT_CTE */ |
| ︙ | ︙ | |||
104347 104348 104349 104350 104351 104352 104353 |
Expr *pE = pFunc->pExpr;
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
"argument");
pFunc->iDistinct = -1;
}else{
| | | 104676 104677 104678 104679 104680 104681 104682 104683 104684 104685 104686 104687 104688 104689 104690 |
Expr *pE = pFunc->pExpr;
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
"argument");
pFunc->iDistinct = -1;
}else{
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO);
}
}
}
}
|
| ︙ | ︙ | |||
104502 104503 104504 104505 104506 104507 104508 | int i, j; /* Loop counters */ WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */ Vdbe *v; /* The virtual machine under construction */ int isAgg; /* True for select lists like "count(*)" */ ExprList *pEList; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ | < < > > > > > | > > > | | 104831 104832 104833 104834 104835 104836 104837 104838 104839 104840 104841 104842 104843 104844 104845 104846 104847 104848 104849 104850 104851 104852 104853 104854 104855 104856 104857 104858 104859 104860 104861 104862 104863 104864 104865 104866 104867 104868 104869 104870 104871 104872 104873 104874 104875 104876 104877 104878 104879 104880 104881 104882 104883 |
int i, j; /* Loop counters */
WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */
Vdbe *v; /* The virtual machine under construction */
int isAgg; /* True for select lists like "count(*)" */
ExprList *pEList; /* List of columns to extract. */
SrcList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
Expr *pHaving; /* The HAVING clause. May be NULL */
int rc = 1; /* Value to return from this function */
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
SortCtx sSort; /* Info on how to code the ORDER BY clause */
AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
#ifndef SQLITE_OMIT_EXPLAIN
int iRestoreSelectId = pParse->iSelectId;
pParse->iSelectId = pParse->iNextSelectId++;
#endif
db = pParse->db;
if( p==0 || db->mallocFailed || pParse->nErr ){
return 1;
}
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
memset(&sAggInfo, 0, sizeof(sAggInfo));
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
if( IgnorableOrderby(pDest) ){
assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
/* If ORDER BY makes no difference in the output then neither does
** DISTINCT so it can be removed too. */
sqlite3ExprListDelete(db, p->pOrderBy);
p->pOrderBy = 0;
p->selFlags &= ~SF_Distinct;
}
sqlite3SelectPrep(pParse, p, 0);
memset(&sSort, 0, sizeof(sSort));
sSort.pOrderBy = p->pOrderBy;
pTabList = p->pSrc;
pEList = p->pEList;
if( pParse->nErr || db->mallocFailed ){
goto select_end;
}
isAgg = (p->selFlags & SF_Aggregate)!=0;
assert( pEList!=0 );
|
| ︙ | ︙ | |||
104656 104657 104658 104659 104660 104661 104662 |
}
if( /*pParse->nErr ||*/ db->mallocFailed ){
goto select_end;
}
pParse->nHeight -= sqlite3SelectExprHeight(p);
pTabList = p->pSrc;
if( !IgnorableOrderby(pDest) ){
| | | 104991 104992 104993 104994 104995 104996 104997 104998 104999 105000 105001 105002 105003 105004 105005 |
}
if( /*pParse->nErr ||*/ db->mallocFailed ){
goto select_end;
}
pParse->nHeight -= sqlite3SelectExprHeight(p);
pTabList = p->pSrc;
if( !IgnorableOrderby(pDest) ){
sSort.pOrderBy = p->pOrderBy;
}
}
pEList = p->pEList;
#endif
pWhere = p->pWhere;
pGroupBy = p->pGroupBy;
pHaving = p->pHaving;
|
| ︙ | ︙ | |||
104683 104684 104685 104686 104687 104688 104689 | /* If there is both a GROUP BY and an ORDER BY clause and they are ** identical, then disable the ORDER BY clause since the GROUP BY ** will cause elements to come out in the correct order. This is ** an optimization - the correct answer should result regardless. ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER ** to disable this optimization for testing purposes. */ | | | | | | | | | | | | | | | | | > | > > > > | | < | | 105018 105019 105020 105021 105022 105023 105024 105025 105026 105027 105028 105029 105030 105031 105032 105033 105034 105035 105036 105037 105038 105039 105040 105041 105042 105043 105044 105045 105046 105047 105048 105049 105050 105051 105052 105053 105054 105055 105056 105057 105058 105059 105060 105061 105062 105063 105064 105065 105066 105067 105068 105069 105070 105071 105072 105073 105074 105075 105076 105077 105078 105079 105080 105081 105082 105083 105084 105085 105086 105087 105088 105089 105090 105091 105092 105093 105094 105095 105096 105097 105098 105099 105100 105101 105102 105103 105104 105105 105106 105107 105108 105109 105110 105111 105112 105113 105114 105115 105116 105117 105118 105119 105120 105121 105122 105123 105124 105125 105126 105127 105128 105129 105130 105131 105132 105133 105134 105135 105136 105137 105138 105139 105140 105141 105142 105143 105144 |
/* If there is both a GROUP BY and an ORDER BY clause and they are
** identical, then disable the ORDER BY clause since the GROUP BY
** will cause elements to come out in the correct order. This is
** an optimization - the correct answer should result regardless.
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
** to disable this optimization for testing purposes.
*/
if( sqlite3ExprListCompare(p->pGroupBy, sSort.pOrderBy, -1)==0
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
sSort.pOrderBy = 0;
}
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
** if the select-list is the same as the ORDER BY list, then this query
** can be rewritten as a GROUP BY. In other words, this:
**
** SELECT DISTINCT xyz FROM ... ORDER BY xyz
**
** is transformed to:
**
** SELECT xyz FROM ... GROUP BY xyz
**
** The second form is preferred as a single index (or temp-table) may be
** used for both the ORDER BY and DISTINCT processing. As originally
** written the query must use a temp-table for at least one of the ORDER
** BY and DISTINCT, and an index or separate temp-table for the other.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
){
p->selFlags &= ~SF_Distinct;
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
sSort.pOrderBy = 0;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
assert( sDistinct.isTnct );
}
/* If there is an ORDER BY clause, then this sorting
** index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the
** OP_OpenEphemeral instruction will be changed to an OP_Noop once
** we figure out that the sorting index is not needed. The addrSortIndex
** variable is used to facilitate that change.
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
sSort.iECursor = pParse->nTab++;
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
sSort.iECursor, sSort.pOrderBy->nExpr+2, 0,
(char*)pKeyInfo, P4_KEYINFO);
}else{
sSort.addrSortIndex = -1;
}
/* If the output is destined for a temporary table, open that table.
*/
if( pDest->eDest==SRT_EphemTab ){
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
}
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
p->nSelectRow = LARGEST_INT64;
computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
sSort.sortFlags |= SORTFLAG_UseSorter;
}
/* Open a virtual index to use for the distinct set.
*/
if( p->selFlags & SF_Distinct ){
sDistinct.tabTnct = pParse->nTab++;
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
sDistinct.tabTnct, 0, 0,
(char*)keyInfoFromExprList(pParse, p->pEList,0,0),
P4_KEYINFO);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
}else{
sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
}
if( !isAgg && pGroupBy==0 ){
/* No aggregate functions and no GROUP BY clause */
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
/* Begin the database scan. */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
p->pEList, wctrlFlags, 0);
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
}
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
}
if( sSort.pOrderBy ){
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
sSort.pOrderBy = 0;
}
}
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
** into an OP_Noop.
*/
if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
}
/* Use the standard inner loop. */
selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
sqlite3WhereContinueLabel(pWInfo),
sqlite3WhereBreakLabel(pWInfo));
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
}else{
|
| ︙ | ︙ | |||
104847 104848 104849 104850 104851 104852 104853 |
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
sNC.pAggInfo = &sAggInfo;
sAggInfo.mnReg = pParse->nMem+1;
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
sAggInfo.pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
| | | 105186 105187 105188 105189 105190 105191 105192 105193 105194 105195 105196 105197 105198 105199 105200 |
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
sNC.pAggInfo = &sAggInfo;
sAggInfo.mnReg = pParse->nMem+1;
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
sAggInfo.pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
if( pHaving ){
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
sNC.ncFlags |= NC_InAggFunc;
|
| ︙ | ︙ | |||
104881 104882 104883 104884 104885 104886 104887 |
/* If there is a GROUP BY clause we might need a sorting index to
** implement it. Allocate that sorting index now. If it turns out
** that we do not need it after all, the OP_SorterOpen instruction
** will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
| | | 105220 105221 105222 105223 105224 105225 105226 105227 105228 105229 105230 105231 105232 105233 105234 |
/* If there is a GROUP BY clause we might need a sorting index to
** implement it. Allocate that sorting index now. If it turns out
** that we do not need it after all, the OP_SorterOpen instruction
** will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);
/* Initialize memory locations used by GROUP BY aggregate processing
*/
iUseFlag = ++pParse->nMem;
|
| ︙ | ︙ | |||
104910 104911 104912 104913 104914 104915 104916 |
/* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
** it might be a single loop that uses an index to extract information
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
| | | | 105249 105250 105251 105252 105253 105254 105255 105256 105257 105258 105259 105260 105261 105262 105263 105264 105265 105266 |
/* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
** it might be a single loop that uses an index to extract information
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
WHERE_GROUPBY, 0);
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
/* The optimizer is able to deliver rows in group by order so
** we do not have to sort. The OP_OpenEphemeral table will be
** cancelled later because we still need to use the pKeyInfo
*/
groupBySort = 0;
}else{
/* Rows are coming out in undetermined order. We have to push
|
| ︙ | ︙ | |||
105064 105065 105066 105067 105068 105069 105070 |
sqlite3VdbeResolveLabel(v, addrOutputRow);
addrOutputRow = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v);
VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
| | | 105403 105404 105405 105406 105407 105408 105409 105410 105411 105412 105413 105414 105415 105416 105417 |
sqlite3VdbeResolveLabel(v, addrOutputRow);
addrOutputRow = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v);
VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
&sDistinct, pDest,
addrOutputRow+1, addrSetAbort);
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
VdbeComment((v, "end groupby result generator"));
/* Generate a subroutine that will reset the group-by accumulator
*/
|
| ︙ | ︙ | |||
105196 105197 105198 105199 105200 105201 105202 |
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
assert( pMinMax==0 || pMinMax->nExpr==1 );
| | | | | | | 105535 105536 105537 105538 105539 105540 105541 105542 105543 105544 105545 105546 105547 105548 105549 105550 105551 105552 105553 105554 105555 105556 105557 105558 105559 105560 105561 105562 105563 105564 105565 105566 105567 105568 105569 105570 105571 105572 105573 105574 105575 105576 105577 |
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
assert( pMinMax==0 || pMinMax->nExpr==1 );
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
VdbeComment((v, "%s() by index",
(flag==WHERE_ORDERBY_MIN?"min":"max")));
}
sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, &sAggInfo);
}
sSort.pOrderBy = 0;
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
}
sqlite3VdbeResolveLabel(v, addrEnd);
} /* endif aggregate query */
if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
explainTempTable(pParse, "DISTINCT");
}
/* If there is an ORDER BY clause, then we need to sort the results
** and send them to the callback one by one.
*/
if( sSort.pOrderBy ){
explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
}
/* Jump here to skip this query
*/
sqlite3VdbeResolveLabel(v, iEnd);
/* The SELECT was successfully coded. Set the return code to 0
|
| ︙ | ︙ | |||
109062 109063 109064 109065 109066 109067 109068 |
u16 nEq; /* Number of equality constraints */
u16 nSkip; /* Number of initial index columns to skip */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
int idxNum; /* Index number */
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
| | | 109401 109402 109403 109404 109405 109406 109407 109408 109409 109410 109411 109412 109413 109414 109415 |
u16 nEq; /* Number of equality constraints */
u16 nSkip; /* Number of initial index columns to skip */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
int idxNum; /* Index number */
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
i8 isOrdered; /* True if satisfies ORDER BY */
u16 omitMask; /* Terms that may be omitted */
char *idxStr; /* Index identifier string */
} vtab;
} u;
u32 wsFlags; /* WHERE_* flags describing the plan */
u16 nLTerm; /* Number of entries in aLTerm[] */
/**** whereLoopXfer() copies fields above ***********************/
|
| ︙ | ︙ | |||
109124 109125 109126 109127 109128 109129 109130 |
** at the end is the choosen query plan.
*/
struct WherePath {
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
| | < | 109463 109464 109465 109466 109467 109468 109469 109470 109471 109472 109473 109474 109475 109476 109477 |
** at the end is the choosen query plan.
*/
struct WherePath {
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
};
/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause. Each WHERE
** clause subexpression is separated from the others by AND operators,
|
| ︙ | ︙ | |||
109339 109340 109341 109342 109343 109344 109345 | SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pResultSet; /* Result set. DISTINCT operates on these */ WhereLoop *pLoops; /* List of all WhereLoop objects */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ LogEst nRowOut; /* Estimated number of output rows */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ | | | 109677 109678 109679 109680 109681 109682 109683 109684 109685 109686 109687 109688 109689 109690 109691 | SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pResultSet; /* Result set. DISTINCT operates on these */ WhereLoop *pLoops; /* List of all WhereLoop objects */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ LogEst nRowOut; /* Estimated number of output rows */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ u8 nLevel; /* Number of nested loop */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ |
| ︙ | ︙ | |||
109423 109424 109425 109426 109427 109428 109429 |
}
/*
** Return TRUE if the WHERE clause returns rows in ORDER BY order.
** Return FALSE if the output needs to be sorted.
*/
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
| | > | 109761 109762 109763 109764 109765 109766 109767 109768 109769 109770 109771 109772 109773 109774 109775 109776 109777 109778 109779 109780 109781 109782 109783 |
}
/*
** Return TRUE if the WHERE clause returns rows in ORDER BY order.
** Return FALSE if the output needs to be sorted.
*/
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
return pWInfo->nOBSat;
}
/*
** Return the VDBE address or label to jump to in order to continue
** immediately with the next row of a WHERE clause.
*/
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){
assert( pWInfo->iContinue!=0 );
return pWInfo->iContinue;
}
/*
** Return the VDBE address or label to jump to in order to break
** out of a WHERE loop.
*/
|
| ︙ | ︙ | |||
112224 112225 112226 112227 112228 112229 112230 |
disableTerm(pLevel, pLoop->aLTerm[j]);
}
}
pLevel->op = OP_VNext;
pLevel->p1 = iCur;
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
| | | 112563 112564 112565 112566 112567 112568 112569 112570 112571 112572 112573 112574 112575 112576 112577 |
disableTerm(pLevel, pLoop->aLTerm[j]);
}
}
pLevel->op = OP_VNext;
pLevel->p1 = iCur;
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
sqlite3ExprCachePop(pParse);
}else
#endif /* SQLITE_OMIT_VIRTUALTABLE */
if( (pLoop->wsFlags & WHERE_IPK)!=0
&& (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
){
/* Case 2: We can directly reference a single row using an
|
| ︙ | ︙ | |||
112420 112421 112422 112423 112424 112425 112426 112427 |
** was passed to this function to implement a "SELECT min(x) ..."
** query, then the caller will only allow the loop to run for
** a single iteration. This means that the first row returned
** should not have a NULL value stored in 'x'. If column 'x' is
** the first one after the nEq equality constraints in the index,
** this requires some special handling.
*/
if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
| > > > | | 112759 112760 112761 112762 112763 112764 112765 112766 112767 112768 112769 112770 112771 112772 112773 112774 112775 112776 112777 |
** was passed to this function to implement a "SELECT min(x) ..."
** query, then the caller will only allow the loop to run for
** a single iteration. This means that the first row returned
** should not have a NULL value stored in 'x'. If column 'x' is
** the first one after the nEq equality constraints in the index,
** this requires some special handling.
*/
assert( pWInfo->pOrderBy==0
|| pWInfo->pOrderBy->nExpr==1
|| (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
&& pWInfo->nOBSat>0
&& (pIdx->nKeyCol>nEq)
){
assert( pLoop->u.btree.nSkip==0 );
bSeekPastNull = 1;
nExtraReg = 1;
}
|
| ︙ | ︙ | |||
112592 112593 112594 112595 112596 112597 112598 |
pLevel->op = OP_Noop;
}else if( bRev ){
pLevel->op = OP_Prev;
}else{
pLevel->op = OP_Next;
}
pLevel->p1 = iIdxCur;
| < | | 112934 112935 112936 112937 112938 112939 112940 112941 112942 112943 112944 112945 112946 112947 112948 |
pLevel->op = OP_Noop;
}else if( bRev ){
pLevel->op = OP_Prev;
}else{
pLevel->op = OP_Next;
}
pLevel->p1 = iIdxCur;
pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}else{
assert( pLevel->p5==0 );
}
}else
|
| ︙ | ︙ | |||
113091 113092 113093 113094 113095 113096 113097 113098 113099 113100 113101 113102 113103 113104 113105 113106 113107 |
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
sqlite3DbFree(db, pWInfo);
}
}
/*
** Insert or replace a WhereLoop entry using the template supplied.
**
** An existing WhereLoop entry might be overwritten if the new template
** is better and has fewer dependencies. Or the template will be ignored
** and no insert will occur if an existing WhereLoop is faster and has
** fewer dependencies than the template. Otherwise a new WhereLoop is
** added based on the template.
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < | | 113432 113433 113434 113435 113436 113437 113438 113439 113440 113441 113442 113443 113444 113445 113446 113447 113448 113449 113450 113451 113452 113453 113454 113455 113456 113457 113458 113459 113460 113461 113462 113463 113464 113465 113466 113467 113468 113469 113470 113471 113472 113473 113474 113475 113476 113477 113478 113479 113480 113481 113482 113483 113484 113485 113486 113487 113488 113489 113490 113491 113492 113493 113494 113495 113496 113497 113498 113499 113500 113501 113502 113503 113504 113505 113506 113507 113508 113509 113510 113511 113512 113513 113514 113515 113516 113517 113518 113519 113520 113521 113522 113523 113524 113525 113526 113527 113528 113529 113530 113531 113532 113533 113534 113535 113536 113537 113538 113539 113540 113541 113542 113543 113544 113545 113546 113547 113548 113549 113550 113551 113552 113553 113554 113555 113556 113557 113558 113559 113560 113561 113562 113563 113564 113565 113566 113567 113568 113569 113570 113571 113572 113573 113574 113575 113576 113577 113578 113579 113580 113581 113582 113583 113584 113585 113586 113587 113588 113589 113590 113591 113592 113593 113594 113595 113596 113597 113598 113599 113600 113601 113602 113603 |
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
sqlite3DbFree(db, pWInfo);
}
}
/*
** Return TRUE if both of the following are true:
**
** (1) X has the same or lower cost that Y
** (2) X is a proper subset of Y
**
** By "proper subset" we mean that X uses fewer WHERE clause terms
** than Y and that every WHERE clause term used by X is also used
** by Y.
**
** If X is a proper subset of Y then Y is a better choice and ought
** to have a lower cost. This routine returns TRUE when that cost
** relationship is inverted and needs to be adjusted.
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
const WhereLoop *pY /* Compare against this WhereLoop */
){
int i, j;
if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */
if( pX->rRun >= pY->rRun ){
if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
}
for(j=0, i=pX->nLTerm-1; i>=0; i--){
for(j=pY->nLTerm-1; j>=0; j--){
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
}
if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
}
return 1; /* All conditions meet */
}
/*
** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
** that:
**
** (1) pTemplate costs less than any other WhereLoops that are a proper
** subset of pTemplate
**
** (2) pTemplate costs more than any other WhereLoops for which pTemplate
** is a proper subset.
**
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
for(; p; p=p->pNextLoop){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
if( whereLoopCheaperProperSubset(p, pTemplate) ){
/* Adjust pTemplate cost downward so that it is cheaper than its
** subset p */
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut - 1;
}else if( whereLoopCheaperProperSubset(pTemplate, p) ){
/* Adjust pTemplate cost upward so that it is costlier than p since
** pTemplate is a proper subset of p */
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut + 1;
}
}
}
/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
** supplanted by pTemplate.
**
** Return NULL if the WhereLoop list contains an entry that can supplant
** pTemplate, in other words if pTemplate does not belong on the list.
**
** If pX is a WhereLoop that pTemplate can supplant, then return the
** link that points to pX.
**
** If pTemplate cannot supplant any existing element of the list but needs
** to be added to the list, then return a pointer to the tail of the list.
*/
static WhereLoop **whereLoopFindLesser(
WhereLoop **ppPrev,
const WhereLoop *pTemplate
){
WhereLoop *p;
for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){
if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
/* If either the iTab or iSortIdx values for two WhereLoop are different
** then those WhereLoops need to be considered separately. Neither is
** a candidate to replace the other. */
continue;
}
/* In the current implementation, the rSetup value is either zero
** or the cost of building an automatic index (NlogN) and the NlogN
** is the same for compatible WhereLoops. */
assert( p->rSetup==0 || pTemplate->rSetup==0
|| p->rSetup==pTemplate->rSetup );
/* whereLoopAddBtree() always generates and inserts the automatic index
** case first. Hence compatible candidate WhereLoops never have a larger
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
/* If existing WhereLoop p is better than pTemplate, pTemplate can be
** discarded. WhereLoop p is better if:
** (1) p has no more dependencies than pTemplate, and
** (2) p has an equal or lower cost than pTemplate
*/
if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */
&& p->rSetup<=pTemplate->rSetup /* (2a) */
&& p->rRun<=pTemplate->rRun /* (2b) */
&& p->nOut<=pTemplate->nOut /* (2c) */
){
return 0; /* Discard pTemplate */
}
/* If pTemplate is always better than p, then cause p to be overwritten
** with pTemplate. pTemplate is better than p if:
** (1) pTemplate has no more dependences than p, and
** (2) pTemplate has an equal or lower cost than p.
*/
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
&& p->rRun>=pTemplate->rRun /* (2a) */
&& p->nOut>=pTemplate->nOut /* (2b) */
){
assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
break; /* Cause p to be overwritten by pTemplate */
}
}
return ppPrev;
}
/*
** Insert or replace a WhereLoop entry using the template supplied.
**
** An existing WhereLoop entry might be overwritten if the new template
** is better and has fewer dependencies. Or the template will be ignored
** and no insert will occur if an existing WhereLoop is faster and has
** fewer dependencies than the template. Otherwise a new WhereLoop is
** added based on the template.
**
** If pBuilder->pOrSet is not NULL then we care about only the
** prerequisites and rRun and nOut costs of the N best loops. That
** information is gathered in the pBuilder->pOrSet object. This special
** processing mode is used only for OR clause processing.
**
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
** still might overwrite similar loops with the new template if the
** new template is better. Loops may be overwritten if the following
** conditions are met:
**
** (1) They have the same iTab.
** (2) They have the same iSortIdx.
** (3) The template has same or fewer dependencies than the current loop
** (4) The template has the same or lower cost than the current loop
*/
static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
WhereLoop **ppPrev, *p;
WhereInfo *pWInfo = pBuilder->pWInfo;
sqlite3 *db = pWInfo->pParse->db;
/* If pBuilder->pOrSet is defined, then only keep track of the costs
** and prereqs.
*/
if( pBuilder->pOrSet!=0 ){
|
| ︙ | ︙ | |||
113142 113143 113144 113145 113146 113147 113148 |
sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
return SQLITE_OK;
}
| | < | | < < < < | < < > | < | | < | < > | | < < < < < < < < < < < < < < < < | < | | < < < < < < < < < < < < < < < | < > | > > > > > > > > > > > > > > > > > | > > > > < < < < < < < < < < < < | 113612 113613 113614 113615 113616 113617 113618 113619 113620 113621 113622 113623 113624 113625 113626 113627 113628 113629 113630 113631 113632 113633 113634 113635 113636 113637 113638 113639 113640 113641 113642 113643 113644 113645 113646 113647 113648 113649 113650 113651 113652 113653 113654 113655 113656 113657 113658 113659 113660 113661 113662 113663 113664 113665 113666 113667 113668 113669 113670 113671 113672 113673 113674 113675 113676 113677 113678 113679 113680 113681 113682 113683 113684 113685 113686 113687 113688 113689 113690 113691 113692 113693 |
sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
return SQLITE_OK;
}
/* Look for an existing WhereLoop to replace with pTemplate
*/
whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
if( ppPrev==0 ){
/* There already exists a WhereLoop on the list that is better
** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-noop: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
return SQLITE_OK;
}else{
p = *ppPrev;
}
/* If we reach this point it means that either p[] should be overwritten
** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
** WhereLoop and insert it.
*/
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
if( p!=0 ){
sqlite3DebugPrintf("ins-del: ");
whereLoopPrint(p, pBuilder->pWC);
}
sqlite3DebugPrintf("ins-new: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
if( p==0 ){
/* Allocate a new WhereLoop to add to the end of the list */
*ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
if( p==0 ) return SQLITE_NOMEM;
whereLoopInit(p);
p->pNextLoop = 0;
}else{
/* We will be overwriting WhereLoop p[]. But before we do, first
** go through the rest of the list and delete any other entries besides
** p[] that are also supplated by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
ppTail = whereLoopFindLesser(ppTail, pTemplate);
if( NEVER(ppTail==0) ) break;
pToDel = *ppTail;
if( pToDel==0 ) break;
*ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-del: ");
whereLoopPrint(pToDel, pBuilder->pWC);
}
#endif
whereLoopDelete(db, pToDel);
}
}
whereLoopXfer(db, p, pTemplate);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
Index *pIndex = p->u.btree.pIndex;
if( pIndex && pIndex->tnum==0 ){
p->u.btree.pIndex = 0;
}
}
return SQLITE_OK;
}
/*
** Adjust the WhereLoop.nOut value downward to account for terms of the
** WHERE clause that reference the loop but which are not used by an
** index.
**
|
| ︙ | ︙ | |||
113394 113395 113396 113397 113398 113399 113400 113401 113402 113403 113404 113405 113406 113407 |
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
nIn = 46; assert( 46==sqlite3LogEst(25) );
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
/* "x IN (value, value, ...)" */
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
}
pNew->rRun += nIn;
pNew->u.btree.nEq++;
pNew->nOut = nRowEst + nInMul + nIn;
}else if( pTerm->eOperator & (WO_EQ) ){
assert(
(pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN|WHERE_SKIPSCAN))!=0
|| nInMul==0
| > > | 113833 113834 113835 113836 113837 113838 113839 113840 113841 113842 113843 113844 113845 113846 113847 113848 |
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
nIn = 46; assert( 46==sqlite3LogEst(25) );
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
/* "x IN (value, value, ...)" */
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
}
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
** changes "x IN (?)" into "x=?". */
pNew->rRun += nIn;
pNew->u.btree.nEq++;
pNew->nOut = nRowEst + nInMul + nIn;
}else if( pTerm->eOperator & (WO_EQ) ){
assert(
(pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN|WHERE_SKIPSCAN))!=0
|| nInMul==0
|
| ︙ | ︙ | |||
113707 113708 113709 113710 113711 113712 113713 113714 113715 113716 113717 113718 113719 |
&& (pProbe->szIdxRow<pTab->szTabRow)
&& (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
&& sqlite3GlobalConfig.bUseCis
&& OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
)
){
pNew->iSortIdx = b ? iSortIdx : 0;
if( m==0 ){
/* TUNING: Cost of a covering index scan is K*(N + log2(N)).
** + The extra factor K of between 1.1 and 3.0 that depends
** on the relative sizes of the table and the index. K
** is smaller for smaller indices, thus favoring them.
*/
| > > > > > > > < | | | > > > > > > > > > > | | 114148 114149 114150 114151 114152 114153 114154 114155 114156 114157 114158 114159 114160 114161 114162 114163 114164 114165 114166 114167 114168 114169 114170 114171 114172 114173 114174 114175 114176 114177 114178 114179 114180 114181 114182 114183 114184 114185 114186 114187 114188 114189 |
&& (pProbe->szIdxRow<pTab->szTabRow)
&& (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
&& sqlite3GlobalConfig.bUseCis
&& OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
)
){
pNew->iSortIdx = b ? iSortIdx : 0;
/* TUNING: The base cost of an index scan is N + log2(N).
** The log2(N) is for the initial seek to the beginning and the N
** is for the scan itself. */
pNew->rRun = sqlite3LogEstAdd(rSize, rLogSize);
if( m==0 ){
/* TUNING: Cost of a covering index scan is K*(N + log2(N)).
** + The extra factor K of between 1.1 and 3.0 that depends
** on the relative sizes of the table and the index. K
** is smaller for smaller indices, thus favoring them.
** The upper bound on K (3.0) matches the penalty factor
** on a full table scan that tries to encourage the use of
** indexed lookups over full scans.
*/
pNew->rRun += 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
}else{
/* TUNING: The cost of scanning a non-covering index is multiplied
** by log2(N) to account for the binary search of the main table
** that must happen for each row of the index.
** TODO: Should there be a multiplier here, analogous to the 3x
** multiplier for a fulltable scan or covering index scan, to
** further discourage the use of an index scan? Or is the log2(N)
** term sufficient discouragement?
** TODO: What if some or all of the WHERE clause terms can be
** computed without reference to the original table. Then the
** penality should reduce to logK where K is the number of output
** rows.
*/
pNew->rRun += rLogSize;
}
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}
}
|
| ︙ | ︙ | |||
113890 113891 113892 113893 113894 113895 113896 |
if( i>=nConstraint ){
pNew->nLTerm = mxTerm+1;
assert( pNew->nLTerm<=pNew->nLSlot );
pNew->u.vtab.idxNum = pIdxInfo->idxNum;
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
pIdxInfo->needToFreeIdxStr = 0;
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
| | | | 114347 114348 114349 114350 114351 114352 114353 114354 114355 114356 114357 114358 114359 114360 114361 114362 |
if( i>=nConstraint ){
pNew->nLTerm = mxTerm+1;
assert( pNew->nLTerm<=pNew->nLSlot );
pNew->u.vtab.idxNum = pIdxInfo->idxNum;
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
pIdxInfo->needToFreeIdxStr = 0;
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
pIdxInfo->nOrderBy : 0);
pNew->rSetup = 0;
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
whereLoopInsert(pBuilder, pNew);
if( pNew->u.vtab.needFree ){
sqlite3_free(pNew->u.vtab.idxStr);
pNew->u.vtab.needFree = 0;
|
| ︙ | ︙ | |||
114052 114053 114054 114055 114056 114057 114058 | whereLoopClear(db, pNew); return rc; } /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th ** parameters) to see if it outputs rows in the requested ORDER BY | | | | | | | 114509 114510 114511 114512 114513 114514 114515 114516 114517 114518 114519 114520 114521 114522 114523 114524 114525 114526 114527 114528 114529 114530 114531 114532 114533 114534 114535 114536 114537 | whereLoopClear(db, pNew); return rc; } /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th ** parameters) to see if it outputs rows in the requested ORDER BY ** (or GROUP BY) without requiring a separate sort operation. Return N: ** ** N>0: N terms of the ORDER BY clause are satisfied ** N==0: No terms of the ORDER BY clause are satisfied ** N<0: Unknown yet how many terms of ORDER BY might be satisfied. ** ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY ** and DISTINT do not require rows to appear in any particular order as long ** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */ u16 nLoop, /* Number of entries in pPath->aLoop[] */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ |
| ︙ | ︙ | |||
114250 114251 114252 114253 114254 114255 114256 114257 114258 114259 114260 114261 114262 114263 |
if( iColumn>=0 ){
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( !pColl ) pColl = db->pDfltColl;
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
}
isMatch = 1;
break;
}
if( isMatch ){
if( iColumn<0 ){
testcase( distinctColumns==0 );
distinctColumns = 1;
}
obSat |= MASKBIT(i);
| > > > > > > > > > > > < < < < < < < < < < < | 114707 114708 114709 114710 114711 114712 114713 114714 114715 114716 114717 114718 114719 114720 114721 114722 114723 114724 114725 114726 114727 114728 114729 114730 114731 114732 114733 114734 114735 114736 114737 114738 |
if( iColumn>=0 ){
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( !pColl ) pColl = db->pDfltColl;
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
}
isMatch = 1;
break;
}
if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
/* Make sure the sort order is compatible in an ORDER BY clause.
** Sort order is irrelevant for a GROUP BY clause. */
if( revSet ){
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
}else{
rev = revIdx ^ pOrderBy->a[i].sortOrder;
if( rev ) *pRevMask |= MASKBIT(iLoop);
revSet = 1;
}
}
if( isMatch ){
if( iColumn<0 ){
testcase( distinctColumns==0 );
distinctColumns = 1;
}
obSat |= MASKBIT(i);
}else{
/* No match found */
if( j==0 || j<nKeyCol ){
testcase( isOrderDistinct!=0 );
isOrderDistinct = 0;
}
break;
|
| ︙ | ︙ | |||
114299 114300 114301 114302 114303 114304 114305 |
if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i);
}
}
}
} /* End the loop over all WhereLoops from outer-most down to inner-most */
| | | > > > > > > | 114756 114757 114758 114759 114760 114761 114762 114763 114764 114765 114766 114767 114768 114769 114770 114771 114772 114773 114774 114775 114776 114777 |
if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i);
}
}
}
} /* End the loop over all WhereLoops from outer-most down to inner-most */
if( obSat==obDone ) return (i8)nOrderBy;
if( !isOrderDistinct ){
for(i=nOrderBy-1; i>0; i--){
Bitmask m = MASKBIT(i) - 1;
if( (obSat&m)==m ) return i;
}
return 0;
}
return -1;
}
#ifdef WHERETRACE_ENABLED
/* For debugging use only: */
static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
static char zName[65];
|
| ︙ | ︙ | |||
114337 114338 114339 114340 114341 114342 114343 114344 114345 114346 114347 | int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ Parse *pParse; /* Parsing context */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ LogEst rCost; /* Cost of a path */ LogEst nOut; /* Number of outputs */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ LogEst mxOut = 0; /* Maximum nOut value on the set of paths */ | > < | 114800 114801 114802 114803 114804 114805 114806 114807 114808 114809 114810 114811 114812 114813 114814 114815 114816 114817 114818 | int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ Parse *pParse; /* Parsing context */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ int nOrderBy; /* Number of ORDER BY clause terms */ LogEst rCost; /* Cost of a path */ LogEst nOut; /* Number of outputs */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ LogEst mxOut = 0; /* Maximum nOut value on the set of paths */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ WherePath *pFrom; /* An element of aFrom[] that we are working on */ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ WhereLoop **pX; /* Used to divy up the pSpace memory */ |
| ︙ | ︙ | |||
114383 114384 114385 114386 114387 114388 114389 | ** of computing an automatic index is not paid back within the first 25 ** rows, then do not use the automatic index. */ aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) ); nFrom = 1; /* Precompute the cost of sorting the final result set, if the caller ** to sqlite3WhereBegin() was concerned about sorting */ | < | > | | < < < < < | | | | < | > | > > | | > > > > | > > > > > > > > > > | > | < < < | | | | | | | < | 114846 114847 114848 114849 114850 114851 114852 114853 114854 114855 114856 114857 114858 114859 114860 114861 114862 114863 114864 114865 114866 114867 114868 114869 114870 114871 114872 114873 114874 114875 114876 114877 114878 114879 114880 114881 114882 114883 114884 114885 114886 114887 114888 114889 114890 114891 114892 114893 114894 114895 114896 114897 114898 114899 114900 114901 114902 114903 114904 114905 114906 114907 114908 114909 114910 114911 114912 114913 114914 114915 114916 114917 114918 114919 114920 114921 114922 114923 114924 114925 114926 114927 114928 114929 114930 114931 114932 114933 114934 114935 114936 114937 114938 114939 114940 114941 114942 114943 114944 114945 114946 114947 114948 114949 114950 114951 114952 114953 114954 114955 114956 114957 114958 114959 114960 114961 114962 114963 114964 114965 114966 114967 114968 114969 114970 114971 114972 114973 114974 114975 114976 114977 114978 114979 114980 114981 114982 114983 114984 114985 114986 114987 114988 114989 114990 114991 |
** of computing an automatic index is not paid back within the first 25
** rows, then do not use the automatic index. */
aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
nFrom = 1;
/* Precompute the cost of sorting the final result set, if the caller
** to sqlite3WhereBegin() was concerned about sorting */
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
aFrom[0].isOrdered = 0;
nOrderBy = 0;
}else{
aFrom[0].isOrdered = -1;
nOrderBy = pWInfo->pOrderBy->nExpr;
}
/* Compute successively longer WherePaths using the previous generation
** of WherePaths as the basis for the next. Keep track of the mxChoice
** best paths at each generation */
for(iLoop=0; iLoop<nLoop; iLoop++){
nTo = 0;
for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
Bitmask maskNew;
Bitmask revMask = 0;
i8 isOrdered = pFrom->isOrdered;
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
if( isOrdered<0 ){
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
if( isOrdered>=0 && isOrdered<nOrderBy ){
/* TUNING: Estimated cost of sorting is N*log(N).
** If the order-by clause has X terms but only the last Y terms
** are out of order, then block-sorting will reduce the sorting
** cost to N*log(N)*log(Y/X). The log(Y/X) term is computed
** by rScale.
** TODO: Should the sorting cost get a small multiplier to help
** discourage the use of sorting and encourage the use of index
** scans instead?
*/
LogEst rScale, rSortCost;
assert( nOrderBy>0 );
rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66;
rSortCost = nRowEst + estLog(nRowEst) + rScale;
/* TUNING: The cost of implementing DISTINCT using a B-TREE is
** also N*log(N) but it has a larger constant of proportionality.
** Multiply by 3.0. */
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
rSortCost += 16;
}
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
rSortCost, (nOrderBy-isOrdered), nOrderBy, rCost,
sqlite3LogEstAdd(rCost,rSortCost)));
rCost = sqlite3LogEstAdd(rCost, rSortCost);
}
}else{
revMask = pFrom->revLoop;
}
/* Check to see if pWLoop should be added to the mxChoice best so far */
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
if( pTo->maskLoop==maskNew
&& ((pTo->isOrdered^isOrdered)&80)==0
&& ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
(pTo->rCost>=rCost && pTo->nRow>=nOut))
){
testcase( jj==nTo-1 );
break;
}
}
if( jj>=nTo ){
if( nTo>=mxChoice && rCost>=mxCost ){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
continue;
}
/* Add a new Path to the aTo[] set */
if( nTo<mxChoice ){
/* Increase the size of the aTo set by one */
jj = nTo++;
}else{
/* New path replaces the prior worst to keep count below mxChoice */
jj = mxI;
}
pTo = &aTo[jj];
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
}else{
if( pTo->rCost<=rCost && pTo->nRow<=nOut ){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Skip %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
testcase( pTo->rCost==rCost );
continue;
}
testcase( pTo->rCost==rCost+1 );
/* A new and better score for a previously created equivalent path */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Update %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
/* pWLoop is a winner. Add it to the set of best so far */
pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
pTo->revLoop = revMask;
pTo->nRow = nOut;
pTo->rCost = rCost;
pTo->isOrdered = isOrdered;
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
pTo->aLoop[iLoop] = pWLoop;
if( nTo>=mxChoice ){
mxI = 0;
mxCost = aTo[0].rCost;
mxOut = aTo[0].nRow;
|
| ︙ | ︙ | |||
114531 114532 114533 114534 114535 114536 114537 |
#ifdef WHERETRACE_ENABLED /* >=2 */
if( sqlite3WhereTrace>=2 ){
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
| | | | 115002 115003 115004 115005 115006 115007 115008 115009 115010 115011 115012 115013 115014 115015 115016 115017 |
#ifdef WHERETRACE_ENABLED /* >=2 */
if( sqlite3WhereTrace>=2 ){
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
if( pTo->isOrdered>0 ){
sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
}else{
sqlite3DebugPrintf("\n");
}
}
}
#endif
|
| ︙ | ︙ | |||
114575 114576 114577 114578 114579 114580 114581 |
&& (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0
&& pWInfo->eDistinct==WHERE_DISTINCT_NOOP
&& nRowEst
){
Bitmask notUsed;
int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used);
| > | | > | > | > | > | 115046 115047 115048 115049 115050 115051 115052 115053 115054 115055 115056 115057 115058 115059 115060 115061 115062 115063 115064 115065 115066 115067 115068 115069 115070 115071 |
&& (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0
&& pWInfo->eDistinct==WHERE_DISTINCT_NOOP
&& nRowEst
){
Bitmask notUsed;
int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used);
if( rc==pWInfo->pResultSet->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}
if( pWInfo->pOrderBy ){
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}else{
pWInfo->nOBSat = pFrom->isOrdered;
if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
pWInfo->revMask = pFrom->revLoop;
}
}
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
sqlite3DbFree(db, pSpace);
|
| ︙ | ︙ | |||
114666 114667 114668 114669 114670 114671 114672 |
}
if( pLoop->wsFlags ){
pLoop->nOut = (LogEst)1;
pWInfo->a[0].pWLoop = pLoop;
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
pWInfo->a[0].iTabCur = iCur;
pWInfo->nRowOut = 1;
| | | 115142 115143 115144 115145 115146 115147 115148 115149 115150 115151 115152 115153 115154 115155 115156 |
}
if( pLoop->wsFlags ){
pLoop->nOut = (LogEst)1;
pWInfo->a[0].pWLoop = pLoop;
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
pWInfo->a[0].iTabCur = iCur;
pWInfo->nRowOut = 1;
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
#ifdef SQLITE_DEBUG
pLoop->cId = '0';
#endif
return 1;
|
| ︙ | ︙ | |||
114770 114771 114772 114773 114774 114775 114776 | ** be used to compute the appropriate cursor depending on which index is ** used. */ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ | | | 115246 115247 115248 115249 115250 115251 115252 115253 115254 115255 115256 115257 115258 115259 115260 |
** be used to compute the appropriate cursor depending on which index is
** used.
*/
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
ExprList *pResultSet, /* Result set of the query */
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
){
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
int nTabList; /* Number of elements in pTabList */
WhereInfo *pWInfo; /* Will become the return value of this function */
|
| ︙ | ︙ | |||
114792 114793 114794 114795 114796 114797 114798 114799 114800 114801 114802 114803 114804 114805 |
sqlite3 *db; /* Database connection */
int rc; /* Return code */
/* Variable initialization */
db = pParse->db;
memset(&sWLB, 0, sizeof(sWLB));
sWLB.pOrderBy = pOrderBy;
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
wctrlFlags &= ~WHERE_WANT_DISTINCT;
}
| > > > > | 115268 115269 115270 115271 115272 115273 115274 115275 115276 115277 115278 115279 115280 115281 115282 115283 115284 115285 |
sqlite3 *db; /* Database connection */
int rc; /* Return code */
/* Variable initialization */
db = pParse->db;
memset(&sWLB, 0, sizeof(sWLB));
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
sWLB.pOrderBy = pOrderBy;
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
wctrlFlags &= ~WHERE_WANT_DISTINCT;
}
|
| ︙ | ︙ | |||
114836 114837 114838 114839 114840 114841 114842 | } pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; pWInfo->nLevel = nTabList; pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; pWInfo->pResultSet = pResultSet; | | | 115316 115317 115318 115319 115320 115321 115322 115323 115324 115325 115326 115327 115328 115329 115330 | } pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; pWInfo->nLevel = nTabList; pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; pWInfo->pResultSet = pResultSet; pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; pMaskSet = &pWInfo->sMaskSet; sWLB.pWInfo = pWInfo; sWLB.pWC = &pWInfo->sWC; sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo); assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) ); |
| ︙ | ︙ | |||
114870 114871 114872 114873 114874 114875 114876 |
sWLB.pWC->a[ii].wtFlags |= TERM_CODED;
}
}
/* Special case: No FROM clause
*/
if( nTabList==0 ){
| | | 115350 115351 115352 115353 115354 115355 115356 115357 115358 115359 115360 115361 115362 115363 115364 |
sWLB.pWC->a[ii].wtFlags |= TERM_CODED;
}
}
/* Special case: No FROM clause
*/
if( nTabList==0 ){
if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
if( wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
}
/* Assign a bit from the bitmask to every term in the FROM clause.
**
|
| ︙ | ︙ | |||
114981 114982 114983 114984 114985 114986 114987 |
if( pParse->nErr || NEVER(db->mallocFailed) ){
goto whereBeginError;
}
#ifdef WHERETRACE_ENABLED /* !=0 */
if( sqlite3WhereTrace ){
int ii;
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
| | | | 115461 115462 115463 115464 115465 115466 115467 115468 115469 115470 115471 115472 115473 115474 115475 115476 |
if( pParse->nErr || NEVER(db->mallocFailed) ){
goto whereBeginError;
}
#ifdef WHERETRACE_ENABLED /* !=0 */
if( sqlite3WhereTrace ){
int ii;
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
if( pWInfo->nOBSat>0 ){
sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
}
switch( pWInfo->eDistinct ){
case WHERE_DISTINCT_UNIQUE: {
sqlite3DebugPrintf(" DISTINCT=unique");
break;
}
case WHERE_DISTINCT_ORDERED: {
|
| ︙ | ︙ | |||
115264 115265 115266 115267 115268 115269 115270 |
if( pTabItem->viaCoroutine && !db->mallocFailed ){
last = sqlite3VdbeCurrentAddr(v);
k = pLevel->addrBody;
pOp = sqlite3VdbeGetOp(v, k);
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
| | | 115744 115745 115746 115747 115748 115749 115750 115751 115752 115753 115754 115755 115756 115757 115758 |
if( pTabItem->viaCoroutine && !db->mallocFailed ){
last = sqlite3VdbeCurrentAddr(v);
k = pLevel->addrBody;
pOp = sqlite3VdbeGetOp(v, k);
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + pTabItem->regResult;
pOp->p2 = pOp->p3;
pOp->p3 = 0;
}else if( pOp->opcode==OP_Rowid ){
pOp->opcode = OP_Null;
pOp->p1 = 0;
pOp->p3 = 0;
|
| ︙ | ︙ | |||
118212 118213 118214 118215 118216 118217 118218 118219 118220 118221 118222 118223 118224 118225 |
** expr1 NOT IN ()
**
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]);
sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr);
}else{
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 118692 118693 118694 118695 118696 118697 118698 118699 118700 118701 118702 118703 118704 118705 118706 118707 118708 118709 118710 118711 118712 118713 118714 118715 118716 118717 118718 118719 118720 118721 118722 118723 118724 118725 118726 118727 118728 118729 118730 118731 118732 |
** expr1 NOT IN ()
**
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]);
sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr);
}else if( yymsp[-1].minor.yy14->nExpr==1 ){
/* Expressions of the form:
**
** expr1 IN (?1)
** expr1 NOT IN (?2)
**
** with exactly one value on the RHS can be simplified to something
** like this:
**
** expr1 == ?1
** expr1 <> ?2
**
** But, the RHS of the == or <> is marked with the EP_Generic flag
** so that it may not contribute to the computation of comparison
** affinity or the collating sequence to use for comparison. Otherwise,
** the semantics would be subtly different from IN or NOT IN.
*/
Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
yymsp[-1].minor.yy14->a[0].pExpr = 0;
sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
/* pRHS cannot be NULL because a malloc error would have been detected
** before now and control would have never reached this point */
if( ALWAYS(pRHS) ){
pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic;
}
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy328 ? TK_NE : TK_EQ, yymsp[-4].minor.yy346.pExpr, pRHS, 0);
}else{
yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
if( yygotominor.yy346.pExpr ){
yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
sqlite3ExprSetHeight(pParse, yygotominor.yy346.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
|
| ︙ | ︙ | |||
120832 120833 120834 120835 120836 120837 120838 120839 120840 120841 120842 120843 120844 120845 |
HashElem *p;
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
Table *pTab = (Table *)sqliteHashData(p);
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
}
}
}
sqlite3BtreeLeaveAll(db);
#else
UNUSED_PARAMETER(db);
#endif
}
/*
| > | 121339 121340 121341 121342 121343 121344 121345 121346 121347 121348 121349 121350 121351 121352 121353 |
HashElem *p;
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
Table *pTab = (Table *)sqliteHashData(p);
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
}
}
}
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
#else
UNUSED_PARAMETER(db);
#endif
}
/*
|
| ︙ | ︙ | |||
123235 123236 123237 123238 123239 123240 123241 123242 123243 123244 123245 123246 123247 123248 |
** }
*/
case SQLITE_TESTCTRL_ALWAYS: {
int x = va_arg(ap,int);
rc = ALWAYS(x);
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
**
** Set the nReserve size to N for the main database on the database
** connection db.
*/
case SQLITE_TESTCTRL_RESERVE: {
| > > > > > > > > > > > > > > > > | 123743 123744 123745 123746 123747 123748 123749 123750 123751 123752 123753 123754 123755 123756 123757 123758 123759 123760 123761 123762 123763 123764 123765 123766 123767 123768 123769 123770 123771 123772 |
** }
*/
case SQLITE_TESTCTRL_ALWAYS: {
int x = va_arg(ap,int);
rc = ALWAYS(x);
break;
}
/*
** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER);
**
** The integer returned reveals the byte-order of the computer on which
** SQLite is running:
**
** 1 big-endian, determined at run-time
** 10 little-endian, determined at run-time
** 432101 big-endian, determined at compile-time
** 123410 little-endian, determined at compile-time
*/
case SQLITE_TESTCTRL_BYTEORDER: {
rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
**
** Set the nReserve size to N for the main database on the database
** connection db.
*/
case SQLITE_TESTCTRL_RESERVE: {
|
| ︙ | ︙ | |||
124571 124572 124573 124574 124575 124576 124577 | sqlite3_stmt *aStmt[37]; char *zReadExprlist; char *zWriteExprlist; int nNodeSize; /* Soft limit for node size */ u8 bFts4; /* True for FTS4, false for FTS3 */ | | | 125095 125096 125097 125098 125099 125100 125101 125102 125103 125104 125105 125106 125107 125108 125109 | sqlite3_stmt *aStmt[37]; char *zReadExprlist; char *zWriteExprlist; int nNodeSize; /* Soft limit for node size */ u8 bFts4; /* True for FTS4, false for FTS3 */ u8 bHasStat; /* True if %_stat table exists (2==unknown) */ u8 bHasDocsize; /* True if %_docsize table exists */ u8 bDescIdx; /* True if doclists are in reverse order */ u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ int nPgsz; /* Page size for host database */ char *zSegmentsTbl; /* Name of %_segments table */ sqlite3_blob *pSegments; /* Blob handle open on %_segments table */ |
| ︙ | ︙ | |||
126063 126064 126065 126066 126067 126068 126069 |
rc = fts3CreateTables(p);
}
/* Check to see if a legacy fts3 table has been "upgraded" by the
** addition of a %_stat table so that it can use incremental merge.
*/
if( !isFts4 && !isCreate ){
| < < < | | 126587 126588 126589 126590 126591 126592 126593 126594 126595 126596 126597 126598 126599 126600 126601 |
rc = fts3CreateTables(p);
}
/* Check to see if a legacy fts3 table has been "upgraded" by the
** addition of a %_stat table so that it can use incremental merge.
*/
if( !isFts4 && !isCreate ){
p->bHasStat = 2;
}
/* Figure out the page-size for the database. This is required in order to
** estimate the cost of loading large doclists from the database. */
fts3DatabasePageSize(&rc, p);
p->nNodeSize = p->nPgsz-35;
|
| ︙ | ︙ | |||
127973 127974 127975 127976 127977 127978 127979 |
if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8);
}
sqlite3Fts3SegmentsClose(p);
return rc;
}
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 128494 128495 128496 128497 128498 128499 128500 128501 128502 128503 128504 128505 128506 128507 128508 128509 128510 128511 128512 128513 128514 128515 128516 128517 128518 128519 128520 128521 128522 128523 128524 128525 128526 128527 128528 128529 128530 128531 128532 128533 128534 128535 128536 128537 128538 128539 128540 128541 128542 128543 128544 128545 128546 |
if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8);
}
sqlite3Fts3SegmentsClose(p);
return rc;
}
/*
** If it is currently unknown whether or not the FTS table has an %_stat
** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat
** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code
** if an error occurs.
*/
static int fts3SetHasStat(Fts3Table *p){
int rc = SQLITE_OK;
if( p->bHasStat==2 ){
const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
if( zSql ){
sqlite3_stmt *pStmt = 0;
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
rc = sqlite3_finalize(pStmt);
if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
}
sqlite3_free(zSql);
}else{
rc = SQLITE_NOMEM;
}
}
return rc;
}
/*
** Implementation of xBegin() method.
*/
static int fts3BeginMethod(sqlite3_vtab *pVtab){
Fts3Table *p = (Fts3Table*)pVtab;
UNUSED_PARAMETER(pVtab);
assert( p->pSegments==0 );
assert( p->nPendingData==0 );
assert( p->inTransaction!=1 );
TESTONLY( p->inTransaction = 1 );
TESTONLY( p->mxSavepoint = -1; );
p->nLeafAdd = 0;
return fts3SetHasStat(p);
}
/*
** Implementation of xCommit() method. This is a no-op. The contents of
** the pending-terms hash-table have already been flushed into the database
** by fts3SyncMethod().
*/
|
| ︙ | ︙ | |||
128233 128234 128235 128236 128237 128238 128239 128240 128241 128242 128243 128244 128245 128246 |
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
Fts3Table *p = (Fts3Table *)pVtab;
sqlite3 *db = p->db; /* Database connection */
int rc; /* Return Code */
/* As it happens, the pending terms table is always empty here. This is
** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
** always opens a savepoint transaction. And the xSavepoint() method
** flushes the pending terms table. But leave the (no-op) call to
** PendingTermsFlush() in in case that changes.
*/
assert( p->nPendingData==0 );
| > > > > > | > | 128781 128782 128783 128784 128785 128786 128787 128788 128789 128790 128791 128792 128793 128794 128795 128796 128797 128798 128799 128800 128801 128802 128803 128804 128805 128806 128807 128808 |
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
Fts3Table *p = (Fts3Table *)pVtab;
sqlite3 *db = p->db; /* Database connection */
int rc; /* Return Code */
/* At this point it must be known if the %_stat table exists or not.
** So bHasStat may not be 2. */
rc = fts3SetHasStat(p);
/* As it happens, the pending terms table is always empty here. This is
** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
** always opens a savepoint transaction. And the xSavepoint() method
** flushes the pending terms table. But leave the (no-op) call to
** PendingTermsFlush() in in case that changes.
*/
assert( p->nPendingData==0 );
if( rc==SQLITE_OK ){
rc = sqlite3Fts3PendingTermsFlush(p);
}
if( p->zContentTbl==0 ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
p->zDb, p->zName, zName
);
}
|
| ︙ | ︙ | |||
139752 139753 139754 139755 139756 139757 139758 139759 139760 139761 139762 139763 139764 139765 |
int rc = SQLITE_OK; /* Return Code */
int isRemove = 0; /* True for an UPDATE or DELETE */
u32 *aSzIns = 0; /* Sizes of inserted documents */
u32 *aSzDel = 0; /* Sizes of deleted documents */
int nChng = 0; /* Net change in number of documents */
int bInsertDone = 0;
assert( p->pSegments==0 );
assert(
nArg==1 /* DELETE operations */
|| nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
);
/* Check for a "special" INSERT operation. One of the form:
| > > > > | 140306 140307 140308 140309 140310 140311 140312 140313 140314 140315 140316 140317 140318 140319 140320 140321 140322 140323 |
int rc = SQLITE_OK; /* Return Code */
int isRemove = 0; /* True for an UPDATE or DELETE */
u32 *aSzIns = 0; /* Sizes of inserted documents */
u32 *aSzDel = 0; /* Sizes of deleted documents */
int nChng = 0; /* Net change in number of documents */
int bInsertDone = 0;
/* At this point it must be known if the %_stat table exists or not.
** So bHasStat may not be 2. */
assert( p->bHasStat==0 || p->bHasStat==1 );
assert( p->pSegments==0 );
assert(
nArg==1 /* DELETE operations */
|| nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
);
/* Check for a "special" INSERT operation. One of the form:
|
| ︙ | ︙ | |||
145133 145134 145135 145136 145137 145138 145139 |
/*
** This function populates the pRtree->nRowEst variable with an estimate
** of the number of rows in the virtual table. If possible, this is based
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
*/
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
| | > > > > > | | < | | | | | | | | | | | > > | 145691 145692 145693 145694 145695 145696 145697 145698 145699 145700 145701 145702 145703 145704 145705 145706 145707 145708 145709 145710 145711 145712 145713 145714 145715 145716 145717 145718 145719 145720 145721 145722 145723 145724 145725 145726 145727 145728 145729 145730 |
/*
** This function populates the pRtree->nRowEst variable with an estimate
** of the number of rows in the virtual table. If possible, this is based
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
*/
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
char *zSql;
sqlite3_stmt *p;
int rc;
i64 nRow = 0;
zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
if( rc==SQLITE_OK ){
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
rc = sqlite3_finalize(p);
}else if( rc!=SQLITE_NOMEM ){
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
if( nRow==0 ){
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
}else{
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
}
}
sqlite3_free(zSql);
}
return rc;
}
static sqlite3_module rtreeModule = {
0, /* iVersion */
|
| ︙ | ︙ | |||
145421 145422 145423 145424 145425 145426 145427 145428 145429 145430 145431 145432 145433 145434 |
sqlite3_free(zSql);
}
}
if( rc==SQLITE_OK ){
*ppVtab = (sqlite3_vtab *)pRtree;
}else{
rtreeRelease(pRtree);
}
return rc;
}
/*
| > > | 145985 145986 145987 145988 145989 145990 145991 145992 145993 145994 145995 145996 145997 145998 145999 146000 |
sqlite3_free(zSql);
}
}
if( rc==SQLITE_OK ){
*ppVtab = (sqlite3_vtab *)pRtree;
}else{
assert( *ppVtab==0 );
assert( pRtree->nBusy==1 );
rtreeRelease(pRtree);
}
return rc;
}
/*
|
| ︙ | ︙ |
Changes to src/sqlite3.h.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.5" #define SQLITE_VERSION_NUMBER 3008005 #define SQLITE_SOURCE_ID "2014-04-18 22:20:31 9a5d38c79d2482a23bcfbc3ff35ca4fa269c768d" /* ** 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 |
| ︙ | ︙ | |||
6119 6120 6121 6122 6123 6124 6125 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 | > | | 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_LAST 22 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for |
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
461 462 463 464 465 466 467 | ** Show diffs of the current working directory and what that ** directory would be if STASHID were applied. ** ** SUMMARY: ** fossil stash ** fossil stash save ?-m|--comment COMMENT? ?FILES...? ** fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? | | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | ** Show diffs of the current working directory and what that ** directory would be if STASHID were applied. ** ** SUMMARY: ** fossil stash ** fossil stash save ?-m|--comment COMMENT? ?FILES...? ** fossil stash snapshot ?-m|--comment COMMENT? ?FILES...? ** fossil stash list|ls ?-v|--verbose? ?-W|--width <num>? ** fossil stash show ?STASHID? ?DIFF-OPTIONS? ** fossil stash pop ** fossil stash apply ?STASHID? ** fossil stash goto ?STASHID? ** fossil stash rm|drop ?STASHID? ?-a|--all? ** fossil stash [g]diff ?STASHID? ?DIFF-OPTIONS? */ |
| ︙ | ︙ | |||
514 515 516 517 518 519 520 |
revert_cmd();
}else
if( memcmp(zCmd, "snapshot", nCmd)==0 ){
stash_create();
}else
if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
Stmt q, q2;
| | > > > > > > > > > > | 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 |
revert_cmd();
}else
if( memcmp(zCmd, "snapshot", nCmd)==0 ){
stash_create();
}else
if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
Stmt q, q2;
int n = 0, width;
int verboseFlag = find_option("verbose","v",0)!=0;
const char *zWidth = find_option("width","W",1);
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=46) ){
fossil_fatal("-W|--width value must be >46 or 0");
}
}else{
width = 79;
}
if( !verboseFlag ){
verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
}
verify_all_options();
db_prepare(&q,
"SELECT stashid, (SELECT uuid FROM blob WHERE rid=vid),"
" comment, datetime(ctime) FROM stash"
|
| ︙ | ︙ | |||
541 542 543 544 545 546 547 |
stashid,
db_column_text(&q, 1),
db_column_text(&q, 3)
);
zCom = db_column_text(&q, 2);
if( zCom && zCom[0] ){
fossil_print(" ");
| | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
stashid,
db_column_text(&q, 1),
db_column_text(&q, 3)
);
zCom = db_column_text(&q, 2);
if( zCom && zCom[0] ){
fossil_print(" ");
comment_print(zCom, 7, width);
}
if( verboseFlag ){
db_bind_int(&q2, "$id", stashid);
while( db_step(&q2)==SQLITE_ROW ){
int isAdded = db_column_int(&q2, 0);
int isRemoved = db_column_int(&q2, 1);
const char *zOrig = db_column_text(&q2, 2);
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
1150 1151 1152 1153 1154 1155 1156 |
},
{ "pre.th1error",
"format for th1 script errors",
@ white-space: pre-wrap;
@ word-wrap: break-word;
@ color: red;
},
| | | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 |
},
{ "pre.th1error",
"format for th1 script errors",
@ white-space: pre-wrap;
@ word-wrap: break-word;
@ color: red;
},
{ "table.label-value th",
"The label/value pairs on (for example) the ci page",
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
},
{ ".statistics-report-graph-line",
"for the /reports views",
|
| ︙ | ︙ |
Changes to src/sync.c.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
if( is_false(zAutosync) ){
return 0; /* Autosync is completely off */
}
}else{
/* Autosync defaults on. To make it default off, "return" here. */
}
url_parse(0, URL_REMEMBER);
| | | | | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
if( is_false(zAutosync) ){
return 0; /* Autosync is completely off */
}
}else{
/* Autosync defaults on. To make it default off, "return" here. */
}
url_parse(0, URL_REMEMBER);
if( g.url.protocol==0 ) return 0;
if( g.url.user!=0 && g.url.passwd==0 ){
g.url.passwd = unobscure(db_get("last-sync-pw", 0));
g.url.flags |= URL_PROMPT_PW;
url_prompt_for_password();
}
g.zHttpAuth = get_httpauth();
url_remember();
#if 0 /* Disabled for now */
if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
/* When doing an automatic pull, also automatically pull shuns from
** the server if pull_shuns is enabled.
**
** TODO: What happens if the shun list gets really big?
** Maybe the shunning list should only be pulled on every 10th
** autosync, or something?
*/
configSync = CONFIGSET_SHUN;
}
#endif
if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
fossil_print("Autosync: %s\n", g.url.canonical);
url_enable_proxy("via proxy: ");
rc = client_sync(flags, configSync, 0);
if( rc ) fossil_warning("Autosync failed");
return rc;
}
/*
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
}
if( urlFlags & URL_REMEMBER ){
clone_ssh_db_set_options();
}
url_parse(zUrl, urlFlags);
remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
url_remember();
| | | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
}
if( urlFlags & URL_REMEMBER ){
clone_ssh_db_set_options();
}
url_parse(zUrl, urlFlags);
remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
url_remember();
if( g.url.protocol==0 ){
if( urlOptional ) fossil_exit(0);
usage("URL");
}
user_select();
if( g.argc==2 ){
if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
fossil_print("Sync with %s\n", g.url.canonical);
}else if( (*pSyncFlags) & SYNC_PUSH ){
fossil_print("Push to %s\n", g.url.canonical);
}else if( (*pSyncFlags) & SYNC_PULL ){
fossil_print("Pull from %s\n", g.url.canonical);
}
}
url_enable_proxy("via proxy: ");
*pConfigFlags |= configSync;
}
/*
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 |
url_remember();
zUrl = db_get("last-sync-url", 0);
if( zUrl==0 ){
fossil_print("off\n");
return;
}else{
url_parse(zUrl, 0);
| | | 276 277 278 279 280 281 282 283 284 285 |
url_remember();
zUrl = db_get("last-sync-url", 0);
if( zUrl==0 ){
fossil_print("off\n");
return;
}else{
url_parse(zUrl, 0);
fossil_print("%s\n", g.url.canonical);
}
}
|
Changes to src/tar.c.
| ︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
/*
** WEBPAGE: tarball
** URL: /tarball/RID.tar.gz
**
** Generate a compressed tarball for a checkin.
** Return that tarball as the HTTP reply content.
*/
void tarball_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob tarball;
| > > > > > > > > > | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
/*
** WEBPAGE: tarball
** URL: /tarball/RID.tar.gz
**
** Generate a compressed tarball for a checkin.
** Return that tarball as the HTTP reply content.
**
** Optional URL Parameters:
**
** - name=base name of the output file. Defaults to
** something project/version-specific.
**
** - uuid=the version to tar (may be a tag/branch name).
** Defaults to trunk.
**
*/
void tarball_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob tarball;
|
| ︙ | ︙ |
Changes to src/th.c.
| ︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
**
** results in nByte being set to 2.
*/
static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
/*
** Given that the input string (z, n) contains a language construct of
** the relevant type (a command enclosed in [], an escape sequence
** like "\xFF" or a variable reference like "${varname}", perform
** substitution on the string and store the resulting string in
| > | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
**
** results in nByte being set to 2.
*/
static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
static int thNextInteger (Th_Interp*, const char *z, int n, int *pN);
static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
/*
** Given that the input string (z, n) contains a language construct of
** the relevant type (a command enclosed in [], an escape sequence
** like "\xFF" or a variable reference like "${varname}", perform
** substitution on the string and store the resulting string in
|
| ︙ | ︙ | |||
1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 |
{">", OP_GT, 5, ARG_NUMBER},
{"&", OP_BITWISE_AND, 8, ARG_INTEGER},
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
{0,0,0,0}
};
/*
** The first part of the string (zInput,nInput) contains a number.
** Set *pnVarname to the number of bytes in the numeric string.
*/
static int thNextNumber(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnLiteral
){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 |
{">", OP_GT, 5, ARG_NUMBER},
{"&", OP_BITWISE_AND, 8, ARG_INTEGER},
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
{0,0,0,0}
};
/*
** The first part of the string (zInput,nInput) contains an integer.
** Set *pnVarname to the number of bytes in the numeric string.
*/
static int thNextInteger(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnLiteral
){
int i;
int (*isdigit)(char) = th_isdigit;
char c;
if( nInput<2) return TH_ERROR;
assert(zInput[0]=='0');
c = zInput[1];
if( c>='A' && c<='Z' ) c += 'a' - 'A';
if( c=='x' ){
isdigit = th_ishexdig;
}else if( c!='o' && c!='b' ){
return TH_ERROR;
}
for(i=2; i<nInput; i++){
c = zInput[i];
if( !isdigit(c) ){
break;
}
}
*pnLiteral = i;
return TH_OK;
}
/*
** The first part of the string (zInput,nInput) contains a number.
** Set *pnVarname to the number of bytes in the numeric string.
*/
static int thNextNumber(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnLiteral
){
int i = 0;
int seenDot = 0;
for(; i<nInput; i++){
char c = zInput[i];
if( (seenDot || c!='.') && !th_isdigit(c) ) break;
if( c=='.' ) seenDot = 1;
}
*pnLiteral = i;
return TH_OK;
}
|
| ︙ | ︙ | |||
1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 |
case OP_BITWISE_AND: iRes = iLeft&iRight; break;
case OP_BITWISE_XOR: iRes = iLeft^iRight; break;
case OP_BITWISE_OR: iRes = iLeft|iRight; break;
case OP_LOGICAL_AND: iRes = iLeft&&iRight; break;
case OP_LOGICAL_OR: iRes = iLeft||iRight; break;
case OP_UNARY_MINUS: iRes = -iLeft; break;
case OP_UNARY_PLUS: iRes = +iLeft; break;
case OP_LOGICAL_NOT: iRes = !iLeft; break;
default: assert(!"Internal error");
}
Th_SetResultInt(interp, iRes);
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
| > | 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 |
case OP_BITWISE_AND: iRes = iLeft&iRight; break;
case OP_BITWISE_XOR: iRes = iLeft^iRight; break;
case OP_BITWISE_OR: iRes = iLeft|iRight; break;
case OP_LOGICAL_AND: iRes = iLeft&&iRight; break;
case OP_LOGICAL_OR: iRes = iLeft||iRight; break;
case OP_UNARY_MINUS: iRes = -iLeft; break;
case OP_UNARY_PLUS: iRes = +iLeft; break;
case OP_BITWISE_NOT: iRes = ~iLeft; break;
case OP_LOGICAL_NOT: iRes = !iLeft; break;
default: assert(!"Internal error");
}
Th_SetResultInt(interp, iRes);
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
|
| ︙ | ︙ | |||
2152 2153 2154 2155 2156 2157 2158 |
if( th_isspace(c) ){ /* White-space */
i++;
}else{
Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
const char *z = &zExpr[i];
switch (c) {
| > > > > > | | | 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 |
if( th_isspace(c) ){ /* White-space */
i++;
}else{
Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
const char *z = &zExpr[i];
switch (c) {
case '0':
if( thNextInteger(interp, z, nExpr-i, &pNew->nValue)==TH_OK ){
break;
}
/* fall through */
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
thNextNumber(interp, z, nExpr-i, &pNew->nValue);
break;
case '$':
thNextVarname(interp, z, nExpr-i, &pNew->nValue);
break;
|
| ︙ | ︙ | |||
2408 2409 2410 2411 2412 2413 2414 | ** '\n' 0x0A ** '\v' 0x0B ** '\f' 0x0C ** '\r' 0x0D ** ** Whitespace characters have the 0x01 flag set. Decimal digits have the ** 0x2 flag set. Single byte printable characters have the 0x4 flag set. | | > | | | | 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 |
** '\n' 0x0A
** '\v' 0x0B
** '\f' 0x0C
** '\r' 0x0D
**
** Whitespace characters have the 0x01 flag set. Decimal digits have the
** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
** Alphabet characters have the 0x8 bit set. Hexadecimal digits have the
** 0x20 flag set.
**
** The special list characters have the 0x10 flag set
**
** { } [ ] \ ; ' "
**
** " 0x22
**
*/
static unsigned char aCharProp[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, /* 0x0. */
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1. */
5, 4, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x2. */
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 4, 20, 4, 4, 4, 4, /* 0x3. */
4, 44, 44, 44, 44, 44, 44, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x4. */
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 4, 4, /* 0x5. */
4, 44, 44, 44, 44, 44, 44, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x6. */
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 4, 20, 4, 4, /* 0x7. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC. */
|
| ︙ | ︙ | |||
2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 |
}
int th_isspecial(char c){
return (aCharProp[(unsigned char)c] & 0x11);
}
int th_isalnum(char c){
return (aCharProp[(unsigned char)c] & 0x0A);
}
#ifndef LONGDOUBLE_TYPE
# define LONGDOUBLE_TYPE long double
#endif
/*
| > > > > > > > > > > > > | 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 |
}
int th_isspecial(char c){
return (aCharProp[(unsigned char)c] & 0x11);
}
int th_isalnum(char c){
return (aCharProp[(unsigned char)c] & 0x0A);
}
int th_isalpha(char c){
return (aCharProp[(unsigned char)c] & 0x08);
}
int th_ishexdig(char c){
return (aCharProp[(unsigned char)c] & 0x20);
}
int th_isoctdig(char c){
return ((c|7) == '7');
}
int th_isbindig(char c){
return ((c|1) == '1');
}
#ifndef LONGDOUBLE_TYPE
# define LONGDOUBLE_TYPE long double
#endif
/*
|
| ︙ | ︙ | |||
2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 |
** If the string cannot be converted to an integer, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
int i = 0;
int iOut = 0;
if( n<0 ){
n = th_strlen(z);
}
if( n>0 && (z[0]=='-' || z[0]=='+') ){
i = 1;
}
for(; i<n; i++){
| > > > > > > > > > > > > > > > > > > > > | > > > > > > > | | 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 |
** If the string cannot be converted to an integer, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
int i = 0;
int iOut = 0;
int base = 10;
int (*isdigit)(char) = th_isdigit;
if( n<0 ){
n = th_strlen(z);
}
if( n>0 && (z[0]=='-' || z[0]=='+') ){
i = 1;
}
if( n>2 ){
if( z[i]=='0' ){
if( z[i+1]=='x' || z[i+1]=='X' ){
i += 2;
base = 16;
isdigit = th_ishexdig;
}else if( z[i+1]=='o' || z[i+1]=='O' ){
i += 2;
base = 8;
isdigit = th_isoctdig;
}else if( z[i+1]=='b' || z[i+1]=='B' ){
i += 2;
base = 2;
isdigit = th_isbindig;
}
}
}
for(; i<n; i++){
char c = z[i];
if( !isdigit(c) ){
Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
return TH_ERROR;
}
if( c>='a' ){
c -= 'a'-10;
}else if( c>='A' ){
c -= 'A'-10;
}else{
c -= '0';
}
iOut = iOut * base + c;
}
if( n>0 && z[0]=='-' ){
iOut *= -1;
}
*piOut = iOut;
|
| ︙ | ︙ |
Changes to src/th.h.
| ︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | /* ** Drop in replacements for the corresponding standard library functions. */ int th_strlen(const char *); int th_isdigit(char); int th_isspace(char); int th_isalnum(char); int th_isspecial(char); char *th_strdup(Th_Interp *interp, const char *z, int n); /* ** Interfaces to register the language extensions. */ int th_register_language(Th_Interp *interp); /* th_lang.c */ int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */ | > > > > | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | /* ** Drop in replacements for the corresponding standard library functions. */ int th_strlen(const char *); int th_isdigit(char); int th_isspace(char); int th_isalnum(char); int th_isalpha(char); int th_isspecial(char); int th_ishexdig(char); int th_isoctdig(char); int th_isbindig(char); char *th_strdup(Th_Interp *interp, const char *z, int n); /* ** Interfaces to register the language extensions. */ int th_register_language(Th_Interp *interp); /* th_lang.c */ int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */ |
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
/*
** Generate a hyperlink to a version.
*/
void hyperlink_to_uuid(const char *zUuid){
char z[UUID_SIZE+1];
shorten_uuid(z, zUuid);
if( g.perm.Hyperlink ){
| | < < < < < < < < < < < < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
/*
** Generate a hyperlink to a version.
*/
void hyperlink_to_uuid(const char *zUuid){
char z[UUID_SIZE+1];
shorten_uuid(z, zUuid);
if( g.perm.Hyperlink ){
@ %z(xhref("class='timelineHistLink'","%R/info/%s",zUuid))[%s(z)]</a>
}else{
@ <span class="timelineHistDsp">[%s(z)]</span>
}
}
/*
** Generate a hyperlink to a date & time.
*/
void hyperlink_to_date(const char *zDate, const char *zSuffix){
if( zSuffix==0 ) zSuffix = "";
if( g.perm.Hyperlink ){
@ %z(href("%R/timeline?c=%T",zDate))%s(zDate)</a>%s(zSuffix)
|
| ︙ | ︙ | |||
446 447 448 449 450 451 452 |
@ (user: %z(href("%z",zLink))%h(zDispUser)</a>%s(zTagList?",":"\051")
}else{
@ (user: %h(zDispUser)%s(zTagList?",":"\051")
}
/* Generate a "detail" link for tags. */
if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
| | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
@ (user: %z(href("%z",zLink))%h(zDispUser)</a>%s(zTagList?",":"\051")
}else{
@ (user: %h(zDispUser)%s(zTagList?",":"\051")
}
/* Generate a "detail" link for tags. */
if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
@ [%z(href("%R/info/%s",zUuid))details</a>]
}
/* Generate the "tags: TAGLIST" at the end of the comment, together
** with hyperlinks to the tag list.
*/
if( zTagList ){
if( g.perm.Hyperlink ){
|
| ︙ | ︙ | |||
525 526 527 528 529 530 531 |
if( !isNew && !isDel && zOldName!=0 ){
@ <li> %h(zOldName) → %h(zFilename)
}
continue;
}
if( isNew ){
@ <li> %h(zFilename) (new file)
| | | | | 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 |
if( !isNew && !isDel && zOldName!=0 ){
@ <li> %h(zOldName) → %h(zFilename)
}
continue;
}
if( isNew ){
@ <li> %h(zFilename) (new file)
@ %z(href("%R/artifact/%s",zNew))[view]</a></li>
}else if( isDel ){
@ <li> %h(zFilename) (deleted)</li>
}else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){
@ <li> %h(zOldName) → %h(zFilename)
@ %z(href("%R/artifact/%s",zNew))[view]</a></li>
}else{
if( zOldName!=0 ){
@ <li> %h(zOldName) → %h(zFilename)
}else{
@ <li> %h(zFilename)
}
@ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zOld,zNew))[diff]</a></li>
}
}
db_reset(&fchngQuery);
if( inUl ){
@ </ul>
}
}
|
| ︙ | ︙ | |||
1440 1441 1442 1443 1444 1445 1446 |
blob_appendf(&desc, "%d most recent %ss", n, zEType);
}else{
blob_appendf(&desc, "%d %ss", n, zEType);
}
if( zUses ){
char *zFilenames = names_of_file(zUses);
blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames,
| | | 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 |
blob_appendf(&desc, "%d most recent %ss", n, zEType);
}else{
blob_appendf(&desc, "%d %ss", n, zEType);
}
if( zUses ){
char *zFilenames = names_of_file(zUses);
blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames,
href("%R/artifact/%s",zUses), zUses);
tmFlags |= TIMELINE_DISJOINT;
}
if( renameOnly ){
blob_appendf(&desc, " that contain filename changes");
tmFlags |= TIMELINE_DISJOINT|TIMELINE_FRENAMES;
}
if( zUser ){
|
| ︙ | ︙ | |||
1786 1787 1788 1789 1790 1791 1792 |
n = atoi(zLimit);
}else{
n = -20;
}
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
| | | 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 |
n = atoi(zLimit);
}else{
n = -20;
}
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("-W|--width value must be >20 or 0");
}
}else{
width = 79;
}
zOffset = find_option("offset",0,1);
iOffset = zOffset ? atoi(zOffset) : 0;
if( g.argc>=4 ){
|
| ︙ | ︙ | |||
1961 1962 1963 1964 1965 1966 1967 |
" FROM plink p, plink c, blob"
" WHERE p.cid=c.pid AND p.mtime>c.mtime"
" AND blob.rid=c.cid"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
@ <li>
| | | 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 |
" FROM plink p, plink c, blob"
" WHERE p.cid=c.pid AND p.mtime>c.mtime"
" AND blob.rid=c.cid"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
@ <li>
@ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&d=%s(zUuid)&unhide">%S(zUuid)</a>
}
db_finalize(&q);
style_footer();
}
/*
|
| ︙ | ︙ | |||
2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 |
*/
}
@ </tbody></table>
db_finalize(&query);
output_table_sorting_javascript("statsTable","tnx");
}
/*
** Helper for stats_report_by_month_year(), which generates a list of
** week numbers. zTimeframe should be either a timeframe in the form YYYY
** or YYYY-MM.
*/
static void stats_report_year_weeks(const char * zUserName){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 |
*/
}
@ </tbody></table>
db_finalize(&query);
output_table_sorting_javascript("statsTable","tnx");
}
/*
** Implements the "byweekday" view for /reports.
*/
static void stats_report_day_of_week(){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int nEventTotal = 0; /* Total event count */
int rowClass = 0; /* counter for alternating
row colors */
Blob sql = empty_blob; /* SQL */
int nMaxEvents = 1; /* max number of events for
all rows. */
static char const * daysOfWeek[] = {
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"
};
stats_report_init_view();
stats_report_event_types_menu("byweekday", NULL);
blob_append(&sql,
"SELECT cast(mtime %% 7 AS INTEGER) dow, "
"COUNT(*) AS eventCount "
"FROM v_reports "
"GROUP BY dow ORDER BY dow",
-1);
db_prepare(&query, blob_str(&sql));
blob_reset(&sql);
@ <h1>Timeline Events
@ (%s(stats_report_label_for_type())) by Day of the Week</h1>
@ <table class='statistics-report-table-events' border='0'
@ cellpadding='2' cellspacing='0' id='statsTable'>
@ <thead><tr>
@ <th>DoW</th>
@ <th>Day</th>
@ <th>Events</th>
@ <th width='90%%'><!-- relative commits graph --></th>
@ </tr></thead><tbody>
while( SQLITE_ROW == db_step(&query) ){
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
int const dayNum =db_column_int(&query, 0);
const int nCount = db_column_int(&query, 1);
int nSize = nCount
? (int)(100 * nCount / nMaxEvents)
: 0;
if(!nCount) continue /* arguable! Possible? */;
else if(!nSize) nSize = 1;
rowClass = ++nRowNumber % 2;
nEventTotal += nCount;
@<tr class='row%d(rowClass)'>
@ <td>%d(dayNum)</td>
@ <td>%s(daysOfWeek[dayNum])</td>
@ <td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='width:%d(nSize)%%;'> </div>
@ </td>
@</tr>
}
@ </tbody></table>
db_finalize(&query);
output_table_sorting_javascript("statsTable","ntnx");
}
/*
** Helper for stats_report_by_month_year(), which generates a list of
** week numbers. zTimeframe should be either a timeframe in the form YYYY
** or YYYY-MM.
*/
static void stats_report_year_weeks(const char * zUserName){
|
| ︙ | ︙ | |||
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 |
if(zUserName && *zUserName){
url_add_parameter(&url,"user", zUserName);
timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
}
timeline_submenu(&url, "By Year", "view", "byyear", 0);
timeline_submenu(&url, "By Month", "view", "bymonth", 0);
timeline_submenu(&url, "By Week", "view", "byweek", 0);
timeline_submenu(&url, "By User", "view", "byuser", "user");
url_reset(&url);
style_header("Activity Reports");
if(0==fossil_strcmp(zView,"byyear")){
stats_report_by_month_year(0, 0, zUserName);
}else if(0==fossil_strcmp(zView,"bymonth")){
stats_report_by_month_year(1, 0, zUserName);
}else if(0==fossil_strcmp(zView,"byweek")){
stats_report_year_weeks(zUserName);
}else if(0==fossil_strcmp(zView,"byuser")){
stats_report_by_user();
}else{
@ <h1>Select a report to show:</h1>
@ <ul>
@ <li><a href='?view=byyear'>Events by year</a></li>
@ <li><a href='?view=bymonth'>Events by month</a></li>
@ <li><a href='?view=byweek'>Events by calendar week</a></li>
@ <li><a href='?view=byuser'>Events by user</a></li>
@ </ul>
}
style_footer();
}
| > > > > | 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 |
if(zUserName && *zUserName){
url_add_parameter(&url,"user", zUserName);
timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
}
timeline_submenu(&url, "By Year", "view", "byyear", 0);
timeline_submenu(&url, "By Month", "view", "bymonth", 0);
timeline_submenu(&url, "By Week", "view", "byweek", 0);
timeline_submenu(&url, "By Weekday", "view", "byweekday", 0);
timeline_submenu(&url, "By User", "view", "byuser", "user");
url_reset(&url);
style_header("Activity Reports");
if(0==fossil_strcmp(zView,"byyear")){
stats_report_by_month_year(0, 0, zUserName);
}else if(0==fossil_strcmp(zView,"bymonth")){
stats_report_by_month_year(1, 0, zUserName);
}else if(0==fossil_strcmp(zView,"byweek")){
stats_report_year_weeks(zUserName);
}else if(0==fossil_strcmp(zView,"byuser")){
stats_report_by_user();
}else if(0==fossil_strcmp(zView,"byweekday")){
stats_report_day_of_week();
}else{
@ <h1>Select a report to show:</h1>
@ <ul>
@ <li><a href='?view=byyear'>Events by year</a></li>
@ <li><a href='?view=bymonth'>Events by month</a></li>
@ <li><a href='?view=byweek'>Events by calendar week</a></li>
@ <li><a href='?view=byweekday'>Events by day of the week</a></li>
@ <li><a href='?view=byuser'>Events by user</a></li>
@ </ul>
}
style_footer();
}
|
Changes to src/tkt.c.
| ︙ | ︙ | |||
444 445 446 447 448 449 450 |
}
if( g.perm.ApndTkt && g.perm.Attach ){
style_submenu_element("Attach", "Add An Attachment",
"%s/attachadd?tkt=%T&from=%s/tktview/%t",
g.zTop, zUuid, g.zTop, zUuid);
}
if( P("plaintext") ){
| | | | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
}
if( g.perm.ApndTkt && g.perm.Attach ){
style_submenu_element("Attach", "Add An Attachment",
"%s/attachadd?tkt=%T&from=%s/tktview/%t",
g.zTop, zUuid, g.zTop, zUuid);
}
if( P("plaintext") ){
style_submenu_element("Formatted", "Formatted", "%R/tktview/%s", zUuid);
}else{
style_submenu_element("Plaintext", "Plaintext",
"%R/tktview/%s?plaintext", zUuid);
}
style_header("View Ticket");
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
ticket_init();
initializeVariablesFromCGI();
getAllTicketFields();
initializeVariablesFromDb();
|
| ︙ | ︙ | |||
893 894 895 896 897 898 899 |
"%s/info/%s", g.zTop, zUuid);
style_submenu_element("Check-ins", "Check-ins",
"%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid);
style_submenu_element("Timeline", "Timeline",
"%s/tkttimeline?name=%s", g.zTop, zUuid);
if( P("plaintext")!=0 ){
style_submenu_element("Formatted", "Formatted",
| | | | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 |
"%s/info/%s", g.zTop, zUuid);
style_submenu_element("Check-ins", "Check-ins",
"%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid);
style_submenu_element("Timeline", "Timeline",
"%s/tkttimeline?name=%s", g.zTop, zUuid);
if( P("plaintext")!=0 ){
style_submenu_element("Formatted", "Formatted",
"%R/tkthistory/%s", zUuid);
}else{
style_submenu_element("Plaintext", "Plaintext",
"%R/tkthistory/%s?plaintext", zUuid);
}
style_header(zTitle);
free(zTitle);
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
if( tagid==0 ){
@ No such ticket: %h(zUuid)
|
| ︙ | ︙ | |||
922 923 924 925 926 927 928 |
" WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
" AND blob.rid=attachid"
" ORDER BY 1",
timeline_utc(), tagid, timeline_utc(), tagid
);
while( db_step(&q)==SQLITE_ROW ){
Manifest *pTicket;
| < < < | | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 |
" WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
" AND blob.rid=attachid"
" ORDER BY 1",
timeline_utc(), tagid, timeline_utc(), tagid
);
while( db_step(&q)==SQLITE_ROW ){
Manifest *pTicket;
const char *zDate = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
const char *zChngUuid = db_column_text(&q, 2);
const char *zFile = db_column_text(&q, 4);
if( nChng==0 ){
@ <ol>
}
nChng++;
if( zFile!=0 ){
const char *zSrc = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 5);
if( zSrc==0 || zSrc[0]==0 ){
@
@ <li><p>Delete attachment "%h(zFile)"
}else{
@
@ <li><p>Add attachment
@ "%z(href("%R/artifact/%s",zSrc))%s(zFile)</a>"
}
@ [%z(href("%R/artifact/%s",zChngUuid))%.10s(zChngUuid)</a>]
@ (rid %d(rid)) by
hyperlink_to_user(zUser,zDate," on");
hyperlink_to_date(zDate, ".</p>");
}else{
pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTicket ){
@
@ <li><p>Ticket change
@ [%z(href("%R/artifact/%s",zChngUuid))%.10s(zChngUuid)</a>]
@ (rid %d(rid)) by
hyperlink_to_user(pTicket->zUser,zDate," on");
hyperlink_to_date(zDate, ":");
@ </p>
ticket_output_change_artifact(pTicket, "a");
}
manifest_destroy(pTicket);
|
| ︙ | ︙ | |||
1217 1218 1219 1220 1221 1222 1223 |
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
zTktUuid);
if( tagid==0 ){
fossil_fatal("no such ticket %h", zTktUuid);
}
db_prepare(&q,
| | | | < < | < < | | 1214 1215 1216 1217 1218 1219 1220 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 |
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
zTktUuid);
if( tagid==0 ){
fossil_fatal("no such ticket %h", zTktUuid);
}
db_prepare(&q,
"SELECT datetime(mtime%s), objid, NULL, NULL, NULL"
" FROM event, blob"
" WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
" AND blob.rid=event.objid"
" UNION "
"SELECT datetime(mtime%s), attachid, filename, "
" src, user"
" FROM attachment, blob"
" WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
" AND blob.rid=attachid"
" ORDER BY 1 DESC",
timeline_utc(), tagid, timeline_utc(), tagid
);
while( db_step(&q)==SQLITE_ROW ){
Manifest *pTicket;
const char *zDate = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
const char *zFile = db_column_text(&q, 2);
if( zFile!=0 ){
const char *zSrc = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 4);
if( zSrc==0 || zSrc[0]==0 ){
fossil_print("Delete attachment %s\n", zFile);
}else{
fossil_print("Add attachment %s\n", zFile);
}
fossil_print(" by %s on %s\n", zUser, zDate);
}else{
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
623 624 625 626 627 628 629 630 631 632 633 634 635 636 |
){
Manifest *pManifest;
ManifestFile *pFile;
int rid=0;
if( revision ){
rid = name_to_typed_rid(revision,"ci");
}else{
rid = db_lget_int("checkout", 0);
}
if( !is_a_version(rid) ){
if( errCode>0 ) return errCode;
fossil_fatal("no such checkin: %s", revision);
}
| > > | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
){
Manifest *pManifest;
ManifestFile *pFile;
int rid=0;
if( revision ){
rid = name_to_typed_rid(revision,"ci");
}else if( !g.localOpen ){
rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
}else{
rid = db_lget_int("checkout", 0);
}
if( !is_a_version(rid) ){
if( errCode>0 ) return errCode;
fossil_fatal("no such checkin: %s", revision);
}
|
| ︙ | ︙ |
Changes to src/url.c.
| ︙ | ︙ | |||
273 274 275 276 277 278 279 | } } /* ** Parse the given URL, which describes a sync server. Populate variables ** in the global "g" structure as follows: ** | | | | | | | | | | | | | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
}
}
/*
** Parse the given URL, which describes a sync server. Populate variables
** in the global "g" structure as follows:
**
** g.url.isFile True if FILE:
** g.url.isHttps True if HTTPS:
** g.url.isSsh True if SSH:
** g.url.protocol "http" or "https" or "file"
** g.url.name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
** g.url.port TCP port number for HTTP or HTTPS.
** g.url.dfltPort Default TCP port number (80 or 443).
** g.url.path Path name for HTTP or HTTPS.
** g.url.user Userid.
** g.url.passwd Password.
** g.url.hostname HOST:PORT or just HOST if port is the default.
** g.url.canonical The URL in canonical form, omitting the password
**
** HTTP url format as follows (HTTPS is the same with a different scheme):
**
** http://userid:password@host:port/path
**
** SSH url format is:
**
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
**
*/
void url_parse(const char *zUrl, unsigned int urlFlags){
url_parse_local(zUrl, urlFlags, &g.url);
}
/*
** COMMAND: test-urlparser
**
** Usage: %fossil test-urlparser URL ?options?
**
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 |
}
if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW;
if( g.argc!=3 && g.argc!=4 ){
usage("URL");
}
url_parse(g.argv[2], fg);
for(i=0; i<2; i++){
| | | | | | | | | | | | | | | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
}
if( find_option("prompt-pw",0,0) ) fg |= URL_PROMPT_PW;
if( g.argc!=3 && g.argc!=4 ){
usage("URL");
}
url_parse(g.argv[2], fg);
for(i=0; i<2; i++){
fossil_print("g.url.isFile = %d\n", g.url.isFile);
fossil_print("g.url.isHttps = %d\n", g.url.isHttps);
fossil_print("g.url.isSsh = %d\n", g.url.isSsh);
fossil_print("g.url.protocol = %s\n", g.url.protocol);
fossil_print("g.url.name = %s\n", g.url.name);
fossil_print("g.url.port = %d\n", g.url.port);
fossil_print("g.url.dfltPort = %d\n", g.url.dfltPort);
fossil_print("g.url.hostname = %s\n", g.url.hostname);
fossil_print("g.url.path = %s\n", g.url.path);
fossil_print("g.url.user = %s\n", g.url.user);
fossil_print("g.url.passwd = %s\n", g.url.passwd);
fossil_print("g.url.canonical = %s\n", g.url.canonical);
fossil_print("g.url.fossil = %s\n", g.url.fossil);
fossil_print("g.url.flags = 0x%02x\n", g.url.flags);
if( g.url.isFile || g.url.isSsh ) break;
if( i==0 ){
fossil_print("********\n");
url_enable_proxy("Using proxy: ");
}
}
}
|
| ︙ | ︙ | |||
383 384 385 386 387 388 389 |
if( zProxy==0 ){
zProxy = db_get("proxy", 0);
if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
zProxy = fossil_getenv("http_proxy");
}
}
if( zProxy && zProxy[0] && !is_false(zProxy)
| | | | | | | | | | | | | | | | | | | | | | | | | | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
if( zProxy==0 ){
zProxy = db_get("proxy", 0);
if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
zProxy = fossil_getenv("http_proxy");
}
}
if( zProxy && zProxy[0] && !is_false(zProxy)
&& !g.url.isSsh && !g.url.isFile ){
char *zOriginalUrl = g.url.canonical;
char *zOriginalHost = g.url.hostname;
int fOriginalIsHttps = g.url.isHttps;
char *zOriginalUser = g.url.user;
char *zOriginalPasswd = g.url.passwd;
char *zOriginalUrlPath = g.url.path;
int iOriginalPort = g.url.port;
unsigned uOriginalFlags = g.url.flags;
g.url.user = 0;
g.url.passwd = "";
url_parse(zProxy, 0);
if( zMsg ) fossil_print("%s%s\n", zMsg, g.url.canonical);
g.url.path = zOriginalUrl;
g.url.hostname = zOriginalHost;
if( g.url.user ){
char *zCredentials1 = mprintf("%s:%s", g.url.user, g.url.passwd);
char *zCredentials2 = encode64(zCredentials1, -1);
g.url.proxyAuth = mprintf("Basic %z", zCredentials2);
free(zCredentials1);
}
g.url.user = zOriginalUser;
g.url.passwd = zOriginalPasswd;
g.url.isHttps = fOriginalIsHttps;
g.url.useProxy = 1;
g.url.proxyUrlPath = zOriginalUrlPath;
g.url.proxyOrigPort = iOriginalPort;
g.url.flags = uOriginalFlags;
}
}
#if INTERFACE
/*
** An instance of this object is used to build a URL with query parameters.
*/
|
| ︙ | ︙ | |||
527 528 529 530 531 532 533 |
}else{
fossil_fatal("missing or incorrect password for user \"%s\"",
pUrlData->user);
}
}
/*
| | | | | | | | | | | 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 |
}else{
fossil_fatal("missing or incorrect password for user \"%s\"",
pUrlData->user);
}
}
/*
** Prompt the user for the password for g.url.user. Store the result
** in g.url.passwd.
*/
void url_prompt_for_password(void){
url_prompt_for_password_local(&g.url);
}
/*
** Remember the URL and password if requested.
*/
void url_remember(void){
if( g.url.flags & URL_REMEMBER ){
db_set("last-sync-url", g.url.canonical, 0);
if( g.url.user!=0 && g.url.passwd!=0 && ( g.url.flags & URL_REMEMBER_PW ) ){
db_set("last-sync-pw", obscure(g.url.passwd), 0);
}
}
}
/* Preemptively prompt for a password if a username is given in the
** URL but no password.
*/
void url_get_password_if_needed(void){
if( (g.url.user && g.url.user[0])
&& (g.url.passwd==0 || g.url.passwd[0]==0)
&& isatty(fileno(stdin))
){
url_prompt_for_password();
}
}
|
Changes to src/user.c.
| ︙ | ︙ | |||
373 374 375 376 377 378 379 |
if( attempt_user(fossil_getenv("USER")) ) return;
if( attempt_user(fossil_getenv("LOGNAME")) ) return;
if( attempt_user(fossil_getenv("USERNAME")) ) return;
url_parse(0, 0);
| | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
if( attempt_user(fossil_getenv("USER")) ) return;
if( attempt_user(fossil_getenv("LOGNAME")) ) return;
if( attempt_user(fossil_getenv("USERNAME")) ) return;
url_parse(0, 0);
if( g.url.user && attempt_user(g.url.user) ) return;
fossil_print(
"Cannot figure out who you are! Consider using the --user\n"
"command line option, setting your USER environment variable,\n"
"or setting a default user with \"fossil user default USER\".\n"
);
fossil_fatal("cannot determine user");
|
| ︙ | ︙ |
Changes to src/util.c.
| ︙ | ︙ | |||
310 311 312 313 314 315 316 |
int is_valid_fd(int fd){
#ifdef _WIN32
return 1;
#else
return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
#endif
}
| > > > > > > > > > > | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
int is_valid_fd(int fd){
#ifdef _WIN32
return 1;
#else
return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
#endif
}
/*
** Returns TRUE if zSym is exactly UUID_SIZE bytes long and contains
** only lower-case ASCII hexadecimal values.
*/
int fossil_is_uuid(char const * zSym){
return zSym
&& (UUID_SIZE==strlen(zSym))
&& validate16(zSym, UUID_SIZE);
}
|
Changes to src/wiki.c.
| ︙ | ︙ | |||
239 240 241 242 243 244 245 |
zMimetype = wiki_filter_mimetypes(zMimetype);
if( !g.isHome ){
if( rid ){
style_submenu_element("Diff", "Last change",
"%R/wdiff?name=%T&a=%d", zPageName, rid);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
style_submenu_element("Details", "Details",
| | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
zMimetype = wiki_filter_mimetypes(zMimetype);
if( !g.isHome ){
if( rid ){
style_submenu_element("Diff", "Last change",
"%R/wdiff?name=%T&a=%d", zPageName, rid);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
style_submenu_element("Details", "Details",
"%R/info/%s", zUuid);
}
if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
if( db_get_boolean("wysiwyg-wiki", 0) ){
style_submenu_element("Edit", "Edit Wiki Page",
"%s/wikiedit?name=%T&wysiwyg=1",
g.zTop, zPageName);
}else{
|
| ︙ | ︙ | |||
889 890 891 892 893 894 895 | @ <h2>Formatting Rule Summary</h2> @ <ol> @ <li>Blank lines are paragraph breaks</li> @ <li>Bullets are "*" surrounded by two spaces at the beginning of the @ line.</li> @ <li>Enumeration items are "#" surrounded by two spaces at the beginning of @ a line.</li> | | | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | @ <h2>Formatting Rule Summary</h2> @ <ol> @ <li>Blank lines are paragraph breaks</li> @ <li>Bullets are "*" surrounded by two spaces at the beginning of the @ line.</li> @ <li>Enumeration items are "#" surrounded by two spaces at the beginning of @ a line.</li> @ <li>Indented paragraphs begin with a tab or two spaces.</li> @ <li>Hyperlinks are contained with square brackets: "[target]" or @ "[target|name]".</li> @ <li>Most ordinary HTML works.</li> @ <li><verbatim> and <nowiki>.</li> @ </ol> @ <p>We call the first five rules above "wiki" formatting rules. The @ last two rules are the HTML formatting rule.</p> |
| ︙ | ︙ | |||
925 926 927 928 929 930 931 |
@ <li> <p><span class="wikiruleHead">Hyperlinks</span>.
@ Text within square brackets ("[...]") becomes a hyperlink. The
@ target can be a wiki page name, the artifact ID of a check-in or ticket,
@ the name of an image, or a URL. By default, the target is displayed
@ as the text of the hyperlink. But you can specify alternative text
@ after the target name separated by a "|" character.</p>
@ <p>You can also link to internal anchor names using [#anchor-name], providing
| | | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 |
@ <li> <p><span class="wikiruleHead">Hyperlinks</span>.
@ Text within square brackets ("[...]") becomes a hyperlink. The
@ target can be a wiki page name, the artifact ID of a check-in or ticket,
@ the name of an image, or a URL. By default, the target is displayed
@ as the text of the hyperlink. But you can specify alternative text
@ after the target name separated by a "|" character.</p>
@ <p>You can also link to internal anchor names using [#anchor-name], providing
@ you have added the necessary "<a name='anchor-name'></a>"
@ tag to your wiki page.</p></li>
@ <li> <p><span class="wikiruleHead">HTML</span>.
@ The following standard HTML elements may be used:
show_allowed_wiki_markup();
@ . There are two non-standard elements available:
@ <verbatim> and <nowiki>.
@ No other elements are allowed. All attributes are checked and
|
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
1373 1374 1375 1376 1377 1378 1379 |
** Floating-point absolute value
*/
static double fossil_fabs(double x){
return x>0.0 ? x : -x;
}
/*
| | | 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 |
** Floating-point absolute value
*/
static double fossil_fabs(double x){
return x>0.0 ? x : -x;
}
/*
** Sync to the host identified in g.url.name and g.url.path. This
** routine is called by the client.
**
** Records are pushed to the server if pushFlag is true. Records
** are pulled if pullFlag is true. A full sync occurs if both are
** true.
*/
int client_sync(
|
| ︙ | ︙ | |||
1821 1822 1823 1824 1825 1826 1827 |
if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
char *zMsg = blob_terminate(&xfer.aToken[1]);
defossilize(zMsg);
fossil_force_newline();
fossil_print("Error: %s\n", zMsg);
if( fossil_strcmp(zMsg, "login failed")==0 ){
if( nCycle<2 ){
| | | | | 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 |
if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
char *zMsg = blob_terminate(&xfer.aToken[1]);
defossilize(zMsg);
fossil_force_newline();
fossil_print("Error: %s\n", zMsg);
if( fossil_strcmp(zMsg, "login failed")==0 ){
if( nCycle<2 ){
g.url.passwd = 0;
go = 1;
if( g.cgiOutput==0 ){
g.url.flags |= URL_PROMPT_PW;
g.url.flags &= ~URL_PROMPTED;
url_prompt_for_password();
url_remember();
}
}
}else{
blob_appendf(&xfer.err, "server says: %s\n", zMsg);
nErr++;
|
| ︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 |
g.clockSkewSeen = 1;
}
fossil_force_newline();
fossil_print(
"%s finished with %lld bytes sent, %lld bytes received\n",
zOpType, nSent, nRcvd);
| | | | 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 |
g.clockSkewSeen = 1;
}
fossil_force_newline();
fossil_print(
"%s finished with %lld bytes sent, %lld bytes received\n",
zOpType, nSent, nRcvd);
transport_close(&g.url);
transport_global_shutdown(&g.url);
db_multi_exec("DROP TABLE onremote");
manifest_crosslink_end(MC_PERMIT_HOOKS);
content_enable_dephantomize(1);
db_end_transaction(0);
return nErr;
}
|
Changes to src/xfersetup.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
setup_menu_entry("Commit", "xfersetup_commit",
"Specific TH1 code to run after processing a commit.");
setup_menu_entry("Ticket", "xfersetup_ticket",
"Specific TH1 code to run after processing a ticket change.");
@ </table>
url_parse(0, 0);
| | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
setup_menu_entry("Commit", "xfersetup_commit",
"Specific TH1 code to run after processing a commit.");
setup_menu_entry("Ticket", "xfersetup_ticket",
"Specific TH1 code to run after processing a ticket change.");
@ </table>
url_parse(0, 0);
if( g.url.protocol ){
unsigned syncFlags;
const char *zButton;
char *zWarning;
if( db_get_boolean("dont-push", 0) ){
syncFlags = SYNC_PULL;
zButton = "Pull";
zWarning = 0;
}else{
syncFlags = SYNC_PUSH | SYNC_PULL;
zButton = "Synchronize";
zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
g.url.canonical);
}
if( P("sync") ){
user_select();
url_enable_proxy(0);
client_sync(syncFlags, 0, 0);
}
@ <p>Press the %h(zButton) button below to synchronize with the
@ "%h(g.url.canonical)" repository now. This may be useful when
@ testing the various transfer scripts.</p>
@ <p>You can use the "http -async" command in your scripts, but
@ make sure the "th1-uri-regexp" setting is set first.</p>
if( zWarning ){
@
@ <big><b>%h(zWarning)</b></big>
free(zWarning);
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
/*
** WEBPAGE: zip
** URL: /zip/RID.zip
**
** Generate a ZIP archive for the baseline.
** Return that ZIP archive as the HTTP reply content.
*/
void baseline_zip_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob zip;
| > > > > > > > > > | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
/*
** WEBPAGE: zip
** URL: /zip/RID.zip
**
** Generate a ZIP archive for the baseline.
** Return that ZIP archive as the HTTP reply content.
**
** Optional URL Parameters:
**
** - name=base name of the output file. Defaults to
** something project/version-specific.
**
** - uuid=the version to zip (may be a tag/branch name).
** Defaults to trunk.
**
*/
void baseline_zip_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob zip;
|
| ︙ | ︙ |
Changes to test/file1.test.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
set i 1
foreach {path result} $args {
fossil test-simplify-name $path
test simplify-name-$testname.$i {$::RESULT=="\[$path\] -> \[$result\]"}
incr i
}
}
simplify-name 100 . . .// . .. .. ..///// ..
simplify-name 101 {} {} / / ///////// / ././././ .
simplify-name 102 x x /x /x ///x //x
simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b
simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c
simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y
simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y
simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y
if {$::tcl_platform(os)=="Windows NT"} {
simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
}
| > > > > > > > > > > > > > > > > > > > > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
set i 1
foreach {path result} $args {
fossil test-simplify-name $path
test simplify-name-$testname.$i {$::RESULT=="\[$path\] -> \[$result\]"}
incr i
}
}
proc relative-name {testname args} {
set i 1
foreach {subdir path result} $args {
fossil test-relative-name --chdir $subdir $path
test relative-name-$testname.$i {$::RESULT==$result}
incr i
}
}
simplify-name 100 . . .// . .. .. ..///// ..
simplify-name 101 {} {} / / ///////// / ././././ .
simplify-name 102 x x /x /x ///x //x
simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b
simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c
simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y
simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y
simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y
if {$::tcl_platform(os)=="Windows NT"} {
simplify-name 108 //?/a:/a/b a:/a/b //?/UNC/a/b //a/b //?/ {}
simplify-name 109 \\\\?\\a:\\a\\b a:/a/b \\\\?\\UNC\\a\\b //a/b \\\\?\\ {}
}
# Those directories are only needed for the testcase being able to "--chdir" to it.
file mkdir test1
file mkdir test1/test2
relative-name 100 . . . test1 [pwd] .. test1 [pwd]/ .. test1 [pwd]/test ../test
relative-name 101 test1/test2 [pwd] ../.. test1/test2 [pwd]/ ../.. test1/test2 [pwd]/test ../../test
relative-name 102 test1 [pwd]/test ../test . [pwd]/file1 ./file1 . [pwd]/file1/file2 ./file1/file2
catch {file delete test1/test2}
catch {file delete test1}
|
Changes to test/th1.test.
| ︙ | ︙ | |||
360 361 362 363 364 365 366 |
fossil test-th-eval "expr +2147483649"
test th1-expr-12 {$RESULT eq {-2147483647}}
###############################################################################
fossil test-th-eval "expr +2147483649.0"
test th1-expr-13 {$RESULT eq {2147483649.0}}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
fossil test-th-eval "expr +2147483649"
test th1-expr-12 {$RESULT eq {-2147483647}}
###############################################################################
fossil test-th-eval "expr +2147483649.0"
test th1-expr-13 {$RESULT eq {2147483649.0}}
###############################################################################
fossil test-th-eval "expr ~(-1)"
test th1-expr-14 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "expr ~-1"
test th1-expr-15 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "expr ~0"
test th1-expr-16 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr ~+0"
test th1-expr-17 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr ~-0"
test th1-expr-18 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr ~(+0)"
test th1-expr-19 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr ~(-0)"
test th1-expr-20 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr ~1"
test th1-expr-21 {$RESULT eq {-2}}
###############################################################################
fossil test-th-eval "expr ~+1"
test th1-expr-22 {$RESULT eq {-2}}
###############################################################################
fossil test-th-eval "expr ~(+1)"
test th1-expr-23 {$RESULT eq {-2}}
###############################################################################
fossil test-th-eval "expr 0+0b11"
test th1-expr-24 {$RESULT eq 3}
###############################################################################
fossil test-th-eval "expr 0+0o15"
test th1-expr-25 {$RESULT eq 13}
###############################################################################
fossil test-th-eval "expr 0+0x15"
test th1-expr-26 {$RESULT eq 21}
###############################################################################
fossil test-th-eval "expr 0+0b2"
test th1-expr-27 {$RESULT eq {TH_ERROR: expected number, got: "0b2"}}
###############################################################################
fossil test-th-eval "expr 0+0o8"
test th1-expr-28 {$RESULT eq {TH_ERROR: expected number, got: "0o8"}}
###############################################################################
fossil test-th-eval "expr 0+0xg"
test th1-expr-29 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0xg"}}
###############################################################################
fossil test-th-eval "expr 0+0b1."
test th1-expr-30 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0b1."}}
###############################################################################
fossil test-th-eval "expr 0+0o1."
test th1-expr-31 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0o1."}}
###############################################################################
fossil test-th-eval "expr 0+0x1."
test th1-expr-32 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0x1."}}
###############################################################################
fossil test-th-eval "expr 0ne5"
test th1-expr-33 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "expr 0b1+5"
test th1-expr-34 {$RESULT eq {6}}
###############################################################################
fossil test-th-eval "expr 0+0b"
test th1-expr-35 {$RESULT eq {TH_ERROR: expected number, got: "0b"}}
|
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
82 83 84 85 86 87 88 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # | | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
667 668 669 670 671 672 673 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h | | < < < < | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean |
| ︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o | < | | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o |
Changes to win/Makefile.mingw.mistachkin.
| ︙ | ︙ | |||
82 83 84 85 86 87 88 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # | | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1g/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1g #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
667 668 669 670 671 672 673 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h | | < < < < | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION) $(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h EXTRAOBJ = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o $(OBJDIR)/cson_amalgamation.o zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean |
| ︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o | < < | 1739 1740 1741 1742 1743 1744 1745 1746 1747 | $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c $(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o |
Changes to win/Makefile.msc.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 | # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL | | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 # Uncomment to enable Tcl support # FOSSIL_ENABLE_TCL = 1 !ifdef FOSSIL_ENABLE_SSL SSLINCDIR = $(B)\compat\openssl-1.0.1g\include SSLLIBDIR = $(B)\compat\openssl-1.0.1g\out32 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib !endif !ifdef FOSSIL_ENABLE_TCL TCLDIR = $(B)\compat\tcl-8.6 TCLSRCDIR = $(TCLDIR) TCLINCDIR = $(TCLSRCDIR)\generic |
| ︙ | ︙ | |||
308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
$(OX)\style$O \
$(OX)\sync$O \
$(OX)\tag$O \
$(OX)\tar$O \
$(OX)\th$O \
$(OX)\th_lang$O \
$(OX)\th_main$O \
$(OX)\timeline$O \
$(OX)\tkt$O \
$(OX)\tktsetup$O \
$(OX)\undo$O \
$(OX)\unicode$O \
$(OX)\update$O \
$(OX)\url$O \
| > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
$(OX)\style$O \
$(OX)\sync$O \
$(OX)\tag$O \
$(OX)\tar$O \
$(OX)\th$O \
$(OX)\th_lang$O \
$(OX)\th_main$O \
$(OX)\th_tcl$O \
$(OX)\timeline$O \
$(OX)\tkt$O \
$(OX)\tktsetup$O \
$(OX)\undo$O \
$(OX)\unicode$O \
$(OX)\update$O \
$(OX)\url$O \
|
| ︙ | ︙ | |||
330 331 332 333 334 335 336 |
$(OX)\winhttp$O \
$(OX)\wysiwyg$O \
$(OX)\xfer$O \
$(OX)\xfersetup$O \
$(OX)\zip$O \
$(OX)\fossil.res
| < < < | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
$(OX)\winhttp$O \
$(OX)\wysiwyg$O \
$(OX)\xfer$O \
$(OX)\xfersetup$O \
$(OX)\zip$O \
$(OX)\fossil.res
APPNAME = $(OX)\fossil$(E)
PDBNAME = $(OX)\fossil$(P)
all: $(OX) $(APPNAME)
zlib:
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | echo $(OX)\style.obj >> $@ echo $(OX)\sync.obj >> $@ echo $(OX)\tag.obj >> $@ echo $(OX)\tar.obj >> $@ echo $(OX)\th.obj >> $@ echo $(OX)\th_lang.obj >> $@ echo $(OX)\th_main.obj >> $@ echo $(OX)\timeline.obj >> $@ echo $(OX)\tkt.obj >> $@ echo $(OX)\tktsetup.obj >> $@ echo $(OX)\undo.obj >> $@ echo $(OX)\unicode.obj >> $@ echo $(OX)\update.obj >> $@ echo $(OX)\url.obj >> $@ echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ echo $(OX)\verify.obj >> $@ echo $(OX)\vfile.obj >> $@ echo $(OX)\wiki.obj >> $@ echo $(OX)\wikiformat.obj >> $@ echo $(OX)\winfile.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ | > < < < | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | echo $(OX)\style.obj >> $@ echo $(OX)\sync.obj >> $@ echo $(OX)\tag.obj >> $@ echo $(OX)\tar.obj >> $@ echo $(OX)\th.obj >> $@ echo $(OX)\th_lang.obj >> $@ echo $(OX)\th_main.obj >> $@ echo $(OX)\th_tcl.obj >> $@ echo $(OX)\timeline.obj >> $@ echo $(OX)\tkt.obj >> $@ echo $(OX)\tktsetup.obj >> $@ echo $(OX)\undo.obj >> $@ echo $(OX)\unicode.obj >> $@ echo $(OX)\update.obj >> $@ echo $(OX)\url.obj >> $@ echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ echo $(OX)\verify.obj >> $@ echo $(OX)\vfile.obj >> $@ echo $(OX)\wiki.obj >> $@ echo $(OX)\wikiformat.obj >> $@ echo $(OX)\winfile.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ echo $(LIBS) >> $@ $(OX): @-mkdir $@ translate$E: $(SRCDIR)\translate.c $(BCC) $** |
| ︙ | ︙ | |||
494 495 496 497 498 499 500 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** | < < | 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** $(OX)\th_tcl$O : $(SRCDIR)\th_tcl.c $(TCC) /Fo$@ -c $** VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION $** > $@ $(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c $(TCC) /Fo$@ /c $** page_index.h: mkindex$E $(SRC) |
| ︙ | ︙ |
Changes to www/changes.wiki.
1 2 3 4 5 |
<title>Change Log</title>
<h2>Changes For Version 1.29 (as yet unreleased)</h2>
* Add the ability to display content, diffs and annotations for UTF16
text files in the web interface.
| > | > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<title>Change Log</title>
<h2>Changes For Version 1.29 (as yet unreleased)</h2>
* Add the ability to display content, diffs and annotations for UTF16
text files in the web interface.
* Add the "SaveAs..." and "Invert" buttons
to the graphical diff display that results
from using the --tk option with the [/help/diff | fossil diff] command.
* Honor timezones in imports from git.
* The [/reports] page now requires Read ("o") permissions. The "byweek"
report now properly propagates the selected year through the event type
filter links.
* The [/help/info | info command] now shows leaf status of the checkout.
* Add support for tunneling https through a http proxy (Ticket [e854101c4f]).
* Add option --empty to the "[/help?cmd=open | fossil open]" command.
* Enhanced [/help?cmd=/fileage|the fileage page] to support a glob parameter.
* Add -w|--ignore-all-space and -Z|--ignore-trailing-space options to
[/help?cmd=annotate|fossil annotate], [/help?cmd=blame|fossil blame],
[/help?cmd=diff|fossil (g)diff], [/help?cmd=stash|fossil stash diff].
* Add --strip-trailing-cr option to [/help?cmd=diff|fossil (g)diff] and
[/help?cmd=stash|fossil stash diff].
* Add button "Ignore Whitespace" to /annotate, /blame, /ci, /fdiff
and /vdiff UI pages.
* Enhance [/reports?view=byweekday|/reports] with a "byweekday" view.
* Enhance the [/help?cmd=cat|fossil cat] command so that it works outside
of a checkout when using the -R command-line option.
* Use full-length SHA1 hashes, not abbreviations, in most hyperlinks.
* Correctly render the <title> markup on wiki pages in the
[/help?cmd=/artifact|/artifact] webpage.
* Enhance the [/help?cmd=whatis|fossil whatis] command to report on attachments
and cluster artifacts. Added the [/help?cmd=test-whatis-all] command for
testing purposes.
* Add support for HTTP Basic Authentication on [/help?cmd=clone|clone] and
[/help?cmd=sync|sync].
* Fix the [/help?cmd=stash|stash] so that it remembers added files and re-adds
them when the stash is applied.
* Fix the server so that it avoids writing to the database (and thus avoids
database locking issues) on a
[/help?cmd=pull|pull] or [/help?cmd=clone|clone].
* Add support for [./server.wiki#loadmgmt|server load management].
* Add the [/help?cmd=praise|fossil praise] command as an alias for
[/help?cmd=blame|fossil blame] for subversion compatibility.
* Enhance the [/help?cmd=test-diff|fossil test-diff] command with -y or --tk
options so that it shows both filenames above their respective columns in
the side-by-side diff output.
* Issue a warning if a [/help?cmd=add|fossil add] command tries to add a file
that matches the ignore-glob.
* Add option -W|--width to "[/help?cmd=stash|fossil stash ls]"
and "[/help?cmd=leaves|fossil leaves]" commands.
<h2>Changes For Version 1.28 (2014-01-27)</h2>
* Enhance [/help?cmd=/reports | /reports] to support event type filtering.
* When cloning a repository, the user name passed via the URL (if any)
is now used as the default local admin user's name.
* Enhance the SSH transport mechanism so that it runs a single instance of
the "fossil" executable on the remote side, obviating the need for a shell
|
| ︙ | ︙ |