Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | catch up with trunk. Remove C++ style comments from http_ssl.c. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | msw-hack |
Files: | files | file ages | folders |
SHA1: |
0f1c41bc20f8856376cdd65e3355fe39 |
User & Date: | martin.weber 2011-09-06 20:12:20.341 |
Context
2011-09-07
| ||
03:51 | begin work on ticket [bc0d0f5642eaf]: track success of (network) write operations and start bubbling that status up. To make it up to ultimately exit(EXIT_FAILURE) on errors, mkindex will need to be updated, too, as well as the signature from command implementing functions need to return int instead of void at some point. More to come. ... (Closed-Leaf check-in: a67e2683 user: martin.weber tags: msw-hack) | |
2011-09-06
| ||
20:12 | catch up with trunk. Remove C++ style comments from http_ssl.c. ... (check-in: 0f1c41bc user: martin.weber tags: msw-hack) | |
13:23 | Close A and LI tags when displaying new and deleted files in timeline. ... (check-in: 8d703ff9 user: dmitry tags: trunk) | |
2011-08-23
| ||
17:57 | Change numbering back so that the preliminary step is 0, the most important one is #1. ... (check-in: 90e310eb user: martin.weber tags: msw-hack) | |
Changes
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/autosetup.
1 2 3 4 5 | #!/bin/sh # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # vim:se syntax=tcl: # \ | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/sh # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/ # All rights reserved # vim:se syntax=tcl: # \ dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@" set autosetup(version) 0.6.2 # Can be set to 1 to debug early-init problems set autosetup(debug) 0 ################################################################## |
︙ | ︙ | |||
180 181 182 183 184 185 186 | exit 0 } # @opt-bool option ... # # Check each of the named, boolean options and return 1 if any of them have # been set by the user. | | | | 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 | exit 0 } # @opt-bool option ... # # Check each of the named, boolean options and return 1 if any of them have # been set by the user. # proc opt-bool {args} { option-check-names {*}$args opt_bool ::useropts {*}$args } # @opt-val option-list ?default=""? # # Returns a list containing all the values given for the non-boolean options in 'option-list'. # There will be one entry in the list for each option given by the user, including if the # same option was used multiple times. # If only a single value is required, use something like: # ## lindex [opt-val $names] end # # If no options were set, $default is returned (exactly, not as a list). # proc opt-val {names {default ""}} { option-check-names {*}$names join [opt_val ::useropts $names $default] } proc option-check-names {args} { foreach o $args { |
︙ | ︙ | |||
394 395 396 397 398 399 400 | # # Undocumented options are also supported by omitting the "=> description. # These options are not displayed with --help and can be useful for internal options or as aliases. # # For example, --disable-lfs is an alias for --disable=largefile: # ## lfs=1 largefile=1 => "Disable large file support" | | | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 | # # Undocumented options are also supported by omitting the "=> description. # These options are not displayed with --help and can be useful for internal options or as aliases. # # For example, --disable-lfs is an alias for --disable=largefile: # ## lfs=1 largefile=1 => "Disable large file support" # proc options {optlist} { # Allow options as a list or args options-add $optlist "Local Options:" if {$::autosetup(showhelp)} { options-show exit 0 |
︙ | ︙ | |||
432 433 434 435 436 437 438 | exec-with-stderr sh $::autosetup(dir)/config.sub $alias } else { return $alias } } # @define name ?value=1? | | | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | exec-with-stderr sh $::autosetup(dir)/config.sub $alias } else { return $alias } } # @define name ?value=1? # # Defines the named variable to the given value. # These (name, value) pairs represent the results of the configuration check # and are available to be checked, modified and substituted. # proc define {name {value 1}} { set ::define($name) $value #dputs "$name <= $value" |
︙ | ︙ | |||
562 563 564 565 566 567 568 569 570 571 572 573 574 575 | proc quote-argv {argv} { set args {} foreach arg $argv { lappend args [quote-if-needed $arg] } join $args } # @find-executable name # # Searches the path for an executable with the given name. # Note that the name may include some parameters, e.g. "cc -mbig-endian", # in which case the parameters are ignored. # Returns 1 if found, or 0 if not. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | proc quote-argv {argv} { set args {} foreach arg $argv { lappend args [quote-if-needed $arg] } join $args } # @suffix suf list # # Takes a list and returns a new list with $suf appended # to each element # ## suffix .c {a b c} => {a.c b.c c.c} # proc suffix {suf list} { set result {} foreach p $list { lappend result $p$suf } return $result } # @prefix pre list # # Takes a list and returns a new list with $pre prepended # to each element # ## prefix jim- {a.c b.c} => {jim-a.c jim-b.c} # proc prefix {pre list} { set result {} foreach p $list { lappend result $pre$p } return $result } # @find-executable name # # Searches the path for an executable with the given name. # Note that the name may include some parameters, e.g. "cc -mbig-endian", # in which case the parameters are ignored. # Returns 1 if found, or 0 if not. |
︙ | ︙ | |||
997 998 999 1000 1001 1002 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 | # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Simple getopt module # Parse everything out of the argv list which looks like an option # Knows about --enable-thing and --disable-thing as alternatives for --thing=0 or --thing=1 proc getopt {argvname} { upvar $argvname argv for {set i 0} {$i < [llength $argv]} {incr i} { set arg [lindex $argv $i] #dputs arg=$arg if {$arg eq "--"} { # End of options incr i break } if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} { lappend opts($name) $value } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} { if {$prefix eq "disable-"} { set value 0 } else { set value 1 } lappend opts($name) $value } else { | > > > | | | | 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 1073 1074 1075 | # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/ # All rights reserved # Simple getopt module # Parse everything out of the argv list which looks like an option # Knows about --enable-thing and --disable-thing as alternatives for --thing=0 or --thing=1 # Everything which doesn't look like an option, or is after --, is left unchanged proc getopt {argvname} { upvar $argvname argv set nargv {} for {set i 0} {$i < [llength $argv]} {incr i} { set arg [lindex $argv $i] #dputs arg=$arg if {$arg eq "--"} { # End of options incr i lappend nargv {*}[lrange $argv $i end] break } if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} { lappend opts($name) $value } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} { if {$prefix eq "disable-"} { set value 0 } else { set value 1 } lappend opts($name) $value } else { lappend nargv $arg } } #puts "getopt: argv=[join $argv] => [join $nargv]" #parray opts set argv $nargv return [array get opts] } proc opt_val {optarrayname options {default {}}} { upvar $optarrayname opts |
︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 | user-notice "Warning: Initialising from the development version of autosetup" writefile configure "#!/bin/sh\nWRAPPER=\"\$0\" exec $::autosetup(dir)/autosetup \"\$@\"\n" } else { writefile configure \ {#!/bin/sh dir="`dirname "$0"`/autosetup" | | | | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 | user-notice "Warning: Initialising from the development version of autosetup" writefile configure "#!/bin/sh\nWRAPPER=\"\$0\" exec $::autosetup(dir)/autosetup \"\$@\"\n" } else { writefile configure \ {#!/bin/sh dir="`dirname "$0"`/autosetup" WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" } } catch {exec chmod 755 configure} } if {![file exists auto.def]} { puts "I don't see auto.def, so I will create a default one." writefile auto.def {# Initial auto.def created by 'autosetup --init' use cc # Add any user options here options { } make-config-header config.h make-template Makefile.in } } if {![file exists Makefile.in]} { puts "Note: I don't see Makefile.in. You will probably need to create one." } |
︙ | ︙ | |||
1509 1510 1511 1512 1513 1514 1515 | # (Assume that Tcl does this for us) proc getenv {name args} { string map {\\ /} [env $name {*}$args] } # Jim uses system() for exec under mingw, so # we need to fetch the output ourselves proc exec-with-stderr {args} { | | | 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 | # (Assume that Tcl does this for us) proc getenv {name args} { string map {\\ /} [env $name {*}$args] } # Jim uses system() for exec under mingw, so # we need to fetch the output ourselves proc exec-with-stderr {args} { set tmpfile auto[format %04x [rand 10000]].tmp set rc [catch [list exec {*}$args >$tmpfile 2>&1] result] set result [readfile $tmpfile] file delete $tmpfile return -code $rc $result } } else { # Jim on unix is simple |
︙ | ︙ |
Changes to autosetup/cc-lib.tcl.
︙ | ︙ | |||
46 47 48 49 50 51 52 | # proc cc-check-endian {} { cc-check-includes sys/types.h sys/param.h set rc 0 msg-checking "Checking endian..." cc-with {-includes {sys/types.h sys/param.h}} { if {[cctest -code { | | | | 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 | # proc cc-check-endian {} { cc-check-includes sys/types.h sys/param.h set rc 0 msg-checking "Checking endian..." cc-with {-includes {sys/types.h sys/param.h}} { if {[cctest -code { #if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER) #error unknown #elif BYTE_ORDER != BIG_ENDIAN #error little #endif }]} { define-feature big-endian msg-result "big" set rc 1 } elseif {[cctest -code { #if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER) #error unknown #elif BYTE_ORDER != LITTLE_ENDIAN #error big #endif }]} { define-feature little-endian msg-result "little" |
︙ | ︙ |
Changes to autosetup/cc-shared.tcl.
︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 | define SH_LDFLAGS -shared define SHOBJ_LDFLAGS -shared } *-*-cygwin { define SH_LDFLAGS -shared define SHOBJ_LDFLAGS -shared } * { # Generic Unix settings define SH_LINKFLAGS -rdynamic | > > > > > > > > > > > > > > > | | | 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 | define SH_LDFLAGS -shared define SHOBJ_LDFLAGS -shared } *-*-cygwin { define SH_LDFLAGS -shared define SHOBJ_LDFLAGS -shared } *-*-solaris* { # XXX: These haven't been fully tested. #define SH_LINKFLAGS -Wl,-export-dynamic define SH_CFLAGS -Kpic define SHOBJ_CFLAGS -Kpic define SHOBJ_LDFLAGS "-G" } *-*-hpux { # XXX: These haven't been tested define SH_LINKFLAGS -Wl,+s define SH_CFLAGS +z define SHOBJ_CFLAGS "+O3 +z" define SHOBJ_LDFLAGS -b define LD_LIBRARY_PATH SHLIB_PATH } * { # Generic Unix settings define SH_LINKFLAGS -rdynamic define SH_CFLAGS -fpic define SH_LDFLAGS -shared define SHOBJ_CFLAGS -fpic define SHOBJ_LDFLAGS "-shared -nostartfiles" } } |
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 |
︙ | ︙ | |||
414 415 416 417 418 419 420 | ## return 0; ## } # # Any failures are recorded in 'config.log' # proc cctest {args} { set src conftest__.c | | | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | ## return 0; ## } # # Any failures are recorded in 'config.log' # proc cctest {args} { set src conftest__.c set tmp conftest__ # Easiest way to merge in the settings cc-with $args { array set opts [cc-get-settings] } if {[info exists opts(-sourcefile)]} { |
︙ | ︙ | |||
466 467 468 469 470 471 472 473 474 475 476 477 478 479 | } default { autosetup-error "cctest called with unknown language: $opts(-lang)" } } if {!$opts(-link)} { lappend cmdline -c } lappend cmdline {*}$opts(-cflags) switch -glob -- [get-define host] { *-*-darwin* { # Don't generate .dSYM directories | > | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | } default { autosetup-error "cctest called with unknown language: $opts(-lang)" } } if {!$opts(-link)} { set tmp conftest__.o lappend cmdline -c } lappend cmdline {*}$opts(-cflags) switch -glob -- [get-define host] { *-*-darwin* { # Don't generate .dSYM directories |
︙ | ︙ |
Changes to autosetup/system.tcl.
1 2 3 4 5 6 7 8 9 10 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # This module supports common system interrogation and options # such as --host, --build, --prefix, and setting srcdir, builddir, and EXEXT. # # It also support the 'feature' naming convention, where searching # for a feature such as sys/type.h defines HAVE_SYS_TYPES_H | | < < > > > > > > > < | 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 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # This module supports common system interrogation and options # such as --host, --build, --prefix, and setting srcdir, builddir, and EXEXT. # # It also support the 'feature' naming convention, where searching # for a feature such as sys/type.h defines HAVE_SYS_TYPES_H # module-options { host:host-alias => {a complete or partial cpu-vendor-opsys for the system where the application will run (defaults to the same value as --build)} build:build-alias => {a complete or partial cpu-vendor-opsys for the system where the application will be built (defaults to the result of running config.guess)} prefix:dir => {the target directory for the build (defaults to /usr/local)} # These (hidden) options are supported for autoconf/automake compatibility exec-prefix: bindir: sbindir: includedir: mandir: infodir: libexecdir: datadir: libdir: sysconfdir: sharedstatedir: localstatedir: maintainer-mode=0 dependency-tracking=0 } # Returns 1 if exists, or 0 if not # proc check-feature {name code} { |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 | # Each pattern of the form @define@ is replaced the the corresponding # define, if it exists, or left unchanged if not. # # The special value @srcdir@ is subsituted with the relative # path to the source directory from the directory where the output # file is created. Use @top_srcdir@ for the absolute path. # proc make-template {template {out {}}} { set infile [file join $::autosetup(srcdir) $template] if {![file exists $infile]} { user-error "Template $template is missing" } | > > > > > > > > > > > > > > > > > > | 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 | # Each pattern of the form @define@ is replaced the the corresponding # define, if it exists, or left unchanged if not. # # The special value @srcdir@ is subsituted with the relative # path to the source directory from the directory where the output # file is created. Use @top_srcdir@ for the absolute path. # # Conditional sections may be specified as follows: ## @if name == value ## lines ## @else ## lines ## @endif # # Where 'name' is a defined variable name and @else is optional. # If the expression does not match, all lines through '@endif' are ignored. # # The alternative forms may also be used: ## @if name ## @if name != value # # Where the first form is true if the variable is defined, but not empty or 0 # # Currently these expressions can't be nested. # proc make-template {template {out {}}} { set infile [file join $::autosetup(srcdir) $template] if {![file exists $infile]} { user-error "Template $template is missing" } |
︙ | ︙ | |||
134 135 136 137 138 139 140 | # Set up srcdir to be relative to the target dir define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir] set mapping {} foreach {n v} [array get ::define] { lappend mapping @$n@ $v } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | # Set up srcdir to be relative to the target dir define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir] set mapping {} foreach {n v} [array get ::define] { lappend mapping @$n@ $v } set result {} foreach line [split [readfile $infile] \n] { if {[info exists cond]} { set l [string trimright $line] if {$l eq "@endif"} { unset cond continue } if {$l eq "@else"} { set cond [expr {!$cond}] continue } if {$cond} { lappend result $line } continue } if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} { lassign $expression equal value set varval [get-define $name ""] if {$equal eq ""} { set cond [expr {$varval ni {"" 0}}] } else { set cond [expr {$varval eq $value}] if {$equal ne "=="} { set cond [expr {!$cond}] } } continue } lappend result $line } writefile $out [string map $mapping [join $result \n]]\n msg-result "Created [relative-path $out] from [relative-path $template]" } # build/host tuples and cross-compilation prefix set build [opt-val build] define build_alias $build |
︙ | ︙ | |||
169 170 171 172 173 174 175 | define target [get-define host] define prefix $prefix define builddir $autosetup(builddir) define srcdir $autosetup(srcdir) # Allow this to come from the environment define top_srcdir [get-env top_srcdir [get-define srcdir]] | | | > | | | > | | | | < | | | > > > | 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 | define target [get-define host] define prefix $prefix define builddir $autosetup(builddir) define srcdir $autosetup(srcdir) # Allow this to come from the environment define top_srcdir [get-env top_srcdir [get-define srcdir]] # autoconf supports all of these define exec_prefix [opt-val exec-prefix [get-env exec-prefix \${prefix}]] foreach {name defpath} { bindir \${exec_prefix}/bin sbindir \${exec_prefix}/sbin libexecdir \${exec_prefix}/libexec libdir \${exec_prefix}/lib datadir \${prefix}/share sysconfdir \${prefix}/etc sharedstatedir \${prefix}/com localstatedir \${prefix}/var infodir \${prefix}/share/info mandir \${prefix}/share/man includedir \${prefix}/include } { define $name [opt-val $name [get-env $name $defpath]] } define SHELL [get-env SHELL [find-an-executable sh bash ksh]] # Windows vs. non-Windows switch -glob -- [get-define host] { *-*-ming* - *-*-cygwin { define-feature windows |
︙ | ︙ |
Changes to configure.
1 2 | #!/bin/sh dir="`dirname "$0"`/autosetup" | | | 1 2 3 | #!/bin/sh dir="`dirname "$0"`/autosetup" WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" |
Changes to src/add.c.
︙ | ︙ | |||
104 105 106 107 108 109 110 | if( db_exists("SELECT 1 FROM vfile" " WHERE pathname=%Q COLLATE %s", zPath, zCollate) ){ 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( | | | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | if( db_exists("SELECT 1 FROM vfile" " WHERE pathname=%Q COLLATE %s", zPath, zCollate) ){ 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_isexe(zFullname), file_islink(zFullname)); fossil_free(zFullname); } if( db_changes() ){ fossil_print("ADDED %s\n", zPath); return 1; }else{ fossil_print("SKIP %s\n", zPath); |
︙ | ︙ | |||
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); | | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | ); 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_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/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.
︙ | ︙ | |||
699 700 701 702 703 704 705 706 707 708 709 710 711 712 | got = fread(blob_buffer(pBlob), 1, size, in); fclose(in); if( got<size ){ blob_resize(pBlob, got); } return got; } /* ** Write the content of a blob into a file. ** ** If the filename is blank or "-" then write to standard output. ** ** Return the number of bytes written. | > > > > > > > > > > > > > > > > > > > > > > > > > > | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | got = fread(blob_buffer(pBlob), 1, size, in); fclose(in); if( got<size ){ blob_resize(pBlob, got); } return got; } /* ** Reads symlink destination path and puts int into blob. ** Any prior content of the blob is discarded, not freed. ** ** Returns length of destination path. ** ** On windows, zeros blob and returns 0. */ int blob_read_link(Blob *pBlob, const char *zFilename){ #if !defined(_WIN32) char zBuf[1024]; ssize_t len = readlink(zFilename, zBuf, 1023); if( len < 0 ){ fossil_panic("cannot read symbolic link %s", zFilename); } zBuf[len] = 0; /* null-terminate */ blob_zero(pBlob); blob_appendf(pBlob, "%s", zBuf); return len; #else blob_zero(pBlob); return 0; #endif } /* ** Write the content of a blob into a file. ** ** If the filename is blank or "-" then write to standard output. ** ** Return the number of bytes written. |
︙ | ︙ |
Changes to src/branch.c.
︙ | ︙ | |||
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 | ** Show a timeline of all branches */ void brlist_page(void){ Stmt q; int cnt; int showClosed = P("closed")!=0; int showAll = P("all")!=0; login_check_credentials(); if( !g.okRead ){ login_needed(); return; } style_header(showClosed ? "Closed Branches" : showAll ? "All Branches" : "Open Branches"); style_submenu_element("Timeline", "Timeline", "brtimeline"); if( showClosed ){ style_submenu_element("All", "All", "brlist?all"); style_submenu_element("Open","Open","brlist"); }else if( showAll ){ style_submenu_element("Closed", "Closed", "brlist?closed"); style_submenu_element("Open","Open","brlist"); }else{ style_submenu_element("All", "All", "brlist?all"); style_submenu_element("Closed","Closed","brlist?closed"); } login_anonymous_available(); style_sidebox_begin("Nomenclature:", "33%"); @ <ol> @ <li> An <div class="sideboxDescribed"><a href="brlist"> @ open branch</a></div> is a branch that has one or @ more <a href="leaves">open leaves.</a> @ The presence of open leaves presumably means | > > > > > > > > > > | 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 | ** Show a timeline of all branches */ void brlist_page(void){ Stmt q; int cnt; int showClosed = P("closed")!=0; int showAll = P("all")!=0; int colorTest = P("colortest")!=0; login_check_credentials(); if( !g.okRead ){ login_needed(); return; } if( colorTest ){ showClosed = 0; showAll = 1; } style_header(showClosed ? "Closed Branches" : showAll ? "All Branches" : "Open Branches"); style_submenu_element("Timeline", "Timeline", "brtimeline"); if( showClosed ){ style_submenu_element("All", "All", "brlist?all"); style_submenu_element("Open","Open","brlist"); }else if( showAll ){ style_submenu_element("Closed", "Closed", "brlist?closed"); style_submenu_element("Open","Open","brlist"); }else{ style_submenu_element("All", "All", "brlist?all"); style_submenu_element("Closed","Closed","brlist?closed"); } if( !colorTest ){ style_submenu_element("Color-Test", "Color-Test", "brlist?colortest"); }else{ style_submenu_element("All", "All", "brlist?all"); } login_anonymous_available(); style_sidebox_begin("Nomenclature:", "33%"); @ <ol> @ <li> An <div class="sideboxDescribed"><a href="brlist"> @ open branch</a></div> is a branch that has one or @ more <a href="leaves">open leaves.</a> @ The presence of open leaves presumably means |
︙ | ︙ | |||
318 319 320 321 322 323 324 | style_sidebox_end(); prepareBranchQuery(&q, showAll, showClosed); cnt = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zBr = db_column_text(&q, 0); if( cnt==0 ){ | > > > > | > > > > | | | 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 | style_sidebox_end(); prepareBranchQuery(&q, showAll, showClosed); cnt = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zBr = db_column_text(&q, 0); if( cnt==0 ){ if( colorTest ){ @ <h2>Default background colors for all branches:</h2> }else if( showAll ){ @ <h2>All Branches:</h2> }else if( showClosed ){ @ <h2>Closed Branches:</h2> }else{ @ <h2>Open Branches:</h2> } @ <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.okHistory ){ @ <li><a href="%s(g.zTop)/timeline?r=%T(zBr)")>%h(zBr)</a></li> }else{ @ <li><b>%h(zBr)</b></li> } } if( cnt ){ @ </ul> } |
︙ | ︙ |
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_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{ |
︙ | ︙ | |||
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); | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | 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_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); |
︙ | ︙ | |||
633 634 635 636 637 638 639 | pFile = 0; } blob_appendf(pOut, "C %F\n", blob_str(pComment)); zDate = date_in_standard_format(zDateOvrd ? zDateOvrd : "now"); blob_appendf(pOut, "D %s\n", zDate); zDate[10] = ' '; db_prepare(&q, | | > | > > > > > > > | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 | pFile = 0; } blob_appendf(pOut, "C %F\n", blob_str(pComment)); zDate = date_in_standard_format(zDateOvrd ? zDateOvrd : "now"); blob_appendf(pOut, "D %s\n", zDate); zDate[10] = ' '; db_prepare(&q, "SELECT pathname, uuid, origname, blob.rid, isexe, islink," " file_is_selected(vfile.id)" " FROM vfile JOIN blob ON vfile.mrid=blob.rid" " WHERE (NOT deleted OR NOT file_is_selected(vfile.id))" " AND vfile.vid=%d" " ORDER BY 1", vid); blob_zero(&filename); blob_appendf(&filename, "%s", g.zLocalRoot); nBasename = blob_size(&filename); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zUuid = db_column_text(&q, 1); const char *zOrig = db_column_text(&q, 2); int frid = db_column_int(&q, 3); int isexe = db_column_int(&q, 4); int isLink = db_column_int(&q, 5); int isSelected = db_column_int(&q, 6); const char *zPerm; int cmp; #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_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_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 = ""; } if( !g.markPrivate ) content_make_public(frid); while( pFile && fossil_strcmp(pFile->zName,zName)<0 ){ blob_appendf(pOut, "F %F\n", pFile->zName); pFile = manifest_file_next(pBaseline, 0); |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | 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); | > > > > | > | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | 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_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); blob_reset(&content); if( rid>0 ){ content_deltify(rid, nrid, 0); } db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id); |
︙ | ︙ |
Changes to src/checkout.c.
︙ | ︙ | |||
90 91 92 93 94 95 96 | db_bind_text(&s, ":path", zFilename); db_step(&s); db_reset(&s); } /* ** Set or clear the execute permission bit (as appropriate) for all | | > | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | db_bind_text(&s, ":path", zFilename); db_step(&s); db_reset(&s); } /* ** Set or clear the execute permission bit (as appropriate) for all ** files in the current check-out, and replace files that have ** symlink bit with actual symlinks. */ void checkout_set_all_exe(int vid){ Blob filename; int baseLen; Manifest *pManifest; ManifestFile *pFile; |
︙ | ︙ |
Changes to src/configure.c.
︙ | ︙ | |||
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 ... ?-R|--repository REPOSITORY? ** ** 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. |
︙ | ︙ |
Changes to src/db.c.
︙ | ︙ | |||
734 735 736 737 738 739 740 741 742 743 744 745 746 | }else{ g.dbConfig = openDatabase(zDbName); } g.configOpen = 1; free(zDbName); } /* ** If zDbName is a valid local database file, open it and return ** true. If it is not a valid local database file, return 0. */ static int isValidLocalDb(const char *zDbName){ i64 lsize; | > > > > > > > > > > > > > > > > > > > < < | < < < | | | < < | | | < < | | < > > > < < < < < < < | > | | > | > | 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 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | }else{ g.dbConfig = openDatabase(zDbName); } g.configOpen = 1; free(zDbName); } /* * * Returns TRUE if zTable exists in the local database. */ static int db_local_table_exists(const char *zTable){ return db_exists("SELECT 1 FROM %s.sqlite_master" " WHERE name=='%s'", db_name("localdb"), zTable); } /* ** Returns TRUE if zColumn exists in zTable in the local database. */ static int db_local_column_exists(const char *zTable, const char *zColumn){ return db_exists("SELECT 1 FROM %s.sqlite_master" " WHERE name=='%s' AND sql GLOB '* %s *'", db_name("localdb"), zTable, zColumn); } /* ** If zDbName is a valid local database file, open it and return ** true. If it is not a valid local database file, return 0. */ static int isValidLocalDb(const char *zDbName){ i64 lsize; if( file_access(zDbName, F_OK) ) return 0; lsize = file_size(zDbName); if( lsize%1024!=0 || lsize<4096 ) return 0; db_open_or_attach(zDbName, "localdb"); g.localOpen = 1; db_open_config(0); db_open_repository(0); /* If the "isexe" column is missing from the vfile table, then ** add it now. This code added on 2010-03-06. After all users have ** upgraded, this code can be safely deleted. */ if( !db_local_column_exists("vfile", "isexe") ) db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0"); /* If "islink"/"isLink" columns are missing from tables, then ** add them now. This code added on 2011-01-17 and 2011-08-27. ** After all users have upgraded, this code can be safely deleted. */ if( !db_local_column_exists("vfile", "islink") ) db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0"); if( !db_local_column_exists("stashfile", "isLink") && db_local_table_exists("stashfile") ) db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOLEAN DEFAULT 0"); if( !db_local_column_exists("undo", "isLink") && db_local_table_exists("undo") ) db_multi_exec("ALTER TABLE undo ADD COLUMN isLink BOOLEAN DEFAULT 0"); if( !db_local_column_exists("undo_vfile", "islink") && db_local_table_exists("undo_vfile") ) db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOLEAN DEFAULT 0"); return 1; } /* ** Locate the root directory of the local repository tree. The root ** directory is found by searching for a file named "_FOSSIL_" or ".fos" |
︙ | ︙ | |||
864 865 866 867 868 869 870 871 872 873 874 875 876 877 | }else{ fossil_panic("not a valid repository: %s", zDbName); } } db_open_or_attach(zDbName, "repository"); g.repositoryOpen = 1; g.zRepositoryName = mprintf("%s", zDbName); } /* ** Flags for the db_find_and_open_repository() function. */ #if INTERFACE #define OPEN_OK_NOT_FOUND 0x001 /* Do not error out if not found */ | > > | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 | }else{ fossil_panic("not a valid repository: %s", zDbName); } } db_open_or_attach(zDbName, "repository"); g.repositoryOpen = 1; g.zRepositoryName = mprintf("%s", zDbName); /* Cache "allow-symlinks" option, because we'll need it on every stat call */ g.allowSymlinks = db_get_boolean("allow-symlinks", 0); } /* ** Flags for the db_find_and_open_repository() function. */ #if INTERFACE #define OPEN_OK_NOT_FOUND 0x001 /* Do not error out if not found */ |
︙ | ︙ | |||
1424 1425 1426 1427 1428 1429 1430 | zVersionedSetting = fossil_strdup(cacheEntry->zValue); break; } cacheEntry = cacheEntry->next; } /* Attempt to read value from file in checkout if there wasn't a cache hit ** and a checkout is open. */ | | | 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 | zVersionedSetting = fossil_strdup(cacheEntry->zValue); break; } cacheEntry = cacheEntry->next; } /* Attempt to read value from file in checkout if there wasn't a cache hit ** and a checkout is open. */ if( cacheEntry==0 ){ Blob versionedPathname; char *zVersionedPathname; blob_zero(&versionedPathname); blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, zName); zVersionedPathname = blob_str(&versionedPathname); if( file_size(zVersionedPathname)>=0 ){ |
︙ | ︙ | |||
1498 1499 1500 1501 1502 1503 1504 | z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName); } if( z==0 && g.configOpen ){ db_swap_connections(); z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName); db_swap_connections(); } | | | 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 | z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName); } if( z==0 && g.configOpen ){ db_swap_connections(); z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName); db_swap_connections(); } if( ctrlSetting!=0 && ctrlSetting->versionable && g.localOpen ){ /* This is a versionable setting, try and get the info from a checked out file */ z = db_get_do_versionable(zName, z); } if( z==0 ){ z = zDefault; } return z; |
︙ | ︙ | |||
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 | int width; /* Width of display. 0 for boolean values */ int versionable; /* Is this setting versionable? */ char const *def; /* Default value */ }; #endif /* INTERFACE */ struct stControlSettings const ctrlSettings[] = { { "access-log", 0, 0, 0, "off" }, { "auto-captcha", "autocaptcha", 0, 0, "on" }, { "auto-shun", 0, 0, 0, "on" }, { "autosync", 0, 0, 0, "on" }, { "binary-glob", 0, 32, 1, "" }, { "clearsign", 0, 0, 0, "off" }, { "case-sensitive",0, 0, 0, "on" }, { "crnl-glob", 0, 16, 1, "" }, | > | 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 | int width; /* Width of display. 0 for boolean values */ int versionable; /* Is this setting versionable? */ char const *def; /* Default value */ }; #endif /* INTERFACE */ struct stControlSettings const ctrlSettings[] = { { "access-log", 0, 0, 0, "off" }, { "allow-symlinks",0, 0, 0, "off" }, { "auto-captcha", "autocaptcha", 0, 0, "on" }, { "auto-shun", 0, 0, 0, "on" }, { "autosync", 0, 0, 0, "on" }, { "binary-glob", 0, 32, 1, "" }, { "clearsign", 0, 0, 0, "off" }, { "case-sensitive",0, 0, 0, "on" }, { "crnl-glob", 0, 16, 1, "" }, |
︙ | ︙ | |||
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 | ** ** Settings marked as versionable are overridden by the contents of the ** file named .fossil-settings/PROPERTY in the checked out files, if that ** file exists. ** ** The "unset" command clears a property setting. ** ** ** auto-captcha If enabled, the Login page provides a button to ** fill in the captcha password. Default: on ** ** auto-shun If enabled, automatically pull the shunning list ** from a server to which the client autosyncs. ** Default: on | > > > > > > | 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 | ** ** Settings marked as versionable are overridden by the contents of the ** file named .fossil-settings/PROPERTY in the checked out files, if that ** file exists. ** ** The "unset" command clears a property setting. ** ** ** allow-symlinks If enabled, don't follow symlinks, and instead treat ** them as symlinks on Unix. Has no effect on Windows ** (existing links in repository created on Unix become ** plain-text files with link destination path inside). ** Default: off ** ** auto-captcha If enabled, the Login page provides a button to ** fill in the captcha password. Default: on ** ** auto-shun If enabled, automatically pull the shunning list ** from a server to which the client autosyncs. ** Default: on |
︙ | ︙ |
Changes to src/diffcmd.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 | const char *zName2; /* Name of zFile2 for display */ /* Read content of zFile2 into memory */ blob_zero(&file2); if( file_size(zFile2)<0 ){ zName2 = "/dev/null"; }else{ | > > > | > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | const char *zName2; /* Name of zFile2 for display */ /* Read content of zFile2 into memory */ blob_zero(&file2); if( file_size(zFile2)<0 ){ zName2 = "/dev/null"; }else{ if( file_islink(zFile2) ){ blob_read_link(&file2, zFile2); }else{ blob_read_from_file(&file2, zFile2); } zName2 = zName; } /* Compute and output the differences */ blob_zero(&out); text_diff(pFile1, &file2, &out, 5, ignoreEolWs); if( blob_size(&out) ){ |
︙ | ︙ | |||
184 185 186 187 188 189 190 191 | const char *zFrom, /* Name of file */ const char *zDiffCmd, /* Use this "diff" command */ int ignoreEolWs, /* Ignore whitespace changes at end of lines */ const char *zFileTreeName ){ Blob fname; Blob content; file_tree_name(zFileTreeName, &fname, 1); | > | > > > | > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | const char *zFrom, /* Name of file */ const char *zDiffCmd, /* Use this "diff" command */ int ignoreEolWs, /* Ignore whitespace changes at end of lines */ 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_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); } /* ** Run a diff between the version zFrom and files on disk. zFrom might ** be NULL which means to simply show the difference between the edited |
︙ | ︙ | |||
220 221 222 223 224 225 226 | if( zFrom ){ int rid = name_to_typed_rid(zFrom, "ci"); if( !is_a_version(rid) ){ fossil_fatal("no such check-in: %s", zFrom); } load_vfile_from_rid(rid); blob_appendf(&sql, | | | | | > > > > > > > | 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 297 298 299 300 301 302 303 304 305 | if( zFrom ){ int rid = name_to_typed_rid(zFrom, "ci"); if( !is_a_version(rid) ){ fossil_fatal("no such check-in: %s", zFrom); } load_vfile_from_rid(rid); blob_appendf(&sql, "SELECT v2.pathname, v2.deleted, v2.chnged, v2.rid==0, v1.rid, v1.islink" " FROM vfile v1, vfile v2 " " WHERE v1.pathname=v2.pathname AND v1.vid=%d AND v2.vid=%d" " AND (v2.deleted OR v2.chnged OR v1.mrid!=v2.rid)" "UNION " "SELECT pathname, 1, 0, 0, 0, islink" " FROM vfile v1" " WHERE v1.vid=%d" " AND NOT EXISTS(SELECT 1 FROM vfile v2" " WHERE v2.vid=%d AND v2.pathname=v1.pathname)" "UNION " "SELECT pathname, 0, 0, 1, 0, islink" " FROM vfile v2" " WHERE v2.vid=%d" " AND NOT EXISTS(SELECT 1 FROM vfile v1" " WHERE v1.vid=%d AND v1.pathname=v2.pathname)" " ORDER BY 1", rid, vid, rid, vid, vid, rid ); }else{ blob_appendf(&sql, "SELECT pathname, deleted, chnged , rid==0, rid, islink" " FROM vfile" " WHERE vid=%d" " AND (deleted OR chnged OR rid==0)" " ORDER BY pathname", vid ); } db_prepare(&q, blob_str(&sql)); while( db_step(&q)==SQLITE_ROW ){ const char *zPathname = db_column_text(&q,0); int isDeleted = db_column_int(&q, 1); int isChnged = db_column_int(&q,2); int isNew = db_column_int(&q,3); int srcid = db_column_int(&q, 4); int isLink = db_column_int(&q, 5); char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); char *zToFree = zFullName; int showDiff = 1; if( isDeleted ){ diff_printf("DELETED %s\n", zPathname); if( !asNewFile ){ showDiff = 0; zFullName = "/dev/null"; } }else if( file_access(zFullName, 0) ){ diff_printf("MISSING %s\n", zPathname); if( !asNewFile ){ showDiff = 0; } }else if( isNew ){ diff_printf("ADDED %s\n", zPathname); srcid = 0; if( !asNewFile ){ showDiff = 0; } }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_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); }else{ blob_zero(&content); } diff_print_index(zPathname); diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs); |
︙ | ︙ | |||
305 306 307 308 309 310 311 312 313 | const char *zDiffCmd, int ignoreEolWs, const char *zFileTreeName ){ char *zName; Blob fname; Blob v1, v2; file_tree_name(zFileTreeName, &fname, 1); zName = blob_str(&fname); | > | | > > > > | > | 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 | const char *zDiffCmd, int ignoreEolWs, const char *zFileTreeName ){ char *zName; Blob fname; Blob v1, v2; int isLink1, isLink2; file_tree_name(zFileTreeName, &fname, 1); zName = blob_str(&fname); historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0); historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0); if( isLink1 != isLink2 ){ diff_printf("--- %s\n+++ %s\n", zName, zName); diff_printf("cannot compute difference between symlink and regular file\n"); }else{ diff_file_mem(&v1, &v2, zName, zDiffCmd, ignoreEolWs); } blob_reset(&v1); blob_reset(&v2); blob_reset(&fname); } /* ** Show the difference between two files identified by ManifestFile |
︙ | ︙ |
Changes to src/export.c.
︙ | ︙ | |||
267 268 269 270 271 272 273 | ); while( db_step(&q4)==SQLITE_ROW ){ const char *zName = db_column_text(&q4,0); int zNew = db_column_int(&q4,1); int mPerm = db_column_int(&q4,2); if( zNew==0) printf("D %s\n", zName); | | > > > > > > | > | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | ); while( db_step(&q4)==SQLITE_ROW ){ const char *zName = db_column_text(&q4,0); int zNew = db_column_int(&q4,1); int mPerm = db_column_int(&q4,2); if( zNew==0) printf("D %s\n", zName); else if( bag_find(&blobs, zNew) ) { const char *zPerm; switch( mPerm ){ case PERM_LNK: zPerm = "120000"; break; case PERM_EXE: zPerm = "100755"; break; default: zPerm = "100644"; break; } printf("M %s :%d %s\n", zPerm, BLOBMARK(zNew), zName); } } db_finalize(&q4); db_finalize(&q3); printf("\n"); } db_finalize(&q2); db_finalize(&q); |
︙ | ︙ |
Changes to src/file.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | /* ** 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__) | < | > | > > > > > > > > > > < > | | 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 | /* ** 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 static int fileStatValid = 0; static struct stat fileStat; static int fossil_stat(const char *zFilename, struct stat *buf){ #if !defined(_WIN32) if( g.allowSymlinks ){ return lstat(zFilename, buf); }else{ return stat(zFilename, buf); } #else return stat(zFilename, buf); #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. ** ** Return the number of errors. No error messages are generated. */ static int getStat(const char *zFilename){ int rc = 0; if( zFilename==0 ){ if( fileStatValid==0 ) rc = 1; }else{ char *zMbcs = fossil_utf8_to_mbcs(zFilename); if( fossil_stat(zMbcs, &fileStat)!=0 ){ fileStatValid = 0; rc = 1; }else{ fileStatValid = 1; rc = 0; } fossil_mbcs_free(zMbcs); |
︙ | ︙ | |||
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | ** 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) ? -1 : fileStat.st_mtime; } /* ** 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 : S_ISREG(fileStat.st_mode); } /* | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > | | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | 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 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 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 | ** 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) ? -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_isfile_or_link(const char *zFilename){ #if !defined(_WIN32) if ( g.allowSymlinks ){ return getStat(zFilename) ? 0 : S_ISREG(fileStat.st_mode) || S_ISLNK(fileStat.st_mode); } #endif return getStat(zFilename) ? 0 : S_ISREG(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 : 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 create_symlink(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) ){ zName = mprintf("%s", zLinkFile); }else{ zName = zBuf; memcpy(zName, zLinkFile, nName+1); } nName = file_simplify_name(zName, nName); for(i=1; i<nName; i++){ if( zName[i]=='/' ){ zName[i] = 0; if( file_mkdir(zName, 1) ){ fossil_fatal_recursive("unable to create directory %s", zName); return; } zName[i] = '/'; } } if( zName!=zBuf ) free(zName); if( symlink(zTargetFile, zName)!=0 ){ fossil_fatal_recursive("unable to create symlink \"%s\"", zName); } }else #endif { Blob content; blob_set(&content, zTargetFile); blob_write_to_file(&content, zLinkFile); 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_perm(const char *zFilename){ if( getStat(zFilename) ) 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_isexe(const char *zFilename){ return file_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_islink(const char *zFilename){ return file_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); free(zFN); }else{ rc = getStat(0); } #if !defined(_WIN32) if( g.allowSymlinks ){ return rc ? 0 : (S_ISDIR(fileStat.st_mode) && !S_ISLNK(fileStat.st_mode) ? 1 : 2); }else{ return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); } #else return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); #endif } /* ** Wrapper around the access() system call. */ int file_access(const char *zFilename, int flags){ char *zMbcs = fossil_utf8_to_mbcs(zFilename); |
︙ | ︙ | |||
197 198 199 200 201 202 203 | ** 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_setexe(const char *zFilename, int onoff){ int rc = 0; #if !defined(_WIN32) struct stat buf; | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | ** 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_setexe(const char *zFilename, int onoff){ int rc = 0; #if !defined(_WIN32) struct stat buf; if( fossil_stat(zFilename, &buf)!=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{ |
︙ | ︙ | |||
467 468 469 470 471 472 473 474 475 476 477 478 479 480 | fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x)); blob_reset(&x); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName)); fossil_print(" file_size = %s\n", zBuf); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName)); fossil_print(" file_mtime = %s\n", zBuf); fossil_print(" file_isfile = %d\n", file_isfile(zName)); fossil_print(" file_isexe = %d\n", file_isexe(zName)); fossil_print(" file_isdir = %d\n", file_isdir(zName)); } } /* ** Return TRUE if the given filename is canonical. | > > | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x)); blob_reset(&x); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName)); fossil_print(" file_size = %s\n", zBuf); sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName)); fossil_print(" file_mtime = %s\n", zBuf); fossil_print(" file_isfile = %d\n", file_isfile(zName)); fossil_print(" file_isfile_or_link = %d\n", file_isfile_or_link(zName)); fossil_print(" file_islink = %d\n", file_islink(zName)); fossil_print(" file_isexe = %d\n", file_isexe(zName)); fossil_print(" file_isdir = %d\n", file_isdir(zName)); } } /* ** Return TRUE if the given filename is canonical. |
︙ | ︙ | |||
737 738 739 740 741 742 743 | i64 iSize; int rc; Blob onDisk; iSize = file_size(zName); if( iSize<0 ) return 0; if( iSize!=blob_size(pContent) ) return 0; | > > > | > | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 | i64 iSize; int rc; Blob onDisk; iSize = file_size(zName); if( iSize<0 ) return 0; if( iSize!=blob_size(pContent) ) return 0; if( file_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.
︙ | ︙ | |||
97 98 99 100 101 102 103 | }else if( find_option("print","p",0) ){ Blob record; Blob fname; const char *zRevision = find_option("revision", "r", 1); file_tree_name(g.argv[2], &fname, 1); if( zRevision ){ | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | }else if( find_option("print","p",0) ){ Blob record; Blob fname; const char *zRevision = find_option("revision", "r", 1); file_tree_name(g.argv[2], &fname, 1); if( zRevision ){ historical_version_of_file(zRevision, blob_str(&fname), &record, 0, 0, 0); }else{ int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B", &fname); if( rid==0 ){ fossil_fatal("no history for file: %b", &fname); } content_get(rid, &record); } |
︙ | ︙ |
Changes to src/http_ssl.c.
︙ | ︙ | |||
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]); } } | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | 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); /* null-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" |
︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | return 1; } if( blob_str(&ans)[0]=='a' ) { ssl_save_certificate(cert); } blob_reset(&ans); } X509_free(cert); return 0; } /* ** Save certificate to global config. */ void ssl_save_certificate(X509 *cert){ BIO *mem; char *zCert, *zHost; mem = BIO_new(BIO_s_mem()); PEM_write_bio_X509(mem, cert); | > > > > > > > > > > > | | 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 | return 1; } if( blob_str(&ans)[0]=='a' ) { ssl_save_certificate(cert); } blob_reset(&ans); } /* Set the Global.zIpAddr variable to the server we are talking to. ** This is used to populate the ipaddr column of the rcvfrom table, ** if any files are received from the server. */ { /* IPv4 only code */ const unsigned char *ip = (const unsigned char *) BIO_get_conn_ip(iBio); g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } X509_free(cert); return 0; } /* ** Save certificate to global config. */ 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); /* null-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.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | */ struct ImportFile { char *zName; /* Name of a file */ char *zUuid; /* UUID of the file */ char *zPrior; /* Prior name if the name was changed */ char isFrom; /* True if obtained from the parent */ char isExe; /* True if executable */ }; #endif /* ** State information about an on-going fast-import parse. */ | > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | */ struct ImportFile { char *zName; /* Name of a file */ char *zUuid; /* UUID of the file */ char *zPrior; /* Prior name if the name was changed */ char isFrom; /* True if obtained from the parent */ char isExe; /* True if executable */ char isLink; /* True if symlink */ }; #endif /* ** State information about an on-going fast-import parse. */ |
︙ | ︙ | |||
56 57 58 59 60 61 62 63 64 65 66 67 68 69 | int nMerge; /* Number of merge values */ int nMergeAlloc; /* Number of slots in azMerge[] */ char **azMerge; /* Merge values */ int nFile; /* Number of aFile values */ int nFileAlloc; /* Number of slots in aFile[] */ ImportFile *aFile; /* Information about files in a commit */ int fromLoaded; /* True zFrom content loaded into aFile[] */ int tagCommit; /* True if the commit adds a tag */ } gg; /* ** Duplicate a string. */ char *fossil_strdup(const char *zOrig){ | > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | int nMerge; /* Number of merge values */ int nMergeAlloc; /* Number of slots in azMerge[] */ char **azMerge; /* Merge values */ int nFile; /* Number of aFile values */ int nFileAlloc; /* Number of slots in aFile[] */ ImportFile *aFile; /* Information about files in a commit */ int fromLoaded; /* True zFrom content loaded into aFile[] */ int hasLinks; /* True if git repository contains symlinks */ int tagCommit; /* True if the commit adds a tag */ } gg; /* ** Duplicate a string. */ char *fossil_strdup(const char *zOrig){ |
︙ | ︙ | |||
240 241 242 243 244 245 246 247 248 249 250 251 252 253 | blob_appendf(&record, "D %s\n", gg.zDate); for(i=0; i<gg.nFile; i++){ const char *zUuid = gg.aFile[i].zUuid; if( zUuid==0 ) continue; blob_appendf(&record, "F %F %s", gg.aFile[i].zName, zUuid); if( gg.aFile[i].isExe ){ blob_append(&record, " x\n", 3); }else{ blob_append(&record, "\n", 1); } } if( gg.zFrom ){ blob_appendf(&record, "P %s", gg.zFrom); for(i=0; i<gg.nMerge; i++){ | > > > | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | blob_appendf(&record, "D %s\n", gg.zDate); for(i=0; i<gg.nFile; i++){ const char *zUuid = gg.aFile[i].zUuid; if( zUuid==0 ) continue; blob_appendf(&record, "F %F %s", gg.aFile[i].zName, zUuid); if( gg.aFile[i].isExe ){ blob_append(&record, " x\n", 3); }else if( gg.aFile[i].isLink ){ blob_append(&record, " l\n", 3); gg.hasLinks = 1; }else{ blob_append(&record, "\n", 1); } } if( gg.zFrom ){ blob_appendf(&record, "P %s", gg.zFrom); for(i=0; i<gg.nMerge; i++){ |
︙ | ︙ | |||
419 420 421 422 423 424 425 426 427 428 429 430 431 432 | p = manifest_get(rid, CFTYPE_MANIFEST); if( p==0 ) return; manifest_file_rewind(p); while( (pOld = manifest_file_next(p, 0))!=0 ){ pNew = import_add_file(); pNew->zName = fossil_strdup(pOld->zName); pNew->isExe = pOld->zPerm && strstr(pOld->zPerm, "x")!=0; pNew->zUuid = fossil_strdup(pOld->zUuid); pNew->isFrom = 1; } manifest_destroy(p); } /* | > | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | p = manifest_get(rid, CFTYPE_MANIFEST); if( p==0 ) return; manifest_file_rewind(p); while( (pOld = manifest_file_next(p, 0))!=0 ){ pNew = import_add_file(); pNew->zName = fossil_strdup(pOld->zName); pNew->isExe = pOld->zPerm && strstr(pOld->zPerm, "x")!=0; pNew->isLink = pOld->zPerm && strstr(pOld->zPerm, "l")!=0; pNew->zUuid = fossil_strdup(pOld->zUuid); pNew->isFrom = 1; } manifest_destroy(p); } /* |
︙ | ︙ | |||
595 596 597 598 599 600 601 602 603 604 605 606 607 608 | i = 0; pFile = import_find_file(zName, &i, gg.nFile); if( pFile==0 ){ pFile = import_add_file(); pFile->zName = fossil_strdup(zName); } pFile->isExe = (fossil_strcmp(zPerm, "100755")==0); fossil_free(pFile->zUuid); pFile->zUuid = resolve_committish(zUuid); pFile->isFrom = 0; }else if( memcmp(zLine, "D ", 2)==0 ){ import_prior_files(); z = &zLine[2]; | > | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | i = 0; pFile = import_find_file(zName, &i, gg.nFile); if( pFile==0 ){ pFile = import_add_file(); pFile->zName = fossil_strdup(zName); } pFile->isExe = (fossil_strcmp(zPerm, "100755")==0); pFile->isLink = (fossil_strcmp(zPerm, "120000")==0); fossil_free(pFile->zUuid); pFile->zUuid = resolve_committish(zUuid); pFile->isFrom = 0; }else if( memcmp(zLine, "D ", 2)==0 ){ import_prior_files(); z = &zLine[2]; |
︙ | ︙ | |||
632 633 634 635 636 637 638 639 640 641 642 643 644 645 | pFile = &gg.aFile[i-1]; if( strlen(pFile->zName)>nFrom ){ pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]); }else{ pNew->zName = fossil_strdup(pFile->zName); } pNew->isExe = pFile->isExe; pNew->zUuid = fossil_strdup(pFile->zUuid); pNew->isFrom = 0; } }else if( memcmp(zLine, "R ", 2)==0 ){ int nFrom; import_prior_files(); | > | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | pFile = &gg.aFile[i-1]; if( strlen(pFile->zName)>nFrom ){ pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]); }else{ pNew->zName = fossil_strdup(pFile->zName); } pNew->isExe = pFile->isExe; pNew->isLink = pFile->isLink; pNew->zUuid = fossil_strdup(pFile->zUuid); pNew->isFrom = 0; } }else if( memcmp(zLine, "R ", 2)==0 ){ int nFrom; import_prior_files(); |
︙ | ︙ | |||
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 680 681 682 683 684 685 686 687 688 | if( strlen(pFile->zName)>nFrom ){ pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]); }else{ pNew->zName = fossil_strdup(pFile->zName); } pNew->zPrior = pFile->zName; pNew->isExe = pFile->isExe; pNew->zUuid = pFile->zUuid; pNew->isFrom = 0; gg.nFile--; *pFile = *pNew; memset(pNew, 0, sizeof(*pNew)); } fossil_fatal("cannot handle R records, use --full-tree"); }else if( memcmp(zLine, "deleteall", 9)==0 ){ gg.fromLoaded = 1; }else if( memcmp(zLine, "N ", 2)==0 ){ /* No-op */ }else { goto malformed_line; } } gg.xFinish(); import_reset(1); return; malformed_line: trim_newline(zLine); fossil_fatal("bad fast-import line: [%s]", zLine); return; | > > > > | 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 | if( strlen(pFile->zName)>nFrom ){ pNew->zName = mprintf("%s%s", zTo, pFile->zName[nFrom]); }else{ pNew->zName = fossil_strdup(pFile->zName); } pNew->zPrior = pFile->zName; pNew->isExe = pFile->isExe; pNew->isLink = pFile->isLink; pNew->zUuid = pFile->zUuid; pNew->isFrom = 0; gg.nFile--; *pFile = *pNew; memset(pNew, 0, sizeof(*pNew)); } fossil_fatal("cannot handle R records, use --full-tree"); }else if( memcmp(zLine, "deleteall", 9)==0 ){ gg.fromLoaded = 1; }else if( memcmp(zLine, "N ", 2)==0 ){ /* No-op */ }else { goto malformed_line; } } gg.xFinish(); if( gg.hasLinks ){ db_set_int("allow-symlinks", 1, 0); } import_reset(1); return; malformed_line: trim_newline(zLine); fossil_fatal("bad fast-import line: [%s]", zLine); return; |
︙ | ︙ |
Changes to src/info.c.
︙ | ︙ | |||
280 281 282 283 284 285 286 | */ static void append_file_change_line( 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 */ | | | > | | 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 | */ static void append_file_change_line( 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.okHistory ){ 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 ){ @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") @ for %h(zName)</p> }else{ @ <p>Changes to %h(zName)</p> } if( showDiff ){ @ <blockquote><pre> append_diff(zOld, zNew); @ </pre></blockquote> } }else{ if( zOld && zNew ){ if( fossil_strcmp(zOld, zNew)!=0 ){ @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a> @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a> @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a> }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){ @ <p>Name change from @ from <a href="%s(g.zTop)/finfo?name=%T(zOldName)">%h(zOldName)</a> @ to <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>. }else{ @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for @ <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a> } }else if( zOld ){ @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a> @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a> }else{ @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a> |
︙ | ︙ | |||
774 775 776 777 778 779 780 781 782 783 784 | Blob *pDownloadName /* Fill with an appropriate download name */ ){ Stmt q; int cnt = 0; int nWiki = 0; char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); db_prepare(&q, "SELECT filename.name, datetime(event.mtime)," " coalesce(event.ecomment,event.comment)," " coalesce(event.euser,event.user)," | > > | > > | > | > > > > | > > > > > | | | | | | | | | > > > > > | > > > > > > > | | < > > > | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 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 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 | Blob *pDownloadName /* Fill with an appropriate download name */ ){ Stmt q; int cnt = 0; int nWiki = 0; char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); char *prevName = 0; db_prepare(&q, "SELECT filename.name, datetime(event.mtime)," " coalesce(event.ecomment,event.comment)," " coalesce(event.euser,event.user)," " b.uuid, mlink.mperm," " coalesce((SELECT value FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=mlink.mid),'trunk')" " FROM mlink, filename, event, blob a, blob b" " WHERE filename.fnid=mlink.fnid" " AND event.objid=mlink.mid" " AND a.rid=mlink.fid" " AND b.rid=mlink.mid" " AND mlink.fid=%d" " ORDER BY filename.name, event.mtime", TAG_BRANCH, rid ); @ <ul> while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); const char *zDate = db_column_text(&q, 1); const char *zCom = db_column_text(&q, 2); const char *zUser = db_column_text(&q, 3); const char *zVers = db_column_text(&q, 4); int mPerm = db_column_int(&q, 5); const char *zBr = db_column_text(&q, 6); if( !prevName || fossil_strcmp(zName, prevName) ) { if( prevName ) { @ </ul> } if( mPerm==PERM_LNK ){ @ <li>Symbolic link }else if( mPerm==PERM_EXE ){ @ <li>Executable file }else{ @ <li>File } if( g.okHistory ){ @ <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.okHistory ){ @ 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.okHistory ){ @ <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); } } @ </ul></ul> free(prevName); db_finalize(&q); db_prepare(&q, "SELECT substr(tagname, 6, 10000), datetime(event.mtime)," " coalesce(event.euser, event.user)" " FROM tagxref, tag, event" " WHERE tagxref.rid=%d" " AND tag.tagid=tagxref.tagid" |
︙ | ︙ | |||
986 987 988 989 990 991 992 | blob_reset(&c2); if( !isPatch ){ style_header("Diff"); style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", g.zTop, P("v1"), P("v2")); @ <h2>Differences From @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> | < | < < | < | 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 | blob_reset(&c2); if( !isPatch ){ style_header("Diff"); style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", g.zTop, P("v1"), P("v2")); @ <h2>Differences From @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> object_description(v1, 0, 0); @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> object_description(v2, 0, 0); @ <hr /> @ <blockquote><pre> @ %h(blob_str(&diff)) @ </pre></blockquote> blob_reset(&diff); style_footer(); } |
︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 | style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } style_header("Hex Artifact Content"); zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid); @ <h2>Artifact %s(zUuid):</h2> | < < | 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 | style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } style_header("Hex Artifact Content"); zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid); @ <h2>Artifact %s(zUuid):</h2> blob_zero(&downloadName); object_description(rid, 0, &downloadName); style_submenu_element("Download", "Download", "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); @ <hr /> content_get(rid, &content); @ <blockquote><pre> hexdump(&content); @ </pre></blockquote> style_footer(); } |
︙ | ︙ | |||
1254 1255 1256 1257 1258 1259 1260 | style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } style_header("Artifact Content"); zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); @ <h2>Artifact %s(zUuid)</h2> | < | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } style_header("Artifact Content"); zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); @ <h2>Artifact %s(zUuid)</h2> blob_zero(&downloadName); object_description(rid, 0, &downloadName); style_submenu_element("Download", "Download", "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); zMime = mimetype_from_name(blob_str(&downloadName)); if( zMime ){ if( fossil_strcmp(zMime, "text/html")==0 ){ |
︙ | ︙ | |||
1281 1282 1283 1284 1285 1286 1287 | }else{ renderAsWiki = 1; style_submenu_element("Text", "Text", "%s/artifact/%s?txt=1", g.zTop, zUuid); } } } | < | 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 | }else{ renderAsWiki = 1; style_submenu_element("Text", "Text", "%s/artifact/%s?txt=1", g.zTop, zUuid); } } } @ <hr /> content_get(rid, &content); if( renderAsWiki ){ wiki_convert(&content, 0, 0); }else if( renderAsHtml ){ @ <div> cgi_append_content(blob_buffer(&content), blob_size(&content)); |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 | /* Storage for the aux() and/or option() SQL function arguments */ int nAux; /* Number of distinct aux() or option() values */ const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */ char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */ const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */ const char **azAuxOpt[MX_AUX]; /* Options of each option() value */ int anAuxCols[MX_AUX]; /* Number of columns for option() values */ }; /* ** Macro for debugging: */ #define CGIDEBUG(X) if( g.fDebug ) cgi_debug X | > > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | /* Storage for the aux() and/or option() SQL function arguments */ int nAux; /* Number of distinct aux() or option() values */ const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */ char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */ const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */ const char **azAuxOpt[MX_AUX]; /* Options of each option() value */ int anAuxCols[MX_AUX]; /* Number of columns for option() values */ int allowSymlinks; /* Cached "allow-symlinks" option */ }; /* ** Macro for debugging: */ #define CGIDEBUG(X) if( g.fDebug ) cgi_debug X |
︙ | ︙ |
Changes to src/manifest.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #define CFTYPE_CLUSTER 2 #define CFTYPE_CONTROL 3 #define CFTYPE_WIKI 4 #define CFTYPE_TICKET 5 #define CFTYPE_ATTACHMENT 6 #define CFTYPE_EVENT 7 /* ** A single F-card within a manifest */ struct ManifestFile { char *zName; /* Name of a file */ char *zUuid; /* UUID of the file */ char *zPerm; /* File permissions */ | > > > > > > > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #define CFTYPE_CLUSTER 2 #define CFTYPE_CONTROL 3 #define CFTYPE_WIKI 4 #define CFTYPE_TICKET 5 #define CFTYPE_ATTACHMENT 6 #define CFTYPE_EVENT 7 /* ** File permissions used by Fossil internally. */ #define PERM_REG 0 /* regular file */ #define PERM_EXE 1 /* executable */ #define PERM_LNK 2 /* symlink */ /* ** A single F-card within a manifest */ struct ManifestFile { char *zName; /* Name of a file */ char *zUuid; /* UUID of the file */ char *zPerm; /* File permissions */ |
︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 | } /* ** Compute an appropriate mlink.mperm integer for the permission string ** of a file. */ int manifest_file_mperm(ManifestFile *pFile){ | | | > | > > | | 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 | } /* ** Compute an appropriate mlink.mperm integer for the permission string ** of a file. */ int manifest_file_mperm(ManifestFile *pFile){ int mperm = PERM_REG; if( pFile && pFile->zPerm){ if( strstr(pFile->zPerm,"x")!=0 ) mperm = PERM_EXE; else if( strstr(pFile->zPerm,"l")!=0 ) mperm = PERM_LNK; } return mperm; } /* ** Add a single entry to the mlink table. Also add the filename to ** the filename table if it is not there already. */ static void add_one_mlink( int mid, /* The record ID of the manifest */ const char *zFromUuid, /* UUID for the mlink.pid. "" to add file */ const char *zToUuid, /* UUID for the mlink.fid. "" to delele */ const char *zFilename, /* Filename */ const char *zPrior, /* Previous filename. NULL if unchanged */ int isPublic, /* True if mid is not a private manifest */ int mperm /* 1: exec, 2: symlink */ ){ int fnid, pfnid, pid, fid; static Stmt s1; fnid = filename_to_fnid(zFilename); if( zPrior==0 ){ pfnid = 0; |
︙ | ︙ |
Changes to src/merge.c.
︙ | ︙ | |||
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 | 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( "DROP TABLE IF EXISTS fv;" "CREATE TEMP TABLE fv(" " fn TEXT PRIMARY KEY COLLATE %s," /* The filename */ " idv INTEGER," /* VFILE entry for current version */ " idp INTEGER," /* VFILE entry for the pivot */ " idm INTEGER," /* VFILE entry for version merging in */ " chnged BOOLEAN," /* True if current version has been edited */ " ridv INTEGER," /* Record ID for current version */ " ridp INTEGER," /* Record ID for pivot */ " ridm INTEGER," /* Record ID for merge */ " isexe BOOLEAN," /* Execute permission enabled */ " fnp TEXT," /* The filename in the pivot */ | > > > > > > > > > | > > | | | | 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 214 215 216 | 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( "DROP TABLE IF EXISTS fv;" "CREATE TEMP TABLE fv(" " fn TEXT PRIMARY KEY COLLATE %s," /* The filename */ " idv INTEGER," /* VFILE entry for current version */ " idp INTEGER," /* VFILE entry for the pivot */ " idm INTEGER," /* VFILE entry for version merging in */ " chnged BOOLEAN," /* True if current version has been edited */ " ridv INTEGER," /* Record ID for current version */ " ridp INTEGER," /* Record ID for pivot */ " ridm INTEGER," /* Record ID for merge */ " isexe BOOLEAN," /* Execute permission enabled */ " fnp TEXT," /* The filename in the pivot */ " fnm TEXT," /* the filename in the merged version */ " islinkv BOOLEAN," /* True if current version is a symlink */ " islinkm BOOLEAN" /* True if merged version in is a symlink */ ");", caseSensitive ? "binary" : "nocase" ); /* Add files found in V */ db_multi_exec( "INSERT OR IGNORE" " INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,isexe,chnged)" " SELECT pathname, pathname, pathname, id, 0, 0, rid, 0, 0, isexe, chnged " " 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"); } |
︙ | ︙ | |||
213 214 215 216 217 218 219 | " 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] |
︙ | ︙ | |||
246 247 248 249 250 251 252 | ** 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); } |
︙ | ︙ | |||
299 300 301 302 303 304 305 | ); 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 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 | ); 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); /* ** Do a three-way merge on files that have changes on both P->M and P->V. */ db_prepare(&q, "SELECT ridm, idv, ridp, ridv, %s, fn, isexe, islinkv, islinkm FROM fv" " WHERE idp>0 AND idv>0 AND idm>0" " AND ridm!=ridp AND (ridv!=ridp OR chnged)", glob_expr("fv.fn", zBinGlob) ); while( db_step(&q)==SQLITE_ROW ){ int ridm = db_column_int(&q, 0); int idv = db_column_int(&q, 1); int ridp = db_column_int(&q, 2); int ridv = db_column_int(&q, 3); int isBinary = db_column_int(&q, 4); const char *zName = db_column_text(&q, 5); int isExe = db_column_int(&q, 6); int islinkv = db_column_int(&q, 7); int islinkm = db_column_int(&q, 8); int rc; char *zFullPath; Blob m, p, r; /* 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_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_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{ fossil_print("***** Cannot merge binary file %s\n", zName); nConflict++; } blob_reset(&p); blob_reset(&m); blob_reset(&r); } db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)", idv,ridm); } db_finalize(&q); /* ** Drop files that are in P and V but not in M |
︙ | ︙ |
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/report.c.
︙ | ︙ | |||
196 197 198 199 200 201 202 203 204 205 206 207 208 209 | rc = SQLITE_DENY; break; } } return rc; } /* ** Check the given SQL to see if is a valid query that does not ** attempt to do anything dangerous. Return 0 on success and a ** pointer to an error message string (obtained from malloc) if ** there is a problem. */ | > > > > > > > > > > > | 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 | rc = SQLITE_DENY; break; } } return rc; } /* ** Activate the query authorizer */ static void report_restrict_sql(char **pzErr){ (void)fossil_localtime(0); sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr); } static void report_unrestrict_sql(void){ sqlite3_set_authorizer(g.db, 0, 0); } /* ** Check the given SQL to see if is a valid query that does not ** attempt to do anything dangerous. Return 0 on success and a ** pointer to an error message string (obtained from malloc) if ** there is a problem. */ |
︙ | ︙ | |||
235 236 237 238 239 240 241 | return mprintf("Semi-colon detected! " "Only a single SQL statement is allowed"); } } } /* Compile the statement and check for illegal accesses or syntax errors. */ | | | | 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 | return mprintf("Semi-colon detected! " "Only a single SQL statement is allowed"); } } } /* Compile the statement and check for illegal accesses or syntax errors. */ report_restrict_sql(&zErr); rc = sqlite3_prepare(g.db, zSql, -1, &pStmt, &zTail); if( rc!=SQLITE_OK ){ zErr = mprintf("Syntax error: %s", sqlite3_errmsg(g.db)); } if( !sqlite3_stmt_readonly(pStmt) ){ zErr = mprintf("SQL must not modify the database"); } if( pStmt ){ sqlite3_finalize(pStmt); } report_unrestrict_sql(); return zErr; } /* ** WEBPAGE: /rptsql */ void view_see_sql(void){ |
︙ | ︙ | |||
961 962 963 964 965 966 967 | } 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"> sState.rn = rn; sState.nCount = 0; | < | | | | | 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 | } 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"> sState.rn = rn; sState.nCount = 0; report_restrict_sql(&zErr1); sqlite3_exec_readonly(g.db, zSql, generate_html, &sState, &zErr2); report_unrestrict_sql(); @ </table> if( zErr1 ){ @ <p class="reportError">Error: %h(zErr1)</p> }else if( zErr2 ){ @ <p class="reportError">Error: %h(zErr2)</p> } style_footer(); }else{ report_restrict_sql(&zErr1); sqlite3_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2); report_unrestrict_sql(); cgi_set_content_type("text/plain"); } } /* ** report number for full table ticket export */ |
︙ | ︙ | |||
1135 1136 1137 1138 1139 1140 1141 | } if( zFilter ){ zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter); } count = 0; tktEncode = enc; zSep = zSepIn; | | | | 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 | } if( zFilter ){ zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter); } count = 0; tktEncode = enc; zSep = zSepIn; report_restrict_sql(&zErr1); sqlite3_exec_readonly(g.db, zSql, output_separated_file, &count, &zErr2); report_unrestrict_sql(); if( zFilter ){ free(zSql); } } |
Changes to src/schema.c.
︙ | ︙ | |||
459 460 461 462 463 464 465 466 467 468 469 470 471 472 | @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ isexe BOOLEAN, -- True if file should be executable @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 @ pathname TEXT, -- Full pathname relative to root @ origname TEXT, -- Original pathname. NULL if unchanged @ UNIQUE(pathname,vid) @ ); | > | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ isexe BOOLEAN, -- True if file should be executable @ islink BOOLEAN, -- True if file should be symlink @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 @ pathname TEXT, -- Full pathname relative to root @ origname TEXT, -- Original pathname. NULL if unchanged @ UNIQUE(pathname,vid) @ ); |
︙ | ︙ |
Changes to src/setup.c.
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 | login_check_credentials(); if( !g.okSetup ){ login_needed(); } style_header("Settings"); db_begin_transaction(); @ <p>This page provides a simple interface to the "fossil setting" command. @ See the "fossil help setting" output below for further information on @ the meaning of each setting.</p><hr /> @ <form action="%s(g.zTop)/setup_settings" method="post"><div> @ <table border="0"><tr><td valign="top"> login_insert_csrf_secret(); | > | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | login_check_credentials(); if( !g.okSetup ){ login_needed(); } style_header("Settings"); db_open_local(); db_begin_transaction(); @ <p>This page provides a simple interface to the "fossil setting" command. @ See the "fossil help setting" output below for further information on @ the meaning of each setting.</p><hr /> @ <form action="%s(g.zTop)/setup_settings" method="post"><div> @ <table border="0"><tr><td valign="top"> login_insert_csrf_secret(); |
︙ | ︙ |
Changes to src/sha1.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ | > > > > > > > > > > | > > > > > > > > | | | | | | | | | | | < < < < < > > > > > > | < < | < | > > > | 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 | /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #endif #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 * * Rl0() for little-endian and Rb0() for big-endian. Endianness is * determined at run-time. */ #define Rl0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2); #define Rb0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R1(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R2(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2); #define R3(v,w,x,y,z,i) \ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2); #define R4(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2); /* * Hash a single 512-bit block. This is the core of the algorithm. */ #define a qq[0] #define b qq[1] #define c qq[2] #define d qq[3] #define e qq[4] void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]) { unsigned int qq[5]; // a, b, c, d, e; static int one = 1; unsigned int block[16]; memcpy(block, buffer, 64); memcpy(qq,state,5*sizeof(unsigned int)); /* Copy context->state[] to working vars */ /* a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; */ /* 4 rounds of 20 operations each. Loop unrolled. */ if( 1 == *(unsigned char*)&one ){ Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3); Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7); Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11); Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15); |
︙ | ︙ | |||
111 112 113 114 115 116 117 | /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; | < < < | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } /* * SHA1Init - Initialize new context */ static void SHA1Init(SHA1Context *context){ |
︙ | ︙ | |||
190 191 192 193 194 195 196 | ** Convert a digest into base-16. digest should be declared as ** "unsigned char digest[20]" in the calling function. The SHA1 ** digest is stored in the first 20 bytes. zBuf should ** be "char zBuf[41]". */ static void DigestToBase16(unsigned char *digest, char *zBuf){ static char const zEncode[] = "0123456789abcdef"; | | | < | | | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | ** Convert a digest into base-16. digest should be declared as ** "unsigned char digest[20]" in the calling function. The SHA1 ** digest is stored in the first 20 bytes. zBuf should ** be "char zBuf[41]". */ static void DigestToBase16(unsigned char *digest, char *zBuf){ static char const zEncode[] = "0123456789abcdef"; int ix; for(ix=0; ix<20; ix++){ *zBuf++ = zEncode[(*digest>>4)&0xf]; *zBuf++ = zEncode[*digest++ & 0xf]; } *zBuf = '\0'; } /* ** The state of a incremental SHA1 checksum computation. Only one ** such computation can be underway at a time, of course. */ static SHA1Context incrCtx; |
︙ | ︙ | |||
263 264 265 266 267 268 269 270 271 272 273 274 275 276 | ** Return the number of errors. */ int sha1sum_file(const char *zFilename, Blob *pCksum){ FILE *in; SHA1Context ctx; unsigned char zResult[20]; char zBuf[10240]; in = fossil_fopen(zFilename,"rb"); if( in==0 ){ return 1; } SHA1Init(&ctx); for(;;){ | > > > > > > > > > > > | 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 | ** Return the number of errors. */ int sha1sum_file(const char *zFilename, Blob *pCksum){ FILE *in; SHA1Context ctx; unsigned char zResult[20]; char zBuf[10240]; if( file_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); return rc; } in = fossil_fopen(zFilename,"rb"); if( in==0 ){ return 1; } SHA1Init(&ctx); for(;;){ |
︙ | ︙ |
Changes to src/sqlite3.c.
︙ | ︙ | |||
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | #endif /* ** Exactly one of the following macros must be defined in order to ** specify which memory allocation subsystem to use. ** ** SQLITE_SYSTEM_MALLOC // Use normal system malloc() ** SQLITE_MEMDEBUG // Debugging version of system malloc() ** ** (Historical note: There used to be several other options, but we've ** pared it down to just these two.) ** ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as ** the default. */ | > > > > > > | | | | 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 | #endif /* ** Exactly one of the following macros must be defined in order to ** specify which memory allocation subsystem to use. ** ** SQLITE_SYSTEM_MALLOC // Use normal system malloc() ** SQLITE_WIN32_MALLOC // Use Win32 native heap API ** SQLITE_MEMDEBUG // Debugging version of system malloc() ** ** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the ** assert() macro is enabled, each call into the Win32 native heap subsystem ** will cause HeapValidate to be called. If heap validation should fail, an ** assertion will be triggered. ** ** (Historical note: There used to be several other options, but we've ** pared it down to just these two.) ** ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as ** the default. */ #if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)>1 # error "At most one of the following compile-time configuration options\ is allows: SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG" #endif #if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)==0 # define SQLITE_SYSTEM_MALLOC 1 #endif /* ** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the ** sizes of memory allocations below this value where possible. */ |
︙ | ︙ | |||
648 649 650 651 652 653 654 | ** ** 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-04 01:27:00 6b657ae75035eb10b0ad640998d3c9eadfdffa6e" /* ** 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 |
︙ | ︙ | |||
1749 1750 1751 1752 1753 1754 1755 | ** and that this object is only useful to a tiny minority of applications ** with specialized memory allocation requirements. This object is ** also used during testing of SQLite in order to specify an alternative ** memory allocator that simulates memory out-of-memory conditions in ** order to verify that SQLite recovers gracefully from such ** conditions. ** | | | < < < | < < < | 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 | ** and that this object is only useful to a tiny minority of applications ** with specialized memory allocation requirements. This object is ** also used during testing of SQLite in order to specify an alternative ** memory allocator that simulates memory out-of-memory conditions in ** order to verify that SQLite recovers gracefully from such ** conditions. ** ** The xMalloc, xRealloc, and xFree methods must work like the ** malloc(), realloc() and free() functions from the standard C library. ** ^SQLite guarantees that the second argument to ** xRealloc is always a value returned by a prior call to xRoundup. ** ** xSize should return the allocated size of a memory allocation ** previously obtained from xMalloc or xRealloc. The allocated size ** is always at least as big as the requested size but may be larger. ** ** The xRoundup method returns what would be the allocated size of ** a memory allocation given a particular requested size. Most memory |
︙ | ︙ | |||
3395 3396 3397 3398 3399 3400 3401 | ** WHERE clause might influence the choice of query plan for a statement, ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column | | | 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 | ** WHERE clause might influence the choice of query plan for a statement, ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT2] compile-time option is enabled. ** the ** </li> ** </ol> */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ |
︙ | ︙ | |||
7709 7710 7711 7712 7713 7714 7715 | ** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value ** that can be stored in a u32 without loss of data. The value ** is 0x00000000ffffffff. But because of quirks of some compilers, we ** have to specify the value in the less intuitive manner shown: */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) | < < < < < < < < < < < < | 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 | ** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value ** that can be stored in a u32 without loss of data. The value ** is 0x00000000ffffffff. But because of quirks of some compilers, we ** have to specify the value in the less intuitive manner shown: */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) /* ** Macros to determine whether the machine is big or little endian, ** evaluated at runtime. */ #ifdef SQLITE_AMALGAMATION SQLITE_PRIVATE const int sqlite3one = 1; #else |
︙ | ︙ | |||
8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 | ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ /* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ typedef struct Vdbe Vdbe; | > | 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 | ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ /* #include <stdio.h> */ /* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ typedef struct Vdbe Vdbe; |
︙ | ︙ | |||
8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 | VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ } p4; #ifdef SQLITE_DEBUG char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE int cnt; /* Number of times this instruction was executed */ u64 cycles; /* Total time spent executing this instruction */ | > | 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 | VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_DEBUG char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE int cnt; /* Number of times this instruction was executed */ u64 cycles; /* Total time spent executing this instruction */ |
︙ | ︙ | |||
8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 | #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the ** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still ** gets freed when the Vdbe is finalized so it still should be obtained ** from a single sqliteMalloc(). But no copy is made and the calling ** function should *not* try to free the KeyInfo. | > | 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 | #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ #define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the ** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still ** gets freed when the Vdbe is finalized so it still should be obtained ** from a single sqliteMalloc(). But no copy is made and the calling ** function should *not* try to free the KeyInfo. |
︙ | ︙ | |||
8399 8400 8401 8402 8403 8404 8405 | #define OP_ReadCookie 35 #define OP_SetCookie 36 #define OP_VerifyCookie 37 #define OP_OpenRead 38 #define OP_OpenWrite 39 #define OP_OpenAutoindex 40 #define OP_OpenEphemeral 41 | > | | | | | | | | | | | | | | | | | > > | | | | | > | | > | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | | | | | > | | | | | < | | | | | 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 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 | #define OP_ReadCookie 35 #define OP_SetCookie 36 #define OP_VerifyCookie 37 #define OP_OpenRead 38 #define OP_OpenWrite 39 #define OP_OpenAutoindex 40 #define OP_OpenEphemeral 41 #define OP_SorterOpen 42 #define OP_OpenPseudo 43 #define OP_Close 44 #define OP_SeekLt 45 #define OP_SeekLe 46 #define OP_SeekGe 47 #define OP_SeekGt 48 #define OP_Seek 49 #define OP_NotFound 50 #define OP_Found 51 #define OP_IsUnique 52 #define OP_NotExists 53 #define OP_Sequence 54 #define OP_NewRowid 55 #define OP_Insert 56 #define OP_InsertInt 57 #define OP_Delete 58 #define OP_ResetCount 59 #define OP_SorterCompare 60 #define OP_SorterData 61 #define OP_RowKey 62 #define OP_RowData 63 #define OP_Rowid 64 #define OP_NullRow 65 #define OP_Last 66 #define OP_SorterSort 67 #define OP_Sort 70 #define OP_Rewind 71 #define OP_SorterNext 72 #define OP_Prev 81 #define OP_Next 92 #define OP_SorterInsert 95 #define OP_IdxInsert 96 #define OP_IdxDelete 97 #define OP_IdxRowid 98 #define OP_IdxLT 99 #define OP_IdxGE 100 #define OP_Destroy 101 #define OP_Clear 102 #define OP_CreateIndex 103 #define OP_CreateTable 104 #define OP_ParseSchema 105 #define OP_LoadAnalysis 106 #define OP_DropTable 107 #define OP_DropIndex 108 #define OP_DropTrigger 109 #define OP_IntegrityCk 110 #define OP_RowSetAdd 111 #define OP_RowSetRead 112 #define OP_RowSetTest 113 #define OP_Program 114 #define OP_Param 115 #define OP_FkCounter 116 #define OP_FkIfZero 117 #define OP_MemMax 118 #define OP_IfPos 119 #define OP_IfNeg 120 #define OP_IfZero 121 #define OP_AggStep 122 #define OP_AggFinal 123 #define OP_Checkpoint 124 #define OP_JournalMode 125 #define OP_Vacuum 126 #define OP_IncrVacuum 127 #define OP_Expire 128 #define OP_TableLock 129 #define OP_VBegin 131 #define OP_VCreate 132 #define OP_VDestroy 133 #define OP_VOpen 134 #define OP_VFilter 135 #define OP_VColumn 136 #define OP_VNext 137 #define OP_VRename 138 #define OP_VUpdate 139 #define OP_Pagecount 140 #define OP_MaxPgcnt 146 #define OP_Trace 147 #define OP_Noop 148 #define OP_Explain 149 /* 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, 0x00, 0x00, 0x00, 0x02,\ /* 32 */ 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00,\ /* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11,\ /* 48 */ 0x11, 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02,\ /* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 64 */ 0x02, 0x00, 0x01, 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, 0x08,\ /* 96 */ 0x08, 0x00, 0x02, 0x01, 0x01, 0x02, 0x00, 0x02,\ /* 104 */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,\ /* 112 */ 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08, 0x05,\ /* 120 */ 0x05, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\ /* 128 */ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,\ /* 136 */ 0x00, 0x01, 0x00, 0x00, 0x02, 0x04, 0x04, 0x04,\ /* 144 */ 0x04, 0x04, 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. */ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*); SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); 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, int N); 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*); |
︙ | ︙ | |||
8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 | ** 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 | > | 8644 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 */ #define PAGER_SORTER 0x0020 /* Accumulator in external merge sort */ /* ** Valid values for the second argument to sqlite3PagerLockingMode(). */ #define PAGER_LOCKINGMODE_QUERY -1 #define PAGER_LOCKINGMODE_NORMAL 0 #define PAGER_LOCKINGMODE_EXCLUSIVE 1 |
︙ | ︙ | |||
9922 9923 9924 9925 9926 9927 9928 | struct Table { char *zName; /* Name of the table or view */ int iPKey; /* If not negative, use aCol[iPKey] as the primary key */ int nCol; /* Number of columns in this table */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ | | | 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 | struct Table { char *zName; /* Name of the table or view */ int iPKey; /* If not negative, use aCol[iPKey] as the primary key */ int nCol; /* Number of columns in this table */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ unsigned nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u16 nRef; /* Number of pointers to this Table */ u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ #ifndef SQLITE_OMIT_CHECK |
︙ | ︙ | |||
10121 10122 10123 10124 10125 10126 10127 | ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. */ struct Index { char *zName; /* Name of this index */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ | | < < < | < | < | < < < | 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 | ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. */ struct Index { char *zName; /* Name of this index */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ u8 bUnordered; /* Use this index for == or IN queries only */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ IndexSample *aSample; /* Array of SQLITE_INDEX_SAMPLES samples */ }; /* ** Each sample stored in the sqlite_stat2 table is represented in memory ** using a structure of this type. */ struct IndexSample { union { char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */ double r; /* Value if eType is SQLITE_FLOAT or SQLITE_INTEGER */ } u; u8 eType; /* SQLITE_NULL, SQLITE_INTEGER ... etc. */ u8 nByte; /* Size in byte of text or blob. */ }; /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** ** Note if Token.z==0 then Token.dyn and Token.n are undefined and |
︙ | ︙ | |||
10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 | */ 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 */ |
︙ | ︙ | |||
10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 | */ #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 */ | > | 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 | */ #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 */ |
︙ | ︙ | |||
11359 11360 11361 11362 11363 11364 11365 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); #else # define sqlite3ViewGetColumnNames(A,B) 0 #endif SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); | < | 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); #else # define sqlite3ViewGetColumnNames(A,B) 0 #endif SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) |
︙ | ︙ | |||
11616 11617 11618 11619 11620 11621 11622 | SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); | | | 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 | SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); #ifdef SQLITE_ENABLE_STAT2 SQLITE_PRIVATE char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *); #endif SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[]; SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; |
︙ | ︙ | |||
12243 12244 12245 12246 12247 12248 12249 | #endif #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #ifdef SQLITE_ENABLE_STAT2 "ENABLE_STAT2", #endif | < < < | 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 | #endif #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #ifdef SQLITE_ENABLE_STAT2 "ENABLE_STAT2", #endif #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", #endif #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT "ENABLE_UPDATE_DELETE_LIMIT", #endif #ifdef SQLITE_HAS_CODEC |
︙ | ︙ | |||
12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 | #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 | > > > | 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 | #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 |
︙ | ︙ | |||
12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 | "OMIT_LOCALTIME", #endif #ifdef SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif #ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif | > > > | 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 | "OMIT_LOCALTIME", #endif #ifdef SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif #ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif #ifdef SQLITE_OMIT_MERGE_SORT "OMIT_MERGE_SORT", #endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif |
︙ | ︙ | |||
12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 | "OMIT_WAL", #endif #ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif #ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif #ifdef SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif #ifdef SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif | > > > | 12441 12442 12443 12444 12445 12446 12447 12448 12449 12450 12451 12452 12453 12454 12455 12456 12457 | "OMIT_WAL", #endif #ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif #ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif #ifdef SQLITE_PAGECACHE_BLOCKALLOC "PAGECACHE_BLOCKALLOC", #endif #ifdef SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif #ifdef SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif |
︙ | ︙ | |||
12572 12573 12574 12575 12576 12577 12578 12579 12580 12581 12582 12583 12584 12585 | typedef struct VdbeOp Op; /* ** Boolean values */ typedef unsigned char Bool; /* ** A cursor is a pointer into a single BTree within a database file. ** The cursor can seek to a BTree entry with a particular key, or ** loop over all entries of the Btree. You can also insert new BTree ** entries or retrieve the key or data from the entry that the cursor ** is currently pointing to. ** | > > > | 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575 12576 12577 12578 12579 12580 12581 | typedef struct VdbeOp Op; /* ** Boolean values */ typedef unsigned char Bool; /* Opaque type used by code in vdbesort.c */ typedef struct VdbeSorter VdbeSorter; /* ** A cursor is a pointer into a single BTree within a database file. ** The cursor can seek to a BTree entry with a particular key, or ** loop over all entries of the Btree. You can also insert new BTree ** entries or retrieve the key or data from the entry that the cursor ** is currently pointing to. ** |
︙ | ︙ | |||
12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 12616 | 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 */ /* 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 | > > | 12594 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 | 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 |
︙ | ︙ | |||
12922 12923 12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 | SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); SQLITE_PRIVATE const char *sqlite3OpcodeName(int); SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem); #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeEnter(X) # define sqlite3VdbeLeave(X) | > > > > > > > > > > > > > > > > > > > > > | 12920 12921 12922 12923 12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 | SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p); #define MemReleaseExt(X) \ if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \ sqlite3VdbeMemReleaseExternal(X); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); SQLITE_PRIVATE const char *sqlite3OpcodeName(int); SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem); #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) # define sqlite3VdbeLeave(X) |
︙ | ︙ | |||
13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 | ** ** Jean Meeus ** Astronomical Algorithms, 2nd Edition, 1998 ** ISBM 0-943396-61-1 ** Willmann-Bell, Inc ** Richmond, Virginia (USA) */ #include <time.h> #ifndef SQLITE_OMIT_DATETIME_FUNCS /* ** A structure for holding a single date and time. | > > | 13242 13243 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254 13255 13256 13257 | ** ** Jean Meeus ** Astronomical Algorithms, 2nd Edition, 1998 ** ISBM 0-943396-61-1 ** Willmann-Bell, Inc ** Richmond, Virginia (USA) */ /* #include <stdlib.h> */ /* #include <assert.h> */ #include <time.h> #ifndef SQLITE_OMIT_DATETIME_FUNCS /* ** A structure for holding a single date and time. |
︙ | ︙ | |||
14976 14977 14978 14979 14980 14981 14982 14983 14984 14985 14986 14987 14988 14989 | #ifdef __GLIBC__ extern int backtrace(void**,int); extern void backtrace_symbols_fd(void*const*,int,int); #else # define backtrace(A,B) 1 # define backtrace_symbols_fd(A,B,C) #endif /* ** Each memory allocation looks like this: ** ** ------------------------------------------------------------------------ ** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | ** ------------------------------------------------------------------------ | > | 14997 14998 14999 15000 15001 15002 15003 15004 15005 15006 15007 15008 15009 15010 15011 | #ifdef __GLIBC__ extern int backtrace(void**,int); extern void backtrace_symbols_fd(void*const*,int,int); #else # define backtrace(A,B) 1 # define backtrace_symbols_fd(A,B,C) #endif /* #include <stdio.h> */ /* ** Each memory allocation looks like this: ** ** ------------------------------------------------------------------------ ** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | ** ------------------------------------------------------------------------ |
︙ | ︙ | |||
18079 18080 18081 18082 18083 18084 18085 18086 18087 18088 18089 18090 18091 18092 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** Memory allocation functions used throughout sqlite. */ /* ** Attempt to release up to n bytes of non-essential memory currently ** held by SQLite. An example of non-essential memory is memory used to ** cache database pages that are not currently in use. */ SQLITE_API int sqlite3_release_memory(int n){ | > | 18101 18102 18103 18104 18105 18106 18107 18108 18109 18110 18111 18112 18113 18114 18115 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** Memory allocation functions used throughout sqlite. */ /* #include <stdarg.h> */ /* ** Attempt to release up to n bytes of non-essential memory currently ** held by SQLite. An example of non-essential memory is memory used to ** cache database pages that are not currently in use. */ SQLITE_API int sqlite3_release_memory(int n){ |
︙ | ︙ | |||
20056 20057 20058 20059 20060 20061 20062 20063 20064 20065 20066 20067 20068 20069 | ** ** ** BOM or Byte Order Mark: ** 0xff 0xfe little-endian utf-16 follows ** 0xfe 0xff big-endian utf-16 follows ** */ #ifndef SQLITE_AMALGAMATION /* ** The following constant value is used by the SQLITE_BIGENDIAN and ** SQLITE_LITTLEENDIAN macros. */ SQLITE_PRIVATE const int sqlite3one = 1; | > | 20079 20080 20081 20082 20083 20084 20085 20086 20087 20088 20089 20090 20091 20092 20093 | ** ** ** BOM or Byte Order Mark: ** 0xff 0xfe little-endian utf-16 follows ** 0xfe 0xff big-endian utf-16 follows ** */ /* #include <assert.h> */ #ifndef SQLITE_AMALGAMATION /* ** The following constant value is used by the SQLITE_BIGENDIAN and ** SQLITE_LITTLEENDIAN macros. */ SQLITE_PRIVATE const int sqlite3one = 1; |
︙ | ︙ | |||
20484 20485 20486 20487 20488 20489 20490 | ** is set to the length of the returned string in bytes. The call should ** arrange to call sqlite3DbFree() on the returned pointer when it is ** no longer required. ** ** If a malloc failure occurs, NULL is returned and the db.mallocFailed ** flag set. */ | | | 20508 20509 20510 20511 20512 20513 20514 20515 20516 20517 20518 20519 20520 20521 20522 | ** is set to the length of the returned string in bytes. The call should ** arrange to call sqlite3DbFree() on the returned pointer when it is ** no longer required. ** ** If a malloc failure occurs, NULL is returned and the db.mallocFailed ** flag set. */ #ifdef SQLITE_ENABLE_STAT2 SQLITE_PRIVATE char *sqlite3Utf8to16(sqlite3 *db, u8 enc, char *z, int n, int *pnOut){ Mem m; memset(&m, 0, sizeof(m)); m.db = db; sqlite3VdbeMemSetStr(&m, z, n, SQLITE_UTF8, SQLITE_STATIC); if( sqlite3VdbeMemTranslate(&m, enc) ){ assert( db->mallocFailed ); |
︙ | ︙ | |||
20598 20599 20600 20601 20602 20603 20604 20605 20606 20607 20608 20609 20610 20611 | ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** */ #ifdef SQLITE_HAVE_ISNAN # include <math.h> #endif /* ** Routine needed to support the testcase() macro. */ | > | 20622 20623 20624 20625 20626 20627 20628 20629 20630 20631 20632 20633 20634 20635 20636 | ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** */ /* #include <stdarg.h> */ #ifdef SQLITE_HAVE_ISNAN # include <math.h> #endif /* ** Routine needed to support the testcase() macro. */ |
︙ | ︙ | |||
21776 21777 21778 21779 21780 21781 21782 21783 21784 21785 21786 21787 21788 21789 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the implementation of generic hash-tables ** used in SQLite. */ /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** ** "pNew" is a pointer to the hash table that is to be initialized. */ SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){ | > | 21801 21802 21803 21804 21805 21806 21807 21808 21809 21810 21811 21812 21813 21814 21815 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the implementation of generic hash-tables ** used in SQLite. */ /* #include <assert.h> */ /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** ** "pNew" is a pointer to the hash table that is to be initialized. */ SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){ |
︙ | ︙ | |||
22086 22087 22088 22089 22090 22091 22092 | /* 35 */ "ReadCookie", /* 36 */ "SetCookie", /* 37 */ "VerifyCookie", /* 38 */ "OpenRead", /* 39 */ "OpenWrite", /* 40 */ "OpenAutoindex", /* 41 */ "OpenEphemeral", | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | 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 | /* 35 */ "ReadCookie", /* 36 */ "SetCookie", /* 37 */ "VerifyCookie", /* 38 */ "OpenRead", /* 39 */ "OpenWrite", /* 40 */ "OpenAutoindex", /* 41 */ "OpenEphemeral", /* 42 */ "SorterOpen", /* 43 */ "OpenPseudo", /* 44 */ "Close", /* 45 */ "SeekLt", /* 46 */ "SeekLe", /* 47 */ "SeekGe", /* 48 */ "SeekGt", /* 49 */ "Seek", /* 50 */ "NotFound", /* 51 */ "Found", /* 52 */ "IsUnique", /* 53 */ "NotExists", /* 54 */ "Sequence", /* 55 */ "NewRowid", /* 56 */ "Insert", /* 57 */ "InsertInt", /* 58 */ "Delete", /* 59 */ "ResetCount", /* 60 */ "SorterCompare", /* 61 */ "SorterData", /* 62 */ "RowKey", /* 63 */ "RowData", /* 64 */ "Rowid", /* 65 */ "NullRow", /* 66 */ "Last", /* 67 */ "SorterSort", /* 68 */ "Or", /* 69 */ "And", /* 70 */ "Sort", /* 71 */ "Rewind", /* 72 */ "SorterNext", /* 73 */ "IsNull", /* 74 */ "NotNull", /* 75 */ "Ne", /* 76 */ "Eq", /* 77 */ "Gt", /* 78 */ "Le", /* 79 */ "Lt", /* 80 */ "Ge", /* 81 */ "Prev", /* 82 */ "BitAnd", /* 83 */ "BitOr", /* 84 */ "ShiftLeft", /* 85 */ "ShiftRight", /* 86 */ "Add", /* 87 */ "Subtract", /* 88 */ "Multiply", /* 89 */ "Divide", /* 90 */ "Remainder", /* 91 */ "Concat", /* 92 */ "Next", /* 93 */ "BitNot", /* 94 */ "String8", /* 95 */ "SorterInsert", /* 96 */ "IdxInsert", /* 97 */ "IdxDelete", /* 98 */ "IdxRowid", /* 99 */ "IdxLT", /* 100 */ "IdxGE", /* 101 */ "Destroy", /* 102 */ "Clear", /* 103 */ "CreateIndex", /* 104 */ "CreateTable", /* 105 */ "ParseSchema", /* 106 */ "LoadAnalysis", /* 107 */ "DropTable", /* 108 */ "DropIndex", /* 109 */ "DropTrigger", /* 110 */ "IntegrityCk", /* 111 */ "RowSetAdd", /* 112 */ "RowSetRead", /* 113 */ "RowSetTest", /* 114 */ "Program", /* 115 */ "Param", /* 116 */ "FkCounter", /* 117 */ "FkIfZero", /* 118 */ "MemMax", /* 119 */ "IfPos", /* 120 */ "IfNeg", /* 121 */ "IfZero", /* 122 */ "AggStep", /* 123 */ "AggFinal", /* 124 */ "Checkpoint", /* 125 */ "JournalMode", /* 126 */ "Vacuum", /* 127 */ "IncrVacuum", /* 128 */ "Expire", /* 129 */ "TableLock", /* 130 */ "Real", /* 131 */ "VBegin", /* 132 */ "VCreate", /* 133 */ "VDestroy", /* 134 */ "VOpen", /* 135 */ "VFilter", /* 136 */ "VColumn", /* 137 */ "VNext", /* 138 */ "VRename", /* 139 */ "VUpdate", /* 140 */ "Pagecount", /* 141 */ "ToText", /* 142 */ "ToBlob", /* 143 */ "ToNumeric", /* 144 */ "ToInt", /* 145 */ "ToReal", /* 146 */ "MaxPgcnt", /* 147 */ "Trace", /* 148 */ "Noop", /* 149 */ "Explain", }; return azName[i]; } #endif /************** End of opcodes.c *********************************************/ /************** Begin file os_os2.c ******************************************/ |
︙ | ︙ | |||
22284 22285 22286 22287 22288 22289 22290 | ** 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 | | | 22314 22315 22316 22317 22318 22319 22320 22321 22322 22323 22324 22325 22326 22327 22328 | ** 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) |
︙ | ︙ | |||
24448 24449 24450 24451 24452 24453 24454 24455 24456 24457 24458 24459 24460 24461 | /* ** standard include files. */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/time.h> #include <errno.h> #ifndef SQLITE_OMIT_WAL #include <sys/mman.h> #endif #if SQLITE_ENABLE_LOCKING_STYLE | > | 24478 24479 24480 24481 24482 24483 24484 24485 24486 24487 24488 24489 24490 24491 24492 | /* ** standard include files. */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> /* #include <time.h> */ #include <sys/time.h> #include <errno.h> #ifndef SQLITE_OMIT_WAL #include <sys/mman.h> #endif #if SQLITE_ENABLE_LOCKING_STYLE |
︙ | ︙ | |||
24483 24484 24485 24486 24487 24488 24489 24490 24491 24492 24493 24494 24495 24496 | #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* ** If we are to be thread-safe, include the pthreads header and define ** the SQLITE_UNIX_THREADS macro. */ #if SQLITE_THREADSAFE # define SQLITE_UNIX_THREADS 1 #endif /* ** Default permissions when creating a new file */ #ifndef SQLITE_DEFAULT_FILE_PERMISSIONS | > | 24514 24515 24516 24517 24518 24519 24520 24521 24522 24523 24524 24525 24526 24527 24528 | #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* ** If we are to be thread-safe, include the pthreads header and define ** the SQLITE_UNIX_THREADS macro. */ #if SQLITE_THREADSAFE /* # include <pthread.h> */ # define SQLITE_UNIX_THREADS 1 #endif /* ** Default permissions when creating a new file */ #ifndef SQLITE_DEFAULT_FILE_PERMISSIONS |
︙ | ︙ | |||
24582 24583 24584 24585 24586 24587 24588 | /* ** Allowed values for the unixFile.ctrlFlags bitmask: */ #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ #define UNIXFILE_RDONLY 0x02 /* Connection is read only */ #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ | > | > > > | 24614 24615 24616 24617 24618 24619 24620 24621 24622 24623 24624 24625 24626 24627 24628 24629 24630 24631 24632 | /* ** Allowed values for the unixFile.ctrlFlags bitmask: */ #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ #define UNIXFILE_RDONLY 0x02 /* Connection is read only */ #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #ifndef SQLITE_DISABLE_DIRSYNC # define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ #else # define UNIXFILE_DIRSYNC 0x00 #endif /* ** Include code that is common to all os_*.c files */ /************** Include os_common.h in the middle of os_unix.c ***************/ /************** Begin file os_common.h ***************************************/ /* |
︙ | ︙ | |||
24620 24621 24622 24623 24624 24625 24626 | ** 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 | | | 24656 24657 24658 24659 24660 24661 24662 24663 24664 24665 24666 24667 24668 24669 24670 | ** 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) |
︙ | ︙ | |||
27059 27060 27061 27062 27063 27064 27065 27066 27067 27068 27069 | ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); | > | | 27095 27096 27097 27098 27099 27100 27101 27102 27103 27104 27105 27106 27107 27108 27109 27110 27111 27112 27113 27114 | ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; afpLockingContext *context; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); context = (afpLockingContext *) pFile->lockingContext; if( context->reserved ){ *pResOut = 1; return SQLITE_OK; } unixEnterMutex(); /* Because pFile->pInode is shared across threads */ /* Check if a thread in this process holds such a lock */ |
︙ | ︙ | |||
27203 27204 27205 27206 27207 27208 27209 | } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( eFileLock==SHARED_LOCK ){ | | | 27240 27241 27242 27243 27244 27245 27246 27247 27248 27249 27250 27251 27252 27253 27254 | } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( eFileLock==SHARED_LOCK ){ int lrc1, lrc2, lrc1Errno = 0; long lk, mask; assert( pInode->nShared==0 ); assert( pInode->eFileLock==0 ); mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff; /* Now get the read-lock SHARED_LOCK */ |
︙ | ︙ | |||
27577 27578 27579 27580 27581 27582 27583 | #endif TIMER_START; #if defined(USE_PREAD) do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR); #else | > | | | | | | | | | | | > | 27614 27615 27616 27617 27618 27619 27620 27621 27622 27623 27624 27625 27626 27627 27628 27629 27630 27631 27632 27633 27634 27635 27636 27637 27638 27639 27640 | #endif TIMER_START; #if defined(USE_PREAD) do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR); #else do{ newOffset = lseek(id->h, offset, SEEK_SET); SimulateIOError( newOffset-- ); if( newOffset!=offset ){ if( newOffset == -1 ){ ((unixFile*)id)->lastErrno = errno; }else{ ((unixFile*)id)->lastErrno = 0; } return -1; } got = osWrite(id->h, pBuf, cnt); }while( got<0 && errno==EINTR ); #endif TIMER_END; if( got<0 ){ ((unixFile*)id)->lastErrno = errno; } OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED)); |
︙ | ︙ | |||
27677 27678 27679 27680 27681 27682 27683 | */ 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. | | | | | 27716 27717 27718 27719 27720 27721 27722 27723 27724 27725 27726 27727 27728 27729 27730 27731 27732 27733 27734 | */ 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. |
︙ | ︙ | |||
27886 27887 27888 27889 27890 27891 27892 27893 27894 27895 27896 27897 27898 27899 | int dirfd; OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, HAVE_FULLFSYNC, isFullsync)); rc = osOpenDirectory(pFile->zPath, &dirfd); if( rc==SQLITE_OK && dirfd>=0 ){ full_fsync(dirfd, 0, 0); robust_close(pFile, dirfd, __LINE__); } pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; } return rc; } /* | > > | 27925 27926 27927 27928 27929 27930 27931 27932 27933 27934 27935 27936 27937 27938 27939 27940 | int dirfd; OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, HAVE_FULLFSYNC, isFullsync)); rc = osOpenDirectory(pFile->zPath, &dirfd); if( rc==SQLITE_OK && dirfd>=0 ){ full_fsync(dirfd, 0, 0); robust_close(pFile, dirfd, __LINE__); }else if( rc==SQLITE_CANTOPEN ){ rc = SQLITE_OK; } pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; } return rc; } /* |
︙ | ︙ | |||
27969 27970 27971 27972 27973 27974 27975 | ** proxying locking division. */ static int proxyFileControl(sqlite3_file*,int,void*); #endif /* ** This function is called to handle the SQLITE_FCNTL_SIZE_HINT | | < | < < > < > < | < < < < < | 28010 28011 28012 28013 28014 28015 28016 28017 28018 28019 28020 28021 28022 28023 28024 28025 28026 28027 28028 28029 28030 28031 28032 28033 28034 28035 | ** proxying locking division. */ static int proxyFileControl(sqlite3_file*,int,void*); #endif /* ** 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 ){ #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE /* The code below is handling the return value of osFallocate() ** correctly. posix_fallocate() is defined to "returns zero on success, ** or an error number on failure". See the manpage for details. */ int err; |
︙ | ︙ | |||
28046 28047 28048 28049 28050 28051 28052 | return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { | > > | > > | 28079 28080 28081 28082 28083 28084 28085 28086 28087 28088 28089 28090 28091 28092 28093 28094 28095 28096 28097 | return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { int rc; SimulateIOErrorBenign(1); rc = fcntlSizeHint(pFile, *(i64 *)pArg); SimulateIOErrorBenign(0); return rc; } case SQLITE_FCNTL_PERSIST_WAL: { int bPersist = *(int*)pArg; if( bPersist<0 ){ *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0; }else if( bPersist==0 ){ pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL; |
︙ | ︙ | |||
28173 28174 28175 28176 28177 28178 28179 28180 28181 | ** 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 */ | > < < < | 28210 28211 28212 28213 28214 28215 28216 28217 28218 28219 28220 28221 28222 28223 28224 28225 28226 | ** 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 */ |
︙ | ︙ | |||
29483 29484 29485 29486 29487 29488 29489 29490 29491 29492 29493 29494 29495 29496 | int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); #if SQLITE_ENABLE_LOCKING_STYLE int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY); #endif /* If creating a master or main-file journal, this function will open ** a file-descriptor on the directory too. The first time unixSync() ** is called the directory file descriptor will be fsync()ed and close()d. */ int syncDir = (isCreate && ( eType==SQLITE_OPEN_MASTER_JOURNAL | > > > | 29518 29519 29520 29521 29522 29523 29524 29525 29526 29527 29528 29529 29530 29531 29532 29533 29534 | int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); #if SQLITE_ENABLE_LOCKING_STYLE int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY); #endif #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE struct statfs fsInfo; #endif /* If creating a master or main-file journal, this function will open ** a file-descriptor on the directory too. The first time unixSync() ** is called the directory file descriptor will be fsync()ed and close()d. */ int syncDir = (isCreate && ( eType==SQLITE_OPEN_MASTER_JOURNAL |
︙ | ︙ | |||
29615 29616 29617 29618 29619 29620 29621 | osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif noLock = eType!=SQLITE_OPEN_MAIN_DB; #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE | < | 29653 29654 29655 29656 29657 29658 29659 29660 29661 29662 29663 29664 29665 29666 | osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif noLock = eType!=SQLITE_OPEN_MAIN_DB; #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE if( fstatfs(fd, &fsInfo) == -1 ){ ((unixFile*)pFile)->lastErrno = errno; robust_close(p, fd, __LINE__); return SQLITE_IOERR_ACCESS; } if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; |
︙ | ︙ | |||
29639 29640 29641 29642 29643 29644 29645 | int useProxy = 0; /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means ** never use proxy, NULL means use proxy for non-local files only. */ if( envforce!=NULL ){ useProxy = atoi(envforce)>0; }else{ | < | 29676 29677 29678 29679 29680 29681 29682 29683 29684 29685 29686 29687 29688 29689 | int useProxy = 0; /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means ** never use proxy, NULL means use proxy for non-local files only. */ if( envforce!=NULL ){ useProxy = atoi(envforce)>0; }else{ if( statfs(zPath, &fsInfo) == -1 ){ /* In theory, the close(fd) call is sub-optimal. If the file opened ** with fd is a database file, and there are other connections open ** on that file that are currently holding advisory locks on it, ** then the call to close() will cancel those locks. In practice, ** we're assuming that statfs() doesn't fail very often. At least ** not while other file descriptors opened by the same process on |
︙ | ︙ | |||
29713 29714 29715 29716 29717 29718 29719 29720 29721 29722 29723 29724 29725 29726 | #else if( fsync(fd) ) #endif { rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } robust_close(0, fd, __LINE__); } } #endif return rc; } /* | > > | 29749 29750 29751 29752 29753 29754 29755 29756 29757 29758 29759 29760 29761 29762 29763 29764 | #else if( fsync(fd) ) #endif { rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } robust_close(0, fd, __LINE__); }else if( rc==SQLITE_CANTOPEN ){ rc = SQLITE_OK; } } #endif return rc; } /* |
︙ | ︙ | |||
30378 30379 30380 30381 30382 30383 30384 30385 30386 30387 30388 30389 30390 30391 | int err = errno; if( pError ){ *pError = err; } return SQLITE_IOERR; } } #endif #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ if( sqlite3_hostid_num != 0){ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF)); } #endif | > > | 30416 30417 30418 30419 30420 30421 30422 30423 30424 30425 30426 30427 30428 30429 30430 30431 | int err = errno; if( pError ){ *pError = err; } return SQLITE_IOERR; } } #else UNUSED_PARAMETER(pError); #endif #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ if( sqlite3_hostid_num != 0){ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF)); } #endif |
︙ | ︙ | |||
30470 30471 30472 30473 30474 30475 30476 30477 30478 30479 30480 30481 30482 30483 | static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *conchFile = pCtx->conchFile; int rc = SQLITE_OK; int nTries = 0; struct timespec conchModTime; do { rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); nTries ++; if( rc==SQLITE_BUSY ){ /* If the lock failed (busy): * 1st try: get the mod time of the conch, wait 0.5s and try again. * 2nd try: fail if the mod time changed or host id is different, wait | > | 30510 30511 30512 30513 30514 30515 30516 30517 30518 30519 30520 30521 30522 30523 30524 | static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *conchFile = pCtx->conchFile; int rc = SQLITE_OK; int nTries = 0; struct timespec conchModTime; memset(&conchModTime, 0, sizeof(conchModTime)); do { rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); nTries ++; if( rc==SQLITE_BUSY ){ /* If the lock failed (busy): * 1st try: get the mod time of the conch, wait 0.5s and try again. * 2nd try: fail if the mod time changed or host id is different, wait |
︙ | ︙ | |||
30701 30702 30703 30704 30705 30706 30707 30708 30709 30710 30711 | } } conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK); end_takeconch: OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); if( rc==SQLITE_OK && pFile->openFlags ){ if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); } pFile->h = -1; | > | | 30742 30743 30744 30745 30746 30747 30748 30749 30750 30751 30752 30753 30754 30755 30756 30757 30758 30759 30760 30761 | } } conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK); end_takeconch: OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); if( rc==SQLITE_OK && pFile->openFlags ){ int fd; if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); } pFile->h = -1; fd = robust_open(pCtx->dbPath, pFile->openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS); OSTRACE(("TRANSPROXY: OPEN %d\n", fd)); if( fd>=0 ){ pFile->h = fd; }else{ rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called during locking */ |
︙ | ︙ | |||
31391 31392 31393 31394 31395 31396 31397 | ** 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 | | | 31433 31434 31435 31436 31437 31438 31439 31440 31441 31442 31443 31444 31445 31446 31447 | ** 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) |
︙ | ︙ | |||
31627 31628 31629 31630 31631 31632 31633 31634 31635 31636 31637 31638 31639 31640 | HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ #endif }; /* ** Forward prototypes. */ static int getSectorSize( sqlite3_vfs *pVfs, const char *zRelative /* UTF-8 file name */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 31669 31670 31671 31672 31673 31674 31675 31676 31677 31678 31679 31680 31681 31682 31683 31684 31685 31686 31687 31688 31689 31690 31691 31692 31693 31694 31695 31696 31697 31698 31699 31700 31701 31702 31703 31704 31705 31706 31707 31708 31709 31710 31711 31712 31713 31714 31715 31716 31717 31718 31719 31720 31721 31722 31723 31724 31725 31726 31727 31728 31729 31730 31731 31732 31733 31734 31735 31736 31737 31738 31739 31740 31741 31742 31743 31744 31745 31746 31747 31748 31749 31750 31751 31752 | HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ #endif }; /* * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * various Win32 API heap functions instead of our own. */ #ifdef SQLITE_WIN32_MALLOC /* * The initial size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_INIT_SIZE # define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \ (SQLITE_DEFAULT_PAGE_SIZE) + 4194304) #endif /* * The maximum size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_MAX_SIZE # define SQLITE_WIN32_HEAP_MAX_SIZE (0) #endif /* * The extra flags to use in calls to the Win32 heap APIs. This value may be * zero for the default behavior. */ #ifndef SQLITE_WIN32_HEAP_FLAGS # define SQLITE_WIN32_HEAP_FLAGS (0) #endif /* ** The winMemData structure stores information required by the Win32-specific ** sqlite3_mem_methods implementation. */ typedef struct winMemData winMemData; struct winMemData { #ifndef NDEBUG u32 magic; /* Magic number to detect structure corruption. */ #endif HANDLE hHeap; /* The handle to our heap. */ BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */ }; #ifndef NDEBUG #define WINMEM_MAGIC 0x42b2830b #endif static struct winMemData win_mem_data = { #ifndef NDEBUG WINMEM_MAGIC, #endif NULL, FALSE }; #ifndef NDEBUG #define winMemAssertMagic() assert( win_mem_data.magic==WINMEM_MAGIC ) #else #define winMemAssertMagic() #endif #define winMemGetHeap() win_mem_data.hHeap static void *winMemMalloc(int nBytes); static void winMemFree(void *pPrior); static void *winMemRealloc(void *pPrior, int nBytes); static int winMemSize(void *p); static int winMemRoundup(int n); static int winMemInit(void *pAppData); static void winMemShutdown(void *pAppData); SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void); #endif /* SQLITE_WIN32_MALLOC */ /* ** Forward prototypes. */ static int getSectorSize( sqlite3_vfs *pVfs, const char *zRelative /* UTF-8 file name */ |
︙ | ︙ | |||
31679 31680 31681 31682 31683 31684 31685 31686 31687 31688 31689 31690 31691 31692 | GetVersionEx(&sInfo); sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; } return sqlite3_os_type==2; } #endif /* SQLITE_OS_WINCE */ /* ** Convert a UTF-8 string to microsoft unicode (UTF-16?). ** ** Space to hold the returned string is obtained from malloc. */ static WCHAR *utf8ToUnicode(const char *zFilename){ int nChar; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 31791 31792 31793 31794 31795 31796 31797 31798 31799 31800 31801 31802 31803 31804 31805 31806 31807 31808 31809 31810 31811 31812 31813 31814 31815 31816 31817 31818 31819 31820 31821 31822 31823 31824 31825 31826 31827 31828 31829 31830 31831 31832 31833 31834 31835 31836 31837 31838 31839 31840 31841 31842 31843 31844 31845 31846 31847 31848 31849 31850 31851 31852 31853 31854 31855 31856 31857 31858 31859 31860 31861 31862 31863 31864 31865 31866 31867 31868 31869 31870 31871 31872 31873 31874 31875 31876 31877 31878 31879 31880 31881 31882 31883 31884 31885 31886 31887 31888 31889 31890 31891 31892 31893 31894 31895 31896 31897 31898 31899 31900 31901 31902 31903 31904 31905 31906 31907 31908 31909 31910 31911 31912 31913 31914 31915 31916 31917 31918 31919 31920 31921 31922 31923 31924 31925 31926 31927 31928 31929 31930 31931 31932 31933 31934 31935 31936 31937 31938 31939 31940 31941 31942 31943 31944 31945 31946 31947 31948 31949 31950 31951 31952 31953 31954 31955 31956 31957 31958 31959 31960 31961 31962 31963 31964 31965 31966 31967 31968 31969 31970 31971 31972 31973 31974 31975 31976 31977 31978 31979 31980 31981 31982 31983 31984 31985 31986 | GetVersionEx(&sInfo); sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; } return sqlite3_os_type==2; } #endif /* SQLITE_OS_WINCE */ #ifdef SQLITE_WIN32_MALLOC /* ** Allocate nBytes of memory. */ static void *winMemMalloc(int nBytes){ HANDLE hHeap; void *p; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #ifdef SQLITE_WIN32_MALLOC_VALIDATE assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif assert( nBytes>=0 ); p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); if( !p ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%d), heap=%p", nBytes, GetLastError(), (void*)hHeap); } return p; } /* ** Free memory. */ static void winMemFree(void *pPrior){ HANDLE hHeap; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #ifdef SQLITE_WIN32_MALLOC_VALIDATE assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ if( !HeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%d), heap=%p", pPrior, GetLastError(), (void*)hHeap); } } /* ** Change the size of an existing memory allocation */ static void *winMemRealloc(void *pPrior, int nBytes){ HANDLE hHeap; void *p; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #ifdef SQLITE_WIN32_MALLOC_VALIDATE assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif assert( nBytes>=0 ); if( !pPrior ){ p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); }else{ p = HeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes); } if( !p ){ sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%d), heap=%p", pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, GetLastError(), (void*)hHeap); } return p; } /* ** Return the size of an outstanding allocation, in bytes. */ static int winMemSize(void *p){ HANDLE hHeap; SIZE_T n; winMemAssertMagic(); hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); #ifdef SQLITE_WIN32_MALLOC_VALIDATE assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif if( !p ) return 0; n = HeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p); if( n==(SIZE_T)-1 ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%d), heap=%p", p, GetLastError(), (void*)hHeap); return 0; } return (int)n; } /* ** Round up a request size to the next valid allocation size. */ static int winMemRoundup(int n){ return n; } /* ** Initialize this module. */ static int winMemInit(void *pAppData){ winMemData *pWinMemData = (winMemData *)pAppData; if( !pWinMemData ) return SQLITE_ERROR; assert( pWinMemData->magic==WINMEM_MAGIC ); if( !pWinMemData->hHeap ){ pWinMemData->hHeap = HeapCreate(SQLITE_WIN32_HEAP_FLAGS, SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE); if( !pWinMemData->hHeap ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u", GetLastError(), SQLITE_WIN32_HEAP_FLAGS, SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE); return SQLITE_NOMEM; } pWinMemData->bOwned = TRUE; } assert( pWinMemData->hHeap!=0 ); assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); #ifdef SQLITE_WIN32_MALLOC_VALIDATE assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif return SQLITE_OK; } /* ** Deinitialize this module. */ static void winMemShutdown(void *pAppData){ winMemData *pWinMemData = (winMemData *)pAppData; if( !pWinMemData ) return; if( pWinMemData->hHeap ){ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); #ifdef SQLITE_WIN32_MALLOC_VALIDATE assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif if( pWinMemData->bOwned ){ if( !HeapDestroy(pWinMemData->hHeap) ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p", GetLastError(), (void*)pWinMemData->hHeap); } pWinMemData->bOwned = FALSE; } pWinMemData->hHeap = NULL; } } /* ** Populate the low-level memory allocation function pointers in ** sqlite3GlobalConfig.m with pointers to the routines in this file. The ** arguments specify the block of memory to manage. ** ** This routine is only called by sqlite3_config(), and therefore ** is not required to be threadsafe (it is not). */ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){ static const sqlite3_mem_methods winMemMethods = { winMemMalloc, winMemFree, winMemRealloc, winMemSize, winMemRoundup, winMemInit, winMemShutdown, &win_mem_data }; return &winMemMethods; } SQLITE_PRIVATE void sqlite3MemSetDefault(void){ sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32()); } #endif /* SQLITE_WIN32_MALLOC */ /* ** Convert a UTF-8 string to microsoft unicode (UTF-16?). ** ** Space to hold the returned string is obtained from malloc. */ static WCHAR *utf8ToUnicode(const char *zFilename){ int nChar; |
︙ | ︙ | |||
31967 31968 31969 31970 31971 31972 31973 31974 31975 31976 31977 31978 31979 31980 | /************************************************************************* ** This section contains code for WinCE only. */ /* ** WindowsCE does not have a localtime() function. So create a ** substitute. */ struct tm *__cdecl localtime(const time_t *t) { static struct tm y; FILETIME uTm, lTm; SYSTEMTIME pTm; sqlite3_int64 t64; t64 = *t; | > | 32261 32262 32263 32264 32265 32266 32267 32268 32269 32270 32271 32272 32273 32274 32275 | /************************************************************************* ** This section contains code for WinCE only. */ /* ** WindowsCE does not have a localtime() function. So create a ** substitute. */ /* #include <time.h> */ struct tm *__cdecl localtime(const time_t *t) { static struct tm y; FILETIME uTm, lTm; SYSTEMTIME pTm; sqlite3_int64 t64; t64 = *t; |
︙ | ︙ | |||
32471 32472 32473 32474 32475 32476 32477 | 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). */ | | | 32766 32767 32768 32769 32770 32771 32772 32773 32774 32775 32776 32777 32778 32779 32780 | 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) ){ |
︙ | ︙ | |||
32858 32859 32860 32861 32862 32863 32864 | return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { | > | > > > > | | | > > > > | 33153 33154 33155 33156 33157 33158 33159 33160 33161 33162 33163 33164 33165 33166 33167 33168 33169 33170 33171 33172 33173 33174 33175 33176 33177 33178 33179 | 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{ |
︙ | ︙ | |||
35471 35472 35473 35474 35475 35476 35477 35478 35479 35480 35481 35482 35483 35484 | typedef struct PCache1 PCache1; typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set ** of one or more PCaches that are able to recycle each others unpinned ** pages when they are under memory pressure. A PGroup is an instance of ** the following object. ** ** This page cache implementation works in one of two modes: ** | > > > | 35775 35776 35777 35778 35779 35780 35781 35782 35783 35784 35785 35786 35787 35788 35789 35790 35791 | typedef struct PCache1 PCache1; typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; typedef struct PGroupBlock PGroupBlock; typedef struct PGroupBlockList PGroupBlockList; /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set ** of one or more PCaches that are able to recycle each others unpinned ** pages when they are under memory pressure. A PGroup is an instance of ** the following object. ** ** This page cache implementation works in one of two modes: ** |
︙ | ︙ | |||
35500 35501 35502 35503 35504 35505 35506 35507 35508 35509 35510 35511 35512 35513 35514 35515 | struct PGroup { sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */ int nMaxPage; /* Sum of nMax for purgeable caches */ int nMinPage; /* Sum of nMin for purgeable caches */ int mxPinned; /* nMaxpage + 10 - nMinPage */ int nCurrentPage; /* Number of purgeable pages allocated */ PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */ }; /* Each page cache is an instance of the following object. Every ** open database file (including each in-memory database and each ** temporary or transient database) has a single page cache which ** is an instance of this object. ** ** Pointers to structures of this type are cast and returned as ** opaque sqlite3_pcache* handles. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 35807 35808 35809 35810 35811 35812 35813 35814 35815 35816 35817 35818 35819 35820 35821 35822 35823 35824 35825 35826 35827 35828 35829 35830 35831 35832 35833 35834 35835 35836 35837 35838 35839 35840 35841 35842 35843 35844 35845 35846 35847 35848 35849 35850 35851 35852 35853 35854 35855 35856 35857 35858 35859 35860 35861 35862 35863 35864 35865 35866 35867 35868 35869 35870 35871 35872 35873 35874 35875 35876 35877 35878 35879 35880 | struct PGroup { sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */ int nMaxPage; /* Sum of nMax for purgeable caches */ int nMinPage; /* Sum of nMin for purgeable caches */ int mxPinned; /* nMaxpage + 10 - nMinPage */ int nCurrentPage; /* Number of purgeable pages allocated */ PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */ #ifdef SQLITE_PAGECACHE_BLOCKALLOC int isBusy; /* Do not run ReleaseMemory() if true */ PGroupBlockList *pBlockList; /* List of block-lists for this group */ #endif }; /* ** If SQLITE_PAGECACHE_BLOCKALLOC is defined when the library is built, ** each PGroup structure has a linked list of the the following starting ** at PGroup.pBlockList. There is one entry for each distinct page-size ** currently used by members of the PGroup (i.e. 1024 bytes, 4096 bytes ** etc.). Variable PGroupBlockList.nByte is set to the actual allocation ** size requested by each pcache, which is the database page-size plus ** the various header structures used by the pcache, pager and btree layers. ** Usually around (pgsz+200) bytes. ** ** This size (pgsz+200) bytes is not allocated efficiently by some ** implementations of malloc. In particular, some implementations are only ** able to allocate blocks of memory chunks of 2^N bytes, where N is some ** integer value. Since the page-size is a power of 2, this means we ** end up wasting (pgsz-200) bytes in each allocation. ** ** If SQLITE_PAGECACHE_BLOCKALLOC is defined, the (pgsz+200) byte blocks ** are not allocated directly. Instead, blocks of roughly M*(pgsz+200) bytes ** are requested from malloc allocator. After a block is returned, ** sqlite3MallocSize() is used to determine how many (pgsz+200) byte ** allocations can fit in the space returned by malloc(). This value may ** be more than M. ** ** The blocks are stored in a doubly-linked list. Variable PGroupBlock.nEntry ** contains the number of allocations that will fit in the aData[] space. ** nEntry is limited to the number of bits in bitmask mUsed. If a slot ** within aData is in use, the corresponding bit in mUsed is set. Thus ** when (mUsed+1==(1 << nEntry)) the block is completely full. ** ** Each time a slot within a block is freed, the block is moved to the start ** of the linked-list. And if a block becomes completely full, then it is ** moved to the end of the list. As a result, when searching for a free ** slot, only the first block in the list need be examined. If it is full, ** then it is guaranteed that all blocks are full. */ struct PGroupBlockList { int nByte; /* Size of each allocation in bytes */ PGroupBlock *pFirst; /* First PGroupBlock in list */ PGroupBlock *pLast; /* Last PGroupBlock in list */ PGroupBlockList *pNext; /* Next block-list attached to group */ }; struct PGroupBlock { Bitmask mUsed; /* Mask of used slots */ int nEntry; /* Maximum number of allocations in aData[] */ u8 *aData; /* Pointer to data block */ PGroupBlock *pNext; /* Next PGroupBlock in list */ PGroupBlock *pPrev; /* Previous PGroupBlock in list */ PGroupBlockList *pList; /* Owner list */ }; /* Minimum value for PGroupBlock.nEntry */ #define PAGECACHE_BLOCKALLOC_MINENTRY 15 /* Each page cache is an instance of the following object. Every ** open database file (including each in-memory database and each ** temporary or transient database) has a single page cache which ** is an instance of this object. ** ** Pointers to structures of this type are cast and returned as ** opaque sqlite3_pcache* handles. |
︙ | ︙ | |||
35604 35605 35606 35607 35608 35609 35610 35611 35612 35613 35614 35615 35616 35617 | ** a pointer to a block of szPage bytes of data and the return value is ** a pointer to the associated PgHdr1 structure. ** ** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(pCache, X))==X ); */ #define PGHDR1_TO_PAGE(p) (void*)(((char*)p) - p->pCache->szPage) #define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage) /* ** Macros to enter and leave the PCache LRU mutex. */ #define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex) #define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex) | > > > > > > > > > > > | 35969 35970 35971 35972 35973 35974 35975 35976 35977 35978 35979 35980 35981 35982 35983 35984 35985 35986 35987 35988 35989 35990 35991 35992 35993 | ** a pointer to a block of szPage bytes of data and the return value is ** a pointer to the associated PgHdr1 structure. ** ** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(pCache, X))==X ); */ #define PGHDR1_TO_PAGE(p) (void*)(((char*)p) - p->pCache->szPage) #define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage) /* ** Blocks used by the SQLITE_PAGECACHE_BLOCKALLOC blocks to store/retrieve ** a PGroupBlock pointer based on a pointer to a page buffer. */ #define PAGE_SET_BLOCKPTR(pCache, pPg, pBlock) \ ( *(PGroupBlock **)&(((u8*)pPg)[sizeof(PgHdr1) + pCache->szPage]) = pBlock ) #define PAGE_GET_BLOCKPTR(pCache, pPg) \ ( *(PGroupBlock **)&(((u8*)pPg)[sizeof(PgHdr1) + pCache->szPage]) ) /* ** Macros to enter and leave the PCache LRU mutex. */ #define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex) #define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex) |
︙ | ︙ | |||
35730 35731 35732 35733 35734 35735 35736 35737 35738 35739 35740 35741 | iSize = sqlite3MallocSize(p); sqlite3MemdebugSetType(p, MEMTYPE_PCACHE); return iSize; } } #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ /* ** Allocate a new page object initially associated with cache pCache. */ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){ int nByte = sizeof(PgHdr1) + pCache->szPage; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 36106 36107 36108 36109 36110 36111 36112 36113 36114 36115 36116 36117 36118 36119 36120 36121 36122 36123 36124 36125 36126 36127 36128 36129 36130 36131 36132 36133 36134 36135 36136 36137 36138 36139 36140 36141 36142 36143 36144 36145 36146 36147 36148 36149 36150 36151 36152 36153 36154 36155 36156 36157 36158 36159 36160 36161 36162 36163 36164 36165 36166 36167 36168 36169 36170 36171 36172 36173 36174 36175 36176 36177 36178 36179 36180 36181 36182 36183 36184 36185 36186 36187 36188 36189 36190 36191 36192 36193 36194 36195 36196 36197 36198 36199 36200 36201 36202 36203 36204 36205 36206 36207 36208 36209 36210 36211 36212 36213 36214 36215 36216 36217 36218 36219 36220 36221 36222 36223 36224 36225 36226 36227 36228 36229 36230 36231 36232 36233 36234 36235 36236 36237 36238 36239 36240 36241 36242 36243 36244 36245 36246 36247 36248 36249 36250 36251 36252 36253 36254 36255 36256 36257 36258 36259 36260 36261 36262 36263 36264 36265 36266 36267 36268 36269 36270 36271 36272 36273 36274 36275 36276 36277 36278 36279 36280 36281 36282 36283 36284 36285 36286 36287 36288 36289 36290 36291 36292 36293 36294 36295 36296 36297 36298 36299 36300 36301 36302 36303 36304 36305 36306 36307 36308 36309 36310 36311 36312 36313 36314 36315 36316 36317 36318 36319 36320 36321 36322 36323 36324 36325 36326 36327 | iSize = sqlite3MallocSize(p); sqlite3MemdebugSetType(p, MEMTYPE_PCACHE); return iSize; } } #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ #ifdef SQLITE_PAGECACHE_BLOCKALLOC /* ** The block pBlock belongs to list pList but is not currently linked in. ** Insert it into the start of the list. */ static void addBlockToList(PGroupBlockList *pList, PGroupBlock *pBlock){ pBlock->pPrev = 0; pBlock->pNext = pList->pFirst; pList->pFirst = pBlock; if( pBlock->pNext ){ pBlock->pNext->pPrev = pBlock; }else{ assert( pList->pLast==0 ); pList->pLast = pBlock; } } /* ** If there are no blocks in the list headed by pList, remove pList ** from the pGroup->pBlockList list and free it with sqlite3_free(). */ static void freeListIfEmpty(PGroup *pGroup, PGroupBlockList *pList){ assert( sqlite3_mutex_held(pGroup->mutex) ); if( pList->pFirst==0 ){ PGroupBlockList **pp; for(pp=&pGroup->pBlockList; *pp!=pList; pp=&(*pp)->pNext); *pp = (*pp)->pNext; sqlite3_free(pList); } } #endif /* SQLITE_PAGECACHE_BLOCKALLOC */ /* ** Allocate a new page object initially associated with cache pCache. */ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){ int nByte = sizeof(PgHdr1) + pCache->szPage; void *pPg = 0; PgHdr1 *p; #ifdef SQLITE_PAGECACHE_BLOCKALLOC PGroup *pGroup = pCache->pGroup; PGroupBlockList *pList; PGroupBlock *pBlock; int i; nByte += sizeof(PGroupBlockList *); nByte = ROUND8(nByte); for(pList=pGroup->pBlockList; pList; pList=pList->pNext){ if( pList->nByte==nByte ) break; } if( pList==0 ){ PGroupBlockList *pNew; assert( pGroup->isBusy==0 ); assert( sqlite3_mutex_held(pGroup->mutex) ); pGroup->isBusy = 1; /* Disable sqlite3PcacheReleaseMemory() */ pNew = (PGroupBlockList *)sqlite3MallocZero(sizeof(PGroupBlockList)); pGroup->isBusy = 0; /* Reenable sqlite3PcacheReleaseMemory() */ if( pNew==0 ){ /* malloc() failure. Return early. */ return 0; } #ifdef SQLITE_DEBUG for(pList=pGroup->pBlockList; pList; pList=pList->pNext){ assert( pList->nByte!=nByte ); } #endif pNew->nByte = nByte; pNew->pNext = pGroup->pBlockList; pGroup->pBlockList = pNew; pList = pNew; } pBlock = pList->pFirst; if( pBlock==0 || pBlock->mUsed==(((Bitmask)1<<pBlock->nEntry)-1) ){ int sz; /* Allocate a new block. Try to allocate enough space for the PGroupBlock ** structure and MINENTRY allocations of nByte bytes each. If the ** allocator returns more memory than requested, then more than MINENTRY ** allocations may fit in it. */ assert( sqlite3_mutex_held(pGroup->mutex) ); pcache1LeaveMutex(pCache->pGroup); sz = sizeof(PGroupBlock) + PAGECACHE_BLOCKALLOC_MINENTRY * nByte; pBlock = (PGroupBlock *)sqlite3Malloc(sz); pcache1EnterMutex(pCache->pGroup); if( !pBlock ){ freeListIfEmpty(pGroup, pList); return 0; } pBlock->nEntry = (sqlite3MallocSize(pBlock) - sizeof(PGroupBlock)) / nByte; if( pBlock->nEntry>=BMS ){ pBlock->nEntry = BMS-1; } pBlock->pList = pList; pBlock->mUsed = 0; pBlock->aData = (u8 *)&pBlock[1]; addBlockToList(pList, pBlock); sz = sqlite3MallocSize(pBlock); sqlite3_mutex_enter(pcache1.mutex); sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); sqlite3_mutex_leave(pcache1.mutex); } for(i=0; pPg==0 && ALWAYS(i<pBlock->nEntry); i++){ if( 0==(pBlock->mUsed & ((Bitmask)1<<i)) ){ pBlock->mUsed |= ((Bitmask)1<<i); pPg = (void *)&pBlock->aData[pList->nByte * i]; } } assert( pPg ); PAGE_SET_BLOCKPTR(pCache, pPg, pBlock); /* If the block is now full, shift it to the end of the list */ if( pBlock->mUsed==(((Bitmask)1<<pBlock->nEntry)-1) && pList->pLast!=pBlock ){ assert( pList->pFirst==pBlock ); assert( pBlock->pPrev==0 ); assert( pList->pLast->pNext==0 ); pList->pFirst = pBlock->pNext; pList->pFirst->pPrev = 0; pBlock->pPrev = pList->pLast; pBlock->pNext = 0; pList->pLast->pNext = pBlock; pList->pLast = pBlock; } p = PAGE_TO_PGHDR1(pCache, pPg); if( pCache->bPurgeable ){ pCache->pGroup->nCurrentPage++; } #else /* The group mutex must be released before pcache1Alloc() is called. This ** is because it may call sqlite3_release_memory(), which assumes that ** this mutex is not held. */ assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); pcache1LeaveMutex(pCache->pGroup); pPg = pcache1Alloc(nByte); pcache1EnterMutex(pCache->pGroup); if( pPg ){ p = PAGE_TO_PGHDR1(pCache, pPg); if( pCache->bPurgeable ){ pCache->pGroup->nCurrentPage++; } }else{ p = 0; } #endif return p; } /* ** Free a page object allocated by pcache1AllocPage(). ** ** The pointer is allowed to be NULL, which is prudent. But it turns out ** that the current implementation happens to never call this routine ** with a NULL pointer, so we mark the NULL test with ALWAYS(). */ static void pcache1FreePage(PgHdr1 *p){ if( ALWAYS(p) ){ PCache1 *pCache = p->pCache; void *pPg = PGHDR1_TO_PAGE(p); #ifdef SQLITE_PAGECACHE_BLOCKALLOC PGroupBlock *pBlock = PAGE_GET_BLOCKPTR(pCache, pPg); PGroupBlockList *pList = pBlock->pList; int i = ((u8 *)pPg - pBlock->aData) / pList->nByte; assert( pPg==(void *)&pBlock->aData[i*pList->nByte] ); assert( pBlock->mUsed & ((Bitmask)1<<i) ); pBlock->mUsed &= ~((Bitmask)1<<i); /* Remove the block from the list. If it is completely empty, free it. ** Or if it is not completely empty, re-insert it at the start of the ** list. */ if( pList->pFirst==pBlock ){ pList->pFirst = pBlock->pNext; if( pList->pFirst ) pList->pFirst->pPrev = 0; }else{ pBlock->pPrev->pNext = pBlock->pNext; } if( pList->pLast==pBlock ){ pList->pLast = pBlock->pPrev; if( pList->pLast ) pList->pLast->pNext = 0; }else{ pBlock->pNext->pPrev = pBlock->pPrev; } if( pBlock->mUsed==0 ){ PGroup *pGroup = p->pCache->pGroup; int sz = sqlite3MallocSize(pBlock); sqlite3_mutex_enter(pcache1.mutex); sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -sz); sqlite3_mutex_leave(pcache1.mutex); freeListIfEmpty(pGroup, pList); sqlite3_free(pBlock); }else{ addBlockToList(pList, pBlock); } #else assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) ); pcache1Free(pPg); #endif if( pCache->bPurgeable ){ pCache->pGroup->nCurrentPage--; } } } /* ** Malloc function used by SQLite to obtain space from the buffer configured ** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer ** exists, this function falls back to sqlite3Malloc(). |
︙ | ︙ | |||
36199 36200 36201 36202 36203 36204 36205 | } /* Step 5. If a usable page buffer has still not been found, ** attempt to allocate a new one. */ if( !pPage ){ if( createFlag==1 ) sqlite3BeginBenignMalloc(); | < < | 36751 36752 36753 36754 36755 36756 36757 36758 36759 36760 36761 36762 36763 36764 36765 | } /* Step 5. If a usable page buffer has still not been found, ** attempt to allocate a new one. */ if( !pPage ){ if( createFlag==1 ) sqlite3BeginBenignMalloc(); pPage = pcache1AllocPage(pCache); if( createFlag==1 ) sqlite3EndBenignMalloc(); } if( pPage ){ unsigned int h = iKey % pCache->nHash; pCache->nPage++; pPage->iKey = iKey; |
︙ | ︙ | |||
36371 36372 36373 36374 36375 36376 36377 36378 36379 36380 36381 36382 36383 36384 | ** ** nReq is the number of bytes of memory required. Once this much has ** been released, the function returns. The return value is the total number ** of bytes of memory released. */ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){ int nFree = 0; assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); assert( sqlite3_mutex_notheld(pcache1.mutex) ); if( pcache1.pStart==0 ){ PgHdr1 *p; pcache1EnterMutex(&pcache1.grp); while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){ nFree += pcache1MemSize(PGHDR1_TO_PAGE(p)); | > > > | 36921 36922 36923 36924 36925 36926 36927 36928 36929 36930 36931 36932 36933 36934 36935 36936 36937 | ** ** nReq is the number of bytes of memory required. Once this much has ** been released, the function returns. The return value is the total number ** of bytes of memory released. */ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){ int nFree = 0; #ifdef SQLITE_PAGECACHE_BLOCKALLOC if( pcache1.grp.isBusy ) return 0; #endif assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); assert( sqlite3_mutex_notheld(pcache1.mutex) ); if( pcache1.pStart==0 ){ PgHdr1 *p; pcache1EnterMutex(&pcache1.grp); while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){ nFree += pcache1MemSize(PGHDR1_TO_PAGE(p)); |
︙ | ︙ | |||
37583 37584 37585 37586 37587 37588 37589 37590 37591 37592 37593 37594 37595 37596 | 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 | > | 38136 38137 38138 38139 38140 38141 38142 38143 38144 38145 38146 38147 38148 38149 38150 | 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 */ u8 hasSeenStress; /* pagerStress() called one or more times */ /************************************************************************** ** 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 |
︙ | ︙ | |||
40702 40703 40704 40705 40706 40707 40708 40709 40710 40711 40712 40713 40714 40715 | ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp); pPager->pWal = 0; | > | 41256 41257 41258 41259 41260 41261 41262 41263 41264 41265 41266 41267 41268 41269 41270 | ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp); pPager->pWal = 0; |
︙ | ︙ | |||
41136 41137 41138 41139 41140 41141 41142 41143 41144 41145 41146 41147 41148 41149 | ** 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; | > | 41691 41692 41693 41694 41695 41696 41697 41698 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. */ pPager->hasSeenStress = 1; 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; |
︙ | ︙ | |||
50428 50429 50430 50431 50432 50433 50434 | nCell = pPage->nCell; for(i=0; i<nCell; i++){ u8 *pCell = findCell(pPage, i); if( eType==PTRMAP_OVERFLOW1 ){ CellInfo info; btreeParseCellPtr(pPage, pCell, &info); | | > | > | | < | 50984 50985 50986 50987 50988 50989 50990 50991 50992 50993 50994 50995 50996 50997 50998 50999 51000 51001 51002 51003 | 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; } } |
︙ | ︙ | |||
51153 51154 51155 51156 51157 51158 51159 | assert( wrFlag==0 || p->inTrans==TRANS_WRITE ); assert( pBt->pPage1 && pBt->pPage1->aData ); if( NEVER(wrFlag && pBt->readOnly) ){ return SQLITE_READONLY; } if( iTable==1 && btreePagecount(pBt)==0 ){ | | > | 51710 51711 51712 51713 51714 51715 51716 51717 51718 51719 51720 51721 51722 51723 51724 51725 | assert( wrFlag==0 || p->inTrans==TRANS_WRITE ); assert( pBt->pPage1 && pBt->pPage1->aData ); if( NEVER(wrFlag && pBt->readOnly) ){ return SQLITE_READONLY; } if( iTable==1 && btreePagecount(pBt)==0 ){ assert( wrFlag==0 ); iTable = 0; } /* Now that no other errors can occur, finish filling in the BtCursor ** variables and link the cursor into the BtShared list. */ pCur->pgnoRoot = (Pgno)iTable; pCur->iPage = -1; pCur->pKeyInfo = pKeyInfo; |
︙ | ︙ | |||
51907 51908 51909 51910 51911 51912 51913 51914 51915 51916 51917 51918 51919 51920 | if( pCur->iPage>=0 ){ int i; for(i=1; i<=pCur->iPage; i++){ releasePage(pCur->apPage[i]); } pCur->iPage = 0; }else{ rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; | > > > | 52465 52466 52467 52468 52469 52470 52471 52472 52473 52474 52475 52476 52477 52478 52479 52480 52481 | if( pCur->iPage>=0 ){ int i; for(i=1; i<=pCur->iPage; i++){ releasePage(pCur->apPage[i]); } pCur->iPage = 0; }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_OK; }else{ rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; |
︙ | ︙ | |||
52016 52017 52018 52019 52020 52021 52022 | int rc; assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( pCur->eState==CURSOR_INVALID ){ | | | 52577 52578 52579 52580 52581 52582 52583 52584 52585 52586 52587 52588 52589 52590 52591 | int rc; assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( pCur->eState==CURSOR_INVALID ){ assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); *pRes = 1; }else{ assert( pCur->apPage[pCur->iPage]->nCell>0 ); *pRes = 0; rc = moveToLeftmost(pCur); } } |
︙ | ︙ | |||
52055 52056 52057 52058 52059 52060 52061 | #endif return SQLITE_OK; } rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( CURSOR_INVALID==pCur->eState ){ | | | 52616 52617 52618 52619 52620 52621 52622 52623 52624 52625 52626 52627 52628 52629 52630 | #endif return SQLITE_OK; } rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( CURSOR_INVALID==pCur->eState ){ assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); *pRes = 1; }else{ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; rc = moveToRightmost(pCur); pCur->atLast = rc==SQLITE_OK ?1:0; } |
︙ | ︙ | |||
52128 52129 52130 52131 52132 52133 52134 | } } rc = moveToRoot(pCur); if( rc ){ return rc; } | | | | | | 52689 52690 52691 52692 52693 52694 52695 52696 52697 52698 52699 52700 52701 52702 52703 52704 52705 52706 52707 52708 | } } rc = moveToRoot(pCur); if( rc ){ return rc; } assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] ); assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit ); assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 ); if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); return SQLITE_OK; } assert( pCur->apPage[0]->intKey || pIdxKey ); for(;;){ int lwr, upr, idx; Pgno chldPg; MemPage *pPage = pCur->apPage[pCur->iPage]; |
︙ | ︙ | |||
52860 52861 52862 52863 52864 52865 52866 52867 52868 52869 52870 52871 52872 52873 | 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; | > > > | 53421 53422 53423 53424 53425 53426 53427 53428 53429 53430 53431 53432 53433 53434 53435 53436 53437 | 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; |
︙ | ︙ | |||
55043 55044 55045 55046 55047 55048 55049 55050 55051 55052 55053 55054 55055 55056 | ** SQLITE_OK is returned if the operation is successfully executed. ** Otherwise, if an error is encountered (i.e. an IO error or database ** corruption) an SQLite error code is returned. */ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ rc = moveToRoot(pCur); /* Unless an error occurs, the following loop runs one iteration for each ** page in the B-Tree structure (not including overflow pages). */ while( rc==SQLITE_OK ){ int iIdx; /* Index of child node in parent */ | > > > > > | 55607 55608 55609 55610 55611 55612 55613 55614 55615 55616 55617 55618 55619 55620 55621 55622 55623 55624 55625 | ** SQLITE_OK is returned if the operation is successfully executed. ** Otherwise, if an error is encountered (i.e. an IO error or database ** corruption) an SQLite error code is returned. */ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ if( pCur->pgnoRoot==0 ){ *pnEntry = 0; return SQLITE_OK; } rc = moveToRoot(pCur); /* Unless an error occurs, the following loop runs one iteration for each ** page in the B-Tree structure (not including overflow pages). */ while( rc==SQLITE_OK ){ int iIdx; /* Index of child node in parent */ |
︙ | ︙ | |||
55827 55828 55829 55830 55831 55832 55833 | ** "write version" (single byte at byte offset 19) fields in the database ** header to iVersion. */ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ BtShared *pBt = pBtree->pBt; int rc; /* Return code */ | < | 56396 56397 56398 56399 56400 56401 56402 56403 56404 56405 56406 56407 56408 56409 | ** "write version" (single byte at byte offset 19) fields in the database ** header to iVersion. */ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ BtShared *pBt = pBtree->pBt; int rc; /* Return code */ assert( iVersion==1 || iVersion==2 ); /* If setting the version fields to 1, do not automatically open the ** WAL connection, even if the version fields are currently set to 2. */ pBt->doNotUseWAL = (u8)(iVersion==1); |
︙ | ︙ | |||
56266 56267 56268 56269 56270 56271 56272 | } /* Update the schema version field in the destination database. This ** is to make sure that the schema-version really does change in ** the case where the source and destination databases have the ** same schema version. */ | | | < < | | | | > > | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 56834 56835 56836 56837 56838 56839 56840 56841 56842 56843 56844 56845 56846 56847 56848 56849 56850 56851 56852 56853 56854 56855 56856 56857 56858 56859 56860 56861 56862 56863 56864 56865 56866 56867 56868 56869 56870 56871 56872 56873 56874 56875 56876 56877 56878 56879 56880 56881 56882 56883 56884 56885 56886 56887 56888 56889 56890 56891 56892 56893 56894 56895 56896 56897 56898 56899 56900 56901 56902 56903 56904 56905 56906 56907 56908 56909 56910 56911 56912 56913 56914 56915 56916 56917 56918 56919 56920 56921 56922 56923 56924 56925 56926 56927 56928 56929 56930 56931 56932 56933 56934 56935 56936 56937 56938 56939 56940 56941 56942 56943 56944 56945 56946 56947 | } /* Update the schema version field in the destination database. This ** is to make sure that the schema-version really does change in ** the case where the source and destination databases have the ** same schema version. */ if( rc==SQLITE_DONE ){ rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); if( rc==SQLITE_OK ){ if( p->pDestDb ){ sqlite3ResetInternalSchema(p->pDestDb, -1); } if( destMode==PAGER_JOURNALMODE_WAL ){ rc = sqlite3BtreeSetVersion(p->pDest, 2); } } if( rc==SQLITE_OK ){ int nDestTruncate; /* Set nDestTruncate to the final number of pages in the destination ** database. The complication here is that the destination page ** size may be different to the source page size. ** ** If the source page size is smaller than the destination page size, ** round up. In this case the call to sqlite3OsTruncate() below will ** fix the size of the file. However it is important to call ** sqlite3PagerTruncateImage() here so that any pages in the ** destination file that lie beyond the nDestTruncate page mark are ** journalled by PagerCommitPhaseOne() before they are destroyed ** by the file truncation. */ assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) ); assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) ); if( pgszSrc<pgszDest ){ int ratio = pgszDest/pgszSrc; nDestTruncate = (nSrcPage+ratio-1)/ratio; if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){ nDestTruncate--; } }else{ nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } sqlite3PagerTruncateImage(pDestPager, nDestTruncate); if( pgszSrc<pgszDest ){ /* If the source page-size is smaller than the destination page-size, ** two extra things may need to happen: ** ** * The destination may need to be truncated, and ** ** * Data stored on the pages immediately following the ** pending-byte page in the source database may need to be ** copied into the destination database. */ const i64 iSize = (i64)pgszSrc * (i64)nSrcPage; sqlite3_file * const pFile = sqlite3PagerFile(pDestPager); i64 iOff; i64 iEnd; assert( pFile ); assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || ( nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest )); /* This call ensures that all data required to recreate the original ** database has been stored in the journal for pDestPager and the ** journal synced to disk. So at this point we may safely modify ** the database file in any way, knowing that if a power failure ** occurs, the original database will be reconstructed from the ** journal file. */ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); /* Write the extra pages and truncate the database file as required */ iEnd = MIN(PENDING_BYTE + pgszDest, iSize); for( iOff=PENDING_BYTE+pgszSrc; rc==SQLITE_OK && iOff<iEnd; iOff+=pgszSrc ){ PgHdr *pSrcPg = 0; const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1); rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg); if( rc==SQLITE_OK ){ u8 *zData = sqlite3PagerGetData(pSrcPg); rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff); } sqlite3PagerUnref(pSrcPg); } if( rc==SQLITE_OK ){ rc = backupTruncateFile(pFile, iSize); } /* Sync the database file to disk. */ if( rc==SQLITE_OK ){ rc = sqlite3PagerSync(pDestPager); } }else{ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); } /* Finish committing the transaction to the destination database. */ if( SQLITE_OK==rc && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) ){ rc = SQLITE_DONE; } } } /* If bCloseTrans is true, then this function opened a read transaction ** on the source database. Close the read transaction here. There is ** no need to check the return values of the btree methods here, as ** "committing" a read-only transaction cannot fail. |
︙ | ︙ | |||
56829 56830 56831 56832 56833 56834 56835 | /* ** If the memory cell contains a string value that must be freed by ** invoking an external callback, free it now. Calling this function ** does not free any Mem.zMalloc buffer. */ SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); | < < < < < | | | | | | | | | | | | < | | 57401 57402 57403 57404 57405 57406 57407 57408 57409 57410 57411 57412 57413 57414 57415 57416 57417 57418 57419 57420 57421 57422 57423 57424 57425 57426 57427 57428 57429 57430 57431 57432 57433 57434 57435 57436 | /* ** If the memory cell contains a string value that must be freed by ** invoking an external callback, free it now. Calling this function ** does not free any Mem.zMalloc buffer. */ SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); sqlite3VdbeMemRelease(p); }else if( p->flags&MEM_Dyn && p->xDel ){ assert( (p->flags&MEM_RowSet)==0 ); p->xDel((void *)p->z); p->xDel = 0; }else if( p->flags&MEM_RowSet ){ sqlite3RowSetClear(p->u.pRowSet); }else if( p->flags&MEM_Frame ){ sqlite3VdbeMemSetNull(p); } } /* ** Release any memory held by the Mem. This may leave the Mem in an ** inconsistent state, for example with (Mem.z==0) and ** (Mem.type==SQLITE_TEXT). */ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ MemReleaseExt(p); sqlite3DbFree(p->db, p->zMalloc); p->z = 0; p->zMalloc = 0; p->xDel = 0; } /* |
︙ | ︙ | |||
57178 57179 57180 57181 57182 57183 57184 | ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are freed. The pFrom->z field is not duplicated. If ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ assert( (pFrom->flags & MEM_RowSet)==0 ); | | | | 57744 57745 57746 57747 57748 57749 57750 57751 57752 57753 57754 57755 57756 57757 57758 57759 57760 57761 57762 57763 57764 57765 57766 57767 57768 57769 57770 57771 57772 57773 57774 57775 57776 | ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are freed. The pFrom->z field is not duplicated. If ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ assert( (pFrom->flags & MEM_RowSet)==0 ); MemReleaseExt(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->xDel = 0; if( (pFrom->flags&MEM_Static)==0 ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); pTo->flags |= srcType; } } /* ** Make a full copy of pFrom into pTo. Prior contents of pTo are ** freed before the copy is made. */ SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; assert( (pFrom->flags & MEM_RowSet)==0 ); MemReleaseExt(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; if( pTo->flags&(MEM_Str|MEM_Blob) ){ if( 0==(pFrom->flags&MEM_Static) ){ pTo->flags |= MEM_Ephem; rc = sqlite3VdbeMemMakeWriteable(pTo); |
︙ | ︙ | |||
57590 57591 57592 57593 57594 57595 57596 | if( !pExpr ){ *ppVal = 0; return SQLITE_OK; } op = pExpr->op; | | | | | 58156 58157 58158 58159 58160 58161 58162 58163 58164 58165 58166 58167 58168 58169 58170 58171 58172 58173 58174 | if( !pExpr ){ *ppVal = 0; return SQLITE_OK; } op = pExpr->op; /* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT2. ** The ifdef here is to enable us to achieve 100% branch test coverage even ** when SQLITE_ENABLE_STAT2 is omitted. */ #ifdef SQLITE_ENABLE_STAT2 if( op==TK_REGISTER ) op = pExpr->op2; #else if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; #endif /* Handle negative integers in a single step. This is needed in the ** case when the value is -9223372036854775808. |
︙ | ︙ | |||
58151 58152 58153 58154 58155 58156 58157 58158 58159 58160 58161 58162 58163 58164 | }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 } if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ assert( -1-pOp->p2<p->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } } | > > > > > > | 58717 58718 58719 58720 58721 58722 58723 58724 58725 58726 58727 58728 58729 58730 58731 58732 58733 58734 58735 58736 | }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; } if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ assert( -1-pOp->p2<p->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } } |
︙ | ︙ | |||
58242 58243 58244 58245 58246 58247 58248 | /* ** Change the value of the P1 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 ** few minor changes to the program. */ | | < | | < | | < | | 58814 58815 58816 58817 58818 58819 58820 58821 58822 58823 58824 58825 58826 58827 58828 58829 58830 58831 58832 58833 58834 58835 58836 58837 58838 58839 58840 58841 58842 58843 58844 58845 58846 58847 58848 58849 58850 58851 | /* ** Change the value of the P1 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 ** few minor changes to the program. */ SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){ assert( p!=0 ); if( ((u32)p->nOp)>addr ){ p->aOp[addr].p1 = val; } } /* ** Change the value of the P2 operand for a specific instruction. ** This routine is useful for setting a jump destination. */ SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){ assert( p!=0 ); if( ((u32)p->nOp)>addr ){ p->aOp[addr].p2 = val; } } /* ** Change the value of the P3 operand for a specific instruction. */ SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){ assert( p!=0 ); if( ((u32)p->nOp)>addr ){ p->aOp[addr].p3 = val; } } /* ** Change the value of the P5 operand for the most recently ** added operation. |
︙ | ︙ | |||
58290 58291 58292 58293 58294 58295 58296 | } /* ** Change the P2 operand of instruction addr so that it points to ** the address of the next instruction to be coded. */ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ | | | | 58859 58860 58861 58862 58863 58864 58865 58866 58867 58868 58869 58870 58871 58872 58873 58874 | } /* ** Change the P2 operand of instruction addr so that it points to ** the address of the next instruction to be coded. */ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ assert( addr>=0 ); sqlite3VdbeChangeP2(p, addr, p->nOp); } /* ** If the input FuncDef structure is ephemeral, then free it. If ** the FuncDef is not ephermal, then do nothing. */ |
︙ | ︙ | |||
58659 58660 58661 58662 58663 58664 58665 58666 58667 58668 58669 58670 58671 58672 | case P4_INTARRAY: { sqlite3_snprintf(nTemp, zTemp, "intarray"); break; } case P4_SUBPROGRAM: { sqlite3_snprintf(nTemp, zTemp, "program"); break; } default: { zP4 = pOp->p4.z; if( zP4==0 ){ zP4 = zTemp; zTemp[0] = 0; } | > > > > | 59228 59229 59230 59231 59232 59233 59234 59235 59236 59237 59238 59239 59240 59241 59242 59243 59244 59245 | case P4_INTARRAY: { sqlite3_snprintf(nTemp, zTemp, "intarray"); break; } case P4_SUBPROGRAM: { sqlite3_snprintf(nTemp, zTemp, "program"); break; } case P4_ADVANCE: { zTemp[0] = 0; break; } default: { zP4 = pOp->p4.z; if( zP4==0 ){ zP4 = zTemp; zTemp[0] = 0; } |
︙ | ︙ | |||
59283 59284 59285 59286 59287 59288 59289 59290 59291 59292 59293 59294 59295 59296 | ** Close a VDBE cursor and release all the resources that cursor ** happens to hold. */ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx==0 ){ return; } if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); /* The pCx->pCursor will be close automatically, if it exists, by ** the call above. */ }else if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } | > | 59856 59857 59858 59859 59860 59861 59862 59863 59864 59865 59866 59867 59868 59869 59870 | ** Close a VDBE cursor and release all the resources that cursor ** happens to hold. */ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx==0 ){ return; } sqlite3VdbeSorterClose(p->db, pCx); if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); /* The pCx->pCursor will be close automatically, if it exists, by ** the call above. */ }else if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } |
︙ | ︙ | |||
62583 62584 62585 62586 62587 62588 62589 62590 62591 62592 62593 62594 62595 62596 | /* ** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) ** P if required. */ #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) /* ** Argument pMem points at a register that will be passed to a ** user-defined function or returned to the user as the result of a query. ** This routine sets the pMem->type variable used by the sqlite3_value_*() ** routines. */ SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem){ | > > > > > > > | 63157 63158 63159 63160 63161 63162 63163 63164 63165 63166 63167 63168 63169 63170 63171 63172 63173 63174 63175 63176 63177 | /* ** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) ** P if required. */ #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ #ifdef SQLITE_OMIT_MERGE_SORT # define isSorter(x) 0 #else # define isSorter(x) ((x)->pSorter!=0) #endif /* ** Argument pMem points at a register that will be passed to a ** user-defined function or returned to the user as the result of a query. ** This routine sets the pMem->type variable used by the sqlite3_value_*() ** routines. */ SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem){ |
︙ | ︙ | |||
63177 63178 63179 63180 63181 63182 63183 63184 63185 63186 63187 63188 63189 63190 | Mem sMem; /* For storing the record being decoded */ u8 *zIdx; /* Index into header */ u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u32 szField; /* Number of bytes in the content of a field */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ Mem *pReg; /* PseudoTable input register */ } am; struct OP_Affinity_stack_vars { const char *zAffinity; /* The affinity to be applied */ char cAff; /* A single character of affinity */ } an; struct OP_MakeRecord_stack_vars { | > | 63758 63759 63760 63761 63762 63763 63764 63765 63766 63767 63768 63769 63770 63771 63772 | Mem sMem; /* For storing the record being decoded */ u8 *zIdx; /* Index into header */ u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u32 szField; /* Number of bytes in the content of a field */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ } am; struct OP_Affinity_stack_vars { const char *zAffinity; /* The affinity to be applied */ char cAff; /* A single character of affinity */ } an; struct OP_MakeRecord_stack_vars { |
︙ | ︙ | |||
63248 63249 63250 63251 63252 63253 63254 63255 63256 | Btree *pX; VdbeCursor *pCur; Db *pDb; } aw; struct OP_OpenEphemeral_stack_vars { VdbeCursor *pCx; } ax; struct OP_OpenPseudo_stack_vars { VdbeCursor *pCx; | > > > | | | | | | | | | > > > > > > > | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 64094 | 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; 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 ){ |
︙ | ︙ | |||
63589 63590 63591 63592 63593 63594 63595 | */ assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){ assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); | | | 64180 64181 64182 64183 64184 64185 64186 64187 64188 64189 64190 64191 64192 64193 64194 | */ assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){ assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); MemReleaseExt(pOut); pOut->flags = MEM_Int; } /* Sanity checking on other operands */ #ifdef SQLITE_DEBUG if( (pOp->opflags & OPFLG_IN1)!=0 ){ assert( pOp->p1>0 ); |
︙ | ︙ | |||
65059 65060 65061 65062 65063 65064 65065 65066 65067 65068 65069 65070 65071 65072 65073 65074 65075 65076 65077 | Mem sMem; /* For storing the record being decoded */ u8 *zIdx; /* Index into header */ u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u32 szField; /* Number of bytes in the content of a field */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ Mem *pReg; /* PseudoTable input register */ #endif /* local variables moved into u.am */ u.am.p1 = pOp->p1; u.am.p2 = pOp->p2; u.am.pC = 0; memset(&u.am.sMem, 0, sizeof(u.am.sMem)); assert( u.am.p1<p->nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); u.am.pDest = &aMem[pOp->p3]; memAboutToChange(p, u.am.pDest); | > < | 65650 65651 65652 65653 65654 65655 65656 65657 65658 65659 65660 65661 65662 65663 65664 65665 65666 65667 65668 65669 65670 65671 65672 65673 65674 65675 65676 | Mem sMem; /* For storing the record being decoded */ u8 *zIdx; /* Index into header */ u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u32 szField; /* Number of bytes in the content of a field */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ #endif /* local variables moved into u.am */ u.am.p1 = pOp->p1; u.am.p2 = pOp->p2; u.am.pC = 0; memset(&u.am.sMem, 0, sizeof(u.am.sMem)); assert( u.am.p1<p->nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); u.am.pDest = &aMem[pOp->p3]; memAboutToChange(p, u.am.pDest); u.am.zRec = 0; /* This block sets the variable u.am.payloadSize to be the total number of ** bytes in the record. ** ** u.am.zRec is set to be the complete text of the record if it is available. ** The complete record text is always available for pseudo-tables |
︙ | ︙ | |||
65115 65116 65117 65118 65119 65120 65121 | assert( (u.am.payloadSize64 & SQLITE_MAX_U32)==(u64)u.am.payloadSize64 ); u.am.payloadSize = (u32)u.am.payloadSize64; }else{ assert( sqlite3BtreeCursorIsValid(u.am.pCrsr) ); rc = sqlite3BtreeDataSize(u.am.pCrsr, &u.am.payloadSize); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ } | | | > | | 65706 65707 65708 65709 65710 65711 65712 65713 65714 65715 65716 65717 65718 65719 65720 65721 65722 65723 65724 65725 65726 65727 65728 65729 65730 65731 65732 65733 65734 65735 65736 | assert( (u.am.payloadSize64 & SQLITE_MAX_U32)==(u64)u.am.payloadSize64 ); u.am.payloadSize = (u32)u.am.payloadSize64; }else{ assert( sqlite3BtreeCursorIsValid(u.am.pCrsr) ); rc = sqlite3BtreeDataSize(u.am.pCrsr, &u.am.payloadSize); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ } }else if( ALWAYS(u.am.pC->pseudoTableReg>0) ){ u.am.pReg = &aMem[u.am.pC->pseudoTableReg]; assert( u.am.pReg->flags & MEM_Blob ); assert( memIsValid(u.am.pReg) ); u.am.payloadSize = u.am.pReg->n; u.am.zRec = u.am.pReg->z; u.am.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr; assert( u.am.payloadSize==0 || u.am.zRec!=0 ); }else{ /* Consider the row to be NULL */ u.am.payloadSize = 0; } /* If u.am.payloadSize is 0, then just store a NULL. This can happen because of ** nullRow or because of a corrupt database. */ if( u.am.payloadSize==0 ){ MemSetTypeFlag(u.am.pDest, MEM_Null); goto op_column_out; } assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 ); if( u.am.payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } |
︙ | ︙ | |||
65237 65238 65239 65240 65241 65242 65243 | ** arrays. u.am.aType[u.am.i] will contain the type integer for the u.am.i-th ** column and u.am.aOffset[u.am.i] will contain the u.am.offset from the beginning ** of the record to the start of the data for the u.am.i-th column */ for(u.am.i=0; u.am.i<u.am.nField; u.am.i++){ if( u.am.zIdx<u.am.zEndHdr ){ u.am.aOffset[u.am.i] = u.am.offset; | > > > > > > | | | 65829 65830 65831 65832 65833 65834 65835 65836 65837 65838 65839 65840 65841 65842 65843 65844 65845 65846 65847 65848 65849 65850 | ** arrays. u.am.aType[u.am.i] will contain the type integer for the u.am.i-th ** column and u.am.aOffset[u.am.i] will contain the u.am.offset from the beginning ** of the record to the start of the data for the u.am.i-th column */ for(u.am.i=0; u.am.i<u.am.nField; u.am.i++){ if( u.am.zIdx<u.am.zEndHdr ){ u.am.aOffset[u.am.i] = u.am.offset; if( u.am.zIdx[0]<0x80 ){ u.am.t = u.am.zIdx[0]; u.am.zIdx++; }else{ u.am.zIdx += sqlite3GetVarint32(u.am.zIdx, &u.am.t); } u.am.aType[u.am.i] = u.am.t; u.am.szField = sqlite3VdbeSerialTypeLen(u.am.t); u.am.offset += u.am.szField; if( u.am.offset<u.am.szField ){ /* True if u.am.offset overflows */ u.am.zIdx = &u.am.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */ break; } }else{ /* If u.am.i is less that u.am.nField, then there are less fields in this |
︙ | ︙ | |||
65279 65280 65281 65282 65283 65284 65285 | ** then there are not enough fields in the record to satisfy the ** request. In this case, set the value NULL or to P4 if P4 is ** a pointer to a Mem object. */ if( u.am.aOffset[u.am.p2] ){ assert( rc==SQLITE_OK ); if( u.am.zRec ){ | | | | 65877 65878 65879 65880 65881 65882 65883 65884 65885 65886 65887 65888 65889 65890 65891 65892 65893 65894 65895 65896 65897 65898 65899 65900 65901 65902 65903 65904 65905 65906 65907 65908 | ** then there are not enough fields in the record to satisfy the ** request. In this case, set the value NULL or to P4 if P4 is ** a pointer to a Mem object. */ if( u.am.aOffset[u.am.p2] ){ assert( rc==SQLITE_OK ); if( u.am.zRec ){ MemReleaseExt(u.am.pDest); sqlite3VdbeSerialGet((u8 *)&u.am.zRec[u.am.aOffset[u.am.p2]], u.am.aType[u.am.p2], u.am.pDest); }else{ u.am.len = sqlite3VdbeSerialTypeLen(u.am.aType[u.am.p2]); sqlite3VdbeMemMove(&u.am.sMem, u.am.pDest); rc = sqlite3VdbeMemFromBtree(u.am.pCrsr, u.am.aOffset[u.am.p2], u.am.len, u.am.pC->isIndex, &u.am.sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } u.am.zData = u.am.sMem.z; sqlite3VdbeSerialGet((u8*)u.am.zData, u.am.aType[u.am.p2], u.am.pDest); } u.am.pDest->enc = encoding; }else{ if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(u.am.pDest, pOp->p4.pMem, MEM_Static); }else{ MemSetTypeFlag(u.am.pDest, MEM_Null); } } /* If we dynamically allocated space to hold the data (in the ** sqlite3VdbeMemFromBtree() call above) then transfer control of that ** dynamically allocated space over to the u.am.pDest structure. ** This prevents a memory copy. |
︙ | ︙ | |||
65498 65499 65500 65501 65502 65503 65504 | case OP_Count: { /* out2-prerelease */ #if 0 /* local variables moved into u.ap */ i64 nEntry; BtCursor *pCrsr; #endif /* local variables moved into u.ap */ u.ap.pCrsr = p->apCsr[pOp->p1]->pCursor; | | | 66096 66097 66098 66099 66100 66101 66102 66103 66104 66105 66106 66107 66108 66109 66110 | case OP_Count: { /* out2-prerelease */ #if 0 /* local variables moved into u.ap */ i64 nEntry; BtCursor *pCrsr; #endif /* local variables moved into u.ap */ u.ap.pCrsr = p->apCsr[pOp->p1]->pCursor; if( ALWAYS(u.ap.pCrsr) ){ rc = sqlite3BtreeCount(u.ap.pCrsr, &u.ap.nEntry); }else{ u.ap.nEntry = 0; } pOut->u.i = u.ap.nEntry; break; } |
︙ | ︙ | |||
66074 66075 66076 66077 66078 66079 66080 | u.aw.pCur = allocateCursor(p, pOp->p1, u.aw.nField, u.aw.iDb, 1); if( u.aw.pCur==0 ) goto no_mem; u.aw.pCur->nullRow = 1; u.aw.pCur->isOrdered = 1; rc = sqlite3BtreeCursor(u.aw.pX, u.aw.p2, u.aw.wrFlag, u.aw.pKeyInfo, u.aw.pCur->pCursor); u.aw.pCur->pKeyInfo = u.aw.pKeyInfo; | | | < < | < < < < | > > > > > | 66672 66673 66674 66675 66676 66677 66678 66679 66680 66681 66682 66683 66684 66685 66686 66687 66688 66689 66690 66691 66692 66693 66694 66695 66696 66697 66698 66699 66700 66701 66702 66703 66704 66705 66706 66707 66708 66709 66710 66711 66712 66713 66714 66715 66716 66717 66718 66719 66720 | u.aw.pCur = allocateCursor(p, pOp->p1, u.aw.nField, u.aw.iDb, 1); if( u.aw.pCur==0 ) goto no_mem; u.aw.pCur->nullRow = 1; u.aw.pCur->isOrdered = 1; rc = sqlite3BtreeCursor(u.aw.pX, u.aw.p2, u.aw.wrFlag, u.aw.pKeyInfo, u.aw.pCur->pCursor); u.aw.pCur->pKeyInfo = u.aw.pKeyInfo; /* Since it performs no memory allocation or IO, the only value that ** sqlite3BtreeCursor() may return is SQLITE_OK. */ assert( rc==SQLITE_OK ); /* Set the VdbeCursor.isTable and isIndex variables. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has ** since moved into the btree layer. */ u.aw.pCur->isTable = pOp->p4type!=P4_KEYINFO; u.aw.pCur->isIndex = !u.aw.pCur->isTable; break; } /* Opcode: OpenEphemeral P1 P2 * P4 P5 ** ** Open a new cursor P1 to a transient table. ** The cursor is always opened read/write even if ** the main database is read-only. The ephemeral ** table is deleted automatically when the cursor is closed. ** ** P2 is the number of columns in the ephemeral table. ** The cursor points to a BTree table if P4==0 and to a BTree index ** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure ** that defines the format of keys in the index. ** ** This opcode was once called OpenTemp. But that created ** confusion because the term "temp table", might refer either ** to a TEMP table at the SQL level, or to a table opened by ** this opcode. Then this opcode was call OpenVirtual. But ** that created confusion with the whole virtual-table idea. ** ** The P5 parameter can be a mask of the BTREE_* flags defined ** in btree.h. These flags control aspects of the operation of ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are ** added automatically. */ /* 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. |
︙ | ︙ | |||
66166 66167 66168 66169 66170 66171 66172 66173 66174 66175 66176 66177 66178 66179 66180 66181 66182 66183 66184 66185 66186 66187 66188 66189 | u.ax.pCx->isTable = 1; } } u.ax.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); u.ax.pCx->isIndex = !u.ax.pCx->isTable; 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: { | > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | 66763 66764 66765 66766 66767 66768 66769 66770 66771 66772 66773 66774 66775 66776 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 | 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. |
︙ | ︙ | |||
66265 66266 66267 66268 66269 66270 66271 | ** ** 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 */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 66886 66887 66888 66889 66890 66891 66892 66893 66894 66895 66896 66897 66898 66899 66900 66901 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 | ** ** 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). */ |
︙ | ︙ | |||
66425 66426 66427 66428 66429 66430 66431 | ** 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 */ | | | | | | | | | | | | 67046 67047 67048 67049 67050 67051 67052 67053 67054 67055 67056 67057 67058 67059 67060 67061 67062 67063 67064 67065 67066 67067 67068 67069 67070 67071 67072 67073 | ** 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 * ** |
︙ | ︙ | |||
66470 66471 66472 66473 66474 66475 66476 | ** 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 */ | | | | | | | | | | | | | | | | | | | | | | | | | | 67091 67092 67093 67094 67095 67096 67097 67098 67099 67100 67101 67102 67103 67104 67105 67106 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 | ** 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; 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{ assert( pIn3->flags & MEM_Blob ); assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ u.bc.pIdxKey = sqlite3VdbeRecordUnpack(u.bc.pC->pKeyInfo, pIn3->n, pIn3->z, u.bc.aTempRec, sizeof(u.bc.aTempRec)); if( u.bc.pIdxKey==0 ){ goto no_mem; } 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 ){ sqlite3VdbeDeleteUnpackedRecord(u.bc.pIdxKey); } 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 |
︙ | ︙ | |||
66557 66558 66559 66560 66561 66562 66563 | ** 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 */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 67178 67179 67180 67181 67182 67183 67184 67185 67186 67187 67188 67189 67190 67191 67192 67193 67194 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 | ** 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. |
︙ | ︙ | |||
66704 66705 66706 66707 66708 66709 66710 | ** 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 */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 67325 67326 67327 67328 67329 67330 67331 67332 67333 67334 67335 67336 67337 67338 67339 67340 67341 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 | ** 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 |
︙ | ︙ | |||
66886 66887 66888 66889 66890 66891 66892 | /* 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: { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 67507 67508 67509 67510 67511 67512 67513 67514 67515 67516 67517 67518 67519 67520 67521 67522 67523 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 | /* 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. |
︙ | ︙ | |||
66975 66976 66977 66978 66979 66980 66981 | ** ** 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: { | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 67596 67597 67598 67599 67600 67601 67602 67603 67604 67605 67606 67607 67608 67609 67610 67611 67612 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 | ** ** 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. |
︙ | ︙ | |||
67055 67056 67057 67058 67059 67060 67061 | ** 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: { | | | | > | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | > > > > | | | | > | > > > | > | | | | | | | | > > > > > > > > > > | < | | | | | | | | | | > | | > > | | | | > > > > | | | | > | | | > > > | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 67719 67720 67721 67722 67723 67724 67725 67726 67727 67728 67729 67730 67731 67732 67733 67734 67735 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 67978 67979 67980 67981 67982 67983 67984 67985 67986 67987 67988 67989 67990 67991 67992 67993 67994 67995 67996 67997 67998 67999 68000 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 | ** 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 ** ** Advance cursor P1 so that it points to the next key/data pair in its ** table or index. If there are no more key/value pairs then fall through ** to the following instruction. But if the cursor advance was successful, ** jump immediately to P2. ** ** The P1 cursor must be for a real table, not a pseudo-table. ** ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreeNext(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** ** See also: Prev */ /* Opcode: Prev P1 P2 * * P5 ** ** Back up cursor P1 so that it points to the previous key/data pair in its ** table or index. If there is no previous key/value pairs then fall through ** to the following instruction. But if the cursor backup was successful, ** jump immediately to P2. ** ** The P1 cursor must be for a real table, not a pseudo-table. ** ** 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 |
︙ | ︙ | |||
67484 67485 67486 67487 67488 67489 67490 | ** 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 */ | | | | | | | | | | | | | | | | | | | 68181 68182 68183 68184 68185 68186 68187 68188 68189 68190 68191 68192 68193 68194 68195 68196 68197 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 | ** 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 * * |
︙ | ︙ | |||
67544 67545 67546 67547 67548 67549 67550 | ** 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 */ | | | | | | | | | | | | | | | | | | | 68241 68242 68243 68244 68245 68246 68247 68248 68249 68250 68251 68252 68253 68254 68255 68256 68257 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 | ** 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 |
︙ | ︙ | |||
67602 67603 67604 67605 67606 67607 67608 | ** 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: { | | | | | | | | 68299 68300 68301 68302 68303 68304 68305 68306 68307 68308 68309 68310 68311 68312 68313 68314 68315 68316 68317 68318 68319 68320 68321 68322 68323 68324 68325 68326 68327 | ** 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 * * * ** |
︙ | ︙ | |||
67646 67647 67648 67649 67650 67651 67652 | ** 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 */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68343 68344 68345 68346 68347 68348 68349 68350 68351 68352 68353 68354 68355 68356 68357 68358 68359 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 | ** 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; |
︙ | ︙ | |||
67797 67798 67799 67800 67801 67802 67803 | ** ** 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: { | | | | | | | | | | | | | | | | | | | | | | 68494 68495 68496 68497 68498 68499 68500 68501 68502 68503 68504 68505 68506 68507 68508 68509 68510 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 | ** ** 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 */ |
︙ | ︙ | |||
67865 67866 67867 67868 67869 67870 67871 | /* 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 */ | | | | | | 68562 68563 68564 68565 68566 68567 68568 68569 68570 68571 68572 68573 68574 68575 68576 68577 68578 68579 68580 68581 68582 68583 68584 68585 68586 68587 68588 68589 | /* 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 |
︙ | ︙ | |||
67907 67908 67909 67910 67911 67912 67913 | ** (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 */ | | | | | | | | | | | 68604 68605 68606 68607 68608 68609 68610 68611 68612 68613 68614 68615 68616 68617 68618 68619 68620 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 | ** (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 |
︙ | ︙ | |||
67959 67960 67961 67962 67963 67964 67965 | ** 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 */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68656 68657 68658 68659 68660 68661 68662 68663 68664 68665 68666 68667 68668 68669 68670 68671 68672 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 | ** 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 * * * |
︙ | ︙ | |||
68136 68137 68138 68139 68140 68141 68142 | ** 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 */ | | | | | | | | | | | 68833 68834 68835 68836 68837 68838 68839 68840 68841 68842 68843 68844 68845 68846 68847 68848 68849 68850 68851 68852 68853 68854 68855 68856 68857 68858 68859 68860 68861 68862 | ** 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 * * * ** |
︙ | ︙ | |||
68218 68219 68220 68221 68222 68223 68224 | ** 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: { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68915 68916 68917 68918 68919 68920 68921 68922 68923 68924 68925 68926 68927 68928 68929 68930 68931 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 | ** 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 */ |
︙ | ︙ | |||
68460 68461 68462 68463 68464 68465 68466 | /* 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 */ | | | | | | 69157 69158 69159 69160 69161 69162 69163 69164 69165 69166 69167 69168 69169 69170 69171 69172 69173 69174 69175 69176 69177 69178 | /* 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 |
︙ | ︙ | |||
68537 68538 68539 68540 68541 68542 68543 | ** 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: { | | | | | | | 69234 69235 69236 69237 69238 69239 69240 69241 69242 69243 69244 69245 69246 69247 69248 69249 69250 69251 69252 69253 | ** 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 * ** |
︙ | ︙ | |||
68581 68582 68583 68584 68585 68586 68587 | /* 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: { | | | | | | | | | | | | | | | | | 69278 69279 69280 69281 69282 69283 69284 69285 69286 69287 69288 69289 69290 69291 69292 69293 69294 69295 69296 69297 69298 69299 69300 69301 69302 69303 69304 69305 69306 69307 69308 69309 69310 69311 69312 69313 69314 69315 69316 69317 | /* 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 |
︙ | ︙ | |||
68633 68634 68635 68636 68637 68638 68639 | ** 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 */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 69330 69331 69332 69333 69334 69335 69336 69337 69338 69339 69340 69341 69342 69343 69344 69345 69346 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 | ** 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 |
︙ | ︙ | |||
68847 68848 68849 68850 68851 68852 68853 | ** 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: { | | | | | | | | | | | | | | | | | | | | 69544 69545 69546 69547 69548 69549 69550 69551 69552 69553 69554 69555 69556 69557 69558 69559 69560 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 | ** 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); } |
︙ | ︙ | |||
68941 68942 68943 68944 68945 68946 68947 | #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: { | | | | | | | | | | 69638 69639 69640 69641 69642 69643 69644 69645 69646 69647 69648 69649 69650 69651 69652 69653 69654 69655 69656 69657 69658 69659 69660 69661 69662 69663 69664 69665 69666 | #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 |
︙ | ︙ | |||
69554 69555 69556 69557 69558 69559 69560 69561 69562 69563 69564 69565 69566 69567 | sqlite3_mutex_leave(db->mutex); return rc; } #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ /************** End of vdbeblob.c ********************************************/ /************** Begin file journal.c *****************************************/ /* ** 2007 August 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 70251 70252 70253 70254 70255 70256 70257 70258 70259 70260 70261 70262 70263 70264 70265 70266 70267 70268 70269 70270 70271 70272 70273 70274 70275 70276 70277 70278 70279 70280 70281 70282 70283 70284 70285 70286 70287 70288 70289 70290 70291 70292 70293 70294 70295 70296 70297 70298 70299 70300 70301 70302 70303 70304 70305 70306 70307 70308 70309 70310 70311 70312 70313 70314 70315 70316 70317 70318 70319 70320 70321 70322 70323 70324 70325 70326 70327 70328 70329 70330 70331 70332 70333 70334 70335 70336 70337 70338 70339 70340 70341 70342 70343 70344 70345 70346 70347 70348 70349 70350 70351 70352 70353 70354 70355 70356 70357 70358 70359 70360 70361 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 70414 70415 70416 70417 70418 70419 70420 70421 70422 70423 70424 70425 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 70476 70477 70478 70479 70480 70481 70482 70483 70484 70485 70486 70487 70488 70489 70490 70491 70492 70493 70494 70495 70496 70497 70498 70499 70500 70501 70502 70503 70504 70505 70506 70507 70508 70509 70510 70511 70512 70513 70514 70515 70516 70517 70518 70519 70520 70521 70522 70523 70524 70525 70526 70527 70528 70529 70530 70531 70532 70533 70534 70535 70536 70537 70538 70539 70540 70541 70542 70543 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 70616 70617 70618 70619 70620 70621 70622 70623 70624 70625 70626 70627 70628 70629 70630 70631 70632 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 70952 70953 70954 70955 70956 70957 70958 70959 70960 70961 70962 70963 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 70990 70991 70992 70993 70994 70995 70996 70997 70998 70999 71000 71001 71002 71003 71004 71005 71006 71007 71008 71009 71010 71011 71012 71013 71014 71015 71016 71017 71018 71019 71020 71021 71022 71023 71024 71025 71026 71027 71028 71029 71030 71031 71032 71033 71034 71035 71036 71037 71038 71039 71040 71041 71042 71043 71044 71045 71046 71047 71048 71049 71050 71051 71052 71053 71054 71055 71056 71057 71058 71059 71060 71061 71062 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 71161 71162 71163 71164 71165 71166 71167 71168 71169 71170 71171 71172 71173 71174 71175 71176 71177 71178 71179 71180 71181 71182 71183 71184 | sqlite3_mutex_leave(db->mutex); return rc; } #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ /************** End of vdbeblob.c ********************************************/ /************** Begin file vdbesort.c ****************************************/ /* ** 2011 July 9 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code for the VdbeSorter object, used in concert with ** a VdbeCursor to sort large numbers of keys (as may be required, for ** example, by CREATE INDEX statements on tables too large to fit in main ** 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 ** to allow the caller to extract keys from the sorter in sorted order, ** all PMAs currently stored on disk must be merged together. This comment ** describes the data structure used to do so. The structure supports ** merging any number of arrays in a single pass with no redundant comparison ** operations. ** ** The aIter[] array contains an iterator for each of the PMAs being merged. ** An aIter[] iterator either points to a valid key or else is at EOF. For ** the purposes of the paragraphs below, we assume that the array is actually ** N elements in size, where N is the smallest power of 2 greater to or equal ** to the number of iterators being merged. The extra aIter[] elements are ** treated as if they are empty (always at EOF). ** ** The aTree[] array is also N elements in size. The value of N is stored in ** the VdbeSorter.nTree variable. ** ** The final (N/2) elements of aTree[] contain the results of comparing ** pairs of iterator keys together. Element i contains the result of ** comparing aIter[2*i-N] and aIter[2*i-N+1]. Whichever key is smaller, the ** aTree element is set to the index of it. ** ** For the purposes of this comparison, EOF is considered greater than any ** other key value. If the keys are equal (only possible with two EOF ** values), it doesn't matter which index is stored. ** ** The (N/4) elements of aTree[] that preceed the final (N/2) described ** above contains the index of the smallest of each block of 4 iterators. ** And so on. So that aTree[1] contains the index of the iterator that ** currently points to the smallest key value. aTree[0] is unused. ** ** Example: ** ** aIter[0] -> Banana ** aIter[1] -> Feijoa ** aIter[2] -> Elderberry ** aIter[3] -> Currant ** aIter[4] -> Grapefruit ** aIter[5] -> Apple ** aIter[6] -> Durian ** aIter[7] -> EOF ** ** aTree[] = { X, 5 0, 5 0, 3, 5, 6 } ** ** The current element is "Apple" (the value of the key indicated by ** iterator 5). When the Next() operation is invoked, iterator 5 will ** be advanced to the next key in its segment. Say the next key is ** "Eggplant": ** ** aIter[5] -> Eggplant ** ** The contents of aTree[] are updated first by comparing the new iterator ** 5 key to the current key of iterator 4 (still "Grapefruit"). The iterator ** 5 value is still smaller, so aTree[6] is set to 5. And so on up the tree. ** The value of iterator 6 - "Durian" - is now smaller than that of iterator ** 5, so aTree[3] is set to 6. Key 0 is smaller than key 6 (Banana<Durian), ** so the value written into element 1 of the array is 0. As follows: ** ** 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 */ char *aSpace; /* Space for UnpackRecord() */ int nSpace; /* Size of aSpace in bytes */ }; /* ** 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 /* ** Free all memory belonging to the VdbeSorterIter object passed as the second ** argument. All structure fields are set to zero before returning. */ static void vdbeSorterIterZero(sqlite3 *db, VdbeSorterIter *pIter){ sqlite3DbFree(db, pIter->aAlloc); memset(pIter, 0, sizeof(VdbeSorterIter)); } /* ** Advance iterator pIter to the next key in its PMA. Return SQLITE_OK if ** no error occurs, or an SQLite error code if one does. */ 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 */ nRead = pIter->iEof - pIter->iReadOff; if( nRead>5 ) nRead = 5; 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; } /* ** Write a single varint, value iVal, to file-descriptor pFile. Return ** SQLITE_OK if successful, or an SQLite error code if some error occurs. ** ** The value of *piOffset when this function is called is used as the byte ** offset in file pFile to write to. Before returning, *piOffset is ** incremented by the number of bytes written. */ static int vdbeSorterWriteVarint( sqlite3_file *pFile, /* File to write to */ i64 iVal, /* Value to write as a varint */ i64 *piOffset /* IN/OUT: Write offset in file pFile */ ){ u8 aVarint[9]; /* Buffer large enough for a varint */ int nVarint; /* Number of used bytes in varint */ int rc; /* Result of write() call */ nVarint = sqlite3PutVarint(aVarint, iVal); rc = sqlite3OsWrite(pFile, aVarint, nVarint, *piOffset); *piOffset += nVarint; return rc; } /* ** Read a single varint from file-descriptor pFile. Return SQLITE_OK if ** successful, or an SQLite error code if some error occurs. ** ** The value of *piOffset when this function is called is used as the ** byte offset in file pFile from whence to read the varint. If successful ** (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; } /* ** Initialize iterator pIter to scan through the PMA stored in file pFile ** starting at offset iStart and ending at offset iEof-1. This function ** leaves the iterator pointing to the first key in the PMA (or EOF if the ** PMA is empty). */ static int vdbeSorterIterInit( sqlite3 *db, /* Database handle */ VdbeSorter *pSorter, /* Sorter object */ i64 iStart, /* Start offset in pFile */ VdbeSorterIter *pIter, /* Iterator to populate */ i64 *pnByte /* IN/OUT: Increment this value by PMA size */ ){ int rc; assert( pSorter->iWriteOff>iStart ); assert( pIter->aAlloc==0 ); 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 int 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; char *aSpace = pSorter->aSpace; int nSpace = pSorter->nSpace; UnpackedRecord *r2; int i; if( aSpace==0 ){ nSpace = ROUND8(sizeof(UnpackedRecord))+(pKeyInfo->nField+1)*sizeof(Mem); aSpace = (char *)sqlite3Malloc(nSpace); if( aSpace==0 ) return SQLITE_NOMEM; pSorter->aSpace = aSpace; pSorter->nSpace = nSpace; } if( pKey2 ){ /* This call cannot fail. As the memory is already allocated. */ r2 = sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, aSpace, nSpace); assert( r2 && (r2->flags & UNPACKED_NEED_FREE)==0 ); assert( r2==(UnpackedRecord*)aSpace ); }else{ r2 = (UnpackedRecord *)aSpace; assert( !bOmitRowid ); } if( bOmitRowid ){ for(i=0; i<r2->nField-1; i++){ if( r2->aMem[i].flags & MEM_Null ){ *pRes = -1; return SQLITE_OK; } } r2->flags |= UNPACKED_PREFIX_MATCH; r2->nField--; assert( r2->nField>0 ); } *pRes = sqlite3VdbeRecordCompare(nKey1, pKey1, r2); return SQLITE_OK; } /* ** 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; int i1; int i2; int iRes; VdbeSorterIter *p1; VdbeSorterIter *p2; assert( iOut<pSorter->nTree && iOut>0 ); if( iOut>=(pSorter->nTree/2) ){ i1 = (iOut - pSorter->nTree/2) * 2; i2 = i1 + 1; }else{ i1 = pSorter->aTree[iOut*2]; i2 = pSorter->aTree[iOut*2+1]; } p1 = &pSorter->aIter[i1]; p2 = &pSorter->aIter[i2]; if( p1->pFile==0 ){ iRes = i2; }else if( p2->pFile==0 ){ iRes = i1; }else{ int res; int rc; assert( pCsr->pSorter->aSpace!=0 ); /* allocated in vdbeSorterMerge() */ rc = vdbeSorterCompare( pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res ); /* The vdbeSorterCompare() call cannot fail since pCsr->pSorter->aSpace ** has already been allocated. */ assert( rc==SQLITE_OK ); 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 */ assert( pCsr->pKeyInfo && pCsr->pBt==0 ); pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter)); if( pSorter==0 ){ return SQLITE_NOMEM; } 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); sqlite3_free(pSorter->aSpace); 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 ); } /* ** Attemp to merge the two sorted lists p1 and p2 into a single list. If no ** error occurs set *ppOut to the head of the new list and return SQLITE_OK. */ static int vdbeSorterMerge( sqlite3 *db, /* Database handle */ VdbeCursor *pCsr, /* For pKeyInfo */ SorterRecord *p1, /* First list to merge */ SorterRecord *p2, /* Second list to merge */ SorterRecord **ppOut /* OUT: Head of merged list */ ){ int rc = SQLITE_OK; SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; void *pVal2 = p2 ? p2->pVal : 0; while( p1 && p2 ){ int res; rc = vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res); if( rc!=SQLITE_OK ){ *pp = 0; vdbeSorterRecordFree(db, p1); vdbeSorterRecordFree(db, p2); vdbeSorterRecordFree(db, pFinal); *ppOut = 0; return rc; } 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; return SQLITE_OK; } /* ** 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(sqlite3 *db, VdbeCursor *pCsr){ int rc = SQLITE_OK; 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; rc==SQLITE_OK && aSlot[i]; i++){ rc = vdbeSorterMerge(db, pCsr, p, aSlot[i], &p); aSlot[i] = 0; } if( rc!=SQLITE_OK ){ vdbeSorterRecordFree(db, pNext); break; } aSlot[i] = p; p = pNext; } p = 0; for(i=0; i<64; i++){ if( rc==SQLITE_OK ){ rc = vdbeSorterMerge(db, pCsr, p, aSlot[i], &p); }else{ vdbeSorterRecordFree(db, aSlot[i]); } } pSorter->pRecord = p; sqlite3_free(aSlot); return rc; } /* ** 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(db, 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); } *pnByte = nByte; return rc; } /* ** Once the sorter has been populated, this function is called to prepare ** for iterating through its contents in sorted order. */ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *db, VdbeCursor *pCsr, int *pbEof){ VdbeSorter *pSorter = pCsr->pSorter; int rc; /* Return code */ sqlite3_file *pTemp2 = 0; /* Second temp file to use */ 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(db, 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)); pSorter->aIter = (VdbeSorterIter *)sqlite3DbMallocZero(db, nByte); if( !pSorter->aIter ) return SQLITE_NOMEM; pSorter->aTree = (int *)&pSorter->aIter[N]; pSorter->nTree = N; do { int iNew; /* Index of new, merged, PMA */ for(iNew=0; rc==SQLITE_OK && iNew*SORTER_MAX_MERGE_COUNT<pSorter->nPMA; iNew++ ){ i64 nWrite; /* Number of bytes in new PMA */ /* If there are SORTER_MAX_MERGE_COUNT or less PMAs in file pTemp1, ** initialize an iterator for each of them and break out of the loop. ** These iterators will be incrementally merged as the VDBE layer calls ** sqlite3VdbeSorterNext(). ** ** Otherwise, if pTemp1 contains more than SORTER_MAX_MERGE_COUNT PMAs, ** initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs ** are merged into a single PMA that is written to file pTemp2. */ rc = vdbeSorterInitMerge(db, pCsr, &nWrite); assert( rc!=SQLITE_OK || pSorter->aIter[ pSorter->aTree[1] ].pFile ); if( rc!=SQLITE_OK || pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ break; } /* Open the second temp file, if it is not already open. */ if( pTemp2==0 ){ assert( iWrite2==0 ); rc = vdbeSorterOpenTempFile(db, &pTemp2); } if( rc==SQLITE_OK ){ rc = vdbeSorterWriteVarint(pTemp2, nWrite, &iWrite2); } if( rc==SQLITE_OK ){ int bEof = 0; while( rc==SQLITE_OK && bEof==0 ){ int nToWrite; VdbeSorterIter *pIter = &pSorter->aIter[ pSorter->aTree[1] ]; assert( pIter->pFile ); nToWrite = pIter->nKey + sqlite3VarintLen(pIter->nKey); rc = sqlite3OsWrite(pTemp2, pIter->aAlloc, nToWrite, iWrite2); iWrite2 += nToWrite; if( rc==SQLITE_OK ){ rc = sqlite3VdbeSorterNext(db, pCsr, &bEof); } } } } if( pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){ break; }else{ sqlite3_file *pTmp = pSorter->pTemp1; pSorter->nPMA = iNew; pSorter->pTemp1 = pTemp2; pTemp2 = pTmp; pSorter->iWriteOff = iWrite2; pSorter->iReadOff = 0; iWrite2 = 0; } }while( rc==SQLITE_OK ); if( pTemp2 ){ sqlite3OsCloseFree(pTemp2); } *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); return rc; } /* ** 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 */ ){ int rc; VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); rc = vdbeSorterCompare(pCsr, 1, pVal->z, pVal->n, pKey, nKey, pRes); assert( rc!=SQLITE_OK || pVal->db->mallocFailed || (*pRes)<=0 ); return rc; } #endif /* #ifndef SQLITE_OMIT_MERGE_SORT */ /************** End of vdbesort.c ********************************************/ /************** Begin file journal.c *****************************************/ /* ** 2007 August 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** |
︙ | ︙ | |||
70070 70071 70072 70073 70074 70075 70076 70077 70078 70079 70080 70081 70082 70083 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for walking the parser tree for ** an SQL statement. */ /* ** Walk an expression tree. Invoke the callback once for each node ** of the expression, while decending. (In other words, the callback ** is invoked before visiting children.) ** | > > | 71687 71688 71689 71690 71691 71692 71693 71694 71695 71696 71697 71698 71699 71700 71701 71702 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for walking the parser tree for ** an SQL statement. */ /* #include <stdlib.h> */ /* #include <string.h> */ /* ** Walk an expression tree. Invoke the callback once for each node ** of the expression, while decending. (In other words, the callback ** is invoked before visiting children.) ** |
︙ | ︙ | |||
70208 70209 70210 70211 70212 70213 70214 70215 70216 70217 70218 70219 70220 70221 | ** ************************************************************************* ** ** This file contains routines used for walking the parser tree and ** resolve all identifiers by associating them with a particular ** table and column. */ /* ** Turn the pExpr expression into an alias for the iCol-th column of the ** result set in pEList. ** ** If the result set column is a simple column reference, then this routine ** makes an exact copy. But for any other kind of expression, this | > > | 71827 71828 71829 71830 71831 71832 71833 71834 71835 71836 71837 71838 71839 71840 71841 71842 | ** ************************************************************************* ** ** This file contains routines used for walking the parser tree and ** resolve all identifiers by associating them with a particular ** table and column. */ /* #include <stdlib.h> */ /* #include <string.h> */ /* ** Turn the pExpr expression into an alias for the iCol-th column of the ** result set in pEList. ** ** If the result set column is a simple column reference, then this routine ** makes an exact copy. But for any other kind of expression, this |
︙ | ︙ | |||
73698 73699 73700 73701 73702 73703 73704 | 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 ){ | | | 75319 75320 75321 75322 75323 75324 75325 75326 75327 75328 75329 75330 75331 75332 75333 | 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 ){ |
︙ | ︙ | |||
76010 76011 76012 76013 76014 76015 76016 | ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 77631 77632 77633 77634 77635 77636 77637 77638 77639 77640 77641 77642 77643 77644 | ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. */ #ifndef SQLITE_OMIT_ANALYZE /* ** This routine generates code that opens the sqlite_stat1 table for ** writing with cursor iStatCur. If the library was built with the ** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is |
︙ | ︙ | |||
76131 76132 76133 76134 76135 76136 76137 | const char *zWhereType /* Either "tbl" or "idx" */ ){ static const struct { const char *zName; const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, | | < < < < | < < < < < < < < < < < < < | 77662 77663 77664 77665 77666 77667 77668 77669 77670 77671 77672 77673 77674 77675 77676 77677 77678 77679 77680 77681 77682 77683 77684 77685 77686 77687 77688 77689 77690 77691 77692 | const char *zWhereType /* Either "tbl" or "idx" */ ){ static const struct { const char *zName; const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, #ifdef SQLITE_ENABLE_STAT2 { "sqlite_stat2", "tbl,idx,sampleno,sample" }, #endif }; int aRoot[] = {0, 0}; u8 aCreateTbl[] = {0, 0}; int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; for(i=0; i<ArraySize(aTable); i++){ const char *zTab = aTable[i].zName; Table *pStat; if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){ /* The sqlite_stat[12] table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important |
︙ | ︙ | |||
76195 76196 76197 76198 76199 76200 76201 | }else{ /* The sqlite_stat[12] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); } } } | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 77709 77710 77711 77712 77713 77714 77715 77716 77717 77718 77719 77720 77721 77722 77723 77724 77725 77726 77727 77728 77729 | }else{ /* The sqlite_stat[12] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); } } } /* Open the sqlite_stat[12] tables for writing. */ for(i=0; i<ArraySize(aTable); i++){ sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb); sqlite3VdbeChangeP4(v, -1, (char *)3, P4_INT32); sqlite3VdbeChangeP5(v, aCreateTbl[i]); } } /* ** Generate code to do an analysis of all indices associated with ** a single table. */ static void analyzeOneTable( Parse *pParse, /* Parser context */ |
︙ | ︙ | |||
76446 76447 76448 76449 76450 76451 76452 | int i; /* Loop counter */ int topOfLoop; /* The top of the loop */ int endOfLoop; /* The end of the loop */ int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ | < < < < < < < < | < < < < < < < | | > > > > > > > > | 77739 77740 77741 77742 77743 77744 77745 77746 77747 77748 77749 77750 77751 77752 77753 77754 77755 77756 77757 77758 77759 77760 77761 77762 77763 77764 77765 77766 | int i; /* Loop counter */ int topOfLoop; /* The top of the loop */ int endOfLoop; /* The end of the loop */ int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regSampleno = iMem++; /* Register containing next sample number */ int regCol = iMem++; /* Content of a column analyzed table */ int regRec = iMem++; /* Register holding completed record */ int regTemp = iMem++; /* Temporary use register */ int regRowid = iMem++; /* Rowid for the inserted record */ #ifdef SQLITE_ENABLE_STAT2 int addr = 0; /* Instruction address */ int regTemp2 = iMem++; /* Temporary use register */ int regSamplerecno = iMem++; /* Index of next sample to record */ int regRecno = iMem++; /* Current sample index */ int regLast = iMem++; /* Index of last sample to record */ int regFirst = iMem++; /* Index of first sample to record */ #endif v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ return; } if( pTab->tnum==0 ){ /* Do not gather statistics on views or virtual tables */ |
︙ | ︙ | |||
76499 76500 76501 76502 76503 76504 76505 | sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); iIdxCur = pParse->nTab++; sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol; KeyInfo *pKey; | < < < < < | | | > > | > > > | | | > > > | > > > > > | | | < < | | 77785 77786 77787 77788 77789 77790 77791 77792 77793 77794 77795 77796 77797 77798 77799 77800 77801 77802 77803 77804 77805 77806 77807 77808 77809 77810 77811 77812 77813 77814 77815 77816 77817 77818 77819 77820 77821 77822 77823 77824 77825 77826 77827 77828 77829 77830 77831 77832 77833 77834 77835 77836 77837 77838 77839 77840 | sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); iIdxCur = pParse->nTab++; sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol; KeyInfo *pKey; if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; nCol = pIdx->nColumn; pKey = sqlite3IndexKeyinfo(pParse, pIdx); if( iMem+1+(nCol*2)>pParse->nMem ){ pParse->nMem = iMem+1+(nCol*2); } /* Open a cursor to the index to be analyzed. */ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); /* Populate the register containing the index name. */ sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0); #ifdef SQLITE_ENABLE_STAT2 /* If this iteration of the loop is generating code to analyze the ** first index in the pTab->pIndex list, then register regLast has ** not been populated. In this case populate it now. */ if( pTab->pIndex==pIdx ){ sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES, regSamplerecno); sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES*2-1, regTemp); sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES*2, regTemp2); sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regLast); sqlite3VdbeAddOp2(v, OP_Null, 0, regFirst); addr = sqlite3VdbeAddOp3(v, OP_Lt, regSamplerecno, 0, regLast); sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regLast, regFirst); sqlite3VdbeAddOp3(v, OP_Multiply, regLast, regTemp, regLast); sqlite3VdbeAddOp2(v, OP_AddImm, regLast, SQLITE_INDEX_SAMPLES*2-2); sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regLast, regLast); sqlite3VdbeJumpHere(v, addr); } /* Zero the regSampleno and regRecno registers. */ sqlite3VdbeAddOp2(v, OP_Integer, 0, regSampleno); sqlite3VdbeAddOp2(v, OP_Integer, 0, regRecno); sqlite3VdbeAddOp2(v, OP_Copy, regFirst, regSamplerecno); #endif /* The block of memory cells initialized here is used as follows. ** ** iMem: ** The total number of rows in the table. ** ** iMem+1 .. iMem+nCol: |
︙ | ︙ | |||
76564 76565 76566 76567 76568 76569 76570 | } /* Start the analysis loop. This loop runs through all the entries in ** the index b-tree. */ endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < < < < < | > > > > > | | | < < < < < < < < < > < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | < | 77856 77857 77858 77859 77860 77861 77862 77863 77864 77865 77866 77867 77868 77869 77870 77871 77872 77873 77874 77875 77876 77877 77878 77879 77880 77881 77882 77883 77884 77885 77886 77887 77888 77889 77890 77891 77892 77893 77894 77895 77896 77897 77898 77899 77900 77901 77902 77903 77904 77905 77906 77907 77908 77909 77910 77911 77912 77913 77914 77915 77916 77917 77918 77919 77920 77921 77922 77923 77924 77925 77926 77927 77928 77929 77930 77931 77932 77933 77934 77935 77936 77937 77938 77939 77940 77941 77942 77943 77944 77945 77946 77947 77948 77949 77950 77951 77952 77953 77954 77955 77956 77957 77958 77959 77960 77961 77962 77963 77964 77965 77966 77967 77968 77969 77970 77971 77972 77973 77974 77975 77976 77977 77978 77979 77980 77981 77982 77983 77984 77985 77986 77987 77988 77989 77990 77991 77992 77993 77994 77995 77996 77997 | } /* Start the analysis loop. This loop runs through all the entries in ** the index b-tree. */ endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1); for(i=0; i<nCol; i++){ CollSeq *pColl; sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol); if( i==0 ){ #ifdef SQLITE_ENABLE_STAT2 /* Check if the record that cursor iIdxCur points to contains a ** value that should be stored in the sqlite_stat2 table. If so, ** store it. */ int ne = sqlite3VdbeAddOp3(v, OP_Ne, regRecno, 0, regSamplerecno); assert( regTabname+1==regIdxname && regTabname+2==regSampleno && regTabname+3==regCol ); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 4, regRec, "aaab", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regRec, regRowid); /* Calculate new values for regSamplerecno and regSampleno. ** ** sampleno = sampleno + 1 ** samplerecno = samplerecno+(remaining records)/(remaining samples) */ sqlite3VdbeAddOp2(v, OP_AddImm, regSampleno, 1); sqlite3VdbeAddOp3(v, OP_Subtract, regRecno, regLast, regTemp); sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1); sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES, regTemp2); sqlite3VdbeAddOp3(v, OP_Subtract, regSampleno, regTemp2, regTemp2); sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regTemp, regTemp); sqlite3VdbeAddOp3(v, OP_Add, regSamplerecno, regTemp, regSamplerecno); sqlite3VdbeJumpHere(v, ne); sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1); #endif /* Always record the very first row */ sqlite3VdbeAddOp1(v, OP_IfNot, iMem+1); } assert( pIdx->azColl!=0 ); assert( pIdx->azColl[i]!=0 ); pColl = sqlite3LocateCollSeq(pParse, pIdx->azColl[i]); sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1, (char*)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); } if( db->mallocFailed ){ /* If a malloc failure has occurred, then the result of the expression ** passed as the second argument to the call to sqlite3VdbeJumpHere() ** below may be negative. Which causes an assert() to fail (or an ** out-of-bounds write if SQLITE_DEBUG is not defined). */ return; } sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop); for(i=0; i<nCol; i++){ int addr2 = sqlite3VdbeCurrentAddr(v) - (nCol*2); if( i==0 ){ sqlite3VdbeJumpHere(v, addr2-1); /* Set jump dest for the OP_IfNot */ } sqlite3VdbeJumpHere(v, addr2); /* Set jump dest for the OP_Ne */ sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1); } /* End of the analysis loop. */ sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); /* Store the results in sqlite_stat1. ** ** The result is a single row of the sqlite_stat1 table. The first ** two columns are the names of the table and index. The third column ** is a string composed of a list of integer statistics about the ** index. The first integer in the list is the total number of entries ** in the index. There is one additional integer in the list for each ** column of the table. This additional integer is a guess of how many ** rows of the table the index will select. If D is the count of distinct ** values and K is the total number of rows, then the integer is computed ** as: ** ** I = (K+D-1)/D ** ** If K==0 then no entry is made into the sqlite_stat1 table. ** If K>0 then it is always the case the D>0 so division by zero ** is never possible. */ sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno); if( jZeroRows<0 ){ jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); } for(i=0; i<nCol; i++){ sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno); sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp); sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1); sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp); sqlite3VdbeAddOp1(v, OP_ToInt, regTemp); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno); } sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); } /* If the table has no indices, create a single sqlite_stat1 entry ** containing NULL as the index name and the row count as the content. */ if( pTab->pIndex==0 ){ sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb); VdbeComment((v, "%s", pTab->zName)); sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regSampleno); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regSampleno); }else{ sqlite3VdbeJumpHere(v, jZeroRows); jZeroRows = sqlite3VdbeAddOp0(v, OP_Goto); } sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); if( pParse->nMem<regRec ) pParse->nMem = regRec; sqlite3VdbeJumpHere(v, jZeroRows); } /* ** Generate code that will cause the most recent index analysis to ** be loaded into internal hash tables where is can be used. */ static void loadAnalysis(Parse *pParse, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); |
︙ | ︙ | |||
76725 76726 76727 76728 76729 76730 76731 | Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; | | | 78008 78009 78010 78011 78012 78013 78014 78015 78016 78017 78018 78019 78020 78021 78022 | Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 2; openStatTable(pParse, iDb, iStatCur, 0, 0); iMem = pParse->nMem+1; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); analyzeOneTable(pParse, pTab, 0, iStatCur, iMem); } |
︙ | ︙ | |||
76750 76751 76752 76753 76754 76755 76756 | int iStatCur; assert( pTab!=0 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; | | | 78033 78034 78035 78036 78037 78038 78039 78040 78041 78042 78043 78044 78045 78046 78047 | int iStatCur; assert( pTab!=0 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 2; if( pOnlyIdx ){ openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx"); }else{ openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl"); } analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem+1); loadAnalysis(pParse, iDb); |
︙ | ︙ | |||
76855 76856 76857 76858 76859 76860 76861 | ** the table. */ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ analysisInfo *pInfo = (analysisInfo*)pData; Index *pIndex; Table *pTable; int i, c, n; | | | 78138 78139 78140 78141 78142 78143 78144 78145 78146 78147 78148 78149 78150 78151 78152 | ** the table. */ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ analysisInfo *pInfo = (analysisInfo*)pData; Index *pIndex; Table *pTable; int i, c, n; unsigned int v; const char *z; assert( argc==3 ); UNUSED_PARAMETER2(NotUsed, argc); if( argv==0 || argv[0]==0 || argv[2]==0 ){ return 0; |
︙ | ︙ | |||
76898 76899 76900 76901 76902 76903 76904 | } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | 78181 78182 78183 78184 78185 78186 78187 78188 78189 78190 78191 78192 78193 78194 78195 78196 78197 78198 78199 78200 78201 78202 78203 78204 78205 78206 78207 78208 78209 78210 78211 78212 78213 78214 78215 78216 78217 78218 78219 78220 78221 78222 78223 78224 | } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ #ifdef SQLITE_ENABLE_STAT2 if( pIdx->aSample ){ int j; for(j=0; j<SQLITE_INDEX_SAMPLES; j++){ IndexSample *p = &pIdx->aSample[j]; if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){ sqlite3DbFree(db, p->u.z); } } sqlite3DbFree(db, pIdx->aSample); } #else UNUSED_PARAMETER(db); UNUSED_PARAMETER(pIdx); #endif } /* ** Load the content of the sqlite_stat1 and sqlite_stat2 tables. The ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] ** arrays. The contents of sqlite_stat2 are used to populate the ** Index.aSample[] arrays. ** ** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR ** is returned. In this case, even if SQLITE_ENABLE_STAT2 was defined ** during compilation and the sqlite_stat2 table is present, no data is ** read from it. ** ** If SQLITE_ENABLE_STAT2 was defined during compilation and the ** sqlite_stat2 table is not present in the database, SQLITE_ERROR is ** returned. However, in this case, data is read from the sqlite_stat1 ** table (if it is present) before returning. ** ** If an OOM error occurs, this function always sets db->mallocFailed. ** This means if the caller does not care about other errors, the return ** code may be ignored. */ |
︙ | ︙ | |||
77081 77082 77083 77084 77085 77086 77087 | assert( db->aDb[iDb].pBt!=0 ); /* Clear any prior statistics */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3DefaultRowEst(pIdx); | < < | | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 78232 78233 78234 78235 78236 78237 78238 78239 78240 78241 78242 78243 78244 78245 78246 78247 78248 78249 78250 78251 78252 78253 78254 78255 78256 78257 78258 78259 78260 78261 78262 78263 78264 78265 78266 78267 78268 78269 78270 78271 78272 78273 78274 78275 78276 78277 78278 78279 78280 78281 78282 78283 78284 78285 78286 78287 78288 78289 78290 78291 78292 78293 78294 78295 78296 78297 78298 78299 78300 78301 78302 78303 78304 78305 78306 78307 78308 78309 78310 78311 78312 78313 78314 78315 78316 78317 78318 78319 78320 78321 78322 78323 78324 78325 78326 78327 78328 78329 78330 78331 78332 78333 78334 78335 78336 78337 78338 78339 | assert( db->aDb[iDb].pBt!=0 ); /* Clear any prior statistics */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3DefaultRowEst(pIdx); sqlite3DeleteIndexSamples(db, pIdx); pIdx->aSample = 0; } /* Check to make sure the sqlite_stat1 table exists */ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zName; if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ return SQLITE_ERROR; } /* Load new statistics out of the sqlite_stat1 table */ zSql = sqlite3MPrintf(db, "SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); sqlite3DbFree(db, zSql); } /* Load the statistics from the sqlite_stat2 table. */ #ifdef SQLITE_ENABLE_STAT2 if( rc==SQLITE_OK && !sqlite3FindTable(db, "sqlite_stat2", sInfo.zDatabase) ){ rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ sqlite3_stmt *pStmt = 0; zSql = sqlite3MPrintf(db, "SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase); if( !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); sqlite3DbFree(db, zSql); } if( rc==SQLITE_OK ){ while( sqlite3_step(pStmt)==SQLITE_ROW ){ char *zIndex; /* Index name */ Index *pIdx; /* Pointer to the index object */ zIndex = (char *)sqlite3_column_text(pStmt, 0); pIdx = zIndex ? sqlite3FindIndex(db, zIndex, sInfo.zDatabase) : 0; if( pIdx ){ int iSample = sqlite3_column_int(pStmt, 1); if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){ int eType = sqlite3_column_type(pStmt, 2); if( pIdx->aSample==0 ){ static const int sz = sizeof(IndexSample)*SQLITE_INDEX_SAMPLES; pIdx->aSample = (IndexSample *)sqlite3DbMallocRaw(0, sz); if( pIdx->aSample==0 ){ db->mallocFailed = 1; break; } memset(pIdx->aSample, 0, sz); } assert( pIdx->aSample ); { IndexSample *pSample = &pIdx->aSample[iSample]; pSample->eType = (u8)eType; if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ pSample->u.r = sqlite3_column_double(pStmt, 2); }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ const char *z = (const char *)( (eType==SQLITE_BLOB) ? sqlite3_column_blob(pStmt, 2): sqlite3_column_text(pStmt, 2) ); int n = sqlite3_column_bytes(pStmt, 2); if( n>24 ){ n = 24; } pSample->nByte = (u8)n; if( n < 1){ pSample->u.z = 0; }else{ pSample->u.z = sqlite3DbStrNDup(0, z, n); if( pSample->u.z==0 ){ db->mallocFailed = 1; break; } } } } } } } rc = sqlite3_finalize(pStmt); } } #endif if( rc==SQLITE_NOMEM ){ db->mallocFailed = 1; } return rc; |
︙ | ︙ | |||
79608 79609 79610 79611 79612 79613 79614 | int noErr /* Suppress error messages if VIEW already exists */ ){ Table *p; int n; const char *z; Token sEnd; DbFixer sFix; | | | 80825 80826 80827 80828 80829 80830 80831 80832 80833 80834 80835 80836 80837 80838 80839 | int noErr /* Suppress error messages if VIEW already exists */ ){ Table *p; int n; const char *z; Token sEnd; DbFixer sFix; Token *pName = 0; int iDb; sqlite3 *db = pParse->db; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); sqlite3SelectDelete(db, pSelect); return; |
︙ | ︙ | |||
79924 79925 79926 79927 79928 79929 79930 | */ static void sqlite3ClearStatTables( Parse *pParse, /* The parsing context */ int iDb, /* The database number */ const char *zType, /* "idx" or "tbl" */ const char *zName /* Name of index or table */ ){ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 81141 81142 81143 81144 81145 81146 81147 81148 81149 81150 81151 81152 81153 81154 81155 81156 81157 81158 81159 81160 81161 81162 81163 81164 81165 | */ static void sqlite3ClearStatTables( Parse *pParse, /* The parsing context */ int iDb, /* The database number */ const char *zType, /* "idx" or "tbl" */ const char *zName /* Name of index or table */ ){ static const char *azStatTab[] = { "sqlite_stat1", "sqlite_stat2" }; int i; const char *zDbName = pParse->db->aDb[iDb].zName; for(i=0; i<ArraySize(azStatTab); i++){ if( sqlite3FindTable(pParse->db, azStatTab[i], zDbName) ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", zDbName, azStatTab[i], zType, zName ); } } } /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. */ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ |
︙ | ︙ | |||
80080 80081 80082 80083 80084 80085 80086 | goto exit_drop_table; } if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } } #endif | | | 81222 81223 81224 81225 81226 81227 81228 81229 81230 81231 81232 81233 81234 81235 81236 | goto exit_drop_table; } if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } } #endif if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; } #ifndef SQLITE_OMIT_VIEW /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used ** on a table. |
︙ | ︙ | |||
80104 80105 80106 80107 80108 80109 80110 80111 80112 | #endif /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3FkDropTable(pParse, pName, pTab); | > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > | 81246 81247 81248 81249 81250 81251 81252 81253 81254 81255 81256 81257 81258 81259 81260 81261 81262 81263 81264 81265 81266 81267 81268 81269 81270 81271 81272 81273 81274 81275 81276 81277 81278 81279 81280 81281 81282 81283 81284 81285 81286 81287 81288 81289 81290 81291 81292 81293 81294 81295 81296 81297 81298 81299 81300 81301 81302 81303 81304 81305 81306 81307 81308 81309 81310 81311 81312 81313 81314 81315 81316 81317 81318 81319 81320 81321 | #endif /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ Trigger *pTrigger; Db *pDb = &db->aDb[iDb]; sqlite3BeginWriteOperation(pParse, 1, iDb); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VdbeAddOp0(v, OP_VBegin); } #endif sqlite3FkDropTable(pParse, pName, pTab); /* Drop all triggers associated with the table being dropped. Code ** is generated to remove entries from sqlite_master and/or ** sqlite_temp_master if required. */ pTrigger = sqlite3TriggerList(pParse, pTab); while( pTrigger ){ assert( pTrigger->pSchema==pTab->pSchema || pTrigger->pSchema==db->aDb[1].pSchema ); sqlite3DropTriggerPtr(pParse, pTrigger); pTrigger = pTrigger->pNext; } #ifndef SQLITE_OMIT_AUTOINCREMENT /* Remove any entries of the sqlite_sequence table associated with ** the table being dropped. This is done before the table is dropped ** at the btree level, in case the sqlite_sequence table needs to ** move as a result of the drop (can happen in auto-vacuum mode). */ if( pTab->tabFlags & TF_Autoincrement ){ sqlite3NestedParse(pParse, "DELETE FROM %s.sqlite_sequence WHERE name=%Q", pDb->zName, pTab->zName ); } #endif /* Drop all SQLITE_MASTER table and index entries that refer to the ** table. The program name loops through the master table and deletes ** every row that refers to a table of the same name as the one being ** dropped. Triggers are handled seperately because a trigger can be ** created in the temp database that refers to a table in another ** database. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); if( !isView && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ if( IsVirtual(pTab) ){ sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); } sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); sqlite3ChangeCookie(pParse, iDb); } sqliteViewResetAll(db, iDb); exit_drop_table: sqlite3SrcListDelete(db, pName); } /* ** This routine is called to create a new foreign key on the table |
︙ | ︙ | |||
80276 80277 80278 80279 80280 80281 80282 80283 80284 80285 80286 80287 80288 80289 80290 | ** the index already exists and must be cleared before being refilled and ** the root page number of the index is taken from pIndex->tnum. */ 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 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); | > > | 81475 81476 81477 81478 81479 81480 81481 81482 81483 81484 81485 81486 81487 81488 81489 81490 81491 | ** the index already exists and must be cleared before being refilled and ** the root page number of the index is taken from pIndex->tnum. */ 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); |
︙ | ︙ | |||
80309 80310 80311 80312 80313 80314 80315 80316 80317 80318 80319 80320 80321 80322 80323 80324 80325 80326 80327 80328 80329 80330 80331 80332 80333 80334 80335 80336 80337 | } pKey = sqlite3IndexKeyinfo(pParse, pIndex); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); if( memRootPage>=0 ){ sqlite3VdbeChangeP5(v, 1); } sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); regRecord = sqlite3GetTempReg(pParse); regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1); 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); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > | 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 81559 81560 81561 81562 81563 81564 81565 81566 81567 81568 81569 81570 81571 81572 81573 81574 81575 81576 81577 81578 81579 81580 81581 81582 81583 81584 81585 81586 | } 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); } /* ** Create a new index for an SQL table. pName1.pName2 is the name of the index ** and pTblList is the name of the table that is to be indexed. Both will ** be NULL for a primary key or an index that is created to satisfy a ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable |
︙ | ︙ | |||
80555 80556 80557 80558 80559 80560 80561 | /* ** Allocate the index structure. */ nName = sqlite3Strlen30(zName); nCol = pList->nExpr; pIndex = sqlite3DbMallocZero(db, sizeof(Index) + /* Index structure */ | < > < | > | | 81790 81791 81792 81793 81794 81795 81796 81797 81798 81799 81800 81801 81802 81803 81804 81805 81806 81807 81808 81809 81810 81811 81812 81813 81814 81815 81816 81817 | /* ** Allocate the index structure. */ nName = sqlite3Strlen30(zName); nCol = pList->nExpr; pIndex = sqlite3DbMallocZero(db, sizeof(Index) + /* Index structure */ sizeof(int)*nCol + /* Index.aiColumn */ sizeof(int)*(nCol+1) + /* Index.aiRowEst */ sizeof(char *)*nCol + /* Index.azColl */ sizeof(u8)*nCol + /* Index.aSortOrder */ nName + 1 + /* Index.zName */ nExtra /* Collation sequence names */ ); if( db->mallocFailed ){ goto exit_create_index; } pIndex->azColl = (char**)(&pIndex[1]); pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]); pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]); pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]); pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]); zExtra = (char *)(&pIndex->zName[nName+1]); memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->nColumn = pList->nExpr; pIndex->onError = (u8)onError; pIndex->autoIndex = (u8)(pName==0); |
︙ | ︙ | |||
80845 80846 80847 80848 80849 80850 80851 | ** aiRowEst[N]>=1 ** ** Apart from that, we have little to go on besides intuition as to ** how aiRowEst[] should be initialized. The numbers generated here ** are based on typical values found in actual indices. */ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ | | | | 82080 82081 82082 82083 82084 82085 82086 82087 82088 82089 82090 82091 82092 82093 82094 82095 82096 | ** aiRowEst[N]>=1 ** ** Apart from that, we have little to go on besides intuition as to ** how aiRowEst[] should be initialized. The numbers generated here ** are based on typical values found in actual indices. */ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ unsigned *a = pIdx->aiRowEst; int i; unsigned n; assert( a!=0 ); a[0] = pIdx->pTable->nRowEst; if( a[0]<10 ) a[0] = 10; n = 10; for(i=1; i<=pIdx->nColumn; i++){ a[i] = n; if( n>5 ) n--; |
︙ | ︙ | |||
81291 81292 81293 81294 81295 81296 81297 | ** A natural cross join B ** ** The operator is "natural cross join". The A and B operands are stored ** in p->a[0] and p->a[1], respectively. The parser initially stores the ** operator with A. This routine shifts that operator over to B. */ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){ | | > | 82526 82527 82528 82529 82530 82531 82532 82533 82534 82535 82536 82537 82538 82539 82540 82541 82542 | ** A natural cross join B ** ** The operator is "natural cross join". The A and B operands are stored ** in p->a[0] and p->a[1], respectively. The parser initially stores the ** operator with A. This routine shifts that operator over to B. */ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){ if( p ){ int i; assert( p->a || p->nSrc==0 ); for(i=p->nSrc-1; i>0; i--){ p->a[i].jointype = p->a[i-1].jointype; } p->a[0].jointype = 0; } } |
︙ | ︙ | |||
82848 82849 82850 82851 82852 82853 82854 82855 82856 82857 82858 82859 82860 82861 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. */ /* ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ return context->pColl; } | > > | 84084 84085 84086 84087 84088 84089 84090 84091 84092 84093 84094 84095 84096 84097 84098 84099 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. */ /* #include <stdlib.h> */ /* #include <assert.h> */ /* ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ return context->pColl; } |
︙ | ︙ | |||
85171 85172 85173 85174 85175 85176 85177 85178 85179 85180 85181 85182 85183 85184 85185 | ** early. */ if( pParse->disableTriggers ){ pTo = sqlite3FindTable(db, pFKey->zTo, zDb); }else{ pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); } if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( pFKey->nCol==1 || (aiFree && pIdx) ); if( aiFree ){ aiCol = aiFree; }else{ | > > > > > > > > > > > > > > > > > | 86409 86410 86411 86412 86413 86414 86415 86416 86417 86418 86419 86420 86421 86422 86423 86424 86425 86426 86427 86428 86429 86430 86431 86432 86433 86434 86435 86436 86437 86438 86439 86440 | ** early. */ if( pParse->disableTriggers ){ pTo = sqlite3FindTable(db, pFKey->zTo, zDb); }else{ pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); } if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); if( !isIgnoreErrors || db->mallocFailed ) return; if( pTo==0 ){ /* If isIgnoreErrors is true, then a table is being dropped. In this ** case SQLite runs a "DELETE FROM xxx" on the table being dropped ** before actually dropping it in order to check FK constraints. ** If the parent table of an FK constraint on the current table is ** missing, behave as if it is empty. i.e. decrement the relevant ** FK counter for each row of the current table with non-NULL keys. */ Vdbe *v = sqlite3GetVdbe(pParse); int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; for(i=0; i<pFKey->nCol; i++){ int iReg = pFKey->aCol[i].iFrom + regOld + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); } continue; } assert( pFKey->nCol==1 || (aiFree && pIdx) ); if( aiFree ){ aiCol = aiFree; }else{ |
︙ | ︙ | |||
88079 88080 88081 88082 88083 88084 88085 88086 88087 88088 88089 88090 88091 88092 | #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #endif /* _SQLITE3EXT_H_ */ /************** End of sqlite3ext.h ******************************************/ /************** Continuing where we left off in loadext.c ********************/ #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer ** for any missing APIs. | > | 89334 89335 89336 89337 89338 89339 89340 89341 89342 89343 89344 89345 89346 89347 89348 | #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #endif /* _SQLITE3EXT_H_ */ /************** End of sqlite3ext.h ******************************************/ /************** Continuing where we left off in loadext.c ********************/ /* #include <string.h> */ #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer ** for any missing APIs. |
︙ | ︙ | |||
91525 91526 91527 91528 91529 91530 91531 91532 91533 91534 91535 91536 | 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); | > > > > > > | | 92781 92782 92783 92784 92785 92786 92787 92788 92789 92790 92791 92792 92793 92794 92795 92796 92797 92798 92799 92800 92801 92802 92803 92804 92805 92806 | 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; |
︙ | ︙ | |||
91999 92000 92001 92002 92003 92004 92005 | if( eDest==SRT_Output || eDest==SRT_Coroutine ){ pseudoTab = pParse->nTab++; sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn); regRowid = 0; }else{ regRowid = sqlite3GetTempReg(pParse); } | > > > > > > > > > > | | | > | 93261 93262 93263 93264 93265 93266 93267 93268 93269 93270 93271 93272 93273 93274 93275 93276 93277 93278 93279 93280 93281 93282 93283 93284 93285 93286 93287 93288 | 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); |
︙ | ︙ | |||
92054 92055 92056 92057 92058 92059 92060 | } sqlite3ReleaseTempReg(pParse, regRow); sqlite3ReleaseTempReg(pParse, regRowid); /* The bottom of the loop */ sqlite3VdbeResolveLabel(v, addrContinue); | > > > | > | 93327 93328 93329 93330 93331 93332 93333 93334 93335 93336 93337 93338 93339 93340 93341 93342 93343 93344 93345 | } 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); } } /* |
︙ | ︙ | |||
95020 95021 95022 95023 95024 95025 95026 95027 95028 95029 95030 95031 95032 95033 | } /* 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); | > > > > | 96297 96298 96299 96300 96301 96302 96303 96304 96305 96306 96307 96308 96309 96310 96311 96312 96313 96314 | } /* 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); |
︙ | ︙ | |||
95055 95056 95057 95058 95059 95060 95061 | sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); p->addrOpenEphm[2] = -1; } if( pWInfo->eDistinct ){ VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ | | | 96336 96337 96338 96339 96340 96341 96342 96343 96344 96345 96346 96347 96348 96349 96350 | sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); 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; |
︙ | ︙ | |||
95114 95115 95116 95117 95118 95119 95120 95121 95122 95123 95124 95125 95126 95127 | 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 */ | > > | 96395 96396 96397 96398 96399 96400 96401 96402 96403 96404 96405 96406 96407 96408 96409 96410 | 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 */ |
︙ | ︙ | |||
95175 95176 95177 95178 95179 95180 95181 | 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 | | | | 96458 96459 96460 96461 96462 96463 96464 96465 96466 96467 96468 96469 96470 96471 96472 96473 96474 96475 96476 96477 | 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; |
︙ | ︙ | |||
95261 95262 95263 95264 95265 95266 95267 | sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1); } j++; } } regRecord = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); | | > > > | > > > | > | 96544 96545 96546 96547 96548 96549 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 | 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); |
︙ | ︙ | |||
95319 95320 95321 95322 95323 95324 95325 | updateAccumulator(pParse, &sAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); /* End of the loop */ if( groupBySort ){ | | | 96609 96610 96611 96612 96613 96614 96615 96616 96617 96618 96619 96620 96621 96622 96623 | 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, 1); } /* Output the final row of result */ |
︙ | ︙ | |||
95648 95649 95650 95651 95652 95653 95654 95655 95656 95657 95658 95659 95660 95661 | ** This file contains the sqlite3_get_table() and sqlite3_free_table() ** interface routines. These are just wrappers around the main ** interface routine of sqlite3_exec(). ** ** These routines are in a separate files so that they will not be linked ** if they are not used. */ #ifndef SQLITE_OMIT_GET_TABLE /* ** This structure is used to pass data from sqlite3_get_table() through ** to the callback function is uses to build the result. */ | > > | 96938 96939 96940 96941 96942 96943 96944 96945 96946 96947 96948 96949 96950 96951 96952 96953 | ** This file contains the sqlite3_get_table() and sqlite3_free_table() ** interface routines. These are just wrappers around the main ** interface routine of sqlite3_exec(). ** ** These routines are in a separate files so that they will not be linked ** if they are not used. */ /* #include <stdlib.h> */ /* #include <string.h> */ #ifndef SQLITE_OMIT_GET_TABLE /* ** This structure is used to pass data from sqlite3_get_table() through ** to the callback function is uses to build the result. */ |
︙ | ︙ | |||
99157 99158 99159 99160 99161 99162 99163 | #define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(db, pExpr) */ #define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */ #define TERM_CODED 0x04 /* This term is already coded */ #define TERM_COPIED 0x08 /* Has a child */ #define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */ #define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */ #define TERM_OR_OK 0x40 /* Used during OR-clause processing */ | | | 100449 100450 100451 100452 100453 100454 100455 100456 100457 100458 100459 100460 100461 100462 100463 | #define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(db, pExpr) */ #define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */ #define TERM_CODED 0x04 /* This term is already coded */ #define TERM_COPIED 0x08 /* Has a child */ #define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */ #define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */ #define TERM_OR_OK 0x40 /* Used during OR-clause processing */ #ifdef SQLITE_ENABLE_STAT2 # define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ #else # define TERM_VNULL 0x00 /* Disabled if not using stat2 */ #endif /* ** An instance of the following structure holds all information about a |
︙ | ︙ | |||
100371 100372 100373 100374 100375 100376 100377 | pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ | | | 101663 101664 101665 101666 101667 101668 101669 101670 101671 101672 101673 101674 101675 101676 101677 | pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef SQLITE_ENABLE_STAT2 /* When sqlite_stat2 histogram data is available an operator of the ** form "x IS NOT NULL" can sometimes be evaluated more efficiently ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a ** virtual term of that form. ** ** Note that the virtual term must be tagged with TERM_VNULL. This ** TERM_VNULL tag will suppress the not-null check at the beginning |
︙ | ︙ | |||
100410 100411 100412 100413 100414 100415 100416 | pNewTerm->iParent = idxTerm; pTerm = &pWC->a[idxTerm]; pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } | | | 101702 101703 101704 101705 101706 101707 101708 101709 101710 101711 101712 101713 101714 101715 101716 | pNewTerm->iParent = idxTerm; pTerm = &pWC->a[idxTerm]; pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } #endif /* SQLITE_ENABLE_STAT2 */ /* Prevent ON clause terms of a LEFT JOIN from being used to drive ** an index for tables to the left of the join. */ pTerm->prereqRight |= extraRight; } |
︙ | ︙ | |||
101459 101460 101461 101462 101463 101464 101465 | /* Try to find a more efficient access pattern by using multiple indexes ** to optimize an OR expression within the WHERE clause. */ bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); } #endif /* SQLITE_OMIT_VIRTUALTABLE */ | < > | > | > > > > < < > > > > > > > > > | > | | | < < < < < < < | < | | | | | < | | | | | < < < | < | < < < < < < < < < < < < < < < < < < | | | < < < | < | < > > > > > | | | | < < | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | | | 102751 102752 102753 102754 102755 102756 102757 102758 102759 102760 102761 102762 102763 102764 102765 102766 102767 102768 102769 102770 102771 102772 102773 102774 102775 102776 102777 102778 102779 102780 102781 102782 102783 102784 102785 102786 102787 102788 102789 102790 102791 102792 102793 102794 102795 102796 102797 102798 102799 102800 102801 102802 102803 102804 102805 102806 102807 102808 102809 102810 102811 102812 102813 102814 102815 102816 102817 102818 102819 102820 102821 102822 102823 102824 102825 102826 102827 102828 102829 102830 102831 102832 102833 102834 102835 102836 102837 102838 102839 102840 102841 102842 102843 102844 102845 102846 102847 102848 102849 102850 102851 102852 102853 102854 102855 102856 102857 102858 102859 102860 102861 102862 102863 102864 102865 102866 102867 102868 102869 102870 102871 102872 102873 102874 102875 102876 102877 102878 102879 102880 102881 102882 102883 102884 102885 102886 102887 102888 102889 102890 102891 102892 102893 102894 | /* Try to find a more efficient access pattern by using multiple indexes ** to optimize an OR expression within the WHERE clause. */ bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Argument pIdx is a pointer to an index structure that has an array of ** SQLITE_INDEX_SAMPLES evenly spaced samples of the first indexed column ** stored in Index.aSample. These samples divide the domain of values stored ** the index into (SQLITE_INDEX_SAMPLES+1) regions. ** Region 0 contains all values less than the first sample value. Region ** 1 contains values between the first and second samples. Region 2 contains ** values between samples 2 and 3. And so on. Region SQLITE_INDEX_SAMPLES ** contains values larger than the last sample. ** ** If the index contains many duplicates of a single value, then it is ** possible that two or more adjacent samples can hold the same value. ** When that is the case, the smallest possible region code is returned ** when roundUp is false and the largest possible region code is returned ** when roundUp is true. ** ** If successful, this function determines which of the regions value ** pVal lies in, sets *piRegion to the region index (a value between 0 ** and SQLITE_INDEX_SAMPLES+1, inclusive) and returns SQLITE_OK. ** Or, if an OOM occurs while converting text values between encodings, ** SQLITE_NOMEM is returned and *piRegion is undefined. */ #ifdef SQLITE_ENABLE_STAT2 static int whereRangeRegion( Parse *pParse, /* Database connection */ Index *pIdx, /* Index to consider domain of */ sqlite3_value *pVal, /* Value to consider */ int roundUp, /* Return largest valid region if true */ int *piRegion /* OUT: Region of domain in which value lies */ ){ assert( roundUp==0 || roundUp==1 ); if( ALWAYS(pVal) ){ IndexSample *aSample = pIdx->aSample; int i = 0; int eType = sqlite3_value_type(pVal); if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ double r = sqlite3_value_double(pVal); for(i=0; i<SQLITE_INDEX_SAMPLES; i++){ if( aSample[i].eType==SQLITE_NULL ) continue; if( aSample[i].eType>=SQLITE_TEXT ) break; if( roundUp ){ if( aSample[i].u.r>r ) break; }else{ if( aSample[i].u.r>=r ) break; } } }else if( eType==SQLITE_NULL ){ i = 0; if( roundUp ){ while( i<SQLITE_INDEX_SAMPLES && aSample[i].eType==SQLITE_NULL ) i++; } }else{ sqlite3 *db = pParse->db; CollSeq *pColl; const u8 *z; int n; /* pVal comes from sqlite3ValueFromExpr() so the type cannot be NULL */ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); if( eType==SQLITE_BLOB ){ z = (const u8 *)sqlite3_value_blob(pVal); pColl = db->pDfltColl; assert( pColl->enc==SQLITE_UTF8 ); }else{ pColl = sqlite3GetCollSeq(db, SQLITE_UTF8, 0, *pIdx->azColl); if( pColl==0 ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", *pIdx->azColl); return SQLITE_ERROR; } z = (const u8 *)sqlite3ValueText(pVal, pColl->enc); if( !z ){ return SQLITE_NOMEM; } assert( z && pColl && pColl->xCmp ); } n = sqlite3ValueBytes(pVal, pColl->enc); for(i=0; i<SQLITE_INDEX_SAMPLES; i++){ int c; int eSampletype = aSample[i].eType; if( eSampletype==SQLITE_NULL || eSampletype<eType ) continue; if( (eSampletype!=eType) ) break; #ifndef SQLITE_OMIT_UTF16 if( pColl->enc!=SQLITE_UTF8 ){ int nSample; char *zSample = sqlite3Utf8to16( db, pColl->enc, aSample[i].u.z, aSample[i].nByte, &nSample ); if( !zSample ){ assert( db->mallocFailed ); return SQLITE_NOMEM; } c = pColl->xCmp(pColl->pUser, nSample, zSample, n, z); sqlite3DbFree(db, zSample); }else #endif { c = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z); } if( c-roundUp>=0 ) break; } } assert( i>=0 && i<=SQLITE_INDEX_SAMPLES ); *piRegion = i; } return SQLITE_OK; } #endif /* #ifdef SQLITE_ENABLE_STAT2 */ /* ** If expression pExpr represents a literal value, set *pp to point to ** an sqlite3_value structure containing the same value, with affinity ** aff applied to it, before returning. It is the responsibility of the ** caller to eventually release this structure by passing it to ** sqlite3ValueFree(). ** ** If the current parse is a recompile (sqlite3Reprepare()) and pExpr ** is an SQL variable that currently has a non-NULL value bound to it, ** create an sqlite3_value structure containing this value, again with ** affinity aff applied to it, instead. ** ** If neither of the above apply, set *pp to NULL. ** ** If an error occurs, return an error code. Otherwise, SQLITE_OK. */ #ifdef SQLITE_ENABLE_STAT2 static int valueFromExpr( Parse *pParse, Expr *pExpr, u8 aff, sqlite3_value **pp ){ if( pExpr->op==TK_VARIABLE |
︙ | ︙ | |||
101686 101687 101688 101689 101690 101691 101692 | ** then nEq should be passed the value 1 (as the range restricted column, ** b, is the second left-most column of the index). Or, if the query is: ** ** ... FROM t1 WHERE a > ? AND a < ? ... ** ** then nEq should be passed 0. ** | | > > | > | < | | | | | | | | > > | | | > | < < < < | < < | < < < < | | < | | > > > > > | > | > | > > | > | | > > > > | > > > > > > | | | | | > | | | > > | > > > > > | > | | | 102928 102929 102930 102931 102932 102933 102934 102935 102936 102937 102938 102939 102940 102941 102942 102943 102944 102945 102946 102947 102948 102949 102950 102951 102952 102953 102954 102955 102956 102957 102958 102959 102960 102961 102962 102963 102964 102965 102966 102967 102968 102969 102970 102971 102972 102973 102974 102975 102976 102977 102978 102979 102980 102981 102982 102983 102984 102985 102986 102987 102988 102989 102990 102991 102992 102993 102994 102995 102996 102997 102998 102999 103000 103001 103002 103003 103004 103005 103006 103007 103008 103009 103010 103011 103012 103013 103014 103015 103016 103017 103018 103019 103020 103021 103022 103023 103024 103025 103026 103027 103028 103029 103030 103031 103032 103033 103034 103035 103036 103037 103038 103039 103040 103041 103042 103043 103044 103045 103046 103047 103048 103049 103050 103051 103052 103053 103054 103055 103056 103057 103058 103059 103060 103061 103062 103063 103064 103065 103066 103067 103068 103069 103070 103071 103072 103073 103074 103075 103076 103077 103078 103079 103080 103081 103082 103083 103084 103085 103086 103087 103088 103089 103090 | ** then nEq should be passed the value 1 (as the range restricted column, ** b, is the second left-most column of the index). Or, if the query is: ** ** ... FROM t1 WHERE a > ? AND a < ? ... ** ** then nEq should be passed 0. ** ** The returned value is an integer between 1 and 100, inclusive. A return ** value of 1 indicates that the proposed range scan is expected to visit ** approximately 1/100th (1%) of the rows selected by the nEq equality ** constraints (if any). A return value of 100 indicates that it is expected ** that the range scan will visit every row (100%) selected by the equality ** constraints. ** ** In the absence of sqlite_stat2 ANALYZE data, each range inequality ** reduces the search space by 3/4ths. Hence a single constraint (x>?) ** results in a return of 25 and a range constraint (x>? AND x<?) results ** in a return of 6. */ static int whereRangeScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index containing the range-compared column; "x" */ int nEq, /* index into p->aCol[] of the range-compared column */ WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ int *piEst /* OUT: Return value */ ){ int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_STAT2 if( nEq==0 && p->aSample ){ sqlite3_value *pLowerVal = 0; sqlite3_value *pUpperVal = 0; int iEst; int iLower = 0; int iUpper = SQLITE_INDEX_SAMPLES; int roundUpUpper = 0; int roundUpLower = 0; u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pLower ){ Expr *pExpr = pLower->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pLowerVal); assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE ); roundUpLower = (pLower->eOperator==WO_GT) ?1:0; } if( rc==SQLITE_OK && pUpper ){ Expr *pExpr = pUpper->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pUpperVal); assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE ); roundUpUpper = (pUpper->eOperator==WO_LE) ?1:0; } if( rc!=SQLITE_OK || (pLowerVal==0 && pUpperVal==0) ){ sqlite3ValueFree(pLowerVal); sqlite3ValueFree(pUpperVal); goto range_est_fallback; }else if( pLowerVal==0 ){ rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper); if( pLower ) iLower = iUpper/2; }else if( pUpperVal==0 ){ rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower); if( pUpper ) iUpper = (iLower + SQLITE_INDEX_SAMPLES + 1)/2; }else{ rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper); if( rc==SQLITE_OK ){ rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower); } } WHERETRACE(("range scan regions: %d..%d\n", iLower, iUpper)); iEst = iUpper - iLower; testcase( iEst==SQLITE_INDEX_SAMPLES ); assert( iEst<=SQLITE_INDEX_SAMPLES ); if( iEst<1 ){ *piEst = 50/SQLITE_INDEX_SAMPLES; }else{ *piEst = (iEst*100)/SQLITE_INDEX_SAMPLES; } sqlite3ValueFree(pLowerVal); sqlite3ValueFree(pUpperVal); return rc; } range_est_fallback: #else UNUSED_PARAMETER(pParse); UNUSED_PARAMETER(p); UNUSED_PARAMETER(nEq); #endif assert( pLower || pUpper ); *piEst = 100; if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *piEst /= 4; if( pUpper ) *piEst /= 4; return rc; } #ifdef SQLITE_ENABLE_STAT2 /* ** Estimate the number of rows that will be returned based on ** an equality constraint x=VALUE and where that VALUE occurs in ** the histogram data. This only works when x is the left-most ** column of an index and sqlite_stat2 histogram data is available ** for that index. When pExpr==NULL that means the constraint is ** "x IS NULL" instead of "x=VALUE". ** ** Write the estimated row count into *pnRow and return SQLITE_OK. ** If unable to make an estimate, leave *pnRow unchanged and return ** non-zero. ** ** This routine can fail if it is unable to load a collating sequence ** required for string comparison, or if unable to allocate memory ** for a UTF conversion required for comparison. The error is stored ** in the pParse structure. */ static int whereEqualScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ double *pnRow /* Write the revised row estimate here */ ){ sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */ int iLower, iUpper; /* Range of histogram regions containing pRhs */ u8 aff; /* Column affinity */ int rc; /* Subfunction return code */ double nRowEst; /* New estimate of the number of rows */ assert( p->aSample!=0 ); aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pExpr ){ rc = valueFromExpr(pParse, pExpr, aff, &pRhs); if( rc ) goto whereEqualScanEst_cancel; }else{ pRhs = sqlite3ValueNew(pParse->db); } if( pRhs==0 ) return SQLITE_NOTFOUND; rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower); if( rc ) goto whereEqualScanEst_cancel; rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper); if( rc ) goto whereEqualScanEst_cancel; WHERETRACE(("equality scan regions: %d..%d\n", iLower, iUpper)); if( iLower>=iUpper ){ nRowEst = p->aiRowEst[0]/(SQLITE_INDEX_SAMPLES*2); if( nRowEst<*pnRow ) *pnRow = nRowEst; }else{ nRowEst = (iUpper-iLower)*p->aiRowEst[0]/SQLITE_INDEX_SAMPLES; *pnRow = nRowEst; } whereEqualScanEst_cancel: sqlite3ValueFree(pRhs); return rc; } #endif /* defined(SQLITE_ENABLE_STAT2) */ #ifdef SQLITE_ENABLE_STAT2 /* ** Estimate the number of rows that will be returned based on ** an IN constraint where the right-hand side of the IN operator ** is a list of values. Example: ** ** WHERE x IN (1,2,3,4) ** |
︙ | ︙ | |||
101834 101835 101836 101837 101838 101839 101840 | */ static int whereInScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ double *pnRow /* Write the revised row estimate here */ ){ | > > > | < | > > > | > > > > > | < > | > > > > > > > > > | > > > > | > > > > > > > > > > | > > | | 103099 103100 103101 103102 103103 103104 103105 103106 103107 103108 103109 103110 103111 103112 103113 103114 103115 103116 103117 103118 103119 103120 103121 103122 103123 103124 103125 103126 103127 103128 103129 103130 103131 103132 103133 103134 103135 103136 103137 103138 103139 103140 103141 103142 103143 103144 103145 103146 103147 103148 103149 103150 103151 103152 103153 103154 103155 103156 103157 103158 103159 103160 103161 103162 103163 103164 103165 103166 | */ static int whereInScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index whose left-most column is pTerm */ ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ double *pnRow /* Write the revised row estimate here */ ){ sqlite3_value *pVal = 0; /* One value from list */ int iLower, iUpper; /* Range of histogram regions containing pRhs */ u8 aff; /* Column affinity */ int rc = SQLITE_OK; /* Subfunction return code */ double nRowEst; /* New estimate of the number of rows */ int nSpan = 0; /* Number of histogram regions spanned */ int nSingle = 0; /* Histogram regions hit by a single value */ int nNotFound = 0; /* Count of values that are not constants */ int i; /* Loop counter */ u8 aSpan[SQLITE_INDEX_SAMPLES+1]; /* Histogram regions that are spanned */ u8 aSingle[SQLITE_INDEX_SAMPLES+1]; /* Histogram regions hit once */ assert( p->aSample!=0 ); aff = p->pTable->aCol[p->aiColumn[0]].affinity; memset(aSpan, 0, sizeof(aSpan)); memset(aSingle, 0, sizeof(aSingle)); for(i=0; i<pList->nExpr; i++){ sqlite3ValueFree(pVal); rc = valueFromExpr(pParse, pList->a[i].pExpr, aff, &pVal); if( rc ) break; if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){ nNotFound++; continue; } rc = whereRangeRegion(pParse, p, pVal, 0, &iLower); if( rc ) break; rc = whereRangeRegion(pParse, p, pVal, 1, &iUpper); if( rc ) break; if( iLower>=iUpper ){ aSingle[iLower] = 1; }else{ assert( iLower>=0 && iUpper<=SQLITE_INDEX_SAMPLES ); while( iLower<iUpper ) aSpan[iLower++] = 1; } } if( rc==SQLITE_OK ){ for(i=nSpan=0; i<=SQLITE_INDEX_SAMPLES; i++){ if( aSpan[i] ){ nSpan++; }else if( aSingle[i] ){ nSingle++; } } nRowEst = (nSpan*2+nSingle)*p->aiRowEst[0]/(2*SQLITE_INDEX_SAMPLES) + nNotFound*p->aiRowEst[1]; if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0]; *pnRow = nRowEst; WHERETRACE(("IN row estimate: nSpan=%d, nSingle=%d, nNotFound=%d, est=%g\n", nSpan, nSingle, nNotFound, nRowEst)); } sqlite3ValueFree(pVal); return rc; } #endif /* defined(SQLITE_ENABLE_STAT2) */ /* ** Find the best query plan for accessing a particular table. Write the ** best query plan and its cost into the WhereCost object supplied as the ** last parameter. ** |
︙ | ︙ | |||
101899 101900 101901 101902 101903 101904 101905 | ){ int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ Index *pProbe; /* An index we are evaluating */ Index *pIdx; /* Copy of pProbe, or zero for IPK index */ int eqTermMask; /* Current mask of valid equality operators */ int idxEqTermMask; /* Index mask of valid equality operators */ Index sPk; /* A fake index object for the primary key */ | | | 103199 103200 103201 103202 103203 103204 103205 103206 103207 103208 103209 103210 103211 103212 103213 | ){ int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ Index *pProbe; /* An index we are evaluating */ Index *pIdx; /* Copy of pProbe, or zero for IPK index */ int eqTermMask; /* Current mask of valid equality operators */ int idxEqTermMask; /* Index mask of valid equality operators */ Index sPk; /* A fake index object for the primary key */ unsigned int aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ int wsFlagMask; /* Allowed flags in pCost->plan.wsFlag */ /* Initialize the cost to a worst-case value */ memset(pCost, 0, sizeof(*pCost)); pCost->rCost = SQLITE_BIG_DBL; |
︙ | ︙ | |||
101954 101955 101956 101957 101958 101959 101960 | eqTermMask = WO_EQ|WO_IN; pIdx = 0; } /* Loop over all indices looking for the best one to use */ for(; pProbe; pIdx=pProbe=pProbe->pNext){ | | | 103254 103255 103256 103257 103258 103259 103260 103261 103262 103263 103264 103265 103266 103267 103268 | eqTermMask = WO_EQ|WO_IN; pIdx = 0; } /* Loop over all indices looking for the best one to use */ for(; pProbe; pIdx=pProbe=pProbe->pNext){ const unsigned int * const aiRowEst = pProbe->aiRowEst; double cost; /* Cost of using pProbe */ double nRow; /* Estimated number of rows in result set */ double log10N; /* base-10 logarithm of nRow (inexact) */ int rev; /* True to scan in reverse order */ int wsFlags = 0; Bitmask used = 0; |
︙ | ︙ | |||
101997 101998 101999 102000 102001 102002 102003 | ** ** bInEst: ** Set to true if there was at least one "x IN (SELECT ...)" term used ** in determining the value of nInMul. Note that the RHS of the ** IN operator must be a SELECT, not a value list, for this variable ** to be true. ** | | | > > | | < | > | 103297 103298 103299 103300 103301 103302 103303 103304 103305 103306 103307 103308 103309 103310 103311 103312 103313 103314 103315 103316 103317 103318 | ** ** bInEst: ** Set to true if there was at least one "x IN (SELECT ...)" term used ** in determining the value of nInMul. Note that the RHS of the ** IN operator must be a SELECT, not a value list, for this variable ** to be true. ** ** estBound: ** An estimate on the amount of the table that must be searched. A ** value of 100 means the entire table is searched. Range constraints ** might reduce this to a value less than 100 to indicate that only ** a fraction of the table needs searching. In the absence of ** sqlite_stat2 ANALYZE data, a single inequality reduces the search ** space to 1/4rd its original size. So an x>? constraint reduces ** estBound to 25. Two constraints (x>? AND x<?) reduce estBound to 6. ** ** bSort: ** Boolean. True if there is an ORDER BY clause that will require an ** external sort (i.e. scanning the index being evaluated will not ** correctly order records). ** ** bLookup: |
︙ | ︙ | |||
102027 102028 102029 102030 102031 102032 102033 | ** ** SELECT a, b FROM tbl WHERE a = 1; ** SELECT a, b, c FROM tbl WHERE a = 1; */ int nEq; /* Number of == or IN terms matching index */ int bInEst = 0; /* True if "x IN (SELECT...)" seen */ int nInMul = 1; /* Number of distinct equalities to lookup */ | | | | 103329 103330 103331 103332 103333 103334 103335 103336 103337 103338 103339 103340 103341 103342 103343 103344 103345 103346 103347 103348 103349 | ** ** SELECT a, b FROM tbl WHERE a = 1; ** SELECT a, b, c FROM tbl WHERE a = 1; */ int nEq; /* Number of == or IN terms matching index */ int bInEst = 0; /* True if "x IN (SELECT...)" seen */ int nInMul = 1; /* Number of distinct equalities to lookup */ int estBound = 100; /* Estimated reduction in search space */ int nBound = 0; /* Number of range constraints seen */ int bSort = !!pOrderBy; /* True if external sort required */ int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */ int bLookup = 0; /* True if not a covering index */ WhereTerm *pTerm; /* A single term of the WHERE clause */ #ifdef SQLITE_ENABLE_STAT2 WhereTerm *pFirstTerm = 0; /* First term matching the index */ #endif /* Determine the values of nEq and nInMul */ for(nEq=0; nEq<pProbe->nColumn; nEq++){ int j = pProbe->aiColumn[nEq]; pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx); |
︙ | ︙ | |||
102057 102058 102059 102060 102061 102062 102063 | }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nInMul *= pExpr->x.pList->nExpr; } }else if( pTerm->eOperator & WO_ISNULL ){ wsFlags |= WHERE_COLUMN_NULL; } | | | | | 103359 103360 103361 103362 103363 103364 103365 103366 103367 103368 103369 103370 103371 103372 103373 103374 103375 103376 103377 103378 103379 103380 103381 103382 103383 103384 103385 | }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nInMul *= pExpr->x.pList->nExpr; } }else if( pTerm->eOperator & WO_ISNULL ){ wsFlags |= WHERE_COLUMN_NULL; } #ifdef SQLITE_ENABLE_STAT2 if( nEq==0 && pProbe->aSample ) pFirstTerm = pTerm; #endif used |= pTerm->prereqRight; } /* Determine the value of estBound. */ if( nEq<pProbe->nColumn && pProbe->bUnordered==0 ){ int j = pProbe->aiColumn[nEq]; if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx); whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound); if( pTop ){ nBound = 1; wsFlags |= WHERE_TOP_LIMIT; used |= pTop->prereqRight; } if( pBtm ){ nBound++; |
︙ | ︙ | |||
102141 102142 102143 102144 102145 102146 102147 | */ nRow = (double)(aiRowEst[nEq] * nInMul); if( bInEst && nRow*2>aiRowEst[0] ){ nRow = aiRowEst[0]/2; nInMul = (int)(nRow / aiRowEst[nEq]); } | | | | | 103443 103444 103445 103446 103447 103448 103449 103450 103451 103452 103453 103454 103455 103456 103457 103458 103459 103460 103461 103462 103463 103464 103465 103466 103467 103468 103469 103470 103471 103472 103473 103474 103475 103476 103477 103478 | */ nRow = (double)(aiRowEst[nEq] * nInMul); if( bInEst && nRow*2>aiRowEst[0] ){ nRow = aiRowEst[0]/2; nInMul = (int)(nRow / aiRowEst[nEq]); } #ifdef SQLITE_ENABLE_STAT2 /* If the constraint is of the form x=VALUE or x IN (E1,E2,...) ** and we do not think that values of x are unique and if histogram ** data is available for column x, then it might be possible ** to get a better estimate on the number of rows based on ** VALUE and how common that value is according to the histogram. */ if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){ if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ testcase( pFirstTerm->eOperator==WO_EQ ); testcase( pFirstTerm->eOperator==WO_ISNULL ); whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow); }else if( pFirstTerm->eOperator==WO_IN && bInEst==0 ){ whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow); } } #endif /* SQLITE_ENABLE_STAT2 */ /* Adjust the number of output rows and downward to reflect rows ** that are excluded by range constraints. */ nRow = (nRow * (double)estBound) / (double)100; if( nRow<1 ) nRow = 1; /* Experiments run on real SQLite databases show that the time needed ** to do a binary search to locate a row in a table or index is roughly ** log10(N) times the time to move from one row to the next row within ** a table or index. The actual times can vary, with the size of ** records being an important factor. Both moves and searches are |
︙ | ︙ | |||
102291 102292 102293 102294 102295 102296 102297 | } } if( nRow<2 ) nRow = 2; } WHERETRACE(( | | | | 103593 103594 103595 103596 103597 103598 103599 103600 103601 103602 103603 103604 103605 103606 103607 103608 103609 103610 | } } if( nRow<2 ) nRow = 2; } WHERETRACE(( "%s(%s): nEq=%d nInMul=%d estBound=%d bSort=%d bLookup=%d wsFlags=0x%x\n" " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n", pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"), nEq, nInMul, estBound, bSort, bLookup, wsFlags, notReady, log10N, nRow, cost, used )); /* If this index is the best we have seen so far, then record this ** index and its cost in the pCost structure. */ if( (!pIdx || wsFlags) |
︙ | ︙ | |||
104225 104226 104227 104228 104229 104230 104231 104232 104233 104234 104235 104236 104237 104238 | ** The only modifications are the addition of a couple of NEVER() ** macros to disable tests that are needed in the case of a general ** LALR(1) grammar but which are always false in the ** specific grammar used by SQLite. */ /* First off, code is included that follows the "include" declaration ** in the input grammar file. */ /* ** Disable all error recovery processing in the parser push-down ** automaton. */ #define YYNOERRORRECOVERY 1 | > | 105527 105528 105529 105530 105531 105532 105533 105534 105535 105536 105537 105538 105539 105540 105541 | ** The only modifications are the addition of a couple of NEVER() ** macros to disable tests that are needed in the case of a general ** LALR(1) grammar but which are always false in the ** specific grammar used by SQLite. */ /* First off, code is included that follows the "include" declaration ** in the input grammar file. */ /* #include <stdio.h> */ /* ** Disable all error recovery processing in the parser push-down ** automaton. */ #define YYNOERRORRECOVERY 1 |
︙ | ︙ | |||
105085 105086 105087 105088 105089 105090 105091 105092 105093 105094 105095 105096 105097 105098 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG /* ** Turn parser tracing on by giving a stream to which to write the trace | > | 106388 106389 106390 106391 106392 106393 106394 106395 106396 106397 106398 106399 106400 106401 106402 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG /* #include <stdio.h> */ static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG /* ** Turn parser tracing on by giving a stream to which to write the trace |
︙ | ︙ | |||
107660 107661 107662 107663 107664 107665 107666 107667 107668 107669 107670 107671 107672 107673 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. */ /* ** The charMap() macro maps alphabetic characters into their ** lower-case ASCII equivalent. On ASCII machines, this is just ** an upper-to-lower case map. On EBCDIC machines we also need ** to adjust the encoding. Only alphabetic characters and underscores ** need to be translated. | > | 108964 108965 108966 108967 108968 108969 108970 108971 108972 108973 108974 108975 108976 108977 108978 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. */ /* #include <stdlib.h> */ /* ** The charMap() macro maps alphabetic characters into their ** lower-case ASCII equivalent. On ASCII machines, this is just ** an upper-to-lower case map. On EBCDIC machines we also need ** to adjust the encoding. Only alphabetic characters and underscores ** need to be translated. |
︙ | ︙ | |||
109051 109052 109053 109054 109055 109056 109057 109058 109059 109060 109061 109062 109063 109064 | assert(sizeof(x)==8); assert(sizeof(x)==sizeof(y)); memcpy(&y, &x, 8); assert( sqlite3IsNaN(y) ); } #endif #endif return rc; } /* ** Undo the effects of sqlite3_initialize(). Must not be called while ** there are outstanding database connections or memory allocations or | > > > > > > > > > > | 110356 110357 110358 110359 110360 110361 110362 110363 110364 110365 110366 110367 110368 110369 110370 110371 110372 110373 110374 110375 110376 110377 110378 110379 | assert(sizeof(x)==8); assert(sizeof(x)==sizeof(y)); memcpy(&y, &x, 8); assert( sqlite3IsNaN(y) ); } #endif #endif /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT ** compile-time option. */ #ifdef SQLITE_EXTRA_INIT if( rc==SQLITE_OK && sqlite3GlobalConfig.isInit ){ int SQLITE_EXTRA_INIT(void); rc = SQLITE_EXTRA_INIT(); } #endif return rc; } /* ** Undo the effects of sqlite3_initialize(). Must not be called while ** there are outstanding database connections or memory allocations or |
︙ | ︙ | |||
113182 113183 113184 113185 113186 113187 113188 113189 113190 113191 113192 113193 113194 113195 | /************** Continuing where we left off in fts3.c ***********************/ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE) # define SQLITE_CORE 1 #endif #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #endif static int fts3EvalNext(Fts3Cursor *pCsr); static int fts3EvalStart(Fts3Cursor *pCsr); | > > > > > > | 114497 114498 114499 114500 114501 114502 114503 114504 114505 114506 114507 114508 114509 114510 114511 114512 114513 114514 114515 114516 | /************** Continuing where we left off in fts3.c ***********************/ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE) # define SQLITE_CORE 1 #endif /* #include <assert.h> */ /* #include <stdlib.h> */ /* #include <stddef.h> */ /* #include <stdio.h> */ /* #include <string.h> */ /* #include <stdarg.h> */ #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #endif static int fts3EvalNext(Fts3Cursor *pCsr); static int fts3EvalStart(Fts3Cursor *pCsr); |
︙ | ︙ | |||
117703 117704 117705 117706 117707 117708 117709 117710 117711 117712 117713 117714 117715 117716 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) typedef struct Fts3auxTable Fts3auxTable; typedef struct Fts3auxCursor Fts3auxCursor; struct Fts3auxTable { sqlite3_vtab base; /* Base class used by SQLite core */ Fts3Table *pFts3Tab; | > > | 119024 119025 119026 119027 119028 119029 119030 119031 119032 119033 119034 119035 119036 119037 119038 119039 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <string.h> */ /* #include <assert.h> */ typedef struct Fts3auxTable Fts3auxTable; typedef struct Fts3auxCursor Fts3auxCursor; struct Fts3auxTable { sqlite3_vtab base; /* Base class used by SQLite core */ Fts3Table *pFts3Tab; |
︙ | ︙ | |||
118241 118242 118243 118244 118245 118246 118247 118248 118249 118250 118251 118252 118253 118254 | #endif /* ** Default span for NEAR operators. */ #define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 /* ** isNot: ** This variable is used by function getNextNode(). When getNextNode() is ** called, it sets ParseContext.isNot to true if the 'next node' is a ** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the ** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to | > > | 119564 119565 119566 119567 119568 119569 119570 119571 119572 119573 119574 119575 119576 119577 119578 119579 | #endif /* ** Default span for NEAR operators. */ #define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 /* #include <string.h> */ /* #include <assert.h> */ /* ** isNot: ** This variable is used by function getNextNode(). When getNextNode() is ** called, it sets ParseContext.isNot to true if the 'next node' is a ** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the ** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to |
︙ | ︙ | |||
118942 118943 118944 118945 118946 118947 118948 118949 118950 118951 118952 118953 118954 118955 | /**************************************************************************** ***************************************************************************** ** Everything after this point is just test code. */ #ifdef SQLITE_TEST /* ** Function to query the hash-table of tokenizers (see README.tokenizers). */ static int queryTestTokenizer( sqlite3 *db, const char *zName, | > | 120267 120268 120269 120270 120271 120272 120273 120274 120275 120276 120277 120278 120279 120280 120281 | /**************************************************************************** ***************************************************************************** ** Everything after this point is just test code. */ #ifdef SQLITE_TEST /* #include <stdio.h> */ /* ** Function to query the hash-table of tokenizers (see README.tokenizers). */ static int queryTestTokenizer( sqlite3 *db, const char *zName, |
︙ | ︙ | |||
119152 119153 119154 119155 119156 119157 119158 119159 119160 119161 119162 119163 119164 119165 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* ** Malloc and Free functions */ static void *fts3HashMalloc(int n){ void *p = sqlite3_malloc(n); | > > > | 120478 120479 120480 120481 120482 120483 120484 120485 120486 120487 120488 120489 120490 120491 120492 120493 120494 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <assert.h> */ /* #include <stdlib.h> */ /* #include <string.h> */ /* ** Malloc and Free functions */ static void *fts3HashMalloc(int n){ void *p = sqlite3_malloc(n); |
︙ | ︙ | |||
119532 119533 119534 119535 119536 119537 119538 119539 119540 119541 119542 119543 119544 119545 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* ** Class derived from sqlite3_tokenizer */ typedef struct porter_tokenizer { sqlite3_tokenizer base; /* Base class */ | > > > > | 120861 120862 120863 120864 120865 120866 120867 120868 120869 120870 120871 120872 120873 120874 120875 120876 120877 120878 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <assert.h> */ /* #include <stdlib.h> */ /* #include <stdio.h> */ /* #include <string.h> */ /* ** Class derived from sqlite3_tokenizer */ typedef struct porter_tokenizer { sqlite3_tokenizer base; /* Base class */ |
︙ | ︙ | |||
120175 120176 120177 120178 120179 120180 120181 120182 120183 120184 120185 120186 120187 120188 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* ** Implementation of the SQL scalar function for accessing the underlying ** hash table. This function may be called as follows: ** ** SELECT <function-name>(<key-name>); ** SELECT <function-name>(<key-name>, <pointer>); | > > | 121508 121509 121510 121511 121512 121513 121514 121515 121516 121517 121518 121519 121520 121521 121522 121523 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <assert.h> */ /* #include <string.h> */ /* ** Implementation of the SQL scalar function for accessing the underlying ** hash table. This function may be called as follows: ** ** SELECT <function-name>(<key-name>); ** SELECT <function-name>(<key-name>, <pointer>); |
︙ | ︙ | |||
120350 120351 120352 120353 120354 120355 120356 120357 120358 120359 120360 120361 120362 120363 | sqlite3_free(zCopy); return rc; } #ifdef SQLITE_TEST /* ** Implementation of a special SQL scalar function for testing tokenizers ** designed to be used in concert with the Tcl testing framework. This ** function must be called with two arguments: ** ** SELECT <function-name>(<key-name>, <input-string>); | > > | 121685 121686 121687 121688 121689 121690 121691 121692 121693 121694 121695 121696 121697 121698 121699 121700 | sqlite3_free(zCopy); return rc; } #ifdef SQLITE_TEST /* #include <tcl.h> */ /* #include <string.h> */ /* ** Implementation of a special SQL scalar function for testing tokenizers ** designed to be used in concert with the Tcl testing framework. This ** function must be called with two arguments: ** ** SELECT <function-name>(<key-name>, <input-string>); |
︙ | ︙ | |||
120661 120662 120663 120664 120665 120666 120667 120668 120669 120670 120671 120672 120673 120674 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) typedef struct simple_tokenizer { sqlite3_tokenizer base; char delim[128]; /* flag ASCII delimiters */ } simple_tokenizer; | > > > > | 121998 121999 122000 122001 122002 122003 122004 122005 122006 122007 122008 122009 122010 122011 122012 122013 122014 122015 | ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS3 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <assert.h> */ /* #include <stdlib.h> */ /* #include <stdio.h> */ /* #include <string.h> */ typedef struct simple_tokenizer { sqlite3_tokenizer base; char delim[128]; /* flag ASCII delimiters */ } simple_tokenizer; |
︙ | ︙ | |||
120886 120887 120888 120889 120890 120891 120892 120893 120894 120895 120896 120897 120898 120899 | ** tables. It also contains code to merge FTS3 b-tree segments. Some ** of the sub-routines used to merge segments are also used by the query ** code in fts3.c. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* ** When full-text index nodes are loaded from disk, the buffer that they ** are loaded into has the following number of bytes of padding at the end ** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer ** of 920 bytes is allocated for it. ** | > > > | 122227 122228 122229 122230 122231 122232 122233 122234 122235 122236 122237 122238 122239 122240 122241 122242 122243 | ** tables. It also contains code to merge FTS3 b-tree segments. Some ** of the sub-routines used to merge segments are also used by the query ** code in fts3.c. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <string.h> */ /* #include <assert.h> */ /* #include <stdlib.h> */ /* ** When full-text index nodes are loaded from disk, the buffer that they ** are loaded into has the following number of bytes of padding at the end ** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer ** of 920 bytes is allocated for it. ** |
︙ | ︙ | |||
124147 124148 124149 124150 124151 124152 124153 124154 124155 124156 124157 124158 124159 124160 | ** May you share freely, never taking more than you give. ** ****************************************************************************** */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* ** Characters that may appear in the second argument to matchinfo(). */ #define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ #define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ #define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ | > > | 125491 125492 125493 125494 125495 125496 125497 125498 125499 125500 125501 125502 125503 125504 125505 125506 | ** May you share freely, never taking more than you give. ** ****************************************************************************** */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <string.h> */ /* #include <assert.h> */ /* ** Characters that may appear in the second argument to matchinfo(). */ #define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ #define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ #define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ |
︙ | ︙ | |||
125734 125735 125736 125737 125738 125739 125740 125741 125742 125743 125744 125745 125746 125747 | #endif #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #else #endif #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; typedef unsigned char u8; typedef unsigned int u32; #endif | > > | 127080 127081 127082 127083 127084 127085 127086 127087 127088 127089 127090 127091 127092 127093 127094 127095 | #endif #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #else #endif /* #include <string.h> */ /* #include <assert.h> */ #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; typedef unsigned char u8; typedef unsigned int u32; #endif |
︙ | ︙ | |||
128948 128949 128950 128951 128952 128953 128954 128955 128956 128957 128958 128959 128960 128961 | /* Include ICU headers */ #include <unicode/utypes.h> #include <unicode/uregex.h> #include <unicode/ustring.h> #include <unicode/ucol.h> #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #else #endif /* | > | 130296 130297 130298 130299 130300 130301 130302 130303 130304 130305 130306 130307 130308 130309 130310 | /* Include ICU headers */ #include <unicode/utypes.h> #include <unicode/uregex.h> #include <unicode/ustring.h> #include <unicode/ucol.h> /* #include <assert.h> */ #ifndef SQLITE_CORE SQLITE_EXTENSION_INIT1 #else #endif /* |
︙ | ︙ | |||
129427 129428 129429 129430 129431 129432 129433 129434 129435 129436 129437 129438 129439 129440 129441 129442 | ** ************************************************************************* ** This file implements a tokenizer for fts3 based on the ICU library. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #ifdef SQLITE_ENABLE_ICU #include <unicode/ubrk.h> #include <unicode/utf16.h> typedef struct IcuTokenizer IcuTokenizer; typedef struct IcuCursor IcuCursor; struct IcuTokenizer { sqlite3_tokenizer base; | > > > > | 130776 130777 130778 130779 130780 130781 130782 130783 130784 130785 130786 130787 130788 130789 130790 130791 130792 130793 130794 130795 | ** ************************************************************************* ** This file implements a tokenizer for fts3 based on the ICU library. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #ifdef SQLITE_ENABLE_ICU /* #include <assert.h> */ /* #include <string.h> */ #include <unicode/ubrk.h> /* #include <unicode/ucol.h> */ /* #include <unicode/ustring.h> */ #include <unicode/utf16.h> typedef struct IcuTokenizer IcuTokenizer; typedef struct IcuCursor IcuCursor; struct IcuTokenizer { sqlite3_tokenizer base; |
︙ | ︙ |
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-04 01:27:00 6b657ae75035eb10b0ad640998d3c9eadfdffa6e" /* ** 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 |
︙ | ︙ | |||
1206 1207 1208 1209 1210 1211 1212 | ** and that this object is only useful to a tiny minority of applications ** with specialized memory allocation requirements. This object is ** also used during testing of SQLite in order to specify an alternative ** memory allocator that simulates memory out-of-memory conditions in ** order to verify that SQLite recovers gracefully from such ** conditions. ** | | | < < < | < < < | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 | ** and that this object is only useful to a tiny minority of applications ** with specialized memory allocation requirements. This object is ** also used during testing of SQLite in order to specify an alternative ** memory allocator that simulates memory out-of-memory conditions in ** order to verify that SQLite recovers gracefully from such ** conditions. ** ** The xMalloc, xRealloc, and xFree methods must work like the ** malloc(), realloc() and free() functions from the standard C library. ** ^SQLite guarantees that the second argument to ** xRealloc is always a value returned by a prior call to xRoundup. ** ** xSize should return the allocated size of a memory allocation ** previously obtained from xMalloc or xRealloc. The allocated size ** is always at least as big as the requested size but may be larger. ** ** The xRoundup method returns what would be the allocated size of ** a memory allocation given a particular requested size. Most memory |
︙ | ︙ | |||
2852 2853 2854 2855 2856 2857 2858 | ** WHERE clause might influence the choice of query plan for a statement, ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column | | | 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 | ** WHERE clause might influence the choice of query plan for a statement, ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT2] compile-time option is enabled. ** the ** </li> ** </ol> */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ |
︙ | ︙ |
Changes to src/stash.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 44 45 46 | @ ); @ CREATE TABLE IF NOT EXISTS %s.stashfile( @ stashid INTEGER REFERENCES stash, -- Stash that contains this file @ rid INTEGER, -- Baseline content in BLOB table or 0. @ isAdded BOOLEAN, -- True if this is an added file @ isRemoved BOOLEAN, -- True if this file is deleted @ isExec BOOLEAN, -- True if file is executable @ origname TEXT, -- Original filename @ newname TEXT, -- New name for file at next check-in @ delta BLOB, -- Delta from baseline. Content if rid=0 @ PRIMARY KEY(origname, stashid) @ ); @ INSERT OR IGNORE INTO vvar(name, value) VALUES('stash-next', 1); ; | > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | @ ); @ CREATE TABLE IF NOT EXISTS %s.stashfile( @ stashid INTEGER REFERENCES stash, -- Stash that contains this file @ rid INTEGER, -- Baseline content in BLOB table or 0. @ isAdded BOOLEAN, -- True if this is an added file @ isRemoved BOOLEAN, -- True if this file is deleted @ isExec BOOLEAN, -- True if file is executable @ isLink BOOLEAN, -- True if file is a symlink @ origname TEXT, -- Original filename @ newname TEXT, -- New name for file at next check-in @ delta BLOB, -- Delta from baseline. Content if rid=0 @ PRIMARY KEY(origname, stashid) @ ); @ INSERT OR IGNORE INTO vvar(name, value) VALUES('stash-next', 1); ; |
︙ | ︙ | |||
59 60 61 62 63 64 65 | Stmt ins; /* Insert statement */ zFile = mprintf("%/", zFName); file_tree_name(zFile, &fname, 1); zTreename = blob_str(&fname); blob_zero(&sql); blob_appendf(&sql, | | | | | | | > > > > > > | > > > > > | > > | 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 | Stmt ins; /* Insert statement */ zFile = mprintf("%/", zFName); file_tree_name(zFile, &fname, 1); zTreename = blob_str(&fname); blob_zero(&sql); blob_appendf(&sql, "SELECT deleted, isexe, islink, mrid, pathname, coalesce(origname,pathname)" " FROM vfile" " WHERE vid=%d AND (chnged OR deleted OR origname NOT NULL OR mrid==0)", vid ); if( fossil_strcmp(zTreename,".")!=0 ){ blob_appendf(&sql, " AND (pathname GLOB '%q/*' OR origname GLOB '%q/*'" " OR pathname=%Q OR origname=%Q)", zTreename, zTreename, zTreename, zTreename ); } db_prepare(&q, blob_str(&sql)); blob_reset(&sql); db_prepare(&ins, "INSERT INTO stashfile(stashid, rid, isAdded, isRemoved, isExec, isLink," "origname, newname, delta)" "VALUES(%d,:rid,:isadd,:isrm,:isexe,:islink,:orig,:new,:content)", stashid ); 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_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); db_bind_text(&ins, ":new", zName); if( rid==0 ){ /* A new file */ if( isNewLink ){ blob_read_link(&content, zPath); }else{ blob_read_from_file(&content, zPath); } db_bind_blob(&ins, ":content", &content); }else if( deleted ){ blob_zero(&content); db_bind_null(&ins, ":content"); }else{ /* A modified file */ Blob orig; Blob disk; if( isNewLink ){ blob_read_link(&disk, zPath); }else{ blob_read_from_file(&disk, zPath); } content_get(rid, &orig); blob_delta_create(&orig, &disk, &content); blob_reset(&orig); blob_reset(&disk); db_bind_blob(&ins, ":content", &content); } db_bind_int(&ins, ":islink", isNewLink); db_step(&ins); db_reset(&ins); fossil_free(zPath); blob_reset(&content); } db_finalize(&ins); db_finalize(&q); |
︙ | ︙ | |||
165 166 167 168 169 170 171 | /* ** Apply a stash to the current check-out. */ static void stash_apply(int stashid, int nConflict){ Stmt q; db_prepare(&q, | | > | | | > | > > > | > | > > > > > > | > > > > > > > | | > | > < | > | > | | | > > > | > > | > > > | > > > > > > > | | < | | | > | | 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 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 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 335 336 337 338 | /* ** Apply a stash to the current check-out. */ static void stash_apply(int stashid, int nConflict){ Stmt q; db_prepare(&q, "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta" " FROM stashfile WHERE stashid=%d", stashid ); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); int isRemoved = db_column_int(&q, 1); int isExec = db_column_int(&q, 2); int isLink = db_column_int(&q, 3); const char *zOrig = db_column_text(&q, 4); const char *zNew = db_column_text(&q, 5); char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); 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_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_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 ){ create_symlink(blob_str(&b), zNPath); }else{ blob_write_to_file(&b, zNPath); } file_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_setexe(zNPath, isExec); } if( rc ){ fossil_print("CONFLICT %s\n", zNew); nConflict++; }else{ fossil_print("MERGE %s\n", zNew); } } blob_reset(&a); blob_reset(&b); blob_reset(&disk); } blob_reset(&delta); if( fossil_strcmp(zOrig,zNew)!=0 ){ undo_save(zOrig); file_delete(zOPath); } } db_finalize(&q); if( nConflict ){ fossil_print("WARNING: %d merge conflicts - see messages above for details.\n", nConflict); } } /* ** Show the diffs associate with a single stash. */ static void stash_diff(int stashid, const char *zDiffCmd){ Stmt q; Blob empty; blob_zero(&empty); db_prepare(&q, "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta" " FROM stashfile WHERE stashid=%d", stashid ); while( db_step(&q)==SQLITE_ROW ){ int rid = db_column_int(&q, 0); int isRemoved = db_column_int(&q, 1); int isLink = db_column_int(&q, 3); const char *zOrig = db_column_text(&q, 4); const char *zNew = db_column_text(&q, 5); char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); Blob delta; 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_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_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); if( !isOrigLink != !isLink ){ diff_print_index(zNew); printf("--- %s\n+++ %s\n", zOrig, zNew); printf("cannot compute difference between symlink and regular file\n"); }else{ content_get(rid, &a); blob_delta_apply(&a, &delta, &b); diff_file_mem(&disk, &b, zNew, zDiffCmd, 0); blob_reset(&a); blob_reset(&b); } blob_reset(&disk); } blob_reset(&delta); } db_finalize(&q); } /* ** Drop the indicated stash */ static void stash_drop(int stashid){ db_multi_exec( "DELETE FROM stash WHERE stashid=%d;" "DELETE FROM stashfile WHERE stashid=%d;", stashid, stashid ); |
︙ | ︙ | |||
343 344 345 346 347 348 349 350 351 352 353 354 355 | ** fossil stash goto ?STASHID? ** ** Update to the baseline checkout for STASHID then apply the ** changes of STASHID. Keep STASHID so that it can be reused ** This command is undoable. ** ** fossil stash drop ?STASHID? ?--all? ** ** Forget everything about STASHID. Forget the whole stash if the ** --all flag is used. Individual drops are undoable but --all is not. ** ** fossil stash snapshot ?-m COMMENT? ?FILES...? ** | > | | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | ** fossil stash goto ?STASHID? ** ** Update to the baseline checkout for STASHID then apply the ** changes of STASHID. Keep STASHID so that it can be reused ** This command is undoable. ** ** fossil stash drop ?STASHID? ?--all? ** fossil stash rm ?STASHID? ?--all? ** ** Forget everything about STASHID. Forget the whole stash if the ** --all flag is used. Individual drops are undoable but --all is not. ** ** fossil stash snapshot ?-m COMMENT? ?FILES...? ** ** Save the current changes in the working tree as a new stash ** but, unlike "save", do not revert those changes. ** ** fossil stash diff ?STASHID? ** fossil stash gdiff ?STASHID? ** ** Show diffs of the current working directory and what that ** directory would be if STASHID were applied. |
︙ | ︙ | |||
426 427 428 429 430 431 432 | fossil_print(" "); comment_print(zCom, 7, 79); } } db_finalize(&q); if( n==0 ) fossil_print("empty stash\n"); }else | | | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | fossil_print(" "); comment_print(zCom, 7, 79); } } db_finalize(&q); if( n==0 ) fossil_print("empty stash\n"); }else if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){ int allFlag = find_option("all", 0, 0)!=0; if( g.argc>4 ) usage("stash apply STASHID"); if( allFlag ){ db_multi_exec("DELETE FROM stash; DELETE FROM stashfile;"); }else{ stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); undo_begin(); |
︙ | ︙ |
Changes to src/tar.c.
︙ | ︙ | |||
278 279 280 281 282 283 284 | */ static void tar_add_header( const char *zName, /* Name of the object */ int nName, /* Number of characters in zName */ int iMode, /* Mode. 0644 or 0755 */ unsigned int mTime, /* File modification time */ int iSize, /* Size of the object in bytes */ | | > | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | */ static void tar_add_header( const char *zName, /* Name of the object */ int nName, /* Number of characters in zName */ int iMode, /* Mode. 0644 or 0755 */ unsigned int mTime, /* File modification time */ int iSize, /* Size of the object in bytes */ char cType /* Type of object: '0'==file. '2'==symlink. '5'==directory */ ){ /* set mode and modification time */ sqlite3_snprintf(8, (char*)&tball.aHdr[100], "%07o", iMode); sqlite3_snprintf(12, (char*)&tball.aHdr[136], "%011o", mTime); /* see if we need to output a Pax Interchange Header */ if( !is_iso646_name(zName, nName) |
︙ | ︙ | |||
357 358 359 360 361 362 363 | /* ** Add a single file to the growing tarball. */ static void tar_add_file( const char *zName, /* Name of the file. nul-terminated */ Blob *pContent, /* Content of the file */ | | > > > > > > > > > > > > > > > | > | 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 | /* ** Add a single file to the growing tarball. */ static void tar_add_file( const char *zName, /* Name of the file. nul-terminated */ Blob *pContent, /* Content of the file */ int mPerm, /* 1: executable file, 2: symlink */ unsigned int mTime /* Last modification time of the file */ ){ int nName = strlen(zName); int n = blob_size(pContent); int lastPage; char cType = '0'; /* length check moved to tar_split_path */ tar_add_directory_of(zName, nName, mTime); /* * If we have a symlink, write its destination path (which is stored in * pContent) into header, and set content length to 0 to avoid storing path * as file content in the next step. Since 'linkname' header is limited to * 100 bytes (-1 byte for terminating zero), if path is greater than that, * store symlink as a plain-text file. (Not sure how TAR handles long links.) */ if( mPerm == PERM_LNK && n <= 100 ){ sqlite3_snprintf(100, (char*)&tball.aHdr[157], "%s", blob_str(pContent)); cType = '2'; n = 0; } tar_add_header(zName, nName, ( mPerm==PERM_EXE ) ? 0755 : 0644, mTime, n, cType); if( n ){ gzip_step(blob_buffer(pContent), n); lastPage = n % 512; if( lastPage!=0 ){ gzip_step(tball.zSpaces, 512 - lastPage); } } |
︙ | ︙ | |||
413 414 415 416 417 418 419 | } 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, | | | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | } 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_perm(g.argv[i]), file_mtime(g.argv[i])); blob_reset(&file); } tar_finish(&zip); blob_write_to_file(&zip, g.argv[2]); } /* |
︙ | ︙ |
Changes to src/timeline.c.
︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | case 3: r = mn; g = h2, b = mx; break; case 4: r = h2; g = mn, b = mx; break; default: r = mx; g = mn, b = h2; break; } sqlite3_snprintf(8, zColor, "#%02x%02x%02x", r,g,b); return zColor; } /* ** Output a timeline in the web format given a query. The query ** should return these columns: ** ** 0. rid ** 1. UUID | > > > > > > > > > > > > > > > | 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 | case 3: r = mn; g = h2, b = mx; break; case 4: r = h2; g = mn, b = mx; break; default: r = mx; g = mn, b = h2; break; } sqlite3_snprintf(8, zColor, "#%02x%02x%02x", r,g,b); return zColor; } /* ** COMMAND: test-hash-color ** ** Usage: %fossil test-hash-color TAG ... ** ** Print out the color names associated with each tag. Used for ** testing the hash_color() function. */ void test_hash_color(void){ int i; for(i=2; i<g.argc; i++){ fossil_print("%20s: %s\n", g.argv[i], hash_color(g.argv[i])); } } /* ** Output a timeline in the web format given a query. The query ** should return these columns: ** ** 0. rid ** 1. UUID |
︙ | ︙ | |||
385 386 387 388 389 390 391 | 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)," | | > | > | | > > > > > > > | > | 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 | 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> |
︙ | ︙ | |||
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | } if( cSep=='[' ) cgi_printf("["); cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n"); } cgi_printf("var nrail = %d\n", pGraph->mxRail+1); graph_free(pGraph); @ var canvasDiv = document.getElementById("canvas"); @ var realCanvas = null; @ function drawBox(color,x0,y0,x1,y1){ @ var n = document.createElement("div"); @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } @ var w = x1-x0+1; @ var h = y1-y0+1; @ n.style.position = "absolute"; | > > | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | } if( cSep=='[' ) cgi_printf("["); cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n"); } cgi_printf("var nrail = %d\n", pGraph->mxRail+1); graph_free(pGraph); @ var canvasDiv = document.getElementById("canvas"); #if 0 @ var realCanvas = null; #endif @ function drawBox(color,x0,y0,x1,y1){ @ var n = document.createElement("div"); @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } @ var w = x1-x0+1; @ var h = y1-y0+1; @ n.style.position = "absolute"; |
︙ | ︙ | |||
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 | @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15; @ var width = nrail*20; @ for(var i in rowinfo){ @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY; @ rowinfo[i].x = left + rowinfo[i].r*20; @ } @ var btm = absoluteY("grbtm") + 10 - canvasY; @ if( btm<32768 ){ @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+ @ 'style="position:absolute;left:'+(left-5)+'px;"' + @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>'; @ realCanvas = document.getElementById('timeline-canvas'); @ }else{ @ realCanvas = 0; @ } @ var context; @ if( realCanvas && realCanvas.getContext @ && (context = realCanvas.getContext('2d'))) { @ drawBox = function(color,x0,y0,x1,y1) { @ if( y0>32767 || y1>32767 ) return; @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return; @ context.fillStyle = color; @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1); @ }; @ } @ for(var i in rowinfo){ @ drawNode(rowinfo[i], left, btm); @ } @ } @ var lastId = "m"+rowinfo[rowinfo.length-1].id; @ var lastY = 0; @ function checkHeight(){ | > > | 690 691 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 | @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15; @ var width = nrail*20; @ for(var i in rowinfo){ @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY; @ rowinfo[i].x = left + rowinfo[i].r*20; @ } @ var btm = absoluteY("grbtm") + 10 - canvasY; #if 0 @ if( btm<32768 ){ @ canvasDiv.innerHTML = '<canvas id="timeline-canvas" '+ @ 'style="position:absolute;left:'+(left-5)+'px;"' + @ ' width="'+width+'" height="'+btm+'"><'+'/canvas>'; @ realCanvas = document.getElementById('timeline-canvas'); @ }else{ @ realCanvas = 0; @ } @ var context; @ if( realCanvas && realCanvas.getContext @ && (context = realCanvas.getContext('2d'))) { @ drawBox = function(color,x0,y0,x1,y1) { @ if( y0>32767 || y1>32767 ) return; @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } @ if(isNaN(x0) || isNaN(y0) || isNaN(x1) || isNaN(y1)) return; @ context.fillStyle = color; @ context.fillRect(x0-left+5,y0,x1-x0+1,y1-y0+1); @ }; @ } #endif @ for(var i in rowinfo){ @ drawNode(rowinfo[i], left, btm); @ } @ } @ var lastId = "m"+rowinfo[rowinfo.length-1].id; @ var lastY = 0; @ function checkHeight(){ |
︙ | ︙ | |||
907 908 909 910 911 912 913 | /* 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 ){ | | | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 | /* 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"); |
︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 | ** 4. Number of non-merge children ** 5. Number of parents */ void print_timeline(Stmt *q, int mxLine, int showfiles){ int nLine = 0; char zPrevDate[20]; const char *zCurrentUuid=0; | < > | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 | ** 4. Number of non-merge children ** 5. Number of parents */ void print_timeline(Stmt *q, int mxLine, int showfiles){ int nLine = 0; char zPrevDate[20]; const char *zCurrentUuid=0; int fchngQueryInit = 0; /* True if fchngQuery is initialized */ Stmt fchngQuery; /* Query for file changes on check-ins */ zPrevDate[0] = 0; if( g.localOpen ){ int rid = db_lget_int("checkout", 0); zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); } while( db_step(q)==SQLITE_ROW && nLine<=mxLine ){ |
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 | n += strlen(zPrefix); } zFree = sqlite3_mprintf("[%.10s] %s%s", zUuid, zPrefix, zCom); nLine += comment_print(zFree, 9, 79); sqlite3_free(zFree); if(showfiles){ | < < < | 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 | n += strlen(zPrefix); } zFree = sqlite3_mprintf("[%.10s] %s%s", zUuid, zPrefix, zCom); nLine += comment_print(zFree, 9, 79); sqlite3_free(zFree); if(showfiles){ 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)" " FROM mlink" " WHERE mid=:mid AND pid!=fid" " 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); if( isNew ){ fossil_print(" ADDED %s\n",zFilename); }else if( isDel ){ fossil_print(" DELETED %s\n",zFilename); }else{ fossil_print(" EDITED %s\n", zFilename); } |
︙ | ︙ |
Changes to src/tkt.c.
︙ | ︙ | |||
99 100 101 102 103 104 105 | */ static void initializeVariablesFromDb(void){ const char *zName; Stmt q; int i, n, size, j; zName = PD("name","-none-"); | | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | */ static void initializeVariablesFromDb(void){ const char *zName; Stmt q; int i, n, size, j; zName = PD("name","-none-"); db_prepare(&q, "SELECT datetime(tkt_mtime,'localtime') AS tkt_datetime, *" " FROM ticket WHERE tkt_uuid GLOB '%q*'", zName); if( db_step(&q)==SQLITE_ROW ){ n = db_column_count(&q); for(i=0; i<n; i++){ const char *zVal = db_column_text(&q, i); const char *zName = db_column_name(&q, i); char *zRevealed = 0; |
︙ | ︙ | |||
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 | ** in "ticket show". So it's possible, to set multiline text or ** text with special characters. ** ** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? ** ** like set, but create a new ticket with the given values. ** ** The values in set|add are not validated against the definitions ** given in "Ticket Common Script". */ void ticket_cmd(void){ int n; /* do some ints, we want to be inside a checkout */ db_find_and_open_repository(0, 0); user_select(); /* ** Check that the user exists. */ if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ fossil_fatal("no such user: %s", g.zLogin); } if( g.argc<3 ){ | > > > > | | | 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 | ** in "ticket show". So it's possible, to set multiline text or ** text with special characters. ** ** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? ** ** like set, but create a new ticket with the given values. ** ** %fossil ticket history TICKETUUID ** ** Show the complete change history for the ticket ** ** The values in set|add are not validated against the definitions ** given in "Ticket Common Script". */ void ticket_cmd(void){ int n; /* do some ints, we want to be inside a checkout */ db_find_and_open_repository(0, 0); user_select(); /* ** Check that the user exists. */ if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ fossil_fatal("no such user: %s", g.zLogin); } if( g.argc<3 ){ usage("add|fieldlist|set|show|history"); }else{ n = strlen(g.argv[2]); if( n==1 && g.argv[2][0]=='s' ){ /* set/show cannot be distinguished, so show the usage */ usage("add|fieldlist|set|show|history"); }else if( strncmp(g.argv[2],"list",n)==0 ){ if( g.argc==3 ){ usage("list fields|reports"); }else{ n = strlen(g.argv[3]); if( !strncmp(g.argv[3],"fields",n) ){ /* simply show all field names */ |
︙ | ︙ | |||
968 969 970 971 972 973 974 | } rptshow( zRep, zSep, zFilterUuid, tktEncoding ); } }else{ /* add a new ticket or update an existing ticket */ | | | > > > > | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 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 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 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 | } rptshow( zRep, zSep, zFilterUuid, tktEncoding ); } }else{ /* add a new ticket or update an existing ticket */ enum { set,add,history,err } eCmd = err; int i = 0; int rid; const char *zTktUuid = 0; Blob tktchng, cksum; /* get command type (set/add) and get uuid, if needed for set */ if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 || strncmp(g.argv[2],"history",n)==0 ){ if( strncmp(g.argv[2],"history",n)==0 ){ eCmd = history; }else{ eCmd = set; } if( g.argc==3 ){ usage("set TICKETUUID"); } zTktUuid = db_text(0, "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3] ); if( !zTktUuid ){ fossil_fatal("unknown ticket: '%s'!",g.argv[3]); } i=4; }else if( strncmp(g.argv[2],"add",n)==0 ){ eCmd = add; i = 3; zTktUuid = db_text(0, "SELECT lower(hex(randomblob(20)))"); } /* none of set/add, so show the usage! */ if( eCmd==err ){ usage("add|fieldlist|set|show|history"); } /* we just handle history separately here, does not get out */ if( eCmd==history ){ Stmt q; char *zTitle; 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 ){ fossil_fatal("no such ticket %h", zTktUuid); } db_prepare(&q, "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" " FROM event, blob" " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" " AND blob.rid=event.objid" " UNION " "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user" " FROM attachment, blob" " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" " AND blob.rid=attachid" " ORDER BY 1 DESC", tagid, tagid ); while( db_step(&q)==SQLITE_ROW ){ Manifest *pTicket; char zShort[12]; const char *zDate = db_column_text(&q, 0); int rid = db_column_int(&q, 1); const char *zChngUuid = db_column_text(&q, 2); const char *zFile = db_column_text(&q, 4); memcpy(zShort, zChngUuid, 10); zShort[10] = 0; if( zFile!=0 ){ const char *zSrc = db_column_text(&q, 3); const char *zUser = db_column_text(&q, 5); if( zSrc==0 || zSrc[0]==0 ){ fossil_print("Delete attachment %h\n", zFile); }else{ fossil_print("Add attachment %h\n", zFile); } fossil_print(" by %h on %h\n", zUser, zDate); }else{ pTicket = manifest_get(rid, CFTYPE_TICKET); if( pTicket ){ int i; fossil_print("Ticket Change by %h on %h:\n", pTicket->zUser, zDate); for(i=0; i<pTicket->nField; i++){ Blob val; const char *z; z = pTicket->aField[i].zName; blob_set(&val, pTicket->aField[i].zValue); if( z[0]=='+' ){ fossil_print(" Append to "); z++; }else{ fossil_print(" Change "); } fossil_print("%h: ",z); if( blob_size(&val)>50 || contains_newline(&val)) { fossil_print("\n ",blob_str(&val)); comment_print(blob_str(&val),4,79); }else{ fossil_print("%s\n",blob_str(&val)); } blob_reset(&val); } } manifest_destroy(pTicket); } } db_finalize(&q); return; } /* read all given ticket field/value pairs from command line */ if( i==g.argc ){ fossil_fatal("empty %s command aborted!",g.argv[2]); } getAllTicketFields(); /* read commandline and assign fields in the azValue array */ while( i<g.argc ){ |
︙ | ︙ |
Changes to src/undo.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | ** true the redo a change. If there is nothing to undo (or redo) then ** this routine is a noop. */ static void undo_one(const char *zPathname, int redoFlag){ Stmt q; char *zFullname; db_prepare(&q, | | > > > > > > > | > > > > > > > | > | | | 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 | ** true the redo a change. If there is nothing to undo (or redo) then ** this routine is a noop. */ static void undo_one(const char *zPathname, int redoFlag){ Stmt q; char *zFullname; db_prepare(&q, "SELECT content, existsflag, isExe, isLink FROM undo" " WHERE pathname=%Q AND redoflag=%d", zPathname, redoFlag ); if( db_step(&q)==SQLITE_ROW ){ int old_exists; int new_exists; int old_exe; 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_islink(zFullname); new_exists = file_size(zFullname)>=0; if( new_exists ){ if( new_link ){ blob_read_link(¤t, zFullname); }else{ blob_read_from_file(¤t, zFullname); } new_exe = file_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 ){ create_symlink(blob_str(&new), zFullname); }else{ blob_write_to_file(&new, zFullname); } file_setexe(zFullname, old_exe); }else{ fossil_print("DELETE %s\n", zPathname); file_delete(zFullname); } blob_reset(&new); free(zFullname); db_finalize(&q); db_prepare(&q, "UPDATE undo SET content=:c, existsflag=%d, isExe=%d, isLink=%d," " redoflag=NOT redoflag" " WHERE pathname=%Q", new_exists, new_exe, new_link, zPathname ); if( new_exists ){ db_bind_blob(&q, ":c", ¤t); } db_step(&q); blob_reset(¤t); } |
︙ | ︙ | |||
207 208 209 210 211 212 213 214 215 216 217 218 219 220 | const char *zDb = db_name("localdb"); static const char zSql[] = @ CREATE TABLE %s.undo( @ pathname TEXT UNIQUE, -- Name of the file @ redoflag BOOLEAN, -- 0 for undoable. 1 for redoable @ existsflag BOOLEAN, -- True if the file exists @ isExe BOOLEAN, -- True if the file is executable @ content BLOB -- Saved content @ ); @ CREATE TABLE %s.undo_vfile AS SELECT * FROM vfile; @ CREATE TABLE %s.undo_vmerge AS SELECT * FROM vmerge; ; if( undoDisable ) return; undo_reset(); | > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | const char *zDb = db_name("localdb"); static const char zSql[] = @ CREATE TABLE %s.undo( @ pathname TEXT UNIQUE, -- Name of the file @ redoflag BOOLEAN, -- 0 for undoable. 1 for redoable @ existsflag BOOLEAN, -- True if the file exists @ isExe BOOLEAN, -- True if the file is executable @ isLink BOOLEAN, -- True if the file is symlink @ content BLOB -- Saved content @ ); @ CREATE TABLE %s.undo_vfile AS SELECT * FROM vfile; @ CREATE TABLE %s.undo_vmerge AS SELECT * FROM vmerge; ; if( undoDisable ) return; undo_reset(); |
︙ | ︙ | |||
247 248 249 250 251 252 253 254 255 256 257 258 259 | ** will be undoable. The name is relative to the root of the ** tree. */ void undo_save(const char *zPathname){ char *zFullname; Blob content; int existsFlag; Stmt q; if( !undoActive ) return; zFullname = mprintf("%s%s", g.zLocalRoot, zPathname); existsFlag = file_size(zFullname)>=0; db_prepare(&q, | > > | > | | > > > | > | 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 | ** will be undoable. The name is relative to the root of the ** tree. */ void undo_save(const char *zPathname){ char *zFullname; Blob content; int existsFlag; int isLink; Stmt q; if( !undoActive ) return; zFullname = mprintf("%s%s", g.zLocalRoot, zPathname); existsFlag = file_size(zFullname)>=0; isLink = file_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_isexe(zFullname), isLink ); if( existsFlag ){ if( isLink ){ blob_read_link(&content, zFullname); }else{ blob_read_from_file(&content, zFullname); } db_bind_blob(&q, ":c", &content); } free(zFullname); db_step(&q); db_finalize(&q); if( existsFlag ){ blob_reset(&content); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
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 | db_multi_exec( "DROP TABLE IF EXISTS fv;" "CREATE TEMP TABLE fv(" " fn TEXT PRIMARY KEY," /* The filename relative to root */ " idv INTEGER," /* VFILE entry for current version */ " idt INTEGER," /* VFILE entry for target version */ " chnged BOOLEAN," /* True if current version has been edited */ " ridv INTEGER," /* Record ID for current version */ " ridt INTEGER," /* Record ID for target */ " isexe BOOLEAN," /* Does target have execute permission? */ " fnt TEXT" /* Filename of same file on target version */ ");" ); /* Add files found in the current version */ db_multi_exec( "INSERT OR IGNORE INTO fv(fn,fnt,idv,idt,ridv,ridt,isexe,chnged)" " SELECT pathname, pathname, id, 0, rid, 0, isexe, chnged" " FROM vfile WHERE vid=%d", vid ); /* Compute file name changes on V->T. Record name changes in files that ** have changed locally. */ | > > | | 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 | db_multi_exec( "DROP TABLE IF EXISTS fv;" "CREATE TEMP TABLE fv(" " fn TEXT PRIMARY KEY," /* The filename relative to root */ " idv INTEGER," /* VFILE entry for current version */ " idt INTEGER," /* VFILE entry for target version */ " chnged BOOLEAN," /* True if current version has been edited */ " islinkv BOOLEAN," /* True if current file is a link */ " islinkt BOOLEAN," /* True if target file is a link */ " ridv INTEGER," /* Record ID for current version */ " ridt INTEGER," /* Record ID for target */ " isexe BOOLEAN," /* Does target have execute permission? */ " fnt TEXT" /* Filename of same file on target version */ ");" ); /* Add files found in the current version */ db_multi_exec( "INSERT OR IGNORE INTO fv(fn,fnt,idv,idt,ridv,ridt,isexe,chnged)" " SELECT pathname, pathname, id, 0, rid, 0, isexe, chnged" " 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] |
︙ | ︙ | |||
252 253 254 255 256 257 258 259 260 261 | */ db_multi_exec( "UPDATE fv SET" " idt=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnt),0)," " ridt=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnt),0)", tid, tid ); if( debugFlag ){ db_prepare(&q, | > > > > > > > > > > > | | | > > | 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 | */ db_multi_exec( "UPDATE fv SET" " idt=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnt),0)," " ridt=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnt),0)", tid, tid ); /* ** Add islink information */ db_multi_exec( "UPDATE fv SET" " islinkv=coalesce((SELECT islink FROM vfile WHERE vid=%d AND pathname=fnt),0)," " islinkt=coalesce((SELECT islink FROM vfile WHERE vid=%d AND pathname=fnt),0)", vid, tid ); if( debugFlag ){ db_prepare(&q, "SELECT rowid, fn, fnt, chnged, ridv, ridt, isexe, islinkv, islinkt FROM fv" ); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%3d: ridv=%-4d ridt=%-4d chnged=%d isexe=%d islinkv=%d islinkt=%d\n", db_column_int(&q, 0), db_column_int(&q, 4), db_column_int(&q, 5), db_column_int(&q, 3), db_column_int(&q, 6), db_column_int(&q, 7), db_column_int(&q, 8)); fossil_print(" fnv = [%s]\n", db_column_text(&q, 1)); fossil_print(" fnt = [%s]\n", db_column_text(&q, 2)); } db_finalize(&q); } /* If FILES appear on the command-line, remove from the "fv" table |
︙ | ︙ | |||
286 287 288 289 290 291 292 | 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 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | 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); } zSep = "AND "; blob_reset(&treename); } db_multi_exec(blob_str(&sql)); blob_reset(&sql); } /* ** Alter the content of the checkout so that it conforms with the ** target */ db_prepare(&q, "SELECT fn, idv, ridv, idt, ridt, chnged, fnt, isexe, islinkv, islinkt FROM fv ORDER BY 1" ); db_prepare(&mtimeXfer, "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)" " WHERE id=:idt" ); assert( g.zLocalRoot!=0 ); assert( strlen(g.zLocalRoot)>1 ); assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' ); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); /* The filename from root */ int idv = db_column_int(&q, 1); /* VFILE entry for current */ int ridv = db_column_int(&q, 2); /* RecordID for current */ int idt = db_column_int(&q, 3); /* VFILE entry for target */ int ridt = db_column_int(&q, 4); /* RecordID for target */ int chnged = db_column_int(&q, 5); /* Current is edited */ const char *zNewName = db_column_text(&q,6);/* New filename */ int isexe = db_column_int(&q, 7); /* EXE perm for new file */ int islinkv = db_column_int(&q, 8); /* Is current file is a link */ int islinkt = db_column_int(&q, 9); /* Is target file is a link */ char *zFullPath; /* Full pathname of the file */ char *zFullNewPath; /* Full pathname of dest */ char nameChng; /* True if the name changed */ zFullPath = mprintf("%s%s", g.zLocalRoot, zName); zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); nameChng = fossil_strcmp(zName, zNewName); |
︙ | ︙ | |||
379 380 381 382 383 384 385 | 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_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_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_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 ){ |
︙ | ︙ | |||
520 521 522 523 524 525 526 527 528 529 530 531 532 533 | ** Get the contents of a file within the checking "revision". If ** revision==NULL then get the file content for the current checkout. */ int historical_version_of_file( const char *revision, /* The checkin containing the file */ const char *file, /* Full treename of the file */ Blob *content, /* Put the content here */ int *pIsExe, /* Set to true if file is executable */ int errCode /* Error code if file not found. Panic if 0. */ ){ Manifest *pManifest; ManifestFile *pFile; int rid=0; | > | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | ** Get the contents of a file within the checking "revision". If ** revision==NULL then get the file content for the current checkout. */ int historical_version_of_file( const char *revision, /* The checkin containing the file */ const char *file, /* Full treename of the file */ Blob *content, /* Put the content here */ int *pIsLink, /* Set to true if file is link. */ int *pIsExe, /* Set to true if file is executable */ int errCode /* Error code if file not found. Panic if 0. */ ){ Manifest *pManifest; ManifestFile *pFile; int rid=0; |
︙ | ︙ | |||
542 543 544 545 546 547 548 | } pManifest = manifest_get(rid, CFTYPE_MANIFEST); if( pManifest ){ pFile = manifest_file_seek(pManifest, file); if( pFile ){ rid = uuid_to_rid(pFile->zUuid, 0); | | > | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | } pManifest = manifest_get(rid, CFTYPE_MANIFEST); if( pManifest ){ pFile = manifest_file_seek(pManifest, file); if( pFile ){ rid = uuid_to_rid(pFile->zUuid, 0); if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE ); if( pIsLink ) *pIsLink = ( manifest_file_mperm(pFile)==PERM_LNK ); manifest_destroy(pManifest); return content_get(rid, content); } manifest_destroy(pManifest); if( errCode<=0 ){ fossil_fatal("file %s does not exist in checkin: %s", file, revision); } |
︙ | ︙ | |||
625 626 627 628 629 630 631 632 633 634 | db_prepare(&q, "SELECT name FROM torevert"); if( zRevision==0 ){ int vid = db_lget_int("checkout", 0); zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); } while( db_step(&q)==SQLITE_ROW ){ int isExe = 0; char *zFull; zFile = db_column_text(&q, 0); zFull = mprintf("%/%/", g.zLocalRoot, zFile); | > | > > > > > > | > | | | 649 650 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 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | db_prepare(&q, "SELECT name FROM torevert"); if( zRevision==0 ){ int vid = db_lget_int("checkout", 0); zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); } while( db_step(&q)==SQLITE_ROW ){ int isExe = 0; int isLink = 0; char *zFull; zFile = db_column_text(&q, 0); zFull = mprintf("%/%/", g.zLocalRoot, zFile); errCode = historical_version_of_file(zRevision, zFile, &record, &isLink, &isExe,2); if( errCode==2 ){ if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){ fossil_print("UNMANAGE: %s\n", zFile); }else{ undo_save(zFile); 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_size(zFull)>=0 && (isLink || file_islink(zFull)) ){ file_delete(zFull); } if( isLink ){ create_symlink(blob_str(&record), zFull); }else{ blob_write_to_file(&record, zFull); } file_setexe(zFull, isExe); fossil_print("REVERTED: %s\n", zFile); mtime = file_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 ); } blob_reset(&record); free(zFull); } db_finalize(&q); undo_finish(); db_end_transaction(0); } |
Changes to src/user.c.
︙ | ︙ | |||
310 311 312 313 314 315 316 | ** ** The user name is stored in g.zLogin. The uid is in g.userUid. */ void user_select(void){ Stmt s; if( g.userUid ) return; | > | > > > > > | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | ** ** The user name is stored in g.zLogin. The uid is in g.userUid. */ void user_select(void){ Stmt s; if( g.userUid ) return; if( g.zLogin ){ if( attempt_user(g.zLogin)==0 ){ fossil_fatal("no such user: %s", g.zLogin); }else{ return; } } if( g.localOpen && attempt_user(db_lget("default-user",0)) ) return; if( attempt_user(db_get("default-user", 0)) ) return; if( attempt_user(getenv("USER")) ) return; |
︙ | ︙ |
Changes to src/vfile.c.
︙ | ︙ | |||
88 89 90 91 92 93 94 | } db_begin_transaction(); p = manifest_get(vid, CFTYPE_MANIFEST); if( p==0 ) return; db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid); db_prepare(&ins, | | | | > | 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 | } db_begin_transaction(); p = manifest_get(vid, CFTYPE_MANIFEST); if( p==0 ) return; db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid); db_prepare(&ins, "INSERT INTO vfile(vid,isexe,islink,rid,mrid,pathname) " " VALUES(:vid,:isexe,:islink,:id,:id,:name)"); db_prepare(&ridq, "SELECT rid,size FROM blob WHERE uuid=:uuid"); db_bind_int(&ins, ":vid", vid); manifest_file_rewind(p); while( (pFile = manifest_file_next(p,0))!=0 ){ if( pFile->zUuid==0 || uuid_is_shunned(pFile->zUuid) ) continue; db_bind_text(&ridq, ":uuid", pFile->zUuid); if( db_step(&ridq)==SQLITE_ROW ){ rid = db_column_int(&ridq, 0); size = db_column_int(&ridq, 0); }else{ rid = 0; size = 0; } db_reset(&ridq); if( rid==0 || size<0 ){ fossil_warning("content missing for %s", pFile->zName); continue; } db_bind_int(&ins, ":isexe", ( manifest_file_mperm(pFile)==PERM_EXE )); db_bind_int(&ins, ":id", rid); db_bind_text(&ins, ":name", pFile->zName); db_bind_int(&ins, ":islink", ( manifest_file_mperm(pFile)==PERM_LNK )); db_step(&ins); db_reset(&ins); } db_finalize(&ridq); db_finalize(&ins); manifest_destroy(p); db_end_transaction(0); |
︙ | ︙ | |||
163 164 165 166 167 168 169 | 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 | 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_isfile_or_link(zName) && file_size(0)>=0 ){ if( notFileIsFatal ){ fossil_warning("not an ordinary file: %s", zName); nErr++; } chnged = 1; }else if( oldChnged>=2 ){ chnged = oldChnged; |
︙ | ︙ | |||
221 222 223 224 225 226 227 | int promptFlag /* Prompt user to confirm overwrites */ ){ Stmt q; Blob content; int nRepos = strlen(g.zLocalRoot); if( vid>0 && id==0 ){ | | | | > | 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 | int promptFlag /* Prompt user to confirm overwrites */ ){ Stmt q; Blob content; int nRepos = strlen(g.zLocalRoot); if( vid>0 && id==0 ){ db_prepare(&q, "SELECT id, %Q || pathname, mrid, isexe, islink" " FROM vfile" " WHERE vid=%d AND mrid>0", g.zLocalRoot, vid); }else{ assert( vid==0 && id>0 ); db_prepare(&q, "SELECT id, %Q || pathname, mrid, isexe, islink" " FROM vfile" " WHERE id=%d AND mrid>0", g.zLocalRoot, id); } while( db_step(&q)==SQLITE_ROW ){ int id, rid, isExe, isLink; const char *zName; id = db_column_int(&q, 0); 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_setexe(zName, isExe) ){ db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", file_mtime(zName), id); } |
︙ | ︙ | |||
268 269 270 271 272 273 274 | } if( cReply=='n' || cReply=='N' ){ blob_reset(&content); continue; } } if( verbose ) fossil_print("%s\n", &zName[nRepos]); | > > > > > > > > > > | > | 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 | } if( cReply=='n' || cReply=='N' ){ blob_reset(&content); continue; } } 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_size(zName)>=0 && (isLink || file_islink(zName)) ){ file_delete(zName); } if( isLink ){ create_symlink(blob_str(&content), zName); }else{ blob_write_to_file(&content, zName); } file_setexe(zName, isExe); blob_reset(&content); db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", file_mtime(zName), id); } db_finalize(&q); } |
︙ | ︙ | |||
378 379 380 381 382 383 384 | 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_isfile_or_link(zPath) ){ db_bind_text(&ins, ":file", &zPath[nPrefix+1]); db_step(&ins); db_reset(&ins); } blob_resize(pPath, origSize); } closedir(d); |
︙ | ︙ | |||
437 438 439 440 441 442 443 | 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 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 | 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_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); blob_reset(&pathBuf); }else{ in = fossil_fopen(zFullpath,"rb"); if( in==0 ){ md5sum_step_text(" 0\n", -1); continue; } fseek(in, 0L, SEEK_END); sqlite3_snprintf(sizeof(zBuf), zBuf, " %ld\n", ftell(in)); fseek(in, 0L, SEEK_SET); md5sum_step_text(zBuf, -1); /*printf("%s %s %s",md5sum_current_state(),zName,zBuf); fflush(stdout);*/ for(;;){ int n; n = fread(zBuf, 1, sizeof(zBuf), in); if( n<=0 ) break; md5sum_step_text(zBuf, n); } fclose(in); } }else{ int rid = db_column_int(&q, 4); const char *zOrigName = db_column_text(&q, 2); char zBuf[100]; Blob file; if( zOrigName ) zName = zOrigName; |
︙ | ︙ | |||
498 499 500 501 502 503 504 | 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 537 538 539 540 | 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_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); continue; } blob_zero(&repo); content_get(rid, &repo); |
︙ | ︙ |
Changes to src/zip.c.
︙ | ︙ | |||
115 116 117 118 119 120 121 | /* ** Append a single file to a growing ZIP archive. ** ** pFile is the file to be appended. zName is the name ** that the file should be saved as. */ | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | /* ** Append a single file to a growing ZIP archive. ** ** pFile is the file to be appended. zName is the name ** that the file should be saved as. */ void zip_add_file(const char *zName, const Blob *pFile, int mPerm){ z_stream stream; int nameLen; int toOut = 0; int iStart; int iCRC = 0; int nByte = 0; int nByteCompr = 0; |
︙ | ︙ | |||
137 138 139 140 141 142 143 | char zOutBuf[100000]; /* Fill in as much of the header as we know. */ nBlob = pFile ? blob_size(pFile) : 0; if( nBlob>0 ){ iMethod = 8; | > | > > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | char zOutBuf[100000]; /* Fill in as much of the header as we know. */ nBlob = pFile ? blob_size(pFile) : 0; if( nBlob>0 ){ iMethod = 8; switch( mPerm ){ case PERM_LNK: iMode = 0120755; break; case PERM_EXE: iMode = 0100755; break; default: iMode = 0100644; break; } }else{ iMethod = 0; iMode = 040755; } nameLen = strlen(zName); memset(zHdr, 0, sizeof(zHdr)); put32(&zHdr[0], 0x04034b50); |
︙ | ︙ | |||
285 286 287 288 289 290 291 | 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_perm(g.argv[i])); blob_reset(&file); } zip_close(&zip); blob_write_to_file(&zip, g.argv[2]); } /* |
︙ | ︙ |
Added test/merge_renames.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | # # Tests for merging with renames # # catch {exec $::fossilexe info} res puts res=$res if {![regexp {not within an open checkout} $res]} { puts stderr "Cannot run this test within an open checkout" return } ###################################### # Test 1 # # Reported: Ticket [554f44ee74e3d] # ###################################### fossil new rep.fossil fossil open rep.fossil write_file f1 "line" fossil add f1 fossil commit -m "c1" fossil tag add pivot current write_file f1 "line2" fossil commit -m "c2" write_file f1 "line3" fossil commit -m "c3" write_file f1 "line4" fossil commit -m "c4" write_file f1 "line5" fossil commit -m "c4" write_file f1 "line6" fossil commit -m "c4" fossil update pivot fossil mv f1 f2 exec mv f1 f2 fossil commit -b rename -m "c5" fossil merge trunk fossil commit -m "trunk merged" fossil update pivot write_file f3 "someline" fossil add f3 fossil commit -b branch2 -m "newbranch" fossil merge trunk puts $RESULT set deletes 0 foreach {status filename} $RESULT { if {$status=="DELETE"} { set deletes [expr $deletes + 1] } } if {$deletes!=0} { # failed protOut "Error, the merge should not delete any file" test merge_renames-1 0 } else { test merge_renames-1 1 } fossil close -f exec rm rep.fossil ###################################### # Test 2 # # Reported: Ticket [74413366fe5067] # ###################################### fossil new rep.fossil fossil open rep.fossil write_file f1 "line" fossil add f1 fossil commit -m "base file" fossil tag add pivot current write_file f2 "line2" fossil add f2 fossil commit -m "newfile" fossil mv f2 f2new exec mv f2 f2new fossil commit -m "rename" fossil update pivot write_file f1 "line3" fossil commit -b branch -m "change" fossil merge trunk fossil commit -m "trunk merged" fossil update trunk fossil merge branch puts $RESULT # Not a nice way to check, but I don't know more tcl now set deletes 0 foreach {status filename} $RESULT { if {$status=="DELETE"} { set deletes [expr $deletes + 1] } } if {$deletes!=0} { # failed protOut "Error, the merge should not delete any file" test merge_renames-2 0 } else { test merge_renames-2 1 } fossil close -f exec rm rep.fossil ###################################### # Test 3 # # Reported: Ticket [30b28cf351] # ###################################### fossil new rep.fossil fossil open rep.fossil write_file f1 "line" fossil add f1 fossil commit -m "base file" fossil tag add pivot current write_file f2 "line2" fossil add f2 fossil commit -m "newfile" fossil mv f2 f2new exec mv f2 f2new fossil commit -m "rename" fossil update pivot write_file f1 "line3" fossil commit -b branch -m "change" fossil merge trunk fossil commit -m "trunk merged" fossil update trunk fossil merge branch puts $RESULT # Not a nice way to check, but I don't know more tcl now set deletes 0 foreach {status filename} $RESULT { if {$status=="DELETE"} { set deletes [expr $deletes + 1] } } if {$deletes!=0} { # failed protOut "Error, the merge should not delete any file" test merge_renames-2 0 } else { test merge_renames-2 1 } fossil close -f exec rm rep.fossil ###################################### # Test 4 # # Reported: Ticket [67176c3aa4] # ###################################### # TO BE WRITTEN. # Tests for troubles not specifically linked with renames but that I'd like to # write: # [c26c63eb1b] - 'merge --backout' does not handle conflicts properly # [953031915f] - Lack of warning when overwriting extra files # [4df5f38f1e] - Troubles merging a file delete with a file change |
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/changes.wiki.
1 2 | <title>Change Log</title> | | > > > > > > > > > | 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 | <title>Change Log</title> <h2>Changes For Version 1.19 (2011-09-02)</h2> * Added a ./configure script based on autosetup. * Added the "[/help/winsrv | fossil winsrv]" command for creating a Fossil service on windows systems. * Added "versionable settings" where settings that affect the local tree can be stored in versioned files in the .fossil-settings directory. * Background colors for branches are choosen automatically if no color is specified by the user. * The status, changes and extras commands now show pathnames relative to the current working directory, unless overridden by command line options or the "relative-paths" setting.<br><b>WARNING:</b> This change will break scripts which rely on the current output when the current working directory is not the repository root. * Added "empty-dirs" versionable setting. * Added support for client-side SSL certificates with "ssl-identity" setting and --ssl-identity option. * Added "ssl-ca-location" setting to specify trusted root SSL certificates. * Added the --case-sensitive BOOLEAN command-line option to many commands. Default to true for unix and false for windows. * Added the "Color-Test" submenu button on the branch list web page. * Compatibility improvements to the git-export feature. * Performance improvements on SHA1 checksums * Update to the latest SQLite version 3.7.8 alpha. * Fix the tarball generator to work with very log pathnames <h2>Changes For Version 1.18 (2011-07-14)</h2> * Added this Change Log * Added sequential version numbering * Added a optional configure script - the Makefile still works for most systems. |
︙ | ︙ |
Changes to www/mkdownload.tcl.
︙ | ︙ | |||
58 59 60 61 62 63 64 | set hr http://www.fossil-scm.org/fossil/timeline?c=$link&y=ci puts $out "<tr><td colspan=6 align=left><hr>" puts $out "<center><b><a href=\"$hr\">$dt</a></b></center>" puts $out "</td></tr>" foreach {prefix suffix img desc} { fossil-linux-x86 zip linux.gif {Linux x86} | < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | set hr http://www.fossil-scm.org/fossil/timeline?c=$link&y=ci puts $out "<tr><td colspan=6 align=left><hr>" puts $out "<center><b><a href=\"$hr\">$dt</a></b></center>" puts $out "</td></tr>" foreach {prefix suffix img desc} { fossil-linux-x86 zip linux.gif {Linux x86} fossil-macosx-x86 zip mac.gif {Mac 10.5 x86} fossil-openbsd-x86 zip openbsd.gif {OpenBSD 4.7 x86} fossil-w32 zip win32.gif {Windows} fossil-src tar.gz src.gif {Source Tarball} } { set filename download/$prefix-$datetime.$suffix if {[file exists $filename]} { |
︙ | ︙ |