Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Merge latest trunk changes. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | tcl-integration |
| Files: | files | file ages | folders |
| SHA1: |
2d2b45bb178f30983dde6a1626e7f27a |
| User & Date: | mistachkin 2011-09-27 03:55:22.839 |
Context
|
2011-09-27
| ||
| 05:31 | Makefile fixes to enable Tcl to be statically linked to Fossil. check-in: 6e6e55a12d user: mistachkin tags: tcl-integration | |
| 03:55 | Merge latest trunk changes. check-in: 2d2b45bb17 user: mistachkin tags: tcl-integration | |
|
2011-09-26
| ||
| 14:43 | Add the test-list-webpage command. check-in: 6a97d77501 user: drh tags: trunk | |
|
2011-09-01
| ||
| 22:06 | Merge all the latest trunk changes into the tcl-integration branch. check-in: 26c515f6ff user: drh tags: tcl-integration | |
Changes
Added Makefile.in.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on a unix platform. This works out-of-the-box on most unix platforms. # But you are free to vary some of the definitions if desired. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = @srcdir@/src #### The directory into which object code files should be written. # # OBJDIR = ./bld #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = @CC_FOR_BUILD@ #### The suffix to add to final executable file. When cross-compiling # to windows, make this ".exe". Otherwise leave it blank. # E = @EXEEXT@ TCC = @CC@ #### 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@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile |
Changes to auto.def.
| ︙ | ︙ | |||
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
}
if {$found} {
define FOSSIL_ENABLE_SSL
define-append EXTRA_CFLAGS $cflags
define-append EXTRA_LDFLAGS $ldflags
define-append LIBS -lssl -lcrypto
msg-result "HTTP support enabled"
} else {
user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
}
}
if {[opt-bool lineedit]} {
# Need readline-compatible line editing
| > > > > > > > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
}
if {$found} {
define FOSSIL_ENABLE_SSL
define-append EXTRA_CFLAGS $cflags
define-append EXTRA_LDFLAGS $ldflags
define-append LIBS -lssl -lcrypto
msg-result "HTTP support enabled"
# Silence OpenSSL deprecation warnings on Mac OS X 10.7.
if {[string match *-darwin* [get-define host]]} {
if {[cctest -cflags {-Wdeprecated-declarations}]} {
define-append EXTRA_CFLAGS -Wdeprecated-declarations
}
}
} else {
user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
}
}
if {[opt-bool lineedit]} {
# Need readline-compatible line editing
|
| ︙ | ︙ |
Changes to autosetup/cc.tcl.
| ︙ | ︙ | |||
329 330 331 332 333 334 335 |
# Similar to cc-add-settings, but each given setting
# simply replaces the existing value.
#
# Returns the previous settings
proc cc-update-settings {args} {
set prev [cc-get-settings]
| < < < < < | < | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# Similar to cc-add-settings, but each given setting
# simply replaces the existing value.
#
# Returns the previous settings
proc cc-update-settings {args} {
set prev [cc-get-settings]
cc-store-settings [dict merge $prev $args]
return $prev
}
# @cc-with settings ?{ script }?
#
# Sets the given 'cctest' settings and then runs the tests in 'script'.
# Note that settings such as -lang replace the current setting, while
|
| ︙ | ︙ |
Deleted ci_cvs.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ci_fossil.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cvs2fossil.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted kktodo.wiki.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted rse-notes.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/add.c.
| ︙ | ︙ | |||
106 107 108 109 110 111 112 |
db_multi_exec("UPDATE vfile SET deleted=0"
" WHERE pathname=%Q COLLATE %s", zPath, zCollate);
}else{
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
db_multi_exec(
"INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink)"
"VALUES(%d,0,0,0,%Q,%d,%d)",
| | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
db_multi_exec("UPDATE vfile SET deleted=0"
" WHERE pathname=%Q COLLATE %s", zPath, zCollate);
}else{
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
db_multi_exec(
"INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink)"
"VALUES(%d,0,0,0,%Q,%d,%d)",
vid, zPath, file_wd_isexe(zFullname), file_wd_islink(zFullname));
fossil_free(zFullname);
}
if( db_changes() ){
fossil_print("ADDED %s\n", zPath);
return 1;
}else{
fossil_print("SKIP %s\n", zPath);
|
| ︙ | ︙ | |||
179 180 181 182 183 184 185 | ** the "--dotfiles" option to the command-line. ** ** The --ignore option is a comma-separate list of glob patterns for files ** to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore option ** does not appear on the command line then the "ignore-glob" setting is ** used. ** | < | > > > > > > | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
** the "--dotfiles" option to the command-line.
**
** The --ignore option is a comma-separate list of glob patterns for files
** to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore option
** does not appear on the command line then the "ignore-glob" setting is
** used.
**
** Options:
**
** --dotfiles include files beginning with a dot (".")
** --ignore <CSG> ignore files matching patterns from the
** comma separated list of glob patterns.
**
** See also: addremove, rm
*/
void add_cmd(void){
int i; /* Loop counter */
int vid; /* Currently checked out version */
int nRoot; /* Full path characters in g.zLocalRoot */
const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
Glob *pIgnore; /* Ignore everything matching this glob pattern */
|
| ︙ | ︙ | |||
257 258 259 260 261 262 263 | ** ** Remove one or more files or directories from the repository. ** ** This command does NOT remove the files from disk. It just marks the ** files as no longer being part of the project. In other words, future ** changes to the named files will not be versioned. ** | | < | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
**
** Remove one or more files or directories from the repository.
**
** This command does NOT remove the files from disk. It just marks the
** files as no longer being part of the project. In other words, future
** changes to the named files will not be versioned.
**
** See also: addremove, add
*/
void delete_cmd(void){
int i;
int vid;
Stmt loop;
db_must_be_within_tree();
|
| ︙ | ︙ | |||
342 343 344 345 346 347 348 | } return caseSensitive; } /* ** COMMAND: addremove ** | | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | } return caseSensitive; } /* ** COMMAND: addremove ** ** 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 "extra" command) are added as ** if by the "add" command. |
| ︙ | ︙ | |||
367 368 369 370 371 372 373 | ** ** The --ignore option overrides the "ignore-glob" setting. See ** documentation on the "settings" command for further information. ** ** The --test option shows what would happen without actually doing anything. ** ** This command can be used to track third party software. | | < | > > > > > > | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
**
** The --ignore option overrides the "ignore-glob" setting. See
** documentation on the "settings" command for further information.
**
** The --test option shows what would happen without actually doing anything.
**
** This command can be used to track third party software.
**
** Options:
** --dotfiles include files beginning with a dot (".")
** --ignore <CSG> ignore files matching patterns from the
** comma separated list of glob patterns.
** --test If given, show what would be done without doing so.
**
** See also: add, rm
*/
void addremove_cmd(void){
Blob path;
const char *zIgnoreFlag = find_option("ignore",0,1);
int allFlag = find_option("dotfiles",0,0)!=0;
int isTest = find_option("test",0,0)!=0;
int caseSensitive;
|
| ︙ | ︙ | |||
424 425 426 427 428 429 430 |
);
while( db_step(&q)==SQLITE_ROW ){
const char * zFile;
const char * zPath;
zFile = db_column_text(&q, 0);
zPath = db_column_text(&q, 1);
| | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
);
while( db_step(&q)==SQLITE_ROW ){
const char * zFile;
const char * zPath;
zFile = db_column_text(&q, 0);
zPath = db_column_text(&q, 1);
if( !file_wd_isfile_or_link(zPath) ){
if( !isTest ){
db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zFile);
}
fossil_print("DELETED %s\n", zFile);
nDelete++;
}
}
|
| ︙ | ︙ |
Changes to src/attach.c.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 |
blob_zero(&sql);
blob_append(&sql,
"SELECT datetime(mtime,'localtime'), src, target, filename, comment, user"
" FROM attachment",
-1
);
if( zPage ){
| | | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
blob_zero(&sql);
blob_append(&sql,
"SELECT datetime(mtime,'localtime'), src, target, filename, comment, user"
" FROM attachment",
-1
);
if( zPage ){
if( g.perm.RdWiki==0 ) login_needed();
style_header("Attachments To %h", zPage);
blob_appendf(&sql, " WHERE target=%Q", zPage);
}else if( zTkt ){
if( g.perm.RdTkt==0 ) login_needed();
style_header("Attachments To Ticket %.10s", zTkt);
blob_appendf(&sql, " WHERE target GLOB '%q*'", zTkt);
}else{
if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ) login_needed();
style_header("All Attachments");
}
blob_appendf(&sql, " ORDER BY mtime DESC");
db_prepare(&q, "%s", blob_str(&sql));
while( db_step(&q)==SQLITE_ROW ){
const char *zDate = db_column_text(&q, 0);
const char *zSrc = db_column_text(&q, 1);
|
| ︙ | ︙ | |||
137 138 139 140 141 142 143 |
int attachid = atoi(PD("attachid","0"));
char *zUUID;
if( zPage && zTkt ) zTkt = 0;
if( zFile==0 ) fossil_redirect_home();
login_check_credentials();
if( zPage ){
| | | | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
int attachid = atoi(PD("attachid","0"));
char *zUUID;
if( zPage && zTkt ) zTkt = 0;
if( zFile==0 ) fossil_redirect_home();
login_check_credentials();
if( zPage ){
if( g.perm.RdWiki==0 ) login_needed();
zTarget = zPage;
}else if( zTkt ){
if( g.perm.RdTkt==0 ) login_needed();
zTarget = zTkt;
}else{
fossil_redirect_home();
}
if( attachid>0 ){
zUUID = db_text(0,
"SELECT coalesce(src,'x') FROM attachment"
|
| ︙ | ︙ | |||
170 171 172 173 174 175 176 |
return;
}else if( zUUID[0]=='x' ){
style_header("Missing");
@ Attachment has been deleted
style_footer();
return;
}
| | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
return;
}else if( zUUID[0]=='x' ){
style_header("Missing");
@ Attachment has been deleted
style_footer();
return;
}
g.perm.Read = 1;
cgi_replace_parameter("name",zUUID);
if( fossil_strcmp(g.zPath,"attachview")==0 ){
artifact_page();
}else{
cgi_replace_parameter("m", mimetype_from_name(zFile));
rawartifact_page();
}
|
| ︙ | ︙ | |||
205 206 207 208 209 210 211 |
int szContent = atoi(PD("f:bytes","0"));
if( P("cancel") ) cgi_redirect(zFrom);
if( zPage && zTkt ) fossil_redirect_home();
if( zPage==0 && zTkt==0 ) fossil_redirect_home();
login_check_credentials();
if( zPage ){
| | | | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
int szContent = atoi(PD("f:bytes","0"));
if( P("cancel") ) cgi_redirect(zFrom);
if( zPage && zTkt ) fossil_redirect_home();
if( zPage==0 && zTkt==0 ) fossil_redirect_home();
login_check_credentials();
if( zPage ){
if( g.perm.ApndWiki==0 || g.perm.Attach==0 ) login_needed();
if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zPage) ){
fossil_redirect_home();
}
zTarget = zPage;
zTargetType = mprintf("Wiki Page <a href=\"%s/wiki?name=%h\">%h</a>",
g.zTop, zPage, zPage);
}else{
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>",
|
| ︙ | ︙ | |||
311 312 313 314 315 316 317 |
const char *zTarget;
if( zPage && zTkt ) fossil_redirect_home();
if( zPage==0 && zTkt==0 ) fossil_redirect_home();
if( zFile==0 ) fossil_redirect_home();
login_check_credentials();
if( zPage ){
| | | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
const char *zTarget;
if( zPage && zTkt ) fossil_redirect_home();
if( zPage==0 && zTkt==0 ) fossil_redirect_home();
if( zFile==0 ) fossil_redirect_home();
login_check_credentials();
if( zPage ){
if( g.perm.WrWiki==0 || g.perm.Attach==0 ) login_needed();
zTarget = zPage;
}else{
if( g.perm.WrTkt==0 || g.perm.Attach==0 ) login_needed();
zTarget = zTkt;
}
if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
if( P("cancel") ){
cgi_redirect(zFrom);
}
if( P("confirm") ){
|
| ︙ | ︙ |
Changes to src/bisect.c.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
if( bisect.bad==0 ){
fossil_fatal("no \"bad\" version has been identified");
}
bisect.good = db_lget_int("bisect-good", 0);
if( bisect.good==0 ){
fossil_fatal("no \"good\" version has been identified");
}
| | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
if( bisect.bad==0 ){
fossil_fatal("no \"bad\" version has been identified");
}
bisect.good = db_lget_int("bisect-good", 0);
if( bisect.good==0 ){
fossil_fatal("no \"good\" version has been identified");
}
p = path_shortest(bisect.good, bisect.bad, bisect_option("direct-only"), 0);
if( p==0 ){
char *zBad = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.bad);
char *zGood = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.good);
fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
zGood, zBad);
}
}
|
| ︙ | ︙ |
Changes to src/blob.c.
| ︙ | ︙ | |||
679 680 681 682 683 684 685 |
int blob_read_from_file(Blob *pBlob, const char *zFilename){
int size, got;
FILE *in;
if( zFilename==0 || zFilename[0]==0
|| (zFilename[0]=='-' && zFilename[1]==0) ){
return blob_read_from_channel(pBlob, stdin, -1);
}
| | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
int blob_read_from_file(Blob *pBlob, const char *zFilename){
int size, got;
FILE *in;
if( zFilename==0 || zFilename[0]==0
|| (zFilename[0]=='-' && zFilename[1]==0) ){
return blob_read_from_channel(pBlob, stdin, -1);
}
size = file_wd_size(zFilename);
blob_zero(pBlob);
if( size<0 ){
fossil_fatal("no such file: %s", zFilename);
}
if( size==0 ){
return 0;
}
|
| ︙ | ︙ |
Changes to src/branch.c.
| ︙ | ︙ | |||
215 216 217 218 219 220 221 | } } /* ** COMMAND: branch ** | | | | > > | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
}
}
/*
** COMMAND: branch
**
** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS?
**
** Run various subcommands to manage branches of the open repository or
** of the repository identified by the -R or --repository option.
**
** %fossil branch new BRANCH-NAME BASIS ?--bgcolor COLOR? ?--private?
**
** Create a new branch BRANCH-NAME off of check-in BASIS.
** You can optionally give the branch a default color. The
** --private option makes the branch private.
**
** %fossil branch list ?-all | --closed?
** %fossil branch ls ?-all | --closed?
**
** List all branches. Use --all or --closed to list all branches
** or closed branches. The default is to show only open branches.
**
** Options:
** -R|--repository FILE Run commands on repository FILE
*/
void branch_cmd(void){
int n;
const char *zCmd = "list";
db_find_and_open_repository(0, 0);
if( g.argc<2 ){
usage("new|list|ls ...");
|
| ︙ | ︙ | |||
282 283 284 285 286 287 288 |
Stmt q;
int cnt;
int showClosed = P("closed")!=0;
int showAll = P("all")!=0;
int colorTest = P("colortest")!=0;
login_check_credentials();
| | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
Stmt q;
int cnt;
int showClosed = P("closed")!=0;
int showAll = P("all")!=0;
int colorTest = P("colortest")!=0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( colorTest ){
showClosed = 0;
showAll = 1;
}
style_header(showClosed ? "Closed Branches" :
showAll ? "All Branches" : "Open Branches");
|
| ︙ | ︙ | |||
344 345 346 347 348 349 350 |
@ <ul>
cnt++;
}
if( colorTest ){
const char *zColor = hash_color(zBr);
@ <li><span style="background-color: %s(zColor)">
@ %h(zBr) → %s(zColor)</span></li>
| | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
@ <ul>
cnt++;
}
if( colorTest ){
const char *zColor = hash_color(zBr);
@ <li><span style="background-color: %s(zColor)">
@ %h(zBr) → %s(zColor)</span></li>
}else if( g.perm.History ){
@ <li><a href="%s(g.zTop)/timeline?r=%T(zBr)")>%h(zBr)</a></li>
}else{
@ <li><b>%h(zBr)</b></li>
}
}
if( cnt ){
@ </ul>
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 |
/*
** This routine is called while for each check-in that is rendered by
** the timeline of a "brlist" page. Add some additional hyperlinks
** to the end of the line.
*/
static void brtimeline_extra(int rid){
Stmt q;
| | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
/*
** This routine is called while for each check-in that is rendered by
** the timeline of a "brlist" page. Add some additional hyperlinks
** to the end of the line.
*/
static void brtimeline_extra(int rid){
Stmt q;
if( !g.perm.History ) return;
db_prepare(&q,
"SELECT substr(tagname,5) FROM tagxref, tag"
" WHERE tagxref.rid=%d"
" AND tagxref.tagid=tag.tagid"
" AND tagxref.tagtype>0"
" AND tag.tagname GLOB 'sym-*'",
rid
|
| ︙ | ︙ | |||
395 396 397 398 399 400 401 |
**
** Show a timeline of all branches
*/
void brtimeline_page(void){
Stmt q;
login_check_credentials();
| | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
**
** Show a timeline of all branches
*/
void brtimeline_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
style_header("Branches");
style_submenu_element("List", "List", "brlist");
login_anonymous_available();
@ <h2>The initial check-in for each branch:</h2>
db_prepare(&q,
"%s AND blob.rid IN (SELECT rid FROM tagxref"
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
*/
void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){
int i, j;
char *zSep = "";
for(i=0; zPath[i]; i=j){
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
| | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
*/
void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){
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.History ){
if( zCI ){
blob_appendf(pOut, "%s<a href=\"%s/dir?ci=%S&name=%#T\">%#h</a>",
zSep, g.zTop, zCI, j, zPath, j-i, &zPath[i]);
}else{
blob_appendf(pOut, "%s<a href=\"%s/dir?name=%#T\">%#h</a>",
zSep, g.zTop, j, zPath, j-i, &zPath[i]);
}
|
| ︙ | ︙ | |||
116 117 118 119 120 121 122 | int rid = 0; char *zUuid = 0; Blob dirname; Manifest *pM = 0; const char *zSubdirLink; login_check_credentials(); | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
int rid = 0;
char *zUuid = 0;
Blob dirname;
Manifest *pM = 0;
const char *zSubdirLink;
login_check_credentials();
if( !g.perm.History ){ login_needed(); return; }
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
style_header("File List");
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
pathelementFunc, 0, 0);
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
zDisplayName += 2; /* no unnecessary ./ prefix */
}
}
blob_append(report, zPrefix, nPrefix);
if( isDeleted ){
blob_appendf(report, "DELETED %s\n", zDisplayName);
| | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
zDisplayName += 2; /* no unnecessary ./ prefix */
}
}
blob_append(report, zPrefix, nPrefix);
if( isDeleted ){
blob_appendf(report, "DELETED %s\n", zDisplayName);
}else if( !file_wd_isfile_or_link(zFullName) ){
if( file_access(zFullName, 0)==0 ){
blob_appendf(report, "NOT_A_FILE %s\n", zDisplayName);
if( missingIsFatal ){
fossil_warning("not a file: %s", zDisplayName);
nErr++;
}
}else{
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
if( relPathOption ){ relativePaths = 1; }
return relativePaths;
}
/*
** COMMAND: changes
**
| | < > > | | < | < < | > > > < | < < | > > > > > | 124 125 126 127 128 129 130 131 132 133 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 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
if( relPathOption ){ relativePaths = 1; }
return relativePaths;
}
/*
** COMMAND: changes
**
** Usage: %fossil changes ?OPTIONS?
**
** Report on the edit status of all files in the current checkout.
**
** 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.
** --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: extra, ls, status
*/
void changes_cmd(void){
Blob report;
int vid;
int useSha1sum = find_option("sha1sum", 0, 0)!=0;
int cwdRelative = 0;
db_must_be_within_tree();
cwdRelative = determine_cwd_relative_option();
blob_zero(&report);
vid = db_lget_int("checkout", 0);
vfile_check_signature(vid, 0, useSha1sum);
status_report(&report, "", 0, cwdRelative);
blob_write_to_file(&report, "-");
}
/*
** COMMAND: status
**
** Usage: %fossil status ?OPTIONS?
**
** Report on the status of the current checkout.
**
** 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.
** --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, extra, ls
*/
void status_cmd(void){
int vid;
db_must_be_within_tree();
/* 012345678901234 */
fossil_print("repository: %s\n", db_lget("repository",""));
fossil_print("local-root: %s\n", g.zLocalRoot);
fossil_print("server-code: %s\n", db_get("server-code", ""));
vid = db_lget_int("checkout", 0);
if( vid ){
show_common_info(vid, "checkout:", 1, 1);
}
changes_cmd();
}
/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS?
**
** Show the names of all files in the current checkout. The -l provides
** extra information about each file.
**
** Options:
** -l Provide extra information about each file.
**
** See also: changes, extra, status
*/
void ls_cmd(void){
int vid;
Stmt q;
int isBrief;
isBrief = find_option("l","l", 0)==0;
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
if( isBrief ){
fossil_print("%s\n", zPathname);
}else if( isNew ){
fossil_print("ADDED %s\n", zPathname);
}else if( isDeleted ){
fossil_print("DELETED %s\n", zPathname);
| | | | | < | > | < | < < | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 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 |
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
if( isBrief ){
fossil_print("%s\n", zPathname);
}else if( isNew ){
fossil_print("ADDED %s\n", zPathname);
}else if( isDeleted ){
fossil_print("DELETED %s\n", zPathname);
}else if( !file_wd_isfile_or_link(zFullName) ){
if( file_access(zFullName, 0)==0 ){
fossil_print("NOT_A_FILE %s\n", zPathname);
}else{
fossil_print("MISSING %s\n", zPathname);
}
}else if( chnged ){
fossil_print("EDITED %s\n", zPathname);
}else if( renamed ){
fossil_print("RENAMED %s\n", zPathname);
}else{
fossil_print("UNCHANGED %s\n", zPathname);
}
free(zFullName);
}
db_finalize(&q);
}
/*
** COMMAND: extras
** Usage: %fossil extras ?OPTIONS?
**
** Print a list of all files in the source tree that are not part of
** the current checkout. See also the "clean" command.
**
** Files and subdirectories whose names begin with "." are normally
** ignored but can be included by adding the --dotfiles option.
**
** The GLOBPATTERN is a comma-separated list of GLOB expressions for
** files that are ignored. The GLOBPATTERN specified by the "ignore-glob"
** is used if the --ignore option is omitted.
**
** 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.
** --dotfiles include files beginning with a dot (".")
** --ignore <CSG> ignore files matching patterns from the
** --rel-paths Display pathnames relative to the current working
** directory.
**
** See also: changes, clean, status
*/
void extra_cmd(void){
Blob path;
Blob repo;
Stmt q;
int n;
const char *zIgnoreFlag = find_option("ignore",0,1);
|
| ︙ | ︙ | |||
326 327 328 329 330 331 332 | } blob_reset(&rewrittenPathname); db_finalize(&q); } /* ** COMMAND: clean | | | | > > > > > > > > | 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 359 360 361 362 363 364 |
}
blob_reset(&rewrittenPathname);
db_finalize(&q);
}
/*
** COMMAND: clean
** Usage: %fossil clean ?OPTIONS?
**
** Delete all "extra" files in the source tree. "Extra" files are
** files that are not officially part of the checkout. This operation
** cannot be undone.
**
** You will be prompted before removing each file. If you are
** sure you wish to remove all "extra" files you can specify the
** optional --force flag and no prompts will be issued.
**
** Files and subdirectories whose names begin with "." are
** normally ignored. They are included if the "--dotfiles" option
** is used.
**
** The GLOBPATTERN is a comma-separated list of GLOB expressions for
** files that are ignored. The GLOBPATTERN specified by the "ignore-glob"
** is used if the --ignore option is omitted.
**
** Options:
** --dotfiles include files beginning with a dot (".")
** --force Remove files without prompting
** --ignore <CSG> ignore files matching patterns from the
** comma separated list of glob patterns.
**
** See also: addremove, extra, status
*/
void clean_cmd(void){
int allFlag;
int dotfilesFlag;
const char *zIgnoreFlag;
Blob path, repo;
Stmt q;
|
| ︙ | ︙ | |||
413 414 415 416 417 418 419 | ** ** parent_rid is the recordid of the parent check-in. */ static void prepare_commit_comment( Blob *pComment, char *zInit, const char *zBranch, | | > | | 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 |
**
** parent_rid is the recordid of the parent check-in.
*/
static void prepare_commit_comment(
Blob *pComment,
char *zInit,
const char *zBranch,
int parent_rid,
const char *zUserOvrd
){
const char *zEditor;
char *zCmd;
char *zFile;
Blob text, line;
char *zComment;
int i;
blob_init(&text, zInit, -1);
blob_append(&text,
"\n"
"# Enter comments on this check-in. Lines beginning with # are ignored.\n"
"# The check-in comment follows wiki formatting rules.\n"
"#\n", -1
);
blob_appendf(&text, "# user: %s\n", zUserOvrd ? zUserOvrd : g.zLogin);
if( zBranch && zBranch[0] ){
blob_appendf(&text, "# tags: %s\n#\n", zBranch);
}else{
char *zTags = info_tags_of_checkin(parent_rid, 1);
if( zTags ) blob_appendf(&text, "# tags: %z\n#\n", zTags);
}
if( g.markPrivate ){
|
| ︙ | ︙ | |||
659 660 661 662 663 664 665 |
#if !defined(_WIN32)
/* For unix, extract the "executable" permission bit directly from
** the filesystem. On windows, the "executable" bit is retained
** unchanged from the original.
*/
blob_resize(&filename, nBasename);
blob_append(&filename, zName, -1);
| | | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
#if !defined(_WIN32)
/* For unix, extract the "executable" permission bit directly from
** the filesystem. On windows, the "executable" bit is retained
** unchanged from the original.
*/
blob_resize(&filename, nBasename);
blob_append(&filename, zName, -1);
isexe = file_wd_isexe(blob_str(&filename));
/* For unix, check if the file on the filesystem is symlink.
** On windows, the bit is retained unchanged from original.
*/
isLink = file_wd_islink(blob_str(&filename));
#endif
if( isexe ){
zPerm = " x";
}else if( isLink ){
zPerm = " l"; /* note: symlinks don't have executable bit on unix */
}else{
zPerm = "";
|
| ︙ | ︙ | |||
837 838 839 840 841 842 843 | ** ** The --branch option followed by a branch name causes the new check-in ** to be placed in the named branch. The --bgcolor option can be followed ** by a color name (ex: '#ffc0c0') to specify the background color of ** entries in the new branch when shown in the web timeline interface. ** ** A check-in is not permitted to fork unless the --force or -f | | < | | | | | | | | | | > | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 |
**
** The --branch option followed by a branch name causes the new check-in
** to be placed in the named branch. The --bgcolor option can be followed
** by a color name (ex: '#ffc0c0') to specify the background color of
** entries in the new branch when shown in the web timeline interface.
**
** A check-in is not permitted to fork unless the --force or -f
** option appears. 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.
**
** Options:
** --baseline use a baseline manifest in the commit process
** --bgcolor COLOR apply given COLOR to the branch
** --branch NEW-BRANCH-NAME check in to this new branch
** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment
** --delta use a delta manifest in the commit process
** --force|-f allow forking with this commit
** --message-file|-M FILE read the commit comment from given file
** --nosign do not attempt to sign this commit with gpg
** --private do not sync changes and their descendants
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
**
** See also: branch, changes, checkout, extra, 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 */
|
| ︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 |
blob_zero(&comment);
blob_append(&comment, zComment, -1);
}else if( zComFile ){
blob_zero(&comment);
blob_read_from_file(&comment, zComFile);
}else{
char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
| | | 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 |
blob_zero(&comment);
blob_append(&comment, zComment, -1);
}else if( zComFile ){
blob_zero(&comment);
blob_read_from_file(&comment, zComFile);
}else{
char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
prepare_commit_comment(&comment, zInit, zBranch, vid, zUserOvrd);
free(zInit);
}
if( blob_size(&comment)==0 ){
Blob ans;
blob_zero(&ans);
prompt_user("empty check-in comment. continue (y/N)? ", &ans);
if( blob_str(&ans)[0]!='y' ){
|
| ︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 |
id = db_column_int(&q, 0);
zFullname = db_column_text(&q, 1);
rid = db_column_int(&q, 2);
crnlOk = db_column_int(&q, 3);
blob_zero(&content);
| | | 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 |
id = db_column_int(&q, 0);
zFullname = db_column_text(&q, 1);
rid = db_column_int(&q, 2);
crnlOk = db_column_int(&q, 3);
blob_zero(&content);
if( file_wd_islink(zFullname) ){
/* Instead of file content, put link destination path */
blob_read_link(&content, zFullname);
}else{
blob_read_from_file(&content, zFullname);
}
if( !crnlOk ) cr_warning(&content, zFullname);
nrid = content_put(&content);
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
blob_appendf(&filename, "%s/", g.zLocalRoot);
baseLen = blob_size(&filename);
manifest_file_rewind(pManifest);
while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
int isExe;
blob_append(&filename, pFile->zName, -1);
isExe = pFile->zPerm && strstr(pFile->zPerm, "x");
| | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
blob_appendf(&filename, "%s/", g.zLocalRoot);
baseLen = blob_size(&filename);
manifest_file_rewind(pManifest);
while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
int isExe;
blob_append(&filename, pFile->zName, -1);
isExe = pFile->zPerm && strstr(pFile->zPerm, "x");
file_wd_setexe(blob_str(&filename), isExe);
set_or_clear_isexe(pFile->zName, vid, isExe);
blob_resize(&filename, baseLen);
}
blob_reset(&filename);
manifest_destroy(pManifest);
}
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
}
/*
** COMMAND: checkout
** COMMAND: co
**
| | > | > > > > | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
}
/*
** COMMAND: checkout
** COMMAND: co
**
** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS?
** or: %fossil co ?VERSION | --latest? ?OPTIONS?
**
** Check out a version specified on the command-line. This command
** will abort if there are edited files in the current checkout unless
** the --force option appears on the command-line. The --keep option
** leaves files on disk unchanged, except the manifest and manifest.uuid
** files.
**
** The --latest flag can be used in place of VERSION to checkout the
** latest version in the repository.
**
** Options:
** --force Ignore edited files in the current checkout
** --keep Only update the manifest and manifest.uuid files
**
** See also: update
*/
void checkout_cmd(void){
int forceFlag; /* Force checkout even if edits exist */
int keepFlag; /* Do not change any files on disk */
int latestFlag; /* Checkout the latest version */
char *zVers; /* Version to checkout */
int promptFlag; /* True to prompt before overwriting */
|
| ︙ | ︙ | |||
267 268 269 270 271 272 273 |
}
}
}
/*
** COMMAND: close
**
| | > > > > > | 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 |
}
}
}
/*
** COMMAND: close
**
** Usage: %fossil close ?OPTIONS?
**
** The opposite of "open". Close the current database connection.
** Require a -f or --force flag if there are unsaved changed in the
** current check-out.
**
** Options:
** --force|-f necessary to close a check out with uncommitted changes
**
** See also: open
*/
void close_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
db_must_be_within_tree();
if( !forceFlag && unsaved_changes()==1 ){
fossil_fatal("there are unsaved changes in the current checkout");
}
unlink_local_database(1);
db_close(1);
unlink_local_database(0);
}
|
Changes to src/clone.c.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 | ** file named FILENAME. ** ** By default, your current login name is used to create the default ** admin user. This can be overridden using the -A|--admin-user ** parameter. ** ** Options: | < | | | > | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
** file named FILENAME.
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
** --admin-user|-A USERNAME Make USERNAME the administrator
** --private Also clone private branches
** --ssl-identity=filename Use the SSL identity if requested by the server
**
** See also: init
*/
void clone_cmd(void){
char *zPassword;
const char *zDefaultUser; /* Optional name of the default user */
const char *zPw; /* The user clone password */
int nErr = 0;
int bPrivate; /* Also clone private branches */
|
| ︙ | ︙ |
Changes to src/configure.c.
| ︙ | ︙ | |||
151 152 153 154 155 156 157 |
if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
zName++;
n -= 2;
}
for(i=0; i<count(aConfig); i++){
if( memcmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
int m = aConfig[i].groupMask;
| | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
zName++;
n -= 2;
}
for(i=0; i<count(aConfig); i++){
if( memcmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
int m = aConfig[i].groupMask;
if( !g.perm.Admin ){
m &= ~CONFIGSET_USER;
}
if( !g.perm.RdAddr ){
m &= ~CONFIGSET_ADDR;
}
return m;
}
}
return 0;
}
|
| ︙ | ︙ | |||
551 552 553 554 555 556 557 |
&& nToken==3
&& blob_is_int(&aToken[2], &size)
){
const char *zName = blob_str(&aToken[1]);
Blob content;
blob_zero(&content);
blob_extract(pIn, size, &content);
| | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
&& nToken==3
&& blob_is_int(&aToken[2], &size)
){
const char *zName = blob_str(&aToken[1]);
Blob content;
blob_zero(&content);
blob_extract(pIn, size, &content);
g.perm.Admin = g.perm.RdAddr = 1;
configure_receive(zName, &content, groupMask);
blob_reset(&content);
blob_seek(pIn, 1, BLOB_SEEK_CUR);
}
}
}
|
| ︙ | ︙ | |||
724 725 726 727 728 729 730 | blob_reset(&out); } /* ** COMMAND: configuration ** | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | blob_reset(&out); } /* ** COMMAND: configuration ** ** Usage: %fossil configuration METHOD ... ?OPTIONS? ** ** Where METHOD is one of: export import merge pull push reset. All methods ** accept the -R or --repository option to specific a repository. ** ** %fossil configuration export AREA FILENAME ** ** Write to FILENAME exported configuraton information for AREA. |
| ︙ | ︙ | |||
770 771 772 773 774 775 776 777 778 779 780 781 782 783 |
**
** Restore the configuration to the default. AREA as above.
**
** %fossil configuration sync AREA ?URL?
**
** Synchronize configuration changes in the local repository with
** the remote repository at URL.
*/
void configuration_cmd(void){
int n;
const char *zMethod;
if( g.argc<3 ){
usage("export|import|merge|pull|reset ...");
}
| > > > > > | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 |
**
** Restore the configuration to the default. AREA as above.
**
** %fossil configuration sync AREA ?URL?
**
** Synchronize configuration changes in the local repository with
** the remote repository at URL.
**
** Options:
** -R|--repository FILE Extract info from repository FILE
**
** See also: set
*/
void configuration_cmd(void){
int n;
const char *zMethod;
if( g.argc<3 ){
usage("export|import|merge|pull|reset ...");
}
|
| ︙ | ︙ |
Changes to src/content.c.
| ︙ | ︙ | |||
310 311 312 313 314 315 316 | ** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS? ** ** Extract an artifact by its SHA1 hash and write the results on ** standard output, or if the optional 4th argument is given, in ** the named output file. ** ** Options: | < | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
** Usage: %fossil artifact ARTIFACT-ID ?OUTPUT-FILENAME? ?OPTIONS?
**
** Extract an artifact by its SHA1 hash and write the results on
** standard output, or if the optional 4th argument is given, in
** the named output file.
**
** Options:
** -R|--repository FILE Extract artifacts from repository FILE
*/
void artifact_cmd(void){
int rid;
Blob content;
const char *zFile;
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
1177 1178 1179 1180 1181 1182 1183 | ** a copy of an existing project. This command starts a new project. ** ** By default, your current login name is used to create the default ** admin user. This can be overridden using the -A|--admin-user ** parameter. ** ** Options: | < | | > | 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 |
** a copy of an existing project. This command starts a new project.
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
** --admin-user|-A USERNAME select given USERNAME as admin user
** --date-override DATETIME use DATETIME as time of the initial checkin
**
** See also: clone
*/
void create_repository_cmd(void){
char *zPassword;
const char *zDate; /* Date of the initial check-in */
const char *zDefaultUser; /* Optional name of the default user */
zDate = find_option("date-override",0,1);
|
| ︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 |
** false or if the lookup fails, return the original string content.
**
** In either case, the string returned is stored in space obtained
** from malloc and should be freed by the calling function.
*/
char *db_reveal(const char *zKey){
char *zOut;
| | | 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 |
** false or if the lookup fails, return the original string content.
**
** In either case, the string returned is stored in space obtained
** from malloc and should be freed by the calling function.
*/
char *db_reveal(const char *zKey){
char *zOut;
if( g.perm.RdAddr ){
zOut = db_text(0, "SELECT content FROM concealed WHERE hash=%Q", zKey);
}else{
zOut = 0;
}
if( zOut==0 ){
zOut = mprintf("%s", zKey);
}
|
| ︙ | ︙ | |||
1640 1641 1642 1643 1644 1645 1646 | db_swap_connections(); blob_reset(&full); } /* ** COMMAND: open ** | | > > > > | | 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 |
db_swap_connections();
blob_reset(&full);
}
/*
** COMMAND: open
**
** Usage: %fossil open FILENAME ?VERSION? ?OPTIONS?
**
** Open a connection to the local repository in FILENAME. A checkout
** for the repository is created with its root at the working directory.
** If VERSION is specified then that version is checked out. Otherwise
** the latest version is checked out. No files other than "manifest"
** and "manifest.uuid" are modified if the --keep option is present.
**
** Options:
** --keep Only modify the manifest and manifest.uuid files
** --nested Allow opening a repository inside an opened checkout
**
** See also: close
*/
void cmd_open(void){
Blob path;
int vid;
int keepFlag;
int allowNested;
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0 };
|
| ︙ | ︙ |
Changes to src/descendants.c.
| ︙ | ︙ | |||
262 263 264 265 266 267 268 | db_finalize(&ins); db_finalize(&q); } /* ** COMMAND: descendants ** | | > > > > > | | > > > > > > > | | 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 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
db_finalize(&ins);
db_finalize(&q);
}
/*
** COMMAND: descendants
**
** Usage: %fossil descendants ?BASELINE-ID? ?OPTIONS?
**
** Find all leaf descendants of the baseline specified or if the argument
** is omitted, of the baseline currently checked out.
**
** Options:
** -R|--repository FILE Extract info from repository FILE
**
** See also: finfo, info, leaves
*/
void descendants_cmd(void){
Stmt q;
int base;
db_find_and_open_repository(0,0);
if( g.argc==2 ){
base = db_lget_int("checkout", 0);
}else{
base = name_to_typed_rid(g.argv[2], "ci");
}
if( base==0 ) return;
compute_leaves(base, 0);
db_prepare(&q,
"%s"
" AND event.objid IN (SELECT rid FROM leaves)"
" ORDER BY event.mtime DESC",
timeline_query_for_tty()
);
print_timeline(&q, 20, 0);
db_finalize(&q);
}
/*
** COMMAND: leaves
**
** Usage: %fossil leaves ?OPTIONS?
**
** Find leaves of all branches. By default show only open leaves.
** The --all flag causes all leaves (closed and open) to be shown.
** The --closed flag shows only closed leaves.
**
** The --recompute flag causes the content of the "leaf" table in the
** repository database to be recomputed.
**
** Options:
** --all show ALL leaves
** --closed show only closed leaves
** --recompute recompute the "leaf" table in the repository DB
**
** See also: descendants, finfo, info, branch
*/
void leaves_cmd(void){
Stmt q;
Blob sql;
int showAll = find_option("all", 0, 0)!=0;
int showClosed = find_option("closed", 0, 0)!=0;
int recomputeFlag = find_option("recompute",0,0)!=0;
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"));
}else if( !showAll ){
|
| ︙ | ︙ | |||
336 337 338 339 340 341 342 |
void leaves_page(void){
Blob sql;
Stmt q;
int showAll = P("all")!=0;
int showClosed = P("closed")!=0;
login_check_credentials();
| | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
void leaves_page(void){
Blob sql;
Stmt q;
int showAll = P("all")!=0;
int showClosed = P("closed")!=0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( !showAll ){
style_submenu_element("All", "All", "leaves?all");
}
if( !showClosed ){
style_submenu_element("Closed", "Closed", "leaves?closed");
}
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
835 836 837 838 839 840 841 | int fnid; int i; int iLimit; int annFlags = 0; Annotator ann; login_check_credentials(); | | | | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 |
int fnid;
int i;
int iLimit;
int annFlags = 0;
Annotator ann;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
mid = name_to_typed_rid(PD("checkin","0"),"ci");
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename"));
if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
iLimit = atoi(PD("limit","-1"));
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
fossil_redirect_home();
}
style_header("File Annotation");
if( P("filevers") ) annFlags |= ANN_FILE_VERS;
annotate_file(&ann, fnid, mid, g.perm.History, iLimit, annFlags);
if( P("log") ){
int i;
@ <h2>Versions analyzed:</h2>
@ <ol>
for(i=0; i<ann.nVers; i++){
@ <li><tt>%s(ann.azVers[i])</tt></li>
}
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 | @ </pre> style_footer(); } /* ** COMMAND: annotate ** | | | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | @ </pre> style_footer(); } /* ** COMMAND: annotate ** ** %fossil annotate ?OPTIONS? FILENAME ** ** Output the text of a file with markings to show when each line of ** the file was last modified. ** ** Options: ** --limit N Only look backwards in time by N versions ** --log List all versions analyzed |
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
if( zDiffCmd==0 ){
Blob out; /* Diff output text */
Blob file2; /* Content of zFile2 */
const char *zName2; /* Name of zFile2 for display */
/* Read content of zFile2 into memory */
blob_zero(&file2);
| | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
if( zDiffCmd==0 ){
Blob out; /* Diff output text */
Blob file2; /* Content of zFile2 */
const char *zName2; /* Name of zFile2 for display */
/* Read content of zFile2 into memory */
blob_zero(&file2);
if( file_wd_size(zFile2)<0 ){
zName2 = "/dev/null";
}else{
if( file_wd_islink(zFile2) ){
blob_read_link(&file2, zFile2);
}else{
blob_read_from_file(&file2, zFile2);
}
zName2 = zName;
}
|
| ︙ | ︙ | |||
191 192 193 194 195 196 197 |
const char *zFileTreeName
){
Blob fname;
Blob content;
int isLink;
file_tree_name(zFileTreeName, &fname, 1);
historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
| | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
const char *zFileTreeName
){
Blob fname;
Blob content;
int isLink;
file_tree_name(zFileTreeName, &fname, 1);
historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
if( !isLink != !file_wd_islink(zFrom) ){
diff_printf("cannot compute difference between symlink and regular file\n");
}else{
diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, ignoreEolWs);
}
blob_reset(&content);
blob_reset(&fname);
}
|
| ︙ | ︙ | |||
286 287 288 289 290 291 292 |
}else if( isChnged==3 ){
diff_printf("ADDED_BY_MERGE %s\n", zPathname);
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}
if( showDiff ){
Blob content;
| | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
}else if( isChnged==3 ){
diff_printf("ADDED_BY_MERGE %s\n", zPathname);
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}
if( showDiff ){
Blob content;
if( !isLink != !file_wd_islink(zFullName) ){
diff_print_index(zPathname);
diff_printf("--- %s\n+++ %s\n", zPathname, zPathname);
diff_printf("cannot compute difference between symlink and regular file\n");
continue;
}
if( srcid>0 ){
content_get(srcid, &content);
|
| ︙ | ︙ | |||
429 430 431 432 433 434 435 | manifest_destroy(pTo); } /* ** COMMAND: diff ** COMMAND: gdiff ** | | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | manifest_destroy(pTo); } /* ** COMMAND: diff ** COMMAND: gdiff ** ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked ** out. Or if the FILE arguments are omitted, show the unsaved changed ** currently in the working check-out. ** ** If the "--from VERSION" or "-r VERSION" option is used it specifies |
| ︙ | ︙ | |||
452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
** The "-i" command-line option forces the use of the internal diff logic
** rather than any external diff program that might be configured using
** the "setting" command. If no external diff program is configured, then
** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff".
**
** The "-N" or "--new-file" option causes the complete text of added or
** deleted files to be displayed.
*/
void diff_cmd(void){
int isGDiff; /* True for gdiff. False for normal diff */
int isInternDiff; /* True for internal diff */
int hasNFlag; /* True if -N or --new-file flag is used */
const char *zFrom; /* Source version number */
const char *zTo; /* Target version number */
| > > > > > > | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
** The "-i" command-line option forces the use of the internal diff logic
** rather than any external diff program that might be configured using
** the "setting" command. If no external diff program is configured, then
** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff".
**
** The "-N" or "--new-file" option causes the complete text of added or
** deleted files to be displayed.
**
** Options:
** --from|-r VERSION select VERSION as source for the diff
** --new-file|-N output complete text of added or deleted files
** -i use internal diff logic
** --to VERSION select VERSION as target for the diff
*/
void diff_cmd(void){
int isGDiff; /* True for gdiff. False for normal diff */
int isInternDiff; /* True for internal diff */
int hasNFlag; /* True if -N or --new-file flag is used */
const char *zFrom; /* Source version number */
const char *zTo; /* Target version number */
|
| ︙ | ︙ | |||
510 511 512 513 514 515 516 |
** WEBPAGE: vpatch
** URL vpatch?from=UUID&to=UUID
*/
void vpatch_page(void){
const char *zFrom = P("from");
const char *zTo = P("to");
login_check_credentials();
| | | 516 517 518 519 520 521 522 523 524 525 526 527 528 |
** WEBPAGE: vpatch
** URL vpatch?from=UUID&to=UUID
*/
void vpatch_page(void){
const char *zFrom = P("from");
const char *zTo = P("to");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
cgi_set_content_type("text/plain");
diff_all_two_versions(zFrom, zTo, 0, DIFF_NEWFILE);
}
|
Changes to src/doc.c.
| ︙ | ︙ | |||
343 344 345 346 347 348 349 | /* ** WEBPAGE: doc ** URL: /doc?name=BASELINE/PATH ** URL: /doc/BASELINE/PATH ** ** BASELINE can be either a baseline uuid prefix or magic words "tip" | | | | 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 370 371 372 373 374 375 |
/*
** WEBPAGE: doc
** URL: /doc?name=BASELINE/PATH
** URL: /doc/BASELINE/PATH
**
** BASELINE can be either a baseline uuid prefix or magic words "tip"
** to mean the most recently checked in baseline or "ckout" to mean the
** content of the local checkout, if any. PATH is the relative pathname
** of some file. This method returns the file content.
**
** If PATH matches the patterns *.wiki or *.txt then formatting content
** is added before returning the file. For all other names, the content
** is returned straight without any interpretation or processing.
*/
void doc_page(void){
const char *zName; /* Argument to the /doc page */
const char *zMime; /* Document MIME type */
int vid = 0; /* Artifact of baseline */
int rid = 0; /* Artifact of file */
int i; /* Loop counter */
Blob filebody; /* Content of the documentation file */
char zBaseline[UUID_SIZE+1]; /* Baseline UUID */
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
zName = PD("name", "tip/index.wiki");
for(i=0; zName[i] && zName[i]!='/'; i++){}
if( zName[i]==0 || i>UUID_SIZE ){
goto doc_not_found;
}
memcpy(zBaseline, zName, i);
zBaseline[i] = 0;
|
| ︙ | ︙ |
Changes to src/event.c.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
void hyperlink_to_event_tagid(int tagid){
char *zEventId;
char zShort[12];
zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
tagid);
sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zEventId);
| | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
void hyperlink_to_event_tagid(int tagid){
char *zEventId;
char zShort[12];
zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
tagid);
sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zEventId);
if( g.perm.History ){
@ [<a href="%s(g.zTop)/event?name=%s(zEventId)">%s(zShort)</a>]
}else{
@ [%s(zShort)]
}
free(zEventId);
}
|
| ︙ | ︙ | |||
72 73 74 75 76 77 78 | Stmt q1; /* Query to search for the event */ int showDetail; /* True to show details */ /* wiki-read privilege is needed in order to read events. */ login_check_credentials(); | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
Stmt q1; /* Query to search for the event */
int showDetail; /* True to show details */
/* wiki-read privilege is needed in order to read events.
*/
login_check_credentials();
if( !g.perm.RdWiki ){
login_needed();
return;
}
zEventId = P("name");
if( zEventId==0 ){ fossil_redirect_home(); return; }
zUuid = (char*)P("aid");
|
| ︙ | ︙ | |||
121 122 123 124 125 126 127 |
blob_init(&fullbody, pEvent->zWiki, -1);
if( wiki_find_title(&fullbody, &title, &tail) ){
style_header(blob_str(&title));
}else{
style_header("Event %S", zEventId);
tail = fullbody;
}
| | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
blob_init(&fullbody, pEvent->zWiki, -1);
if( wiki_find_title(&fullbody, &title, &tail) ){
style_header(blob_str(&title));
}else{
style_header("Event %S", zEventId);
tail = fullbody;
}
if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){
style_submenu_element("Edit", "Edit", "%s/eventedit?name=%s",
g.zTop, zEventId);
}
zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
style_submenu_element("Context", "Context", "%s/timeline?c=%T",
g.zTop, zETime);
if( g.perm.History ){
if( showDetail ){
style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s",
g.zTop, zEventId, zUuid);
if( nextRid ){
char *zNext;
zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid);
style_submenu_element("Next", "Next",
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 |
}else{
style_submenu_element("Detail", "Detail",
"%s/event?name=%s&aid=%s&detail=1",
g.zTop, zEventId, zUuid);
}
}
| | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
}else{
style_submenu_element("Detail", "Detail",
"%s/event?name=%s&aid=%s&detail=1",
g.zTop, zEventId, zUuid);
}
}
if( showDetail && g.perm.History ){
int i;
const char *zClr = 0;
Blob comment;
zATime = db_text(0, "SELECT datetime(%.17g)", pEvent->rDate);
@ <p>Event [<a href="%s(g.zTop)/artifact/%s(zUuid)">%S(zUuid)</a>] at
@ [<a href="%s(g.zTop)/timeline?c=%T(zETime)">%s(zETime)</a>]
|
| ︙ | ︙ | |||
234 235 236 237 238 239 240 |
" ORDER BY mtime DESC", zTag
);
free(zTag);
/* Need both check-in and wiki-write or wiki-create privileges in order
** to edit/create an event.
*/
| | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
" ORDER BY mtime DESC", zTag
);
free(zTag);
/* Need both check-in and wiki-write or wiki-create privileges in order
** to edit/create an event.
*/
if( !g.perm.Write || (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
login_needed();
return;
}
/* Figure out the color */
if( rid ){
zClr = db_text("", "SELECT bgcolor FROM event WHERE objid=%d", rid);
|
| ︙ | ︙ |
Changes to src/export.c.
| ︙ | ︙ | |||
82 83 84 85 86 87 88 | #define BLOBMARK(rid) ((rid) * 2) #define COMMITMARK(rid) ((rid) * 2 + 1) /* ** COMMAND: export ** | | > > > > > > > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#define BLOBMARK(rid) ((rid) * 2)
#define COMMITMARK(rid) ((rid) * 2 + 1)
/*
** COMMAND: export
**
** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY?
**
** Write an export of all check-ins to standard output. The export is
** written in the git-fast-export file format assuming the --git option is
** provided. The git-fast-export format is currently the only VCS
** interchange format supported, though other formats may be added in
** the future.
**
** Run this command within a checkout. Or use the -R or --repository
** option to specify a Fossil repository to be exported.
**
** Only check-ins are exported using --git. Git does not support tickets
** or wiki or events or attachments, so none of those are exported.
**
** If the "--import-marks FILE" option is used, it contains a list of
** rids to skip.
**
** If the "--export-marks FILE" option is used, the rid of all commits and
** blobs written on exit for use with "--import-marks" on the next run.
**
** Options:
** --export-marks FILE export rids of exported data to FILE
** --import-marks FILE read rids of data to ignore from FILE
** --repository|-R REPOSITORY export the given REPOSITORY
**
** See also: import
*/
void export_cmd(void){
Stmt q, q2, q3;
int i;
Bag blobs, vers;
const char *markfile_in;
const char *markfile_out;
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** | | > > > > > > > > > > > > > > > > | | > > > > | > > | < | < < | > > > > > > > | > > > > > > > | < < < < | < < | < | | < < < | < < | < < < < < < | | 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 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 88 89 90 91 92 93 94 95 96 97 98 99 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 133 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 |
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** File utilities.
**
** Functions named file_* are generic functions that always follow symlinks.
**
** Functions named file_wd_* are to be used for files inside working
** directories. They follow symlinks depending on 'allow-symlinks' setting.
*/
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "file.h"
/*
** The file status information from the most recent stat() call.
**
** Use _stati64 rather than stat on windows, in order to handle files
** larger than 2GB.
*/
#if defined(_WIN32) && defined(__MSVCRT__)
# define stat _stati64
#endif
/*
** On Windows S_ISLNK always returns FALSE.
*/
#if defined(_WIN32)
# define S_ISLNK(x) (0)
#endif
static int fileStatValid = 0;
static struct stat fileStat;
/*
** Fill stat buf with information received from stat() or lstat().
** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
**
*/
static int fossil_stat(const char *zFilename, struct stat *buf, int isWd){
#if !defined(_WIN32)
if( isWd && g.allowSymlinks ){
return lstat(zFilename, buf);
}else{
return stat(zFilename, buf);
}
#else
int rc = 0;
char *zMbcs = fossil_utf8_to_mbcs(zFilename);
rc = stat(zMbcs, buf);
fossil_mbcs_free(zMbcs);
return rc;
#endif
}
/*
** Fill in the fileStat variable for the file named zFilename.
** If zFilename==0, then use the previous value of fileStat if
** there is a previous value.
**
** If isWd is TRUE, do lstat() instead of stat() if allow-symlinks is on.
**
** Return the number of errors. No error messages are generated.
*/
static int getStat(const char *zFilename, int isWd){
int rc = 0;
if( zFilename==0 ){
if( fileStatValid==0 ) rc = 1;
}else{
if( fossil_stat(zFilename, &fileStat, isWd)!=0 ){
fileStatValid = 0;
rc = 1;
}else{
fileStatValid = 1;
rc = 0;
}
}
return rc;
}
/*
** Return the size of a file in bytes. Return -1 if the file does not
** exist. If zFilename is NULL, return the size of the most recently
** stat-ed file.
*/
i64 file_size(const char *zFilename){
return getStat(zFilename, 0) ? -1 : fileStat.st_size;
}
/*
** Same as file_size(), but takes into account symlinks.
*/
i64 file_wd_size(const char *zFilename){
return getStat(zFilename, 1) ? -1 : fileStat.st_size;
}
/*
** Return the modification time for a file. Return -1 if the file
** does not exist. If zFilename is NULL return the size of the most
** recently stat-ed file.
*/
i64 file_mtime(const char *zFilename){
return getStat(zFilename, 0) ? -1 : fileStat.st_mtime;
}
/*
** Same as file_mtime(), but takes into account symlinks.
*/
i64 file_wd_mtime(const char *zFilename){
return getStat(zFilename, 1) ? -1 : fileStat.st_mtime;
}
/*
** Return TRUE if the named file is an ordinary file or symlink
** and symlinks are allowed.
** Return false for directories, devices, fifos, etc.
*/
int file_wd_isfile_or_link(const char *zFilename){
return getStat(zFilename, 1) ? 0 : S_ISREG(fileStat.st_mode) ||
S_ISLNK(fileStat.st_mode);
}
/*
** Return TRUE if the named file is an ordinary file. Return false
** for directories, devices, fifos, symlinks, etc.
*/
int file_isfile(const char *zFilename){
return getStat(zFilename, 0) ? 0 : S_ISREG(fileStat.st_mode);
}
/*
** Same as file_isfile(), but takes into account symlinks.
*/
int file_wd_isfile(const char *zFilename){
return getStat(zFilename, 1) ? 0 : S_ISREG(fileStat.st_mode);
}
/*
** Create symlink to file on Unix, or plain-text file with
** symlink target if "allow-symlinks" is off or we're on Windows.
**
** Arguments: target file (symlink will point to it), link file
**/
void symlink_create(const char *zTargetFile, const char *zLinkFile){
#if !defined(_WIN32)
if( g.allowSymlinks ){
int i, nName;
char *zName, zBuf[1000];
nName = strlen(zLinkFile);
if( nName>=sizeof(zBuf) ){
|
| ︙ | ︙ | |||
178 179 180 181 182 183 184 |
blob_set(&content, zTargetFile);
blob_write_to_file(&content, zLinkFile);
blob_reset(&content);
}
}
/*
| > > > > > > > > | > > > > | | | | > > > > | > > > > > > > > > > > | > > | > > | < | < < < < | | < < | > | > > > > | | > > > > > | > > < > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 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 |
blob_set(&content, zTargetFile);
blob_write_to_file(&content, zLinkFile);
blob_reset(&content);
}
}
/*
** Copy symbolic link from zFrom to zTo.
*/
void symlink_copy(const char *zFrom, const char *zTo){
Blob content;
blob_read_link(&content, zFrom);
symlink_create(blob_str(&content), zTo);
blob_reset(&content);
}
/*
** Return file permissions (normal, executable, or symlink):
** - PERM_EXE if file is executable;
** - PERM_LNK on Unix if file is symlink and allow-symlinks option is on;
** - PERM_REG for all other cases (regular file, directory, fifo, etc).
*/
int file_wd_perm(const char *zFilename){
if( getStat(zFilename, 1) ) return PERM_REG;
#if defined(_WIN32)
# if defined(__DMC__) || defined(_MSC_VER)
# define S_IXUSR _S_IEXEC
# endif
if( S_ISREG(fileStat.st_mode) && ((S_IXUSR)&fileStat.st_mode)!=0 )
return PERM_EXE;
else
return PERM_REG;
#else
if( S_ISREG(fileStat.st_mode) &&
((S_IXUSR|S_IXGRP|S_IXOTH)&fileStat.st_mode)!=0 )
return PERM_EXE;
else if( g.allowSymlinks && S_ISLNK(fileStat.st_mode) )
return PERM_LNK;
else
return PERM_REG;
#endif
}
/*
** Return TRUE if the named file is an executable. Return false
** for directories, devices, fifos, symlinks, etc.
*/
int file_wd_isexe(const char *zFilename){
return file_wd_perm(zFilename)==PERM_EXE;
}
/*
** Return TRUE if the named file is a symlink and symlinks are allowed.
** Return false for all other cases.
**
** On Windows, always return False.
*/
int file_wd_islink(const char *zFilename){
return file_wd_perm(zFilename)==PERM_LNK;
}
/*
** Return 1 if zFilename is a directory. Return 0 if zFilename
** does not exist. Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename){
int rc;
if( zFilename ){
char *zFN = mprintf("%s", zFilename);
file_simplify_name(zFN, -1);
rc = getStat(zFN, 0);
free(zFN);
}else{
rc = getStat(0, 0);
}
return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2);
}
/*
** Same as file_isdir(), but takes into account symlinks.
*/
int file_wd_isdir(const char *zFilename){
int rc;
if( zFilename ){
char *zFN = mprintf("%s", zFilename);
file_simplify_name(zFN, -1);
rc = getStat(zFN, 1);
free(zFN);
}else{
rc = getStat(0, 1);
}
return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2);
}
/*
** Wrapper around the access() system call.
*/
int file_access(const char *zFilename, int flags){
char *zMbcs = fossil_utf8_to_mbcs(zFilename);
int rc = access(zMbcs, flags);
|
| ︙ | ︙ | |||
303 304 305 306 307 308 309 | fclose(out); } /* ** Set or clear the execute bit on a file. Return true if a change ** occurred and false if this routine is a no-op. */ | | | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
fclose(out);
}
/*
** Set or clear the execute bit on a file. Return true if a change
** occurred and false if this routine is a no-op.
*/
int file_wd_setexe(const char *zFilename, int onoff){
int rc = 0;
#if !defined(_WIN32)
struct stat buf;
if( fossil_stat(zFilename, &buf, 1)!=0 || S_ISLNK(buf.st_mode) ) return 0;
if( onoff ){
int targetMode = (buf.st_mode & 0444)>>2;
if( (buf.st_mode & 0111)!=targetMode ){
chmod(zFilename, buf.st_mode | targetMode);
rc = 1;
}
}else{
|
| ︙ | ︙ | |||
572 573 574 575 576 577 578 |
blob_zero(&x);
for(i=2; i<g.argc; i++){
char zBuf[100];
const char *zName = g.argv[i];
file_canonical_name(zName, &x);
fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x));
blob_reset(&x);
| | | | | | | | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
blob_zero(&x);
for(i=2; i<g.argc; i++){
char zBuf[100];
const char *zName = g.argv[i];
file_canonical_name(zName, &x);
fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x));
blob_reset(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_wd_size(zName));
fossil_print(" file_size = %s\n", zBuf);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_wd_mtime(zName));
fossil_print(" file_mtime = %s\n", zBuf);
fossil_print(" file_isfile = %d\n", file_wd_isfile(zName));
fossil_print(" file_isfile_or_link = %d\n",file_wd_isfile_or_link(zName));
fossil_print(" file_islink = %d\n", file_wd_islink(zName));
fossil_print(" file_isexe = %d\n", file_wd_isexe(zName));
fossil_print(" file_isdir = %d\n", file_wd_isdir(zName));
}
}
/*
** Return TRUE if the given filename is canonical.
**
** Canonical names are full pathnames using "/" not "\" and which
|
| ︙ | ︙ | |||
849 850 851 852 853 854 855 | i64 iSize; int rc; Blob onDisk; iSize = file_size(zName); if( iSize<0 ) return 0; if( iSize!=blob_size(pContent) ) return 0; | | | 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
i64 iSize;
int rc;
Blob onDisk;
iSize = file_size(zName);
if( iSize<0 ) return 0;
if( iSize!=blob_size(pContent) ) return 0;
if( file_wd_islink(zName) ){
blob_read_link(&onDisk, zName);
}else{
blob_read_from_file(&onDisk, zName);
}
rc = blob_compare(&onDisk, pContent);
blob_reset(&onDisk);
return rc==0;
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | */ #include "config.h" #include "finfo.h" /* ** COMMAND: finfo ** | | | | | > > > > > > > > > > > > | 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 57 58 59 60 |
*/
#include "config.h"
#include "finfo.h"
/*
** COMMAND: finfo
**
** Usage: %fossil finfo ?OPTIONS? FILENAME
**
** Print the complete change history for a single file going backwards
** in time. The default is -l.
**
** For the -l|--log option: If "-b|--brief" is specified one line per revision
** is printed, otherwise the full comment is printed. The "--limit N"
** and "--offset P" options limits the output to the first N changes
** after skipping P changes.
**
** In the -s form prints the status as <status> <revision>. This is
** a quick status and does not check for up-to-date-ness of the file.
**
** In the -p form, there's an optional flag "-r|--revision REVISION".
** The specified version (or the latest checked out version) is printed
** to stdout.
**
** Options:
** --brief|-b display a brief (one line / revision) summary
** --limit N display the first N changes
** --log|-l select log mode (the default)
** --offset P skip P changes
** -p select print mode
** --revision|-r R print the given revision (or ckout, if none is given)
** to stdout (only in print mode)
** -s select status mode (print a status indicator for FILE)
**
** See also: descendants, info, leaves
*/
void finfo_cmd(void){
db_must_be_within_tree();
if (find_option("status","s",0)) {
Stmt q;
Blob line;
Blob fname;
|
| ︙ | ︙ | |||
208 209 210 211 212 213 214 |
Blob title;
Blob sql;
GraphContext *pGraph;
int brBg = P("brbg")!=0;
int uBg = P("ubg")!=0;
login_check_credentials();
| | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
Blob title;
Blob sql;
GraphContext *pGraph;
int brBg = P("brbg")!=0;
int uBg = P("ubg")!=0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
style_header("File History");
login_anonymous_available();
zPrevDate[0] = 0;
zFilename = PD("name","");
blob_zero(&sql);
blob_appendf(&sql,
|
| ︙ | ︙ | |||
295 296 297 298 299 300 301 |
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
}else{
@ <td class="timelineTableCell">
}
sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
if( zUuid ){
| | | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
}else{
@ <td class="timelineTableCell">
}
sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
if( zUuid ){
if( g.perm.History ){
@ <a href="%s(g.zTop)/artifact/%s(zUuid)">[%S(zUuid)]</a>
}else{
@ [%S(zUuid)]
}
@ part of check-in
}else{
@ <b>Deleted</b> by check-in
}
hyperlink_to_uuid(zShortCkin);
@ %h(zCom) (user:
hyperlink_to_user(zUser, zDate, "");
@ branch: %h(zBr))
if( g.perm.History && zUuid ){
const char *z = zFilename;
if( fpid ){
@ <a href="%s(g.zTop)/fdiff?v1=%s(zPUuid)&v2=%s(zUuid)">[diff]</a>
}
@ <a href="%s(g.zTop)/annotate?checkin=%S(zCkin)&filename=%h(z)">
@ [annotate]</a>
}
|
| ︙ | ︙ |
Changes to src/http_ssl.c.
| ︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
if( sslIsInit==0 ){
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
sslCtx = SSL_CTX_new(SSLv23_client_method());
/* Set up acceptable CA root certificates */
zCaSetting = db_get("ssl-ca-location", 0);
if( zCaSetting==0 || zCaSetting[0]=='\0' ){
/* CA location not specified, use platform's default certificate store */
X509_STORE_set_default_paths(SSL_CTX_get_cert_store(sslCtx));
}else{
| > > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
if( sslIsInit==0 ){
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
sslCtx = SSL_CTX_new(SSLv23_client_method());
/* Disable SSLv2 */
SSL_CTX_set_options(sslCtx, SSL_OP_NO_SSLv2);
/* Set up acceptable CA root certificates */
zCaSetting = db_get("ssl-ca-location", 0);
if( zCaSetting==0 || zCaSetting[0]=='\0' ){
/* CA location not specified, use platform's default certificate store */
X509_STORE_set_default_paths(SSL_CTX_get_cert_store(sslCtx));
}else{
|
| ︙ | ︙ | |||
247 248 249 250 251 252 253 |
BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n ");
if(X509_digest(cert, EVP_sha1(), md, &mdLength)){
int j;
for( j = 0; j < mdLength; ++j ) {
BIO_printf(mem, " %02x", md[j]);
}
}
| | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n ");
if(X509_digest(cert, EVP_sha1(), md, &mdLength)){
int j;
for( j = 0; j < mdLength; ++j ) {
BIO_printf(mem, " %02x", md[j]);
}
}
BIO_write(mem, "", 1); /* nul-terminate mem buffer */
BIO_get_mem_data(mem, &desc);
if( hasSavedCertificate ){
warning = "WARNING: Certificate doesn't match the "
"saved certificate for this host!";
}
prompt = mprintf("\nUnknown SSL certificate:\n\n%s\n\n%s\n"
|
| ︙ | ︙ | |||
302 303 304 305 306 307 308 |
*/
void ssl_save_certificate(X509 *cert){
BIO *mem;
char *zCert, *zHost;
mem = BIO_new(BIO_s_mem());
PEM_write_bio_X509(mem, cert);
| | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
*/
void ssl_save_certificate(X509 *cert){
BIO *mem;
char *zCert, *zHost;
mem = BIO_new(BIO_s_mem());
PEM_write_bio_X509(mem, cert);
BIO_write(mem, "", 1); /* nul-terminate mem buffer */
BIO_get_mem_data(mem, &zCert);
zHost = mprintf("cert:%s", g.urlName);
db_set(zHost, zCert, 1);
free(zHost);
BIO_free(mem);
}
|
| ︙ | ︙ |
Changes to src/import.c.
| ︙ | ︙ | |||
699 700 701 702 703 704 705 |
fossil_fatal("bad fast-import line: [%s]", zLine);
return;
}
/*
** COMMAND: import
**
| | > > > > > | 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 |
fossil_fatal("bad fast-import line: [%s]", zLine);
return;
}
/*
** COMMAND: import
**
** Usage: %fossil import --git ?OPTIONS? NEW-REPOSITORY
**
** Read text generated by the git-fast-export command and use it to
** construct a new Fossil repository named by the NEW-REPOSITORY
** argument. The git-fast-export text is read from standard input.
**
** The git-fast-export file format is currently the only VCS interchange
** format that is understood, though other interchange formats may be added
** in the future.
**
** The --incremental option allows an existing repository to be extended
** with new content.
**
** Options:
** --incremental allow importing into an existing repository
**
** See also: export
*/
void git_import_cmd(void){
char *zPassword;
FILE *pIn;
Stmt q;
int forceFlag = find_option("force", "f", 0)!=0;
int incrFlag = find_option("incremental", "i", 0)!=0;
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
78 79 80 81 82 83 84 |
"SELECT coalesce(ecomment,comment) || "
" ' (user: ' || coalesce(euser,user,'?') || ')' "
" FROM event WHERE objid=%d",
rid
);
}
if( showFamily ){
| | | > > | | | > > | | > > > > < < < | > | | > | | < < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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 133 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 175 176 177 178 179 180 181 |
"SELECT coalesce(ecomment,comment) || "
" ' (user: ' || coalesce(euser,user,'?') || ')' "
" FROM event WHERE objid=%d",
rid
);
}
if( showFamily ){
db_prepare(&q, "SELECT uuid, pid, isprim FROM plink JOIN blob ON pid=rid "
" WHERE cid=%d"
" ORDER BY isprim DESC, mtime DESC /*sort*/", rid);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
const char *zType = db_column_int(&q, 2) ? "parent:" : "merged-from:";
zDate = db_text("",
"SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d",
db_column_int(&q, 1)
);
fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
free(zDate);
}
db_finalize(&q);
db_prepare(&q, "SELECT uuid, cid, isprim FROM plink JOIN blob ON cid=rid "
" WHERE pid=%d"
" ORDER BY isprim DESC, mtime DESC /*sort*/", rid);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
const char *zType = db_column_int(&q, 2) ? "child:" : "merged-into:";
zDate = db_text("",
"SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d",
db_column_int(&q, 1)
);
fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
free(zDate);
}
db_finalize(&q);
}
zTags = info_tags_of_checkin(rid, 0);
if( zTags && zTags[0] ){
fossil_print("tags: %s\n", zTags);
}
free(zTags);
if( zComment ){
fossil_print("comment: ");
comment_print(zComment, 14, 79);
free(zComment);
}
}
/*
** COMMAND: info
**
** Usage: %fossil info ?VERSION | REPOSITORY_FILENAME? ?OPTIONS?
**
** With no arguments, provide information about the current tree.
** If an argument is specified, provide information about the object
** in the respository of the current tree that the argument refers
** to. Or if the argument is the name of a repository, show
** information about that repository.
**
** Use the "finfo" command to get information about a specific
** file in a checkout.
**
** Options:
**
** -R|--repository FILE Extract info from repository FILE
*/
void info_cmd(void){
i64 fsize;
if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
db_open_config(0);
db_record_repository_filename(g.argv[2]);
db_open_repository(g.argv[2]);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
fossil_print("server-code: %s\n", db_get("server-code", "<none>"));
return;
}
db_find_and_open_repository(0,0);
if( g.argc==2 ){
int vid;
/* 012345678901234 */
db_record_repository_filename(0);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
if( g.localOpen ){
fossil_print("repository: %s\n", db_lget("repository", ""));
fossil_print("local-root: %s\n", g.zLocalRoot);
}
#if defined(_WIN32)
if( g.zHome ){
fossil_print("user-home: %s\n", g.zHome);
}
#endif
fossil_print("project-code: %s\n", db_get("project-code", ""));
fossil_print("server-code: %s\n", db_get("server-code", ""));
vid = g.localOpen ? db_lget_int("checkout", 0) : 0;
if( vid ){
show_common_info(vid, "checkout:", 1, 1);
}
}else{
int rid;
rid = name_to_rid(g.argv[2]);
if( rid==0 ){
fossil_panic("no such object: %s\n", g.argv[2]);
|
| ︙ | ︙ | |||
282 283 284 285 286 287 288 |
const char *zName, /* Name of the file that has changed */
const char *zOld, /* blob.uuid before change. NULL for added files */
const char *zNew, /* blob.uuid after change. NULL for deletes */
const char *zOldName, /* Prior name. NULL if no name change. */
int showDiff, /* Show edit diffs if true */
int mperm /* executable or symlink permission for zNew */
){
| | | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
const char *zName, /* Name of the file that has changed */
const char *zOld, /* blob.uuid before change. NULL for added files */
const char *zNew, /* blob.uuid after change. NULL for deletes */
const char *zOldName, /* Prior name. NULL if no name change. */
int showDiff, /* Show edit diffs if true */
int mperm /* executable or symlink permission for zNew */
){
if( !g.perm.History ){
if( zNew==0 ){
@ <p>Deleted %h(zName)</p>
}else if( zOld==0 ){
@ <p>Added %h(zName)</p>
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
@ <p>Name change from %h(zOldName) to %h(zName)
}else if( fossil_strcmp(zNew, zOld)==0 ){
|
| ︙ | ︙ | |||
359 360 361 362 363 364 365 | int isLeaf; int showDiff; const char *zName; /* Name of the checkin to be displayed */ const char *zUuid; /* UUID of zName */ const char *zParent; /* UUID of the parent checkin (if any) */ login_check_credentials(); | | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
int isLeaf;
int showDiff;
const char *zName; /* Name of the checkin to be displayed */
const char *zUuid; /* UUID of zName */
const char *zParent; /* UUID of the parent checkin (if any) */
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
zName = P("name");
rid = name_to_rid_www("name");
if( rid==0 ){
style_header("Check-in Information Error");
@ No such object: %h(g.argv[2])
style_footer();
return;
|
| ︙ | ︙ | |||
407 408 409 410 411 412 413 |
zUser = db_column_text(&q, 2);
zComment = db_column_text(&q, 3);
zDate = db_column_text(&q,1);
zOrigDate = db_column_text(&q, 4);
@ <div class="section">Overview</div>
@ <table class="label-value">
@ <tr><th>SHA1 Hash:</th><td>%s(zUuid)
| | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
zUser = db_column_text(&q, 2);
zComment = db_column_text(&q, 3);
zDate = db_column_text(&q,1);
zOrigDate = db_column_text(&q, 4);
@ <div class="section">Overview</div>
@ <table class="label-value">
@ <tr><th>SHA1 Hash:</th><td>%s(zUuid)
if( g.perm.Setup ){
@ (Record ID: %d(rid))
}
@ </td></tr>
@ <tr><th>Date:</th><td>
hyperlink_to_date(zDate, "</td></tr>");
if( zOrigDate && fossil_strcmp(zDate, zOrigDate)!=0 ){
@ <tr><th>Original Date:</th><td>
|
| ︙ | ︙ | |||
432 433 434 435 436 437 438 |
}
if( zEComment ){
@ <tr><th>Edited Comment:</th><td>%w(zEComment)</td></tr>
@ <tr><th>Original Comment:</th><td>%w(zComment)</td></tr>
}else{
@ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
}
| | | | 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 |
}
if( zEComment ){
@ <tr><th>Edited Comment:</th><td>%w(zEComment)</td></tr>
@ <tr><th>Original Comment:</th><td>%w(zComment)</td></tr>
}else{
@ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
}
if( g.perm.Admin ){
db_prepare(&q,
"SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
" FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
" WHERE blob.rid=%d",
rid
);
if( db_step(&q)==SQLITE_ROW ){
const char *zIpAddr = db_column_text(&q, 0);
const char *zUser = db_column_text(&q, 1);
const char *zDate = db_column_text(&q, 2);
if( zUser==0 || zUser[0]==0 ) zUser = "unknown";
@ <tr><th>Received From:</th>
@ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
}
db_finalize(&q);
}
if( g.perm.History ){
const char *zProjName = db_get("project-name", "unnamed");
@ <tr><th>Timelines:</th><td>
@ <a href="%s(g.zTop)/timeline?f=%S(zUuid)">family</a>
if( zParent ){
@ | <a href="%s(g.zTop)/timeline?p=%S(zUuid)">ancestors</a>
}
if( !isLeaf ){
|
| ︙ | ︙ | |||
475 476 477 478 479 480 481 |
@ | <a href="%s(g.zTop)/timeline?r=%T(zTagName)">%h(zTagName)</a>
}
db_finalize(&q);
@ </td></tr>
@ <tr><th>Other Links:</th>
@ <td>
@ <a href="%s(g.zTop)/dir?ci=%S(zUuid)">files</a>
| | | | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 |
@ | <a href="%s(g.zTop)/timeline?r=%T(zTagName)">%h(zTagName)</a>
}
db_finalize(&q);
@ </td></tr>
@ <tr><th>Other Links:</th>
@ <td>
@ <a href="%s(g.zTop)/dir?ci=%S(zUuid)">files</a>
if( g.perm.Zip ){
char *zUrl = mprintf("%s/tarball/%s-%S.tar.gz?uuid=%s",
g.zTop, zProjName, zUuid, zUuid);
@ | <a href="%s(zUrl)">Tarball</a>
@ | <a href="%s(g.zTop)/zip/%s(zProjName)-%S(zUuid).zip?uuid=%s(zUuid)">
@ ZIP archive</a>
fossil_free(zUrl);
}
@ | <a href="%s(g.zTop)/artifact/%S(zUuid)">manifest</a>
if( g.perm.Write ){
@ | <a href="%s(g.zTop)/ci_edit?r=%S(zUuid)">edit</a>
}
@ </td>
@ </tr>
}
@ </table>
}else{
|
| ︙ | ︙ | |||
551 552 553 554 555 556 557 |
** Return information about a wiki page.
*/
void winfo_page(void){
Stmt q;
int rid;
login_check_credentials();
| | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
** Return information about a wiki page.
*/
void winfo_page(void){
Stmt q;
int rid;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
rid = name_to_rid_www("name");
if( rid==0 ){
style_header("Wiki Page Information Error");
@ No such object: %h(g.argv[2])
style_footer();
return;
}
|
| ︙ | ︙ | |||
584 585 586 587 588 589 590 |
free(zTitle);
login_anonymous_available();
@ <div class="section">Overview</div>
@ <p><table class="label-value">
@ <tr><th>Version:</th><td>%s(zUuid)</td></tr>
@ <tr><th>Date:</th><td>
hyperlink_to_date(zDate, "</td></tr>");
| | | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
free(zTitle);
login_anonymous_available();
@ <div class="section">Overview</div>
@ <p><table class="label-value">
@ <tr><th>Version:</th><td>%s(zUuid)</td></tr>
@ <tr><th>Date:</th><td>
hyperlink_to_date(zDate, "</td></tr>");
if( g.perm.Setup ){
@ <tr><th>Record ID:</th><td>%d(rid)</td></tr>
}
@ <tr><th>Original User:</th><td>
hyperlink_to_user(zUser, zDate, "</td></tr>");
if( g.perm.History ){
@ <tr><th>Commands:</th>
@ <td>
@ <a href="%s(g.zTop)/whistory?name=%t(zName)">history</a>
@ | <a href="%s(g.zTop)/artifact/%S(zUuid)">raw-text</a>
@ </td>
@ </tr>
}
|
| ︙ | ︙ | |||
694 695 696 697 698 699 700 |
void vdiff_page(void){
int ridFrom, ridTo;
int showDetail = 0;
Manifest *pFrom, *pTo;
ManifestFile *pFileFrom, *pFileTo;
login_check_credentials();
| | | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 |
void vdiff_page(void){
int ridFrom, ridTo;
int showDetail = 0;
Manifest *pFrom, *pTo;
ManifestFile *pFileFrom, *pFileTo;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
login_anonymous_available();
pFrom = vdiff_parse_manifest("from", &ridFrom);
if( pFrom==0 ) return;
pTo = vdiff_parse_manifest("to", &ridTo);
if( pTo==0 ) return;
showDetail = atoi(PD("detail","0"));
|
| ︙ | ︙ | |||
813 814 815 816 817 818 819 |
if( mPerm==PERM_LNK ){
@ <li>Symbolic link
}else if( mPerm==PERM_EXE ){
@ <li>Executable file
}else{
@ <li>File
}
| | | | | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
if( mPerm==PERM_LNK ){
@ <li>Symbolic link
}else if( mPerm==PERM_EXE ){
@ <li>Executable file
}else{
@ <li>File
}
if( g.perm.History ){
@ <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
}else{
@ %h(zName)
}
@ <ul>
prevName = fossil_strdup(zName);
}
@ <li>
hyperlink_to_date(zDate,"");
@ - part of checkin
hyperlink_to_uuid(zVers);
if( zBr && zBr[0] ){
if( g.perm.History ){
@ on branch <a href="%s(g.zTop)/timeline?r=%T(zBr)">%h(zBr)</a>
}else{
@ on branch %h(zBr)
}
}
@ - %w(zCom) (user:
hyperlink_to_user(zUser,zDate,"");
@ )
if( g.perm.History ){
@ <a href="%s(g.zTop)/annotate?checkin=%S(zVers)&filename=%T(zName)">
@ [annotate]</a>
}
cnt++;
if( pDownloadName && blob_size(pDownloadName)==0 ){
blob_append(pDownloadName, zName, -1);
}
|
| ︙ | ︙ | |||
866 867 868 869 870 871 872 |
const char *zDate = db_column_text(&q, 1);
const char *zUser = db_column_text(&q, 2);
if( cnt>0 ){
@ Also wiki page
}else{
@ Wiki page
}
| | | 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 |
const char *zDate = db_column_text(&q, 1);
const char *zUser = db_column_text(&q, 2);
if( cnt>0 ){
@ Also wiki page
}else{
@ Wiki page
}
if( g.perm.History ){
@ [<a href="%s(g.zTop)/wiki?name=%t(zPagename)">%h(zPagename)</a>]
}else{
@ [%h(zPagename)]
}
@ by
hyperlink_to_user(zUser,zDate," on");
hyperlink_to_date(zDate,".");
|
| ︙ | ︙ | |||
942 943 944 945 946 947 948 |
/* const char *zSrc = db_column_text(&q, 4); */
if( cnt>0 ){
@ Also attachment "%h(zFilename)" to
}else{
@ Attachment "%h(zFilename)" to
}
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
| | | | | 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 985 986 987 |
/* const char *zSrc = db_column_text(&q, 4); */
if( cnt>0 ){
@ Also attachment "%h(zFilename)" to
}else{
@ Attachment "%h(zFilename)" to
}
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
if( g.perm.History && g.perm.RdTkt ){
@ ticket [<a href="%s(g.zTop)/tktview?name=%S(zTarget)">%S(zTarget)</a>]
}else{
@ ticket [%S(zTarget)]
}
}else{
if( g.perm.History && g.perm.RdWiki ){
@ wiki page [<a href="%s(g.zTop)/wiki?name=%t(zTarget)">%h(zTarget)</a>]
}else{
@ wiki page [%h(zTarget)]
}
}
@ added by
hyperlink_to_user(zUser,zDate," on");
hyperlink_to_date(zDate,".");
cnt++;
if( pDownloadName && blob_size(pDownloadName)==0 ){
blob_append(pDownloadName, zFilename, -1);
}
}
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.History ){
@ <a href="%s(g.zTop)/artifact/%S(zUuid)">[view]</a>
}
}
/*
** WEBPAGE: fdiff
|
| ︙ | ︙ | |||
990 991 992 993 994 995 996 | int v1, v2; int isPatch; Blob c1, c2, diff, *pOut; char *zV1; char *zV2; login_check_credentials(); | | | 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
int v1, v2;
int isPatch;
Blob c1, c2, diff, *pOut;
char *zV1;
char *zV2;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
v1 = name_to_rid_www("v1");
v2 = name_to_rid_www("v2");
if( v1==0 || v2==0 ) fossil_redirect_home();
zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
isPatch = P("patch")!=0;
if( isPatch ){
|
| ︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 |
int rid;
const char *zMime;
Blob content;
rid = name_to_rid_www("name");
zMime = PD("m","application/x-fossil-artifact");
login_check_credentials();
| | | 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 |
int rid;
const char *zMime;
Blob content;
rid = name_to_rid_www("name");
zMime = PD("m","application/x-fossil-artifact");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
content_get(rid, &content);
cgi_set_content_type(zMime);
cgi_set_content(&content);
}
/*
|
| ︙ | ︙ | |||
1115 1116 1117 1118 1119 1120 1121 |
int rid;
Blob content;
Blob downloadName;
char *zUuid;
rid = name_to_rid_www("name");
login_check_credentials();
| | | | 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 |
int rid;
Blob content;
Blob downloadName;
char *zUuid;
rid = name_to_rid_www("name");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
if( g.perm.Admin ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
|
| ︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 |
rid = artifact_from_ci_and_filename();
}
if( rid==0 ){
rid = name_to_rid_www("name");
}
login_check_credentials();
| | | | 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 |
rid = artifact_from_ci_and_filename();
}
if( rid==0 ){
rid = name_to_rid_www("name");
}
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
if( g.perm.Admin ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
|
| ︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 | int rid; char *zDate; const char *zUuid; char zTktName[20]; Manifest *pTktChng; login_check_credentials(); | | | | | 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 1381 1382 1383 1384 1385 1386 1387 1388 1389 |
int rid;
char *zDate;
const char *zUuid;
char zTktName[20];
Manifest *pTktChng;
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(); return; }
rid = name_to_rid_www("name");
if( rid==0 ){ fossil_redirect_home(); }
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( g.perm.Admin ){
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
}
}
pTktChng = manifest_get(rid, CFTYPE_TICKET);
if( pTktChng==0 ){
fossil_redirect_home();
}
style_header("Ticket Change Details");
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
memcpy(zTktName, pTktChng->zTicketUuid, 10);
zTktName[10] = 0;
if( g.perm.History ){
@ <h2>Changes to ticket
@ <a href="%s(pTktChng->zTicketUuid)">%s(zTktName)</a></h2>
@
@ <p>By %h(pTktChng->zUser) on %s(zDate). See also:
@ <a href="%s(g.zTop)/artifact/%T(zUuid)">artifact content</a>, and
@ <a href="%s(g.zTop)/tkthistory/%s(pTktChng->zTicketUuid)">ticket
@ history</a></p>
|
| ︙ | ︙ | |||
1610 1611 1612 1613 1614 1615 1616 | int fPropagateColor; /* True if color propagates before edit */ int fNewPropagateColor; /* True if color propagates after edit */ char *zUuid; Blob comment; Stmt q; login_check_credentials(); | | | 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 |
int fPropagateColor; /* True if color propagates before edit */
int fNewPropagateColor; /* True if color propagates after edit */
char *zUuid;
Blob comment;
Stmt q;
login_check_credentials();
if( !g.perm.Write ){ login_needed(); return; }
rid = name_to_typed_rid(P("r"), "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zComment = db_text(0, "SELECT coalesce(ecomment,comment)"
" FROM event WHERE objid=%d", rid);
if( zComment==0 ) fossil_redirect_home();
if( P("cancel") ){
cgi_redirectf("ci?name=%s", zUuid);
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
224 225 226 227 228 229 230 |
anonFlag = P("anon")!=0;
if( P("out")!=0 ){
/* To logout, change the cookie value to an empty string */
const char *zCookieName = login_cookie_name();
cgi_set_cookie(zCookieName, "", login_cookie_path(), -86400);
redirect_to_g();
}
| | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
anonFlag = P("anon")!=0;
if( P("out")!=0 ){
/* To logout, change the cookie value to an empty string */
const char *zCookieName = login_cookie_name();
cgi_set_cookie(zCookieName, "", login_cookie_path(), -86400);
redirect_to_g();
}
if( g.perm.Password && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
/* The user requests a password change */
zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
if( db_int(1, "SELECT 0 FROM user"
" WHERE uid=%d AND (pw=%Q OR pw=%Q)",
g.userUid, zPasswd, zSha1Pw) ){
sleep(1);
zErrMsg =
|
| ︙ | ︙ | |||
429 430 431 432 433 434 435 |
if( g.zLogin ){
@ <hr />
@ <p>To log off the system (and delete your login cookie)
@ press the following button:<br />
@ <input type="submit" name="out" value="Logout" /></p>
}
@ </form>
| | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
if( g.zLogin ){
@ <hr />
@ <p>To log off the system (and delete your login cookie)
@ press the following button:<br />
@ <input type="submit" name="out" value="Logout" /></p>
}
@ </form>
if( g.perm.Password ){
@ <hr />
@ <p>To change your password, enter your old password and your
@ new password twice below then press the "Change Password"
@ button.</p>
@ <form action="login" method="post">
@ <table>
@ <tr><td class="login_out_label">Old Password:</td>
|
| ︙ | ︙ | |||
539 540 541 542 543 544 545 | return uid; } /* ** This routine examines the login cookie to see if it exists and ** and is valid. If the login cookie checks out, it then sets ** global variables appropriately. Global variables set include | | | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
return uid;
}
/*
** This routine examines the login cookie to see if it exists and
** and is valid. If the login cookie checks out, it then sets
** global variables appropriately. Global variables set include
** g.userUid and g.zLogin and of the g.perm.Read family of permission
** booleans.
**
*/
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
|
| ︙ | ︙ | |||
723 724 725 726 727 728 729 |
/*
** Set the global capability flags based on a capability string.
*/
void login_set_capabilities(const char *zCap, unsigned flags){
int i;
for(i=0; zCap[i]; i++){
switch( zCap[i] ){
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
/*
** Set the global capability flags based on a capability string.
*/
void login_set_capabilities(const char *zCap, unsigned flags){
int i;
for(i=0; zCap[i]; i++){
switch( zCap[i] ){
case 's': g.perm.Setup = 1; /* Fall thru into Admin */
case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
g.perm.ApndWiki = g.perm.History = g.perm.Clone =
g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1;
/* Fall thru into Read/Write */
case 'i': g.perm.Read = g.perm.Write = 1; break;
case 'o': g.perm.Read = 1; break;
case 'z': g.perm.Zip = 1; break;
case 'd': g.perm.Delete = 1; break;
case 'h': g.perm.History = 1; break;
case 'g': g.perm.Clone = 1; break;
case 'p': g.perm.Password = 1; break;
case 'j': g.perm.RdWiki = 1; break;
case 'k': g.perm.WrWiki = g.perm.RdWiki = g.perm.ApndWiki =1; break;
case 'm': g.perm.ApndWiki = 1; break;
case 'f': g.perm.NewWiki = 1; break;
case 'e': g.perm.RdAddr = 1; break;
case 'r': g.perm.RdTkt = 1; break;
case 'n': g.perm.NewTkt = 1; break;
case 'w': g.perm.WrTkt = g.perm.RdTkt = g.perm.NewTkt =
g.perm.ApndTkt = 1; break;
case 'c': g.perm.ApndTkt = 1; break;
case 't': g.perm.TktFmt = 1; break;
case 'b': g.perm.Attach = 1; break;
case 'x': g.perm.Private = 1; break;
/* The "u" privileges is a little different. It recursively
** inherits all privileges of the user named "reader" */
case 'u': {
if( (flags & LOGIN_IGNORE_U)==0 ){
const char *zUser;
zUser = db_text("", "SELECT cap FROM user WHERE login='reader'");
|
| ︙ | ︙ | |||
790 791 792 793 794 795 796 |
*/
int login_has_capability(const char *zCap, int nCap){
int i;
int rc = 1;
if( nCap<0 ) nCap = strlen(zCap);
for(i=0; i<nCap && rc && zCap[i]; i++){
switch( zCap[i] ){
| | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < | 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 |
*/
int login_has_capability(const char *zCap, int nCap){
int i;
int rc = 1;
if( nCap<0 ) nCap = strlen(zCap);
for(i=0; i<nCap && rc && zCap[i]; i++){
switch( zCap[i] ){
case 'a': rc = g.perm.Admin; break;
case 'b': rc = g.perm.Attach; break;
case 'c': rc = g.perm.ApndTkt; break;
case 'd': rc = g.perm.Delete; break;
case 'e': rc = g.perm.RdAddr; break;
case 'f': rc = g.perm.NewWiki; break;
case 'g': rc = g.perm.Clone; break;
case 'h': rc = g.perm.History; break;
case 'i': rc = g.perm.Write; break;
case 'j': rc = g.perm.RdWiki; break;
case 'k': rc = g.perm.WrWiki; break;
/* case 'l': */
case 'm': rc = g.perm.ApndWiki; break;
case 'n': rc = g.perm.NewTkt; break;
case 'o': rc = g.perm.Read; break;
case 'p': rc = g.perm.Password; break;
/* case 'q': */
case 'r': rc = g.perm.RdTkt; break;
case 's': rc = g.perm.Setup; break;
case 't': rc = g.perm.TktFmt; break;
/* case 'u': READER */
/* case 'v': DEVELOPER */
case 'w': rc = g.perm.WrTkt; break;
case 'x': rc = g.perm.Private; break;
/* case 'y': */
case 'z': rc = g.perm.Zip; break;
default: rc = 0; break;
}
}
return rc;
}
/*
** Change the login to zUser.
*/
void login_as_user(const char *zUser){
char *zCap = ""; /* New capabilities */
/* Turn off all capabilities from prior logins */
memset( &g.perm, 0, sizeof(g.perm) );
/* Set the global variables recording the userid and login. The
** "nobody" user is a special case in that g.zLogin==0.
*/
g.userUid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUser);
if( g.userUid==0 ){
zUser = 0;
|
| ︙ | ︙ | |||
890 891 892 893 894 895 896 |
/*
** Call this routine if the user lacks okHistory permission. If
** the anonymous user has okHistory permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
| | | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 |
/*
** Call this routine if the user lacks okHistory permission. If
** the anonymous user has okHistory permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
if( !g.perm.History &&
db_exists("SELECT 1 FROM user"
" WHERE login='anonymous'"
" AND cap LIKE '%%h%%'") ){
const char *zUrl = PD("REQUEST_URI", "index");
@ <p>Many <span class="disabled">hyperlinks are disabled.</span><br />
@ Use <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">anonymous login</a>
@ to enable hyperlinks.</p>
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#define UUID_SIZE 40
/*
** Maximum number of auxiliary parameters on reports
*/
#define MX_AUX 5
/*
** All global variables are in this structure.
*/
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
int isConst; /* True if the output is unchanging */
sqlite3 *db; /* The connection to the databases */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 78 79 80 81 82 83 84 |
#define UUID_SIZE 40
/*
** Maximum number of auxiliary parameters on reports
*/
#define MX_AUX 5
/*
** Holds flags for fossil user permissions.
*/
struct FossilUserPerms {
char Setup; /* s: use Setup screens on web interface */
char Admin; /* a: administrative permission */
char Delete; /* d: delete wiki or tickets */
char Password; /* p: change password */
char Query; /* q: create new reports */
char Write; /* i: xfer inbound. checkin */
char Read; /* o: xfer outbound. checkout */
char History; /* h: access historical information. */
char Clone; /* g: clone */
char RdWiki; /* j: view wiki via web */
char NewWiki; /* f: create new wiki via web */
char ApndWiki; /* m: append to wiki via web */
char WrWiki; /* k: edit wiki via web */
char RdTkt; /* r: view tickets via web */
char NewTkt; /* n: create new tickets */
char ApndTkt; /* c: append to tickets via the web */
char WrTkt; /* w: make changes to tickets via web */
char Attach; /* b: add attachments */
char TktFmt; /* t: create new ticket report formats */
char RdAddr; /* e: read email addresses or other private data */
char Zip; /* z: download zipped artifact via /zip URL */
char Private; /* x: can send and receive private content */
};
/*
** All global variables are in this structure.
*/
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
int isConst; /* True if the output is unchanging */
sqlite3 *db; /* The connection to the databases */
|
| ︙ | ︙ | |||
117 118 119 120 121 122 123 | /* Information used to populate the RCVFROM table */ int rcvid; /* The rcvid. 0 if not yet defined. */ char *zIpAddr; /* The remote IP address */ char *zNonce; /* The nonce used for login */ /* permissions used by the server */ | | < < < < < < < < < < < < < < < < < < < < < | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | /* Information used to populate the RCVFROM table */ int rcvid; /* The rcvid. 0 if not yet defined. */ char *zIpAddr; /* The remote IP address */ char *zNonce; /* The nonce used for login */ /* permissions used by the server */ struct FossilUserPerms perm; /* For defense against Cross-site Request Forgery attacks */ char zCsrfToken[12]; /* Value of the anti-CSRF token */ int okCsrf; /* Anti-CSRF token is present and valid */ FILE *fDebug; /* Write debug information here, if the file exists */ int thTrace; /* True to enable TH1 debugging output */ |
| ︙ | ︙ | |||
644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
for(i=nCmd=0; i<count(aCommand); i++){
if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
aCmd[nCmd++] = aCommand[i].zName;
}
multi_column_list(aCmd, nCmd);
}
/*
** COMMAND: version
**
** Usage: %fossil version
**
** Print the source code version number for the fossil executable.
| > > > > > > > > > > > > > > > | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
for(i=nCmd=0; i<count(aCommand); i++){
if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
aCmd[nCmd++] = aCommand[i].zName;
}
multi_column_list(aCmd, nCmd);
}
/*
** COMMAND: test-list-webpage
**
** List all web pages
*/
void cmd_test_webpage_list(void){
int i, nCmd;
const char *aCmd[count(aWebpage)];
for(i=nCmd=0; i<count(aWebpage); i++){
aCmd[nCmd++] = aWebpage[i].zName;
}
multi_column_list(aCmd, nCmd);
}
/*
** COMMAND: version
**
** Usage: %fossil version
**
** Print the source code version number for the fossil executable.
|
| ︙ | ︙ | |||
1013 1014 1015 1016 1017 1018 1019 |
if( zAltRepo[0]!='/' ){
zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
file_simplify_name(zAltRepo, -1);
}
db_close(1);
db_open_repository(zAltRepo);
login_as_user(zUser);
| | | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 |
if( zAltRepo[0]!='/' ){
zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
file_simplify_name(zAltRepo, -1);
}
db_close(1);
db_open_repository(zAltRepo);
login_as_user(zUser);
g.perm.Password = 0;
zPath += i;
nHost = g.zTop - g.zBaseURL;
g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
g.zTop = g.zBaseURL + nHost;
continue;
}
}else{
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 | #include "merge.h" #include <assert.h> /* ** COMMAND: merge ** | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include "merge.h" #include <assert.h> /* ** COMMAND: merge ** ** Usage: %fossil merge ?OPTIONS? VERSION ** ** The argument VERSION is a version that should be merged into the ** current checkout. All changes from VERSION back to the nearest ** common ancestor are merged. Except, if either of the --cherrypick or ** --backout options are used only the changes associated with the ** single check-in VERSION are merged. The --backout option causes ** the changes associated with VERSION to be removed from the current |
| ︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
fossil_fatal("not a version: record #%d", pid);
}
vfile_check_signature(vid, 1, 0);
db_begin_transaction();
if( !nochangeFlag ) undo_begin();
load_vfile_from_rid(mid);
load_vfile_from_rid(pid);
/*
** The vfile.pathname field is used to match files against each other. The
** FV table contains one row for each each unique filename in
** in the current checkout, the pivot, and the version being merged.
*/
db_multi_exec(
| > > > > > > > > > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
fossil_fatal("not a version: record #%d", pid);
}
vfile_check_signature(vid, 1, 0);
db_begin_transaction();
if( !nochangeFlag ) undo_begin();
load_vfile_from_rid(mid);
load_vfile_from_rid(pid);
if( debugFlag ){
char *z;
z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pid);
fossil_print("P=%d %z\n", pid, z);
z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
fossil_print("M=%d %z\n", mid, z);
z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
fossil_print("V=%d %z\n", vid, z);
}
/*
** The vfile.pathname field is used to match files against each other. The
** FV table contains one row for each each unique filename in
** in the current checkout, the pivot, and the version being merged.
*/
db_multi_exec(
|
| ︙ | ︙ | |||
185 186 187 188 189 190 191 |
" FROM vfile WHERE vid=%d",
vid
);
/*
** Compute name changes from P->V
*/
| | | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
" FROM vfile WHERE vid=%d",
vid
);
/*
** Compute name changes from P->V
*/
find_filename_changes(pid, vid, 0, &nChng, &aChng, debugFlag ? "P->V" : 0);
if( nChng ){
for(i=0; i<nChng; i++){
char *z;
z = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]);
db_multi_exec(
"UPDATE fv SET fnp=%Q, fnm=%Q"
" WHERE fn=(SELECT name FROM filename WHERE fnid=%d)",
z, z, aChng[i*2+1]
);
free(z);
}
fossil_free(aChng);
db_multi_exec("UPDATE fv SET fnm=fnp WHERE fnp!=fn");
}
|
| ︙ | ︙ | |||
215 216 217 218 219 220 221 |
" WHERE vid=%d AND pathname NOT IN (SELECT fnp FROM fv)",
pid
);
/*
** Compute name changes from P->M
*/
| | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
" WHERE vid=%d AND pathname NOT IN (SELECT fnp FROM fv)",
pid
);
/*
** Compute name changes from P->M
*/
find_filename_changes(pid, mid, 0, &nChng, &aChng, debugFlag ? "P->M" : 0);
if( nChng ){
if( nChng>4 ) db_multi_exec("CREATE INDEX fv_fnp ON fv(fnp)");
for(i=0; i<nChng; i++){
db_multi_exec(
"UPDATE fv SET fnm=(SELECT name FROM filename WHERE fnid=%d)"
" WHERE fnp=(SELECT name FROM filename WHERE fnid=%d)",
aChng[i*2+1], aChng[i*2]
|
| ︙ | ︙ | |||
248 249 250 251 252 253 254 |
** Compute the file version ids for P and M.
*/
db_multi_exec(
"UPDATE fv SET"
" idp=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnp),0),"
" ridp=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnp),0),"
" idm=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnm),0),"
| | > > > > | | > | > | > > | 257 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 |
** Compute the file version ids for P and M.
*/
db_multi_exec(
"UPDATE fv SET"
" idp=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnp),0),"
" ridp=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnp),0),"
" idm=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnm),0),"
" ridm=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnm),0),"
" islinkv=coalesce((SELECT islink FROM vfile"
" WHERE vid=%d AND pathname=fnm),0),"
" islinkm=coalesce((SELECT islink FROM vfile"
" WHERE vid=%d AND pathname=fnm),0)",
pid, pid, mid, mid, vid, mid
);
if( debugFlag ){
db_prepare(&q,
"SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm, "
" isexe, islinkv, islinkm FROM fv"
);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d isexe=%d "
" islinkv=%d islinkm=%d\n",
db_column_int(&q, 0),
db_column_int(&q, 5),
db_column_int(&q, 6),
db_column_int(&q, 7),
db_column_int(&q, 4),
db_column_int(&q, 8),
db_column_int(&q, 9),
db_column_int(&q, 10));
fossil_print(" fn = [%s]\n", db_column_text(&q, 1));
fossil_print(" fnp = [%s]\n", db_column_text(&q, 2));
fossil_print(" fnm = [%s]\n", db_column_text(&q, 3));
}
db_finalize(&q);
}
|
| ︙ | ︙ | |||
301 302 303 304 305 306 307 |
);
while( db_step(&q)==SQLITE_ROW ){
int idm = db_column_int(&q, 0);
int rowid = db_column_int(&q, 1);
int idv;
const char *zName;
db_multi_exec(
| | | < < < < < < < < < < < | > | > | 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 359 360 361 362 363 364 365 366 367 |
);
while( db_step(&q)==SQLITE_ROW ){
int idm = db_column_int(&q, 0);
int rowid = db_column_int(&q, 1);
int idv;
const char *zName;
db_multi_exec(
"INSERT INTO vfile(vid,chnged,deleted,rid,mrid,isexe,islink,pathname)"
" SELECT %d,3,0,rid,mrid,isexe,islink,pathname FROM vfile WHERE id=%d",
vid, idm
);
idv = db_last_insert_rowid();
db_multi_exec("UPDATE fv SET idv=%d WHERE rowid=%d", idv, rowid);
zName = db_column_text(&q, 2);
fossil_print("ADDED %s\n", zName);
if( !nochangeFlag ){
undo_save(zName);
vfile_to_disk(0, idm, 0, 0);
}
}
db_finalize(&q);
/*
** Find files that have changed from P->M but not P->V.
** Copy the M content over into V.
*/
db_prepare(&q,
"SELECT idv, ridm, fn, islinkm FROM fv"
" WHERE idp>0 AND idv>0 AND idm>0"
" AND ridm!=ridp AND ridv=ridp AND NOT chnged"
);
while( db_step(&q)==SQLITE_ROW ){
int idv = db_column_int(&q, 0);
int ridm = db_column_int(&q, 1);
const char *zName = db_column_text(&q, 2);
int islinkm = db_column_int(&q, 3);
/* Copy content from idm over into idv. Overwrite idv. */
fossil_print("UPDATE %s\n", zName);
if( !nochangeFlag ){
undo_save(zName);
db_multi_exec(
"UPDATE vfile SET mtime=0, mrid=%d, chnged=2, islink=%d "
" WHERE id=%d", ridm, islinkm, idv
);
vfile_to_disk(0, idv, 0, 0);
}
}
db_finalize(&q);
/*
|
| ︙ | ︙ | |||
381 382 383 384 385 386 387 |
/* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
if( detailFlag ){
fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
zName, ridp, ridm, ridv);
}else{
fossil_print("MERGE %s\n", zName);
}
| | | | 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 |
/* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
if( detailFlag ){
fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n",
zName, ridp, ridm, ridv);
}else{
fossil_print("MERGE %s\n", zName);
}
if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
fossil_print("***** Cannot merge symlink %s\n", zName);
nConflict++;
}else{
undo_save(zName);
zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
content_get(ridp, &p);
content_get(ridm, &m);
if( isBinary ){
rc = -1;
blob_zero(&r);
}else{
rc = merge_3way(&p, zFullPath, &m, &r);
}
if( rc>=0 ){
if( !nochangeFlag ){
blob_write_to_file(&r, zFullPath);
file_wd_setexe(zFullPath, isExe);
}
db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv);
if( rc>0 ){
fossil_print("***** %d merge conflicts in %s\n", rc, zName);
nConflict++;
}
}else{
|
| ︙ | ︙ | |||
470 471 472 473 474 475 476 |
db_multi_exec(
"UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
" WHERE id=%d AND vid=%d", zNewName, idv, vid
);
if( !nochangeFlag ){
char *zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName);
char *zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
| > > > | > | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
db_multi_exec(
"UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
" WHERE id=%d AND vid=%d", zNewName, idv, vid
);
if( !nochangeFlag ){
char *zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName);
char *zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
if( file_wd_islink(zFullOldPath) ){
symlink_copy(zFullOldPath, zFullNewPath);
}else{
file_copy(zFullOldPath, zFullNewPath);
}
file_delete(zFullOldPath);
free(zFullNewPath);
free(zFullOldPath);
}
}
db_finalize(&q);
|
| ︙ | ︙ |
Changes to src/merge3.c.
| ︙ | ︙ | |||
420 421 422 423 424 425 426 |
azSubst[0] = "%baseline"; azSubst[1] = zPivot;
azSubst[2] = "%original"; azSubst[3] = zOrig;
azSubst[4] = "%merge"; azSubst[5] = zOther;
azSubst[6] = "%output"; azSubst[7] = zOut;
zCmd = string_subst(zGMerge, 8, azSubst);
printf("%s\n", zCmd); fflush(stdout);
fossil_system(zCmd);
| | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
azSubst[0] = "%baseline"; azSubst[1] = zPivot;
azSubst[2] = "%original"; azSubst[3] = zOrig;
azSubst[4] = "%merge"; azSubst[5] = zOther;
azSubst[6] = "%output"; azSubst[7] = zOut;
zCmd = string_subst(zGMerge, 8, azSubst);
printf("%s\n", zCmd); fflush(stdout);
fossil_system(zCmd);
if( file_wd_size(zOut)>=0 ){
blob_read_from_file(pOut, zOut);
file_delete(zPivot);
file_delete(zOrig);
file_delete(zOther);
file_delete(zOut);
}
fossil_free(zCmd);
|
| ︙ | ︙ |
Changes to src/path.c.
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
PathNode *p;
while( path.pAll ){
p = path.pAll;
path.pAll = p->pAll;
fossil_free(p);
}
bag_clear(&path.seen);
| < | < < | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
PathNode *p;
while( path.pAll ){
p = path.pAll;
path.pAll = p->pAll;
fossil_free(p);
}
bag_clear(&path.seen);
memset(&path, 0, sizeof(&path));
}
/*
** Construct the path from path.pStart to path.pEnd in the u.pTo fields.
*/
void path_reverse_path(void){
PathNode *p;
|
| ︙ | ︙ | |||
117 118 119 120 121 122 123 | ** ** Return a pointer to the beginning of the path (the iFrom node). ** Elements of the path can be traversed by following the PathNode.u.pTo ** pointer chain. ** ** Return NULL if no path is found. */ | | > > > > > > > > > | | 114 115 116 117 118 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 145 146 147 148 |
**
** Return a pointer to the beginning of the path (the iFrom node).
** Elements of the path can be traversed by following the PathNode.u.pTo
** pointer chain.
**
** Return NULL if no path is found.
*/
PathNode *path_shortest(
int iFrom, /* Path starts here */
int iTo, /* Path ends here */
int directOnly, /* No merge links if true */
int oneWayOnly /* Parent->child only if true */
){
Stmt s;
PathNode *pPrev;
PathNode *p;
path_reset();
path.pStart = path_new_node(iFrom, 0, 0);
if( iTo==iFrom ){
path.pEnd = path.pStart;
return path.pStart;
}
if( oneWayOnly ){
db_prepare(&s,
"SELECT cid, 1 FROM plink WHERE pid=:pid "
);
}else if( directOnly ){
db_prepare(&s,
"SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim "
"UNION ALL "
"SELECT pid, 0 FROM plink WHERE cid=:pid AND isprim"
);
}else{
db_prepare(&s,
|
| ︙ | ︙ | |||
194 195 196 197 198 199 200 201 202 203 204 205 206 |
*/
void shortest_path_test_cmd(void){
int iFrom;
int iTo;
PathNode *p;
int n;
int directOnly;
db_find_and_open_repository(0,0);
directOnly = find_option("no-merge",0,0)!=0;
if( g.argc!=4 ) usage("VERSION1 VERSION2");
iFrom = name_to_rid(g.argv[2]);
iTo = name_to_rid(g.argv[3]);
| > > | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
*/
void shortest_path_test_cmd(void){
int iFrom;
int iTo;
PathNode *p;
int n;
int directOnly;
int oneWay;
db_find_and_open_repository(0,0);
directOnly = find_option("no-merge",0,0)!=0;
oneWay = find_option("one-way",0,0)!=0;
if( g.argc!=4 ) usage("VERSION1 VERSION2");
iFrom = name_to_rid(g.argv[2]);
iTo = name_to_rid(g.argv[3]);
p = path_shortest(iFrom, iTo, directOnly, oneWay);
if( p==0 ){
fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]);
}
for(n=1, p=path.pStart; p; p=p->u.pTo, n++){
char *z;
z = db_text(0,
"SELECT substr(uuid,1,12) || ' ' || datetime(mtime)"
" FROM blob, event"
" WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'",
p->rid, p->rid);
fossil_print("%4d: %5d %s", n, p->rid, z);
fossil_free(z);
if( p->u.pTo ){
fossil_print(" is a %s of\n",
p->u.pTo->fromIsParent ? "parent" : "child");
}else{
fossil_print("\n");
}
|
| ︙ | ︙ | |||
311 312 313 314 315 316 317 |
for(n=1, p=path.pStart; p; p=p->u.pTo, n++){
char *z;
z = db_text(0,
"SELECT substr(uuid,1,12) || ' ' || datetime(mtime)"
" FROM blob, event"
" WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'",
p->rid, p->rid);
| | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
for(n=1, p=path.pStart; p; p=p->u.pTo, n++){
char *z;
z = db_text(0,
"SELECT substr(uuid,1,12) || ' ' || datetime(mtime)"
" FROM blob, event"
" WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'",
p->rid, p->rid);
fossil_print("%4d: %5d %s", n, p->rid, z);
fossil_free(z);
if( p->rid==iFrom ) fossil_print(" VERSION1");
if( p->rid==iTo ) fossil_print(" VERSION2");
if( p->rid==iPivot ) fossil_print(" PIVOT");
fossil_print("\n");
}
}
|
| ︙ | ︙ | |||
338 339 340 341 342 343 344 | /* ** Compute all file name changes that occur going from checkin iFrom ** to checkin iTo. ** ** The number of name changes is written into *pnChng. For each name ** change, two integers are allocated for *piChng. The first is the | | > > | | | > | | > | | | > > < | | < > > | > > > > | > > > > > > > > > | | > > < | > > > > > > > > > > | > > > | > > > > | > | | | > > | | | | | | | | | > > | > | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 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 480 481 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 |
/*
** Compute all file name changes that occur going from checkin iFrom
** to checkin iTo.
**
** The number of name changes is written into *pnChng. For each name
** change, two integers are allocated for *piChng. The first is the
** filename.fnid for the original name as seen in check-in iFrom and
** the second is for new name as it is used in check-in iTo.
**
** Space to hold *piChng is obtained from fossil_malloc() and should
** be released by the caller.
**
** This routine really has nothing to do with path. It is located
** in this path.c module in order to leverage some of the path
** infrastructure.
*/
void find_filename_changes(
int iFrom, /* Ancestor check-in */
int iTo, /* Recent check-in */
int revOk, /* Ok to move backwards (child->parent) if true */
int *pnChng, /* Number of name changes along the path */
int **aiChng, /* Name changes */
const char *zDebug /* Generate trace output if no NULL */
){
PathNode *p; /* For looping over path from iFrom to iTo */
NameChange *pAll = 0; /* List of all name changes seen so far */
NameChange *pChng; /* For looping through the name change list */
int nChng = 0; /* Number of files whose names have changed */
int *aChng; /* Two integers per name change */
int i; /* Loop counter */
Stmt q1; /* Query of name changes */
*pnChng = 0;
*aiChng = 0;
if( iFrom==iTo ) return;
path_reset();
p = path_shortest(iFrom, iTo, 1, revOk==0);
if( p==0 ) return;
path_reverse_path();
db_prepare(&q1,
"SELECT pfnid, fnid FROM mlink"
" WHERE mid=:mid AND (pfnid>0 OR fid==0)"
" ORDER BY pfnid"
);
for(p=path.pStart; p; p=p->u.pTo){
int fnid, pfnid;
if( !p->fromIsParent && (p->u.pTo==0 || p->u.pTo->fromIsParent) ){
/* Skip nodes where the parent is not on the path */
continue;
}
db_bind_int(&q1, ":mid", p->rid);
while( db_step(&q1)==SQLITE_ROW ){
fnid = db_column_int(&q1, 1);
pfnid = db_column_int(&q1, 0);
if( pfnid==0 ){
pfnid = fnid;
fnid = 0;
}
if( !p->fromIsParent ){
int t = fnid;
fnid = pfnid;
pfnid = t;
}
if( zDebug ){
fossil_print("%s at %d%s %.10z: %d[%z] -> %d[%z]\n",
zDebug, p->rid, p->fromIsParent ? ">" : "<",
db_text(0, "SELECT uuid FROM blob WHERE rid=%d", p->rid),
pfnid,
db_text(0, "SELECT name FROM filename WHERE fnid=%d", pfnid),
fnid,
db_text(0, "SELECT name FROM filename WHERE fnid=%d", fnid));
}
for(pChng=pAll; pChng; pChng=pChng->pNext){
if( pChng->curName==pfnid ){
pChng->newName = fnid;
break;
}
}
if( pChng==0 && fnid>0 ){
pChng = fossil_malloc( sizeof(*pChng) );
pChng->pNext = pAll;
pAll = pChng;
pChng->origName = pfnid;
pChng->curName = pfnid;
pChng->newName = fnid;
nChng++;
}
}
for(pChng=pAll; pChng; pChng=pChng->pNext){
pChng->curName = pChng->newName;
}
db_reset(&q1);
}
db_finalize(&q1);
if( nChng ){
aChng = *aiChng = fossil_malloc( nChng*2*sizeof(int) );
for(pChng=pAll, i=0; pChng; pChng=pChng->pNext){
if( pChng->newName==0 ) continue;
if( pChng->origName==0 ) continue;
if( pChng->newName==pChng->origName ) continue;
aChng[i] = pChng->origName;
aChng[i+1] = pChng->newName;
if( zDebug ){
fossil_print("%s summary %d[%z] -> %d[%z]\n",
zDebug,
aChng[i],
db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i]),
aChng[i+1],
db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i+1]));
}
i += 2;
}
*pnChng = i/2;
while( pAll ){
pChng = pAll;
pAll = pAll->pNext;
fossil_free(pChng);
}
}
}
/*
** COMMAND: test-name-changes
**
** Usage: %fossil test-name-changes [--debug] VERSION1 VERSION2
**
** Show all filename changes that occur going from VERSION1 to VERSION2
*/
void test_name_change(void){
int iFrom;
int iTo;
int *aChng;
int nChng;
int i;
const char *zDebug = 0;
int revOk = 0;
db_find_and_open_repository(0,0);
zDebug = find_option("debug",0,0)!=0 ? "debug" : 0;
revOk = find_option("bidirectional",0,0)!=0;
if( g.argc<4 ) usage("VERSION1 VERSION2");
while( g.argc>=4 ){
iFrom = name_to_rid(g.argv[2]);
iTo = name_to_rid(g.argv[3]);
find_filename_changes(iFrom, iTo, revOk, &nChng, &aChng, zDebug);
fossil_print("------ Changes for (%d) %s -> (%d) %s\n",
iFrom, g.argv[2], iTo, g.argv[3]);
for(i=0; i<nChng; i++){
char *zFrom, *zTo;
zFrom = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]);
zTo = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]);
fossil_print("[%s] -> [%s]\n", zFrom, zTo);
fossil_free(zFrom);
fossil_free(zTo);
}
fossil_free(aChng);
g.argv += 2;
g.argc -= 2;
}
}
|
Changes to src/rebuild.c.
| ︙ | ︙ | |||
336 337 338 339 340 341 342 | int errCnt = 0; char *zTable; int incrSize; bag_init(&bagDone); ttyOutput = doOut; processCnt = 0; | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
int errCnt = 0;
char *zTable;
int incrSize;
bag_init(&bagDone);
ttyOutput = doOut;
processCnt = 0;
if (ttyOutput && !g.fQuiet) {
percent_complete(0);
}
rebuild_update_schema();
for(;;){
zTable = db_text(0,
"SELECT name FROM sqlite_master /*scan*/"
" WHERE type='table'"
|
| ︙ | ︙ | |||
408 409 410 411 412 413 414 |
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
rebuild_step_done(rid);
}
}
db_finalize(&s);
manifest_crosslink_end();
rebuild_tag_trunk();
| | | | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
rebuild_step_done(rid);
}
}
db_finalize(&s);
manifest_crosslink_end();
rebuild_tag_trunk();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
processCnt += incrSize;
percent_complete((processCnt*1000)/totalSize);
}
if( doClustering ) create_cluster();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
processCnt += incrSize;
percent_complete((processCnt*1000)/totalSize);
}
if(!g.fQuiet && ttyOutput ){
fossil_print("\n");
}
return errCnt;
|
| ︙ | ︙ | |||
483 484 485 486 487 488 489 | db_end_transaction(0); } /* ** COMMAND: rebuild ** | | | | | < < | > > > | 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 |
db_end_transaction(0);
}
/*
** COMMAND: rebuild
**
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
**
** Reconstruct the named repository database from the core
** records. Run this command after updating the fossil
** executable in a way that changes the database schema.
**
** Options:
** --cluster Compute clusters for unclustered artifacts
** --compress Strive to make the database as small as possible
** --force Force the rebuild to complete even if errors are seen
** --noverify Skip the verification of changes to the BLOB table
** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
** --randomize Scan artifacts in a random order
** --vacuum Run VACUUM on the database after rebuilding
** --wal Set Write-Ahead-Log journalling mode on the database
**
** See also: deconstruct, reconstruct
*/
void rebuild_database(void){
int forceFlag;
int randomizeFlag;
int errCnt;
int omitVerify;
int doClustering;
|
| ︙ | ︙ | |||
691 692 693 694 695 696 697 |
}
db_finalize(&q);
}
}
/*
** COMMAND: scrub
| | > > > > > | 692 693 694 695 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 |
}
db_finalize(&q);
}
}
/*
** COMMAND: scrub
** %fossil scrub ?OPTIONS? ?REPOSITORY?
**
** The command removes sensitive information (such as passwords) from a
** repository so that the respository can be sent to an untrusted reader.
**
** By default, only passwords are removed. However, if the --verily option
** is added, then private branches, concealed email addresses, IP
** addresses of correspondents, and similar privacy-sensitive fields
** are also purged. If the --private option is used, then only private
** branches are removed and all other information is left intact.
**
** This command permanently deletes the scrubbed information. The effects
** of this command are irreversible. Use with caution.
**
** The user is prompted to confirm the scrub unless the --force option
** is used.
**
** Options:
** --force do not prompt for confirmation
** --private only private branches are removed from the repository
** --verily scrub real thoroughly (see above)
*/
void scrub_cmd(void){
int bVerily = find_option("verily",0,0)!=0;
int bForce = find_option("force", "f", 0)!=0;
int privateOnly = find_option("private",0,0)!=0;
int bNeedRebuild = 0;
if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
|
| ︙ | ︙ | |||
827 828 829 830 831 832 833 834 835 836 837 838 839 840 |
** Usage: %fossil reconstruct FILENAME DIRECTORY
**
** This command studies the artifacts (files) in DIRECTORY and
** reconstructs the fossil record from them. It places the new
** fossil repository in FILENAME. Subdirectories are read, files
** with leading '.' in the filename are ignored.
**
*/
void reconstruct_cmd(void) {
char *zPassword;
if( g.argc!=4 ){
usage("FILENAME DIRECTORY");
}
if( file_isdir(g.argv[3])!=1 ){
| > | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 |
** Usage: %fossil reconstruct FILENAME DIRECTORY
**
** This command studies the artifacts (files) in DIRECTORY and
** reconstructs the fossil record from them. It places the new
** fossil repository in FILENAME. Subdirectories are read, files
** with leading '.' in the filename are ignored.
**
** See also: deconstruct, rebuild
*/
void reconstruct_cmd(void) {
char *zPassword;
if( g.argc!=4 ){
usage("FILENAME DIRECTORY");
}
if( file_isdir(g.argv[3])!=1 ){
|
| ︙ | ︙ | |||
882 883 884 885 886 887 888 | } /* ** COMMAND: deconstruct ** ** Usage %fossil deconstruct ?OPTIONS? DESTINATION ** | < < < > > > > > > > | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 |
}
/*
** COMMAND: deconstruct
**
** Usage %fossil deconstruct ?OPTIONS? DESTINATION
**
**
** This command exports all artifacts of a given repository and
** writes all artifacts to the file system. The DESTINATION directory
** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where
** AABBBBBBBBB.. is the 40 character artifact ID, AA the first 2 characters.
** If -L|--prefixlength is given, the length (default 2) of the directory
** prefix can be set to 0,1,..,9 characters.
**
** Options:
** -R|--repository REPOSITORY deconstruct given REPOSITORY
** -L|--prefixlength N set the length of the names of the DESTINATION
** subdirectories to N
**
** See also: rebuild, reconstruct
*/
void deconstruct_cmd(void){
const char *zDestDir;
const char *zPrefixOpt;
Stmt s;
/* check number of arguments */
|
| ︙ | ︙ |
Changes to src/report.c.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 | const char *zScript; Blob ril; /* Report Item List */ Stmt q; int rn = 0; int cnt = 0; login_check_credentials(); | | | | | | | | | 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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
const char *zScript;
Blob ril; /* Report Item List */
Stmt q;
int rn = 0;
int cnt = 0;
login_check_credentials();
if( !g.perm.RdTkt && !g.perm.NewTkt ){ login_needed(); return; }
style_header("Ticket Main Menu");
if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST<br />\n", -1);
zScript = ticket_reportlist_code();
if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST_SCRIPT<br />\n", -1);
blob_zero(&ril);
ticket_init();
db_prepare(&q, "SELECT rn, title, owner FROM reportfmt ORDER BY title");
while( db_step(&q)==SQLITE_ROW ){
const char *zTitle = db_column_text(&q, 1);
const char *zOwner = db_column_text(&q, 2);
if( zTitle[0] =='_' && !g.perm.TktFmt ){
continue;
}
rn = db_column_int(&q, 0);
cnt++;
blob_appendf(&ril, "<li>");
if( zTitle[0] == '_' ){
blob_appendf(&ril, "%s", zTitle);
} else {
blob_appendf(&ril, "<a href=\"rptview?rn=%d\" rel=\"nofollow\">%h</a>", rn, zTitle);
}
blob_appendf(&ril, " ");
if( g.perm.Write && zOwner && zOwner[0] ){
blob_appendf(&ril, "(by <i>%h</i></i>) ", zOwner);
}
if( g.perm.TktFmt ){
blob_appendf(&ril, "[<a href=\"rptedit?rn=%d&copy=1\" rel=\"nofollow\">copy</a>] ", rn);
}
if( g.perm.Admin
|| (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0)
){
blob_appendf(&ril, "[<a href=\"rptedit?rn=%d\" rel=\"nofollow\">edit</a>] ", rn);
}
if( g.perm.TktFmt ){
blob_appendf(&ril, "[<a href=\"rptsql?rn=%d\" rel=\"nofollow\">sql</a>] ", rn);
}
blob_appendf(&ril, "</li>\n");
}
Th_Store("report_items", blob_str(&ril));
|
| ︙ | ︙ | |||
182 183 184 185 186 187 188 |
int i;
for(i=0; i<sizeof(azAllowed)/sizeof(azAllowed[0]); i++){
if( fossil_stricmp(zArg1, azAllowed[i])==0 ) break;
}
if( i>=sizeof(azAllowed)/sizeof(azAllowed[0]) ){
*(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1);
rc = SQLITE_DENY;
| | | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
int i;
for(i=0; i<sizeof(azAllowed)/sizeof(azAllowed[0]); i++){
if( fossil_stricmp(zArg1, azAllowed[i])==0 ) break;
}
if( i>=sizeof(azAllowed)/sizeof(azAllowed[0]) ){
*(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1);
rc = SQLITE_DENY;
}else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
rc = SQLITE_IGNORE;
}
break;
}
default: {
*(char**)pError = mprintf("only SELECT statements are allowed");
rc = SQLITE_DENY;
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 | const char *zTitle; const char *zSQL; const char *zOwner; const char *zClrKey; Stmt q; login_check_credentials(); | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
const char *zTitle;
const char *zSQL;
const char *zOwner;
const char *zClrKey;
Stmt q;
login_check_credentials();
if( !g.perm.TktFmt ){
login_needed();
return;
}
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);
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 | const char *z; const char *zOwner; const char *zClrKey; char *zSQL; char *zErr = 0; login_check_credentials(); | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
const char *z;
const char *zOwner;
const char *zClrKey;
char *zSQL;
char *zErr = 0;
login_check_credentials();
if( !g.perm.TktFmt ){
login_needed();
return;
}
/*view_add_functions(0);*/
rn = atoi(PD("rn","0"));
zTitle = P("t");
zOwner = PD("w",g.zLogin);
|
| ︙ | ︙ | |||
428 429 430 431 432 433 434 | @ <input type="hidden" name="rn" value="%d(rn)" /> @ <p>Report Title:<br /> @ <input type="text" name="t" value="%h(zTitle)" size="60" /></p> @ <p>Enter a complete SQL query statement against the "TICKET" table:<br /> @ <textarea name="s" rows="20" cols="80">%h(zSQL)</textarea> @ </p> login_insert_csrf_secret(); | | | | 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 |
@ <input type="hidden" name="rn" value="%d(rn)" />
@ <p>Report Title:<br />
@ <input type="text" name="t" value="%h(zTitle)" size="60" /></p>
@ <p>Enter a complete SQL query statement against the "TICKET" table:<br />
@ <textarea name="s" rows="20" cols="80">%h(zSQL)</textarea>
@ </p>
login_insert_csrf_secret();
if( g.perm.Admin ){
@ <p>Report owner:
@ <input type="text" name="w" size="20" value="%h(zOwner)" />
@ </p>
} else {
@ <input type="hidden" name="w" value="%h(zOwner)" />
}
@ <p>Enter an optional color key in the following box. (If blank, no
@ color key is displayed.) Each line contains the text for a single
@ entry in the key. The first token of each line is the background
@ color for that line.<br />
@ <textarea name="k" rows="8" cols="50">%h(zClrKey)</textarea>
@ </p>
if( !g.perm.Admin && fossil_strcmp(zOwner,g.zLogin)!=0 ){
@ <p>This report format is owned by %h(zOwner). You are not allowed
@ to change it.</p>
@ </form>
report_format_hints();
style_footer();
return;
}
|
| ︙ | ︙ | |||
657 658 659 660 661 662 663 |
pState->iNewRow = -1;
pState->iBg = -1;
for(i=0; i<nArg; i++){
if( azName[i][0]=='b' && fossil_strcmp(azName[i],"bgcolor")==0 ){
pState->iBg = i;
continue;
}
| | | | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
pState->iNewRow = -1;
pState->iBg = -1;
for(i=0; i<nArg; i++){
if( azName[i][0]=='b' && fossil_strcmp(azName[i],"bgcolor")==0 ){
pState->iBg = i;
continue;
}
if( g.perm.Write && azName[i][0]=='#' ){
pState->nCol++;
}
if( !pState->isMultirow ){
if( azName[i][0]=='_' ){
pState->isMultirow = 1;
pState->iNewRow = i;
}else{
pState->nCol++;
}
}
}
/* The first time this routine is called, output a table header
*/
@ <tr>
zTid = 0;
for(i=0; i<nArg; i++){
char *zName = azName[i];
if( i==pState->iBg ) continue;
if( pState->iNewRow>=0 && i>=pState->iNewRow ){
if( g.perm.Write && zTid ){
@ <th> </th>
zTid = 0;
}
if( zName[0]=='_' ) zName++;
@ </tr><tr><th colspan=%d(pState->nCol)>%h(zName)</th>
}else{
if( zName[0]=='#' ){
zTid = zName;
}
@ <th>%h(zName)</th>
}
}
if( g.perm.Write && zTid ){
@ <th> </th>
}
@ </tr>
}
if( azArg==0 ){
@ <tr><td colspan="%d(pState->nCol)">
@ <i>No records match the report criteria</i>
|
| ︙ | ︙ | |||
724 725 726 727 728 729 730 |
zPage[0] = 0;
for(i=0; i<nArg; i++){
char *zData;
if( i==pState->iBg ) continue;
zData = azArg[i];
if( zData==0 ) zData = "";
if( pState->iNewRow>=0 && i>=pState->iNewRow ){
| | | | | 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 752 753 754 755 756 757 758 759 760 761 762 763 764 |
zPage[0] = 0;
for(i=0; i<nArg; i++){
char *zData;
if( i==pState->iBg ) continue;
zData = azArg[i];
if( zData==0 ) zData = "";
if( pState->iNewRow>=0 && i>=pState->iNewRow ){
if( zTid && g.perm.Write ){
@ <td valign="top"><a href="tktedit/%h(zTid)">edit</a></td>
zTid = 0;
}
if( zData[0] ){
Blob content;
@ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)>
blob_init(&content, zData, -1);
wiki_convert(&content, 0, 0);
blob_reset(&content);
}
}else if( azName[i][0]=='#' ){
zTid = zData;
if( g.perm.History ){
@ <td valign="top"><a href="tktview?name=%h(zData)">%h(zData)</a></td>
}else{
@ <td valign="top">%h(zData)</td>
}
}else if( zData[0]==0 ){
@ <td valign="top"> </td>
}else{
@ <td valign="top">
@ %h(zData)
@ </td>
}
}
if( zTid && g.perm.Write ){
@ <td valign="top"><a href="tktedit/%h(zTid)">edit</a></td>
}
@ </tr>
return 0;
}
/*
|
| ︙ | ︙ | |||
913 914 915 916 917 918 919 | char *zClrKey; int tabs; Stmt q; char *zErr1 = 0; char *zErr2 = 0; login_check_credentials(); | | | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
char *zClrKey;
int tabs;
Stmt q;
char *zErr1 = 0;
char *zErr2 = 0;
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(); return; }
rn = atoi(PD("rn","0"));
if( rn==0 ){
cgi_redirect("reportlist");
return;
}
tabs = P("tablist")!=0;
/* view_add_functions(tabs); */
|
| ︙ | ︙ | |||
955 956 957 958 959 960 961 |
count = 0;
if( !tabs ){
struct GenerateHTML sState;
db_multi_exec("PRAGMA empty_result_callbacks=ON");
style_submenu_element("Raw", "Raw",
"rptview?tablist=1&%h", PD("QUERY_STRING",""));
| | | | | | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 |
count = 0;
if( !tabs ){
struct GenerateHTML sState;
db_multi_exec("PRAGMA empty_result_callbacks=ON");
style_submenu_element("Raw", "Raw",
"rptview?tablist=1&%h", PD("QUERY_STRING",""));
if( g.perm.Admin
|| (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn);
}
if( g.perm.TktFmt ){
style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn);
}
if( g.perm.NewTkt ){
style_submenu_element("New Ticket", "Create a new ticket",
"%s/tktnew", g.zTop);
}
style_header(zTitle);
output_color_key(zClrKey, 1,
"border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\"");
@ <table border="1" cellpadding="2" cellspacing="0" class="report">
|
| ︙ | ︙ |
Changes to src/rss.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
@ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim),
@ (SELECT count(*) FROM plink WHERE cid=blob.rid)
@ FROM event, blob
@ WHERE blob.rid=event.objid
;
login_check_credentials();
| | | | | | | | | | | | | 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 78 79 80 81 82 83 84 |
@ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim),
@ (SELECT count(*) FROM plink WHERE cid=blob.rid)
@ FROM event, blob
@ WHERE blob.rid=event.objid
;
login_check_credentials();
if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){
return;
}
blob_zero(&bSQL);
blob_append( &bSQL, zSQL1, -1 );
if( zType[0]!='a' ){
if( zType[0]=='c' && !g.perm.Read ) zType = "x";
if( zType[0]=='w' && !g.perm.RdWiki ) zType = "x";
if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x";
blob_appendf(&bSQL, " AND event.type=%Q", zType);
}else{
if( !g.perm.Read ){
if( g.perm.RdTkt && g.perm.RdWiki ){
blob_append(&bSQL, " AND event.type!='ci'", -1);
}else if( g.perm.RdTkt ){
blob_append(&bSQL, " AND event.type=='t'", -1);
}else{
blob_append(&bSQL, " AND event.type=='w'", -1);
}
}else if( !g.perm.RdWiki ){
if( g.perm.RdTkt ){
blob_append(&bSQL, " AND event.type!='w'", -1);
}else{
blob_append(&bSQL, " AND event.type=='ci'", -1);
}
}else if( !g.perm.RdTkt ){
assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
blob_append(&bSQL, " AND event.type!='t'", -1);
}
}
blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
cgi_set_content_type("application/rss+xml");
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
if( zProjectDescr==0 ){
zProjectDescr = zProjectName;
}
zPubDate = cgi_rfc822_datestamp(time(NULL));
@ <?xml version="1.0"?>
| | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
if( zProjectDescr==0 ){
zProjectDescr = zProjectName;
}
zPubDate = cgi_rfc822_datestamp(time(NULL));
@ <?xml version="1.0"?>
@ <rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
@ <channel>
@ <title>%h(zProjectName)</title>
@ <link>%s(g.zBaseURL)</link>
@ <description>%h(zProjectDescr)</description>
@ <pubDate>%s(zPubDate)</pubDate>
@ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator>
free(zPubDate);
|
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
}
@ <item>
@ <title>%s(zPrefix)%h(zCom)</title>
@ <link>%s(g.zBaseURL)/info/%s(zId)</link>
@ <description>%s(zPrefix)%h(zCom)</description>
@ <pubDate>%s(zDate)</pubDate>
| | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
}
@ <item>
@ <title>%s(zPrefix)%h(zCom)</title>
@ <link>%s(g.zBaseURL)/info/%s(zId)</link>
@ <description>%s(zPrefix)%h(zCom)</description>
@ <pubDate>%s(zDate)</pubDate>
@ <dc:creator>%h(zAuthor)</dc:creator>
@ <guid>%s(g.zBaseURL)/info/%s(zId)</guid>
@ </item>
free(zDate);
nLine++;
}
db_finalize(&q);
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 |
}
/*
** WEBPAGE: /setup
*/
void setup_page(void){
login_check_credentials();
| | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
}
/*
** WEBPAGE: /setup
*/
void setup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Server Administration");
@ <table border="0" cellspacing="7">
setup_menu_entry("Users", "setup_ulist",
"Grant privileges to individual users.");
|
| ︙ | ︙ | |||
104 105 106 107 108 109 110 |
** Show a list of users. Clicking on any user jumps to the edit
** screen for that user.
*/
void setup_ulist(void){
Stmt s;
login_check_credentials();
| | | | | 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 133 134 135 136 137 138 139 140 141 142 143 |
** Show a list of users. Clicking on any user jumps to the edit
** screen for that user.
*/
void setup_ulist(void){
Stmt s;
login_check_credentials();
if( !g.perm.Admin ){
login_needed();
return;
}
style_submenu_element("Add", "Add User", "setup_uedit");
style_header("User List");
@ <table class="usetupLayoutTable">
@ <tr><td class="usetupColumnLayout">
@ <span class="note">Users:</span>
@ <table class="usetupUserList">
@ <tr>
@ <th class="usetupListUser" style="text-align: right;padding-right: 20px;">User ID</th>
@ <th class="usetupListCap" style="text-align: center;padding-right: 15px;">Capabilities</th>
@ <th class="usetupListCon" style="text-align: left;">Contact Info</th>
@ </tr>
db_prepare(&s, "SELECT uid, login, cap, info FROM user ORDER BY login");
while( db_step(&s)==SQLITE_ROW ){
const char *zCap = db_column_text(&s, 2);
@ <tr>
@ <td class="usetupListUser" style="text-align: right;padding-right: 20px;white-space:nowrap;">
if( g.perm.Admin && (zCap[0]!='s' || g.perm.Setup) ){
@ <a href="setup_uedit?id=%d(db_column_int(&s,0))">
}
@ %h(db_column_text(&s,1))
if( g.perm.Admin ){
@ </a>
}
@ </td>
@ <td class="usetupListCap" style="text-align: center;padding-right: 15px;">%s(zCap)</td>
@ <td class="usetupListCon" style="text-align: left;">%s(db_column_text(&s,3))</td>
@ </tr>
}
|
| ︙ | ︙ | |||
257 258 259 260 261 262 263 |
int uid;
int higherUser = 0; /* True if user being edited is SETUP and the */
/* user doing the editing is ADMIN. Disallow editing */
/* Must have ADMIN privleges to access this page
*/
login_check_credentials();
| | | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
int uid;
int higherUser = 0; /* True if user being edited is SETUP and the */
/* user doing the editing is ADMIN. Disallow editing */
/* Must have ADMIN privleges to access this page
*/
login_check_credentials();
if( !g.perm.Admin ){ login_needed(); return; }
/* Check to see if an ADMIN user is trying to edit a SETUP account.
** Don't allow that.
*/
zId = PD("id", "0");
uid = atoi(zId);
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");
|
| ︙ | ︙ | |||
294 295 296 297 298 299 300 |
int ai = P("ai")!=0;
int aj = P("aj")!=0;
int ak = P("ak")!=0;
int an = P("an")!=0;
int ao = P("ao")!=0;
int ap = P("ap")!=0;
int ar = P("ar")!=0;
| | | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
int ai = P("ai")!=0;
int aj = P("aj")!=0;
int ak = P("ak")!=0;
int an = P("an")!=0;
int ao = P("ao")!=0;
int ap = P("ap")!=0;
int ar = P("ar")!=0;
int as = g.perm.Setup && P("as")!=0;
int aw = P("aw")!=0;
int ac = P("ac")!=0;
int af = P("af")!=0;
int am = P("am")!=0;
int ah = P("ah")!=0;
int ag = P("ag")!=0;
int at = P("at")!=0;
|
| ︙ | ︙ | |||
333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
if( aw ){ zCap[i++] = 'w'; }
if( ax ){ zCap[i++] = 'x'; }
if( az ){ zCap[i++] = 'z'; }
zCap[i] = 0;
zPw = P("pw");
zLogin = P("login");
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( uid>0 &&
| > > > > > > > > | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
if( aw ){ zCap[i++] = 'w'; }
if( ax ){ zCap[i++] = 'x'; }
if( az ){ zCap[i++] = 'z'; }
zCap[i] = 0;
zPw = P("pw");
zLogin = P("login");
if( strlen(zLogin)==0 ){
style_header("User Creation Error");
@ <span class="loginError">Empty login not allowed.</span>
@
@ <p><a href="setup_uedit?id=%d(uid)">[Bummer]</a></p>
style_footer();
return;
}
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( uid>0 &&
|
| ︙ | ︙ | |||
503 504 505 506 507 508 509 | @ <td class="usetupEditLabel">Contact Info:</td> @ <td><input type="text" name="info" size="40" value="%h(zInfo)" /></td> @ </tr> @ <tr> @ <td class="usetupEditLabel">Capabilities:</td> @ <td> #define B(x) inherit[x] | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
@ <td class="usetupEditLabel">Contact Info:</td>
@ <td><input type="text" name="info" size="40" value="%h(zInfo)" /></td>
@ </tr>
@ <tr>
@ <td class="usetupEditLabel">Capabilities:</td>
@ <td>
#define B(x) inherit[x]
if( g.perm.Setup ){
@ <input type="checkbox" name="as"%s(oas) />%s(B('s'))Setup<br />
}
@ <input type="checkbox" name="aa"%s(oaa) />%s(B('a'))Admin<br />
@ <input type="checkbox" name="ad"%s(oad) />%s(B('d'))Delete<br />
@ <input type="checkbox" name="ae"%s(oae) />%s(B('e'))Email<br />
@ <input type="checkbox" name="ap"%s(oap) />%s(B('p'))Password<br />
@ <input type="checkbox" name="ai"%s(oai) />%s(B('i'))Check-In<br />
|
| ︙ | ︙ | |||
806 807 808 809 810 811 812 |
/*
** WEBPAGE: setup_access
*/
void setup_access(void){
login_check_credentials();
| | | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
/*
** WEBPAGE: setup_access
*/
void setup_access(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Access Control Settings");
db_begin_transaction();
@ <form action="%s(g.zTop)/setup_access" method="post"><div>
login_insert_csrf_secret();
|
| ︙ | ︙ | |||
908 909 910 911 912 913 914 |
char *zSelfRepo;
const char *zRepo = PD("repo", "");
const char *zLogin = PD("login", "");
const char *zPw = PD("pw", "");
const char *zNewName = PD("newname", "New Login Group");
login_check_credentials();
| | | 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 |
char *zSelfRepo;
const char *zRepo = PD("repo", "");
const char *zLogin = PD("login", "");
const char *zPw = PD("pw", "");
const char *zNewName = PD("newname", "New Login Group");
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
file_canonical_name(g.zRepositoryName, &fullName);
zSelfRepo = mprintf(blob_str(&fullName));
blob_reset(&fullName);
if( P("join")!=0 ){
login_group_join(zRepo, zLogin, zPw, zNewName, &zErrMsg);
|
| ︙ | ︙ | |||
994 995 996 997 998 999 1000 |
}
/*
** WEBPAGE: setup_timeline
*/
void setup_timeline(void){
login_check_credentials();
| | | 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 |
}
/*
** WEBPAGE: setup_timeline
*/
void setup_timeline(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Timeline Display Preferences");
db_begin_transaction();
@ <form action="%s(g.zTop)/setup_timeline" method="post"><div>
login_insert_csrf_secret();
|
| ︙ | ︙ | |||
1043 1044 1045 1046 1047 1048 1049 |
/*
** WEBPAGE: setup_settings
*/
void setup_settings(void){
struct stControlSettings const *pSet;
login_check_credentials();
| | | 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
/*
** WEBPAGE: setup_settings
*/
void setup_settings(void){
struct stControlSettings const *pSet;
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Settings");
db_open_local();
db_begin_transaction();
@ <p>This page provides a simple interface to the "fossil setting" command.
|
| ︙ | ︙ | |||
1097 1098 1099 1100 1101 1102 1103 |
}
/*
** WEBPAGE: setup_config
*/
void setup_config(void){
login_check_credentials();
| | | 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 |
}
/*
** WEBPAGE: setup_config
*/
void setup_config(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("WWW Configuration");
db_begin_transaction();
@ <form action="%s(g.zTop)/setup_config" method="post"><div>
login_insert_csrf_secret();
|
| ︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 |
}
/*
** WEBPAGE: setup_editcss
*/
void setup_editcss(void){
login_check_credentials();
| | | 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 |
}
/*
** WEBPAGE: setup_editcss
*/
void setup_editcss(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
db_begin_transaction();
if( P("clear")!=0 ){
db_multi_exec("DELETE FROM config WHERE name='css'");
cgi_replace_parameter("css", zDefaultCSS);
db_end_transaction(0);
|
| ︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 |
}
/*
** WEBPAGE: setup_header
*/
void setup_header(void){
login_check_credentials();
| | | 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 |
}
/*
** WEBPAGE: setup_header
*/
void setup_header(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
db_begin_transaction();
if( P("clear")!=0 ){
db_multi_exec("DELETE FROM config WHERE name='header'");
cgi_replace_parameter("header", zDefaultHeader);
}else{
|
| ︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 |
}
/*
** WEBPAGE: setup_footer
*/
void setup_footer(void){
login_check_credentials();
| | | 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 |
}
/*
** WEBPAGE: setup_footer
*/
void setup_footer(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
db_begin_transaction();
if( P("clear")!=0 ){
db_multi_exec("DELETE FROM config WHERE name='footer'");
cgi_replace_parameter("footer", zDefaultFooter);
}else{
|
| ︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 |
const char *zMime = db_get("logo-mimetype","image/gif");
const char *aImg = P("im");
int szImg = atoi(PD("im:bytes","0"));
if( szImg>0 ){
zMime = PD("im:mimetype","image/gif");
}
login_check_credentials();
| | | 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 |
const char *zMime = db_get("logo-mimetype","image/gif");
const char *aImg = P("im");
int szImg = atoi(PD("im:bytes","0"));
if( szImg>0 ){
zMime = PD("im:mimetype","image/gif");
}
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
db_begin_transaction();
if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){
Blob img;
Stmt ins;
blob_init(&img, aImg, szImg);
|
| ︙ | ︙ |
Changes to src/sha1.c.
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
*/
int sha1sum_file(const char *zFilename, Blob *pCksum){
FILE *in;
SHA1Context ctx;
unsigned char zResult[20];
char zBuf[10240];
| | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
*/
int sha1sum_file(const char *zFilename, Blob *pCksum){
FILE *in;
SHA1Context ctx;
unsigned char zResult[20];
char zBuf[10240];
if( file_wd_islink(zFilename) ){
/* Instead of file content, return sha1 of link destination path */
Blob destinationPath;
int rc;
blob_read_link(&destinationPath, zFilename);
rc = sha1sum_blob(&destinationPath, pCksum);
blob_reset(&destinationPath);
|
| ︙ | ︙ |
Changes to src/shun.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
Stmt q;
int cnt = 0;
const char *zUuid = P("uuid");
int nUuid;
char zCanonical[UUID_SIZE+1];
login_check_credentials();
| | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
Stmt q;
int cnt = 0;
const char *zUuid = P("uuid");
int nUuid;
char zCanonical[UUID_SIZE+1];
login_check_credentials();
if( !g.perm.Admin ){
login_needed();
}
if( P("rebuild") ){
db_close(1);
db_open_repository(g.zRepositoryName);
db_begin_transaction();
rebuild_db(0, 0, 0);
|
| ︙ | ︙ | |||
217 218 219 220 221 222 223 |
*/
void rcvfromlist_page(void){
int ofst = atoi(PD("ofst","0"));
int cnt;
Stmt q;
login_check_credentials();
| | | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
*/
void rcvfromlist_page(void){
int ofst = atoi(PD("ofst","0"));
int cnt;
Stmt q;
login_check_credentials();
if( !g.perm.Admin ){
login_needed();
}
style_header("Content Sources");
if( ofst>0 ){
style_submenu_element("Newer", "Newer", "rcvfromlist?ofst=%d",
ofst>30 ? ofst-30 : 0);
}
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 |
** Show a single RCVFROM table entry.
*/
void rcvfrom_page(void){
int rcvid = atoi(PD("rcvid","0"));
Stmt q;
login_check_credentials();
| | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
** Show a single RCVFROM table entry.
*/
void rcvfrom_page(void){
int rcvid = atoi(PD("rcvid","0"));
Stmt q;
login_check_credentials();
if( !g.perm.Admin ){
login_needed();
}
style_header("Content Source %d", rcvid);
db_prepare(&q,
"SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr"
" FROM rcvfrom LEFT JOIN user USING(uid)"
" WHERE rcvid=%d",
|
| ︙ | ︙ |
Changes to src/skins.c.
| ︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 | char *zName; char *zErr = 0; const char *zCurrent; /* Current skin */ int i; /* Loop counter */ Stmt q; login_check_credentials(); | | | 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 |
char *zName;
char *zErr = 0;
const char *zCurrent; /* Current skin */
int i; /* Loop counter */
Stmt q;
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
db_begin_transaction();
/* Process requests to delete a user-defined skin */
if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
style_header("Confirm Custom Skin Delete");
|
| ︙ | ︙ |
Changes to src/sqlite3.c.
| ︙ | ︙ | |||
654 655 656 657 658 659 660 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.8" #define SQLITE_VERSION_NUMBER 3007008 | | | 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.8" #define SQLITE_VERSION_NUMBER 3007008 #define SQLITE_SOURCE_ID "2011-09-19 14:49:19 3e0da808d2f5b4d12046e05980ca04578f581177" /* ** 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 |
| ︙ | ︙ | |||
7630 7631 7632 7633 7634 7635 7636 | ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 #endif | < < < < < < < < | 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 | ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ #ifndef offsetof #define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) #endif |
| ︙ | ︙ | |||
7980 7981 7982 7983 7984 7985 7986 | ** pager.h. */ #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */ #define BTREE_MEMORY 4 /* This is an in-memory DB */ #define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */ | < | 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 | ** pager.h. */ #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */ #define BTREE_MEMORY 4 /* This is an in-memory DB */ #define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int); SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); |
| ︙ | ︙ | |||
8381 8382 8383 8384 8385 8386 8387 | #define OP_Permutation 23 #define OP_Compare 24 #define OP_Jump 25 #define OP_And 69 /* same as TK_AND */ #define OP_Or 68 /* same as TK_OR */ #define OP_Not 19 /* same as TK_NOT */ #define OP_BitNot 93 /* same as TK_BITNOT */ | > | | | | | | | | | | | | | | < > | | | | | | | | | | | | | | | | | > > | | | | | > | | > | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < | | | | | | | | > | | | | | < | | 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 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 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 |
#define OP_Permutation 23
#define OP_Compare 24
#define OP_Jump 25
#define OP_And 69 /* same as TK_AND */
#define OP_Or 68 /* same as TK_OR */
#define OP_Not 19 /* same as TK_NOT */
#define OP_BitNot 93 /* same as TK_BITNOT */
#define OP_Once 26
#define OP_If 27
#define OP_IfNot 28
#define OP_IsNull 73 /* same as TK_ISNULL */
#define OP_NotNull 74 /* same as TK_NOTNULL */
#define OP_Column 29
#define OP_Affinity 30
#define OP_MakeRecord 31
#define OP_Count 32
#define OP_Savepoint 33
#define OP_AutoCommit 34
#define OP_Transaction 35
#define OP_ReadCookie 36
#define OP_SetCookie 37
#define OP_VerifyCookie 38
#define OP_OpenRead 39
#define OP_OpenWrite 40
#define OP_OpenAutoindex 41
#define OP_OpenEphemeral 42
#define OP_SorterOpen 43
#define OP_OpenPseudo 44
#define OP_Close 45
#define OP_SeekLt 46
#define OP_SeekLe 47
#define OP_SeekGe 48
#define OP_SeekGt 49
#define OP_Seek 50
#define OP_NotFound 51
#define OP_Found 52
#define OP_IsUnique 53
#define OP_NotExists 54
#define OP_Sequence 55
#define OP_NewRowid 56
#define OP_Insert 57
#define OP_InsertInt 58
#define OP_Delete 59
#define OP_ResetCount 60
#define OP_SorterCompare 61
#define OP_SorterData 62
#define OP_RowKey 63
#define OP_RowData 64
#define OP_Rowid 65
#define OP_NullRow 66
#define OP_Last 67
#define OP_SorterSort 70
#define OP_Sort 71
#define OP_Rewind 72
#define OP_SorterNext 81
#define OP_Prev 92
#define OP_Next 95
#define OP_SorterInsert 96
#define OP_IdxInsert 97
#define OP_IdxDelete 98
#define OP_IdxRowid 99
#define OP_IdxLT 100
#define OP_IdxGE 101
#define OP_Destroy 102
#define OP_Clear 103
#define OP_CreateIndex 104
#define OP_CreateTable 105
#define OP_ParseSchema 106
#define OP_LoadAnalysis 107
#define OP_DropTable 108
#define OP_DropIndex 109
#define OP_DropTrigger 110
#define OP_IntegrityCk 111
#define OP_RowSetAdd 112
#define OP_RowSetRead 113
#define OP_RowSetTest 114
#define OP_Program 115
#define OP_Param 116
#define OP_FkCounter 117
#define OP_FkIfZero 118
#define OP_MemMax 119
#define OP_IfPos 120
#define OP_IfNeg 121
#define OP_IfZero 122
#define OP_AggStep 123
#define OP_AggFinal 124
#define OP_Checkpoint 125
#define OP_JournalMode 126
#define OP_Vacuum 127
#define OP_IncrVacuum 128
#define OP_Expire 129
#define OP_TableLock 131
#define OP_VBegin 132
#define OP_VCreate 133
#define OP_VDestroy 134
#define OP_VOpen 135
#define OP_VFilter 136
#define OP_VColumn 137
#define OP_VNext 138
#define OP_VRename 139
#define OP_VUpdate 140
#define OP_Pagecount 146
#define OP_MaxPgcnt 147
#define OP_Trace 148
#define OP_Noop 149
#define OP_Explain 150
/* 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 */
#define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */
#define OPFLG_IN1 0x0004 /* in1: P1 is an input */
#define OPFLG_IN2 0x0008 /* in2: P2 is an input */
#define OPFLG_IN3 0x0010 /* in3: P3 is an input */
#define OPFLG_OUT2 0x0020 /* out2: P2 is an output */
#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x01, 0x05, 0x04, 0x04, 0x10, 0x00, 0x02,\
/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\
/* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\
/* 24 */ 0x00, 0x01, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00,\
/* 32 */ 0x02, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,\
/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,\
/* 48 */ 0x11, 0x11, 0x08, 0x11, 0x11, 0x11, 0x11, 0x02,\
/* 56 */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 64 */ 0x00, 0x02, 0x00, 0x01, 0x4c, 0x4c, 0x01, 0x01,\
/* 72 */ 0x01, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\
/* 80 */ 0x15, 0x01, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,\
/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x01, 0x24, 0x02, 0x01,\
/* 96 */ 0x08, 0x08, 0x00, 0x02, 0x01, 0x01, 0x02, 0x00,\
/* 104 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 112 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08,\
/* 120 */ 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00,\
/* 128 */ 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 136 */ 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x04,\
/* 144 */ 0x04, 0x04, 0x02, 0x02, 0x00, 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.
|
| ︙ | ︙ | |||
8532 8533 8534 8535 8536 8537 8538 | SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); | | | 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 | SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*); |
| ︙ | ︙ | |||
8564 8565 8566 8567 8568 8569 8570 | SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8); SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif | | < > | 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 | SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetValue(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*); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif #ifndef NDEBUG |
| ︙ | ︙ | |||
8651 8652 8653 8654 8655 8656 8657 | ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** ** NOTE: These values must match the corresponding BTREE_ values in btree.h. */ #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ #define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */ #define PAGER_MEMORY 0x0004 /* In-memory database */ | < | 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 | ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** ** NOTE: These values must match the corresponding BTREE_ values in btree.h. */ #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ #define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */ #define PAGER_MEMORY 0x0004 /* In-memory database */ /* ** Valid values for the second argument to sqlite3PagerLockingMode(). */ #define PAGER_LOCKINGMODE_QUERY -1 #define PAGER_LOCKINGMODE_NORMAL 0 #define PAGER_LOCKINGMODE_EXCLUSIVE 1 |
| ︙ | ︙ | |||
8747 8748 8749 8750 8751 8752 8753 | SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*); SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); SQLITE_PRIVATE int sqlite3PagerNosync(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); | < < < | 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 | SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*); SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); SQLITE_PRIVATE int sqlite3PagerNosync(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); /* Functions used to truncate the database file. */ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); #endif |
| ︙ | ︙ | |||
10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 |
*/
struct AggInfo {
u8 directMode; /* Direct rendering mode means take data directly
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
int sortingIdx; /* Cursor number of the sorting index */
ExprList *pGroupBy; /* The group by clause */
int nSortingColumn; /* Number of columns in the sorting index */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
int iTable; /* Cursor number of the source table */
int iColumn; /* Column number within the source table */
int iSorterColumn; /* Column number in the sorting index */
| > | 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 |
*/
struct AggInfo {
u8 directMode; /* Direct rendering mode means take data directly
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
int sortingIdx; /* Cursor number of the sorting index */
int sortingIdxPTab; /* Cursor number of pseudo-table */
ExprList *pGroupBy; /* The group by clause */
int nSortingColumn; /* Number of columns in the sorting index */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
int iTable; /* Cursor number of the source table */
int iColumn; /* Column number within the source table */
int iSorterColumn; /* Column number in the sorting index */
|
| ︙ | ︙ | |||
10493 10494 10495 10496 10497 10498 10499 |
i16 nAlloc; /* Number of entries allocated in a[] below */
struct SrcList_item {
char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */
| | > | 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 |
i16 nAlloc; /* Number of entries allocated in a[] below */
struct SrcList_item {
char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */
int addrFillSub; /* Address of subroutine to manifest a subquery */
int regReturn; /* Register holding return address of addrFillSub */
u8 jointype; /* Type of join between this able and the previous */
u8 notIndexed; /* True if there is a NOT INDEXED clause */
u8 isCorrelated; /* True if sub-query is correlated */
#ifndef SQLITE_OMIT_EXPLAIN
u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
#endif
int iCursor; /* The VDBE cursor number used to access this table */
|
| ︙ | ︙ | |||
10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 | */ #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 */ /* ** The results of a select can be distributed in several ways. The ** "SRT" prefix means "SELECT Result Type". */ #define SRT_Union 1 /* Store result as keys in an index */ | > | 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 | */ #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 */ #define SF_UseSorter 0x0040 /* Sort using a sorter */ /* ** The results of a select can be distributed in several ways. The ** "SRT" prefix means "SELECT Result Type". */ #define SRT_Union 1 /* Store result as keys in an index */ |
| ︙ | ︙ | |||
12042 12043 12044 12045 12046 12047 12048 |
*/
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
0x7ffffffe, /* mxStrlen */
| | | 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045 12046 12047 12048 12049 |
*/
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
0x7ffffffe, /* mxStrlen */
128, /* szLookaside */
500, /* nLookaside */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
{0,0,0,0,0,0,0,0,0,0,0}, /* pcache */
(void*)0, /* pHeap */
0, /* nHeap */
0, 0, /* mnHeap, mxHeap */
|
| ︙ | ︙ | |||
12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 | #endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif #ifdef SQLITE_NO_SYNC | > > > | 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 | #endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #ifdef SQLITE_MAX_SCHEMA_RETRY "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), #endif #ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif #ifdef SQLITE_NO_SYNC |
| ︙ | ︙ | |||
12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 | Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isTable; /* True if a table requiring integer keys */ Bool isIndex; /* True if an index containing keys only - no data */ Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ | > | | 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 | Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isTable; /* True if a table requiring integer keys */ Bool isIndex; /* True if an index containing keys only - no data */ Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */ Bool isSorter; /* True if a new-style sorter */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or ** OP_IsUnique opcode on this cursor. */ int seekResult; /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches |
| ︙ | ︙ | |||
12942 12943 12944 12945 12946 12947 12948 12949 12950 | #ifdef SQLITE_OMIT_MERGE_SORT # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterClose(Y,Z) # define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK # define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterNext(X,Y,Z) SQLITE_OK #else SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); | > < > > | | 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 | #ifdef SQLITE_OMIT_MERGE_SORT # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterClose(Y,Z) # define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK # define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterNext(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterCompare(X,Y,Z) SQLITE_OK #else SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(VdbeCursor *, Mem *, int *); #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeEnter(X) |
| ︙ | ︙ | |||
14535 14536 14537 14538 14539 14540 14541 |
const char *zFile,
sqlite3_file **ppFile,
int flags,
int *pOutFlags
){
int rc = SQLITE_NOMEM;
sqlite3_file *pFile;
| | | 14534 14535 14536 14537 14538 14539 14540 14541 14542 14543 14544 14545 14546 14547 14548 |
const char *zFile,
sqlite3_file **ppFile,
int flags,
int *pOutFlags
){
int rc = SQLITE_NOMEM;
sqlite3_file *pFile;
pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
if( pFile ){
rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
if( rc!=SQLITE_OK ){
sqlite3_free(pFile);
}else{
*ppFile = pFile;
}
|
| ︙ | ︙ | |||
22098 22099 22100 22101 22102 22103 22104 |
/* 19 */ "Not",
/* 20 */ "AddImm",
/* 21 */ "MustBeInt",
/* 22 */ "RealAffinity",
/* 23 */ "Permutation",
/* 24 */ "Compare",
/* 25 */ "Jump",
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > | 22097 22098 22099 22100 22101 22102 22103 22104 22105 22106 22107 22108 22109 22110 22111 22112 22113 22114 22115 22116 22117 22118 22119 22120 22121 22122 22123 22124 22125 22126 22127 22128 22129 22130 22131 22132 22133 22134 22135 22136 22137 22138 22139 22140 22141 22142 22143 22144 22145 22146 22147 22148 22149 22150 22151 22152 22153 22154 22155 22156 22157 22158 22159 22160 22161 22162 22163 22164 22165 22166 22167 22168 22169 22170 22171 22172 22173 22174 22175 22176 22177 22178 22179 22180 22181 22182 22183 22184 22185 22186 22187 22188 22189 22190 22191 22192 22193 22194 22195 22196 22197 22198 22199 22200 22201 22202 22203 22204 22205 22206 22207 22208 22209 22210 22211 22212 22213 22214 22215 22216 22217 22218 22219 22220 22221 22222 22223 22224 22225 22226 22227 22228 22229 22230 22231 22232 22233 22234 22235 |
/* 19 */ "Not",
/* 20 */ "AddImm",
/* 21 */ "MustBeInt",
/* 22 */ "RealAffinity",
/* 23 */ "Permutation",
/* 24 */ "Compare",
/* 25 */ "Jump",
/* 26 */ "Once",
/* 27 */ "If",
/* 28 */ "IfNot",
/* 29 */ "Column",
/* 30 */ "Affinity",
/* 31 */ "MakeRecord",
/* 32 */ "Count",
/* 33 */ "Savepoint",
/* 34 */ "AutoCommit",
/* 35 */ "Transaction",
/* 36 */ "ReadCookie",
/* 37 */ "SetCookie",
/* 38 */ "VerifyCookie",
/* 39 */ "OpenRead",
/* 40 */ "OpenWrite",
/* 41 */ "OpenAutoindex",
/* 42 */ "OpenEphemeral",
/* 43 */ "SorterOpen",
/* 44 */ "OpenPseudo",
/* 45 */ "Close",
/* 46 */ "SeekLt",
/* 47 */ "SeekLe",
/* 48 */ "SeekGe",
/* 49 */ "SeekGt",
/* 50 */ "Seek",
/* 51 */ "NotFound",
/* 52 */ "Found",
/* 53 */ "IsUnique",
/* 54 */ "NotExists",
/* 55 */ "Sequence",
/* 56 */ "NewRowid",
/* 57 */ "Insert",
/* 58 */ "InsertInt",
/* 59 */ "Delete",
/* 60 */ "ResetCount",
/* 61 */ "SorterCompare",
/* 62 */ "SorterData",
/* 63 */ "RowKey",
/* 64 */ "RowData",
/* 65 */ "Rowid",
/* 66 */ "NullRow",
/* 67 */ "Last",
/* 68 */ "Or",
/* 69 */ "And",
/* 70 */ "SorterSort",
/* 71 */ "Sort",
/* 72 */ "Rewind",
/* 73 */ "IsNull",
/* 74 */ "NotNull",
/* 75 */ "Ne",
/* 76 */ "Eq",
/* 77 */ "Gt",
/* 78 */ "Le",
/* 79 */ "Lt",
/* 80 */ "Ge",
/* 81 */ "SorterNext",
/* 82 */ "BitAnd",
/* 83 */ "BitOr",
/* 84 */ "ShiftLeft",
/* 85 */ "ShiftRight",
/* 86 */ "Add",
/* 87 */ "Subtract",
/* 88 */ "Multiply",
/* 89 */ "Divide",
/* 90 */ "Remainder",
/* 91 */ "Concat",
/* 92 */ "Prev",
/* 93 */ "BitNot",
/* 94 */ "String8",
/* 95 */ "Next",
/* 96 */ "SorterInsert",
/* 97 */ "IdxInsert",
/* 98 */ "IdxDelete",
/* 99 */ "IdxRowid",
/* 100 */ "IdxLT",
/* 101 */ "IdxGE",
/* 102 */ "Destroy",
/* 103 */ "Clear",
/* 104 */ "CreateIndex",
/* 105 */ "CreateTable",
/* 106 */ "ParseSchema",
/* 107 */ "LoadAnalysis",
/* 108 */ "DropTable",
/* 109 */ "DropIndex",
/* 110 */ "DropTrigger",
/* 111 */ "IntegrityCk",
/* 112 */ "RowSetAdd",
/* 113 */ "RowSetRead",
/* 114 */ "RowSetTest",
/* 115 */ "Program",
/* 116 */ "Param",
/* 117 */ "FkCounter",
/* 118 */ "FkIfZero",
/* 119 */ "MemMax",
/* 120 */ "IfPos",
/* 121 */ "IfNeg",
/* 122 */ "IfZero",
/* 123 */ "AggStep",
/* 124 */ "AggFinal",
/* 125 */ "Checkpoint",
/* 126 */ "JournalMode",
/* 127 */ "Vacuum",
/* 128 */ "IncrVacuum",
/* 129 */ "Expire",
/* 130 */ "Real",
/* 131 */ "TableLock",
/* 132 */ "VBegin",
/* 133 */ "VCreate",
/* 134 */ "VDestroy",
/* 135 */ "VOpen",
/* 136 */ "VFilter",
/* 137 */ "VColumn",
/* 138 */ "VNext",
/* 139 */ "VRename",
/* 140 */ "VUpdate",
/* 141 */ "ToText",
/* 142 */ "ToBlob",
/* 143 */ "ToNumeric",
/* 144 */ "ToInt",
/* 145 */ "ToReal",
/* 146 */ "Pagecount",
/* 147 */ "MaxPgcnt",
/* 148 */ "Trace",
/* 149 */ "Noop",
/* 150 */ "Explain",
};
return azName[i];
}
#endif
/************** End of opcodes.c *********************************************/
/************** Begin file os_os2.c ******************************************/
|
| ︙ | ︙ | |||
22312 22313 22314 22315 22316 22317 22318 | ** macro to SQLITE_DEBUG and some older makefiles have not yet made the ** switch. The following code should catch this problem at compile-time. */ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif | | | 22316 22317 22318 22319 22320 22321 22322 22323 22324 22325 22326 22327 22328 22329 22330 | ** macro to SQLITE_DEBUG and some older makefiles have not yet made the ** switch. The following code should catch this problem at compile-time. */ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) # ifndef SQLITE_DEBUG_OS_TRACE # define SQLITE_DEBUG_OS_TRACE 0 # endif int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; # define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X #else # define OSTRACE(X) |
| ︙ | ︙ | |||
24654 24655 24656 24657 24658 24659 24660 | ** macro to SQLITE_DEBUG and some older makefiles have not yet made the ** switch. The following code should catch this problem at compile-time. */ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif | | | 24658 24659 24660 24661 24662 24663 24664 24665 24666 24667 24668 24669 24670 24671 24672 | ** macro to SQLITE_DEBUG and some older makefiles have not yet made the ** switch. The following code should catch this problem at compile-time. */ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) # ifndef SQLITE_DEBUG_OS_TRACE # define SQLITE_DEBUG_OS_TRACE 0 # endif int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; # define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X #else # define OSTRACE(X) |
| ︙ | ︙ | |||
27714 27715 27716 27717 27718 27719 27720 | */ SQLITE_API int sqlite3_sync_count = 0; SQLITE_API int sqlite3_fullsync_count = 0; #endif /* ** We do not trust systems to provide a working fdatasync(). Some do. | | | | | 27718 27719 27720 27721 27722 27723 27724 27725 27726 27727 27728 27729 27730 27731 27732 27733 27734 27735 27736 | */ SQLITE_API int sqlite3_sync_count = 0; SQLITE_API int sqlite3_fullsync_count = 0; #endif /* ** We do not trust systems to provide a working fdatasync(). Some do. ** Others do no. To be safe, we will stick with the (slightly slower) ** fsync(). If you know that your system does support fdatasync() correctly, ** then simply compile with -Dfdatasync=fdatasync */ #if !defined(fdatasync) # define fdatasync fsync #endif /* ** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not ** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently ** only available on Mac OS X. But that could change. |
| ︙ | ︙ | |||
28013 28014 28015 28016 28017 28018 28019 |
/*
** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
** file-control operation. Enlarge the database to nBytes in size
** (rounded up to the next chunk-size). If the database is already
** nBytes or larger, this routine is a no-op.
*/
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
| | | 28017 28018 28019 28020 28021 28022 28023 28024 28025 28026 28027 28028 28029 28030 28031 |
/*
** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
** file-control operation. Enlarge the database to nBytes in size
** (rounded up to the next chunk-size). If the database is already
** nBytes or larger, this routine is a no-op.
*/
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
if( pFile->szChunk>0 ){
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
if( nSize>(i64)buf.st_size ){
|
| ︙ | ︙ | |||
28208 28209 28210 28211 28212 28213 28214 28215 28216 |
** All other fields are read/write. The unixShm.pFile->mutex must be held
** while accessing any read/write fields.
*/
struct unixShm {
unixShmNode *pShmNode; /* The underlying unixShmNode object */
unixShm *pNext; /* Next unixShm with the same unixShmNode */
u8 hasMutex; /* True if holding the unixShmNode mutex */
u16 sharedMask; /* Mask of shared locks held */
u16 exclMask; /* Mask of exclusive locks held */
| > < < < | 28212 28213 28214 28215 28216 28217 28218 28219 28220 28221 28222 28223 28224 28225 28226 28227 28228 |
** All other fields are read/write. The unixShm.pFile->mutex must be held
** while accessing any read/write fields.
*/
struct unixShm {
unixShmNode *pShmNode; /* The underlying unixShmNode object */
unixShm *pNext; /* Next unixShm with the same unixShmNode */
u8 hasMutex; /* True if holding the unixShmNode mutex */
u8 id; /* Id of this connection within its unixShmNode */
u16 sharedMask; /* Mask of shared locks held */
u16 exclMask; /* Mask of exclusive locks held */
};
/*
** Constants used for locking
*/
#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
|
| ︙ | ︙ | |||
31433 31434 31435 31436 31437 31438 31439 | ** macro to SQLITE_DEBUG and some older makefiles have not yet made the ** switch. The following code should catch this problem at compile-time. */ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif | | | 31435 31436 31437 31438 31439 31440 31441 31442 31443 31444 31445 31446 31447 31448 31449 | ** macro to SQLITE_DEBUG and some older makefiles have not yet made the ** switch. The following code should catch this problem at compile-time. */ #ifdef MEMORY_DEBUG # error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) # ifndef SQLITE_DEBUG_OS_TRACE # define SQLITE_DEBUG_OS_TRACE 0 # endif int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; # define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X #else # define OSTRACE(X) |
| ︙ | ︙ | |||
32766 32767 32768 32769 32770 32771 32772 | SimulateIOError(return SQLITE_IOERR_TRUNCATE); /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the ** actual file size after the operation may be larger than the requested ** size). */ | | | 32768 32769 32770 32771 32772 32773 32774 32775 32776 32777 32778 32779 32780 32781 32782 |
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
/* If the user has configured a chunk-size for this file, truncate the
** file so that it consists of an integer number of chunks (i.e. the
** actual file size after the operation may be larger than the requested
** size).
*/
if( pFile->szChunk>0 ){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( seekWinFile(pFile, nByte) ){
rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath);
}else if( 0==SetEndOfFile(pFile->h) ){
|
| ︙ | ︙ | |||
32795 32796 32797 32798 32799 32800 32801 |
SQLITE_API int sqlite3_fullsync_count = 0;
#endif
/*
** Make sure all writes to a particular file are committed to disk.
*/
static int winSync(sqlite3_file *id, int flags){
| > > > > > > | > > > > > < | 32797 32798 32799 32800 32801 32802 32803 32804 32805 32806 32807 32808 32809 32810 32811 32812 32813 32814 32815 32816 32817 32818 32819 32820 32821 32822 32823 |
SQLITE_API int sqlite3_fullsync_count = 0;
#endif
/*
** Make sure all writes to a particular file are committed to disk.
*/
static int winSync(sqlite3_file *id, int flags){
#ifndef SQLITE_NO_SYNC
/*
** Used only when SQLITE_NO_SYNC is not defined.
*/
BOOL rc;
#endif
#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
(defined(SQLITE_TEST) && defined(SQLITE_DEBUG))
/*
** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
** OSTRACE() macros.
*/
winFile *pFile = (winFile*)id;
#else
UNUSED_PARAMETER(id);
#endif
assert( pFile );
/* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
assert((flags&0x0F)==SQLITE_SYNC_NORMAL
|
| ︙ | ︙ | |||
33153 33154 33155 33156 33157 33158 33159 |
return SQLITE_OK;
}
case SQLITE_FCNTL_CHUNK_SIZE: {
pFile->szChunk = *(int *)pArg;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
| | | | | | | | | | | | | > > | 33165 33166 33167 33168 33169 33170 33171 33172 33173 33174 33175 33176 33177 33178 33179 33180 33181 33182 33183 33184 33185 33186 33187 33188 33189 33190 33191 33192 |
return SQLITE_OK;
}
case SQLITE_FCNTL_CHUNK_SIZE: {
pFile->szChunk = *(int *)pArg;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
if( pFile->szChunk>0 ){
sqlite3_int64 oldSz;
int rc = winFileSize(id, &oldSz);
if( rc==SQLITE_OK ){
sqlite3_int64 newSz = *(sqlite3_int64*)pArg;
if( newSz>oldSz ){
SimulateIOErrorBenign(1);
rc = winTruncate(id, newSz);
SimulateIOErrorBenign(0);
}
}
return rc;
}
return SQLITE_OK;
}
case SQLITE_FCNTL_PERSIST_WAL: {
int bPersist = *(int*)pArg;
if( bPersist<0 ){
*(int*)pArg = pFile->bPersistWal;
}else{
pFile->bPersistWal = bPersist!=0;
|
| ︙ | ︙ | |||
38134 38135 38136 38137 38138 38139 38140 | u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ | < < | 38148 38149 38150 38151 38152 38153 38154 38155 38156 38157 38158 38159 38160 38161 | u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ /************************************************************************** ** The following block contains those class members that change during ** routine opertion. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe |
| ︙ | ︙ | |||
38359 38360 38361 38362 38363 38364 38365 |
assert( p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_MEMORY
);
assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
assert( pagerUseWal(p)==0 );
}
| < < < < < < < < < | 38371 38372 38373 38374 38375 38376 38377 38378 38379 38380 38381 38382 38383 38384 |
assert( p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_MEMORY
);
assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
assert( pagerUseWal(p)==0 );
}
/* If changeCountDone is set, a RESERVED lock or greater must be held
** on the file.
*/
assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK );
assert( p->eLock!=PENDING_LOCK );
switch( p->eState ){
|
| ︙ | ︙ | |||
41699 41700 41701 41702 41703 41704 41705 | ** Spilling is also prohibited when in an error state since that could ** lead to database corruption. In the current implementaton it ** is impossible for sqlite3PCacheFetch() to be called with createFlag==1 ** while in the error state, hence it is impossible for this routine to ** be called in the error state. Nevertheless, we include a NEVER() ** test for the error state as a safeguard against future changes. */ | < | 41702 41703 41704 41705 41706 41707 41708 41709 41710 41711 41712 41713 41714 41715 |
** Spilling is also prohibited when in an error state since that could
** lead to database corruption. In the current implementaton it
** is impossible for sqlite3PCacheFetch() to be called with createFlag==1
** while in the error state, hence it is impossible for this routine to
** be called in the error state. Nevertheless, we include a NEVER()
** test for the error state as a safeguard against future changes.
*/
if( NEVER(pPager->errCode) ) return SQLITE_OK;
if( pPager->doNotSpill ) return SQLITE_OK;
if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){
return SQLITE_OK;
}
pPg->pDirty = 0;
|
| ︙ | ︙ | |||
42071 42072 42073 42074 42075 42076 42077 |
}else if( memDb ){
pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
}
/* pPager->xBusyHandler = 0; */
/* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit;
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
| < < < < < < | 42073 42074 42075 42076 42077 42078 42079 42080 42081 42082 42083 42084 42085 42086 |
}else if( memDb ){
pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
}
/* pPager->xBusyHandler = 0; */
/* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit;
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
*ppPager = pPager;
return SQLITE_OK;
}
|
| ︙ | ︙ | |||
43621 43622 43623 43624 43625 43626 43627 |
/*
** Return true if this is an in-memory pager.
*/
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
return MEMDB;
}
| < < < < < < < < < < < | 43617 43618 43619 43620 43621 43622 43623 43624 43625 43626 43627 43628 43629 43630 |
/*
** Return true if this is an in-memory pager.
*/
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
return MEMDB;
}
/*
** Check that there are at least nSavepoint savepoints open. If there are
** currently less than nSavepoints open, then open one or more savepoints
** to make up the difference. If the number of savepoints is already
** equal to nSavepoint, then this function is a no-op.
**
** If a memory allocation fails, SQLITE_NOMEM is returned. If an error
|
| ︙ | ︙ | |||
48922 48923 48924 48925 48926 48927 48928 48929 48930 48931 |
i64 nKey, /* Integer key for tables. Size of pKey for indices */
int bias, /* Bias search to the high end */
int *pRes /* Write search results here */
){
int rc; /* Status code */
UnpackedRecord *pIdxKey; /* Unpacked index key */
char aSpace[150]; /* Temp space for pIdxKey - to avoid a malloc */
if( pKey ){
assert( nKey==(i64)(int)nKey );
| > | | > > | | | 48907 48908 48909 48910 48911 48912 48913 48914 48915 48916 48917 48918 48919 48920 48921 48922 48923 48924 48925 48926 48927 48928 48929 48930 48931 48932 48933 48934 48935 |
i64 nKey, /* Integer key for tables. Size of pKey for indices */
int bias, /* Bias search to the high end */
int *pRes /* Write search results here */
){
int rc; /* Status code */
UnpackedRecord *pIdxKey; /* Unpacked index key */
char aSpace[150]; /* Temp space for pIdxKey - to avoid a malloc */
char *pFree = 0;
if( pKey ){
assert( nKey==(i64)(int)nKey );
pIdxKey = sqlite3VdbeAllocUnpackedRecord(
pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
);
if( pIdxKey==0 ) return SQLITE_NOMEM;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
}else{
pIdxKey = 0;
}
rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
if( pFree ){
sqlite3DbFree(pCur->pKeyInfo->db, pFree);
}
return rc;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
** when saveCursorPosition() was called. Note that this call deletes the
|
| ︙ | ︙ | |||
50000 50001 50002 50003 50004 50005 50006 | /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 ); /* A BTREE_SINGLE database is always a temporary and/or ephemeral */ assert( (flags & BTREE_SINGLE)==0 || isTempDb ); | < < < < < < < < < < < | 49988 49989 49990 49991 49992 49993 49994 49995 49996 49997 49998 49999 50000 50001 50002 50003 50004 50005 50006 |
/* Only a BTREE_SINGLE database can be BTREE_UNORDERED */
assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 );
/* A BTREE_SINGLE database is always a temporary and/or ephemeral */
assert( (flags & BTREE_SINGLE)==0 || isTempDb );
if( db->flags & SQLITE_NoReadlock ){
flags |= BTREE_NO_READLOCK;
}
if( isMemdb ){
flags |= BTREE_MEMORY;
}
if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
}
p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
return SQLITE_NOMEM;
|
| ︙ | ︙ | |||
51020 51021 51022 51023 51024 51025 51026 |
nCell = pPage->nCell;
for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i);
if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info;
btreeParseCellPtr(pPage, pCell, &info);
| | > | > | | < | 50997 50998 50999 51000 51001 51002 51003 51004 51005 51006 51007 51008 51009 51010 51011 51012 51013 51014 51015 51016 |
nCell = pPage->nCell;
for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i);
if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info;
btreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow
&& pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
&& iFrom==get4byte(&pCell[info.iOverflow])
){
put4byte(&pCell[info.iOverflow], iTo);
break;
}
}else{
if( get4byte(pCell)==iFrom ){
put4byte(pCell, iTo);
break;
}
}
|
| ︙ | ︙ | |||
53456 53457 53458 53459 53460 53461 53462 53463 53464 53465 53466 53467 53468 53469 |
u32 ovflPageSize;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
btreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
ovflPgno = get4byte(&pCell[info.iOverflow]);
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
assert( ovflPgno==0 || nOvfl>0 );
while( nOvfl-- ){
Pgno iNext = 0;
| > > > | 53434 53435 53436 53437 53438 53439 53440 53441 53442 53443 53444 53445 53446 53447 53448 53449 53450 |
u32 ovflPageSize;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
btreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){
return SQLITE_CORRUPT; /* Cell extends past end of page */
}
ovflPgno = get4byte(&pCell[info.iOverflow]);
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
assert( ovflPgno==0 || nOvfl>0 );
while( nOvfl-- ){
Pgno iNext = 0;
|
| ︙ | ︙ | |||
55558 55559 55560 55561 55562 55563 55564 |
*/
zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
releasePage(pPage);
}
return rc;
}
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
| < < < < < < | < | 55539 55540 55541 55542 55543 55544 55545 55546 55547 55548 55549 55550 55551 55552 55553 55554 55555 |
*/
zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
releasePage(pPage);
}
return rc;
}
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
int rc;
sqlite3BtreeEnter(p);
rc = btreeDropTable(p, iTable, piMoved);
sqlite3BtreeLeave(p);
return rc;
}
/*
** This function may only be called if the b-tree connection already
|
| ︙ | ︙ | |||
58756 58757 58758 58759 58760 58761 58762 |
}else if( opcode==OP_VFilter ){
int n;
assert( p->nOp - i >= 3 );
assert( pOp[-1].opcode==OP_Integer );
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
#endif
| | | 58730 58731 58732 58733 58734 58735 58736 58737 58738 58739 58740 58741 58742 58743 58744 |
}else if( opcode==OP_VFilter ){
int n;
assert( p->nOp - i >= 3 );
assert( pOp[-1].opcode==OP_Integer );
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
#endif
}else if( opcode==OP_Next || opcode==OP_SorterNext ){
pOp->p4.xAdvance = sqlite3BtreeNext;
pOp->p4type = P4_ADVANCE;
}else if( opcode==OP_Prev ){
pOp->p4.xAdvance = sqlite3BtreePrevious;
pOp->p4type = P4_ADVANCE;
}
|
| ︙ | ︙ | |||
58993 58994 58995 58996 58997 58998 58999 |
*/
SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
p->pNext = pVdbe->pProgram;
pVdbe->pProgram = p;
}
/*
| | | < | | | < < | 58967 58968 58969 58970 58971 58972 58973 58974 58975 58976 58977 58978 58979 58980 58981 58982 58983 58984 58985 58986 58987 58988 58989 |
*/
SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
p->pNext = pVdbe->pProgram;
pVdbe->pProgram = p;
}
/*
** Change the opcode at addr into OP_Noop
*/
SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
if( p->aOp ){
VdbeOp *pOp = &p->aOp[addr];
sqlite3 *db = p->db;
freeP4(db, pOp->p4type, pOp->p4.p);
memset(pOp, 0, sizeof(pOp[0]));
pOp->opcode = OP_Noop;
}
}
/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
** static array using sqlite3VdbeAddOpList but we want to make a
|
| ︙ | ︙ | |||
59160 59161 59162 59163 59164 59165 59166 |
** having to double-check to make sure that the result is non-negative. But
** if SQLITE_OMIT_TRACE is defined, the OP_Trace is omitted and we do need to
** check the value of p->nOp-1 before continuing.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* C89 specifies that the constant "dummy" will be initialized to all
** zeros, which is correct. MSVC generates a warning, nevertheless. */
| | | 59131 59132 59133 59134 59135 59136 59137 59138 59139 59140 59141 59142 59143 59144 59145 |
** having to double-check to make sure that the result is non-negative. But
** if SQLITE_OMIT_TRACE is defined, the OP_Trace is omitted and we do need to
** check the value of p->nOp-1 before continuing.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* C89 specifies that the constant "dummy" will be initialized to all
** zeros, which is correct. MSVC generates a warning, nevertheless. */
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->magic==VDBE_MAGIC_INIT );
if( addr<0 ){
#ifdef SQLITE_OMIT_TRACE
if( p->nOp==0 ) return (VdbeOp*)&dummy;
#endif
addr = p->nOp - 1;
}
|
| ︙ | ︙ | |||
61153 61154 61155 61156 61157 61158 61159 |
}
return len;
}
}
return 0;
}
| < < | | > | > | | | > | < | | | < < | | > < | | < < | < < < | < | < < | | > | < | | > > > > | > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < | 61124 61125 61126 61127 61128 61129 61130 61131 61132 61133 61134 61135 61136 61137 61138 61139 61140 61141 61142 61143 61144 61145 61146 61147 61148 61149 61150 61151 61152 61153 61154 61155 61156 61157 61158 61159 61160 61161 61162 61163 61164 61165 61166 61167 61168 61169 61170 61171 61172 61173 61174 61175 61176 61177 61178 61179 61180 61181 61182 61183 61184 61185 61186 61187 61188 61189 61190 61191 61192 61193 61194 61195 61196 61197 61198 61199 61200 61201 61202 61203 61204 61205 61206 61207 61208 61209 61210 61211 61212 61213 61214 61215 61216 61217 61218 61219 |
}
return len;
}
}
return 0;
}
/*
** This routine is used to allocate sufficient space for an UnpackedRecord
** structure large enough to be used with sqlite3VdbeRecordUnpack() if
** the first argument is a pointer to KeyInfo structure pKeyInfo.
**
** The space is either allocated using sqlite3DbMallocRaw() or from within
** the unaligned buffer passed via the second and third arguments (presumably
** stack space). If the former, then *ppFree is set to a pointer that should
** be eventually freed by the caller using sqlite3DbFree(). Or, if the
** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL
** before returning.
**
** If an OOM error occurs, NULL is returned.
*/
SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
KeyInfo *pKeyInfo, /* Description of the record */
char *pSpace, /* Unaligned space available */
int szSpace, /* Size of pSpace[] in bytes */
char **ppFree /* OUT: Caller should free this pointer */
){
UnpackedRecord *p; /* Unpacked record to return */
int nOff; /* Increment pSpace by nOff to align it */
int nByte; /* Number of bytes required for *p */
/* We want to shift the pointer pSpace up such that it is 8-byte aligned.
** Thus, we need to calculate a value, nOff, between 0 and 7, to shift
** it by. If pSpace is already 8-byte aligned, nOff should be zero.
*/
nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7;
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
if( nByte>szSpace+nOff ){
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
*ppFree = (char *)p;
if( !p ) return 0;
}else{
p = (UnpackedRecord*)&pSpace[nOff];
*ppFree = 0;
}
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nField + 1;
return p;
}
/*
** Given the nKey-byte encoding of a record in pKey[], populate the
** UnpackedRecord structure indicated by the fourth argument with the
** contents of the decoded record.
*/
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
KeyInfo *pKeyInfo, /* Information about the record format */
int nKey, /* Size of the binary record */
const void *pKey, /* The binary record */
UnpackedRecord *p /* Populate this structure before returning. */
){
const unsigned char *aKey = (const unsigned char *)pKey;
int d;
u32 idx; /* Offset in aKey[] to read from */
u16 u; /* Unsigned loop counter */
u32 szHdr;
Mem *pMem = p->aMem;
p->flags = 0;
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
idx = getVarint32(aKey, szHdr);
d = szHdr;
u = 0;
while( idx<szHdr && u<p->nField && d<=nKey ){
u32 serial_type;
idx += getVarint32(&aKey[idx], serial_type);
pMem->enc = pKeyInfo->enc;
pMem->db = pKeyInfo->db;
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->zMalloc = 0;
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
pMem++;
u++;
}
assert( u<=pKeyInfo->nField + 1 );
p->nField = u;
}
/*
** This function compares the two table rows or index records
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
** or positive integer if key1 is less than, equal to or
** greater than key2. The {nKey1, pKey1} key must be a blob
|
| ︙ | ︙ | |||
63869 63870 63871 63872 63873 63874 63875 63876 63877 |
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
} aw;
struct OP_OpenEphemeral_stack_vars {
VdbeCursor *pCx;
} ax;
struct OP_OpenPseudo_stack_vars {
VdbeCursor *pCx;
| > > > | | | > | | | | | | > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 63828 63829 63830 63831 63832 63833 63834 63835 63836 63837 63838 63839 63840 63841 63842 63843 63844 63845 63846 63847 63848 63849 63850 63851 63852 63853 63854 63855 63856 63857 63858 63859 63860 63861 63862 63863 63864 63865 63866 63867 63868 63869 63870 63871 63872 63873 63874 63875 63876 63877 63878 63879 63880 63881 63882 63883 63884 63885 63886 63887 63888 63889 63890 63891 63892 63893 63894 63895 63896 63897 63898 63899 63900 63901 63902 63903 63904 63905 63906 63907 63908 63909 63910 63911 63912 63913 63914 63915 63916 63917 63918 63919 63920 63921 63922 63923 63924 63925 63926 63927 63928 63929 63930 63931 63932 63933 63934 63935 63936 63937 63938 63939 63940 63941 63942 63943 63944 63945 63946 63947 63948 63949 63950 63951 63952 63953 63954 63955 63956 63957 63958 63959 63960 63961 63962 63963 63964 63965 63966 63967 63968 63969 63970 63971 63972 63973 63974 63975 63976 63977 63978 63979 63980 63981 63982 63983 63984 63985 63986 63987 63988 63989 63990 63991 63992 63993 63994 63995 63996 63997 63998 63999 64000 64001 64002 64003 64004 64005 64006 64007 64008 64009 64010 64011 64012 64013 64014 64015 64016 64017 64018 64019 64020 64021 64022 64023 64024 64025 64026 64027 64028 64029 64030 64031 64032 64033 64034 64035 64036 64037 64038 64039 64040 64041 64042 64043 64044 64045 64046 64047 64048 64049 64050 64051 64052 64053 64054 64055 64056 64057 64058 64059 64060 64061 64062 64063 64064 64065 64066 64067 64068 64069 64070 64071 64072 64073 64074 64075 64076 64077 64078 64079 64080 64081 64082 64083 64084 64085 64086 64087 64088 64089 64090 64091 64092 64093 |
Btree *pX;
VdbeCursor *pCur;
Db *pDb;
} aw;
struct OP_OpenEphemeral_stack_vars {
VdbeCursor *pCx;
} ax;
struct OP_SorterOpen_stack_vars {
VdbeCursor *pCx;
} ay;
struct OP_OpenPseudo_stack_vars {
VdbeCursor *pCx;
} az;
struct OP_SeekGt_stack_vars {
int res;
int oc;
VdbeCursor *pC;
UnpackedRecord r;
int nField;
i64 iKey; /* The rowid we are to seek to */
} ba;
struct OP_Seek_stack_vars {
VdbeCursor *pC;
} bb;
struct OP_Found_stack_vars {
int alreadyExists;
VdbeCursor *pC;
int res;
char *pFree;
UnpackedRecord *pIdxKey;
UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
} bc;
struct OP_IsUnique_stack_vars {
u16 ii;
VdbeCursor *pCx;
BtCursor *pCrsr;
u16 nField;
Mem *aMx;
UnpackedRecord r; /* B-Tree index search key */
i64 R; /* Rowid stored in register P3 */
} bd;
struct OP_NotExists_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
} be;
struct OP_NewRowid_stack_vars {
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
int res; /* Result of an sqlite3BtreeLast() */
int cnt; /* Counter to limit the number of searches */
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
VdbeFrame *pFrame; /* Root frame of VDBE */
} bf;
struct OP_InsertInt_stack_vars {
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
i64 iKey; /* The integer ROWID or key for the record to be inserted */
VdbeCursor *pC; /* Cursor to table into which insert is written */
int nZero; /* Number of zero-bytes to append */
int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */
const char *zDb; /* database name - used by the update hook */
const char *zTbl; /* Table name - used by the opdate hook */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
} bg;
struct OP_Delete_stack_vars {
i64 iKey;
VdbeCursor *pC;
} bh;
struct OP_SorterCompare_stack_vars {
VdbeCursor *pC;
int res;
} bi;
struct OP_SorterData_stack_vars {
VdbeCursor *pC;
} bj;
struct OP_RowData_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
i64 n64;
} bk;
struct OP_Rowid_stack_vars {
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
} bl;
struct OP_NullRow_stack_vars {
VdbeCursor *pC;
} bm;
struct OP_Last_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
} bn;
struct OP_Rewind_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
} bo;
struct OP_Next_stack_vars {
VdbeCursor *pC;
int res;
} bp;
struct OP_IdxInsert_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int nKey;
const char *zKey;
} bq;
struct OP_IdxDelete_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
UnpackedRecord r;
} br;
struct OP_IdxRowid_stack_vars {
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
} bs;
struct OP_IdxGE_stack_vars {
VdbeCursor *pC;
int res;
UnpackedRecord r;
} bt;
struct OP_Destroy_stack_vars {
int iMoved;
int iCnt;
Vdbe *pVdbe;
int iDb;
} bu;
struct OP_Clear_stack_vars {
int nChange;
} bv;
struct OP_CreateTable_stack_vars {
int pgno;
int flags;
Db *pDb;
} bw;
struct OP_ParseSchema_stack_vars {
int iDb;
const char *zMaster;
char *zSql;
InitData initData;
} bx;
struct OP_IntegrityCk_stack_vars {
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
int j; /* Loop counter */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
} by;
struct OP_RowSetRead_stack_vars {
i64 val;
} bz;
struct OP_RowSetTest_stack_vars {
int iSet;
int exists;
} ca;
struct OP_Program_stack_vars {
int nMem; /* Number of memory registers for sub-program */
int nByte; /* Bytes of runtime space required for sub-program */
Mem *pRt; /* Register to allocate runtime space */
Mem *pMem; /* Used to iterate through memory cells */
Mem *pEnd; /* Last memory cell in new array */
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
} cb;
struct OP_Param_stack_vars {
VdbeFrame *pFrame;
Mem *pIn;
} cc;
struct OP_MemMax_stack_vars {
Mem *pIn1;
VdbeFrame *pFrame;
} cd;
struct OP_AggStep_stack_vars {
int n;
int i;
Mem *pMem;
Mem *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
} ce;
struct OP_AggFinal_stack_vars {
Mem *pMem;
} cf;
struct OP_Checkpoint_stack_vars {
int i; /* Loop counter */
int aRes[3]; /* Results */
Mem *pMem; /* Write results here */
} cg;
struct OP_JournalMode_stack_vars {
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
const char *zFilename; /* Name of database file for pPager */
} ch;
struct OP_IncrVacuum_stack_vars {
Btree *pBt;
} ci;
struct OP_VBegin_stack_vars {
VTable *pVTab;
} cj;
struct OP_VOpen_stack_vars {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
} ck;
struct OP_VFilter_stack_vars {
int nArg;
int iQuery;
const sqlite3_module *pModule;
Mem *pQuery;
Mem *pArgc;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
VdbeCursor *pCur;
int res;
int i;
Mem **apArg;
} cl;
struct OP_VColumn_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
} cm;
struct OP_VNext_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
} cn;
struct OP_VRename_stack_vars {
sqlite3_vtab *pVtab;
Mem *pName;
} co;
struct OP_VUpdate_stack_vars {
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
int nArg;
int i;
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
} cp;
struct OP_Trace_stack_vars {
char *zTrace;
char *z;
} cq;
} u;
/* End automatically generated code
********************************************************************/
assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
sqlite3VdbeEnter(p);
if( p->rc==SQLITE_NOMEM ){
|
| ︙ | ︙ | |||
65579 65580 65581 65582 65583 65584 65585 65586 65587 65588 65589 65590 65591 65592 65593 65594 65595 65596 65597 65598 65599 65600 65601 65602 65603 65604 65605 65606 65607 65608 65609 65610 65611 65612 65613 65614 65615 65616 65617 65618 65619 65620 65621 65622 |
sqlite3VdbeMemSetNull(pOut);
}else{
sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
}
break;
}
/* Opcode: If P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is true. The value
** is considered true if it is numeric and non-zero. If the value
** in P1 is NULL then take the jump if P3 is true.
*/
/* Opcode: IfNot P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is False. The value
** is considered true if it has a numeric value of zero. If the value
** in P1 is NULL then take the jump if P3 is true.
*/
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
#if 0 /* local variables moved into u.al */
int c;
#endif /* local variables moved into u.al */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ){
u.al.c = pOp->p3;
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
u.al.c = sqlite3VdbeIntValue(pIn1)!=0;
#else
u.al.c = sqlite3VdbeRealValue(pIn1)!=0.0;
#endif
if( pOp->opcode==OP_IfNot ) u.al.c = !u.al.c;
}
if( u.al.c ){
pc = pOp->p2-1;
}
break;
}
/* Opcode: IsNull P1 P2 * * *
**
** Jump to P2 if the value in register P1 is NULL.
| > > > > > > > > > > > > > > > > > | 65549 65550 65551 65552 65553 65554 65555 65556 65557 65558 65559 65560 65561 65562 65563 65564 65565 65566 65567 65568 65569 65570 65571 65572 65573 65574 65575 65576 65577 65578 65579 65580 65581 65582 65583 65584 65585 65586 65587 65588 65589 65590 65591 65592 65593 65594 65595 65596 65597 65598 65599 65600 65601 65602 65603 65604 65605 65606 65607 65608 65609 |
sqlite3VdbeMemSetNull(pOut);
}else{
sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1));
}
break;
}
/* Opcode: Once P1 P2 * * *
**
** Jump to P2 if the value in register P1 is a not null or zero. If
** the value is NULL or zero, fall through and change the P1 register
** to an integer 1.
**
** When P1 is not used otherwise in a program, this opcode falls through
** once and jumps on all subsequent invocations. It is the equivalent
** of "OP_If P1 P2", followed by "OP_Integer 1 P1".
*/
/* Opcode: If P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is true. The value
** is considered true if it is numeric and non-zero. If the value
** in P1 is NULL then take the jump if P3 is true.
*/
/* Opcode: IfNot P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is False. The value
** is considered true if it has a numeric value of zero. If the value
** in P1 is NULL then take the jump if P3 is true.
*/
case OP_Once: /* jump, in1 */
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
#if 0 /* local variables moved into u.al */
int c;
#endif /* local variables moved into u.al */
pIn1 = &aMem[pOp->p1];
if( pIn1->flags & MEM_Null ){
u.al.c = pOp->p3;
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
u.al.c = sqlite3VdbeIntValue(pIn1)!=0;
#else
u.al.c = sqlite3VdbeRealValue(pIn1)!=0.0;
#endif
if( pOp->opcode==OP_IfNot ) u.al.c = !u.al.c;
}
if( u.al.c ){
pc = pOp->p2-1;
}else if( pOp->opcode==OP_Once ){
assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 );
memAboutToChange(p, pIn1);
pIn1->flags = MEM_Int;
pIn1->u.i = 1;
REGISTER_TRACE(pOp->p1, pIn1);
}
break;
}
/* Opcode: IsNull P1 P2 * * *
**
** Jump to P2 if the value in register P1 is NULL.
|
| ︙ | ︙ | |||
66744 66745 66746 66747 66748 66749 66750 | /* Opcode: OpenAutoindex P1 P2 * P4 * ** ** This opcode works the same as OP_OpenEphemeral. It has a ** different name to distinguish its use. Tables created using ** by this opcode will be used for automatically created transient ** indices in joins. */ | < < < < < < < < | 66731 66732 66733 66734 66735 66736 66737 66738 66739 66740 66741 66742 66743 66744 66745 66746 66747 66748 66749 66750 66751 66752 66753 66754 66755 66756 66757 |
/* Opcode: OpenAutoindex P1 P2 * P4 *
**
** This opcode works the same as OP_OpenEphemeral. It has a
** different name to distinguish its use. Tables created using
** by this opcode will be used for automatically created transient
** indices in joins.
*/
case OP_OpenAutoindex:
case OP_OpenEphemeral: {
#if 0 /* local variables moved into u.ax */
VdbeCursor *pCx;
#endif /* local variables moved into u.ax */
static const int vfsFlags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
SQLITE_OPEN_EXCLUSIVE |
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( u.ax.pCx==0 ) goto no_mem;
u.ax.pCx->nullRow = 1;
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ax.pCx->pBt,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1);
|
| ︙ | ︙ | |||
66798 66799 66800 66801 66802 66803 66804 66805 |
}else{
rc = sqlite3BtreeCursor(u.ax.pCx->pBt, MASTER_ROOT, 1, 0, u.ax.pCx->pCursor);
u.ax.pCx->isTable = 1;
}
}
u.ax.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
u.ax.pCx->isIndex = !u.ax.pCx->isTable;
#ifndef SQLITE_OMIT_MERGE_SORT
| > > > > > > > > > > > > > > > > > | | < > > > | | | | | | | | | 66777 66778 66779 66780 66781 66782 66783 66784 66785 66786 66787 66788 66789 66790 66791 66792 66793 66794 66795 66796 66797 66798 66799 66800 66801 66802 66803 66804 66805 66806 66807 66808 66809 66810 66811 66812 66813 66814 66815 66816 66817 66818 66819 66820 66821 66822 66823 66824 66825 66826 66827 66828 66829 66830 66831 66832 66833 66834 66835 66836 66837 66838 66839 66840 66841 66842 66843 66844 |
}else{
rc = sqlite3BtreeCursor(u.ax.pCx->pBt, MASTER_ROOT, 1, 0, u.ax.pCx->pCursor);
u.ax.pCx->isTable = 1;
}
}
u.ax.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
u.ax.pCx->isIndex = !u.ax.pCx->isTable;
break;
}
/* Opcode: OpenSorter P1 P2 * P4 *
**
** This opcode works like OP_OpenEphemeral except that it opens
** a transient index that is specifically designed to sort large
** tables using an external merge-sort algorithm.
*/
case OP_SorterOpen: {
#if 0 /* local variables moved into u.ay */
VdbeCursor *pCx;
#endif /* local variables moved into u.ay */
#ifndef SQLITE_OMIT_MERGE_SORT
u.ay.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( u.ay.pCx==0 ) goto no_mem;
u.ay.pCx->pKeyInfo = pOp->p4.pKeyInfo;
u.ay.pCx->pKeyInfo->enc = ENC(p->db);
u.ay.pCx->isSorter = 1;
rc = sqlite3VdbeSorterInit(db, u.ay.pCx);
#else
pOp->opcode = OP_OpenEphemeral;
pc--;
#endif
break;
}
/* Opcode: OpenPseudo P1 P2 P3 * *
**
** Open a new cursor that points to a fake table that contains a single
** row of data. The content of that one row in the content of memory
** register P2. In other words, cursor P1 becomes an alias for the
** MEM_Blob content contained in register P2.
**
** A pseudo-table created by this opcode is used to hold a single
** row output from the sorter so that the row can be decomposed into
** individual columns using the OP_Column opcode. The OP_Column opcode
** is the only cursor opcode that works with a pseudo-table.
**
** P3 is the number of fields in the records that will be stored by
** the pseudo-table.
*/
case OP_OpenPseudo: {
#if 0 /* local variables moved into u.az */
VdbeCursor *pCx;
#endif /* local variables moved into u.az */
assert( pOp->p1>=0 );
u.az.pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
if( u.az.pCx==0 ) goto no_mem;
u.az.pCx->nullRow = 1;
u.az.pCx->pseudoTableReg = pOp->p2;
u.az.pCx->isTable = 1;
u.az.pCx->isIndex = 0;
break;
}
/* Opcode: Close P1 * * * *
**
** Close a cursor previously opened as P1. If P1 is not
** currently open, this instruction is a no-op.
|
| ︙ | ︙ | |||
66904 66905 66906 66907 66908 66909 66910 |
**
** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLt: /* jump, in3 */
case OP_SeekLe: /* jump, in3 */
case OP_SeekGe: /* jump, in3 */
case OP_SeekGt: { /* jump, in3 */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 66902 66903 66904 66905 66906 66907 66908 66909 66910 66911 66912 66913 66914 66915 66916 66917 66918 66919 66920 66921 66922 66923 66924 66925 66926 66927 66928 66929 66930 66931 66932 66933 66934 66935 66936 66937 66938 66939 66940 66941 66942 66943 66944 66945 66946 66947 66948 66949 66950 66951 66952 66953 66954 66955 66956 66957 66958 66959 66960 66961 66962 66963 66964 66965 66966 66967 66968 66969 66970 66971 66972 66973 66974 66975 66976 66977 66978 66979 66980 66981 66982 66983 66984 66985 66986 66987 66988 66989 66990 66991 66992 66993 66994 66995 66996 66997 66998 66999 67000 67001 67002 67003 67004 67005 67006 67007 67008 67009 67010 67011 67012 67013 67014 67015 67016 67017 67018 67019 67020 67021 67022 67023 67024 67025 67026 67027 67028 67029 67030 67031 67032 67033 67034 67035 67036 67037 67038 67039 67040 67041 67042 67043 67044 67045 67046 67047 67048 67049 67050 67051 67052 67053 |
**
** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLt: /* jump, in3 */
case OP_SeekLe: /* jump, in3 */
case OP_SeekGe: /* jump, in3 */
case OP_SeekGt: { /* jump, in3 */
#if 0 /* local variables moved into u.ba */
int res;
int oc;
VdbeCursor *pC;
UnpackedRecord r;
int nField;
i64 iKey; /* The rowid we are to seek to */
#endif /* local variables moved into u.ba */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p2!=0 );
u.ba.pC = p->apCsr[pOp->p1];
assert( u.ba.pC!=0 );
assert( u.ba.pC->pseudoTableReg==0 );
assert( OP_SeekLe == OP_SeekLt+1 );
assert( OP_SeekGe == OP_SeekLt+2 );
assert( OP_SeekGt == OP_SeekLt+3 );
assert( u.ba.pC->isOrdered );
if( ALWAYS(u.ba.pC->pCursor!=0) ){
u.ba.oc = pOp->opcode;
u.ba.pC->nullRow = 0;
if( u.ba.pC->isTable ){
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so covert it. */
pIn3 = &aMem[pOp->p3];
applyNumericAffinity(pIn3);
u.ba.iKey = sqlite3VdbeIntValue(pIn3);
u.ba.pC->rowidIsValid = 0;
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
if( (pIn3->flags & MEM_Int)==0 ){
if( (pIn3->flags & MEM_Real)==0 ){
/* If the P3 value cannot be converted into any kind of a number,
** then the seek is not possible, so jump to P2 */
pc = pOp->p2 - 1;
break;
}
/* If we reach this point, then the P3 value must be a floating
** point number. */
assert( (pIn3->flags & MEM_Real)!=0 );
if( u.ba.iKey==SMALLEST_INT64 && (pIn3->r<(double)u.ba.iKey || pIn3->r>0) ){
/* The P3 value is too large in magnitude to be expressed as an
** integer. */
u.ba.res = 1;
if( pIn3->r<0 ){
if( u.ba.oc>=OP_SeekGe ){ assert( u.ba.oc==OP_SeekGe || u.ba.oc==OP_SeekGt );
rc = sqlite3BtreeFirst(u.ba.pC->pCursor, &u.ba.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}else{
if( u.ba.oc<=OP_SeekLe ){ assert( u.ba.oc==OP_SeekLt || u.ba.oc==OP_SeekLe );
rc = sqlite3BtreeLast(u.ba.pC->pCursor, &u.ba.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}
if( u.ba.res ){
pc = pOp->p2 - 1;
}
break;
}else if( u.ba.oc==OP_SeekLt || u.ba.oc==OP_SeekGe ){
/* Use the ceiling() function to convert real->int */
if( pIn3->r > (double)u.ba.iKey ) u.ba.iKey++;
}else{
/* Use the floor() function to convert real->int */
assert( u.ba.oc==OP_SeekLe || u.ba.oc==OP_SeekGt );
if( pIn3->r < (double)u.ba.iKey ) u.ba.iKey--;
}
}
rc = sqlite3BtreeMovetoUnpacked(u.ba.pC->pCursor, 0, (u64)u.ba.iKey, 0, &u.ba.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( u.ba.res==0 ){
u.ba.pC->rowidIsValid = 1;
u.ba.pC->lastRowid = u.ba.iKey;
}
}else{
u.ba.nField = pOp->p4.i;
assert( pOp->p4type==P4_INT32 );
assert( u.ba.nField>0 );
u.ba.r.pKeyInfo = u.ba.pC->pKeyInfo;
u.ba.r.nField = (u16)u.ba.nField;
/* The next line of code computes as follows, only faster:
** if( u.ba.oc==OP_SeekGt || u.ba.oc==OP_SeekLe ){
** u.ba.r.flags = UNPACKED_INCRKEY;
** }else{
** u.ba.r.flags = 0;
** }
*/
u.ba.r.flags = (u16)(UNPACKED_INCRKEY * (1 & (u.ba.oc - OP_SeekLt)));
assert( u.ba.oc!=OP_SeekGt || u.ba.r.flags==UNPACKED_INCRKEY );
assert( u.ba.oc!=OP_SeekLe || u.ba.r.flags==UNPACKED_INCRKEY );
assert( u.ba.oc!=OP_SeekGe || u.ba.r.flags==0 );
assert( u.ba.oc!=OP_SeekLt || u.ba.r.flags==0 );
u.ba.r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<u.ba.r.nField; i++) assert( memIsValid(&u.ba.r.aMem[i]) ); }
#endif
ExpandBlob(u.ba.r.aMem);
rc = sqlite3BtreeMovetoUnpacked(u.ba.pC->pCursor, &u.ba.r, 0, 0, &u.ba.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
u.ba.pC->rowidIsValid = 0;
}
u.ba.pC->deferredMoveto = 0;
u.ba.pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
if( u.ba.oc>=OP_SeekGe ){ assert( u.ba.oc==OP_SeekGe || u.ba.oc==OP_SeekGt );
if( u.ba.res<0 || (u.ba.res==0 && u.ba.oc==OP_SeekGt) ){
rc = sqlite3BtreeNext(u.ba.pC->pCursor, &u.ba.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
u.ba.pC->rowidIsValid = 0;
}else{
u.ba.res = 0;
}
}else{
assert( u.ba.oc==OP_SeekLt || u.ba.oc==OP_SeekLe );
if( u.ba.res>0 || (u.ba.res==0 && u.ba.oc==OP_SeekLt) ){
rc = sqlite3BtreePrevious(u.ba.pC->pCursor, &u.ba.res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
u.ba.pC->rowidIsValid = 0;
}else{
/* u.ba.res might be negative because the table is empty. Check to
** see if this is the case.
*/
u.ba.res = sqlite3BtreeEof(u.ba.pC->pCursor);
}
}
assert( pOp->p2>0 );
if( u.ba.res ){
pc = pOp->p2 - 1;
}
}else{
/* This happens when attempting to open the sqlite3_master table
** for read access returns SQLITE_EMPTY. In this case always
** take the jump (since there are no records in the table).
*/
|
| ︙ | ︙ | |||
67064 67065 67066 67067 67068 67069 67070 |
** for P1 to move so that it points to the rowid given by P2.
**
** This is actually a deferred seek. Nothing actually happens until
** the cursor is used to read a record. That way, if no reads
** occur, no unnecessary I/O happens.
*/
case OP_Seek: { /* in2 */
| | | | | | | | | | | | 67062 67063 67064 67065 67066 67067 67068 67069 67070 67071 67072 67073 67074 67075 67076 67077 67078 67079 67080 67081 67082 67083 67084 67085 67086 67087 67088 67089 |
** for P1 to move so that it points to the rowid given by P2.
**
** This is actually a deferred seek. Nothing actually happens until
** the cursor is used to read a record. That way, if no reads
** occur, no unnecessary I/O happens.
*/
case OP_Seek: { /* in2 */
#if 0 /* local variables moved into u.bb */
VdbeCursor *pC;
#endif /* local variables moved into u.bb */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bb.pC = p->apCsr[pOp->p1];
assert( u.bb.pC!=0 );
if( ALWAYS(u.bb.pC->pCursor!=0) ){
assert( u.bb.pC->isTable );
u.bb.pC->nullRow = 0;
pIn2 = &aMem[pOp->p2];
u.bb.pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
u.bb.pC->rowidIsValid = 0;
u.bb.pC->deferredMoveto = 1;
}
break;
}
/* Opcode: Found P1 P2 P3 P4 *
**
|
| ︙ | ︙ | |||
67109 67110 67111 67112 67113 67114 67115 |
** falls through to the next instruction and P1 is left pointing at the
** matching entry.
**
** See also: Found, NotExists, IsUnique
*/
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
| | > | | | | | | | | | | | | > > > > | < < < < | | | | | | | | | 67107 67108 67109 67110 67111 67112 67113 67114 67115 67116 67117 67118 67119 67120 67121 67122 67123 67124 67125 67126 67127 67128 67129 67130 67131 67132 67133 67134 67135 67136 67137 67138 67139 67140 67141 67142 67143 67144 67145 67146 67147 67148 67149 67150 67151 67152 67153 67154 67155 67156 67157 67158 67159 67160 67161 67162 67163 67164 67165 67166 67167 67168 67169 67170 67171 67172 67173 67174 67175 67176 67177 |
** falls through to the next instruction and P1 is left pointing at the
** matching entry.
**
** See also: Found, NotExists, IsUnique
*/
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
#if 0 /* local variables moved into u.bc */
int alreadyExists;
VdbeCursor *pC;
int res;
char *pFree;
UnpackedRecord *pIdxKey;
UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
#endif /* local variables moved into u.bc */
#ifdef SQLITE_TEST
sqlite3_found_count++;
#endif
u.bc.alreadyExists = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p4type==P4_INT32 );
u.bc.pC = p->apCsr[pOp->p1];
assert( u.bc.pC!=0 );
pIn3 = &aMem[pOp->p3];
if( ALWAYS(u.bc.pC->pCursor!=0) ){
assert( u.bc.pC->isTable==0 );
if( pOp->p4.i>0 ){
u.bc.r.pKeyInfo = u.bc.pC->pKeyInfo;
u.bc.r.nField = (u16)pOp->p4.i;
u.bc.r.aMem = pIn3;
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<u.bc.r.nField; i++) assert( memIsValid(&u.bc.r.aMem[i]) ); }
#endif
u.bc.r.flags = UNPACKED_PREFIX_MATCH;
u.bc.pIdxKey = &u.bc.r;
}else{
u.bc.pIdxKey = sqlite3VdbeAllocUnpackedRecord(
u.bc.pC->pKeyInfo, u.bc.aTempRec, sizeof(u.bc.aTempRec), &u.bc.pFree
);
if( u.bc.pIdxKey==0 ) goto no_mem;
assert( pIn3->flags & MEM_Blob );
assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
sqlite3VdbeRecordUnpack(u.bc.pC->pKeyInfo, pIn3->n, pIn3->z, u.bc.pIdxKey);
u.bc.pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
}
rc = sqlite3BtreeMovetoUnpacked(u.bc.pC->pCursor, u.bc.pIdxKey, 0, 0, &u.bc.res);
if( pOp->p4.i==0 ){
sqlite3DbFree(db, u.bc.pFree);
}
if( rc!=SQLITE_OK ){
break;
}
u.bc.alreadyExists = (u.bc.res==0);
u.bc.pC->deferredMoveto = 0;
u.bc.pC->cacheStatus = CACHE_STALE;
}
if( pOp->opcode==OP_Found ){
if( u.bc.alreadyExists ) pc = pOp->p2 - 1;
}else{
if( !u.bc.alreadyExists ) pc = pOp->p2 - 1;
}
break;
}
/* Opcode: IsUnique P1 P2 P3 P4 *
**
** Cursor P1 is open on an index b-tree - that is to say, a btree which
|
| ︙ | ︙ | |||
67196 67197 67198 67199 67200 67201 67202 |
** to instruction P2. Otherwise, the rowid of the conflicting index
** entry is copied to register P3 and control falls through to the next
** instruction.
**
** See also: NotFound, NotExists, Found
*/
case OP_IsUnique: { /* jump, in3 */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 67195 67196 67197 67198 67199 67200 67201 67202 67203 67204 67205 67206 67207 67208 67209 67210 67211 67212 67213 67214 67215 67216 67217 67218 67219 67220 67221 67222 67223 67224 67225 67226 67227 67228 67229 67230 67231 67232 67233 67234 67235 67236 67237 67238 67239 67240 67241 67242 67243 67244 67245 67246 67247 67248 67249 67250 67251 67252 67253 67254 67255 67256 67257 67258 67259 67260 67261 67262 67263 67264 67265 67266 67267 67268 67269 67270 67271 67272 67273 67274 67275 67276 67277 67278 67279 67280 67281 67282 67283 67284 67285 67286 67287 67288 67289 67290 67291 67292 67293 67294 67295 67296 67297 67298 67299 67300 67301 67302 67303 67304 67305 67306 67307 67308 67309 67310 67311 67312 67313 67314 67315 67316 67317 67318 67319 67320 67321 |
** to instruction P2. Otherwise, the rowid of the conflicting index
** entry is copied to register P3 and control falls through to the next
** instruction.
**
** See also: NotFound, NotExists, Found
*/
case OP_IsUnique: { /* jump, in3 */
#if 0 /* local variables moved into u.bd */
u16 ii;
VdbeCursor *pCx;
BtCursor *pCrsr;
u16 nField;
Mem *aMx;
UnpackedRecord r; /* B-Tree index search key */
i64 R; /* Rowid stored in register P3 */
#endif /* local variables moved into u.bd */
pIn3 = &aMem[pOp->p3];
u.bd.aMx = &aMem[pOp->p4.i];
/* Assert that the values of parameters P1 and P4 are in range. */
assert( pOp->p4type==P4_INT32 );
assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
/* Find the index cursor. */
u.bd.pCx = p->apCsr[pOp->p1];
assert( u.bd.pCx->deferredMoveto==0 );
u.bd.pCx->seekResult = 0;
u.bd.pCx->cacheStatus = CACHE_STALE;
u.bd.pCrsr = u.bd.pCx->pCursor;
/* If any of the values are NULL, take the jump. */
u.bd.nField = u.bd.pCx->pKeyInfo->nField;
for(u.bd.ii=0; u.bd.ii<u.bd.nField; u.bd.ii++){
if( u.bd.aMx[u.bd.ii].flags & MEM_Null ){
pc = pOp->p2 - 1;
u.bd.pCrsr = 0;
break;
}
}
assert( (u.bd.aMx[u.bd.nField].flags & MEM_Null)==0 );
if( u.bd.pCrsr!=0 ){
/* Populate the index search key. */
u.bd.r.pKeyInfo = u.bd.pCx->pKeyInfo;
u.bd.r.nField = u.bd.nField + 1;
u.bd.r.flags = UNPACKED_PREFIX_SEARCH;
u.bd.r.aMem = u.bd.aMx;
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<u.bd.r.nField; i++) assert( memIsValid(&u.bd.r.aMem[i]) ); }
#endif
/* Extract the value of u.bd.R from register P3. */
sqlite3VdbeMemIntegerify(pIn3);
u.bd.R = pIn3->u.i;
/* Search the B-Tree index. If no conflicting record is found, jump
** to P2. Otherwise, copy the rowid of the conflicting record to
** register P3 and fall through to the next instruction. */
rc = sqlite3BtreeMovetoUnpacked(u.bd.pCrsr, &u.bd.r, 0, 0, &u.bd.pCx->seekResult);
if( (u.bd.r.flags & UNPACKED_PREFIX_SEARCH) || u.bd.r.rowid==u.bd.R ){
pc = pOp->p2 - 1;
}else{
pIn3->u.i = u.bd.r.rowid;
}
}
break;
}
/* Opcode: NotExists P1 P2 P3 * *
**
** Use the content of register P3 as an integer key. If a record
** with that key does not exist in table of P1, then jump to P2.
** If the record does exist, then fall through. The cursor is left
** pointing to the record if it exists.
**
** The difference between this operation and NotFound is that this
** operation assumes the key is an integer and that P1 is a table whereas
** NotFound assumes key is a blob constructed from MakeRecord and
** P1 is an index.
**
** See also: Found, NotFound, IsUnique
*/
case OP_NotExists: { /* jump, in3 */
#if 0 /* local variables moved into u.be */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
#endif /* local variables moved into u.be */
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.be.pC = p->apCsr[pOp->p1];
assert( u.be.pC!=0 );
assert( u.be.pC->isTable );
assert( u.be.pC->pseudoTableReg==0 );
u.be.pCrsr = u.be.pC->pCursor;
if( ALWAYS(u.be.pCrsr!=0) ){
u.be.res = 0;
u.be.iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(u.be.pCrsr, 0, u.be.iKey, 0, &u.be.res);
u.be.pC->lastRowid = pIn3->u.i;
u.be.pC->rowidIsValid = u.be.res==0 ?1:0;
u.be.pC->nullRow = 0;
u.be.pC->cacheStatus = CACHE_STALE;
u.be.pC->deferredMoveto = 0;
if( u.be.res!=0 ){
pc = pOp->p2 - 1;
assert( u.be.pC->rowidIsValid==0 );
}
u.be.pC->seekResult = u.be.res;
}else{
/* This happens when an attempt to open a read cursor on the
** sqlite_master table returns SQLITE_EMPTY.
*/
pc = pOp->p2 - 1;
assert( u.be.pC->rowidIsValid==0 );
u.be.pC->seekResult = 0;
}
break;
}
/* Opcode: Sequence P1 P2 * * *
**
** Find the next available sequence number for cursor P1.
|
| ︙ | ︙ | |||
67343 67344 67345 67346 67347 67348 67349 |
** the largest previously generated record number. No new record numbers are
** allowed to be less than this value. When this value reaches its maximum,
** an SQLITE_FULL error is generated. The P3 register is updated with the '
** generated record number. This P3 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
case OP_NewRowid: { /* out2-prerelease */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 67342 67343 67344 67345 67346 67347 67348 67349 67350 67351 67352 67353 67354 67355 67356 67357 67358 67359 67360 67361 67362 67363 67364 67365 67366 67367 67368 67369 67370 67371 67372 67373 67374 67375 67376 67377 67378 67379 67380 67381 67382 67383 67384 67385 67386 67387 67388 67389 67390 67391 67392 67393 67394 67395 67396 67397 67398 67399 67400 67401 67402 67403 67404 67405 67406 67407 67408 67409 67410 67411 67412 67413 67414 67415 67416 67417 67418 67419 67420 67421 67422 67423 67424 67425 67426 67427 67428 67429 67430 67431 67432 67433 67434 67435 67436 67437 67438 67439 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 67477 67478 67479 67480 67481 67482 67483 67484 67485 67486 67487 67488 |
** the largest previously generated record number. No new record numbers are
** allowed to be less than this value. When this value reaches its maximum,
** an SQLITE_FULL error is generated. The P3 register is updated with the '
** generated record number. This P3 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
case OP_NewRowid: { /* out2-prerelease */
#if 0 /* local variables moved into u.bf */
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
int res; /* Result of an sqlite3BtreeLast() */
int cnt; /* Counter to limit the number of searches */
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
VdbeFrame *pFrame; /* Root frame of VDBE */
#endif /* local variables moved into u.bf */
u.bf.v = 0;
u.bf.res = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bf.pC = p->apCsr[pOp->p1];
assert( u.bf.pC!=0 );
if( NEVER(u.bf.pC->pCursor==0) ){
/* The zero initialization above is all that is needed */
}else{
/* The next rowid or record number (different terms for the same
** thing) is obtained in a two-step algorithm.
**
** First we attempt to find the largest existing rowid and add one
** to that. But if the largest existing rowid is already the maximum
** positive integer, we have to fall through to the second
** probabilistic algorithm
**
** The second algorithm is to select a rowid at random and see if
** it already exists in the table. If it does not exist, we have
** succeeded. If the random rowid does exist, we select a new one
** and try again, up to 100 times.
*/
assert( u.bf.pC->isTable );
#ifdef SQLITE_32BIT_ROWID
# define MAX_ROWID 0x7fffffff
#else
/* Some compilers complain about constants of the form 0x7fffffffffffffff.
** Others complain about 0x7ffffffffffffffffLL. The following macro seems
** to provide the constant while making all compilers happy.
*/
# define MAX_ROWID (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff )
#endif
if( !u.bf.pC->useRandomRowid ){
u.bf.v = sqlite3BtreeGetCachedRowid(u.bf.pC->pCursor);
if( u.bf.v==0 ){
rc = sqlite3BtreeLast(u.bf.pC->pCursor, &u.bf.res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( u.bf.res ){
u.bf.v = 1; /* IMP: R-61914-48074 */
}else{
assert( sqlite3BtreeCursorIsValid(u.bf.pC->pCursor) );
rc = sqlite3BtreeKeySize(u.bf.pC->pCursor, &u.bf.v);
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
if( u.bf.v==MAX_ROWID ){
u.bf.pC->useRandomRowid = 1;
}else{
u.bf.v++; /* IMP: R-29538-34987 */
}
}
}
#ifndef SQLITE_OMIT_AUTOINCREMENT
if( pOp->p3 ){
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3>0 );
if( p->pFrame ){
for(u.bf.pFrame=p->pFrame; u.bf.pFrame->pParent; u.bf.pFrame=u.bf.pFrame->pParent);
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3<=u.bf.pFrame->nMem );
u.bf.pMem = &u.bf.pFrame->aMem[pOp->p3];
}else{
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3<=p->nMem );
u.bf.pMem = &aMem[pOp->p3];
memAboutToChange(p, u.bf.pMem);
}
assert( memIsValid(u.bf.pMem) );
REGISTER_TRACE(pOp->p3, u.bf.pMem);
sqlite3VdbeMemIntegerify(u.bf.pMem);
assert( (u.bf.pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
if( u.bf.pMem->u.i==MAX_ROWID || u.bf.pC->useRandomRowid ){
rc = SQLITE_FULL; /* IMP: R-12275-61338 */
goto abort_due_to_error;
}
if( u.bf.v<u.bf.pMem->u.i+1 ){
u.bf.v = u.bf.pMem->u.i + 1;
}
u.bf.pMem->u.i = u.bf.v;
}
#endif
sqlite3BtreeSetCachedRowid(u.bf.pC->pCursor, u.bf.v<MAX_ROWID ? u.bf.v+1 : 0);
}
if( u.bf.pC->useRandomRowid ){
/* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the
** largest possible integer (9223372036854775807) then the database
** engine starts picking positive candidate ROWIDs at random until
** it finds one that is not previously used. */
assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is
** an AUTOINCREMENT table. */
/* on the first attempt, simply do one more than previous */
u.bf.v = lastRowid;
u.bf.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
u.bf.v++; /* ensure non-zero */
u.bf.cnt = 0;
while( ((rc = sqlite3BtreeMovetoUnpacked(u.bf.pC->pCursor, 0, (u64)u.bf.v,
0, &u.bf.res))==SQLITE_OK)
&& (u.bf.res==0)
&& (++u.bf.cnt<100)){
/* collision - try another random rowid */
sqlite3_randomness(sizeof(u.bf.v), &u.bf.v);
if( u.bf.cnt<5 ){
/* try "small" random rowids for the initial attempts */
u.bf.v &= 0xffffff;
}else{
u.bf.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
}
u.bf.v++; /* ensure non-zero */
}
if( rc==SQLITE_OK && u.bf.res==0 ){
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
goto abort_due_to_error;
}
assert( u.bf.v>0 ); /* EV: R-40812-03570 */
}
u.bf.pC->rowidIsValid = 0;
u.bf.pC->deferredMoveto = 0;
u.bf.pC->cacheStatus = CACHE_STALE;
}
pOut->u.i = u.bf.v;
break;
}
/* Opcode: Insert P1 P2 P3 P4 P5
**
** Write an entry into the table of cursor P1. A new entry is
** created if it doesn't already exist or the data for an existing
|
| ︙ | ︙ | |||
67525 67526 67527 67528 67529 67530 67531 |
/* Opcode: InsertInt P1 P2 P3 P4 P5
**
** This works exactly like OP_Insert except that the key is the
** integer value P3, not the value of the integer stored in register P3.
*/
case OP_Insert:
case OP_InsertInt: {
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 67524 67525 67526 67527 67528 67529 67530 67531 67532 67533 67534 67535 67536 67537 67538 67539 67540 67541 67542 67543 67544 67545 67546 67547 67548 67549 67550 67551 67552 67553 67554 67555 67556 67557 67558 67559 67560 67561 67562 67563 67564 67565 67566 67567 67568 67569 67570 67571 67572 67573 67574 67575 67576 67577 67578 67579 67580 67581 67582 67583 67584 67585 67586 67587 67588 67589 67590 67591 67592 67593 67594 67595 67596 67597 67598 67599 67600 67601 |
/* Opcode: InsertInt P1 P2 P3 P4 P5
**
** This works exactly like OP_Insert except that the key is the
** integer value P3, not the value of the integer stored in register P3.
*/
case OP_Insert:
case OP_InsertInt: {
#if 0 /* local variables moved into u.bg */
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
i64 iKey; /* The integer ROWID or key for the record to be inserted */
VdbeCursor *pC; /* Cursor to table into which insert is written */
int nZero; /* Number of zero-bytes to append */
int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */
const char *zDb; /* database name - used by the update hook */
const char *zTbl; /* Table name - used by the opdate hook */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
#endif /* local variables moved into u.bg */
u.bg.pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( memIsValid(u.bg.pData) );
u.bg.pC = p->apCsr[pOp->p1];
assert( u.bg.pC!=0 );
assert( u.bg.pC->pCursor!=0 );
assert( u.bg.pC->pseudoTableReg==0 );
assert( u.bg.pC->isTable );
REGISTER_TRACE(pOp->p2, u.bg.pData);
if( pOp->opcode==OP_Insert ){
u.bg.pKey = &aMem[pOp->p3];
assert( u.bg.pKey->flags & MEM_Int );
assert( memIsValid(u.bg.pKey) );
REGISTER_TRACE(pOp->p3, u.bg.pKey);
u.bg.iKey = u.bg.pKey->u.i;
}else{
assert( pOp->opcode==OP_InsertInt );
u.bg.iKey = pOp->p3;
}
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bg.iKey;
if( u.bg.pData->flags & MEM_Null ){
u.bg.pData->z = 0;
u.bg.pData->n = 0;
}else{
assert( u.bg.pData->flags & (MEM_Blob|MEM_Str) );
}
u.bg.seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bg.pC->seekResult : 0);
if( u.bg.pData->flags & MEM_Zero ){
u.bg.nZero = u.bg.pData->u.nZero;
}else{
u.bg.nZero = 0;
}
sqlite3BtreeSetCachedRowid(u.bg.pC->pCursor, 0);
rc = sqlite3BtreeInsert(u.bg.pC->pCursor, 0, u.bg.iKey,
u.bg.pData->z, u.bg.pData->n, u.bg.nZero,
pOp->p5 & OPFLAG_APPEND, u.bg.seekResult
);
u.bg.pC->rowidIsValid = 0;
u.bg.pC->deferredMoveto = 0;
u.bg.pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
u.bg.zDb = db->aDb[u.bg.pC->iDb].zName;
u.bg.zTbl = pOp->p4.z;
u.bg.op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
assert( u.bg.pC->isTable );
db->xUpdateCallback(db->pUpdateArg, u.bg.op, u.bg.zDb, u.bg.zTbl, u.bg.iKey);
assert( u.bg.pC->iDb>=0 );
}
break;
}
/* Opcode: Delete P1 P2 * P4 *
**
** Delete the record at which the P1 cursor is currently pointing.
|
| ︙ | ︙ | |||
67614 67615 67616 67617 67618 67619 67620 |
**
** If P4 is not NULL, then it is the name of the table that P1 is
** pointing to. The update hook will be invoked, if it exists.
** If P4 is not NULL then the P1 cursor must have been positioned
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
| | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 67613 67614 67615 67616 67617 67618 67619 67620 67621 67622 67623 67624 67625 67626 67627 67628 67629 67630 67631 67632 67633 67634 67635 67636 67637 67638 67639 67640 67641 67642 67643 67644 67645 67646 67647 67648 67649 67650 67651 67652 67653 67654 67655 67656 67657 67658 67659 67660 67661 67662 67663 67664 67665 67666 67667 67668 67669 67670 67671 67672 67673 67674 67675 67676 67677 67678 67679 67680 67681 67682 67683 67684 67685 67686 67687 67688 67689 67690 67691 67692 67693 67694 67695 67696 67697 67698 67699 67700 67701 67702 67703 67704 67705 67706 67707 67708 67709 67710 67711 67712 67713 67714 67715 67716 67717 67718 67719 67720 67721 67722 67723 67724 67725 67726 |
**
** If P4 is not NULL, then it is the name of the table that P1 is
** pointing to. The update hook will be invoked, if it exists.
** If P4 is not NULL then the P1 cursor must have been positioned
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
#if 0 /* local variables moved into u.bh */
i64 iKey;
VdbeCursor *pC;
#endif /* local variables moved into u.bh */
u.bh.iKey = 0;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bh.pC = p->apCsr[pOp->p1];
assert( u.bh.pC!=0 );
assert( u.bh.pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
/* If the update-hook will be invoked, set u.bh.iKey to the rowid of the
** row being deleted.
*/
if( db->xUpdateCallback && pOp->p4.z ){
assert( u.bh.pC->isTable );
assert( u.bh.pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
u.bh.iKey = u.bh.pC->lastRowid;
}
/* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
** OP_Column on the same table without any intervening operations that
** might move or invalidate the cursor. Hence cursor u.bh.pC is always pointing
** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
** below is always a no-op and cannot fail. We will run it anyhow, though,
** to guard against future changes to the code generator.
**/
assert( u.bh.pC->deferredMoveto==0 );
rc = sqlite3VdbeCursorMoveto(u.bh.pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
sqlite3BtreeSetCachedRowid(u.bh.pC->pCursor, 0);
rc = sqlite3BtreeDelete(u.bh.pC->pCursor);
u.bh.pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
const char *zDb = db->aDb[u.bh.pC->iDb].zName;
const char *zTbl = pOp->p4.z;
db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, u.bh.iKey);
assert( u.bh.pC->iDb>=0 );
}
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
break;
}
/* Opcode: ResetCount * * * * *
**
** The value of the change counter is copied to the database handle
** change counter (returned by subsequent calls to sqlite3_changes()).
** Then the VMs internal change counter resets to 0.
** This is used by trigger programs.
*/
case OP_ResetCount: {
sqlite3VdbeSetChanges(db, p->nChange);
p->nChange = 0;
break;
}
/* Opcode: SorterCompare P1 P2 P3
**
** P1 is a sorter cursor. This instruction compares the record blob in
** register P3 with the entry that the sorter cursor currently points to.
** If, excluding the rowid fields at the end, the two records are a match,
** fall through to the next instruction. Otherwise, jump to instruction P2.
*/
case OP_SorterCompare: {
#if 0 /* local variables moved into u.bi */
VdbeCursor *pC;
int res;
#endif /* local variables moved into u.bi */
u.bi.pC = p->apCsr[pOp->p1];
assert( isSorter(u.bi.pC) );
pIn3 = &aMem[pOp->p3];
rc = sqlite3VdbeSorterCompare(u.bi.pC, pIn3, &u.bi.res);
if( u.bi.res ){
pc = pOp->p2-1;
}
break;
};
/* Opcode: SorterData P1 P2 * * *
**
** Write into register P2 the current sorter data for sorter cursor P1.
*/
case OP_SorterData: {
#if 0 /* local variables moved into u.bj */
VdbeCursor *pC;
#endif /* local variables moved into u.bj */
#ifndef SQLITE_OMIT_MERGE_SORT
pOut = &aMem[pOp->p2];
u.bj.pC = p->apCsr[pOp->p1];
assert( u.bj.pC->isSorter );
rc = sqlite3VdbeSorterRowkey(u.bj.pC, pOut);
#else
pOp->opcode = OP_RowKey;
pc--;
#endif
break;
}
/* Opcode: RowData P1 P2 * * *
**
** Write into register P2 the complete row data for cursor P1.
** There is no interpretation of the data.
** It is just copied onto the P2 register exactly as
** it is found in the database file.
|
| ︙ | ︙ | |||
67694 67695 67696 67697 67698 67699 67700 |
** it is found in the database file.
**
** If the P1 cursor must be pointing to a valid row (not a NULL row)
** of a real table, not a pseudo-table.
*/
case OP_RowKey:
case OP_RowData: {
| | | | > | | | | | | < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | | | | > | | | | | | | | | | | | | 67736 67737 67738 67739 67740 67741 67742 67743 67744 67745 67746 67747 67748 67749 67750 67751 67752 67753 67754 67755 67756 67757 67758 67759 67760 67761 67762 67763 67764 67765 67766 67767 67768 67769 67770 67771 67772 67773 67774 67775 67776 67777 67778 67779 67780 67781 67782 67783 67784 67785 67786 67787 67788 67789 67790 67791 67792 67793 67794 67795 67796 67797 67798 67799 67800 67801 67802 67803 67804 67805 67806 67807 67808 67809 67810 67811 67812 67813 67814 67815 67816 67817 67818 67819 67820 67821 67822 67823 67824 67825 67826 67827 67828 67829 67830 67831 67832 67833 67834 67835 67836 67837 67838 67839 67840 67841 67842 67843 67844 67845 67846 67847 67848 67849 67850 67851 67852 67853 67854 67855 67856 67857 67858 67859 67860 67861 67862 67863 67864 67865 67866 67867 67868 67869 67870 67871 67872 67873 67874 67875 67876 67877 67878 67879 67880 67881 67882 67883 67884 67885 67886 67887 67888 67889 67890 67891 67892 67893 67894 67895 67896 67897 67898 67899 67900 67901 67902 67903 67904 67905 67906 67907 67908 67909 67910 67911 67912 67913 67914 67915 67916 67917 67918 67919 67920 67921 67922 67923 67924 67925 67926 67927 67928 67929 67930 67931 67932 67933 67934 67935 67936 67937 67938 67939 67940 67941 67942 67943 67944 67945 67946 67947 67948 67949 67950 67951 67952 67953 67954 67955 67956 67957 67958 67959 67960 67961 67962 67963 67964 67965 67966 67967 67968 67969 67970 67971 67972 67973 67974 67975 67976 67977 |
** it is found in the database file.
**
** If the P1 cursor must be pointing to a valid row (not a NULL row)
** of a real table, not a pseudo-table.
*/
case OP_RowKey:
case OP_RowData: {
#if 0 /* local variables moved into u.bk */
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
i64 n64;
#endif /* local variables moved into u.bk */
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
/* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bk.pC = p->apCsr[pOp->p1];
assert( u.bk.pC->isSorter==0 );
assert( u.bk.pC->isTable || pOp->opcode!=OP_RowData );
assert( u.bk.pC->isIndex || pOp->opcode==OP_RowData );
assert( u.bk.pC!=0 );
assert( u.bk.pC->nullRow==0 );
assert( u.bk.pC->pseudoTableReg==0 );
assert( !u.bk.pC->isSorter );
assert( u.bk.pC->pCursor!=0 );
u.bk.pCrsr = u.bk.pC->pCursor;
assert( sqlite3BtreeCursorIsValid(u.bk.pCrsr) );
/* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
** OP_Rewind/Op_Next with no intervening instructions that might invalidate
** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always
** a no-op and can never fail. But we leave it in place as a safety.
*/
assert( u.bk.pC->deferredMoveto==0 );
rc = sqlite3VdbeCursorMoveto(u.bk.pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
if( u.bk.pC->isIndex ){
assert( !u.bk.pC->isTable );
rc = sqlite3BtreeKeySize(u.bk.pCrsr, &u.bk.n64);
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
if( u.bk.n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
u.bk.n = (u32)u.bk.n64;
}else{
rc = sqlite3BtreeDataSize(u.bk.pCrsr, &u.bk.n);
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
if( u.bk.n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
}
if( sqlite3VdbeMemGrow(pOut, u.bk.n, 0) ){
goto no_mem;
}
pOut->n = u.bk.n;
MemSetTypeFlag(pOut, MEM_Blob);
if( u.bk.pC->isIndex ){
rc = sqlite3BtreeKey(u.bk.pCrsr, 0, u.bk.n, pOut->z);
}else{
rc = sqlite3BtreeData(u.bk.pCrsr, 0, u.bk.n, pOut->z);
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
/* Opcode: Rowid P1 P2 * * *
**
** Store in register P2 an integer which is the key of the table entry that
** P1 is currently point to.
**
** P1 can be either an ordinary table or a virtual table. There used to
** be a separate OP_VRowid opcode for use with virtual tables, but this
** one opcode now works for both table types.
*/
case OP_Rowid: { /* out2-prerelease */
#if 0 /* local variables moved into u.bl */
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
#endif /* local variables moved into u.bl */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bl.pC = p->apCsr[pOp->p1];
assert( u.bl.pC!=0 );
assert( u.bl.pC->pseudoTableReg==0 );
if( u.bl.pC->nullRow ){
pOut->flags = MEM_Null;
break;
}else if( u.bl.pC->deferredMoveto ){
u.bl.v = u.bl.pC->movetoTarget;
#ifndef SQLITE_OMIT_VIRTUALTABLE
}else if( u.bl.pC->pVtabCursor ){
u.bl.pVtab = u.bl.pC->pVtabCursor->pVtab;
u.bl.pModule = u.bl.pVtab->pModule;
assert( u.bl.pModule->xRowid );
rc = u.bl.pModule->xRowid(u.bl.pC->pVtabCursor, &u.bl.v);
importVtabErrMsg(p, u.bl.pVtab);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{
assert( u.bl.pC->pCursor!=0 );
rc = sqlite3VdbeCursorMoveto(u.bl.pC);
if( rc ) goto abort_due_to_error;
if( u.bl.pC->rowidIsValid ){
u.bl.v = u.bl.pC->lastRowid;
}else{
rc = sqlite3BtreeKeySize(u.bl.pC->pCursor, &u.bl.v);
assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */
}
}
pOut->u.i = u.bl.v;
break;
}
/* Opcode: NullRow P1 * * * *
**
** Move the cursor P1 to a null row. Any OP_Column operations
** that occur while the cursor is on the null row will always
** write a NULL.
*/
case OP_NullRow: {
#if 0 /* local variables moved into u.bm */
VdbeCursor *pC;
#endif /* local variables moved into u.bm */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bm.pC = p->apCsr[pOp->p1];
assert( u.bm.pC!=0 );
u.bm.pC->nullRow = 1;
u.bm.pC->rowidIsValid = 0;
assert( u.bm.pC->pCursor || u.bm.pC->pVtabCursor );
if( u.bm.pC->pCursor ){
sqlite3BtreeClearCursor(u.bm.pC->pCursor);
}
break;
}
/* Opcode: Last P1 P2 * * *
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the last entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Last: { /* jump */
#if 0 /* local variables moved into u.bn */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
#endif /* local variables moved into u.bn */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bn.pC = p->apCsr[pOp->p1];
assert( u.bn.pC!=0 );
u.bn.pCrsr = u.bn.pC->pCursor;
if( NEVER(u.bn.pCrsr==0) ){
u.bn.res = 1;
}else{
rc = sqlite3BtreeLast(u.bn.pCrsr, &u.bn.res);
}
u.bn.pC->nullRow = (u8)u.bn.res;
u.bn.pC->deferredMoveto = 0;
u.bn.pC->rowidIsValid = 0;
u.bn.pC->cacheStatus = CACHE_STALE;
if( pOp->p2>0 && u.bn.res ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: Sort P1 P2 * * *
**
** This opcode does exactly the same thing as OP_Rewind except that
** it increments an undocumented global variable used for testing.
**
** Sorting is accomplished by writing records into a sorting index,
** then rewinding that index and playing it back from beginning to
** end. We use the OP_Sort opcode instead of OP_Rewind to do the
** rewinding so that the global variable will be incremented and
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
case OP_SorterSort: /* jump */
#ifdef SQLITE_OMIT_MERGE_SORT
pOp->opcode = OP_Sort;
#endif
case OP_Sort: { /* jump */
#ifdef SQLITE_TEST
sqlite3_sort_count++;
sqlite3_search_count--;
#endif
p->aCounter[SQLITE_STMTSTATUS_SORT-1]++;
/* Fall through into OP_Rewind */
}
/* Opcode: Rewind P1 P2 * * *
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Rewind: { /* jump */
#if 0 /* local variables moved into u.bo */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
#endif /* local variables moved into u.bo */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bo.pC = p->apCsr[pOp->p1];
assert( u.bo.pC!=0 );
assert( u.bo.pC->isSorter==(pOp->opcode==OP_SorterSort) );
u.bo.res = 1;
if( isSorter(u.bo.pC) ){
rc = sqlite3VdbeSorterRewind(db, u.bo.pC, &u.bo.res);
}else{
u.bo.pCrsr = u.bo.pC->pCursor;
assert( u.bo.pCrsr );
rc = sqlite3BtreeFirst(u.bo.pCrsr, &u.bo.res);
u.bo.pC->atFirst = u.bo.res==0 ?1:0;
u.bo.pC->deferredMoveto = 0;
u.bo.pC->cacheStatus = CACHE_STALE;
u.bo.pC->rowidIsValid = 0;
}
u.bo.pC->nullRow = (u8)u.bo.res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
if( u.bo.res ){
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: Next P1 P2 * P4 P5
**
|
| ︙ | ︙ | |||
67959 67960 67961 67962 67963 67964 67965 67966 67967 |
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreePrevious().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
case OP_Prev: /* jump */
case OP_Next: { /* jump */
| > > > > | | | | > | | | | | | | | | | | > > > > | | | | > | | | > > > | | < < | | | | > < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68001 68002 68003 68004 68005 68006 68007 68008 68009 68010 68011 68012 68013 68014 68015 68016 68017 68018 68019 68020 68021 68022 68023 68024 68025 68026 68027 68028 68029 68030 68031 68032 68033 68034 68035 68036 68037 68038 68039 68040 68041 68042 68043 68044 68045 68046 68047 68048 68049 68050 68051 68052 68053 68054 68055 68056 68057 68058 68059 68060 68061 68062 68063 68064 68065 68066 68067 68068 68069 68070 68071 68072 68073 68074 68075 68076 68077 68078 68079 68080 68081 68082 68083 68084 68085 68086 68087 68088 68089 68090 68091 68092 68093 68094 68095 68096 68097 68098 68099 68100 68101 68102 68103 68104 68105 68106 68107 68108 68109 68110 68111 68112 68113 68114 68115 68116 68117 68118 68119 68120 68121 68122 68123 68124 68125 68126 68127 68128 68129 68130 68131 68132 68133 68134 68135 68136 68137 68138 68139 68140 68141 68142 68143 68144 68145 68146 68147 68148 68149 68150 68151 68152 68153 68154 68155 68156 68157 68158 68159 68160 68161 68162 68163 68164 68165 68166 68167 68168 68169 68170 68171 68172 68173 68174 68175 68176 68177 |
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreePrevious().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
case OP_SorterNext: /* jump */
#ifdef SQLITE_OMIT_MERGE_SORT
pOp->opcode = OP_Next;
#endif
case OP_Prev: /* jump */
case OP_Next: { /* jump */
#if 0 /* local variables moved into u.bp */
VdbeCursor *pC;
int res;
#endif /* local variables moved into u.bp */
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<=ArraySize(p->aCounter) );
u.bp.pC = p->apCsr[pOp->p1];
if( u.bp.pC==0 ){
break; /* See ticket #2273 */
}
assert( u.bp.pC->isSorter==(pOp->opcode==OP_SorterNext) );
if( isSorter(u.bp.pC) ){
assert( pOp->opcode==OP_SorterNext );
rc = sqlite3VdbeSorterNext(db, u.bp.pC, &u.bp.res);
}else{
u.bp.res = 1;
assert( u.bp.pC->deferredMoveto==0 );
assert( u.bp.pC->pCursor );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
rc = pOp->p4.xAdvance(u.bp.pC->pCursor, &u.bp.res);
}
u.bp.pC->nullRow = (u8)u.bp.res;
u.bp.pC->cacheStatus = CACHE_STALE;
if( u.bp.res==0 ){
pc = pOp->p2 - 1;
if( pOp->p5 ) p->aCounter[pOp->p5-1]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
}
u.bp.pC->rowidIsValid = 0;
break;
}
/* Opcode: IdxInsert P1 P2 P3 * P5
**
** Register P2 holds an SQL index key made using the
** MakeRecord instructions. This opcode writes that key
** into the index P1. Data for the entry is nil.
**
** P3 is a flag that provides a hint to the b-tree layer that this
** insert is likely to be an append.
**
** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert.
*/
case OP_SorterInsert: /* in2 */
#ifdef SQLITE_OMIT_MERGE_SORT
pOp->opcode = OP_IdxInsert;
#endif
case OP_IdxInsert: { /* in2 */
#if 0 /* local variables moved into u.bq */
VdbeCursor *pC;
BtCursor *pCrsr;
int nKey;
const char *zKey;
#endif /* local variables moved into u.bq */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bq.pC = p->apCsr[pOp->p1];
assert( u.bq.pC!=0 );
assert( u.bq.pC->isSorter==(pOp->opcode==OP_SorterInsert) );
pIn2 = &aMem[pOp->p2];
assert( pIn2->flags & MEM_Blob );
u.bq.pCrsr = u.bq.pC->pCursor;
if( ALWAYS(u.bq.pCrsr!=0) ){
assert( u.bq.pC->isTable==0 );
rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){
if( isSorter(u.bq.pC) ){
rc = sqlite3VdbeSorterWrite(db, u.bq.pC, pIn2);
}else{
u.bq.nKey = pIn2->n;
u.bq.zKey = pIn2->z;
rc = sqlite3BtreeInsert(u.bq.pCrsr, u.bq.zKey, u.bq.nKey, "", 0, 0, pOp->p3,
((pOp->p5 & OPFLAG_USESEEKRESULT) ? u.bq.pC->seekResult : 0)
);
assert( u.bq.pC->deferredMoveto==0 );
u.bq.pC->cacheStatus = CACHE_STALE;
}
}
}
break;
}
/* Opcode: IdxDelete P1 P2 P3 * *
**
** The content of P3 registers starting at register P2 form
** an unpacked index key. This opcode removes that entry from the
** index opened by cursor P1.
*/
case OP_IdxDelete: {
#if 0 /* local variables moved into u.br */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
UnpackedRecord r;
#endif /* local variables moved into u.br */
assert( pOp->p3>0 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.br.pC = p->apCsr[pOp->p1];
assert( u.br.pC!=0 );
u.br.pCrsr = u.br.pC->pCursor;
if( ALWAYS(u.br.pCrsr!=0) ){
u.br.r.pKeyInfo = u.br.pC->pKeyInfo;
u.br.r.nField = (u16)pOp->p3;
u.br.r.flags = 0;
u.br.r.aMem = &aMem[pOp->p2];
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<u.br.r.nField; i++) assert( memIsValid(&u.br.r.aMem[i]) ); }
#endif
rc = sqlite3BtreeMovetoUnpacked(u.br.pCrsr, &u.br.r, 0, 0, &u.br.res);
if( rc==SQLITE_OK && u.br.res==0 ){
rc = sqlite3BtreeDelete(u.br.pCrsr);
}
assert( u.br.pC->deferredMoveto==0 );
u.br.pC->cacheStatus = CACHE_STALE;
}
break;
}
/* Opcode: IdxRowid P1 P2 * * *
**
** Write into register P2 an integer which is the last entry in the record at
** the end of the index key pointed to by cursor P1. This integer should be
** the rowid of the table entry to which this index entry points.
**
** See also: Rowid, MakeRecord.
*/
case OP_IdxRowid: { /* out2-prerelease */
#if 0 /* local variables moved into u.bs */
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
#endif /* local variables moved into u.bs */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bs.pC = p->apCsr[pOp->p1];
assert( u.bs.pC!=0 );
u.bs.pCrsr = u.bs.pC->pCursor;
pOut->flags = MEM_Null;
if( ALWAYS(u.bs.pCrsr!=0) ){
rc = sqlite3VdbeCursorMoveto(u.bs.pC);
if( NEVER(rc) ) goto abort_due_to_error;
assert( u.bs.pC->deferredMoveto==0 );
assert( u.bs.pC->isTable==0 );
if( !u.bs.pC->nullRow ){
rc = sqlite3VdbeIdxRowid(db, u.bs.pCrsr, &u.bs.rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
pOut->u.i = u.bs.rowid;
pOut->flags = MEM_Int;
}
}
break;
}
/* Opcode: IdxGE P1 P2 P3 P4 P5
|
| ︙ | ︙ | |||
68145 68146 68147 68148 68149 68150 68151 |
** Otherwise fall through to the next instruction.
**
** If P5 is non-zero then the key value is increased by an epsilon prior
** to the comparison. This makes the opcode work like IdxLE.
*/
case OP_IdxLT: /* jump */
case OP_IdxGE: { /* jump */
| | | | | | | | | | | | | | | | | | | 68198 68199 68200 68201 68202 68203 68204 68205 68206 68207 68208 68209 68210 68211 68212 68213 68214 68215 68216 68217 68218 68219 68220 68221 68222 68223 68224 68225 68226 68227 68228 68229 68230 68231 68232 68233 68234 68235 68236 68237 68238 68239 68240 68241 68242 68243 68244 |
** Otherwise fall through to the next instruction.
**
** If P5 is non-zero then the key value is increased by an epsilon prior
** to the comparison. This makes the opcode work like IdxLE.
*/
case OP_IdxLT: /* jump */
case OP_IdxGE: { /* jump */
#if 0 /* local variables moved into u.bt */
VdbeCursor *pC;
int res;
UnpackedRecord r;
#endif /* local variables moved into u.bt */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bt.pC = p->apCsr[pOp->p1];
assert( u.bt.pC!=0 );
assert( u.bt.pC->isOrdered );
if( ALWAYS(u.bt.pC->pCursor!=0) ){
assert( u.bt.pC->deferredMoveto==0 );
assert( pOp->p5==0 || pOp->p5==1 );
assert( pOp->p4type==P4_INT32 );
u.bt.r.pKeyInfo = u.bt.pC->pKeyInfo;
u.bt.r.nField = (u16)pOp->p4.i;
if( pOp->p5 ){
u.bt.r.flags = UNPACKED_INCRKEY | UNPACKED_IGNORE_ROWID;
}else{
u.bt.r.flags = UNPACKED_IGNORE_ROWID;
}
u.bt.r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<u.bt.r.nField; i++) assert( memIsValid(&u.bt.r.aMem[i]) ); }
#endif
rc = sqlite3VdbeIdxKeyCompare(u.bt.pC, &u.bt.r, &u.bt.res);
if( pOp->opcode==OP_IdxLT ){
u.bt.res = -u.bt.res;
}else{
assert( pOp->opcode==OP_IdxGE );
u.bt.res++;
}
if( u.bt.res>0 ){
pc = pOp->p2 - 1 ;
}
}
break;
}
/* Opcode: Destroy P1 P2 P3 * *
|
| ︙ | ︙ | |||
68205 68206 68207 68208 68209 68210 68211 |
** movement was required (because the table being dropped was already
** the last one in the database) then a zero is stored in register P2.
** If AUTOVACUUM is disabled then a zero is stored in register P2.
**
** See also: Clear
*/
case OP_Destroy: { /* out2-prerelease */
| | | | | | | | | | | | | | | | | | | 68258 68259 68260 68261 68262 68263 68264 68265 68266 68267 68268 68269 68270 68271 68272 68273 68274 68275 68276 68277 68278 68279 68280 68281 68282 68283 68284 68285 68286 68287 68288 68289 68290 68291 68292 68293 68294 68295 68296 68297 68298 68299 68300 68301 68302 68303 68304 |
** movement was required (because the table being dropped was already
** the last one in the database) then a zero is stored in register P2.
** If AUTOVACUUM is disabled then a zero is stored in register P2.
**
** See also: Clear
*/
case OP_Destroy: { /* out2-prerelease */
#if 0 /* local variables moved into u.bu */
int iMoved;
int iCnt;
Vdbe *pVdbe;
int iDb;
#endif /* local variables moved into u.bu */
#ifndef SQLITE_OMIT_VIRTUALTABLE
u.bu.iCnt = 0;
for(u.bu.pVdbe=db->pVdbe; u.bu.pVdbe; u.bu.pVdbe = u.bu.pVdbe->pNext){
if( u.bu.pVdbe->magic==VDBE_MAGIC_RUN && u.bu.pVdbe->inVtabMethod<2 && u.bu.pVdbe->pc>=0 ){
u.bu.iCnt++;
}
}
#else
u.bu.iCnt = db->activeVdbeCnt;
#endif
pOut->flags = MEM_Null;
if( u.bu.iCnt>1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
u.bu.iDb = pOp->p3;
assert( u.bu.iCnt==1 );
assert( (p->btreeMask & (((yDbMask)1)<<u.bu.iDb))!=0 );
rc = sqlite3BtreeDropTable(db->aDb[u.bu.iDb].pBt, pOp->p1, &u.bu.iMoved);
pOut->flags = MEM_Int;
pOut->u.i = u.bu.iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && u.bu.iMoved!=0 ){
sqlite3RootPageMoved(db, u.bu.iDb, u.bu.iMoved, pOp->p1);
/* All OP_Destroy operations occur on the same btree */
assert( resetSchemaOnFault==0 || resetSchemaOnFault==u.bu.iDb+1 );
resetSchemaOnFault = u.bu.iDb+1;
}
#endif
}
break;
}
/* Opcode: Clear P1 P2 P3
|
| ︙ | ︙ | |||
68263 68264 68265 68266 68267 68268 68269 |
** count is incremented by the number of rows in the table being cleared.
** If P3 is greater than zero, then the value stored in register P3 is
** also incremented by the number of rows in the table being cleared.
**
** See also: Destroy
*/
case OP_Clear: {
| | | | | | | | 68316 68317 68318 68319 68320 68321 68322 68323 68324 68325 68326 68327 68328 68329 68330 68331 68332 68333 68334 68335 68336 68337 68338 68339 68340 68341 68342 68343 68344 |
** count is incremented by the number of rows in the table being cleared.
** If P3 is greater than zero, then the value stored in register P3 is
** also incremented by the number of rows in the table being cleared.
**
** See also: Destroy
*/
case OP_Clear: {
#if 0 /* local variables moved into u.bv */
int nChange;
#endif /* local variables moved into u.bv */
u.bv.nChange = 0;
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
rc = sqlite3BtreeClearTable(
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &u.bv.nChange : 0)
);
if( pOp->p3 ){
p->nChange += u.bv.nChange;
if( pOp->p3>0 ){
assert( memIsValid(&aMem[pOp->p3]) );
memAboutToChange(p, &aMem[pOp->p3]);
aMem[pOp->p3].u.i += u.bv.nChange;
}
}
break;
}
/* Opcode: CreateTable P1 P2 * * *
**
|
| ︙ | ︙ | |||
68307 68308 68309 68310 68311 68312 68313 |
** P1>1. Write the root page number of the new table into
** register P2.
**
** See documentation on OP_CreateTable for additional information.
*/
case OP_CreateIndex: /* out2-prerelease */
case OP_CreateTable: { /* out2-prerelease */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68360 68361 68362 68363 68364 68365 68366 68367 68368 68369 68370 68371 68372 68373 68374 68375 68376 68377 68378 68379 68380 68381 68382 68383 68384 68385 68386 68387 68388 68389 68390 68391 68392 68393 68394 68395 68396 68397 68398 68399 68400 68401 68402 68403 68404 68405 68406 68407 68408 68409 68410 68411 68412 68413 68414 68415 68416 68417 68418 68419 68420 68421 68422 68423 68424 68425 68426 68427 68428 68429 68430 68431 68432 68433 68434 68435 68436 68437 68438 68439 68440 68441 68442 |
** P1>1. Write the root page number of the new table into
** register P2.
**
** See documentation on OP_CreateTable for additional information.
*/
case OP_CreateIndex: /* out2-prerelease */
case OP_CreateTable: { /* out2-prerelease */
#if 0 /* local variables moved into u.bw */
int pgno;
int flags;
Db *pDb;
#endif /* local variables moved into u.bw */
u.bw.pgno = 0;
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
u.bw.pDb = &db->aDb[pOp->p1];
assert( u.bw.pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
/* u.bw.flags = BTREE_INTKEY; */
u.bw.flags = BTREE_INTKEY;
}else{
u.bw.flags = BTREE_BLOBKEY;
}
rc = sqlite3BtreeCreateTable(u.bw.pDb->pBt, &u.bw.pgno, u.bw.flags);
pOut->u.i = u.bw.pgno;
break;
}
/* Opcode: ParseSchema P1 * * P4 *
**
** Read and parse all entries from the SQLITE_MASTER table of database P1
** that match the WHERE clause P4.
**
** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine. It is thus a re-entrant opcode.
*/
case OP_ParseSchema: {
#if 0 /* local variables moved into u.bx */
int iDb;
const char *zMaster;
char *zSql;
InitData initData;
#endif /* local variables moved into u.bx */
/* Any prepared statement that invokes this opcode will hold mutexes
** on every btree. This is a prerequisite for invoking
** sqlite3InitCallback().
*/
#ifdef SQLITE_DEBUG
for(u.bx.iDb=0; u.bx.iDb<db->nDb; u.bx.iDb++){
assert( u.bx.iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[u.bx.iDb].pBt) );
}
#endif
u.bx.iDb = pOp->p1;
assert( u.bx.iDb>=0 && u.bx.iDb<db->nDb );
assert( DbHasProperty(db, u.bx.iDb, DB_SchemaLoaded) );
/* Used to be a conditional */ {
u.bx.zMaster = SCHEMA_TABLE(u.bx.iDb);
u.bx.initData.db = db;
u.bx.initData.iDb = pOp->p1;
u.bx.initData.pzErrMsg = &p->zErrMsg;
u.bx.zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
db->aDb[u.bx.iDb].zName, u.bx.zMaster, pOp->p4.z);
if( u.bx.zSql==0 ){
rc = SQLITE_NOMEM;
}else{
assert( db->init.busy==0 );
db->init.busy = 1;
u.bx.initData.rc = SQLITE_OK;
assert( !db->mallocFailed );
rc = sqlite3_exec(db, u.bx.zSql, sqlite3InitCallback, &u.bx.initData, 0);
if( rc==SQLITE_OK ) rc = u.bx.initData.rc;
sqlite3DbFree(db, u.bx.zSql);
db->init.busy = 0;
}
}
if( rc==SQLITE_NOMEM ){
goto no_mem;
}
break;
|
| ︙ | ︙ | |||
68458 68459 68460 68461 68462 68463 68464 |
**
** If P5 is not zero, the check is done on the auxiliary database
** file, not the main database file.
**
** This opcode is used to implement the integrity_check pragma.
*/
case OP_IntegrityCk: {
| | | | | | | | | | | | | | | | | | | | | | 68511 68512 68513 68514 68515 68516 68517 68518 68519 68520 68521 68522 68523 68524 68525 68526 68527 68528 68529 68530 68531 68532 68533 68534 68535 68536 68537 68538 68539 68540 68541 68542 68543 68544 68545 68546 68547 68548 68549 68550 68551 68552 68553 68554 68555 68556 68557 68558 68559 |
**
** If P5 is not zero, the check is done on the auxiliary database
** file, not the main database file.
**
** This opcode is used to implement the integrity_check pragma.
*/
case OP_IntegrityCk: {
#if 0 /* local variables moved into u.by */
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
int j; /* Loop counter */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
#endif /* local variables moved into u.by */
u.by.nRoot = pOp->p2;
assert( u.by.nRoot>0 );
u.by.aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(u.by.nRoot+1) );
if( u.by.aRoot==0 ) goto no_mem;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
u.by.pnErr = &aMem[pOp->p3];
assert( (u.by.pnErr->flags & MEM_Int)!=0 );
assert( (u.by.pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
for(u.by.j=0; u.by.j<u.by.nRoot; u.by.j++){
u.by.aRoot[u.by.j] = (int)sqlite3VdbeIntValue(&pIn1[u.by.j]);
}
u.by.aRoot[u.by.j] = 0;
assert( pOp->p5<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p5))!=0 );
u.by.z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, u.by.aRoot, u.by.nRoot,
(int)u.by.pnErr->u.i, &u.by.nErr);
sqlite3DbFree(db, u.by.aRoot);
u.by.pnErr->u.i -= u.by.nErr;
sqlite3VdbeMemSetNull(pIn1);
if( u.by.nErr==0 ){
assert( u.by.z==0 );
}else if( u.by.z==0 ){
goto no_mem;
}else{
sqlite3VdbeMemSetStr(pIn1, u.by.z, -1, SQLITE_UTF8, sqlite3_free);
}
UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
break;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
| ︙ | ︙ | |||
68526 68527 68528 68529 68530 68531 68532 |
/* Opcode: RowSetRead P1 P2 P3 * *
**
** Extract the smallest value from boolean index P1 and put that value into
** register P3. Or, if boolean index P1 is initially empty, leave P3
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: { /* jump, in1, out3 */
| | | | | | 68579 68580 68581 68582 68583 68584 68585 68586 68587 68588 68589 68590 68591 68592 68593 68594 68595 68596 68597 68598 68599 68600 68601 68602 68603 68604 68605 68606 |
/* Opcode: RowSetRead P1 P2 P3 * *
**
** Extract the smallest value from boolean index P1 and put that value into
** register P3. Or, if boolean index P1 is initially empty, leave P3
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: { /* jump, in1, out3 */
#if 0 /* local variables moved into u.bz */
i64 val;
#endif /* local variables moved into u.bz */
CHECK_FOR_INTERRUPT;
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_RowSet)==0
|| sqlite3RowSetNext(pIn1->u.pRowSet, &u.bz.val)==0
){
/* The boolean index is empty */
sqlite3VdbeMemSetNull(pIn1);
pc = pOp->p2 - 1;
}else{
/* A value was pulled from the index */
sqlite3VdbeMemSetInt64(&aMem[pOp->p3], u.bz.val);
}
break;
}
/* Opcode: RowSetTest P1 P2 P3 P4
**
** Register P3 is assumed to hold a 64-bit integer value. If register P1
|
| ︙ | ︙ | |||
68568 68569 68570 68571 68572 68573 68574 |
** (b) when P4==-1 there is no need to insert the value, as it will
** never be tested for, and (c) when a value that is part of set X is
** inserted, there is no need to search to see if the same value was
** previously inserted as part of set X (only if it was previously
** inserted as part of some other set).
*/
case OP_RowSetTest: { /* jump, in1, in3 */
| | | | | | | | | | | 68621 68622 68623 68624 68625 68626 68627 68628 68629 68630 68631 68632 68633 68634 68635 68636 68637 68638 68639 68640 68641 68642 68643 68644 68645 68646 68647 68648 68649 68650 68651 68652 68653 68654 68655 68656 68657 68658 68659 68660 68661 68662 68663 68664 |
** (b) when P4==-1 there is no need to insert the value, as it will
** never be tested for, and (c) when a value that is part of set X is
** inserted, there is no need to search to see if the same value was
** previously inserted as part of set X (only if it was previously
** inserted as part of some other set).
*/
case OP_RowSetTest: { /* jump, in1, in3 */
#if 0 /* local variables moved into u.ca */
int iSet;
int exists;
#endif /* local variables moved into u.ca */
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
u.ca.iSet = pOp->p4.i;
assert( pIn3->flags&MEM_Int );
/* If there is anything other than a rowset object in memory cell P1,
** delete it now and initialize P1 with an empty rowset
*/
if( (pIn1->flags & MEM_RowSet)==0 ){
sqlite3VdbeMemSetRowSet(pIn1);
if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
}
assert( pOp->p4type==P4_INT32 );
assert( u.ca.iSet==-1 || u.ca.iSet>=0 );
if( u.ca.iSet ){
u.ca.exists = sqlite3RowSetTest(pIn1->u.pRowSet,
(u8)(u.ca.iSet>=0 ? u.ca.iSet & 0xf : 0xff),
pIn3->u.i);
if( u.ca.exists ){
pc = pOp->p2 - 1;
break;
}
}
if( u.ca.iSet>=0 ){
sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
}
break;
}
#ifndef SQLITE_OMIT_TRIGGER
|
| ︙ | ︙ | |||
68620 68621 68622 68623 68624 68625 68626 |
** exception using the RAISE() function. Register P3 contains the address
** of a memory cell in this (the parent) VM that is used to allocate the
** memory required by the sub-vdbe at runtime.
**
** P4 is a pointer to the VM containing the trigger program.
*/
case OP_Program: { /* jump */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68673 68674 68675 68676 68677 68678 68679 68680 68681 68682 68683 68684 68685 68686 68687 68688 68689 68690 68691 68692 68693 68694 68695 68696 68697 68698 68699 68700 68701 68702 68703 68704 68705 68706 68707 68708 68709 68710 68711 68712 68713 68714 68715 68716 68717 68718 68719 68720 68721 68722 68723 68724 68725 68726 68727 68728 68729 68730 68731 68732 68733 68734 68735 68736 68737 68738 68739 68740 68741 68742 68743 68744 68745 68746 68747 68748 68749 68750 68751 68752 68753 68754 68755 68756 68757 68758 68759 68760 68761 68762 68763 68764 68765 68766 68767 68768 68769 68770 68771 68772 68773 68774 68775 68776 68777 68778 68779 68780 68781 68782 68783 68784 68785 68786 68787 68788 68789 68790 68791 68792 68793 68794 68795 68796 68797 68798 68799 68800 68801 68802 68803 68804 68805 68806 68807 68808 |
** exception using the RAISE() function. Register P3 contains the address
** of a memory cell in this (the parent) VM that is used to allocate the
** memory required by the sub-vdbe at runtime.
**
** P4 is a pointer to the VM containing the trigger program.
*/
case OP_Program: { /* jump */
#if 0 /* local variables moved into u.cb */
int nMem; /* Number of memory registers for sub-program */
int nByte; /* Bytes of runtime space required for sub-program */
Mem *pRt; /* Register to allocate runtime space */
Mem *pMem; /* Used to iterate through memory cells */
Mem *pEnd; /* Last memory cell in new array */
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
#endif /* local variables moved into u.cb */
u.cb.pProgram = pOp->p4.pProgram;
u.cb.pRt = &aMem[pOp->p3];
assert( memIsValid(u.cb.pRt) );
assert( u.cb.pProgram->nOp>0 );
/* If the p5 flag is clear, then recursive invocation of triggers is
** disabled for backwards compatibility (p5 is set if this sub-program
** is really a trigger, not a foreign key action, and the flag set
** and cleared by the "PRAGMA recursive_triggers" command is clear).
**
** It is recursive invocation of triggers, at the SQL level, that is
** disabled. In some cases a single trigger may generate more than one
** SubProgram (if the trigger may be executed with more than one different
** ON CONFLICT algorithm). SubProgram structures associated with a
** single trigger all have the same value for the SubProgram.token
** variable. */
if( pOp->p5 ){
u.cb.t = u.cb.pProgram->token;
for(u.cb.pFrame=p->pFrame; u.cb.pFrame && u.cb.pFrame->token!=u.cb.t; u.cb.pFrame=u.cb.pFrame->pParent);
if( u.cb.pFrame ) break;
}
if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, db, "too many levels of trigger recursion");
break;
}
/* Register u.cb.pRt is used to store the memory required to save the state
** of the current program, and the memory required at runtime to execute
** the trigger program. If this trigger has been fired before, then u.cb.pRt
** is already allocated. Otherwise, it must be initialized. */
if( (u.cb.pRt->flags&MEM_Frame)==0 ){
/* SubProgram.nMem is set to the number of memory cells used by the
** program stored in SubProgram.aOp. As well as these, one memory
** cell is required for each cursor used by the program. Set local
** variable u.cb.nMem (and later, VdbeFrame.nChildMem) to this value.
*/
u.cb.nMem = u.cb.pProgram->nMem + u.cb.pProgram->nCsr;
u.cb.nByte = ROUND8(sizeof(VdbeFrame))
+ u.cb.nMem * sizeof(Mem)
+ u.cb.pProgram->nCsr * sizeof(VdbeCursor *);
u.cb.pFrame = sqlite3DbMallocZero(db, u.cb.nByte);
if( !u.cb.pFrame ){
goto no_mem;
}
sqlite3VdbeMemRelease(u.cb.pRt);
u.cb.pRt->flags = MEM_Frame;
u.cb.pRt->u.pFrame = u.cb.pFrame;
u.cb.pFrame->v = p;
u.cb.pFrame->nChildMem = u.cb.nMem;
u.cb.pFrame->nChildCsr = u.cb.pProgram->nCsr;
u.cb.pFrame->pc = pc;
u.cb.pFrame->aMem = p->aMem;
u.cb.pFrame->nMem = p->nMem;
u.cb.pFrame->apCsr = p->apCsr;
u.cb.pFrame->nCursor = p->nCursor;
u.cb.pFrame->aOp = p->aOp;
u.cb.pFrame->nOp = p->nOp;
u.cb.pFrame->token = u.cb.pProgram->token;
u.cb.pEnd = &VdbeFrameMem(u.cb.pFrame)[u.cb.pFrame->nChildMem];
for(u.cb.pMem=VdbeFrameMem(u.cb.pFrame); u.cb.pMem!=u.cb.pEnd; u.cb.pMem++){
u.cb.pMem->flags = MEM_Null;
u.cb.pMem->db = db;
}
}else{
u.cb.pFrame = u.cb.pRt->u.pFrame;
assert( u.cb.pProgram->nMem+u.cb.pProgram->nCsr==u.cb.pFrame->nChildMem );
assert( u.cb.pProgram->nCsr==u.cb.pFrame->nChildCsr );
assert( pc==u.cb.pFrame->pc );
}
p->nFrame++;
u.cb.pFrame->pParent = p->pFrame;
u.cb.pFrame->lastRowid = lastRowid;
u.cb.pFrame->nChange = p->nChange;
p->nChange = 0;
p->pFrame = u.cb.pFrame;
p->aMem = aMem = &VdbeFrameMem(u.cb.pFrame)[-1];
p->nMem = u.cb.pFrame->nChildMem;
p->nCursor = (u16)u.cb.pFrame->nChildCsr;
p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
p->aOp = aOp = u.cb.pProgram->aOp;
p->nOp = u.cb.pProgram->nOp;
pc = -1;
break;
}
/* Opcode: Param P1 P2 * * *
**
** This opcode is only ever present in sub-programs called via the
** OP_Program instruction. Copy a value currently stored in a memory
** cell of the calling (parent) frame to cell P2 in the current frames
** address space. This is used by trigger programs to access the new.*
** and old.* values.
**
** The address of the cell in the parent frame is determined by adding
** the value of the P1 argument to the value of the P1 argument to the
** calling OP_Program instruction.
*/
case OP_Param: { /* out2-prerelease */
#if 0 /* local variables moved into u.cc */
VdbeFrame *pFrame;
Mem *pIn;
#endif /* local variables moved into u.cc */
u.cc.pFrame = p->pFrame;
u.cc.pIn = &u.cc.pFrame->aMem[pOp->p1 + u.cc.pFrame->aOp[u.cc.pFrame->pc].p1];
sqlite3VdbeMemShallowCopy(pOut, u.cc.pIn, MEM_Ephem);
break;
}
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
#ifndef SQLITE_OMIT_FOREIGN_KEY
/* Opcode: FkCounter P1 P2 * * *
|
| ︙ | ︙ | |||
68797 68798 68799 68800 68801 68802 68803 |
** within a sub-program). Set the value of register P1 to the maximum of
** its current value and the value in register P2.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
case OP_MemMax: { /* in2 */
| | | | | | | | | | | 68850 68851 68852 68853 68854 68855 68856 68857 68858 68859 68860 68861 68862 68863 68864 68865 68866 68867 68868 68869 68870 68871 68872 68873 68874 68875 68876 68877 68878 68879 |
** within a sub-program). Set the value of register P1 to the maximum of
** its current value and the value in register P2.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
case OP_MemMax: { /* in2 */
#if 0 /* local variables moved into u.cd */
Mem *pIn1;
VdbeFrame *pFrame;
#endif /* local variables moved into u.cd */
if( p->pFrame ){
for(u.cd.pFrame=p->pFrame; u.cd.pFrame->pParent; u.cd.pFrame=u.cd.pFrame->pParent);
u.cd.pIn1 = &u.cd.pFrame->aMem[pOp->p1];
}else{
u.cd.pIn1 = &aMem[pOp->p1];
}
assert( memIsValid(u.cd.pIn1) );
sqlite3VdbeMemIntegerify(u.cd.pIn1);
pIn2 = &aMem[pOp->p2];
sqlite3VdbeMemIntegerify(pIn2);
if( u.cd.pIn1->u.i<pIn2->u.i){
u.cd.pIn1->u.i = pIn2->u.i;
}
break;
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
/* Opcode: IfPos P1 P2 * * *
**
|
| ︙ | ︙ | |||
68879 68880 68881 68882 68883 68884 68885 |
** structure that specifies the function. Use register
** P3 as the accumulator.
**
** The P5 arguments are taken from register P2 and its
** successors.
*/
case OP_AggStep: {
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68932 68933 68934 68935 68936 68937 68938 68939 68940 68941 68942 68943 68944 68945 68946 68947 68948 68949 68950 68951 68952 68953 68954 68955 68956 68957 68958 68959 68960 68961 68962 68963 68964 68965 68966 68967 68968 68969 68970 68971 68972 68973 68974 68975 68976 68977 68978 68979 68980 68981 68982 68983 68984 68985 68986 68987 68988 68989 68990 68991 68992 68993 68994 68995 68996 68997 68998 68999 69000 69001 69002 69003 69004 69005 69006 69007 69008 69009 69010 69011 69012 69013 69014 69015 69016 69017 69018 69019 69020 69021 69022 69023 69024 69025 69026 69027 69028 69029 69030 69031 69032 69033 69034 69035 69036 69037 69038 69039 69040 69041 69042 69043 69044 69045 69046 69047 69048 69049 69050 69051 69052 69053 69054 69055 69056 69057 69058 69059 69060 69061 69062 69063 69064 69065 69066 69067 69068 69069 69070 69071 69072 69073 69074 69075 69076 69077 69078 69079 69080 69081 69082 69083 69084 69085 69086 69087 69088 69089 69090 69091 69092 69093 69094 69095 69096 69097 69098 69099 69100 69101 69102 69103 69104 69105 69106 69107 69108 69109 69110 69111 69112 69113 69114 69115 69116 69117 69118 69119 69120 69121 69122 69123 69124 69125 69126 69127 69128 69129 69130 69131 69132 69133 69134 69135 69136 69137 69138 69139 69140 69141 69142 69143 69144 69145 69146 69147 69148 69149 69150 69151 69152 69153 69154 69155 69156 69157 69158 69159 |
** structure that specifies the function. Use register
** P3 as the accumulator.
**
** The P5 arguments are taken from register P2 and its
** successors.
*/
case OP_AggStep: {
#if 0 /* local variables moved into u.ce */
int n;
int i;
Mem *pMem;
Mem *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
#endif /* local variables moved into u.ce */
u.ce.n = pOp->p5;
assert( u.ce.n>=0 );
u.ce.pRec = &aMem[pOp->p2];
u.ce.apVal = p->apArg;
assert( u.ce.apVal || u.ce.n==0 );
for(u.ce.i=0; u.ce.i<u.ce.n; u.ce.i++, u.ce.pRec++){
assert( memIsValid(u.ce.pRec) );
u.ce.apVal[u.ce.i] = u.ce.pRec;
memAboutToChange(p, u.ce.pRec);
sqlite3VdbeMemStoreType(u.ce.pRec);
}
u.ce.ctx.pFunc = pOp->p4.pFunc;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
u.ce.ctx.pMem = u.ce.pMem = &aMem[pOp->p3];
u.ce.pMem->n++;
u.ce.ctx.s.flags = MEM_Null;
u.ce.ctx.s.z = 0;
u.ce.ctx.s.zMalloc = 0;
u.ce.ctx.s.xDel = 0;
u.ce.ctx.s.db = db;
u.ce.ctx.isError = 0;
u.ce.ctx.pColl = 0;
if( u.ce.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>p->aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
u.ce.ctx.pColl = pOp[-1].p4.pColl;
}
(u.ce.ctx.pFunc->xStep)(&u.ce.ctx, u.ce.n, u.ce.apVal); /* IMP: R-24505-23230 */
if( u.ce.ctx.isError ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ce.ctx.s));
rc = u.ce.ctx.isError;
}
sqlite3VdbeMemRelease(&u.ce.ctx.s);
break;
}
/* Opcode: AggFinal P1 P2 * P4 *
**
** Execute the finalizer function for an aggregate. P1 is
** the memory location that is the accumulator for the aggregate.
**
** P2 is the number of arguments that the step function takes and
** P4 is a pointer to the FuncDef for this function. The P2
** argument is not used by this opcode. It is only there to disambiguate
** functions that can take varying numbers of arguments. The
** P4 argument is only needed for the degenerate case where
** the step function was not previously called.
*/
case OP_AggFinal: {
#if 0 /* local variables moved into u.cf */
Mem *pMem;
#endif /* local variables moved into u.cf */
assert( pOp->p1>0 && pOp->p1<=p->nMem );
u.cf.pMem = &aMem[pOp->p1];
assert( (u.cf.pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
rc = sqlite3VdbeMemFinalize(u.cf.pMem, pOp->p4.pFunc);
if( rc ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(u.cf.pMem));
}
sqlite3VdbeChangeEncoding(u.cf.pMem, encoding);
UPDATE_MAX_BLOBSIZE(u.cf.pMem);
if( sqlite3VdbeMemTooBig(u.cf.pMem) ){
goto too_big;
}
break;
}
#ifndef SQLITE_OMIT_WAL
/* Opcode: Checkpoint P1 P2 P3 * *
**
** Checkpoint database P1. This is a no-op if P1 is not currently in
** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL
** or RESTART. Write 1 or 0 into mem[P3] if the checkpoint returns
** SQLITE_BUSY or not, respectively. Write the number of pages in the
** WAL after the checkpoint into mem[P3+1] and the number of pages
** in the WAL that have been checkpointed after the checkpoint
** completes into mem[P3+2]. However on an error, mem[P3+1] and
** mem[P3+2] are initialized to -1.
*/
case OP_Checkpoint: {
#if 0 /* local variables moved into u.cg */
int i; /* Loop counter */
int aRes[3]; /* Results */
Mem *pMem; /* Write results here */
#endif /* local variables moved into u.cg */
u.cg.aRes[0] = 0;
u.cg.aRes[1] = u.cg.aRes[2] = -1;
assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
|| pOp->p2==SQLITE_CHECKPOINT_FULL
|| pOp->p2==SQLITE_CHECKPOINT_RESTART
);
rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &u.cg.aRes[1], &u.cg.aRes[2]);
if( rc==SQLITE_BUSY ){
rc = SQLITE_OK;
u.cg.aRes[0] = 1;
}
for(u.cg.i=0, u.cg.pMem = &aMem[pOp->p3]; u.cg.i<3; u.cg.i++, u.cg.pMem++){
sqlite3VdbeMemSetInt64(u.cg.pMem, (i64)u.cg.aRes[u.cg.i]);
}
break;
};
#endif
#ifndef SQLITE_OMIT_PRAGMA
/* Opcode: JournalMode P1 P2 P3 * P5
**
** Change the journal mode of database P1 to P3. P3 must be one of the
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
** modes (delete, truncate, persist, off and memory), this is a simple
** operation. No IO is required.
**
** If changing into or out of WAL mode the procedure is more complicated.
**
** Write a string containing the final journal-mode to register P2.
*/
case OP_JournalMode: { /* out2-prerelease */
#if 0 /* local variables moved into u.ch */
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
const char *zFilename; /* Name of database file for pPager */
#endif /* local variables moved into u.ch */
u.ch.eNew = pOp->p3;
assert( u.ch.eNew==PAGER_JOURNALMODE_DELETE
|| u.ch.eNew==PAGER_JOURNALMODE_TRUNCATE
|| u.ch.eNew==PAGER_JOURNALMODE_PERSIST
|| u.ch.eNew==PAGER_JOURNALMODE_OFF
|| u.ch.eNew==PAGER_JOURNALMODE_MEMORY
|| u.ch.eNew==PAGER_JOURNALMODE_WAL
|| u.ch.eNew==PAGER_JOURNALMODE_QUERY
);
assert( pOp->p1>=0 && pOp->p1<db->nDb );
u.ch.pBt = db->aDb[pOp->p1].pBt;
u.ch.pPager = sqlite3BtreePager(u.ch.pBt);
u.ch.eOld = sqlite3PagerGetJournalMode(u.ch.pPager);
if( u.ch.eNew==PAGER_JOURNALMODE_QUERY ) u.ch.eNew = u.ch.eOld;
if( !sqlite3PagerOkToChangeJournalMode(u.ch.pPager) ) u.ch.eNew = u.ch.eOld;
#ifndef SQLITE_OMIT_WAL
u.ch.zFilename = sqlite3PagerFilename(u.ch.pPager);
/* Do not allow a transition to journal_mode=WAL for a database
** in temporary storage or if the VFS does not support shared memory
*/
if( u.ch.eNew==PAGER_JOURNALMODE_WAL
&& (u.ch.zFilename[0]==0 /* Temp file */
|| !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */
){
u.ch.eNew = u.ch.eOld;
}
if( (u.ch.eNew!=u.ch.eOld)
&& (u.ch.eOld==PAGER_JOURNALMODE_WAL || u.ch.eNew==PAGER_JOURNALMODE_WAL)
){
if( !db->autoCommit || db->activeVdbeCnt>1 ){
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, db,
"cannot change %s wal mode from within a transaction",
(u.ch.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
);
break;
}else{
if( u.ch.eOld==PAGER_JOURNALMODE_WAL ){
/* If leaving WAL mode, close the log file. If successful, the call
** to PagerCloseWal() checkpoints and deletes the write-ahead-log
** file. An EXCLUSIVE lock may still be held on the database file
** after a successful return.
*/
rc = sqlite3PagerCloseWal(u.ch.pPager);
if( rc==SQLITE_OK ){
sqlite3PagerSetJournalMode(u.ch.pPager, u.ch.eNew);
}
}else if( u.ch.eOld==PAGER_JOURNALMODE_MEMORY ){
/* Cannot transition directly from MEMORY to WAL. Use mode OFF
** as an intermediate */
sqlite3PagerSetJournalMode(u.ch.pPager, PAGER_JOURNALMODE_OFF);
}
/* Open a transaction on the database file. Regardless of the journal
** mode, this transaction always uses a rollback journal.
*/
assert( sqlite3BtreeIsInTrans(u.ch.pBt)==0 );
if( rc==SQLITE_OK ){
rc = sqlite3BtreeSetVersion(u.ch.pBt, (u.ch.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
}
}
}
#endif /* ifndef SQLITE_OMIT_WAL */
if( rc ){
u.ch.eNew = u.ch.eOld;
}
u.ch.eNew = sqlite3PagerSetJournalMode(u.ch.pPager, u.ch.eNew);
pOut = &aMem[pOp->p2];
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
pOut->z = (char *)sqlite3JournalModename(u.ch.eNew);
pOut->n = sqlite3Strlen30(pOut->z);
pOut->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pOut, encoding);
break;
};
#endif /* SQLITE_OMIT_PRAGMA */
|
| ︙ | ︙ | |||
69121 69122 69123 69124 69125 69126 69127 |
/* Opcode: IncrVacuum P1 P2 * * *
**
** Perform a single step of the incremental vacuum procedure on
** the P1 database. If the vacuum has finished, jump to instruction
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
| | | | | | 69174 69175 69176 69177 69178 69179 69180 69181 69182 69183 69184 69185 69186 69187 69188 69189 69190 69191 69192 69193 69194 69195 |
/* Opcode: IncrVacuum P1 P2 * * *
**
** Perform a single step of the incremental vacuum procedure on
** the P1 database. If the vacuum has finished, jump to instruction
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
#if 0 /* local variables moved into u.ci */
Btree *pBt;
#endif /* local variables moved into u.ci */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
u.ci.pBt = db->aDb[pOp->p1].pBt;
rc = sqlite3BtreeIncrVacuum(u.ci.pBt);
if( rc==SQLITE_DONE ){
pc = pOp->p2 - 1;
rc = SQLITE_OK;
}
break;
}
#endif
|
| ︙ | ︙ | |||
69198 69199 69200 69201 69202 69203 69204 |
** xBegin method for that table.
**
** Also, whether or not P4 is set, check that this is not being called from
** within a callback to a virtual table xSync() method. If it is, the error
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
| | | | | | | 69251 69252 69253 69254 69255 69256 69257 69258 69259 69260 69261 69262 69263 69264 69265 69266 69267 69268 69269 69270 |
** xBegin method for that table.
**
** Also, whether or not P4 is set, check that this is not being called from
** within a callback to a virtual table xSync() method. If it is, the error
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
#if 0 /* local variables moved into u.cj */
VTable *pVTab;
#endif /* local variables moved into u.cj */
u.cj.pVTab = pOp->p4.pVtab;
rc = sqlite3VtabBegin(db, u.cj.pVTab);
if( u.cj.pVTab ) importVtabErrMsg(p, u.cj.pVTab->pVtab);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VCreate P1 * * P4 *
**
|
| ︙ | ︙ | |||
69242 69243 69244 69245 69246 69247 69248 |
/* Opcode: VOpen P1 * * P4 *
**
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
** P1 is a cursor number. This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
case OP_VOpen: {
| | | | | | | | | | | | | | | | | 69295 69296 69297 69298 69299 69300 69301 69302 69303 69304 69305 69306 69307 69308 69309 69310 69311 69312 69313 69314 69315 69316 69317 69318 69319 69320 69321 69322 69323 69324 69325 69326 69327 69328 69329 69330 69331 69332 69333 69334 |
/* Opcode: VOpen P1 * * P4 *
**
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
** P1 is a cursor number. This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
case OP_VOpen: {
#if 0 /* local variables moved into u.ck */
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
#endif /* local variables moved into u.ck */
u.ck.pCur = 0;
u.ck.pVtabCursor = 0;
u.ck.pVtab = pOp->p4.pVtab->pVtab;
u.ck.pModule = (sqlite3_module *)u.ck.pVtab->pModule;
assert(u.ck.pVtab && u.ck.pModule);
rc = u.ck.pModule->xOpen(u.ck.pVtab, &u.ck.pVtabCursor);
importVtabErrMsg(p, u.ck.pVtab);
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
u.ck.pVtabCursor->pVtab = u.ck.pVtab;
/* Initialise vdbe cursor object */
u.ck.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
if( u.ck.pCur ){
u.ck.pCur->pVtabCursor = u.ck.pVtabCursor;
u.ck.pCur->pModule = u.ck.pVtabCursor->pVtab->pModule;
}else{
db->mallocFailed = 1;
u.ck.pModule->xClose(u.ck.pVtabCursor);
}
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| ︙ | ︙ | |||
69294 69295 69296 69297 69298 69299 69300 |
** xFilter method. Registers P3+2..P3+1+argc are the argc
** additional parameters which are passed to
** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter.
**
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* jump */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 69347 69348 69349 69350 69351 69352 69353 69354 69355 69356 69357 69358 69359 69360 69361 69362 69363 69364 69365 69366 69367 69368 69369 69370 69371 69372 69373 69374 69375 69376 69377 69378 69379 69380 69381 69382 69383 69384 69385 69386 69387 69388 69389 69390 69391 69392 69393 69394 69395 69396 69397 69398 69399 69400 69401 69402 69403 69404 69405 69406 69407 69408 69409 69410 69411 69412 69413 69414 69415 69416 69417 69418 69419 69420 69421 69422 69423 69424 69425 69426 69427 69428 69429 69430 69431 69432 69433 69434 69435 69436 69437 69438 69439 69440 69441 69442 69443 69444 69445 69446 69447 69448 69449 69450 69451 69452 69453 69454 69455 69456 69457 69458 69459 69460 69461 69462 69463 69464 69465 69466 69467 69468 69469 69470 69471 69472 69473 69474 69475 69476 69477 69478 69479 69480 69481 69482 69483 69484 69485 69486 69487 69488 69489 69490 69491 69492 69493 69494 69495 69496 69497 69498 69499 69500 69501 69502 69503 69504 69505 69506 69507 69508 69509 69510 69511 69512 69513 69514 69515 69516 69517 69518 69519 69520 69521 69522 69523 69524 69525 69526 69527 69528 69529 69530 69531 69532 69533 69534 69535 69536 69537 69538 69539 69540 69541 69542 69543 |
** xFilter method. Registers P3+2..P3+1+argc are the argc
** additional parameters which are passed to
** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter.
**
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* jump */
#if 0 /* local variables moved into u.cl */
int nArg;
int iQuery;
const sqlite3_module *pModule;
Mem *pQuery;
Mem *pArgc;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
VdbeCursor *pCur;
int res;
int i;
Mem **apArg;
#endif /* local variables moved into u.cl */
u.cl.pQuery = &aMem[pOp->p3];
u.cl.pArgc = &u.cl.pQuery[1];
u.cl.pCur = p->apCsr[pOp->p1];
assert( memIsValid(u.cl.pQuery) );
REGISTER_TRACE(pOp->p3, u.cl.pQuery);
assert( u.cl.pCur->pVtabCursor );
u.cl.pVtabCursor = u.cl.pCur->pVtabCursor;
u.cl.pVtab = u.cl.pVtabCursor->pVtab;
u.cl.pModule = u.cl.pVtab->pModule;
/* Grab the index number and argc parameters */
assert( (u.cl.pQuery->flags&MEM_Int)!=0 && u.cl.pArgc->flags==MEM_Int );
u.cl.nArg = (int)u.cl.pArgc->u.i;
u.cl.iQuery = (int)u.cl.pQuery->u.i;
/* Invoke the xFilter method */
{
u.cl.res = 0;
u.cl.apArg = p->apArg;
for(u.cl.i = 0; u.cl.i<u.cl.nArg; u.cl.i++){
u.cl.apArg[u.cl.i] = &u.cl.pArgc[u.cl.i+1];
sqlite3VdbeMemStoreType(u.cl.apArg[u.cl.i]);
}
p->inVtabMethod = 1;
rc = u.cl.pModule->xFilter(u.cl.pVtabCursor, u.cl.iQuery, pOp->p4.z, u.cl.nArg, u.cl.apArg);
p->inVtabMethod = 0;
importVtabErrMsg(p, u.cl.pVtab);
if( rc==SQLITE_OK ){
u.cl.res = u.cl.pModule->xEof(u.cl.pVtabCursor);
}
if( u.cl.res ){
pc = pOp->p2 - 1;
}
}
u.cl.pCur->nullRow = 0;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VColumn P1 P2 P3 * *
**
** Store the value of the P2-th column of
** the row of the virtual-table that the
** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
#if 0 /* local variables moved into u.cm */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
#endif /* local variables moved into u.cm */
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
u.cm.pDest = &aMem[pOp->p3];
memAboutToChange(p, u.cm.pDest);
if( pCur->nullRow ){
sqlite3VdbeMemSetNull(u.cm.pDest);
break;
}
u.cm.pVtab = pCur->pVtabCursor->pVtab;
u.cm.pModule = u.cm.pVtab->pModule;
assert( u.cm.pModule->xColumn );
memset(&u.cm.sContext, 0, sizeof(u.cm.sContext));
/* The output cell may already have a buffer allocated. Move
** the current contents to u.cm.sContext.s so in case the user-function
** can use the already allocated buffer instead of allocating a
** new one.
*/
sqlite3VdbeMemMove(&u.cm.sContext.s, u.cm.pDest);
MemSetTypeFlag(&u.cm.sContext.s, MEM_Null);
rc = u.cm.pModule->xColumn(pCur->pVtabCursor, &u.cm.sContext, pOp->p2);
importVtabErrMsg(p, u.cm.pVtab);
if( u.cm.sContext.isError ){
rc = u.cm.sContext.isError;
}
/* Copy the result of the function to the P3 register. We
** do this regardless of whether or not an error occurred to ensure any
** dynamic allocation in u.cm.sContext.s (a Mem struct) is released.
*/
sqlite3VdbeChangeEncoding(&u.cm.sContext.s, encoding);
sqlite3VdbeMemMove(u.cm.pDest, &u.cm.sContext.s);
REGISTER_TRACE(pOp->p3, u.cm.pDest);
UPDATE_MAX_BLOBSIZE(u.cm.pDest);
if( sqlite3VdbeMemTooBig(u.cm.pDest) ){
goto too_big;
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VNext P1 P2 * * *
**
** Advance virtual table P1 to the next row in its result set and
** jump to instruction P2. Or, if the virtual table has reached
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* jump */
#if 0 /* local variables moved into u.cn */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
#endif /* local variables moved into u.cn */
u.cn.res = 0;
u.cn.pCur = p->apCsr[pOp->p1];
assert( u.cn.pCur->pVtabCursor );
if( u.cn.pCur->nullRow ){
break;
}
u.cn.pVtab = u.cn.pCur->pVtabCursor->pVtab;
u.cn.pModule = u.cn.pVtab->pModule;
assert( u.cn.pModule->xNext );
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
** xNext(). Instead, if an error occurs, true is returned (indicating that
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
p->inVtabMethod = 1;
rc = u.cn.pModule->xNext(u.cn.pCur->pVtabCursor);
p->inVtabMethod = 0;
importVtabErrMsg(p, u.cn.pVtab);
if( rc==SQLITE_OK ){
u.cn.res = u.cn.pModule->xEof(u.cn.pCur->pVtabCursor);
}
if( !u.cn.res ){
/* If there is data, jump to P2 */
pc = pOp->p2 - 1;
}
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VRename P1 * * P4 *
**
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
** This opcode invokes the corresponding xRename method. The value
** in register P1 is passed as the zName argument to the xRename method.
*/
case OP_VRename: {
#if 0 /* local variables moved into u.co */
sqlite3_vtab *pVtab;
Mem *pName;
#endif /* local variables moved into u.co */
u.co.pVtab = pOp->p4.pVtab->pVtab;
u.co.pName = &aMem[pOp->p1];
assert( u.co.pVtab->pModule->xRename );
assert( memIsValid(u.co.pName) );
REGISTER_TRACE(pOp->p1, u.co.pName);
assert( u.co.pName->flags & MEM_Str );
rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z);
importVtabErrMsg(p, u.co.pVtab);
p->expired = 0;
break;
}
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| ︙ | ︙ | |||
69508 69509 69510 69511 69512 69513 69514 |
** a row to delete.
**
** P1 is a boolean flag. If it is set to true and the xUpdate call
** is successful, then the value returned by sqlite3_last_insert_rowid()
** is set to the value of the rowid for the row just inserted.
*/
case OP_VUpdate: {
| | | | | | | | | | | | | | | | | | | | 69561 69562 69563 69564 69565 69566 69567 69568 69569 69570 69571 69572 69573 69574 69575 69576 69577 69578 69579 69580 69581 69582 69583 69584 69585 69586 69587 69588 69589 69590 69591 69592 69593 69594 69595 69596 69597 69598 69599 69600 69601 69602 69603 69604 69605 69606 69607 69608 69609 |
** a row to delete.
**
** P1 is a boolean flag. If it is set to true and the xUpdate call
** is successful, then the value returned by sqlite3_last_insert_rowid()
** is set to the value of the rowid for the row just inserted.
*/
case OP_VUpdate: {
#if 0 /* local variables moved into u.cp */
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
int nArg;
int i;
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
#endif /* local variables moved into u.cp */
assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
|| pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
);
u.cp.pVtab = pOp->p4.pVtab->pVtab;
u.cp.pModule = (sqlite3_module *)u.cp.pVtab->pModule;
u.cp.nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
if( ALWAYS(u.cp.pModule->xUpdate) ){
u8 vtabOnConflict = db->vtabOnConflict;
u.cp.apArg = p->apArg;
u.cp.pX = &aMem[pOp->p3];
for(u.cp.i=0; u.cp.i<u.cp.nArg; u.cp.i++){
assert( memIsValid(u.cp.pX) );
memAboutToChange(p, u.cp.pX);
sqlite3VdbeMemStoreType(u.cp.pX);
u.cp.apArg[u.cp.i] = u.cp.pX;
u.cp.pX++;
}
db->vtabOnConflict = pOp->p5;
rc = u.cp.pModule->xUpdate(u.cp.pVtab, u.cp.nArg, u.cp.apArg, &u.cp.rowid);
db->vtabOnConflict = vtabOnConflict;
importVtabErrMsg(p, u.cp.pVtab);
if( rc==SQLITE_OK && pOp->p1 ){
assert( u.cp.nArg>1 && u.cp.apArg[0] && (u.cp.apArg[0]->flags&MEM_Null) );
db->lastRowid = lastRowid = u.cp.rowid;
}
if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
if( pOp->p5==OE_Ignore ){
rc = SQLITE_OK;
}else{
p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5);
}
|
| ︙ | ︙ | |||
69602 69603 69604 69605 69606 69607 69608 |
#ifndef SQLITE_OMIT_TRACE
/* Opcode: Trace * * * P4 *
**
** If tracing is enabled (by the sqlite3_trace()) interface, then
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
case OP_Trace: {
| | | | | | | | | | 69655 69656 69657 69658 69659 69660 69661 69662 69663 69664 69665 69666 69667 69668 69669 69670 69671 69672 69673 69674 69675 69676 69677 69678 69679 69680 69681 69682 69683 |
#ifndef SQLITE_OMIT_TRACE
/* Opcode: Trace * * * P4 *
**
** If tracing is enabled (by the sqlite3_trace()) interface, then
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
case OP_Trace: {
#if 0 /* local variables moved into u.cq */
char *zTrace;
char *z;
#endif /* local variables moved into u.cq */
if( db->xTrace && (u.cq.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){
u.cq.z = sqlite3VdbeExpandSql(p, u.cq.zTrace);
db->xTrace(db->pTraceArg, u.cq.z);
sqlite3DbFree(db, u.cq.z);
}
#ifdef SQLITE_DEBUG
if( (db->flags & SQLITE_SqlTrace)!=0
&& (u.cq.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
){
sqlite3DebugPrintf("SQL-trace: %s\n", u.cq.zTrace);
}
#endif /* SQLITE_DEBUG */
break;
}
#endif
|
| ︙ | ︙ | |||
70019 70020 70021 70022 70023 70024 70025 |
sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
/* Make sure a mutex is held on the table to be accessed */
sqlite3VdbeUsesBtree(v, iDb);
/* Configure the OP_TableLock instruction */
#ifdef SQLITE_OMIT_SHARED_CACHE
| | | | 70072 70073 70074 70075 70076 70077 70078 70079 70080 70081 70082 70083 70084 70085 70086 70087 70088 70089 70090 70091 70092 70093 70094 70095 70096 |
sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
/* Make sure a mutex is held on the table to be accessed */
sqlite3VdbeUsesBtree(v, iDb);
/* Configure the OP_TableLock instruction */
#ifdef SQLITE_OMIT_SHARED_CACHE
sqlite3VdbeChangeToNoop(v, 2);
#else
sqlite3VdbeChangeP1(v, 2, iDb);
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
sqlite3VdbeChangeP3(v, 2, flags);
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
#endif
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. */
sqlite3VdbeChangeToNoop(v, 4 - flags);
sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
sqlite3VdbeChangeP3(v, 3 + flags, iDb);
/* Configure the number of columns. Configure the cursor to
** think that the table has one more column than it really
** does. An OP_Column to retrieve this imaginary column will
** always return an SQL NULL. This is useful because it means
|
| ︙ | ︙ | |||
70237 70238 70239 70240 70241 70242 70243 70244 70245 70246 70247 70248 70249 70250 | ** memory). */ #ifndef SQLITE_OMIT_MERGE_SORT typedef struct VdbeSorterIter VdbeSorterIter; /* ** NOTES ON DATA STRUCTURE USED FOR N-WAY MERGES: ** ** As keys are added to the sorter, they are written to disk in a series ** of sorted packed-memory-arrays (PMAs). The size of each PMA is roughly ** the same as the cache-size allowed for temporary databases. In order | > | 70290 70291 70292 70293 70294 70295 70296 70297 70298 70299 70300 70301 70302 70303 70304 | ** memory). */ #ifndef SQLITE_OMIT_MERGE_SORT typedef struct VdbeSorterIter VdbeSorterIter; typedef struct SorterRecord SorterRecord; /* ** NOTES ON DATA STRUCTURE USED FOR N-WAY MERGES: ** ** As keys are added to the sorter, they are written to disk in a series ** of sorted packed-memory-arrays (PMAs). The size of each PMA is roughly ** the same as the cache-size allowed for temporary databases. In order |
| ︙ | ︙ | |||
70308 70309 70310 70311 70312 70313 70314 |
** aTree[] = { X, 0 0, 6 0, 3, 5, 6 }
**
** In other words, each time we advance to the next sorter element, log2(N)
** key comparison operations are required, where N is the number of segments
** being merged (rounded up to the next power of 2).
*/
struct VdbeSorter {
| | < > > > > > > > > > > > > > > > | 70362 70363 70364 70365 70366 70367 70368 70369 70370 70371 70372 70373 70374 70375 70376 70377 70378 70379 70380 70381 70382 70383 70384 70385 70386 70387 70388 70389 70390 70391 70392 70393 70394 70395 70396 70397 70398 70399 70400 70401 70402 70403 70404 70405 70406 70407 70408 70409 70410 70411 70412 70413 |
** aTree[] = { X, 0 0, 6 0, 3, 5, 6 }
**
** In other words, each time we advance to the next sorter element, log2(N)
** key comparison operations are required, where N is the number of segments
** being merged (rounded up to the next power of 2).
*/
struct VdbeSorter {
int nInMemory; /* Current size of pRecord list as PMA */
int nTree; /* Used size of aTree/aIter (power of 2) */
VdbeSorterIter *aIter; /* Array of iterators to merge */
int *aTree; /* Current state of incremental merge */
i64 iWriteOff; /* Current write offset within file pTemp1 */
i64 iReadOff; /* Current read offset within file pTemp1 */
sqlite3_file *pTemp1; /* PMA file 1 */
int nPMA; /* Number of PMAs stored in pTemp1 */
SorterRecord *pRecord; /* Head of in-memory record list */
int mnPmaSize; /* Minimum PMA size, in bytes */
int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */
UnpackedRecord *pUnpacked; /* Used to unpack keys */
};
/*
** The following type is an iterator for a PMA. It caches the current key in
** variables nKey/aKey. If the iterator is at EOF, pFile==0.
*/
struct VdbeSorterIter {
i64 iReadOff; /* Current read offset */
i64 iEof; /* 1 byte past EOF for this iterator */
sqlite3_file *pFile; /* File iterator is reading from */
int nAlloc; /* Bytes of space at aAlloc */
u8 *aAlloc; /* Allocated space */
int nKey; /* Number of bytes in key */
u8 *aKey; /* Pointer to current key */
};
/*
** A structure to store a single record. All in-memory records are connected
** together into a linked list headed at VdbeSorter.pRecord using the
** SorterRecord.pNext pointer.
*/
struct SorterRecord {
void *pVal;
int nVal;
SorterRecord *pNext;
};
/* Minimum allowable value for the VdbeSorter.nWorking variable */
#define SORTER_MIN_WORKING 10
/* Maximum number of segments to merge in a single pass. */
#define SORTER_MAX_MERGE_COUNT 16
|
| ︙ | ︙ | |||
70358 70359 70360 70361 70362 70363 70364 |
*/
static int vdbeSorterIterNext(
sqlite3 *db, /* Database handle (for sqlite3DbMalloc() ) */
VdbeSorterIter *pIter /* Iterator to advance */
){
int rc; /* Return Code */
int nRead; /* Number of bytes read */
| | | > | | > > > > | < | | | | | | | | | | | | | | | | > | | 70426 70427 70428 70429 70430 70431 70432 70433 70434 70435 70436 70437 70438 70439 70440 70441 70442 70443 70444 70445 70446 70447 70448 70449 70450 70451 70452 70453 70454 70455 70456 70457 70458 70459 70460 70461 70462 70463 70464 70465 70466 70467 70468 70469 70470 70471 70472 70473 70474 70475 |
*/
static int vdbeSorterIterNext(
sqlite3 *db, /* Database handle (for sqlite3DbMalloc() ) */
VdbeSorterIter *pIter /* Iterator to advance */
){
int rc; /* Return Code */
int nRead; /* Number of bytes read */
int nRec = 0; /* Size of record in bytes */
int iOff = 0; /* Size of serialized size varint in bytes */
assert( pIter->iEof>=pIter->iReadOff );
if( pIter->iEof-pIter->iReadOff>5 ){
nRead = 5;
}else{
nRead = (int)(pIter->iEof - pIter->iReadOff);
}
if( nRead<=0 ){
/* This is an EOF condition */
vdbeSorterIterZero(db, pIter);
return SQLITE_OK;
}
rc = sqlite3OsRead(pIter->pFile, pIter->aAlloc, nRead, pIter->iReadOff);
if( rc==SQLITE_OK ){
iOff = getVarint32(pIter->aAlloc, nRec);
if( (iOff+nRec)>nRead ){
int nRead2; /* Number of extra bytes to read */
if( (iOff+nRec)>pIter->nAlloc ){
int nNew = pIter->nAlloc*2;
while( (iOff+nRec)>nNew ) nNew = nNew*2;
pIter->aAlloc = sqlite3DbReallocOrFree(db, pIter->aAlloc, nNew);
if( !pIter->aAlloc ) return SQLITE_NOMEM;
pIter->nAlloc = nNew;
}
nRead2 = iOff + nRec - nRead;
rc = sqlite3OsRead(
pIter->pFile, &pIter->aAlloc[nRead], nRead2, pIter->iReadOff+nRead
);
}
}
assert( rc!=SQLITE_OK || nRec>0 );
pIter->iReadOff += iOff+nRec;
pIter->nKey = nRec;
pIter->aKey = &pIter->aAlloc[iOff];
return rc;
}
/*
|
| ︙ | ︙ | |||
70432 70433 70434 70435 70436 70437 70438 | ** (i.e. if no IO error occurs), then *piOffset is set to the offset of ** the first byte past the end of the varint before returning. *piVal is ** set to the integer value read. If an error occurs, the final values of ** both *piOffset and *piVal are undefined. */ static int vdbeSorterReadVarint( sqlite3_file *pFile, /* File to read from */ | < < < < < < < | | 70505 70506 70507 70508 70509 70510 70511 70512 70513 70514 70515 70516 70517 70518 70519 70520 70521 70522 70523 70524 70525 70526 |
** (i.e. if no IO error occurs), then *piOffset is set to the offset of
** the first byte past the end of the varint before returning. *piVal is
** set to the integer value read. If an error occurs, the final values of
** both *piOffset and *piVal are undefined.
*/
static int vdbeSorterReadVarint(
sqlite3_file *pFile, /* File to read from */
i64 *piOffset, /* IN/OUT: Read offset in pFile */
i64 *piVal /* OUT: Value read from file */
){
u8 aVarint[9]; /* Buffer large enough for a varint */
i64 iOff = *piOffset; /* Offset in file to read from */
int rc; /* Return code */
rc = sqlite3OsRead(pFile, aVarint, 9, iOff);
if( rc==SQLITE_OK ){
*piOffset += getVarint(aVarint, (u64 *)piVal);
}
return rc;
}
|
| ︙ | ︙ | |||
70478 70479 70480 70481 70482 70483 70484 |
pIter->pFile = pSorter->pTemp1;
pIter->iReadOff = iStart;
pIter->nAlloc = 128;
pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc);
if( !pIter->aAlloc ){
rc = SQLITE_NOMEM;
}else{
| < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 70544 70545 70546 70547 70548 70549 70550 70551 70552 70553 70554 70555 70556 70557 70558 70559 70560 70561 70562 70563 70564 70565 70566 70567 70568 70569 70570 70571 70572 70573 70574 70575 70576 70577 70578 70579 70580 70581 70582 70583 70584 70585 70586 70587 70588 70589 70590 70591 70592 70593 70594 70595 70596 70597 70598 70599 70600 70601 70602 70603 70604 70605 70606 70607 70608 70609 70610 70611 70612 70613 70614 70615 |
pIter->pFile = pSorter->pTemp1;
pIter->iReadOff = iStart;
pIter->nAlloc = 128;
pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc);
if( !pIter->aAlloc ){
rc = SQLITE_NOMEM;
}else{
i64 nByte; /* Total size of PMA in bytes */
rc = vdbeSorterReadVarint(pSorter->pTemp1, &pIter->iReadOff, &nByte);
*pnByte += nByte;
pIter->iEof = pIter->iReadOff + nByte;
}
if( rc==SQLITE_OK ){
rc = vdbeSorterIterNext(db, pIter);
}
return rc;
}
/*
** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
** size nKey2 bytes). Argument pKeyInfo supplies the collation functions
** used by the comparison. If an error occurs, return an SQLite error code.
** Otherwise, return SQLITE_OK and set *pRes to a negative, zero or positive
** value, depending on whether key1 is smaller, equal to or larger than key2.
**
** If the bOmitRowid argument is non-zero, assume both keys end in a rowid
** field. For the purposes of the comparison, ignore it. Also, if bOmitRowid
** is true and key1 contains even a single NULL value, it is considered to
** be less than key2. Even if key2 also contains NULL values.
**
** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace
** has been allocated and contains an unpacked record that is used as key2.
*/
static void vdbeSorterCompare(
VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */
int bOmitRowid, /* Ignore rowid field at end of keys */
void *pKey1, int nKey1, /* Left side of comparison */
void *pKey2, int nKey2, /* Right side of comparison */
int *pRes /* OUT: Result of comparison */
){
KeyInfo *pKeyInfo = pCsr->pKeyInfo;
VdbeSorter *pSorter = pCsr->pSorter;
UnpackedRecord *r2 = pSorter->pUnpacked;
int i;
if( pKey2 ){
sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2);
}
if( bOmitRowid ){
r2->nField = pKeyInfo->nField;
assert( r2->nField>0 );
for(i=0; i<r2->nField; i++){
if( r2->aMem[i].flags & MEM_Null ){
*pRes = -1;
return;
}
}
r2->flags |= UNPACKED_PREFIX_MATCH;
}
*pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2);
}
/*
** This function is called to compare two iterator keys when merging
** multiple b-tree segments. Parameter iOut is the index of the aTree[]
** value to recalculate.
*/
static int vdbeSorterDoCompare(VdbeCursor *pCsr, int iOut){
VdbeSorter *pSorter = pCsr->pSorter;
|
| ︙ | ︙ | |||
70521 70522 70523 70524 70525 70526 70527 |
p2 = &pSorter->aIter[i2];
if( p1->pFile==0 ){
iRes = i2;
}else if( p2->pFile==0 ){
iRes = i1;
}else{
| | | | < | < | < < > > > > > | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < < | < < | > | > > > | | | | > < | | < < < | < < | < < < < < < < < < < < < < < | | | | | < | | | | > > > | | > | | | < < < < < < < < < < | | > > > | < | | | < | | > > | | < < < | < | < | | < < < < < < < < | > > > | < > > | | | < | | | < < < | < < | < | | < < < | | | | 70633 70634 70635 70636 70637 70638 70639 70640 70641 70642 70643 70644 70645 70646 70647 70648 70649 70650 70651 70652 70653 70654 70655 70656 70657 70658 70659 70660 70661 70662 70663 70664 70665 70666 70667 70668 70669 70670 70671 70672 70673 70674 70675 70676 70677 70678 70679 70680 70681 70682 70683 70684 70685 70686 70687 70688 70689 70690 70691 70692 70693 70694 70695 70696 70697 70698 70699 70700 70701 70702 70703 70704 70705 70706 70707 70708 70709 70710 70711 70712 70713 70714 70715 70716 70717 70718 70719 70720 70721 70722 70723 70724 70725 70726 70727 70728 70729 70730 70731 70732 70733 70734 70735 70736 70737 70738 70739 70740 70741 70742 70743 70744 70745 70746 70747 70748 70749 70750 70751 70752 70753 70754 70755 70756 70757 70758 70759 70760 70761 70762 70763 70764 70765 70766 70767 70768 70769 70770 70771 70772 70773 70774 70775 70776 70777 70778 70779 70780 70781 70782 70783 70784 70785 70786 70787 70788 70789 70790 70791 70792 70793 70794 70795 70796 70797 70798 70799 70800 70801 70802 70803 70804 70805 70806 70807 70808 70809 70810 70811 70812 70813 70814 70815 70816 70817 70818 70819 70820 70821 70822 70823 70824 70825 70826 70827 70828 70829 70830 70831 70832 70833 70834 70835 70836 70837 70838 70839 70840 70841 70842 70843 70844 70845 70846 70847 70848 70849 70850 70851 70852 70853 70854 70855 70856 70857 70858 70859 70860 70861 70862 70863 70864 70865 70866 70867 70868 70869 70870 70871 70872 70873 70874 70875 70876 70877 70878 70879 70880 70881 70882 70883 70884 70885 70886 70887 70888 70889 70890 70891 70892 70893 70894 70895 70896 70897 70898 70899 70900 70901 70902 70903 70904 70905 70906 70907 70908 70909 70910 70911 70912 70913 70914 70915 70916 70917 70918 70919 70920 70921 70922 70923 70924 70925 70926 70927 70928 70929 70930 70931 70932 70933 70934 70935 70936 70937 70938 70939 70940 70941 70942 70943 70944 70945 70946 70947 70948 70949 70950 70951 |
p2 = &pSorter->aIter[i2];
if( p1->pFile==0 ){
iRes = i2;
}else if( p2->pFile==0 ){
iRes = i1;
}else{
int res;
assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */
vdbeSorterCompare(
pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res
);
if( res<=0 ){
iRes = i1;
}else{
iRes = i2;
}
}
pSorter->aTree[iOut] = iRes;
return SQLITE_OK;
}
/*
** Initialize the temporary index cursor just opened as a sorter cursor.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){
int pgsz; /* Page size of main database */
int mxCache; /* Cache size */
VdbeSorter *pSorter; /* The new sorter */
char *d; /* Dummy */
assert( pCsr->pKeyInfo && pCsr->pBt==0 );
pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter));
if( pSorter==0 ){
return SQLITE_NOMEM;
}
pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo, 0, 0, &d);
if( pSorter->pUnpacked==0 ) return SQLITE_NOMEM;
assert( pSorter->pUnpacked==(UnpackedRecord *)d );
if( !sqlite3TempInMemory(db) ){
pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz;
mxCache = db->aDb[0].pSchema->cache_size;
if( mxCache<SORTER_MIN_WORKING ) mxCache = SORTER_MIN_WORKING;
pSorter->mxPmaSize = mxCache * pgsz;
}
return SQLITE_OK;
}
/*
** Free the list of sorted records starting at pRecord.
*/
static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
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 ){
if( pSorter->aIter ){
int i;
for(i=0; i<pSorter->nTree; i++){
vdbeSorterIterZero(db, &pSorter->aIter[i]);
}
sqlite3DbFree(db, pSorter->aIter);
}
if( pSorter->pTemp1 ){
sqlite3OsCloseFree(pSorter->pTemp1);
}
vdbeSorterRecordFree(db, pSorter->pRecord);
sqlite3DbFree(db, pSorter->pUnpacked);
sqlite3DbFree(db, pSorter);
pCsr->pSorter = 0;
}
}
/*
** Allocate space for a file-handle and open a temporary file. If successful,
** set *ppFile to point to the malloc'd file-handle and return SQLITE_OK.
** Otherwise, set *ppFile to 0 and return an SQLite error code.
*/
static int vdbeSorterOpenTempFile(sqlite3 *db, sqlite3_file **ppFile){
int dummy;
return sqlite3OsOpenMalloc(db->pVfs, 0, ppFile,
SQLITE_OPEN_TEMP_JOURNAL |
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &dummy
);
}
/*
** Merge the two sorted lists p1 and p2 into a single list.
** Set *ppOut to the head of the new list.
*/
static void vdbeSorterMerge(
VdbeCursor *pCsr, /* For pKeyInfo */
SorterRecord *p1, /* First list to merge */
SorterRecord *p2, /* Second list to merge */
SorterRecord **ppOut /* OUT: Head of merged list */
){
SorterRecord *pFinal = 0;
SorterRecord **pp = &pFinal;
void *pVal2 = p2 ? p2->pVal : 0;
while( p1 && p2 ){
int res;
vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res);
if( res<=0 ){
*pp = p1;
pp = &p1->pNext;
p1 = p1->pNext;
pVal2 = 0;
}else{
*pp = p2;
pp = &p2->pNext;
p2 = p2->pNext;
if( p2==0 ) break;
pVal2 = p2->pVal;
}
}
*pp = p1 ? p1 : p2;
*ppOut = pFinal;
}
/*
** Sort the linked list of records headed at pCsr->pRecord. Return SQLITE_OK
** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error
** occurs.
*/
static int vdbeSorterSort(VdbeCursor *pCsr){
int i;
SorterRecord **aSlot;
SorterRecord *p;
VdbeSorter *pSorter = pCsr->pSorter;
aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
if( !aSlot ){
return SQLITE_NOMEM;
}
p = pSorter->pRecord;
while( p ){
SorterRecord *pNext = p->pNext;
p->pNext = 0;
for(i=0; aSlot[i]; i++){
vdbeSorterMerge(pCsr, p, aSlot[i], &p);
aSlot[i] = 0;
}
aSlot[i] = p;
p = pNext;
}
p = 0;
for(i=0; i<64; i++){
vdbeSorterMerge(pCsr, p, aSlot[i], &p);
}
pSorter->pRecord = p;
sqlite3_free(aSlot);
return SQLITE_OK;
}
/*
** Write the current contents of the in-memory linked-list to a PMA. Return
** SQLITE_OK if successful, or an SQLite error code otherwise.
**
** The format of a PMA is:
**
** * A varint. This varint contains the total number of bytes of content
** in the PMA (not including the varint itself).
**
** * One or more records packed end-to-end in order of ascending keys.
** Each record consists of a varint followed by a blob of data (the
** key). The varint is the number of bytes in the blob of data.
*/
static int vdbeSorterListToPMA(sqlite3 *db, VdbeCursor *pCsr){
int rc = SQLITE_OK; /* Return code */
VdbeSorter *pSorter = pCsr->pSorter;
if( pSorter->nInMemory==0 ){
assert( pSorter->pRecord==0 );
return rc;
}
rc = vdbeSorterSort(pCsr);
/* If the first temporary PMA file has not been opened, open it now. */
if( rc==SQLITE_OK && pSorter->pTemp1==0 ){
rc = vdbeSorterOpenTempFile(db, &pSorter->pTemp1);
assert( rc!=SQLITE_OK || pSorter->pTemp1 );
assert( pSorter->iWriteOff==0 );
assert( pSorter->nPMA==0 );
}
if( rc==SQLITE_OK ){
i64 iOff = pSorter->iWriteOff;
SorterRecord *p;
SorterRecord *pNext = 0;
static const char eightZeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
pSorter->nPMA++;
rc = vdbeSorterWriteVarint(pSorter->pTemp1, pSorter->nInMemory, &iOff);
for(p=pSorter->pRecord; rc==SQLITE_OK && p; p=pNext){
pNext = p->pNext;
rc = vdbeSorterWriteVarint(pSorter->pTemp1, p->nVal, &iOff);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pSorter->pTemp1, p->pVal, p->nVal, iOff);
iOff += p->nVal;
}
sqlite3DbFree(db, p);
}
/* This assert verifies that unless an error has occurred, the size of
** the PMA on disk is the same as the expected size stored in
** pSorter->nInMemory. */
assert( rc!=SQLITE_OK || pSorter->nInMemory==(
iOff-pSorter->iWriteOff-sqlite3VarintLen(pSorter->nInMemory)
));
pSorter->iWriteOff = iOff;
if( rc==SQLITE_OK ){
/* Terminate each file with 8 extra bytes so that from any offset
** in the file we can always read 9 bytes without a SHORT_READ error */
rc = sqlite3OsWrite(pSorter->pTemp1, eightZeros, 8, iOff);
}
pSorter->pRecord = p;
}
return rc;
}
/*
** Add a record to the sorter.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
sqlite3 *db, /* Database handle */
VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal /* Memory cell containing record */
){
VdbeSorter *pSorter = pCsr->pSorter;
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
assert( pSorter );
pSorter->nInMemory += sqlite3VarintLen(pVal->n) + pVal->n;
pNew = (SorterRecord *)sqlite3DbMallocRaw(db, pVal->n + sizeof(SorterRecord));
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
pNew->pVal = (void *)&pNew[1];
memcpy(pNew->pVal, pVal->z, pVal->n);
pNew->nVal = pVal->n;
pNew->pNext = pSorter->pRecord;
pSorter->pRecord = pNew;
}
/* See if the contents of the sorter should now be written out. They
** are written out when either of the following are true:
**
** * The total memory allocated for the in-memory list is greater
** than (page-size * cache-size), or
**
** * The total memory allocated for the in-memory list is greater
** than (page-size * 10) and sqlite3HeapNearlyFull() returns true.
*/
if( rc==SQLITE_OK && pSorter->mxPmaSize>0 && (
(pSorter->nInMemory>pSorter->mxPmaSize)
|| (pSorter->nInMemory>pSorter->mnPmaSize && sqlite3HeapNearlyFull())
)){
rc = vdbeSorterListToPMA(db, pCsr);
pSorter->nInMemory = 0;
}
return rc;
}
/*
** Helper function for sqlite3VdbeSorterRewind().
*/
static int vdbeSorterInitMerge(
sqlite3 *db, /* Database handle */
VdbeCursor *pCsr, /* Cursor handle for this sorter */
i64 *pnByte /* Sum of bytes in all opened PMAs */
){
VdbeSorter *pSorter = pCsr->pSorter;
int rc = SQLITE_OK; /* Return code */
int i; /* Used to iterator through aIter[] */
i64 nByte = 0; /* Total bytes in all opened PMAs */
/* Initialize the iterators. */
for(i=0; i<SORTER_MAX_MERGE_COUNT; i++){
VdbeSorterIter *pIter = &pSorter->aIter[i];
rc = vdbeSorterIterInit(db, pSorter, pSorter->iReadOff, pIter, &nByte);
pSorter->iReadOff = pIter->iEof;
assert( rc!=SQLITE_OK || pSorter->iReadOff<=pSorter->iWriteOff );
if( rc!=SQLITE_OK || pSorter->iReadOff>=pSorter->iWriteOff ) break;
}
/* Initialize the aTree[] array. */
for(i=pSorter->nTree-1; rc==SQLITE_OK && i>0; i--){
rc = vdbeSorterDoCompare(pCsr, i);
}
|
| ︙ | ︙ | |||
70791 70792 70793 70794 70795 70796 70797 | i64 iWrite2 = 0; /* Write offset for pTemp2 */ int nIter; /* Number of iterators used */ int nByte; /* Bytes of space required for aIter/aTree */ int N = 2; /* Power of 2 >= nIter */ assert( pSorter ); | | | | < | > | > > > > | 70964 70965 70966 70967 70968 70969 70970 70971 70972 70973 70974 70975 70976 70977 70978 70979 70980 70981 70982 70983 70984 70985 70986 70987 70988 70989 |
i64 iWrite2 = 0; /* Write offset for pTemp2 */
int nIter; /* Number of iterators used */
int nByte; /* Bytes of space required for aIter/aTree */
int N = 2; /* Power of 2 >= nIter */
assert( pSorter );
/* If no data has been written to disk, then do not do so now. Instead,
** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly
** from the in-memory list. */
if( pSorter->nPMA==0 ){
*pbEof = !pSorter->pRecord;
assert( pSorter->aTree==0 );
return vdbeSorterSort(pCsr);
}
/* Write the current b-tree to a PMA. Close the b-tree cursor. */
rc = vdbeSorterListToPMA(db, pCsr);
if( rc!=SQLITE_OK ) return rc;
/* Allocate space for aIter[] and aTree[]. */
nIter = pSorter->nPMA;
if( nIter>SORTER_MAX_MERGE_COUNT ) nIter = SORTER_MAX_MERGE_COUNT;
assert( nIter>0 );
while( N<nIter ) N += N;
nByte = N * (sizeof(int) + sizeof(VdbeSorterIter));
|
| ︙ | ︙ | |||
70886 70887 70888 70889 70890 70891 70892 |
}
/*
** Advance to the next element in the sorter.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter;
| > > > | | < | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < < < < | < | | > > > > > > > > > > > > > > > > > > > > > > > | 71063 71064 71065 71066 71067 71068 71069 71070 71071 71072 71073 71074 71075 71076 71077 71078 71079 71080 71081 71082 71083 71084 71085 71086 71087 71088 71089 71090 71091 71092 71093 71094 71095 71096 71097 71098 71099 71100 71101 71102 71103 71104 71105 71106 71107 71108 71109 71110 71111 71112 71113 71114 71115 71116 71117 71118 71119 71120 71121 71122 71123 71124 71125 71126 71127 71128 71129 71130 71131 71132 71133 71134 71135 71136 71137 71138 71139 71140 71141 71142 71143 71144 71145 71146 71147 71148 71149 71150 71151 71152 71153 71154 71155 71156 71157 71158 71159 71160 |
}
/*
** Advance to the next element in the sorter.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, 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 */
int i; /* Index of aTree[] to recalculate */
rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){
rc = vdbeSorterDoCompare(pCsr, i);
}
*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;
}
return rc;
}
/*
** Return a pointer to a buffer owned by the sorter that contains the
** current key.
*/
static void *vdbeSorterRowkey(
VdbeSorter *pSorter, /* Sorter object */
int *pnKey /* OUT: Size of current key in bytes */
){
void *pKey;
if( pSorter->aTree ){
VdbeSorterIter *pIter;
pIter = &pSorter->aIter[ pSorter->aTree[1] ];
*pnKey = pIter->nKey;
pKey = pIter->aKey;
}else{
*pnKey = pSorter->pRecord->nVal;
pKey = pSorter->pRecord->pVal;
}
return pKey;
}
/*
** Copy the current sorter key into the memory cell pOut.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(VdbeCursor *pCsr, Mem *pOut){
VdbeSorter *pSorter = pCsr->pSorter;
void *pKey; int nKey; /* Sorter key to copy into pOut */
pKey = vdbeSorterRowkey(pSorter, &nKey);
if( sqlite3VdbeMemGrow(pOut, nKey, 0) ){
return SQLITE_NOMEM;
}
pOut->n = nKey;
MemSetTypeFlag(pOut, MEM_Blob);
memcpy(pOut->z, pKey, nKey);
return SQLITE_OK;
}
/*
** Compare the key in memory cell pVal with the key that the sorter cursor
** passed as the first argument currently points to. For the purposes of
** the comparison, ignore the rowid field at the end of each record.
**
** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM).
** Otherwise, set *pRes to a negative, zero or positive value if the
** key in pVal is smaller than, equal to or larger than the current sorter
** key.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal, /* Value to compare to current sorter key */
int *pRes /* OUT: Result of comparison */
){
VdbeSorter *pSorter = pCsr->pSorter;
void *pKey; int nKey; /* Sorter key to compare pVal with */
pKey = vdbeSorterRowkey(pSorter, &nKey);
vdbeSorterCompare(pCsr, 1, pVal->z, pVal->n, pKey, nKey, pRes);
return SQLITE_OK;
}
#endif /* #ifndef SQLITE_OMIT_MERGE_SORT */
/************** End of vdbesort.c ********************************************/
/************** Begin file journal.c *****************************************/
/*
** 2007 August 22
|
| ︙ | ︙ | |||
73689 73690 73691 73692 73693 73694 73695 |
struct SrcList_item *pOldItem = &p->a[i];
Table *pTab;
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
pNewItem->jointype = pOldItem->jointype;
pNewItem->iCursor = pOldItem->iCursor;
| > | | 73913 73914 73915 73916 73917 73918 73919 73920 73921 73922 73923 73924 73925 73926 73927 73928 |
struct SrcList_item *pOldItem = &p->a[i];
Table *pTab;
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
pNewItem->jointype = pOldItem->jointype;
pNewItem->iCursor = pOldItem->iCursor;
pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn;
pNewItem->isCorrelated = pOldItem->isCorrelated;
pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex);
pNewItem->notIndexed = pOldItem->notIndexed;
pNewItem->pIndex = pOldItem->pIndex;
pTab = pNewItem->pTab = pOldItem->pTab;
if( pTab ){
pTab->nRef++;
|
| ︙ | ︙ | |||
74249 74250 74251 74252 74253 74254 74255 |
** successful here.
*/
assert(v);
if( iCol<0 ){
int iMem = ++pParse->nMem;
int iAddr;
| | < | 74474 74475 74476 74477 74478 74479 74480 74481 74482 74483 74484 74485 74486 74487 74488 |
** successful here.
*/
assert(v);
if( iCol<0 ){
int iMem = ++pParse->nMem;
int iAddr;
iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
eType = IN_INDEX_ROWID;
sqlite3VdbeJumpHere(v, iAddr);
}else{
Index *pIdx; /* Iterator variable */
|
| ︙ | ︙ | |||
74281 74282 74283 74284 74285 74286 74287 |
&& (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
){
int iMem = ++pParse->nMem;
int iAddr;
char *pKey;
pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
| | < | 74505 74506 74507 74508 74509 74510 74511 74512 74513 74514 74515 74516 74517 74518 74519 |
&& (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
){
int iMem = ++pParse->nMem;
int iAddr;
char *pKey;
pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
pKey,P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
eType = IN_INDEX_INDEX;
sqlite3VdbeJumpHere(v, iAddr);
|
| ︙ | ︙ | |||
74363 74364 74365 74366 74367 74368 74369 |
#ifndef SQLITE_OMIT_SUBQUERY
SQLITE_PRIVATE int sqlite3CodeSubselect(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
int rMayHaveNull, /* Register that records whether NULLs exist in RHS */
int isRowid /* If true, LHS of IN operator is a rowid */
){
| | < | < | | 74586 74587 74588 74589 74590 74591 74592 74593 74594 74595 74596 74597 74598 74599 74600 74601 74602 74603 74604 74605 74606 74607 74608 74609 74610 74611 74612 74613 74614 74615 74616 74617 74618 74619 74620 74621 74622 74623 74624 |
#ifndef SQLITE_OMIT_SUBQUERY
SQLITE_PRIVATE int sqlite3CodeSubselect(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
int rMayHaveNull, /* Register that records whether NULLs exist in RHS */
int isRowid /* If true, LHS of IN operator is a rowid */
){
int testAddr = -1; /* One-time test address */
int rReg = 0; /* Register storing resulting */
Vdbe *v = sqlite3GetVdbe(pParse);
if( NEVER(v==0) ) return 0;
sqlite3ExprCachePush(pParse);
/* This code must be run in its entirety every time it is encountered
** if any of the following is true:
**
** * The right-hand side is a correlated subquery
** * The right-hand side is an expression list containing variables
** * We are inside a trigger
**
** If all of the above are false, then we can run this code just once
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){
int mem = ++pParse->nMem;
testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem);
}
#ifndef SQLITE_OMIT_EXPLAIN
if( pParse->explain==2 ){
char *zMsg = sqlite3MPrintf(
pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ",
pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
);
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
}
#endif
switch( pExpr->op ){
|
| ︙ | ︙ | |||
74481 74482 74483 74484 74485 74486 74487 |
int iValToIns;
/* If the expression is not constant then we will need to
** disable the test that was generated above that makes sure
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
| | | | | 74702 74703 74704 74705 74706 74707 74708 74709 74710 74711 74712 74713 74714 74715 74716 74717 74718 |
int iValToIns;
/* If the expression is not constant then we will need to
** disable the test that was generated above that makes sure
** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time.
*/
if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){
sqlite3VdbeChangeToNoop(v, testAddr);
testAddr = -1;
}
/* Evaluate the expression and insert it into the temp table */
if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
}else{
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
| ︙ | ︙ | |||
74552 74553 74554 74555 74556 74557 74558 |
}
rReg = dest.iParm;
ExprSetIrreducible(pExpr);
break;
}
}
| | | | 74773 74774 74775 74776 74777 74778 74779 74780 74781 74782 74783 74784 74785 74786 74787 74788 |
}
rReg = dest.iParm;
ExprSetIrreducible(pExpr);
break;
}
}
if( testAddr>=0 ){
sqlite3VdbeJumpHere(v, testAddr);
}
sqlite3ExprCachePop(pParse, 1);
return rReg;
}
#endif /* SQLITE_OMIT_SUBQUERY */
|
| ︙ | ︙ | |||
75075 75076 75077 75078 75079 75080 75081 |
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
assert( pCol->iMem>0 );
inReg = pCol->iMem;
break;
}else if( pAggInfo->useSortingIdx ){
| | | 75296 75297 75298 75299 75300 75301 75302 75303 75304 75305 75306 75307 75308 75309 75310 |
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
assert( pCol->iMem>0 );
inReg = pCol->iMem;
break;
}else if( pAggInfo->useSortingIdx ){
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pCol->iSorterColumn, target);
break;
}
/* Otherwise, fall thru into the TK_COLUMN case */
}
case TK_COLUMN: {
if( pExpr->iTable<0 ){
|
| ︙ | ︙ | |||
81233 81234 81235 81236 81237 81238 81239 81240 81241 81242 81243 81244 81245 81246 81247 |
*/
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
Table *pTab = pIndex->pTable; /* The table that is indexed */
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
int iSorter = iTab; /* Cursor opened by OpenSorter (if in use) */
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
KeyInfo *pKey; /* KeyInfo for index */
int regIdxKey; /* Registers containing the index key */
int regRecord; /* Register holding assemblied index record */
sqlite3 *db = pParse->db; /* The database connection */
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
| > < < < < < < < < < | 81454 81455 81456 81457 81458 81459 81460 81461 81462 81463 81464 81465 81466 81467 81468 81469 81470 81471 81472 81473 81474 81475 81476 |
*/
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
Table *pTab = pIndex->pTable; /* The table that is indexed */
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
int iSorter = iTab; /* Cursor opened by OpenSorter (if in use) */
int addr1; /* Address of top of loop */
int addr2; /* Address to jump to for next iteration */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
KeyInfo *pKey; /* KeyInfo for index */
int regIdxKey; /* Registers containing the index key */
int regRecord; /* Register holding assemblied index record */
sqlite3 *db = pParse->db; /* The database connection */
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
db->aDb[iDb].zName ) ){
return;
}
#endif
|
| ︙ | ︙ | |||
81275 81276 81277 81278 81279 81280 81281 81282 |
pKey = sqlite3IndexKeyinfo(pParse, pIndex);
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
(char *)pKey, P4_KEYINFO_HANDOFF);
if( memRootPage>=0 ){
sqlite3VdbeChangeP5(v, 1);
}
/* Open the sorter cursor if we are to use one. */
| > < | | | < > < > | | | | > > | > > > > > | > | > > > > | > | | 81488 81489 81490 81491 81492 81493 81494 81495 81496 81497 81498 81499 81500 81501 81502 81503 81504 81505 81506 81507 81508 81509 81510 81511 81512 81513 81514 81515 81516 81517 81518 81519 81520 81521 81522 81523 81524 81525 81526 81527 81528 81529 81530 81531 81532 81533 81534 81535 81536 81537 81538 81539 81540 81541 81542 81543 81544 81545 81546 81547 81548 81549 81550 81551 81552 81553 81554 81555 81556 81557 81558 |
pKey = sqlite3IndexKeyinfo(pParse, pIndex);
sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
(char *)pKey, P4_KEYINFO_HANDOFF);
if( memRootPage>=0 ){
sqlite3VdbeChangeP5(v, 1);
}
#ifndef SQLITE_OMIT_MERGE_SORT
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)pKey, P4_KEYINFO);
#endif
/* Open the table. Loop through all rows of the table, inserting index
** records into the sorter. */
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
addr2 = addr1 + 1;
regRecord = sqlite3GetTempReg(pParse);
regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
#ifndef SQLITE_OMIT_MERGE_SORT
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
sqlite3VdbeJumpHere(v, addr1);
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0);
if( pIndex->onError!=OE_None ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
addr2 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord);
sqlite3HaltConstraint(
pParse, OE_Abort, "indexed columns are not unique", P4_STATIC
);
}else{
addr2 = sqlite3VdbeCurrentAddr(v);
}
sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
#else
if( pIndex->onError!=OE_None ){
const int regRowid = regIdxKey + pIndex->nColumn;
const int j2 = sqlite3VdbeCurrentAddr(v) + 2;
void * const pRegKey = SQLITE_INT_TO_PTR(regIdxKey);
/* The registers accessed by the OP_IsUnique opcode were allocated
** using sqlite3GetTempRange() inside of the sqlite3GenerateIndexKey()
** call above. Just before that function was freed they were released
** (made available to the compiler for reuse) using
** sqlite3ReleaseTempRange(). So in some ways having the OP_IsUnique
** opcode use the values stored within seems dangerous. However, since
** we can be sure that no other temp registers have been allocated
** since sqlite3ReleaseTempRange() was called, it is safe to do so.
*/
sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
sqlite3HaltConstraint(
pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
}
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
#endif
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp1(v, OP_Close, iTab);
sqlite3VdbeAddOp1(v, OP_Close, iIdx);
sqlite3VdbeAddOp1(v, OP_Close, iSorter);
}
|
| ︙ | ︙ | |||
92202 92203 92204 92205 92206 92207 92208 92209 92210 92211 92212 92213 92214 92215 |
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->addrOpenEphm[2] = -1;
if( db->mallocFailed ) {
clearSelect(db, pNew);
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
pNew = 0;
}
return pNew;
}
/*
** Delete the given Select structure and all of its substructures.
*/
| > > | 92428 92429 92430 92431 92432 92433 92434 92435 92436 92437 92438 92439 92440 92441 92442 92443 |
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->addrOpenEphm[2] = -1;
if( db->mallocFailed ) {
clearSelect(db, pNew);
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
pNew = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
}
return pNew;
}
/*
** Delete the given Select structure and all of its substructures.
*/
|
| ︙ | ︙ | |||
92532 92533 92534 92535 92536 92537 92538 92539 92540 92541 92542 92543 |
Select *pSelect, /* The whole SELECT statement */
int regData /* Register holding data to be sorted */
){
Vdbe *v = pParse->pVdbe;
int nExpr = pOrderBy->nExpr;
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
int regRecord = sqlite3GetTempReg(pParse);
sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
| > > > > > > | | 92760 92761 92762 92763 92764 92765 92766 92767 92768 92769 92770 92771 92772 92773 92774 92775 92776 92777 92778 92779 92780 92781 92782 92783 92784 92785 |
Select *pSelect, /* The whole SELECT statement */
int regData /* Register holding data to be sorted */
){
Vdbe *v = pParse->pVdbe;
int nExpr = pOrderBy->nExpr;
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
int regRecord = sqlite3GetTempReg(pParse);
int op;
sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
if( pSelect->selFlags & SF_UseSorter ){
op = OP_SorterInsert;
}else{
op = OP_IdxInsert;
}
sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
if( pSelect->iLimit ){
int addr1, addr2;
int iLimit;
if( pSelect->iOffset ){
iLimit = pSelect->iOffset+1;
|
| ︙ | ︙ | |||
93006 93007 93008 93009 93010 93011 93012 |
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
pseudoTab = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
regRowid = 0;
}else{
regRowid = sqlite3GetTempReg(pParse);
}
| > > > > > > > > > > | | | > | 93240 93241 93242 93243 93244 93245 93246 93247 93248 93249 93250 93251 93252 93253 93254 93255 93256 93257 93258 93259 93260 93261 93262 93263 93264 93265 93266 93267 |
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
pseudoTab = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
regRowid = 0;
}else{
regRowid = sqlite3GetTempReg(pParse);
}
if( p->selFlags & SF_UseSorter ){
int regSortOut = ++pParse->nMem;
int ptab2 = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+2);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
codeOffset(v, p, addrContinue);
sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
sqlite3VdbeAddOp3(v, OP_Column, ptab2, pOrderBy->nExpr+1, regRow);
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
}else{
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak);
codeOffset(v, p, addrContinue);
sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+1, regRow);
}
switch( eDest ){
case SRT_Table:
case SRT_EphemTab: {
testcase( eDest==SRT_Table );
testcase( eDest==SRT_EphemTab );
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
|
| ︙ | ︙ | |||
93061 93062 93063 93064 93065 93066 93067 | } sqlite3ReleaseTempReg(pParse, regRow); sqlite3ReleaseTempReg(pParse, regRowid); /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); | > > > | > | 93306 93307 93308 93309 93310 93311 93312 93313 93314 93315 93316 93317 93318 93319 93320 93321 93322 93323 93324 |
}
sqlite3ReleaseTempReg(pParse, regRow);
sqlite3ReleaseTempReg(pParse, regRowid);
/* The bottom of the loop
*/
sqlite3VdbeResolveLabel(v, addrContinue);
if( p->selFlags & SF_UseSorter ){
sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr);
}else{
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr);
}
sqlite3VdbeResolveLabel(v, addrBreak);
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
}
}
/*
|
| ︙ | ︙ | |||
95893 95894 95895 95896 95897 95898 95899 |
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
SelectDest dest;
Select *pSub = pItem->pSelect;
int isAggSub;
| | > > > > < > > > > > > > > > > > > > > > > > > > > > < < > > > > > | 96142 96143 96144 96145 96146 96147 96148 96149 96150 96151 96152 96153 96154 96155 96156 96157 96158 96159 96160 96161 96162 96163 96164 96165 96166 96167 96168 96169 96170 96171 96172 96173 96174 96175 96176 96177 96178 96179 96180 96181 96182 96183 96184 96185 96186 96187 96188 96189 96190 96191 96192 96193 96194 96195 96196 96197 96198 96199 96200 96201 96202 96203 96204 96205 96206 96207 96208 |
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
SelectDest dest;
Select *pSub = pItem->pSelect;
int isAggSub;
if( pSub==0 ) continue;
if( pItem->addrFillSub ){
sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
continue;
}
/* Increment Parse.nHeight by the height of the largest expression
** tree refered to by this, the parent select. The child select
** may contain expression trees of at most
** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
** more conservative than necessary, but much easier than enforcing
** an exact limit.
*/
pParse->nHeight += sqlite3SelectExprHeight(p);
isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
/* This subquery can be absorbed into its parent. */
if( isAggSub ){
isAgg = 1;
p->selFlags |= SF_Aggregate;
}
i = -1;
}else{
/* Generate a subroutine that will fill an ephemeral table with
** the content of this subquery. pItem->addrFillSub will point
** to the address of the generated subroutine. pItem->regReturn
** is a register allocated to hold the subroutine return address
*/
int topAddr;
int onceAddr = 0;
int retAddr;
assert( pItem->addrFillSub==0 );
pItem->regReturn = ++pParse->nMem;
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
pItem->addrFillSub = topAddr+1;
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
/* If the subquery is no correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery
** once. */
int regOnce = ++pParse->nMem;
onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
sqlite3VdbeChangeP1(v, topAddr, retAddr);
}
if( /*pParse->nErr ||*/ db->mallocFailed ){
goto select_end;
}
pParse->nHeight -= sqlite3SelectExprHeight(p);
pTabList = p->pSrc;
if( !IgnorableOrderby(pDest) ){
|
| ︙ | ︙ | |||
96027 96028 96029 96030 96031 96032 96033 96034 96035 96036 96037 96038 96039 96040 |
}
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
p->nSelectRow = (double)LARGEST_INT64;
computeLimitRegisters(pParse, p, iEnd);
/* Open a virtual index to use for the distinct set.
*/
if( p->selFlags & SF_Distinct ){
KeyInfo *pKeyInfo;
distinct = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
| > > > > | 96303 96304 96305 96306 96307 96308 96309 96310 96311 96312 96313 96314 96315 96316 96317 96318 96319 96320 |
}
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
p->nSelectRow = (double)LARGEST_INT64;
computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && addrSortIndex>=0 ){
sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen;
p->selFlags |= SF_UseSorter;
}
/* Open a virtual index to use for the distinct set.
*/
if( p->selFlags & SF_Distinct ){
KeyInfo *pKeyInfo;
distinct = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
|
| ︙ | ︙ | |||
96055 96056 96057 96058 96059 96060 96061 |
if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
/* 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( addrSortIndex>=0 && pOrderBy==0 ){
| | | | 96335 96336 96337 96338 96339 96340 96341 96342 96343 96344 96345 96346 96347 96348 96349 96350 96351 96352 96353 96354 96355 96356 |
if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
/* 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( addrSortIndex>=0 && pOrderBy==0 ){
sqlite3VdbeChangeToNoop(v, addrSortIndex);
p->addrOpenEphm[2] = -1;
}
if( pWInfo->eDistinct ){
VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
assert( addrDistinctIndex>=0 );
pOp = sqlite3VdbeGetOp(v, addrDistinctIndex);
assert( isDistinct );
assert( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
|| pWInfo->eDistinct==WHERE_DISTINCT_UNIQUE
);
distinct = -1;
|
| ︙ | ︙ | |||
96121 96122 96123 96124 96125 96126 96127 96128 96129 96130 96131 96132 96133 96134 |
int iBMem; /* First Mem address for previous GROUP BY */
int iUseFlag; /* Mem address holding flag indicating that at least
** one row of the input to the aggregator has been
** processed */
int iAbortFlag; /* Mem address which causes query abort if positive */
int groupBySort; /* Rows come from source in GROUP BY order */
int addrEnd; /* End of processing for this SELECT */
/* Remove any and all aliases between the result set and the
** GROUP BY clause.
*/
if( pGroupBy ){
int k; /* Loop counter */
struct ExprList_item *pItem; /* For looping over expression in a list */
| > > | 96401 96402 96403 96404 96405 96406 96407 96408 96409 96410 96411 96412 96413 96414 96415 96416 |
int iBMem; /* First Mem address for previous GROUP BY */
int iUseFlag; /* Mem address holding flag indicating that at least
** one row of the input to the aggregator has been
** processed */
int iAbortFlag; /* Mem address which causes query abort if positive */
int groupBySort; /* Rows come from source in GROUP BY order */
int addrEnd; /* End of processing for this SELECT */
int sortPTab = 0; /* Pseudotable used to decode sorting results */
int sortOut = 0; /* Output register from the sorter */
/* Remove any and all aliases between the result set and the
** GROUP BY clause.
*/
if( pGroupBy ){
int k; /* Loop counter */
struct ExprList_item *pItem; /* For looping over expression in a list */
|
| ︙ | ︙ | |||
96182 96183 96184 96185 96186 96187 96188 |
int addrTopOfLoop; /* Top of the input loop */
int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */
int addrReset; /* Subroutine for resetting the accumulator */
int regReset; /* Return address register for reset subroutine */
/* 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
| | | | 96464 96465 96466 96467 96468 96469 96470 96471 96472 96473 96474 96475 96476 96477 96478 96479 96480 96481 96482 96483 |
int addrTopOfLoop; /* Top of the input loop */
int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */
int addrReset; /* Subroutine for resetting the accumulator */
int regReset; /* Return address register for reset subroutine */
/* 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);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
/* Initialize memory locations used by GROUP BY aggregate processing
*/
iUseFlag = ++pParse->nMem;
iAbortFlag = ++pParse->nMem;
|
| ︙ | ︙ | |||
96268 96269 96270 96271 96272 96273 96274 |
sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
}
j++;
}
}
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
| | > > > | > > > | > | 96550 96551 96552 96553 96554 96555 96556 96557 96558 96559 96560 96561 96562 96563 96564 96565 96566 96567 96568 96569 96570 96571 96572 96573 96574 96575 96576 96577 96578 96579 96580 96581 96582 96583 96584 96585 96586 96587 96588 96589 96590 |
sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
}
j++;
}
}
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
sqlite3WhereEnd(pWInfo);
sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort"));
sAggInfo.useSortingIdx = 1;
sqlite3ExprCacheClear(pParse);
}
/* Evaluate the current GROUP BY terms and store in b0, b1, b2...
** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
** Then compare the current GROUP BY terms against the GROUP BY terms
** from the previous row currently stored in a0, a1, a2...
*/
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
sqlite3ExprCacheClear(pParse);
if( groupBySort ){
sqlite3VdbeAddOp2(v, OP_SorterData, sAggInfo.sortingIdx, sortOut);
}
for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
if( j==0 ) sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
}else{
sAggInfo.directMode = 1;
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
}
}
sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
(char*)pKeyInfo, P4_KEYINFO);
|
| ︙ | ︙ | |||
96326 96327 96328 96329 96330 96331 96332 |
updateAccumulator(pParse, &sAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
VdbeComment((v, "indicate data in accumulator"));
/* End of the loop
*/
if( groupBySort ){
| | | | 96615 96616 96617 96618 96619 96620 96621 96622 96623 96624 96625 96626 96627 96628 96629 96630 96631 96632 |
updateAccumulator(pParse, &sAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
VdbeComment((v, "indicate data in accumulator"));
/* End of the loop
*/
if( groupBySort ){
sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
}else{
sqlite3WhereEnd(pWInfo);
sqlite3VdbeChangeToNoop(v, addrSortingIdx);
}
/* Output the final row of result
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
VdbeComment((v, "output final row"));
|
| ︙ | ︙ | |||
100515 100516 100517 100518 100519 100520 100521 100522 100523 100524 100525 100526 100527 100528 100529 100530 100531 100532 100533 |
}
}
return mask;
}
static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){
Bitmask mask = 0;
while( pS ){
mask |= exprListTableUsage(pMaskSet, pS->pEList);
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
mask |= exprTableUsage(pMaskSet, pS->pWhere);
mask |= exprTableUsage(pMaskSet, pS->pHaving);
pS = pS->pPrior;
}
return mask;
}
/*
** Return TRUE if the given operator is one of the operators that is
| > > > > > > > > | 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 |
}
}
return mask;
}
static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){
Bitmask mask = 0;
while( pS ){
SrcList *pSrc = pS->pSrc;
mask |= exprListTableUsage(pMaskSet, pS->pEList);
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
mask |= exprTableUsage(pMaskSet, pS->pWhere);
mask |= exprTableUsage(pMaskSet, pS->pHaving);
if( ALWAYS(pSrc!=0) ){
int i;
for(i=0; i<pSrc->nSrc; i++){
mask |= exprSelectTableUsage(pMaskSet, pSrc->a[i].pSelect);
mask |= exprTableUsage(pMaskSet, pSrc->a[i].pOn);
}
}
pS = pS->pPrior;
}
return mask;
}
/*
** Return TRUE if the given operator is one of the operators that is
|
| ︙ | ︙ | |||
102042 102043 102044 102045 102046 102047 102048 | Bitmask extraCols; /* Bitmap of additional columns */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ v = pParse->pVdbe; assert( v!=0 ); regIsInit = ++pParse->nMem; | | < | 102339 102340 102341 102342 102343 102344 102345 102346 102347 102348 102349 102350 102351 102352 102353 | Bitmask extraCols; /* Bitmap of additional columns */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ v = pParse->pVdbe; assert( v!=0 ); regIsInit = ++pParse->nMem; addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit); /* Count the number of columns that will be added to the index ** and used to match WHERE clause constraints */ nColumn = 0; pTable = pSrc->pTab; pWCEnd = &pWC->a[pWC->nTerm]; idxCols = 0; |
| ︙ | ︙ | |||
115979 115980 115981 115982 115983 115984 115985 | char *p2 = a2; char *p; char *aOut; int bFirstOut = 0; *paOut = 0; *pnOut = 0; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 116275 116276 116277 116278 116279 116280 116281 116282 116283 116284 116285 116286 116287 116288 116289 116290 116291 116292 116293 116294 116295 116296 116297 116298 116299 116300 116301 116302 116303 116304 116305 116306 116307 116308 116309 116310 116311 116312 116313 116314 116315 116316 116317 116318 116319 |
char *p2 = a2;
char *p;
char *aOut;
int bFirstOut = 0;
*paOut = 0;
*pnOut = 0;
/* Allocate space for the output. Both the input and output doclists
** are delta encoded. If they are in ascending order (bDescDoclist==0),
** then the first docid in each list is simply encoded as a varint. For
** each subsequent docid, the varint stored is the difference between the
** current and previous docid (a positive number - since the list is in
** ascending order).
**
** The first docid written to the output is therefore encoded using the
** same number of bytes as it is in whichever of the input lists it is
** read from. And each subsequent docid read from the same input list
** consumes either the same or less bytes as it did in the input (since
** the difference between it and the previous value in the output must
** be a positive value less than or equal to the delta value read from
** the input list). The same argument applies to all but the first docid
** read from the 'other' list. And to the contents of all position lists
** that will be copied and merged from the input to the output.
**
** However, if the first docid copied to the output is a negative number,
** then the encoding of the first docid from the 'other' input list may
** be larger in the output than it was in the input (since the delta value
** may be a larger positive integer than the actual docid).
**
** The space required to store the output is therefore the sum of the
** sizes of the two inputs, plus enough space for exactly one of the input
** docids to grow.
**
** A symetric argument may be made if the doclists are in descending
** order.
*/
aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1);
if( !aOut ) return SQLITE_NOMEM;
p = aOut;
fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1);
fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2);
while( p1 || p2 ){
sqlite3_int64 iDiff = DOCID_CMP(i1, i2);
|
| ︙ | ︙ | |||
116006 116007 116008 116009 116010 116011 116012 116013 116014 116015 116016 116017 116018 116019 |
fts3PoslistCopy(&p, &p2);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}
}
*paOut = aOut;
*pnOut = (p-aOut);
return SQLITE_OK;
}
/*
** This function does a "phrase" merge of two doclists. In a phrase merge,
** the output contains a copy of each position from the right-hand input
** doclist for which there is a position in the left-hand input doclist
| > | 116332 116333 116334 116335 116336 116337 116338 116339 116340 116341 116342 116343 116344 116345 116346 |
fts3PoslistCopy(&p, &p2);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}
}
*paOut = aOut;
*pnOut = (p-aOut);
assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 );
return SQLITE_OK;
}
/*
** This function does a "phrase" merge of two doclists. In a phrase merge,
** the output contains a copy of each position from the right-hand input
** doclist for which there is a position in the left-hand input doclist
|
| ︙ | ︙ |
Changes to src/sqlite3.h.
| ︙ | ︙ | |||
105 106 107 108 109 110 111 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.8" #define SQLITE_VERSION_NUMBER 3007008 | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.8" #define SQLITE_VERSION_NUMBER 3007008 #define SQLITE_SOURCE_ID "2011-09-19 14:49:19 3e0da808d2f5b4d12046e05980ca04578f581177" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
while( db_step(&q)==SQLITE_ROW ){
int deleted = db_column_int(&q, 0);
int rid = db_column_int(&q, 3);
const char *zName = db_column_text(&q, 4);
const char *zOrig = db_column_text(&q, 5);
char *zPath = mprintf("%s%s", g.zLocalRoot, zName);
Blob content;
| | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
while( db_step(&q)==SQLITE_ROW ){
int deleted = db_column_int(&q, 0);
int rid = db_column_int(&q, 3);
const char *zName = db_column_text(&q, 4);
const char *zOrig = db_column_text(&q, 5);
char *zPath = mprintf("%s%s", g.zLocalRoot, zName);
Blob content;
int isNewLink = file_wd_islink(zPath);
db_bind_int(&ins, ":rid", rid);
db_bind_int(&ins, ":isadd", rid==0);
db_bind_int(&ins, ":isrm", deleted);
db_bind_int(&ins, ":isexe", db_column_int(&q, 1));
db_bind_int(&ins, ":islink", db_column_int(&q, 2));
db_bind_text(&ins, ":orig", zOrig);
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew);
Blob delta;
undo_save(zNew);
blob_zero(&delta);
if( rid==0 ){
db_ephemeral_blob(&q, 6, &delta);
blob_write_to_file(&delta, zNPath);
| | | | | | | | > < | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
char *zNPath = mprintf("%s%s", g.zLocalRoot, zNew);
Blob delta;
undo_save(zNew);
blob_zero(&delta);
if( rid==0 ){
db_ephemeral_blob(&q, 6, &delta);
blob_write_to_file(&delta, zNPath);
file_wd_setexe(zNPath, isExec);
fossil_print("ADD %s\n", zNew);
}else if( isRemoved ){
fossil_print("DELETE %s\n", zOrig);
file_delete(zOPath);
}else{
Blob a, b, out, disk;
int isNewLink = file_wd_islink(zOPath);
db_ephemeral_blob(&q, 6, &delta);
if( isNewLink ){
blob_read_link(&disk, zOPath);
}else{
blob_read_from_file(&disk, zOPath);
}
content_get(rid, &a);
blob_delta_apply(&a, &delta, &b);
if( blob_compare(&disk, &a)==0 && isLink == isNewLink ){
if( isLink || isNewLink ){
file_delete(zNPath);
}
if( isLink ){
symlink_create(blob_str(&b), zNPath);
}else{
blob_write_to_file(&b, zNPath);
}
file_wd_setexe(zNPath, isExec);
fossil_print("UPDATE %s\n", zNew);
}else{
int rc;
if( isLink || isNewLink ){
rc = -1;
blob_zero(&b); /* because we reset it later */
fossil_print("***** Cannot merge symlink %s\n", zNew);
}else{
rc = merge_3way(&a, zOPath, &b, &out);
blob_write_to_file(&out, zNPath);
blob_reset(&out);
file_wd_setexe(zNPath, isExec);
}
if( rc ){
fossil_print("CONFLICT %s\n", zNew);
nConflict++;
}else{
fossil_print("MERGE %s\n", zNew);
}
}
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
if( rid==0 ){
db_ephemeral_blob(&q, 6, &delta);
fossil_print("ADDED %s\n", zNew);
diff_print_index(zNew);
diff_file_mem(&empty, &delta, zNew, zDiffCmd, 0);
}else if( isRemoved ){
fossil_print("DELETE %s\n", zOrig);
| | | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
if( rid==0 ){
db_ephemeral_blob(&q, 6, &delta);
fossil_print("ADDED %s\n", zNew);
diff_print_index(zNew);
diff_file_mem(&empty, &delta, zNew, zDiffCmd, 0);
}else if( isRemoved ){
fossil_print("DELETE %s\n", zOrig);
if( file_wd_islink(zOPath) ){
blob_read_link(&delta, zOPath);
}else{
blob_read_from_file(&delta, zOPath);
}
diff_print_index(zNew);
diff_file_mem(&delta, &empty, zOrig, zDiffCmd, 0);
}else{
Blob a, b, disk;
int isOrigLink = file_wd_islink(zOPath);
db_ephemeral_blob(&q, 6, &delta);
if( isOrigLink ){
blob_read_link(&disk, zOPath);
}else{
blob_read_from_file(&disk, zOPath);
}
fossil_print("CHANGED %s\n", zNew);
|
| ︙ | ︙ |
Changes to src/stat.c.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 |
** Show statistics and global information about the repository.
*/
void stat_page(void){
i64 t, fsize;
int n, m;
int szMax, szAvg;
const char *zDb;
char zBuf[100];
login_check_credentials();
| > | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | < < | < < | 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 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
** Show statistics and global information about the repository.
*/
void stat_page(void){
i64 t, fsize;
int n, m;
int szMax, szAvg;
const char *zDb;
int brief;
char zBuf[100];
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
@ <table class="label-value">
@ <tr><th>Repository Size:</th><td>
fsize = file_size(g.zRepositoryName);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", fsize);
@ %s(zBuf) bytes
@ </td></tr>
if( !brief ){
@ <tr><th>Number Of Artifacts:</th><td>
n = db_int(0, "SELECT count(*) FROM blob");
m = db_int(0, "SELECT count(*) FROM delta");
@ %d(n) (stored as %d(n-m) full text and %d(m) delta blobs)
@ </td></tr>
if( n>0 ){
int a, b;
Stmt q;
@ <tr><th>Uncompressed Artifact Size:</th><td>
db_prepare(&q, "SELECT total(size), avg(size), max(size)"
" FROM blob WHERE size>0");
db_step(&q);
t = db_column_int64(&q, 0);
szAvg = db_column_int(&q, 1);
szMax = db_column_int(&q, 2);
db_finalize(&q);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", t);
@ %d(szAvg) bytes average, %d(szMax) bytes max, %s(zBuf) bytes total
@ </td></tr>
@ <tr><th>Compression Ratio:</th><td>
if( t/fsize < 5 ){
b = 10;
fsize /= 10;
}else{
b = 1;
}
a = t/fsize;
@ %d(a):%d(b)
@ </td></tr>
}
@ <tr><th>Number Of Check-ins:</th><td>
n = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/");
@ %d(n)
@ </td></tr>
@ <tr><th>Number Of Files:</th><td>
n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
@ %d(n)
@ </td></tr>
@ <tr><th>Number Of Wiki Pages:</th><td>
n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
" WHERE +tagname GLOB 'wiki-*'");
@ %d(n)
@ </td></tr>
@ <tr><th>Number Of Tickets:</th><td>
n = db_int(0, "SELECT count(*) FROM tag /*scan*/"
" WHERE +tagname GLOB 'tkt-*'");
@ %d(n)
@ </td></tr>
}
@ <tr><th>Duration Of Project:</th><td>
n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
" + 0.99");
@ %d(n) days
sqlite3_snprintf(sizeof(zBuf), zBuf, "%.2f", n/365.24);
@ or approximately %s(zBuf) years
@ </td></tr>
@ <tr><th>Project ID:</th><td>%h(db_get("project-code",""))</td></tr>
@ <tr><th>Server ID:</th><td>%h(db_get("server-code",""))</td></tr>
@ <tr><th>Fossil Version:</th><td>
@ %h(RELEASE_VERSION) %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
@ (%h(COMPILER_NAME))
@ </td></tr>
@ <tr><th>SQLite Version:</th><td>
sqlite3_snprintf(sizeof(zBuf), zBuf, "%.19s [%.10s] (%s)",
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 |
** WEBPAGE: test_env
*/
void page_test_env(void){
char c;
int i;
char zCap[30];
login_check_credentials();
style_header("Environment Test");
#if !defined(_WIN32)
@ uid=%d(getuid()), gid=%d(getgid())<br />
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br />
@ g.zTop = %h(g.zTop)<br />
for(i=0, c='a'; c<='z'; c++){
if( login_has_capability(&c, 1) ) zCap[i++] = c;
}
zCap[i] = 0;
@ g.userUid = %d(g.userUid)<br />
@ g.zLogin = %h(g.zLogin)<br />
@ capabilities = %s(zCap)<br />
@ <hr>
cgi_print_all();
| > | | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 |
** WEBPAGE: test_env
*/
void page_test_env(void){
char c;
int i;
char zCap[30];
login_check_credentials();
if( !g.perm.Admin && !g.perm.Setup ){ login_needed(); return; }
style_header("Environment Test");
#if !defined(_WIN32)
@ uid=%d(getuid()), gid=%d(getgid())<br />
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br />
@ g.zTop = %h(g.zTop)<br />
for(i=0, c='a'; c<='z'; c++){
if( login_has_capability(&c, 1) ) zCap[i++] = c;
}
zCap[i] = 0;
@ g.userUid = %d(g.userUid)<br />
@ g.zLogin = %h(g.zLogin)<br />
@ capabilities = %s(zCap)<br />
@ <hr>
cgi_print_all();
if( g.perm.Setup ){
const char *zRedir = P("redirect");
if( zRedir ) cgi_redirect(zRedir);
}
style_footer();
}
|
Changes to src/tag.c.
| ︙ | ︙ | |||
527 528 529 530 531 532 533 |
/*
** WEBPAGE: /taglist
*/
void taglist_page(void){
Stmt q;
login_check_credentials();
| | | | | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
/*
** WEBPAGE: /taglist
*/
void taglist_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Read ){
login_needed();
}
login_anonymous_available();
style_header("Tags");
style_submenu_element("Timeline", "Timeline", "tagtimeline");
@ <h2>Non-propagating tags:</h2>
db_prepare(&q,
"SELECT substr(tagname,5)"
" FROM tag"
" WHERE EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=tag.tagid"
" AND tagtype=1)"
" AND tagname GLOB 'sym-*'"
" ORDER BY tagname"
);
@ <ul>
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
if( g.perm.History ){
@ <li><a class="tagLink" href="%s(g.zTop)/timeline?t=%T(zName)">
@ %h(zName)</a></li>
}else{
@ <li><span class="tagDsp">%h(zName)</span></li>
}
}
@ </ul>
db_finalize(&q);
style_footer();
}
/*
** WEBPAGE: /tagtimeline
*/
void tagtimeline_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
style_header("Tagged Check-ins");
style_submenu_element("List", "List", "taglist");
login_anonymous_available();
@ <h2>Check-ins with non-propagating tags:</h2>
db_prepare(&q,
"%s AND blob.rid IN (SELECT rid FROM tagxref"
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
414 415 416 417 418 419 420 | blob_reset(&tball.pax); } /* ** COMMAND: test-tarball ** | | | | 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 |
blob_reset(&tball.pax);
}
/*
** COMMAND: test-tarball
**
** Generate a GZIP-compressed tarball in the file given by the first argument
** that contains files given in the second and subsequent arguments.
*/
void test_tarball_cmd(void){
int i;
Blob zip;
Blob file;
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
sqlite3_open(":memory:", &g.db);
tar_begin();
for(i=3; i<g.argc; i++){
blob_zero(&file);
blob_read_from_file(&file, g.argv[i]);
tar_add_file(g.argv[i], &file,
file_wd_perm(g.argv[i]), file_wd_mtime(g.argv[i]));
blob_reset(&file);
}
tar_finish(&zip);
blob_write_to_file(&zip, g.argv[2]);
}
/*
|
| ︙ | ︙ | |||
570 571 572 573 574 575 576 |
void tarball_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob tarball;
login_check_credentials();
| | | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
void tarball_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob tarball;
login_check_credentials();
if( !g.perm.Zip ){ login_needed(); return; }
zName = mprintf("%s", PD("name",""));
nName = strlen(zName);
zRid = mprintf("%s", PD("uuid",""));
nRid = strlen(zRid);
if( nName>7 && fossil_strcmp(&zName[nName-7], ".tar.gz")==0 ){
/* Special case: Remove the ".tar.gz" suffix. */
nName -= 7;
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 |
/*
** Generate a hyperlink to a version.
*/
void hyperlink_to_uuid(const char *zUuid){
char z[UUID_SIZE+1];
shorten_uuid(z, zUuid);
| | | | | | 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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
/*
** 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.History ){
@ <a class="timelineHistLink" href="%s(g.zTop)/info/%s(z)">[%s(z)]</a>
}else{
@ <span class="timelineHistDsp">[%s(z)]</span>
}
}
/*
** Generate a hyperlink to a diff between two versions.
*/
void hyperlink_to_diff(const char *zV1, const char *zV2){
if( g.perm.History ){
if( zV2==0 ){
@ <a href="%s(g.zTop)/diff?v2=%s(zV1)">[diff]</a>
}else{
@ <a href="%s(g.zTop)/diff?v1=%s(zV1)&v2=%s(zV2)">[diff]</a>
}
}
}
/*
** Generate a hyperlink to a date & time.
*/
void hyperlink_to_date(const char *zDate, const char *zSuffix){
if( zSuffix==0 ) zSuffix = "";
if( g.perm.History ){
@ <a href="%s(g.zTop)/timeline?c=%T(zDate)">%s(zDate)</a>%s(zSuffix)
}else{
@ %s(zDate)%s(zSuffix)
}
}
/*
** Generate a hyperlink to a user. This will link to a timeline showing
** events by that user. If the date+time is specified, then the timeline
** is centered on that date+time.
*/
void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
if( zSuf==0 ) zSuf = "";
if( g.perm.History ){
if( zD && zD[0] ){
@ <a href="%s(g.zTop)/timeline?c=%T(zD)&u=%T(zU)">%h(zU)</a>%s(zSuf)
}else{
@ <a href="%s(g.zTop)/timeline?u=%T(zU)">%h(zU)</a>%s(zSuf)
}
}else{
@ %s(zU)
|
| ︙ | ︙ | |||
348 349 350 351 352 353 354 |
}
blob_reset(&comment);
/* Generate the "user: USERNAME" at the end of the comment, together
** with a hyperlink to another timeline for that user.
*/
if( zTagList && zTagList[0]==0 ) zTagList = 0;
| | | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
}
blob_reset(&comment);
/* Generate the "user: USERNAME" at the end of the comment, together
** with a hyperlink to another timeline for that user.
*/
if( zTagList && zTagList[0]==0 ) zTagList = 0;
if( g.perm.History && fossil_strcmp(zUser, zThisUser)!=0 ){
char *zLink = mprintf("%s/timeline?u=%h&c=%t&nd",
g.zTop, zUser, zDate);
@ (user: <a href="%s(zLink)">%h(zUser)</a>%s(zTagList?",":"\051")
fossil_free(zLink);
}else{
@ (user: %h(zUser)%s(zTagList?",":"\051")
}
/* Generate the "tags: TAGLIST" at the end of the comment, together
** with hyperlinks to the tag list.
*/
if( zTagList ){
if( g.perm.History ){
int i;
const char *z = zTagList;
Blob links;
blob_zero(&links);
while( z && z[0] ){
for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
|
| ︙ | ︙ | |||
392 393 394 395 396 397 398 |
/* Generate extra hyperlinks at the end of the comment */
if( xExtra ){
xExtra(rid);
}
/* Generate the file-change list if requested */
| | | > | > | | > > > > > > > | > | 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 |
/* Generate extra hyperlinks at the end of the comment */
if( xExtra ){
xExtra(rid);
}
/* Generate the file-change list if requested */
if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' && g.perm.History ){
int inUl = 0;
if( !fchngQueryInit ){
db_prepare(&fchngQuery,
"SELECT (pid==0) AS isnew,"
" (fid==0) AS isdel,"
" (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name,"
" (SELECT uuid FROM blob WHERE rid=fid),"
" (SELECT uuid FROM blob WHERE rid=pid),"
" (SELECT name FROM filename WHERE fnid=mlink.pfnid) AS oldnm"
" FROM mlink"
" WHERE mid=:mid AND (pid!=fid OR pfnid>0)"
" ORDER BY 3 /*sort*/"
);
fchngQueryInit = 1;
}
db_bind_int(&fchngQuery, ":mid", rid);
while( db_step(&fchngQuery)==SQLITE_ROW ){
const char *zFilename = db_column_text(&fchngQuery, 2);
int isNew = db_column_int(&fchngQuery, 0);
int isDel = db_column_int(&fchngQuery, 1);
const char *zOldName = db_column_text(&fchngQuery, 5);
const char *zOld = db_column_text(&fchngQuery, 4);
const char *zNew = db_column_text(&fchngQuery, 3);
if( !inUl ){
@ <ul class="filelist">
inUl = 1;
}
if( isNew ){
@ <li> %h(zFilename) (new file)
@ <a href="%s(g.zTop)/artifact/%S(zNew)"
@ target="diffwindow">[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)
@ <a href="%s(g.zTop)/artifact/%S(zNew)"
@ target="diffwindow">[view]</a></li>
}else{
if( zOldName!=0 ){
@ <li> %h(zOldName) → %h(zFilename)
}else{
@ <li> %h(zFilename)
}
@ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)"
@ target="diffwindow">[diff]</a></li>
}
}
db_reset(&fchngQuery);
if( inUl ){
@ </ul>
|
| ︙ | ︙ | |||
884 885 886 887 888 889 890 |
int noMerge = P("nomerge")!=0; /* Do not follow merge links */
int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */
int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */
/* To view the timeline, must have permission to read project data.
*/
login_check_credentials();
| | | | | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 |
int noMerge = P("nomerge")!=0; /* Do not follow merge links */
int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */
int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */
/* To view the timeline, must have permission to read project data.
*/
login_check_credentials();
if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ login_needed(); return; }
if( zTagName && g.perm.Read ){
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
zThisTag = zTagName;
}else if( zBrName && g.perm.Read ){
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
zThisTag = zBrName;
}else{
tagid = 0;
}
if( zType[0]=='a' ){
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
|
| ︙ | ︙ | |||
918 919 920 921 922 923 924 |
blob_append(&sql, timeline_query_for_www(), -1);
url_initialize(&url, "timeline");
if( P("fc")!=0 || P("detail")!=0 ){
tmFlags |= TIMELINE_FCHANGES;
url_add_parameter(&url, "fc", 0);
}
if( !useDividers ) url_add_parameter(&url, "nd", 0);
| | | | | | | 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 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
blob_append(&sql, timeline_query_for_www(), -1);
url_initialize(&url, "timeline");
if( P("fc")!=0 || P("detail")!=0 ){
tmFlags |= TIMELINE_FCHANGES;
url_add_parameter(&url, "fc", 0);
}
if( !useDividers ) url_add_parameter(&url, "nd", 0);
if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){
/* If from= and to= are present, display all nodes on a path connecting
** the two */
PathNode *p = 0;
const char *zFrom = 0;
const char *zTo = 0;
if( from_rid && to_rid ){
p = path_shortest(from_rid, to_rid, noMerge, 0);
zFrom = P("from");
zTo = P("to");
}else{
if( path_common_ancestor(me_rid, you_rid) ){
p = path_first();
}
zFrom = P("me");
zTo = P("you");
}
blob_append(&sql, " AND event.objid IN (0", -1);
while( p ){
blob_appendf(&sql, ",%d", p->rid);
p = p->u.pTo;
}
blob_append(&sql, ")", -1);
path_reset();
blob_append(&desc, "All nodes on the path from ", -1);
if( g.perm.History ){
blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>", g.zTop,zFrom,zFrom);
}else{
blob_appendf(&desc, "[%h]", zFrom);
}
blob_append(&desc, " and ", -1);
if( g.perm.History ){
blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.", g.zTop, zTo, zTo);
}else{
blob_appendf(&desc, "[%h].", zTo);
}
tmFlags |= TIMELINE_DISJOINT;
db_multi_exec("%s", blob_str(&sql));
}else if( (p_rid || d_rid) && g.perm.Read ){
/* If p= or d= is present, ignore all other parameters other than n= */
char *zUuid;
int np, nd;
if( p_rid && d_rid ){
if( p_rid!=d_rid ) p_rid = d_rid;
if( P("n")==0 ) nEntry = 10;
|
| ︙ | ︙ | |||
993 994 995 996 997 998 999 |
if( np>0 ){
if( nd>0 ) blob_appendf(&desc, " and ");
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
| | | | | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 |
if( np>0 ){
if( nd>0 ) blob_appendf(&desc, " and ");
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
if( g.perm.History ){
blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
g.zTop, zUuid, zUuid);
}else{
blob_appendf(&desc, " of check-in [%.10s]", zUuid);
}
}else if( f_rid && g.perm.Read ){
/* If f= is present, ignore all other parameters other than n= */
char *zUuid;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
"INSERT INTO ok VALUES(%d);"
"INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;"
"INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;",
f_rid, f_rid, f_rid
);
blob_appendf(&sql, " AND event.objid IN ok");
db_multi_exec("%s", blob_str(&sql));
if( useDividers ) timeline_add_dividers(0, f_rid);
blob_appendf(&desc, "Parents and children of check-in ");
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
if( g.perm.History ){
blob_appendf(&desc, "<a href='%s/info/%s'>[%.10s]</a>",
g.zTop, zUuid, zUuid);
}else{
blob_appendf(&desc, "[%.10s]", zUuid);
}
}else{
/* Otherwise, a timeline based on a span of time */
|
| ︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 |
url_add_parameter(&url, "mionly", "1");
}
}else{
url_add_parameter(&url, "t", zTagName);
}
blob_appendf(&sql, ")");
}
| | | | | | | | | | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 |
url_add_parameter(&url, "mionly", "1");
}
}else{
url_add_parameter(&url, "t", zTagName);
}
blob_appendf(&sql, ")");
}
if( (zType[0]=='w' && !g.perm.RdWiki)
|| (zType[0]=='t' && !g.perm.RdTkt)
|| (zType[0]=='e' && !g.perm.RdWiki)
|| (zType[0]=='c' && !g.perm.Read)
){
zType = "all";
}
if( zType[0]=='a' ){
if( !g.perm.Read || !g.perm.RdWiki || !g.perm.RdTkt ){
char cSep = '(';
blob_appendf(&sql, " AND event.type IN ");
if( g.perm.Read ){
blob_appendf(&sql, "%c'ci'", cSep);
cSep = ',';
}
if( g.perm.RdWiki ){
blob_appendf(&sql, "%c'w','e'", cSep);
cSep = ',';
}
if( g.perm.RdTkt ){
blob_appendf(&sql, "%c't'", cSep);
cSep = ',';
}
blob_appendf(&sql, ")");
}
}else{ /* zType!="all" */
blob_appendf(&sql, " AND event.type=%Q", zType);
|
| ︙ | ︙ | |||
1188 1189 1190 1191 1192 1193 1194 |
blob_appendf(&desc, " occurring on or before %h.<br />", zBefore);
}else if( zCirca ){
blob_appendf(&desc, " occurring around %h.<br />", zCirca);
}
if( zSearch ){
blob_appendf(&desc, " matching \"%h\"", zSearch);
}
| | | | | | | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 |
blob_appendf(&desc, " occurring on or before %h.<br />", zBefore);
}else if( zCirca ){
blob_appendf(&desc, " occurring around %h.<br />", zCirca);
}
if( zSearch ){
blob_appendf(&desc, " matching \"%h\"", zSearch);
}
if( g.perm.History ){
if( zAfter || n==nEntry ){
zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
timeline_submenu(&url, "Older", "b", zDate, "a");
free(zDate);
}
if( zBefore || (zAfter && n==nEntry) ){
zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
timeline_submenu(&url, "Newer", "a", zDate, "b");
free(zDate);
}else if( tagid==0 ){
if( zType[0]!='a' ){
timeline_submenu(&url, "All Types", "y", "all", 0);
}
if( zType[0]!='w' && g.perm.RdWiki ){
timeline_submenu(&url, "Wiki Only", "y", "w", 0);
}
if( zType[0]!='c' && g.perm.Read ){
timeline_submenu(&url, "Checkins Only", "y", "ci", 0);
}
if( zType[0]!='t' && g.perm.RdTkt ){
timeline_submenu(&url, "Tickets Only", "y", "t", 0);
}
if( zType[0]!='e' && g.perm.RdWiki ){
timeline_submenu(&url, "Events Only", "y", "e", 0);
}
}
if( nEntry>20 ){
timeline_submenu(&url, "20 Entries", "n", "20", 0);
}
if( nEntry<200 ){
|
| ︙ | ︙ | |||
1590 1591 1592 1593 1594 1595 1596 |
/*
** WEBPAGE: test_timewarps
*/
void test_timewarp_page(void){
Stmt q;
login_check_credentials();
| | | 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 |
/*
** WEBPAGE: test_timewarps
*/
void test_timewarp_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Read || !g.perm.History ){ login_needed(); return; }
style_header("Instances of timewarp");
@ <ul>
db_prepare(&q,
"SELECT blob.uuid "
" FROM plink p, plink c, blob"
" WHERE p.cid=c.pid AND p.mtime>c.mtime"
" AND blob.rid=c.cid"
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
87 88 89 90 91 92 93 | ** ticket whose name is given by the "name" CGI parameter. ** Load the values for all fields into the interpreter. ** ** Only load those fields which do not already exist as ** variables. ** ** Fields of the TICKET table that begin with "private_" are | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
** ticket whose name is given by the "name" CGI parameter.
** Load the values for all fields into the interpreter.
**
** Only load those fields which do not already exist as
** variables.
**
** Fields of the TICKET table that begin with "private_" are
** expanded using the db_reveal() function. If g.perm.RdAddr is
** true, then the db_reveal() function will decode the content
** using the CONCEALED table so that the content legable.
** Otherwise, db_reveal() is a no-op and the content remains
** obscured.
*/
static void initializeVariablesFromDb(void){
const char *zName;
|
| ︙ | ︙ | |||
290 291 292 293 294 295 296 |
*/
void tktview_page(void){
const char *zScript;
char *zFullName;
const char *zUuid = PD("name","");
login_check_credentials();
| | | | | | | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
*/
void tktview_page(void){
const char *zScript;
char *zFullName;
const char *zUuid = PD("name","");
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(); return; }
if( g.perm.WrTkt || g.perm.ApndTkt ){
style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
g.zTop, PD("name",""));
}
if( g.perm.History ){
style_submenu_element("History", "History Of This Ticket",
"%s/tkthistory/%T", g.zTop, zUuid);
style_submenu_element("Timeline", "Timeline Of This Ticket",
"%s/tkttimeline/%T", g.zTop, zUuid);
style_submenu_element("Check-ins", "Check-ins Of This Ticket",
"%s/tkttimeline/%T?y=ci", g.zTop, zUuid);
}
if( g.perm.NewTkt ){
style_submenu_element("New Ticket", "Create a new ticket",
"%s/tktnew", g.zTop);
}
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);
}
style_header("View Ticket");
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
ticket_init();
|
| ︙ | ︙ | |||
343 344 345 346 347 348 349 |
const char *zUser = db_column_text(&q, 2);
if( cnt==0 ){
@ <hr /><h2>Attachments:</h2>
@ <ul>
}
cnt++;
@ <li>
| | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
const char *zUser = db_column_text(&q, 2);
if( cnt==0 ){
@ <hr /><h2>Attachments:</h2>
@ <ul>
}
cnt++;
@ <li>
if( g.perm.Read && g.perm.History ){
@ <a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&file=%t(zFile)">
@ %h(zFile)</a>
}else{
@ %h(zFile)
}
@ added by %h(zUser) on
hyperlink_to_date(zDate, ".");
if( g.perm.WrTkt && g.perm.Attach ){
@ [<a href="%s(g.zTop)/attachdelete?tkt=%s(zFullName)&file=%t(zFile)&from=%s(g.zTop)/tktview%%3fname=%s(zFullName)">delete</a>]
}
@ </li>
}
if( cnt ){
@ </ul>
}
|
| ︙ | ︙ | |||
508 509 510 511 512 513 514 |
** top of the screen.
*/
void tktnew_page(void){
const char *zScript;
char *zNewUuid = 0;
login_check_credentials();
| | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
** top of the screen.
*/
void tktnew_page(void){
const char *zScript;
char *zNewUuid = 0;
login_check_credentials();
if( !g.perm.NewTkt ){ login_needed(); return; }
if( P("cancel") ){
cgi_redirect("home");
}
style_header("New Ticket");
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW<br />\n", -1);
ticket_init();
getAllTicketFields();
|
| ︙ | ︙ | |||
554 555 556 557 558 559 560 |
void tktedit_page(void){
const char *zScript;
int nName;
const char *zName;
int nRec;
login_check_credentials();
| | | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
void tktedit_page(void){
const char *zScript;
int nName;
const char *zName;
int nRec;
login_check_credentials();
if( !g.perm.ApndTkt && !g.perm.WrTkt ){ login_needed(); return; }
zName = P("name");
if( P("cancel") ){
cgi_redirectf("tktview?name=%T", zName);
}
style_header("Edit Ticket");
if( zName==0 || (nName = strlen(zName))<4 || nName>UUID_SIZE
|| !validate16(zName,nName) ){
|
| ︙ | ︙ | |||
649 650 651 652 653 654 655 | const char *zUuid; char *zFullUuid; int tagid; char zGlobPattern[50]; const char *zType; login_check_credentials(); | | | 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
const char *zUuid;
char *zFullUuid;
int tagid;
char zGlobPattern[50];
const char *zType;
login_check_credentials();
if( !g.perm.History || !g.perm.RdTkt ){ login_needed(); return; }
zUuid = PD("name","");
zType = PD("y","a");
if( zType[0]!='c' ){
style_submenu_element("Check-ins", "Check-ins",
"%s/tkttimeline?name=%T&y=ci", g.zTop, zUuid);
}else{
style_submenu_element("Timeline", "Timeline",
|
| ︙ | ︙ | |||
723 724 725 726 727 728 729 |
void tkthistory_page(void){
Stmt q;
char *zTitle;
const char *zUuid;
int tagid;
login_check_credentials();
| | | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 |
void tkthistory_page(void){
Stmt q;
char *zTitle;
const char *zUuid;
int tagid;
login_check_credentials();
if( !g.perm.History || !g.perm.RdTkt ){ login_needed(); return; }
zUuid = PD("name","");
zTitle = mprintf("History Of Ticket %h", zUuid);
style_submenu_element("Status", "Status",
"%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",
|
| ︙ | ︙ | |||
1009 1010 1011 1012 1013 1014 1015 |
if( eCmd==err ){
usage("add|fieldlist|set|show|history");
}
/* we just handle history separately here, does not get out */
if( eCmd==history ){
Stmt q;
| < | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 |
if( eCmd==err ){
usage("add|fieldlist|set|show|history");
}
/* we just handle history separately here, does not get out */
if( eCmd==history ){
Stmt q;
int tagid;
if ( i != g.argc ){
fossil_fatal("no other parameters expected to %s!",g.argv[2]);
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zTktUuid);
if( tagid==0 ){
|
| ︙ | ︙ |
Changes to src/tktsetup.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
/*
** Main sub-menu for configuring the ticketing system.
** WEBPAGE: tktsetup
*/
void tktsetup_page(void){
login_check_credentials();
| | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/*
** Main sub-menu for configuring the ticketing system.
** WEBPAGE: tktsetup
*/
void tktsetup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Ticket Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Table", "tktsetup_tab",
"Specify the schema of the \"ticket\" table in the database.");
|
| ︙ | ︙ | |||
100 101 102 103 104 105 106 |
void (*xRebuild)(void), /* Run after successulf update */
int height /* Height of the edit box */
){
const char *z;
int isSubmit;
login_check_credentials();
| | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
void (*xRebuild)(void), /* Run after successulf update */
int height /* Height of the edit box */
){
const char *z;
int isSubmit;
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
if( P("setup") ){
cgi_redirect("tktsetup");
}
isSubmit = P("submit")!=0;
z = P("x");
|
| ︙ | ︙ | |||
688 689 690 691 692 693 694 |
}
/*
** WEBPAGE: tktsetup_timeline
*/
void tktsetup_timeline_page(void){
login_check_credentials();
| | | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 |
}
/*
** WEBPAGE: tktsetup_timeline
*/
void tktsetup_timeline_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
if( P("setup") ){
cgi_redirect("tktsetup");
}
style_header("Ticket Display On Timelines");
|
| ︙ | ︙ |
Changes to src/undo.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 |
int new_exe;
int new_link;
int old_link;
Blob current;
Blob new;
zFullname = mprintf("%s/%s", g.zLocalRoot, zPathname);
old_link = db_column_int(&q, 3);
| | | | | | | | | 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 78 79 80 81 82 83 84 85 86 87 88 89 90 |
int new_exe;
int new_link;
int old_link;
Blob current;
Blob new;
zFullname = mprintf("%s/%s", g.zLocalRoot, zPathname);
old_link = db_column_int(&q, 3);
new_link = file_wd_islink(zFullname);
new_exists = file_wd_size(zFullname)>=0;
if( new_exists ){
if( new_link ){
blob_read_link(¤t, zFullname);
}else{
blob_read_from_file(¤t, zFullname);
}
new_exe = file_wd_isexe(zFullname);
}else{
blob_zero(¤t);
new_exe = 0;
}
blob_zero(&new);
old_exists = db_column_int(&q, 1);
old_exe = db_column_int(&q, 2);
if( old_exists ){
db_ephemeral_blob(&q, 0, &new);
}
if( old_exists ){
if( new_exists ){
fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname);
}else{
fossil_print("NEW %s\n", zPathname);
}
if( new_exists && (new_link || old_link) ){
file_delete(zFullname);
}
if( old_link ){
symlink_create(blob_str(&new), zFullname);
}else{
blob_write_to_file(&new, zFullname);
}
file_wd_setexe(zFullname, old_exe);
}else{
fossil_print("DELETE %s\n", zPathname);
file_delete(zFullname);
}
blob_reset(&new);
free(zFullname);
db_finalize(&q);
|
| ︙ | ︙ | |||
268 269 270 271 272 273 274 |
Blob content;
int existsFlag;
int isLink;
Stmt q;
if( !undoActive ) return;
zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
| | > > | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
Blob content;
int existsFlag;
int isLink;
Stmt q;
if( !undoActive ) return;
zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
existsFlag = file_wd_size(zFullname)>=0;
isLink = file_wd_islink(zFullname);
db_prepare(&q,
"INSERT OR IGNORE INTO"
" undo(pathname,redoflag,existsflag,isExe,isLink,content)"
" VALUES(%Q,0,%d,%d,%d,:c)",
zPathname, existsFlag, file_wd_isexe(zFullname), isLink
);
if( existsFlag ){
if( isLink ){
blob_read_link(&content, zFullname);
}else{
blob_read_from_file(&content, zFullname);
}
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
221 222 223 224 225 226 227 |
" FROM vfile WHERE vid=%d",
vid
);
/* Compute file name changes on V->T. Record name changes in files that
** have changed locally.
*/
| | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
" FROM vfile WHERE vid=%d",
vid
);
/* Compute file name changes on V->T. Record name changes in files that
** have changed locally.
*/
find_filename_changes(vid, tid, 1, &nChng, &aChng, debugFlag ? "V->T": 0);
if( nChng ){
for(i=0; i<nChng; i++){
db_multi_exec(
"UPDATE fv"
" SET fnt=(SELECT name FROM filename WHERE fnid=%d)"
" WHERE fn=(SELECT name FROM filename WHERE fnid=%d) AND chnged",
aChng[i*2+1], aChng[i*2]
|
| ︙ | ︙ | |||
301 302 303 304 305 306 307 |
blob_zero(&sql);
blob_append(&sql, "DELETE FROM fv WHERE ", -1);
zSep = "";
for(i=3; i<g.argc; i++){
file_tree_name(g.argv[i], &treename, 1);
if( file_isdir(g.argv[i])==1 ){
| | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
blob_zero(&sql);
blob_append(&sql, "DELETE FROM fv WHERE ", -1);
zSep = "";
for(i=3; i<g.argc; i++){
file_tree_name(g.argv[i], &treename, 1);
if( file_isdir(g.argv[i])==1 ){
if( blob_size(&treename) != 1 || blob_str(&treename)[0] != '.' ){
blob_appendf(&sql, "%sfn NOT GLOB '%b/*' ", zSep, &treename);
}else{
blob_reset(&sql);
break;
}
}else{
blob_appendf(&sql, "%sfn<>%B ", zSep, &treename);
|
| ︙ | ︙ | |||
365 366 367 368 369 370 371 |
undo_save(zName);
if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){
/* The file is unedited. Change it to the target version */
undo_save(zName);
fossil_print("UPDATE %s\n", zName);
if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0);
| | | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
undo_save(zName);
if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){
/* The file is unedited. Change it to the target version */
undo_save(zName);
fossil_print("UPDATE %s\n", zName);
if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt>0 && idv>0 && file_wd_size(zFullPath)<0 ){
/* The file missing from the local check-out. Restore it to the
** version that appears in the target. */
fossil_print("UPDATE %s\n", zName);
undo_save(zName);
if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt==0 && idv>0 ){
if( ridv==0 ){
|
| ︙ | ︙ | |||
396 397 398 399 400 401 402 |
Blob r, t, v;
int rc;
if( nameChng ){
fossil_print("MERGE %s -> %s\n", zName, zNewName);
}else{
fossil_print("MERGE %s\n", zName);
}
| | < | | | | | | | | | | | | | | | | | | | | | | 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 |
Blob r, t, v;
int rc;
if( nameChng ){
fossil_print("MERGE %s -> %s\n", zName, zNewName);
}else{
fossil_print("MERGE %s\n", zName);
}
if( islinkv || islinkt /* || file_wd_islink(zFullPath) */ ){
fossil_print("***** Cannot merge symlink %s\n", zNewName);
nConflict++;
}else{
undo_save(zName);
content_get(ridt, &t);
content_get(ridv, &v);
rc = merge_3way(&v, zFullPath, &t, &r);
if( rc>=0 ){
if( !nochangeFlag ){
blob_write_to_file(&r, zFullNewPath);
file_wd_setexe(zFullNewPath, isexe);
}
if( rc>0 ){
fossil_print("***** %d merge conflicts in %s\n", rc, zNewName);
nConflict++;
}
}else{
if( !nochangeFlag ){
blob_write_to_file(&t, zFullNewPath);
file_wd_setexe(zFullNewPath, isexe);
}
fossil_print("***** Cannot merge binary file %s\n", zNewName);
nConflict++;
}
}
if( nameChng && !nochangeFlag ) file_delete(zFullPath);
blob_reset(&v);
blob_reset(&t);
blob_reset(&r);
}else{
if( chnged ){
|
| ︙ | ︙ | |||
667 668 669 670 671 672 673 |
file_delete(zFull);
fossil_print("DELETE: %s\n", zFile);
}
db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile);
}else{
sqlite3_int64 mtime;
undo_save(zFile);
| | | | | | | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
file_delete(zFull);
fossil_print("DELETE: %s\n", zFile);
}
db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile);
}else{
sqlite3_int64 mtime;
undo_save(zFile);
if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
file_delete(zFull);
}
if( isLink ){
symlink_create(blob_str(&record), zFull);
}else{
blob_write_to_file(&record, zFull);
}
file_wd_setexe(zFull, isExe);
fossil_print("REVERTED: %s\n", zFile);
mtime = file_wd_mtime(zFull);
db_multi_exec(
"UPDATE vfile"
" SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d, mrid=rid,"
" pathname=coalesce(origname,pathname), origname=NULL"
" WHERE pathname=%Q",
mtime, isExe, isLink, zFile
);
|
| ︙ | ︙ |
Changes to src/user.c.
| ︙ | ︙ | |||
391 392 393 394 395 396 397 |
int skip = atoi(PD("o","0"));
Blob sql;
Stmt q;
int cnt = 0;
int rc;
login_check_credentials();
| | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
int skip = atoi(PD("o","0"));
Blob sql;
Stmt q;
int cnt = 0;
int rc;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(); return; }
create_accesslog_table();
if( P("delall") && P("delallbtn") ){
db_multi_exec("DELETE FROM accesslog");
cgi_redirectf("%s/access_log?y=%d&n=%d&o=%o", g.zTop, y, n, skip);
return;
}
|
| ︙ | ︙ |
Changes to src/vfile.c.
| ︙ | ︙ | |||
164 165 166 167 168 169 170 |
zName = db_column_text(&q, 1);
rid = db_column_int(&q, 2);
isDeleted = db_column_int(&q, 3);
oldChnged = db_column_int(&q, 4);
oldMtime = db_column_int64(&q, 7);
if( isDeleted ){
chnged = 1;
| | | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
zName = db_column_text(&q, 1);
rid = db_column_int(&q, 2);
isDeleted = db_column_int(&q, 3);
oldChnged = db_column_int(&q, 4);
oldMtime = db_column_int64(&q, 7);
if( isDeleted ){
chnged = 1;
}else if( !file_wd_isfile_or_link(zName) && file_wd_size(0)>=0 ){
if( notFileIsFatal ){
fossil_warning("not an ordinary file: %s", zName);
nErr++;
}
chnged = 1;
}else if( oldChnged>=2 ){
chnged = oldChnged;
}else if( rid==0 ){
chnged = 1;
}
if( chnged!=1 ){
i64 origSize = db_column_int64(&q, 6);
currentMtime = file_wd_mtime(0);
if( origSize!=file_wd_size(0) ){
/* A file size change is definitive - the file has changed. No
** need to check the sha1sum */
chnged = 1;
}
}
if( chnged!=1 && (checkMtime==0 || currentMtime!=oldMtime) ){
db_ephemeral_blob(&q, 5, &origCksum);
|
| ︙ | ︙ | |||
245 246 247 248 249 250 251 |
zName = db_column_text(&q, 1);
rid = db_column_int(&q, 2);
isExe = db_column_int(&q, 3);
isLink = db_column_int(&q, 4);
content_get(rid, &content);
if( file_is_the_same(&content, zName) ){
blob_reset(&content);
| | | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
zName = db_column_text(&q, 1);
rid = db_column_int(&q, 2);
isExe = db_column_int(&q, 3);
isLink = db_column_int(&q, 4);
content_get(rid, &content);
if( file_is_the_same(&content, zName) ){
blob_reset(&content);
if( file_wd_setexe(zName, isExe) ){
db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
file_wd_mtime(zName), id);
}
continue;
}
if( promptFlag && file_wd_size(zName)>=0 ){
Blob ans;
char *zMsg;
char cReply;
zMsg = mprintf("overwrite %s (a=always/y/N)? ", zName);
prompt_user(zMsg, &ans);
free(zMsg);
cReply = blob_str(&ans)[0];
|
| ︙ | ︙ | |||
274 275 276 277 278 279 280 |
}
}
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
if( file_isdir(zName) == 1 ){
/*TODO(dchest): remove directories? */
fossil_fatal("%s is directory, cannot overwrite\n", zName);
}
| | | | | | 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 |
}
}
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
if( file_isdir(zName) == 1 ){
/*TODO(dchest): remove directories? */
fossil_fatal("%s is directory, cannot overwrite\n", zName);
}
if( file_wd_size(zName)>=0 && (isLink || file_wd_islink(zName)) ){
file_delete(zName);
}
if( isLink ){
symlink_create(blob_str(&content), zName);
}else{
blob_write_to_file(&content, zName);
}
file_wd_setexe(zName, isExe);
blob_reset(&content);
db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
file_wd_mtime(zName), id);
}
db_finalize(&q);
}
/*
** Delete from the disk every file in VFILE vid.
|
| ︙ | ︙ | |||
391 392 393 394 395 396 397 |
zPath = blob_str(pPath);
if( glob_match(pIgnore, &zPath[nPrefix+1]) ){
/* do nothing */
}else if( file_isdir(zPath)==1 ){
if( !vfile_top_of_checkout(zPath) ){
vfile_scan(pPath, nPrefix, allFlag, pIgnore);
}
| | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
zPath = blob_str(pPath);
if( glob_match(pIgnore, &zPath[nPrefix+1]) ){
/* do nothing */
}else if( file_isdir(zPath)==1 ){
if( !vfile_top_of_checkout(zPath) ){
vfile_scan(pPath, nPrefix, allFlag, pIgnore);
}
}else if( file_wd_isfile_or_link(zPath) ){
db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
db_step(&ins);
db_reset(&ins);
}
blob_resize(pPath, origSize);
}
closedir(d);
|
| ︙ | ︙ | |||
450 451 452 453 454 455 456 |
while( db_step(&q)==SQLITE_ROW ){
const char *zFullpath = db_column_text(&q, 0);
const char *zName = db_column_text(&q, 1);
int isSelected = db_column_int(&q, 3);
if( isSelected ){
md5sum_step_text(zName, -1);
| | | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
while( db_step(&q)==SQLITE_ROW ){
const char *zFullpath = db_column_text(&q, 0);
const char *zName = db_column_text(&q, 1);
int isSelected = db_column_int(&q, 3);
if( isSelected ){
md5sum_step_text(zName, -1);
if( file_wd_islink(zFullpath) ){
/* Instead of file content, use link destination path */
Blob pathBuf;
sqlite3_snprintf(sizeof(zBuf), zBuf, " %ld\n",
blob_read_link(&pathBuf, zFullpath));
md5sum_step_text(zBuf, -1);
md5sum_step_text(blob_str(&pathBuf), -1);
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 |
md5sum_init();
while( db_step(&q)==SQLITE_ROW ){
const char *zFullpath = db_column_text(&q, 0);
const char *zName = db_column_text(&q, 1);
int rid = db_column_int(&q, 2);
blob_zero(&disk);
| | | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
md5sum_init();
while( db_step(&q)==SQLITE_ROW ){
const char *zFullpath = db_column_text(&q, 0);
const char *zName = db_column_text(&q, 1);
int rid = db_column_int(&q, 2);
blob_zero(&disk);
if( file_wd_islink(zFullpath) ){
rc = blob_read_link(&disk, zFullpath);
}else{
rc = blob_read_from_file(&disk, zFullpath);
}
if( rc<0 ){
fossil_print("ERROR: cannot read file [%s]\n", zFullpath);
blob_reset(&disk);
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
while( zIndexPage[0]=='/' ) zIndexPage++;
while( zPathInfo[0]=='/' ) zPathInfo++;
if( fossil_strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0;
}
if( zIndexPage ){
cgi_redirectf("%s/%s", g.zTop, zIndexPage);
}
| | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
while( zIndexPage[0]=='/' ) zIndexPage++;
while( zPathInfo[0]=='/' ) zPathInfo++;
if( fossil_strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0;
}
if( zIndexPage ){
cgi_redirectf("%s/%s", g.zTop, zIndexPage);
}
if( !g.perm.RdWiki ){
cgi_redirectf("%s/login?g=%s/home", g.zTop, g.zTop);
}
if( zPageName ){
login_check_credentials();
g.zExtra = zPageName;
cgi_set_parameter_nocopy("name", g.zExtra);
g.isHome = 1;
|
| ︙ | ︙ | |||
133 134 135 136 137 138 139 |
Manifest *pWiki = 0;
const char *zPageName;
char *zBody = mprintf("%s","<i>Empty Page</i>");
Stmt q;
int cnt = 0;
login_check_credentials();
| | | | | 133 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 |
Manifest *pWiki = 0;
const char *zPageName;
char *zBody = mprintf("%s","<i>Empty Page</i>");
Stmt q;
int cnt = 0;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
zPageName = P("name");
if( zPageName==0 ){
style_header("Wiki");
@ <ul>
{ char *zHomePageName = db_get("project-name",0);
if( zHomePageName ){
@ <li> <a href="%s(g.zTop)/wiki?name=%t(zHomePageName)">
@ %h(zHomePageName)</a> wiki home page.</li>
}
}
@ <li> <a href="%s(g.zTop)/timeline?y=w">Recent changes</a> to wiki
@ pages. </li>
@ <li> <a href="%s(g.zTop)/wiki_rules">Formatting rules</a> for
@ wiki.</li>
@ <li> Use the <a href="%s(g.zTop)/wiki?name=Sandbox">Sandbox</a>
@ to experiment.</li>
if( g.perm.NewWiki ){
@ <li> Create a <a href="%s(g.zTop)/wikinew">new wiki page</a>.</li>
if( g.perm.Write ){
@ <li> Create a <a href="%s(g.zTop)/eventedit">new event</a>.</li>
}
}
@ <li> <a href="%s(g.zTop)/wcontent">List of All Wiki Pages</a>
@ available on this server.</li>
@ <li> <form method="get" action="%s(g.zTop)/wfind"><div>
@ Search wiki titles: <input type="text" name="title"/>
|
| ︙ | ︙ | |||
184 185 186 187 188 189 190 |
free(zTag);
pWiki = manifest_get(rid, CFTYPE_WIKI);
if( pWiki ){
zBody = pWiki->zWiki;
}
}
if( !g.isHome ){
| | | | | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
free(zTag);
pWiki = manifest_get(rid, CFTYPE_WIKI);
if( pWiki ){
zBody = pWiki->zWiki;
}
}
if( !g.isHome ){
if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
g.zTop, zPageName);
}
if( rid && g.perm.ApndWiki && g.perm.Attach ){
style_submenu_element("Attach", "Add An Attachment",
"%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
g.zTop, zPageName, g.zTop, zPageName);
}
if( rid && g.perm.ApndWiki ){
style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
g.zTop, zPageName);
}
if( g.perm.History ){
style_submenu_element("History", "History", "%s/whistory?name=%T",
g.zTop, zPageName);
}
}
style_header(zPageName);
blob_init(&wiki, zBody, -1);
wiki_convert(&wiki, 0, 0);
|
| ︙ | ︙ | |||
223 224 225 226 227 228 229 |
const char *zUser = db_column_text(&q, 2);
if( cnt==0 ){
@ <hr /><h2>Attachments:</h2>
@ <ul>
}
cnt++;
@ <li>
| | | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
const char *zUser = db_column_text(&q, 2);
if( cnt==0 ){
@ <hr /><h2>Attachments:</h2>
@ <ul>
}
cnt++;
@ <li>
if( g.perm.History && g.perm.Read ){
@ <a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)">
@ %h(zFile)</a>
}else{
@ %h(zFile)
}
@ added by %h(zUser) on
hyperlink_to_date(zDate, ".");
if( g.perm.WrWiki && g.perm.Attach ){
@ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&from=%s(g.zTop)/wiki%%3fname=%s(zPageName)">delete</a>]
}
@ </li>
}
if( cnt ){
@ </ul>
}
|
| ︙ | ︙ | |||
269 270 271 272 273 274 275 |
zBody = mprintf("%s", zBody);
}
login_check_credentials();
zPageName = PD("name","");
if( check_name(zPageName) ) return;
isSandbox = is_sandbox(zPageName);
if( isSandbox ){
| | | | 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 |
zBody = mprintf("%s", zBody);
}
login_check_credentials();
zPageName = PD("name","");
if( check_name(zPageName) ) return;
isSandbox = is_sandbox(zPageName);
if( isSandbox ){
if( !g.perm.WrWiki ){
login_needed();
return;
}
if( zBody==0 ){
zBody = db_get("sandbox","");
}
}else{
zTag = mprintf("wiki-%s", zPageName);
rid = db_int(0,
"SELECT rid FROM tagxref"
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
" ORDER BY mtime DESC", zTag
);
free(zTag);
if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
login_needed();
return;
}
if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
zBody = pWiki->zWiki;
}
}
|
| ︙ | ︙ | |||
373 374 375 376 377 378 379 |
**
** Prompt the user to enter the name of a new wiki page. Then redirect
** to the wikiedit screen for that new page.
*/
void wikinew_page(void){
const char *zName;
login_check_credentials();
| | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
**
** Prompt the user to enter the name of a new wiki page. Then redirect
** to the wikiedit screen for that new page.
*/
void wikinew_page(void){
const char *zName;
login_check_credentials();
if( !g.perm.NewWiki ){
login_needed();
return;
}
zName = PD("name","");
if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
cgi_redirectf("wikiedit?name=%T", zName);
}
|
| ︙ | ︙ | |||
448 449 450 451 452 453 454 |
);
free(zTag);
if( !rid ){
fossil_redirect_home();
return;
}
}
| | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
);
free(zTag);
if( !rid ){
fossil_redirect_home();
return;
}
}
if( !g.perm.ApndWiki ){
login_needed();
return;
}
if( P("submit")!=0 && P("r")!=0 && P("u")!=0 ){
char *zDate;
Blob cksum;
int nrid;
|
| ︙ | ︙ | |||
558 559 560 561 562 563 564 |
*/
void whistory_page(void){
Stmt q;
char *zTitle;
char *zSQL;
const char *zPageName;
login_check_credentials();
| | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
*/
void whistory_page(void){
Stmt q;
char *zTitle;
char *zSQL;
const char *zPageName;
login_check_credentials();
if( !g.perm.History ){ login_needed(); return; }
zPageName = PD("name","");
zTitle = mprintf("History Of %s", zPageName);
style_header(zTitle);
free(zTitle);
zSQL = mprintf("%s AND event.objid IN "
" (SELECT rid FROM tagxref WHERE tagid="
|
| ︙ | ︙ | |||
594 595 596 597 598 599 600 |
int rid1, rid2;
const char *zPageName;
Manifest *pW1, *pW2 = 0;
Blob w1, w2, d;
login_check_credentials();
rid1 = atoi(PD("a","0"));
| | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
int rid1, rid2;
const char *zPageName;
Manifest *pW1, *pW2 = 0;
Blob w1, w2, d;
login_check_credentials();
rid1 = atoi(PD("a","0"));
if( !g.perm.History ){ login_needed(); return; }
if( rid1==0 ) fossil_redirect_home();
rid2 = atoi(PD("b","0"));
zPageName = PD("name","");
zTitle = mprintf("Changes To %s", zPageName);
style_header(zTitle);
free(zTitle);
|
| ︙ | ︙ | |||
640 641 642 643 644 645 646 |
** List all available wiki pages with date created and last modified.
*/
void wcontent_page(void){
Stmt q;
int showAll = P("all")!=0;
login_check_credentials();
| | | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 |
** List all available wiki pages with date created and last modified.
*/
void wcontent_page(void){
Stmt q;
int showAll = P("all")!=0;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
style_header("Available Wiki Pages");
if( showAll ){
style_submenu_element("Active", "Only Active Pages", "%s/wcontent", g.zTop);
}else{
style_submenu_element("All", "All", "%s/wcontent?all=1", g.zTop);
}
@ <ul>
|
| ︙ | ︙ | |||
679 680 681 682 683 684 685 |
** URL: /wfind?title=TITLE
** List all wiki pages whose titles contain the search text
*/
void wfind_page(void){
Stmt q;
const char * zTitle;
login_check_credentials();
| | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
** URL: /wfind?title=TITLE
** List all wiki pages whose titles contain the search text
*/
void wfind_page(void){
Stmt q;
const char * zTitle;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
zTitle = PD("title","*");
style_header("Wiki Pages Found");
@ <ul>
db_prepare(&q,
"SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'"
" ORDER BY lower(tagname) /*sort*/" ,
zTitle);
|
| ︙ | ︙ |
Changes to src/wikiformat.c.
| ︙ | ︙ | |||
1041 1042 1043 1044 1045 1046 1047 |
|| strncmp(zTarget, "https:", 6)==0
|| strncmp(zTarget, "ftp:", 4)==0
|| strncmp(zTarget, "mailto:", 7)==0
){
blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
/* zTerm = "⟾</a>"; // doesn't work on windows */
}else if( zTarget[0]=='/' ){
| | | | | | | 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 |
|| strncmp(zTarget, "https:", 6)==0
|| strncmp(zTarget, "ftp:", 4)==0
|| strncmp(zTarget, "mailto:", 7)==0
){
blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
/* zTerm = "⟾</a>"; // doesn't work on windows */
}else if( zTarget[0]=='/' ){
if( 1 /* g.perm.History */ ){
blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
}else{
zTerm = "";
}
}else if( zTarget[0]=='.' || zTarget[0]=='#' ){
if( 1 /* g.perm.History */ ){
blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
}else{
zTerm = "";
}
}else if( is_valid_uuid(zTarget) ){
int isClosed = 0;
if( is_ticket(zTarget, &isClosed) ){
/* Special display processing for tickets. Display the hyperlink
** as crossed out if the ticket is closed.
*/
if( isClosed ){
if( g.perm.History ){
blob_appendf(p->pOut,
"<a href=\"%s/info/%s\"><span class=\"wikiTagCancelled\">[",
g.zTop, zTarget
);
zTerm = "]</span></a>";
}else{
blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">[");
zTerm = "]</span>";
}
}else{
if( g.perm.History ){
blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[",
g.zTop, zTarget
);
zTerm = "]</a>";
}else{
blob_appendf(p->pOut, "[");
zTerm = "]";
}
}
}else if( !in_this_repo(zTarget) ){
blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
zTerm = "]</span>";
}else if( g.perm.History ){
blob_appendf(p->pOut, "<a href=\"%s/info/%s\">[", g.zTop, zTarget);
zTerm = "]</a>";
}
}else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
&& db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget);
}else if( strncmp(zTarget, "wiki:", 5)==0
|
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
127 128 129 130 131 132 133 |
blob_zero(&content);
blob_zero(&hash);
blob_extract(pXfer->pIn, n, &content);
if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
/* Ignore files that have been shunned */
return;
}
| | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
blob_zero(&content);
blob_zero(&hash);
blob_extract(pXfer->pIn, n, &content);
if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
/* Ignore files that have been shunned */
return;
}
if( isPriv && !g.perm.Private ){
/* Do not accept private files if not authorized */
return;
}
if( cloneFlag ){
if( pXfer->nToken==4 ){
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
pXfer->nDeltaRcvd++;
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
|| szC<0 || szU<0
|| (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
){
blob_appendf(&pXfer->err, "malformed cfile line");
return;
}
| | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
|| szC<0 || szU<0
|| (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
){
blob_appendf(&pXfer->err, "malformed cfile line");
return;
}
if( isPriv && !g.perm.Private ){
/* Do not accept private files if not authorized */
return;
}
blob_zero(&content);
blob_extract(pXfer->pIn, szC, &content);
if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
/* Ignore files that have been shunned */
|
| ︙ | ︙ | |||
814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
memset(&xfer, 0, sizeof(xfer));
blobarray_zero(xfer.aToken, count(xfer.aToken));
cgi_set_content_type(g.zContentType);
if( db_schema_is_outofdate() ){
@ error database\sschema\sis\sout-of-date\son\sthe\sserver.
return;
}
blob_zero(&xfer.err);
xfer.pIn = &g.cgiIn;
xfer.pOut = cgi_output_blob();
| > | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
memset(&xfer, 0, sizeof(xfer));
blobarray_zero(xfer.aToken, count(xfer.aToken));
cgi_set_content_type(g.zContentType);
cgi_reset_content();
if( db_schema_is_outofdate() ){
@ error database\sschema\sis\sout-of-date\son\sthe\sserver.
return;
}
blob_zero(&xfer.err);
xfer.pIn = &g.cgiIn;
xfer.pOut = cgi_output_blob();
|
| ︙ | ︙ | |||
905 906 907 908 909 910 911 |
if( xfer.nToken>=2
&& blob_eq(&xfer.aToken[0], "igot")
&& blob_is_uuid(&xfer.aToken[1])
){
if( isPush ){
if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){
rid_from_uuid(&xfer.aToken[1], 1, 0);
| | | 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 |
if( xfer.nToken>=2
&& blob_eq(&xfer.aToken[0], "igot")
&& blob_is_uuid(&xfer.aToken[1])
){
if( isPush ){
if( xfer.nToken==2 || blob_eq(&xfer.aToken[2],"1")==0 ){
rid_from_uuid(&xfer.aToken[1], 1, 0);
}else if( g.perm.Private ){
rid_from_uuid(&xfer.aToken[1], 1, 1);
}else{
server_private_xfer_not_authorized();
}
}
}else
|
| ︙ | ︙ | |||
938 939 940 941 942 943 944 |
cgi_reset_content();
@ error wrong\sproject
nErr++;
break;
}
login_check_credentials();
if( blob_eq(&xfer.aToken[0], "pull") ){
| | | | | 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 |
cgi_reset_content();
@ error wrong\sproject
nErr++;
break;
}
login_check_credentials();
if( blob_eq(&xfer.aToken[0], "pull") ){
if( !g.perm.Read ){
cgi_reset_content();
@ error not\sauthorized\sto\sread
nErr++;
break;
}
isPull = 1;
}else{
if( !g.perm.Write ){
if( !isPull ){
cgi_reset_content();
@ error not\sauthorized\sto\swrite
nErr++;
}else{
@ message pull\sonly\s-\snot\sauthorized\sto\spush
}
}else{
isPush = 1;
}
}
}else
/* clone ?PROTOCOL-VERSION? ?SEQUENCE-NUMBER?
**
** The client knows nothing. Tell all.
*/
if( blob_eq(&xfer.aToken[0], "clone") ){
int iVers;
login_check_credentials();
if( !g.perm.Clone ){
cgi_reset_content();
@ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
@ error not\sauthorized\sto\sclone
nErr++;
break;
}
if( xfer.nToken==3
|
| ︙ | ︙ | |||
1011 1012 1013 1014 1015 1016 1017 |
** Check for a valid login. This has to happen before anything else.
** The client can send multiple logins. Permissions are cumulative.
*/
if( blob_eq(&xfer.aToken[0], "login")
&& xfer.nToken==4
){
if( disableLogin ){
| | | | | | | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 |
** Check for a valid login. This has to happen before anything else.
** The client can send multiple logins. Permissions are cumulative.
*/
if( blob_eq(&xfer.aToken[0], "login")
&& xfer.nToken==4
){
if( disableLogin ){
g.perm.Read = g.perm.Write = g.perm.Private = g.perm.Admin = 1;
}else{
if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
|| check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
){
cgi_reset_content();
@ error login\sfailed
nErr++;
break;
}
}
}else
/* reqconfig NAME
**
** Request a configuration value
*/
if( blob_eq(&xfer.aToken[0], "reqconfig")
&& xfer.nToken==2
){
if( g.perm.Read ){
char *zName = blob_str(&xfer.aToken[1]);
if( zName[0]=='/' ){
/* New style configuration transfer */
int groupMask = configure_name_to_mask(&zName[1], 0);
if( !g.perm.Admin ) groupMask &= ~CONFIGSET_USER;
if( !g.perm.RdAddr ) groupMask &= ~CONFIGSET_ADDR;
configure_send_group(xfer.pOut, groupMask, 0);
}else if( configure_is_exportable(zName) ){
/* Old style configuration transfer */
send_legacy_config_card(&xfer, zName);
}
}
}else
/* config NAME SIZE \n CONTENT
**
** Receive a configuration value from the client. This is only
** permitted for high-privilege users.
*/
if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
&& blob_is_int(&xfer.aToken[2], &size) ){
const char *zName = blob_str(&xfer.aToken[1]);
Blob content;
blob_zero(&content);
blob_extract(xfer.pIn, size, &content);
if( !g.perm.Admin ){
cgi_reset_content();
@ error not\sauthorized\sto\spush\sconfiguration
nErr++;
break;
}
if( !recvConfig && zName[0]=='@' ){
configure_prepare_to_receive(0);
|
| ︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 |
/* private
**
** This card indicates that the next "file" or "cfile" will contain
** private content.
*/
if( blob_eq(&xfer.aToken[0], "private") ){
| | | 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 |
/* private
**
** This card indicates that the next "file" or "cfile" will contain
** private content.
*/
if( blob_eq(&xfer.aToken[0], "private") ){
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.nextIsPrivate = 1;
}
}else
|
| ︙ | ︙ | |||
1125 1126 1127 1128 1129 1130 1131 |
**
** If the user has the "x" privilege (which must be set explicitly -
** it is not automatic with "a" or "s") then this pragma causes
** private information to be pulled in addition to public records.
*/
if( blob_eq(&xfer.aToken[1], "send-private") ){
login_check_credentials();
| | | 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 |
**
** If the user has the "x" privilege (which must be set explicitly -
** it is not automatic with "a" or "s") then this pragma causes
** private information to be pulled in addition to public records.
*/
if( blob_eq(&xfer.aToken[1], "send-private") ){
login_check_credentials();
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.syncPrivate = 1;
}
}
}else
|
| ︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 |
transport_stats(0, 0, 1);
socket_global_init();
memset(&xfer, 0, sizeof(xfer));
xfer.pIn = &recv;
xfer.pOut = &send;
xfer.mxSend = db_get_int("max-upload", 250000);
if( privateFlag ){
| | | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 |
transport_stats(0, 0, 1);
socket_global_init();
memset(&xfer, 0, sizeof(xfer));
xfer.pIn = &recv;
xfer.pOut = &send;
xfer.mxSend = db_get_int("max-upload", 250000);
if( privateFlag ){
g.perm.Private = 1;
xfer.syncPrivate = 1;
}
assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
db_begin_transaction();
db_record_repository_filename(0);
db_multi_exec(
|
| ︙ | ︙ | |||
1505 1506 1507 1508 1509 1510 1511 |
&& blob_is_uuid(&xfer.aToken[1])
){
int rid;
int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
if( rid>0 ){
if( !isPriv ) content_make_public(rid);
| | | 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 |
&& blob_is_uuid(&xfer.aToken[1])
){
int rid;
int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
if( rid>0 ){
if( !isPriv ) content_make_public(rid);
}else if( isPriv && !g.perm.Private ){
/* ignore private files */
}else if( pullFlag || cloneFlag ){
rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
if( rid ) newPhantom = 1;
}
remote_has(rid);
}else
|
| ︙ | ︙ | |||
1550 1551 1552 1553 1554 1555 1556 |
*/
if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
&& blob_is_int(&xfer.aToken[2], &size) ){
const char *zName = blob_str(&xfer.aToken[1]);
Blob content;
blob_zero(&content);
blob_extract(xfer.pIn, size, &content);
| | | 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 |
*/
if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
&& blob_is_int(&xfer.aToken[2], &size) ){
const char *zName = blob_str(&xfer.aToken[1]);
Blob content;
blob_zero(&content);
blob_extract(xfer.pIn, size, &content);
g.perm.Admin = g.perm.RdAddr = 1;
configure_receive(zName, &content, origConfigRcvMask);
nCardSent++;
blob_reset(&content);
blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
}else
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
289 290 291 292 293 294 295 |
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
zip_open();
for(i=3; i<g.argc; i++){
blob_zero(&file);
blob_read_from_file(&file, g.argv[i]);
| | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
zip_open();
for(i=3; i<g.argc; i++){
blob_zero(&file);
blob_read_from_file(&file, g.argv[i]);
zip_add_file(g.argv[i], &file, file_wd_perm(g.argv[i]));
blob_reset(&file);
}
zip_close(&zip);
blob_write_to_file(&zip, g.argv[2]);
}
/*
|
| ︙ | ︙ | |||
424 425 426 427 428 429 430 |
void baseline_zip_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob zip;
login_check_credentials();
| | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
void baseline_zip_page(void){
int rid;
char *zName, *zRid;
int nName, nRid;
Blob zip;
login_check_credentials();
if( !g.perm.Zip ){ login_needed(); return; }
zName = mprintf("%s", PD("name",""));
nName = strlen(zName);
zRid = mprintf("%s", PD("uuid",""));
nRid = strlen(zRid);
for(nName=strlen(zName)-1; nName>5; nName--){
if( zName[nName]=='.' ){
zName[nName] = 0;
|
| ︙ | ︙ |
Changes to test/release-checklist.wiki.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Verify that there are no errors. <li><p> Click on each of the links in in the [./graph-test-1.wiki] document and verify that all graphs are rendered correctly. <li><p> Compile for all of the following platforms: <ol type="a"> <li> Linux x86 <li> Linux x86_64 <li> Mac x86 <li> Mac x86_64 | > > > > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | Verify that there are no errors. <li><p> Click on each of the links in in the [./graph-test-1.wiki] document and verify that all graphs are rendered correctly. <li><p> Verify correct name-change tracking behavior (no net changes) for: <blockquote><b> fossil test-name-changes --debug b120bc8b262ac 374920b20944b </b></blockquote> <li><p> Compile for all of the following platforms: <ol type="a"> <li> Linux x86 <li> Linux x86_64 <li> Mac x86 <li> Mac x86_64 |
| ︙ | ︙ |
Changes to www/build.wiki.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | <h2>1.0 Obtaining The Source Code</h2> <p>Fossil is self-hosting, so you can obtain a ZIP archive containing a snapshot of the latest version directly from fossil's own fossil repository. Follow these steps:</p> <ol> | | | < | < | | | 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 63 64 65 66 67 68 | <h2>1.0 Obtaining The Source Code</h2> <p>Fossil is self-hosting, so you can obtain a ZIP archive containing a snapshot of the latest version directly from fossil's own fossil repository. Follow these steps:</p> <ol> <li><p>Point your web browser at <a href="http://www.fossil-scm.org/"> http://www.fossil-scm.org/</a>. Click on the "Login" menu button.</p></li> <li><p>Log in as anonymous. The password is shown on screen. The reason for requiring this login is to prevent spiders from walking the entire website, downloading ZIP archives of every historical version, and thereby soaking up all our bandwidth.</p></li> <li><p>Click on the <a href="http://www.fossil-scm.org/fossil/timeline">Timeline</a> link at the top of the page.</p></li> <li><p>Select a version of of fossil you want to download. Click on its link. Note that you must successfully log in as "anonymous" in step 1 above in order to see the link to the detailed version information.</p></li> <li><p>Finally, click on one of the "Zip Archive" or "Tarball" links, according to your preference. These link will build a ZIP archive or a gzip-compressed tarball of the complete source code and download it to your browser. </ol> <h2>2.0 Compiling</h2> <ol> <li value="6"> <p>Unpack the ZIP or tarball you downloaded into that directory then <b>cd</b> into the directory created.</p></li> <li><i>(Optional, unix only)</i> Run <b>./configure</b> to construct a makefile. <ol type="a"> <li><p> If you do not have the OpenSSL library installed on your system, then |
| ︙ | ︙ |
Changes to www/quotes.wiki.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 | represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.</nowiki> <blockquote> <i>At [http://tartley.com/?p=1267]</i> </blockquote> <li>We've been using git and github for a few months now, and it's not intuitive... I'm hoping someone will make a set of standard wrappers/GUI for making git bearable. <blockquote> <i>maro at [http://news.ycombinator.com/item?id=1433387]</i> | > > > > > > > > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.</nowiki> <blockquote> <i>At [http://tartley.com/?p=1267]</i> </blockquote> <li>Git is not a Prius. Git is a Model T. Its plumbing and wiring sticks out all over the place. You have to be a mechanic to operate it successfully or you'll be stuck on the side of the road when it breaks down. And it <b>will</b> break down. <blockquote> <i>Nick Farina at [http://nfarina.com/post/9868516270/git-is-simpler]</i> </blockquote> <li>We've been using git and github for a few months now, and it's not intuitive... I'm hoping someone will make a set of standard wrappers/GUI for making git bearable. <blockquote> <i>maro at [http://news.ycombinator.com/item?id=1433387]</i> |
| ︙ | ︙ |
Changes to www/reference.wiki.
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
<td><a href="#undo">undo</a></td>
</tr>
<tr>
<td><a href="#checkout">checkout</a>*</td>
<td><a href="#descendants">descendants</a></td>
<td><a href="#mv">mv</a>*</td>
<td><a href="#rm">rm</a>*</td>
| | | | 92 93 94 95 96 97 98 99 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 |
<td><a href="#undo">undo</a></td>
</tr>
<tr>
<td><a href="#checkout">checkout</a>*</td>
<td><a href="#descendants">descendants</a></td>
<td><a href="#mv">mv</a>*</td>
<td><a href="#rm">rm</a>*</td>
<td><a href="#settings">unset</a></td>
</tr>
<tr>
<td><a href="#commit">ci</a></td>
<td><a href="#diff">diff</a></td>
<td><a href="#new">new</a>*</td>
<td><a href="#rstats">rstats</a></td>
<td><a href="#update">update</a>*</td>
</tr>
<tr>
<td><a href="#clean">clean</a></td>
<td><a href="#extra">extra</a>*</td>
<td><a href="#open">open</a></td>
<td><a href="#server">server</a></td>
<td><a href="#user">user</a></td>
</tr>
<tr>
<td><a href="#clone">clone</a></td>
<td><a href="#diff">gdiff</a></td>
<td><a href="#pull">pull</a></td>
<td><a href="#settings">settings</a></td>
<td><a href="#version">version</a>*</td>
</tr>
<tr>
<td><a href="#close">close</a></td>
<td><a href="#help">help</a></td>
<td><a href="#push">push</a></td>
<td><a href="#status">status</a>*</td>
|
| ︙ | ︙ |
Changes to www/reviews.wiki.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<title>Reviews</title>
<b>External links:</b>
* [http://sheddingbikes.com/posts/1276624594.html | Why I Use Fossil]
by Zed A. Shaw.
* [http://nixtu.blogspot.com/2010/03/fossil-dvcs-on-go-first-impressions.html |
Fossil DVCS on the Go - First Impressions]
by Juho Vepsäläinen.
* [http://blog.fupps.com/2010/12/04/exploring-the-fossil-dvcs |
Exploring the Fossil DVCS] by Jan-Piet Mens.
* [http://blog.mired.org/2011/02/fossil-sweet-spot-in-vcs-space.html |
Fossil - a sweet spot in the VCS space] by Mike Meyer.
<b>See Also:</b>
* [./quotes.wiki | Short Quotes on Fossil, Git, And DVCSes]
<b>Daniel writes on 2009-01-06:</b>
| > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<title>Reviews</title>
<b>External links:</b>
* [http://sheddingbikes.com/posts/1276624594.html | Why I Use Fossil]
by Zed A. Shaw.
* [http://nixtu.blogspot.com/2010/03/fossil-dvcs-on-go-first-impressions.html |
Fossil DVCS on the Go - First Impressions]
by Juho Vepsäläinen.
* [http://blog.fupps.com/2010/12/04/exploring-the-fossil-dvcs |
Exploring the Fossil DVCS] by Jan-Piet Mens.
* [http://blog.mired.org/2011/02/fossil-sweet-spot-in-vcs-space.html |
Fossil - a sweet spot in the VCS space] by Mike Meyer.
* [http://blog.s11n.net/?p=72|Four reasons to take a closer look at the Fossil SCM] by Stephan Beal
<b>See Also:</b>
* [./quotes.wiki | Short Quotes on Fossil, Git, And DVCSes]
<b>Daniel writes on 2009-01-06:</b>
|
| ︙ | ︙ | |||
37 38 39 40 41 42 43 | pick the earlier changes, then figure out how to make my new branch shared instead of private. Just want to say thanks for fossil making my life easier on most of my projects, and being able to move commits to another branch after the fact and shared-by-default branches are good features. Also not having a misanthropic command line interface. </blockquote> | | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | pick the earlier changes, then figure out how to make my new branch shared instead of private. Just want to say thanks for fossil making my life easier on most of my projects, and being able to move commits to another branch after the fact and shared-by-default branches are good features. Also not having a misanthropic command line interface. </blockquote> <b>Stephan Beal writes on 2009-01-11:</b> <blockquote> Sometime in late 2007 I came across a link to fossil on <a href="http://www.sqlite.org/">sqlite.org</a>. It was a good thing I bookmarked it, because I was never able to find the link again (it might have been in a bug report or something). The reasons I first took a close look at it were (A) it stemmed from the |
| ︙ | ︙ | |||
134 135 136 137 138 139 140 | Firefox, or the Linux Kernel), but 99.9% of projects never reach anywhere near that size or complexity. In summary: I remember my first reaction to fossil being, "this will be an | | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | Firefox, or the Linux Kernel), but 99.9% of projects never reach anywhere near that size or complexity. In summary: I remember my first reaction to fossil being, "this will be an excellent solution for small projects (like the dozens we've all got sitting on our hard drives but which don't justify the hassle of version control)." A year of daily use in over 15 source trees has confirmed that, and I continue to heartily recommend fossil to other developers I know who also have their own collection of "unhosted" pet projects. </blockquote> |
Changes to www/wikitheory.wiki.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | <h2>Embedded Documentation</h2> Files in the source tree that use the ".wiki" suffix can be accessed and displayed using special URLs to the fossil server. This allows project documentation to be stored in the source tree and accessed online. (Details are described [./embeddeddoc.wiki | separately].) | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | <h2>Embedded Documentation</h2> Files in the source tree that use the ".wiki" suffix can be accessed and displayed using special URLs to the fossil server. This allows project documentation to be stored in the source tree and accessed online. (Details are described [./embeddeddoc.wiki | separately].) Some projects prefer to store their documentation in wiki. There is nothing wrong with that. But other projects prefer to keep documentation as part of the source tree, so that it is versioned along with the source tree and so that only developers with check-in privileges can change it. Embedded documentation serves this latter purpose. Both forms of documentation use the exact same wiki markup language. Some projects may choose to use both forms of documentation at the same time. Because the same format is used, it is trivial to move a file from wiki to embedded documentation |
| ︙ | ︙ |