Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | merge in trunk |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | mgagnon_fix |
| Files: | files | file ages | folders |
| SHA1: |
150074d1d6dc6cf3c1ff3664b4d895c4 |
| User & Date: | mgagnon 2012-03-29 14:48:07.432 |
| Original User & Date: | meeks 2012-03-29 14:48:07.432 |
Context
|
2012-03-29
| ||
| 14:54 | Add vim modline everywhere check-in: a496d8e88d user: mgagnon tags: mgagnon_fix | |
| 14:48 | merge in trunk check-in: 150074d1d6 user: mgagnon tags: mgagnon_fix | |
|
2012-03-28
| ||
| 21:25 | added advapi32 to libs of dmc. Needed for windows service check-in: c0ad5f6bc4 user: renez tags: trunk | |
|
2012-01-22
| ||
| 22:02 | merge with trunk check-in: e1c424cb69 user: mgagnon tags: mgagnon_fix | |
Changes
Changes to VERSION.
|
| | | 1 | 1.22 |
Changes to ajax/i-test/rhino-test.js.
1 2 3 4 5 6 7 |
var TestApp = {
serverUrl:
'http://localhost:8080'
//'http://fjson/cgi-bin/fossil-json.cgi'
//'http://192.168.1.62:8080'
//'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi'
,
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var TestApp = {
serverUrl:
'http://localhost:8080'
//'http://fjson/cgi-bin/fossil-json.cgi'
//'http://192.168.1.62:8080'
//'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi'
,
verbose:true,
fossilBinary:'fossil',
wiki:{}
};
(function bootstrap() {
var srcdir = '../js/';
var includes = [srcdir+'json2.js',
srcdir+'whajaj.js',
|
| ︙ | ︙ | |||
169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
assertResponseOK(rs);
assert(rs.payload.name == TestApp.wiki.list[0], "Fetched page name matches expectations.");
print("Got first wiki page: "+WhAjaj.stringify(rs.payload));
}
testAnonWiki.description = 'Fetch wiki list as anonymous user.';
function testAnonLogout(){
var rs;
TestApp.fossil.logout({
onResponse:function(resp,req){
rs = resp;
}
});
| > > > > > > > > > > > > > > > > | 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 |
assertResponseOK(rs);
assert(rs.payload.name == TestApp.wiki.list[0], "Fetched page name matches expectations.");
print("Got first wiki page: "+WhAjaj.stringify(rs.payload));
}
testAnonWiki.description = 'Fetch wiki list as anonymous user.';
function testFetchCheckinArtifact(){
var art = '18dd383e5e7684ece';
var rs;
TestApp.fossil.sendCommand('/json/artifact',{
'name': art
},
{
onResponse:function(resp,req){
rs = resp;
}
});
assertResponseOK(rs);
assert(3 == rs.payload.artifact.parents.length, 'Got 3 parent artifacts.');
}
testFetchCheckinArtifact.description = '/json/artifact/CHECKIN';
function testAnonLogout(){
var rs;
TestApp.fossil.logout({
onResponse:function(resp,req){
rs = resp;
}
});
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 |
var args = [TestApp.fossilBinary, 'json', '--json-input', '-'];
var p = java.lang.Runtime.getRuntime().exec(args);
var outs = p.getOutputStream();
var osr = new java.io.OutputStreamWriter(outs);
var osb = new java.io.BufferedWriter(osr);
var json = JSON.stringify(req);
osb.write(json,0, json.length);
| < > | > > | 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 |
var args = [TestApp.fossilBinary, 'json', '--json-input', '-'];
var p = java.lang.Runtime.getRuntime().exec(args);
var outs = p.getOutputStream();
var osr = new java.io.OutputStreamWriter(outs);
var osb = new java.io.BufferedWriter(osr);
var json = JSON.stringify(req);
osb.write(json,0, json.length);
osb.close();
req = json = outs = osr = osb = undefined;
var ins = p.getInputStream();
var isr = new java.io.InputStreamReader(ins);
var br = new java.io.BufferedReader(isr);
var line;
while( null !== (line=br.readLine())){
print(line);
}
br.close();
isr.close();
ins.close();
p.waitFor();
}
testExternalProcess.description = 'Run fossil as external process.';
function testExternalProcessHandler(){
var aj = TestApp.fossil.ajaj;
var oldImpl = aj.sendImpl;
aj.sendImpl = FossilAjaj.rhinoLocalBinarySendImpl;
|
| ︙ | ︙ | |||
235 236 237 238 239 240 241 242 |
(function runAllTests(){
var testList = [
testHAI,
testIAmNobody,
testAnonymousLogin,
testAnonWiki,
testAnonLogout,
| > | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
(function runAllTests(){
var testList = [
testHAI,
testIAmNobody,
testAnonymousLogin,
testAnonWiki,
testFetchCheckinArtifact,
testAnonLogout,
testExternalProcess,
testExternalProcessHandler
];
var i, f;
for( i = 0; i < testList.length; ++i ){
f = testList[i];
try{
print("Running test #"+(i+1)+": "+(f.description || "no description."));
|
| ︙ | ︙ |
Changes to ajax/index.html.
| ︙ | ︙ | |||
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
<br/>
<input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' />
<input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' />
<input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' />
<input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' />
<input type='button' value='timeline/branch' onclick='TheApp.cgi.sendCommand("/json/timeline/branch")' />
<input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' />
<input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' />
<input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' />
<br/>
<input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' />
<input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
<input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
<input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
| > > > > > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
<br/>
<input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' />
<input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' />
<input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' />
<input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' />
<input type='button' value='timeline/branch' onclick='TheApp.cgi.sendCommand("/json/timeline/branch")' />
<br/>
<input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' />
<input type='button' value='wiki/list verbose' onclick='TheApp.cgi.sendCommand("/json/wiki/list",{verbose:1})' />
<input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' />
<input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' />
<input type='button' value='wiki/diff' onclick='TheApp.cgi.sendCommand("/json/wiki/diff/e32ccdcda59e930c77c/e15992f475760cdf3a9")' />
<br/>
<input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' />
<input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
<input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
<input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
|
| ︙ | ︙ | |||
265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
<input type='button' value='report list'
onclick='TheApp.cgi.sendCommand("/json/report/list")' />
<input type='button' value='report get'
onclick='TheApp.cgi.sendCommand("/json/report/get",2)' />
<input type='button' value='report run'
onclick='TheApp.cgi.sendCommand("/json/report/run",{"report":2,"format":"o"})' />
<!-- not yet ready...
<input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' />
-->
<!--
<input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' />
| > > | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
<input type='button' value='report list'
onclick='TheApp.cgi.sendCommand("/json/report/list")' />
<input type='button' value='report get'
onclick='TheApp.cgi.sendCommand("/json/report/get",2)' />
<input type='button' value='report run'
onclick='TheApp.cgi.sendCommand("/json/report/run",{"report":2,"format":"o"})' />
<input type='button' value='config/get' onclick='TheApp.cgi.sendCommand("/json/config/get")' />
<!-- not yet ready...
<input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' />
-->
<!--
<input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' />
|
| ︙ | ︙ |
Changes to ajax/js/whajaj.js.
| ︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
if( 0 === arguments.length ) {
if( ('undefined' === typeof window) ||
!window.location ||
!window.location.search ) return false;
else str = (''+window.location.search).substring(1);
}
if( ! str ) return false;
var args = {};
var sp = str.split(/&+/);
var rx = /^([^=]+)(=(.+))?/;
var i, m;
for( i in sp ) {
m = rx.exec( sp[i] );
if( ! m ) continue;
| > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
if( 0 === arguments.length ) {
if( ('undefined' === typeof window) ||
!window.location ||
!window.location.search ) return false;
else str = (''+window.location.search).substring(1);
}
if( ! str ) return false;
str = (''+str).split(/#/,2)[0]; // remove #... to avoid it being added as part of the last value.
var args = {};
var sp = str.split(/&+/);
var rx = /^([^=]+)(=(.+))?/;
var i, m;
for( i in sp ) {
m = rx.exec( sp[i] );
if( ! m ) continue;
|
| ︙ | ︙ |
Changes to auto.def.
| ︙ | ︙ | |||
154 155 156 157 158 159 160 |
if {$dir eq ""} {
set msg "system ssl"
set cflags ""
set ldflags ""
} else {
set msg "ssl in $dir"
set cflags "-I$dir/include"
| | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
if {$dir eq ""} {
set msg "system ssl"
set cflags ""
set ldflags ""
} else {
set msg "ssl in $dir"
set cflags "-I$dir/include"
set ldflags "-L$dir/lib"
}
if {[check-for-openssl $msg "$cflags $ldflags"]} {
incr found
break
}
}
}
|
| ︙ | ︙ |
Changes to autosetup/README.autosetup.
|
| | | 1 | This is autosetup v0.6.4. See http://msteveb.github.com/autosetup/ |
Changes to autosetup/autosetup.
1 2 3 4 5 6 7 | #!/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" "$@" | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/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.4 # Can be set to 1 to debug early-init problems set autosetup(debug) 0 ################################################################## # # Main flow of control, option handling |
| ︙ | ︙ | |||
514 515 516 517 518 519 520 521 522 523 524 525 |
}
getenv $name $default
}
# @env-is-set name
#
# Returns 1 if the $name was specified on the command line or in the environment.
#
proc env-is-set {name} {
if {[dict exists $::autosetup(cmdline) $name]} {
return 1
}
| > | > > > | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 |
}
getenv $name $default
}
# @env-is-set name
#
# Returns 1 if the $name was specified on the command line or in the environment.
# Note that an empty environment variable is not considered to be set.
#
proc env-is-set {name} {
if {[dict exists $::autosetup(cmdline) $name]} {
return 1
}
if {[getenv $name ""] ne ""} {
return 1
}
return 0
}
# @readfile filename ?default=""?
#
# Return the contents of the file, without the trailing newline.
# If the doesn't exist or can't be read, returns $default.
#
|
| ︙ | ︙ | |||
1290 1291 1292 1293 1294 1295 1296 |
} else {
puts "I don't see configure, so I will create it."
}
if {$create_configure} {
if {!$::autosetup(installed)} {
user-notice "Warning: Initialising from the development version of autosetup"
| | | | 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 |
} else {
puts "I don't see configure, so I will create it."
}
if {$create_configure} {
if {!$::autosetup(installed)} {
user-notice "Warning: Initialising from the development version of autosetup"
writefile configure "#!/bin/sh\nWRAPPER=\"\$0\"; export WRAPPER; exec $::autosetup(dir)/autosetup \"\$@\"\n"
} else {
writefile configure \
{#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0"; export WRAPPER; 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'
|
| ︙ | ︙ | |||
1539 1540 1541 1542 1543 1544 1545 |
}
} elseif {$autosetup(iswin)} {
# On Windows, backslash convert all environment variables
# (Assume that Tcl does this for us)
proc getenv {name args} {
string map {\\ /} [env $name {*}$args]
}
| < < < < < < < < < | 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 |
}
} elseif {$autosetup(iswin)} {
# On Windows, backslash convert all environment variables
# (Assume that Tcl does this for us)
proc getenv {name args} {
string map {\\ /} [env $name {*}$args]
}
} else {
# Jim on unix is simple
alias getenv env
}
# In case 'file normalize' doesn't exist
#
|
| ︙ | ︙ |
Added autosetup/cc-db.tcl.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved
# @synopsis:
#
# The 'cc-db' module provides a knowledge based of system idiosyncracies
# In general, this module can always be included
use cc
module-options {}
# openbsd needs sys/types.h to detect some system headers
cc-include-needs sys/socket.h sys/types.h
cc-include-needs netinet/in.h sys/types.h
|
Changes to autosetup/cc-shared.tcl.
1 2 3 4 5 6 7 8 9 10 11 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ # All rights reserved # @synopsis: # # The 'cc-shared' module provides support for shared libraries and shared objects. # It defines the following variables: # ## SH_CFLAGS Flags to use compiling sources destined for a shared library ## SH_LDFLAGS Flags to use linking a shared library ## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object | | > > > > > > > > > > > | > > > > | 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 |
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved
# @synopsis:
#
# The 'cc-shared' module provides support for shared libraries and shared objects.
# It defines the following variables:
#
## SH_CFLAGS Flags to use compiling sources destined for a shared library
## SH_LDFLAGS Flags to use linking a shared library
## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object
## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed
## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved
## SH_LINKFLAGS Flags to use linking an executable which will load shared objects
## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries
module-options {}
foreach i {SH_LINKFLAGS SH_CFLAGS SH_LDFLAGS SHOBJ_CFLAGS SHOBJ_LDFLAGS} {
define $i ""
}
define LD_LIBRARY_PATH LD_LIBRARY_PATH
switch -glob -- [get-define host] {
*-*-darwin* {
define SH_CFLAGS -dynamic
define SH_LDFLAGS "-dynamiclib"
define SHOBJ_CFLAGS "-dynamic -fno-common"
define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
define SHOBJ_LDFLAGS_R "-bundle"
define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
}
*-*-ming* {
define SH_LDFLAGS -shared
define SHOBJ_LDFLAGS -shared
define SHOBJ_LDFLAGS_R -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
}
sparc* {
# sparc has a very small GOT table limit, so use -fPIC
define SH_LINKFLAGS -rdynamic
define SH_CFLAGS -fPIC
define SH_LDFLAGS -shared
define SHOBJ_CFLAGS -fPIC
define SHOBJ_LDFLAGS -shared
}
* {
# Generic Unix settings
define SH_LINKFLAGS -rdynamic
define SH_CFLAGS -fpic
define SH_LDFLAGS -shared
define SHOBJ_CFLAGS -fpic
define SHOBJ_LDFLAGS -shared
}
}
if {![is-defined SHOBJ_LDFLAGS_R]} {
define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
}
|
Changes to autosetup/cc.tcl.
| ︙ | ︙ | |||
109 110 111 112 113 114 115 |
}
# @cc-check-includes includes ...
#
# Checks that the given include files can be used
proc cc-check-includes {args} {
cc-check-some-feature $args {
| > > > > > > > > > > > > | | > > | > > > > > > > > > > | 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 |
}
# @cc-check-includes includes ...
#
# Checks that the given include files can be used
proc cc-check-includes {args} {
cc-check-some-feature $args {
set with {}
if {[dict exists $::autosetup(cc-include-deps) $each]} {
set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
msg-quiet cc-check-includes $deps
foreach i $deps {
if {[have-feature $i]} {
lappend with $i
}
}
}
if {[llength $with]} {
cc-with [list -includes $with] {
cctest -includes $each
}
} else {
cctest -includes $each
}
}
}
# @cc-include-needs include required
#
# Ensures that when checking for 'include', a check is first
# made for 'required', and if found, it is #included
proc cc-include-needs {file depfile} {
dict set ::autosetup(cc-include-deps) $file $depfile 1
}
# @cc-check-types type ...
#
# Checks that the types exist.
proc cc-check-types {args} {
cc-check-some-feature $args {
cctest_type $each
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 |
} elseif {[llength $args] > 1} {
autosetup-error "usage: cc-with settings ?script?"
} else {
set save [cc-add-settings $settings]
set rc [catch {uplevel 1 [lindex $args 0]} result info]
cc-store-settings $save
if {$rc != 0} {
| | | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
} elseif {[llength $args] > 1} {
autosetup-error "usage: cc-with settings ?script?"
} else {
set save [cc-add-settings $settings]
set rc [catch {uplevel 1 [lindex $args 0]} result info]
cc-store-settings $save
if {$rc != 0} {
return -code [dict get $info -code] $result
}
return $result
}
}
# @cctest ?settings?
#
|
| ︙ | ︙ | |||
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 |
user-error "Could not find a C compiler. Tried: [join $try ", "]"
}
define CCACHE [find-an-executable [get-env CCACHE ccache]]
# Initial cctest settings
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}
msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
if {[get-define CXX] ne "false"} {
msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
}
msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
if {![cc-check-includes stdlib.h]} {
user-error "Compiler does not work. See config.log"
}
| > | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 |
user-error "Could not find a C compiler. Tried: [join $try ", "]"
}
define CCACHE [find-an-executable [get-env CCACHE ccache]]
# Initial cctest settings
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}
set autosetup(cc-include-deps) {}
msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
if {[get-define CXX] ne "false"} {
msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
}
msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
if {![cc-check-includes stdlib.h]} {
user-error "Compiler does not work. See config.log"
}
|
Changes to autosetup/find-tclsh.
1 2 3 4 | #!/bin/sh # Looks for a suitable tclsh or jimsh in the PATH # If not found, builds a bootstrap jimsh from source d=`dirname "$0"` | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/sh
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh from source
d=`dirname "$0"`
{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
PATH="$PATH:$d"; export PATH
for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do
{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
"$d/jimsh0" "$d/test-tclsh" && exit 0
done
|
| ︙ | ︙ |
Changes to autosetup/jimsh0.c.
more than 10,000 changes
Changes to autosetup/system.tcl.
| ︙ | ︙ | |||
224 225 226 227 228 229 230 | 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 | | > | | | | > > > > | | | | | | | | | 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 |
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
set exec_prefix [opt-val exec-prefix $prefix]
define exec_prefix $exec_prefix
foreach {name defpath} {
bindir /bin
sbindir /sbin
libexecdir /libexec
libdir /lib
} {
define $name [opt-val $name $exec_prefix$defpath]
}
foreach {name defpath} {
datadir /share
sysconfdir /etc
sharedstatedir /com
localstatedir /var
infodir /share/info
mandir /share/man
includedir /include
} {
define $name [opt-val $name $prefix$defpath]
}
define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
# Windows vs. non-Windows
switch -glob -- [get-define host] {
*-*-ming* - *-*-cygwin {
|
| ︙ | ︙ |
Changes to autosetup/test-tclsh.
1 2 3 4 5 6 7 |
# A small Tcl script to verify that the chosen
# interpreter works. Sometimes we might e.g. pick up
# an interpreter for a different arch.
# Outputs the full path to the interpreter
if {[catch {info version} version] == 0} {
# This is Jim Tcl
| | < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# A small Tcl script to verify that the chosen
# interpreter works. Sometimes we might e.g. pick up
# an interpreter for a different arch.
# Outputs the full path to the interpreter
if {[catch {info version} version] == 0} {
# This is Jim Tcl
if {$version >= 0.72} {
# Ensure that regexp works
regexp (a.*?) a
puts [info nameofexecutable]
exit 0
}
} elseif {[catch {info tclversion} version] == 0} {
if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
puts [info nameofexecutable]
exit 0
}
|
| ︙ | ︙ |
Changes to configure.
1 2 | #!/bin/sh dir="`dirname "$0"`/autosetup" | | | 1 2 3 | #!/bin/sh dir="`dirname "$0"`/autosetup" WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" |
Changes to debian/makedeb.sh.
1 2 3 4 5 |
#!/bin/bash
# A quick hack to generate a Debian package of fossil. i took most of this
# from Martin Krafft's "The Debian System" book.
DEB_REV=${1-1} # .deb package build/revision number.
| | < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#!/bin/bash
# A quick hack to generate a Debian package of fossil. i took most of this
# from Martin Krafft's "The Debian System" book.
DEB_REV=${1-1} # .deb package build/revision number.
PACKAGE_DEBNAME=fossil
THISDIR=${PWD}
if uname -a | grep -i nexenta &>/dev/null; then
# Assume NexentaOS/GnuSolaris:
DEB_ARCH_NAME=solaris-i386
DEB_ARCH_PKGDEPENDS="sunwcsl" # for -lsocket
else
DEB_ARCH_NAME=$(dpkg --print-architecture)
fi
SRCDIR=$(cd ..; pwd)
test -e ${SRCDIR}/fossil || {
echo "This script must be run from a BUILT copy of the source tree."
exit 1
}
|
| ︙ | ︙ | |||
39 40 41 42 43 44 45 |
rm -fr DEBIAN
mkdir DEBIAN
PACKAGE_VERSION=$(date +%Y.%m.%d)
PACKAGE_DEB_VERSION=${PACKAGE_VERSION}-${DEB_REV}
| | | | | | | | 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 |
rm -fr DEBIAN
mkdir DEBIAN
PACKAGE_VERSION=$(date +%Y.%m.%d)
PACKAGE_DEB_VERSION=${PACKAGE_VERSION}-${DEB_REV}
DEBFILE=${THISDIR}/${PACKAGE_DEBNAME}-${PACKAGE_DEB_VERSION}-dev-${DEB_ARCH_NAME}.deb
PACKAGE_TIME=$(/bin/date)
rm -f ${DEBFILE}
echo "Creating .deb package [${DEBFILE}]..."
echo "Generating md5 sums..."
find ${DEBLOCALPREFIX} -type f -exec md5sum {} \; > DEBIAN/md5sums
true && {
echo "Generating Debian-specific files..."
COPYRIGHT=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/copyright
cat <<EOF > ${COPYRIGHT}
This package was created by fossil-scm <fossil-dev@lists.fossil-scm.org>
on ${PACKAGE_TIME}.
The original sources for fossil can be downloaded for free from:
http://www.fossil-scm.org/
fossil is released under the terms of the GNU General Public License.
EOF
}
true && {
CHANGELOG=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/changelog.gz
cat <<EOF | gzip -c > ${CHANGELOG}
${PACKAGE_DEBNAME} ${PACKAGE_DEB_VERSION}; urgency=low
This release has no changes over the core source distribution. It has
simply been Debianized.
Packaged by fossil-dev <fossil-dev@lists.fossil-scm.org> on
${PACKAGE_TIME}.
EOF
}
true && {
CONTROL=DEBIAN/control
echo "Generating ${CONTROL}..."
cat <<EOF > ${CONTROL}
Package: ${PACKAGE_DEBNAME}
Section: vcs
Priority: optional
Maintainer: fossil-dev <fossil-dev@lists.fossil-scm.org>
Architecture: ${DEB_ARCH_NAME}
Depends: libc6 ${DEB_ARCH_PKGDEPENDS+, }${DEB_ARCH_PKGDEPENDS}
Version: ${PACKAGE_DEB_VERSION}
Description: Fossil is a unique SCM (Software Configuration Management) system.
This package contains the Fossil binary for *buntu/Debian systems.
Fossil is a unique SCM program which supports distributed source control
management using local repositories, access over HTTP CGI, or using the
built-in HTTP server. It has a built-in wiki, file browsing, etc.
Fossil home page: http://fossil-scm.org
|
| ︙ | ︙ |
Changes to src/add.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
** its associated journals
*/
static const char *azName[] = {
"_FOSSIL_",
"_FOSSIL_-journal",
"_FOSSIL_-wal",
"_FOSSIL_-shm",
".fos",
".fos-journal",
".fos-wal",
".fos-shm",
};
/* Names of auxiliary files generated by SQLite when the "manifest"
| > > > > > > > > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
** its associated journals
*/
static const char *azName[] = {
"_FOSSIL_",
"_FOSSIL_-journal",
"_FOSSIL_-wal",
"_FOSSIL_-shm",
".fslckout",
".fslckout-journal",
".fslckout-wal",
".fslckout-shm",
/* The use of ".fos" as the name of the checkout database is
** deprecated. Use ".fslckout" instead. At some point, the following
** entries should be removed. 2012-02-04 */
".fos",
".fos-journal",
".fos-wal",
".fos-shm",
};
/* Names of auxiliary files generated by SQLite when the "manifest"
|
| ︙ | ︙ | |||
231 232 233 234 235 236 237 |
/* Load the names of all files that are to be added into sfile temp table */
for(i=2; i<g.argc; i++){
char *zName;
int isDir;
Blob fullName;
| | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
/* Load the names of all files that are to be added into sfile temp table */
for(i=2; i<g.argc; i++){
char *zName;
int isDir;
Blob fullName;
file_canonical_name(g.argv[i], &fullName, 0);
zName = blob_str(&fullName);
isDir = file_wd_isdir(zName);
if( isDir==1 ){
vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore);
}else if( isDir==0 ){
fossil_fatal("not found: %s", zName);
}else if( file_access(zName, R_OK) ){
|
| ︙ | ︙ | |||
497 498 499 500 501 502 503 | ** Move or rename one or more files or directories within the repository tree. ** You can either rename a file or directory or move it to another subdirectory. ** ** This command does NOT rename or move the files on disk. This command merely ** records the fact that filenames have changed so that appropriate notations ** can be made at the next commit/checkin. ** | | < < | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 |
** Move or rename one or more files or directories within the repository tree.
** You can either rename a file or directory or move it to another subdirectory.
**
** This command does NOT rename or move the files on disk. This command merely
** records the fact that filenames have changed so that appropriate notations
** can be made at the next commit/checkin.
**
** See also: changes, status
*/
void mv_cmd(void){
int i;
int vid;
char *zDest;
Blob dest;
Stmt q;
|
| ︙ | ︙ |
Changes to src/allrepo.c.
| ︙ | ︙ | |||
166 167 168 169 170 171 172 |
db_unset(zRepo, 1);
free(zRepo);
}else if( !file_is_canonical(zFilename) ){
Blob cname;
char *zRepo = mprintf("repo:%s", zFilename);
db_unset(zRepo, 1);
free(zRepo);
| | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
db_unset(zRepo, 1);
free(zRepo);
}else if( !file_is_canonical(zFilename) ){
Blob cname;
char *zRepo = mprintf("repo:%s", zFilename);
db_unset(zRepo, 1);
free(zRepo);
file_canonical_name(zFilename, &cname, 0);
zRepo = mprintf("repo:%s", blob_str(&cname));
db_set(zRepo, "1", 1);
free(zRepo);
}
}
db_reset(&q);
db_end_transaction(0);
|
| ︙ | ︙ |
Changes to src/blob.c.
| ︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
*/
int fossil_islower(char c){ return c>='a' && c<='z'; }
int fossil_isupper(char c){ return c>='A' && c<='Z'; }
int fossil_isdigit(char c){ return c>='0' && c<='9'; }
int fossil_tolower(char c){
return fossil_isupper(c) ? c - 'A' + 'a' : c;
}
int fossil_isalpha(char c){
return (c>='a' && c<='z') || (c>='A' && c<='Z');
}
int fossil_isalnum(char c){
return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
}
| > > > | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
*/
int fossil_islower(char c){ return c>='a' && c<='z'; }
int fossil_isupper(char c){ return c>='A' && c<='Z'; }
int fossil_isdigit(char c){ return c>='0' && c<='9'; }
int fossil_tolower(char c){
return fossil_isupper(c) ? c - 'A' + 'a' : c;
}
int fossil_toupper(char c){
return fossil_islower(c) ? c - 'a' + 'A' : c;
}
int fossil_isalpha(char c){
return (c>='a' && c<='z') || (c>='A' && c<='Z');
}
int fossil_isalnum(char c){
return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
}
|
| ︙ | ︙ | |||
789 790 791 792 793 794 795 |
nName = strlen(zFilename);
if( nName>=sizeof(zBuf) ){
zName = mprintf("%s", zFilename);
}else{
zName = zBuf;
memcpy(zName, zFilename, nName+1);
}
| | | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 |
nName = strlen(zFilename);
if( nName>=sizeof(zBuf) ){
zName = mprintf("%s", zFilename);
}else{
zName = zBuf;
memcpy(zName, zFilename, nName+1);
}
nName = file_simplify_name(zName, nName, 0);
for(i=1; i<nName; i++){
if( zName[i]=='/' ){
zName[i] = 0;
#if defined(_WIN32)
/*
** On Windows, local path looks like: C:/develop/project/file.txt
** The if stops us from trying to create a directory of a drive letter
|
| ︙ | ︙ |
Changes to src/branch.c.
| ︙ | ︙ | |||
144 145 146 147 148 149 150 |
prompt_user("unable to sign manifest. continue (y/N)? ", &ans);
if( blob_str(&ans)[0]!='y' ){
db_end_transaction(1);
fossil_exit(1);
}
}
| | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
prompt_user("unable to sign manifest. continue (y/N)? ", &ans);
if( blob_str(&ans)[0]!='y' ){
db_end_transaction(1);
fossil_exit(1);
}
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
fossil_panic("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
if( manifest_crosslink(brid, &branch)==0 ){
fossil_panic("unable to install new manifest");
}
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
**
** Examples:
**
** pathelement('abc/pqr/xyz', 4) -> '/pqr'
** pathelement('abc/pqr', 4) -> 'pqr'
** pathelement('abc/pqr/xyz', 0) -> '/abc'
*/
| | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
**
** Examples:
**
** pathelement('abc/pqr/xyz', 4) -> '/pqr'
** pathelement('abc/pqr', 4) -> 'pqr'
** pathelement('abc/pqr/xyz', 0) -> '/abc'
*/
void pathelementFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const unsigned char *z;
int len, n, i;
char *zOut;
|
| ︙ | ︙ |
Changes to src/cgi.c.
| ︙ | ︙ | |||
736 737 738 739 740 741 742 743 744 745 746 747 |
**
** If contentLen is 0 then the whole file is read.
*/
void cgi_parse_POST_JSON( FILE * zIn, unsigned int contentLen ){
cson_value * jv = NULL;
int rc;
CgiPostReadState state;
state.fh = zIn;
state.len = contentLen;
state.pos = 0;
rc = cson_parse( &jv,
contentLen ? cson_data_source_FILE_n : cson_data_source_FILE,
| > > > | > > > > > > > > > > > | > | 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 |
**
** If contentLen is 0 then the whole file is read.
*/
void cgi_parse_POST_JSON( FILE * zIn, unsigned int contentLen ){
cson_value * jv = NULL;
int rc;
CgiPostReadState state;
cson_parse_opt popt = cson_parse_opt_empty;
cson_parse_info pinfo = cson_parse_info_empty;
popt.maxDepth = 15;
state.fh = zIn;
state.len = contentLen;
state.pos = 0;
rc = cson_parse( &jv,
contentLen ? cson_data_source_FILE_n : cson_data_source_FILE,
contentLen ? (void *)&state : (void *)zIn, &popt, &pinfo );
if(rc){
goto invalidRequest;
}else{
json_gc_add( "POST.JSON", jv );
g.json.post.v = jv;
g.json.post.o = cson_value_get_object( jv );
if( !g.json.post.o ){ /* we don't support non-Object (Array) requests */
goto invalidRequest;
}
}
return;
invalidRequest:
cgi_set_content_type(json_guess_content_type());
if(0 != pinfo.errorCode){ /* fancy error message */
char * msg = mprintf("JSON parse error at line %u, column %u, "
"byte offset %u: %s",
pinfo.line, pinfo.col, pinfo.length,
cson_rc_string(pinfo.errorCode));
json_err( FSL_JSON_E_INVALID_REQUEST, msg, 1 );
free(msg);
}else if(jv && !g.json.post.o){
json_err( FSL_JSON_E_INVALID_REQUEST,
"Request envelope must be a JSON Object (not array).", 1 );
}else{ /* generic error message */
json_err( FSL_JSON_E_INVALID_REQUEST, NULL, 1 );
}
fossil_exit( g.isHTTP ? 0 : 1);
}
#endif /* FOSSIL_ENABLE_JSON */
/*
** Initialize the query parameter database. Information is pulled from
|
| ︙ | ︙ | |||
912 913 914 915 916 917 918 |
}
/* If no match is found and the name begins with an upper-case
** letter, then check to see if there is an environment variable
** with the given name.
*/
if( fossil_isupper(zName[0]) ){
| | | 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 |
}
/* If no match is found and the name begins with an upper-case
** letter, then check to see if there is an environment variable
** with the given name.
*/
if( fossil_isupper(zName[0]) ){
const char *zValue = fossil_getenv(zName);
if( zValue ){
cgi_set_parameter_nocopy(zName, zValue);
CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
return zValue;
}
}
CGIDEBUG(("no-match [%s]\n", zName));
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 |
const char *zDisplayName = zPathname;
int isDeleted = db_column_int(&q, 1);
int isChnged = db_column_int(&q,2);
int isNew = db_column_int(&q,3)==0;
int isRenamed = db_column_int(&q,4);
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
if( cwdRelative ){
| | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
const char *zDisplayName = zPathname;
int isDeleted = db_column_int(&q, 1);
int isChnged = db_column_int(&q,2);
int isNew = db_column_int(&q,3)==0;
int isRenamed = db_column_int(&q,4);
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
if( cwdRelative ){
file_relative_name(zFullName, &rewrittenPathname, 0);
zDisplayName = blob_str(&rewrittenPathname);
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
zDisplayName += 2; /* no unnecessary ./ prefix */
}
}
blob_append(report, zPrefix, nPrefix);
if( isDeleted ){
|
| ︙ | ︙ | |||
178 179 180 181 182 183 184 |
**
** See also: changes, extra, ls
*/
void status_cmd(void){
int vid;
db_must_be_within_tree();
/* 012345678901234 */
| | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
**
** See also: changes, extra, ls
*/
void status_cmd(void){
int vid;
db_must_be_within_tree();
/* 012345678901234 */
fossil_print("repository: %s\n", db_repository_filename());
fossil_print("local-root: %s\n", g.zLocalRoot);
vid = db_lget_int("checkout", 0);
if( vid ){
show_common_info(vid, "checkout:", 1, 1);
}
db_record_repository_filename(0);
changes_cmd();
|
| ︙ | ︙ | |||
311 312 313 314 315 316 317 |
}
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
blob_zero(&rewrittenPathname);
while( db_step(&q)==SQLITE_ROW ){
zDisplayName = zPathname = db_column_text(&q, 0);
if( cwdRelative ) {
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
| | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
}
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
blob_zero(&rewrittenPathname);
while( db_step(&q)==SQLITE_ROW ){
zDisplayName = zPathname = db_column_text(&q, 0);
if( cwdRelative ) {
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
file_relative_name(zFullName, &rewrittenPathname, 0);
free(zFullName);
zDisplayName = blob_str(&rewrittenPathname);
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
zDisplayName += 2; /* no unnecessary ./ prefix */
}
}
fossil_print("%s\n", zDisplayName);
|
| ︙ | ︙ | |||
454 455 456 457 458 459 460 |
"# repositories.\n"
"#\n", -1
);
}
status_report(&text, "# ", 1, 0);
zEditor = db_get("editor", 0);
if( zEditor==0 ){
| | | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
"# repositories.\n"
"#\n", -1
);
}
status_report(&text, "# ", 1, 0);
zEditor = db_get("editor", 0);
if( zEditor==0 ){
zEditor = fossil_getenv("VISUAL");
}
if( zEditor==0 ){
zEditor = fossil_getenv("EDITOR");
}
if( zEditor==0 ){
blob_append(&text,
"#\n"
"# Since no default text editor is set using EDITOR or VISUAL\n"
"# environment variables or the \"fossil set editor\" command,\n"
"# and because no check-in comment was specified using the \"-m\"\n"
|
| ︙ | ︙ | |||
630 631 632 633 634 635 636 | Blob *pComment, /* Check-in comment text */ int vid, /* blob-id of the parent manifest */ int verifyDate, /* Verify that child is younger */ Blob *pCksum, /* Repository checksum. May be 0 */ const char *zDateOvrd, /* Date override. If 0 then use 'now' */ const char *zUserOvrd, /* User override. If 0 then use g.zLogin */ const char *zBranch, /* Branch name. May be 0 */ | | > | > | 630 631 632 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 |
Blob *pComment, /* Check-in comment text */
int vid, /* blob-id of the parent manifest */
int verifyDate, /* Verify that child is younger */
Blob *pCksum, /* Repository checksum. May be 0 */
const char *zDateOvrd, /* Date override. If 0 then use 'now' */
const char *zUserOvrd, /* User override. If 0 then use g.zLogin */
const char *zBranch, /* Branch name. May be 0 */
const char *zColor, /* One-time gackground color. May be 0 */
const char *zBrClr, /* Persistent branch color. May be 0 */
const char **azTag, /* Tags to apply to this check-in */
int *pnFBcard /* Number of generated B- and F-cards */
){
char *zDate; /* Date of the check-in */
char *zParentUuid; /* UUID of parent check-in */
Blob filename; /* A single filename */
int nBasename; /* Size of base filename */
Stmt q; /* Query of files changed */
Stmt q2; /* Query of merge parents */
Blob mcksum; /* Manifest checksum */
ManifestFile *pFile; /* File from the baseline */
int nFBcard = 0; /* Number of B-cards and F-cards */
int i; /* Loop counter */
assert( pBaseline==0 || pBaseline->zBaseline==0 );
assert( pBaseline==0 || zBaselineUuid!=0 );
blob_zero(pOut);
zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
if( pBaseline ){
blob_appendf(pOut, "B %s\n", zBaselineUuid);
|
| ︙ | ︙ | |||
754 755 756 757 758 759 760 |
db_finalize(&q2);
free(zDate);
blob_appendf(pOut, "\n");
if( pCksum ) blob_appendf(pOut, "R %b\n", pCksum);
if( zBranch && zBranch[0] ){
/* Set tags for the new branch */
| > | | > > > > | > | > | > | | | 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 |
db_finalize(&q2);
free(zDate);
blob_appendf(pOut, "\n");
if( pCksum ) blob_appendf(pOut, "R %b\n", pCksum);
if( zBranch && zBranch[0] ){
/* Set tags for the new branch */
if( zBrClr && zBrClr[0] ){
zColor = 0;
blob_appendf(pOut, "T *bgcolor * %F\n", zBrClr);
}
blob_appendf(pOut, "T *branch * %F\n", zBranch);
blob_appendf(pOut, "T *sym-%F *\n", zBranch);
}
if( zColor && zColor[0] ){
/* One-time background color */
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
}
if( g.markPrivate ){
/* If this manifest is private, mark it as such */
blob_appendf(pOut, "T +private *\n");
}
if( azTag ){
for(i=0; azTag[i]; i++){
/* Add a symbolic tag to this check-in. The tag names have already
** been sorted and converted using the %F format */
blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
}
}
if( zBranch && zBranch[0] ){
/* For a new branch, cancel all prior propagating tags */
Stmt q;
db_prepare(&q,
"SELECT tagname FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
" AND tagtype==2 AND tagname GLOB 'sym-*'"
" AND tagname!='sym-'||%Q"
" ORDER BY tagname",
vid, zBranch);
while( db_step(&q)==SQLITE_ROW ){
const char *zBrTag = db_column_text(&q, 0);
blob_appendf(pOut, "T -%F *\n", zBrTag);
}
db_finalize(&q);
}
blob_appendf(pOut, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
md5sum_blob(pOut, &mcksum);
blob_appendf(pOut, "Z %b\n", &mcksum);
if( pnFBcard ) *pnFBcard = nFBcard;
|
| ︙ | ︙ | |||
824 825 826 827 828 829 830 |
}else{
lastNl++;
if( lastNl>1000 ) return; /* Binary if any line longer than 1000 */
}
}
if( nCrNl ){
char c;
| | > > > > > > > > > | 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 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 |
}else{
lastNl++;
if( lastNl>1000 ) return; /* Binary if any line longer than 1000 */
}
}
if( nCrNl ){
char c;
file_relative_name(zFilename, &fname, 0);
blob_zero(&ans);
zMsg = mprintf(
"%s contains CR/NL line endings; commit anyhow (yes/no/all)?",
blob_str(&fname));
prompt_user(zMsg, &ans);
fossil_free(zMsg);
c = blob_str(&ans)[0];
if( c=='a' ){
allOk = 1;
}else if( c!='y' ){
fossil_fatal("Abandoning commit due to CR+NL line endings in %s",
blob_str(&fname));
}
blob_reset(&ans);
blob_reset(&fname);
}
}
/*
** qsort() comparison routine for an array of pointers to strings.
*/
static int tagCmp(const void *a, const void *b){
char **pA = (char**)a;
char **pB = (char**)b;
return fossil_strcmp(pA[0], pB[0]);
}
/*
** COMMAND: ci*
** COMMAND: commit
**
** Usage: %fossil commit ?OPTIONS? ?FILE...?
**
|
| ︙ | ︙ | |||
875 876 877 878 879 880 881 | ** The --private option creates a private check-in that is never synced. ** Children of private check-ins are automatically private. ** ** the --tag option applies the symbolic tag name to the check-in. ** ** Options: ** --baseline use a baseline manifest in the commit process | | > | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | ** The --private option creates a private check-in that is never synced. ** Children of private check-ins are automatically private. ** ** the --tag option applies the symbolic tag name to the check-in. ** ** Options: ** --baseline use a baseline manifest in the commit process ** --bgcolor COLOR apply COLOR to this one check-in only ** --branch NEW-BRANCH-NAME check in to this new branch ** --branchcolor COLOR apply given COLOR to the branch ** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment ** --delta use a delta manifest in the commit process ** --force|-f allow forking with this commit ** --message-file|-M FILE read the commit comment from given file ** --nosign do not attempt to sign this commit with gpg ** --private do not sync changes and their descendants ** --tag TAG-NAME assign given tag TAG-NAME to the checkin |
| ︙ | ︙ | |||
906 907 908 909 910 911 912 | int forceDelta = 0; /* Force a delta-manifest */ int forceBaseline = 0; /* Force a baseline-manifest */ char *zManifestFile; /* Name of the manifest file */ int useCksum; /* True if checksums should be computed and verified */ int outputManifest; /* True to output "manifest" and "manifest.uuid" */ int testRun; /* True for a test run. Debugging only */ const char *zBranch; /* Create a new branch with this name */ | | > > | > | > | > > > > > | > > > > > > > | 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 |
int forceDelta = 0; /* Force a delta-manifest */
int forceBaseline = 0; /* Force a baseline-manifest */
char *zManifestFile; /* Name of the manifest file */
int useCksum; /* True if checksums should be computed and verified */
int outputManifest; /* True to output "manifest" and "manifest.uuid" */
int testRun; /* True for a test run. Debugging only */
const char *zBranch; /* Create a new branch with this name */
const char *zBrClr; /* Set background color when branching */
const char *zColor; /* One-time check-in color */
const char *zDateOvrd; /* Override date string */
const char *zUserOvrd; /* Override user name */
const char *zComFile; /* Read commit message from this file */
int nTag = 0; /* Number of --tag arguments */
const char *zTag; /* A single --tag argument */
const char **azTag = 0;/* Array of all --tag arguments */
Blob manifest; /* Manifest in baseline form */
Blob muuid; /* Manifest uuid */
Blob cksum1, cksum2; /* Before and after commit checksums */
Blob cksum1b; /* Checksum recorded in the manifest */
int szD; /* Size of the delta manifest */
int szB; /* Size of the baseline manifest */
url_proxy_options();
noSign = find_option("nosign",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta && forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
testRun = find_option("test",0,0)!=0;
zComment = find_option("comment","m",1);
forceFlag = find_option("force", "f", 0)!=0;
zBranch = find_option("branch","b",1);
zColor = find_option("bgcolor",0,1);
zBrClr = find_option("branchcolor",0,1);
while( (zTag = find_option("tag",0,1))!=0 ){
if( zTag[0]==0 ) continue;
azTag = fossil_realloc(azTag, sizeof(char*)*(nTag+2));
azTag[nTag++] = zTag;
azTag[nTag] = 0;
}
zComFile = find_option("message-file", "M", 1);
if( find_option("private",0,0) ){
g.markPrivate = 1;
if( zBranch==0 ) zBranch = "private";
if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */
}
zDateOvrd = find_option("date-override",0,1);
zUserOvrd = find_option("user-override",0,1);
db_must_be_within_tree();
noSign = db_get_boolean("omitsign", 0)|noSign;
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
useCksum = db_get_boolean("repo-cksum", 1);
outputManifest = db_get_boolean("manifest", 0);
verify_all_options();
/* Escape special characters in tags and put all tags in sorted order */
if( nTag ){
int i;
for(i=0; i<nTag; i++) azTag[i] = mprintf("%F", azTag[i]);
qsort((void*)azTag, nTag, sizeof(azTag[0]), tagCmp);
}
/* So that older versions of Fossil (that do not understand delta-
** manifest) can continue to use this repository, do not create a new
** delta-manifest unless this repository already contains one or more
** delta-manifets, or unless the delta-manifest is explicitly requested
** by the --delta option.
*/
|
| ︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 |
blob_append(&comment, "(no comment)", -1);
}
if( forceDelta ){
blob_zero(&manifest);
}else{
create_manifest(&manifest, 0, 0, &comment, vid,
!forceFlag, useCksum ? &cksum1 : 0,
| | > | > | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 |
blob_append(&comment, "(no comment)", -1);
}
if( forceDelta ){
blob_zero(&manifest);
}else{
create_manifest(&manifest, 0, 0, &comment, vid,
!forceFlag, useCksum ? &cksum1 : 0,
zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
azTag, &szB);
}
/* See if a delta-manifest would be more appropriate */
if( !forceBaseline ){
const char *zBaselineUuid;
Manifest *pParent;
Manifest *pBaseline;
pParent = manifest_get(vid, CFTYPE_MANIFEST);
if( pParent && pParent->zBaseline ){
zBaselineUuid = pParent->zBaseline;
pBaseline = manifest_get_by_name(zBaselineUuid, 0);
}else{
zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
pBaseline = pParent;
}
if( pBaseline ){
Blob delta;
create_manifest(&delta, zBaselineUuid, pBaseline, &comment, vid,
!forceFlag, useCksum ? &cksum1 : 0,
zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
azTag, &szD);
/*
** At this point, two manifests have been constructed, either of
** which would work for this checkin. The first manifest (held
** in the "manifest" variable) is a baseline manifest and the second
** (held in variable named "delta") is a delta manifest. The
** question now is: which manifest should we use?
**
|
| ︙ | ︙ |
Changes to src/clone.c.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** This file contains code used to clone a repository */ #include "config.h" #include "clone.h" #include <assert.h> /* ** COMMAND: clone ** ** Usage: %fossil clone ?OPTIONS? URL FILENAME ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
**
** This file contains code used to clone a repository
*/
#include "config.h"
#include "clone.h"
#include <assert.h>
/*
** If there are public BLOBs that deltas from private BLOBs, then
** undeltify the public BLOBs so that the private BLOBs may be safely
** deleted.
*/
void fix_private_blob_dependencies(int showWarning){
Bag toUndelta;
Stmt q;
int rid;
/* Careful: We are about to delete all BLOB entries that are private.
** So make sure that any no public BLOBs are deltas from a private BLOB.
** Otherwise after the deletion, we won't be able to recreate the public
** BLOBs.
*/
db_prepare(&q,
"SELECT "
" rid, (SELECT uuid FROM blob WHERE rid=delta.rid),"
" srcid, (SELECT uuid FROM blob WHERE rid=delta.srcid)"
" FROM delta"
" WHERE srcid in private AND rid NOT IN private"
);
bag_init(&toUndelta);
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
const char *zId = db_column_text(&q, 1);
int srcid = db_column_int(&q, 2);
const char *zSrc = db_column_text(&q, 3);
if( showWarning ){
fossil_warning(
"public artifact %S (%d) is a delta from private artifact %S (%d)",
zId, rid, zSrc, srcid
);
}
bag_insert(&toUndelta, rid);
}
db_finalize(&q);
while( (rid = bag_first(&toUndelta))>0 ){
content_undelta(rid);
bag_remove(&toUndelta, rid);
}
bag_clear(&toUndelta);
}
/*
** Delete all private content from a repository.
*/
void delete_private_content(void){
fix_private_blob_dependencies(1);
db_multi_exec(
"DELETE FROM blob WHERE rid IN private;"
"DELETE FROM delta wHERE rid IN private;"
"DELETE FROM private;"
);
}
/*
** COMMAND: clone
**
** Usage: %fossil clone ?OPTIONS? URL FILENAME
**
|
| ︙ | ︙ | |||
70 71 72 73 74 75 76 |
db_multi_exec(
"REPLACE INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))),now());"
"REPLACE INTO config(name,value,mtime)"
" VALUES('last-sync-url', '%q',now());",
g.urlCanonical
);
| < < < | < | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
db_multi_exec(
"REPLACE INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))),now());"
"REPLACE INTO config(name,value,mtime)"
" VALUES('last-sync-url', '%q',now());",
g.urlCanonical
);
if( !bPrivate ) delete_private_content();
shun_artifacts();
db_create_default_users(1, zDefaultUser);
if( zDefaultUser ){
g.zLogin = zDefaultUser;
}else{
g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
}
|
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
db_set("last-sync-url", g.argv[2], 0);
if( g.zSSLIdentity!=0 ){
/* If the --ssl-identity option was specified, store it as a setting */
Blob fn;
blob_zero(&fn);
| | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
db_set("last-sync-url", g.argv[2], 0);
if( g.zSSLIdentity!=0 ){
/* If the --ssl-identity option was specified, store it as a setting */
Blob fn;
blob_zero(&fn);
file_canonical_name(g.zSSLIdentity, &fn, 0);
db_set("ssl-identity", blob_str(&fn), 0);
blob_reset(&fn);
}
db_multi_exec(
"REPLACE INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))), now());"
);
|
| ︙ | ︙ |
Changes to src/configure.c.
| ︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
#endif
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "ticket-table", CONFIGSET_TKT },
{ "ticket-common", CONFIGSET_TKT },
{ "ticket-newpage", CONFIGSET_TKT },
{ "ticket-viewpage", CONFIGSET_TKT },
{ "ticket-editpage", CONFIGSET_TKT },
{ "ticket-reportlist", CONFIGSET_TKT },
{ "ticket-report-template", CONFIGSET_TKT },
{ "ticket-key-template", CONFIGSET_TKT },
{ "ticket-title-expr", CONFIGSET_TKT },
| > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
#endif
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "ticket-table", CONFIGSET_TKT },
{ "ticket-common", CONFIGSET_TKT },
{ "ticket-change", CONFIGSET_TKT },
{ "ticket-newpage", CONFIGSET_TKT },
{ "ticket-viewpage", CONFIGSET_TKT },
{ "ticket-editpage", CONFIGSET_TKT },
{ "ticket-reportlist", CONFIGSET_TKT },
{ "ticket-report-template", CONFIGSET_TKT },
{ "ticket-key-template", CONFIGSET_TKT },
{ "ticket-title-expr", CONFIGSET_TKT },
|
| ︙ | ︙ | |||
782 783 784 785 786 787 788 | ** ** Synchronize configuration changes in the local repository with ** the remote repository at URL. ** ** Options: ** -R|--repository FILE Extract info from repository FILE ** | | | 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 |
**
** Synchronize configuration changes in the local repository with
** the remote repository at URL.
**
** Options:
** -R|--repository FILE Extract info from repository FILE
**
** See also: settings, unset
*/
void configuration_cmd(void){
int n;
const char *zMethod;
if( g.argc<3 ){
usage("export|import|merge|pull|reset ...");
}
|
| ︙ | ︙ |
Changes to src/content.c.
| ︙ | ︙ | |||
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
**
** Extract an artifact by its SHA1 hash and write the results on
** standard output, or if the optional 4th argument is given, in
** the named output file.
**
** Options:
** -R|--repository FILE Extract artifacts from repository FILE
*/
void artifact_cmd(void){
int rid;
Blob content;
const char *zFile;
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
if( g.argc!=4 && g.argc!=3 ) usage("ARTIFACT-ID ?FILENAME? ?OPTIONS?");
zFile = g.argc==4 ? g.argv[3] : "-";
rid = name_to_rid(g.argv[2]);
content_get(rid, &content);
blob_write_to_file(&content, zFile);
}
/*
** COMMAND: test-content-rawget
**
| > > > > > | 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 |
**
** Extract an artifact by its SHA1 hash and write the results on
** standard output, or if the optional 4th argument is given, in
** the named output file.
**
** Options:
** -R|--repository FILE Extract artifacts from repository FILE
**
** See also: finfo
*/
void artifact_cmd(void){
int rid;
Blob content;
const char *zFile;
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
if( g.argc!=4 && g.argc!=3 ) usage("ARTIFACT-ID ?FILENAME? ?OPTIONS?");
zFile = g.argc==4 ? g.argv[3] : "-";
rid = name_to_rid(g.argv[2]);
if( rid==0 ){
fossil_fatal("%s",g.zErrMsg);
}
content_get(rid, &content);
blob_write_to_file(&content, zFile);
}
/*
** COMMAND: test-content-rawget
**
|
| ︙ | ︙ |
Changes to src/cson_amalgamation.c.
| ︙ | ︙ | |||
1425 1426 1427 1428 1429 1430 1431 |
/**
Type IDs corresponding to JavaScript/JSON types.
*/
enum cson_type_id {
/**
| | | 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 |
/**
Type IDs corresponding to JavaScript/JSON types.
*/
enum cson_type_id {
/**
The special "undefined" value constant.
Its value must be 0 for internal reasons.
*/
CSON_TYPE_UNDEF = 0,
/**
The special "null" value constant.
*/
|
| ︙ | ︙ | |||
1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 |
static const cson_value cson_value_bool_empty = { &cson_value_api_bool, NULL, 0 };
static const cson_value cson_value_integer_empty = { &cson_value_api_integer, NULL, 0 };
static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 };
static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 };
static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 };
static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 };
struct cson_string
{
unsigned int length;
};
#define cson_string_empty_m {0/*length*/}
static const cson_string cson_string_empty = cson_string_empty_m;
#define CSON_CAST(T,V) ((T*)((V)->value))
#define CSON_VCAST(V) ((cson_value *)(((unsigned char *)(V))-sizeof(cson_value)))
| > > > > > > > > > > > > | > > | 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 |
static const cson_value cson_value_bool_empty = { &cson_value_api_bool, NULL, 0 };
static const cson_value cson_value_integer_empty = { &cson_value_api_integer, NULL, 0 };
static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 };
static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 };
static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 };
static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 };
/**
Strings are allocated as an instances of this class with N+1
trailing bytes, where N is the length of the string being
allocated. To convert a cson_string to c-string we simply increment
the cson_string pointer. To do the opposite we use (cstr -
sizeof(cson_string)). Zero-length strings are a special case
handled by a couple of the cson_string functions.
*/
struct cson_string
{
unsigned int length;
};
#define cson_string_empty_m {0/*length*/}
static const cson_string cson_string_empty = cson_string_empty_m;
#define CSON_CAST(T,V) ((T*)((V)->value))
#define CSON_VCAST(V) ((cson_value *)(((unsigned char *)(V))-sizeof(cson_value)))
#if CSON_VOID_PTR_IS_BIG
# define CSON_INT(V) ((cson_int_t*)(&((V)->value)))
#else
# define CSON_INT(V) ((cson_int_t*)(V)->value)
#endif
#define CSON_DBL(V) CSON_CAST(cson_double_t,(V))
#define CSON_STR(V) CSON_CAST(cson_string,(V))
#define CSON_OBJ(V) CSON_CAST(cson_object,(V))
#define CSON_ARRAY(V) CSON_CAST(cson_array,(V))
/**
|
| ︙ | ︙ | |||
1666 1667 1668 1669 1670 1671 1672 |
{ &cson_value_api_undef, NULL, 0 }, /* UNDEF */
{ &cson_value_api_null, NULL, 0 }, /* NULL */
{ &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */
{ &cson_value_api_bool, NULL, 0 }, /* FALSE */
{ &cson_value_api_integer, NULL, 0 }, /* INT_0 */
{ &cson_value_api_double, NULL, 0 }, /* DBL_0 */
{ &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */
| | | 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 |
{ &cson_value_api_undef, NULL, 0 }, /* UNDEF */
{ &cson_value_api_null, NULL, 0 }, /* NULL */
{ &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */
{ &cson_value_api_bool, NULL, 0 }, /* FALSE */
{ &cson_value_api_integer, NULL, 0 }, /* INT_0 */
{ &cson_value_api_double, NULL, 0 }, /* DBL_0 */
{ &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */
{ NULL, NULL, 0 }
};
/**
Returns non-0 (true) if m is one of our special
"built-in" values, e.g. from CSON_SPECIAL_VALUES and some
"empty" values.
|
| ︙ | ︙ | |||
1914 1915 1916 1917 1918 1919 1920 | /** Fetches v's string value as a non-const string. cson_strings are supposed to be immutable, but this form provides access to the immutable bits, which are v->length bytes long. A length-0 string is returned as NULL from here, as opposed to "". (This is a side-effect of the string allocation mechanism.) | | | 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
/**
Fetches v's string value as a non-const string.
cson_strings are supposed to be immutable, but this form provides
access to the immutable bits, which are v->length bytes long. A
length-0 string is returned as NULL from here, as opposed to
"". (This is a side-effect of the string allocation mechanism.)
Returns NULL if !v or if v is the internal empty-string singleton.
*/
static char * cson_string_str(cson_string *v)
{
/*
See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
*/
#if 1
|
| ︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 |
{
/*
See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
*/
#if 1
if( ! v ) return NULL;
else if( v == &CSON_EMPTY_HOLDER.stringValue ) return "";
| > > | > | 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 |
{
/*
See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
*/
#if 1
if( ! v ) return NULL;
else if( v == &CSON_EMPTY_HOLDER.stringValue ) return "";
else {
assert((0 < v->length) && "How do we have a non-singleton empty string?");
return (char const *)((unsigned char const *)(v+1));
}
#else
return (NULL == v)
? NULL
: (v->length
? (char const *) ((unsigned char const *)(v+1))
: "");
#endif
|
| ︙ | ︙ | |||
2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 |
cson_value * key;
cson_value * value;
};
#define cson_kvp_empty_m {NULL,NULL}
static const cson_kvp cson_kvp_empty = cson_kvp_empty_m;
/** @def CSON_OBJECT_PROPS_SORT
If CSON_OBJECT_PROPS_SORT is set to a true value then
qsort() and bsearch() are used to sort (upon insertion)
and search cson_object::kvp property lists. This costs us
a re-sort on each insertion but searching is O(log n)
average/worst case (and O(1) best-case).
| > > > | 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 |
cson_value * key;
cson_value * value;
};
#define cson_kvp_empty_m {NULL,NULL}
static const cson_kvp cson_kvp_empty = cson_kvp_empty_m;
/** @def CSON_OBJECT_PROPS_SORT
Don't use this - it has not been updated to account for internal
changes in cson_object.
If CSON_OBJECT_PROPS_SORT is set to a true value then
qsort() and bsearch() are used to sort (upon insertion)
and search cson_object::kvp property lists. This costs us
a re-sort on each insertion but searching is O(log n)
average/worst case (and O(1) best-case).
|
| ︙ | ︙ | |||
2198 2199 2200 2201 2202 2203 2204 | # define LIST_T cson_kvp_list # define VALUE_T cson_kvp * # define VALUE_T_IS_PTR 1 #else #endif /** | | | < | | > | < < | 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 |
# define LIST_T cson_kvp_list
# define VALUE_T cson_kvp *
# define VALUE_T_IS_PTR 1
#else
#endif
/**
Allocates a new value of the specified type. Ownership is
transfered to the caller, who must eventually free it by passing it
to cson_value_free() or transfering ownership to a container.
extra is only valid for type CSON_TYPE_STRING, and must be the length
of the string to allocate + 1 byte (for the NUL).
The returned value->api member will be set appropriately and
val->value will be set to point to the memory allocated to hold the
native value type. Use the internal CSON_CAST() family of macros to
convert the cson_values to their corresponding native
representation.
Returns NULL on allocation error.
@see cson_value_new_array()
@see cson_value_new_object()
@see cson_value_new_string()
@see cson_value_new_integer()
@see cson_value_new_double()
@see cson_value_new_bool()
@see cson_value_free()
*/
static cson_value * cson_value_new(cson_type_id t, size_t extra)
{
static const size_t vsz = sizeof(cson_value);
const size_t sz = vsz + extra;
size_t tx = 0;
cson_value def = cson_value_undef;
cson_value * v = NULL;
char const * reason = "cson_value_new";
|
| ︙ | ︙ | |||
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 |
def = cson_value_double_empty;
tx = sizeof(cson_double_t);
reason = "cson_value:double";
break;
case CSON_TYPE_INTEGER:
assert( 0 == extra );
def = cson_value_integer_empty;
tx = sizeof(cson_int_t);
reason = "cson_value:int";
break;
case CSON_TYPE_STRING:
assert( 0 != extra );
def = cson_value_string_empty;
tx = sizeof(cson_string);
reason = "cson_value:string";
| > > | 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 |
def = cson_value_double_empty;
tx = sizeof(cson_double_t);
reason = "cson_value:double";
break;
case CSON_TYPE_INTEGER:
assert( 0 == extra );
def = cson_value_integer_empty;
#if !CSON_VOID_PTR_IS_BIG
tx = sizeof(cson_int_t);
#endif
reason = "cson_value:int";
break;
case CSON_TYPE_STRING:
assert( 0 != extra );
def = cson_value_string_empty;
tx = sizeof(cson_string);
reason = "cson_value:string";
|
| ︙ | ︙ | |||
2279 2280 2281 2282 2283 2284 2285 |
memset(v+1, 0, tx + extra);
v->value = (void *)(v+1);
}
}
return v;
}
| < | 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 |
memset(v+1, 0, tx + extra);
v->value = (void *)(v+1);
}
}
return v;
}
void cson_value_free(cson_value *v)
{
cson_refcount_decr( v );
}
#if 0 /* we might actually want this later on. */
/** Returns true if v is not NULL and has the given type ID. */
|
| ︙ | ︙ | |||
2302 2303 2304 2305 2306 2307 2308 |
{
return (v && v->api) ? v->api->typeID : CSON_TYPE_UNDEF;
}
#endif
char cson_value_is_undef( cson_value const * v )
{
| < < < < < | 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 |
{
return (v && v->api) ? v->api->typeID : CSON_TYPE_UNDEF;
}
#endif
char cson_value_is_undef( cson_value const * v )
{
return ( !v || !v->api || (v->api==&cson_value_api_undef))
? 1 : 0;
}
#define ISA(T,TID) char cson_value_is_##T( cson_value const * v ) { \
/*return (v && v->api) ? cson_value_is_a(v,CSON_TYPE_##TID) : 0;*/ \
return (v && (v->api == &cson_value_api_##T)) ? 1 : 0; \
} static const char bogusPlaceHolderForEmacsIndention##TID = CSON_TYPE_##TID
|
| ︙ | ︙ | |||
2648 2649 2650 2651 2652 2653 2654 |
i = (cson_int_t)d;
break;
}
case CSON_TYPE_STRING:
case CSON_TYPE_ARRAY:
case CSON_TYPE_OBJECT:
default:
| > | | | 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 |
i = (cson_int_t)d;
break;
}
case CSON_TYPE_STRING:
case CSON_TYPE_ARRAY:
case CSON_TYPE_OBJECT:
default:
rc = cson_rc.TypeError;
break;
}
if(!rc && v) *v = i;
return rc;
}
}
cson_int_t cson_value_get_integer( cson_value const * val )
{
cson_int_t i = 0;
|
| ︙ | ︙ | |||
2863 2864 2865 2866 2867 2868 2869 |
cson_value * cson_value_new_integer( cson_int_t v )
{
if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0];
else
{
cson_value * c = cson_value_new(CSON_TYPE_INTEGER,0);
| | > > | 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 |
cson_value * cson_value_new_integer( cson_int_t v )
{
if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0];
else
{
cson_value * c = cson_value_new(CSON_TYPE_INTEGER,0);
#if !defined(NDEBUG) && CSON_VOID_PTR_IS_BIG
assert( sizeof(cson_int_t) <= sizeof(void *) );
#endif
if( c )
{
*CSON_INT(c) = v;
}
return c;
}
}
|
| ︙ | ︙ | |||
3142 3143 3144 3145 3146 3147 3148 |
cson_value_free( kvp->value );
cson_refcount_incr( v );
kvp->value = v;
}
return 0;
}
if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
| | | 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 |
cson_value_free( kvp->value );
cson_refcount_incr( v );
kvp->value = v;
}
return 0;
}
if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
{ /* reserve space */
unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
{
return cson_rc.AllocError;
}
}
{ /* insert new item... */
|
| ︙ | ︙ | |||
3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 |
kvp = cson_kvp_alloc();
if( ! kvp )
{
cson_value_free(val);
return cson_rc.AllocError;
}
kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
p->ckey = NULL;
kvp->value = val;
cson_refcount_incr( val );
rc = cson_kvp_list_append( &obj->kvp, kvp );
if( 0 != rc )
{
cson_kvp_free( kvp );
| > > | 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 |
kvp = cson_kvp_alloc();
if( ! kvp )
{
cson_value_free(val);
return cson_rc.AllocError;
}
kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
assert(0 == kvp->key->refcount);
cson_refcount_incr(kvp->key);
p->ckey = NULL;
kvp->value = val;
cson_refcount_incr( val );
rc = cson_kvp_list_append( &obj->kvp, kvp );
if( 0 != rc )
{
cson_kvp_free( kvp );
|
| ︙ | ︙ | |||
3361 3362 3363 3364 3365 3366 3367 |
case JSON_T_OBJECT_BEGIN: {
cson_value * obja = (JSON_T_ARRAY_BEGIN == type)
? cson_value_new_array()
: cson_value_new_object();
if( ! obja )
{
p->errNo = cson_rc.AllocError;
| | | 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 |
case JSON_T_OBJECT_BEGIN: {
cson_value * obja = (JSON_T_ARRAY_BEGIN == type)
? cson_value_new_array()
: cson_value_new_object();
if( ! obja )
{
p->errNo = cson_rc.AllocError;
break;
}
if( 0 != rc ) break;
if( ! p->root )
{
p->root = p->node = obja;
rc = cson_array_append( &p->stack, obja );
if( 0 != rc )
|
| ︙ | ︙ | |||
3384 3385 3386 3387 3388 3389 3390 |
;
++p->totalValueCount;
}
}
else
{
rc = cson_array_append( &p->stack, obja );
| > > > | | > | 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 |
;
++p->totalValueCount;
}
}
else
{
rc = cson_array_append( &p->stack, obja );
if(rc) cson_value_free( obja );
else
{
rc = cson_parser_push_value( p, obja );
if( 0 == rc ) p->node = obja;
}
}
break;
}
case JSON_T_ARRAY_END:
case JSON_T_OBJECT_END: {
if( 0 == p->stack.list.count )
{
|
| ︙ | ︙ | |||
3731 3732 3733 3734 3735 3736 3737 | int c; READ_UTF8(z, zTerm, c); *pzNext = z; return c; } #undef READ_UTF8 | | > | > | 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 |
int c;
READ_UTF8(z, zTerm, c);
*pzNext = z;
return c;
}
#undef READ_UTF8
#ifdef _MSC_VER
# if _MSC_VER >= 1400 /* Visual Studio 2005 and up */
# pragma warning( pop )
# endif
#endif
unsigned int cson_string_length_utf8( cson_string const * str )
{
if( ! str ) return 0;
else
{
|
| ︙ | ︙ | |||
4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 |
cson_value * cson_object_get_sub2( cson_object const * obj, char const * path )
{
cson_value * v = NULL;
cson_object_fetch_sub2( obj, &v, path );
return v;
}
static cson_value * cson_value_clone_array( cson_value const * orig )
{
unsigned int i = 0;
cson_array const * asrc = cson_value_get_array( orig );
unsigned int alen = cson_array_length_get( asrc );
cson_value * destV = NULL;
cson_array * destA = NULL;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 |
cson_value * cson_object_get_sub2( cson_object const * obj, char const * path )
{
cson_value * v = NULL;
cson_object_fetch_sub2( obj, &v, path );
return v;
}
/**
If v is-a Object or Array then this function returns a deep
clone, otherwise it returns v. In either case, the refcount
of the returned value is increased by 1 by this call.
*/
static cson_value * cson_value_clone_ref( cson_value * v )
{
cson_value * rc = NULL;
#define TRY_SHARING 1
#if TRY_SHARING
if(!v ) return rc;
else if( cson_value_is_object(v)
|| cson_value_is_array(v))
{
rc = cson_value_clone( v );
}
else
{
rc = v;
}
#else
rc = cson_value_clone(v);
#endif
#undef TRY_SHARING
cson_value_add_reference(rc);
return rc;
}
static cson_value * cson_value_clone_array( cson_value const * orig )
{
unsigned int i = 0;
cson_array const * asrc = cson_value_get_array( orig );
unsigned int alen = cson_array_length_get( asrc );
cson_value * destV = NULL;
cson_array * destA = NULL;
|
| ︙ | ︙ | |||
4598 4599 4600 4601 4602 4603 4604 |
return NULL;
}
for( ; i < alen; ++i )
{
cson_value * ch = cson_array_get( asrc, i );
if( NULL != ch )
{
| | > | | 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 |
return NULL;
}
for( ; i < alen; ++i )
{
cson_value * ch = cson_array_get( asrc, i );
if( NULL != ch )
{
cson_value * cl = cson_value_clone_ref( ch );
if( NULL == cl )
{
cson_value_free( destV );
return NULL;
}
if( 0 != cson_array_set( destA, i, cl ) )
{
cson_value_free( cl );
cson_value_free( destV );
return NULL;
}
cson_value_free(cl)/*remove our artificial reference */;
}
}
return destV;
}
static cson_value * cson_value_clone_object( cson_value const * orig )
{
cson_object const * src = cson_value_get_object( orig );
cson_value * destV = NULL;
cson_object * dest = NULL;
cson_kvp const * kvp = NULL;
cson_object_iterator iter = cson_object_iterator_empty;
|
| ︙ | ︙ | |||
4637 4638 4639 4640 4641 4642 4643 |
assert( dest );
if( src->kvp.count > cson_kvp_list_reserve( &dest->kvp, src->kvp.count ) ){
cson_value_free( destV );
return NULL;
}
while( (kvp = cson_object_iter_next( &iter )) )
{
| < < < < > | | < < < < > > > > | | > > > > | | < > | 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 |
assert( dest );
if( src->kvp.count > cson_kvp_list_reserve( &dest->kvp, src->kvp.count ) ){
cson_value_free( destV );
return NULL;
}
while( (kvp = cson_object_iter_next( &iter )) )
{
cson_value * key = NULL;
cson_value * val = NULL;
assert( kvp->key && (kvp->key->refcount>0) );
key = cson_value_clone_ref(kvp->key);
val = key ? cson_value_clone_ref(kvp->value) : NULL;
if( ! key || !val ){
goto error;
}
assert( CSON_STR(key) );
if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) )
{
goto error;
}
/* remove our references */
cson_value_free(key);
cson_value_free(val);
continue;
error:
cson_value_free(key);
cson_value_free(val);
cson_value_free(destV);
destV = NULL;
break;
}
return destV;
}
cson_value * cson_value_clone( cson_value const * orig )
{
if( NULL == orig ) return NULL;
|
| ︙ | ︙ | |||
4731 4732 4733 4734 4735 4736 4737 |
if(x) cson_value_free(cson_object_value(x));
}
void cson_free_array(cson_array *x)
{
if(x) cson_value_free(cson_array_value(x));
}
| | | | 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 |
if(x) cson_value_free(cson_object_value(x));
}
void cson_free_array(cson_array *x)
{
if(x) cson_value_free(cson_array_value(x));
}
void cson_free_string(cson_string *x)
{
if(x) cson_value_free(cson_string_value(x));
}
void cson_free_value(cson_value *x)
{
if(x) cson_value_free(x);
}
#if 0
/* i'm not happy with this... */
char * cson_pod_to_string( cson_value const * orig )
{
|
| ︙ | ︙ | |||
4905 4906 4907 4908 4909 4910 4911 |
case CSON_TYPE_NULL:
case CSON_TYPE_BOOL:
assert( 0 && "Should have been caught by is-builtin check!" );
break;
default:
assert(0 && "Invalid typeID!");
return 0;
| | | 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 |
case CSON_TYPE_NULL:
case CSON_TYPE_BOOL:
assert( 0 && "Should have been caught by is-builtin check!" );
break;
default:
assert(0 && "Invalid typeID!");
return 0;
#undef RCCHECK
}
return rc;
}
}
int cson_object_merge( cson_object * dest, cson_object const * src, int flags ){
cson_object_iterator iter = cson_object_iterator_empty;
|
| ︙ | ︙ | |||
4952 4953 4954 4955 4956 4957 4958 |
else continue;
}
return 0;
}
static cson_value * cson_guess_arg_type(char const *arg){
char * end = NULL;
| > | < > > > | < > | | | | | | < | 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 |
else continue;
}
return 0;
}
static cson_value * cson_guess_arg_type(char const *arg){
char * end = NULL;
if(!arg || !*arg) return cson_value_null();
else if(('0'>*arg) || ('9'<*arg)){
goto do_string;
}
else{ /* try numbers... */
long const val = strtol(arg, &end, 10);
if(!*end){
return cson_value_new_integer( (cson_int_t)val);
}
else if( '.' != *end ) {
goto do_string;
}
else {
double const val = strtod(arg, &end);
if(!*end){
return cson_value_new_double(val);
}
}
}
do_string:
return cson_value_new_string(arg, strlen(arg));
}
int cson_parse_argv_flags( int argc, char const * const * argv,
cson_object ** tgt, unsigned int * count ){
|
| ︙ | ︙ | |||
5003 5004 5005 5006 5007 5008 5009 |
break;
}
if(!*pos){ /** --key */
v = cson_value_true();
}else{ /** --key=...*/
assert('=' == *pos);
++pos /*skip '='*/;
| < | < | 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 |
break;
}
if(!*pos){ /** --key */
v = cson_value_true();
}else{ /** --key=...*/
assert('=' == *pos);
++pos /*skip '='*/;
v = cson_guess_arg_type(pos);
}
if(0 != (rc=cson_object_set_s(o, k, v))){
cson_free_string(k);
cson_value_free(v);
break;
}
else if(count) ++*count;
|
| ︙ | ︙ | |||
5502 5503 5504 5505 5506 5507 5508 |
#define RETURN(RC) { if(rootV) cson_value_free(rootV); return RC; }
if( ! tgt || !st ) return cson_rc.ArgError;
else
{
cson_value * rootV = NULL;
cson_object * root = NULL;
cson_value * aryV = NULL;
| < | 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 |
#define RETURN(RC) { if(rootV) cson_value_free(rootV); return RC; }
if( ! tgt || !st ) return cson_rc.ArgError;
else
{
cson_value * rootV = NULL;
cson_object * root = NULL;
cson_value * aryV = NULL;
cson_value * rowsV = NULL;
cson_array * rows = NULL;
int rc = 0;
int const colCount = sqlite3_column_count(st);
if( colCount <= 0 ) return cson_rc.ArgError;
rootV = cson_value_new_object();
if( ! rootV ) return cson_rc.AllocError;
|
| ︙ | ︙ | |||
5524 5525 5526 5527 5528 5529 5530 |
rc = cson_object_set( root, "columns", aryV );
if( rc )
{
cson_value_free( aryV );
RETURN(rc);
}
aryV = NULL;
| < | 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 |
rc = cson_object_set( root, "columns", aryV );
if( rc )
{
cson_value_free( aryV );
RETURN(rc);
}
aryV = NULL;
rowsV = cson_value_new_array();
if( ! rowsV ) RETURN(cson_rc.AllocError);
rc = cson_object_set( root, "rows", rowsV );
if( 0 != rc )
{
cson_value_free( rowsV );
RETURN(rc);
|
| ︙ | ︙ |
Changes to src/cson_amalgamation.h.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #define CSON_DOUBLE_T_SFMT "Lf" #define CSON_DOUBLE_T_PFMT "Lf" #else typedef double cson_double_t; #define CSON_DOUBLE_T_SFMT "f" #define CSON_DOUBLE_T_PFMT "f" #endif /** @def CSON_INT_T_SFMT scanf()-compatible format token for cson_int_t. */ /** @def CSON_INT_T_PFMT | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
#define CSON_DOUBLE_T_SFMT "Lf"
#define CSON_DOUBLE_T_PFMT "Lf"
#else
typedef double cson_double_t;
#define CSON_DOUBLE_T_SFMT "f"
#define CSON_DOUBLE_T_PFMT "f"
#endif
/** @def CSON_VOID_PTR_IS_BIG
ONLY define this to a true value if you know that
(sizeof(cson_int_t) <= sizeof(void*))
If that is the case, cson does not need to dynamically
allocate integers. However, enabling this may cause
compilation warnings in 32-bit builds even though the code
being warned about cannot ever be called. To get around such
warnings, when building on a 64-bit environment you can define
this to 1 to get "big" integer support. HOWEVER, all clients must
also use the same value for this macro. If i knew a halfway reliable
way to determine this automatically at preprocessor-time, i would
automate this. We might be able to do halfway reliably by looking
for a large INT_MAX value?
*/
#if !defined(CSON_VOID_PTR_IS_BIG)
/* Largely taken from http://predef.sourceforge.net/prearch.html
See also: http://poshlib.hookatooka.com/poshlib/trac.cgi/browser/posh.h
*/
# if defined(_WIN64) || defined(__LP64__)/*gcc*/ \
|| defined(_M_X64) || defined(__amd64__) || defined(__amd64) \
|| defined(__x86_64__) || defined(__x86_64) \
|| defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) \
|| defined(_M_IA64) \
|| defined(__sparc_v9__) || defined(__sparcv9) || defined(_ADDR64) \
|| defined(__64BIT__)
# define CSON_VOID_PTR_IS_BIG 1
# else
# define CSON_VOID_PTR_IS_BIG 0
# endif
#endif
/** @def CSON_INT_T_SFMT
scanf()-compatible format token for cson_int_t.
*/
/** @def CSON_INT_T_PFMT
|
| ︙ | ︙ | |||
926 927 928 929 930 931 932 | cson_string * cson_value_get_string( cson_value const * val ); /** Returns a pointer to the NULL-terminated string bytes of str. The bytes are owned by string and will be invalided when it is cleaned up. | | > | 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 | cson_string * cson_value_get_string( cson_value const * val ); /** Returns a pointer to the NULL-terminated string bytes of str. The bytes are owned by string and will be invalided when it is cleaned up. If str is NULL then NULL is returned. If the string has a length of 0 then "" is returned. @see cson_string_length_bytes() @see cson_value_get_string() */ char const * cson_string_cstr( cson_string const * str ); /** |
| ︙ | ︙ | |||
1259 1260 1261 1262 1263 1264 1265 | Equivalent to cson_value_free(cson_array_value(x)). */ void cson_free_array(cson_array *x); /** Equivalent to cson_value_free(cson_string_value(x)). */ | | | 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 | Equivalent to cson_value_free(cson_array_value(x)). */ void cson_free_array(cson_array *x); /** Equivalent to cson_value_free(cson_string_value(x)). */ void cson_free_string(cson_string *x); /** Allocates a new "array" value and transfers ownership of it to the caller. It must eventually be destroyed, by the caller or its owning container, by passing it to cson_value_free(). |
| ︙ | ︙ | |||
2035 2036 2037 2038 2039 2040 2041 | int cson_value_refcount_set( cson_value * v, unsigned short rc ); #endif /** Deeply copies a JSON value, be it an object/array or a "plain" value (e.g. number/string/boolean). If cv is not NULL then this function makes a deep clone of it and returns that clone. Ownership | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > | | | | | | | 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 |
int cson_value_refcount_set( cson_value * v, unsigned short rc );
#endif
/**
Deeply copies a JSON value, be it an object/array or a "plain"
value (e.g. number/string/boolean). If cv is not NULL then this
function makes a deep clone of it and returns that clone. Ownership
of the clone is identical t transfered to the caller, who must
eventually free the value using cson_value_free() or add it to a
container object/array to transfer ownership to the container. The
returned object will be of the same logical type as orig.
ACHTUNG: if orig contains any cyclic references at any depth level
this function will endlessly recurse. (Having _any_ cyclic
references violates this library's requirements.)
Returns NULL if orig is NULL or if cloning fails. Assuming that
orig is in a valid state, the only "likely" error case is that an
allocation fails while constructing the clone. In other words, if
cloning fails due to something other than an allocation error then
either orig is in an invalid state or there is a bug.
When this function clones Objects or Arrays it shares any immutable
values (including object keys) between the parent and the
clone. Mutable values (Objects and Arrays) are copied, however.
For example, if we clone:
@code
{ a: 1, b: 2, c:["hi"] }
@endcode
The cloned object and the array "c" would be a new Object/Array
instances but the object keys (a,b,b) and the values of (a,b), as
well as the string value within the "c" array, would be shared
between the original and the clone. The "c" array itself would be
deeply cloned, such that future changes to the clone are not
visible to the parent, and vice versa, but immutable values within
the array are shared (in this case the string "hi"). The
justification for this heuristic is that immutable values can never
be changed, so there is no harm in sharing them across
clones. Additionally, such types can never contribute to cycles in
a JSON tree, so they are safe to share this way. Objects and
Arrays, on the other hand, can be modified later and can contribute
to cycles, and thus the clone needs to be an independent instance.
Note, however, that if this function directly passed a
non-Object/Array, that value is deeply cloned. The sharing
behaviour only applies when traversing Objects/Arrays.
*/
cson_value * cson_value_clone( cson_value const * orig );
/**
Returns the value handle associated with s. The handle itself owns
s, and ownership of the handle is not changed by calling this
function. If the returned handle is part of a container, calling
cson_value_free() on the returned handle invoked undefined
behaviour (quite possibly downstream when the container tries to
use it).
This function only returns NULL if s is NULL. The length of the
returned string is cson_string_length_bytes().
*/
cson_value * cson_string_value(cson_string const * s);
/**
The Object form of cson_string_value(). See that function
for full details.
*/
cson_value * cson_object_value(cson_object const * s);
/**
The Array form of cson_string_value(). See that function
for full details.
*/
cson_value * cson_array_value(cson_array const * s);
/**
Calculates the approximate in-memory-allocated size of v,
recursively if it is a container type, with the following caveats
and limitations:
If a given value is reference counted then it is only and multiple
times within a traversed container, each reference is counted at
full cost. We have no way of knowing if a given reference has been
visited already and whether it should or should not be counted, so
we pessimistically count them even though the _might_ not really
count for the given object tree (it depends on where the other open
references live).
This function returns 0 if any of the following are true:
- v is NULL
- v is one of the special singleton values (null, bools, empty
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
fprintf(stderr, "%s: %s\n\n%s", fossil_nameofexe(), z, zRebuildMsg);
}
free(z);
db_force_rollback();
fossil_exit(rc);
}
| > > > > > | | | > > > | | | | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 240 241 242 243 244 245 246 247 248 249 250 251 |
fprintf(stderr, "%s: %s\n\n%s", fossil_nameofexe(), z, zRebuildMsg);
}
free(z);
db_force_rollback();
fossil_exit(rc);
}
/*
** All static variable that a used by only this file are gathered into
** the following structure.
*/
static struct DbLocalData {
int nBegin; /* Nesting depth of BEGIN */
int doRollback; /* True to force a rollback */
int nCommitHook; /* Number of commit hooks */
Stmt *pAllStmt; /* List of all unfinalized statements */
int nPrepare; /* Number of calls to sqlite3_prepare() */
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
struct sCommitHook {
int (*xHook)(void); /* Functions to call at db_end_transaction() */
int sequence; /* Call functions in sequence order */
} aHook[5];
char *azDeleteOnFail[3]; /* Files to delete on a failure */
} db = {0, 0, 0, 0, 0, 0, };
/*
** Arrange for the given file to be deleted on a failure.
*/
void db_delete_on_failure(const char *zFilename){
assert( db.nDeleteOnFail<count(db.azDeleteOnFail) );
db.azDeleteOnFail[db.nDeleteOnFail++] = fossil_strdup(zFilename);
}
/*
** This routine is called by the SQLite commit-hook mechanism
** just prior to each commit. All this routine does is verify
** that nBegin really is zero. That insures that transactions
** cannot commit by any means other than by calling db_end_transaction()
** below.
**
** This is just a safety and sanity check.
*/
static int db_verify_at_commit(void *notUsed){
if( db.nBegin ){
fossil_panic("illegal commit attempt");
return 1;
}
return 0;
}
/*
** Begin and end a nested transaction
*/
void db_begin_transaction(void){
if( db.nBegin==0 ){
db_multi_exec("BEGIN");
sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
}
db.nBegin++;
}
void db_end_transaction(int rollbackFlag){
if( g.db==0 ) return;
if( db.nBegin<=0 ) return;
if( rollbackFlag ) db.doRollback = 1;
db.nBegin--;
if( db.nBegin==0 ){
int i;
if( db.doRollback==0 ) leaf_do_pending_checks();
for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){
db.doRollback |= db.aHook[i].xHook();
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
db_multi_exec(db.doRollback ? "ROLLBACK" : "COMMIT");
db.doRollback = 0;
}
}
/*
** Force a rollback and shutdown the database
*/
void db_force_rollback(void){
int i;
static int busy = 0;
sqlite3_stmt *pStmt = 0;
if( busy || g.db==0 ) return;
busy = 1;
undo_rollback();
while( (pStmt = sqlite3_next_stmt(g.db,pStmt))!=0 ){
sqlite3_reset(pStmt);
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
if( db.nBegin ){
sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
db.nBegin = 0;
}
busy = 0;
db_close(0);
for(i=0; i<db.nDeleteOnFail; i++){
file_delete(db.azDeleteOnFail[i]);
}
}
/*
** Install a commit hook. Hooks are installed in sequence order.
** It is an error to install the same commit hook more than once.
**
** Each commit hook is called (in order of accending sequence) at
** each commit operation. If any commit hook returns non-zero,
** the subsequence commit hooks are omitted and the transaction
** rolls back rather than commit. It is the responsibility of the
** hooks themselves to issue any error messages.
*/
void db_commit_hook(int (*x)(void), int sequence){
int i;
assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) );
for(i=0; i<db.nCommitHook; i++){
assert( x!=db.aHook[i].xHook );
if( db.aHook[i].sequence>sequence ){
int s = sequence;
int (*xS)(void) = x;
sequence = db.aHook[i].sequence;
x = db.aHook[i].xHook;
db.aHook[i].sequence = s;
db.aHook[i].xHook = xS;
}
}
db.aHook[db.nCommitHook].sequence = sequence;
db.aHook[db.nCommitHook].xHook = x;
db.nCommitHook++;
}
/*
** Prepare a Stmt. Assume that the Stmt is previously uninitialized.
** If the input string contains multiple SQL statements, only the first
** one is processed. All statements beyond the first are silently ignored.
*/
int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
int rc;
char *zSql;
blob_zero(&pStmt->sql);
blob_vappendf(&pStmt->sql, zFormat, ap);
va_end(ap);
zSql = blob_str(&pStmt->sql);
db.nPrepare++;
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
if( rc!=0 && !errOk ){
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
}
pStmt->pNext = pStmt->pPrev = 0;
pStmt->nStep = 0;
return rc;
|
| ︙ | ︙ | |||
263 264 265 266 267 268 269 |
}
int db_static_prepare(Stmt *pStmt, const char *zFormat, ...){
int rc = SQLITE_OK;
if( blob_size(&pStmt->sql)==0 ){
va_list ap;
va_start(ap, zFormat);
rc = db_vprepare(pStmt, 0, zFormat, ap);
| | | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
}
int db_static_prepare(Stmt *pStmt, const char *zFormat, ...){
int rc = SQLITE_OK;
if( blob_size(&pStmt->sql)==0 ){
va_list ap;
va_start(ap, zFormat);
rc = db_vprepare(pStmt, 0, zFormat, ap);
pStmt->pNext = db.pAllStmt;
pStmt->pPrev = 0;
if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt;
db.pAllStmt = pStmt;
va_end(ap);
}
return rc;
}
/*
** Return the index of a bind parameter
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 |
db_check_result(rc);
pStmt->pStmt = 0;
if( pStmt->pNext ){
pStmt->pNext->pPrev = pStmt->pPrev;
}
if( pStmt->pPrev ){
pStmt->pPrev->pNext = pStmt->pNext;
| | | | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
db_check_result(rc);
pStmt->pStmt = 0;
if( pStmt->pNext ){
pStmt->pNext->pPrev = pStmt->pPrev;
}
if( pStmt->pPrev ){
pStmt->pPrev->pNext = pStmt->pNext;
}else if( db.pAllStmt==pStmt ){
db.pAllStmt = pStmt->pNext;
}
pStmt->pNext = 0;
pStmt->pPrev = 0;
return rc;
}
/*
|
| ︙ | ︙ | |||
654 655 656 657 658 659 660 |
** connection. An error results in process abort.
*/
static sqlite3 *openDatabase(const char *zDbName){
int rc;
const char *zVfs;
sqlite3 *db;
| | | 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
** connection. An error results in process abort.
*/
static sqlite3 *openDatabase(const char *zDbName){
int rc;
const char *zVfs;
sqlite3 *db;
zVfs = fossil_getenv("FOSSIL_VFS");
rc = sqlite3_open_v2(
zDbName, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
zVfs
);
if( rc!=SQLITE_OK ){
db_err(sqlite3_errmsg(db));
|
| ︙ | ︙ | |||
702 703 704 705 706 707 708 |
** case, invoke this routine with useAttach as 1.
*/
void db_open_config(int useAttach){
char *zDbName;
const char *zHome;
if( g.configOpen ) return;
#if defined(_WIN32)
| | | | | < | | 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 |
** case, invoke this routine with useAttach as 1.
*/
void db_open_config(int useAttach){
char *zDbName;
const char *zHome;
if( g.configOpen ) return;
#if defined(_WIN32)
zHome = fossil_getenv("LOCALAPPDATA");
if( zHome==0 ){
zHome = fossil_getenv("APPDATA");
if( zHome==0 ){
char *zDrive = fossil_getenv("HOMEDRIVE");
zHome = fossil_getenv("HOMEPATH");
if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome);
}
}
if( zHome==0 ){
fossil_fatal("cannot locate home directory - "
"please set the LOCALAPPDATA or APPDATA or HOMEPATH "
"environment variables");
}
#else
zHome = fossil_getenv("HOME");
if( zHome==0 ){
fossil_fatal("cannot locate home directory - "
"please set the HOME environment variable");
}
#endif
if( file_isdir(zHome)!=1 ){
fossil_fatal("invalid home directory: %s", zHome);
|
| ︙ | ︙ | |||
783 784 785 786 787 788 789 |
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");
| < < < | > | | > | | > | | > | | | > > > | | | | | | > > > > > > > > > > > > > > > > > > > > > | | 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 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 |
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");
/* 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 ".fslckout"
** that contains a valid repository database.
**
** For legacy, also look for ".fos". The use of ".fos" is deprecated
** since "fos" has negative connotations in Hungarian, we are told.
**
** If no valid _FOSSIL_ or .fos file is found, we move up one level and
** try again. Once the file is found, the g.zLocalRoot variable is set
** to the root of the repository tree and this routine returns 1. If
** no database is found, then this routine return 0.
**
** This routine always opens the user database regardless of whether or
** not the repository database is found. If the _FOSSIL_ or .fos file
** is found, it is attached to the open database connection too.
*/
int db_open_local(void){
int i, n;
char zPwd[2000];
static const char *aDbName[] = { "_FOSSIL_", "fslckout", ".fos" };
if( g.localOpen) return 1;
file_getcwd(zPwd, sizeof(zPwd)-20);
n = strlen(zPwd);
while( n>0 ){
if( file_access(zPwd, W_OK) ) break;
for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){
if( zPwd[n-1] == '/'){
sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]);
}else{
sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
}
if( isValidLocalDb(zPwd) ){
/* Found a valid checkout database file */
zPwd[n] = 0;
while( n>1 && zPwd[n-1]=='/' ){
n--;
zPwd[n] = 0;
}
if( zPwd[n-1] == '/'){
g.zLocalRoot = mprintf("%s", zPwd);
}else{
g.zLocalRoot = mprintf("%s/", zPwd);
}
g.localOpen = 1;
db_open_config(0);
db_open_repository(0);
return 1;
}
}
n--;
while( n>0 && zPwd[n]!='/' ){ n--; }
while( n>0 && zPwd[n-1]=='/' ){ n--; }
if(n==0 && zPwd[0]=='/'){
n=1;
}
zPwd[n] = 0;
}
/* A checkout database file could not be found */
return 0;
}
/*
** Get the full pathname to the repository database file. The
** local database (the _FOSSIL_ or .fslckout database) must have already
** been opened before this routine is called.
*/
const char *db_repository_filename(void){
static char *zRepo = 0;
assert( g.localOpen );
assert( g.zLocalRoot );
if( zRepo==0 ){
zRepo = db_lget("repository", 0);
if( zRepo && !file_is_absolute_path(zRepo) ){
zRepo = mprintf("%s%s", g.zLocalRoot, zRepo);
}
}
return zRepo;
}
/*
** Open the repository database given by zDbName. If zDbName==NULL then
** get the name from the already open local database.
*/
void db_open_repository(const char *zDbName){
if( g.repositoryOpen ) return;
if( zDbName==0 ){
if( g.localOpen ){
zDbName = db_repository_filename();
}
if( zDbName==0 ){
db_err("unable to find the name of a repository database");
}
}
if( file_access(zDbName, R_OK) || file_size(zDbName)<1024 ){
if( file_access(zDbName, 0) ){
|
| ︙ | ︙ | |||
938 939 940 941 942 943 944 |
if( zRep==0 && nArgUsed && g.argc==nArgUsed+1 ){
zRep = g.argv[nArgUsed];
}
if( zRep==0 ){
if( db_open_local()==0 ){
goto rep_not_found;
}
| | | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
if( zRep==0 && nArgUsed && g.argc==nArgUsed+1 ){
zRep = g.argv[nArgUsed];
}
if( zRep==0 ){
if( db_open_local()==0 ){
goto rep_not_found;
}
zRep = db_repository_filename();
if( zRep==0 ){
goto rep_not_found;
}
}
db_open_repository(zRep);
if( g.repositoryOpen ){
if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema();
|
| ︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 |
if( g.argc!=3 ){
usage("PATHNAME");
}
if( db_open_local()==0 ){
fossil_fatal("not in a local checkout");
return;
}
| | | 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
if( g.argc!=3 ){
usage("PATHNAME");
}
if( db_open_local()==0 ){
fossil_fatal("not in a local checkout");
return;
}
file_canonical_name(g.argv[2], &repo, 0);
zRepo = blob_str(&repo);
if( file_access(zRepo, 0) ){
fossil_fatal("no such file: %s", zRepo);
}
db_open_or_attach(zRepo, "test_repo");
db_lset("repository", blob_str(&repo));
db_close(1);
|
| ︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 |
fprintf(stderr, "-- MEMORY_USED %10d %10d\n", cur, hiwtr);
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_SIZE %10d\n", hiwtr);
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_COUNT %10d %10d\n", cur, hiwtr);
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0);
fprintf(stderr, "-- PCACHE_OVFLOW %10d %10d\n", cur, hiwtr);
| | | | | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 |
fprintf(stderr, "-- MEMORY_USED %10d %10d\n", cur, hiwtr);
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_SIZE %10d\n", hiwtr);
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_COUNT %10d %10d\n", cur, hiwtr);
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0);
fprintf(stderr, "-- PCACHE_OVFLOW %10d %10d\n", cur, hiwtr);
fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
db_end_transaction(1);
pStmt = 0;
if( reportErrors ){
while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
}
|
| ︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 |
void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
const char *zUser = zDefaultUser;
if( zUser==0 ){
zUser = db_get("default-user", 0);
}
if( zUser==0 ){
#if defined(_WIN32)
| | | | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 |
void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
const char *zUser = zDefaultUser;
if( zUser==0 ){
zUser = db_get("default-user", 0);
}
if( zUser==0 ){
#if defined(_WIN32)
zUser = fossil_getenv("USERNAME");
#else
zUser = fossil_getenv("USER");
#endif
}
if( zUser==0 ){
zUser = "root";
}
db_multi_exec(
"INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser
|
| ︙ | ︙ | |||
1675 1676 1677 1678 1679 1680 1681 |
**
** Where %s is the checkout root. The value is the repository file.
*/
void db_record_repository_filename(const char *zName){
Blob full;
if( zName==0 ){
if( !g.localOpen ) return;
| | | > > | > | 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 |
**
** Where %s is the checkout root. The value is the repository file.
*/
void db_record_repository_filename(const char *zName){
Blob full;
if( zName==0 ){
if( !g.localOpen ) return;
zName = db_repository_filename();
}
file_canonical_name(zName, &full, 0);
db_swap_connections();
db_multi_exec(
"INSERT OR IGNORE INTO global_config(name,value)"
"VALUES('repo:%q',1)",
blob_str(&full)
);
if( g.localOpen && g.zLocalRoot && g.zLocalRoot[0] ){
Blob localRoot;
file_canonical_name(g.zLocalRoot, &localRoot, 1);
db_multi_exec(
"REPLACE INTO global_config(name, value)"
"VALUES('ckout:%q','%q');",
blob_str(&localRoot), blob_str(&full)
);
blob_reset(&localRoot);
}
db_swap_connections();
blob_reset(&full);
}
/*
** COMMAND: open
|
| ︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 |
allowNested = find_option("nested",0,0)!=0;
if( g.argc!=3 && g.argc!=4 ){
usage("REPOSITORY-FILENAME ?VERSION?");
}
if( !allowNested && db_open_local() ){
fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
}
| | | | 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 |
allowNested = find_option("nested",0,0)!=0;
if( g.argc!=3 && g.argc!=4 ){
usage("REPOSITORY-FILENAME ?VERSION?");
}
if( !allowNested && db_open_local() ){
fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
}
file_canonical_name(g.argv[2], &path, 0);
db_open_repository(blob_str(&path));
db_init_database("./_FOSSIL_", zLocalSchema, (char*)0);
db_delete_on_failure("./_FOSSIL_");
db_open_local();
db_lset("repository", g.argv[2]);
db_record_repository_filename(blob_str(&path));
vid = db_int(0, "SELECT pid FROM plink y"
" WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)");
if( vid==0 ){
db_lset_int("checkout", 1);
}else{
char **oldArgv = g.argv;
|
| ︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 |
{ 0,0,0,0,0 }
};
/*
** COMMAND: settings
** COMMAND: unset*
**
| | | | 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 |
{ 0,0,0,0,0 }
};
/*
** COMMAND: settings
** COMMAND: unset*
**
** %fossil settings ?PROPERTY? ?VALUE? ?OPTIONS?
** %fossil unset PROPERTY ?OPTIONS?
**
** The "settings" command with no arguments lists all properties and their
** values. With just a property name it shows the value of that property.
** With a value argument it changes the property for the current repository.
**
** Settings marked as versionable are overridden by the contents of the
** file named .fossil-settings/PROPERTY in the checked out files, if that
|
| ︙ | ︙ | |||
2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 |
** Tcl interpreter will be able to evaluate TH1 expressions
** and scripts. Default: off.
**
** web-browser A shell command used to launch your preferred
** web browser when given a URL as an argument.
** Defaults to "start" on windows, "open" on Mac,
** and "firefox" on Unix.
*/
void setting_cmd(void){
int i;
int globalFlag = find_option("global","g",0)!=0;
int unsetFlag = g.argv[1][0]=='u';
db_open_config(1);
if( !globalFlag ){
| > > > > > > | 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 |
** Tcl interpreter will be able to evaluate TH1 expressions
** and scripts. Default: off.
**
** web-browser A shell command used to launch your preferred
** web browser when given a URL as an argument.
** Defaults to "start" on windows, "open" on Mac,
** and "firefox" on Unix.
**
** Options:
** --global set or unset the given property globally instead of
** setting or unsetting it for the open repository only.
**
** See also: configuration
*/
void setting_cmd(void){
int i;
int globalFlag = find_option("global","g",0)!=0;
int unsetFlag = g.argv[1][0]=='u';
db_open_config(1);
if( !globalFlag ){
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 | #include <assert.h> #if INTERFACE /* ** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions: */ | | | | | | > > > > > > | 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 | #include <assert.h> #if INTERFACE /* ** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions: */ #define DIFF_CONTEXT_MASK 0x0000ffff /* Lines of context. Default if 0 */ #define DIFF_WIDTH_MASK 0x00ff0000 /* side-by-side column width */ #define DIFF_IGNORE_EOLWS 0x01000000 /* Ignore end-of-line whitespace */ #define DIFF_SIDEBYSIDE 0x02000000 /* Generate a side-by-side diff */ #define DIFF_NEWFILE 0x04000000 /* Missing files are as empty files */ #define DIFF_BRIEF 0x08000000 /* Show filenames only */ #define DIFF_INLINE 0x00000000 /* Inline (not side-by-side) diff */ #define DIFF_HTML 0x10000000 /* Render for HTML */ #define DIFF_LINENO 0x20000000 /* Show line numbers in context diff */ #define DIFF_NOOPT 0x40000000 /* Suppress optimizations for debug */ #define DIFF_INVERT 0x80000000 /* Invert the diff for debug */ #endif /* INTERFACE */ /* ** Maximum length of a line in a text file. (8192) */ #define LENGTH_MASK_SZ 13 |
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | /* an array of DLine elements services two purposes. The fields ** above are one per line of input text. But each entry is also ** a bucket in a hash table, as follows: */ unsigned int iHash; /* 1+(first entry in the hash chain) */ }; /* | > > > > > | > > > > > > > > > > | 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 |
/* an array of DLine elements services two purposes. The fields
** above are one per line of input text. But each entry is also
** a bucket in a hash table, as follows: */
unsigned int iHash; /* 1+(first entry in the hash chain) */
};
/*
** Length of a dline
*/
#define LENGTH(X) ((X)->h & LENGTH_MASK)
/*
** A context for running a raw diff.
**
** The aEdit[] array describes the raw diff. Each triple of integers in
** aEdit[] means:
**
** (1) COPY: Number of lines aFrom and aTo have in common
** (2) DELETE: Number of lines found only in aFrom
** (3) INSERT: Number of lines found only in aTo
**
** The triples repeat until all lines of both aFrom and aTo are accounted
** for.
*/
typedef struct DContext DContext;
struct DContext {
int *aEdit; /* Array of copy/delete/insert triples */
int nEdit; /* Number of integers (3x num of triples) in aEdit[] */
int nEditAlloc; /* Space allocated for aEdit[] */
DLine *aFrom; /* File on left side of the diff */
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 |
** Return true if two DLine elements are identical.
*/
static int same_dline(DLine *pA, DLine *pB){
return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
}
/*
| | | > > > > > > > > > > > > > > | > > > > > | > | | | < < < | < < | < | < < < < < < < | < < < > | > | | < < > | > | < < | < < < < | > > > > > > > | 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 240 241 242 243 244 245 246 247 248 249 250 |
** Return true if two DLine elements are identical.
*/
static int same_dline(DLine *pA, DLine *pB){
return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
}
/*
** Append a single line of context-diff output to pOut.
*/
static void appendDiffLine(
Blob *pOut, /* Where to write the line of output */
char cPrefix, /* One of " ", "+", or "-" */
DLine *pLine, /* The line to be output */
int html /* True if generating HTML. False for plain text */
){
blob_append(pOut, &cPrefix, 1);
if( html ){
char *zHtml;
if( cPrefix=='+' ){
blob_append(pOut, "<span class=\"diffadd\">", -1);
}else if( cPrefix=='-' ){
blob_append(pOut, "<span class=\"diffrm\">", -1);
}
zHtml = htmlize(pLine->z, (pLine->h & LENGTH_MASK));
blob_append(pOut, zHtml, -1);
fossil_free(zHtml);
if( cPrefix!=' ' ){
blob_append(pOut, "</span>", -1);
}
}else{
blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);
}
blob_append(pOut, "\n", 1);
}
/*
** Add two line numbers to the beginning of an output line for a context
** diff. One or of the other of the two numbers might be zero, which means
** to leave that number field blank. The "html" parameter means to format
** the output for HTML.
*/
static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){
if( html ) blob_append(pOut, "<span class=\"diffln\">", -1);
if( lnA>0 ){
blob_appendf(pOut, "%6d ", lnA);
}else{
blob_append(pOut, " ", 7);
}
if( lnB>0 ){
blob_appendf(pOut, "%6d ", lnB);
}else{
blob_append(pOut, " ", 8);
}
if( html ) blob_append(pOut, "</span>", -1);
}
/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a context diff into pOut.
*/
static void contextDiff(
DContext *p, /* The difference */
Blob *pOut, /* Output a context diff to here */
int nContext, /* Number of lines of context */
int showLn, /* Show line numbers */
int html /* Render as HTML */
){
DLine *A; /* Left side of the diff */
DLine *B; /* Right side of the diff */
int a = 0; /* Index of next line in A[] */
int b = 0; /* Index of next line in B[] */
int *R; /* Array of COPY/DELETE/INSERT triples */
int r; /* Index into R[] */
int nr; /* Number of COPY/DELETE/INSERT triples to process */
int mxr; /* Maximum value for r */
int na, nb; /* Number of lines shown from A and B */
int i, j; /* Loop counters */
int m; /* Number of lines to output */
int skip; /* Number of lines to skip */
int nChunk = 0; /* Number of diff chunks seen so far */
A = p->aFrom;
B = p->aTo;
R = p->aEdit;
mxr = p->nEdit;
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
for(r=0; r<mxr; r += 3*nr){
|
| ︙ | ︙ | |||
245 246 247 248 249 250 251 |
na += R[r+nr*3];
nb += R[r+nr*3];
}
for(i=1; i<nr; i++){
na += R[r+i*3];
nb += R[r+i*3];
}
| > > > > > > > > > > > > > > > > > | | | | | | | | > > > > | > | > | > | > | | < > | | | > > > > > > > > > | > > > > > | < > | > > > | > | > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | < | < > | | > > > | | 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 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 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 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 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 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 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 684 685 686 687 688 689 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 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 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 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 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 |
na += R[r+nr*3];
nb += R[r+nr*3];
}
for(i=1; i<nr; i++){
na += R[r+i*3];
nb += R[r+i*3];
}
/* Show the header for this block, or if we are doing a modified
** context diff that contains line numbers, show the separate from
** the previous block.
*/
nChunk++;
if( showLn ){
if( r==0 ){
/* Do not show a top divider */
}else if( html ){
blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
}else{
blob_appendf(pOut, "%.80c\n", '.');
}
}else{
if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
/*
* If the patch changes an empty file or results in an empty file,
* the block header must use 0,0 as position indicator and not 1,0.
* Otherwise, patch would be confused and may reject the diff.
*/
blob_appendf(pOut,"@@ -%d,%d +%d,%d @@",
na ? a+skip+1 : 0, na,
nb ? b+skip+1 : 0, nb);
if( html ) blob_appendf(pOut, "</span>");
blob_append(pOut, "\n", 1);
}
/* Show the initial common area */
a += skip;
b += skip;
m = R[r] - skip;
for(j=0; j<m; j++){
if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
appendDiffLine(pOut, ' ', &A[a+j], html);
}
a += m;
b += m;
/* Show the differences */
for(i=0; i<nr; i++){
m = R[r+i*3+1];
for(j=0; j<m; j++){
if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
appendDiffLine(pOut, '-', &A[a+j], html);
}
a += m;
m = R[r+i*3+2];
for(j=0; j<m; j++){
if( showLn ) appendDiffLineno(pOut, 0, b+j+1, html);
appendDiffLine(pOut, '+', &B[b+j], html);
}
b += m;
if( i<nr-1 ){
m = R[r+i*3+3];
for(j=0; j<m; j++){
if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
appendDiffLine(pOut, ' ', &B[b+j], html);
}
b += m;
a += m;
}
}
/* Show the final common area */
assert( nr==i );
m = R[r+nr*3];
if( m>nContext ) m = nContext;
for(j=0; j<m; j++){
if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
appendDiffLine(pOut, ' ', &B[b+j], html);
}
}
}
/*
** Status of a single output line
*/
typedef struct SbsLine SbsLine;
struct SbsLine {
char *zLine; /* The output line under construction */
int n; /* Index of next unused slot in the zLine[] */
int width; /* Maximum width of a column in the output */
unsigned char escHtml; /* True to escape html characters */
int iStart; /* Write zStart prior to character iStart */
const char *zStart; /* A <span> tag */
int iEnd; /* Write </span> prior to character iEnd */
int iStart2; /* Write zStart2 prior to character iStart2 */
const char *zStart2; /* A <span> tag */
int iEnd2; /* Write </span> prior to character iEnd2 */
};
/*
** Flags for sbsWriteText()
*/
#define SBS_NEWLINE 0x0001 /* End with \n\000 */
#define SBS_PAD 0x0002 /* Pad output to width spaces */
/*
** Write up to width characters of pLine into z[]. Translate tabs into
** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters
** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set.
*/
static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
int n = pLine->h & LENGTH_MASK;
int i; /* Number of input characters consumed */
int j; /* Number of output characters generated */
int k; /* Cursor position */
int needEndSpan = 0;
const char *zIn = pLine->z;
char *z = &p->zLine[p->n];
int w = p->width;
for(i=j=k=0; k<w && i<n; i++, k++){
char c = zIn[i];
if( p->escHtml ){
if( i==p->iStart ){
int x = strlen(p->zStart);
memcpy(z+j, p->zStart, x);
j += x;
needEndSpan = 1;
if( p->iStart2 ){
p->iStart = p->iStart2;
p->zStart = p->zStart2;
p->iStart2 = 0;
}
}else if( i==p->iEnd ){
memcpy(z+j, "</span>", 7);
j += 7;
needEndSpan = 0;
if( p->iEnd2 ){
p->iEnd = p->iEnd2;
p->iEnd2 = 0;
}
}
}
if( c=='\t' ){
z[j++] = ' ';
while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; }
}else if( c=='\r' || c=='\f' ){
z[j++] = ' ';
}else if( c=='<' && p->escHtml ){
memcpy(&z[j], "<", 4);
j += 4;
}else if( c=='&' && p->escHtml ){
memcpy(&z[j], "&", 5);
j += 5;
}else if( c=='>' && p->escHtml ){
memcpy(&z[j], ">", 4);
j += 4;
}else{
z[j++] = c;
}
}
if( needEndSpan ){
memcpy(&z[j], "</span>", 7);
j += 7;
}
if( (flags & SBS_PAD)!=0 ){
while( k<w ){ k++; z[j++] = ' '; }
}
if( flags & SBS_NEWLINE ){
z[j++] = '\n';
}
p->n += j;
}
/*
** Append a string to an SbSLine with coding, interpretation, or padding.
*/
static void sbsWrite(SbsLine *p, const char *zIn, int nIn){
memcpy(p->zLine+p->n, zIn, nIn);
p->n += nIn;
}
/*
** Append n spaces to the string.
*/
static void sbsWriteSpace(SbsLine *p, int n){
while( n-- ) p->zLine[p->n++] = ' ';
}
/*
** Append a string to the output only if we are rendering HTML.
*/
static void sbsWriteHtml(SbsLine *p, const char *zIn){
if( p->escHtml ) sbsWrite(p, zIn, strlen(zIn));
}
/*
** Write a 6-digit line number followed by a single space onto the line.
*/
static void sbsWriteLineno(SbsLine *p, int ln){
sbsWriteHtml(p, "<span class=\"diffln\">");
sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
p->n += 6;
sbsWriteHtml(p, "</span>");
p->zLine[p->n++] = ' ';
}
/*
** The two text segments zLeft and zRight are known to be different on
** both ends, but they might have a common segment in the middle. If
** they do not have a common segment, return 0. If they do have a large
** common segment, return 1 and before doing so set:
**
** aLCS[0] = start of the common segment in zLeft
** aLCS[1] = end of the common segment in zLeft
** aLCS[2] = start of the common segment in zLeft
** aLCS[3] = end of the common segment in zLeft
**
** This computation is for display purposes only and does not have to be
** optimal or exact.
*/
static int textLCS(
const char *zLeft, int nA, /* String on the left */
const char *zRight, int nB, /* String on the right */
int *aLCS /* Identify bounds of LCS here */
){
const unsigned char *zA = (const unsigned char*)zLeft; /* left string */
const unsigned char *zB = (const unsigned char*)zRight; /* right string */
int nt; /* Number of target points */
int ti[3]; /* Index for start of each 4-byte target */
unsigned int target[3]; /* 4-byte alignment targets */
unsigned int probe; /* probe to compare against target */
int iAS, iAE, iBS, iBE; /* Range of common segment */
int i, j; /* Loop counters */
int rc = 0; /* Result code. 1 for success */
if( nA<6 || nB<6 ) return 0;
memset(aLCS, 0, sizeof(int)*4);
ti[0] = i = nB/2-2;
target[0] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
probe = 0;
if( nB<16 ){
nt = 1;
}else{
ti[1] = i = nB/4-2;
target[1] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
ti[2] = i = (nB*3)/4-2;
target[2] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
nt = 3;
}
probe = (zA[0]<<16) | (zA[1]<<8) | zA[2];
for(i=3; i<nA; i++){
probe = (probe<<8) | zA[i];
for(j=0; j<nt; j++){
if( probe==target[j] ){
iAS = i-3;
iAE = i+1;
iBS = ti[j];
iBE = ti[j]+4;
while( iAE<nA && iBE<nB && zA[iAE]==zB[iBE] ){ iAE++; iBE++; }
while( iAS>0 && iBS>0 && zA[iAS-1]==zB[iBS-1] ){ iAS--; iBS--; }
if( iAE-iAS > aLCS[1] - aLCS[0] ){
aLCS[0] = iAS;
aLCS[1] = iAE;
aLCS[2] = iBS;
aLCS[3] = iBE;
rc = 1;
}
}
}
}
return rc;
}
/*
** Write out lines that have been edited. Adjust the highlight to cover
** only those parts of the line that actually changed.
*/
static void sbsWriteLineChange(
SbsLine *p, /* The SBS output line */
DLine *pLeft, /* Left line of the change */
int lnLeft, /* Line number for the left line */
DLine *pRight, /* Right line of the change */
int lnRight /* Line number of the right line */
){
int nLeft; /* Length of left line in bytes */
int nRight; /* Length of right line in bytes */
int nPrefix; /* Length of common prefix */
int nSuffix; /* Length of common suffix */
const char *zLeft; /* Text of the left line */
const char *zRight; /* Text of the right line */
int nLeftDiff; /* nLeft - nPrefix - nSuffix */
int nRightDiff; /* nRight - nPrefix - nSuffix */
int aLCS[4]; /* Bounds of common middle segment */
static const char zClassRm[] = "<span class=\"diffrm\">";
static const char zClassAdd[] = "<span class=\"diffadd\">";
static const char zClassChng[] = "<span class=\"diffchng\">";
nLeft = pLeft->h & LENGTH_MASK;
zLeft = pLeft->z;
nRight = pRight->h & LENGTH_MASK;
zRight = pRight->z;
nPrefix = 0;
while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){
nPrefix++;
}
nSuffix = 0;
if( nPrefix<nLeft && nPrefix<nRight ){
while( nSuffix<nLeft && nSuffix<nRight
&& zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
nSuffix++;
}
if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
}
if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
/* A single chunk of text inserted on the right */
if( nPrefix+nSuffix==nLeft ){
sbsWriteLineno(p, lnLeft);
p->iStart2 = p->iEnd2 = 0;
p->iStart = p->iEnd = -1;
sbsWriteText(p, pLeft, SBS_PAD);
sbsWrite(p, " | ", 3);
sbsWriteLineno(p, lnRight);
p->iStart = nPrefix;
p->iEnd = nRight - nSuffix;
p->zStart = zClassAdd;
sbsWriteText(p, pRight, SBS_NEWLINE);
return;
}
/* A single chunk of text deleted from the left */
if( nPrefix+nSuffix==nRight ){
/* Text deleted from the left */
sbsWriteLineno(p, lnLeft);
p->iStart2 = p->iEnd2 = 0;
p->iStart = nPrefix;
p->iEnd = nLeft - nSuffix;
p->zStart = zClassRm;
sbsWriteText(p, pLeft, SBS_PAD);
sbsWrite(p, " | ", 3);
sbsWriteLineno(p, lnRight);
p->iStart = p->iEnd = -1;
sbsWriteText(p, pRight, SBS_NEWLINE);
return;
}
/* At this point we know that there is a chunk of text that has
** changed between the left and the right. Check to see if there
** is a large unchanged section in the middle of that changed block.
*/
nLeftDiff = nLeft - nSuffix - nPrefix;
nRightDiff = nRight - nSuffix - nPrefix;
if( p->escHtml
&& nLeftDiff >= 6
&& nRightDiff >= 6
&& textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
){
sbsWriteLineno(p, lnLeft);
p->iStart = nPrefix;
p->iEnd = nPrefix + aLCS[0];
p->zStart = aLCS[2]==0 ? zClassRm : zClassChng;
p->iStart2 = nPrefix + aLCS[1];
p->iEnd2 = nLeft - nSuffix;
p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
if( p->iStart==p->iEnd ){
p->iStart = p->iStart2;
p->iEnd = p->iEnd2;
p->zStart = p->zStart2;
p->iStart2 = 0;
p->iEnd2 = 0;
}
if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
sbsWriteText(p, pLeft, SBS_PAD);
sbsWrite(p, " | ", 3);
sbsWriteLineno(p, lnRight);
p->iStart = nPrefix;
p->iEnd = nPrefix + aLCS[2];
p->zStart = aLCS[0]==0 ? zClassAdd : zClassChng;
p->iStart2 = nPrefix + aLCS[3];
p->iEnd2 = nRight - nSuffix;
p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
if( p->iStart==p->iEnd ){
p->iStart = p->iStart2;
p->iEnd = p->iEnd2;
p->zStart = p->zStart2;
p->iStart2 = 0;
p->iEnd2 = 0;
}
if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
sbsWriteText(p, pRight, SBS_NEWLINE);
return;
}
/* If all else fails, show a single big change between left and right */
sbsWriteLineno(p, lnLeft);
p->iStart2 = p->iEnd2 = 0;
p->iStart = nPrefix;
p->iEnd = nLeft - nSuffix;
p->zStart = zClassChng;
sbsWriteText(p, pLeft, SBS_PAD);
sbsWrite(p, " | ", 3);
sbsWriteLineno(p, lnRight);
p->iEnd = nRight - nSuffix;
sbsWriteText(p, pRight, SBS_NEWLINE);
}
/*
** Minimum of two values
*/
static int minInt(int a, int b){ return a<b ? a : b; }
/*
** Return the number between 0 and 100 that is smaller the closer pA and
** pB match. Return 0 for a perfect match. Return 100 if pA and pB are
** completely different.
**
** The current algorithm is as follows:
**
** (1) Remove leading and trailing whitespace.
** (2) Truncate both strings to at most 250 characters
** (3) Find the length of the longest common subsequence
** (4) Longer common subsequences yield lower scores.
*/
static int match_dline(DLine *pA, DLine *pB){
const char *zA; /* Left string */
const char *zB; /* right string */
int nA; /* Bytes in zA[] */
int nB; /* Bytes in zB[] */
int avg; /* Average length of A and B */
int i, j, k; /* Loop counters */
int best = 0; /* Longest match found so far */
int score; /* Final score. 0..100 */
unsigned char c; /* Character being examined */
unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
zA = pA->z;
zB = pB->z;
nA = pA->h & LENGTH_MASK;
nB = pB->h & LENGTH_MASK;
while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; }
while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; }
while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; }
while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; }
if( nA>250 ) nA = 250;
if( nB>250 ) nB = 250;
avg = (nA+nB)/2;
if( avg==0 ) return 0;
if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
memset(aFirst, 0, sizeof(aFirst));
zA--; zB--; /* Make both zA[] and zB[] 1-indexed */
for(i=nB; i>0; i--){
c = (unsigned char)zB[i];
aNext[i] = aFirst[c];
aFirst[c] = i;
}
best = 0;
for(i=1; i<=nA-best; i++){
c = (unsigned char)zA[i];
for(j=aFirst[c]; j>0 && j<nB-best; j = aNext[j]){
int limit = minInt(nA-i, nB-j);
for(k=1; k<=limit && zA[k+i]==zB[k+j]; k++){}
if( k>best ) best = k;
}
}
score = (best>avg) ? 0 : (avg - best)*100/avg;
#if 0
fprintf(stderr, "A: [%.*s]\nB: [%.*s]\nbest=%d avg=%d score=%d\n",
nA, zA+1, nB, zB+1, best, avg, score);
#endif
/* Return the result */
return score;
}
/*
** There is a change block in which nLeft lines of text on the left are
** converted into nRight lines of text on the right. This routine computes
** how the lines on the left line up with the lines on the right.
**
** The return value is a buffer of unsigned characters, obtained from
** fossil_malloc(). (The caller needs to free the return value using
** fossil_free().) Entries in the returned array have values as follows:
**
** 1. Delete the next line of pLeft.
** 2. The next line of pLeft changes into the next line of pRight.
** 3. Insert the next line of pRight.
**
** The length of the returned array will be just large enough to cause
** all elements of pLeft and pRight to be consumed.
**
** Algorithm: Wagner's minimum edit-distance algorithm, modified by
** adding a cost to each match based on how well the two rows match
** each other. Insertion and deletion costs are 50. Match costs
** are between 0 and 100 where 0 is a perfect match 100 is a complete
** mismatch.
*/
static unsigned char *sbsAlignment(
DLine *aLeft, int nLeft, /* Text on the left */
DLine *aRight, int nRight /* Text on the right */
){
int i, j, k; /* Loop counters */
int *a; /* One row of the Wagner matrix */
int *pToFree; /* Space that needs to be freed */
unsigned char *aM; /* Wagner result matrix */
int aBuf[100]; /* Stack space for a[] if nRight not to big */
aM = fossil_malloc( (nLeft+1)*(nRight+1) );
if( nLeft==0 ){
memset(aM, 3, nRight);
return aM;
}
if( nRight==0 ){
memset(aM, 1, nLeft);
return aM;
}
if( nRight < (sizeof(aBuf)/sizeof(aBuf[0]))-1 ){
pToFree = 0;
a = aBuf;
}else{
a = pToFree = fossil_malloc( sizeof(a[0])*(nRight+1) );
}
/* Compute the best alignment */
for(i=0; i<=nRight; i++){
aM[i] = 3;
a[i] = i*50;
}
aM[0] = 0;
for(j=1; j<=nLeft; j++){
int p = a[0];
a[0] = p+50;
aM[j*(nRight+1)] = 1;
for(i=1; i<=nRight; i++){
int m = a[i-1]+50;
int d = 3;
if( m>a[i]+50 ){
m = a[i]+50;
d = 1;
}
if( m>p ){
int score = match_dline(&aLeft[j-1], &aRight[i-1]);
if( (score<66 || (i<j+1 && i>j-1)) && m>p+score ){
m = p+score;
d = 2;
}
}
p = a[i];
a[i] = m;
aM[j*(nRight+1)+i] = d;
}
}
/* Compute the lowest-cost path back through the matrix */
i = nRight;
j = nLeft;
k = (nRight+1)*(nLeft+1)-1;
while( i+j>0 ){
unsigned char c = aM[k--];
if( c==2 ){
assert( i>0 && j>0 );
i--;
j--;
}else if( c==3 ){
assert( i>0 );
i--;
}else{
assert( j>0 );
j--;
}
aM[k] = aM[j*(nRight+1)+i];
}
k++;
i = (nRight+1)*(nLeft+1) - k;
memmove(aM, &aM[k], i);
/* Return the result */
fossil_free(pToFree);
return aM;
}
/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a side-by-side diff into pOut.
*/
static void sbsDiff(
DContext *p, /* The computed diff */
Blob *pOut, /* Write the results here */
int nContext, /* Number of lines of context around each change */
int width, /* Width of each column of output */
int escHtml /* True to generate HTML output */
){
DLine *A; /* Left side of the diff */
DLine *B; /* Right side of the diff */
int a = 0; /* Index of next line in A[] */
int b = 0; /* Index of next line in B[] */
int *R; /* Array of COPY/DELETE/INSERT triples */
int r; /* Index into R[] */
int nr; /* Number of COPY/DELETE/INSERT triples to process */
int mxr; /* Maximum value for r */
int na, nb; /* Number of lines shown from A and B */
int i, j; /* Loop counters */
int m, ma, mb;/* Number of lines to output */
int skip; /* Number of lines to skip */
int nChunk = 0; /* Number of chunks of diff output seen so far */
SbsLine s; /* Output line buffer */
memset(&s, 0, sizeof(s));
s.zLine = fossil_malloc( 10*width + 200 );
if( s.zLine==0 ) return;
s.width = width;
s.escHtml = escHtml;
s.iStart = -1;
s.iEnd = -1;
A = p->aFrom;
B = p->aTo;
R = p->aEdit;
mxr = p->nEdit;
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
for(r=0; r<mxr; r += 3*nr){
/* Figure out how many triples to show in a single block */
|
| ︙ | ︙ | |||
393 394 395 396 397 398 399 |
na += R[r+nr*3];
nb += R[r+nr*3];
}
for(i=1; i<nr; i++){
na += R[r+i*3];
nb += R[r+i*3];
}
| | | | | > | > | > > > > > > | | > | > | | | > | | < > | < > > | < | > | | > | < | > | > | > > > > | | > > > | > | < | | | > | > > > | < < < < < < < < > | | > | > | | | | | > | > | | | | | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 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 |
na += R[r+nr*3];
nb += R[r+nr*3];
}
for(i=1; i<nr; i++){
na += R[r+i*3];
nb += R[r+i*3];
}
/* Draw the separator between blocks */
if( r>0 ){
if( escHtml ){
blob_appendf(pOut, "<span class=\"diffhr\">%.*c</span>\n",
width*2+16, '.');
}else{
blob_appendf(pOut, "%.*c\n", width*2+16, '.');
}
}
nChunk++;
if( escHtml ){
blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
}
/* Show the initial common area */
a += skip;
b += skip;
m = R[r] - skip;
for(j=0; j<m; j++){
s.n = 0;
sbsWriteLineno(&s, a+j);
s.iStart = s.iEnd = -1;
sbsWriteText(&s, &A[a+j], SBS_PAD);
sbsWrite(&s, " ", 3);
sbsWriteLineno(&s, b+j);
sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
blob_append(pOut, s.zLine, s.n);
}
a += m;
b += m;
/* Show the differences */
for(i=0; i<nr; i++){
unsigned char *alignment;
ma = R[r+i*3+1]; /* Lines on left but not on right */
mb = R[r+i*3+2]; /* Lines on right but not on left */
alignment = sbsAlignment(&A[a], ma, &B[b], mb);
for(j=0; ma+mb>0; j++){
if( alignment[j]==1 ){
s.n = 0;
sbsWriteLineno(&s, a);
s.iStart = 0;
s.zStart = "<span class=\"diffrm\">";
s.iEnd = s.width;
sbsWriteText(&s, &A[a], SBS_PAD);
sbsWrite(&s, " <\n", 3);
blob_append(pOut, s.zLine, s.n);
assert( ma>0 );
ma--;
a++;
}else if( alignment[j]==2 ){
s.n = 0;
sbsWriteLineChange(&s, &A[a], a, &B[b], b);
blob_append(pOut, s.zLine, s.n);
assert( ma>0 && mb>0 );
ma--;
mb--;
a++;
b++;
}else{
s.n = 0;
sbsWriteSpace(&s, width + 7);
sbsWrite(&s, " > ", 3);
sbsWriteLineno(&s, b);
s.iStart = 0;
s.zStart = "<span class=\"diffadd\">";
s.iEnd = s.width;
sbsWriteText(&s, &B[b], SBS_NEWLINE);
blob_append(pOut, s.zLine, s.n);
assert( mb>0 );
mb--;
b++;
}
}
fossil_free(alignment);
if( i<nr-1 ){
m = R[r+i*3+3];
for(j=0; j<m; j++){
s.n = 0;
sbsWriteLineno(&s, a+j);
s.iStart = s.iEnd = -1;
sbsWriteText(&s, &A[a+j], SBS_PAD);
sbsWrite(&s, " ", 3);
sbsWriteLineno(&s, b+j);
sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
blob_append(pOut, s.zLine, s.n);
}
b += m;
a += m;
}
}
/* Show the final common area */
assert( nr==i );
m = R[r+nr*3];
if( m>nContext ) m = nContext;
for(j=0; j<m; j++){
s.n = 0;
sbsWriteLineno(&s, a+j);
s.iStart = s.iEnd = -1;
sbsWriteText(&s, &A[a+j], SBS_PAD);
sbsWrite(&s, " ", 3);
sbsWriteLineno(&s, b+j);
sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
blob_append(pOut, s.zLine, s.n);
}
}
free(s.zLine);
}
/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search. This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.
|
| ︙ | ︙ | |||
550 551 552 553 554 555 556 |
DContext *p, /* Two files being compared */
int iS1, int iE1, /* Range of lines in p->aFrom[] */
int iS2, int iE2, /* Range of lines in p->aTo[] */
int *piSX, int *piEX, /* Write p->aFrom[] common segment here */
int *piSY, int *piEY /* Write p->aTo[] common segment here */
){
double bestScore = -1e30; /* Best score seen so far */
| > | > | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 |
DContext *p, /* Two files being compared */
int iS1, int iE1, /* Range of lines in p->aFrom[] */
int iS2, int iE2, /* Range of lines in p->aTo[] */
int *piSX, int *piEX, /* Write p->aFrom[] common segment here */
int *piSY, int *piEY /* Write p->aTo[] common segment here */
){
double bestScore = -1e30; /* Best score seen so far */
int i, j, k; /* Loop counters */
int n; /* Loop limit */
DLine *pA, *pB; /* Pointers to lines */
int iSX, iSY, iEX, iEY; /* Current match */
double score; /* Current score */
int skew; /* How lopsided is the match */
int dist; /* Distance of match from center */
int mid; /* Center of the span */
int iSXb, iSYb, iEXb, iEYb; /* Best match so far */
int iSXp, iSYp, iEXp, iEYp; /* Previous match */
|
| ︙ | ︙ | |||
583 584 585 586 587 588 589 |
}
if( j==0 ) continue;
assert( i>=iSXb && i>=iSXp );
if( i<iEXb && j>=iSYb && j<iEYb ) continue;
if( i<iEXp && j>=iSYp && j<iEYp ) continue;
iSX = i;
iSY = j-1;
| | > > > | | < | > > > | | < | 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 |
}
if( j==0 ) continue;
assert( i>=iSXb && i>=iSXp );
if( i<iEXb && j>=iSYb && j<iEYb ) continue;
if( i<iEXp && j>=iSYp && j<iEYp ) continue;
iSX = i;
iSY = j-1;
pA = &p->aFrom[iSX-1];
pB = &p->aTo[iSY-1];
n = minInt(iSX-iS1, iSY-iS2);
for(k=0; k<n && same_dline(pA,pB); k++, pA--, pB--){}
iSX -= k;
iSY -= k;
iEX = i+1;
iEY = j;
pA = &p->aFrom[iEX];
pB = &p->aTo[iEY];
n = minInt(iE1-iEX, iE2-iEY);
for(k=0; k<n && same_dline(pA,pB); k++, pA++, pB++){}
iEX += k;
iEY += k;
skew = (iSX-iS1) - (iSY-iS2);
if( skew<0 ) skew = -skew;
dist = (iSX+iEX)/2 - mid;
if( dist<0 ) dist = -dist;
score = (iEX - iSX) - 0.05*skew - 0.05*dist;
if( score>bestScore ){
bestScore = score;
|
| ︙ | ︙ | |||
624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
*piSY = iSYb;
*piEX = iEXb;
*piEY = iEYb;
}
/* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n",
iS1, iE1, iS2, iE2, *piSX, *piEX, *piSY, *piEY); */
}
/*
** Do a single step in the difference. Compute a sequence of
** copy/delete/insert steps that will convert lines iS1 through iE1-1 of
** the input into lines iS2 through iE2-1 of the output and write
** that sequence into the difference context.
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 |
*piSY = iSYb;
*piEX = iEXb;
*piEY = iEYb;
}
/* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n",
iS1, iE1, iS2, iE2, *piSX, *piEX, *piSY, *piEY); */
}
/*
** Expand the size of aEdit[] array to hold at least nEdit elements.
*/
static void expandEdit(DContext *p, int nEdit){
p->aEdit = fossil_realloc(p->aEdit, nEdit*sizeof(int));
p->nEditAlloc = nEdit;
}
/*
** Append a new COPY/DELETE/INSERT triple.
*/
static void appendTriple(DContext *p, int nCopy, int nDel, int nIns){
/* printf("APPEND %d/%d/%d\n", nCopy, nDel, nIns); */
if( p->nEdit>=3 ){
if( p->aEdit[p->nEdit-1]==0 ){
if( p->aEdit[p->nEdit-2]==0 ){
p->aEdit[p->nEdit-3] += nCopy;
p->aEdit[p->nEdit-2] += nDel;
p->aEdit[p->nEdit-1] += nIns;
return;
}
if( nCopy==0 ){
p->aEdit[p->nEdit-2] += nDel;
p->aEdit[p->nEdit-1] += nIns;
return;
}
}
if( nCopy==0 && nDel==0 ){
p->aEdit[p->nEdit-1] += nIns;
return;
}
}
if( p->nEdit+3>p->nEditAlloc ){
expandEdit(p, p->nEdit*2 + 15);
if( p->aEdit==0 ) return;
}
p->aEdit[p->nEdit++] = nCopy;
p->aEdit[p->nEdit++] = nDel;
p->aEdit[p->nEdit++] = nIns;
}
/*
** Do a single step in the difference. Compute a sequence of
** copy/delete/insert steps that will convert lines iS1 through iE1-1 of
** the input into lines iS2 through iE2-1 of the output and write
** that sequence into the difference context.
**
|
| ︙ | ︙ | |||
657 658 659 660 661 662 663 |
return;
}
/* Find the longest matching segment between the two sequences */
longestCommonSequence(p, iS1, iE1, iS2, iE2, &iSX, &iEX, &iSY, &iEY);
if( iEX>iSX ){
| | | 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 |
return;
}
/* Find the longest matching segment between the two sequences */
longestCommonSequence(p, iS1, iE1, iS2, iE2, &iSX, &iEX, &iSY, &iEY);
if( iEX>iSX ){
/* A common segment has been found.
** Recursively diff either side of the matching segment */
diff_step(p, iS1, iSX, iS2, iSY);
if( iEX>iSX ){
appendTriple(p, iEX - iSX, 0, 0);
}
diff_step(p, iEX, iE1, iEY, iE2);
}else{
|
| ︙ | ︙ | |||
716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
expandEdit(p, p->nEdit+3);
if( p->aEdit ){
p->aEdit[p->nEdit++] = 0;
p->aEdit[p->nEdit++] = 0;
p->aEdit[p->nEdit++] = 0;
}
}
/*
** Extract the number of lines of context from diffFlags. Supply an
** appropriate default if no context width is specified.
*/
int diff_context_lines(int diffFlags){
int n = diffFlags & DIFF_CONTEXT_MASK;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 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 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 |
expandEdit(p, p->nEdit+3);
if( p->aEdit ){
p->aEdit[p->nEdit++] = 0;
p->aEdit[p->nEdit++] = 0;
p->aEdit[p->nEdit++] = 0;
}
}
/*
** Attempt to shift insertion or deletion blocks so that they begin and
** end on lines that are pure whitespace. In other words, try to transform
** this:
**
** int func1(int x){
** return x*10;
** +}
** +
** +int func2(int x){
** + return x*20;
** }
**
** int func3(int x){
** return x/5;
** }
**
** Into one of these:
**
** int func1(int x){ int func1(int x){
** return x*10; return x*10;
** } }
** +
** +int func2(int x){ +int func2(int x){
** + return x*20; + return x*20;
** +} +}
** +
** int func3(int x){ int func3(int x){
** return x/5; return x/5;
** } }
*/
static void diff_optimize(DContext *p){
int r; /* Index of current triple */
int lnFrom; /* Line number in p->aFrom */
int lnTo; /* Line number in p->aTo */
int cpy, del, ins;
lnFrom = lnTo = 0;
for(r=0; r<p->nEdit; r += 3){
cpy = p->aEdit[r];
del = p->aEdit[r+1];
ins = p->aEdit[r+2];
lnFrom += cpy;
lnTo += cpy;
/* Shift insertions toward the beginning of the file */
while( cpy>0 && del==0 && ins>0 ){
DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */
DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */
if( same_dline(pTop, pBtm)==0 ) break;
if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
lnFrom--;
lnTo--;
p->aEdit[r]--;
p->aEdit[r+3]++;
cpy--;
}
/* Shift insertions toward the end of the file */
while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
DLine *pTop = &p->aTo[lnTo]; /* First line inserted */
DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */
if( same_dline(pTop, pBtm)==0 ) break;
if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
lnFrom++;
lnTo++;
p->aEdit[r]++;
p->aEdit[r+3]--;
cpy++;
}
/* Shift deletions toward the beginning of the file */
while( cpy>0 && del>0 && ins==0 ){
DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */
DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
if( same_dline(pTop, pBtm)==0 ) break;
if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
lnFrom--;
lnTo--;
p->aEdit[r]--;
p->aEdit[r+3]++;
cpy--;
}
/* Shift deletions toward the end of the file */
while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */
DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
if( same_dline(pTop, pBtm)==0 ) break;
if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
lnFrom++;
lnTo++;
p->aEdit[r]++;
p->aEdit[r+3]--;
cpy++;
}
lnFrom += del;
lnTo += ins;
}
}
/*
** Extract the number of lines of context from diffFlags. Supply an
** appropriate default if no context width is specified.
*/
int diff_context_lines(int diffFlags){
int n = diffFlags & DIFF_CONTEXT_MASK;
|
| ︙ | ︙ | |||
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 |
Blob *pOut, /* Write diff here if not NULL */
int diffFlags /* DIFF_* flags defined above */
){
int ignoreEolWs; /* Ignore whitespace at the end of lines */
int nContext; /* Amount of context to display */
DContext c;
nContext = diff_context_lines(diffFlags);
ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
/* Prepare the input files */
memset(&c, 0, sizeof(c));
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
&c.nFrom, ignoreEolWs);
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
&c.nTo, ignoreEolWs);
if( c.aFrom==0 || c.aTo==0 ){
free(c.aFrom);
free(c.aTo);
if( pOut ){
blob_appendf(pOut, "cannot compute difference between binary files\n");
}
return 0;
}
/* Compute the difference */
diff_all(&c);
if( pOut ){
/* Compute a context or side-by-side diff into pOut */
if( diffFlags & DIFF_SIDEBYSIDE ){
int width = diff_width(diffFlags);
| > > > > > > > | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 |
Blob *pOut, /* Write diff here if not NULL */
int diffFlags /* DIFF_* flags defined above */
){
int ignoreEolWs; /* Ignore whitespace at the end of lines */
int nContext; /* Amount of context to display */
DContext c;
if( diffFlags & DIFF_INVERT ){
Blob *pTemp = pA_Blob;
pA_Blob = pB_Blob;
pB_Blob = pTemp;
}
nContext = diff_context_lines(diffFlags);
ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
/* Prepare the input files */
memset(&c, 0, sizeof(c));
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
&c.nFrom, ignoreEolWs);
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
&c.nTo, ignoreEolWs);
if( c.aFrom==0 || c.aTo==0 ){
free(c.aFrom);
free(c.aTo);
if( pOut ){
blob_appendf(pOut, "cannot compute difference between binary files\n");
}
return 0;
}
/* Compute the difference */
diff_all(&c);
if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c);
if( pOut ){
/* Compute a context or side-by-side diff into pOut */
int escHtml = (diffFlags & DIFF_HTML)!=0;
if( diffFlags & DIFF_SIDEBYSIDE ){
int width = diff_width(diffFlags);
sbsDiff(&c, pOut, nContext, width, escHtml);
}else{
int showLn = (diffFlags & DIFF_LINENO)!=0;
contextDiff(&c, pOut, nContext, showLn, escHtml);
}
free(c.aFrom);
free(c.aTo);
free(c.aEdit);
return 0;
}else{
/* If a context diff is not requested, then return the
** array of COPY/DELETE/INSERT triples.
*/
free(c.aFrom);
free(c.aTo);
return c.aEdit;
}
}
/*
** Process diff-related command-line options and return an appropriate
** "diffFlags" integer.
**
** --brief Show filenames only DIFF_BRIEF
** --context|-c N N lines of context. DIFF_CONTEXT_MASK
** --html Format for HTML DIFF_HTML
** --invert Invert the diff DIFF_INVERT
** --linenum|-n Show line numbers DIFF_LINENO
** --noopt Disable optimization DIFF_NOOPT
** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE
** --width|-W N N character lines. DIFF_WIDTH_MASK
*/
int diff_options(void){
int diffFlags = 0;
const char *z;
int f;
if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>0 ){
if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK;
diffFlags |= f;
}
if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
f *= DIFF_CONTEXT_MASK+1;
if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
diffFlags |= f;
}
if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML;
if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;
return diffFlags;
}
/*
** COMMAND: test-rawdiff
*/
void test_rawdiff_cmd(void){
Blob a, b;
int r;
int i;
int *R;
int diffFlags = diff_options();
if( g.argc<4 ) usage("FILE1 FILE2 ...");
blob_read_from_file(&a, g.argv[2]);
for(i=3; i<g.argc; i++){
if( i>3 ) fossil_print("-------------------------------\n");
blob_read_from_file(&b, g.argv[i]);
R = text_diff(&a, &b, 0, diffFlags);
for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]);
}
/* free(R); */
blob_reset(&b);
}
}
/*
** COMMAND: test-udiff
**
** Print the difference between two files. The usual diff options apply.
*/
void test_udiff_cmd(void){
|
| ︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 |
while( db_step(&q)==SQLITE_ROW ){
int pid = db_column_int(&q, 0);
const char *zUuid = db_column_text(&q, 1);
const char *zDate = db_column_text(&q, 2);
const char *zUser = db_column_text(&q, 3);
if( webLabel ){
zLabel = mprintf(
| | | | 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 |
while( db_step(&q)==SQLITE_ROW ){
int pid = db_column_int(&q, 0);
const char *zUuid = db_column_text(&q, 1);
const char *zDate = db_column_text(&q, 2);
const char *zUser = db_column_text(&q, 3);
if( webLabel ){
zLabel = mprintf(
"<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %13.13s",
g.zTop, zUuid, zUuid, zDate, zUser
);
}else{
zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser);
}
p->nVers++;
p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
p->azVers[p->nVers-1] = zLabel;
content_get(pid, &step);
annotation_step(p, &step, zLabel);
blob_reset(&step);
|
| ︙ | ︙ | |||
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 |
** Output the text of a file with markings to show when each line of
** the file was last modified.
**
** Options:
** --limit N Only look backwards in time by N versions
** --log List all versions analyzed
** --filevers Show file version numbers rather than check-in versions
*/
void annotate_cmd(void){
int fnid; /* Filename ID */
int fid; /* File instance ID */
int mid; /* Manifest where file was checked in */
int cid; /* Checkout ID */
Blob treename; /* FILENAME translated to canonical form */
| > > | 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 |
** Output the text of a file with markings to show when each line of
** the file was last modified.
**
** Options:
** --limit N Only look backwards in time by N versions
** --log List all versions analyzed
** --filevers Show file version numbers rather than check-in versions
**
** See also: info, finfo, timeline
*/
void annotate_cmd(void){
int fnid; /* Filename ID */
int fid; /* File instance ID */
int mid; /* Manifest where file was checked in */
int cid; /* Checkout ID */
Blob treename; /* FILENAME translated to canonical form */
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | ** This file contains code used to implement the "diff" command */ #include "config.h" #include "diffcmd.h" #include <assert.h> /* | | < < < < | < > | < < > | < | | | > > | | 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 |
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>
/*
** Use the right null device for the platform.
*/
#if defined(_WIN32)
# define NULL_DEVICE "NUL"
#else
# define NULL_DEVICE "/dev/null"
#endif
/*
** Print the "Index:" message that patches wants to see at the top of a diff.
*/
void diff_print_index(const char *zFile, int diffFlags){
if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF))==0 ){
char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
fossil_print("%s", z);
fossil_free(z);
}
}
/*
** Print the +++/--- filename lines for a diff operation.
*/
void diff_print_filenames(const char *zLeft, const char *zRight, int diffFlags){
char *z = 0;
if( diffFlags & DIFF_BRIEF ){
/* no-op */
}else if( diffFlags & DIFF_SIDEBYSIDE ){
int w = diff_width(diffFlags);
int n1 = strlen(zLeft);
int x;
if( n1>w*2 ) n1 = w*2;
x = w*2+17 - (n1+2);
z = mprintf("%.*c %.*s %.*c\n",
x/2, '=', n1, zLeft, (x+1)/2, '=');
}else{
z = mprintf("--- %s\n+++ %s\n", zLeft, zRight);
}
fossil_print("%s", z);
fossil_free(z);
}
/*
** Show the difference between two files, one in memory and one on disk.
**
** The difference is the set of edits needed to transform pFile1 into
|
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
Blob out; /* Diff output text */
Blob file2; /* Content of zFile2 */
const char *zName2; /* Name of zFile2 for display */
/* Read content of zFile2 into memory */
blob_zero(&file2);
if( file_wd_size(zFile2)<0 ){
| | > > > > > | | | | | > > < | 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 |
Blob out; /* Diff output text */
Blob file2; /* Content of zFile2 */
const char *zName2; /* Name of zFile2 for display */
/* Read content of zFile2 into memory */
blob_zero(&file2);
if( file_wd_size(zFile2)<0 ){
zName2 = NULL_DEVICE;
}else{
if( file_wd_islink(zFile2) ){
blob_read_link(&file2, zFile2);
}else{
blob_read_from_file(&file2, zFile2);
}
zName2 = zName;
}
/* Compute and output the differences */
if( diffFlags & DIFF_BRIEF ){
if( blob_compare(pFile1, &file2) ){
fossil_print("CHANGED %s\n", zName);
}
}else{
blob_zero(&out);
text_diff(pFile1, &file2, &out, diffFlags);
if( blob_size(&out) ){
diff_print_filenames(zName, zName2, diffFlags);
fossil_print("%s\n", blob_str(&out));
}
blob_reset(&out);
}
/* Release memory resources */
blob_reset(&file2);
}else{
int cnt = 0;
Blob nameFile1; /* Name of temporary file to old pFile1 content */
Blob cmd; /* Text of command to run */
/* Construct a temporary file to hold pFile1 based on the name of
** zFile2 */
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 162 163 164 165 166 167 |
void diff_file_mem(
Blob *pFile1, /* In memory content to compare from */
Blob *pFile2, /* In memory content to compare to */
const char *zName, /* Display name of the file */
const char *zDiffCmd, /* Command for comparison */
int diffFlags /* Diff flags */
){
if( zDiffCmd==0 ){
Blob out; /* Diff output text */
blob_zero(&out);
text_diff(pFile1, pFile2, &out, diffFlags);
diff_print_filenames(zName, zName, diffFlags);
| > | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
void diff_file_mem(
Blob *pFile1, /* In memory content to compare from */
Blob *pFile2, /* In memory content to compare to */
const char *zName, /* Display name of the file */
const char *zDiffCmd, /* Command for comparison */
int diffFlags /* Diff flags */
){
if( diffFlags & DIFF_BRIEF ) return;
if( zDiffCmd==0 ){
Blob out; /* Diff output text */
blob_zero(&out);
text_diff(pFile1, pFile2, &out, diffFlags);
diff_print_filenames(zName, zName, diffFlags);
fossil_print("%s\n", blob_str(&out));
/* Release memory resources */
blob_reset(&out);
}else{
Blob cmd;
char zTemp1[300];
char zTemp2[300];
|
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
){
Blob fname;
Blob content;
int isLink;
file_tree_name(zFileTreeName, &fname, 1);
historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
if( !isLink != !file_wd_islink(zFrom) ){
| | > | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
){
Blob fname;
Blob content;
int isLink;
file_tree_name(zFileTreeName, &fname, 1);
historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
if( !isLink != !file_wd_islink(zFrom) ){
fossil_print("cannot compute difference between "
"symlink and regular file\n");
}else{
diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags);
}
blob_reset(&content);
blob_reset(&fname);
}
|
| ︙ | ︙ | |||
285 286 287 288 289 290 291 |
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 ){
| | | | | | | > | 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 |
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 ){
fossil_print("DELETED %s\n", zPathname);
if( !asNewFile ){ showDiff = 0; zFullName = NULL_DEVICE; }
}else if( file_access(zFullName, 0) ){
fossil_print("MISSING %s\n", zPathname);
if( !asNewFile ){ showDiff = 0; }
}else if( isNew ){
fossil_print("ADDED %s\n", zPathname);
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}else if( isChnged==3 ){
fossil_print("ADDED_BY_MERGE %s\n", zPathname);
srcid = 0;
if( !asNewFile ){ showDiff = 0; }
}
if( showDiff ){
Blob content;
if( !isLink != !file_wd_islink(zFullName) ){
diff_print_index(zPathname, diffFlags);
diff_print_filenames(zPathname, zPathname, diffFlags);
fossil_print("cannot compute difference between "
"symlink and regular file\n");
continue;
}
if( srcid>0 ){
content_get(srcid, &content);
}else{
blob_zero(&content);
}
|
| ︙ | ︙ | |||
337 338 339 340 341 342 343 344 345 346 347 348 349 |
int diffFlags,
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_print_filenames(zName, zName, diffFlags);
| > > | | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
int diffFlags,
const char *zFileTreeName
){
char *zName;
Blob fname;
Blob v1, v2;
int isLink1, isLink2;
if( diffFlags & DIFF_BRIEF ) return;
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_print_filenames(zName, zName, diffFlags);
fossil_print("cannot compute difference "
" between symlink and regular file\n");
}else{
diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags);
}
blob_reset(&v1);
blob_reset(&v2);
blob_reset(&fname);
}
|
| ︙ | ︙ | |||
365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
struct ManifestFile *pTo,
const char *zDiffCmd,
int diffFlags
){
Blob f1, f2;
int rid;
const char *zName = pFrom ? pFrom->zName : pTo->zName;
diff_print_index(zName, diffFlags);
if( pFrom ){
rid = uuid_to_rid(pFrom->zUuid, 0);
content_get(rid, &f1);
}else{
blob_zero(&f1);
}
| > | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
struct ManifestFile *pTo,
const char *zDiffCmd,
int diffFlags
){
Blob f1, f2;
int rid;
const char *zName = pFrom ? pFrom->zName : pTo->zName;
if( diffFlags & DIFF_BRIEF ) return;
diff_print_index(zName, diffFlags);
if( pFrom ){
rid = uuid_to_rid(pFrom->zUuid, 0);
content_get(rid, &f1);
}else{
blob_zero(&f1);
}
|
| ︙ | ︙ | |||
413 414 415 416 417 418 419 |
cmp = +1;
}else if( pToFile==0 ){
cmp = -1;
}else{
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
}
if( cmp<0 ){
| | | > | > | > | 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 |
cmp = +1;
}else if( pToFile==0 ){
cmp = -1;
}else{
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
}
if( cmp<0 ){
fossil_print("DELETED %s\n", pFromFile->zName);
if( asNewFlag ){
diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags);
}
pFromFile = manifest_file_next(pFrom,0);
}else if( cmp>0 ){
fossil_print("ADDED %s\n", pToFile->zName);
if( asNewFlag ){
diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags);
}
pToFile = manifest_file_next(pTo,0);
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
/* No changes */
pFromFile = manifest_file_next(pFrom,0);
pToFile = manifest_file_next(pTo,0);
}else{
if( diffFlags & DIFF_BRIEF ){
fossil_print("CHANGED %s\n", pFromFile->zName);
}else{
diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags);
}
pFromFile = manifest_file_next(pFrom,0);
pToFile = manifest_file_next(pTo,0);
}
}
manifest_destroy(pFrom);
manifest_destroy(pTo);
}
|
| ︙ | ︙ | |||
468 469 470 471 472 473 474 475 476 | ** the "setting" command. If no external diff program is configured, then ** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff". ** ** The "-N" or "--new-file" option causes the complete text of added or ** deleted files to be displayed. ** ** Options: ** --context|-c N Use N lines of context ** --from|-r VERSION select VERSION as source for the diff | > < > | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
** the "setting" command. If no external diff program is configured, then
** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff".
**
** The "-N" or "--new-file" option causes the complete text of added or
** deleted files to be displayed.
**
** Options:
** --brief Show filenames only
** --context|-c N Use N lines of context
** --from|-r VERSION select VERSION as source for the diff
** -i use internal diff logic
** --new-file|-N output complete text of added or deleted files
** --to VERSION select VERSION as target for the diff
** --side-by-side|-y side-by-side diff
** --width|-W N Width of lines in side-by-side diff
*/
void diff_cmd(void){
int isGDiff; /* True for gdiff. False for normal diff */
int isInternDiff; /* True for internal diff */
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <errno.h> #include "file.h" /* ** The file status information from the most recent stat() call. ** ** Use _stati64 rather than stat on windows, in order to handle files ** larger than 2GB. */ #if defined(_WIN32) && (defined(__MSVCRT__) || defined(_MSC_VER)) | > > > > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <errno.h> #include "file.h" /* ** On Windows, include the Platform SDK header file. */ #ifdef _WIN32 # include <windows.h> #endif /* ** 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__) || defined(_MSC_VER)) |
| ︙ | ︙ | |||
166 167 168 169 170 171 172 |
nName = strlen(zLinkFile);
if( nName>=sizeof(zBuf) ){
zName = mprintf("%s", zLinkFile);
}else{
zName = zBuf;
memcpy(zName, zLinkFile, nName+1);
}
| | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
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, 0);
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;
}
|
| ︙ | ︙ | |||
257 258 259 260 261 262 263 |
** other than a directory.
*/
int file_isdir(const char *zFilename){
int rc;
if( zFilename ){
char *zFN = mprintf("%s", zFilename);
| | | | 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 |
** other than a directory.
*/
int file_isdir(const char *zFilename){
int rc;
if( zFilename ){
char *zFN = mprintf("%s", zFilename);
file_simplify_name(zFN, -1, 0);
rc = getStat(zFN, 0);
free(zFN);
}else{
rc = getStat(0, 0);
}
return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2);
}
/*
** Same as file_isdir(), but takes into account symlinks.
*/
int file_wd_isdir(const char *zFilename){
int rc;
if( zFilename ){
char *zFN = mprintf("%s", zFilename);
file_simplify_name(zFN, -1, 0);
rc = getStat(zFN, 1);
free(zFN);
}else{
rc = getStat(0, 1);
}
return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2);
}
|
| ︙ | ︙ | |||
312 313 314 315 316 317 318 |
z = mprintf("%s-%s", zBase, zSuffix);
while( file_size(z)>=0 ){
fossil_free(z);
z = mprintf("%s-%s-%d", zBase, zSuffix, cnt++);
}
if( relFlag ){
Blob x;
| | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
z = mprintf("%s-%s", zBase, zSuffix);
while( file_size(z)>=0 ){
fossil_free(z);
z = mprintf("%s-%s-%d", zBase, zSuffix, cnt++);
}
if( relFlag ){
Blob x;
file_relative_name(z, &x, 0);
fossil_free(z);
z = blob_str(&x);
}
return z;
}
/*
|
| ︙ | ︙ | |||
471 472 473 474 475 476 477 478 | ** ** * Convert all \ into / on windows ** * removing any trailing and duplicate / ** * removing /./ ** * removing /A/../ ** ** Changes are made in-place. Return the new name length. */ | > > | > | > | 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 508 509 |
**
** * Convert all \ into / on windows
** * removing any trailing and duplicate /
** * removing /./
** * removing /A/../
**
** Changes are made in-place. Return the new name length.
** If the slash parameter is non-zero, the trailing slash, if any,
** is retained.
*/
int file_simplify_name(char *z, int n, int slash){
int i, j;
if( n<0 ) n = strlen(z);
/* On windows convert all \ characters to / */
#if defined(_WIN32)
for(i=0; i<n; i++){
if( z[i]=='\\' ) z[i] = '/';
}
#endif
/* Removing trailing "/" characters */
if ( !slash ){
while( n>1 && z[n-1]=='/' ){ n--; }
}
/* Remove duplicate '/' characters. Except, two // at the beginning
** of a pathname is allowed since this is important on windows. */
for(i=j=1; i<n; i++){
z[j++] = z[i];
while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
}
|
| ︙ | ︙ | |||
538 539 540 541 542 543 544 |
*/
void cmd_test_simplify_name(void){
int i;
char *z;
for(i=2; i<g.argc; i++){
z = mprintf("%s", g.argv[i]);
fossil_print("[%s] -> ", z);
| | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
*/
void cmd_test_simplify_name(void){
int i;
char *z;
for(i=2; i<g.argc; i++){
z = mprintf("%s", g.argv[i]);
fossil_print("[%s] -> ", z);
file_simplify_name(z, -1, 0);
fossil_print("[%s]\n", z);
fossil_free(z);
}
}
/*
** Get the current working directory.
|
| ︙ | ︙ | |||
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
}else{
fossil_fatal("cannot find current working directory; %s",
strerror(errno));
}
}
#endif
}
/*
** Compute a canonical pathname for a file or directory.
** Make the name absolute if it is relative.
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
*/
| > > > > > > > > > > > > > > > > > > > > | | | < < < > > > > > > > > > > > > > > > > > | > | | 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 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 |
}else{
fossil_fatal("cannot find current working directory; %s",
strerror(errno));
}
}
#endif
}
/*
** Return true if zPath is an absolute pathname. Return false
** if it is relative.
*/
int file_is_absolute_path(const char *zPath){
if( zPath[0]=='/'
#if defined(_WIN32)
|| zPath[0]=='\\'
|| (strlen(zPath)>3 && zPath[1]==':'
&& (zPath[2]=='\\' || zPath[2]=='/'))
#endif
){
return 1;
}else{
return 0;
}
}
/*
** Compute a canonical pathname for a file or directory.
** Make the name absolute if it is relative.
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
** If the slash parameter is non-zero, the trailing slash, if any,
** is retained.
*/
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
if( file_is_absolute_path(zOrigName) ){
#if defined(_WIN32)
char *zOut;
#endif
blob_set(pOut, zOrigName);
blob_materialize(pOut);
#if defined(_WIN32)
/*
** On Windows, normalize the drive letter to upper case.
*/
zOut = blob_str(pOut);
if( fossil_isalpha(zOut[0]) && zOut[1]==':' ){
zOut[0] = fossil_toupper(zOut[0]);
}
#endif
}else{
char zPwd[2000];
file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
#if defined(_WIN32)
/*
** On Windows, normalize the drive letter to upper case.
*/
if( fossil_isalpha(zPwd[0]) && zPwd[1]==':' ){
zPwd[0] = fossil_toupper(zPwd[0]);
}
#endif
blob_zero(pOut);
blob_appendf(pOut, "%//%/", zPwd, zOrigName);
}
blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
blob_size(pOut), slash));
}
/*
** COMMAND: test-canonical-name
** Usage: %fossil test-canonical-name FILENAME...
**
** Test the operation of the canonical name generator.
** Also test Fossil's ability to measure attributes of a file.
*/
void cmd_test_canonical_name(void){
int i;
Blob x;
blob_zero(&x);
for(i=2; i<g.argc; i++){
char zBuf[100];
const char *zName = g.argv[i];
file_canonical_name(zName, &x, 0);
fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x));
blob_reset(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_wd_size(zName));
fossil_print(" file_size = %s\n", zBuf);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_wd_mtime(zName));
fossil_print(" file_mtime = %s\n", zBuf);
fossil_print(" file_isfile = %d\n", file_wd_isfile(zName));
|
| ︙ | ︙ | |||
674 675 676 677 678 679 680 | if( fossil_isalpha(zIn[0]) && zIn[1]==':' ) zIn += 2; #endif return zIn; } /* ** Compute a pathname for a file or directory that is relative | | > | | > | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 |
if( fossil_isalpha(zIn[0]) && zIn[1]==':' ) zIn += 2;
#endif
return zIn;
}
/*
** Compute a pathname for a file or directory that is relative
** to the current directory. If the slash parameter is non-zero,
** the trailing slash, if any, is retained.
*/
void file_relative_name(const char *zOrigName, Blob *pOut, int slash){
char *zPath;
blob_set(pOut, zOrigName);
blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
blob_size(pOut), slash));
zPath = file_without_drive_letter(blob_buffer(pOut));
if( zPath[0]=='/' ){
int i, j;
Blob tmp;
char *zPwd;
char zBuf[2000];
zPwd = zBuf;
|
| ︙ | ︙ | |||
739 740 741 742 743 744 745 |
** Test the operation of the relative name generator.
*/
void cmd_test_relative_name(void){
int i;
Blob x;
blob_zero(&x);
for(i=2; i<g.argc; i++){
| | > | > | > | | > | > > | > | > > | 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 |
** Test the operation of the relative name generator.
*/
void cmd_test_relative_name(void){
int i;
Blob x;
blob_zero(&x);
for(i=2; i<g.argc; i++){
file_relative_name(g.argv[i], &x, 0);
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
}
/*
** Compute a pathname for a file relative to the root of the local
** tree. Return TRUE on success. On failure, print and error
** message and quit if the errFatal flag is true. If errFatal is
** false, then simply return 0.
**
** The root of the tree is defined by the g.zLocalRoot variable.
*/
int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
Blob localRoot;
int nLocalRoot;
char *zLocalRoot;
Blob full;
int nFull;
char *zFull;
blob_zero(pOut);
db_must_be_within_tree();
file_canonical_name(g.zLocalRoot, &localRoot, 1);
nLocalRoot = blob_size(&localRoot);
zLocalRoot = blob_buffer(&localRoot);
assert( nLocalRoot>0 && zLocalRoot[nLocalRoot-1]=='/' );
file_canonical_name(zOrigName, &full, 0);
nFull = blob_size(&full);
zFull = blob_buffer(&full);
/* Special case. zOrigName refers to g.zLocalRoot directory. */
if( nFull==nLocalRoot-1 && memcmp(zLocalRoot, zFull, nFull)==0 ){
blob_append(pOut, ".", 1);
blob_reset(&localRoot);
blob_reset(&full);
return 1;
}
if( nFull<=nLocalRoot || memcmp(zLocalRoot, zFull, nLocalRoot) ){
blob_reset(&localRoot);
blob_reset(&full);
if( errFatal ){
fossil_fatal("file outside of checkout tree: %s", zOrigName);
}
return 0;
}
blob_append(pOut, &zFull[nLocalRoot], nFull-nLocalRoot);
blob_reset(&localRoot);
blob_reset(&full);
return 1;
}
/*
** COMMAND: test-tree-name
**
** Test the operation of the tree name generator.
|
| ︙ | ︙ | |||
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
}
/*
** Construct a random temporary filename into zBuf[].
*/
void file_tempname(int nBuf, char *zBuf){
static const char *azDirs[] = {
"/var/tmp",
"/usr/tmp",
"/tmp",
"/temp",
".",
};
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
const char *zDir = ".";
int cnt = 0;
| > > > > > > | > > > > > > > > > > > > > | 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 938 939 940 941 942 943 944 945 946 947 948 949 950 951 |
}
/*
** Construct a random temporary filename into zBuf[].
*/
void file_tempname(int nBuf, char *zBuf){
static const char *azDirs[] = {
#if defined(_WIN32)
0, /* GetTempPath */
0, /* TEMP */
0, /* TMP */
#else
"/var/tmp",
"/usr/tmp",
"/tmp",
"/temp",
#endif
".",
};
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
const char *zDir = ".";
int cnt = 0;
#if defined(_WIN32)
char zTmpPath[MAX_PATH];
if( GetTempPath(sizeof(zTmpPath), zTmpPath) ){
azDirs[0] = zTmpPath;
}
azDirs[1] = fossil_getenv("TEMP");
azDirs[2] = fossil_getenv("TMP");
#endif
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
if( azDirs[i]==0 ) continue;
if( !file_isdir(azDirs[i]) ) continue;
zDir = azDirs[i];
break;
}
/* Check that the output buffer is large enough for the temporary file
** name. If it is not, return SQLITE_ERROR.
|
| ︙ | ︙ | |||
884 885 886 887 888 889 890 891 892 893 894 895 896 897 |
j = (int)strlen(zBuf);
sqlite3_randomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
}while( file_size(zBuf)>=0 );
}
/*
** Return true if a file named zName exists and has identical content
** to the blob pContent. If zName does not exist or if the content is
** different in any way, then return false.
| > > > > > | 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 |
j = (int)strlen(zBuf);
sqlite3_randomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
}while( file_size(zBuf)>=0 );
#if defined(_WIN32)
fossil_mbcs_free((char *)azDirs[1]);
fossil_mbcs_free((char *)azDirs[2]);
#endif
}
/*
** Return true if a file named zName exists and has identical content
** to the blob pContent. If zName does not exist or if the content is
** different in any way, then return false.
|
| ︙ | ︙ | |||
916 917 918 919 920 921 922 | /************************************************************************** ** The following routines translate between MBCS and UTF8 on windows. ** Since everything is always UTF8 on unix, these routines are no-ops ** there. */ | < < < | 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 |
/**************************************************************************
** The following routines translate between MBCS and UTF8 on windows.
** Since everything is always UTF8 on unix, these routines are no-ops
** there.
*/
/*
** Translate MBCS to UTF8. Return a pointer to the translated text.
** Call fossil_mbcs_free() to deallocate any memory used to store the
** returned pointer when done.
*/
char *fossil_mbcs_to_utf8(const char *zMbcs){
|
| ︙ | ︙ | |||
947 948 949 950 951 952 953 954 955 956 957 958 959 960 |
#ifdef _WIN32
extern char *sqlite3_win32_utf8_to_mbcs(const char*);
return sqlite3_win32_utf8_to_mbcs(zUtf8);
#else
return (char*)zUtf8; /* No-op on unix */
#endif
}
/*
** Translate UTF8 to MBCS for display on the console. Return a pointer to the
** translated text.. Call fossil_mbcs_free() to deallocate any memory
** used to store the returned pointer when done.
*/
char *fossil_utf8_to_console(const char *zUtf8){
| > > > > > > > > > > > | 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 |
#ifdef _WIN32
extern char *sqlite3_win32_utf8_to_mbcs(const char*);
return sqlite3_win32_utf8_to_mbcs(zUtf8);
#else
return (char*)zUtf8; /* No-op on unix */
#endif
}
/*
** Return the value of an environment variable as UTF8.
*/
char *fossil_getenv(const char *zName){
char *zValue = getenv(zName);
#ifdef _WIN32
if( zValue ) zValue = fossil_mbcs_to_utf8(zValue);
#endif
return zValue;
}
/*
** Translate UTF8 to MBCS for display on the console. Return a pointer to the
** translated text.. Call fossil_mbcs_free() to deallocate any memory
** used to store the returned pointer when done.
*/
char *fossil_utf8_to_console(const char *zUtf8){
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 | ** -p select print mode ** --revision|-r R print the given revision (or ckout, if none is given) ** to stdout (only in print mode) ** -s select status mode (print a status indicator for FILE) ** --case-sensitive B Enable or disable case-sensitive filenames. B is a ** boolean: "yes", "no", "true", "false", etc. ** | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
** -p select print mode
** --revision|-r R print the given revision (or ckout, if none is given)
** to stdout (only in print mode)
** -s select status mode (print a status indicator for FILE)
** --case-sensitive B Enable or disable case-sensitive filenames. B is a
** boolean: "yes", "no", "true", "false", etc.
**
** See also: artifact, descendants, info, leaves
*/
void finfo_cmd(void){
capture_case_sensitive_option();
db_must_be_within_tree();
if (find_option("status","s",0)) {
Stmt q;
Blob line;
|
| ︙ | ︙ |
Changes to src/http.c.
| ︙ | ︙ | |||
172 173 174 175 176 177 178 |
*/
if( g.fHttpTrace ){
static int traceCnt = 0;
char *zOutFile;
FILE *out;
traceCnt++;
zOutFile = mprintf("http-request-%d.txt", traceCnt);
| | | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
*/
if( g.fHttpTrace ){
static int traceCnt = 0;
char *zOutFile;
FILE *out;
traceCnt++;
zOutFile = mprintf("http-request-%d.txt", traceCnt);
out = fopen(zOutFile, "wb");
if( out ){
fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), out);
fwrite(blob_buffer(&payload), 1, blob_size(&payload), out);
fclose(out);
}
free(zOutFile);
zOutFile = mprintf("http-reply-%d.txt", traceCnt);
out = fopen(zOutFile, "wb");
transport_log(out);
free(zOutFile);
}
/*
** Send the request to the server.
*/
|
| ︙ | ︙ | |||
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
"application/x-fossil-uncompressed", -1)==0 ){
isCompressed = 0;
}else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
isError = 1;
}
}
}
if( rc!=200 ){
fossil_warning("\"location:\" missing from 302 redirect reply");
goto write_err;
}
/*
** Extract the reply payload that follows the header
*/
| > > > > < < < < | 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 |
"application/x-fossil-uncompressed", -1)==0 ){
isCompressed = 0;
}else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
isError = 1;
}
}
}
if( iLength<0 ){
fossil_fatal("server did not reply");
goto write_err;
}
if( rc!=200 ){
fossil_warning("\"location:\" missing from 302 redirect reply");
goto write_err;
}
/*
** Extract the reply payload that follows the header
*/
blob_zero(pReply);
blob_resize(pReply, iLength);
iLength = transport_receive(blob_buffer(pReply), iLength);
blob_resize(pReply, iLength);
if( isError ){
char *z;
int i, j;
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
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 |
**
** Use the "finfo" command to get information about a specific
** file in a checkout.
**
** Options:
**
** -R|--repository FILE Extract info from repository FILE
*/
void info_cmd(void){
i64 fsize;
if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
db_open_config(0);
db_record_repository_filename(g.argv[2]);
db_open_repository(g.argv[2]);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
return;
}
db_find_and_open_repository(0,0);
if( g.argc==2 ){
int vid;
/* 012345678901234 */
db_record_repository_filename(0);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
if( g.localOpen ){
| > > | | 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 |
**
** Use the "finfo" command to get information about a specific
** file in a checkout.
**
** Options:
**
** -R|--repository FILE Extract info from repository FILE
**
** See also: annotate, artifact, finfo, timeline
*/
void info_cmd(void){
i64 fsize;
if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
db_open_config(0);
db_record_repository_filename(g.argv[2]);
db_open_repository(g.argv[2]);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
return;
}
db_find_and_open_repository(0,0);
if( g.argc==2 ){
int vid;
/* 012345678901234 */
db_record_repository_filename(0);
fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
if( g.localOpen ){
fossil_print("repository: %s\n", db_repository_filename());
fossil_print("local-root: %s\n", g.zLocalRoot);
}
#if defined(_WIN32)
if( g.zHome ){
fossil_print("user-home: %s\n", g.zHome);
}
#endif
|
| ︙ | ︙ | |||
249 250 251 252 253 254 255 | } } /* ** Append the difference between two RIDs to the output */ | | > | > | < < < < | < < < < < < < < < < < | < | < < < | > < < < < < > | < | < < < | | | < | 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 |
}
}
/*
** Append the difference between two RIDs to the output
*/
static void append_diff(const char *zFrom, const char *zTo, int diffFlags){
int fromid;
int toid;
Blob from, to, out;
if( zFrom ){
fromid = uuid_to_rid(zFrom, 0);
content_get(fromid, &from);
}else{
blob_zero(&from);
}
if( zTo ){
toid = uuid_to_rid(zTo, 0);
content_get(toid, &to);
}else{
blob_zero(&to);
}
blob_zero(&out);
if( diffFlags & DIFF_SIDEBYSIDE ){
text_diff(&from, &to, &out, diffFlags | DIFF_HTML);
@ <div class="sbsdiff">
@ %s(blob_str(&out))
@ </div>
}else{
text_diff(&from, &to, &out, diffFlags | DIFF_LINENO | DIFF_HTML);
@ <div class="udiff">
@ %s(blob_str(&out))
@ </div>
}
blob_reset(&from);
blob_reset(&to);
blob_reset(&out);
}
/*
** Write a line of web-page output that shows changes that have occurred
** to a file between two check-ins.
*/
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 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
int mperm /* executable or symlink permission for zNew */
){
if( !g.perm.History ){
if( zNew==0 ){
@ <p>Deleted %h(zName)</p>
}else if( zOld==0 ){
@ <p>Added %h(zName)</p>
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
@ <p>Name change from %h(zOldName) to %h(zName)
}else if( fossil_strcmp(zNew, zOld)==0 ){
@ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
@ for %h(zName)</p>
}else{
@ <p>Changes to %h(zName)</p>
}
if( diffFlags ){
@ <pre style="white-space:pre;">
append_diff(zOld, zNew, diffFlags);
@ </pre>
}
}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>
|
| ︙ | ︙ | |||
359 360 361 362 363 364 365 |
}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>
@ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
}
| | < < < | | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
}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>
@ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
}
if( diffFlags ){
@ <pre style="white-space:pre;">
append_diff(zOld, zNew, diffFlags);
@ </pre>
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
@
@ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)">[diff]</a>
}
@ </p>
}
}
/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/
int construct_diff_flags(int showDiff, int sideBySide){
int diffFlags;
if( showDiff==0 ){
diffFlags = 0; /* Zero means do not show any diff */
}else{
int x;
if( sideBySide ){
diffFlags = DIFF_SIDEBYSIDE | DIFF_IGNORE_EOLWS;
/* "dw" query parameter determines width of each column */
x = atoi(PD("dw","80"))*(DIFF_CONTEXT_MASK+1);
if( x<0 || x>DIFF_WIDTH_MASK ) x = DIFF_WIDTH_MASK;
diffFlags += x;
}else{
diffFlags = DIFF_INLINE | DIFF_IGNORE_EOLWS;
}
/* "dc" query parameter determines lines of context */
x = atoi(PD("dc","7"));
if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK;
diffFlags += x;
/* The "noopt" parameter disables diff optimization */
if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT;
}
return diffFlags;
}
/*
** WEBPAGE: vinfo
** WEBPAGE: ci
** URL: /ci?name=RID|ARTIFACTID
**
|
| ︙ | ︙ | |||
395 396 397 398 399 400 401 |
** shown, without diffs. This behavior is inverted if the
** "show-version-diffs" setting is turned on.
*/
void ci_page(void){
Stmt q;
int rid;
int isLeaf;
| | | > | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
** shown, without diffs. This behavior is inverted if the
** "show-version-diffs" setting is turned on.
*/
void ci_page(void){
Stmt q;
int rid;
int isLeaf;
int showDiff; /* True to show diffs */
int sideBySide; /* True for side-by-side diffs */
int diffFlags; /* Flag parameter for text_diff() */
const char *zName; /* Name of the checkin to be displayed */
const char *zUuid; /* UUID of zName */
const char *zParent; /* UUID of the parent checkin (if any) */
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
zName = P("name");
|
| ︙ | ︙ | |||
593 594 595 596 597 598 599 600 601 602 603 604 605 |
" (SELECT uuid FROM blob WHERE rid=mlink.fid),"
" (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
" FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
" WHERE mlink.mid=%d"
" ORDER BY name /*sort*/",
rid
);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q,0);
int mperm = db_column_int(&q, 1);
const char *zOld = db_column_text(&q,2);
const char *zNew = db_column_text(&q,3);
const char *zOldName = db_column_text(&q, 4);
| > | < | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 |
" (SELECT uuid FROM blob WHERE rid=mlink.fid),"
" (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
" FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
" WHERE mlink.mid=%d"
" ORDER BY name /*sort*/",
rid
);
diffFlags = construct_diff_flags(showDiff, sideBySide);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q,0);
int mperm = db_column_int(&q, 1);
const char *zOld = db_column_text(&q,2);
const char *zNew = db_column_text(&q,3);
const char *zOldName = db_column_text(&q, 4);
append_file_change_line(zName, zOld, zNew, zOldName, diffFlags, mperm);
}
db_finalize(&q);
}
style_footer();
}
/*
|
| ︙ | ︙ | |||
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 |
**
** Show all differences between two checkins.
*/
void vdiff_page(void){
int ridFrom, ridTo;
int showDetail = 0;
int sideBySide = 0;
Manifest *pFrom, *pTo;
ManifestFile *pFileFrom, *pFileTo;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
login_anonymous_available();
pFrom = vdiff_parse_manifest("from", &ridFrom);
if( pFrom==0 ) return;
pTo = vdiff_parse_manifest("to", &ridTo);
if( pTo==0 ) return;
showDetail = atoi(PD("detail","0"));
| > > | > | | | | 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 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 |
**
** Show all differences between two checkins.
*/
void vdiff_page(void){
int ridFrom, ridTo;
int showDetail = 0;
int sideBySide = 0;
int diffFlags = 0;
Manifest *pFrom, *pTo;
ManifestFile *pFileFrom, *pFileTo;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
login_anonymous_available();
pFrom = vdiff_parse_manifest("from", &ridFrom);
if( pFrom==0 ) return;
pTo = vdiff_parse_manifest("to", &ridTo);
if( pTo==0 ) return;
sideBySide = atoi(PD("sbs","1"));
showDetail = atoi(PD("detail","0"));
if( !showDetail && sideBySide ) showDetail = 1;
if( !sideBySide ){
style_submenu_element("Side-by-side Diff", "sbsdiff",
"%s/vdiff?from=%T&to=%T&detail=%d&sbs=1",
g.zTop, P("from"), P("to"), showDetail);
}else{
style_submenu_element("Unified Diff", "udiff",
"%s/vdiff?from=%T&to=%T&detail=%d&sbs=0",
g.zTop, P("from"), P("to"), showDetail);
}
style_header("Check-in Differences");
@ <h2>Difference From:</h2><blockquote>
checkin_description(ridFrom);
@ </blockquote><h2>To:</h2><blockquote>
checkin_description(ridTo);
@ </blockquote><hr /><p>
manifest_file_rewind(pFrom);
pFileFrom = manifest_file_next(pFrom, 0);
manifest_file_rewind(pTo);
pFileTo = manifest_file_next(pTo, 0);
diffFlags = construct_diff_flags(showDetail, sideBySide);
while( pFileFrom || pFileTo ){
int cmp;
if( pFileFrom==0 ){
cmp = +1;
}else if( pFileTo==0 ){
cmp = -1;
}else{
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
}
if( cmp<0 ){
append_file_change_line(pFileFrom->zName,
pFileFrom->zUuid, 0, 0, 0, 0);
pFileFrom = manifest_file_next(pFrom, 0);
}else if( cmp>0 ){
append_file_change_line(pFileTo->zName,
0, pFileTo->zUuid, 0, 0,
manifest_file_mperm(pFileTo));
pFileTo = manifest_file_next(pTo, 0);
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
/* No changes */
pFileFrom = manifest_file_next(pFrom, 0);
pFileTo = manifest_file_next(pTo, 0);
}else{
append_file_change_line(pFileFrom->zName,
pFileFrom->zUuid,
pFileTo->zUuid, 0, diffFlags,
manifest_file_mperm(pFileTo));
pFileFrom = manifest_file_next(pFrom, 0);
pFileTo = manifest_file_next(pTo, 0);
}
}
manifest_destroy(pFrom);
manifest_destroy(pTo);
|
| ︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 |
void diff_page(void){
int v1, v2;
int isPatch;
int sideBySide;
Blob c1, c2, diff, *pOut;
char *zV1;
char *zV2;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
v1 = name_to_rid_www("v1");
v2 = name_to_rid_www("v2");
if( v1==0 || v2==0 ) fossil_redirect_home();
sideBySide = atoi(PD("sbs","1"));
zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
isPatch = P("patch")!=0;
if( isPatch ){
pOut = cgi_output_blob();
cgi_set_content_type("text/plain");
}else{
blob_zero(&diff);
pOut = &diff;
| > > > > > > > > > | < > | | | | | < > > > > > | | | > | | > < < < | | | < | 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 |
void diff_page(void){
int v1, v2;
int isPatch;
int sideBySide;
Blob c1, c2, diff, *pOut;
char *zV1;
char *zV2;
int diffFlags;
const char *zStyle = "sbsdiff";
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
v1 = name_to_rid_www("v1");
v2 = name_to_rid_www("v2");
if( v1==0 || v2==0 ) fossil_redirect_home();
sideBySide = atoi(PD("sbs","1"));
zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
isPatch = P("patch")!=0;
if( isPatch ){
pOut = cgi_output_blob();
cgi_set_content_type("text/plain");
diffFlags = 4;
}else{
blob_zero(&diff);
pOut = &diff;
diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
if( sideBySide ){
zStyle = "sbsdiff";
}else{
diffFlags |= DIFF_LINENO;
zStyle = "udiff";
}
}
content_get(v1, &c1);
content_get(v2, &c2);
text_diff(&c1, &c2, pOut, diffFlags);
blob_reset(&c1);
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"));
if( !sideBySide ){
style_submenu_element("Side-by-side Diff", "sbsdiff",
"%s/fdiff?v1=%T&v2=%T&sbs=1",
g.zTop, P("v1"), P("v2"));
}else{
style_submenu_element("Unified Diff", "udiff",
"%s/fdiff?v1=%T&v2=%T&sbs=0",
g.zTop, P("v1"), P("v2"));
}
if( P("smhdr")!=0 ){
@ <h2>Differences From Artifact
@ <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a> To
@ <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>.</h2>
}else{
@ <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 />
@ <div class="%s(zStyle)">
@ %s(blob_str(&diff))
@ </div>
blob_reset(&diff);
style_footer();
}
}
/*
** WEBPAGE: raw
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | "payload" /* payload */, "requestId" /*requestId*/, "resultCode" /*resultCode*/, "resultText" /*resultText*/, "timestamp" /*timestamp*/ }; | < < < < < < < < < < < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | "payload" /* payload */, "requestId" /*requestId*/, "resultCode" /*resultCode*/, "resultText" /*resultText*/, "timestamp" /*timestamp*/ }; /* Timer code taken from sqlite3's shell.c, modified slightly. FIXME: move the timer into the fossil core API so that we can start the timer early on in the app init phase. Right now we're just timing the json ops themselves. */ #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL) |
| ︙ | ︙ | |||
93 94 95 96 97 98 99 |
/*
** Print the timing results.
*/
static double endTimer(void){
struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
| < < > > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
/*
** Print the timing results.
*/
static double endTimer(void){
struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
#if 0
printf("CPU Time: user %f sys %f\n",
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
#endif
return timeDiff(&sBegin.ru_utime, &sEnd.ru_utime)
+ timeDiff(&sBegin.ru_stime, &sEnd.ru_stime);
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER 1
#elif (defined(_WIN32) || defined(WIN32))
|
| ︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
static double endTimer(void){
if(getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
return timeDiff(&ftUserBegin, &ftUserEnd) +
timeDiff(&ftKernelBegin, &ftKernelEnd);
}
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER hasTimer()
#else
| > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
static double endTimer(void){
if(getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
return timeDiff(&ftUserBegin, &ftUserEnd) +
timeDiff(&ftKernelBegin, &ftKernelEnd);
}
return 0.0;
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER hasTimer()
#else
|
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
static char const * json_err_cstr( int errCode ){
switch( errCode ){
case 0: return "Success";
#define C(X,V) case FSL_JSON_E_ ## X: return V
C(GENERIC,"Generic error");
C(INVALID_REQUEST,"Invalid request");
| | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
static char const * json_err_cstr( int errCode ){
switch( errCode ){
case 0: return "Success";
#define C(X,V) case FSL_JSON_E_ ## X: return V
C(GENERIC,"Generic error");
C(INVALID_REQUEST,"Invalid request");
C(UNKNOWN_COMMAND,"Unknown command or subcommand");
C(UNKNOWN,"Unknown error");
C(TIMEOUT,"Timeout reached");
C(ASSERT,"Assertion failed");
C(ALLOC,"Resource allocation failed");
C(NYI,"Not yet implemented");
C(PANIC,"x");
C(MANIFEST_READ_FAILED,"Reading artifact manifest failed");
|
| ︙ | ︙ | |||
433 434 435 436 437 438 439 |
}else{
char const * cv = PD(zKey,NULL);
if(!cv && !g.isHTTP){
/* reminder to self: in CLI mode i'd like to try
find_option(zKey,NULL,XYZ) here, but we don't have a sane
default for the XYZ param here.
*/
| | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
}else{
char const * cv = PD(zKey,NULL);
if(!cv && !g.isHTTP){
/* reminder to self: in CLI mode i'd like to try
find_option(zKey,NULL,XYZ) here, but we don't have a sane
default for the XYZ param here.
*/
cv = fossil_getenv(zKey);
}
if(cv){/*transform it to JSON for later use.*/
/* use sscanf() to figure out if it's an int,
and transform it to JSON int if it is.
FIXME: use strtol(), since it has more accurate
error handling.
|
| ︙ | ︙ | |||
498 499 500 501 502 503 504 | } /* ** Wrapper around json_getenv() which tries to evaluate a payload/env ** value as a boolean. Uses mostly the same logic as ** json_getenv_int(), with the addition that string values which | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | } /* ** Wrapper around json_getenv() which tries to evaluate a payload/env ** value as a boolean. Uses mostly the same logic as ** json_getenv_int(), with the addition that string values which ** either start with a digit 1..9 or the letters [tTyY] are considered ** to be true. If this function cannot find a matching key/value then ** dflt is returned. e.g. if it finds the key but the value is-a ** Object then dftl is returned. ** ** If an entry is found, this function guarantees that it will return ** either 0 or 1, as opposed to "0 or non-zero", so that clients can ** pass a different value as dflt. Thus they can use, e.g. -1 to know |
| ︙ | ︙ | |||
520 521 522 523 524 525 526 |
}else if( cson_value_is_number(v) ){
return cson_value_get_integer(v) ? 1 : 0;
}else if( cson_value_is_string(v) ){
char const * sv = cson_string_cstr(cson_value_get_string(v));
if(!*sv || ('0'==*sv)){
return 0;
}else{
| > | | > | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
}else if( cson_value_is_number(v) ){
return cson_value_get_integer(v) ? 1 : 0;
}else if( cson_value_is_string(v) ){
char const * sv = cson_string_cstr(cson_value_get_string(v));
if(!*sv || ('0'==*sv)){
return 0;
}else{
return ((('1'<=*sv) && ('9'>=*sv))
|| ('t'==*sv) || ('T'==*sv)
|| ('y'==*sv) || ('Y'==*sv)
)
? 1 : 0;
}
}else if( cson_value_is_bool(v) ){
return cson_value_get_bool(v) ? 1 : 0;
}else if( cson_value_is_null(v) ){
return 0;
}else{
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 | } /* ** An extended form of find_option() which tries to look up a combo ** GET/POST/CLI argument. ** ** zKey must be the GET/POST parameter key. zCLILong must be the "long | | | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 | } /* ** An extended form of find_option() which tries to look up a combo ** GET/POST/CLI argument. ** ** zKey must be the GET/POST parameter key. zCLILong must be the "long s** form" CLI flag (NULL means to use zKey). zCLIShort may be NULL or ** the "short form" CLI flag (if NULL, no short form is used). ** ** If argPos is >=0 and no other match is found, ** json_command_arg(argPos) is also checked. ** ** On error (no match found) NULL is returned. ** |
| ︙ | ︙ | |||
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 |
assert(NULL != zKey);
if(!g.isHTTP){
rc = find_option(zCLILong ? zCLILong : zKey,
zCLIShort, 1);
}
if(!rc && fossil_has_json()){
rc = json_getenv_cstr(zKey);
}
if(!rc && (argPos>=0)){
rc = json_command_arg((unsigned char)argPos);
}
return rc;
}
char const * json_find_option_cstr(char const * zKey,
char const * zCLILong,
char const * zCLIShort){
| > > > > > > | | 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 |
assert(NULL != zKey);
if(!g.isHTTP){
rc = find_option(zCLILong ? zCLILong : zKey,
zCLIShort, 1);
}
if(!rc && fossil_has_json()){
rc = json_getenv_cstr(zKey);
if(!rc && zCLIShort){
rc = cson_value_get_cstr( cson_object_get( g.json.param.o, zCLIShort) );
}
}
if(!rc && (argPos>=0)){
rc = json_command_arg((unsigned char)argPos);
}
return rc;
}
/*
** Short-hand form of json_find_option_cstr2(zKey,zCLILong,zCLIShort,-1).
*/
char const * json_find_option_cstr(char const * zKey,
char const * zCLILong,
char const * zCLIShort){
return json_find_option_cstr2(zKey, zCLILong, zCLIShort, -1);
}
/*
** The boolean equivalent of json_find_option_cstr().
** If the option is not found, dftl is returned.
*/
char json_find_option_bool(char const * zKey,
|
| ︙ | ︙ | |||
607 608 609 610 611 612 613 |
if((-1==rc) && fossil_has_json()){
rc = json_getenv_bool(zKey,-1);
}
return (-1==rc) ? dflt : rc;
}
/*
| | | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
if((-1==rc) && fossil_has_json()){
rc = json_getenv_bool(zKey,-1);
}
return (-1==rc) ? dflt : rc;
}
/*
** The integer equivalent of json_find_option_cstr2().
** If the option is not found, dftl is returned.
*/
int json_find_option_int(char const * zKey,
char const * zCLILong,
char const * zCLIShort,
int dflt ){
enum { Magic = -1947854832 };
int rc = Magic;
if(!g.isHTTP){
/* FIXME: use strtol() for better error/dflt handling. */
char const * opt = find_option(zCLILong ? zCLILong : zKey,
zCLIShort, 1);
if(NULL!=opt){
rc = atoi(opt);
|
| ︙ | ︙ | |||
783 784 785 786 787 788 789 |
}
}
}
return g.json.authToken;
}
/*
| | | < | > > | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
}
}
}
return g.json.authToken;
}
/*
** If g.json.reqPayload.o is NULL then NULL is returned, else the
** given property is searched for in the request payload. If found it
** is returned. The returned value is owned by (or shares ownership
** with) g.json, and must NOT be cson_value_free()'d by the
** caller.
*/
cson_value * json_req_payload_get(char const *pKey){
return g.json.reqPayload.o
? cson_object_get(g.json.reqPayload.o,pKey)
: NULL;
}
|
| ︙ | ︙ | |||
918 919 920 921 922 923 924 |
char separator,
char doDeHttp,
cson_array * target ){
char const * p = zStr /* current byte */;
char const * head /* current start-of-token */;
unsigned int len = 0 /* current token's length */;
int rc = 0 /* return code (number of added elements)*/;
| < | 917 918 919 920 921 922 923 924 925 926 927 928 929 930 |
char separator,
char doDeHttp,
cson_array * target ){
char const * p = zStr /* current byte */;
char const * head /* current start-of-token */;
unsigned int len = 0 /* current token's length */;
int rc = 0 /* return code (number of added elements)*/;
assert( zStr && target );
while( fossil_isspace(*p) ){
++p;
}
head = p;
for( ; ; ++p){
if( !*p || (separator == *p) ){
|
| ︙ | ︙ | |||
985 986 987 988 989 990 991 | /* ** Wrapper around json_string_split(), taking the same first 3 ** parameters as this function, but returns the results as a JSON ** Array (if splitting produced tokens) or NULL (if splitting failed ** in any way or produced no tokens). ** ** The returned value is owned by the caller. If not NULL then it | | | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 |
/*
** Wrapper around json_string_split(), taking the same first 3
** parameters as this function, but returns the results as a JSON
** Array (if splitting produced tokens) or NULL (if splitting failed
** in any way or produced no tokens).
**
** The returned value is owned by the caller. If not NULL then it
** _will_ have a JSON type of Array.
*/
cson_value * json_string_split2( char const * zStr,
char separator,
char doDeHttp ){
cson_value * v = cson_value_new_array();
cson_array * a = cson_value_get_array(v);
int rc = json_string_split( zStr, separator, doDeHttp, a );
|
| ︙ | ︙ | |||
1021 1022 1023 1024 1025 1026 1027 |
** before they do any work.
**
** This must only be called once, or an assertion may be triggered.
*/
static void json_mode_bootstrap(){
static char once = 0 /* guard against multiple runs */;
char const * zPath = P("PATH_INFO");
| < | 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 |
** before they do any work.
**
** This must only be called once, or an assertion may be triggered.
*/
static void json_mode_bootstrap(){
static char once = 0 /* guard against multiple runs */;
char const * zPath = P("PATH_INFO");
assert( (0==once) && "json_mode_bootstrap() called too many times!");
if( once ){
return;
}else{
once = 1;
}
g.json.isJsonMode = 1;
|
| ︙ | ︙ | |||
1157 1158 1159 1160 1161 1162 1163 |
}
if(!g.isHTTP){
g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/;
}
{/* set up JSON output formatting options. */
int indent = -1;
| < > > > > > > > | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
}
if(!g.isHTTP){
g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/;
}
{/* set up JSON output formatting options. */
int indent = -1;
indent = json_find_option_int("indent",NULL,"I",-1);
g.json.outOpt.indentation = (0>indent)
? (g.isHTTP ? 0 : 1)
: (unsigned char)indent;
g.json.outOpt.addNewline = g.isHTTP
? 0
: (g.json.jsonp ? 0 : 1);
}
if( g.isHTTP ){
json_auth_token()/* will copy our auth token, if any, to fossil's
core, which we need before we call
login_check_credentials(). */;
login_check_credentials()/* populates g.perm */;
}
else{
/* FIXME: we need an option which allows us to skip this. At least
one known command (/json/version) does not need an opened
repo. The problem here is we cannot know which functions need
it from here (because command dispatching hasn't yet happened)
and all other commands rely on the repo being opened before
they are called. A textbook example of lack of foresight :/.
*/
db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
}
}
/*
** Returns the ndx'th item in the "command path", where index 0 is the
** position of the "json" part of the path. Returns NULL if ndx is out
|
| ︙ | ︙ | |||
1226 1227 1228 1229 1230 1231 1232 |
if(g.json.cmd.offset < 0){
return NULL;
}else{
ndx = g.json.cmd.offset + ndx;
return cson_string_cstr(cson_value_get_string(cson_array_get( ar, g.json.cmd.offset + ndx )));
}
}
| < < < < < < < < < < < < < < | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 |
if(g.json.cmd.offset < 0){
return NULL;
}else{
ndx = g.json.cmd.offset + ndx;
return cson_string_cstr(cson_value_get_string(cson_array_get( ar, g.json.cmd.offset + ndx )));
}
}
/* Returns the C-string form of json_auth_token(), or NULL
** if json_auth_token() returns NULL.
*/
char const * json_auth_token_cstr(){
return cson_value_get_cstr( json_auth_token() );
}
|
| ︙ | ︙ | |||
1299 1300 1301 1302 1303 1304 1305 |
return code;
}
}
/*
** Convenience routine which converts a Julian time value into a Unix
** Epoch timestamp. Requires the db, so this cannot be used before the
| | > > | > < > | > | | 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 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 |
return code;
}
}
/*
** Convenience routine which converts a Julian time value into a Unix
** Epoch timestamp. Requires the db, so this cannot be used before the
** repo is opened (will trigger a fatal error in db_xxx()). The returned
** value is owned by the caller.
*/
cson_value * json_julian_to_timestamp(double j){
return cson_value_new_integer((cson_int_t)
db_int64(0,"SELECT cast(strftime('%%s',%lf) as int)",j)
);
}
/*
** Returns a timestamp value.
*/
cson_int_t json_timestamp(){
return (cson_int_t)time(0);
}
/*
** Returns a new JSON value (owned by the caller) representing
** a timestamp. If timeVal is < 0 then time(0) is used to fetch
** the time, else timeVal is used as-is. The returned value is
** owned by the caller.
*/
cson_value * json_new_timestamp(cson_int_t timeVal){
return cson_value_new_integer((timeVal<0) ? (cson_int_t)time(0) : timeVal);
}
/*
** Internal helper for json_create_response(). Appends the first
** g.json.dispatchDepth elements of g.json.cmd.a, skipping the first
** one (the "json" part), to a string and returns that string value
** (which is owned by the caller).
*/
static cson_value * json_response_command_path(){
if(!g.json.cmd.a){
return NULL;
}else{
cson_value * rc = NULL;
Blob path = empty_blob;
unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/
unsigned int i = 1;
for( ; i < aLen; ++i ){
char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i)));
if(!part){
#if 1
fossil_warning("Iterating further than expected in %s.",
__FILE__);
#endif
break;
}
blob_appendf(&path,"%s%s", (i>1 ? "/": ""), part);
}
rc = json_new_string((blob_size(&path)>0)
? blob_buffer(&path)
: "")
/* reminder; we need an empty string instead of NULL
|
| ︙ | ︙ | |||
1467 1468 1469 1470 1471 1472 1473 | /* ** Creates a new Fossil/JSON response envelope skeleton. It is owned ** by the caller, who must eventually free it using cson_value_free(), ** or add it to a cson container to transfer ownership. Returns NULL ** on error. ** ** If payload is not NULL and resultCode is 0 then it is set as the | | > | | | | > | | 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 |
/*
** Creates a new Fossil/JSON response envelope skeleton. It is owned
** by the caller, who must eventually free it using cson_value_free(),
** or add it to a cson container to transfer ownership. Returns NULL
** on error.
**
** If payload is not NULL and resultCode is 0 then it is set as the
** "payload" property of the returned object. If resultCode is 0 then
** it defaults to g.json.resultCode. If resultCode is (or defaults to)
** non-zero and payload is not NULL then this function calls
** cson_value_free(payload) and does not insert the payload into the
** response. In either case, onwership of payload is transfered to (or
** shared with, if the caller holds a reference) this function.
**
** pMsg is an optional message string property (resultText) of the
** response. If resultCode is non-0 and pMsg is NULL then
** json_err_cstr() is used to get the error string. The caller may
** provide his own or may use an empty string to suppress the
** resultText property.
**
*/
static cson_value * json_create_response( int resultCode,
char const * pMsg,
cson_value * payload){
cson_value * v = NULL;
cson_value * tmp = NULL;
cson_object * o = NULL;
int rc;
resultCode = json_dumbdown_rc(resultCode ? resultCode : g.json.resultCode);
o = cson_new_object();
v = cson_object_value(o);
if( ! o ) return NULL;
#define SET(K) if(!tmp) goto cleanup; \
rc = cson_object_set( o, K, tmp ); \
if(rc) do{\
cson_value_free(tmp); \
tmp = NULL; \
goto cleanup; \
}while(0)
tmp = json_new_string(MANIFEST_UUID);
SET("fossil");
tmp = json_new_timestamp(-1);
SET(FossilJsonKeys.timestamp);
if( 0 != resultCode ){
if( ! pMsg ){
|
| ︙ | ︙ | |||
1606 1607 1608 1609 1610 1611 1612 | ** the cgi_xxx() family of functions, this function inherits any ** compression which fossil does for its output. ** ** If alsoOutput is true AND g.isHTTP then cgi_reply() is called to ** flush the output (and headers). Generally only do this if you are ** about to call exit(). ** | | | 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 |
** the cgi_xxx() family of functions, this function inherits any
** compression which fossil does for its output.
**
** If alsoOutput is true AND g.isHTTP then cgi_reply() is called to
** flush the output (and headers). Generally only do this if you are
** about to call exit().
**
** If !g.isHTTP then alsoOutput is ignored and all output is sent to
** stdout immediately.
**
** For generating the resultText property: if msg is not NULL then it
** is used as-is. If it is NULL then g.zErrMsg is checked, and if that
** is NULL then json_err_cstr(code) is used.
*/
void json_err( int code, char const * msg, char alsoOutput ){
|
| ︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 |
if(!a){
a = cson_new_array();
assert(NULL!=a);
}
if(!colNames){
colNamesV = cson_sqlite3_column_names(pStmt->pStmt);
assert(NULL != colNamesV);
| | | 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 |
if(!a){
a = cson_new_array();
assert(NULL!=a);
}
if(!colNames){
colNamesV = cson_sqlite3_column_names(pStmt->pStmt);
assert(NULL != colNamesV);
cson_value_add_reference(colNamesV)/*avoids an ownership problem*/;
colNames = cson_value_get_array(colNamesV);
assert(NULL != colNames);
}
row = cson_sqlite3_row_to_object2(pStmt->pStmt, colNames);
if(!row && !warnMsg){
warnMsg = "Could not convert at least one result row to JSON.";
continue;
|
| ︙ | ︙ | |||
1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 |
}
row = cson_sqlite3_row_to_array(pStmt->pStmt);
cson_array_append(a, row);
}
return cson_array_value(a);
}
/*
** Executes the given SQL and runs it through
** json_stmt_to_array_of_obj(), returning the result of that
** function. If resetBlob is true then blob_reset(pSql) is called
** after preparing the query.
**
** pTgt has the same semantics as described for
** json_stmt_to_array_of_obj().
*/
cson_value * json_sql_to_array_of_obj(Blob * pSql, cson_array * pTgt,
char resetBlob){
Stmt q = empty_Stmt;
cson_value * pay = NULL;
assert( blob_size(pSql) > 0 );
db_prepare(&q, "%s", blob_str(pSql));
if(resetBlob){
blob_reset(pSql);
}
pay = json_stmt_to_array_of_obj(&q, pTgt);
db_finalize(&q);
return pay;
}
/*
** If the given COMMIT rid has any tags associated with it, this
| > > > > > > > > > > > > > > > > > > > > | | > > > | 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 |
}
row = cson_sqlite3_row_to_array(pStmt->pStmt);
cson_array_append(a, row);
}
return cson_array_value(a);
}
cson_value * json_stmt_to_array_of_values(Stmt *pStmt,
int resultColumn,
cson_array * pTgt){
cson_array * a = pTgt;
while( (SQLITE_ROW==db_step(pStmt)) ){
cson_value * row = cson_sqlite3_column_to_value(pStmt->pStmt,
resultColumn);
if(row){
if(!a){
a = cson_new_array();
assert(NULL!=a);
}
cson_array_append(a, row);
}
}
return cson_array_value(a);
}
/*
** Executes the given SQL and runs it through
** json_stmt_to_array_of_obj(), returning the result of that
** function. If resetBlob is true then blob_reset(pSql) is called
** after preparing the query.
**
** pTgt has the same semantics as described for
** json_stmt_to_array_of_obj().
**
** FIXME: change this to take a (char const *) instead of a blob,
** to simplify the trivial use-cases (which don't need a Blob).
*/
cson_value * json_sql_to_array_of_obj(Blob * pSql, cson_array * pTgt,
char resetBlob){
Stmt q = empty_Stmt;
cson_value * pay = NULL;
assert( blob_size(pSql) > 0 );
db_prepare(&q, "%s", blob_str(pSql));
if(resetBlob){
blob_reset(pSql);
}
pay = json_stmt_to_array_of_obj(&q, pTgt);
db_finalize(&q);
return pay;
}
/*
** If the given COMMIT rid has any tags associated with it, this
** function returns a JSON Array containing the tag names (owned by
** the caller), else it returns NULL.
**
** See info_tags_of_checkin() for more details (this is simply a JSON
** wrapper for that function).
**
** If there are no tags then this function returns NULL, not an empty
** Array.
*/
cson_value * json_tags_for_checkin_rid(int rid, char propagatingOnly){
cson_value * v = NULL;
char * tags = info_tags_of_checkin(rid, propagatingOnly);
if(tags){
if(*tags){
v = json_string_split2(tags,',',0);
|
| ︙ | ︙ | |||
1817 1818 1819 1820 1821 1822 1823 |
cson_array * list = cson_value_get_array(listV);
cson_value * objV = NULL;
cson_object * obj = NULL;
cson_string * kRC;
cson_string * kSymbol;
cson_string * kNumber;
cson_string * kDesc;
| | < < < < | 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 |
cson_array * list = cson_value_get_array(listV);
cson_value * objV = NULL;
cson_object * obj = NULL;
cson_string * kRC;
cson_string * kSymbol;
cson_string * kNumber;
cson_string * kDesc;
cson_array_reserve( list, 35 );
kRC = cson_new_string("resultCode",10);
kSymbol = cson_new_string("cSymbol",7);
kNumber = cson_new_string("number",6);
kDesc = cson_new_string("description",11);
#define C(K) objV = cson_value_new_object(); obj = cson_value_get_object(objV); \
cson_object_set_s(obj, kRC, json_new_string(json_rc_cstr(FSL_JSON_E_##K)) ); \
cson_object_set_s(obj, kSymbol, json_new_string("FSL_JSON_E_"#K) ); \
|
| ︙ | ︙ | |||
1892 1893 1894 1895 1896 1897 1898 | jobj = cson_value_get_object(jval); #define FSET(X,K) cson_object_set( jobj, K, cson_value_new_string(X,strlen(X))) FSET(MANIFEST_UUID,"manifestUuid"); FSET(MANIFEST_VERSION,"manifestVersion"); FSET(MANIFEST_DATE,"manifestDate"); FSET(MANIFEST_YEAR,"manifestYear"); FSET(RELEASE_VERSION,"releaseVersion"); | < > > | 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 |
jobj = cson_value_get_object(jval);
#define FSET(X,K) cson_object_set( jobj, K, cson_value_new_string(X,strlen(X)))
FSET(MANIFEST_UUID,"manifestUuid");
FSET(MANIFEST_VERSION,"manifestVersion");
FSET(MANIFEST_DATE,"manifestDate");
FSET(MANIFEST_YEAR,"manifestYear");
FSET(RELEASE_VERSION,"releaseVersion");
cson_object_set( jobj, "releaseVersionNumber",
cson_value_new_integer(RELEASE_VERSION_NUMBER) );
cson_object_set( jobj, "resultCodeParanoiaLevel",
cson_value_new_integer(g.json.errorDetailParanoia) );
/*FSET(FOSSIL_JSON_API_VERSION, "jsonApiVersion" );*/
#undef FSET
return jval;
}
/*
** Returns the current user's capabilities string as a String value.
** Returned value is owned by the caller, and will only be NULL if
|
| ︙ | ︙ | |||
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 |
const char *zDb;
enum { BufLen = 1000 };
char zBuf[BufLen];
cson_value * jv = NULL;
cson_object * jo = NULL;
cson_value * jv2 = NULL;
cson_object * jo2 = NULL;
if( !g.perm.Read ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' permissions.");
return NULL;
}
full = json_find_option_bool("full",NULL,"f",0);
#define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf)));
jv = cson_value_new_object();
jo = cson_value_get_object(jv);
| > | | > | < | < > > | 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 |
const char *zDb;
enum { BufLen = 1000 };
char zBuf[BufLen];
cson_value * jv = NULL;
cson_object * jo = NULL;
cson_value * jv2 = NULL;
cson_object * jo2 = NULL;
char * zTmp = NULL;
if( !g.perm.Read ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' permissions.");
return NULL;
}
full = json_find_option_bool("full",NULL,"f",0);
#define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf)));
jv = cson_value_new_object();
jo = cson_value_get_object(jv);
zTmp = db_get("project-name",NULL);
cson_object_set(jo, "projectName", json_new_string(zTmp));
free(zTmp);
zTmp = db_get("project-description",NULL);
cson_object_set(jo, "projectDescription", json_new_string(zTmp));
free(zTmp);
zTmp = NULL;
fsize = file_size(g.zRepositoryName);
cson_object_set(jo, "repositorySize", cson_value_new_integer((cson_int_t)fsize));
if(full){
n = db_int(0, "SELECT count(*) FROM blob");
m = db_int(0, "SELECT count(*) FROM delta");
cson_object_set(jo, "blobCount", cson_value_new_integer((cson_int_t)n));
|
| ︙ | ︙ | |||
2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 |
if((zPages+1)->name){
blob_append(pOut, ", ",2);
}
}
return i;
}
cson_value * json_page_dispatch_helper(JsonPageDef const * pages){
JsonPageDef const * def;
char const * cmd = json_command_arg(1+g.json.dispatchDepth);
assert( NULL != pages );
if( ! cmd ){
| > > > > > > > > > > > > > > > > > > > > > > > > < | < | < < > | > | 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 |
if((zPages+1)->name){
blob_append(pOut, ", ",2);
}
}
return i;
}
/*
** Creates an error message using zErrPrefix and the given array of
** JSON command definitions, and sets the g.json error state to
** reflect FSL_JSON_E_MISSING_ARGS. If zErrPrefix is NULL then
** some default is used (e.g. "Try one of: "). If it is "" then
** no prefix is used.
**
** The intention is to provide the user (via the response.resultText)
** a list of available commands/subcommands.
**
*/
void json_dispatch_missing_args_err( JsonPageDef const * pCommands,
char const * zErrPrefix ){
Blob cmdNames = empty_blob;
blob_init(&cmdNames,NULL,0);
if( !zErrPrefix ) {
zErrPrefix = "Try one of: ";
}
blob_append( &cmdNames, zErrPrefix, strlen(zErrPrefix) );
json_pagedefs_to_string(pCommands, &cmdNames);
json_set_err(FSL_JSON_E_MISSING_ARGS, "%s",
blob_str(&cmdNames));
blob_reset(&cmdNames);
}
cson_value * json_page_dispatch_helper(JsonPageDef const * pages){
JsonPageDef const * def;
char const * cmd = json_command_arg(1+g.json.dispatchDepth);
assert( NULL != pages );
if( ! cmd ){
json_dispatch_missing_args_err(pages,
"No subcommand specified. "
"Try one of: ");
return NULL;
}
def = json_handler_for_name( cmd, pages );
if(!def){
json_set_err(FSL_JSON_E_UNKNOWN_COMMAND,
"Unknown subcommand: %s", cmd);
return NULL;
}
else{
++g.json.dispatchDepth;
return (*def->func)();
}
}
|
| ︙ | ︙ | |||
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 |
cson_value * json_page_anon_password();
/* Impl in json_artifact.c. */
cson_value * json_page_artifact();
/* Impl in json_branch.c. */
cson_value * json_page_branch();
/* Impl in json_diff.c. */
cson_value * json_page_diff();
/* Impl in json_login.c. */
cson_value * json_page_login();
/* Impl in json_login.c. */
cson_value * json_page_logout();
/* Impl in json_query.c. */
cson_value * json_page_query();
/* Impl in json_report.c. */
cson_value * json_page_report();
/* Impl in json_tag.c. */
cson_value * json_page_tag();
/* Impl in json_user.c. */
cson_value * json_page_user();
/*
** Mapping of names to JSON pages/commands. Each name is a subpath of
** /json (in CGI mode) or a subcommand of the json command in CLI mode
*/
static const JsonPageDef JsonPageDefs[] = {
/* please keep alphabetically sorted (case-insensitive) for maintenance reasons. */
{"anonymousPassword", json_page_anon_password, 0},
{"artifact", json_page_artifact, 0},
{"branch", json_page_branch,0},
{"cap", json_page_cap, 0},
{"diff", json_page_diff, 0},
| > > > > > > > | > | < > | > > > > > > > | | | > | | < < < > > > > > > | < < < > | | | < < < | < > | < < | | < < < | < | < < | | < < < | < < < < < < < | < < < < < < < < < < | | < < < < < < < < < < | | | > > > > > > > > > > > > > > > > | | < > > < < < > | < < < < < < < < < < < | < < < < < < < < < | | | | | | | < < | > | > | | < < > | < < < < < | 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 |
cson_value * json_page_anon_password();
/* Impl in json_artifact.c. */
cson_value * json_page_artifact();
/* Impl in json_branch.c. */
cson_value * json_page_branch();
/* Impl in json_diff.c. */
cson_value * json_page_diff();
/* Impl in json_dir.c. */
cson_value * json_page_dir();
/* Impl in json_login.c. */
cson_value * json_page_login();
/* Impl in json_login.c. */
cson_value * json_page_logout();
/* Impl in json_query.c. */
cson_value * json_page_query();
/* Impl in json_report.c. */
cson_value * json_page_report();
/* Impl in json_tag.c. */
cson_value * json_page_tag();
/* Impl in json_user.c. */
cson_value * json_page_user();
/* Impl in json_config.c. */
cson_value * json_page_config();
/* Impl in json_finfo.c. */
cson_value * json_page_finfo();
/*
** Mapping of names to JSON pages/commands. Each name is a subpath of
** /json (in CGI mode) or a subcommand of the json command in CLI mode
*/
static const JsonPageDef JsonPageDefs[] = {
/* please keep alphabetically sorted (case-insensitive) for maintenance reasons. */
{"anonymousPassword", json_page_anon_password, 0},
{"artifact", json_page_artifact, 0},
{"branch", json_page_branch,0},
{"cap", json_page_cap, 0},
{"config", json_page_config, 0 },
{"diff", json_page_diff, 0},
{"dir", json_page_dir, 0},
{"finfo", json_page_finfo, 0},
{"g", json_page_g, 0},
{"HAI",json_page_version,0},
{"login",json_page_login,0},
{"logout",json_page_logout,0},
{"query",json_page_query,0},
{"rebuild",json_page_rebuild,0},
{"report", json_page_report, 0},
{"resultCodes", json_page_resultCodes,0},
{"stat",json_page_stat,0},
{"tag", json_page_tag,0},
/*{"ticket", json_page_nyi,0},*/
{"timeline", json_page_timeline,0},
{"user",json_page_user,0},
{"version",json_page_version,0},
{"whoami",json_page_whoami,0},
{"wiki",json_page_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Internal helper for json_cmd_top() and json_page_top().
**
** Searches JsonPageDefs for a command with the given name. If found,
** it is used to generate and output a JSON response. If not found, it
** generates a JSON-style error response. Returns 0 on success, non-0
** on error. On error it will set g.json's error state.
*/
static int json_dispatch_root_command( char const * zCommand ){
int rc = 0;
cson_value * payload = NULL;
JsonPageDef const * pageDef = NULL;
pageDef = json_handler_for_name(zCommand,&JsonPageDefs[0]);
if( ! pageDef ){
rc = FSL_JSON_E_UNKNOWN_COMMAND;
json_set_err( rc, "Unknown command: %s", zCommand );
}else if( pageDef->runMode < 0 /*CLI only*/){
rc = FSL_JSON_E_WRONG_MODE;
}else if( (g.isHTTP && (pageDef->runMode < 0 /*CLI only*/))
||
(!g.isHTTP && (pageDef->runMode > 0 /*HTTP only*/))
){
rc = FSL_JSON_E_WRONG_MODE;
}
else{
rc = 0;
g.json.dispatchDepth = 1;
payload = (*pageDef->func)();
}
payload = json_create_response(rc, NULL, payload);
json_send_response(payload);
cson_value_free(payload);
return rc;
}
#ifdef FOSSIL_ENABLE_JSON /* dupe ifdef needed for mkindex */
/*
** WEBPAGE: json
**
** Pages under /json/... must be entered into JsonPageDefs.
** This function dispatches them, and is the HTTP equivalent of
** json_cmd_top().
*/
void json_page_top(void){
char const * zCommand;
BEGIN_TIMER;
json_mode_bootstrap();
zCommand = json_command_arg(1);
if(!zCommand || !*zCommand){
json_dispatch_missing_args_err( JsonPageDefs,
"No command (sub-path) specified."
" Try one of: ");
return;
}
json_dispatch_root_command( zCommand );
}
#endif /* FOSSIL_ENABLE_JSON for mkindex */
#ifdef FOSSIL_ENABLE_JSON /* dupe ifdef needed for mkindex */
/*
** This function dispatches json commands and is the CLI equivalent of
** json_page_top().
**
** COMMAND: json
**
** Usage: %fossil json SUBCOMMAND ?OPTIONS?
**
** In CLI mode, the -R REPO common option is supported. Due to limitations
** in the argument dispatching code, any -FLAGS must come after the final
** sub- (or subsub-) command.
**
** The commands include:
**
** anonymousPassord
** artifact
** branch
** cap
** diff
** g
** login
** logout
** query
** rebuild
** report
** resultCodes
** stat
** tag
** timeline
** user
** version (alias: HAI)
** whoami
** wiki
**
** Run '%fossil json' without any subcommand to see the full list (but be
** aware that some listed might not yet be implemented).
**
** PS: the notable TODO-commands include: config, dir, finfo, ticket
**
*/
void json_cmd_top(void){
char const * cmd = NULL;
int rc = 0;
BEGIN_TIMER;
memset( &g.perm, 0xff, sizeof(g.perm) )
/* In CLI mode fossil does not use permissions
and they all default to false. We enable them
here because (A) fossil doesn't use them in local
mode but (B) having them set gives us one less
difference in the CLI/CGI/Server-mode JSON
handling.
*/
;
json_main_bootstrap();
json_mode_bootstrap();
if( 2 > cson_array_length_get(g.json.cmd.a) ){
goto usage;
}
#if 0
json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again.");
#endif
cmd = json_command_arg(1);
if( !cmd || !*cmd ){
goto usage;
}
rc = json_dispatch_root_command( cmd );
if(0 != rc){
/* FIXME: we need a way of passing this error back
up to the routine which called this callback.
e.g. add g.errCode.
*/
fossil_exit(1);
}
return;
usage:
{
cson_value * payload;
json_dispatch_missing_args_err( JsonPageDefs,
"No subcommand specified."
" Try one of: ");
payload = json_create_response(0, NULL, NULL);
json_send_response(payload);
cson_value_free(payload);
fossil_exit(1);
}
}
#endif /* FOSSIL_ENABLE_JSON for mkindex */
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_artifact.c.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/**
JSON construction callback. Creates the contents for the
payload.artifact property of /json/artifact responses.
*/
artifact_f func;
} ArtifactDispatchEntry;
/*
** Generates an artifact Object for the given rid,
** which must refer to a Checkin.
**
** Returned value is NULL or an Object owned by the caller.
*/
cson_value * json_artifact_for_ci( int rid, char showFiles ){
| > > > > > > > > > > > > > > > > > > > > > > > > < | < < < < < | | | | > | | < | | | < > > > > > > > > | | < < < < < < | | | | | | < < | 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 |
/**
JSON construction callback. Creates the contents for the
payload.artifact property of /json/artifact responses.
*/
artifact_f func;
} ArtifactDispatchEntry;
/*
** Generates a JSON Array reference holding the parent UUIDs (as strings).
** If it finds no matches then it returns NULL (OOM is a fatal error).
**
** Returned value is NULL or an Array owned by the caller.
*/
cson_value * json_parent_uuids_for_ci( int rid ){
Stmt q = empty_Stmt;
cson_array * pParents = NULL;
db_prepare( &q,
"SELECT uuid FROM plink, blob"
" WHERE plink.cid=%d AND blob.rid=plink.pid"
" ORDER BY plink.isprim DESC",
rid );
while( SQLITE_ROW==db_step(&q) ){
if(!pParents) {
pParents = cson_new_array();
}
cson_array_append( pParents, cson_sqlite3_column_to_value( q.pStmt, 0 ) );
}
db_finalize(&q);
return cson_array_value(pParents);
}
/*
** Generates an artifact Object for the given rid,
** which must refer to a Checkin.
**
** Returned value is NULL or an Object owned by the caller.
*/
cson_value * json_artifact_for_ci( int rid, char showFiles ){
cson_value * v = NULL;
Stmt q = empty_Stmt;
static cson_value * eventTypeLabel = NULL;
if(!eventTypeLabel){
eventTypeLabel = json_new_string("checkin");
json_gc_add("$EVENT_TYPE_LABEL(commit)", eventTypeLabel);
}
db_prepare(&q,
"SELECT b.uuid, "
" cast(strftime('%%s',e.mtime) as int), "
" strftime('%%s',e.omtime),"
" e.user, "
" e.comment"
" FROM blob b, event e"
" WHERE b.rid=%d"
" AND e.objid=%d",
rid, rid
);
if( db_step(&q)==SQLITE_ROW ){
cson_object * o;
cson_value * tmpV = NULL;
const char *zUuid = db_column_text(&q, 0);
const char *zUser;
const char *zComment;
char * zEUser, * zEComment;
int mtime, omtime;
v = cson_value_new_object();
o = cson_value_get_object(v);
#define SET(K,V) cson_object_set(o,(K), (V))
SET("type", eventTypeLabel );
SET("uuid",json_new_string(zUuid));
SET("isLeaf", cson_value_new_bool(is_a_leaf(rid)));
mtime = db_column_int(&q,1);
SET("timestamp",json_new_int(mtime));
omtime = db_column_int(&q,2);
if(omtime && (omtime!=mtime)){
SET("originTime",json_new_int(omtime));
}
zUser = db_column_text(&q,3);
zEUser = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
TAG_USER, rid);
if(zEUser){
SET("user", json_new_string(zEUser));
if(0!=strcmp(zEUser,zUser)){
SET("originUser",json_new_string(zUser));
}
free(zEUser);
}else{
SET("user",json_new_string(zUser));
}
zComment = db_column_text(&q,4);
zEComment = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
TAG_COMMENT, rid);
if(zEComment){
SET("comment",json_new_string(zEComment));
if(0 != strcmp(zEComment,zComment)){
SET("originComment", json_new_string(zComment));
}
free(zEComment);
}else{
SET("comment",json_new_string(zComment));
}
tmpV = json_parent_uuids_for_ci(rid);
if(tmpV){
SET("parents", tmpV);
}
tmpV = json_tags_for_checkin_rid(rid,0);
if(tmpV){
SET("tags",tmpV);
}
if( showFiles ){
tmpV = json_get_changed_files(rid);
if(tmpV){
SET("files",tmpV);
}
}
#undef SET
}
db_finalize(&q);
return v;
}
/*
** Very incomplete/incorrect impl of /json/artifact/TICKET_ID.
*/
|
| ︙ | ︙ | |||
187 188 189 190 191 192 193 |
return cson_object_value(pay);
}
/*
** Sub-impl of /json/artifact for checkins.
*/
static cson_value * json_artifact_ci( int rid ){
| | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
return cson_object_value(pay);
}
/*
** Sub-impl of /json/artifact for checkins.
*/
static cson_value * json_artifact_ci( int rid ){
if(!g.perm.Read){
json_set_err( FSL_JSON_E_DENIED, "Viewing checkins requires 'o' privileges." );
return NULL;
}else{
return json_artifact_for_ci(rid, 1);
}
}
/*
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 |
cson_value * json_artifact_wiki(int rid){
if( ! g.perm.RdWiki ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'j' privileges.");
return NULL;
}else{
| > > > > | > > > > > > > > > > > > > > > > > < < > > > | < < < | < | | > | | | > > > | | | > > > | > | > > > > > > > > > > > | > | | | 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 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 |
cson_value * json_artifact_wiki(int rid){
if( ! g.perm.RdWiki ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'j' privileges.");
return NULL;
}else{
char contentFormat = json_wiki_get_content_format_flag(-9);
if(-9 == contentFormat){
contentFormat = json_artifact_include_content_flag() ? -1 : 0;
}
return json_get_wiki_page_by_rid(rid, contentFormat);
}
}
/*
** Internal helper for routines which add a "status" flag to file
** artifact data. isNew and isDel should be the "is this object new?"
** and "is this object removed?" flags of the underlying query. This
** function returns a static string from the set (added, removed,
** modified), depending on the combination of the two args.
**
** Reminder to self: (mlink.pid==0) AS isNew, (mlink.fid==0) AS isDel
*/
char const * json_artifact_status_to_string( char isNew, char isDel ){
return isNew
? "added"
: (isDel
? "removed"
: "modified");
}
cson_value * json_artifact_file(int rid){
cson_object * pay = NULL;
Stmt q = empty_Stmt;
cson_array * checkin_arr = NULL;
if( ! g.perm.Read ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' privileges.");
return NULL;
}
pay = cson_new_object();
if( json_artifact_include_content_flag() ){
Blob content = empty_blob;
const char *zMime;
content_get(rid, &content);
zMime = mimetype_from_content(&content);
cson_object_set(pay, "contentType",
json_new_string(zMime ? zMime : "text/plain"));
cson_object_set(pay, "size", json_new_int( blob_size(&content)) );
if(!zMime){
cson_object_set(pay, "content",
cson_value_new_string(blob_str(&content),
(unsigned int)blob_size(&content)));
}
blob_reset(&content);
}
db_prepare(&q,
"SELECT filename.name AS name, "
" (mlink.pid==0) AS isNew,"
" (mlink.fid==0) AS isDel,"
" cast(strftime('%%s',event.mtime) as int) AS timestamp,"
" coalesce(event.ecomment,event.comment) as comment,"
" coalesce(event.euser,event.user) as user,"
" a.size AS size,"
" b.uuid as uuid, "
#if 0
" mlink.mperm as mperm,"
#endif
" coalesce((SELECT value FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND "
" rid=mlink.mid),'trunk') as branch"
" 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
);
/* TODO: add a "state" flag for the file in each checkin,
e.g. "modified", "new", "deleted".
*/
checkin_arr = cson_new_array();
cson_object_set(pay, "checkins", cson_array_value(checkin_arr));
while( (SQLITE_ROW==db_step(&q) ) ){
cson_object * row = cson_value_get_object(cson_sqlite3_row_to_object(q.pStmt));
char const isNew = cson_value_get_bool(cson_object_get(row,"isNew"));
char const isDel = cson_value_get_bool(cson_object_get(row,"isDel"));
cson_object_set(row, "isNew", NULL);
cson_object_set(row, "isDel", NULL);
cson_object_set(row, "state",
json_new_string(json_artifact_status_to_string(isNew, isDel)));
cson_array_append( checkin_arr, cson_object_value(row) );
}
db_finalize(&q);
return cson_object_value(pay);
}
/*
** Impl of /json/artifact. This basically just determines the type of
** an artifact and forwards the real work to another function.
*/
cson_value * json_page_artifact(){
cson_object * pay = NULL;
char const * zName = NULL;
char const * zType = NULL;
char const * zUuid = NULL;
cson_value * entry = NULL;
Blob uuid = empty_blob;
int rc;
int rid = 0;
ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0];
zName = json_find_option_cstr2("name", NULL, NULL, g.json.dispatchDepth+1);
if(!zName || !*zName) {
json_set_err(FSL_JSON_E_MISSING_ARGS,
"Missing 'name' argument.");
return NULL;
}
if( validate16(zName, strlen(zName)) ){
if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
zType = "ticket";
goto handle_entry;
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 |
if(!g.json.resultCode){
assert( NULL != entry );
assert( NULL != zType );
pay = cson_new_object();
cson_object_set( pay, "type", json_new_string(zType) );
/*cson_object_set( pay, "uuid", json_new_string(zUuid) );*/
cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );
| | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
if(!g.json.resultCode){
assert( NULL != entry );
assert( NULL != zType );
pay = cson_new_object();
cson_object_set( pay, "type", json_new_string(zType) );
/*cson_object_set( pay, "uuid", json_new_string(zUuid) );*/
cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );
/*cson_object_set( pay, "rid", cson_value_new_integer(rid) );*/
if(entry){
cson_object_set(pay, "artifact", entry);
}
}
veryend:
blob_reset(&uuid);
return cson_object_value(pay);
}
#endif /* FOSSIL_ENABLE_JSON */
|
Added src/json_config.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
#ifdef FOSSIL_ENABLE_JSON
/*
** Copyright (c) 2011 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*/
#include "VERSION.h"
#include "config.h"
#include "json_config.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_config_get();
static cson_value * json_config_save();
/*
** Mapping of /json/config/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Config[] = {
{"get", json_config_get, 0},
{"save", json_config_save, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/config family of pages/commands.
**
*/
cson_value * json_page_config(){
return json_page_dispatch_helper(&JsonPageDefs_Config[0]);
}
/*
** JSON-internal mapping of config options to config groups. This is
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
char const * name;
int groupMask;
} JsonConfigProperties[] = {
{ "css", CONFIGSET_SKIN },
{ "header", CONFIGSET_SKIN },
{ "footer", CONFIGSET_SKIN },
{ "index-page", CONFIGSET_SKIN },
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "project-name", CONFIGSET_PROJ },
{ "project-description", CONFIGSET_PROJ },
{ "manifest", CONFIGSET_PROJ },
{ "ignore-glob", CONFIGSET_PROJ },
{ "crnl-glob", CONFIGSET_PROJ },
{ "empty-dirs", CONFIGSET_PROJ },
{ "allow-symlinks", CONFIGSET_PROJ },
{ "ticket-table", CONFIGSET_TKT },
{ "ticket-common", CONFIGSET_TKT },
{ "ticket-change", CONFIGSET_TKT },
{ "ticket-newpage", CONFIGSET_TKT },
{ "ticket-viewpage", CONFIGSET_TKT },
{ "ticket-editpage", CONFIGSET_TKT },
{ "ticket-reportlist", CONFIGSET_TKT },
{ "ticket-report-template", CONFIGSET_TKT },
{ "ticket-key-template", CONFIGSET_TKT },
{ "ticket-title-expr", CONFIGSET_TKT },
{ "ticket-closed-expr", CONFIGSET_TKT },
{NULL, 0}
};
/*
** Impl of /json/config/get. Requires setup rights.
**
*/
static cson_value * json_config_get(){
cson_object * pay = NULL;
Stmt q = empty_Stmt;
Blob sql = empty_blob;
char const * zName = NULL;
int confMask = 0;
char optSkinBackups = 0;
unsigned int i;
if(!g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED, "Requires 's' permissions.");
return NULL;
}
i = g.json.dispatchDepth + 1;
zName = json_command_arg(i);
for( ; zName; zName = json_command_arg(++i) ){
if(0==(strcmp("all", zName))){
confMask = CONFIGSET_ALL;
}else if(0==(strcmp("project", zName))){
confMask |= CONFIGSET_PROJ;
}else if(0==(strcmp("skin", zName))){
confMask |= CONFIGSET_SKIN;
}else if(0==(strcmp("ticket", zName))){
confMask |= CONFIGSET_TKT;
}else if(0==(strcmp("skin-backup", zName))){
optSkinBackups = 1;
}else{
json_set_err( FSL_JSON_E_INVALID_ARGS,
"Unknown config area: %s", zName);
return NULL;
}
}
if(!confMask && !optSkinBackups){
json_set_err(FSL_JSON_E_MISSING_ARGS, "No configuration area(s) selected.");
}
blob_append(&sql,
"SELECT name, value"
" FROM config "
" WHERE 0 ", -1);
{
const struct JsonConfigProperty * prop = &JsonConfigProperties[0];
blob_append(&sql," OR name IN (",-1);
for( i = 0; prop->name; ++prop ){
if(prop->groupMask & confMask){
if( i++ ){
blob_append(&sql,",",1);
}
blob_appendf(&sql, "%Q", prop->name);
}
}
blob_append(&sql,") ", -1);
}
if( optSkinBackups ){
blob_append(&sql, " OR name GLOB 'skin:*'", -1);
}
blob_append(&sql," ORDER BY name", -1);
db_prepare(&q, blob_str(&sql));
blob_reset(&sql);
pay = cson_new_object();
while( (SQLITE_ROW==db_step(&q)) ){
cson_object_set(pay,
db_column_text(&q,0),
json_new_string(db_column_text(&q,1)));
}
db_finalize(&q);
return cson_object_value(pay);
}
/*
** Impl of /json/config/save.
**
** TODOs:
*/
static cson_value * json_config_save(){
json_set_err(FSL_JSON_E_NYI, NULL);
return NULL;
}
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_detail.h.
| ︙ | ︙ | |||
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 |
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*/
#include "cson_amalgamation.h"
/*
** Impl details for the JSON API which need to be shared
** across multiple C files.
*/
/*
** The "official" list of Fossil/JSON error codes. Their values might
** very well change during initial development but after their first
** public release they must stay stable.
**
** Values must be in the range 1000..9999 for error codes and 1..999
** for warning codes.
**
** Numbers evenly dividable by 100 are "categories", and error codes
** for a given category have their high bits set to the category
** value.
**
*/
enum FossilJsonCodes {
FSL_JSON_W_START = 0,
FSL_JSON_W_UNKNOWN /*+1*/,
FSL_JSON_W_ROW_TO_JSON_FAILED /*+2*/,
FSL_JSON_W_COL_TO_JSON_FAILED /*+3*/,
| > > > > > > > > > > > > > | 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 |
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*/
#include "cson_amalgamation.h"
/**
FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest
"significant" change to the JSON API (a change in an interface
or new functionality). It is sent as part of the /json/version
request. We could arguably add it to each response.
*/
#define FOSSIL_JSON_API_VERSION "20120409"
/*
** Impl details for the JSON API which need to be shared
** across multiple C files.
*/
/*
** The "official" list of Fossil/JSON error codes. Their values might
** very well change during initial development but after their first
** public release they must stay stable.
**
** Values must be in the range 1000..9999 for error codes and 1..999
** for warning codes.
**
** Numbers evenly dividable by 100 are "categories", and error codes
** for a given category have their high bits set to the category
** value.
**
** Maintenance reminder: when entries are added to this list, update
** the code in json_page_resultCodes() and json_err_cstr() (both in
** json.c)!
**
*/
enum FossilJsonCodes {
FSL_JSON_W_START = 0,
FSL_JSON_W_UNKNOWN /*+1*/,
FSL_JSON_W_ROW_TO_JSON_FAILED /*+2*/,
FSL_JSON_W_COL_TO_JSON_FAILED /*+3*/,
|
| ︙ | ︙ |
Changes to src/json_diff.c.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 34 35 | /* ** Generates a diff between two versions (zFrom and zTo), using nContext ** content lines in the output. On success, returns a new JSON String ** object. On error it sets g.json's error state and returns NULL. ** ** If fSbs is true (non-0) them side-by-side diffs are used. */ cson_value * json_generate_diff(const char *zFrom, const char *zTo, | > > | > < | > | | > | 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 |
/*
** Generates a diff between two versions (zFrom and zTo), using nContext
** content lines in the output. On success, returns a new JSON String
** object. On error it sets g.json's error state and returns NULL.
**
** If fSbs is true (non-0) them side-by-side diffs are used.
**
** If fHtml is true then HTML markup is added to the diff.
*/
cson_value * json_generate_diff(const char *zFrom, const char *zTo,
int nContext, char fSbs,
char fHtml){
int fromid;
int toid;
int outLen;
Blob from = empty_blob, to = empty_blob, out = empty_blob;
cson_value * rc = NULL;
int flags = (DIFF_CONTEXT_MASK & nContext)
| (fSbs ? DIFF_SIDEBYSIDE : 0)
| (fHtml ? DIFF_HTML : 0);
fromid = name_to_typed_rid(zFrom, "*");
if(fromid<=0){
json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
"Could not resolve 'from' ID.");
return NULL;
}
toid = name_to_typed_rid(zTo, "*");
if(toid<=0){
json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
"Could not resolve 'to' ID.");
return NULL;
}
content_get(fromid, &from);
content_get(toid, &to);
blob_zero(&out);
text_diff(&from, &to, &out, flags);
blob_reset(&from);
blob_reset(&to);
outLen = blob_size(&out);
if(outLen>=0){
rc = cson_value_new_string(blob_buffer(&out),
(unsigned int)blob_size(&out));
}
blob_reset(&out);
return rc;
}
/*
** Implementation of the /json/diff page.
|
| ︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
cson_value * json_page_diff(){
cson_object * pay = NULL;
cson_value * v = NULL;
char const * zFrom;
char const * zTo;
int nContext = 0;
char doSBS;
if(!g.perm.Read){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' permissions.");
return NULL;
}
zFrom = json_find_option_cstr("v1",NULL,NULL);
if(!zFrom){
| > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
cson_value * json_page_diff(){
cson_object * pay = NULL;
cson_value * v = NULL;
char const * zFrom;
char const * zTo;
int nContext = 0;
char doSBS;
char doHtml;
if(!g.perm.Read){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' permissions.");
return NULL;
}
zFrom = json_find_option_cstr("v1",NULL,NULL);
if(!zFrom){
|
| ︙ | ︙ | |||
108 109 110 111 112 113 114 |
if(!zTo){
json_set_err(FSL_JSON_E_MISSING_ARGS,
"Required 'v2' parameter is missing.");
return NULL;
}
nContext = json_find_option_int("context",NULL,"c",5);
doSBS = json_find_option_bool("sbs",NULL,"y",0);
| > | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
if(!zTo){
json_set_err(FSL_JSON_E_MISSING_ARGS,
"Required 'v2' parameter is missing.");
return NULL;
}
nContext = json_find_option_int("context",NULL,"c",5);
doSBS = json_find_option_bool("sbs",NULL,"y",0);
doHtml = json_find_option_bool("html",NULL,"h",0);
v = json_generate_diff(zFrom, zTo, nContext, doSBS, doHtml);
if(!v){
if(!g.json.resultCode){
json_set_err(FSL_JSON_E_UNKNOWN,
"Generating diff failed for unknown reason.");
}
return NULL;
}
|
| ︙ | ︙ |
Added src/json_dir.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 |
#ifdef FOSSIL_ENABLE_JSON
/*
** Copyright (c) 2011 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*/
#include "VERSION.h"
#include "config.h"
#include "json_dir.h"
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_page_dir_list();
/*
** Mapping of /json/wiki/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Dir[] = {
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
#if 0 /* TODO: Not used? */
static char const * json_dir_path_extra(){
static char const * zP = NULL;
if( !zP ){
zP = g.zExtra;
while(zP && *zP && ('/'==*zP)){
++zP;
}
}
return zP;
}
#endif
/*
** Impl of /json/dir. 98% of it was taken directly
** from browse.c::page_dir()
*/
static cson_value * json_page_dir_list(){
cson_object * zPayload = NULL; /* return value */
cson_array * zEntries = NULL; /* accumulated list of entries. */
cson_object * zEntry = NULL; /* a single dir/file entry. */
cson_array * keyStore = NULL; /* garbage collector for shared strings. */
cson_string * zKeyName = NULL;
cson_string * zKeySize = NULL;
cson_string * zKeyIsDir = NULL;
cson_string * zKeyUuid = NULL;
cson_string * zKeyTime = NULL;
cson_string * zKeyRaw = NULL;
char * zD = NULL;
char const * zDX = NULL;
int nD;
char * zUuid = NULL;
char const * zCI = NULL;
Manifest * pM = NULL;
Stmt q = empty_Stmt;
int rid = 0;
if( !g.perm.History ){
json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions.");
return NULL;
}
zCI = json_find_option_cstr("checkin",NULL,"ci" );
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
*/
if( zCI && *zCI ){
pM = manifest_get_by_name(zCI, &rid);
if( pM ){
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
}else{
json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
"Checkin name [%s] is unresolved.",
zCI);
return NULL;
}
}
/* Jump through some hoops to find the directory name... */
zDX = json_find_option_cstr("name",NULL,NULL);
if(!zDX && !g.isHTTP){
zDX = json_command_arg(g.json.dispatchDepth+1);
}
if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){
zDX = NULL;
}
zD = zDX ? fossil_strdup(zDX) : NULL;
nD = zD ? strlen(zD)+1 : 0;
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
pathelementFunc, 0, 0);
/* Compute the temporary table "localfiles" containing the names
** of all files and subdirectories in the zD[] directory.
**
** Subdirectory names begin with "/". This causes them to sort
** first and it also gives us an easy way to distinguish files
** from directories in the loop that follows.
*/
if( zCI ){
Stmt ins;
ManifestFile *pFile;
ManifestFile *pPrev = 0;
int nPrev = 0;
int c;
db_multi_exec(
"CREATE TEMP TABLE json_dir_files("
" n UNIQUE NOT NULL %s," /* file name */
" fn UNIQUE NOT NULL %s," /* full file name */
" u DEFAULT NULL," /* file uuid */
" sz DEFAULT -1," /* file size */
" mtime DEFAULT NULL" /* file mtime in unix epoch format */
");",
filename_collation(), filename_collation()
);
db_prepare(&ins,
"INSERT OR IGNORE INTO json_dir_files (n,fn,u,sz,mtime) "
"SELECT"
" pathelement(:path,0),"
" CASE WHEN %Q IS NULL THEN '' ELSE %Q||'/' END ||:abspath,"
" a.uuid,"
" a.size,"
" CAST(strftime('%%s',e.mtime) AS INTEGER) "
"FROM"
" mlink m, "
" event e,"
" blob a,"
" blob b "
"WHERE"
" e.objid=m.mid"
" AND a.rid=m.fid"/*FILE artifact*/
" AND b.rid=m.mid"/*CHECKIN artifact*/
" AND a.uuid=:uuid",
zD, zD
);
manifest_file_rewind(pM);
while( (pFile = manifest_file_next(pM,0))!=0 ){
if( nD>0
&& ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1)))
){
continue;
}
/*printf("zD=%s, nD=%d, pFile->zName=%s\n", zD, nD, pFile->zName);*/
if( pPrev
&& memcmp(&pFile->zName[nD],&pPrev->zName[nD],nPrev)==0
&& (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/')
){
continue;
}
db_bind_text( &ins, ":path", &pFile->zName[nD] );
db_bind_text( &ins, ":abspath", &pFile->zName[nD] );
db_bind_text( &ins, ":uuid", pFile->zUuid );
db_step(&ins);
db_reset(&ins);
pPrev = pFile;
for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){}
if( c=='/' ) nPrev++;
}
db_finalize(&ins);
}else if( zD && *zD ){
if( filenames_are_case_sensitive() ){
db_multi_exec(
"CREATE TEMP VIEW json_dir_files AS"
" SELECT DISTINCT(pathelement(name,%d)) AS n,"
" %Q||'/'||name AS fn,"
" NULL AS u, NULL AS sz, NULL AS mtime"
" FROM filename"
" WHERE name GLOB '%q/*'"
" GROUP BY n",
nD, zD, zD
);
}else{
db_multi_exec(
"CREATE TEMP VIEW json_dir_files AS"
" SELECT DISTINCT(pathelement(name,%d)) AS n, "
" %Q||'/'||name AS fn,"
" NULL AS u, NULL AS sz, NULL AS mtime"
" FROM filename"
" WHERE name LIKE '%q/%%'"
" GROUP BY n",
nD, zD, zD
);
}
}else{
db_multi_exec(
"CREATE TEMP VIEW json_dir_files"
" AS SELECT DISTINCT(pathelement(name,0)) AS n, NULL AS fn"
" FROM filename"
);
}
if(zCI){
db_prepare( &q, "SELECT"
" n as name,"
" fn as fullname,"
" u as uuid,"
" sz as size,"
" mtime as mtime "
"FROM json_dir_files ORDER BY n");
}else{/* UUIDs are all NULL. */
db_prepare( &q, "SELECT n, fn FROM json_dir_files ORDER BY n");
}
zKeyName = cson_new_string("name",4);
zKeyUuid = cson_new_string("uuid",4);
zKeyIsDir = cson_new_string("isDir",5);
keyStore = cson_new_array();
cson_array_append( keyStore, cson_string_value(zKeyName) );
cson_array_append( keyStore, cson_string_value(zKeyUuid) );
cson_array_append( keyStore, cson_string_value(zKeyIsDir) );
if( zCI ){
zKeySize = cson_new_string("size",4);
cson_array_append( keyStore, cson_string_value(zKeySize) );
zKeyTime = cson_new_string("timestamp",9);
cson_array_append( keyStore, cson_string_value(zKeyTime) );
zKeyRaw = cson_new_string("downloadPath",12);
cson_array_append( keyStore, cson_string_value(zKeyRaw) );
}
zPayload = cson_new_object();
cson_object_set_s( zPayload, zKeyName,
json_new_string((zD&&*zD) ? zD : "/") );
if( zUuid ){
cson_object_set( zPayload, "checkin", json_new_string(zUuid) );
}
while( (SQLITE_ROW==db_step(&q)) ){
cson_value * name = NULL;
char const * n = db_column_text(&q,0);
char const isDir = ('/'==*n);
zEntry = cson_new_object();
if(!zEntries){
zEntries = cson_new_array();
cson_object_set( zPayload, "entries", cson_array_value(zEntries) );
}
cson_array_append(zEntries, cson_object_value(zEntry) );
if(isDir){
name = json_new_string( n+1 );
cson_object_set_s(zEntry, zKeyIsDir, cson_value_true() );
} else{
name = json_new_string( n );
}
cson_object_set_s(zEntry, zKeyName, name );
if( zCI && !isDir){
/* Don't add the uuid/size for dir entries - that data refers to
one of the files in that directory :/. Entries with no
--checkin may refer to N versions, and therefore we cannot
associate a single size and uuid with them (and fetching all
would be overkill for most use cases).
*/
char const * fullName = db_column_text(&q,1);
char const * u = db_column_text(&q,2);
sqlite_int64 const sz = db_column_int64(&q,3);
sqlite_int64 const ts = db_column_int64(&q,4);
cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) );
cson_object_set_s(zEntry, zKeySize,
cson_value_new_integer( (cson_int_t)sz ));
cson_object_set_s(zEntry, zKeyTime,
cson_value_new_integer( (cson_int_t)ts ));
cson_object_set_s(zEntry, zKeyRaw,
json_new_string_f("/raw/%T?name=%t",
fullName, u));
}
}
db_finalize(&q);
if(pM){
manifest_destroy(pM);
}
cson_free_array( keyStore );
free( zUuid );
free( zD );
return cson_object_value(zPayload);
}
/*
** Implements the /json/dir family of pages/commands.
**
*/
cson_value * json_page_dir(){
#if 1
return json_page_dir_list();
#else
return json_page_dispatch_helper(&JsonPageDefs_Dir[0]);
#endif
}
#endif /* FOSSIL_ENABLE_JSON */
|
Added src/json_finfo.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
#ifdef FOSSIL_ENABLE_JSON
/*
** Copyright (c) 2011 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*/
#include "VERSION.h"
#include "config.h"
#include "json_finfo.h"
#if INTERFACE
#include "json_detail.h"
#endif
/*
** Implements the /json/finfo page/command.
**
*/
cson_value * json_page_finfo(){
cson_object * pay = NULL;
cson_array * checkins = NULL;
char const * zFilename = NULL;
Blob sql = empty_blob;
Stmt q = empty_Stmt;
char const * zAfter = NULL;
char const * zBefore = NULL;
int limit = -1;
int currentRow = 0;
char const * zCheckin = NULL;
char sort = -1;
if(!g.perm.Read){
json_set_err(FSL_JSON_E_DENIED,"Requires 'o' privileges.");
return NULL;
}
json_warn( FSL_JSON_W_UNKNOWN, "Achtung: the output of the finfo command is up for change.");
/* For the "name" argument we have to jump through some hoops to make sure that we don't
get the fossil-internally-assigned "name" option.
*/
zFilename = json_find_option_cstr2("name",NULL,NULL, g.json.dispatchDepth+1);
if(!zFilename || !*zFilename){
json_set_err(FSL_JSON_E_MISSING_ARGS, "Missing 'name' parameter.");
return NULL;
}
if(0==db_int(0,"SELECT 1 FROM filename WHERE name=%Q",zFilename)){
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND, "File entry not found.");
return NULL;
}
zBefore = json_find_option_cstr("before",NULL,"b");
zAfter = json_find_option_cstr("after",NULL,"a");
limit = json_find_option_int("limit",NULL,"n", -1);
zCheckin = json_find_option_cstr("checkin",NULL,"ci");
blob_appendf(&sql,
/*0*/ "SELECT b.uuid,"
/*1*/ " ci.uuid,"
/*2*/ " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */
/*3*/ " cast(strftime('%%s',event.mtime) AS INTEGER),"
/*4*/ " coalesce(event.euser, event.user),"
/*5*/ " coalesce(event.ecomment, event.comment),"
/*6*/ " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
/*7*/ " event.bgcolor,"
/*8*/ " b.size,"
/*9*/ " (mlink.pid==0) AS isNew,"
/*10*/ " (mlink.fid==0) AS isDel"
" FROM mlink, blob b, event, blob ci, filename"
" WHERE filename.name=%Q %s"
" AND mlink.fnid=filename.fnid"
" AND b.rid=mlink.fid"
" AND event.objid=mlink.mid"
" AND event.objid=ci.rid",
zFilename, filename_collation()
);
if( zCheckin && *zCheckin ){
char * zU = NULL;
int rc = name_to_uuid2( zCheckin, "ci", &zU );
/*printf("zCheckin=[%s], zU=[%s]", zCheckin, zU);*/
if(rc<=0){
json_set_err((rc<0) ? FSL_JSON_E_AMBIGUOUS_UUID : FSL_JSON_E_RESOURCE_NOT_FOUND,
"Checkin UUID %s.", (rc<0) ? "is ambiguous" : "not found");
blob_reset(&sql);
return NULL;
}
blob_appendf(&sql, " AND ci.uuid='%q'", zU);
free(zU);
}else{
if( zAfter && *zAfter ){
blob_appendf(&sql, " AND event.mtime>=julianday('%q')", zAfter);
sort = 1;
}else if( zBefore && *zBefore ){
blob_appendf(&sql, " AND event.mtime<=julianday('%q')", zBefore);
}
}
blob_appendf(&sql," ORDER BY event.mtime %s /*sort*/", (sort>0?"ASC":"DESC"));
/*printf("SQL=\n%s\n",blob_str(&sql));*/
db_prepare(&q, "%s", blob_str(&sql)/*extra %s to avoid double-expanding
SQL escapes*/);
blob_reset(&sql);
pay = cson_new_object();
cson_object_set(pay, "name", json_new_string(zFilename));
if( limit > 0 ){
cson_object_set(pay, "limit", json_new_int(limit));
}
checkins = cson_new_array();
cson_object_set(pay, "checkins", cson_array_value(checkins));
while( db_step(&q)==SQLITE_ROW ){
cson_object * row = cson_new_object();
int const isNew = db_column_int(&q,9);
int const isDel = db_column_int(&q,10);
cson_array_append( checkins, cson_object_value(row) );
cson_object_set(row, "checkin", json_new_string( db_column_text(&q,1) ));
cson_object_set(row, "uuid", json_new_string( db_column_text(&q,2) ));
/*cson_object_set(row, "parentArtifact", json_new_string( db_column_text(&q,6) ));*/
cson_object_set(row, "timestamp", json_new_int( db_column_int(&q,3) ));
cson_object_set(row, "user", json_new_string( db_column_text(&q,4) ));
cson_object_set(row, "comment", json_new_string( db_column_text(&q,5) ));
/*cson_object_set(row, "bgColor", json_new_string( db_column_text(&q,7) ));*/
cson_object_set(row, "size", cson_value_new_integer( (cson_int_t)db_column_int64(&q,8) ));
cson_object_set(row, "state",
json_new_string(json_artifact_status_to_string(isNew,isDel)));
if( (0 < limit) && (++currentRow >= limit) ){
break;
}
}
db_finalize(&q);
return pay ? cson_object_value(pay) : NULL;
}
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_login.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 |
Summary: If we check for P("name") first, then P("n"),
then ONLY a GET param of "name" will match ("n"
is not recognized). If we reverse the order of the
checks then both forms work. Strangely enough, the
"p"/"password" check is not affected by this.
*/
| | | | 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 |
Summary: If we check for P("name") first, then P("n"),
then ONLY a GET param of "name" will match ("n"
is not recognized). If we reverse the order of the
checks then both forms work. Strangely enough, the
"p"/"password" check is not affected by this.
*/
char const * name = cson_value_get_cstr(json_req_payload_get("name"));
char const * pw = NULL;
char const * anonSeed = NULL;
cson_value * payload = NULL;
int uid = 0;
/* reminder to self: Fossil internally (for the sake of /wiki)
interprets paths in the form /foo/bar/baz such that P("name") ==
"bar/baz". This collides with our name/password checking, and
thus we do some rather elaborate name=... checking.
*/
pw = cson_value_get_cstr(json_req_payload_get("password"));
if( !pw ){
pw = PD("p",NULL);
if( !pw ){
pw = PD("password",NULL);
}
}
if(!pw){
|
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
80-digit number.
*/
};
static char seedBuffer[SeedBufLen];
cson_value const * jseed = json_getenv(FossilJsonKeys.anonymousSeed);
seedBuffer[0] = 0;
if( !jseed ){
| | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
80-digit number.
*/
};
static char seedBuffer[SeedBufLen];
cson_value const * jseed = json_getenv(FossilJsonKeys.anonymousSeed);
seedBuffer[0] = 0;
if( !jseed ){
jseed = json_req_payload_get(FossilJsonKeys.anonymousSeed);
if( !jseed ){
jseed = json_getenv("cs") /* name used by HTML interface */;
}
}
if(jseed){
if( cson_value_is_number(jseed) ){
sprintf(seedBuffer, "%"CSON_INT_T_PFMT, cson_value_get_integer(jseed));
|
| ︙ | ︙ |
Changes to src/json_report.c.
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
json_set_err(FSL_JSON_E_DENIED,
"Requires 't' privileges.");
return NULL;
}
nReport = json_report_get_number(3);
if(nReport <=0){
json_set_err(FSL_JSON_E_MISSING_ARGS,
| | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
json_set_err(FSL_JSON_E_DENIED,
"Requires 't' privileges.");
return NULL;
}
nReport = json_report_get_number(3);
if(nReport <=0){
json_set_err(FSL_JSON_E_MISSING_ARGS,
"Missing or invalid 'report' (-r) parameter.");
return NULL;
}
db_prepare(&q,"SELECT rn AS report,"
" owner AS owner,"
" title AS title,"
" cast(strftime('%%s',mtime) as int) as timestamp,"
" cols as columns,"
" sqlcode as sqlCode"
" FROM reportfmt"
" WHERE rn=%d",
nReport);
if( SQLITE_ROW != db_step(&q) ){
db_finalize(&q);
|
| ︙ | ︙ |
Changes to src/json_tag.c.
| ︙ | ︙ | |||
274 275 276 277 278 279 280 |
}else{
char const * zSqlBase = /*modified from timeline_query_for_tty()*/
" SELECT"
#if 0
" blob.rid AS rid,"
#endif
" uuid AS uuid,"
| | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
}else{
char const * zSqlBase = /*modified from timeline_query_for_tty()*/
" SELECT"
#if 0
" blob.rid AS rid,"
#endif
" uuid AS uuid,"
" cast(strftime('%s',event.mtime) as int) AS timestamp,"
" coalesce(ecomment,comment) AS comment,"
" coalesce(euser,user) AS user,"
" CASE event.type"
" WHEN 'ci' THEN 'checkin'"
" WHEN 'w' THEN 'wiki'"
" WHEN 'e' THEN 'event'"
" WHEN 't' THEN 'ticket'"
|
| ︙ | ︙ |
Changes to src/json_timeline.c.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 |
static const JsonPageDef JsonPageDefs_Timeline[] = {
/* the short forms are only enabled in CLI mode, to avoid
that we end up with HTTP clients using 3 different names
for the same requests.
*/
{"branch", json_timeline_branch, 0},
{"checkin", json_timeline_ci, 0},
| < < < | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
static const JsonPageDef JsonPageDefs_Timeline[] = {
/* the short forms are only enabled in CLI mode, to avoid
that we end up with HTTP clients using 3 different names
for the same requests.
*/
{"branch", json_timeline_branch, 0},
{"checkin", json_timeline_ci, 0},
{"ticket", json_timeline_ticket, 0},
{"wiki", json_timeline_wiki, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
|
| ︙ | ︙ | |||
98 99 100 101 102 103 104 |
const char const * json_timeline_query(void){
/* Field order MUST match that from json_timeline_temp_table()!!! */
static const char zBaseSql[] =
@ SELECT
@ NULL,
@ blob.rid,
@ uuid,
| | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
const char const * json_timeline_query(void){
/* Field order MUST match that from json_timeline_temp_table()!!! */
static const char zBaseSql[] =
@ SELECT
@ NULL,
@ blob.rid,
@ uuid,
@ CAST(strftime('%%s',event.mtime) AS INTEGER),
@ datetime(event.mtime,'utc'),
@ coalesce(ecomment, comment),
@ coalesce(euser, user),
@ blob.rid IN leaf,
@ bgcolor,
@ event.type,
@ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref
|
| ︙ | ︙ | |||
133 134 135 136 137 138 139 | ** ** pSql is the target blob to append the query [subset] ** to. ** ** Returns a positive value if it modifies pSql, 0 if it ** does not. It returns a negative value if the tag ** provided to the request was not found (pSql is not modified | | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | ** ** pSql is the target blob to append the query [subset] ** to. ** ** Returns a positive value if it modifies pSql, 0 if it ** does not. It returns a negative value if the tag ** provided to the request was not found (pSql is not modified ** in that case). ** ** If payload is not NULL then on success its "tag" or "branch" ** property is set to the tag/branch name found in the request. ** ** Only one of "tag" or "branch" modes will work at a time, and if ** both are specified, which one takes precedence is unspecified. */ |
| ︙ | ︙ | |||
231 232 233 234 235 236 237 | /* ** Tries to figure out a timeline query length limit base on ** environment parameters. If it can it returns that value, ** else it returns some statically defined default value. ** ** Never returns a negative value. 0 means no limit. */ | | < | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
/*
** Tries to figure out a timeline query length limit base on
** environment parameters. If it can it returns that value,
** else it returns some statically defined default value.
**
** Never returns a negative value. 0 means no limit.
*/
static int json_timeline_limit(int defaultLimit){
int limit = -1;
if(!g.isHTTP){/* CLI mode */
char const * arg = find_option("limit","n",1);
if(arg && *arg){
limit = atoi(arg);
}
}
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 |
blob_append(pSql, "INSERT OR IGNORE INTO json_timeline ", -1);
blob_append(pSql, json_timeline_query(), -1 );
blob_appendf(pSql, " AND event.type IN(%Q) ", zEventType);
if( json_timeline_add_tag_branch_clause(pSql, pPayload) < 0 ){
return FSL_JSON_E_INVALID_ARGS;
}
json_timeline_add_time_clause(pSql);
| | | < < < < < < < < < < | | > | > < | > > | < < < < > | > > > > < < > > > | | | > > > | < | > > > > > > | < < < > | | < < | | | | | 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 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 435 436 437 438 439 440 441 442 |
blob_append(pSql, "INSERT OR IGNORE INTO json_timeline ", -1);
blob_append(pSql, json_timeline_query(), -1 );
blob_appendf(pSql, " AND event.type IN(%Q) ", zEventType);
if( json_timeline_add_tag_branch_clause(pSql, pPayload) < 0 ){
return FSL_JSON_E_INVALID_ARGS;
}
json_timeline_add_time_clause(pSql);
limit = json_timeline_limit(20);
if(limit>0){
blob_appendf(pSql,"LIMIT %d ",limit);
}
if(pPayload){
cson_object_set(pPayload, "limit", json_new_int(limit));
}
return 0;
}
/*
** If any files are associated with the given rid, a JSON array
** containing information about them is returned (and is owned by the
** caller). If no files are associated with it then NULL is returned.
*/
cson_value * json_get_changed_files(int rid){
cson_value * rowsV = NULL;
cson_array * rows = NULL;
Stmt q = empty_Stmt;
db_prepare(&q,
"SELECT (pid==0) AS isnew,"
" (fid==0) AS isdel,"
" (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name,"
" blob.uuid as uuid,"
" (SELECT uuid FROM blob WHERE rid=pid) as parent,"
" blob.size as size"
" FROM mlink, blob"
" WHERE mid=%d AND pid!=fid"
" AND blob.rid=fid "
" ORDER BY name /*sort*/",
rid
);
while( (SQLITE_ROW == db_step(&q)) ){
cson_value * rowV = cson_value_new_object();
cson_object * row = cson_value_get_object(rowV);
int const isNew = db_column_int(&q,0);
int const isDel = db_column_int(&q,1);
char * zDownload = NULL;
if(!rowsV){
rowsV = cson_value_new_array();
rows = cson_value_get_array(rowsV);
}
cson_array_append( rows, rowV );
cson_object_set(row, "name", json_new_string(db_column_text(&q,2)));
cson_object_set(row, "uuid", json_new_string(db_column_text(&q,3)));
if(!isNew){
cson_object_set(row, "parent", json_new_string(db_column_text(&q,4)));
}
cson_object_set(row, "size", json_new_int(db_column_int(&q,5)));
cson_object_set(row, "state",
json_new_string(json_artifact_status_to_string(isNew,isDel)));
zDownload = mprintf("/raw/%s?name=%s",
/* reminder: g.zBaseURL is of course not set for CLI mode. */
db_column_text(&q,2),
db_column_text(&q,3));
cson_object_set(row, "downloadPath", json_new_string(zDownload));
free(zDownload);
}
db_finalize(&q);
return rowsV;
}
static cson_value * json_timeline_branch(){
cson_value * pay = NULL;
Blob sql = empty_blob;
Stmt q = empty_Stmt;
int limit = 0;
if(!g.perm.Read){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' permissions.");
return NULL;
}
json_timeline_temp_table();
blob_append(&sql,
"SELECT"
" blob.rid AS rid,"
" uuid AS uuid,"
" CAST(strftime('%s',event.mtime) AS INTEGER) as timestamp,"
" coalesce(ecomment, comment) as comment,"
" coalesce(euser, user) as user,"
" blob.rid IN leaf as isLeaf,"
" bgcolor as bgColor"
" FROM event JOIN blob"
" WHERE blob.rid=event.objid",
-1);
blob_appendf(&sql,
" AND event.type='ci'"
" AND blob.rid IN (SELECT rid FROM tagxref"
" WHERE tagtype>0 AND tagid=%d AND srcid!=0)"
" ORDER BY event.mtime DESC",
TAG_BRANCH);
limit = json_timeline_limit(20);
if(limit>0){
blob_appendf(&sql," LIMIT %d ",limit);
}
db_prepare(&q,"%s", blob_str(&sql));
blob_reset(&sql);
pay = json_stmt_to_array_of_obj(&q, NULL);
db_finalize(&q);
assert(NULL != pay);
if(pay){
/* get the array-form tags of each record. */
cson_string * tags = cson_new_string("tags",4);
cson_string * isLeaf = cson_new_string("isLeaf",6);
cson_array * ar = cson_value_get_array(pay);
cson_object * outer = NULL;
unsigned int i = 0;
unsigned int len = cson_array_length_get(ar);
cson_value_add_reference( cson_string_value(tags) );
cson_value_add_reference( cson_string_value(isLeaf) );
for( ; i < len; ++i ){
cson_object * row = cson_value_get_object(cson_array_get(ar,i));
int rid = cson_value_get_integer(cson_object_get(row,"rid"));
assert( rid > 0 );
cson_object_set_s(row, tags, json_tags_for_checkin_rid(rid,0));
cson_object_set_s(row, isLeaf,
json_value_to_bool(cson_object_get(row,"isLeaf")));
cson_object_set(row, "rid", NULL)
/* remove rid - we don't really want it to be public */;
}
cson_value_free( cson_string_value(tags) );
cson_value_free( cson_string_value(isLeaf) );
/* now we wrap the payload in an outer shell, for consistency with
other /json/timeline/xyz APIs...
*/
outer = cson_new_object();
if(limit>0){
cson_object_set( outer, "limit", json_new_int(limit) );
}
cson_object_set( outer, "timeline", pay );
pay = cson_object_value(outer);
}
return pay;
}
/*
** Implementation of /json/timeline/ci.
**
** Still a few TODOs (like figuring out how to structure
** inheritance info).
*/
static cson_value * json_timeline_ci(){
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_value * tmp = NULL;
cson_value * listV = NULL;
cson_array * list = NULL;
int check = 0;
char showFiles = -1/*magic number*/;
Stmt q = empty_Stmt;
char warnRowToJsonFailed = 0;
Blob sql = empty_blob;
if( !g.perm.History ){
/* Reminder to self: HTML impl requires 'o' (Read)
rights.
*/
json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." );
return NULL;
}
showFiles = json_find_option_bool("files",NULL,"f",0);
payV = cson_value_new_object();
pay = cson_value_get_object(payV);
check = json_timeline_setup_sql( "ci", &sql, pay );
if(check){
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 |
tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)));
SET("timelineSql");
#endif
db_multi_exec(blob_buffer(&sql));
blob_reset(&sql);
db_prepare(&q, "SELECT "
" rid AS rid"
| < < < < < < < < < < < < < < < < < | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)));
SET("timelineSql");
#endif
db_multi_exec(blob_buffer(&sql));
blob_reset(&sql);
db_prepare(&q, "SELECT "
" rid AS rid"
" FROM json_timeline"
" ORDER BY rowid");
listV = cson_value_new_array();
list = cson_value_get_array(listV);
tmp = listV;
SET("timeline");
while( (SQLITE_ROW == db_step(&q) )){
|
| ︙ | ︙ | |||
517 518 519 520 521 522 523 |
** Implementation of /json/timeline/wiki.
**
*/
cson_value * json_timeline_wiki(){
/* This code is 95% the same as json_timeline_ci(), by the way. */
cson_value * payV = NULL;
cson_object * pay = NULL;
| < < < < < < < | < < < > | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
** Implementation of /json/timeline/wiki.
**
*/
cson_value * json_timeline_wiki(){
/* This code is 95% the same as json_timeline_ci(), by the way. */
cson_value * payV = NULL;
cson_object * pay = NULL;
cson_array * list = NULL;
int check = 0;
Stmt q = empty_Stmt;
Blob sql = empty_blob;
if( !g.perm.RdWiki && !g.perm.Read ){
json_set_err( FSL_JSON_E_DENIED, "Wiki timeline requires 'o' or 'j' access.");
return NULL;
}
payV = cson_value_new_object();
pay = cson_value_get_object(payV);
check = json_timeline_setup_sql( "w", &sql, pay );
if(check){
json_set_err(check, "Query initialization failed.");
goto error;
}
#if 0
/* only for testing! */
tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)));
SET("timelineSql");
#endif
db_multi_exec(blob_buffer(&sql));
blob_reset(&sql);
db_prepare(&q, "SELECT"
" uuid AS uuid,"
" mtime AS timestamp,"
#if 0
" timestampString AS timestampString,"
#endif
" comment AS comment, "
" user AS user,"
" eventType AS eventType"
#if 0
/* can wiki pages have tags? */
" tags AS tags," /*FIXME: split this into
a JSON array*/
" tagId AS tagId,"
#endif
" FROM json_timeline"
" ORDER BY rowid",
-1);
list = cson_new_array();
json_stmt_to_array_of_obj(&q, list);
cson_object_set(pay, "timeline", cson_array_value(list));
goto ok;
error:
assert( 0 != g.json.resultCode );
cson_value_free(payV);
payV = NULL;
ok:
db_finalize(&q);
|
| ︙ | ︙ | |||
649 650 651 652 653 654 655 |
tmp = listV;
SET("timeline");
while( (SQLITE_ROW == db_step(&q) )){
/* convert each row into a JSON object...*/
int rc;
int const rid = db_column_int(&q,0);
Manifest * pMan = NULL;
| > > > > > > > > > > > > > > > | | > < < < | | | | | < | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 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 |
tmp = listV;
SET("timeline");
while( (SQLITE_ROW == db_step(&q) )){
/* convert each row into a JSON object...*/
int rc;
int const rid = db_column_int(&q,0);
Manifest * pMan = NULL;
cson_value * rowV;
cson_object * row;
/*printf("rid=%d\n",rid);*/
pMan = manifest_get(rid, CFTYPE_TICKET);
if(!pMan){
/* this might be an attachment? i'm seeing this with
rid 15380, uuid [1292fef05f2472108].
/json/artifact/1292fef05f2472108 returns not-found,
probably because we haven't added artifact/ticket
yet(?).
*/
continue;
}
rowV = cson_sqlite3_row_to_object(q.pStmt);
row = cson_value_get_object(rowV);
if(!row){
manifest_destroy(pMan);
json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED,
"Could not convert at least one timeline result row to JSON." );
continue;
}
/* FIXME: certainly there's a more efficient way for use to get
the ticket UUIDs?
*/
cson_object_set(row,"ticketUuid",json_new_string(pMan->zTicketUuid));
manifest_destroy(pMan);
rc = cson_array_append( list, rowV );
if( 0 != rc ){
cson_value_free(rowV);
g.json.resultCode = (cson_rc.AllocError==rc)
? FSL_JSON_E_ALLOC
: FSL_JSON_E_UNKNOWN;
goto error;
|
| ︙ | ︙ |
Changes to src/json_user.c.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 | #if INTERFACE #include "json_detail.h" #endif static cson_value * json_user_get(); static cson_value * json_user_list(); static cson_value * json_user_save(); | < < < < < | | | > | | 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 |
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_user_get();
static cson_value * json_user_list();
static cson_value * json_user_save();
/*
** Mapping of /json/user/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_User[] = {
{"save", json_user_save, 0},
{"get", json_user_get, 0},
{"list", json_user_list, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/user family of pages/commands.
**
*/
cson_value * json_page_user(){
return json_page_dispatch_helper(&JsonPageDefs_User[0]);
}
/*
** Impl of /json/user/list. Requires admin/setup rights.
*/
static cson_value * json_user_list(){
cson_value * payV = NULL;
Stmt q;
if(!g.perm.Admin && !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'a' or 's' privileges.");
return NULL;
}
db_prepare(&q,"SELECT uid AS uid,"
" login AS name,"
" cap AS capabilities,"
" info AS info,"
" mtime AS timestamp"
" FROM user ORDER BY login");
payV = json_stmt_to_array_of_obj(&q, NULL);
db_finalize(&q);
if(NULL == payV){
json_set_err(FSL_JSON_E_UNKNOWN,
"Could not convert user list to JSON.");
}
|
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
static cson_value * json_load_user_by_name(char const * zName){
cson_value * u = NULL;
Stmt q;
db_prepare(&q,"SELECT uid AS uid,"
" login AS name,"
" cap AS capabilities,"
" info AS info,"
| | | | | | | | < < < < < < < | 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 |
static cson_value * json_load_user_by_name(char const * zName){
cson_value * u = NULL;
Stmt q;
db_prepare(&q,"SELECT uid AS uid,"
" login AS name,"
" cap AS capabilities,"
" info AS info,"
" mtime AS timestamp"
" FROM user"
" WHERE login=%Q",
zName);
if( (SQLITE_ROW == db_step(&q)) ){
u = cson_sqlite3_row_to_object(q.pStmt);
}
db_finalize(&q);
return u;
}
/*
** Identical to json_load_user_by_name(), but expects a user ID. Returns
** NULL if no user found with that ID.
*/
static cson_value * json_load_user_by_id(int uid){
cson_value * u = NULL;
Stmt q;
db_prepare(&q,"SELECT uid AS uid,"
" login AS name,"
" cap AS capabilities,"
" info AS info,"
" mtime AS timestamp"
" FROM user"
" WHERE uid=%d",
uid);
if( (SQLITE_ROW == db_step(&q)) ){
u = cson_sqlite3_row_to_object(q.pStmt);
}
db_finalize(&q);
return u;
}
/*
** Impl of /json/user/get. Requires admin or setup rights.
*/
static cson_value * json_user_get(){
cson_value * payV = NULL;
char const * pUser = NULL;
if(!g.perm.Admin && !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'a' or 's' privileges.");
return NULL;
}
pUser = json_find_option_cstr2("name", NULL, NULL, g.json.dispatchDepth+1);
if(!pUser || !*pUser){
json_set_err(FSL_JSON_E_MISSING_ARGS,"Missing 'name' property.");
return NULL;
}
payV = json_load_user_by_name(pUser);
if(!payV){
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,"User not found.");
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 | ** At least one of (name, uid) must be included. All others are ** optional and their db fields will not be updated if those fields ** are not included in pUser. ** ** If uid is specified then name may refer to a _new_ name ** for a user, otherwise the name must refer to an existing user. ** If uid=-1 then the name must be specified and a new user is | | | | < < < | | > > > | | | > | | | > | | > | | > < < < < < < > > > > | > > > > > > > > > > > > > > > | > | | < | | > > > > > > > > > > > > > > > > > > < < < < < < | | < > > > > | | | | | | | | | > > > > > > > > > > | > < > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < | | | | | < | | 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 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 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 |
** At least one of (name, uid) must be included. All others are
** optional and their db fields will not be updated if those fields
** are not included in pUser.
**
** If uid is specified then name may refer to a _new_ name
** for a user, otherwise the name must refer to an existing user.
** If uid=-1 then the name must be specified and a new user is
** created (fails if one already exists).
**
** If uid is not set, this function might modify pUser to contain the
** db-found (or inserted) user ID.
**
** On error g.json's error state is set and one of the FSL_JSON_E_xxx
** values from FossilJsonCodes is returned.
**
** On success the db record for the given user is updated.
**
** Requires either Admin, Setup, or Password access. Non-admin/setup
** users can only change their own information. Non-setup users may
** not modify the 's' permission. Admin users without setup
** permissions may not edit any other user who has the 's' permission.
**
*/
int json_user_update_from_json( cson_object * pUser ){
#define CSTR(X) cson_string_cstr(cson_value_get_string( cson_object_get(pUser, X ) ))
char const * zName = CSTR("name");
char const * zNameNew = zName;
char * zNameFree = NULL;
char const * zInfo = CSTR("info");
char const * zCap = CSTR("capabilities");
char const * zPW = CSTR("password");
cson_value const * forceLogout = cson_object_get(pUser, "forceLogout");
int gotFields = 0;
#undef CSTR
cson_int_t uid = cson_value_get_integer( cson_object_get(pUser, "uid") );
char const tgtHasSetup = zCap && (NULL!=strchr(zCap, 's'));
char tgtHadSetup = 0;
Blob sql = empty_blob;
Stmt q = empty_Stmt;
#if 0
if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){
return json_set_err( FSL_JSON_E_DENIED,
"Password change requires 'a', 's', "
"or 'p' permissions.");
}
#endif
if(uid<=0 && (!zName||!*zName)){
return json_set_err(FSL_JSON_E_MISSING_ARGS,
"One of 'uid' or 'name' is required.");
}else if(uid>0){
zNameFree = db_text(NULL, "SELECT login FROM user WHERE uid=%d",uid);
if(!zNameFree){
return json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
"No login found for uid %d.", uid);
}
zName = zNameFree;
}else if(-1==uid){
/* try to create a new user */
if(!g.perm.Admin && !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'a' or 's' privileges.");
goto error;
}else if(!zName || !*zName){
json_set_err(FSL_JSON_E_MISSING_ARGS,
"No name specified for new user.");
goto error;
}else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){
json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
"User %s already exists.", zName);
goto error;
}else{
Stmt ins = empty_Stmt;
db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName);
db_step( &ins );
db_finalize(&ins);
uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName);
assert(uid>0);
zNameNew = zName;
cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
}
}else{
uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName);
if(uid<=0){
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
"No login found for user [%s].", zName);
goto error;
}
cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
}
/* Maintenance note: all error-returns from here on out should go
via 'goto error' in order to clean up.
*/
if(uid != g.userUid){
if(!g.perm.Admin && !g.perm.Setup){
json_set_err(FSL_JSON_E_DENIED,
"Changing another user's data requires "
"'a' or 's' privileges.");
goto error;
}
}
/* check if the target uid currently has setup rights. */
tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d"
" AND cap GLOB '*s*'", uid);
if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){
/*
Do not allow a non-setup user to set or remove setup
privileges. setup.c uses similar logic.
*/
json_set_err(FSL_JSON_E_DENIED,
"Modifying 's' users/privileges requires "
"'s' privileges.");
goto error;
}
/*
Potential todo: do not allow a setup user to remove 's' from
himself, to avoid locking himself out?
*/
blob_append(&sql, "UPDATE user SET",-1 );
blob_append(&sql, " mtime=cast(strftime('%s') AS INTEGER)", -1);
if((uid>0) && zNameNew){
/* Check for name change... */
if(0!=strcmp(zName,zNameNew)){
if( (!g.perm.Admin && !g.perm.Setup)
&& (zName != zNameNew)){
json_set_err( FSL_JSON_E_DENIED,
"Modifying user names requires 'a' or 's' privileges.");
goto error;
}
forceLogout = cson_value_true()
/* reminders: 1) does not allocate.
2) we do this because changing a name
invalidates any login token because the old name
is part of the token hash.
*/;
blob_appendf(&sql, ", login=%Q", zNameNew);
++gotFields;
}
}
if( zCap && *zCap ){
if(!g.perm.Admin || !g.perm.Setup){
/* we "could" arguably silently ignore cap in this case. */
json_set_err(FSL_JSON_E_DENIED,
"Changing capabilities requires 'a' or 's' privileges.");
goto error;
}
blob_appendf(&sql, ", cap=%Q", zCap);
++gotFields;
}
if( zPW && *zPW ){
if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){
json_set_err( FSL_JSON_E_DENIED,
"Password change requires 'a', 's', "
"or 'p' permissions.");
goto error;
}else{
#define TRY_LOGIN_GROUP 0 /* login group support is not yet implemented. */
#if !TRY_LOGIN_GROUP
char * zPWHash = NULL;
++gotFields;
zPWHash = sha1_shared_secret(zPW, zNameNew ? zNameNew : zName, NULL);
blob_appendf(&sql, ", pw=%Q", zPWHash);
free(zPWHash);
#else
++gotFields;
blob_appendf(&sql, ", pw=coalesce(shared_secret(%Q,%Q,"
"(SELECT value FROM config WHERE name='project-code')))",
zPW, zNameNew ? zNameNew : zName);
/* shared_secret() func is undefined? */
#endif
}
}
if( zInfo ){
blob_appendf(&sql, ", info=%Q", zInfo);
++gotFields;
}
if((g.perm.Admin || g.perm.Setup)
&& forceLogout && cson_value_get_bool(forceLogout)){
blob_append(&sql, ", cookie=NULL, cexpire=NULL", -1);
++gotFields;
}
if(!gotFields){
json_set_err( FSL_JSON_E_MISSING_ARGS,
"Required user data are missing.");
goto error;
}
assert(uid>0);
#if !TRY_LOGIN_GROUP
blob_appendf(&sql, " WHERE uid=%d", uid);
#else /* need name for login group support :/ */
blob_appendf(&sql, " WHERE login=%Q", zName);
#endif
#if 0
puts(blob_str(&sql));
cson_output_FILE( cson_object_value(pUser), stdout, NULL );
#endif
db_prepare(&q, "%s", blob_str(&sql));
db_exec(&q);
db_finalize(&q);
#if TRY_LOGIN_GROUP
if( zPW || forceLogout ){
Blob groupSql = empty_blob;
char * zErr = NULL;
blob_appendf(&groupSql,
"INSERT INTO user(login)"
" SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);",
zName, zName
);
blob_append(&groupSql, blob_str(&sql), blob_size(&sql));
login_group_sql(blob_str(&groupSql), NULL, NULL, &zErr);
blob_reset(&groupSql);
if( zErr ){
json_set_err( FSL_JSON_E_UNKNOWN,
"Repo-group update at least partially failed: %s",
zErr);
free(zErr);
goto error;
}
}
#endif /* TRY_LOGIN_GROUP */
#undef TRY_LOGIN_GROUP
free( zNameFree );
blob_reset(&sql);
return 0;
error:
assert(0 != g.json.resultCode);
free(zNameFree);
blob_reset(&sql);
return g.json.resultCode;
}
/*
** Impl of /json/user/save.
*/
static cson_value * json_user_save(){
/* try to get user info from GET/CLI args and construct
a JSON form of it... */
cson_object * u = cson_new_object();
char const * str = NULL;
char b = -1;
int i = -1;
int uid = -1;
cson_value * payload = NULL;
#define PROP(LK,SK) str = json_find_option_cstr(LK,NULL,SK); \
if(str){ cson_object_set(u, LK, json_new_string(str)); } (void)0
PROP("name","n");
PROP("password","p");
PROP("info","i");
PROP("capabilities","c");
#undef PROP
#define PROP(LK,DFLT) b = json_find_option_bool(LK,NULL,NULL,DFLT); \
if(DFLT!=b){ cson_object_set(u, LK, cson_value_new_bool(b)); } (void)0
PROP("forceLogout",-1);
#undef PROP
#define PROP(LK,DFLT) i = json_find_option_int(LK,NULL,NULL,DFLT); \
if(DFLT != i){ cson_object_set(u, LK, cson_value_new_integer(i)); } (void)0
PROP("uid",-99);
#undef PROP
if( g.json.reqPayload.o ){
cson_object_merge( u, g.json.reqPayload.o, CSON_MERGE_NO_RECURSE );
}
json_user_update_from_json( u );
|
| ︙ | ︙ |
Changes to src/json_wiki.c.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 29 | #if INTERFACE #include "json_detail.h" #endif static cson_value * json_wiki_create(); static cson_value * json_wiki_get(); static cson_value * json_wiki_list(); static cson_value * json_wiki_save(); | > | | > > | > | > > > > > > > > > | | | | > > > > | | < | < < | < < < < > | < < | < < | < < < < < < | < | > > > | > > > > > | | > > | > | > > | | > | | < | > | | | | | | > | | | > > > | > > > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > | > > > > > > > > > > > > > > > > > > | > > > > > > > | | | > | < | | < < | > > > | > > > > | < | < > < < | | | < < | | < < > | | > > > > | > | > | > | < | | > > > > > > > > > > | > > > | | | | | | < < | > | < | | | | | > | | | < | < < < > > > > > | | | | > > > > | > | < < < | < | | 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 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 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 |
#if INTERFACE
#include "json_detail.h"
#endif
static cson_value * json_wiki_create();
static cson_value * json_wiki_get();
static cson_value * json_wiki_list();
static cson_value * json_wiki_preview();
static cson_value * json_wiki_save();
static cson_value * json_wiki_diff();
/*
** Mapping of /json/wiki/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Wiki[] = {
{"create", json_wiki_create, 0},
{"diff", json_wiki_diff, 0},
{"get", json_wiki_get, 0},
{"list", json_wiki_list, 0},
{"preview", json_wiki_preview, 0},
{"save", json_wiki_save, 0},
{"timeline", json_timeline_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};
/*
** Implements the /json/wiki family of pages/commands.
**
*/
cson_value * json_page_wiki(){
return json_page_dispatch_helper(&JsonPageDefs_Wiki[0]);
}
char * json_wiki_get_uuid_for_rid( int rid )
{
return db_text(NULL,
"SELECT b.uuid FROM tag t, tagxref x, blob b"
" WHERE x.tagid=t.tagid AND t.tagname GLOB 'wiki-*' "
" AND b.rid=x.rid AND b.rid=%d"
" ORDER BY x.mtime DESC LIMIT 1",
rid
);
}
/*
** Tries to load a wiki page from the given rid creates a JSON object
** representation of it. If the page is not found then NULL is
** returned. If contentFormat is positive then the page content
** is HTML-ized using fossil's conventional wiki format, if it is
** negative then no parsing is performed, if it is 0 then the content
** is not returned in the response. If contentFormat is 0 then the
** contentSize reflects the number of bytes, not characters, stored in
** the page.
**
** The returned value, if not NULL, is-a JSON Object owned by the
** caller. If it returns NULL then it may set g.json's error state.
*/
cson_value * json_get_wiki_page_by_rid(int rid, char contentFormat){
Manifest * pWiki = NULL;
if( NULL == (pWiki = manifest_get(rid, CFTYPE_WIKI)) ){
json_set_err( FSL_JSON_E_UNKNOWN,
"Error reading wiki page from manifest (rid=%d).",
rid );
return NULL;
}else{
/*char const * zFormat = NULL;*/
unsigned int len = 0;
cson_object * pay = cson_new_object();
char const * zBody = pWiki->zWiki;
char const * zFormat = NULL;
char * zUuid = json_wiki_get_uuid_for_rid(rid);
cson_object_set(pay,"name",json_new_string(pWiki->zWikiTitle));
cson_object_set(pay,"uuid",json_new_string(zUuid));
free(zUuid);
zUuid = NULL;
if( pWiki->nParent > 0 ){
cson_object_set( pay, "parent", json_new_string(pWiki->azParent[0]) )
/* Reminder: wiki pages do not branch and have only one parent
(except for the initial version, which has no parents). */;
}
/*cson_object_set(pay,"rid",json_new_int((cson_int_t)rid));*/
cson_object_set(pay,"user",json_new_string(pWiki->zUser));
cson_object_set(pay,FossilJsonKeys.timestamp,
json_julian_to_timestamp(pWiki->rDate));
if(0 == contentFormat){
cson_object_set(pay,"size",
json_new_int((cson_int_t)(zBody?strlen(zBody):0)));
}else{
if( contentFormat>0 ){/*HTML-ize it*/
zFormat = "html";
Blob content = empty_blob;
Blob raw = empty_blob;
if(zBody && *zBody){
blob_append(&raw,zBody,-1);
wiki_convert(&raw,&content,0);
len = (unsigned int)blob_size(&content);
}
cson_object_set(pay,"size",json_new_int((cson_int_t)len));
cson_object_set(pay,"content",
cson_value_new_string(blob_buffer(&content),len));
blob_reset(&content);
blob_reset(&raw);
}else{/*raw format*/
zFormat = "raw";
len = zBody ? strlen(zBody) : 0;
cson_object_set(pay,"size",json_new_int((cson_int_t)len));
cson_object_set(pay,"content",cson_value_new_string(zBody,len));
}
cson_object_set(pay,"contentFormat",json_new_string(zFormat));
}
/*TODO: add 'T' (tag) fields*/
/*TODO: add the 'A' card (file attachment) entries?*/
manifest_destroy(pWiki);
return cson_object_value(pay);
}
}
/*
** Searches for the latest version of a wiki page with the given
** name. If found it behaves like json_get_wiki_page_by_rid(theRid,
** contentFormat), else it returns NULL.
*/
cson_value * json_get_wiki_page_by_name(char const * zPageName, char contentFormat){
int rid;
rid = db_int(0,
"SELECT x.rid FROM tag t, tagxref x, blob b"
" WHERE x.tagid=t.tagid AND t.tagname='wiki-%q' "
" AND b.rid=x.rid"
" ORDER BY x.mtime DESC LIMIT 1",
zPageName
);
if( 0==rid ){
json_set_err( FSL_JSON_E_RESOURCE_NOT_FOUND, "Wiki page not found: %s",
zPageName );
return NULL;
}
return json_get_wiki_page_by_rid(rid, contentFormat);
}
/*
** Searches json_find_option_ctr("format",NULL,"f") for a flag.
** If not found it returns defaultValue else it returns a value
** depending on the first character of the format option:
**
** [h]tml = 1
** [n]one = 0
** [r]aw = -1
**
** The return value is intended for use with
** json_get_wiki_page_by_rid() and friends.
*/
char json_wiki_get_content_format_flag( char defaultValue ){
char contentFormat = defaultValue;
char const * zFormat = json_find_option_cstr("format",NULL,"f");
if( !zFormat || !*zFormat ){
return contentFormat;
}
else if('r'==*zFormat){
contentFormat = -1;
}
else if('h'==*zFormat){
contentFormat = 1;
}
else if('n'==*zFormat){
contentFormat = 0;
}
return contentFormat;
}
/*
** Helper for /json/wiki/get and /json/wiki/preview. At least one of
** zPageName (wiki page name) or zSymname must be set to a
** non-empty/non-NULL value. zSymname takes precedence. On success
** the result of one of json_get_wiki_page_by_rid() or
** json_get_wiki_page_by_name() will be returned (owned by the
** caller). On error g.json's error state is set and NULL is returned.
*/
static cson_value * json_wiki_get_by_name_or_symname(char const * zPageName,
char const * zSymname,
char contentFormat ){
if(!zSymname || !*zSymname){
return json_get_wiki_page_by_name(zPageName, contentFormat);
}else{
int rid = symbolic_name_to_rid( zSymname ? zSymname : zPageName, "w" );
if(rid<0){
json_set_err(FSL_JSON_E_AMBIGUOUS_UUID,
"UUID [%s] is ambiguious.", zSymname);
return NULL;
}else if(rid==0){
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
"UUID [%s] does not resolve to a wiki page.", zSymname);
return NULL;
}else{
return json_get_wiki_page_by_rid(rid, contentFormat);
}
}
}
/*
** Implementation of /json/wiki/get.
**
*/
static cson_value * json_wiki_get(){
char const * zPageName;
char const * zSymName = NULL;
char contentFormat = -1;
if( !g.perm.RdWiki && !g.perm.Read ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'o' or 'j' access.");
return NULL;
}
zPageName = json_find_option_cstr2("name",NULL,"n",g.json.dispatchDepth+1);
zSymName = json_find_option_cstr("uuid",NULL,"u");
if((!zPageName||!*zPageName) && (!zSymName || !*zSymName)){
json_set_err(FSL_JSON_E_MISSING_ARGS,
"At least one of the 'name' or 'uuid' arguments must be provided.");
return NULL;
}
/* TODO: see if we have a page named zPageName. If not, try to resolve
zPageName as a UUID.
*/
contentFormat = json_wiki_get_content_format_flag(contentFormat);
return json_wiki_get_by_name_or_symname( zPageName, zSymName, contentFormat );
}
/*
** Implementation of /json/wiki/preview.
**
*/
static cson_value * json_wiki_preview(){
char const * zContent = NULL;
cson_value * pay = NULL;
Blob contentOrig = empty_blob;
Blob contentHtml = empty_blob;
if( !g.perm.WrWiki ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'k' access.");
return NULL;
}
zContent = cson_string_cstr(cson_value_get_string(g.json.reqPayload.v));
if(!zContent) {
json_set_err(FSL_JSON_E_MISSING_ARGS,
"The 'payload' property must be a string containing the wiki code to preview.");
return NULL;
}
blob_append( &contentOrig, zContent, (int)cson_string_length_bytes(cson_value_get_string(g.json.reqPayload.v)) );
wiki_convert( &contentOrig, &contentHtml, 0 );
blob_reset( &contentOrig );
pay = cson_value_new_string( blob_str(&contentHtml), (unsigned int)blob_size(&contentHtml));
blob_reset( &contentHtml );
return pay;
}
/*
** Internal impl of /wiki/save and /wiki/create. If createMode is 0
** and the page already exists then a
** FSL_JSON_E_RESOURCE_ALREADY_EXISTS error is triggered. If
** createMode is false then the FSL_JSON_E_RESOURCE_NOT_FOUND is
** triggered if the page does not already exists.
**
** Note that the error triggered when createMode==0 and no such page
** exists is rather arbitrary - we could just as well create the entry
** here if it doesn't already exist. With that, save/create would
** become one operation. That said, i expect there are people who
** would categorize such behaviour as "being too clever" or "doing too
** much automatically" (and i would likely agree with them).
**
** If allowCreateIfNotExists is true then this function will allow a new
** page to be created even if createMode is false.
*/
static cson_value * json_wiki_create_or_save(char createMode,
char allowCreateIfNotExists){
Blob content = empty_blob; /* wiki page content */
cson_value * nameV; /* wiki page name */
char const * zPageName; /* cstr form of page name */
cson_value * contentV; /* passed-in content */
cson_value * emptyContent = NULL; /* placeholder for empty content. */
cson_value * payV = NULL; /* payload/return value */
cson_string const * jstr = NULL; /* temp for cson_value-to-cson_string conversions. */
unsigned int contentLen = 0;
int rid;
if( (createMode && !g.perm.NewWiki)
|| (!createMode && !g.perm.WrWiki)){
json_set_err(FSL_JSON_E_DENIED,
"Requires '%c' permissions.",
(createMode ? 'f' : 'k'));
return NULL;
}
nameV = json_req_payload_get("name");
if(!nameV){
json_set_err( FSL_JSON_E_MISSING_ARGS,
"'name' parameter is missing.");
return NULL;
}
zPageName = cson_string_cstr(cson_value_get_string(nameV));
if(!zPageName || !*zPageName){
json_set_err(FSL_JSON_E_INVALID_ARGS,
"'name' parameter must be a non-empty string.");
return NULL;
}
rid = db_int(0,
"SELECT x.rid FROM tag t, tagxref x"
" WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
" ORDER BY x.mtime DESC LIMIT 1",
zPageName
);
if(rid){
if(createMode){
json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
"Wiki page '%s' already exists.",
zPageName);
goto error;
}
}else if(!createMode && !allowCreateIfNotExists){
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
"Wiki page '%s' not found.",
zPageName);
goto error;
}
contentV = json_req_payload_get("content");
if( !contentV ){
if( createMode || (!rid && allowCreateIfNotExists) ){
contentV = emptyContent = cson_value_new_string("",0);
}else{
json_set_err(FSL_JSON_E_MISSING_ARGS,
"'content' parameter is missing.");
goto error;
}
}
if( !cson_value_is_string(nameV)
|| !cson_value_is_string(contentV)){
json_set_err(FSL_JSON_E_INVALID_ARGS,
"'content' parameter must be a string.");
goto error;
}
jstr = cson_value_get_string(contentV);
contentLen = (int)cson_string_length_bytes(jstr);
if(contentLen){
blob_append(&content, cson_string_cstr(jstr),contentLen);
}
wiki_cmd_commit(zPageName, 0==rid, &content);
blob_reset(&content);
/*
Our return value here has a race condition: if this operation
is called concurrently for the same wiki page via two requests,
payV could reflect the results of the other save operation.
*/
payV = json_get_wiki_page_by_name(
cson_string_cstr(
cson_value_get_string(nameV)),
0);
goto ok;
error:
assert( 0 != g.json.resultCode );
assert( NULL == payV );
ok:
if( emptyContent ){
/* We have some potentially tricky memory ownership
here, which is why we handle emptyContent separately.
This is, in fact, overkill because cson_value_new_string("",0)
actually returns a shared singleton instance (i.e. doesn't
|
| ︙ | ︙ | |||
325 326 327 328 329 330 331 |
/*
** Implementation of /json/wiki/list.
*/
static cson_value * json_wiki_list(){
cson_value * listV = NULL;
cson_array * list = NULL;
| > | > > > | | | > > > > > > > > > > | > > > > > > > | > | 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 |
/*
** Implementation of /json/wiki/list.
*/
static cson_value * json_wiki_list(){
cson_value * listV = NULL;
cson_array * list = NULL;
char const * zGlob = NULL;
Stmt q = empty_Stmt;
Blob sql = empty_blob;
char const verbose = json_find_option_bool("verbose",NULL,"v",0);
if( !g.perm.RdWiki && !g.perm.Read ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'j' or 'o' permissions.");
return NULL;
}
blob_append(&sql,"SELECT"
" substr(tagname,6) as name"
" FROM tag WHERE tagname GLOB 'wiki-*' ",
-1);
zGlob = json_find_option_cstr("glob",NULL,"g");
if(zGlob && *zGlob){
blob_appendf(&sql," AND name GLOB %Q ", zGlob);
}else{
zGlob = json_find_option_cstr("like",NULL,"l");
if(zGlob && *zGlob){
blob_appendf(&sql," AND name LIKE %Q ", zGlob);
}
}
blob_append(&sql,"ORDER BY lower(name)", -1);
db_prepare(&q,"%s", blob_str(&sql));
blob_reset(&sql);
listV = cson_value_new_array();
list = cson_value_get_array(listV);
while( SQLITE_ROW == db_step(&q) ){
cson_value * v;
if( verbose ){
char const * name = db_column_text(&q,0);
v = json_get_wiki_page_by_name(name,0);
}else{
v = cson_sqlite3_column_to_value(q.pStmt,0);
}
if(!v){
json_set_err(FSL_JSON_E_UNKNOWN,
"Could not convert wiki name column to JSON.");
goto error;
}else if( 0 != cson_array_append( list, v ) ){
cson_value_free(v);
json_set_err(FSL_JSON_E_ALLOC,"Could not append wiki page name to array.")
|
| ︙ | ︙ | |||
360 361 362 363 364 365 366 367 | assert(0 != g.json.resultCode); cson_value_free(listV); listV = NULL; end: db_finalize(&q); return listV; } #endif /* FOSSIL_ENABLE_JSON */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
assert(0 != g.json.resultCode);
cson_value_free(listV);
listV = NULL;
end:
db_finalize(&q);
return listV;
}
static cson_value * json_wiki_diff(){
char const * zV1 = NULL;
char const * zV2 = NULL;
cson_object * pay = NULL;
int argPos = g.json.dispatchDepth;
int r1 = 0, r2 = 0;
Manifest * pW1 = NULL, *pW2 = NULL;
Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
char const * zErrTag = NULL;
int diffFlags;
char * zUuid = NULL;
if( !g.perm.History ){
json_set_err(FSL_JSON_E_DENIED,
"Requires 'h' permissions.");
return NULL;
}
zV1 = json_find_option_cstr2( "v1",NULL, NULL, ++argPos );
zV2 = json_find_option_cstr2( "v2",NULL, NULL, ++argPos );
if(!zV1 || !*zV1 || !zV2 || !*zV2) {
json_set_err(FSL_JSON_E_INVALID_ARGS,
"Requires both 'v1' and 'v2' arguments.");
return NULL;
}
r1 = symbolic_name_to_rid( zV1, "w" );
zErrTag = zV1;
if(r1<0){
goto ambiguous;
}else if(0==r1){
goto invalid;
}
r2 = symbolic_name_to_rid( zV2, "w" );
zErrTag = zV2;
if(r2<0){
goto ambiguous;
}else if(0==r2){
goto invalid;
}
zErrTag = zV1;
pW1 = manifest_get(r1, CFTYPE_WIKI);
if( pW1==0 ) {
goto manifest;
}
zErrTag = zV2;
pW2 = manifest_get(r2, CFTYPE_WIKI);
if( pW2==0 ) {
goto manifest;
}
blob_init(&w1, pW1->zWiki, -1);
blob_zero(&w2);
blob_init(&w2, pW2->zWiki, -1);
blob_zero(&d);
diffFlags = DIFF_IGNORE_EOLWS | DIFF_INLINE;
text_diff(&w2, &w1, &d, diffFlags);
blob_reset(&w1);
blob_reset(&w2);
pay = cson_new_object();
zUuid = json_wiki_get_uuid_for_rid( pW1->rid );
cson_object_set(pay, "v1", json_new_string(zUuid) );
free(zUuid);
zUuid = json_wiki_get_uuid_for_rid( pW2->rid );
cson_object_set(pay, "v2", json_new_string(zUuid) );
free(zUuid);
zUuid = NULL;
manifest_destroy(pW1);
manifest_destroy(pW2);
cson_object_set(pay, "diff",
cson_value_new_string( blob_str(&d),
(unsigned int)blob_size(&d)));
return cson_object_value(pay);
manifest:
json_set_err(FSL_JSON_E_UNKNOWN,
"Could not load wiki manifest for UUID [%s].",
zErrTag);
goto end;
ambiguous:
json_set_err(FSL_JSON_E_AMBIGUOUS_UUID,
"UUID [%s] is ambiguous.", zErrTag);
goto end;
invalid:
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
"UUID [%s] not found.", zErrTag);
goto end;
end:
cson_free_object(pay);
return NULL;
}
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/login.c.
| ︙ | ︙ | |||
259 260 261 262 263 264 265 |
char ** zDest /* Optional: store generated cookie value. */
){
const char *zCookieName = login_cookie_name();
const char *zExpire = db_get("cookie-expire","8766");
int expires = atoi(zExpire)*3600;
char *zHash;
char *zCookie;
| | | > > > > > > > > | | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
char ** zDest /* Optional: store generated cookie value. */
){
const char *zCookieName = login_cookie_name();
const char *zExpire = db_get("cookie-expire","8766");
int expires = atoi(zExpire)*3600;
char *zHash;
char *zCookie;
char const *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */
char *zRemoteAddr = ipPrefix(zIpAddr); /* Abbreviated IP address */
assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data.");
zHash = db_text(0,
"SELECT cookie FROM user"
" WHERE uid=%d"
" AND ipaddr=%Q"
" AND cexpire>julianday('now')"
" AND length(cookie)>30",
uid, zRemoteAddr);
if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))");
zCookie = login_gen_user_cookie_value(zUsername, zHash);
cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
record_login_attempt(zUsername, zIpAddr, 1);
db_multi_exec(
"UPDATE user SET cookie=%Q, ipaddr=%Q, "
" cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
zHash, zRemoteAddr, expires, uid
|
| ︙ | ︙ | |||
1394 1395 1396 1397 1398 1399 1400 |
char *zSql; /* SQL to run on all peers */
const char *zSelf; /* The ATTACH name of our repository */
*pzErrMsg = 0; /* Default to no errors */
zSelf = db_name("repository");
/* Get the full pathname of the other repository */
| | | | 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 |
char *zSql; /* SQL to run on all peers */
const char *zSelf; /* The ATTACH name of our repository */
*pzErrMsg = 0; /* Default to no errors */
zSelf = db_name("repository");
/* Get the full pathname of the other repository */
file_canonical_name(zRepo, &fullName, 0);
zRepo = mprintf(blob_str(&fullName));
blob_reset(&fullName);
/* Get the full pathname for our repository. Also the project code
** and project name for ourself. */
file_canonical_name(g.zRepositoryName, &fullName, 0);
zSelfRepo = mprintf(blob_str(&fullName));
blob_reset(&fullName);
zSelfProjCode = db_get("project-code", "unknown");
zSelfLabel = db_get("project-name", 0);
if( zSelfLabel==0 ){
zSelfLabel = zSelfProjCode;
}
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
437 438 439 440 441 442 443 | g.json.outOpt.addNewline = 1; g.json.outOpt.indentation = 1 /* in CGI/server mode this can be configured */; #endif /* FOSSIL_ENABLE_JSON */ expand_args_option(); argc = g.argc; argv = g.argv; for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]); | | | < | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
g.json.outOpt.addNewline = 1;
g.json.outOpt.indentation = 1 /* in CGI/server mode this can be configured */;
#endif /* FOSSIL_ENABLE_JSON */
expand_args_option();
argc = g.argc;
argv = g.argv;
for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
zCmdName = "cgi";
g.isHTTP = 1;
}else if( argc<2 ){
fossil_print(
"Usage: %s COMMAND ...\n"
" or: %s help -- for a list of common commands\n"
" or: %s help COMMMAND -- for help with the named command\n",
argv[0], argv[0], argv[0]);
fossil_exit(1);
}else{
g.isHTTP = 0;
g.fQuiet = find_option("quiet", 0, 0)!=0;
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
|
| ︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 |
#if !defined(_WIN32)
if( getuid()==0 ){
int i;
struct stat sStat;
Blob dir;
char *zDir;
| | | 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
#if !defined(_WIN32)
if( getuid()==0 ){
int i;
struct stat sStat;
Blob dir;
char *zDir;
file_canonical_name(zRepo, &dir, 0);
zDir = blob_str(&dir);
if( file_isdir(zDir)==1 ){
if( chdir(zDir) || chroot(zDir) || chdir("/") ){
fossil_fatal("unable to chroot into %s", zDir);
}
zRepo = "/";
}else{
|
| ︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 |
i++;
continue;
}
zRepo[j] = '.';
}
if( szFile<1024 ){
if( zNotFound ){
cgi_redirect(zNotFound);
}else{
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode){
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
return;
| > | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 |
i++;
continue;
}
zRepo[j] = '.';
}
if( szFile<1024 ){
set_base_url();
if( zNotFound ){
cgi_redirect(zNotFound);
}else{
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode){
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
return;
|
| ︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 |
zAltRepo += jj+1;
}else{
zUser = "nobody";
}
if( g.zLogin==0 ) zUser = "nobody";
if( zAltRepo[0]!='/' ){
zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
| | > > > > > > > > > > > > > > > > > > > > | | > > > | 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 |
zAltRepo += jj+1;
}else{
zUser = "nobody";
}
if( g.zLogin==0 ) zUser = "nobody";
if( zAltRepo[0]!='/' ){
zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
file_simplify_name(zAltRepo, -1, 0);
}
db_close(1);
db_open_repository(zAltRepo);
login_as_user(zUser);
g.perm.Password = 0;
zPath += i;
nHost = g.zTop - g.zBaseURL;
g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
g.zTop = g.zBaseURL + nHost;
continue;
}
}else{
g.zExtra = 0;
}
break;
}
#ifdef FOSSIL_ENABLE_JSON
/*
** Workaround to allow us to customize some following behaviour for
** JSON mode. The problem is, we don't always know if we're in JSON
** mode at this point (namely, for GET mode we don't know but POST
** we do), so we snoop g.zPath and cheat a bit.
*/
if( g.zPath && (0==strcmp("json",g.zPath)) ){
g.json.isJsonMode = 1;
}
#endif
if( g.zExtra ){
/* CGI parameters get this treatment elsewhere, but places like getfile
** will use g.zExtra directly.
** Reminder: the login mechanism uses 'name' differently, and may
** eventually have a problem/collision with this.
**
** Disabled by stephan when running in JSON mode because this
** particular parameter name is very common and i have had no end
** of grief with this handling. The JSON API never relies on the
** handling below, and by disabling it in JSON mode i can remove
** lots of special-case handling in several JSON handlers.
*/
#ifdef FOSSIL_ENABLE_JSON
if(!g.json.isJsonMode){
#endif
dehttpize(g.zExtra);
cgi_set_parameter_nocopy("name", g.zExtra);
#ifdef FOSSIL_ENABLE_JSON
}
#endif
}
/* Locate the method specified by the path and execute the function
** that implements that method.
*/
if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) &&
name_search("not_found", aWebpage, count(aWebpage), &idx) ){
|
| ︙ | ︙ | |||
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 |
**
** #!/usr/bin/fossil
** repository: /home/somebody/project.db
**
** The second line defines the name of the repository. After locating
** the repository, fossil will generate a webpage on stdout based on
** the values of standard CGI environment variables.
*/
void cmd_cgi(void){
const char *zFile;
const char *zNotFound = 0;
char **azRedirect = 0; /* List of repositories to redirect to */
int nRedirect = 0; /* Number of entries in azRedirect */
Blob config, line, key, value, value2;
| > > | 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 |
**
** #!/usr/bin/fossil
** repository: /home/somebody/project.db
**
** The second line defines the name of the repository. After locating
** the repository, fossil will generate a webpage on stdout based on
** the values of standard CGI environment variables.
**
** See also: http, server, winsrv
*/
void cmd_cgi(void){
const char *zFile;
const char *zNotFound = 0;
char **azRedirect = 0; /* List of repositories to redirect to */
int nRedirect = 0; /* Number of entries in azRedirect */
Blob config, line, key, value, value2;
|
| ︙ | ︙ | |||
1523 1524 1525 1526 1527 1528 1529 |
** is disallowed.
*/
static void find_server_repository(int disallowDir){
if( g.argc<3 ){
db_must_be_within_tree();
}else if( !disallowDir && file_isdir(g.argv[2])==1 ){
g.zRepositoryName = mprintf("%s", g.argv[2]);
| | | | > > > | > | < | > > > < < > | 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 |
** is disallowed.
*/
static void find_server_repository(int disallowDir){
if( g.argc<3 ){
db_must_be_within_tree();
}else if( !disallowDir && file_isdir(g.argv[2])==1 ){
g.zRepositoryName = mprintf("%s", g.argv[2]);
file_simplify_name(g.zRepositoryName, -1, 0);
}else{
db_open_repository(g.argv[2]);
}
}
/*
** undocumented format:
**
** fossil http REPOSITORY INFILE OUTFILE IPADDR
**
** The argv==6 form is used by the win32 server only.
**
** COMMAND: http*
**
** Usage: %fossil http REPOSITORY ?OPTIONS?
**
** Handle a single HTTP request appearing on stdin. The resulting webpage
** is delivered on stdout. This method is used to launch an HTTP request
** handler from inetd, for example. The argument is the name of the
** repository.
**
** If REPOSITORY is a directory that contains one or more respositories
** with names of the form "*.fossil" then the first element of the URL
** pathname selects among the various repositories. If the pathname does
** not select a valid repository and the --notfound option is available,
** then the server redirects (HTTP code 302) to the URL of --notfound.
**
** The --host option can be used to specify the hostname for the server.
** The --https option indicates that the request came from HTTPS rather
** than HTTP. If --nossl is given, then SSL connections will not be available,
** thus also no redirecting from http: to https: will take place.
**
** If the --localauth option is given, then automatic login is performed
** for requests coming from localhost, if the "localauth" setting is not
** enabled.
**
** Options:
** --localauth enable automatic login for local connections
** --host NAME specify hostname of the server
** --https signal a request coming in via https
** --nossl signal that no SSL connections are available
** --notfound URL use URL as "HTTP 404, object not found" page.
**
** See also: cgi, server, winsrv
*/
void cmd_http(void){
const char *zIpAddr;
const char *zNotFound;
const char *zHost;
zNotFound = find_option("notfound", 0, 1);
g.useLocalauth = find_option("localauth", 0, 0)!=0;
|
| ︙ | ︙ | |||
1601 1602 1603 1604 1605 1606 1607 |
/*
** Note that the following command is used by ssh:// processing.
**
** COMMAND: test-http
** Works like the http command but gives setup permission to all users.
*/
void cmd_test_http(void){
| | > > | | 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 |
/*
** Note that the following command is used by ssh:// processing.
**
** COMMAND: test-http
** Works like the http command but gives setup permission to all users.
*/
void cmd_test_http(void){
login_set_capabilities("sx", 0);
g.useLocalauth = 1;
cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
g.httpIn = stdin;
g.httpOut = stdout;
find_server_repository(0);
g.cgiOutput = 1;
g.fullHttpReply = 1;
cgi_handle_http_request(0);
process_one_web_page(0);
}
#if !defined(_WIN32)
#if !defined(__DARWIN__) && !defined(__APPLE__)
/*
** Search for an executable on the PATH environment variable.
** Return true (1) if found and false (0) if not found.
*/
static int binaryOnPath(const char *zBinary){
const char *zPath = fossil_getenv("PATH");
char *zFull;
int i;
int bExists;
while( zPath && zPath[0] ){
while( zPath[0]==':' ) zPath++;
for(i=0; zPath[i] && zPath[i]!=':'; i++){}
zFull = mprintf("%.*s/%s", i, zPath, zBinary);
|
| ︙ | ︙ | |||
1640 1641 1642 1643 1644 1645 1646 | #endif #endif /* ** COMMAND: server* ** COMMAND: ui ** | | | | 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 | #endif #endif /* ** COMMAND: server* ** COMMAND: ui ** ** Usage: %fossil server ?OPTIONS? ?REPOSITORY? ** Or: %fossil ui ?OPTIONS? ?REPOSITORY? ** ** Open a socket and begin listening and responding to HTTP requests on ** TCP port 8080, or on any other TCP port defined by the -P or ** --port option. The optional argument is the name of the repository. ** The repository argument may be omitted if the working directory is ** within an open checkout. ** |
| ︙ | ︙ | |||
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 |
** various repositories.
**
** By default, the "ui" command provides full administrative access without
** having to log in. This can be disabled by setting turning off the
** "localauth" setting. Automatic login for the "server" command is available
** if the --localauth option is present and the "localauth" setting is off
** and the connection is from localhost.
*/
void cmd_webserver(void){
int iPort, mxPort; /* Range of TCP ports allowed */
const char *zPort; /* Value of the --port option */
char *zBrowser; /* Name of web browser program */
char *zBrowserCmd = 0; /* Command to launch the web browser */
int isUiCmd; /* True if command is "ui", not "server' */
| > > > > > > > | 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 |
** various repositories.
**
** By default, the "ui" command provides full administrative access without
** having to log in. This can be disabled by setting turning off the
** "localauth" setting. Automatic login for the "server" command is available
** if the --localauth option is present and the "localauth" setting is off
** and the connection is from localhost.
**
** Options:
** --localauth enable automatic login for requests from localhost
** -P|--port TCPPORT listen to request on port TCPPORT
** --th-trace trace TH1 execution (for debugging purposes)
**
** See also: cgi, http, winsrv
*/
void cmd_webserver(void){
int iPort, mxPort; /* Range of TCP ports allowed */
const char *zPort; /* Value of the --port option */
char *zBrowser; /* Name of web browser program */
char *zBrowserCmd = 0; /* Command to launch the web browser */
int isUiCmd; /* True if command is "ui", not "server' */
|
| ︙ | ︙ |
Changes to src/main.mk.
1 2 3 4 5 6 7 8 9 10 11 12 | # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This file is included by primary Makefile. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # ############################################################################## # WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl") ############################################################################## # # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This file is included by primary Makefile. # XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) -I$(OBJDIR) SRC = \ $(SRCDIR)/add.c \ $(SRCDIR)/allrepo.c \ $(SRCDIR)/attach.c \ $(SRCDIR)/bag.c \ |
| ︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_login.c \ $(SRCDIR)/json_query.c \ $(SRCDIR)/json_report.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ | > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_config.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_dir.c \ $(SRCDIR)/json_finfo.c \ $(SRCDIR)/json_login.c \ $(SRCDIR)/json_query.c \ $(SRCDIR)/json_report.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ |
| ︙ | ︙ | |||
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_login_.c \ $(OBJDIR)/json_query_.c \ $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ | > > > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_config_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_dir_.c \ $(OBJDIR)/json_finfo_.c \ $(OBJDIR)/json_login_.c \ $(OBJDIR)/json_query_.c \ $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ |
| ︙ | ︙ | |||
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_login.o \ $(OBJDIR)/json_query.o \ $(OBJDIR)/json_report.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ | > > > | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_config.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_dir.o \ $(OBJDIR)/json_finfo.o \ $(OBJDIR)/json_login.o \ $(OBJDIR)/json_query.o \ $(OBJDIR)/json_report.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ |
| ︙ | ︙ | |||
363 364 365 366 367 368 369 | clean: rm -rf $(OBJDIR)/* $(APPNAME) $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(OBJDIR)/mkindex $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h | | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | clean: rm -rf $(OBJDIR)/* $(APPNAME) $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(OBJDIR)/mkindex $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h touch $(OBJDIR)/headers $(OBJDIR)/headers: Makefile $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c $(OBJDIR)/add.o: $(OBJDIR)/add_.c $(OBJDIR)/add.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c |
| ︙ | ︙ | |||
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | $(OBJDIR)/json_branch_.c: $(SRCDIR)/json_branch.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.o: $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h: $(OBJDIR)/headers $(OBJDIR)/json_diff_.c: $(SRCDIR)/json_diff.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.o: $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h: $(OBJDIR)/headers $(OBJDIR)/json_login_.c: $(SRCDIR)/json_login.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.o: $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h: $(OBJDIR)/headers | > > > > > > > > > > > > > > > > > > > > > | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | $(OBJDIR)/json_branch_.c: $(SRCDIR)/json_branch.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.o: $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h: $(OBJDIR)/headers $(OBJDIR)/json_config_.c: $(SRCDIR)/json_config.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_config.c >$(OBJDIR)/json_config_.c $(OBJDIR)/json_config.o: $(OBJDIR)/json_config_.c $(OBJDIR)/json_config.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_config.o -c $(OBJDIR)/json_config_.c $(OBJDIR)/json_config.h: $(OBJDIR)/headers $(OBJDIR)/json_diff_.c: $(SRCDIR)/json_diff.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.o: $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h: $(OBJDIR)/headers $(OBJDIR)/json_dir_.c: $(SRCDIR)/json_dir.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_dir.c >$(OBJDIR)/json_dir_.c $(OBJDIR)/json_dir.o: $(OBJDIR)/json_dir_.c $(OBJDIR)/json_dir.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_dir.o -c $(OBJDIR)/json_dir_.c $(OBJDIR)/json_dir.h: $(OBJDIR)/headers $(OBJDIR)/json_finfo_.c: $(SRCDIR)/json_finfo.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_finfo.c >$(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.o: $(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_finfo.o -c $(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.h: $(OBJDIR)/headers $(OBJDIR)/json_login_.c: $(SRCDIR)/json_login.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.o: $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h: $(OBJDIR)/headers |
| ︙ | ︙ |
Changes to src/makemake.tcl.
| ︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | http_socket http_transport import info json json_artifact json_branch json_diff json_login json_query json_report json_tag json_timeline json_user json_wiki | > > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | http_socket http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_tag json_timeline json_user json_wiki |
| ︙ | ︙ | |||
150 151 152 153 154 155 156 | # This file is automatically generated. Instead of editing this # file, edit "makemake.tcl" then run "tclsh makemake.tcl" # to regenerate this file. # # This file is included by primary Makefile. # | | | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# This file is automatically generated. Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
# This file is included by primary Makefile.
#
XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) -I$(OBJDIR)
}
writeln -nonewline "SRC ="
foreach s [lsort $src] {
writeln -nonewline " \\\n \$(SRCDIR)/$s.c"
}
writeln "\n"
|
| ︙ | ︙ | |||
255 256 257 258 259 260 261 | append mhargs " \$(OBJDIR)/VERSION.h" writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex" writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@" writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h" writeln "\t\$(OBJDIR)/makeheaders $mhargs" writeln "\ttouch \$(OBJDIR)/headers" writeln "\$(OBJDIR)/headers: Makefile" | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
append mhargs " \$(OBJDIR)/VERSION.h"
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
writeln "\t\$(OBJDIR)/makeheaders $mhargs"
writeln "\ttouch \$(OBJDIR)/headers"
writeln "\$(OBJDIR)/headers: Makefile"
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/json_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h"
writeln "Makefile:"
set extra_h(main) \$(OBJDIR)/page_index.h
foreach s [lsort $src] {
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
|
| ︙ | ︙ | |||
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 | #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = gcc #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### The directories where the zlib include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "zlib-1.x.y" sub-directory of the # Fossil source code directory and the target zlib source directory. # | > > > > | | | | | 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 | #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = gcc #### Enable JSON (http://www.json.org) support using "cson" # # FOSSIL_ENABLE_JSON = 1 #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### The directories where the zlib include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "zlib-1.x.y" sub-directory of the # Fossil source code directory and the target zlib source directory. # ZINCDIR = $(SRCDIR)/../zlib-1.2.6 ZLIBDIR = $(SRCDIR)/../zlib-1.2.6 #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.0g/include OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.0g #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
407 408 409 410 411 412 413 414 415 416 417 418 419 420 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win | > | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -Dpqueue_insert=pqueue_insert_fossil TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win |
| ︙ | ︙ | |||
428 429 430 431 432 433 434 435 436 437 438 439 440 441 | TCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support (statically linked) ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 -DSTATIC_BUILD endif #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. We add the -static option here # so that we can build a static executable that will run in a # chroot jail. # | > > > > > | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | TCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support (statically linked) ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 -DSTATIC_BUILD endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 endif #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. We add the -static option here # so that we can build a static executable that will run in a # chroot jail. # |
| ︙ | ︙ | |||
454 455 456 457 458 459 460 | #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 else | | | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 else LIB += -lkernel32 -lws2_32 endif #### Tcl shell for use in running the fossil test suite. This is only # used for testing. # TCLSH = tclsh |
| ︙ | ︙ | |||
597 598 599 600 601 602 603 |
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
set opt $SQLITE_OPTIONS
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
set opt {}
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
| | | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
set opt $SQLITE_OPTIONS
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
set opt {}
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
set opt {-Dmain=sqlite3_shell}
append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
|
| ︙ | ︙ | |||
654 655 656 657 658 659 660 | #SSL = -DFOSSIL_ENABLE_SSL=1 SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) | | | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 |
#SSL = -DFOSSIL_ENABLE_SSL=1
SSL =
CFLAGS = -o
BCC = $(DMDIR)\bin\dmc $(CFLAGS)
TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
}
writeln "SQLITE_OPTIONS = $SQLITE_OPTIONS\n"
writeln -nonewline "SRC = "
foreach s [lsort $src] {
writeln -nonewline "${s}_.c "
}
writeln "\n"
|
| ︙ | ︙ | |||
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h | > > > | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| ︙ | ︙ | |||
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h | > > > | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| ︙ | ︙ |
Changes to src/manifest.c.
| ︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 |
}
}
if( p->zBaseline==0 ) return 0;
fetch_baseline(p, 1);
pBase = p->pBaseline;
if( pBase==0 ) return 0;
for(i=0; i<pBase->nFile; i++){
| | | | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 |
}
}
if( p->zBaseline==0 ) return 0;
fetch_baseline(p, 1);
pBase = p->pBaseline;
if( pBase==0 ) return 0;
for(i=0; i<pBase->nFile; i++){
if( fossil_stricmp(zName, pBase->aFile[i].zName)==0 ){
return &pBase->aFile[i];
}
}
return 0;
}
/*
** Add mlink table entries associated with manifest cid, pChild. The
|
| ︙ | ︙ | |||
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 |
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
const char *zUuid;
blob_zero(&comment);
for(i=0; i<p->nTag; i++){
zUuid = p->aTag[i].zUuid;
if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){
if( i>0 ) blob_append(&comment, " ", 1);
| > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | < < | | | | | | > > | 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
const char *zUuid;
int branchMove = 0;
blob_zero(&comment);
for(i=0; i<p->nTag; i++){
zUuid = p->aTag[i].zUuid;
if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){
if( i>0 ) blob_append(&comment, " ", 1);
blob_appendf(&comment,
"Edit [[/info/%S | %S]]:",
zUuid, zUuid);
branchMove = 0;
}
zName = p->aTag[i].zName;
zValue = p->aTag[i].zValue;
if( strcmp(zName, "*branch")==0 ){
blob_appendf(&comment,
" Move to branch [/timeline?r=%h&nd&dp=%S | %h].",
zValue, zUuid, zValue);
branchMove = 1;
}else if( strcmp(zName, "*bgcolor")==0 ){
blob_appendf(&comment,
" Change branch background color to \"%h\".", zValue);
}else if( strcmp(zName, "+bgcolor")==0 ){
blob_appendf(&comment,
" Change background color to \"%h\".", zValue);
}else if( strcmp(zName, "-bgcolor")==0 ){
blob_appendf(&comment, " Cancel background color.");
}else if( strcmp(zName, "+comment")==0 ){
blob_appendf(&comment, " Edit check-in comment.");
}else if( strcmp(zName, "+user")==0 ){
blob_appendf(&comment, " Change user to \"%h\".", zValue);
}else if( strcmp(zName, "+date")==0 ){
blob_appendf(&comment, " Timestamp %h.", zValue);
}else if( memcmp(zName, "-sym-",5)==0 ){
if( !branchMove ) blob_appendf(&comment, " Cancel tag %h.", &zName[5]);
}else if( memcmp(zName, "*sym-",5)==0 ){
if( !branchMove ){
blob_appendf(&comment, " Add propagating tag \"%h\".", &zName[5]);
}
}else if( memcmp(zName, "+sym-",5)==0 ){
blob_appendf(&comment, " Add tag \"%h\".", &zName[5]);
}else if( memcmp(zName, "-sym-",5)==0 ){
blob_appendf(&comment, " Cancel tag \"%h\".", &zName[5]);
}else if( strcmp(zName, "+closed")==0 ){
blob_appendf(&comment, " Marked \"Closed\".");
}else if( strcmp(zName, "-closed")==0 ){
blob_appendf(&comment, " Removed the \"Closed\" mark.");
}else {
if( zName[0]=='-' ){
blob_appendf(&comment, " Cancel \"%h\"", &zName[1]);
}else if( zName[0]=='+' ){
blob_appendf(&comment, " Add \"%h\"", &zName[1]);
}else{
blob_appendf(&comment, " Add propagating \"%h\"", &zName[1]);
}
if( zValue && zValue[0] ){
blob_appendf(&comment, " with value \"%h\".", zValue);
}else{
blob_appendf(&comment, ".");
}
}
}
/*blob_appendf(&comment, " [[/info/%S | details]]");*/
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('g',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, blob_str(&comment)
);
blob_reset(&comment);
}
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** This file contains code used to merge two or more branches into ** a single tree. */ #include "config.h" #include "merge.h" #include <assert.h> /* ** COMMAND: merge ** ** Usage: %fossil merge ?OPTIONS? VERSION ** ** The argument VERSION is a version that should be merged into the | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
** This file contains code used to merge two or more branches into
** a single tree.
*/
#include "config.h"
#include "merge.h"
#include <assert.h>
/*
** Print information about a particular check-in.
*/
void print_checkin_description(int rid, int indent, const char *zLabel){
Stmt q;
db_prepare(&q,
"SELECT datetime(mtime,'localtime'),"
" coalesce(euser,user), coalesce(ecomment,comment),"
" (SELECT uuid FROM blob WHERE rid=%d),"
" (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref"
" WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
" AND tagxref.rid=%d AND tagxref.tagtype>0)"
" FROM event WHERE objid=%d", rid, rid, rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zTagList = db_column_text(&q, 4);
char *zCom;
if( zTagList && zTagList[0] ){
zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
}else{
zCom = mprintf("%s", db_column_text(&q,2));
}
fossil_print("%-*s [%S] by %s on %s\n%*s",
indent-1, zLabel,
db_column_text(&q, 3),
db_column_text(&q, 1),
db_column_text(&q, 0),
indent, "");
comment_print(zCom, indent, 78);
fossil_free(zCom);
}
db_finalize(&q);
}
/*
** COMMAND: merge
**
** Usage: %fossil merge ?OPTIONS? VERSION
**
** The argument VERSION is a version that should be merged into the
|
| ︙ | ︙ | |||
114 115 116 117 118 119 120 |
pid = name_to_typed_rid(zPivot, "ci");
if( pid==0 || !is_a_version(pid) ){
fossil_fatal("not a version: %s", zPivot);
}
if( pickFlag ){
fossil_fatal("incompatible options: --cherrypick & --baseline");
}
| < | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
pid = name_to_typed_rid(zPivot, "ci");
if( pid==0 || !is_a_version(pid) ){
fossil_fatal("not a version: %s", zPivot);
}
if( pickFlag ){
fossil_fatal("incompatible options: --cherrypick & --baseline");
}
}else if( pickFlag || backoutFlag ){
pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid);
if( pid<=0 ){
fossil_fatal("cannot find an ancestor for %s", g.argv[2]);
}
}else{
pivot_set_primary(mid);
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
int t = pid;
pid = mid;
mid = t;
}
if( !is_a_version(pid) ){
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;
| > > > > | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
int t = pid;
pid = mid;
mid = t;
}
if( !is_a_version(pid) ){
fossil_fatal("not a version: record #%d", pid);
}
if( detailFlag ){
print_checkin_description(mid, 12, "merge-from:");
print_checkin_description(pid, 12, "baseline:");
}
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;
|
| ︙ | ︙ | |||
516 517 518 519 520 521 522 |
}
}
/*
** Clean up the mid and pid VFILE entries. Then commit the changes.
*/
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
| > > | > > | > > > > > | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
}
}
/*
** Clean up the mid and pid VFILE entries. Then commit the changes.
*/
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)",
pickFlag ? -1 : (backoutFlag ? -2 : 0), mid);
if( pickFlag ){
/* For a cherry-pick merge, make the default check-in comment the same
** as the check-in comment on the check-in that is being merged in. */
db_multi_exec(
"REPLACE INTO vvar(name,value)"
" SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
" WHERE type='ci' AND objid=%d",
mid
);
}
undo_finish();
db_end_transaction(nochangeFlag);
}
|
Changes to src/merge3.c.
| ︙ | ︙ | |||
393 394 395 396 397 398 399 400 401 402 |
Blob *pPivot, /* Common ancestor (older) */
const char *zV1, /* Name of file for version merging into (mine) */
Blob *pV2, /* Version merging from (yours) */
Blob *pOut /* Output written here */
){
Blob v1; /* Content of zV1 */
int rc; /* Return code of subroutines and this routine */
blob_read_from_file(&v1, zV1);
rc = blob_merge(pPivot, &v1, pV2, pOut);
| > > > | < < < < < > > > > | 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 |
Blob *pPivot, /* Common ancestor (older) */
const char *zV1, /* Name of file for version merging into (mine) */
Blob *pV2, /* Version merging from (yours) */
Blob *pOut /* Output written here */
){
Blob v1; /* Content of zV1 */
int rc; /* Return code of subroutines and this routine */
char *zPivot; /* Name of the pivot file */
char *zOrig; /* Name of the original content file */
char *zOther; /* Name of the merge file */
blob_read_from_file(&v1, zV1);
rc = blob_merge(pPivot, &v1, pV2, pOut);
if( rc!=0 ){
zPivot = file_newname(zV1, "baseline", 1);
blob_write_to_file(pPivot, zPivot);
zOrig = file_newname(zV1, "original", 1);
blob_write_to_file(&v1, zOrig);
zOther = file_newname(zV1, "merge", 1);
blob_write_to_file(pV2, zOther);
}
if( rc>0 ){
const char *zGMerge; /* Name of the gmerge command */
zGMerge = db_get("gmerge-command", 0);
if( zGMerge && zGMerge[0] ){
char *zOut; /* Temporary output file */
char *zCmd; /* Command to invoke */
const char *azSubst[8]; /* Strings to be substituted */
zOut = file_newname(zV1, "output", 1);
|
| ︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
file_delete(zOrig);
file_delete(zOther);
file_delete(zOut);
}
fossil_free(zCmd);
fossil_free(zOut);
}
fossil_free(zPivot);
fossil_free(zOrig);
fossil_free(zOther);
}
blob_reset(&v1);
return rc;
}
| > > | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
file_delete(zOrig);
file_delete(zOther);
file_delete(zOut);
}
fossil_free(zCmd);
fossil_free(zOut);
}
}
if( rc!=0 ){
fossil_free(zPivot);
fossil_free(zOrig);
fossil_free(zOther);
}
blob_reset(&v1);
return rc;
}
|
Changes to src/name.c.
| ︙ | ︙ | |||
67 68 69 70 71 72 73 | ** match any known object. Or return -1 if the name is ambiguious. ** ** The zType parameter specifies the type of artifact: ci, t, w, e, g. ** If zType is NULL or "" or "*" then any type of artifact will serve. ** zType is "ci" in most use cases since we are usually searching for ** a check-in. */ | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
** match any known object. Or return -1 if the name is ambiguious.
**
** The zType parameter specifies the type of artifact: ci, t, w, e, g.
** If zType is NULL or "" or "*" then any type of artifact will serve.
** zType is "ci" in most use cases since we are usually searching for
** a check-in.
*/
int symbolic_name_to_rid(const char *zTag, const char *zType){
int vid;
int rid = 0;
int nTag;
int i;
if( zType==0 || zType[0]==0 ) zType = "*";
if( zTag==0 || zTag[0]==0 ) return 0;
|
| ︙ | ︙ | |||
263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
return 1;
}else{
blob_reset(pName);
db_blob(pName, "SELECT uuid FROM blob WHERE rid=%d", rid);
return 0;
}
}
/*
** COMMAND: test-name-to-id
**
** Convert a name to a full artifact ID.
*/
void test_name_to_id(void){
| > > > > > > > > > > > > > > > > > > > > | 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 |
return 1;
}else{
blob_reset(pName);
db_blob(pName, "SELECT uuid FROM blob WHERE rid=%d", rid);
return 0;
}
}
/*
** This routine is similar to name_to_uuid() except in the form it
** takes its parameters and returns its value, and in that it does not
** treat errors as fatal. zName must be a UUID, as described for
** name_to_uuid(). zType is also as described for that function. If
** zName does not resolve, 0 is returned. If it is ambiguous, a
** negative value is returned. On success the rid is returned and
** pUuid (if it is not NULL) is set to the a newly-allocated string,
** the full UUID, which must eventually be free()d by the caller.
*/
int name_to_uuid2(char const *zName, const char *zType, char **pUuid){
int rid = symbolic_name_to_rid(zName, zType);
if((rid>0) && pUuid){
*pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
return rid;
}
/*
** COMMAND: test-name-to-id
**
** Convert a name to a full artifact ID.
*/
void test_name_to_id(void){
|
| ︙ | ︙ | |||
401 402 403 404 405 406 407 |
rid = symbolic_name_to_rid(zName, 0);
if( rid<0 ){
fossil_print("Ambiguous artifact name prefix: %s\n", zName);
}else if( rid==0 ){
fossil_print("Unknown artifact: %s\n", zName);
}else{
Stmt q;
| > | > > > | | | | > > > > | 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 |
rid = symbolic_name_to_rid(zName, 0);
if( rid<0 ){
fossil_print("Ambiguous artifact name prefix: %s\n", zName);
}else if( rid==0 ){
fossil_print("Unknown artifact: %s\n", zName);
}else{
Stmt q;
db_prepare(&q,
"SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr,"
" (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref"
" WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
" AND tagxref.rid=blob.rid AND tagxref.tagtype>0)"
" FROM blob, rcvfrom"
" WHERE rid=%d"
" AND rcvfrom.rcvid=blob.rcvid",
rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zTagList = db_column_text(&q, 4);
if( fExtra ){
fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
fossil_print("size: %d bytes\n", db_column_int(&q,1));
fossil_print("received: %s from %s\n",
db_column_text(&q, 2),
db_column_text(&q, 3));
}else{
fossil_print("artifact: %s\n", db_column_text(&q,0));
fossil_print("size: %d bytes\n", db_column_int(&q,1));
}
if( zTagList && zTagList[0] ){
fossil_print("tags: %s\n", zTagList);
}
}
db_finalize(&q);
db_prepare(&q,
"SELECT type, datetime(mtime,'localtime'),"
" coalesce(euser,user), coalesce(ecomment,comment)"
" FROM event WHERE objid=%d", rid);
if( db_step(&q)==SQLITE_ROW ){
|
| ︙ | ︙ |
Changes to src/path.c.
| ︙ | ︙ | |||
131 132 133 134 135 136 137 |
path_reset();
path.pStart = path_new_node(iFrom, 0, 0);
if( iTo==iFrom ){
path.pEnd = path.pStart;
return path.pStart;
}
| | > > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
path_reset();
path.pStart = path_new_node(iFrom, 0, 0);
if( iTo==iFrom ){
path.pEnd = path.pStart;
return path.pStart;
}
if( oneWayOnly && directOnly ){
db_prepare(&s,
"SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim"
);
}else 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 "
|
| ︙ | ︙ |
Changes to src/printf.c.
| ︙ | ︙ | |||
820 821 822 823 824 825 826 827 828 829 830 831 832 833 | assert( toStdErr==0 || toStdErr==1 ); if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z); fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); free(zToFree); #else fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); #endif } /* ** Write output for user consumption. If g.cgiOutput is enabled, then ** send the output as part of the CGI reply. If g.cgiOutput is false, ** then write on standard output. */ | > | 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | assert( toStdErr==0 || toStdErr==1 ); if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z); fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); free(zToFree); #else fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); #endif fflush(toStdErr ? stderr : stdout); } /* ** Write output for user consumption. If g.cgiOutput is enabled, then ** send the output as part of the CGI reply. If g.cgiOutput is false, ** then write on standard output. */ |
| ︙ | ︙ |
Changes to src/rebuild.c.
| ︙ | ︙ | |||
422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
}
if( doClustering ) create_cluster();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
processCnt += incrSize;
percent_complete((processCnt*1000)/totalSize);
}
if(!g.fQuiet && ttyOutput ){
fossil_print("\n");
}
return errCnt;
}
/*
** Attempt to convert more full-text blobs into delta-blobs for
| > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
}
if( doClustering ) create_cluster();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
processCnt += incrSize;
percent_complete((processCnt*1000)/totalSize);
}
if(!g.fQuiet && ttyOutput ){
percent_complete(1000);
fossil_print("\n");
}
return errCnt;
}
/*
** Attempt to convert more full-text blobs into delta-blobs for
|
| ︙ | ︙ | |||
483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
previd = rid;
}
}
db_finalize(&q);
db_end_transaction(0);
}
/*
** COMMAND: rebuild
**
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
**
** Reconstruct the named repository database from the core
| > > > > > > > > > > > > > > > > > > > > | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
previd = rid;
}
}
db_finalize(&q);
db_end_transaction(0);
}
/* Reconstruct the private table. The private table contains the rid
** of every manifest that is tagged with "private" and every file that
** is not used by a manifest that is not private.
*/
static void reconstruct_private_table(void){
db_multi_exec(
"CREATE TEMP TABLE private_ckin(rid INTEGER PRIMARY KEY);"
"INSERT INTO private_ckin "
" SELECT rid FROM tagxref WHERE tagid=%d AND tagtype>0;"
"INSERT OR IGNORE INTO private"
" SELECT fid FROM mlink"
" EXCEPT SELECT fid FROM mlink WHERE mid NOT IN private_ckin;"
"INSERT OR IGNORE INTO private SELECT rid FROM private_ckin;"
"DROP TABLE private_ckin;", TAG_PRIVATE
);
fix_private_blob_dependencies(0);
}
/*
** COMMAND: rebuild
**
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
**
** Reconstruct the named repository database from the core
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
}
db_close(1);
db_open_repository(g.zRepositoryName);
}
db_begin_transaction();
ttyOutput = 1;
errCnt = rebuild_db(randomizeFlag, 1, doClustering);
db_multi_exec(
"REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
"REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());",
CONTENT_SCHEMA, AUX_SCHEMA
);
if( errCnt && !forceFlag ){
fossil_print(
| > | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
}
db_close(1);
db_open_repository(g.zRepositoryName);
}
db_begin_transaction();
ttyOutput = 1;
errCnt = rebuild_db(randomizeFlag, 1, doClustering);
reconstruct_private_table();
db_multi_exec(
"REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
"REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());",
CONTENT_SCHEMA, AUX_SCHEMA
);
if( errCnt && !forceFlag ){
fossil_print(
|
| ︙ | ︙ | |||
730 731 732 733 734 735 736 | ** ** By default, only passwords are removed. However, if the --verily option ** is added, then private branches, concealed email addresses, IP ** addresses of correspondents, and similar privacy-sensitive fields ** are also purged. If the --private option is used, then only private ** branches are removed and all other information is left intact. ** | | | | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | ** ** By default, only passwords are removed. However, if the --verily option ** is added, then private branches, concealed email addresses, IP ** addresses of correspondents, and similar privacy-sensitive fields ** are also purged. If the --private option is used, then only private ** branches are removed and all other information is left intact. ** ** This command permanently deletes the scrubbed information. THE EFFECTS ** OF THIS COMMAND ARE IRREVERSIBLE. USE WITH CAUTION! ** ** The user is prompted to confirm the scrub unless the --force option ** is used. ** ** Options: ** --force do not prompt for confirmation ** --private only private branches are removed from the repository |
| ︙ | ︙ | |||
769 770 771 772 773 774 775 |
if( blob_str(&ans)[0]!='y' ){
fossil_exit(1);
}
}
db_begin_transaction();
if( privateOnly || bVerily ){
bNeedRebuild = db_exists("SELECT 1 FROM private");
| < < < | < | 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 |
if( blob_str(&ans)[0]!='y' ){
fossil_exit(1);
}
}
db_begin_transaction();
if( privateOnly || bVerily ){
bNeedRebuild = db_exists("SELECT 1 FROM private");
delete_private_content();
}
if( !privateOnly ){
db_multi_exec(
"UPDATE user SET pw='';"
"DELETE FROM config WHERE name GLOB 'last-sync-*';"
"DELETE FROM config WHERE name GLOB 'peer-*';"
"DELETE FROM config WHERE name GLOB 'login-group-*';"
|
| ︙ | ︙ | |||
883 884 885 886 887 888 889 |
db_initial_setup(0, 0, 1);
fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
recon_read_dir(g.argv[3]);
fossil_print("\nBuilding the Fossil repository...\n");
rebuild_db(0, 1, 1);
| | < < < < < < < < < < < < < < | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 |
db_initial_setup(0, 0, 1);
fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
recon_read_dir(g.argv[3]);
fossil_print("\nBuilding the Fossil repository...\n");
rebuild_db(0, 1, 1);
reconstruct_private_table();
/* Skip the verify_before_commit() step on a reconstruct. Most artifacts
** will have been changed and verification therefore takes a really, really
** long time.
*/
verify_cancel();
|
| ︙ | ︙ |
Changes to src/report.c.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 | ** ** Code to generate the ticket listings */ #include "config.h" #include <time.h> #include "report.h" #include <assert.h> | < < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** Code to generate the ticket listings */ #include "config.h" #include <time.h> #include "report.h" #include <assert.h> /* Forward references to static routines */ static void report_format_hints(void); /* ** WEBPAGE: /reportlist */ |
| ︙ | ︙ | |||
1139 1140 1141 1142 1143 1144 1145 |
report_restrict_sql(&zErr1);
sqlite3_exec_readonly(g.db, zSql, output_separated_file, &count, &zErr2);
report_unrestrict_sql();
if( zFilter ){
free(zSql);
}
}
| < | 1136 1137 1138 1139 1140 1141 1142 |
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.
| ︙ | ︙ | |||
472 473 474 475 476 477 478 | @ UNIQUE(pathname,vid) @ ); @ @ -- This table holds a record of uncommitted merges in the local @ -- file tree. If a VFILE entry with id has merged with another @ -- record, there is an entry in this table with (id,merge) where @ -- merge is the RECORD table entry that the file merged against. | | > | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | @ UNIQUE(pathname,vid) @ ); @ @ -- This table holds a record of uncommitted merges in the local @ -- file tree. If a VFILE entry with id has merged with another @ -- record, there is an entry in this table with (id,merge) where @ -- merge is the RECORD table entry that the file merged against. @ -- An id of 0 here means the version record itself. When id==(-1) @ -- that is a cherrypick merge and id==(-2) is a backout merge. @ @ CREATE TABLE vmerge( @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged @ merge INTEGER, -- Merged with this record @ UNIQUE(id, merge) @ ); @ |
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
866 867 868 869 870 871 872 |
"remote_user_ok", "remote_user_ok", 0);
@ <p>When enabled, if the REMOTE_USER environment variable is set to the
@ login name of a valid user and no other login credentials are available,
@ then the REMOTE_USER is accepted as an authenticated user.
@ </p>
@
@ <hr />
| | | | | > | 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 |
"remote_user_ok", "remote_user_ok", 0);
@ <p>When enabled, if the REMOTE_USER environment variable is set to the
@ login name of a valid user and no other login credentials are available,
@ then the REMOTE_USER is accepted as an authenticated user.
@ </p>
@
@ <hr />
entry_attribute("IP address terms used in login cookie", 3,
"ip-prefix-terms", "ipt", "2");
@ <p>The number of octets of of the IP address used in the login cookie.
@ Set to zero to omit the IP address from the login cookie. A value of
@ 2 is recommended.
@ </p>
@
@ <hr />
entry_attribute("Login expiration time", 6, "cookie-expire", "cex", "8766");
@ <p>The number of hours for which a login is valid. This must be a
@ positive number. The default is 8760 hours which is approximately equal
@ to a year.</p>
|
| ︙ | ︙ | |||
948 949 950 951 952 953 954 |
const char *zPw = PD("pw", "");
const char *zNewName = PD("newname", "New Login Group");
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
| | | 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 |
const char *zPw = PD("pw", "");
const char *zNewName = PD("newname", "New Login Group");
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
file_canonical_name(g.zRepositoryName, &fullName, 0);
zSelfRepo = mprintf(blob_str(&fullName));
blob_reset(&fullName);
if( P("join")!=0 ){
login_group_join(zRepo, zLogin, zPw, zNewName, &zErrMsg);
}else if( P("leave") ){
login_group_leave(&zErrMsg);
}
|
| ︙ | ︙ |
Changes to src/shell.c.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | # include <editline/editline.h> #endif #if defined(HAVE_READLINE) && HAVE_READLINE==1 # include <readline/readline.h> # include <readline/history.h> #endif #if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1) | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | # include <editline/editline.h> #endif #if defined(HAVE_READLINE) && HAVE_READLINE==1 # include <readline/readline.h> # include <readline/history.h> #endif #if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1) # define readline(p) local_getline(p,stdin,0) # define add_history(X) # define read_history(X) # define write_history(X) # define stifle_history(X) #endif #if defined(_WIN32) || defined(WIN32) |
| ︙ | ︙ | |||
330 331 332 333 334 335 336 | ** the text in memory obtained from malloc() and returns a pointer ** to the text. NULL is returned at end of file, or if malloc() ** fails. ** ** The interface is like "readline" but no command-line editing ** is done. */ | | > | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
** fails.
**
** The interface is like "readline" but no command-line editing
** is done.
*/
static char *local_getline(char *zPrompt, FILE *in, int csvFlag){
char *zLine;
int nLine;
int n;
int inQuote = 0;
if( zPrompt && *zPrompt ){
printf("%s",zPrompt);
fflush(stdout);
}
nLine = 100;
zLine = malloc( nLine );
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 |
if( n==0 ){
free(zLine);
return 0;
}
zLine[n] = 0;
break;
}
| | > > > | | | 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 |
if( n==0 ){
free(zLine);
return 0;
}
zLine[n] = 0;
break;
}
while( zLine[n] ){
if( zLine[n]=='"' ) inQuote = !inQuote;
n++;
}
if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){
n--;
if( n>0 && zLine[n-1]=='\r' ) n--;
zLine[n] = 0;
break;
}
}
zLine = realloc( zLine, n+1 );
return zLine;
}
/*
** Retrieve a single line of input text.
**
** zPrior is a string of prior text retrieved. If not the empty
** string, then issue a continuation prompt.
*/
static char *one_input_line(const char *zPrior, FILE *in){
char *zPrompt;
char *zResult;
if( in!=0 ){
return local_getline(0, in, 0);
}
if( zPrior && zPrior[0] ){
zPrompt = continuePrompt;
}else{
zPrompt = mainPrompt;
}
zResult = readline(zPrompt);
|
| ︙ | ︙ | |||
610 611 612 613 614 615 616 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; /* ** Output a single term of CSV. Actually, p->separator is used for ** the separator, which may or may not be a comma. p->nullvalue is | | < | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
/*
** Output a single term of CSV. Actually, p->separator is used for
** the separator, which may or may not be a comma. p->nullvalue is
** the null value. Strings are quoted if necessary.
*/
static void output_csv(struct callback_data *p, const char *z, int bSep){
FILE *out = p->out;
if( z==0 ){
fprintf(out,"%s",p->nullvalue);
}else{
int i;
|
| ︙ | ︙ | |||
930 931 932 933 934 935 936 | } return zIn; } /* | | > | < | > > > > > > > > | > > > > > > > > > > | 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 |
}
return zIn;
}
/*
** Execute a query statement that will generate SQL output. Print
** the result columns, comma-separated, on a line and then add a
** semicolon terminator to the end of that line.
**
** If the number of columns is 1 and that column contains text "--"
** then write the semicolon on a separate line. That way, if a
** "--" comment occurs at the end of the statement, the comment
** won't consume the semicolon terminator.
*/
static int run_table_dump_query(
struct callback_data *p, /* Query context */
const char *zSelect, /* SELECT statement to extract content */
const char *zFirstRow /* Print before first row, if not NULL */
){
sqlite3_stmt *pSelect;
int rc;
int nResult;
int i;
const char *z;
rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
p->nErr++;
return rc;
}
rc = sqlite3_step(pSelect);
nResult = sqlite3_column_count(pSelect);
while( rc==SQLITE_ROW ){
if( zFirstRow ){
fprintf(p->out, "%s", zFirstRow);
zFirstRow = 0;
}
z = (const char*)sqlite3_column_text(pSelect, 0);
fprintf(p->out, "%s", z);
for(i=1; i<nResult; i++){
fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
}
if( z==0 ) z = "";
while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
if( z[0] ){
fprintf(p->out, "\n;\n");
}else{
fprintf(p->out, ";\n");
}
rc = sqlite3_step(pSelect);
}
rc = sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
p->nErr++;
}
|
| ︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 |
if( strcmp(zType, "table")==0 ){
sqlite3_stmt *pTableInfo = 0;
char *zSelect = 0;
char *zTableInfo = 0;
char *zTmp = 0;
int nRow = 0;
zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
zTableInfo = appendText(zTableInfo, zTable, '"');
zTableInfo = appendText(zTableInfo, ");", 0);
rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
free(zTableInfo);
if( rc!=SQLITE_OK || !pTableInfo ){
return 1;
}
zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
| > > > > > > | | | 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 |
if( strcmp(zType, "table")==0 ){
sqlite3_stmt *pTableInfo = 0;
char *zSelect = 0;
char *zTableInfo = 0;
char *zTmp = 0;
int nRow = 0;
int kk;
zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
zTableInfo = appendText(zTableInfo, zTable, '"');
zTableInfo = appendText(zTableInfo, ");", 0);
rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
free(zTableInfo);
if( rc!=SQLITE_OK || !pTableInfo ){
return 1;
}
zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
if( !isalpha(zTable[0]) ){
kk = 0;
}else{
for(kk=1; isalnum(zTable[kk]); kk++){}
}
zTmp = appendText(zTmp, zTable, zTable[kk] ? '"' : 0);
if( zTmp ){
zSelect = appendText(zSelect, zTmp, '\'');
}
zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
rc = sqlite3_step(pTableInfo);
while( rc==SQLITE_ROW ){
const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
zSelect = appendText(zSelect, "quote(", 0);
zSelect = appendText(zSelect, zText, '"');
rc = sqlite3_step(pTableInfo);
if( rc==SQLITE_ROW ){
zSelect = appendText(zSelect, "), ", 0);
}else{
zSelect = appendText(zSelect, ") ", 0);
}
nRow++;
}
rc = sqlite3_finalize(pTableInfo);
if( rc!=SQLITE_OK || nRow==0 ){
|
| ︙ | ︙ | |||
1765 1766 1767 1768 1769 1770 1771 |
fprintf(stderr, "Error: out of memory\n");
fclose(in);
sqlite3_finalize(pStmt);
return 1;
}
sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
| | | > | > > | > > > > > > > > | 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 |
fprintf(stderr, "Error: out of memory\n");
fclose(in);
sqlite3_finalize(pStmt);
return 1;
}
sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
while( (zLine = local_getline(0, in, 1))!=0 ){
char *z, c;
int inQuote = 0;
lineno++;
azCol[0] = zLine;
for(i=0, z=zLine; (c = *z)!=0; z++){
if( c=='"' ) inQuote = !inQuote;
if( c=='\n' ) lineno++;
if( !inQuote && c==p->separator[0] && strncmp(z,p->separator,nSep)==0 ){
*z = 0;
i++;
if( i<nCol ){
azCol[i] = &z[nSep];
z += nSep-1;
}
}
} /* end for */
*z = 0;
if( i+1!=nCol ){
fprintf(stderr,
"Error: %s line %d: expected %d columns of data but found %d\n",
zFile, lineno, nCol, i+1);
zCommit = "ROLLBACK";
free(zLine);
rc = 1;
break; /* from while */
}
for(i=0; i<nCol; i++){
if( azCol[i][0]=='"' ){
int k;
for(z=azCol[i], j=1, k=0; z[j]; j++){
if( z[j]=='"' ){ j++; if( z[j]==0 ) break; }
z[k++] = z[j];
}
z[k] = 0;
}
sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
}
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
free(zLine);
if( rc!=SQLITE_OK ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
|
| ︙ | ︙ | |||
2662 2663 2664 2665 2666 2667 2668 | return rc; } /* ** Show available command line options */ static const char zOptions[] = | < < < < < > > > > > > > > > > < < < < | 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 |
return rc;
}
/*
** Show available command line options
*/
static const char zOptions[] =
" -bail stop after hitting an error\n"
" -batch force batch I/O\n"
" -column set output mode to 'column'\n"
" -cmd command run \"command\" before reading stdin\n"
" -csv set output mode to 'csv'\n"
" -echo print commands before execution\n"
" -init filename read/process named file\n"
" -[no]header turn headers on or off\n"
" -help show this message\n"
" -html set output mode to HTML\n"
" -interactive force interactive I/O\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
" -multiplex enable the multiplexor VFS\n"
#endif
" -nullvalue 'text' set text string for NULL values\n"
" -separator 'x' set output field separator (|)\n"
" -stats print memory stats before each finalize\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
" -vfstrace enable tracing of all VFS calls\n"
#endif
;
static void usage(int showDetail){
fprintf(stderr,
"Usage: %s [OPTIONS] FILENAME [SQL]\n"
"FILENAME is the name of an SQLite database. A new database is created\n"
"if the file does not previously exist.\n", Argv0);
if( showDetail ){
|
| ︙ | ︙ | |||
2747 2748 2749 2750 2751 2752 2753 |
** the size of the alternative malloc heap,
** and the first command to execute.
*/
for(i=1; i<argc-1; i++){
char *z;
if( argv[i][0]!='-' ) break;
z = argv[i];
| | > | > > | | | | | | | 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 |
** the size of the alternative malloc heap,
** and the first command to execute.
*/
for(i=1; i<argc-1; i++){
char *z;
if( argv[i][0]!='-' ) break;
z = argv[i];
if( z[1]=='-' ) z++;
if( strcmp(z,"-separator")==0
|| strcmp(z,"-nullvalue")==0
|| strcmp(z,"-cmd")==0
){
i++;
}else if( strcmp(z,"-init")==0 ){
i++;
zInitFile = argv[i];
/* Need to check for batch mode here to so we can avoid printing
** informational messages (like from process_sqliterc) before
** we do the actual processing of arguments later in a second pass.
*/
}else if( strcmp(z,"-batch")==0 ){
stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
int j, c;
const char *zSize;
sqlite3_int64 szHeap;
zSize = argv[++i];
szHeap = atoi(zSize);
for(j=0; (c = zSize[j])!=0; j++){
if( c=='M' ){ szHeap *= 1000000; break; }
if( c=='K' ){ szHeap *= 1000; break; }
if( c=='G' ){ szHeap *= 1000000000; break; }
}
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
#endif
#ifdef SQLITE_ENABLE_VFSTRACE
}else if( strcmp(z,"-vfstrace")==0 ){
extern int vfstrace_register(
const char *zTraceName,
const char *zOldVfsName,
int (*xOut)(const char*,void*),
void *pOutArg,
int makeDefault
);
vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( strcmp(z,"-multiplex")==0 ){
extern int sqlite3_multiple_initialize(const char*,int);
sqlite3_multiplex_initialize(0, 1);
#endif
}else if( strcmp(z,"-vfs")==0 ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
if( pVfs ){
sqlite3_vfs_register(pVfs, 1);
}else{
fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
exit(1);
}
|
| ︙ | ︙ | |||
2879 2880 2881 2882 2883 2884 2885 |
data.mode = MODE_Column;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.separator,",",2);
}else if( strcmp(z,"-separator")==0 ){
i++;
if(i>=argc){
| | > | > | 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 |
data.mode = MODE_Column;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.separator,",",2);
}else if( strcmp(z,"-separator")==0 ){
i++;
if(i>=argc){
fprintf(stderr,"%s: Error: missing argument for option: %s\n",
Argv0, z);
fprintf(stderr,"Use -help for a list of options.\n");
return 1;
}
sqlite3_snprintf(sizeof(data.separator), data.separator,
"%.*s",(int)sizeof(data.separator)-1,argv[i]);
}else if( strcmp(z,"-nullvalue")==0 ){
i++;
if(i>=argc){
fprintf(stderr,"%s: Error: missing argument for option: %s\n",
Argv0, z);
fprintf(stderr,"Use -help for a list of options.\n");
return 1;
}
sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
"%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
}else if( strcmp(z,"-header")==0 ){
data.showHeader = 1;
|
| ︙ | ︙ | |||
2923 2924 2925 2926 2927 2928 2929 |
}else if( strcmp(z,"-vfstrace")==0 ){
i++;
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( strcmp(z,"-multiplex")==0 ){
i++;
#endif
| | > > > > > > > > > > > > > > > > > > | 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 |
}else if( strcmp(z,"-vfstrace")==0 ){
i++;
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( strcmp(z,"-multiplex")==0 ){
i++;
#endif
}else if( strcmp(z,"-help")==0 ){
usage(1);
}else if( strcmp(z,"-cmd")==0 ){
if( i==argc-1 ) break;
i++;
z = argv[i];
if( z[0]=='.' ){
rc = do_meta_command(z, &data);
if( rc && bail_on_error ) return rc;
}else{
open_db(&data);
rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
if( zErrMsg!=0 ){
fprintf(stderr,"Error: %s\n", zErrMsg);
if( bail_on_error ) return rc!=0 ? rc : 1;
}else if( rc!=0 ){
fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
if( bail_on_error ) return rc;
}
}
}else{
fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
fprintf(stderr,"Use -help for a list of options.\n");
return 1;
}
}
|
| ︙ | ︙ |
Changes to src/skins.c.
| ︙ | ︙ | |||
151 152 153 154 155 156 157 |
@ }
@
@ /* The label/value pairs on (for example) the vinfo page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
@ }
@
@ /* The label/value pairs on (for example) the vinfo page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$home/style.css?blackwhite" type="text/css"
|
| ︙ | ︙ | |||
398 399 400 401 402 403 404 |
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$home/style.css?tan" type="text/css"
|
| ︙ | ︙ | |||
678 679 680 681 682 683 684 |
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$home/style.css?black2" type="text/css"
|
| ︙ | ︙ | |||
1022 1023 1024 1025 1026 1027 1028 |
@
@ table.report tr td {
@ padding: 3px 5px;
@ }
@
@ textarea {
@ font-size: 1em;
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 887 888 889 890 891 892 893 894 895 896 897 898 899 900 |
@
@ table.report tr td {
@ padding: 3px 5px;
@ }
@
@ textarea {
@ font-size: 1em;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$home/style.css?black2" type="text/css"
|
| ︙ | ︙ |
Changes to src/sqlcmd.c.
| ︙ | ︙ | |||
73 74 75 76 77 78 79 | pOut[2] = nIn>>8 & 0xff; pOut[3] = nIn & 0xff; compress(&pOut[4], &nOut, pIn, nIn); sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free); } /* | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | pOut[2] = nIn>>8 & 0xff; pOut[3] = nIn & 0xff; compress(&pOut[4], &nOut, pIn, nIn); sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free); } /* ** Implementation of the "decompress(X)" SQL function. The argument X ** is a blob which was obtained from compress(Y). The output will be ** the value Y. */ static void sqlcmd_decompress( sqlite3_context *context, int argc, sqlite3_value **argv |
| ︙ | ︙ |
Changes to src/sqlite3.c.
1 2 | /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite | | | 1 2 3 4 5 6 7 8 9 10 | /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite ** version 3.7.11. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements ** of 5% or more are commonly seen when SQLite is compiled as a single ** translation unit. ** ** This file is all you need to compile SQLite. To use SQLite in other |
| ︙ | ︙ | |||
653 654 655 656 657 658 659 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.11" #define SQLITE_VERSION_NUMBER 3007011 #define SQLITE_SOURCE_ID "2012-03-16 00:28:11 74eadeec34c4b19cf5f8b7f648db3b7ad601a00e" /* ** 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 |
| ︙ | ︙ | |||
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 | #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | > | 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
| ︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. This capability ** is used during testing and only needs to be supported when SQLITE_TEST ** is defined. | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 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 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. This capability ** is used during testing and only needs to be supported when SQLITE_TEST ** is defined. ** <ul> ** <li>[[SQLITE_FCNTL_SIZE_HINT]] ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database ** file run faster. ** ** <li>[[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified ** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and ** improve performance on some systems. ** ** <li>[[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See the [sqlite3_file_control()] documentation for ** additional information. ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] ** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by ** SQLite and sent to all VFSes in place of a call to the xSync method ** when the database connection has [PRAGMA synchronous] set to OFF.)^ ** Some specialized VFSes need this signal in order to operate correctly ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most ** VFSes do not need this signal and should silently ignore this opcode. ** Applications should not call [sqlite3_file_control()] with this ** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. ** ** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic ** retry counts and intervals for certain disk I/O operations for the ** windows [VFS] in order to provide robustness in the presence of ** anti-virus programs. By default, the windows VFS will retry file read, ** file write, and file delete operations up to 10 times, with a delay ** of 25 milliseconds before the first retry and with the delay increasing ** by an additional 25 milliseconds with each subsequent retry. This ** opcode allows these two values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two ** integers where the first integer i the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be ** interrogated. The zDbName parameter is ignored. ** ** <li>[[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write AHead Log] setting. By default, the auxiliary ** write ahead log and shared memory files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not ** have write permission on the directory containing the database file want ** to read the database file, as the WAL and shared memory files must exist ** in order for the database to be readable. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable persistent WAL mode or 1 to enable persistent ** WAL mode. If the integer is -1, then it is overwritten with the current ** WAL persistence setting. ** ** <li>[[SQLITE_FCNTL_POWERSAFE_OVERWRITE]] ** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the ** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting ** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the ** xDeviceCharacteristics methods. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage ** mode. If the integer is -1, then it is overwritten with the current ** zero-damage mode setting. ** ** <li>[[SQLITE_FCNTL_OVERWRITE]] ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** a write transaction to indicate that, unless it is rolled back for some ** reason, the entire database file will be overwritten by the current ** transaction. This is used by VACUUM operations. ** ** <li>[[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of ** all [VFSes] in the VFS stack. The names are of all VFS shims and the ** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. ** The caller is responsible for freeing the memory when done. As with ** all file-control actions, there is no guarantee that this will actually ** do anything. Callers should initialize the char* variable to a NULL ** pointer in case this file-control is not implemented. This file-control ** is intended for diagnostic use only. ** ** <li>[[SQLITE_FCNTL_PRAGMA]] ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] ** file control is sent to the open [sqlite3_file] object corresponding ** to the database file to which the pragma statement refers. ^The argument ** to the [SQLITE_FCNTL_PRAGMA] file control is an array of ** pointers to strings (char**) in which the second element of the array ** is the name of the pragma and the third element is the argument to the ** pragma or NULL if the pragma has no argument. ^The handler for an ** [SQLITE_FCNTL_PRAGMA] file control can optionally make the first element ** of the char** argument point to a string obtained from [sqlite3_mprintf()] ** or the equivalent and that string will become the result of the pragma or ** the error message if the pragma fails. ^If the ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] ** file control returns [SQLITE_OK], then the parser assumes that the ** VFS has handled the PRAGMA itself and the parser generates a no-op ** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] ** file control occurs at the beginning of pragma statement analysis and so ** it is able to override built-in [PRAGMA] statements. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
| ︙ | ︙ | |||
3178 3179 3180 3181 3182 3183 3184 | /* ** CAPI3REF: Obtain Values For URI Parameters ** ** These are utility routines, useful to VFS implementations, that check ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** | | > > | | > > > > | > | | | > | 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 | /* ** CAPI3REF: Obtain Values For URI Parameters ** ** These are utility routines, useful to VFS implementations, that check ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** ** If F is the database filename pointer passed into the xOpen() method of ** a VFS implementation when the flags parameter to xOpen() has one or ** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and ** P is the name of the query parameter, then ** sqlite3_uri_parameter(F,P) returns the value of the P ** parameter if it exists or a NULL pointer if P does not appear as a ** query parameter on F. If P is a query parameter of F ** has no explicit value, then sqlite3_uri_parameter(F,P) returns ** a pointer to an empty string. ** ** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean ** parameter and returns true (1) or false (0) according to the value ** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the ** value of query parameter P is one of "yes", "true", or "on" in any ** case or if the value begins with a non-zero number. The ** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of ** query parameter P is one of "no", "false", or "off" in any case or ** if the value begins with a numeric zero. If P is not a query ** parameter on F or if the value of P is does not match any of the ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not ** exist. If the value of P is something other than an integer, then ** zero is returned. ** ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and ** is not a database file pathname pointer that SQLite passed into the xOpen ** VFS method, then the behavior of this routine is undefined and probably ** undesirable. */ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); /* |
| ︙ | ︙ | |||
5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 | ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. */ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Find the next prepared statement ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL ** then this interface returns a pointer to the first prepared statement ** associated with the database connection pDb. ^If no prepared statement | > > > > > > > > > | 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 | ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. */ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only ** ** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N ** of connection D is read-only, 0 if it is read/write, or -1 if N is not ** the name of a database on connection D. */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Find the next prepared statement ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL ** then this interface returns a pointer to the first prepared statement ** associated with the database connection pDb. ^If no prepared statement |
| ︙ | ︙ | |||
6756 6757 6758 6759 6760 6761 6762 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] ** handle invalid, and will not use it with any other sqlite3_pcache_methods2 ** functions. ** ** [[the xShrink() page cache method]] ** ^SQLite invokes the xShrink() method when it wants the page cache to ** free up as much of heap memory as possible. The page cache implementation | | | 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 |
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
** handle invalid, and will not use it with any other sqlite3_pcache_methods2
** functions.
**
** [[the xShrink() page cache method]]
** ^SQLite invokes the xShrink() method when it wants the page cache to
** free up as much of heap memory as possible. The page cache implementation
** is not obligated to free any memory, but well-behaved implementations should
** do their best.
*/
typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2;
struct sqlite3_pcache_methods2 {
int iVersion;
void *pArg;
int (*xInit)(void*);
|
| ︙ | ︙ | |||
7127 7128 7129 7130 7131 7132 7133 | void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** | | | | | > | 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 | void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** ** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications ** and extensions to compare the contents of two buffers containing UTF-8 ** strings in a case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ SQLITE_API int sqlite3_stricmp(const char *, const char *); SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: Error Logging Interface ** ** ^The [sqlite3_log()] interface writes a message into the error log ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. |
| ︙ | ︙ | |||
8008 8009 8010 8011 8012 8013 8014 | ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** The following value as a destructor means to use sqlite3DbFree(). | > > > > | | | 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 | ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** The following value as a destructor means to use sqlite3DbFree(). ** The sqlite3DbFree() routine requires two parameters instead of the ** one parameter that destructors normally want. So we have to introduce ** this magic value that the code knows to handle differently. Any ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. */ #define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize) /* ** When SQLITE_OMIT_WSD is defined, it means that the target platform does ** not support Writable Static Data (WSD) such as global and static variables. ** All variables must either be on the stack or dynamically allocated from ** the heap. When WSD is unsupported, the variable declarations scattered ** throughout the SQLite code must become constants instead. The SQLITE_WSD |
| ︙ | ︙ | |||
8170 8171 8172 8173 8174 8175 8176 | /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the ** following values. ** ** NOTE: These values must match the corresponding PAGER_ values in ** pager.h. */ #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ | < | | | | | 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 | /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the ** following values. ** ** NOTE: These values must match the corresponding PAGER_ values in ** pager.h. */ #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_MEMORY 2 /* This is an in-memory DB */ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int); SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*); SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags); SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree); |
| ︙ | ︙ | |||
8846 8847 8848 8849 8850 8851 8852 | /* ** 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 */ | < | | 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 | /* ** 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_MEMORY 0x0002 /* 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 |
| ︙ | ︙ | |||
8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 | SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*); SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager); /* Functions used to query pager state and configuration. */ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*); SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*); | > > > | 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 | SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*); SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager); #ifdef SQLITE_ENABLE_ZIPVFS SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager); #endif /* Functions used to query pager state and configuration. */ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*); SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*); |
| ︙ | ︙ | |||
9004 9005 9006 9007 9008 9009 9010 |
** structure.
*/
struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
PgHdr *pDirty; /* Transient list of dirty pages */
| < > | 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 |
** structure.
*/
struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
PgHdr *pDirty; /* Transient list of dirty pages */
Pager *pPager; /* The pager this page is part of */
Pgno pgno; /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
u32 pageHash; /* Hash of page content */
#endif
u16 flags; /* PGHDR flags defined below */
/**********************************************************************
** Elements above are public. All that follows is private to pcache.c
|
| ︙ | ︙ | |||
9233 9234 9235 9236 9237 9238 9239 | # define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP) #else # define SQLITE_TEMPNAME_SIZE 200 #endif /* ** Determine if we are dealing with Windows NT. | | > > > | | | | > > > > > > > > > | 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 | # define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP) #else # define SQLITE_TEMPNAME_SIZE 200 #endif /* ** Determine if we are dealing with Windows NT. ** ** We ought to be able to determine if we are compiling for win98 or winNT ** using the _WIN32_WINNT macro as follows: ** ** #if defined(_WIN32_WINNT) ** # define SQLITE_OS_WINNT 1 ** #else ** # define SQLITE_OS_WINNT 0 ** #endif ** ** However, vs2005 does not set _WIN32_WINNT by default, as it ought to, ** so the above test does not work. We'll just assume that everything is ** winNT unless the programmer explicitly says otherwise by setting ** SQLITE_OS_WINNT to 0. */ #if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) # define SQLITE_OS_WINNT 1 #endif /* ** Determine if we are dealing with WindowsCE - which has a much ** reduced API. */ #if defined(_WIN32_WCE) |
| ︙ | ︙ | |||
9635 9636 9637 9638 9639 9640 9641 |
*/
struct FuncDefHash {
FuncDef *a[23]; /* Hash table for functions */
};
/*
** Each database connection is an instance of the following structure.
| < < < < < < < < < < < < < < < < < < < < < < < | > > > > > < < < < < > < < < > > | 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 |
*/
struct FuncDefHash {
FuncDef *a[23]; /* Hash table for functions */
};
/*
** Each database connection is an instance of the following structure.
*/
struct sqlite3 {
sqlite3_vfs *pVfs; /* OS Interface */
struct Vdbe *pVdbe; /* List of active virtual machines */
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
sqlite3_mutex *mutex; /* Connection mutex */
Db *aDb; /* All backends */
int nDb; /* Number of backends currently in use */
int flags; /* Miscellaneous flags. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
u8 mallocFailed; /* True if we have seen a malloc failure */
u8 dfltLockMode; /* Default locking-mode for attached dbs */
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
u8 suppressErr; /* Do not issue error messages if true */
u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
int nTotalChange; /* Value returned by sqlite3_total_changes() */
int aLimit[SQLITE_N_LIMIT]; /* Limits */
struct sqlite3InitInfo { /* Information used during initialization */
int newTnum; /* Rootpage of table being initialized */
u8 iDb; /* Which db file is being initialized */
u8 busy; /* TRUE if currently initializing */
u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
} init;
int activeVdbeCnt; /* Number of VDBEs currently executing */
int writeVdbeCnt; /* Number of active VDBEs that are writing */
int vdbeExecCnt; /* Number of nested calls to VdbeExec() */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
void *pCommitArg; /* Argument to xCommitCallback() */
int (*xCommitCallback)(void*); /* Invoked at every commit. */
void *pRollbackArg; /* Argument to xRollbackCallback() */
|
| ︙ | ︙ | |||
9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 | #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ | > < < > < | 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 | #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE int nVTrans; /* Allocated size of aVTrans */ Hash aModule; /* populated by sqlite3_create_module() */ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif FuncDefHash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int busyTimeout; /* Busy handler timeout, in msec */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** |
| ︙ | ︙ | |||
9788 9789 9790 9791 9792 9793 9794 |
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_NullCallback 0x00002000 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */
#define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */
#define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */
| | < | 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 |
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_NullCallback 0x00002000 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */
#define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */
#define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */
/* 0x00020000 Unused */
#define SQLITE_IgnoreChecks 0x00040000 /* Do not enforce check constraints */
#define SQLITE_ReadUncommitted 0x0080000 /* For shared-cache mode */
#define SQLITE_LegacyFileFmt 0x00100000 /* Create new databases in format 1 */
#define SQLITE_FullFSync 0x00200000 /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync 0x00400000 /* Use full fsync for checkpoint */
#define SQLITE_RecoveryMode 0x00800000 /* Ignore schema errors */
#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
|
| ︙ | ︙ | |||
9878 9879 9880 9881 9882 9883 9884 | /* ** Possible values for FuncDef.flags */ #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */ | < | 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 | /* ** Possible values for FuncDef.flags */ #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */ #define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */ #define SQLITE_FUNC_COALESCE 0x40 /* Built-in coalesce() or ifnull() function */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are ** used to create the initializers for the FuncDef structures. ** |
| ︙ | ︙ | |||
10161 10162 10163 10164 10165 10166 10167 | ** Allowed values for Tabe.tabFlags. */ #define TF_Readonly 0x01 /* Read-only system table */ #define TF_Ephemeral 0x02 /* An ephemeral table */ #define TF_HasPrimaryKey 0x04 /* Table has a primary key */ #define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ #define TF_Virtual 0x10 /* Is a virtual table */ | < < | 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 | ** Allowed values for Tabe.tabFlags. */ #define TF_Readonly 0x01 /* Read-only system table */ #define TF_Ephemeral 0x02 /* An ephemeral table */ #define TF_HasPrimaryKey 0x04 /* Table has a primary key */ #define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ #define TF_Virtual 0x10 /* Is a virtual table */ /* ** Test to see whether or not a table is a virtual table. This is ** done as a macro so that it will be optimized out when virtual ** table support is omitted from the build. */ |
| ︙ | ︙ | |||
10324 10325 10326 10327 10328 10329 10330 |
** it means this is not a unique index. Otherwise it is a unique index
** and the value of Index.onError indicate the which conflict resolution
** algorithm to employ whenever an attempt is made to insert a non-unique
** element.
*/
struct Index {
char *zName; /* Name of this index */
| < < < < < > > > > > | 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 |
** it means this is not a unique index. Otherwise it is a unique index
** and the value of Index.onError indicate the which conflict resolution
** algorithm to employ whenever an attempt is made to insert a non-unique
** element.
*/
struct Index {
char *zName; /* Name of this index */
int *aiColumn; /* Which columns are used by this index. 1st is 0 */
tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
Table *pTable; /* The SQL table being indexed */
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 */
int nColumn; /* Number of columns in the table used by this index */
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 */
#ifdef SQLITE_ENABLE_STAT3
int nSample; /* Number of elements in aSample[] */
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
#endif
};
|
| ︙ | ︙ | |||
10395 10396 10397 10398 10399 10400 10401 |
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 */
| < > < < | 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 |
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 */
int nSortingColumn; /* Number of columns in the sorting index */
ExprList *pGroupBy; /* The group by clause */
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 */
int iMem; /* Memory location that acts as accumulator */
Expr *pExpr; /* The original expression */
} *aCol;
int nColumn; /* Number of used entries in aCol[] */
int nAccumulator; /* Number of columns that show through to the output.
** Additional columns are used only as parameters to
** aggregate functions */
struct AggInfo_func { /* For each aggregate function */
Expr *pExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
};
/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit. 16-bit is preferred because
** it uses less memory in the Expr object, which is a big memory user
|
| ︙ | ︙ | |||
10614 10615 10616 10617 10618 10619 10620 |
** as the list of "expr AS ID" fields following a "SELECT" or in the
** list of "ID = expr" items in an UPDATE. A list of expressions can
** also be used as the argument to a function, in which case the a.zName
** field is not used.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
| < | | | 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 |
** as the list of "expr AS ID" fields following a "SELECT" or in the
** list of "ID = expr" items in an UPDATE. A list of expressions can
** also be used as the argument to a function, in which case the a.zName
** field is not used.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
int iECursor; /* VDBE Cursor associated with this ExprList */
struct ExprList_item { /* For each expression in the list */
Expr *pExpr; /* The list of expressions */
char *zName; /* Token associated with this expression */
char *zSpan; /* Original text of the expression */
u8 sortOrder; /* 1 for DESC or 0 for ASC */
u8 done; /* A flag to indicate when processing is finished */
u16 iOrderByCol; /* For ORDER BY, column number in result set */
u16 iAlias; /* Index into Parse.aAlias[] for zName */
} *a; /* Alloc a power of two greater or equal to nExpr */
};
/*
** An instance of this structure is used by the parser to record both
** the parse tree for an expression and the span of input text for an
** expression.
*/
|
| ︙ | ︙ | |||
10659 10660 10661 10662 10663 10664 10665 |
*/
struct IdList {
struct IdList_item {
char *zName; /* Name of the identifier */
int idx; /* Index in some Table.aCol[] of a column named zName */
} *a;
int nId; /* Number of identifiers on the list */
| < | 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 |
*/
struct IdList {
struct IdList_item {
char *zName; /* Name of the identifier */
int idx; /* Index in some Table.aCol[] of a column named zName */
} *a;
int nId; /* Number of identifiers on the list */
};
/*
** The bitmask datatype defined below is used for various optimizations.
**
** Changing this from a 64-bit to a 32-bit type limits the number of
** tables in a join to 32 instead of 64. But it also reduces the size
|
| ︙ | ︙ | |||
10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 |
** sequences for the ORDER BY clause.
*/
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
char affinity; /* MakeRecord with this affinity for SRT_Set */
u16 selFlags; /* Various SF_* values */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */
Select *pPrior; /* Prior select in a compound select statement */
Select *pNext; /* Next select to the left in a compound */
Select *pRightmost; /* Right-most select in a compound select statement */
Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */
| > > > < < < > | 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 |
** sequences for the ORDER BY clause.
*/
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
char affinity; /* MakeRecord with this affinity for SRT_Set */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
double nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */
Select *pPrior; /* Prior select in a compound select statement */
Select *pNext; /* Next select to the left in a compound */
Select *pRightmost; /* Right-most select in a compound select statement */
Expr *pLimit; /* LIMIT expression. NULL means not used. */
Expr *pOffset; /* OFFSET expression. NULL means not used. */
};
/*
** Allowed values for Select.selFlags. The "SF" prefix stands for
** "Select Flag".
*/
#define SF_Distinct 0x01 /* Output should be DISTINCT */
#define SF_Resolved 0x02 /* Identifiers have been resolved */
#define SF_Aggregate 0x04 /* Contains aggregate functions */
#define SF_UsesEphemeral 0x08 /* Uses the OpenEphemeral opcode */
#define SF_Expanded 0x10 /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo 0x20 /* FROM subqueries have Table metadata */
#define SF_UseSorter 0x40 /* Sort using a sorter */
#define SF_Values 0x80 /* Synthesized from VALUES clause */
/*
** 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 */
|
| ︙ | ︙ | |||
11006 11007 11008 11009 11010 11011 11012 |
** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
** accessed (or set to 0 for triggers fired as a result of INSERT
** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
** a mask of new.* columns used by the program.
*/
struct TriggerPrg {
Trigger *pTrigger; /* Trigger this program was coded from */
| | > < | 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 |
** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
** accessed (or set to 0 for triggers fired as a result of INSERT
** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
** a mask of new.* columns used by the program.
*/
struct TriggerPrg {
Trigger *pTrigger; /* Trigger this program was coded from */
TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
SubProgram *pProgram; /* Program implementing pTrigger/orconf */
int orconf; /* Default ON CONFLICT policy */
u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */
};
/*
** The yDbMask datatype for the bitmask of all attached databases.
*/
#if SQLITE_MAX_ATTACHED>30
typedef sqlite3_uint64 yDbMask;
|
| ︙ | ︙ | |||
11039 11040 11041 11042 11043 11044 11045 |
** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
** used to store the set of table-locks required by the statement being
** compiled. Function sqlite3TableLock() is used to add entries to the
** list.
*/
struct Parse {
sqlite3 *db; /* The main database structure */
| < > > > > > < < < < > > > < < < > < | | > > > > > > > > > > > | | < | < < < | | > > | < < | < | | < < < < < > > > | 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 |
** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
** used to store the set of table-locks required by the statement being
** compiled. Function sqlite3TableLock() is used to add entries to the
** list.
*/
struct Parse {
sqlite3 *db; /* The main database structure */
char *zErrMsg; /* An error message */
Vdbe *pVdbe; /* An engine for executing database bytecode */
int rc; /* Return code from execution */
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
u8 nTempInUse; /* Number of aTempReg[] currently checked out */
u8 nColCache; /* Number of entries in aColCache[] */
u8 iColCache; /* Next entry in aColCache[] to replace */
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
u8 mayAbort; /* True if statement may throw an ABORT exception */
int aTempReg[8]; /* Holding area for temporary registers */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets used so far */
int nOnce; /* Number of OP_Once instructions so far */
int ckBase; /* Base register of data during check constraints */
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
struct yColCache {
int iTable; /* Table cursor number */
int iColumn; /* Table column number */
u8 tempReg; /* iReg is a temp register that needs to be freed */
int iLevel; /* Nesting level */
int iReg; /* Reg with value of this column. 0 means none. */
int lru; /* Least recently used entry has the smallest value */
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
/* Information used while coding trigger programs. */
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
double nQueryLoop; /* Estimated number of iterations of a query */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
u8 disableTriggers; /* True to disable triggers */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
int nVar; /* Number of '?' variables seen in the SQL so far */
int nzVar; /* Number of available slots in azVar[] */
u8 explain; /* True if the EXPLAIN flag is found on the query */
#ifndef SQLITE_OMIT_VIRTUALTABLE
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
int nVtabLock; /* Number of virtual tables to lock */
#endif
int nAlias; /* Number of aliased result set columns */
int nHeight; /* Expression tree height of current sub-select */
#ifndef SQLITE_OMIT_EXPLAIN
int iSelectId; /* ID of current select for EXPLAIN output */
int iNextSelectId; /* Next available select ID for EXPLAIN output */
#endif
char **azVar; /* Pointers to names of parameters */
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
int *aAlias; /* Register used to hold aliased result */
const char *zTail; /* All SQL text past the last semicolon parsed */
Table *pNewTable; /* A table being constructed by CREATE TABLE */
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
Token sNameToken; /* Token with unqualified schema object name */
Token sLastToken; /* The last token parsed */
#ifndef SQLITE_OMIT_VIRTUALTABLE
Token sArg; /* Complete text of a module argument */
Table **apVtabLock; /* Pointer to virtual tables needing locking */
#endif
Table *pZombieTab; /* List of Table objects to delete after code gen */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
};
/*
** Return true if currently inside an sqlite3_declare_vtab() call.
*/
#ifdef SQLITE_OMIT_VIRTUALTABLE
#define IN_DECLARE_VTAB 0
#else
#define IN_DECLARE_VTAB (pParse->declareVtab)
#endif
/*
|
| ︙ | ︙ | |||
11275 11276 11277 11278 11279 11280 11281 |
/*
** A pointer to this structure is used to communicate information
** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
*/
typedef struct {
sqlite3 *db; /* The database being initialized */
| < > | 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 |
/*
** A pointer to this structure is used to communicate information
** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
*/
typedef struct {
sqlite3 *db; /* The database being initialized */
char **pzErrMsg; /* Error message stored here */
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
int rc; /* Result code stored here */
} InitData;
/*
** Structure containing global configuration data for the SQLite library.
**
** This structure also contains some state information.
|
| ︙ | ︙ | |||
11418 11419 11420 11421 11422 11423 11424 | # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) #endif /* ** Internal function prototypes */ | | | 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 | # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) #endif /* ** Internal function prototypes */ #define sqlite3StrICmp sqlite3_stricmp SQLITE_PRIVATE int sqlite3Strlen30(const char*); #define sqlite3StrNICmp sqlite3_strnicmp SQLITE_PRIVATE int sqlite3MallocInit(void); SQLITE_PRIVATE void sqlite3MallocEnd(void); SQLITE_PRIVATE void *sqlite3Malloc(int); SQLITE_PRIVATE void *sqlite3MallocZero(int); |
| ︙ | ︙ | |||
11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 |
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*);
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
sqlite3_vfs**,char**,char **);
SQLITE_PRIVATE int sqlite3CodeOnce(Parse *);
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32);
SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32);
SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32);
SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*);
SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*);
| > | 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 |
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*);
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
sqlite3_vfs**,char**,char **);
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
SQLITE_PRIVATE int sqlite3CodeOnce(Parse *);
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32);
SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32);
SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32);
SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*);
SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*);
|
| ︙ | ︙ | |||
11601 11602 11603 11604 11605 11606 11607 | SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int); | | | 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 |
SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse);
SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse);
#else
# define sqlite3AutoincrementBegin(X)
# define sqlite3AutoincrementEnd(X)
#endif
SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int);
SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*);
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, Expr*, IdList*);
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
|
| ︙ | ︙ | |||
11665 11666 11667 11668 11669 11670 11671 | SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); SQLITE_PRIVATE void sqlite3PrngSaveState(void); SQLITE_PRIVATE void sqlite3PrngRestoreState(void); SQLITE_PRIVATE void sqlite3PrngResetState(void); | | | 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 | SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); SQLITE_PRIVATE void sqlite3PrngSaveState(void); SQLITE_PRIVATE void sqlite3PrngRestoreState(void); SQLITE_PRIVATE void sqlite3PrngResetState(void); SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); |
| ︙ | ︙ | |||
11839 11840 11841 11842 11843 11844 11845 | SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); SQLITE_PRIVATE int sqlite3AbsInt32(int); #ifdef SQLITE_ENABLE_8_3_NAMES SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif | | | 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897 |
SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
SQLITE_PRIVATE int sqlite3AbsInt32(int);
#ifdef SQLITE_ENABLE_8_3_NAMES
SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
#else
# define sqlite3FileSuffix3(X,Y)
#endif
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,int);
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 *);
|
| ︙ | ︙ | |||
11965 11966 11967 11968 11969 11970 11971 | SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); | | | 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018 12019 12020 12021 12022 12023 | SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); SQLITE_PRIVATE void sqlite3VtabArgInit(Parse*); SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse*, Token*); SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*); SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *); |
| ︙ | ︙ | |||
12894 12895 12896 12897 12898 12899 12900 |
**
** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
** set to NULL if the currently executing frame is the main program.
*/
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
| | < < < > > > | > > < < | 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 12962 12963 12964 12965 12966 |
**
** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
** set to NULL if the currently executing frame is the main program.
*/
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
u16 nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
int nMem; /* Number of entries in aMem */
int nOnceFlag; /* Number of entries in aOnceFlag */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
int nChange; /* Statement changes (Vdbe.nChanges) */
};
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
/*
** A value for VdbeCursor.cacheValid that means the cache is always invalid.
*/
|
| ︙ | ︙ | |||
13035 13036 13037 13038 13039 13040 13041 13042 |
** (Mem) which are only defined there.
*/
struct sqlite3_context {
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
Mem s; /* The return value is stored here */
Mem *pMem; /* Memory cell used to store aggregate context */
int isError; /* Error code returned by the function. */
| > | | 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 |
** (Mem) which are only defined there.
*/
struct sqlite3_context {
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
Mem s; /* The return value is stored here */
Mem *pMem; /* Memory cell used to store aggregate context */
CollSeq *pColl; /* Collating sequence */
int isError; /* Error code returned by the function. */
int skipFlag; /* Skip skip accumulator loading if true */
};
/*
** An Explain object accumulates indented output which is helpful
** in describing recursive data structures.
*/
struct Explain {
|
| ︙ | ︙ | |||
13077 13078 13079 13080 13081 13082 13083 | Mem **apArg; /* Arguments to currently executing user function */ Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ int nMem; /* Number of memory locations currently allocated */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Number of slots allocated for aOp[] */ int nLabel; /* Number of labels used */ | < | 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 | Mem **apArg; /* Arguments to currently executing user function */ Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ int nMem; /* Number of memory locations currently allocated */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Number of slots allocated for aOp[] */ int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ u16 nResColumn; /* Number of columns in one row of the result set */ u16 nCursor; /* Number of slots in apCsr[] */ u32 magic; /* Magic number for sanity checking */ char *zErrMsg; /* Error message written here */ Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ |
| ︙ | ︙ | |||
15144 15145 15146 15147 15148 15149 15150 | ************************************************************************* ** ** This file contains low-level memory allocation drivers for when ** SQLite will use the standard C-library malloc/realloc/free interface ** to obtain the memory it needs. ** ** This file contains implementations of the low-level memory allocation | | > > > > > > > > > > > > > > > > > > > > > > > > | > > | | < | | > | > > > > > < > | > | | 15188 15189 15190 15191 15192 15193 15194 15195 15196 15197 15198 15199 15200 15201 15202 15203 15204 15205 15206 15207 15208 15209 15210 15211 15212 15213 15214 15215 15216 15217 15218 15219 15220 15221 15222 15223 15224 15225 15226 15227 15228 15229 15230 15231 15232 15233 15234 15235 15236 15237 15238 15239 15240 15241 15242 15243 15244 15245 15246 15247 15248 15249 15250 15251 15252 15253 15254 15255 15256 15257 15258 15259 15260 15261 15262 15263 15264 15265 15266 15267 15268 15269 15270 15271 15272 15273 15274 15275 15276 15277 15278 15279 15280 |
*************************************************************************
**
** This file contains low-level memory allocation drivers for when
** SQLite will use the standard C-library malloc/realloc/free interface
** to obtain the memory it needs.
**
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object. The content of
** this file is only used if SQLITE_SYSTEM_MALLOC is defined. The
** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the
** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined. The
** default configuration is to use memory allocation routines in this
** file.
**
** C-preprocessor macro summary:
**
** HAVE_MALLOC_USABLE_SIZE The configure script sets this symbol if
** the malloc_usable_size() interface exists
** on the target platform. Or, this symbol
** can be set manually, if desired.
** If an equivalent interface exists by
** a different name, using a separate -D
** option to rename it.
**
** SQLITE_WITHOUT_ZONEMALLOC Some older macs lack support for the zone
** memory allocator. Set this symbol to enable
** building on older macs.
**
** SQLITE_WITHOUT_MSIZE Set this symbol to disable the use of
** _msize() on windows systems. This might
** be necessary when compiling for Delphi,
** for example.
*/
/*
** This version of the memory allocator is the default. It is
** used when no other memory allocator is specified using compile-time
** macros.
*/
#ifdef SQLITE_SYSTEM_MALLOC
/*
** The MSVCRT has malloc_usable_size() but it is called _msize().
** The use of _msize() is automatic, but can be disabled by compiling
** with -DSQLITE_WITHOUT_MSIZE
*/
#if defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)
# define SQLITE_MALLOCSIZE _msize
#endif
#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
/*
** Use the zone allocator available on apple products unless the
** SQLITE_WITHOUT_ZONEMALLOC symbol is defined.
*/
#include <sys/sysctl.h>
#include <malloc/malloc.h>
#include <libkern/OSAtomic.h>
static malloc_zone_t* _sqliteZone_;
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
#define SQLITE_MALLOCSIZE(x) \
(_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))
#else /* if not __APPLE__ */
/*
** Use standard C library malloc and free on non-Apple systems.
** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined.
*/
#define SQLITE_MALLOC(x) malloc(x)
#define SQLITE_FREE(x) free(x)
#define SQLITE_REALLOC(x,y) realloc((x),(y))
#if (defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)) \
|| (defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE))
# include <malloc.h> /* Needed for malloc_usable_size on linux */
#endif
#ifdef HAVE_MALLOC_USABLE_SIZE
# ifndef SQLITE_MALLOCSIZE
# define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)
# endif
#else
# undef SQLITE_MALLOCSIZE
#endif
#endif /* __APPLE__ or not __APPLE__ */
/*
** Like malloc(), but remember the size of the allocation
** so that we can find it later using sqlite3MemSize().
|
| ︙ | ︙ | |||
15312 15313 15314 15315 15316 15317 15318 |
return ROUND8(n);
}
/*
** Initialize this module.
*/
static int sqlite3MemInit(void *NotUsed){
| | | 15388 15389 15390 15391 15392 15393 15394 15395 15396 15397 15398 15399 15400 15401 15402 |
return ROUND8(n);
}
/*
** Initialize this module.
*/
static int sqlite3MemInit(void *NotUsed){
#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC)
int cpuCount;
size_t len;
if( _sqliteZone_ ){
return SQLITE_OK;
}
len = sizeof(cpuCount);
/* One usually wants to use hw.acctivecpu for MT decisions, but not here */
|
| ︙ | ︙ | |||
21187 21188 21189 21190 21191 21192 21193 | ** ** IMPLEMENTATION-OF: R-20522-24639 The sqlite3_strnicmp() API allows ** applications and extensions to compare the contents of two buffers ** containing UTF-8 strings in a case-independent fashion, using the same ** definition of case independence that SQLite uses internally when ** comparing identifiers. */ | | | 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 21273 21274 21275 21276 21277 |
**
** IMPLEMENTATION-OF: R-20522-24639 The sqlite3_strnicmp() API allows
** applications and extensions to compare the contents of two buffers
** containing UTF-8 strings in a case-independent fashion, using the same
** definition of case independence that SQLite uses internally when
** comparing identifiers.
*/
SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
register unsigned char *a, *b;
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
return UpperToLower[*a] - UpperToLower[*b];
}
SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
|
| ︙ | ︙ | |||
24938 24939 24940 24941 24942 24943 24944 |
typedef struct unixFile unixFile;
struct unixFile {
sqlite3_io_methods const *pMethod; /* Always the first entry */
sqlite3_vfs *pVfs; /* The VFS that created this unixFile */
unixInodeInfo *pInode; /* Info about locks on this inode */
int h; /* The file descriptor */
unsigned char eFileLock; /* The type of lock held on this fd */
| | | 25014 25015 25016 25017 25018 25019 25020 25021 25022 25023 25024 25025 25026 25027 25028 |
typedef struct unixFile unixFile;
struct unixFile {
sqlite3_io_methods const *pMethod; /* Always the first entry */
sqlite3_vfs *pVfs; /* The VFS that created this unixFile */
unixInodeInfo *pInode; /* Info about locks on this inode */
int h; /* The file descriptor */
unsigned char eFileLock; /* The type of lock held on this fd */
unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
#if SQLITE_ENABLE_LOCKING_STYLE
|
| ︙ | ︙ | |||
24989 24990 24991 24992 24993 24994 24995 24996 24997 24998 24999 25000 25001 25002 | #else # define UNIXFILE_DIRSYNC 0x00 #endif #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ #define UNIXFILE_DELETE 0x20 /* Delete on close */ #define UNIXFILE_URI 0x40 /* Filename might have query parameters */ #define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ /* ** 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 ***************************************/ /* | > | 25065 25066 25067 25068 25069 25070 25071 25072 25073 25074 25075 25076 25077 25078 25079 | #else # define UNIXFILE_DIRSYNC 0x00 #endif #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ #define UNIXFILE_DELETE 0x20 /* Delete on close */ #define UNIXFILE_URI 0x40 /* Filename might have query parameters */ #define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ #define UNIXFILE_CHOWN 0x100 /* File ownership was changed */ /* ** 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 ***************************************/ /* |
| ︙ | ︙ | |||
25353 25354 25355 25356 25357 25358 25359 25360 25361 25362 25363 25364 25365 25366 |
{ "mkdir", (sqlite3_syscall_ptr)mkdir, 0 },
#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
{ "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes. Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
| > > > > > > | 25430 25431 25432 25433 25434 25435 25436 25437 25438 25439 25440 25441 25442 25443 25444 25445 25446 25447 25448 25449 |
{ "mkdir", (sqlite3_syscall_ptr)mkdir, 0 },
#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)
{ "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
{ "fchown", (sqlite3_syscall_ptr)fchown, 0 },
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
{ "umask", (sqlite3_syscall_ptr)umask, 0 },
#define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes. Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
|
| ︙ | ︙ | |||
25439 25440 25441 25442 25443 25444 25445 |
for(i++; i<ArraySize(aSyscall); i++){
if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
}
return 0;
}
/*
| > | > > > > > > > > > > > > > | > > > > > > > > | > > > | 25522 25523 25524 25525 25526 25527 25528 25529 25530 25531 25532 25533 25534 25535 25536 25537 25538 25539 25540 25541 25542 25543 25544 25545 25546 25547 25548 25549 25550 25551 25552 25553 25554 25555 25556 25557 25558 25559 25560 25561 25562 25563 25564 25565 |
for(i++; i<ArraySize(aSyscall); i++){
if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
}
return 0;
}
/*
** Invoke open(). Do so multiple times, until it either succeeds or
** files for some reason other than EINTR.
**
** If the file creation mode "m" is 0 then set it to the default for
** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
** 0644) as modified by the system umask. If m is not 0, then
** make the file creation mode be exactly m ignoring the umask.
**
** The m parameter will be non-zero only when creating -wal, -journal,
** and -shm files. We want those files to have *exactly* the same
** permissions as their original database, unadulterated by the umask.
** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
** transaction crashes and leaves behind hot journals, then any
** process that is able to write to the database will also be able to
** recover the hot journals.
*/
static int robust_open(const char *z, int f, mode_t m){
int rc;
mode_t m2;
mode_t origM = 0;
if( m==0 ){
m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
}else{
m2 = m;
origM = osUmask(0);
}
do{ rc = osOpen(z,f,m2); }while( rc<0 && errno==EINTR );
if( m ){
osUmask(origM);
}
return rc;
}
/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect the unixInodeInfo and
** vxworksFileId objects used by this file, all of which may be
|
| ︙ | ︙ | |||
28791 28792 28793 28794 28795 28796 28797 |
pInode = pDbFd->pInode;
pShmNode = pInode->pShmNode;
if( pShmNode==0 ){
struct stat sStat; /* fstat() info for database file */
/* Call fstat() to figure out the permissions on the database file. If
** a new *-shm file is created, an attempt will be made to create it
| | < | 28899 28900 28901 28902 28903 28904 28905 28906 28907 28908 28909 28910 28911 28912 28913 |
pInode = pDbFd->pInode;
pShmNode = pInode->pShmNode;
if( pShmNode==0 ){
struct stat sStat; /* fstat() info for database file */
/* Call fstat() to figure out the permissions on the database file. If
** a new *-shm file is created, an attempt will be made to create it
** with the same permissions.
*/
if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
rc = SQLITE_IOERR_FSTAT;
goto shm_open_err;
}
#ifdef SQLITE_SHM_DIRECTORY
|
| ︙ | ︙ | |||
28836 28837 28838 28839 28840 28841 28842 |
int openFlags = O_RDWR | O_CREAT;
if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
openFlags = O_RDONLY;
pShmNode->isReadonly = 1;
}
pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
if( pShmNode->h<0 ){
| < | | | > > > > > > > > > > | 28943 28944 28945 28946 28947 28948 28949 28950 28951 28952 28953 28954 28955 28956 28957 28958 28959 28960 28961 28962 28963 28964 28965 28966 28967 28968 28969 |
int openFlags = O_RDWR | O_CREAT;
if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
openFlags = O_RDONLY;
pShmNode->isReadonly = 1;
}
pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
if( pShmNode->h<0 ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
goto shm_open_err;
}
/* If this process is running as root, make sure that the SHM file
** is owned by the same user that owns the original database. Otherwise,
** the original owner will not be able to connect. If this process is
** not root, the following fchown() will fail, but we don't care. The
** if(){..} and the UNIXFILE_CHOWN flag are purely to silence compiler
** warnings.
*/
if( osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid)==0 ){
pDbFd->ctrlFlags |= UNIXFILE_CHOWN;
}
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
*/
rc = SQLITE_OK;
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
|
| ︙ | ︙ | |||
29814 29815 29816 29817 29818 29819 29820 | /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. ** | | | < | < | | > > | > > | 29930 29931 29932 29933 29934 29935 29936 29937 29938 29939 29940 29941 29942 29943 29944 29945 29946 29947 29948 29949 29950 29951 29952 29953 29954 29955 29956 29957 29958 29959 29960 29961 29962 29963 29964 29965 29966 29967 29968 |
/*
** This function is called by unixOpen() to determine the unix permissions
** to create new files with. If no error occurs, then SQLITE_OK is returned
** and a value suitable for passing as the third argument to open(2) is
** written to *pMode. If an IO error occurs, an SQLite error code is
** returned and the value of *pMode is not modified.
**
** In most cases cases, this routine sets *pMode to 0, which will become
** an indication to robust_open() to create the file using
** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
** But if the file being opened is a WAL or regular journal file, then
** this function queries the file-system for the permissions on the
** corresponding database file and sets *pMode to this value. Whenever
** possible, WAL and journal files are created using the same permissions
** as the associated database file.
**
** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
** original filename is unavailable. But 8_3_NAMES is only used for
** FAT filesystems and permissions do not matter there, so just use
** the default permissions.
*/
static int findCreateFileMode(
const char *zPath, /* Path of file (possibly) being created */
int flags, /* Flags passed as 4th argument to xOpen() */
mode_t *pMode, /* OUT: Permissions to open file with */
uid_t *pUid, /* OUT: uid to set on the file */
gid_t *pGid /* OUT: gid to set on the file */
){
int rc = SQLITE_OK; /* Return Code */
*pMode = 0;
*pUid = 0;
*pGid = 0;
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
char zDb[MAX_PATHNAME+1]; /* Database file path */
int nDb; /* Number of valid bytes in zDb */
struct stat sStat; /* Output of stat() on database file */
/* zPath is a path to a WAL or journal file. The following block derives
** the path to the associated database file from zPath. This block handles
|
| ︙ | ︙ | |||
29870 29871 29872 29873 29874 29875 29876 29877 29878 29879 29880 29881 29882 29883 |
}
#endif
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
if( 0==osStat(zDb, &sStat) ){
*pMode = sStat.st_mode & 0777;
}else{
rc = SQLITE_IOERR_FSTAT;
}
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
*pMode = 0600;
}
return rc;
| > > | 29988 29989 29990 29991 29992 29993 29994 29995 29996 29997 29998 29999 30000 30001 30002 30003 |
}
#endif
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
if( 0==osStat(zDb, &sStat) ){
*pMode = sStat.st_mode & 0777;
*pUid = sStat.st_uid;
*pGid = sStat.st_gid;
}else{
rc = SQLITE_IOERR_FSTAT;
}
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
*pMode = 0600;
}
return rc;
|
| ︙ | ︙ | |||
30016 30017 30018 30019 30020 30021 30022 |
if( isReadWrite ) openFlags |= O_RDWR;
if( isCreate ) openFlags |= O_CREAT;
if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
openFlags |= (O_LARGEFILE|O_BINARY);
if( fd<0 ){
mode_t openMode; /* Permissions to create file with */
| > > | > > > > > > > > > > > | 30136 30137 30138 30139 30140 30141 30142 30143 30144 30145 30146 30147 30148 30149 30150 30151 30152 30153 30154 30155 30156 30157 30158 30159 30160 30161 30162 30163 30164 30165 30166 30167 30168 30169 30170 30171 30172 30173 30174 30175 30176 30177 30178 30179 30180 30181 30182 30183 |
if( isReadWrite ) openFlags |= O_RDWR;
if( isCreate ) openFlags |= O_CREAT;
if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
openFlags |= (O_LARGEFILE|O_BINARY);
if( fd<0 ){
mode_t openMode; /* Permissions to create file with */
uid_t uid; /* Userid for the file */
gid_t gid; /* Groupid for the file */
rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
if( rc!=SQLITE_OK ){
assert( !p->pUnused );
assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
return rc;
}
fd = robust_open(zName, openFlags, openMode);
OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
/* Failed to open the file for read/write access. Try read-only. */
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
openFlags &= ~(O_RDWR|O_CREAT);
flags |= SQLITE_OPEN_READONLY;
openFlags |= O_RDONLY;
isReadonly = 1;
fd = robust_open(zName, openFlags, openMode);
}
if( fd<0 ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
goto open_finished;
}
/* If this process is running as root and if creating a new rollback
** journal or WAL file, set the ownership of the journal or WAL to be
** the same as the original database. If we are not running as root,
** then the fchown() call will fail, but that's ok. The "if(){}" and
** the setting of the UNIXFILE_CHOWN flag are purely to silence compiler
** warnings from gcc.
*/
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
if( osFchown(fd, uid, gid)==0 ){ p->ctrlFlags |= UNIXFILE_CHOWN; }
}
}
assert( fd>=0 );
if( pOutFlags ){
*pOutFlags = flags;
}
if( p->pUnused ){
|
| ︙ | ︙ | |||
30348 30349 30350 30351 30352 30353 30354 |
** When testing, initializing zBuf[] to zero is all we do. That means
** that we always use the same random number sequence. This makes the
** tests repeatable.
*/
memset(zBuf, 0, nBuf);
#if !defined(SQLITE_TEST)
{
| | | | 30481 30482 30483 30484 30485 30486 30487 30488 30489 30490 30491 30492 30493 30494 30495 30496 30497 30498 30499 30500 30501 30502 30503 30504 30505 30506 |
** When testing, initializing zBuf[] to zero is all we do. That means
** that we always use the same random number sequence. This makes the
** tests repeatable.
*/
memset(zBuf, 0, nBuf);
#if !defined(SQLITE_TEST)
{
int pid, fd, got;
fd = robust_open("/dev/urandom", O_RDONLY, 0);
if( fd<0 ){
time_t t;
time(&t);
memcpy(zBuf, &t, sizeof(t));
pid = getpid();
memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
nBuf = sizeof(t) + sizeof(pid);
}else{
do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR );
robust_close(0, fd, __LINE__);
}
}
#endif
return nBuf;
}
|
| ︙ | ︙ | |||
30763 30764 30765 30766 30767 30768 30769 |
}else{
pUnused = sqlite3_malloc(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM;
}
}
if( fd<0 ){
| | | | | 30896 30897 30898 30899 30900 30901 30902 30903 30904 30905 30906 30907 30908 30909 30910 30911 30912 30913 30914 30915 30916 30917 30918 30919 30920 |
}else{
pUnused = sqlite3_malloc(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM;
}
}
if( fd<0 ){
fd = robust_open(path, openFlags, 0);
terrno = errno;
if( fd<0 && errno==ENOENT && islockfile ){
if( proxyCreateLockPath(path) == SQLITE_OK ){
fd = robust_open(path, openFlags, 0);
}
}
}
if( fd<0 ){
openFlags = O_RDONLY;
fd = robust_open(path, openFlags, 0);
terrno = errno;
}
if( fd<0 ){
if( islockfile ){
return SQLITE_BUSY;
}
switch (terrno) {
|
| ︙ | ︙ | |||
30897 30898 30899 30900 30901 30902 30903 |
/* read the conch content */
readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
if( readLen<PROXY_PATHINDEX ){
sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
goto end_breaklock;
}
/* write it out to the temporary break file */
| | < | 31030 31031 31032 31033 31034 31035 31036 31037 31038 31039 31040 31041 31042 31043 31044 |
/* read the conch content */
readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
if( readLen<PROXY_PATHINDEX ){
sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
goto end_breaklock;
}
/* write it out to the temporary break file */
fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0);
if( fd<0 ){
sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
goto end_breaklock;
}
if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
goto end_breaklock;
|
| ︙ | ︙ | |||
31175 31176 31177 31178 31179 31180 31181 |
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;
| | < | 31307 31308 31309 31310 31311 31312 31313 31314 31315 31316 31317 31318 31319 31320 31321 |
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, 0);
OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
if( fd>=0 ){
pFile->h = fd;
}else{
rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called
during locking */
}
|
| ︙ | ︙ | |||
31745 31746 31747 31748 31749 31750 31751 |
UNIXVFS("unix-proxy", proxyIoFinder ),
#endif
};
unsigned int i; /* Loop counter */
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
| | | 31876 31877 31878 31879 31880 31881 31882 31883 31884 31885 31886 31887 31888 31889 31890 |
UNIXVFS("unix-proxy", proxyIoFinder ),
#endif
};
unsigned int i; /* Loop counter */
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==22 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
sqlite3_vfs_register(&aVfs[i], i==0);
}
return SQLITE_OK;
}
|
| ︙ | ︙ | |||
36784 36785 36786 36787 36788 36789 36790 36791 36792 36793 36794 36795 36796 36797 36798 | PGroup *pGroup; /* PGroup this cache belongs to */ int szPage; /* Size of allocated pages in bytes */ int szExtra; /* Size of extra space in bytes */ int bPurgeable; /* True if cache is purgeable */ unsigned int nMin; /* Minimum number of pages reserved */ unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. */ unsigned int nRecyclable; /* Number of pages in the LRU list */ unsigned int nPage; /* Total number of pages in apHash */ unsigned int nHash; /* Number of slots in apHash[] */ PgHdr1 **apHash; /* Hash table for fast lookup by key */ | > < < | 36915 36916 36917 36918 36919 36920 36921 36922 36923 36924 36925 36926 36927 36928 36929 36930 36931 36932 36933 36934 36935 36936 36937 | PGroup *pGroup; /* PGroup this cache belongs to */ int szPage; /* Size of allocated pages in bytes */ int szExtra; /* Size of extra space in bytes */ int bPurgeable; /* True if cache is purgeable */ unsigned int nMin; /* Minimum number of pages reserved */ unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ unsigned int iMaxKey; /* Largest key seen since xTruncate() */ /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. */ unsigned int nRecyclable; /* Number of pages in the LRU list */ unsigned int nPage; /* Total number of pages in apHash */ unsigned int nHash; /* Number of slots in apHash[] */ PgHdr1 **apHash; /* Hash table for fast lookup by key */ }; /* ** Each cache entry is represented by an instance of the following ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of ** PgHdr1.pCache->szPage bytes is allocated directly before this structure ** in memory. |
| ︙ | ︙ | |||
36837 36838 36839 36840 36841 36842 36843 | int isInit; /* True if initialized */ int szSlot; /* Size of each free slot */ int nSlot; /* The number of pcache slots */ int nReserve; /* Try to keep nFreeSlot above this */ void *pStart, *pEnd; /* Bounds of pagecache malloc range */ /* Above requires no mutex. Use mutex below for variable that follow. */ sqlite3_mutex *mutex; /* Mutex for accessing the following: */ | < > | 36967 36968 36969 36970 36971 36972 36973 36974 36975 36976 36977 36978 36979 36980 36981 36982 | int isInit; /* True if initialized */ int szSlot; /* Size of each free slot */ int nSlot; /* The number of pcache slots */ int nReserve; /* Try to keep nFreeSlot above this */ void *pStart, *pEnd; /* Bounds of pagecache malloc range */ /* Above requires no mutex. Use mutex below for variable that follow. */ sqlite3_mutex *mutex; /* Mutex for accessing the following: */ PgFreeslot *pFree; /* Free page blocks */ int nFreeSlot; /* Number of unused pcache slots */ /* The following value requires a mutex to change. We skip the mutex on ** reading because (1) most platforms read a 32-bit integer atomically and ** (2) even if an incorrect value is read, no great harm is done since this ** is really just an optimization. */ int bUnderPressure; /* True if low on PAGECACHE memory */ } pcache1_g; |
| ︙ | ︙ | |||
38219 38220 38221 38222 38223 38224 38225 38226 38227 38228 38229 38230 38231 38232 | # define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0 # define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0 # define sqlite3WalCallback(z) 0 # define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalHeapMemory(z) 0 #else #define WAL_SAVEPOINT_NDATA 4 /* Connection to a write-ahead log (WAL) file. ** There is one object of this type for each pager. */ | > | 38349 38350 38351 38352 38353 38354 38355 38356 38357 38358 38359 38360 38361 38362 38363 | # define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0 # define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0 # define sqlite3WalCallback(z) 0 # define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalHeapMemory(z) 0 # define sqlite3WalFramesize(z) 0 #else #define WAL_SAVEPOINT_NDATA 4 /* Connection to a write-ahead log (WAL) file. ** There is one object of this type for each pager. */ |
| ︙ | ︙ | |||
38299 38300 38301 38302 38303 38304 38305 38306 38307 38308 38309 38310 38311 38312 | SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op); /* Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the ** WAL module is using shared-memory, return false. */ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* _WAL_H_ */ /************** End of wal.h *************************************************/ /************** Continuing where we left off in pager.c **********************/ | > > > > > > > | 38430 38431 38432 38433 38434 38435 38436 38437 38438 38439 38440 38441 38442 38443 38444 38445 38446 38447 38448 38449 38450 | SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op); /* Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the ** WAL module is using shared-memory, return false. */ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); #ifdef SQLITE_ENABLE_ZIPVFS /* If the WAL file is not empty, return the number of bytes of content ** stored in each frame (i.e. the db page-size when the WAL was created). */ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal); #endif #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* _WAL_H_ */ /************** End of wal.h *************************************************/ /************** Continuing where we left off in pager.c **********************/ |
| ︙ | ︙ | |||
38896 38897 38898 38899 38900 38901 38902 |
** sub-codes.
*/
struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */
u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */
u8 useJournal; /* Use a rollback journal on this file */
| < | 39034 39035 39036 39037 39038 39039 39040 39041 39042 39043 39044 39045 39046 39047 |
** sub-codes.
*/
struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */
u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */
u8 useJournal; /* Use a rollback journal on this file */
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 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
u8 tempFile; /* zFilename is a temporary file */
u8 readOnly; /* True for a read-only database */
|
| ︙ | ︙ | |||
39144 39145 39146 39147 39148 39149 39150 |
assert( pPager->errCode==SQLITE_OK );
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
break;
case PAGER_READER:
assert( pPager->errCode==SQLITE_OK );
assert( p->eLock!=UNKNOWN_LOCK );
| | | 39281 39282 39283 39284 39285 39286 39287 39288 39289 39290 39291 39292 39293 39294 39295 |
assert( pPager->errCode==SQLITE_OK );
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
break;
case PAGER_READER:
assert( pPager->errCode==SQLITE_OK );
assert( p->eLock!=UNKNOWN_LOCK );
assert( p->eLock>=SHARED_LOCK );
break;
case PAGER_WRITER_LOCKED:
assert( p->eLock!=UNKNOWN_LOCK );
assert( pPager->errCode==SQLITE_OK );
if( !pagerUseWal(pPager) ){
assert( p->eLock>=RESERVED_LOCK );
|
| ︙ | ︙ | |||
41353 41354 41355 41356 41357 41358 41359 | /* Query the WAL sub-system for the database size. The WalDbsize() ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or ** if the database size is not available. The database size is not ** available from the WAL sub-system if the log file is empty or ** contains no valid committed transactions. */ assert( pPager->eState==PAGER_OPEN ); | | | 41490 41491 41492 41493 41494 41495 41496 41497 41498 41499 41500 41501 41502 41503 41504 | /* Query the WAL sub-system for the database size. The WalDbsize() ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or ** if the database size is not available. The database size is not ** available from the WAL sub-system if the log file is empty or ** contains no valid committed transactions. */ assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK ); nPage = sqlite3WalDbsize(pPager->pWal); /* If the database size was not available from the WAL sub-system, ** determine it based on the size of the database file. If the size ** of the database file is not an integer multiple of the page-size, ** round down to the nearest page. Except, any file larger than 0 ** bytes in size is considered to contain at least one page. |
| ︙ | ︙ | |||
41408 41409 41410 41411 41412 41413 41414 |
** a WAL on a none-empty database, this ensures there is no race condition
** between the xAccess() below and an xDelete() being executed by some
** other connection.
*/
static int pagerOpenWalIfPresent(Pager *pPager){
int rc = SQLITE_OK;
assert( pPager->eState==PAGER_OPEN );
| | | 41545 41546 41547 41548 41549 41550 41551 41552 41553 41554 41555 41556 41557 41558 41559 |
** a WAL on a none-empty database, this ensures there is no race condition
** between the xAccess() below and an xDelete() being executed by some
** other connection.
*/
static int pagerOpenWalIfPresent(Pager *pPager){
int rc = SQLITE_OK;
assert( pPager->eState==PAGER_OPEN );
assert( pPager->eLock>=SHARED_LOCK );
if( !pPager->tempFile ){
int isWal; /* True if WAL file exists */
Pgno nPage; /* Size of the database file */
rc = pagerPagecount(pPager, &nPage);
if( rc ) return rc;
|
| ︙ | ︙ | |||
42571 42572 42573 42574 42575 42576 42577 | ** ** The nExtra parameter specifies the number of bytes of space allocated ** along with each page reference. This space is available to the user ** via the sqlite3PagerGetExtra() API. ** ** The flags argument is used to specify properties that affect the ** operation of the pager. It should be passed some bitwise combination | | | 42708 42709 42710 42711 42712 42713 42714 42715 42716 42717 42718 42719 42720 42721 42722 | ** ** The nExtra parameter specifies the number of bytes of space allocated ** along with each page reference. This space is available to the user ** via the sqlite3PagerGetExtra() API. ** ** The flags argument is used to specify properties that affect the ** operation of the pager. It should be passed some bitwise combination ** of the PAGER_* flags. ** ** The vfsFlags parameter is a bitmask to pass to the flags parameter ** of the xOpen() method of the supplied VFS when opening files. ** ** If the pager object is allocated and the specified file opened ** successfully, SQLITE_OK is returned and *ppPager set to point to ** the new pager object. If an error occurs, *ppPager is set to NULL |
| ︙ | ︙ | |||
42602 42603 42604 42605 42606 42607 42608 | int tempFile = 0; /* True for temp files (incl. in-memory files) */ int memDb = 0; /* True if this is an in-memory file */ int readOnly = 0; /* True if this is a read-only file */ int journalFileSize; /* Bytes to allocate for each journal fd */ char *zPathname = 0; /* Full path to database file */ int nPathname = 0; /* Number of bytes in zPathname */ int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ | < | 42739 42740 42741 42742 42743 42744 42745 42746 42747 42748 42749 42750 42751 42752 | int tempFile = 0; /* True for temp files (incl. in-memory files) */ int memDb = 0; /* True if this is an in-memory file */ int readOnly = 0; /* True if this is a read-only file */ int journalFileSize; /* Bytes to allocate for each journal fd */ char *zPathname = 0; /* Full path to database file */ int nPathname = 0; /* Number of bytes in zPathname */ int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ const char *zUri = 0; /* URI args to copy */ int nUri = 0; /* Number of bytes of URI args at *zUri */ /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). This |
| ︙ | ︙ | |||
42809 42810 42811 42812 42813 42814 42815 |
sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
!memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
pPager->useJournal = (u8)useJournal;
| < | 42945 42946 42947 42948 42949 42950 42951 42952 42953 42954 42955 42956 42957 42958 |
sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
!memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
pPager->useJournal = (u8)useJournal;
/* pPager->stmtOpen = 0; */
/* pPager->stmtInUse = 0; */
/* pPager->nRef = 0; */
/* pPager->stmtSize = 0; */
/* pPager->stmtJSize = 0; */
/* pPager->nPage = 0; */
pPager->mxPgno = SQLITE_MAX_PAGE_COUNT;
|
| ︙ | ︙ | |||
43031 43032 43033 43034 43035 43036 43037 |
assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
int bHotJournal = 1; /* True if there exists a hot journal-file */
assert( !MEMDB );
| < < | | | | < | 43166 43167 43168 43169 43170 43171 43172 43173 43174 43175 43176 43177 43178 43179 43180 43181 43182 43183 43184 |
assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
int bHotJournal = 1; /* True if there exists a hot journal-file */
assert( !MEMDB );
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
goto failed;
}
/* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted.
*/
if( pPager->eLock<=SHARED_LOCK ){
rc = hasHotJournal(pPager, &bHotJournal);
|
| ︙ | ︙ | |||
45046 45047 45048 45049 45050 45051 45052 |
** lock on the database file and use heap-memory to store the wal-index
** in. Otherwise, use the normal shared-memory.
*/
static int pagerOpenWal(Pager *pPager){
int rc = SQLITE_OK;
assert( pPager->pWal==0 && pPager->tempFile==0 );
| | | 45178 45179 45180 45181 45182 45183 45184 45185 45186 45187 45188 45189 45190 45191 45192 |
** lock on the database file and use heap-memory to store the wal-index
** in. Otherwise, use the normal shared-memory.
*/
static int pagerOpenWal(Pager *pPager){
int rc = SQLITE_OK;
assert( pPager->pWal==0 && pPager->tempFile==0 );
assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
/* If the pager is already in exclusive-mode, the WAL module will use
** heap-memory for the wal-index instead of the VFS shared-memory
** implementation. Take the exclusive lock now, before opening the WAL
** file, to make sure this is safe.
*/
if( pPager->exclusiveMode ){
|
| ︙ | ︙ | |||
45160 45161 45162 45163 45164 45165 45166 45167 45168 45169 45170 45171 45172 45173 |
rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
}
}
return rc;
}
#ifdef SQLITE_HAS_CODEC
/*
** This function is called by the wal module when writing page content
** into the log file.
**
** This function returns a pointer to a buffer containing the encrypted
| > > > > > > > > > > > > > > | 45292 45293 45294 45295 45296 45297 45298 45299 45300 45301 45302 45303 45304 45305 45306 45307 45308 45309 45310 45311 45312 45313 45314 45315 45316 45317 45318 45319 |
rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
}
}
return rc;
}
#ifdef SQLITE_ENABLE_ZIPVFS
/*
** A read-lock must be held on the pager when this function is called. If
** the pager is in WAL mode and the WAL file currently contains one or more
** frames, return the size in bytes of the page images stored within the
** WAL frames. Otherwise, if this is not a WAL database or the WAL file
** is empty, return 0.
*/
SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
assert( pPager->eState==PAGER_READER );
return sqlite3WalFramesize(pPager->pWal);
}
#endif
#ifdef SQLITE_HAS_CODEC
/*
** This function is called by the wal module when writing page content
** into the log file.
**
** This function returns a pointer to a buffer containing the encrypted
|
| ︙ | ︙ | |||
47580 47581 47582 47583 47584 47585 47586 |
sz = pWal->hdr.szPage;
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
testcase( sz<=32768 );
testcase( sz>=65536 );
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
*pInWal = 1;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
| | | 47726 47727 47728 47729 47730 47731 47732 47733 47734 47735 47736 47737 47738 47739 47740 |
sz = pWal->hdr.szPage;
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
testcase( sz<=32768 );
testcase( sz>=65536 );
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
*pInWal = 1;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
*pInWal = 0;
return SQLITE_OK;
}
|
| ︙ | ︙ | |||
48250 48251 48252 48253 48254 48255 48256 48257 48258 48259 48260 48261 48262 48263 |
** Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
** WAL module is using shared-memory, return false.
*/
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
}
#endif /* #ifndef SQLITE_OMIT_WAL */
/************** End of wal.c *************************************************/
/************** Begin file btmutex.c *****************************************/
/*
** 2007 August 27
| > > > > > > > > > > > > | 48396 48397 48398 48399 48400 48401 48402 48403 48404 48405 48406 48407 48408 48409 48410 48411 48412 48413 48414 48415 48416 48417 48418 48419 48420 48421 |
** Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
** WAL module is using shared-memory, return false.
*/
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
}
#ifdef SQLITE_ENABLE_ZIPVFS
/*
** If the argument is not NULL, it points to a Wal object that holds a
** read-lock. This function returns the database page-size if it is known,
** or zero if it is not (or if pWal is NULL).
*/
SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
assert( pWal==0 || pWal->readLock>=0 );
return (pWal ? pWal->szPage : 0);
}
#endif
#endif /* #ifndef SQLITE_OMIT_WAL */
/************** End of wal.c *************************************************/
/************** Begin file btmutex.c *****************************************/
/*
** 2007 August 27
|
| ︙ | ︙ | |||
48559 48560 48561 48562 48563 48564 48565 | u8 max1bytePayload; /* min(maxLocal,127) */ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ u16 nFree; /* Number of free bytes on the page */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ | < | | | | 48717 48718 48719 48720 48721 48722 48723 48724 48725 48726 48727 48728 48729 48730 48731 48732 48733 |
u8 max1bytePayload; /* min(maxLocal,127) */
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */
u16 maskPage; /* Mask for page offset */
u16 aiOvfl[5]; /* Insert the i-th overflow cell before the aiOvfl-th
** non-overflow cell */
u8 *apOvfl[5]; /* Pointers to the body of overflow cells */
BtShared *pBt; /* Pointer to BtShared that this page is part of */
u8 *aData; /* Pointer to disk image of the page data */
u8 *aDataEnd; /* One byte past the end of usable data */
u8 *aCellIdx; /* The cell index area */
DbPage *pDbPage; /* Pager page handle */
Pgno pgno; /* Page number for this page */
};
|
| ︙ | ︙ | |||
48770 48771 48772 48773 48774 48775 48776 48777 48778 48779 48780 48781 48782 48783 48784 48785 48786 48787 |
** found at self->pBt->mutex.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
Pgno pgnoRoot; /* The root page of this tree */
sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
CellInfo info; /* A parse of the cell we are pointing at */
i64 nKey; /* Size of pKey, or last integer key */
void *pKey; /* Saved key that was cursor's last known position */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
u8 wrFlag; /* True if writable */
u8 atLast; /* Cursor pointing to the last entry */
u8 validNKey; /* True if info.nKey is valid */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_INCRBLOB
| > > > < | 48927 48928 48929 48930 48931 48932 48933 48934 48935 48936 48937 48938 48939 48940 48941 48942 48943 48944 48945 48946 48947 48948 48949 48950 48951 48952 48953 48954 |
** found at self->pBt->mutex.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
#ifndef SQLITE_OMIT_INCRBLOB
Pgno *aOverflow; /* Cache of overflow page locations */
#endif
Pgno pgnoRoot; /* The root page of this tree */
sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
CellInfo info; /* A parse of the cell we are pointing at */
i64 nKey; /* Size of pKey, or last integer key */
void *pKey; /* Saved key that was cursor's last known position */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
u8 wrFlag; /* True if writable */
u8 atLast; /* Cursor pointing to the last entry */
u8 validNKey; /* True if info.nKey is valid */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_INCRBLOB
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
#endif
i16 iPage; /* Index of current page in apPage */
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
};
|
| ︙ | ︙ | |||
48910 48911 48912 48913 48914 48915 48916 |
** This structure is passed around through all the sanity checking routines
** in order to keep track of some global state information.
*/
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
| < > | 49069 49070 49071 49072 49073 49074 49075 49076 49077 49078 49079 49080 49081 49082 49083 49084 |
** This structure is passed around through all the sanity checking routines
** in order to keep track of some global state information.
*/
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int *anRef; /* Number of times each page is referenced */
Pgno nPage; /* Number of pages in the database */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
int mallocFailed; /* A memory allocation error has occurred */
StrAccum errMsg; /* Accumulate the error message text here */
};
/*
|
| ︙ | ︙ | |||
50071 50072 50073 50074 50075 50076 50077 |
** pages that do contain overflow cells.
*/
static u8 *findOverflowCell(MemPage *pPage, int iCell){
int i;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
for(i=pPage->nOverflow-1; i>=0; i--){
int k;
| < | < | | 50230 50231 50232 50233 50234 50235 50236 50237 50238 50239 50240 50241 50242 50243 50244 50245 50246 50247 |
** pages that do contain overflow cells.
*/
static u8 *findOverflowCell(MemPage *pPage, int iCell){
int i;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
for(i=pPage->nOverflow-1; i>=0; i--){
int k;
k = pPage->aiOvfl[i];
if( k<=iCell ){
if( k==iCell ){
return pPage->apOvfl[i];
}
iCell--;
}
}
return findCell(pPage, iCell);
}
|
| ︙ | ︙ | |||
50890 50891 50892 50893 50894 50895 50896 | ** be exclusively in memory, or it might use a disk-based memory cache. ** Either way, the ephemeral database will be automatically deleted ** when sqlite3BtreeClose() is called. ** ** If zFilename is ":memory:" then an in-memory database is created ** that is automatically destroyed when it is closed. ** | | | < < < | 51047 51048 51049 51050 51051 51052 51053 51054 51055 51056 51057 51058 51059 51060 51061 51062 | ** be exclusively in memory, or it might use a disk-based memory cache. ** Either way, the ephemeral database will be automatically deleted ** when sqlite3BtreeClose() is called. ** ** If zFilename is ":memory:" then an in-memory database is created ** that is automatically destroyed when it is closed. ** ** The "flags" parameter is a bitmask that might contain bits like ** BTREE_OMIT_JOURNAL and/or BTREE_MEMORY. ** ** If the database is already opened in the same database connection ** and we are in shared cache mode, then the open will fail with an ** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared ** objects in the same database connection since doing so will lead ** to problems with locking. */ |
| ︙ | ︙ | |||
50941 50942 50943 50944 50945 50946 50947 | /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 ); /* A BTREE_SINGLE database is always a temporary and/or ephemeral */ assert( (flags & BTREE_SINGLE)==0 || isTempDb ); | < < < | 51095 51096 51097 51098 51099 51100 51101 51102 51103 51104 51105 51106 51107 51108 |
/* Only a BTREE_SINGLE database can be BTREE_UNORDERED */
assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 );
/* A BTREE_SINGLE database is always a temporary and/or ephemeral */
assert( (flags & BTREE_SINGLE)==0 || isTempDb );
if( isMemdb ){
flags |= BTREE_MEMORY;
}
if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
}
p = sqlite3MallocZero(sizeof(Btree));
|
| ︙ | ︙ | |||
51250 51251 51252 51253 51254 51255 51256 |
}
}
/* Rollback any active transaction and free the handle structure.
** The call to sqlite3BtreeRollback() drops any table-locks held by
** this handle.
*/
| | | 51401 51402 51403 51404 51405 51406 51407 51408 51409 51410 51411 51412 51413 51414 51415 |
}
}
/* Rollback any active transaction and free the handle structure.
** The call to sqlite3BtreeRollback() drops any table-locks held by
** this handle.
*/
sqlite3BtreeRollback(p, SQLITE_OK);
sqlite3BtreeLeave(p);
/* If there are still other outstanding references to the shared-btree
** structure, return now. The remainder of this procedure cleans
** up the shared-btree.
*/
assert( p->wantToLock==0 && p->locked==0 );
|
| ︙ | ︙ | |||
52488 52489 52490 52491 52492 52493 52494 52495 52496 52497 52498 52499 52500 52501 |
** the rollback. The rollback may have deleted tables
** or moved root pages, so it is not sufficient to
** save the state of the cursor. The cursor must be
** invalidated.
*/
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
BtCursor *p;
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
sqlite3BtreeClearCursor(p);
p->eState = CURSOR_FAULT;
p->skipNext = errCode;
for(i=0; i<=p->iPage; i++){
| > | 52639 52640 52641 52642 52643 52644 52645 52646 52647 52648 52649 52650 52651 52652 52653 |
** the rollback. The rollback may have deleted tables
** or moved root pages, so it is not sufficient to
** save the state of the cursor. The cursor must be
** invalidated.
*/
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
BtCursor *p;
if( pBtree==0 ) return;
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
sqlite3BtreeClearCursor(p);
p->eState = CURSOR_FAULT;
p->skipNext = errCode;
for(i=0; i<=p->iPage; i++){
|
| ︙ | ︙ | |||
52511 52512 52513 52514 52515 52516 52517 | ** invalided by this operation. Any attempt to use a cursor ** that was open at the beginning of this operation will result ** in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ | | > | > | > | < < < < < < < | < | 52663 52664 52665 52666 52667 52668 52669 52670 52671 52672 52673 52674 52675 52676 52677 52678 52679 52680 52681 52682 52683 52684 52685 52686 52687 52688 52689 52690 |
** invalided by this operation. Any attempt to use a cursor
** that was open at the beginning of this operation will result
** in an error.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
int rc;
BtShared *pBt = p->pBt;
MemPage *pPage1;
sqlite3BtreeEnter(p);
if( tripCode==SQLITE_OK ){
rc = tripCode = saveAllCursors(pBt, 0, 0);
}else{
rc = SQLITE_OK;
}
if( tripCode ){
sqlite3BtreeTripAllCursors(p, tripCode);
}
btreeIntegrity(p);
if( p->inTrans==TRANS_WRITE ){
int rc2;
assert( TRANS_WRITE==pBt->inTransaction );
rc2 = sqlite3PagerRollback(pBt->pPager);
|
| ︙ | ︙ | |||
53395 53396 53397 53398 53399 53400 53401 |
pCur->validNKey = 0;
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
return SQLITE_CORRUPT_BKPT;
}
return SQLITE_OK;
}
| | | 53542 53543 53544 53545 53546 53547 53548 53549 53550 53551 53552 53553 53554 53555 53556 |
pCur->validNKey = 0;
if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
return SQLITE_CORRUPT_BKPT;
}
return SQLITE_OK;
}
#if 0
/*
** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
** cell in page pParent. Or, if iIdx is equal to the total number of
** cells in pParent, that page number iChild is the right-child of
** the page.
*/
|
| ︙ | ︙ | |||
53428 53429 53430 53431 53432 53433 53434 53435 53436 53437 53438 53439 53440 53441 53442 53443 53444 53445 53446 |
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
);
releasePage(pCur->apPage[pCur->iPage]);
pCur->iPage--;
pCur->info.nSize = 0;
pCur->validNKey = 0;
}
/*
| > > > > > > > > > > | 53575 53576 53577 53578 53579 53580 53581 53582 53583 53584 53585 53586 53587 53588 53589 53590 53591 53592 53593 53594 53595 53596 53597 53598 53599 53600 53601 53602 53603 |
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
/* UPDATE: It is actually possible for the condition tested by the assert
** below to be untrue if the database file is corrupt. This can occur if
** one cursor has modified page pParent while a reference to it is held
** by a second cursor. Which can only happen if a single page is linked
** into more than one b-tree structure in a corrupt database. */
#if 0
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
);
#endif
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
releasePage(pCur->apPage[pCur->iPage]);
pCur->iPage--;
pCur->info.nSize = 0;
pCur->validNKey = 0;
}
/*
|
| ︙ | ︙ | |||
53902 53903 53904 53905 53906 53907 53908 |
return SQLITE_OK;
}
pCur->skipNext = 0;
pPage = pCur->apPage[pCur->iPage];
idx = ++pCur->aiIdx[pCur->iPage];
assert( pPage->isInit );
| > > > > > > | | 54059 54060 54061 54062 54063 54064 54065 54066 54067 54068 54069 54070 54071 54072 54073 54074 54075 54076 54077 54078 54079 |
return SQLITE_OK;
}
pCur->skipNext = 0;
pPage = pCur->apPage[pCur->iPage];
idx = ++pCur->aiIdx[pCur->iPage];
assert( pPage->isInit );
/* If the database file is corrupt, it is possible for the value of idx
** to be invalid here. This can only occur if a second cursor modifies
** the page while cursor pCur is holding a reference to it. Which can
** only happen if the database is corrupt in such a way as to link the
** page into more than one b-tree structure. */
testcase( idx>pPage->nCell );
pCur->info.nSize = 0;
pCur->validNKey = 0;
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
if( rc ) return rc;
|
| ︙ | ︙ | |||
54712 54713 54714 54715 54716 54717 54718 | /* ** Insert a new cell on pPage at cell index "i". pCell points to the ** content of the cell. ** ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry | | | 54875 54876 54877 54878 54879 54880 54881 54882 54883 54884 54885 54886 54887 54888 54889 | /* ** Insert a new cell on pPage at cell index "i". pCell points to the ** content of the cell. ** ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. ** ** If nSkip is non-zero, then do not copy the first nSkip bytes of the ** cell. The caller will overwrite them after this function returns. If ** nSkip is non-zero, then pCell may not point to an invalid memory location |
| ︙ | ︙ | |||
54746 54747 54748 54749 54750 54751 54752 | int nSkip = (iChild ? 4 : 0); if( *pRC ) return; assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 ); | | > | | | | 54909 54910 54911 54912 54913 54914 54915 54916 54917 54918 54919 54920 54921 54922 54923 54924 54925 54926 54927 54928 54929 54930 54931 54932 54933 54934 54935 54936 54937 54938 54939 54940 54941 54942 54943 |
int nSkip = (iChild ? 4 : 0);
if( *pRC ) return;
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 );
assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
/* The cell should normally be sized correctly. However, when moving a
** malformed cell from a leaf page to an interior page, if the cell size
** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
** might be less than 8 (leaf-size + pointer) on the interior node. Hence
** the term after the || in the following assert(). */
assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip);
pCell = pTemp;
}
if( iChild ){
put4byte(pCell, iChild);
}
j = pPage->nOverflow++;
assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
pPage->apOvfl[j] = pCell;
pPage->aiOvfl[j] = (u16)i;
}else{
int rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc!=SQLITE_OK ){
*pRC = rc;
return;
}
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
| ︙ | ︙ | |||
54913 54914 54915 54916 54917 54918 54919 |
** may be inserted. If both these operations are successful, proceed.
*/
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
if( rc==SQLITE_OK ){
u8 *pOut = &pSpace[4];
| | | 55077 55078 55079 55080 55081 55082 55083 55084 55085 55086 55087 55088 55089 55090 55091 |
** may be inserted. If both these operations are successful, proceed.
*/
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
if( rc==SQLITE_OK ){
u8 *pOut = &pSpace[4];
u8 *pCell = pPage->apOvfl[0];
u16 szCell = cellSizePtr(pPage, pCell);
u8 *pStop;
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
assemblePage(pNew, 1, &pCell, &szCell);
|
| ︙ | ︙ | |||
55023 55024 55025 55026 55027 55028 55029 | ** on page pFrom to page pTo. If page pFrom was not a leaf page, then ** the pointer-map entries for each child page are updated so that the ** parent page stored in the pointer map is page pTo. If pFrom contained ** any cells with overflow page pointers, then the corresponding pointer ** map entries are also updated so that the parent page is page pTo. ** ** If pFrom is currently carrying any overflow cells (entries in the | | | 55187 55188 55189 55190 55191 55192 55193 55194 55195 55196 55197 55198 55199 55200 55201 | ** on page pFrom to page pTo. If page pFrom was not a leaf page, then ** the pointer-map entries for each child page are updated so that the ** parent page stored in the pointer map is page pTo. If pFrom contained ** any cells with overflow page pointers, then the corresponding pointer ** map entries are also updated so that the parent page is page pTo. ** ** If pFrom is currently carrying any overflow cells (entries in the ** MemPage.apOvfl[] array), they are not copied to pTo. ** ** Before returning, page pTo is reinitialized using btreeInitPage(). ** ** The performance of this function is not critical. It is only used by ** the balance_shallower() and balance_deeper() procedures, neither of ** which are called often under normal circumstances. */ |
| ︙ | ︙ | |||
55160 55161 55162 55163 55164 55165 55166 | /* At this point pParent may have at most one overflow cell. And if ** this overflow cell is present, it must be the cell with ** index iParentIdx. This scenario comes about when this function ** is called (indirectly) from sqlite3BtreeDelete(). */ assert( pParent->nOverflow==0 || pParent->nOverflow==1 ); | | | 55324 55325 55326 55327 55328 55329 55330 55331 55332 55333 55334 55335 55336 55337 55338 |
/* At this point pParent may have at most one overflow cell. And if
** this overflow cell is present, it must be the cell with
** index iParentIdx. This scenario comes about when this function
** is called (indirectly) from sqlite3BtreeDelete().
*/
assert( pParent->nOverflow==0 || pParent->nOverflow==1 );
assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
if( !aOvflSpace ){
return SQLITE_NOMEM;
}
/* Find the sibling pages to balance. Also locate the cells in pParent
** that divide the siblings. An attempt is made to find NN siblings on
|
| ︙ | ︙ | |||
55207 55208 55209 55210 55211 55212 55213 |
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup;
}
nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
if( (i--)==0 ) break;
| | | | 55371 55372 55373 55374 55375 55376 55377 55378 55379 55380 55381 55382 55383 55384 55385 55386 |
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup;
}
nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
if( (i--)==0 ) break;
if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
apDiv[i] = pParent->apOvfl[0];
pgno = get4byte(apDiv[i]);
szNew[i] = cellSizePtr(pParent, apDiv[i]);
pParent->nOverflow = 0;
}else{
apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow);
pgno = get4byte(apDiv[i]);
szNew[i] = cellSizePtr(pParent, apDiv[i]);
|
| ︙ | ︙ | |||
55649 55650 55651 55652 55653 55654 55655 |
** setting a pointer map entry is a relatively expensive operation, this
** code only sets pointer map entries for child or overflow pages that have
** actually moved between pages. */
MemPage *pNew = apNew[0];
MemPage *pOld = apCopy[0];
int nOverflow = pOld->nOverflow;
int iNextOld = pOld->nCell + nOverflow;
| | | | | | 55813 55814 55815 55816 55817 55818 55819 55820 55821 55822 55823 55824 55825 55826 55827 55828 55829 55830 55831 55832 55833 55834 55835 55836 55837 55838 55839 55840 55841 55842 55843 55844 55845 55846 55847 55848 |
** setting a pointer map entry is a relatively expensive operation, this
** code only sets pointer map entries for child or overflow pages that have
** actually moved between pages. */
MemPage *pNew = apNew[0];
MemPage *pOld = apCopy[0];
int nOverflow = pOld->nOverflow;
int iNextOld = pOld->nCell + nOverflow;
int iOverflow = (nOverflow ? pOld->aiOvfl[0] : -1);
j = 0; /* Current 'old' sibling page */
k = 0; /* Current 'new' sibling page */
for(i=0; i<nCell; i++){
int isDivider = 0;
while( i==iNextOld ){
/* Cell i is the cell immediately following the last cell on old
** sibling page j. If the siblings are not leaf pages of an
** intkey b-tree, then cell i was a divider cell. */
assert( j+1 < ArraySize(apCopy) );
pOld = apCopy[++j];
iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow;
if( pOld->nOverflow ){
nOverflow = pOld->nOverflow;
iOverflow = i + !leafData + pOld->aiOvfl[0];
}
isDivider = !leafData;
}
assert(nOverflow>0 || iOverflow<i );
assert(nOverflow<2 || pOld->aiOvfl[0]==pOld->aiOvfl[1]-1);
assert(nOverflow<3 || pOld->aiOvfl[1]==pOld->aiOvfl[2]-1);
if( i==iOverflow ){
isDivider = 1;
if( (--nOverflow)>0 ){
iOverflow++;
}
}
|
| ︙ | ︙ | |||
55791 55792 55793 55794 55795 55796 55797 |
assert( sqlite3PagerIswriteable(pChild->pDbPage) );
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
assert( pChild->nCell==pRoot->nCell );
TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
| > | > > | 55955 55956 55957 55958 55959 55960 55961 55962 55963 55964 55965 55966 55967 55968 55969 55970 55971 55972 |
assert( sqlite3PagerIswriteable(pChild->pDbPage) );
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
assert( pChild->nCell==pRoot->nCell );
TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
memcpy(pChild->aiOvfl, pRoot->aiOvfl,
pRoot->nOverflow*sizeof(pRoot->aiOvfl[0]));
memcpy(pChild->apOvfl, pRoot->apOvfl,
pRoot->nOverflow*sizeof(pRoot->apOvfl[0]));
pChild->nOverflow = pRoot->nOverflow;
/* Zero the contents of pRoot. Then install pChild as the right-child. */
zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF);
put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild);
*ppChild = pChild;
|
| ︙ | ︙ | |||
55854 55855 55856 55857 55858 55859 55860 |
int const iIdx = pCur->aiIdx[iPage-1];
rc = sqlite3PagerWrite(pParent->pDbPage);
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
if( pPage->hasData
&& pPage->nOverflow==1
| | | 56021 56022 56023 56024 56025 56026 56027 56028 56029 56030 56031 56032 56033 56034 56035 |
int const iIdx = pCur->aiIdx[iPage-1];
rc = sqlite3PagerWrite(pParent->pDbPage);
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
if( pPage->hasData
&& pPage->nOverflow==1
&& pPage->aiOvfl[0]==pPage->nCell
&& pParent->pgno!=1
&& pParent->nCell==iIdx
){
/* Call balance_quick() to create a new sibling of pPage on which
** to store the overflow cell. balance_quick() inserts a new cell
** into pParent, which may cause pParent overflow. If this
** happens, the next interation of the do-loop will balance pParent
|
| ︙ | ︙ | |||
58031 58032 58033 58034 58035 58036 58037 |
while( *pp!=p ){
pp = &(*pp)->pNext;
}
*pp = p->pNext;
}
/* If a transaction is still open on the Btree, roll it back. */
| | | 58198 58199 58200 58201 58202 58203 58204 58205 58206 58207 58208 58209 58210 58211 58212 |
while( *pp!=p ){
pp = &(*pp)->pNext;
}
*pp = p->pNext;
}
/* If a transaction is still open on the Btree, roll it back. */
sqlite3BtreeRollback(p->pDest, SQLITE_OK);
/* Set the error code of the destination database handle. */
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
sqlite3Error(p->pDestDb, rc, 0);
/* Exit the mutexes and free the backup context structure. */
if( p->pDestDb ){
|
| ︙ | ︙ | |||
58275 58276 58277 58278 58279 58280 58281 58282 58283 58284 58285 58286 58287 58288 |
}
}
if( pMem->z && preserve && pMem->zMalloc && pMem->z!=pMem->zMalloc ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( pMem->flags&MEM_Dyn && pMem->xDel ){
pMem->xDel((void *)(pMem->z));
}
pMem->z = pMem->zMalloc;
if( pMem->z==0 ){
pMem->flags = MEM_Null;
}else{
| > | 58442 58443 58444 58445 58446 58447 58448 58449 58450 58451 58452 58453 58454 58455 58456 |
}
}
if( pMem->z && preserve && pMem->zMalloc && pMem->z!=pMem->zMalloc ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( pMem->flags&MEM_Dyn && pMem->xDel ){
assert( pMem->xDel!=SQLITE_DYNAMIC );
pMem->xDel((void *)(pMem->z));
}
pMem->z = pMem->zMalloc;
if( pMem->z==0 ){
pMem->flags = MEM_Null;
}else{
|
| ︙ | ︙ | |||
58454 58455 58456 58457 58458 58459 58460 58461 58462 58463 58464 58465 58466 58467 |
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);
}
| > | 58622 58623 58624 58625 58626 58627 58628 58629 58630 58631 58632 58633 58634 58635 58636 |
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 );
assert( p->xDel!=SQLITE_DYNAMIC );
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);
}
|
| ︙ | ︙ | |||
58596 58597 58598 58599 58600 58601 58602 | ** ** The second and third terms in the following conditional enforces ** the second condition under the assumption that addition overflow causes ** values to wrap around. On x86 hardware, the third term is always ** true and could be omitted. But we leave it in because other ** architectures might behave differently. */ | | > > | > > > > | 58765 58766 58767 58768 58769 58770 58771 58772 58773 58774 58775 58776 58777 58778 58779 58780 58781 58782 58783 58784 58785 58786 |
**
** The second and third terms in the following conditional enforces
** the second condition under the assumption that addition overflow causes
** values to wrap around. On x86 hardware, the third term is always
** true and could be omitted. But we leave it in because other
** architectures might behave differently.
*/
if( pMem->r==(double)pMem->u.i
&& pMem->u.i>SMALLEST_INT64
#if defined(__i486__) || defined(__x86_64__)
&& ALWAYS(pMem->u.i<LARGEST_INT64)
#else
&& pMem->u.i<LARGEST_INT64
#endif
){
pMem->flags |= MEM_Int;
}
}
/*
** Convert pMem to type integer. Invalidate any prior representations.
*/
|
| ︙ | ︙ | |||
59571 59572 59573 59574 59575 59576 59577 |
** The VDBE knows that a P2 value is a label because labels are
** always negative and P2 values are suppose to be non-negative.
** Hence, a negative P2 value is a label that has yet to be resolved.
**
** Zero is returned if a malloc() fails.
*/
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *p){
| < | | < | | < | 59746 59747 59748 59749 59750 59751 59752 59753 59754 59755 59756 59757 59758 59759 59760 59761 59762 59763 59764 |
** The VDBE knows that a P2 value is a label because labels are
** always negative and P2 values are suppose to be non-negative.
** Hence, a negative P2 value is a label that has yet to be resolved.
**
** Zero is returned if a malloc() fails.
*/
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *p){
int i = p->nLabel++;
assert( p->magic==VDBE_MAGIC_INIT );
if( (i & (i-1))==0 ){
p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel,
(i*2+1)*sizeof(p->aLabel[0]));
}
if( p->aLabel ){
p->aLabel[i] = -1;
}
return -1-i;
}
|
| ︙ | ︙ | |||
61336 61337 61338 61339 61340 61341 61342 | assert( cnt==db->activeVdbeCnt ); assert( nWrite==db->writeVdbeCnt ); } #else #define checkActiveVdbeCnt(x) #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < | 61508 61509 61510 61511 61512 61513 61514 61515 61516 61517 61518 61519 61520 61521 | assert( cnt==db->activeVdbeCnt ); assert( nWrite==db->writeVdbeCnt ); } #else #define checkActiveVdbeCnt(x) #endif /* ** If the Vdbe passed as the first argument opened a statement-transaction, ** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or ** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement ** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the ** statement transaction is commtted. ** |
| ︙ | ︙ | |||
61526 61527 61528 61529 61530 61531 61532 |
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
*/
| < | | 61672 61673 61674 61675 61676 61677 61678 61679 61680 61681 61682 61683 61684 61685 61686 |
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
*/
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
}
}
}
/* Check for immediate foreign key violations. */
|
| ︙ | ︙ | |||
61569 61570 61571 61572 61573 61574 61575 |
rc = vdbeCommit(db, p);
}
if( rc==SQLITE_BUSY && p->readOnly ){
sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
p->rc = rc;
| | | < | < | < < < < < < | 61714 61715 61716 61717 61718 61719 61720 61721 61722 61723 61724 61725 61726 61727 61728 61729 61730 61731 61732 61733 61734 61735 61736 61737 61738 61739 61740 61741 61742 61743 61744 61745 61746 61747 61748 61749 61750 61751 61752 61753 61754 61755 61756 61757 61758 61759 61760 61761 61762 61763 61764 61765 61766 61767 61768 61769 61770 61771 61772 61773 61774 61775 61776 61777 61778 61779 |
rc = vdbeCommit(db, p);
}
if( rc==SQLITE_BUSY && p->readOnly ){
sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
p->rc = rc;
sqlite3RollbackAll(db, SQLITE_OK);
}else{
db->nDeferredCons = 0;
sqlite3CommitInternalChanges(db);
}
}else{
sqlite3RollbackAll(db, SQLITE_OK);
}
db->nStatement = 0;
}else if( eStatementOp==0 ){
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
eStatementOp = SAVEPOINT_RELEASE;
}else if( p->errorAction==OE_Abort ){
eStatementOp = SAVEPOINT_ROLLBACK;
}else{
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
}
}
/* If eStatementOp is non-zero, then a statement transaction needs to
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
** do so. If this operation returns an error, and the current statement
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
** current statement error code.
*/
if( eStatementOp ){
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
if( rc ){
if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
p->rc = rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
sqlite3CloseSavepoints(db);
db->autoCommit = 1;
}
}
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
** has been rolled back, update the database connection change-counter.
*/
if( p->changeCntOn ){
if( eStatementOp!=SAVEPOINT_ROLLBACK ){
sqlite3VdbeSetChanges(db, p->nChange);
}else{
sqlite3VdbeSetChanges(db, 0);
}
p->nChange = 0;
}
/* Release the locks */
sqlite3VdbeLeave(p);
}
/* We have successfully halted and closed the VM. Record this fact. */
if( p->pc>=0 ){
|
| ︙ | ︙ | |||
66049 66050 66051 66052 66053 66054 66055 | break; arithmetic_result_is_null: sqlite3VdbeMemSetNull(pOut); break; } | | > > > > > > > | 66186 66187 66188 66189 66190 66191 66192 66193 66194 66195 66196 66197 66198 66199 66200 66201 66202 66203 66204 66205 66206 66207 66208 66209 66210 66211 66212 66213 66214 66215 66216 66217 66218 66219 |
break;
arithmetic_result_is_null:
sqlite3VdbeMemSetNull(pOut);
break;
}
/* Opcode: CollSeq P1 * * P4
**
** P4 is a pointer to a CollSeq struct. If the next call to a user function
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
** be returned. This is used by the built-in min(), max() and nullif()
** functions.
**
** If P1 is not zero, then it is a register that a subsequent min() or
** max() aggregate will set to 1 if the current row is not the minimum or
** maximum. The P1 register is initialized to 0 by this instruction.
**
** The interface used by the implementation of the aforementioned functions
** to retrieve the collation sequence set by this opcode is not available
** publicly, only to user functions defined in func.c.
*/
case OP_CollSeq: {
assert( pOp->p4type==P4_COLLSEQ );
if( pOp->p1 ){
sqlite3VdbeMemSetInt64(&aMem[pOp->p1], 0);
}
break;
}
/* Opcode: Function P1 P2 P3 P4 P5
**
** Invoke a user function (P4 is a pointer to a Function structure that
** defines the function) with P5 arguments taken from register P2 and
|
| ︙ | ︙ | |||
67417 67418 67419 67420 67421 67422 67423 |
u.ar.pSavepoint = u.ar.pSavepoint->pNext
){
u.ar.iSavepoint++;
}
if( !u.ar.pSavepoint ){
sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.ar.zName);
rc = SQLITE_ERROR;
| | < < | < | < | 67561 67562 67563 67564 67565 67566 67567 67568 67569 67570 67571 67572 67573 67574 67575 67576 67577 67578 67579 67580 |
u.ar.pSavepoint = u.ar.pSavepoint->pNext
){
u.ar.iSavepoint++;
}
if( !u.ar.pSavepoint ){
sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", u.ar.zName);
rc = SQLITE_ERROR;
}else if( db->writeVdbeCnt>0 && u.ar.p1==SAVEPOINT_RELEASE ){
/* It is not possible to release (commit) a savepoint if there are
** active write statements.
*/
sqlite3SetString(&p->zErrMsg, db,
"cannot release savepoint - SQL statements in progress"
);
rc = SQLITE_BUSY;
}else{
/* Determine whether or not this is a transaction savepoint. If so,
** and this is a RELEASE command, then the current transaction
** is committed.
|
| ︙ | ︙ | |||
67451 67452 67453 67454 67455 67456 67457 67458 67459 67460 67461 67462 67463 67464 |
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
db->isTransactionSavepoint = 0;
rc = p->rc;
}else{
u.ar.iSavepoint = db->nSavepoint - u.ar.iSavepoint - 1;
for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){
rc = sqlite3BtreeSavepoint(db->aDb[u.ar.ii].pBt, u.ar.p1, u.ar.iSavepoint);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}
if( u.ar.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
| > > > | 67591 67592 67593 67594 67595 67596 67597 67598 67599 67600 67601 67602 67603 67604 67605 67606 67607 |
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
db->isTransactionSavepoint = 0;
rc = p->rc;
}else{
u.ar.iSavepoint = db->nSavepoint - u.ar.iSavepoint - 1;
for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){
sqlite3BtreeTripAllCursors(db->aDb[u.ar.ii].pBt, SQLITE_ABORT);
}
for(u.ar.ii=0; u.ar.ii<db->nDb; u.ar.ii++){
rc = sqlite3BtreeSavepoint(db->aDb[u.ar.ii].pBt, u.ar.p1, u.ar.iSavepoint);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}
if( u.ar.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
|
| ︙ | ︙ | |||
67521 67522 67523 67524 67525 67526 67527 67528 67529 67530 67531 67532 67533 67534 67535 |
u.as.desiredAutoCommit = pOp->p1;
u.as.iRollback = pOp->p2;
u.as.turnOnAC = u.as.desiredAutoCommit && !db->autoCommit;
assert( u.as.desiredAutoCommit==1 || u.as.desiredAutoCommit==0 );
assert( u.as.desiredAutoCommit==1 || u.as.iRollback==0 );
assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */
if( u.as.turnOnAC && u.as.iRollback && db->activeVdbeCnt>1 ){
/* If this instruction implements a ROLLBACK and other VMs are
** still running, and a transaction is active, return an error indicating
** that the other VMs must complete first.
*/
sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
| > > > | | | 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 |
u.as.desiredAutoCommit = pOp->p1;
u.as.iRollback = pOp->p2;
u.as.turnOnAC = u.as.desiredAutoCommit && !db->autoCommit;
assert( u.as.desiredAutoCommit==1 || u.as.desiredAutoCommit==0 );
assert( u.as.desiredAutoCommit==1 || u.as.iRollback==0 );
assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */
#if 0
if( u.as.turnOnAC && u.as.iRollback && db->activeVdbeCnt>1 ){
/* If this instruction implements a ROLLBACK and other VMs are
** still running, and a transaction is active, return an error indicating
** that the other VMs must complete first.
*/
sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
}else
#endif
if( u.as.turnOnAC && !u.as.iRollback && db->writeVdbeCnt>0 ){
/* If this instruction implements a COMMIT and other VMs are writing
** return an error indicating that the other VMs must complete first.
*/
sqlite3SetString(&p->zErrMsg, db, "cannot commit transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
}else if( u.as.desiredAutoCommit!=db->autoCommit ){
if( u.as.iRollback ){
assert( u.as.desiredAutoCommit==1 );
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
db->autoCommit = 1;
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
goto vdbe_return;
}else{
db->autoCommit = (u8)u.as.desiredAutoCommit;
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
p->pc = pc;
|
| ︙ | ︙ | |||
67595 67596 67597 67598 67599 67600 67601 | ** on the file. ** ** If a write-transaction is started and the Vdbe.usesStmtJournal flag is ** true (this flag is set if the Vdbe may modify more than one row and may ** throw an ABORT exception), a statement transaction may also be opened. ** More specifically, a statement transaction is opened iff the database ** connection is currently not in autocommit mode, or if there are other | | | 67741 67742 67743 67744 67745 67746 67747 67748 67749 67750 67751 67752 67753 67754 67755 |
** on the file.
**
** If a write-transaction is started and the Vdbe.usesStmtJournal flag is
** true (this flag is set if the Vdbe may modify more than one row and may
** throw an ABORT exception), a statement transaction may also be opened.
** More specifically, a statement transaction is opened iff the database
** connection is currently not in autocommit mode, or if there are other
** active statements. A statement transaction allows the changes made by this
** VDBE to be rolled back after an error without having to roll back the
** entire transaction. If no error is encountered, the statement transaction
** will automatically commit when the VDBE halts.
**
** If P2 is zero, then a read-lock is obtained on the database file.
*/
case OP_Transaction: {
|
| ︙ | ︙ | |||
68605 68606 68607 68608 68609 68610 68611 |
}
if( u.bg.res ){
u.bg.v = 1; /* IMP: R-61914-48074 */
}else{
assert( sqlite3BtreeCursorIsValid(u.bg.pC->pCursor) );
rc = sqlite3BtreeKeySize(u.bg.pC->pCursor, &u.bg.v);
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
| | | 68751 68752 68753 68754 68755 68756 68757 68758 68759 68760 68761 68762 68763 68764 68765 |
}
if( u.bg.res ){
u.bg.v = 1; /* IMP: R-61914-48074 */
}else{
assert( sqlite3BtreeCursorIsValid(u.bg.pC->pCursor) );
rc = sqlite3BtreeKeySize(u.bg.pC->pCursor, &u.bg.v);
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
if( u.bg.v>=MAX_ROWID ){
u.bg.pC->useRandomRowid = 1;
}else{
u.bg.v++; /* IMP: R-29538-34987 */
}
}
}
|
| ︙ | ︙ | |||
69639 69640 69641 69642 69643 69644 69645 69646 69647 69648 69649 69650 69651 69652 |
assert( !db->mallocFailed );
rc = sqlite3_exec(db, u.by.zSql, sqlite3InitCallback, &u.by.initData, 0);
if( rc==SQLITE_OK ) rc = u.by.initData.rc;
sqlite3DbFree(db, u.by.zSql);
db->init.busy = 0;
}
}
if( rc==SQLITE_NOMEM ){
goto no_mem;
}
break;
}
#if !defined(SQLITE_OMIT_ANALYZE)
| > | 69785 69786 69787 69788 69789 69790 69791 69792 69793 69794 69795 69796 69797 69798 69799 |
assert( !db->mallocFailed );
rc = sqlite3_exec(db, u.by.zSql, sqlite3InitCallback, &u.by.initData, 0);
if( rc==SQLITE_OK ) rc = u.by.initData.rc;
sqlite3DbFree(db, u.by.zSql);
db->init.busy = 0;
}
}
if( rc ) sqlite3ResetInternalSchema(db, -1);
if( rc==SQLITE_NOMEM ){
goto no_mem;
}
break;
}
#if !defined(SQLITE_OMIT_ANALYZE)
|
| ︙ | ︙ | |||
69981 69982 69983 69984 69985 69986 69987 | p->nMem = u.cc.pFrame->nChildMem; p->nCursor = (u16)u.cc.pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&aMem[p->nMem+1]; p->aOp = aOp = u.cc.pProgram->aOp; p->nOp = u.cc.pProgram->nOp; p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; p->nOnceFlag = u.cc.pProgram->nOnce; | < | 70128 70129 70130 70131 70132 70133 70134 70135 70136 70137 70138 70139 70140 70141 | p->nMem = u.cc.pFrame->nChildMem; p->nCursor = (u16)u.cc.pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&aMem[p->nMem+1]; p->aOp = aOp = u.cc.pProgram->aOp; p->nOp = u.cc.pProgram->nOp; p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; p->nOnceFlag = u.cc.pProgram->nOnce; pc = -1; memset(p->aOnceFlag, 0, p->nOnceFlag); break; } /* Opcode: Param P1 P2 * * * |
| ︙ | ︙ | |||
70176 70177 70178 70179 70180 70181 70182 70183 70184 70185 70186 70187 70188 70189 70190 70191 70192 70193 70194 70195 70196 70197 70198 70199 70200 |
u.cf.ctx.s.flags = MEM_Null;
u.cf.ctx.s.z = 0;
u.cf.ctx.s.zMalloc = 0;
u.cf.ctx.s.xDel = 0;
u.cf.ctx.s.db = db;
u.cf.ctx.isError = 0;
u.cf.ctx.pColl = 0;
if( u.cf.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>p->aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
u.cf.ctx.pColl = pOp[-1].p4.pColl;
}
(u.cf.ctx.pFunc->xStep)(&u.cf.ctx, u.cf.n, u.cf.apVal); /* IMP: R-24505-23230 */
if( u.cf.ctx.isError ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cf.ctx.s));
rc = u.cf.ctx.isError;
}
sqlite3VdbeMemRelease(&u.cf.ctx.s);
break;
}
/* Opcode: AggFinal P1 P2 * P4 *
| > > > > > > | 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 |
u.cf.ctx.s.flags = MEM_Null;
u.cf.ctx.s.z = 0;
u.cf.ctx.s.zMalloc = 0;
u.cf.ctx.s.xDel = 0;
u.cf.ctx.s.db = db;
u.cf.ctx.isError = 0;
u.cf.ctx.pColl = 0;
u.cf.ctx.skipFlag = 0;
if( u.cf.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>p->aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
u.cf.ctx.pColl = pOp[-1].p4.pColl;
}
(u.cf.ctx.pFunc->xStep)(&u.cf.ctx, u.cf.n, u.cf.apVal); /* IMP: R-24505-23230 */
if( u.cf.ctx.isError ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cf.ctx.s));
rc = u.cf.ctx.isError;
}
if( u.cf.ctx.skipFlag ){
assert( pOp[-1].opcode==OP_CollSeq );
u.cf.i = pOp[-1].p1;
if( u.cf.i ) sqlite3VdbeMemSetInt64(&aMem[u.cf.i], 1);
}
sqlite3VdbeMemRelease(&u.cf.ctx.s);
break;
}
/* Opcode: AggFinal P1 P2 * P4 *
|
| ︙ | ︙ | |||
71580 71581 71582 71583 71584 71585 71586 71587 71588 71589 71590 |
** 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 */
| > > > > > < < < < < < < > > | 71732 71733 71734 71735 71736 71737 71738 71739 71740 71741 71742 71743 71744 71745 71746 71747 71748 71749 71750 71751 71752 71753 71754 71755 71756 71757 71758 71759 71760 71761 71762 71763 71764 71765 71766 71767 71768 71769 71770 |
** 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 {
i64 iWriteOff; /* Current write offset within file pTemp1 */
i64 iReadOff; /* Current read offset within file pTemp1 */
int nInMemory; /* Current size of pRecord list as PMA */
int nTree; /* Used size of aTree/aIter (power of 2) */
int nPMA; /* Number of PMAs stored in pTemp1 */
int mnPmaSize; /* Minimum PMA size, in bytes */
int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */
VdbeSorterIter *aIter; /* Array of iterators to merge */
int *aTree; /* Current state of incremental merge */
sqlite3_file *pTemp1; /* PMA file 1 */
SorterRecord *pRecord; /* Head of in-memory record list */
UnpackedRecord *pUnpacked; /* Used to unpack keys */
};
/*
** The following type is an iterator for a PMA. It caches the current key in
** variables nKey/aKey. If the iterator is at EOF, pFile==0.
*/
struct VdbeSorterIter {
i64 iReadOff; /* Current read offset */
i64 iEof; /* 1 byte past EOF for this iterator */
int nAlloc; /* Bytes of space at aAlloc */
int nKey; /* Number of bytes in key */
sqlite3_file *pFile; /* File iterator is reading from */
u8 *aAlloc; /* Allocated space */
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.
|
| ︙ | ︙ | |||
75091 75092 75093 75094 75095 75096 75097 | ExprList *pNew; struct ExprList_item *pItem, *pOldItem; int i; if( p==0 ) return 0; pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); if( pNew==0 ) return 0; pNew->iECursor = 0; | | > | | 75243 75244 75245 75246 75247 75248 75249 75250 75251 75252 75253 75254 75255 75256 75257 75258 75259 |
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->iECursor = 0;
pNew->nExpr = i = p->nExpr;
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
if( pItem==0 ){
sqlite3DbFree(db, pNew);
return 0;
}
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
Expr *pOldExpr = pOldItem->pExpr;
|
| ︙ | ︙ | |||
75160 75161 75162 75163 75164 75165 75166 |
}
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
IdList *pNew;
int i;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
| | > > > | 75313 75314 75315 75316 75317 75318 75319 75320 75321 75322 75323 75324 75325 75326 75327 75328 75329 75330 75331 75332 75333 75334 75335 |
}
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
IdList *pNew;
int i;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nId = p->nId;
pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
sqlite3DbFree(db, pNew);
return 0;
}
/* Note that because the size of the allocation for p->a[] is not
** necessarily a power of two, sqlite3IdListAppend() may not be called
** on the duplicate created by this function. */
for(i=0; i<p->nId; i++){
struct IdList_item *pNewItem = &pNew->a[i];
struct IdList_item *pOldItem = &p->a[i];
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->idx = pOldItem->idx;
}
return pNew;
|
| ︙ | ︙ | |||
75227 75228 75229 75230 75231 75232 75233 |
){
sqlite3 *db = pParse->db;
if( pList==0 ){
pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
if( pList==0 ){
goto no_mem;
}
| > | < | | | < | 75383 75384 75385 75386 75387 75388 75389 75390 75391 75392 75393 75394 75395 75396 75397 75398 75399 75400 75401 75402 75403 75404 75405 75406 |
){
sqlite3 *db = pParse->db;
if( pList==0 ){
pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
if( pList==0 ){
goto no_mem;
}
pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
if( pList->a==0 ) goto no_mem;
}else if( (pList->nExpr & (pList->nExpr-1))==0 ){
struct ExprList_item *a;
assert( pList->nExpr>0 );
a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
if( a==0 ){
goto no_mem;
}
pList->a = a;
}
assert( pList->a!=0 );
if( 1 ){
struct ExprList_item *pItem = &pList->a[pList->nExpr++];
memset(pItem, 0, sizeof(*pItem));
pItem->pExpr = pExpr;
}
|
| ︙ | ︙ | |||
75328 75329 75330 75331 75332 75333 75334 |
/*
** Delete an entire expression list.
*/
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
int i;
struct ExprList_item *pItem;
if( pList==0 ) return;
| | < | 75483 75484 75485 75486 75487 75488 75489 75490 75491 75492 75493 75494 75495 75496 75497 |
/*
** Delete an entire expression list.
*/
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
int i;
struct ExprList_item *pItem;
if( pList==0 ) return;
assert( pList->a!=0 || pList->nExpr==0 );
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
sqlite3ExprDelete(db, pItem->pExpr);
sqlite3DbFree(db, pItem->zName);
sqlite3DbFree(db, pItem->zSpan);
}
sqlite3DbFree(db, pList->a);
sqlite3DbFree(db, pList);
|
| ︙ | ︙ | |||
78010 78011 78012 78013 78014 78015 78016 |
*/
static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
int i;
pInfo->aCol = sqlite3ArrayAllocate(
db,
pInfo->aCol,
sizeof(pInfo->aCol[0]),
| < < < < | 78164 78165 78166 78167 78168 78169 78170 78171 78172 78173 78174 78175 78176 78177 78178 78179 78180 78181 78182 78183 78184 78185 78186 78187 78188 78189 78190 78191 78192 78193 78194 |
*/
static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
int i;
pInfo->aCol = sqlite3ArrayAllocate(
db,
pInfo->aCol,
sizeof(pInfo->aCol[0]),
&pInfo->nColumn,
&i
);
return i;
}
/*
** Add a new element to the pAggInfo->aFunc[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
int i;
pInfo->aFunc = sqlite3ArrayAllocate(
db,
pInfo->aFunc,
sizeof(pInfo->aFunc[0]),
&pInfo->nFunc,
&i
);
return i;
}
/*
** This is the xExprCallback for a tree walker. It is used to
|
| ︙ | ︙ | |||
78807 78808 78809 78810 78811 78812 78813 |
#endif
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
"'sqlite_autoindex_' || %Q || substr(name,%d+18) "
"ELSE name END "
| | | 78957 78958 78959 78960 78961 78962 78963 78964 78965 78966 78967 78968 78969 78970 78971 |
#endif
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
"'sqlite_autoindex_' || %Q || substr(name,%d+18) "
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
#ifndef SQLITE_OMIT_TRIGGER
zName,
#endif
zName, nTabName, zTabName
);
|
| ︙ | ︙ | |||
82676 82677 82678 82679 82680 82681 82682 |
sqlite3Strlen30(p->zName),p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
db->mallocFailed = 1;
return;
}
pParse->pNewTable = 0;
| < | 82826 82827 82828 82829 82830 82831 82832 82833 82834 82835 82836 82837 82838 82839 |
sqlite3Strlen30(p->zName),p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
db->mallocFailed = 1;
return;
}
pParse->pNewTable = 0;
db->flags |= SQLITE_InternChanges;
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
const char *zName = (const char *)pParse->sNameToken.z;
int nName;
assert( !pSelect && pCons && pEnd );
|
| ︙ | ︙ | |||
84097 84098 84099 84100 84101 84102 84103 | ** might be the same as the pArray parameter or it might be a different ** pointer if the array was resized. */ SQLITE_PRIVATE void *sqlite3ArrayAllocate( sqlite3 *db, /* Connection to notify of malloc failures */ void *pArray, /* Array of objects. Might be reallocated */ int szEntry, /* Size of each object in the array */ | < < | | | < | < | | < < < | 84246 84247 84248 84249 84250 84251 84252 84253 84254 84255 84256 84257 84258 84259 84260 84261 84262 84263 84264 84265 84266 84267 84268 84269 84270 84271 84272 84273 84274 84275 84276 84277 84278 84279 84280 84281 84282 84283 84284 84285 84286 84287 84288 84289 84290 84291 84292 84293 84294 84295 84296 84297 |
** might be the same as the pArray parameter or it might be a different
** pointer if the array was resized.
*/
SQLITE_PRIVATE void *sqlite3ArrayAllocate(
sqlite3 *db, /* Connection to notify of malloc failures */
void *pArray, /* Array of objects. Might be reallocated */
int szEntry, /* Size of each object in the array */
int *pnEntry, /* Number of objects currently in use */
int *pIdx /* Write the index of a new slot here */
){
char *z;
int n = *pnEntry;
if( (n & (n-1))==0 ){
int sz = (n==0) ? 1 : 2*n;
void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry);
if( pNew==0 ){
*pIdx = -1;
return pArray;
}
pArray = pNew;
}
z = (char*)pArray;
memset(&z[n * szEntry], 0, szEntry);
*pIdx = n;
++*pnEntry;
return pArray;
}
/*
** Append a new element to the given IdList. Create a new IdList if
** need be.
**
** A new IdList is returned, or NULL if malloc() fails.
*/
SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
int i;
if( pList==0 ){
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
if( pList==0 ) return 0;
}
pList->a = sqlite3ArrayAllocate(
db,
pList->a,
sizeof(pList->a[0]),
&pList->nId,
&i
);
if( i<0 ){
sqlite3IdListDelete(db, pList);
return 0;
}
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
|
| ︙ | ︙ | |||
86000 86001 86002 86003 86004 86005 86006 86007 86008 86009 86010 86011 86012 86013 |
/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
return context->pColl;
}
/*
** Implementation of the non-aggregate min() and max() functions
*/
static void minmaxFunc(
sqlite3_context *context,
int argc,
| > > > > > > > > | 86142 86143 86144 86145 86146 86147 86148 86149 86150 86151 86152 86153 86154 86155 86156 86157 86158 86159 86160 86161 86162 86163 |
/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
return context->pColl;
}
/*
** Indicate that the accumulator load should be skipped on this
** iteration of the aggregate loop.
*/
static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){
context->skipFlag = 1;
}
/*
** Implementation of the non-aggregate min() and max() functions
*/
static void minmaxFunc(
sqlite3_context *context,
int argc,
|
| ︙ | ︙ | |||
86381 86382 86383 86384 86385 86386 86387 |
** (or -9223372036854775808) since when you do abs() of that
** number of you get the same value back again. To do this
** in a way that is testable, mask the sign bit off of negative
** values, resulting in a positive value. Then take the
** 2s complement of that positive value. The end result can
** therefore be no less than -9223372036854775807.
*/
| | | 86531 86532 86533 86534 86535 86536 86537 86538 86539 86540 86541 86542 86543 86544 86545 |
** (or -9223372036854775808) since when you do abs() of that
** number of you get the same value back again. To do this
** in a way that is testable, mask the sign bit off of negative
** values, resulting in a positive value. Then take the
** 2s complement of that positive value. The end result can
** therefore be no less than -9223372036854775807.
*/
r = -(r & LARGEST_INT64);
}
sqlite3_result_int64(context, r);
}
/*
** Implementation of randomblob(N). Return a random blob
** that is N bytes long.
|
| ︙ | ︙ | |||
87307 87308 87309 87310 87311 87312 87313 |
int NotUsed,
sqlite3_value **argv
){
Mem *pArg = (Mem *)argv[0];
Mem *pBest;
UNUSED_PARAMETER(NotUsed);
| < > > | > > | | 87457 87458 87459 87460 87461 87462 87463 87464 87465 87466 87467 87468 87469 87470 87471 87472 87473 87474 87475 87476 87477 87478 87479 87480 87481 87482 87483 87484 87485 87486 87487 87488 87489 87490 87491 87492 87493 87494 87495 87496 87497 87498 87499 87500 87501 87502 87503 |
int NotUsed,
sqlite3_value **argv
){
Mem *pArg = (Mem *)argv[0];
Mem *pBest;
UNUSED_PARAMETER(NotUsed);
pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
if( !pBest ) return;
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
if( pBest->flags ) sqlite3SkipAccumulatorLoad(context);
}else if( pBest->flags ){
int max;
int cmp;
CollSeq *pColl = sqlite3GetFuncCollSeq(context);
/* This step function is used for both the min() and max() aggregates,
** the only difference between the two being that the sense of the
** comparison is inverted. For the max() aggregate, the
** sqlite3_user_data() function returns (void *)-1. For min() it
** returns (void *)db, where db is the sqlite3* database pointer.
** Therefore the next statement sets variable 'max' to 1 for the max()
** aggregate, or 0 for min().
*/
max = sqlite3_user_data(context)!=0;
cmp = sqlite3MemCompare(pBest, pArg, pColl);
if( (max && cmp<0) || (!max && cmp>0) ){
sqlite3VdbeMemCopy(pBest, pArg);
}else{
sqlite3SkipAccumulatorLoad(context);
}
}else{
sqlite3VdbeMemCopy(pBest, pArg);
}
}
static void minMaxFinalize(sqlite3_context *context){
sqlite3_value *pRes;
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
if( pRes ){
if( pRes->flags ){
sqlite3_result_value(context, pRes);
}
sqlite3VdbeMemRelease(pRes);
}
}
/*
|
| ︙ | ︙ | |||
91918 91919 91920 91921 91922 91923 91924 | ************************************************************************* ** This file contains code used to implement the PRAGMA command. */ /* ** Interpret the given string as a safety level. Return 0 for OFF, ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or | | > | | | | | | 92071 92072 92073 92074 92075 92076 92077 92078 92079 92080 92081 92082 92083 92084 92085 92086 92087 92088 92089 92090 92091 92092 92093 92094 92095 92096 92097 92098 92099 92100 92101 92102 92103 92104 92105 92106 92107 92108 92109 92110 92111 92112 92113 92114 92115 92116 |
*************************************************************************
** This file contains code used to implement the PRAGMA command.
*/
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
** unrecognized string argument. The FULL option is disallowed
** if the omitFull parameter it 1.
**
** Note that the values returned are one less that the values that
** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static u8 getSafetyLevel(const char *z, int omitFull, int dflt){
/* 123456789 123456789 */
static const char zText[] = "onoffalseyestruefull";
static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
int i, n;
if( sqlite3Isdigit(*z) ){
return (u8)sqlite3Atoi(z);
}
n = sqlite3Strlen30(z);
for(i=0; i<ArraySize(iLength)-omitFull; i++){
if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
return iValue[i];
}
}
return dflt;
}
/*
** Interpret the given string as a boolean value.
*/
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, int dflt){
return getSafetyLevel(z,1,dflt)!=0;
}
/* The sqlite3GetBoolean() function is used by other modules but the
** remainder of this file is specific to PRAGMA processing. So omit
** the rest of the file if PRAGMAs are omitted from the build.
*/
#if !defined(SQLITE_OMIT_PRAGMA)
|
| ︙ | ︙ | |||
92091 92092 92093 92094 92095 92096 92097 |
{ "vdbe_trace", SQLITE_VdbeTrace },
#endif
#ifndef SQLITE_OMIT_CHECK
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
#endif
/* The following is VERY experimental */
{ "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
| < | 92245 92246 92247 92248 92249 92250 92251 92252 92253 92254 92255 92256 92257 92258 |
{ "vdbe_trace", SQLITE_VdbeTrace },
#endif
#ifndef SQLITE_OMIT_CHECK
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
#endif
/* The following is VERY experimental */
{ "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
** flag if there are any active statements. */
{ "read_uncommitted", SQLITE_ReadUncommitted },
{ "recursive_triggers", SQLITE_RecTriggers },
/* This flag may only be set if both foreign-key and trigger support
|
| ︙ | ︙ | |||
92123 92124 92125 92126 92127 92128 92129 |
int mask = p->mask; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
/* Foreign key support may not be enabled or disabled while not
** in auto-commit mode. */
mask &= ~(SQLITE_ForeignKeys);
}
| | | 92276 92277 92278 92279 92280 92281 92282 92283 92284 92285 92286 92287 92288 92289 92290 |
int mask = p->mask; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
/* Foreign key support may not be enabled or disabled while not
** in auto-commit mode. */
mask &= ~(SQLITE_ForeignKeys);
}
if( sqlite3GetBoolean(zRight, 0) ){
db->flags |= mask;
}else{
db->flags &= ~mask;
}
/* Many of the flag-pragmas modify the code generated by the SQL
** compiler (eg. count_changes). So add an opcode to expire all
|
| ︙ | ︙ | |||
92214 92215 92216 92217 92218 92219 92220 |
int minusFlag /* True if a '-' sign preceded <value> */
){
char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
const char *zDb = 0; /* The database name */
Token *pId; /* Pointer to <id> token */
int iDb; /* Database index for <database> */
| > > | | | > | 92367 92368 92369 92370 92371 92372 92373 92374 92375 92376 92377 92378 92379 92380 92381 92382 92383 92384 92385 92386 |
int minusFlag /* True if a '-' sign preceded <value> */
){
char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
const char *zDb = 0; /* The database name */
Token *pId; /* Pointer to <id> token */
int iDb; /* Database index for <database> */
char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db); /* Prepared statement */
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
pParse->nMem = 2;
/* Interpret the [database.] part of the pragma statement. iDb is the
** index of the database this pragma is being applied to in db.aDb[]. */
iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
|
| ︙ | ︙ | |||
92247 92248 92249 92250 92251 92252 92253 92254 92255 92256 92257 92258 92259 92260 |
}
assert( pId2 );
zDb = pId2->n>0 ? pDb->zName : 0;
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
goto pragma_out;
}
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
** PRAGMA [database.]default_cache_size
** PRAGMA [database.]default_cache_size=N
**
** The first form reports the current persistent setting for the
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 92403 92404 92405 92406 92407 92408 92409 92410 92411 92412 92413 92414 92415 92416 92417 92418 92419 92420 92421 92422 92423 92424 92425 92426 92427 92428 92429 92430 92431 92432 92433 92434 92435 92436 92437 92438 92439 92440 92441 92442 92443 92444 |
}
assert( pId2 );
zDb = pId2->n>0 ? pDb->zName : 0;
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
goto pragma_out;
}
/* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS
** connection. If it returns SQLITE_OK, then assume that the VFS
** handled the pragma and generate a no-op prepared statement.
*/
aFcntl[0] = 0;
aFcntl[1] = zLeft;
aFcntl[2] = zRight;
aFcntl[3] = 0;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
if( rc==SQLITE_OK ){
if( aFcntl[0] ){
int mem = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_String8, 0, mem, 0, aFcntl[0], 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "result", SQLITE_STATIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
sqlite3_free(aFcntl[0]);
}
}else if( rc!=SQLITE_NOTFOUND ){
if( aFcntl[0] ){
sqlite3ErrorMsg(pParse, "%s", aFcntl[0]);
sqlite3_free(aFcntl[0]);
}
pParse->nErr++;
pParse->rc = rc;
}else
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
** PRAGMA [database.]default_cache_size
** PRAGMA [database.]default_cache_size=N
**
** The first form reports the current persistent setting for the
|
| ︙ | ︙ | |||
92339 92340 92341 92342 92343 92344 92345 |
** flag setting and reports thenew value.
*/
if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){
Btree *pBt = pDb->pBt;
int b = -1;
assert( pBt!=0 );
if( zRight ){
| | | 92523 92524 92525 92526 92527 92528 92529 92530 92531 92532 92533 92534 92535 92536 92537 |
** flag setting and reports thenew value.
*/
if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){
Btree *pBt = pDb->pBt;
int b = -1;
assert( pBt!=0 );
if( zRight ){
b = sqlite3GetBoolean(zRight, 0);
}
if( pId2->n==0 && b>=0 ){
int ii;
for(ii=0; ii<db->nDb; ii++){
sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
}
}
|
| ︙ | ︙ | |||
92534 92535 92536 92537 92538 92539 92540 |
db->nextAutovac = (u8)eAuto;
if( ALWAYS(eAuto>=0) ){
/* Call SetAutoVacuum() to set initialize the internal auto and
** incr-vacuum flags. This is required in case this connection
** creates the database file. It is important that it is created
** as an auto-vacuum capable db.
*/
| | | 92718 92719 92720 92721 92722 92723 92724 92725 92726 92727 92728 92729 92730 92731 92732 |
db->nextAutovac = (u8)eAuto;
if( ALWAYS(eAuto>=0) ){
/* Call SetAutoVacuum() to set initialize the internal auto and
** incr-vacuum flags. This is required in case this connection
** creates the database file. It is important that it is created
** as an auto-vacuum capable db.
*/
rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
/* When setting the auto_vacuum mode to either "full" or
** "incremental", write the value of meta[6] in the database
** file. Before writing to meta[6], check that meta[3] indicates
** that this really is an auto-vacuum capable database.
*/
static const VdbeOpList setMeta6[] = {
|
| ︙ | ︙ | |||
92652 92653 92654 92655 92656 92657 92658 |
"temp_store_directory", SQLITE_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
| < | 92836 92837 92838 92839 92840 92841 92842 92843 92844 92845 92846 92847 92848 92849 |
"temp_store_directory", SQLITE_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
int res;
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
goto pragma_out;
}
}
|
| ︙ | ︙ | |||
92744 92745 92746 92747 92748 92749 92750 |
if( !zRight ){
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
}else{
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
}else{
| | | 92927 92928 92929 92930 92931 92932 92933 92934 92935 92936 92937 92938 92939 92940 92941 |
if( !zRight ){
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
}else{
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
}else{
pDb->safety_level = getSafetyLevel(zRight,0,1)+1;
}
}
}else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
if( flagPragma(pParse, zLeft, zRight) ){
|
| ︙ | ︙ | |||
92943 92944 92945 92946 92947 92948 92949 |
}
}else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){
| | | | 93126 93127 93128 93129 93130 93131 93132 93133 93134 93135 93136 93137 93138 93139 93140 93141 93142 93143 93144 93145 93146 93147 93148 93149 93150 93151 93152 93153 93154 |
}
}else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){
if( sqlite3GetBoolean(zRight, 0) ){
sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
}
}
}else
#endif
/* Reinstall the LIKE and GLOB functions. The variant of LIKE
** used will be case sensitive or not depending on the RHS.
*/
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
if( zRight ){
sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight, 0));
}
}else
#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
#endif
|
| ︙ | ︙ | |||
94383 94384 94385 94386 94387 94388 94389 94390 94391 94392 94393 94394 94395 94396 |
pNew = &standin;
memset(pNew, 0, sizeof(*pNew));
}
if( pEList==0 ){
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
}
pNew->pEList = pEList;
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy;
pNew->selFlags = isDistinct ? SF_Distinct : 0;
pNew->op = TK_SELECT;
| > | 94566 94567 94568 94569 94570 94571 94572 94573 94574 94575 94576 94577 94578 94579 94580 |
pNew = &standin;
memset(pNew, 0, sizeof(*pNew));
}
if( pEList==0 ){
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
}
pNew->pEList = pEList;
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy;
pNew->selFlags = isDistinct ? SF_Distinct : 0;
pNew->op = TK_SELECT;
|
| ︙ | ︙ | |||
95567 95568 95569 95570 95571 95572 95573 | int cnt; /* Index added to make the name unique */ Column *aCol, *pCol; /* For looping over result columns */ int nCol; /* Number of columns in the result set */ Expr *p; /* Expression for a single result column */ char *zName; /* Column name */ int nName; /* Size of name in zName[] */ | | | 95751 95752 95753 95754 95755 95756 95757 95758 95759 95760 95761 95762 95763 95764 95765 |
int cnt; /* Index added to make the name unique */
Column *aCol, *pCol; /* For looping over result columns */
int nCol; /* Number of columns in the result set */
Expr *p; /* Expression for a single result column */
char *zName; /* Column name */
int nName; /* Size of name in zName[] */
*pnCol = nCol = pEList ? pEList->nExpr : 0;
aCol = *paCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
if( aCol==0 ) return SQLITE_NOMEM;
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
/* Get an appropriate name for the column
*/
p = pEList->a[i].pExpr;
assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
|
| ︙ | ︙ | |||
95921 95922 95923 95924 95925 95926 95927 |
}
/* Make sure all SELECTs in the statement have the same number of elements
** in their result sets.
*/
assert( p->pEList && pPrior->pEList );
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
| > > > | | > | 96105 96106 96107 96108 96109 96110 96111 96112 96113 96114 96115 96116 96117 96118 96119 96120 96121 96122 96123 96124 |
}
/* Make sure all SELECTs in the statement have the same number of elements
** in their result sets.
*/
assert( p->pEList && pPrior->pEList );
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
if( p->selFlags & SF_Values ){
sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
}else{
sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
" do not have the same number of result columns", selectOpName(p->op));
}
rc = 1;
goto multi_select_end;
}
/* Compound SELECTs that have an ORDER BY clause are handled separately.
*/
if( p->pOrderBy ){
|
| ︙ | ︙ | |||
96538 96539 96540 96541 96542 96543 96544 |
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
if( pNew==0 ) return SQLITE_NOMEM;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
| | | 96726 96727 96728 96729 96730 96731 96732 96733 96734 96735 96736 96737 96738 96739 96740 |
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
if( pNew==0 ) return SQLITE_NOMEM;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
if( pOrderBy ) pOrderBy->a[nOrderBy++].iOrderByCol = (u16)i;
}
}
}
/* Compute the comparison permutation and keyinfo that is used with
** the permutation used to determine if the next
** row of results comes from selectA or selectB. Also add explicit
|
| ︙ | ︙ | |||
97901 97902 97903 97904 97905 97906 97907 97908 97909 97910 97911 97912 97913 97914 |
/*
** Update the accumulator memory cells for an aggregate based on
** the current cursor position.
*/
static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
int i;
struct AggInfo_func *pF;
struct AggInfo_col *pC;
pAggInfo->directMode = 1;
sqlite3ExprCacheClear(pParse);
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
| > > | 98089 98090 98091 98092 98093 98094 98095 98096 98097 98098 98099 98100 98101 98102 98103 98104 |
/*
** Update the accumulator memory cells for an aggregate based on
** the current cursor position.
*/
static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
int i;
int regHit = 0;
int addrHitTest = 0;
struct AggInfo_func *pF;
struct AggInfo_col *pC;
pAggInfo->directMode = 1;
sqlite3ExprCacheClear(pParse);
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
|
| ︙ | ︙ | |||
97936 97937 97938 97939 97940 97941 97942 |
assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
}
if( !pColl ){
pColl = pParse->db->pDfltColl;
}
| > | | 98126 98127 98128 98129 98130 98131 98132 98133 98134 98135 98136 98137 98138 98139 98140 98141 |
assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
}
if( !pColl ){
pColl = pParse->db->pDfltColl;
}
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
}
sqlite3VdbeAddOp4(v, OP_AggStep, 0, regAgg, pF->iMem,
(void*)pF->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg);
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
if( addrNext ){
|
| ︙ | ︙ | |||
97959 97960 97961 97962 97963 97964 97965 97966 97967 97968 97969 97970 97971 97972 97973 97974 97975 97976 97977 97978 |
** to pC->iMem. But by the time the value is used, the original register
** may have been used, invalidating the underlying buffer holding the
** text or blob value. See ticket [883034dcb5].
**
** Another solution would be to change the OP_SCopy used to copy cached
** values to an OP_Copy.
*/
sqlite3ExprCacheClear(pParse);
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
pAggInfo->directMode = 0;
sqlite3ExprCacheClear(pParse);
}
/*
** Add a single OP_Explain instruction to the VDBE to explain a simple
** count(*) query ("SELECT count(*) FROM pTab").
*/
#ifndef SQLITE_OMIT_EXPLAIN
| > > > > > > | 98150 98151 98152 98153 98154 98155 98156 98157 98158 98159 98160 98161 98162 98163 98164 98165 98166 98167 98168 98169 98170 98171 98172 98173 98174 98175 |
** to pC->iMem. But by the time the value is used, the original register
** may have been used, invalidating the underlying buffer holding the
** text or blob value. See ticket [883034dcb5].
**
** Another solution would be to change the OP_SCopy used to copy cached
** values to an OP_Copy.
*/
if( regHit ){
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit);
}
sqlite3ExprCacheClear(pParse);
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
pAggInfo->directMode = 0;
sqlite3ExprCacheClear(pParse);
if( addrHitTest ){
sqlite3VdbeJumpHere(v, addrHitTest);
}
}
/*
** Add a single OP_Explain instruction to the VDBE to explain a simple
** count(*) query ("SELECT count(*) FROM pTab").
*/
#ifndef SQLITE_OMIT_EXPLAIN
|
| ︙ | ︙ | |||
98905 98906 98907 98908 98909 98910 98911 | } sqlite3ExplainPrintf(pVdbe, "END"); sqlite3ExplainPop(pVdbe); } /* End of the structure debug printing code *****************************************************************************/ | | | 99102 99103 99104 99105 99106 99107 99108 99109 99110 99111 99112 99113 99114 99115 99116 | } sqlite3ExplainPrintf(pVdbe, "END"); sqlite3ExplainPop(pVdbe); } /* End of the structure debug printing code *****************************************************************************/ #endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */ /************** End of select.c **********************************************/ /************** Begin file table.c *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of |
| ︙ | ︙ | |||
101084 101085 101086 101087 101088 101089 101090 101091 101092 101093 101094 101095 101096 101097 101098 101099 101100 101101 101102 101103 101104 |
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
if( nKey ) db->nextPagesize = 0;
}
#endif
/* Do not attempt to change the page size for a WAL database */
if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
==PAGER_JOURNALMODE_WAL ){
db->nextPagesize = 0;
}
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| NEVER(db->mallocFailed)
){
rc = SQLITE_NOMEM;
goto end_of_vacuum;
}
| > > > > > > > > > > > > < < < < < < < < | 101281 101282 101283 101284 101285 101286 101287 101288 101289 101290 101291 101292 101293 101294 101295 101296 101297 101298 101299 101300 101301 101302 101303 101304 101305 101306 101307 101308 101309 101310 101311 101312 101313 101314 101315 101316 101317 101318 101319 101320 101321 101322 101323 101324 101325 101326 |
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
if( nKey ) db->nextPagesize = 0;
}
#endif
rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Begin a transaction and take an exclusive lock on the main database
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
** to ensure that we do not try to change the page-size on a WAL database.
*/
rc = execSql(db, pzErrMsg, "BEGIN;");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeBeginTrans(pMain, 2);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Do not attempt to change the page size for a WAL database */
if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
==PAGER_JOURNALMODE_WAL ){
db->nextPagesize = 0;
}
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| NEVER(db->mallocFailed)
){
rc = SQLITE_NOMEM;
goto end_of_vacuum;
}
#ifndef SQLITE_OMIT_AUTOVACUUM
sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
sqlite3BtreeGetAutoVacuum(pMain));
#endif
/* Query the schema of the main database. Create a mirror schema
** in the temporary database.
*/
rc = execExecSql(db, pzErrMsg,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
" AND rootpage>0"
|
| ︙ | ︙ | |||
101532 101533 101534 101535 101536 101537 101538 | ** statement. The module name has been parsed, but the optional list ** of parameters that follow the module name are still pending. */ SQLITE_PRIVATE void sqlite3VtabBeginParse( Parse *pParse, /* Parsing context */ Token *pName1, /* Name of new table, or database name */ Token *pName2, /* Name of new table or NULL */ | | > | | 101733 101734 101735 101736 101737 101738 101739 101740 101741 101742 101743 101744 101745 101746 101747 101748 101749 101750 101751 101752 101753 101754 |
** statement. The module name has been parsed, but the optional list
** of parameters that follow the module name are still pending.
*/
SQLITE_PRIVATE void sqlite3VtabBeginParse(
Parse *pParse, /* Parsing context */
Token *pName1, /* Name of new table, or database name */
Token *pName2, /* Name of new table or NULL */
Token *pModuleName, /* Name of the module for the virtual table */
int ifNotExists /* No error if the table already exists */
){
int iDb; /* The database the table is being created in */
Table *pTable; /* The new virtual table */
sqlite3 *db; /* Database connection */
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists);
pTable = pParse->pNewTable;
if( pTable==0 ) return;
assert( 0==pTable->pIndex );
db = pParse->db;
iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
assert( iDb>=0 );
|
| ︙ | ︙ | |||
101573 101574 101575 101576 101577 101578 101579 |
/*
** This routine takes the module argument that has been accumulating
** in pParse->zArg[] and appends it to the list of arguments on the
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
| | | 101775 101776 101777 101778 101779 101780 101781 101782 101783 101784 101785 101786 101787 101788 101789 |
/*
** This routine takes the module argument that has been accumulating
** in pParse->zArg[] and appends it to the list of arguments on the
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){
const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n;
sqlite3 *db = pParse->db;
addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
}
}
|
| ︙ | ︙ | |||
105425 105426 105427 105428 105429 105430 105431 |
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
wsFlags |= (rev ? WHERE_REVERSE : 0);
}
/* If there is a DISTINCT qualifier and this index will scan rows in
** order of the DISTINCT expressions, clear bDist and set the appropriate
** flags in wsFlags. */
| | > > | 105627 105628 105629 105630 105631 105632 105633 105634 105635 105636 105637 105638 105639 105640 105641 105642 105643 |
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
wsFlags |= (rev ? WHERE_REVERSE : 0);
}
/* If there is a DISTINCT qualifier and this index will scan rows in
** order of the DISTINCT expressions, clear bDist and set the appropriate
** flags in wsFlags. */
if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq)
&& (wsFlags & WHERE_COLUMN_IN)==0
){
bDist = 0;
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT;
}
/* If currently calculating the cost of using an index (not the IPK
** index), determine if all required column data may be obtained without
** using the main table (i.e. if the index is a covering
|
| ︙ | ︙ | |||
106122 106123 106124 106125 106126 106127 106128 | ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ static Bitmask codeOneLoopStart( WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ | | < | 106326 106327 106328 106329 106330 106331 106332 106333 106334 106335 106336 106337 106338 106339 106340 |
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
*/
static Bitmask codeOneLoopStart(
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
int iLevel, /* Which level of pWInfo->a[] should be coded */
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
Bitmask notReady /* Which tables are currently available */
){
int j, k; /* Loop counters */
int iCur; /* The VDBE cursor for the table */
int addrNxt; /* Where to jump to continue with the next IN case */
int omitTable; /* True if we use the index only */
int bRev; /* True if we need to scan in reverse order */
WhereLevel *pLevel; /* The where level to be coded */
|
| ︙ | ︙ | |||
106662 106663 106664 106665 106666 106667 106668 106669 106670 |
}
iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
/* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y
** Then for every term xN, evaluate as the subexpression: xN AND z
** That way, terms in y that are factored into the disjunction will
** be picked up by the recursive calls to sqlite3WhereBegin() below.
*/
if( pWC->nTerm>1 ){
| > > > > > > > > > > > > | > | > > | 106865 106866 106867 106868 106869 106870 106871 106872 106873 106874 106875 106876 106877 106878 106879 106880 106881 106882 106883 106884 106885 106886 106887 106888 106889 106890 106891 106892 106893 106894 106895 106896 106897 |
}
iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
/* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y
** Then for every term xN, evaluate as the subexpression: xN AND z
** That way, terms in y that are factored into the disjunction will
** be picked up by the recursive calls to sqlite3WhereBegin() below.
**
** Actually, each subexpression is converted to "xN AND w" where w is
** the "interesting" terms of z - terms that did not originate in the
** ON or USING clause of a LEFT JOIN, and terms that are usable as
** indices.
*/
if( pWC->nTerm>1 ){
int iTerm;
for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
Expr *pExpr = pWC->a[iTerm].pExpr;
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue;
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr);
}
if( pAndExpr ){
pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
}
}
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr;
|
| ︙ | ︙ | |||
106707 106708 106709 106710 106711 106712 106713 |
if( pSubWInfo->untestedTerms ) untestedTerms = 1;
/* Finish the loop through table entries that match term pOrTerm. */
sqlite3WhereEnd(pSubWInfo);
}
}
}
| > > | > | 106925 106926 106927 106928 106929 106930 106931 106932 106933 106934 106935 106936 106937 106938 106939 106940 106941 106942 |
if( pSubWInfo->untestedTerms ) untestedTerms = 1;
/* Finish the loop through table entries that match term pOrTerm. */
sqlite3WhereEnd(pSubWInfo);
}
}
}
if( pAndExpr ){
pAndExpr->pLeft = 0;
sqlite3ExprDelete(pParse->db, pAndExpr);
}
sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
sqlite3VdbeResolveLabel(v, iLoopBody);
if( pWInfo->nLevel>1 ) sqlite3StackFree(pParse->db, pOrTab);
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
|
| ︙ | ︙ | |||
107363 107364 107365 107366 107367 107368 107369 |
** loop below generates code for a single nested loop of the VM
** program.
*/
notReady = ~(Bitmask)0;
for(i=0; i<nTabList; i++){
pLevel = &pWInfo->a[i];
explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
| | | 107584 107585 107586 107587 107588 107589 107590 107591 107592 107593 107594 107595 107596 107597 107598 |
** loop below generates code for a single nested loop of the VM
** program.
*/
notReady = ~(Bitmask)0;
for(i=0; i<nTabList; i++){
pLevel = &pWInfo->a[i];
explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
pWInfo->iContinue = pLevel->addrCont;
}
#ifdef SQLITE_TEST /* For testing and debugging use only */
/* Record in the query plan information about the current table
** and the index used to access it (if any). If the table itself
** is not used, its name is just '{}'. If no index is used
|
| ︙ | ︙ | |||
107618 107619 107620 107621 107622 107623 107624 107625 107626 107627 107628 107629 107630 107631 |
struct TrigEvent { int a; IdList * b; };
/*
** An instance of this structure holds the ATTACH key and the key type.
*/
struct AttachKey { int type; Token key; };
/* This is a utility routine used to set the ExprSpan.zStart and
** ExprSpan.zEnd values of pOut so that the span covers the complete
** range of text beginning with pStart and going to the end of pEnd.
*/
static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
pOut->zStart = pStart->z;
| > > > > > > > > | 107839 107840 107841 107842 107843 107844 107845 107846 107847 107848 107849 107850 107851 107852 107853 107854 107855 107856 107857 107858 107859 107860 |
struct TrigEvent { int a; IdList * b; };
/*
** An instance of this structure holds the ATTACH key and the key type.
*/
struct AttachKey { int type; Token key; };
/*
** One or more VALUES claues
*/
struct ValueList {
ExprList *pList;
Select *pSelect;
};
/* This is a utility routine used to set the ExprSpan.zStart and
** ExprSpan.zEnd values of pOut so that the span covers the complete
** range of text beginning with pStart and going to the end of pEnd.
*/
static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
pOut->zStart = pStart->z;
|
| ︙ | ︙ | |||
107741 107742 107743 107744 107745 107746 107747 | ** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. */ #define YYCODETYPE unsigned char | | < | | | | | | | | > | > | | | | | | 107970 107971 107972 107973 107974 107975 107976 107977 107978 107979 107980 107981 107982 107983 107984 107985 107986 107987 107988 107989 107990 107991 107992 107993 107994 107995 107996 107997 107998 107999 108000 108001 108002 108003 108004 108005 108006 108007 108008 108009 108010 108011 108012 108013 108014 |
** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser
** YYNSTATE the combined number of states.
** YYNRULE the number of rules in the grammar
** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
*/
#define YYCODETYPE unsigned char
#define YYNOCODE 251
#define YYACTIONTYPE unsigned short int
#define YYWILDCARD 67
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
struct LimitVal yy64;
Expr* yy122;
Select* yy159;
IdList* yy180;
struct {int value; int mask;} yy207;
u8 yy258;
struct LikeOp yy318;
TriggerStep* yy327;
ExprSpan yy342;
SrcList* yy347;
int yy392;
struct TrigEvent yy410;
ExprList* yy442;
struct ValueList yy487;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define sqlite3ParserARG_SDECL Parse *pParse;
#define sqlite3ParserARG_PDECL ,Parse *pParse
#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
#define sqlite3ParserARG_STORE yypParser->pParse = pParse
#define YYNSTATE 629
#define YYNRULE 327
#define YYFALLBACK 1
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
/* The yyzerominor constant is used to initialize instances of
** YYMINORTYPE objects to zero. */
|
| ︙ | ︙ | |||
107840 107841 107842 107843 107844 107845 107846 | ** yy_action. Used to detect hash collisions. ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 108070 108071 108072 108073 108074 108075 108076 108077 108078 108079 108080 108081 108082 108083 108084 108085 108086 108087 108088 108089 108090 108091 108092 108093 108094 108095 108096 108097 108098 108099 108100 108101 108102 108103 108104 108105 108106 108107 108108 108109 108110 108111 108112 108113 108114 108115 108116 108117 108118 108119 108120 108121 108122 108123 108124 108125 108126 108127 108128 108129 108130 108131 108132 108133 108134 108135 108136 108137 108138 108139 108140 108141 108142 108143 108144 108145 108146 108147 108148 108149 108150 108151 108152 108153 108154 108155 108156 108157 108158 108159 108160 108161 108162 108163 108164 108165 108166 108167 108168 108169 108170 108171 108172 108173 108174 108175 108176 108177 108178 108179 108180 108181 108182 108183 108184 108185 108186 108187 108188 108189 108190 108191 108192 108193 108194 108195 108196 108197 108198 108199 108200 108201 108202 108203 108204 108205 108206 108207 108208 108209 108210 108211 108212 108213 108214 108215 108216 108217 108218 108219 108220 108221 108222 108223 108224 108225 108226 108227 108228 108229 108230 108231 108232 108233 108234 108235 108236 108237 108238 108239 108240 108241 108242 108243 108244 108245 108246 108247 108248 108249 108250 108251 108252 108253 108254 108255 108256 108257 108258 108259 108260 108261 108262 108263 108264 108265 108266 108267 108268 108269 108270 108271 108272 108273 108274 108275 108276 108277 108278 108279 108280 108281 108282 108283 108284 108285 108286 108287 108288 108289 108290 108291 108292 108293 108294 108295 108296 108297 108298 108299 108300 108301 108302 108303 108304 108305 108306 108307 108308 108309 108310 108311 108312 108313 108314 108315 108316 108317 108318 108319 108320 108321 108322 108323 108324 108325 108326 108327 108328 108329 108330 108331 108332 108333 108334 108335 108336 108337 108338 108339 108340 108341 108342 108343 108344 108345 108346 108347 108348 108349 108350 108351 108352 108353 108354 108355 108356 108357 108358 108359 108360 108361 108362 108363 108364 108365 108366 108367 108368 108369 108370 108371 108372 108373 108374 108375 108376 108377 108378 108379 108380 108381 108382 108383 108384 108385 108386 108387 108388 108389 108390 108391 108392 108393 108394 108395 108396 108397 108398 108399 108400 108401 108402 108403 108404 108405 108406 108407 108408 108409 108410 108411 108412 108413 108414 108415 108416 108417 108418 108419 108420 108421 108422 108423 108424 108425 108426 108427 108428 108429 108430 108431 108432 108433 108434 108435 108436 108437 108438 108439 108440 108441 108442 108443 108444 108445 108446 108447 108448 108449 108450 108451 108452 108453 108454 108455 108456 108457 108458 108459 108460 108461 108462 108463 108464 108465 108466 108467 108468 108469 108470 108471 108472 108473 108474 108475 108476 108477 108478 108479 108480 108481 108482 108483 108484 108485 108486 108487 108488 108489 108490 108491 108492 108493 108494 108495 108496 108497 108498 108499 108500 108501 108502 108503 108504 108505 108506 108507 108508 108509 108510 108511 108512 108513 108514 108515 108516 108517 108518 108519 108520 108521 108522 108523 108524 108525 108526 108527 108528 108529 108530 108531 108532 108533 108534 108535 108536 108537 108538 108539 108540 108541 108542 108543 108544 108545 108546 108547 108548 108549 108550 108551 108552 108553 |
** yy_action. Used to detect hash collisions.
** yy_shift_ofst[] For each state, the offset into yy_action for
** shifting terminals.
** yy_reduce_ofst[] For each state, the offset into yy_action for
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
*/
#define YY_ACTTAB_COUNT (1580)
static const YYACTIONTYPE yy_action[] = {
/* 0 */ 310, 328, 574, 573, 15, 172, 187, 596, 56, 56,
/* 10 */ 56, 56, 49, 54, 54, 54, 54, 53, 53, 52,
/* 20 */ 52, 52, 51, 234, 622, 621, 626, 622, 621, 299,
/* 30 */ 589, 583, 56, 56, 56, 56, 236, 54, 54, 54,
/* 40 */ 54, 53, 53, 52, 52, 52, 51, 234, 351, 57,
/* 50 */ 58, 48, 581, 580, 582, 582, 55, 55, 56, 56,
/* 60 */ 56, 56, 570, 54, 54, 54, 54, 53, 53, 52,
/* 70 */ 52, 52, 51, 234, 310, 596, 326, 607, 233, 232,
/* 80 */ 33, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 90 */ 51, 234, 619, 618, 326, 619, 618, 166, 605, 492,
/* 100 */ 381, 378, 377, 235, 589, 583, 554, 495, 1, 59,
/* 110 */ 19, 376, 622, 621, 53, 53, 52, 52, 52, 51,
/* 120 */ 234, 571, 571, 57, 58, 48, 581, 580, 582, 582,
/* 130 */ 55, 55, 56, 56, 56, 56, 215, 54, 54, 54,
/* 140 */ 54, 53, 53, 52, 52, 52, 51, 234, 310, 224,
/* 150 */ 50, 47, 147, 177, 139, 281, 384, 276, 383, 169,
/* 160 */ 408, 553, 578, 578, 622, 621, 272, 224, 439, 550,
/* 170 */ 552, 410, 139, 281, 384, 276, 383, 169, 589, 583,
/* 180 */ 619, 618, 280, 620, 272, 195, 413, 309, 440, 441,
/* 190 */ 567, 491, 214, 279, 560, 600, 92, 57, 58, 48,
/* 200 */ 581, 580, 582, 582, 55, 55, 56, 56, 56, 56,
/* 210 */ 559, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 220 */ 51, 234, 310, 464, 233, 232, 558, 133, 519, 50,
/* 230 */ 47, 147, 619, 618, 565, 436, 397, 515, 514, 518,
/* 240 */ 410, 387, 438, 389, 437, 622, 621, 442, 570, 433,
/* 250 */ 203, 390, 589, 583, 6, 413, 166, 670, 250, 381,
/* 260 */ 378, 377, 525, 190, 600, 92, 594, 571, 571, 465,
/* 270 */ 376, 57, 58, 48, 581, 580, 582, 582, 55, 55,
/* 280 */ 56, 56, 56, 56, 599, 54, 54, 54, 54, 53,
/* 290 */ 53, 52, 52, 52, 51, 234, 310, 592, 592, 592,
/* 300 */ 490, 182, 247, 548, 249, 397, 273, 410, 7, 439,
/* 310 */ 398, 606, 67, 619, 618, 620, 472, 256, 347, 255,
/* 320 */ 473, 620, 413, 576, 620, 65, 589, 583, 236, 440,
/* 330 */ 336, 600, 92, 68, 364, 192, 481, 622, 621, 547,
/* 340 */ 622, 621, 560, 323, 207, 57, 58, 48, 581, 580,
/* 350 */ 582, 582, 55, 55, 56, 56, 56, 56, 559, 54,
/* 360 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 234,
/* 370 */ 310, 410, 397, 146, 558, 531, 401, 348, 599, 166,
/* 380 */ 248, 204, 381, 378, 377, 541, 413, 171, 337, 570,
/* 390 */ 622, 621, 40, 376, 38, 600, 74, 465, 548, 490,
/* 400 */ 589, 583, 532, 350, 579, 619, 618, 297, 619, 618,
/* 410 */ 480, 67, 470, 39, 620, 599, 406, 574, 573, 57,
/* 420 */ 58, 48, 581, 580, 582, 582, 55, 55, 56, 56,
/* 430 */ 56, 56, 577, 54, 54, 54, 54, 53, 53, 52,
/* 440 */ 52, 52, 51, 234, 310, 256, 347, 255, 530, 52,
/* 450 */ 52, 52, 51, 234, 345, 564, 236, 386, 619, 618,
/* 460 */ 957, 185, 418, 2, 408, 410, 578, 578, 198, 197,
/* 470 */ 196, 499, 183, 167, 589, 583, 671, 570, 505, 506,
/* 480 */ 413, 267, 601, 672, 546, 208, 602, 36, 601, 600,
/* 490 */ 91, 468, 602, 57, 58, 48, 581, 580, 582, 582,
/* 500 */ 55, 55, 56, 56, 56, 56, 202, 54, 54, 54,
/* 510 */ 54, 53, 53, 52, 52, 52, 51, 234, 310, 599,
/* 520 */ 157, 408, 527, 578, 578, 263, 490, 265, 410, 873,
/* 530 */ 410, 474, 474, 366, 373, 410, 504, 428, 67, 290,
/* 540 */ 599, 620, 352, 413, 408, 413, 578, 578, 589, 583,
/* 550 */ 413, 382, 600, 92, 600, 16, 543, 62, 503, 600,
/* 560 */ 92, 408, 346, 578, 578, 168, 45, 57, 58, 48,
/* 570 */ 581, 580, 582, 582, 55, 55, 56, 56, 56, 56,
/* 580 */ 200, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 590 */ 51, 234, 310, 393, 395, 534, 510, 617, 616, 615,
/* 600 */ 318, 314, 172, 66, 596, 410, 338, 596, 324, 571,
/* 610 */ 571, 50, 47, 147, 599, 629, 627, 330, 539, 315,
/* 620 */ 413, 30, 589, 583, 272, 236, 199, 144, 176, 600,
/* 630 */ 73, 420, 947, 620, 947, 420, 946, 351, 946, 175,
/* 640 */ 596, 57, 58, 48, 581, 580, 582, 582, 55, 55,
/* 650 */ 56, 56, 56, 56, 410, 54, 54, 54, 54, 53,
/* 660 */ 53, 52, 52, 52, 51, 234, 310, 261, 410, 413,
/* 670 */ 269, 208, 596, 363, 410, 596, 424, 360, 600, 69,
/* 680 */ 424, 327, 620, 413, 50, 47, 147, 410, 358, 413,
/* 690 */ 575, 553, 600, 94, 483, 509, 589, 583, 600, 97,
/* 700 */ 552, 484, 413, 620, 188, 599, 551, 563, 596, 566,
/* 710 */ 334, 600, 95, 205, 201, 57, 58, 48, 581, 580,
/* 720 */ 582, 582, 55, 55, 56, 56, 56, 56, 352, 54,
/* 730 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 234,
/* 740 */ 310, 410, 261, 410, 167, 22, 356, 599, 359, 623,
/* 750 */ 50, 47, 147, 548, 357, 562, 413, 620, 413, 332,
/* 760 */ 523, 270, 410, 167, 620, 600, 104, 600, 103, 603,
/* 770 */ 589, 583, 339, 539, 304, 423, 222, 413, 174, 304,
/* 780 */ 422, 561, 567, 405, 214, 260, 600, 106, 620, 57,
/* 790 */ 58, 48, 581, 580, 582, 582, 55, 55, 56, 56,
/* 800 */ 56, 56, 410, 54, 54, 54, 54, 53, 53, 52,
/* 810 */ 52, 52, 51, 234, 310, 410, 557, 413, 410, 421,
/* 820 */ 273, 35, 512, 146, 421, 12, 600, 107, 213, 144,
/* 830 */ 413, 410, 32, 413, 410, 620, 365, 353, 358, 600,
/* 840 */ 134, 11, 600, 135, 589, 583, 413, 21, 548, 413,
/* 850 */ 316, 148, 620, 620, 170, 600, 98, 223, 600, 102,
/* 860 */ 374, 168, 167, 57, 58, 48, 581, 580, 582, 582,
/* 870 */ 55, 55, 56, 56, 56, 56, 410, 54, 54, 54,
/* 880 */ 54, 53, 53, 52, 52, 52, 51, 234, 310, 410,
/* 890 */ 273, 413, 410, 273, 212, 469, 410, 167, 628, 2,
/* 900 */ 600, 101, 545, 221, 413, 620, 130, 413, 620, 410,
/* 910 */ 539, 413, 537, 600, 93, 315, 600, 100, 589, 583,
/* 920 */ 600, 77, 425, 305, 413, 620, 254, 322, 599, 458,
/* 930 */ 320, 171, 543, 600, 96, 521, 520, 57, 58, 48,
/* 940 */ 581, 580, 582, 582, 55, 55, 56, 56, 56, 56,
/* 950 */ 410, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 960 */ 51, 234, 310, 410, 273, 413, 410, 457, 358, 35,
/* 970 */ 426, 230, 306, 319, 600, 138, 467, 520, 413, 620,
/* 980 */ 143, 413, 410, 620, 410, 353, 529, 600, 137, 142,
/* 990 */ 600, 136, 589, 583, 604, 261, 528, 413, 229, 413,
/* 1000 */ 620, 321, 495, 28, 543, 543, 600, 76, 600, 90,
/* 1010 */ 620, 57, 46, 48, 581, 580, 582, 582, 55, 55,
/* 1020 */ 56, 56, 56, 56, 410, 54, 54, 54, 54, 53,
/* 1030 */ 53, 52, 52, 52, 51, 234, 310, 261, 451, 413,
/* 1040 */ 410, 211, 611, 285, 283, 610, 609, 502, 600, 89,
/* 1050 */ 380, 217, 620, 128, 140, 413, 220, 620, 410, 409,
/* 1060 */ 620, 620, 588, 587, 600, 75, 589, 583, 271, 620,
/* 1070 */ 51, 234, 127, 413, 620, 599, 627, 330, 27, 375,
/* 1080 */ 449, 279, 600, 88, 585, 584, 58, 48, 581, 580,
/* 1090 */ 582, 582, 55, 55, 56, 56, 56, 56, 410, 54,
/* 1100 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 234,
/* 1110 */ 310, 586, 410, 413, 410, 261, 593, 165, 399, 556,
/* 1120 */ 126, 371, 600, 87, 478, 186, 123, 413, 367, 413,
/* 1130 */ 620, 620, 410, 620, 620, 410, 600, 99, 600, 86,
/* 1140 */ 589, 583, 475, 122, 258, 171, 471, 413, 160, 121,
/* 1150 */ 413, 14, 159, 463, 25, 24, 600, 17, 448, 600,
/* 1160 */ 85, 48, 581, 580, 582, 582, 55, 55, 56, 56,
/* 1170 */ 56, 56, 158, 54, 54, 54, 54, 53, 53, 52,
/* 1180 */ 52, 52, 51, 234, 44, 404, 261, 3, 544, 261,
/* 1190 */ 540, 414, 621, 460, 119, 118, 538, 275, 10, 349,
/* 1200 */ 4, 620, 407, 620, 620, 620, 116, 44, 404, 410,
/* 1210 */ 3, 620, 620, 410, 414, 621, 456, 454, 252, 450,
/* 1220 */ 508, 402, 111, 109, 413, 407, 155, 444, 413, 447,
/* 1230 */ 435, 565, 219, 600, 84, 620, 108, 600, 83, 64,
/* 1240 */ 434, 417, 625, 150, 402, 333, 410, 237, 238, 124,
/* 1250 */ 274, 41, 42, 533, 565, 206, 189, 261, 43, 412,
/* 1260 */ 411, 413, 261, 594, 488, 620, 329, 149, 419, 268,
/* 1270 */ 600, 72, 620, 266, 41, 42, 181, 620, 410, 620,
/* 1280 */ 105, 43, 412, 411, 620, 624, 594, 614, 620, 599,
/* 1290 */ 228, 125, 313, 413, 592, 592, 592, 591, 590, 13,
/* 1300 */ 218, 410, 600, 71, 236, 244, 44, 404, 264, 3,
/* 1310 */ 312, 613, 340, 414, 621, 180, 413, 592, 592, 592,
/* 1320 */ 591, 590, 13, 620, 407, 600, 82, 410, 416, 34,
/* 1330 */ 404, 410, 3, 410, 262, 410, 414, 621, 612, 331,
/* 1340 */ 178, 415, 413, 402, 8, 236, 413, 407, 413, 620,
/* 1350 */ 413, 600, 81, 565, 257, 600, 80, 600, 70, 600,
/* 1360 */ 18, 598, 361, 462, 461, 30, 402, 294, 31, 620,
/* 1370 */ 293, 354, 251, 41, 42, 410, 565, 620, 620, 620,
/* 1380 */ 43, 412, 411, 453, 396, 594, 620, 620, 394, 61,
/* 1390 */ 413, 292, 443, 622, 621, 243, 41, 42, 620, 600,
/* 1400 */ 79, 597, 291, 43, 412, 411, 60, 620, 594, 240,
/* 1410 */ 620, 410, 231, 37, 555, 173, 592, 592, 592, 591,
/* 1420 */ 590, 13, 216, 239, 620, 184, 413, 302, 301, 300,
/* 1430 */ 179, 298, 388, 565, 452, 600, 78, 286, 620, 592,
/* 1440 */ 592, 592, 591, 590, 13, 429, 29, 413, 151, 289,
/* 1450 */ 242, 145, 392, 194, 193, 288, 600, 9, 542, 241,
/* 1460 */ 620, 525, 391, 284, 620, 594, 620, 620, 522, 536,
/* 1470 */ 620, 535, 153, 385, 465, 516, 282, 325, 154, 517,
/* 1480 */ 277, 152, 512, 511, 513, 129, 226, 308, 487, 486,
/* 1490 */ 485, 164, 372, 493, 307, 227, 592, 592, 592, 225,
/* 1500 */ 479, 163, 368, 370, 162, 476, 210, 477, 26, 259,
/* 1510 */ 161, 466, 362, 141, 132, 120, 117, 455, 156, 115,
/* 1520 */ 344, 343, 256, 342, 245, 114, 113, 446, 311, 112,
/* 1530 */ 23, 317, 432, 236, 131, 431, 110, 430, 20, 427,
/* 1540 */ 608, 595, 295, 63, 379, 287, 509, 191, 278, 403,
/* 1550 */ 572, 569, 497, 498, 496, 494, 335, 459, 445, 303,
/* 1560 */ 296, 246, 341, 355, 5, 568, 369, 507, 253, 549,
/* 1570 */ 526, 209, 400, 501, 500, 524, 234, 958, 489, 482,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 19, 169, 170, 171, 22, 24, 24, 26, 77, 78,
/* 10 */ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
/* 20 */ 89, 90, 91, 92, 26, 27, 1, 26, 27, 15,
/* 30 */ 49, 50, 77, 78, 79, 80, 116, 82, 83, 84,
/* 40 */ 85, 86, 87, 88, 89, 90, 91, 92, 128, 68,
/* 50 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
/* 60 */ 79, 80, 230, 82, 83, 84, 85, 86, 87, 88,
/* 70 */ 89, 90, 91, 92, 19, 94, 19, 23, 86, 87,
/* 80 */ 25, 82, 83, 84, 85, 86, 87, 88, 89, 90,
/* 90 */ 91, 92, 94, 95, 19, 94, 95, 96, 172, 173,
/* 100 */ 99, 100, 101, 197, 49, 50, 177, 181, 22, 54,
/* 110 */ 204, 110, 26, 27, 86, 87, 88, 89, 90, 91,
/* 120 */ 92, 129, 130, 68, 69, 70, 71, 72, 73, 74,
/* 130 */ 75, 76, 77, 78, 79, 80, 22, 82, 83, 84,
/* 140 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 92,
/* 150 */ 221, 222, 223, 96, 97, 98, 99, 100, 101, 102,
/* 160 */ 112, 32, 114, 115, 26, 27, 109, 92, 150, 25,
/* 170 */ 41, 150, 97, 98, 99, 100, 101, 102, 49, 50,
/* 180 */ 94, 95, 98, 165, 109, 25, 165, 163, 170, 171,
/* 190 */ 166, 167, 168, 109, 12, 174, 175, 68, 69, 70,
/* 200 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
/* 210 */ 28, 82, 83, 84, 85, 86, 87, 88, 89, 90,
/* 220 */ 91, 92, 19, 11, 86, 87, 44, 24, 46, 221,
/* 230 */ 222, 223, 94, 95, 66, 97, 215, 7, 8, 57,
/* 240 */ 150, 220, 104, 19, 106, 26, 27, 229, 230, 241,
/* 250 */ 160, 27, 49, 50, 22, 165, 96, 118, 16, 99,
/* 260 */ 100, 101, 94, 119, 174, 175, 98, 129, 130, 57,
/* 270 */ 110, 68, 69, 70, 71, 72, 73, 74, 75, 76,
/* 280 */ 77, 78, 79, 80, 194, 82, 83, 84, 85, 86,
/* 290 */ 87, 88, 89, 90, 91, 92, 19, 129, 130, 131,
/* 300 */ 150, 23, 60, 25, 62, 215, 150, 150, 76, 150,
/* 310 */ 220, 161, 162, 94, 95, 165, 30, 105, 106, 107,
/* 320 */ 34, 165, 165, 23, 165, 25, 49, 50, 116, 170,
/* 330 */ 171, 174, 175, 22, 48, 185, 186, 26, 27, 120,
/* 340 */ 26, 27, 12, 187, 160, 68, 69, 70, 71, 72,
/* 350 */ 73, 74, 75, 76, 77, 78, 79, 80, 28, 82,
/* 360 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
/* 370 */ 19, 150, 215, 95, 44, 23, 46, 220, 194, 96,
/* 380 */ 138, 160, 99, 100, 101, 23, 165, 25, 229, 230,
/* 390 */ 26, 27, 135, 110, 137, 174, 175, 57, 120, 150,
/* 400 */ 49, 50, 88, 219, 113, 94, 95, 158, 94, 95,
/* 410 */ 161, 162, 21, 136, 165, 194, 169, 170, 171, 68,
/* 420 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
/* 430 */ 79, 80, 23, 82, 83, 84, 85, 86, 87, 88,
/* 440 */ 89, 90, 91, 92, 19, 105, 106, 107, 23, 88,
/* 450 */ 89, 90, 91, 92, 63, 23, 116, 88, 94, 95,
/* 460 */ 142, 143, 144, 145, 112, 150, 114, 115, 105, 106,
/* 470 */ 107, 23, 23, 25, 49, 50, 118, 230, 97, 98,
/* 480 */ 165, 16, 113, 118, 120, 160, 117, 136, 113, 174,
/* 490 */ 175, 100, 117, 68, 69, 70, 71, 72, 73, 74,
/* 500 */ 75, 76, 77, 78, 79, 80, 160, 82, 83, 84,
/* 510 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 194,
/* 520 */ 25, 112, 23, 114, 115, 60, 150, 62, 150, 138,
/* 530 */ 150, 105, 106, 107, 19, 150, 36, 161, 162, 224,
/* 540 */ 194, 165, 217, 165, 112, 165, 114, 115, 49, 50,
/* 550 */ 165, 51, 174, 175, 174, 175, 166, 232, 58, 174,
/* 560 */ 175, 112, 237, 114, 115, 50, 22, 68, 69, 70,
/* 570 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
/* 580 */ 160, 82, 83, 84, 85, 86, 87, 88, 89, 90,
/* 590 */ 91, 92, 19, 215, 214, 205, 23, 7, 8, 9,
/* 600 */ 215, 155, 24, 22, 26, 150, 97, 26, 108, 129,
/* 610 */ 130, 221, 222, 223, 194, 0, 1, 2, 150, 104,
/* 620 */ 165, 126, 49, 50, 109, 116, 206, 207, 118, 174,
/* 630 */ 175, 22, 23, 165, 25, 22, 23, 128, 25, 118,
/* 640 */ 26, 68, 69, 70, 71, 72, 73, 74, 75, 76,
/* 650 */ 77, 78, 79, 80, 150, 82, 83, 84, 85, 86,
/* 660 */ 87, 88, 89, 90, 91, 92, 19, 150, 150, 165,
/* 670 */ 23, 160, 94, 227, 150, 94, 67, 231, 174, 175,
/* 680 */ 67, 213, 165, 165, 221, 222, 223, 150, 150, 165,
/* 690 */ 23, 32, 174, 175, 181, 182, 49, 50, 174, 175,
/* 700 */ 41, 188, 165, 165, 22, 194, 177, 11, 94, 23,
/* 710 */ 193, 174, 175, 160, 22, 68, 69, 70, 71, 72,
/* 720 */ 73, 74, 75, 76, 77, 78, 79, 80, 217, 82,
/* 730 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
/* 740 */ 19, 150, 150, 150, 25, 24, 19, 194, 237, 150,
/* 750 */ 221, 222, 223, 25, 27, 23, 165, 165, 165, 242,
/* 760 */ 165, 23, 150, 25, 165, 174, 175, 174, 175, 174,
/* 770 */ 49, 50, 219, 150, 22, 23, 238, 165, 25, 22,
/* 780 */ 23, 23, 166, 167, 168, 193, 174, 175, 165, 68,
/* 790 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
/* 800 */ 79, 80, 150, 82, 83, 84, 85, 86, 87, 88,
/* 810 */ 89, 90, 91, 92, 19, 150, 23, 165, 150, 67,
/* 820 */ 150, 25, 103, 95, 67, 35, 174, 175, 206, 207,
/* 830 */ 165, 150, 25, 165, 150, 165, 213, 150, 150, 174,
/* 840 */ 175, 35, 174, 175, 49, 50, 165, 52, 120, 165,
/* 850 */ 245, 246, 165, 165, 35, 174, 175, 187, 174, 175,
/* 860 */ 23, 50, 25, 68, 69, 70, 71, 72, 73, 74,
/* 870 */ 75, 76, 77, 78, 79, 80, 150, 82, 83, 84,
/* 880 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 150,
/* 890 */ 150, 165, 150, 150, 160, 23, 150, 25, 144, 145,
/* 900 */ 174, 175, 120, 216, 165, 165, 22, 165, 165, 150,
/* 910 */ 150, 165, 27, 174, 175, 104, 174, 175, 49, 50,
/* 920 */ 174, 175, 247, 248, 165, 165, 238, 187, 194, 23,
/* 930 */ 187, 25, 166, 174, 175, 190, 191, 68, 69, 70,
/* 940 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
/* 950 */ 150, 82, 83, 84, 85, 86, 87, 88, 89, 90,
/* 960 */ 91, 92, 19, 150, 150, 165, 150, 23, 150, 25,
/* 970 */ 23, 205, 25, 213, 174, 175, 190, 191, 165, 165,
/* 980 */ 118, 165, 150, 165, 150, 150, 23, 174, 175, 39,
/* 990 */ 174, 175, 49, 50, 173, 150, 23, 165, 52, 165,
/* 1000 */ 165, 187, 181, 22, 166, 166, 174, 175, 174, 175,
/* 1010 */ 165, 68, 69, 70, 71, 72, 73, 74, 75, 76,
/* 1020 */ 77, 78, 79, 80, 150, 82, 83, 84, 85, 86,
/* 1030 */ 87, 88, 89, 90, 91, 92, 19, 150, 193, 165,
/* 1040 */ 150, 160, 150, 205, 205, 150, 150, 29, 174, 175,
/* 1050 */ 52, 216, 165, 22, 150, 165, 238, 165, 150, 150,
/* 1060 */ 165, 165, 49, 50, 174, 175, 49, 50, 23, 165,
/* 1070 */ 91, 92, 22, 165, 165, 194, 1, 2, 22, 52,
/* 1080 */ 193, 109, 174, 175, 71, 72, 69, 70, 71, 72,
/* 1090 */ 73, 74, 75, 76, 77, 78, 79, 80, 150, 82,
/* 1100 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
/* 1110 */ 19, 98, 150, 165, 150, 150, 150, 102, 150, 150,
/* 1120 */ 22, 19, 174, 175, 20, 24, 104, 165, 43, 165,
/* 1130 */ 165, 165, 150, 165, 165, 150, 174, 175, 174, 175,
/* 1140 */ 49, 50, 59, 53, 138, 25, 53, 165, 104, 22,
/* 1150 */ 165, 5, 118, 1, 76, 76, 174, 175, 193, 174,
/* 1160 */ 175, 70, 71, 72, 73, 74, 75, 76, 77, 78,
/* 1170 */ 79, 80, 35, 82, 83, 84, 85, 86, 87, 88,
/* 1180 */ 89, 90, 91, 92, 19, 20, 150, 22, 150, 150,
/* 1190 */ 150, 26, 27, 27, 108, 127, 150, 150, 22, 25,
/* 1200 */ 22, 165, 37, 165, 165, 165, 119, 19, 20, 150,
/* 1210 */ 22, 165, 165, 150, 26, 27, 23, 1, 16, 20,
/* 1220 */ 150, 56, 119, 108, 165, 37, 121, 128, 165, 193,
/* 1230 */ 23, 66, 193, 174, 175, 165, 127, 174, 175, 16,
/* 1240 */ 23, 146, 147, 15, 56, 65, 150, 152, 140, 154,
/* 1250 */ 150, 86, 87, 88, 66, 160, 22, 150, 93, 94,
/* 1260 */ 95, 165, 150, 98, 150, 165, 3, 246, 4, 150,
/* 1270 */ 174, 175, 165, 150, 86, 87, 6, 165, 150, 165,
/* 1280 */ 164, 93, 94, 95, 165, 149, 98, 149, 165, 194,
/* 1290 */ 180, 180, 249, 165, 129, 130, 131, 132, 133, 134,
/* 1300 */ 193, 150, 174, 175, 116, 193, 19, 20, 150, 22,
/* 1310 */ 249, 149, 217, 26, 27, 151, 165, 129, 130, 131,
/* 1320 */ 132, 133, 134, 165, 37, 174, 175, 150, 149, 19,
/* 1330 */ 20, 150, 22, 150, 150, 150, 26, 27, 13, 244,
/* 1340 */ 151, 159, 165, 56, 25, 116, 165, 37, 165, 165,
/* 1350 */ 165, 174, 175, 66, 150, 174, 175, 174, 175, 174,
/* 1360 */ 175, 194, 150, 150, 150, 126, 56, 199, 124, 165,
/* 1370 */ 200, 150, 150, 86, 87, 150, 66, 165, 165, 165,
/* 1380 */ 93, 94, 95, 150, 122, 98, 165, 165, 123, 22,
/* 1390 */ 165, 201, 150, 26, 27, 150, 86, 87, 165, 174,
/* 1400 */ 175, 203, 202, 93, 94, 95, 125, 165, 98, 150,
/* 1410 */ 165, 150, 225, 135, 157, 118, 129, 130, 131, 132,
/* 1420 */ 133, 134, 5, 150, 165, 157, 165, 10, 11, 12,
/* 1430 */ 13, 14, 150, 66, 17, 174, 175, 210, 165, 129,
/* 1440 */ 130, 131, 132, 133, 134, 150, 104, 165, 31, 150,
/* 1450 */ 33, 150, 150, 86, 87, 150, 174, 175, 211, 42,
/* 1460 */ 165, 94, 121, 210, 165, 98, 165, 165, 176, 211,
/* 1470 */ 165, 211, 55, 104, 57, 184, 210, 47, 61, 176,
/* 1480 */ 176, 64, 103, 176, 178, 22, 92, 179, 176, 176,
/* 1490 */ 176, 156, 18, 184, 179, 228, 129, 130, 131, 228,
/* 1500 */ 157, 156, 45, 157, 156, 236, 157, 157, 135, 235,
/* 1510 */ 156, 189, 157, 68, 218, 189, 22, 199, 156, 192,
/* 1520 */ 157, 18, 105, 106, 107, 192, 192, 199, 111, 192,
/* 1530 */ 240, 157, 40, 116, 218, 157, 189, 157, 240, 38,
/* 1540 */ 153, 166, 198, 243, 178, 209, 182, 196, 177, 226,
/* 1550 */ 230, 230, 166, 177, 177, 166, 139, 199, 199, 148,
/* 1560 */ 195, 209, 209, 239, 196, 166, 234, 183, 239, 208,
/* 1570 */ 174, 233, 191, 183, 183, 174, 92, 250, 186, 186,
};
#define YY_SHIFT_USE_DFLT (-81)
#define YY_SHIFT_COUNT (417)
#define YY_SHIFT_MIN (-80)
#define YY_SHIFT_MAX (1503)
static const short yy_shift_ofst[] = {
/* 0 */ 1075, 1188, 1417, 1188, 1287, 1287, 138, 138, 1, -19,
/* 10 */ 1287, 1287, 1287, 1287, 340, -2, 129, 129, 795, 1165,
/* 20 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
/* 30 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
/* 40 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1310, 1287,
/* 50 */ 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
/* 60 */ 1287, 1287, 212, -2, -2, -8, -8, 614, 1229, 55,
/* 70 */ 721, 647, 573, 499, 425, 351, 277, 203, 869, 869,
/* 80 */ 869, 869, 869, 869, 869, 869, 869, 869, 869, 869,
/* 90 */ 869, 869, 869, 943, 869, 1017, 1091, 1091, -69, -45,
/* 100 */ -45, -45, -45, -45, -1, 57, 28, 361, -2, -2,
/* 110 */ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
/* 120 */ -2, -2, -2, -2, 391, 515, -2, -2, -2, -2,
/* 130 */ -2, 509, -80, 614, 979, 1484, -81, -81, -81, 1367,
/* 140 */ 75, 182, 182, 314, 311, 364, 219, 86, 613, 609,
/* 150 */ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
/* 160 */ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
/* 170 */ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
/* 180 */ -2, -2, 578, 578, 578, 615, 1229, 1229, 1229, -81,
/* 190 */ -81, -81, 160, 168, 168, 283, 500, 500, 500, 278,
/* 200 */ 449, 330, 432, 409, 352, 48, 48, 48, 48, 426,
/* 210 */ 286, 48, 48, 728, 581, 369, 590, 495, 224, 224,
/* 220 */ 727, 495, 727, 719, 614, 659, 614, 659, 811, 659,
/* 230 */ 224, 257, 480, 480, 614, 144, 375, -18, 1501, 1297,
/* 240 */ 1297, 1492, 1492, 1297, 1494, 1445, 1239, 1503, 1503, 1503,
/* 250 */ 1503, 1297, 1474, 1239, 1494, 1445, 1445, 1297, 1474, 1373,
/* 260 */ 1457, 1297, 1297, 1474, 1297, 1474, 1297, 1474, 1463, 1369,
/* 270 */ 1369, 1369, 1430, 1394, 1394, 1463, 1369, 1379, 1369, 1430,
/* 280 */ 1369, 1369, 1341, 1342, 1341, 1342, 1341, 1342, 1297, 1297,
/* 290 */ 1278, 1281, 1262, 1244, 1265, 1239, 1229, 1319, 1325, 1325,
/* 300 */ 1270, 1270, 1270, 1270, -81, -81, -81, -81, -81, -81,
/* 310 */ 1013, 242, 757, 752, 465, 363, 947, 232, 944, 906,
/* 320 */ 872, 837, 738, 448, 381, 230, 84, 362, 300, 1264,
/* 330 */ 1263, 1234, 1108, 1228, 1180, 1223, 1217, 1207, 1099, 1174,
/* 340 */ 1109, 1115, 1103, 1199, 1105, 1202, 1216, 1087, 1193, 1178,
/* 350 */ 1174, 1176, 1068, 1079, 1078, 1086, 1166, 1137, 1034, 1152,
/* 360 */ 1146, 1127, 1044, 1006, 1093, 1120, 1090, 1083, 1085, 1022,
/* 370 */ 1101, 1104, 1102, 972, 1015, 1098, 1027, 1056, 1050, 1045,
/* 380 */ 1031, 998, 1018, 981, 946, 950, 973, 963, 862, 885,
/* 390 */ 819, 884, 782, 796, 806, 807, 790, 796, 793, 758,
/* 400 */ 753, 732, 692, 696, 682, 686, 667, 544, 291, 521,
/* 410 */ 510, 365, 358, 139, 114, 54, 14, 25,
};
#define YY_REDUCE_USE_DFLT (-169)
#define YY_REDUCE_COUNT (309)
#define YY_REDUCE_MIN (-168)
#define YY_REDUCE_MAX (1411)
static const short yy_reduce_ofst[] = {
/* 0 */ 318, 90, 1095, 221, 157, 21, 159, 18, 150, 390,
/* 10 */ 385, 378, 380, 315, 325, 249, 529, -71, 8, 1282,
/* 20 */ 1261, 1225, 1185, 1183, 1181, 1177, 1151, 1128, 1096, 1063,
/* 30 */ 1059, 985, 982, 964, 962, 948, 908, 890, 874, 834,
/* 40 */ 832, 816, 813, 800, 759, 746, 742, 739, 726, 684,
/* 50 */ 681, 668, 665, 652, 612, 593, 591, 537, 524, 518,
/* 60 */ 504, 455, 511, 376, 517, 247, -168, 24, 420, 463,
/* 70 */ 463, 463, 463, 463, 463, 463, 463, 463, 463, 463,
/* 80 */ 463, 463, 463, 463, 463, 463, 463, 463, 463, 463,
/* 90 */ 463, 463, 463, 463, 463, 463, 463, 463, 463, 463,
/* 100 */ 463, 463, 463, 463, 463, -74, 463, 463, 1112, 835,
/* 110 */ 1107, 1039, 1036, 965, 887, 845, 818, 760, 688, 687,
/* 120 */ 538, 743, 623, 592, 446, 513, 814, 740, 670, 156,
/* 130 */ 468, 553, 184, 616, 463, 463, 463, 463, 463, 595,
/* 140 */ 821, 786, 745, 909, 1305, 1302, 1301, 1299, 675, 675,
/* 150 */ 1295, 1273, 1259, 1245, 1242, 1233, 1222, 1221, 1214, 1213,
/* 160 */ 1212, 1204, 1184, 1158, 1123, 1119, 1114, 1100, 1070, 1047,
/* 170 */ 1046, 1040, 1038, 969, 968, 966, 909, 904, 896, 895,
/* 180 */ 892, 599, 839, 838, 766, 754, 881, 734, 346, 605,
/* 190 */ 622, -94, 1393, 1401, 1396, 1392, 1391, 1390, 1384, 1361,
/* 200 */ 1365, 1381, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1332,
/* 210 */ 1338, 1365, 1365, 1361, 1399, 1368, 1411, 1359, 1353, 1352,
/* 220 */ 1329, 1358, 1324, 1366, 1389, 1377, 1386, 1376, 1364, 1371,
/* 230 */ 1336, 1323, 1321, 1320, 1375, 1344, 1351, 1387, 1300, 1380,
/* 240 */ 1378, 1298, 1290, 1374, 1316, 1347, 1328, 1337, 1334, 1333,
/* 250 */ 1327, 1363, 1362, 1318, 1296, 1326, 1322, 1355, 1354, 1269,
/* 260 */ 1274, 1350, 1349, 1348, 1346, 1345, 1343, 1335, 1315, 1314,
/* 270 */ 1313, 1312, 1309, 1271, 1267, 1308, 1307, 1306, 1304, 1291,
/* 280 */ 1303, 1292, 1260, 1266, 1258, 1253, 1247, 1227, 1268, 1257,
/* 290 */ 1187, 1198, 1200, 1190, 1170, 1168, 1167, 1182, 1189, 1164,
/* 300 */ 1179, 1162, 1138, 1136, 1061, 1043, 1021, 1111, 1110, 1116,
};
static const YYACTIONTYPE yy_default[] = {
/* 0 */ 634, 868, 956, 956, 868, 868, 956, 956, 956, 758,
/* 10 */ 956, 956, 956, 866, 956, 956, 786, 786, 930, 956,
/* 20 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 30 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 40 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 50 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 60 */ 956, 956, 956, 956, 956, 956, 956, 673, 762, 792,
/* 70 */ 956, 956, 956, 956, 956, 956, 956, 956, 929, 931,
/* 80 */ 800, 799, 909, 773, 797, 790, 794, 869, 862, 863,
/* 90 */ 861, 865, 870, 956, 793, 829, 846, 828, 840, 845,
/* 100 */ 852, 844, 841, 831, 830, 665, 832, 833, 956, 956,
/* 110 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 120 */ 956, 956, 956, 956, 660, 727, 956, 956, 956, 956,
/* 130 */ 956, 956, 956, 956, 834, 835, 849, 848, 847, 956,
/* 140 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 150 */ 956, 936, 934, 956, 881, 956, 956, 956, 956, 956,
/* 160 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 170 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 180 */ 956, 640, 758, 758, 758, 634, 956, 956, 956, 948,
/* 190 */ 762, 752, 718, 956, 956, 956, 956, 956, 956, 956,
/* 200 */ 956, 956, 956, 956, 956, 802, 741, 919, 921, 956,
/* 210 */ 902, 739, 662, 760, 675, 750, 642, 796, 775, 775,
/* 220 */ 914, 796, 914, 699, 956, 786, 956, 786, 696, 786,
/* 230 */ 775, 864, 956, 956, 956, 759, 750, 956, 941, 766,
/* 240 */ 766, 933, 933, 766, 808, 731, 796, 738, 738, 738,
/* 250 */ 738, 766, 657, 796, 808, 731, 731, 766, 657, 908,
/* 260 */ 906, 766, 766, 657, 766, 657, 766, 657, 874, 729,
/* 270 */ 729, 729, 714, 878, 878, 874, 729, 699, 729, 714,
/* 280 */ 729, 729, 779, 774, 779, 774, 779, 774, 766, 766,
/* 290 */ 956, 791, 780, 789, 787, 796, 956, 717, 650, 650,
/* 300 */ 639, 639, 639, 639, 953, 953, 948, 701, 701, 683,
/* 310 */ 956, 956, 956, 956, 956, 956, 956, 883, 956, 956,
/* 320 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 330 */ 635, 943, 956, 956, 940, 956, 956, 956, 956, 801,
/* 340 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 350 */ 918, 956, 956, 956, 956, 956, 956, 956, 912, 956,
/* 360 */ 956, 956, 956, 956, 956, 905, 904, 956, 956, 956,
/* 370 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 380 */ 956, 956, 956, 956, 956, 956, 956, 956, 956, 956,
/* 390 */ 956, 956, 956, 788, 956, 781, 956, 867, 956, 956,
/* 400 */ 956, 956, 956, 956, 956, 956, 956, 956, 744, 817,
/* 410 */ 956, 816, 820, 815, 667, 956, 648, 956, 631, 636,
/* 420 */ 952, 955, 954, 951, 950, 949, 944, 942, 939, 938,
/* 430 */ 937, 935, 932, 928, 887, 885, 892, 891, 890, 889,
/* 440 */ 888, 886, 884, 882, 803, 798, 795, 927, 880, 740,
/* 450 */ 737, 736, 656, 945, 911, 920, 807, 806, 809, 917,
/* 460 */ 916, 915, 913, 910, 897, 805, 804, 732, 872, 871,
/* 470 */ 659, 901, 900, 899, 903, 907, 898, 768, 658, 655,
/* 480 */ 664, 721, 720, 728, 726, 725, 724, 723, 722, 719,
/* 490 */ 666, 674, 685, 713, 698, 697, 877, 879, 876, 875,
/* 500 */ 706, 705, 711, 710, 709, 708, 707, 704, 703, 702,
/* 510 */ 695, 694, 700, 693, 716, 715, 712, 692, 735, 734,
/* 520 */ 733, 730, 691, 690, 689, 820, 688, 687, 826, 825,
/* 530 */ 813, 856, 755, 754, 753, 765, 764, 777, 776, 811,
/* 540 */ 810, 778, 763, 757, 756, 772, 771, 770, 769, 761,
/* 550 */ 751, 783, 785, 784, 782, 858, 767, 855, 926, 925,
/* 560 */ 924, 923, 922, 860, 859, 827, 824, 678, 679, 895,
/* 570 */ 894, 896, 893, 681, 680, 677, 676, 857, 746, 745,
/* 580 */ 853, 850, 842, 838, 854, 851, 843, 839, 837, 836,
/* 590 */ 822, 821, 819, 818, 814, 823, 669, 747, 743, 742,
/* 600 */ 812, 749, 748, 686, 684, 682, 663, 661, 654, 652,
/* 610 */ 651, 653, 649, 647, 646, 645, 644, 643, 672, 671,
/* 620 */ 670, 668, 667, 641, 638, 637, 633, 632, 630,
};
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
**
** %fallback ID X Y Z.
**
|
| ︙ | ︙ | |||
108519 108520 108521 108522 108523 108524 108525 | "init_deferred_pred_opt", "conslist", "tcons", "idxlist", "defer_subclause_opt", "orconf", "resolvetype", "raisetype", "ifexists", "fullname", "oneselect", "multiselect_op", "distinct", "selcollist", "from", "where_opt", "groupby_opt", "having_opt", "orderby_opt", "limit_opt", "sclp", "as", "seltablist", "stl_prefix", "joinop", "indexed_opt", "on_opt", "using_opt", | | | | | | | | | | | | 108752 108753 108754 108755 108756 108757 108758 108759 108760 108761 108762 108763 108764 108765 108766 108767 108768 108769 108770 108771 108772 108773 108774 108775 |
"init_deferred_pred_opt", "conslist", "tcons", "idxlist",
"defer_subclause_opt", "orconf", "resolvetype", "raisetype",
"ifexists", "fullname", "oneselect", "multiselect_op",
"distinct", "selcollist", "from", "where_opt",
"groupby_opt", "having_opt", "orderby_opt", "limit_opt",
"sclp", "as", "seltablist", "stl_prefix",
"joinop", "indexed_opt", "on_opt", "using_opt",
"joinop2", "inscollist", "sortlist", "nexprlist",
"setlist", "insert_cmd", "inscollist_opt", "valuelist",
"exprlist", "likeop", "between_op", "in_op",
"case_operand", "case_exprlist", "case_else", "uniqueflag",
"collate", "nmnum", "number", "trigger_decl",
"trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause",
"when_clause", "trigger_cmd", "trnm", "tridxby",
"database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt",
"create_vtab", "vtabarglist", "vtabarg", "vtabargtoken",
"lp", "anylist",
};
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
|
| ︙ | ︙ | |||
108689 108690 108691 108692 108693 108694 108695 | /* 146 */ "indexed_opt ::=", /* 147 */ "indexed_opt ::= INDEXED BY nm", /* 148 */ "indexed_opt ::= NOT INDEXED", /* 149 */ "using_opt ::= USING LP inscollist RP", /* 150 */ "using_opt ::=", /* 151 */ "orderby_opt ::=", /* 152 */ "orderby_opt ::= ORDER BY sortlist", | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | > | | | < | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | > | | | < | | | | | | | | | | | | | | > | | | | | | | | | | | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 108922 108923 108924 108925 108926 108927 108928 108929 108930 108931 108932 108933 108934 108935 108936 108937 108938 108939 108940 108941 108942 108943 108944 108945 108946 108947 108948 108949 108950 108951 108952 108953 108954 108955 108956 108957 108958 108959 108960 108961 108962 108963 108964 108965 108966 108967 108968 108969 108970 108971 108972 108973 108974 108975 108976 108977 108978 108979 108980 108981 108982 108983 108984 108985 108986 108987 108988 108989 108990 108991 108992 108993 108994 108995 108996 108997 108998 108999 109000 109001 109002 109003 109004 109005 109006 109007 109008 109009 109010 109011 109012 109013 109014 109015 109016 109017 109018 109019 109020 109021 109022 109023 109024 109025 109026 109027 109028 109029 109030 109031 109032 109033 109034 109035 109036 109037 109038 109039 109040 109041 109042 109043 109044 109045 109046 109047 109048 109049 109050 109051 109052 109053 109054 109055 109056 109057 109058 109059 109060 109061 109062 109063 109064 109065 109066 109067 109068 109069 109070 109071 109072 109073 109074 109075 109076 109077 109078 109079 109080 109081 109082 109083 109084 109085 109086 109087 109088 109089 109090 109091 109092 109093 109094 109095 109096 109097 109098 109099 109100 109101 109102 109103 109104 109105 109106 109107 109108 109109 | /* 146 */ "indexed_opt ::=", /* 147 */ "indexed_opt ::= INDEXED BY nm", /* 148 */ "indexed_opt ::= NOT INDEXED", /* 149 */ "using_opt ::= USING LP inscollist RP", /* 150 */ "using_opt ::=", /* 151 */ "orderby_opt ::=", /* 152 */ "orderby_opt ::= ORDER BY sortlist", /* 153 */ "sortlist ::= sortlist COMMA expr sortorder", /* 154 */ "sortlist ::= expr sortorder", /* 155 */ "sortorder ::= ASC", /* 156 */ "sortorder ::= DESC", /* 157 */ "sortorder ::=", /* 158 */ "groupby_opt ::=", /* 159 */ "groupby_opt ::= GROUP BY nexprlist", /* 160 */ "having_opt ::=", /* 161 */ "having_opt ::= HAVING expr", /* 162 */ "limit_opt ::=", /* 163 */ "limit_opt ::= LIMIT expr", /* 164 */ "limit_opt ::= LIMIT expr OFFSET expr", /* 165 */ "limit_opt ::= LIMIT expr COMMA expr", /* 166 */ "cmd ::= DELETE FROM fullname indexed_opt where_opt", /* 167 */ "where_opt ::=", /* 168 */ "where_opt ::= WHERE expr", /* 169 */ "cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt", /* 170 */ "setlist ::= setlist COMMA nm EQ expr", /* 171 */ "setlist ::= nm EQ expr", /* 172 */ "cmd ::= insert_cmd INTO fullname inscollist_opt valuelist", /* 173 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select", /* 174 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES", /* 175 */ "insert_cmd ::= INSERT orconf", /* 176 */ "insert_cmd ::= REPLACE", /* 177 */ "valuelist ::= VALUES LP nexprlist RP", /* 178 */ "valuelist ::= valuelist COMMA LP exprlist RP", /* 179 */ "inscollist_opt ::=", /* 180 */ "inscollist_opt ::= LP inscollist RP", /* 181 */ "inscollist ::= inscollist COMMA nm", /* 182 */ "inscollist ::= nm", /* 183 */ "expr ::= term", /* 184 */ "expr ::= LP expr RP", /* 185 */ "term ::= NULL", /* 186 */ "expr ::= id", /* 187 */ "expr ::= JOIN_KW", /* 188 */ "expr ::= nm DOT nm", /* 189 */ "expr ::= nm DOT nm DOT nm", /* 190 */ "term ::= INTEGER|FLOAT|BLOB", /* 191 */ "term ::= STRING", /* 192 */ "expr ::= REGISTER", /* 193 */ "expr ::= VARIABLE", /* 194 */ "expr ::= expr COLLATE ids", /* 195 */ "expr ::= CAST LP expr AS typetoken RP", /* 196 */ "expr ::= ID LP distinct exprlist RP", /* 197 */ "expr ::= ID LP STAR RP", /* 198 */ "term ::= CTIME_KW", /* 199 */ "expr ::= expr AND expr", /* 200 */ "expr ::= expr OR expr", /* 201 */ "expr ::= expr LT|GT|GE|LE expr", /* 202 */ "expr ::= expr EQ|NE expr", /* 203 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", /* 204 */ "expr ::= expr PLUS|MINUS expr", /* 205 */ "expr ::= expr STAR|SLASH|REM expr", /* 206 */ "expr ::= expr CONCAT expr", /* 207 */ "likeop ::= LIKE_KW", /* 208 */ "likeop ::= NOT LIKE_KW", /* 209 */ "likeop ::= MATCH", /* 210 */ "likeop ::= NOT MATCH", /* 211 */ "expr ::= expr likeop expr", /* 212 */ "expr ::= expr likeop expr ESCAPE expr", /* 213 */ "expr ::= expr ISNULL|NOTNULL", /* 214 */ "expr ::= expr NOT NULL", /* 215 */ "expr ::= expr IS expr", /* 216 */ "expr ::= expr IS NOT expr", /* 217 */ "expr ::= NOT expr", /* 218 */ "expr ::= BITNOT expr", /* 219 */ "expr ::= MINUS expr", /* 220 */ "expr ::= PLUS expr", /* 221 */ "between_op ::= BETWEEN", /* 222 */ "between_op ::= NOT BETWEEN", /* 223 */ "expr ::= expr between_op expr AND expr", /* 224 */ "in_op ::= IN", /* 225 */ "in_op ::= NOT IN", /* 226 */ "expr ::= expr in_op LP exprlist RP", /* 227 */ "expr ::= LP select RP", /* 228 */ "expr ::= expr in_op LP select RP", /* 229 */ "expr ::= expr in_op nm dbnm", /* 230 */ "expr ::= EXISTS LP select RP", /* 231 */ "expr ::= CASE case_operand case_exprlist case_else END", /* 232 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", /* 233 */ "case_exprlist ::= WHEN expr THEN expr", /* 234 */ "case_else ::= ELSE expr", /* 235 */ "case_else ::=", /* 236 */ "case_operand ::= expr", /* 237 */ "case_operand ::=", /* 238 */ "exprlist ::= nexprlist", /* 239 */ "exprlist ::=", /* 240 */ "nexprlist ::= nexprlist COMMA expr", /* 241 */ "nexprlist ::= expr", /* 242 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP", /* 243 */ "uniqueflag ::= UNIQUE", /* 244 */ "uniqueflag ::=", /* 245 */ "idxlist_opt ::=", /* 246 */ "idxlist_opt ::= LP idxlist RP", /* 247 */ "idxlist ::= idxlist COMMA nm collate sortorder", /* 248 */ "idxlist ::= nm collate sortorder", /* 249 */ "collate ::=", /* 250 */ "collate ::= COLLATE ids", /* 251 */ "cmd ::= DROP INDEX ifexists fullname", /* 252 */ "cmd ::= VACUUM", /* 253 */ "cmd ::= VACUUM nm", /* 254 */ "cmd ::= PRAGMA nm dbnm", /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", /* 256 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", /* 257 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", /* 258 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", /* 259 */ "nmnum ::= plus_num", /* 260 */ "nmnum ::= nm", /* 261 */ "nmnum ::= ON", /* 262 */ "nmnum ::= DELETE", /* 263 */ "nmnum ::= DEFAULT", /* 264 */ "plus_num ::= PLUS number", /* 265 */ "plus_num ::= number", /* 266 */ "minus_num ::= MINUS number", /* 267 */ "number ::= INTEGER|FLOAT", /* 268 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", /* 269 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", /* 270 */ "trigger_time ::= BEFORE", /* 271 */ "trigger_time ::= AFTER", /* 272 */ "trigger_time ::= INSTEAD OF", /* 273 */ "trigger_time ::=", /* 274 */ "trigger_event ::= DELETE|INSERT", /* 275 */ "trigger_event ::= UPDATE", /* 276 */ "trigger_event ::= UPDATE OF inscollist", /* 277 */ "foreach_clause ::=", /* 278 */ "foreach_clause ::= FOR EACH ROW", /* 279 */ "when_clause ::=", /* 280 */ "when_clause ::= WHEN expr", /* 281 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", /* 282 */ "trigger_cmd_list ::= trigger_cmd SEMI", /* 283 */ "trnm ::= nm", /* 284 */ "trnm ::= nm DOT nm", /* 285 */ "tridxby ::=", /* 286 */ "tridxby ::= INDEXED BY nm", /* 287 */ "tridxby ::= NOT INDEXED", /* 288 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", /* 289 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt valuelist", /* 290 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select", /* 291 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", /* 292 */ "trigger_cmd ::= select", /* 293 */ "expr ::= RAISE LP IGNORE RP", /* 294 */ "expr ::= RAISE LP raisetype COMMA nm RP", /* 295 */ "raisetype ::= ROLLBACK", /* 296 */ "raisetype ::= ABORT", /* 297 */ "raisetype ::= FAIL", /* 298 */ "cmd ::= DROP TRIGGER ifexists fullname", /* 299 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", /* 300 */ "cmd ::= DETACH database_kw_opt expr", /* 301 */ "key_opt ::=", /* 302 */ "key_opt ::= KEY expr", /* 303 */ "database_kw_opt ::= DATABASE", /* 304 */ "database_kw_opt ::=", /* 305 */ "cmd ::= REINDEX", /* 306 */ "cmd ::= REINDEX nm dbnm", /* 307 */ "cmd ::= ANALYZE", /* 308 */ "cmd ::= ANALYZE nm dbnm", /* 309 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", /* 310 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column", /* 311 */ "add_column_fullname ::= fullname", /* 312 */ "kwcolumn_opt ::=", /* 313 */ "kwcolumn_opt ::= COLUMNKW", /* 314 */ "cmd ::= create_vtab", /* 315 */ "cmd ::= create_vtab LP vtabarglist RP", /* 316 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", /* 317 */ "vtabarglist ::= vtabarg", /* 318 */ "vtabarglist ::= vtabarglist COMMA vtabarg", /* 319 */ "vtabarg ::=", /* 320 */ "vtabarg ::= vtabarg vtabargtoken", /* 321 */ "vtabargtoken ::= ANY", /* 322 */ "vtabargtoken ::= lp anylist RP", /* 323 */ "lp ::= LP", /* 324 */ "anylist ::=", /* 325 */ "anylist ::= anylist LP anylist RP", /* 326 */ "anylist ::= anylist ANY", }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. |
| ︙ | ︙ | |||
108946 108947 108948 108949 108950 108951 108952 |
** Note: during a reduce, the only symbols destroyed are those
** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
case 160: /* select */
case 194: /* oneselect */
{
| | | | | | < | | | < | | | | | | | > > > > > > > > | | | | | | 109177 109178 109179 109180 109181 109182 109183 109184 109185 109186 109187 109188 109189 109190 109191 109192 109193 109194 109195 109196 109197 109198 109199 109200 109201 109202 109203 109204 109205 109206 109207 109208 109209 109210 109211 109212 109213 109214 109215 109216 109217 109218 109219 109220 109221 109222 109223 109224 109225 109226 109227 109228 109229 109230 109231 109232 109233 109234 109235 109236 109237 109238 109239 109240 109241 109242 109243 109244 109245 109246 109247 109248 109249 109250 109251 109252 109253 109254 109255 109256 109257 |
** Note: during a reduce, the only symbols destroyed are those
** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
case 160: /* select */
case 194: /* oneselect */
{
sqlite3SelectDelete(pParse->db, (yypminor->yy159));
}
break;
case 174: /* term */
case 175: /* expr */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy342).pExpr);
}
break;
case 179: /* idxlist_opt */
case 187: /* idxlist */
case 197: /* selcollist */
case 200: /* groupby_opt */
case 202: /* orderby_opt */
case 204: /* sclp */
case 214: /* sortlist */
case 215: /* nexprlist */
case 216: /* setlist */
case 220: /* exprlist */
case 225: /* case_exprlist */
{
sqlite3ExprListDelete(pParse->db, (yypminor->yy442));
}
break;
case 193: /* fullname */
case 198: /* from */
case 206: /* seltablist */
case 207: /* stl_prefix */
{
sqlite3SrcListDelete(pParse->db, (yypminor->yy347));
}
break;
case 199: /* where_opt */
case 201: /* having_opt */
case 210: /* on_opt */
case 224: /* case_operand */
case 226: /* case_else */
case 236: /* when_clause */
case 241: /* key_opt */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy122));
}
break;
case 211: /* using_opt */
case 213: /* inscollist */
case 218: /* inscollist_opt */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy180));
}
break;
case 219: /* valuelist */
{
sqlite3ExprListDelete(pParse->db, (yypminor->yy487).pList);
sqlite3SelectDelete(pParse->db, (yypminor->yy487).pSelect);
}
break;
case 232: /* trigger_cmd_list */
case 237: /* trigger_cmd */
{
sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy327));
}
break;
case 234: /* trigger_event */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy410).b);
}
break;
default: break; /* If no destructor action specified: do nothing */
}
}
/*
|
| ︙ | ︙ | |||
109406 109407 109408 109409 109410 109411 109412 |
{ 209, 2 },
{ 211, 4 },
{ 211, 0 },
{ 202, 0 },
{ 202, 3 },
{ 214, 4 },
{ 214, 2 },
| < | | | | | < < | | > > | 109643 109644 109645 109646 109647 109648 109649 109650 109651 109652 109653 109654 109655 109656 109657 109658 109659 109660 109661 109662 109663 109664 109665 109666 109667 109668 109669 109670 109671 109672 109673 109674 109675 109676 109677 109678 109679 109680 109681 109682 |
{ 209, 2 },
{ 211, 4 },
{ 211, 0 },
{ 202, 0 },
{ 202, 3 },
{ 214, 4 },
{ 214, 2 },
{ 177, 1 },
{ 177, 1 },
{ 177, 0 },
{ 200, 0 },
{ 200, 3 },
{ 201, 0 },
{ 201, 2 },
{ 203, 0 },
{ 203, 2 },
{ 203, 4 },
{ 203, 4 },
{ 147, 5 },
{ 199, 0 },
{ 199, 2 },
{ 147, 7 },
{ 216, 5 },
{ 216, 3 },
{ 147, 5 },
{ 147, 5 },
{ 147, 6 },
{ 217, 2 },
{ 217, 1 },
{ 219, 4 },
{ 219, 5 },
{ 218, 0 },
{ 218, 3 },
{ 213, 3 },
{ 213, 1 },
{ 175, 1 },
{ 175, 3 },
{ 174, 1 },
{ 175, 1 },
{ 175, 1 },
|
| ︙ | ︙ | |||
109459 109460 109461 109462 109463 109464 109465 |
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
| | | | | | | | | | | | | | | | | | | | | | | | | | | | > | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | > | < | | < < < | | 109695 109696 109697 109698 109699 109700 109701 109702 109703 109704 109705 109706 109707 109708 109709 109710 109711 109712 109713 109714 109715 109716 109717 109718 109719 109720 109721 109722 109723 109724 109725 109726 109727 109728 109729 109730 109731 109732 109733 109734 109735 109736 109737 109738 109739 109740 109741 109742 109743 109744 109745 109746 109747 109748 109749 109750 109751 109752 109753 109754 109755 109756 109757 109758 109759 109760 109761 109762 109763 109764 109765 109766 109767 109768 109769 109770 109771 109772 109773 109774 109775 109776 109777 109778 109779 109780 109781 109782 109783 109784 109785 109786 109787 109788 109789 109790 109791 109792 109793 109794 109795 109796 109797 109798 109799 109800 109801 109802 109803 109804 109805 109806 109807 109808 109809 109810 109811 109812 109813 109814 109815 109816 109817 109818 109819 109820 109821 109822 109823 109824 109825 109826 109827 109828 |
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 175, 3 },
{ 221, 1 },
{ 221, 2 },
{ 221, 1 },
{ 221, 2 },
{ 175, 3 },
{ 175, 5 },
{ 175, 2 },
{ 175, 3 },
{ 175, 3 },
{ 175, 4 },
{ 175, 2 },
{ 175, 2 },
{ 175, 2 },
{ 175, 2 },
{ 222, 1 },
{ 222, 2 },
{ 175, 5 },
{ 223, 1 },
{ 223, 2 },
{ 175, 5 },
{ 175, 3 },
{ 175, 5 },
{ 175, 4 },
{ 175, 4 },
{ 175, 5 },
{ 225, 5 },
{ 225, 4 },
{ 226, 2 },
{ 226, 0 },
{ 224, 1 },
{ 224, 0 },
{ 220, 1 },
{ 220, 0 },
{ 215, 3 },
{ 215, 1 },
{ 147, 11 },
{ 227, 1 },
{ 227, 0 },
{ 179, 0 },
{ 179, 3 },
{ 187, 5 },
{ 187, 3 },
{ 228, 0 },
{ 228, 2 },
{ 147, 4 },
{ 147, 1 },
{ 147, 2 },
{ 147, 3 },
{ 147, 5 },
{ 147, 6 },
{ 147, 5 },
{ 147, 6 },
{ 229, 1 },
{ 229, 1 },
{ 229, 1 },
{ 229, 1 },
{ 229, 1 },
{ 170, 2 },
{ 170, 1 },
{ 171, 2 },
{ 230, 1 },
{ 147, 5 },
{ 231, 11 },
{ 233, 1 },
{ 233, 1 },
{ 233, 2 },
{ 233, 0 },
{ 234, 1 },
{ 234, 1 },
{ 234, 3 },
{ 235, 0 },
{ 235, 3 },
{ 236, 0 },
{ 236, 2 },
{ 232, 3 },
{ 232, 2 },
{ 238, 1 },
{ 238, 3 },
{ 239, 0 },
{ 239, 3 },
{ 239, 2 },
{ 237, 7 },
{ 237, 5 },
{ 237, 5 },
{ 237, 5 },
{ 237, 1 },
{ 175, 4 },
{ 175, 6 },
{ 191, 1 },
{ 191, 1 },
{ 191, 1 },
{ 147, 4 },
{ 147, 6 },
{ 147, 3 },
{ 241, 0 },
{ 241, 2 },
{ 240, 1 },
{ 240, 0 },
{ 147, 1 },
{ 147, 3 },
{ 147, 1 },
{ 147, 3 },
{ 147, 6 },
{ 147, 6 },
{ 242, 1 },
{ 243, 0 },
{ 243, 1 },
{ 147, 1 },
{ 147, 4 },
{ 244, 8 },
{ 245, 1 },
{ 245, 3 },
{ 246, 0 },
{ 246, 2 },
{ 247, 1 },
{ 247, 3 },
{ 248, 1 },
{ 249, 0 },
{ 249, 4 },
{ 249, 2 },
};
static void yy_accept(yyParser*); /* Forward Declaration */
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
|
| ︙ | ︙ | |||
109647 109648 109649 109650 109651 109652 109653 |
case 7: /* explain ::= EXPLAIN QUERY PLAN */
{ sqlite3BeginParse(pParse, 2); }
break;
case 8: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
break;
case 9: /* cmd ::= BEGIN transtype trans_opt */
| | | | | 109882 109883 109884 109885 109886 109887 109888 109889 109890 109891 109892 109893 109894 109895 109896 109897 109898 109899 109900 109901 109902 109903 109904 109905 109906 |
case 7: /* explain ::= EXPLAIN QUERY PLAN */
{ sqlite3BeginParse(pParse, 2); }
break;
case 8: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
break;
case 9: /* cmd ::= BEGIN transtype trans_opt */
{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy392);}
break;
case 13: /* transtype ::= */
{yygotominor.yy392 = TK_DEFERRED;}
break;
case 14: /* transtype ::= DEFERRED */
case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15);
case 16: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==16);
case 115: /* multiselect_op ::= UNION */ yytestcase(yyruleno==115);
case 117: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==117);
{yygotominor.yy392 = yymsp[0].major;}
break;
case 17: /* cmd ::= COMMIT trans_opt */
case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18);
{sqlite3CommitTransaction(pParse);}
break;
case 19: /* cmd ::= ROLLBACK trans_opt */
{sqlite3RollbackTransaction(pParse);}
|
| ︙ | ︙ | |||
109683 109684 109685 109686 109687 109688 109689 |
case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
break;
case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
| | | | | | | | | | | 109918 109919 109920 109921 109922 109923 109924 109925 109926 109927 109928 109929 109930 109931 109932 109933 109934 109935 109936 109937 109938 109939 109940 109941 109942 109943 109944 109945 109946 109947 109948 109949 109950 109951 109952 109953 109954 109955 109956 109957 109958 109959 109960 109961 109962 109963 109964 109965 109966 109967 109968 109969 109970 109971 109972 109973 |
case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
break;
case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy392,0,0,yymsp[-2].minor.yy392);
}
break;
case 27: /* createkw ::= CREATE */
{
pParse->db->lookaside.bEnabled = 0;
yygotominor.yy0 = yymsp[0].minor.yy0;
}
break;
case 28: /* ifnotexists ::= */
case 31: /* temp ::= */ yytestcase(yyruleno==31);
case 70: /* autoinc ::= */ yytestcase(yyruleno==70);
case 83: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==83);
case 85: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==85);
case 87: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==87);
case 98: /* defer_subclause_opt ::= */ yytestcase(yyruleno==98);
case 109: /* ifexists ::= */ yytestcase(yyruleno==109);
case 120: /* distinct ::= ALL */ yytestcase(yyruleno==120);
case 121: /* distinct ::= */ yytestcase(yyruleno==121);
case 221: /* between_op ::= BETWEEN */ yytestcase(yyruleno==221);
case 224: /* in_op ::= IN */ yytestcase(yyruleno==224);
{yygotominor.yy392 = 0;}
break;
case 29: /* ifnotexists ::= IF NOT EXISTS */
case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30);
case 71: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==71);
case 86: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==86);
case 108: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==108);
case 119: /* distinct ::= DISTINCT */ yytestcase(yyruleno==119);
case 222: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==222);
case 225: /* in_op ::= NOT IN */ yytestcase(yyruleno==225);
{yygotominor.yy392 = 1;}
break;
case 32: /* create_table_args ::= LP columnlist conslist_opt RP */
{
sqlite3EndTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0);
}
break;
case 33: /* create_table_args ::= AS select */
{
sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy159);
sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159);
}
break;
case 36: /* column ::= columnid type carglist */
{
yygotominor.yy0.z = yymsp[-2].minor.yy0.z;
yygotominor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-2].minor.yy0.z) + pParse->sLastToken.n;
}
|
| ︙ | ︙ | |||
109751 109752 109753 109754 109755 109756 109757 |
case 43: /* nm ::= JOIN_KW */ yytestcase(yyruleno==43);
case 46: /* typetoken ::= typename */ yytestcase(yyruleno==46);
case 49: /* typename ::= ids */ yytestcase(yyruleno==49);
case 127: /* as ::= AS nm */ yytestcase(yyruleno==127);
case 128: /* as ::= ids */ yytestcase(yyruleno==128);
case 138: /* dbnm ::= DOT nm */ yytestcase(yyruleno==138);
case 147: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==147);
| | | | | | | > | | | 109986 109987 109988 109989 109990 109991 109992 109993 109994 109995 109996 109997 109998 109999 110000 110001 110002 110003 110004 110005 110006 110007 110008 110009 110010 |
case 43: /* nm ::= JOIN_KW */ yytestcase(yyruleno==43);
case 46: /* typetoken ::= typename */ yytestcase(yyruleno==46);
case 49: /* typename ::= ids */ yytestcase(yyruleno==49);
case 127: /* as ::= AS nm */ yytestcase(yyruleno==127);
case 128: /* as ::= ids */ yytestcase(yyruleno==128);
case 138: /* dbnm ::= DOT nm */ yytestcase(yyruleno==138);
case 147: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==147);
case 250: /* collate ::= COLLATE ids */ yytestcase(yyruleno==250);
case 259: /* nmnum ::= plus_num */ yytestcase(yyruleno==259);
case 260: /* nmnum ::= nm */ yytestcase(yyruleno==260);
case 261: /* nmnum ::= ON */ yytestcase(yyruleno==261);
case 262: /* nmnum ::= DELETE */ yytestcase(yyruleno==262);
case 263: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==263);
case 264: /* plus_num ::= PLUS number */ yytestcase(yyruleno==264);
case 265: /* plus_num ::= number */ yytestcase(yyruleno==265);
case 266: /* minus_num ::= MINUS number */ yytestcase(yyruleno==266);
case 267: /* number ::= INTEGER|FLOAT */ yytestcase(yyruleno==267);
case 283: /* trnm ::= nm */ yytestcase(yyruleno==283);
{yygotominor.yy0 = yymsp[0].minor.yy0;}
break;
case 45: /* type ::= typetoken */
{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy0);}
break;
case 47: /* typetoken ::= typename LP signed RP */
{
|
| ︙ | ︙ | |||
109783 109784 109785 109786 109787 109788 109789 |
}
break;
case 50: /* typename ::= typename ids */
{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
break;
case 57: /* ccons ::= DEFAULT term */
case 59: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==59);
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | | > > > < < < | < < < | | | | | | | | | | | > > > > > > > > > < < < < < < | | | | | | | | | > > | > | > > > | > > | > > > > | | | > > | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 110019 110020 110021 110022 110023 110024 110025 110026 110027 110028 110029 110030 110031 110032 110033 110034 110035 110036 110037 110038 110039 110040 110041 110042 110043 110044 110045 110046 110047 110048 110049 110050 110051 110052 110053 110054 110055 110056 110057 110058 110059 110060 110061 110062 110063 110064 110065 110066 110067 110068 110069 110070 110071 110072 110073 110074 110075 110076 110077 110078 110079 110080 110081 110082 110083 110084 110085 110086 110087 110088 110089 110090 110091 110092 110093 110094 110095 110096 110097 110098 110099 110100 110101 110102 110103 110104 110105 110106 110107 110108 110109 110110 110111 110112 110113 110114 110115 110116 110117 110118 110119 110120 110121 110122 110123 110124 110125 110126 110127 110128 110129 110130 110131 110132 110133 110134 110135 110136 110137 110138 110139 110140 110141 110142 110143 110144 110145 110146 110147 110148 110149 110150 110151 110152 110153 110154 110155 110156 110157 110158 110159 110160 110161 110162 110163 110164 110165 110166 110167 110168 110169 110170 110171 110172 110173 110174 110175 110176 110177 110178 110179 110180 110181 110182 110183 110184 110185 110186 110187 110188 110189 110190 110191 110192 110193 110194 110195 110196 110197 110198 110199 110200 110201 110202 110203 110204 110205 110206 110207 110208 110209 110210 110211 110212 110213 110214 110215 110216 110217 110218 110219 110220 110221 110222 110223 110224 110225 110226 110227 110228 110229 110230 110231 110232 110233 110234 110235 110236 110237 110238 110239 110240 110241 110242 110243 110244 110245 110246 110247 110248 110249 110250 110251 110252 110253 110254 110255 110256 110257 110258 110259 110260 110261 110262 110263 110264 110265 110266 110267 110268 110269 110270 110271 110272 110273 110274 110275 110276 110277 110278 110279 110280 110281 110282 110283 110284 110285 110286 110287 110288 110289 110290 110291 110292 110293 110294 110295 110296 110297 110298 110299 110300 110301 110302 110303 110304 110305 110306 110307 110308 110309 110310 110311 110312 110313 110314 110315 110316 110317 110318 110319 110320 110321 110322 110323 110324 110325 110326 110327 110328 110329 110330 110331 110332 110333 110334 110335 110336 110337 110338 110339 110340 110341 110342 110343 110344 110345 110346 110347 110348 110349 110350 110351 110352 110353 110354 110355 110356 110357 110358 110359 110360 110361 110362 110363 110364 110365 110366 110367 110368 110369 110370 110371 110372 110373 110374 110375 110376 110377 110378 110379 110380 110381 110382 110383 110384 110385 110386 110387 110388 110389 110390 110391 110392 110393 110394 110395 110396 110397 110398 110399 110400 110401 110402 110403 110404 110405 110406 110407 110408 110409 110410 110411 110412 110413 110414 110415 110416 110417 110418 110419 110420 110421 110422 110423 110424 110425 110426 110427 110428 110429 110430 110431 110432 110433 110434 110435 110436 110437 110438 110439 110440 110441 110442 110443 110444 110445 110446 110447 110448 110449 110450 110451 110452 110453 110454 110455 110456 110457 110458 110459 110460 110461 110462 110463 110464 110465 110466 110467 110468 110469 110470 110471 110472 110473 110474 110475 110476 110477 110478 110479 110480 110481 110482 110483 110484 110485 110486 110487 110488 110489 110490 110491 110492 110493 110494 110495 110496 110497 110498 110499 110500 110501 110502 110503 110504 110505 110506 110507 110508 110509 110510 110511 110512 110513 110514 110515 110516 110517 110518 110519 110520 110521 110522 110523 110524 110525 110526 110527 110528 110529 110530 110531 110532 110533 110534 110535 110536 110537 110538 110539 110540 110541 110542 110543 110544 110545 110546 110547 110548 110549 110550 110551 110552 110553 110554 110555 110556 110557 110558 110559 110560 110561 110562 110563 110564 110565 110566 110567 110568 110569 110570 110571 110572 110573 110574 110575 110576 110577 110578 110579 110580 110581 110582 110583 110584 110585 110586 110587 110588 110589 110590 110591 110592 110593 110594 110595 110596 110597 110598 110599 110600 110601 110602 110603 110604 110605 110606 110607 110608 110609 110610 110611 110612 110613 110614 110615 110616 110617 110618 110619 110620 110621 110622 110623 110624 110625 110626 110627 110628 110629 110630 110631 110632 110633 110634 110635 110636 110637 110638 110639 110640 110641 110642 110643 110644 110645 110646 110647 110648 110649 110650 110651 110652 110653 110654 110655 110656 110657 110658 110659 110660 110661 110662 110663 110664 110665 110666 110667 110668 110669 110670 110671 110672 110673 110674 110675 110676 110677 110678 110679 110680 110681 110682 110683 110684 110685 110686 110687 110688 110689 110690 110691 110692 110693 110694 110695 110696 110697 110698 110699 110700 110701 110702 110703 110704 110705 110706 110707 110708 110709 110710 110711 110712 110713 110714 110715 110716 110717 110718 110719 110720 110721 110722 110723 110724 110725 110726 110727 110728 110729 110730 110731 110732 110733 110734 110735 110736 110737 110738 110739 110740 110741 110742 110743 110744 110745 110746 110747 110748 110749 110750 110751 110752 110753 110754 110755 110756 110757 110758 110759 110760 110761 110762 110763 110764 110765 110766 110767 110768 110769 110770 110771 110772 110773 110774 110775 110776 110777 110778 110779 110780 110781 110782 110783 110784 110785 110786 110787 110788 110789 110790 110791 110792 110793 110794 110795 110796 110797 110798 110799 110800 110801 110802 110803 110804 110805 110806 110807 110808 110809 110810 110811 110812 110813 110814 110815 110816 110817 110818 110819 110820 110821 110822 110823 110824 110825 110826 110827 110828 110829 110830 110831 110832 110833 110834 110835 110836 110837 110838 110839 110840 110841 110842 110843 110844 110845 110846 110847 110848 110849 110850 110851 110852 110853 110854 110855 110856 110857 110858 110859 110860 110861 110862 110863 110864 110865 110866 110867 110868 110869 110870 110871 110872 110873 110874 110875 110876 110877 110878 110879 110880 110881 110882 110883 110884 110885 110886 110887 110888 110889 110890 110891 110892 110893 110894 110895 110896 110897 110898 110899 110900 110901 110902 110903 110904 110905 110906 110907 110908 110909 110910 110911 110912 110913 110914 110915 110916 110917 110918 110919 110920 110921 110922 110923 110924 110925 110926 110927 110928 110929 110930 110931 110932 110933 110934 110935 110936 110937 110938 110939 110940 110941 110942 110943 110944 110945 110946 110947 110948 110949 110950 110951 110952 110953 110954 110955 110956 110957 110958 110959 110960 110961 110962 110963 110964 110965 |
}
break;
case 50: /* typename ::= typename ids */
{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
break;
case 57: /* ccons ::= DEFAULT term */
case 59: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==59);
{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy342);}
break;
case 58: /* ccons ::= DEFAULT LP expr RP */
{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy342);}
break;
case 60: /* ccons ::= DEFAULT MINUS term */
{
ExprSpan v;
v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy342.pExpr, 0, 0);
v.zStart = yymsp[-1].minor.yy0.z;
v.zEnd = yymsp[0].minor.yy342.zEnd;
sqlite3AddDefaultValue(pParse,&v);
}
break;
case 61: /* ccons ::= DEFAULT id */
{
ExprSpan v;
spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0);
sqlite3AddDefaultValue(pParse,&v);
}
break;
case 63: /* ccons ::= NOT NULL onconf */
{sqlite3AddNotNull(pParse, yymsp[0].minor.yy392);}
break;
case 64: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy392,yymsp[0].minor.yy392,yymsp[-2].minor.yy392);}
break;
case 65: /* ccons ::= UNIQUE onconf */
{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy392,0,0,0,0);}
break;
case 66: /* ccons ::= CHECK LP expr RP */
{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy342.pExpr);}
break;
case 67: /* ccons ::= REFERENCES nm idxlist_opt refargs */
{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy442,yymsp[0].minor.yy392);}
break;
case 68: /* ccons ::= defer_subclause */
{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy392);}
break;
case 69: /* ccons ::= COLLATE ids */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
case 72: /* refargs ::= */
{ yygotominor.yy392 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
case 73: /* refargs ::= refargs refarg */
{ yygotominor.yy392 = (yymsp[-1].minor.yy392 & ~yymsp[0].minor.yy207.mask) | yymsp[0].minor.yy207.value; }
break;
case 74: /* refarg ::= MATCH nm */
case 75: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==75);
{ yygotominor.yy207.value = 0; yygotominor.yy207.mask = 0x000000; }
break;
case 76: /* refarg ::= ON DELETE refact */
{ yygotominor.yy207.value = yymsp[0].minor.yy392; yygotominor.yy207.mask = 0x0000ff; }
break;
case 77: /* refarg ::= ON UPDATE refact */
{ yygotominor.yy207.value = yymsp[0].minor.yy392<<8; yygotominor.yy207.mask = 0x00ff00; }
break;
case 78: /* refact ::= SET NULL */
{ yygotominor.yy392 = OE_SetNull; /* EV: R-33326-45252 */}
break;
case 79: /* refact ::= SET DEFAULT */
{ yygotominor.yy392 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
case 80: /* refact ::= CASCADE */
{ yygotominor.yy392 = OE_Cascade; /* EV: R-33326-45252 */}
break;
case 81: /* refact ::= RESTRICT */
{ yygotominor.yy392 = OE_Restrict; /* EV: R-33326-45252 */}
break;
case 82: /* refact ::= NO ACTION */
{ yygotominor.yy392 = OE_None; /* EV: R-33326-45252 */}
break;
case 84: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
case 99: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==99);
case 101: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==101);
case 104: /* resolvetype ::= raisetype */ yytestcase(yyruleno==104);
{yygotominor.yy392 = yymsp[0].minor.yy392;}
break;
case 88: /* conslist_opt ::= */
{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;}
break;
case 89: /* conslist_opt ::= COMMA conslist */
{yygotominor.yy0 = yymsp[-1].minor.yy0;}
break;
case 94: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */
{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy442,yymsp[0].minor.yy392,yymsp[-2].minor.yy392,0);}
break;
case 95: /* tcons ::= UNIQUE LP idxlist RP onconf */
{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy442,yymsp[0].minor.yy392,0,0,0,0);}
break;
case 96: /* tcons ::= CHECK LP expr RP onconf */
{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy342.pExpr);}
break;
case 97: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
{
sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy442, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy442, yymsp[-1].minor.yy392);
sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy392);
}
break;
case 100: /* onconf ::= */
{yygotominor.yy392 = OE_Default;}
break;
case 102: /* orconf ::= */
{yygotominor.yy258 = OE_Default;}
break;
case 103: /* orconf ::= OR resolvetype */
{yygotominor.yy258 = (u8)yymsp[0].minor.yy392;}
break;
case 105: /* resolvetype ::= IGNORE */
{yygotominor.yy392 = OE_Ignore;}
break;
case 106: /* resolvetype ::= REPLACE */
{yygotominor.yy392 = OE_Replace;}
break;
case 107: /* cmd ::= DROP TABLE ifexists fullname */
{
sqlite3DropTable(pParse, yymsp[0].minor.yy347, 0, yymsp[-1].minor.yy392);
}
break;
case 110: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select */
{
sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, yymsp[0].minor.yy159, yymsp[-6].minor.yy392, yymsp[-4].minor.yy392);
}
break;
case 111: /* cmd ::= DROP VIEW ifexists fullname */
{
sqlite3DropTable(pParse, yymsp[0].minor.yy347, 1, yymsp[-1].minor.yy392);
}
break;
case 112: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0};
sqlite3Select(pParse, yymsp[0].minor.yy159, &dest);
sqlite3ExplainBegin(pParse->pVdbe);
sqlite3ExplainSelect(pParse->pVdbe, yymsp[0].minor.yy159);
sqlite3ExplainFinish(pParse->pVdbe);
sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159);
}
break;
case 113: /* select ::= oneselect */
{yygotominor.yy159 = yymsp[0].minor.yy159;}
break;
case 114: /* select ::= select multiselect_op oneselect */
{
if( yymsp[0].minor.yy159 ){
yymsp[0].minor.yy159->op = (u8)yymsp[-1].minor.yy392;
yymsp[0].minor.yy159->pPrior = yymsp[-2].minor.yy159;
}else{
sqlite3SelectDelete(pParse->db, yymsp[-2].minor.yy159);
}
yygotominor.yy159 = yymsp[0].minor.yy159;
}
break;
case 116: /* multiselect_op ::= UNION ALL */
{yygotominor.yy392 = TK_ALL;}
break;
case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
yygotominor.yy159 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy392,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset);
}
break;
case 122: /* sclp ::= selcollist COMMA */
case 246: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==246);
{yygotominor.yy442 = yymsp[-1].minor.yy442;}
break;
case 123: /* sclp ::= */
case 151: /* orderby_opt ::= */ yytestcase(yyruleno==151);
case 158: /* groupby_opt ::= */ yytestcase(yyruleno==158);
case 239: /* exprlist ::= */ yytestcase(yyruleno==239);
case 245: /* idxlist_opt ::= */ yytestcase(yyruleno==245);
{yygotominor.yy442 = 0;}
break;
case 124: /* selcollist ::= sclp expr as */
{
yygotominor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy442, yymsp[-1].minor.yy342.pExpr);
if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[0].minor.yy0, 1);
sqlite3ExprListSetSpan(pParse,yygotominor.yy442,&yymsp[-1].minor.yy342);
}
break;
case 125: /* selcollist ::= sclp STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
yygotominor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy442, p);
}
break;
case 126: /* selcollist ::= sclp nm DOT STAR */
{
Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &yymsp[0].minor.yy0);
Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442, pDot);
}
break;
case 129: /* as ::= */
{yygotominor.yy0.n = 0;}
break;
case 130: /* from ::= */
{yygotominor.yy347 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy347));}
break;
case 131: /* from ::= FROM seltablist */
{
yygotominor.yy347 = yymsp[0].minor.yy347;
sqlite3SrcListShiftJoinType(yygotominor.yy347);
}
break;
case 132: /* stl_prefix ::= seltablist joinop */
{
yygotominor.yy347 = yymsp[-1].minor.yy347;
if( ALWAYS(yygotominor.yy347 && yygotominor.yy347->nSrc>0) ) yygotominor.yy347->a[yygotominor.yy347->nSrc-1].jointype = (u8)yymsp[0].minor.yy392;
}
break;
case 133: /* stl_prefix ::= */
{yygotominor.yy347 = 0;}
break;
case 134: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
sqlite3SrcListIndexedBy(pParse, yygotominor.yy347, &yymsp[-2].minor.yy0);
}
break;
case 135: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy159,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
}
break;
case 136: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
if( yymsp[-6].minor.yy347==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy122==0 && yymsp[0].minor.yy180==0 ){
yygotominor.yy347 = yymsp[-4].minor.yy347;
}else{
Select *pSubquery;
sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy347);
pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,0,0,0);
yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
}
}
break;
case 137: /* dbnm ::= */
case 146: /* indexed_opt ::= */ yytestcase(yyruleno==146);
{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
break;
case 139: /* fullname ::= nm dbnm */
{yygotominor.yy347 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
break;
case 140: /* joinop ::= COMMA|JOIN */
{ yygotominor.yy392 = JT_INNER; }
break;
case 141: /* joinop ::= JOIN_KW JOIN */
{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
break;
case 142: /* joinop ::= JOIN_KW nm JOIN */
{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
break;
case 143: /* joinop ::= JOIN_KW nm nm JOIN */
{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
break;
case 144: /* on_opt ::= ON expr */
case 161: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==161);
case 168: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==168);
case 234: /* case_else ::= ELSE expr */ yytestcase(yyruleno==234);
case 236: /* case_operand ::= expr */ yytestcase(yyruleno==236);
{yygotominor.yy122 = yymsp[0].minor.yy342.pExpr;}
break;
case 145: /* on_opt ::= */
case 160: /* having_opt ::= */ yytestcase(yyruleno==160);
case 167: /* where_opt ::= */ yytestcase(yyruleno==167);
case 235: /* case_else ::= */ yytestcase(yyruleno==235);
case 237: /* case_operand ::= */ yytestcase(yyruleno==237);
{yygotominor.yy122 = 0;}
break;
case 148: /* indexed_opt ::= NOT INDEXED */
{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
break;
case 149: /* using_opt ::= USING LP inscollist RP */
case 180: /* inscollist_opt ::= LP inscollist RP */ yytestcase(yyruleno==180);
{yygotominor.yy180 = yymsp[-1].minor.yy180;}
break;
case 150: /* using_opt ::= */
case 179: /* inscollist_opt ::= */ yytestcase(yyruleno==179);
{yygotominor.yy180 = 0;}
break;
case 152: /* orderby_opt ::= ORDER BY sortlist */
case 159: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==159);
case 238: /* exprlist ::= nexprlist */ yytestcase(yyruleno==238);
{yygotominor.yy442 = yymsp[0].minor.yy442;}
break;
case 153: /* sortlist ::= sortlist COMMA expr sortorder */
{
yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442,yymsp[-1].minor.yy342.pExpr);
if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
case 154: /* sortlist ::= expr sortorder */
{
yygotominor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy342.pExpr);
if( yygotominor.yy442 && ALWAYS(yygotominor.yy442->a) ) yygotominor.yy442->a[0].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
case 155: /* sortorder ::= ASC */
case 157: /* sortorder ::= */ yytestcase(yyruleno==157);
{yygotominor.yy392 = SQLITE_SO_ASC;}
break;
case 156: /* sortorder ::= DESC */
{yygotominor.yy392 = SQLITE_SO_DESC;}
break;
case 162: /* limit_opt ::= */
{yygotominor.yy64.pLimit = 0; yygotominor.yy64.pOffset = 0;}
break;
case 163: /* limit_opt ::= LIMIT expr */
{yygotominor.yy64.pLimit = yymsp[0].minor.yy342.pExpr; yygotominor.yy64.pOffset = 0;}
break;
case 164: /* limit_opt ::= LIMIT expr OFFSET expr */
{yygotominor.yy64.pLimit = yymsp[-2].minor.yy342.pExpr; yygotominor.yy64.pOffset = yymsp[0].minor.yy342.pExpr;}
break;
case 165: /* limit_opt ::= LIMIT expr COMMA expr */
{yygotominor.yy64.pOffset = yymsp[-2].minor.yy342.pExpr; yygotominor.yy64.pLimit = yymsp[0].minor.yy342.pExpr;}
break;
case 166: /* cmd ::= DELETE FROM fullname indexed_opt where_opt */
{
sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy347, &yymsp[-1].minor.yy0);
sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy347,yymsp[0].minor.yy122);
}
break;
case 169: /* cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt */
{
sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy347, &yymsp[-3].minor.yy0);
sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy442,"set list");
sqlite3Update(pParse,yymsp[-4].minor.yy347,yymsp[-1].minor.yy442,yymsp[0].minor.yy122,yymsp[-5].minor.yy258);
}
break;
case 170: /* setlist ::= setlist COMMA nm EQ expr */
{
yygotominor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr);
sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1);
}
break;
case 171: /* setlist ::= nm EQ expr */
{
yygotominor.yy442 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy342.pExpr);
sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1);
}
break;
case 172: /* cmd ::= insert_cmd INTO fullname inscollist_opt valuelist */
{sqlite3Insert(pParse, yymsp[-2].minor.yy347, yymsp[0].minor.yy487.pList, yymsp[0].minor.yy487.pSelect, yymsp[-1].minor.yy180, yymsp[-4].minor.yy258);}
break;
case 173: /* cmd ::= insert_cmd INTO fullname inscollist_opt select */
{sqlite3Insert(pParse, yymsp[-2].minor.yy347, 0, yymsp[0].minor.yy159, yymsp[-1].minor.yy180, yymsp[-4].minor.yy258);}
break;
case 174: /* cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */
{sqlite3Insert(pParse, yymsp[-3].minor.yy347, 0, 0, yymsp[-2].minor.yy180, yymsp[-5].minor.yy258);}
break;
case 175: /* insert_cmd ::= INSERT orconf */
{yygotominor.yy258 = yymsp[0].minor.yy258;}
break;
case 176: /* insert_cmd ::= REPLACE */
{yygotominor.yy258 = OE_Replace;}
break;
case 177: /* valuelist ::= VALUES LP nexprlist RP */
{
yygotominor.yy487.pList = yymsp[-1].minor.yy442;
yygotominor.yy487.pSelect = 0;
}
break;
case 178: /* valuelist ::= valuelist COMMA LP exprlist RP */
{
Select *pRight = sqlite3SelectNew(pParse, yymsp[-1].minor.yy442, 0, 0, 0, 0, 0, 0, 0, 0);
if( yymsp[-4].minor.yy487.pList ){
yymsp[-4].minor.yy487.pSelect = sqlite3SelectNew(pParse, yymsp[-4].minor.yy487.pList, 0, 0, 0, 0, 0, 0, 0, 0);
yymsp[-4].minor.yy487.pList = 0;
}
yygotominor.yy487.pList = 0;
if( yymsp[-4].minor.yy487.pSelect==0 || pRight==0 ){
sqlite3SelectDelete(pParse->db, pRight);
sqlite3SelectDelete(pParse->db, yymsp[-4].minor.yy487.pSelect);
yygotominor.yy487.pSelect = 0;
}else{
pRight->op = TK_ALL;
pRight->pPrior = yymsp[-4].minor.yy487.pSelect;
pRight->selFlags |= SF_Values;
pRight->pPrior->selFlags |= SF_Values;
yygotominor.yy487.pSelect = pRight;
}
}
break;
case 181: /* inscollist ::= inscollist COMMA nm */
{yygotominor.yy180 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy180,&yymsp[0].minor.yy0);}
break;
case 182: /* inscollist ::= nm */
{yygotominor.yy180 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
break;
case 183: /* expr ::= term */
{yygotominor.yy342 = yymsp[0].minor.yy342;}
break;
case 184: /* expr ::= LP expr RP */
{yygotominor.yy342.pExpr = yymsp[-1].minor.yy342.pExpr; spanSet(&yygotominor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
break;
case 185: /* term ::= NULL */
case 190: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==190);
case 191: /* term ::= STRING */ yytestcase(yyruleno==191);
{spanExpr(&yygotominor.yy342, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
break;
case 186: /* expr ::= id */
case 187: /* expr ::= JOIN_KW */ yytestcase(yyruleno==187);
{spanExpr(&yygotominor.yy342, pParse, TK_ID, &yymsp[0].minor.yy0);}
break;
case 188: /* expr ::= nm DOT nm */
{
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
spanSet(&yygotominor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
}
break;
case 189: /* expr ::= nm DOT nm DOT nm */
{
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
spanSet(&yygotominor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
}
break;
case 192: /* expr ::= REGISTER */
{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &yymsp[0].minor.yy0);
yygotominor.yy342.pExpr = 0;
}else{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0);
if( yygotominor.yy342.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy342.pExpr->iTable);
}
spanSet(&yygotominor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
case 193: /* expr ::= VARIABLE */
{
spanExpr(&yygotominor.yy342, pParse, TK_VARIABLE, &yymsp[0].minor.yy0);
sqlite3ExprAssignVarNumber(pParse, yygotominor.yy342.pExpr);
spanSet(&yygotominor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
case 194: /* expr ::= expr COLLATE ids */
{
yygotominor.yy342.pExpr = sqlite3ExprSetCollByToken(pParse, yymsp[-2].minor.yy342.pExpr, &yymsp[0].minor.yy0);
yygotominor.yy342.zStart = yymsp[-2].minor.yy342.zStart;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 195: /* expr ::= CAST LP expr AS typetoken RP */
{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy342.pExpr, 0, &yymsp[-1].minor.yy0);
spanSet(&yygotominor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
}
break;
case 196: /* expr ::= ID LP distinct exprlist RP */
{
if( yymsp[-1].minor.yy442 && yymsp[-1].minor.yy442->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
}
yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy442, &yymsp[-4].minor.yy0);
spanSet(&yygotominor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
if( yymsp[-2].minor.yy392 && yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->flags |= EP_Distinct;
}
}
break;
case 197: /* expr ::= ID LP STAR RP */
{
yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
spanSet(&yygotominor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
}
break;
case 198: /* term ::= CTIME_KW */
{
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, 0,&yymsp[0].minor.yy0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->op = TK_CONST_FUNC;
}
spanSet(&yygotominor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
case 199: /* expr ::= expr AND expr */
case 200: /* expr ::= expr OR expr */ yytestcase(yyruleno==200);
case 201: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==201);
case 202: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==202);
case 203: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==203);
case 204: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==204);
case 205: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==205);
case 206: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==206);
{spanBinaryExpr(&yygotominor.yy342,pParse,yymsp[-1].major,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);}
break;
case 207: /* likeop ::= LIKE_KW */
case 209: /* likeop ::= MATCH */ yytestcase(yyruleno==209);
{yygotominor.yy318.eOperator = yymsp[0].minor.yy0; yygotominor.yy318.not = 0;}
break;
case 208: /* likeop ::= NOT LIKE_KW */
case 210: /* likeop ::= NOT MATCH */ yytestcase(yyruleno==210);
{yygotominor.yy318.eOperator = yymsp[0].minor.yy0; yygotominor.yy318.not = 1;}
break;
case 211: /* expr ::= expr likeop expr */
{
ExprList *pList;
pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy342.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy342.pExpr);
yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy318.eOperator);
if( yymsp[-1].minor.yy318.not ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
yygotominor.yy342.zStart = yymsp[-2].minor.yy342.zStart;
yygotominor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
if( yygotominor.yy342.pExpr ) yygotominor.yy342.pExpr->flags |= EP_InfixFunc;
}
break;
case 212: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy342.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr);
yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy318.eOperator);
if( yymsp[-3].minor.yy318.not ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
yygotominor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
if( yygotominor.yy342.pExpr ) yygotominor.yy342.pExpr->flags |= EP_InfixFunc;
}
break;
case 213: /* expr ::= expr ISNULL|NOTNULL */
{spanUnaryPostfix(&yygotominor.yy342,pParse,yymsp[0].major,&yymsp[-1].minor.yy342,&yymsp[0].minor.yy0);}
break;
case 214: /* expr ::= expr NOT NULL */
{spanUnaryPostfix(&yygotominor.yy342,pParse,TK_NOTNULL,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy0);}
break;
case 215: /* expr ::= expr IS expr */
{
spanBinaryExpr(&yygotominor.yy342,pParse,TK_IS,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yygotominor.yy342.pExpr, TK_ISNULL);
}
break;
case 216: /* expr ::= expr IS NOT expr */
{
spanBinaryExpr(&yygotominor.yy342,pParse,TK_ISNOT,&yymsp[-3].minor.yy342,&yymsp[0].minor.yy342);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yygotominor.yy342.pExpr, TK_NOTNULL);
}
break;
case 217: /* expr ::= NOT expr */
case 218: /* expr ::= BITNOT expr */ yytestcase(yyruleno==218);
{spanUnaryPrefix(&yygotominor.yy342,pParse,yymsp[-1].major,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
case 219: /* expr ::= MINUS expr */
{spanUnaryPrefix(&yygotominor.yy342,pParse,TK_UMINUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
case 220: /* expr ::= PLUS expr */
{spanUnaryPrefix(&yygotominor.yy342,pParse,TK_UPLUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
case 223: /* expr ::= expr between_op expr AND expr */
{
ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr);
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy342.pExpr, 0, 0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
if( yymsp[-3].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
yygotominor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
}
break;
case 226: /* expr ::= expr in_op LP exprlist RP */
{
if( yymsp[-1].minor.yy442==0 ){
/* Expressions of the form
**
** expr1 IN ()
** expr1 NOT IN ()
**
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy392]);
sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy342.pExpr);
}else{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->x.pList = yymsp[-1].minor.yy442;
sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy442);
}
if( yymsp[-3].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
}
yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 227: /* expr ::= LP select RP */
{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->x.pSelect = yymsp[-1].minor.yy159;
ExprSetProperty(yygotominor.yy342.pExpr, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy159);
}
yygotominor.yy342.zStart = yymsp[-2].minor.yy0.z;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 228: /* expr ::= expr in_op LP select RP */
{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->x.pSelect = yymsp[-1].minor.yy159;
ExprSetProperty(yygotominor.yy342.pExpr, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy159);
}
if( yymsp[-3].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
yygotominor.yy342.zStart = yymsp[-4].minor.yy342.zStart;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 229: /* expr ::= expr in_op nm dbnm */
{
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy342.pExpr, 0, 0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
ExprSetProperty(yygotominor.yy342.pExpr, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
}
if( yymsp[-2].minor.yy392 ) yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy342.pExpr, 0, 0);
yygotominor.yy342.zStart = yymsp[-3].minor.yy342.zStart;
yygotominor.yy342.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
}
break;
case 230: /* expr ::= EXISTS LP select RP */
{
Expr *p = yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->x.pSelect = yymsp[-1].minor.yy159;
ExprSetProperty(p, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, p);
}else{
sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy159);
}
yygotominor.yy342.zStart = yymsp[-3].minor.yy0.z;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 231: /* expr ::= CASE case_operand case_exprlist case_else END */
{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy122, yymsp[-1].minor.yy122, 0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->x.pList = yymsp[-2].minor.yy442;
sqlite3ExprSetHeight(pParse, yygotominor.yy342.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy442);
}
yygotominor.yy342.zStart = yymsp[-4].minor.yy0.z;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 232: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[-2].minor.yy342.pExpr);
yygotominor.yy442 = sqlite3ExprListAppend(pParse,yygotominor.yy442, yymsp[0].minor.yy342.pExpr);
}
break;
case 233: /* case_exprlist ::= WHEN expr THEN expr */
{
yygotominor.yy442 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
yygotominor.yy442 = sqlite3ExprListAppend(pParse,yygotominor.yy442, yymsp[0].minor.yy342.pExpr);
}
break;
case 240: /* nexprlist ::= nexprlist COMMA expr */
{yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[0].minor.yy342.pExpr);}
break;
case 241: /* nexprlist ::= expr */
{yygotominor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy342.pExpr);}
break;
case 242: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP */
{
sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0,
sqlite3SrcListAppend(pParse->db,0,&yymsp[-3].minor.yy0,0), yymsp[-1].minor.yy442, yymsp[-9].minor.yy392,
&yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy392);
}
break;
case 243: /* uniqueflag ::= UNIQUE */
case 296: /* raisetype ::= ABORT */ yytestcase(yyruleno==296);
{yygotominor.yy392 = OE_Abort;}
break;
case 244: /* uniqueflag ::= */
{yygotominor.yy392 = OE_None;}
break;
case 247: /* idxlist ::= idxlist COMMA nm collate sortorder */
{
Expr *p = 0;
if( yymsp[-1].minor.yy0.n>0 ){
p = sqlite3Expr(pParse->db, TK_COLUMN, 0);
sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0);
}
yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, p);
sqlite3ExprListSetName(pParse,yygotominor.yy442,&yymsp[-2].minor.yy0,1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index");
if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
case 248: /* idxlist ::= nm collate sortorder */
{
Expr *p = 0;
if( yymsp[-1].minor.yy0.n>0 ){
p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
sqlite3ExprSetCollByToken(pParse, p, &yymsp[-1].minor.yy0);
}
yygotominor.yy442 = sqlite3ExprListAppend(pParse,0, p);
sqlite3ExprListSetName(pParse, yygotominor.yy442, &yymsp[-2].minor.yy0, 1);
sqlite3ExprListCheckLength(pParse, yygotominor.yy442, "index");
if( yygotominor.yy442 ) yygotominor.yy442->a[yygotominor.yy442->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy392;
}
break;
case 249: /* collate ::= */
{yygotominor.yy0.z = 0; yygotominor.yy0.n = 0;}
break;
case 251: /* cmd ::= DROP INDEX ifexists fullname */
{sqlite3DropIndex(pParse, yymsp[0].minor.yy347, yymsp[-1].minor.yy392);}
break;
case 252: /* cmd ::= VACUUM */
case 253: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==253);
{sqlite3Vacuum(pParse);}
break;
case 254: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
case 255: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
case 256: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
case 257: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
case 258: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
case 268: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
Token all;
all.z = yymsp[-3].minor.yy0.z;
all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy327, &all);
}
break;
case 269: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy392, yymsp[-4].minor.yy410.a, yymsp[-4].minor.yy410.b, yymsp[-2].minor.yy347, yymsp[0].minor.yy122, yymsp[-10].minor.yy392, yymsp[-8].minor.yy392);
yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0);
}
break;
case 270: /* trigger_time ::= BEFORE */
case 273: /* trigger_time ::= */ yytestcase(yyruleno==273);
{ yygotominor.yy392 = TK_BEFORE; }
break;
case 271: /* trigger_time ::= AFTER */
{ yygotominor.yy392 = TK_AFTER; }
break;
case 272: /* trigger_time ::= INSTEAD OF */
{ yygotominor.yy392 = TK_INSTEAD;}
break;
case 274: /* trigger_event ::= DELETE|INSERT */
case 275: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==275);
{yygotominor.yy410.a = yymsp[0].major; yygotominor.yy410.b = 0;}
break;
case 276: /* trigger_event ::= UPDATE OF inscollist */
{yygotominor.yy410.a = TK_UPDATE; yygotominor.yy410.b = yymsp[0].minor.yy180;}
break;
case 279: /* when_clause ::= */
case 301: /* key_opt ::= */ yytestcase(yyruleno==301);
{ yygotominor.yy122 = 0; }
break;
case 280: /* when_clause ::= WHEN expr */
case 302: /* key_opt ::= KEY expr */ yytestcase(yyruleno==302);
{ yygotominor.yy122 = yymsp[0].minor.yy342.pExpr; }
break;
case 281: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
assert( yymsp[-2].minor.yy327!=0 );
yymsp[-2].minor.yy327->pLast->pNext = yymsp[-1].minor.yy327;
yymsp[-2].minor.yy327->pLast = yymsp[-1].minor.yy327;
yygotominor.yy327 = yymsp[-2].minor.yy327;
}
break;
case 282: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
assert( yymsp[-1].minor.yy327!=0 );
yymsp[-1].minor.yy327->pLast = yymsp[-1].minor.yy327;
yygotominor.yy327 = yymsp[-1].minor.yy327;
}
break;
case 284: /* trnm ::= nm DOT nm */
{
yygotominor.yy0 = yymsp[0].minor.yy0;
sqlite3ErrorMsg(pParse,
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
"statements within triggers");
}
break;
case 286: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
case 287: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
case 288: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
{ yygotominor.yy327 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy442, yymsp[0].minor.yy122, yymsp[-5].minor.yy258); }
break;
case 289: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt valuelist */
{yygotominor.yy327 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy180, yymsp[0].minor.yy487.pList, yymsp[0].minor.yy487.pSelect, yymsp[-4].minor.yy258);}
break;
case 290: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select */
{yygotominor.yy327 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy180, 0, yymsp[0].minor.yy159, yymsp[-4].minor.yy258);}
break;
case 291: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
{yygotominor.yy327 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy122);}
break;
case 292: /* trigger_cmd ::= select */
{yygotominor.yy327 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy159); }
break;
case 293: /* expr ::= RAISE LP IGNORE RP */
{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
if( yygotominor.yy342.pExpr ){
yygotominor.yy342.pExpr->affinity = OE_Ignore;
}
yygotominor.yy342.zStart = yymsp[-3].minor.yy0.z;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 294: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
yygotominor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0);
if( yygotominor.yy342.pExpr ) {
yygotominor.yy342.pExpr->affinity = (char)yymsp[-3].minor.yy392;
}
yygotominor.yy342.zStart = yymsp[-5].minor.yy0.z;
yygotominor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
case 295: /* raisetype ::= ROLLBACK */
{yygotominor.yy392 = OE_Rollback;}
break;
case 297: /* raisetype ::= FAIL */
{yygotominor.yy392 = OE_Fail;}
break;
case 298: /* cmd ::= DROP TRIGGER ifexists fullname */
{
sqlite3DropTrigger(pParse,yymsp[0].minor.yy347,yymsp[-1].minor.yy392);
}
break;
case 299: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
sqlite3Attach(pParse, yymsp[-3].minor.yy342.pExpr, yymsp[-1].minor.yy342.pExpr, yymsp[0].minor.yy122);
}
break;
case 300: /* cmd ::= DETACH database_kw_opt expr */
{
sqlite3Detach(pParse, yymsp[0].minor.yy342.pExpr);
}
break;
case 305: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
case 306: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
case 307: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
case 308: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
case 309: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy347,&yymsp[0].minor.yy0);
}
break;
case 310: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
{
sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
}
break;
case 311: /* add_column_fullname ::= fullname */
{
pParse->db->lookaside.bEnabled = 0;
sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy347);
}
break;
case 314: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
case 315: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
case 316: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy392);
}
break;
case 319: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
case 321: /* vtabargtoken ::= ANY */
case 322: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==322);
case 323: /* lp ::= LP */ yytestcase(yyruleno==323);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
default:
/* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
/* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
/* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
/* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
|
| ︙ | ︙ | |||
110720 110721 110722 110723 110724 110725 110726 |
/* (55) carg ::= CONSTRAINT nm ccons */ yytestcase(yyruleno==55);
/* (56) carg ::= ccons */ yytestcase(yyruleno==56);
/* (62) ccons ::= NULL onconf */ yytestcase(yyruleno==62);
/* (90) conslist ::= conslist COMMA tcons */ yytestcase(yyruleno==90);
/* (91) conslist ::= conslist tcons */ yytestcase(yyruleno==91);
/* (92) conslist ::= tcons */ yytestcase(yyruleno==92);
/* (93) tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==93);
| < < | | | | | | | | | | | | | | 110980 110981 110982 110983 110984 110985 110986 110987 110988 110989 110990 110991 110992 110993 110994 110995 110996 110997 110998 110999 111000 111001 111002 111003 111004 111005 111006 |
/* (55) carg ::= CONSTRAINT nm ccons */ yytestcase(yyruleno==55);
/* (56) carg ::= ccons */ yytestcase(yyruleno==56);
/* (62) ccons ::= NULL onconf */ yytestcase(yyruleno==62);
/* (90) conslist ::= conslist COMMA tcons */ yytestcase(yyruleno==90);
/* (91) conslist ::= conslist tcons */ yytestcase(yyruleno==91);
/* (92) conslist ::= tcons */ yytestcase(yyruleno==92);
/* (93) tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==93);
/* (277) foreach_clause ::= */ yytestcase(yyruleno==277);
/* (278) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==278);
/* (285) tridxby ::= */ yytestcase(yyruleno==285);
/* (303) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==303);
/* (304) database_kw_opt ::= */ yytestcase(yyruleno==304);
/* (312) kwcolumn_opt ::= */ yytestcase(yyruleno==312);
/* (313) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==313);
/* (317) vtabarglist ::= vtabarg */ yytestcase(yyruleno==317);
/* (318) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==318);
/* (320) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==320);
/* (324) anylist ::= */ yytestcase(yyruleno==324);
/* (325) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==325);
/* (326) anylist ::= anylist ANY */ yytestcase(yyruleno==326);
break;
};
yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
if( yyact < YYNSTATE ){
|
| ︙ | ︙ | |||
113019 113020 113021 113022 113023 113024 113025 |
sqlite3_free(db->lookaside.pStart);
}
sqlite3_free(db);
return SQLITE_OK;
}
/*
| | > > > | | > | | | 113277 113278 113279 113280 113281 113282 113283 113284 113285 113286 113287 113288 113289 113290 113291 113292 113293 113294 113295 113296 113297 113298 113299 113300 113301 113302 113303 113304 113305 113306 113307 |
sqlite3_free(db->lookaside.pStart);
}
sqlite3_free(db);
return SQLITE_OK;
}
/*
** Rollback all database files. If tripCode is not SQLITE_OK, then
** any open cursors are invalidated ("tripped" - as in "tripping a circuit
** breaker") and made to return tripCode if there are any further
** attempts to use that cursor.
*/
SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
int i;
int inTrans = 0;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3BeginBenignMalloc();
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
if( p ){
if( sqlite3BtreeIsInTrans(p) ){
inTrans = 1;
}
sqlite3BtreeRollback(p, tripCode);
db->aDb[i].inTrans = 0;
}
}
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
if( db->flags&SQLITE_InternChanges ){
|
| ︙ | ︙ | |||
113086 113087 113088 113089 113090 113091 113092 |
/* SQLITE_MISUSE */ "library routine called out of sequence",
/* SQLITE_NOLFS */ "large file support is disabled",
/* SQLITE_AUTH */ "authorization denied",
/* SQLITE_FORMAT */ "auxiliary database format error",
/* SQLITE_RANGE */ "bind or column index out of range",
/* SQLITE_NOTADB */ "file is encrypted or is not a database",
};
| > > > > > > > | | | > | < | > > | 113348 113349 113350 113351 113352 113353 113354 113355 113356 113357 113358 113359 113360 113361 113362 113363 113364 113365 113366 113367 113368 113369 113370 113371 113372 113373 113374 113375 113376 |
/* SQLITE_MISUSE */ "library routine called out of sequence",
/* SQLITE_NOLFS */ "large file support is disabled",
/* SQLITE_AUTH */ "authorization denied",
/* SQLITE_FORMAT */ "auxiliary database format error",
/* SQLITE_RANGE */ "bind or column index out of range",
/* SQLITE_NOTADB */ "file is encrypted or is not a database",
};
const char *zErr = "unknown error";
switch( rc ){
case SQLITE_ABORT_ROLLBACK: {
zErr = "abort due to ROLLBACK";
break;
}
default: {
rc &= 0xff;
if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){
zErr = aMsg[rc];
}
break;
}
}
return zErr;
}
/*
** This routine implements a busy callback that sleeps and tries
** again until a timeout value is reached. The timeout value is
** an integer number of milliseconds passed in as the first
** argument.
|
| ︙ | ︙ | |||
113469 113470 113471 113472 113473 113474 113475 | db->xProfile = xProfile; db->pProfileArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_TRACE */ | | < | | 113740 113741 113742 113743 113744 113745 113746 113747 113748 113749 113750 113751 113752 113753 113754 113755 | db->xProfile = xProfile; db->pProfileArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_TRACE */ /* ** Register a function to be invoked when a transaction commits. ** If the invoked function returns non-zero, then the commit becomes a ** rollback. */ SQLITE_API void *sqlite3_commit_hook( sqlite3 *db, /* Attach the hook to this database */ int (*xCallback)(void*), /* Function to invoke on each commit */ void *pArg /* Argument to the function */ |
| ︙ | ︙ | |||
114862 114863 114864 114865 114866 114867 114868 |
}
/*
** Invoke the xFileControl method on a particular database.
*/
SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
int rc = SQLITE_ERROR;
| > | | < < < < < < < < | | | | | | | | | | | | | | | | | < | 115132 115133 115134 115135 115136 115137 115138 115139 115140 115141 115142 115143 115144 115145 115146 115147 115148 115149 115150 115151 115152 115153 115154 115155 115156 115157 115158 115159 115160 115161 115162 115163 115164 115165 115166 |
}
/*
** Invoke the xFileControl method on a particular database.
*/
SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
int rc = SQLITE_ERROR;
Btree *pBtree;
sqlite3_mutex_enter(db->mutex);
pBtree = sqlite3DbNameToBtree(db, zDbName);
if( pBtree ){
Pager *pPager;
sqlite3_file *fd;
sqlite3BtreeEnter(pBtree);
pPager = sqlite3BtreePager(pBtree);
assert( pPager!=0 );
fd = sqlite3PagerFile(pPager);
assert( fd!=0 );
if( op==SQLITE_FCNTL_FILE_POINTER ){
*(sqlite3_file**)pArg = fd;
rc = SQLITE_OK;
}else if( fd->pMethods ){
rc = sqlite3OsFileControl(fd, op, pArg);
}else{
rc = SQLITE_NOTFOUND;
}
sqlite3BtreeLeave(pBtree);
}
sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** Interface to the testing logic.
|
| ︙ | ︙ | |||
115165 115166 115167 115168 115169 115170 115171 |
}
/*
** Return a boolean value for a query parameter.
*/
SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
| > | > > > > > > > > > > > > > > > < < | | | | > > > > > > | | 115427 115428 115429 115430 115431 115432 115433 115434 115435 115436 115437 115438 115439 115440 115441 115442 115443 115444 115445 115446 115447 115448 115449 115450 115451 115452 115453 115454 115455 115456 115457 115458 115459 115460 115461 115462 115463 115464 115465 115466 115467 115468 115469 115470 115471 115472 115473 115474 115475 115476 115477 115478 115479 115480 115481 115482 115483 115484 115485 115486 115487 115488 115489 115490 115491 |
}
/*
** Return a boolean value for a query parameter.
*/
SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
bDflt = bDflt!=0;
return z ? sqlite3GetBoolean(z, bDflt) : bDflt;
}
/*
** Return a 64-bit integer value for a query parameter.
*/
SQLITE_API sqlite3_int64 sqlite3_uri_int64(
const char *zFilename, /* Filename as passed to xOpen */
const char *zParam, /* URI parameter sought */
sqlite3_int64 bDflt /* return if parameter is missing */
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
if( z && sqlite3Atoi64(z, &v, sqlite3Strlen30(z), SQLITE_UTF8)==SQLITE_OK ){
bDflt = v;
}
return bDflt;
}
/*
** Return the Btree pointer identified by zDbName. Return NULL if not found.
*/
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
int i;
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt
&& (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
){
return db->aDb[i].pBt;
}
}
return 0;
}
/*
** Return the filename of the database associated with a database
** connection.
*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3BtreeGetFilename(pBt) : 0;
}
/*
** Return 1 if database is read-only or 0 if read/write. Return -1 if
** no such database exists.
*/
SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
Btree *pBt = sqlite3DbNameToBtree(db, zDbName);
return pBt ? sqlite3PagerIsreadonly(sqlite3BtreePager(pBt)) : -1;
}
/************** End of main.c ************************************************/
/************** Begin file notify.c ******************************************/
/*
** 2009 March 3
**
|
| ︙ | ︙ | |||
115821 115822 115823 115824 115825 115826 115827 | ** index when a document is deleted or updated. For deletions, we ** write an empty doclist (varint(docid) varint(POS_END)), for updates ** we simply write the new doclist. Segment merges overwrite older ** data for a particular docid with newer data, so deletes or updates ** will eventually overtake the earlier data and knock it out. The ** query logic likewise merges doclists so that newer data knocks out ** older data. | < < < < | 116103 116104 116105 116106 116107 116108 116109 116110 116111 116112 116113 116114 116115 116116 | ** index when a document is deleted or updated. For deletions, we ** write an empty doclist (varint(docid) varint(POS_END)), for updates ** we simply write the new doclist. Segment merges overwrite older ** data for a particular docid with newer data, so deletes or updates ** will eventually overtake the earlier data and knock it out. The ** query logic likewise merges doclists so that newer data knocks out ** older data. */ /************** Include fts3Int.h in the middle of fts3.c ********************/ /************** Begin file fts3Int.h *****************************************/ /* ** 2009 Nov 12 ** |
| ︙ | ︙ | |||
115920 115921 115922 115923 115924 115925 115926 |
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module {
/*
| | | 116198 116199 116200 116201 116202 116203 116204 116205 116206 116207 116208 116209 116210 116211 116212 |
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
struct sqlite3_tokenizer_module {
/*
** Structure version. Should always be set to 0 or 1.
*/
int iVersion;
/*
** Create a new tokenizer. The values in the argv[] array are the
** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL
** TABLE statement that created the fts3 table. For example, if
|
| ︙ | ︙ | |||
116001 116002 116003 116004 116005 116006 116007 116008 116009 116010 116011 116012 116013 116014 |
int (*xNext)(
sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int *piPosition /* OUT: Number of tokens returned before this one */
);
};
struct sqlite3_tokenizer {
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
/* Tokenizer implementations will typically add additional fields */
};
| > > > > > > > > > | 116279 116280 116281 116282 116283 116284 116285 116286 116287 116288 116289 116290 116291 116292 116293 116294 116295 116296 116297 116298 116299 116300 116301 |
int (*xNext)(
sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
int *piPosition /* OUT: Number of tokens returned before this one */
);
/***********************************************************************
** Methods below this point are only available if iVersion>=1.
*/
/*
** Configure the language id of a tokenizer cursor.
*/
int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
};
struct sqlite3_tokenizer {
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
/* Tokenizer implementations will typically add additional fields */
};
|
| ︙ | ︙ | |||
116292 116293 116294 116295 116296 116297 116298 116299 116300 116301 116302 | sqlite3 *db; /* The database connection */ const char *zDb; /* logical database name */ const char *zName; /* virtual table name */ int nColumn; /* number of named columns in virtual table */ char **azColumn; /* column names. malloced */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. */ | > | | | | | | | > | | > | 116579 116580 116581 116582 116583 116584 116585 116586 116587 116588 116589 116590 116591 116592 116593 116594 116595 116596 116597 116598 116599 116600 116601 116602 116603 116604 116605 116606 116607 116608 116609 116610 116611 116612 116613 116614 116615 116616 116617 116618 116619 116620 116621 116622 116623 116624 116625 116626 116627 116628 116629 116630 116631 116632 116633 116634 116635 116636 116637 116638 116639 116640 116641 116642 116643 116644 116645 116646 116647 116648 116649 116650 116651 116652 116653 116654 116655 116656 116657 116658 |
sqlite3 *db; /* The database connection */
const char *zDb; /* logical database name */
const char *zName; /* virtual table name */
int nColumn; /* number of named columns in virtual table */
char **azColumn; /* column names. malloced */
sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */
char *zContentTbl; /* content=xxx option, or NULL */
char *zLanguageid; /* languageid=xxx option, or NULL */
/* Precompiled statements used by the implementation. Each of these
** statements is run and reset within a single virtual table API call.
*/
sqlite3_stmt *aStmt[28];
char *zReadExprlist;
char *zWriteExprlist;
int nNodeSize; /* Soft limit for node size */
u8 bHasStat; /* True if %_stat table exists */
u8 bHasDocsize; /* True if %_docsize table exists */
u8 bDescIdx; /* True if doclists are in reverse order */
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
/* TODO: Fix the first paragraph of this comment.
**
** The following array of hash tables is used to buffer pending index
** updates during transactions. Variable nPendingData estimates the memory
** size of the pending data, including hash table overhead, not including
** malloc overhead. When nPendingData exceeds nMaxPendingData, the buffer
** is flushed automatically. Variable iPrevDocid is the docid of the most
** recently inserted record.
**
** A single FTS4 table may have multiple full-text indexes. For each index
** there is an entry in the aIndex[] array. Index 0 is an index of all the
** terms that appear in the document set. Each subsequent index in aIndex[]
** is an index of prefixes of a specific length.
*/
int nIndex; /* Size of aIndex[] */
struct Fts3Index {
int nPrefix; /* Prefix length (0 for main terms index) */
Fts3Hash hPending; /* Pending terms table for this index */
} *aIndex;
int nMaxPendingData; /* Max pending data before flush to disk */
int nPendingData; /* Current bytes of pending data */
sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
int iPrevLangid; /* Langid of recently inserted document */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
/* State variables used for validating that the transaction control
** methods of the virtual table are called at appropriate times. These
** values do not contribute to FTS functionality; they are used for
** verifying the operation of the SQLite core.
*/
int inTransaction; /* True after xBegin but before xCommit/xRollback */
int mxSavepoint; /* Largest valid xSavepoint integer */
#endif
};
/*
** When the core wants to read from the virtual table, it creates a
** virtual table cursor (an instance of the following structure) using
** the xOpen method. Cursors are destroyed using the xClose method.
*/
struct Fts3Cursor {
sqlite3_vtab_cursor base; /* Base class used by SQLite core */
i16 eSearch; /* Search strategy (see below) */
u8 isEof; /* True if at End Of Results */
u8 isRequireSeek; /* True if must seek pStmt to %_content row */
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
Fts3Expr *pExpr; /* Parsed MATCH query string */
int iLangid; /* Language being queried for */
int nPhrase; /* Number of matchable phrases in query */
Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */
sqlite3_int64 iPrevId; /* Previous id read from aDoclist */
char *pNextId; /* Pointer into the body of aDoclist */
char *aDoclist; /* List of docids for full-text queries */
int nDoclist; /* Size of buffer at aDoclist */
u8 bDesc; /* True to sort in descending order */
|
| ︙ | ︙ | |||
116501 116502 116503 116504 116505 116506 116507 | /* fts3_write.c */ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *); SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *); SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *); | | | | | | 116791 116792 116793 116794 116795 116796 116797 116798 116799 116800 116801 116802 116803 116804 116805 116806 116807 116808 116809 116810 116811 116812 116813 116814 116815 116816 116817 116818 116819 116820 116821 116822 116823 116824 116825 116826 116827 116828 116829 116830 116831 116832 |
/* fts3_write.c */
SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *);
SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *);
SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *);
SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64,
sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
Fts3Table*,int,const char*,int,int,Fts3SegReader**);
SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *);
SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, int, sqlite3_stmt **);
SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *);
SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*);
SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **);
SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **);
SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *);
/* Special values interpreted by sqlite3SegReaderCursor() */
#define FTS3_SEGCURSOR_PENDING -1
#define FTS3_SEGCURSOR_ALL -2
SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Fts3SegFilter*);
SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *);
SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *);
SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *,
int, int, int, const char *, int, int, int, Fts3MultiSegReader *);
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
#define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002
#define FTS3_SEGMENT_COLUMN_FILTER 0x00000004
#define FTS3_SEGMENT_PREFIX 0x00000008
#define FTS3_SEGMENT_SCAN 0x00000010
|
| ︙ | ︙ | |||
116595 116596 116597 116598 116599 116600 116601 | SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*); SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, const char *, const char *, int, int ); SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); /* fts3_expr.c */ | | > > > > | 116885 116886 116887 116888 116889 116890 116891 116892 116893 116894 116895 116896 116897 116898 116899 116900 116901 116902 116903 116904 116905 116906 116907 116908 116909 116910 | SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*); SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, const char *, const char *, int, int ); SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); /* fts3_expr.c */ SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, char **, int, int, int, const char *, int, Fts3Expr ** ); SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); #endif SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, sqlite3_tokenizer_cursor ** ); /* fts3_aux.c */ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( |
| ︙ | ︙ | |||
116798 116799 116800 116801 116802 116803 116804 116805 116806 116807 116808 116809 116810 116811 |
for(i=0; i<SizeofArray(p->aStmt); i++){
sqlite3_finalize(p->aStmt[i]);
}
sqlite3_free(p->zSegmentsTbl);
sqlite3_free(p->zReadExprlist);
sqlite3_free(p->zWriteExprlist);
sqlite3_free(p->zContentTbl);
/* Invoke the tokenizer destructor to free the tokenizer. */
p->pTokenizer->pModule->xDestroy(p->pTokenizer);
sqlite3_free(p);
return SQLITE_OK;
}
| > | 117092 117093 117094 117095 117096 117097 117098 117099 117100 117101 117102 117103 117104 117105 117106 |
for(i=0; i<SizeofArray(p->aStmt); i++){
sqlite3_finalize(p->aStmt[i]);
}
sqlite3_free(p->zSegmentsTbl);
sqlite3_free(p->zReadExprlist);
sqlite3_free(p->zWriteExprlist);
sqlite3_free(p->zContentTbl);
sqlite3_free(p->zLanguageid);
/* Invoke the tokenizer destructor to free the tokenizer. */
p->pTokenizer->pModule->xDestroy(p->pTokenizer);
sqlite3_free(p);
return SQLITE_OK;
}
|
| ︙ | ︙ | |||
116874 116875 116876 116877 116878 116879 116880 116881 116882 116883 116884 116885 116886 116887 116888 116889 116890 116891 |
*/
static void fts3DeclareVtab(int *pRc, Fts3Table *p){
if( *pRc==SQLITE_OK ){
int i; /* Iterator variable */
int rc; /* Return code */
char *zSql; /* SQL statement passed to declare_vtab() */
char *zCols; /* List of user defined columns */
sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
/* Create a list of user columns for the virtual table */
zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
for(i=1; zCols && i<p->nColumn; i++){
zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]);
}
/* Create the whole "CREATE TABLE" statement to pass to SQLite */
zSql = sqlite3_mprintf(
| > > | > | 117169 117170 117171 117172 117173 117174 117175 117176 117177 117178 117179 117180 117181 117182 117183 117184 117185 117186 117187 117188 117189 117190 117191 117192 117193 117194 117195 117196 117197 |
*/
static void fts3DeclareVtab(int *pRc, Fts3Table *p){
if( *pRc==SQLITE_OK ){
int i; /* Iterator variable */
int rc; /* Return code */
char *zSql; /* SQL statement passed to declare_vtab() */
char *zCols; /* List of user defined columns */
const char *zLanguageid;
zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid");
sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
/* Create a list of user columns for the virtual table */
zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
for(i=1; zCols && i<p->nColumn; i++){
zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]);
}
/* Create the whole "CREATE TABLE" statement to pass to SQLite */
zSql = sqlite3_mprintf(
"CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)",
zCols, p->zName, zLanguageid
);
if( !zCols || !zSql ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_declare_vtab(p->db, zSql);
}
|
| ︙ | ︙ | |||
116914 116915 116916 116917 116918 116919 116920 116921 116922 116923 116924 116925 116926 116927 116928 116929 116930 116931 116932 116933 116934 116935 |
*/
static int fts3CreateTables(Fts3Table *p){
int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
sqlite3 *db = p->db; /* The database connection */
if( p->zContentTbl==0 ){
char *zContentCols; /* Columns of %_content table */
/* Create a list of user columns for the content table */
zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
for(i=0; zContentCols && i<p->nColumn; i++){
char *z = p->azColumn[i];
zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
}
if( zContentCols==0 ) rc = SQLITE_NOMEM;
/* Create the content table */
fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_content'(%s)",
p->zDb, p->zName, zContentCols
);
| > > > > | 117212 117213 117214 117215 117216 117217 117218 117219 117220 117221 117222 117223 117224 117225 117226 117227 117228 117229 117230 117231 117232 117233 117234 117235 117236 117237 |
*/
static int fts3CreateTables(Fts3Table *p){
int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
sqlite3 *db = p->db; /* The database connection */
if( p->zContentTbl==0 ){
const char *zLanguageid = p->zLanguageid;
char *zContentCols; /* Columns of %_content table */
/* Create a list of user columns for the content table */
zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
for(i=0; zContentCols && i<p->nColumn; i++){
char *z = p->azColumn[i];
zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
}
if( zLanguageid && zContentCols ){
zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid);
}
if( zContentCols==0 ) rc = SQLITE_NOMEM;
/* Create the content table */
fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_content'(%s)",
p->zDb, p->zName, zContentCols
);
|
| ︙ | ︙ | |||
117121 117122 117123 117124 117125 117126 117127 117128 117129 117130 117131 117132 117133 |
}else{
zFree = zFunction = fts3QuoteId(zFunc);
}
fts3Appendf(pRc, &zRet, "docid");
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
}
sqlite3_free(zFree);
}else{
fts3Appendf(pRc, &zRet, "rowid");
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]);
}
| > > > > > | > | | 117423 117424 117425 117426 117427 117428 117429 117430 117431 117432 117433 117434 117435 117436 117437 117438 117439 117440 117441 117442 117443 117444 117445 117446 117447 117448 117449 117450 |
}else{
zFree = zFunction = fts3QuoteId(zFunc);
}
fts3Appendf(pRc, &zRet, "docid");
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
}
if( p->zLanguageid ){
fts3Appendf(pRc, &zRet, ", x.%Q", "langid");
}
sqlite3_free(zFree);
}else{
fts3Appendf(pRc, &zRet, "rowid");
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]);
}
if( p->zLanguageid ){
fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid);
}
}
fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x",
p->zDb,
(p->zContentTbl ? p->zContentTbl : p->zName),
(p->zContentTbl ? "" : "_content")
);
return zRet;
}
|
| ︙ | ︙ | |||
117171 117172 117173 117174 117175 117176 117177 117178 117179 117180 117181 117182 117183 117184 |
}else{
zFree = zFunction = fts3QuoteId(zFunc);
}
fts3Appendf(pRc, &zRet, "?");
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ",%s(?)", zFunction);
}
sqlite3_free(zFree);
return zRet;
}
/*
** This function interprets the string at (*pp) as a non-negative integer
** value. It reads the integer and sets *pnOut to the value read, then
| > > > | 117479 117480 117481 117482 117483 117484 117485 117486 117487 117488 117489 117490 117491 117492 117493 117494 117495 |
}else{
zFree = zFunction = fts3QuoteId(zFunc);
}
fts3Appendf(pRc, &zRet, "?");
for(i=0; i<p->nColumn; i++){
fts3Appendf(pRc, &zRet, ",%s(?)", zFunction);
}
if( p->zLanguageid ){
fts3Appendf(pRc, &zRet, ", ?");
}
sqlite3_free(zFree);
return zRet;
}
/*
** This function interprets the string at (*pp) as a non-negative integer
** value. It reads the integer and sets *pnOut to the value read, then
|
| ︙ | ︙ | |||
117386 117387 117388 117389 117390 117391 117392 117393 117394 117395 117396 117397 117398 117399 |
/* The results of parsing supported FTS4 key=value options: */
int bNoDocsize = 0; /* True to omit %_docsize table */
int bDescIdx = 0; /* True to store descending indexes */
char *zPrefix = 0; /* Prefix parameter value (or NULL) */
char *zCompress = 0; /* compress=? parameter (or NULL) */
char *zUncompress = 0; /* uncompress=? parameter (or NULL) */
char *zContent = 0; /* content=? parameter (or NULL) */
assert( strlen(argv[0])==4 );
assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
|| (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4)
);
nDb = (int)strlen(argv[1]) + 1;
| > | 117697 117698 117699 117700 117701 117702 117703 117704 117705 117706 117707 117708 117709 117710 117711 |
/* The results of parsing supported FTS4 key=value options: */
int bNoDocsize = 0; /* True to omit %_docsize table */
int bDescIdx = 0; /* True to store descending indexes */
char *zPrefix = 0; /* Prefix parameter value (or NULL) */
char *zCompress = 0; /* compress=? parameter (or NULL) */
char *zUncompress = 0; /* uncompress=? parameter (or NULL) */
char *zContent = 0; /* content=? parameter (or NULL) */
char *zLanguageid = 0; /* languageid=? parameter (or NULL) */
assert( strlen(argv[0])==4 );
assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
|| (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4)
);
nDb = (int)strlen(argv[1]) + 1;
|
| ︙ | ︙ | |||
117435 117436 117437 117438 117439 117440 117441 |
int nOpt;
} aFts4Opt[] = {
{ "matchinfo", 9 }, /* 0 -> MATCHINFO */
{ "prefix", 6 }, /* 1 -> PREFIX */
{ "compress", 8 }, /* 2 -> COMPRESS */
{ "uncompress", 10 }, /* 3 -> UNCOMPRESS */
{ "order", 5 }, /* 4 -> ORDER */
| | > | 117747 117748 117749 117750 117751 117752 117753 117754 117755 117756 117757 117758 117759 117760 117761 117762 |
int nOpt;
} aFts4Opt[] = {
{ "matchinfo", 9 }, /* 0 -> MATCHINFO */
{ "prefix", 6 }, /* 1 -> PREFIX */
{ "compress", 8 }, /* 2 -> COMPRESS */
{ "uncompress", 10 }, /* 3 -> UNCOMPRESS */
{ "order", 5 }, /* 4 -> ORDER */
{ "content", 7 }, /* 5 -> CONTENT */
{ "languageid", 10 } /* 6 -> LANGUAGEID */
};
int iOpt;
if( !zVal ){
rc = SQLITE_NOMEM;
}else{
for(iOpt=0; iOpt<SizeofArray(aFts4Opt); iOpt++){
|
| ︙ | ︙ | |||
117489 117490 117491 117492 117493 117494 117495 |
){
*pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
rc = SQLITE_ERROR;
}
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
break;
| | < | > > > > > > > | 117802 117803 117804 117805 117806 117807 117808 117809 117810 117811 117812 117813 117814 117815 117816 117817 117818 117819 117820 117821 117822 117823 117824 117825 117826 117827 |
){
*pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
rc = SQLITE_ERROR;
}
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
break;
case 5: /* CONTENT */
sqlite3_free(zContent);
zContent = zVal;
zVal = 0;
break;
case 6: /* LANGUAGEID */
assert( iOpt==6 );
sqlite3_free(zLanguageid);
zLanguageid = zVal;
zVal = 0;
break;
}
}
sqlite3_free(zVal);
}
}
/* Otherwise, the argument is a column name. */
|
| ︙ | ︙ | |||
117524 117525 117526 117527 117528 117529 117530 |
sqlite3_free(zUncompress);
zCompress = 0;
zUncompress = 0;
if( nCol==0 ){
sqlite3_free((void*)aCol);
aCol = 0;
rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
| | > > | > > > > > > > > > > | 117843 117844 117845 117846 117847 117848 117849 117850 117851 117852 117853 117854 117855 117856 117857 117858 117859 117860 117861 117862 117863 117864 117865 117866 117867 117868 117869 117870 |
sqlite3_free(zUncompress);
zCompress = 0;
zUncompress = 0;
if( nCol==0 ){
sqlite3_free((void*)aCol);
aCol = 0;
rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
/* If a languageid= option was specified, remove the language id
** column from the aCol[] array. */
if( rc==SQLITE_OK && zLanguageid ){
int j;
for(j=0; j<nCol; j++){
if( sqlite3_stricmp(zLanguageid, aCol[j])==0 ){
memmove(&aCol[j], &aCol[j+1], (nCol-j) * sizeof(aCol[0]));
nCol--;
break;
}
}
}
}
}
if( rc!=SQLITE_OK ) goto fts3_init_out;
if( nCol==0 ){
assert( nString==0 );
aCol[0] = "content";
nString = 8;
|
| ︙ | ︙ | |||
117572 117573 117574 117575 117576 117577 117578 117579 117580 117581 117582 117583 117584 117585 117586 |
p->azColumn = (char **)&p[1];
p->pTokenizer = pTokenizer;
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
p->bHasDocsize = (isFts4 && bNoDocsize==0);
p->bHasStat = isFts4;
p->bDescIdx = bDescIdx;
p->zContentTbl = zContent;
zContent = 0;
TESTONLY( p->inTransaction = -1 );
TESTONLY( p->mxSavepoint = -1 );
p->aIndex = (struct Fts3Index *)&p->azColumn[nCol];
memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex);
p->nIndex = nIndex;
for(i=0; i<nIndex; i++){
| > > | 117903 117904 117905 117906 117907 117908 117909 117910 117911 117912 117913 117914 117915 117916 117917 117918 117919 |
p->azColumn = (char **)&p[1];
p->pTokenizer = pTokenizer;
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
p->bHasDocsize = (isFts4 && bNoDocsize==0);
p->bHasStat = isFts4;
p->bDescIdx = bDescIdx;
p->zContentTbl = zContent;
p->zLanguageid = zLanguageid;
zContent = 0;
zLanguageid = 0;
TESTONLY( p->inTransaction = -1 );
TESTONLY( p->mxSavepoint = -1 );
p->aIndex = (struct Fts3Index *)&p->azColumn[nCol];
memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex);
p->nIndex = nIndex;
for(i=0; i<nIndex; i++){
|
| ︙ | ︙ | |||
117635 117636 117637 117638 117639 117640 117641 117642 117643 117644 117645 117646 117647 117648 |
fts3_init_out:
sqlite3_free(zPrefix);
sqlite3_free(aIndex);
sqlite3_free(zCompress);
sqlite3_free(zUncompress);
sqlite3_free(zContent);
sqlite3_free((void *)aCol);
if( rc!=SQLITE_OK ){
if( p ){
fts3DisconnectMethod((sqlite3_vtab *)p);
}else if( pTokenizer ){
pTokenizer->pModule->xDestroy(pTokenizer);
}
| > | 117968 117969 117970 117971 117972 117973 117974 117975 117976 117977 117978 117979 117980 117981 117982 |
fts3_init_out:
sqlite3_free(zPrefix);
sqlite3_free(aIndex);
sqlite3_free(zCompress);
sqlite3_free(zUncompress);
sqlite3_free(zContent);
sqlite3_free(zLanguageid);
sqlite3_free((void *)aCol);
if( rc!=SQLITE_OK ){
if( p ){
fts3DisconnectMethod((sqlite3_vtab *)p);
}else if( pTokenizer ){
pTokenizer->pModule->xDestroy(pTokenizer);
}
|
| ︙ | ︙ | |||
117686 117687 117688 117689 117690 117691 117692 117693 117694 117695 117696 117697 117698 117699 117700 117701 117702 117703 117704 |
** 2. Full-text search using a MATCH operator on a non-docid column.
** 3. Linear scan of %_content table.
*/
static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts3Table *p = (Fts3Table *)pVTab;
int i; /* Iterator variable */
int iCons = -1; /* Index of constraint to use */
/* By default use a full table scan. This is an expensive option,
** so search through the constraints to see if a more efficient
** strategy is possible.
*/
pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
pInfo->estimatedCost = 500000;
for(i=0; i<pInfo->nConstraint; i++){
struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i];
if( pCons->usable==0 ) continue;
/* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */
| > > | | 118020 118021 118022 118023 118024 118025 118026 118027 118028 118029 118030 118031 118032 118033 118034 118035 118036 118037 118038 118039 118040 118041 118042 118043 118044 118045 118046 118047 118048 |
** 2. Full-text search using a MATCH operator on a non-docid column.
** 3. Linear scan of %_content table.
*/
static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts3Table *p = (Fts3Table *)pVTab;
int i; /* Iterator variable */
int iCons = -1; /* Index of constraint to use */
int iLangidCons = -1; /* Index of langid=x constraint, if present */
/* By default use a full table scan. This is an expensive option,
** so search through the constraints to see if a more efficient
** strategy is possible.
*/
pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
pInfo->estimatedCost = 500000;
for(i=0; i<pInfo->nConstraint; i++){
struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i];
if( pCons->usable==0 ) continue;
/* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */
if( iCons<0
&& pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
&& (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1 )
){
pInfo->idxNum = FTS3_DOCID_SEARCH;
pInfo->estimatedCost = 1.0;
iCons = i;
}
|
| ︙ | ︙ | |||
117721 117722 117723 117724 117725 117726 117727 |
*/
if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH
&& pCons->iColumn>=0 && pCons->iColumn<=p->nColumn
){
pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn;
pInfo->estimatedCost = 2.0;
iCons = i;
| > | > > > > > > > > | 118057 118058 118059 118060 118061 118062 118063 118064 118065 118066 118067 118068 118069 118070 118071 118072 118073 118074 118075 118076 118077 118078 118079 118080 118081 118082 118083 118084 118085 118086 118087 |
*/
if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH
&& pCons->iColumn>=0 && pCons->iColumn<=p->nColumn
){
pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn;
pInfo->estimatedCost = 2.0;
iCons = i;
}
/* Equality constraint on the langid column */
if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
&& pCons->iColumn==p->nColumn + 2
){
iLangidCons = i;
}
}
if( iCons>=0 ){
pInfo->aConstraintUsage[iCons].argvIndex = 1;
pInfo->aConstraintUsage[iCons].omit = 1;
}
if( iLangidCons>=0 ){
pInfo->aConstraintUsage[iLangidCons].argvIndex = 2;
}
/* Regardless of the strategy selected, FTS can deliver rows in rowid (or
** docid) order. Both ascending and descending are possible.
*/
if( pInfo->nOrderBy==1 ){
struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0];
if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){
|
| ︙ | ︙ | |||
118878 118879 118880 118881 118882 118883 118884 118885 118886 118887 118888 118889 118890 118891 | ** 8th argument. ** ** This function returns SQLITE_OK if successful, or an SQLite error code ** otherwise. */ static int fts3SegReaderCursor( Fts3Table *p, /* FTS3 table handle */ int iIndex, /* Index to search (from 0 to p->nIndex-1) */ int iLevel, /* Level of segments to scan */ const char *zTerm, /* Term to query for */ int nTerm, /* Size of zTerm in bytes */ int isPrefix, /* True for a prefix search */ int isScan, /* True to scan from zTerm to EOF */ Fts3MultiSegReader *pCsr /* Cursor object to populate */ | > | 119223 119224 119225 119226 119227 119228 119229 119230 119231 119232 119233 119234 119235 119236 119237 | ** 8th argument. ** ** This function returns SQLITE_OK if successful, or an SQLite error code ** otherwise. */ static int fts3SegReaderCursor( Fts3Table *p, /* FTS3 table handle */ int iLangid, /* Language id */ int iIndex, /* Index to search (from 0 to p->nIndex-1) */ int iLevel, /* Level of segments to scan */ const char *zTerm, /* Term to query for */ int nTerm, /* Size of zTerm in bytes */ int isPrefix, /* True for a prefix search */ int isScan, /* True to scan from zTerm to EOF */ Fts3MultiSegReader *pCsr /* Cursor object to populate */ |
| ︙ | ︙ | |||
118906 118907 118908 118909 118910 118911 118912 |
if( rc==SQLITE_OK && pSeg ){
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
}
}
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
if( rc==SQLITE_OK ){
| | | 119252 119253 119254 119255 119256 119257 119258 119259 119260 119261 119262 119263 119264 119265 119266 |
if( rc==SQLITE_OK && pSeg ){
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
}
}
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
if( rc==SQLITE_OK ){
rc = sqlite3Fts3AllSegdirs(p, iLangid, iIndex, iLevel, &pStmt);
}
while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
Fts3SegReader *pSeg = 0;
/* Read the values returned by the SELECT into local variables. */
sqlite3_int64 iStartBlock = sqlite3_column_int64(pStmt, 1);
|
| ︙ | ︙ | |||
118929 118930 118931 118932 118933 118934 118935 |
sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0);
rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi);
if( rc!=SQLITE_OK ) goto finished;
if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock;
}
rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
| > | > > | 119275 119276 119277 119278 119279 119280 119281 119282 119283 119284 119285 119286 119287 119288 119289 119290 119291 119292 119293 119294 119295 119296 119297 119298 119299 119300 119301 119302 119303 119304 119305 119306 119307 119308 119309 119310 119311 |
sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0);
rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi);
if( rc!=SQLITE_OK ) goto finished;
if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock;
}
rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
(isPrefix==0 && isScan==0),
iStartBlock, iLeavesEndBlock,
iEndBlock, zRoot, nRoot, &pSeg
);
if( rc!=SQLITE_OK ) goto finished;
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
}
}
finished:
rc2 = sqlite3_reset(pStmt);
if( rc==SQLITE_DONE ) rc = rc2;
return rc;
}
/*
** Set up a cursor object for iterating through a full-text index or a
** single level therein.
*/
SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
Fts3Table *p, /* FTS3 table handle */
int iLangid,
int iIndex, /* Index to search (from 0 to p->nIndex-1) */
int iLevel, /* Level of segments to scan */
const char *zTerm, /* Term to query for */
int nTerm, /* Size of zTerm in bytes */
int isPrefix, /* True for a prefix search */
int isScan, /* True to scan from zTerm to EOF */
Fts3MultiSegReader *pCsr /* Cursor object to populate */
|
| ︙ | ︙ | |||
118973 118974 118975 118976 118977 118978 118979 | /* "isScan" is only set to true by the ft4aux module, an ordinary ** full-text tables. */ assert( isScan==0 || p->aIndex==0 ); memset(pCsr, 0, sizeof(Fts3MultiSegReader)); return fts3SegReaderCursor( | | > | > > | 119322 119323 119324 119325 119326 119327 119328 119329 119330 119331 119332 119333 119334 119335 119336 119337 119338 119339 119340 119341 119342 119343 119344 119345 119346 119347 119348 119349 119350 119351 119352 119353 119354 119355 |
/* "isScan" is only set to true by the ft4aux module, an ordinary
** full-text tables. */
assert( isScan==0 || p->aIndex==0 );
memset(pCsr, 0, sizeof(Fts3MultiSegReader));
return fts3SegReaderCursor(
p, iLangid, iIndex, iLevel, zTerm, nTerm, isPrefix, isScan, pCsr
);
}
/*
** In addition to its current configuration, have the Fts3MultiSegReader
** passed as the 4th argument also scan the doclist for term zTerm/nTerm.
**
** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
*/
static int fts3SegReaderCursorAddZero(
Fts3Table *p, /* FTS virtual table handle */
int iLangid,
const char *zTerm, /* Term to scan doclist of */
int nTerm, /* Number of bytes in zTerm */
Fts3MultiSegReader *pCsr /* Fts3MultiSegReader to modify */
){
return fts3SegReaderCursor(p,
iLangid, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0,pCsr
);
}
/*
** Open an Fts3MultiSegReader to scan the doclist for term zTerm/nTerm. Or,
** if isPrefix is true, to scan the doclist for all terms for which
** zTerm/nTerm is a prefix. If successful, return SQLITE_OK and write
** a pointer to the new Fts3MultiSegReader to *ppSegcsr. Otherwise, return
|
| ︙ | ︙ | |||
119025 119026 119027 119028 119029 119030 119031 |
int bFound = 0; /* True once an index has been found */
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
if( isPrefix ){
for(i=1; bFound==0 && i<p->nIndex; i++){
if( p->aIndex[i].nPrefix==nTerm ){
bFound = 1;
| | | > | | | > > | | | 119377 119378 119379 119380 119381 119382 119383 119384 119385 119386 119387 119388 119389 119390 119391 119392 119393 119394 119395 119396 119397 119398 119399 119400 119401 119402 119403 119404 119405 119406 119407 119408 119409 119410 119411 119412 119413 119414 119415 |
int bFound = 0; /* True once an index has been found */
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
if( isPrefix ){
for(i=1; bFound==0 && i<p->nIndex; i++){
if( p->aIndex[i].nPrefix==nTerm ){
bFound = 1;
rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr
);
pSegcsr->bLookup = 1;
}
}
for(i=1; bFound==0 && i<p->nIndex; i++){
if( p->aIndex[i].nPrefix==nTerm+1 ){
bFound = 1;
rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr
);
if( rc==SQLITE_OK ){
rc = fts3SegReaderCursorAddZero(
p, pCsr->iLangid, zTerm, nTerm, pSegcsr
);
}
}
}
}
if( bFound==0 ){
rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr
);
pSegcsr->bLookup = !isPrefix;
}
}
*ppSegcsr = pSegcsr;
return rc;
|
| ︙ | ︙ | |||
119201 119202 119203 119204 119205 119206 119207 | Fts3Table *p = (Fts3Table *)pCursor->pVtab; Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); | | | 119556 119557 119558 119559 119560 119561 119562 119563 119564 119565 119566 119567 119568 119569 119570 | Fts3Table *p = (Fts3Table *)pCursor->pVtab; Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); assert( nVal==0 || nVal==1 || nVal==2 ); assert( (nVal==0)==(idxNum==FTS3_FULLSCAN_SEARCH) ); assert( p->pSegments==0 ); /* In case the cursor has been used before, clear it now. */ sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr->aDoclist); sqlite3Fts3ExprFree(pCsr->pExpr); |
| ︙ | ︙ | |||
119226 119227 119228 119229 119230 119231 119232 |
int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
return SQLITE_NOMEM;
}
| > > > | | | 119581 119582 119583 119584 119585 119586 119587 119588 119589 119590 119591 119592 119593 119594 119595 119596 119597 119598 119599 |
int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
return SQLITE_NOMEM;
}
pCsr->iLangid = 0;
if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
p->azColumn, p->bHasStat, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_ERROR ){
static const char *zErr = "malformed MATCH expression: [%s]";
p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
}
return rc;
|
| ︙ | ︙ | |||
119298 119299 119300 119301 119302 119303 119304 119305 119306 119307 | *pRowid = pCsr->iPrevId; return SQLITE_OK; } /* ** This is the xColumn method, called by SQLite to request a value from ** the row that the supplied cursor currently points to. */ static int fts3ColumnMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ | > > > > > > > | | | | < | > > > > > > > > > > > > | | > | 119656 119657 119658 119659 119660 119661 119662 119663 119664 119665 119666 119667 119668 119669 119670 119671 119672 119673 119674 119675 119676 119677 119678 119679 119680 119681 119682 119683 119684 119685 119686 119687 119688 119689 119690 119691 119692 119693 119694 119695 119696 119697 119698 119699 119700 119701 119702 119703 119704 119705 119706 119707 119708 119709 119710 119711 119712 119713 119714 119715 |
*pRowid = pCsr->iPrevId;
return SQLITE_OK;
}
/*
** This is the xColumn method, called by SQLite to request a value from
** the row that the supplied cursor currently points to.
**
** If:
**
** (iCol < p->nColumn) -> The value of the iCol'th user column.
** (iCol == p->nColumn) -> Magic column with the same name as the table.
** (iCol == p->nColumn+1) -> Docid column
** (iCol == p->nColumn+2) -> Langid column
*/
static int fts3ColumnMethod(
sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
int iCol /* Index of column to read value from */
){
int rc = SQLITE_OK; /* Return Code */
Fts3Cursor *pCsr = (Fts3Cursor *) pCursor;
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
/* The column value supplied by SQLite must be in range. */
assert( iCol>=0 && iCol<=p->nColumn+2 );
if( iCol==p->nColumn+1 ){
/* This call is a request for the "docid" column. Since "docid" is an
** alias for "rowid", use the xRowid() method to obtain the value.
*/
sqlite3_result_int64(pCtx, pCsr->iPrevId);
}else if( iCol==p->nColumn ){
/* The extra column whose name is the same as the table.
** Return a blob which is a pointer to the cursor. */
sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
}else if( iCol==p->nColumn+2 && pCsr->pExpr ){
sqlite3_result_int64(pCtx, pCsr->iLangid);
}else{
/* The requested column is either a user column (one that contains
** indexed data), or the language-id column. */
rc = fts3CursorSeek(0, pCsr);
if( rc==SQLITE_OK ){
if( iCol==p->nColumn+2 ){
int iLangid = 0;
if( p->zLanguageid ){
iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
}
sqlite3_result_int(pCtx, iLangid);
}else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
}
}
}
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
return rc;
}
|
| ︙ | ︙ | |||
121800 121801 121802 121803 121804 121805 121806 |
if( idxNum&FTS4AUX_LE_CONSTRAINT ){
int iIdx = (idxNum&FTS4AUX_GE_CONSTRAINT) ? 1 : 0;
pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iIdx]));
pCsr->nStop = sqlite3_value_bytes(apVal[iIdx]);
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
}
| | | 122177 122178 122179 122180 122181 122182 122183 122184 122185 122186 122187 122188 122189 122190 122191 |
if( idxNum&FTS4AUX_LE_CONSTRAINT ){
int iIdx = (idxNum&FTS4AUX_GE_CONSTRAINT) ? 1 : 0;
pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iIdx]));
pCsr->nStop = sqlite3_value_bytes(apVal[iIdx]);
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
}
rc = sqlite3Fts3SegReaderCursor(pFts3, 0, 0, FTS3_SEGCURSOR_ALL,
pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr
);
if( rc==SQLITE_OK ){
rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter);
}
if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor);
|
| ︙ | ︙ | |||
121992 121993 121994 121995 121996 121997 121998 121999 122000 122001 122002 122003 122004 122005 |
** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the
** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to
** zero.
*/
typedef struct ParseContext ParseContext;
struct ParseContext {
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
const char **azCol; /* Array of column names for fts3 table */
int bFts4; /* True to allow FTS4-only syntax */
int nCol; /* Number of entries in azCol[] */
int iDefaultCol; /* Default column to query */
int isNot; /* True if getNextNode() sees a unary - */
sqlite3_context *pCtx; /* Write error message here */
int nNest; /* Number of nested brackets */
| > | 122369 122370 122371 122372 122373 122374 122375 122376 122377 122378 122379 122380 122381 122382 122383 |
** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the
** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to
** zero.
*/
typedef struct ParseContext ParseContext;
struct ParseContext {
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
int iLangid; /* Language id used with tokenizer */
const char **azCol; /* Array of column names for fts3 table */
int bFts4; /* True to allow FTS4-only syntax */
int nCol; /* Number of entries in azCol[] */
int iDefaultCol; /* Default column to query */
int isNot; /* True if getNextNode() sees a unary - */
sqlite3_context *pCtx; /* Write error message here */
int nNest; /* Number of nested brackets */
|
| ︙ | ︙ | |||
122027 122028 122029 122030 122031 122032 122033 122034 122035 122036 122037 122038 122039 122040 |
*/
static void *fts3MallocZero(int nByte){
void *pRet = sqlite3_malloc(nByte);
if( pRet ) memset(pRet, 0, nByte);
return pRet;
}
/*
** Extract the next token from buffer z (length n) using the tokenizer
** and other information (column names etc.) in pParse. Create an Fts3Expr
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
** single token and set *ppExpr to point to it. If the end of the buffer is
** reached before a token is found, set *ppExpr to zero. It is the
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 122405 122406 122407 122408 122409 122410 122411 122412 122413 122414 122415 122416 122417 122418 122419 122420 122421 122422 122423 122424 122425 122426 122427 122428 122429 122430 122431 122432 122433 122434 122435 122436 122437 122438 122439 122440 122441 122442 122443 122444 122445 |
*/
static void *fts3MallocZero(int nByte){
void *pRet = sqlite3_malloc(nByte);
if( pRet ) memset(pRet, 0, nByte);
return pRet;
}
SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(
sqlite3_tokenizer *pTokenizer,
int iLangid,
const char *z,
int n,
sqlite3_tokenizer_cursor **ppCsr
){
sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
sqlite3_tokenizer_cursor *pCsr = 0;
int rc;
rc = pModule->xOpen(pTokenizer, z, n, &pCsr);
assert( rc==SQLITE_OK || pCsr==0 );
if( rc==SQLITE_OK ){
pCsr->pTokenizer = pTokenizer;
if( pModule->iVersion>=1 ){
rc = pModule->xLanguageid(pCsr, iLangid);
if( rc!=SQLITE_OK ){
pModule->xClose(pCsr);
pCsr = 0;
}
}
}
*ppCsr = pCsr;
return rc;
}
/*
** Extract the next token from buffer z (length n) using the tokenizer
** and other information (column names etc.) in pParse. Create an Fts3Expr
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
** single token and set *ppExpr to point to it. If the end of the buffer is
** reached before a token is found, set *ppExpr to zero. It is the
|
| ︙ | ︙ | |||
122054 122055 122056 122057 122058 122059 122060 | sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; int rc; sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; int nConsumed = 0; | | < < | 122459 122460 122461 122462 122463 122464 122465 122466 122467 122468 122469 122470 122471 122472 122473 122474 122475 122476 122477 122478 122479 |
sqlite3_tokenizer *pTokenizer = pParse->pTokenizer;
sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
int rc;
sqlite3_tokenizer_cursor *pCursor;
Fts3Expr *pRet = 0;
int nConsumed = 0;
rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
if( rc==SQLITE_OK ){
const char *zToken;
int nToken, iStart, iEnd, iPosition;
int nByte; /* total space to allocate */
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
if( rc==SQLITE_OK ){
nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
pRet = (Fts3Expr *)fts3MallocZero(nByte);
if( !pRet ){
rc = SQLITE_NOMEM;
}else{
pRet->eType = FTSQUERY_PHRASE;
|
| ︙ | ︙ | |||
122168 122169 122170 122171 122172 122173 122174 | ** ** Buffer zTemp: Contains copies of all tokens. ** ** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below, ** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase ** structures. */ | > | < | 122571 122572 122573 122574 122575 122576 122577 122578 122579 122580 122581 122582 122583 122584 122585 122586 122587 122588 |
**
** Buffer zTemp: Contains copies of all tokens.
**
** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below,
** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase
** structures.
*/
rc = sqlite3Fts3OpenTokenizer(
pTokenizer, pParse->iLangid, zInput, nInput, &pCursor);
if( rc==SQLITE_OK ){
int ii;
for(ii=0; rc==SQLITE_OK; ii++){
const char *zByte;
int nByte, iBegin, iEnd, iPos;
rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
if( rc==SQLITE_OK ){
Fts3PhraseToken *pToken;
|
| ︙ | ︙ | |||
122645 122646 122647 122648 122649 122650 122651 122652 122653 122654 122655 122656 122657 122658 122659 122660 122661 122662 122663 122664 122665 |
** that appears on the left-hand-side of the MATCH operator (the default
** column to match against for tokens for which a column name is not explicitly
** specified as part of the query string), or -1 if tokens may by default
** match any table column.
*/
SQLITE_PRIVATE int sqlite3Fts3ExprParse(
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
char **azCol, /* Array of column names for fts3 table */
int bFts4, /* True to allow FTS4-only syntax */
int nCol, /* Number of entries in azCol[] */
int iDefaultCol, /* Default column to query */
const char *z, int n, /* Text of MATCH query */
Fts3Expr **ppExpr /* OUT: Parsed query structure */
){
int nParsed;
int rc;
ParseContext sParse;
sParse.pTokenizer = pTokenizer;
sParse.azCol = (const char **)azCol;
sParse.nCol = nCol;
sParse.iDefaultCol = iDefaultCol;
| > > > > < | 123048 123049 123050 123051 123052 123053 123054 123055 123056 123057 123058 123059 123060 123061 123062 123063 123064 123065 123066 123067 123068 123069 123070 123071 123072 123073 123074 123075 123076 123077 123078 123079 |
** that appears on the left-hand-side of the MATCH operator (the default
** column to match against for tokens for which a column name is not explicitly
** specified as part of the query string), or -1 if tokens may by default
** match any table column.
*/
SQLITE_PRIVATE int sqlite3Fts3ExprParse(
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
int iLangid, /* Language id for tokenizer */
char **azCol, /* Array of column names for fts3 table */
int bFts4, /* True to allow FTS4-only syntax */
int nCol, /* Number of entries in azCol[] */
int iDefaultCol, /* Default column to query */
const char *z, int n, /* Text of MATCH query */
Fts3Expr **ppExpr /* OUT: Parsed query structure */
){
int nParsed;
int rc;
ParseContext sParse;
memset(&sParse, 0, sizeof(ParseContext));
sParse.pTokenizer = pTokenizer;
sParse.iLangid = iLangid;
sParse.azCol = (const char **)azCol;
sParse.nCol = nCol;
sParse.iDefaultCol = iDefaultCol;
sParse.bFts4 = bFts4;
if( z==0 ){
*ppExpr = 0;
return SQLITE_OK;
}
if( n<0 ){
n = (int)strlen(z);
|
| ︙ | ︙ | |||
122850 122851 122852 122853 122854 122855 122856 |
goto exprtest_out;
}
for(ii=0; ii<nCol; ii++){
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
}
rc = sqlite3Fts3ExprParse(
| | | 123256 123257 123258 123259 123260 123261 123262 123263 123264 123265 123266 123267 123268 123269 123270 |
goto exprtest_out;
}
for(ii=0; ii<nCol; ii++){
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
}
rc = sqlite3Fts3ExprParse(
pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
);
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
sqlite3_result_error(context, "Error parsing expression", -1);
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
sqlite3_result_error_nomem(context);
}else{
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
| ︙ | ︙ | |||
123899 123900 123901 123902 123903 123904 123905 123906 123907 123908 123909 123910 123911 123912 |
static const sqlite3_tokenizer_module porterTokenizerModule = {
0,
porterCreate,
porterDestroy,
porterOpen,
porterClose,
porterNext,
};
/*
** Allocate a new porter tokenizer. Return a pointer to the new
** tokenizer in *ppModule
*/
SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
| > | 124305 124306 124307 124308 124309 124310 124311 124312 124313 124314 124315 124316 124317 124318 124319 |
static const sqlite3_tokenizer_module porterTokenizerModule = {
0,
porterCreate,
porterDestroy,
porterOpen,
porterClose,
porterNext,
0
};
/*
** Allocate a new porter tokenizer. Return a pointer to the new
** tokenizer in *ppModule
*/
SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
|
| ︙ | ︙ | |||
124204 124205 124206 124207 124208 124209 124210 |
Tcl_IncrRefCount(pRet);
if( SQLITE_OK!=p->xCreate(zArg ? 1 : 0, &zArg, &pTokenizer) ){
zErr = "error in xCreate()";
goto finish;
}
pTokenizer->pModule = p;
| | < | 124611 124612 124613 124614 124615 124616 124617 124618 124619 124620 124621 124622 124623 124624 124625 124626 124627 124628 |
Tcl_IncrRefCount(pRet);
if( SQLITE_OK!=p->xCreate(zArg ? 1 : 0, &zArg, &pTokenizer) ){
zErr = "error in xCreate()";
goto finish;
}
pTokenizer->pModule = p;
if( sqlite3Fts3OpenTokenizer(pTokenizer, 0, zInput, nInput, &pCsr) ){
zErr = "error in xOpen()";
goto finish;
}
while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){
Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos));
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken));
zToken = &zInput[iStart];
nToken = iEnd-iStart;
Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken));
|
| ︙ | ︙ | |||
124624 124625 124626 124627 124628 124629 124630 124631 124632 124633 124634 124635 124636 124637 |
static const sqlite3_tokenizer_module simpleTokenizerModule = {
0,
simpleCreate,
simpleDestroy,
simpleOpen,
simpleClose,
simpleNext,
};
/*
** Allocate a new simple tokenizer. Return a pointer to the new
** tokenizer in *ppModule
*/
SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
| > | 125030 125031 125032 125033 125034 125035 125036 125037 125038 125039 125040 125041 125042 125043 125044 |
static const sqlite3_tokenizer_module simpleTokenizerModule = {
0,
simpleCreate,
simpleDestroy,
simpleOpen,
simpleClose,
simpleNext,
0,
};
/*
** Allocate a new simple tokenizer. Return a pointer to the new
** tokenizer in *ppModule
*/
SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
|
| ︙ | ︙ | |||
124751 124752 124753 124754 124755 124756 124757 124758 124759 124760 124761 124762 124763 124764 |
**
** fts3SegReaderNext()
** fts3SegReaderFirstDocid()
** fts3SegReaderNextDocid()
*/
struct Fts3SegReader {
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */
sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */
sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */
sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */
char *aNode; /* Pointer to node data (or NULL) */
| > | 125158 125159 125160 125161 125162 125163 125164 125165 125166 125167 125168 125169 125170 125171 125172 |
**
** fts3SegReaderNext()
** fts3SegReaderFirstDocid()
** fts3SegReaderNextDocid()
*/
struct Fts3SegReader {
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
int bLookup; /* True for a lookup only */
sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */
sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */
sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */
sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */
char *aNode; /* Pointer to node data (or NULL) */
|
| ︙ | ︙ | |||
124872 124873 124874 124875 124876 124877 124878 124879 124880 124881 124882 124883 124884 124885 | #define SQL_REPLACE_DOCTOTAL 23 #define SQL_SELECT_ALL_PREFIX_LEVEL 24 #define SQL_DELETE_ALL_TERMS_SEGDIR 25 #define SQL_DELETE_SEGDIR_RANGE 26 /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, ** *pp is set to the requested statement handle and SQLITE_OK returned. ** Otherwise, an SQLite error code is returned and *pp is set to 0. ** ** If argument apVal is not NULL, then it must point to an array with | > > | 125280 125281 125282 125283 125284 125285 125286 125287 125288 125289 125290 125291 125292 125293 125294 125295 | #define SQL_REPLACE_DOCTOTAL 23 #define SQL_SELECT_ALL_PREFIX_LEVEL 24 #define SQL_DELETE_ALL_TERMS_SEGDIR 25 #define SQL_DELETE_SEGDIR_RANGE 26 #define SQL_SELECT_ALL_LANGID 27 /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, ** *pp is set to the requested statement handle and SQLITE_OK returned. ** Otherwise, an SQLite error code is returned and *pp is set to 0. ** ** If argument apVal is not NULL, then it must point to an array with |
| ︙ | ︙ | |||
124925 124926 124927 124928 124929 124930 124931 124932 124933 124934 124935 124936 124937 124938 | /* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?", /* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=0", /* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(0,?)", /* 24 */ "", /* 25 */ "", /* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); assert( eStmt<SizeofArray(azSql) && eStmt>=0 ); | > | 125335 125336 125337 125338 125339 125340 125341 125342 125343 125344 125345 125346 125347 125348 125349 | /* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?", /* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=0", /* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(0,?)", /* 24 */ "", /* 25 */ "", /* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", /* 27 */ "SELECT DISTINCT level / (1024 * ?) FROM %Q.'%q_segdir'", }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); assert( eStmt<SizeofArray(azSql) && eStmt>=0 ); |
| ︙ | ︙ | |||
125070 125071 125072 125073 125074 125075 125076 125077 125078 125079 125080 125081 125082 125083 125084 125085 125086 125087 125088 125089 125090 125091 125092 125093 125094 125095 125096 125097 125098 125099 125100 125101 125102 125103 125104 125105 125106 125107 125108 125109 125110 125111 |
}
}else{
rc = SQLITE_OK;
}
return rc;
}
/*
** Set *ppStmt to a statement handle that may be used to iterate through
** all rows in the %_segdir table, from oldest to newest. If successful,
** return SQLITE_OK. If an error occurs while preparing the statement,
** return an SQLite error code.
**
** There is only ever one instance of this SQL statement compiled for
** each FTS3 table.
**
** The statement returns the following columns from the %_segdir table:
**
** 0: idx
** 1: start_block
** 2: leaves_end_block
** 3: end_block
** 4: root
*/
SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(
Fts3Table *p, /* FTS3 table */
int iIndex, /* Index for p->aIndex[] */
int iLevel, /* Level to select */
sqlite3_stmt **ppStmt /* OUT: Compiled statement */
){
int rc;
sqlite3_stmt *pStmt = 0;
assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel>=0 );
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
assert( iIndex>=0 && iIndex<p->nIndex );
if( iLevel<0 ){
/* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0);
if( rc==SQLITE_OK ){
| > > > > > > > > > > > > > > > | | > | | 125481 125482 125483 125484 125485 125486 125487 125488 125489 125490 125491 125492 125493 125494 125495 125496 125497 125498 125499 125500 125501 125502 125503 125504 125505 125506 125507 125508 125509 125510 125511 125512 125513 125514 125515 125516 125517 125518 125519 125520 125521 125522 125523 125524 125525 125526 125527 125528 125529 125530 125531 125532 125533 125534 125535 125536 125537 125538 125539 125540 125541 125542 125543 125544 125545 125546 125547 125548 125549 125550 125551 125552 125553 |
}
}else{
rc = SQLITE_OK;
}
return rc;
}
static sqlite3_int64 getAbsoluteLevel(
Fts3Table *p,
int iLangid,
int iIndex,
int iLevel
){
assert( iLangid>=0 );
assert( p->nIndex>0 );
assert( iIndex>=0 && iIndex<p->nIndex );
return (iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL + iLevel;
}
/*
** Set *ppStmt to a statement handle that may be used to iterate through
** all rows in the %_segdir table, from oldest to newest. If successful,
** return SQLITE_OK. If an error occurs while preparing the statement,
** return an SQLite error code.
**
** There is only ever one instance of this SQL statement compiled for
** each FTS3 table.
**
** The statement returns the following columns from the %_segdir table:
**
** 0: idx
** 1: start_block
** 2: leaves_end_block
** 3: end_block
** 4: root
*/
SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(
Fts3Table *p, /* FTS3 table */
int iLangid, /* Language being queried */
int iIndex, /* Index for p->aIndex[] */
int iLevel, /* Level to select */
sqlite3_stmt **ppStmt /* OUT: Compiled statement */
){
int rc;
sqlite3_stmt *pStmt = 0;
assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel>=0 );
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
assert( iIndex>=0 && iIndex<p->nIndex );
if( iLevel<0 ){
/* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
sqlite3_bind_int(pStmt, 2,
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
);
}
}else{
/* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
}
}
*ppStmt = pStmt;
return rc;
}
|
| ︙ | ︙ | |||
125278 125279 125280 125281 125282 125283 125284 125285 125286 125287 125288 125289 125290 125291 |
** pending-terms hash-table. The docid used is that currently stored in
** p->iPrevDocid, and the column is specified by argument iCol.
**
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
*/
static int fts3PendingTermsAdd(
Fts3Table *p, /* Table into which text will be inserted */
const char *zText, /* Text of document to be inserted */
int iCol, /* Column into which text is being inserted */
u32 *pnWord /* OUT: Number of tokens inserted */
){
int rc;
int iStart;
int iEnd;
| > | 125705 125706 125707 125708 125709 125710 125711 125712 125713 125714 125715 125716 125717 125718 125719 |
** pending-terms hash-table. The docid used is that currently stored in
** p->iPrevDocid, and the column is specified by argument iCol.
**
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
*/
static int fts3PendingTermsAdd(
Fts3Table *p, /* Table into which text will be inserted */
int iLangid, /* Language id to use */
const char *zText, /* Text of document to be inserted */
int iCol, /* Column into which text is being inserted */
u32 *pnWord /* OUT: Number of tokens inserted */
){
int rc;
int iStart;
int iEnd;
|
| ︙ | ︙ | |||
125307 125308 125309 125310 125311 125312 125313 |
** zText==0. In this case, add zero token entries to the hash table and
** return early. */
if( zText==0 ){
*pnWord = 0;
return SQLITE_OK;
}
| | < | 125735 125736 125737 125738 125739 125740 125741 125742 125743 125744 125745 125746 125747 125748 125749 125750 125751 125752 |
** zText==0. In this case, add zero token entries to the hash table and
** return early. */
if( zText==0 ){
*pnWord = 0;
return SQLITE_OK;
}
rc = sqlite3Fts3OpenTokenizer(pTokenizer, iLangid, zText, -1, &pCsr);
if( rc!=SQLITE_OK ){
return rc;
}
xNext = pModule->xNext;
while( SQLITE_OK==rc
&& SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos))
){
int i;
if( iPos>=nWord ) nWord = iPos+1;
|
| ︙ | ︙ | |||
125354 125355 125356 125357 125358 125359 125360 | } /* ** Calling this function indicates that subsequent calls to ** fts3PendingTermsAdd() are to add term/position-list pairs for the ** contents of the document with docid iDocid. */ | | > > > > > > | > > > > | 125781 125782 125783 125784 125785 125786 125787 125788 125789 125790 125791 125792 125793 125794 125795 125796 125797 125798 125799 125800 125801 125802 125803 125804 125805 125806 125807 125808 125809 125810 125811 125812 125813 125814 125815 125816 |
}
/*
** Calling this function indicates that subsequent calls to
** fts3PendingTermsAdd() are to add term/position-list pairs for the
** contents of the document with docid iDocid.
*/
static int fts3PendingTermsDocid(
Fts3Table *p, /* Full-text table handle */
int iLangid, /* Language id of row being written */
sqlite_int64 iDocid /* Docid of row being written */
){
assert( iLangid>=0 );
/* TODO(shess) Explore whether partially flushing the buffer on
** forced-flush would provide better performance. I suspect that if
** we ordered the doclists by size and flushed the largest until the
** buffer was half empty, that would let the less frequent terms
** generate longer doclists.
*/
if( iDocid<=p->iPrevDocid
|| p->iPrevLangid!=iLangid
|| p->nPendingData>p->nMaxPendingData
){
int rc = sqlite3Fts3PendingTermsFlush(p);
if( rc!=SQLITE_OK ) return rc;
}
p->iPrevDocid = iDocid;
p->iPrevLangid = iLangid;
return SQLITE_OK;
}
/*
** Discard the contents of the pending-terms hash tables.
*/
SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
|
| ︙ | ︙ | |||
125394 125395 125396 125397 125398 125399 125400 | ** This function is called by the xUpdate() method as part of an INSERT ** operation. It adds entries for each term in the new record to the ** pendingTerms hash table. ** ** Argument apVal is the same as the similarly named argument passed to ** fts3InsertData(). Parameter iDocid is the docid of the new row. */ | | > > > > > | > | 125831 125832 125833 125834 125835 125836 125837 125838 125839 125840 125841 125842 125843 125844 125845 125846 125847 125848 125849 125850 125851 125852 125853 125854 125855 125856 125857 125858 125859 125860 125861 125862 125863 125864 125865 125866 125867 125868 125869 125870 125871 125872 125873 125874 125875 |
** This function is called by the xUpdate() method as part of an INSERT
** operation. It adds entries for each term in the new record to the
** pendingTerms hash table.
**
** Argument apVal is the same as the similarly named argument passed to
** fts3InsertData(). Parameter iDocid is the docid of the new row.
*/
static int fts3InsertTerms(
Fts3Table *p,
int iLangid,
sqlite3_value **apVal,
u32 *aSz
){
int i; /* Iterator variable */
for(i=2; i<p->nColumn+2; i++){
const char *zText = (const char *)sqlite3_value_text(apVal[i]);
int rc = fts3PendingTermsAdd(p, iLangid, zText, i-2, &aSz[i-2]);
if( rc!=SQLITE_OK ){
return rc;
}
aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]);
}
return SQLITE_OK;
}
/*
** This function is called by the xUpdate() method for an INSERT operation.
** The apVal parameter is passed a copy of the apVal argument passed by
** SQLite to the xUpdate() method. i.e:
**
** apVal[0] Not used for INSERT.
** apVal[1] rowid
** apVal[2] Left-most user-defined column
** ...
** apVal[p->nColumn+1] Right-most user-defined column
** apVal[p->nColumn+2] Hidden column with same name as table
** apVal[p->nColumn+3] Hidden "docid" column (alias for rowid)
** apVal[p->nColumn+4] Hidden languageid column
*/
static int fts3InsertData(
Fts3Table *p, /* Full-text table */
sqlite3_value **apVal, /* Array of values to insert */
sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */
){
int rc; /* Return code */
|
| ︙ | ︙ | |||
125449 125450 125451 125452 125453 125454 125455 | ** ** INSERT INTO %_content VALUES(?, ?, ?, ...) ** ** The statement features N '?' variables, where N is the number of user ** defined columns in the FTS3 table, plus one for the docid field. */ rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); | | | > > > > | 125892 125893 125894 125895 125896 125897 125898 125899 125900 125901 125902 125903 125904 125905 125906 125907 125908 125909 125910 125911 125912 |
**
** INSERT INTO %_content VALUES(?, ?, ?, ...)
**
** The statement features N '?' variables, where N is the number of user
** defined columns in the FTS3 table, plus one for the docid field.
*/
rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]);
if( rc==SQLITE_OK && p->zLanguageid ){
rc = sqlite3_bind_int(
pContentInsert, p->nColumn+2,
sqlite3_value_int(apVal[p->nColumn+4])
);
}
if( rc!=SQLITE_OK ) return rc;
/* There is a quirk here. The users INSERT statement may have specified
** a value for the "rowid" field, for the "docid" field, or for both.
** Which is a problem, since "rowid" and "docid" are aliases for the
** same value. For example:
**
** INSERT INTO fts3tbl(rowid, docid) VALUES(1, 2);
|
| ︙ | ︙ | |||
125510 125511 125512 125513 125514 125515 125516 125517 125518 125519 125520 125521 125522 125523 125524 125525 125526 125527 125528 125529 125530 125531 125532 125533 125534 125535 125536 |
fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
}
if( p->bHasStat ){
fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0);
}
return rc;
}
/*
** The first element in the apVal[] array is assumed to contain the docid
** (an integer) of a row about to be deleted. Remove all terms from the
** full-text index.
*/
static void fts3DeleteTerms(
int *pRC, /* Result code */
Fts3Table *p, /* The FTS table to delete from */
sqlite3_value *pRowid, /* The docid to be deleted */
u32 *aSz /* Sizes of deleted document written here */
){
int rc;
sqlite3_stmt *pSelect;
if( *pRC ) return;
rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
| > > > > > > > > > > > | | > > | | | | < < | > > > > | > > | | 125957 125958 125959 125960 125961 125962 125963 125964 125965 125966 125967 125968 125969 125970 125971 125972 125973 125974 125975 125976 125977 125978 125979 125980 125981 125982 125983 125984 125985 125986 125987 125988 125989 125990 125991 125992 125993 125994 125995 125996 125997 125998 125999 126000 126001 126002 126003 126004 126005 126006 126007 126008 126009 126010 126011 126012 126013 126014 126015 126016 126017 126018 126019 126020 126021 126022 126023 126024 126025 126026 126027 126028 126029 126030 126031 126032 126033 126034 126035 126036 126037 126038 126039 126040 126041 126042 126043 126044 126045 126046 126047 126048 126049 126050 126051 126052 126053 126054 126055 126056 126057 126058 126059 126060 126061 126062 126063 126064 126065 126066 126067 126068 126069 126070 126071 126072 126073 126074 |
fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
}
if( p->bHasStat ){
fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0);
}
return rc;
}
/*
**
*/
static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){
int iLangid = 0;
if( p->zLanguageid ) iLangid = sqlite3_column_int(pSelect, p->nColumn+1);
return iLangid;
}
/*
** The first element in the apVal[] array is assumed to contain the docid
** (an integer) of a row about to be deleted. Remove all terms from the
** full-text index.
*/
static void fts3DeleteTerms(
int *pRC, /* Result code */
Fts3Table *p, /* The FTS table to delete from */
sqlite3_value *pRowid, /* The docid to be deleted */
u32 *aSz /* Sizes of deleted document written here */
){
int rc;
sqlite3_stmt *pSelect;
if( *pRC ) return;
rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
int iLangid = langidFromSelect(p, pSelect);
rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0));
for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){
const char *zText = (const char *)sqlite3_column_text(pSelect, i);
rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[i-1]);
aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i);
}
if( rc!=SQLITE_OK ){
sqlite3_reset(pSelect);
*pRC = rc;
return;
}
}
rc = sqlite3_reset(pSelect);
}else{
sqlite3_reset(pSelect);
}
*pRC = rc;
}
/*
** Forward declaration to account for the circular dependency between
** functions fts3SegmentMerge() and fts3AllocateSegdirIdx().
*/
static int fts3SegmentMerge(Fts3Table *, int, int, int);
/*
** This function allocates a new level iLevel index in the segdir table.
** Usually, indexes are allocated within a level sequentially starting
** with 0, so the allocated index is one greater than the value returned
** by:
**
** SELECT max(idx) FROM %_segdir WHERE level = :iLevel
**
** However, if there are already FTS3_MERGE_COUNT indexes at the requested
** level, they are merged into a single level (iLevel+1) segment and the
** allocated index is 0.
**
** If successful, *piIdx is set to the allocated index slot and SQLITE_OK
** returned. Otherwise, an SQLite error code is returned.
*/
static int fts3AllocateSegdirIdx(
Fts3Table *p,
int iLangid, /* Language id */
int iIndex, /* Index for p->aIndex */
int iLevel,
int *piIdx
){
int rc; /* Return Code */
sqlite3_stmt *pNextIdx; /* Query for next idx at level iLevel */
int iNext = 0; /* Result of query pNextIdx */
assert( iLangid>=0 );
assert( p->nIndex>=1 );
/* Set variable iNext to the next available segdir index at level iLevel. */
rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pNextIdx, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(
pNextIdx, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel)
);
if( SQLITE_ROW==sqlite3_step(pNextIdx) ){
iNext = sqlite3_column_int(pNextIdx, 0);
}
rc = sqlite3_reset(pNextIdx);
}
if( rc==SQLITE_OK ){
/* If iNext is FTS3_MERGE_COUNT, indicating that level iLevel is already
** full, merge all segments in level iLevel into a single iLevel+1
** segment and allocate (newly freed) index 0 at level iLevel. Otherwise,
** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
*/
if( iNext>=FTS3_MERGE_COUNT ){
rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
*piIdx = 0;
}else{
*piIdx = iNext;
}
}
return rc;
|
| ︙ | ︙ | |||
125728 125729 125730 125731 125732 125733 125734 125735 125736 125737 125738 125739 125740 125741 |
while( pReader->pBlob && rc==SQLITE_OK
&& (pFrom - pReader->aNode + nByte)>pReader->nPopulate
){
rc = fts3SegReaderIncrRead(pReader);
}
return rc;
}
/*
** Move the iterator passed as the first argument to the next term in the
** segment. If successful, SQLITE_OK is returned. If there is no next term,
** SQLITE_DONE. Otherwise, an SQLite error code.
*/
static int fts3SegReaderNext(
| > > > > > > > > > > > > | 126192 126193 126194 126195 126196 126197 126198 126199 126200 126201 126202 126203 126204 126205 126206 126207 126208 126209 126210 126211 126212 126213 126214 126215 126216 126217 |
while( pReader->pBlob && rc==SQLITE_OK
&& (pFrom - pReader->aNode + nByte)>pReader->nPopulate
){
rc = fts3SegReaderIncrRead(pReader);
}
return rc;
}
/*
** Set an Fts3SegReader cursor to point at EOF.
*/
static void fts3SegReaderSetEof(Fts3SegReader *pSeg){
if( !fts3SegReaderIsRootOnly(pSeg) ){
sqlite3_free(pSeg->aNode);
sqlite3_blob_close(pSeg->pBlob);
pSeg->pBlob = 0;
}
pSeg->aNode = 0;
}
/*
** Move the iterator passed as the first argument to the next term in the
** segment. If successful, SQLITE_OK is returned. If there is no next term,
** SQLITE_DONE. Otherwise, an SQLite error code.
*/
static int fts3SegReaderNext(
|
| ︙ | ︙ | |||
125768 125769 125770 125771 125772 125773 125774 |
pReader->aNode = pReader->aDoclist = pList->aData;
pReader->ppNextElem++;
assert( pReader->aNode );
}
return SQLITE_OK;
}
| | < < < < < | 126244 126245 126246 126247 126248 126249 126250 126251 126252 126253 126254 126255 126256 126257 126258 |
pReader->aNode = pReader->aDoclist = pList->aData;
pReader->ppNextElem++;
assert( pReader->aNode );
}
return SQLITE_OK;
}
fts3SegReaderSetEof(pReader);
/* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
** blocks have already been traversed. */
assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock );
if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){
return SQLITE_OK;
}
|
| ︙ | ︙ | |||
126020 126021 126022 126023 126024 126025 126026 126027 126028 126029 126030 126031 126032 126033 |
}
/*
** Allocate a new SegReader object.
*/
SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
int iAge, /* Segment "age". */
sqlite3_int64 iStartLeaf, /* First leaf to traverse */
sqlite3_int64 iEndLeaf, /* Final leaf to traverse */
sqlite3_int64 iEndBlock, /* Final block of segment */
const char *zRoot, /* Buffer containing root node */
int nRoot, /* Size of buffer containing root node */
Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */
){
| > | 126491 126492 126493 126494 126495 126496 126497 126498 126499 126500 126501 126502 126503 126504 126505 |
}
/*
** Allocate a new SegReader object.
*/
SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
int iAge, /* Segment "age". */
int bLookup, /* True for a lookup only */
sqlite3_int64 iStartLeaf, /* First leaf to traverse */
sqlite3_int64 iEndLeaf, /* Final leaf to traverse */
sqlite3_int64 iEndBlock, /* Final block of segment */
const char *zRoot, /* Buffer containing root node */
int nRoot, /* Size of buffer containing root node */
Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */
){
|
| ︙ | ︙ | |||
126041 126042 126043 126044 126045 126046 126047 126048 126049 126050 126051 126052 126053 126054 |
pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
if( !pReader ){
return SQLITE_NOMEM;
}
memset(pReader, 0, sizeof(Fts3SegReader));
pReader->iIdx = iAge;
pReader->iStartBlock = iStartLeaf;
pReader->iLeafEndBlock = iEndLeaf;
pReader->iEndBlock = iEndBlock;
if( nExtra ){
/* The entire segment is stored in the root node. */
pReader->aNode = (char *)&pReader[1];
| > | 126513 126514 126515 126516 126517 126518 126519 126520 126521 126522 126523 126524 126525 126526 126527 |
pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
if( !pReader ){
return SQLITE_NOMEM;
}
memset(pReader, 0, sizeof(Fts3SegReader));
pReader->iIdx = iAge;
pReader->bLookup = bLookup;
pReader->iStartBlock = iStartLeaf;
pReader->iLeafEndBlock = iEndLeaf;
pReader->iEndBlock = iEndBlock;
if( nExtra ){
/* The entire segment is stored in the root node. */
pReader->aNode = (char *)&pReader[1];
|
| ︙ | ︙ | |||
126810 126811 126812 126813 126814 126815 126816 | ** Set *pnMax to the largest segment level in the database for the index ** iIndex. ** ** Segment levels are stored in the 'level' column of the %_segdir table. ** ** Return SQLITE_OK if successful, or an SQLite error code if not. */ | | > > > > > | | > > | 127283 127284 127285 127286 127287 127288 127289 127290 127291 127292 127293 127294 127295 127296 127297 127298 127299 127300 127301 127302 127303 127304 127305 127306 127307 127308 127309 127310 127311 127312 127313 127314 127315 127316 127317 127318 |
** Set *pnMax to the largest segment level in the database for the index
** iIndex.
**
** Segment levels are stored in the 'level' column of the %_segdir table.
**
** Return SQLITE_OK if successful, or an SQLite error code if not.
*/
static int fts3SegmentMaxLevel(
Fts3Table *p,
int iLangid,
int iIndex,
int *pnMax
){
sqlite3_stmt *pStmt;
int rc;
assert( iIndex>=0 && iIndex<p->nIndex );
/* Set pStmt to the compiled version of:
**
** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?
**
** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR).
*/
rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
sqlite3_bind_int(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
sqlite3_bind_int(pStmt, 2,
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
*pnMax = sqlite3_column_int(pStmt, 0);
}
return sqlite3_reset(pStmt);
}
/*
|
| ︙ | ︙ | |||
126847 126848 126849 126850 126851 126852 126853 126854 126855 126856 126857 126858 126859 126860 |
** 2) deletes all %_segdir entries with level iLevel, or all %_segdir
** entries regardless of level if (iLevel<0).
**
** SQLITE_OK is returned if successful, otherwise an SQLite error code.
*/
static int fts3DeleteSegdir(
Fts3Table *p, /* Virtual table handle */
int iIndex, /* Index for p->aIndex */
int iLevel, /* Level of %_segdir entries to delete */
Fts3SegReader **apSegment, /* Array of SegReader objects */
int nReader /* Size of array apSegment */
){
int rc; /* Return Code */
int i; /* Iterator variable */
| > | 127327 127328 127329 127330 127331 127332 127333 127334 127335 127336 127337 127338 127339 127340 127341 |
** 2) deletes all %_segdir entries with level iLevel, or all %_segdir
** entries regardless of level if (iLevel<0).
**
** SQLITE_OK is returned if successful, otherwise an SQLite error code.
*/
static int fts3DeleteSegdir(
Fts3Table *p, /* Virtual table handle */
int iLangid, /* Language id */
int iIndex, /* Index for p->aIndex */
int iLevel, /* Level of %_segdir entries to delete */
Fts3SegReader **apSegment, /* Array of SegReader objects */
int nReader /* Size of array apSegment */
){
int rc; /* Return Code */
int i; /* Iterator variable */
|
| ︙ | ︙ | |||
126874 126875 126876 126877 126878 126879 126880 |
return rc;
}
assert( iLevel>=0 || iLevel==FTS3_SEGCURSOR_ALL );
if( iLevel==FTS3_SEGCURSOR_ALL ){
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0);
if( rc==SQLITE_OK ){
| | | > > | | 127355 127356 127357 127358 127359 127360 127361 127362 127363 127364 127365 127366 127367 127368 127369 127370 127371 127372 127373 127374 127375 127376 127377 |
return rc;
}
assert( iLevel>=0 || iLevel==FTS3_SEGCURSOR_ALL );
if( iLevel==FTS3_SEGCURSOR_ALL ){
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
sqlite3_bind_int(pDelete, 2,
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
);
}
}else{
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pDelete, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel));
}
}
if( rc==SQLITE_OK ){
sqlite3_step(pDelete);
rc = sqlite3_reset(pDelete);
}
|
| ︙ | ︙ | |||
127043 127044 127045 127046 127047 127048 127049 127050 127051 127052 127053 |
/* If the Fts3SegFilter defines a specific term (or term prefix) to search
** for, then advance each segment iterator until it points to a term of
** equal or greater value than the specified term. This prevents many
** unnecessary merge/sort operations for the case where single segment
** b-tree leaf nodes contain more than one term.
*/
for(i=0; pCsr->bRestart==0 && i<pCsr->nSegment; i++){
Fts3SegReader *pSeg = pCsr->apSegment[i];
do {
int rc = fts3SegReaderNext(p, pSeg, 0);
if( rc!=SQLITE_OK ) return rc;
| > | > > > > | 127526 127527 127528 127529 127530 127531 127532 127533 127534 127535 127536 127537 127538 127539 127540 127541 127542 127543 127544 127545 127546 127547 127548 127549 |
/* If the Fts3SegFilter defines a specific term (or term prefix) to search
** for, then advance each segment iterator until it points to a term of
** equal or greater value than the specified term. This prevents many
** unnecessary merge/sort operations for the case where single segment
** b-tree leaf nodes contain more than one term.
*/
for(i=0; pCsr->bRestart==0 && i<pCsr->nSegment; i++){
int res = 0;
Fts3SegReader *pSeg = pCsr->apSegment[i];
do {
int rc = fts3SegReaderNext(p, pSeg, 0);
if( rc!=SQLITE_OK ) return rc;
}while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 );
if( pSeg->bLookup && res!=0 ){
fts3SegReaderSetEof(pSeg);
}
}
fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp);
return SQLITE_OK;
}
SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(
|
| ︙ | ︙ | |||
127168 127169 127170 127171 127172 127173 127174 |
int nMerge;
int i;
/* Advance the first pCsr->nAdvance entries in the apSegment[] array
** forward. Then sort the list in order of current term again.
*/
for(i=0; i<pCsr->nAdvance; i++){
| > > > > | > | 127656 127657 127658 127659 127660 127661 127662 127663 127664 127665 127666 127667 127668 127669 127670 127671 127672 127673 127674 127675 |
int nMerge;
int i;
/* Advance the first pCsr->nAdvance entries in the apSegment[] array
** forward. Then sort the list in order of current term again.
*/
for(i=0; i<pCsr->nAdvance; i++){
Fts3SegReader *pSeg = apSegment[i];
if( pSeg->bLookup ){
fts3SegReaderSetEof(pSeg);
}else{
rc = fts3SegReaderNext(p, pSeg, 0);
}
if( rc!=SQLITE_OK ) return rc;
}
fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp);
pCsr->nAdvance = 0;
/* If all the seg-readers are at EOF, we're finished. return SQLITE_OK. */
assert( rc==SQLITE_OK );
|
| ︙ | ︙ | |||
127339 127340 127341 127342 127343 127344 127345 | ** currently present in the database. ** ** If this function is called with iLevel<0, but there is only one ** segment in the database, SQLITE_DONE is returned immediately. ** Otherwise, if successful, SQLITE_OK is returned. If an error occurs, ** an SQLite error code is returned. */ | | > > > > > | | | | | | | | | | > > | | 127832 127833 127834 127835 127836 127837 127838 127839 127840 127841 127842 127843 127844 127845 127846 127847 127848 127849 127850 127851 127852 127853 127854 127855 127856 127857 127858 127859 127860 127861 127862 127863 127864 127865 127866 127867 127868 127869 127870 127871 127872 127873 127874 127875 127876 127877 127878 127879 127880 127881 127882 127883 127884 127885 127886 127887 127888 127889 127890 127891 127892 127893 127894 127895 127896 127897 127898 127899 127900 127901 127902 127903 127904 127905 127906 127907 127908 127909 127910 127911 127912 127913 127914 127915 127916 127917 127918 127919 127920 127921 127922 127923 127924 127925 127926 127927 127928 127929 127930 127931 127932 127933 127934 |
** currently present in the database.
**
** If this function is called with iLevel<0, but there is only one
** segment in the database, SQLITE_DONE is returned immediately.
** Otherwise, if successful, SQLITE_OK is returned. If an error occurs,
** an SQLite error code is returned.
*/
static int fts3SegmentMerge(
Fts3Table *p,
int iLangid, /* Language id to merge */
int iIndex, /* Index in p->aIndex[] to merge */
int iLevel /* Level to merge */
){
int rc; /* Return code */
int iIdx = 0; /* Index of new segment */
int iNewLevel = 0; /* Level/index to create new segment at */
SegmentWriter *pWriter = 0; /* Used to write the new, merged, segment */
Fts3SegFilter filter; /* Segment term filter condition */
Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */
int bIgnoreEmpty = 0; /* True to ignore empty segments */
assert( iLevel==FTS3_SEGCURSOR_ALL
|| iLevel==FTS3_SEGCURSOR_PENDING
|| iLevel>=0
);
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
assert( iIndex>=0 && iIndex<p->nIndex );
rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr);
if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished;
if( iLevel==FTS3_SEGCURSOR_ALL ){
/* This call is to merge all segments in the database to a single
** segment. The level of the new segment is equal to the the numerically
** greatest segment level currently present in the database for this
** index. The idx of the new segment is always 0. */
if( csr.nSegment==1 ){
rc = SQLITE_DONE;
goto finished;
}
rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iNewLevel);
bIgnoreEmpty = 1;
}else if( iLevel==FTS3_SEGCURSOR_PENDING ){
iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, 0);
rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, 0, &iIdx);
}else{
/* This call is to merge all segments at level iLevel. find the next
** available segment index at level iLevel+1. The call to
** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to
** a single iLevel+2 segment if necessary. */
rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx);
iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1);
}
if( rc!=SQLITE_OK ) goto finished;
assert( csr.nSegment>0 );
assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
assert( iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) );
memset(&filter, 0, sizeof(Fts3SegFilter));
filter.flags = FTS3_SEGMENT_REQUIRE_POS;
filter.flags |= (bIgnoreEmpty ? FTS3_SEGMENT_IGNORE_EMPTY : 0);
rc = sqlite3Fts3SegReaderStart(p, &csr, &filter);
while( SQLITE_OK==rc ){
rc = sqlite3Fts3SegReaderStep(p, &csr);
if( rc!=SQLITE_ROW ) break;
rc = fts3SegWriterAdd(p, &pWriter, 1,
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
}
if( rc!=SQLITE_OK ) goto finished;
assert( pWriter );
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
rc = fts3DeleteSegdir(
p, iLangid, iIndex, iLevel, csr.apSegment, csr.nSegment
);
if( rc!=SQLITE_OK ) goto finished;
}
rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
finished:
fts3SegWriterFree(pWriter);
sqlite3Fts3SegReaderFinish(&csr);
return rc;
}
/*
** Flush the contents of pendingTerms to level 0 segments.
*/
SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
int rc = SQLITE_OK;
int i;
for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
sqlite3Fts3PendingTermsClear(p);
return rc;
}
/*
|
| ︙ | ︙ | |||
127575 127576 127577 127578 127579 127580 127581 127582 |
}
sqlite3_bind_blob(pStmt, 1, pBlob, nBlob, SQLITE_STATIC);
sqlite3_step(pStmt);
*pRC = sqlite3_reset(pStmt);
sqlite3_free(a);
}
static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
| > > > > < | > > > > > > > > > | | | | | | | > > > > > | 128075 128076 128077 128078 128079 128080 128081 128082 128083 128084 128085 128086 128087 128088 128089 128090 128091 128092 128093 128094 128095 128096 128097 128098 128099 128100 128101 128102 128103 128104 128105 128106 128107 128108 128109 128110 128111 128112 128113 128114 128115 128116 |
}
sqlite3_bind_blob(pStmt, 1, pBlob, nBlob, SQLITE_STATIC);
sqlite3_step(pStmt);
*pRC = sqlite3_reset(pStmt);
sqlite3_free(a);
}
/*
** Merge the entire database so that there is one segment for each
** iIndex/iLangid combination.
*/
static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
int bSeenDone = 0;
int rc;
sqlite3_stmt *pAllLangid = 0;
rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int(pAllLangid, 1, p->nIndex);
while( sqlite3_step(pAllLangid)==SQLITE_ROW ){
int i;
int iLangid = sqlite3_column_int(pAllLangid, 0);
for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
rc = fts3SegmentMerge(p, iLangid, i, FTS3_SEGCURSOR_ALL);
if( rc==SQLITE_DONE ){
bSeenDone = 1;
rc = SQLITE_OK;
}
}
}
rc2 = sqlite3_reset(pAllLangid);
if( rc==SQLITE_OK ) rc = rc2;
}
sqlite3Fts3SegmentsClose(p);
sqlite3Fts3PendingTermsClear(p);
return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
}
/*
|
| ︙ | ︙ | |||
127636 127637 127638 127639 127640 127641 127642 |
aSzIns = &aSz[p->nColumn+1];
aSzDel = &aSzIns[p->nColumn+1];
}
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
int iCol;
| > | | | 128153 128154 128155 128156 128157 128158 128159 128160 128161 128162 128163 128164 128165 128166 128167 128168 128169 128170 128171 128172 |
aSzIns = &aSz[p->nColumn+1];
aSzDel = &aSzIns[p->nColumn+1];
}
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
int iCol;
int iLangid = langidFromSelect(p, pStmt);
rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0));
aSz[p->nColumn] = 0;
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1);
rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]);
aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1);
}
if( p->bHasDocsize ){
fts3InsertDocsize(&rc, p, aSz);
}
if( rc!=SQLITE_OK ){
sqlite3_finalize(pStmt);
|
| ︙ | ︙ | |||
127759 127760 127761 127762 127763 127764 127765 |
assert( pCsr->isRequireSeek==0 );
iDocid = sqlite3_column_int64(pCsr->pStmt, 0);
for(i=0; i<p->nColumn && rc==SQLITE_OK; i++){
const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1);
sqlite3_tokenizer_cursor *pTC = 0;
| | < | 128277 128278 128279 128280 128281 128282 128283 128284 128285 128286 128287 128288 128289 128290 128291 128292 128293 128294 128295 128296 128297 |
assert( pCsr->isRequireSeek==0 );
iDocid = sqlite3_column_int64(pCsr->pStmt, 0);
for(i=0; i<p->nColumn && rc==SQLITE_OK; i++){
const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1);
sqlite3_tokenizer_cursor *pTC = 0;
rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC);
while( rc==SQLITE_OK ){
char const *zToken; /* Buffer containing token */
int nToken; /* Number of bytes in token */
int iDum1, iDum2; /* Dummy variables */
int iPos; /* Position of token in zText */
rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
Fts3PhraseToken *pPT = pDef->pToken;
if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
&& (pPT->bFirst==0 || iPos==0)
&& (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
&& (0==memcmp(zToken, pPT->z, pPT->n))
|
| ︙ | ︙ | |||
127866 127867 127868 127869 127870 127871 127872 |
if( isEmpty ){
/* Deleting this row means the whole table is empty. In this case
** delete the contents of all three tables and throw away any
** data in the pendingTerms hash table. */
rc = fts3DeleteAll(p, 1);
*pnDoc = *pnDoc - 1;
}else{
| < < | > > > > > > > > > > > > > > > > > > | 128383 128384 128385 128386 128387 128388 128389 128390 128391 128392 128393 128394 128395 128396 128397 128398 128399 128400 128401 128402 128403 128404 128405 128406 128407 128408 128409 128410 128411 128412 128413 128414 128415 128416 128417 128418 128419 128420 128421 128422 128423 128424 128425 128426 128427 128428 128429 128430 128431 128432 128433 128434 128435 128436 128437 128438 128439 128440 128441 128442 128443 128444 128445 128446 128447 128448 128449 128450 128451 128452 128453 128454 128455 128456 128457 128458 128459 128460 128461 |
if( isEmpty ){
/* Deleting this row means the whole table is empty. In this case
** delete the contents of all three tables and throw away any
** data in the pendingTerms hash table. */
rc = fts3DeleteAll(p, 1);
*pnDoc = *pnDoc - 1;
}else{
fts3DeleteTerms(&rc, p, pRowid, aSzDel);
if( p->zContentTbl==0 ){
fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
}else{
*pnDoc = *pnDoc - 1;
}
if( p->bHasDocsize ){
fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
}
}
}
return rc;
}
/*
** This function does the work for the xUpdate method of FTS3 virtual
** tables. The schema of the virtual table being:
**
** CREATE TABLE <table name>(
** <user COLUMns>,
** <table name> HIDDEN,
** docid HIDDEN,
** <langid> HIDDEN
** );
**
**
*/
SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
sqlite3_vtab *pVtab, /* FTS3 vtab object */
int nArg, /* Size of argument array */
sqlite3_value **apVal, /* Array of arguments */
sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */
){
Fts3Table *p = (Fts3Table *)pVtab;
int rc = SQLITE_OK; /* Return Code */
int isRemove = 0; /* True for an UPDATE or DELETE */
u32 *aSzIns = 0; /* Sizes of inserted documents */
u32 *aSzDel; /* Sizes of deleted documents */
int nChng = 0; /* Net change in number of documents */
int bInsertDone = 0;
assert( p->pSegments==0 );
assert(
nArg==1 /* DELETE operations */
|| nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
);
/* Check for a "special" INSERT operation. One of the form:
**
** INSERT INTO xyz(xyz) VALUES('command');
*/
if( nArg>1
&& sqlite3_value_type(apVal[0])==SQLITE_NULL
&& sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL
){
rc = fts3SpecialInsert(p, apVal[p->nColumn+2]);
goto update_out;
}
if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){
rc = SQLITE_CONSTRAINT;
goto update_out;
}
/* Allocate space to hold the change in document sizes */
aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
if( aSzIns==0 ){
rc = SQLITE_NOMEM;
goto update_out;
}
|
| ︙ | ︙ | |||
127983 127984 127985 127986 127987 127988 127989 127990 127991 127992 127993 127994 127995 127996 |
assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER );
rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel);
isRemove = 1;
}
/* If this is an INSERT or UPDATE operation, insert the new record. */
if( nArg>1 && rc==SQLITE_OK ){
if( bInsertDone==0 ){
rc = fts3InsertData(p, apVal, pRowid);
if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){
rc = FTS_CORRUPT_VTAB;
}
}
if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
| > | | | 128516 128517 128518 128519 128520 128521 128522 128523 128524 128525 128526 128527 128528 128529 128530 128531 128532 128533 128534 128535 128536 128537 128538 128539 128540 128541 128542 |
assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER );
rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel);
isRemove = 1;
}
/* If this is an INSERT or UPDATE operation, insert the new record. */
if( nArg>1 && rc==SQLITE_OK ){
int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]);
if( bInsertDone==0 ){
rc = fts3InsertData(p, apVal, pRowid);
if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){
rc = FTS_CORRUPT_VTAB;
}
}
if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
rc = fts3PendingTermsDocid(p, iLangid, *pRowid);
}
if( rc==SQLITE_OK ){
assert( p->iPrevDocid==*pRowid );
rc = fts3InsertTerms(p, iLangid, apVal, aSzIns);
}
if( p->bHasDocsize ){
fts3InsertDocsize(&rc, p, aSzIns);
}
nChng++;
}
|
| ︙ | ︙ | |||
128571 128572 128573 128574 128575 128576 128577 128578 128579 128580 128581 128582 128583 128584 |
** This is done as part of extracting the snippet text, not when selecting
** the snippet. Snippet selection is done based on doclists only, so there
** is no way for fts3BestSnippet() to know whether or not the document
** actually contains terms that follow the final highlighted term.
*/
static int fts3SnippetShift(
Fts3Table *pTab, /* FTS3 table snippet comes from */
int nSnippet, /* Number of tokens desired for snippet */
const char *zDoc, /* Document text to extract snippet from */
int nDoc, /* Size of buffer zDoc in bytes */
int *piPos, /* IN/OUT: First token of snippet */
u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */
){
u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */
| > | 129105 129106 129107 129108 129109 129110 129111 129112 129113 129114 129115 129116 129117 129118 129119 |
** This is done as part of extracting the snippet text, not when selecting
** the snippet. Snippet selection is done based on doclists only, so there
** is no way for fts3BestSnippet() to know whether or not the document
** actually contains terms that follow the final highlighted term.
*/
static int fts3SnippetShift(
Fts3Table *pTab, /* FTS3 table snippet comes from */
int iLangid, /* Language id to use in tokenizing */
int nSnippet, /* Number of tokens desired for snippet */
const char *zDoc, /* Document text to extract snippet from */
int nDoc, /* Size of buffer zDoc in bytes */
int *piPos, /* IN/OUT: First token of snippet */
u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */
){
u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */
|
| ︙ | ︙ | |||
128606 128607 128608 128609 128610 128611 128612 |
sqlite3_tokenizer_module *pMod;
sqlite3_tokenizer_cursor *pC;
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
/* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired)
** or more tokens in zDoc/nDoc.
*/
| | < | 129141 129142 129143 129144 129145 129146 129147 129148 129149 129150 129151 129152 129153 129154 129155 129156 129157 129158 |
sqlite3_tokenizer_module *pMod;
sqlite3_tokenizer_cursor *pC;
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
/* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired)
** or more tokens in zDoc/nDoc.
*/
rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC);
if( rc!=SQLITE_OK ){
return rc;
}
while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){
const char *ZDUMMY; int DUMMY1, DUMMY2, DUMMY3;
rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
}
pMod->xClose(pC);
if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; }
|
| ︙ | ︙ | |||
128670 128671 128672 128673 128674 128675 128676 |
}
return SQLITE_OK;
}
nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol);
/* Open a token cursor on the document. */
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
| | < | 129204 129205 129206 129207 129208 129209 129210 129211 129212 129213 129214 129215 129216 129217 129218 129219 129220 129221 |
}
return SQLITE_OK;
}
nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol);
/* Open a token cursor on the document. */
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc,nDoc,&pC);
if( rc!=SQLITE_OK ){
return rc;
}
while( rc==SQLITE_OK ){
int iBegin; /* Offset in zDoc of start of token */
int iFin; /* Offset in zDoc of end of token */
int isHighlight; /* True for highlighted terms */
rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent);
|
| ︙ | ︙ | |||
128696 128697 128698 128699 128700 128701 128702 |
}
break;
}
if( iCurrent<iPos ){ continue; }
if( !isShiftDone ){
int n = nDoc - iBegin;
| | > > | 129229 129230 129231 129232 129233 129234 129235 129236 129237 129238 129239 129240 129241 129242 129243 129244 129245 |
}
break;
}
if( iCurrent<iPos ){ continue; }
if( !isShiftDone ){
int n = nDoc - iBegin;
rc = fts3SnippetShift(
pTab, pCsr->iLangid, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask
);
isShiftDone = 1;
/* Now that the shift has been done, check if the initial "..." are
** required. They are required if (a) this is not the first fragment,
** or (b) this fragment does not begin at position 0 of its column.
*/
if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){
|
| ︙ | ︙ | |||
129429 129430 129431 129432 129433 129434 129435 |
continue;
}
rc = SQLITE_NOMEM;
goto offsets_out;
}
/* Initialize a tokenizer iterator to iterate through column iCol. */
| > | > < | 129964 129965 129966 129967 129968 129969 129970 129971 129972 129973 129974 129975 129976 129977 129978 129979 129980 129981 |
continue;
}
rc = SQLITE_NOMEM;
goto offsets_out;
}
/* Initialize a tokenizer iterator to iterate through column iCol. */
rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid,
zDoc, nDoc, &pC
);
if( rc!=SQLITE_OK ) goto offsets_out;
rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent);
while( rc==SQLITE_OK ){
int i; /* Used to loop through terms */
int iMinPos = 0x7FFFFFFF; /* Position of next token */
TermOffset *pTerm = 0; /* TermOffset associated with next token */
|
| ︙ | ︙ |
Changes to src/sqlite3.h.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.11" #define SQLITE_VERSION_NUMBER 3007011 #define SQLITE_SOURCE_ID "2012-03-16 00:28:11 74eadeec34c4b19cf5f8b7f648db3b7ad601a00e" /* ** 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 |
| ︙ | ︙ | |||
457 458 459 460 461 462 463 464 465 466 467 468 469 470 | #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | > | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
| ︙ | ︙ | |||
712 713 714 715 716 717 718 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. This capability ** is used during testing and only needs to be supported when SQLITE_TEST ** is defined. | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 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 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 | ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. This capability ** is used during testing and only needs to be supported when SQLITE_TEST ** is defined. ** <ul> ** <li>[[SQLITE_FCNTL_SIZE_HINT]] ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database ** file run faster. ** ** <li>[[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified ** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and ** improve performance on some systems. ** ** <li>[[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See the [sqlite3_file_control()] documentation for ** additional information. ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] ** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by ** SQLite and sent to all VFSes in place of a call to the xSync method ** when the database connection has [PRAGMA synchronous] set to OFF.)^ ** Some specialized VFSes need this signal in order to operate correctly ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most ** VFSes do not need this signal and should silently ignore this opcode. ** Applications should not call [sqlite3_file_control()] with this ** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. ** ** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic ** retry counts and intervals for certain disk I/O operations for the ** windows [VFS] in order to provide robustness in the presence of ** anti-virus programs. By default, the windows VFS will retry file read, ** file write, and file delete operations up to 10 times, with a delay ** of 25 milliseconds before the first retry and with the delay increasing ** by an additional 25 milliseconds with each subsequent retry. This ** opcode allows these two values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two ** integers where the first integer i the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be ** interrogated. The zDbName parameter is ignored. ** ** <li>[[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write AHead Log] setting. By default, the auxiliary ** write ahead log and shared memory files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not ** have write permission on the directory containing the database file want ** to read the database file, as the WAL and shared memory files must exist ** in order for the database to be readable. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable persistent WAL mode or 1 to enable persistent ** WAL mode. If the integer is -1, then it is overwritten with the current ** WAL persistence setting. ** ** <li>[[SQLITE_FCNTL_POWERSAFE_OVERWRITE]] ** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the ** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting ** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the ** xDeviceCharacteristics methods. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage ** mode. If the integer is -1, then it is overwritten with the current ** zero-damage mode setting. ** ** <li>[[SQLITE_FCNTL_OVERWRITE]] ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** a write transaction to indicate that, unless it is rolled back for some ** reason, the entire database file will be overwritten by the current ** transaction. This is used by VACUUM operations. ** ** <li>[[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of ** all [VFSes] in the VFS stack. The names are of all VFS shims and the ** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. ** The caller is responsible for freeing the memory when done. As with ** all file-control actions, there is no guarantee that this will actually ** do anything. Callers should initialize the char* variable to a NULL ** pointer in case this file-control is not implemented. This file-control ** is intended for diagnostic use only. ** ** <li>[[SQLITE_FCNTL_PRAGMA]] ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] ** file control is sent to the open [sqlite3_file] object corresponding ** to the database file to which the pragma statement refers. ^The argument ** to the [SQLITE_FCNTL_PRAGMA] file control is an array of ** pointers to strings (char**) in which the second element of the array ** is the name of the pragma and the third element is the argument to the ** pragma or NULL if the pragma has no argument. ^The handler for an ** [SQLITE_FCNTL_PRAGMA] file control can optionally make the first element ** of the char** argument point to a string obtained from [sqlite3_mprintf()] ** or the equivalent and that string will become the result of the pragma or ** the error message if the pragma fails. ^If the ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] ** file control returns [SQLITE_OK], then the parser assumes that the ** VFS has handled the PRAGMA itself and the parser generates a no-op ** prepared statement. ^If the [SQLITE_FCNTL_PRAGMA] file control returns ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] ** file control occurs at the beginning of pragma statement analysis and so ** it is able to override built-in [PRAGMA] statements. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
| ︙ | ︙ | |||
2628 2629 2630 2631 2632 2633 2634 | /* ** CAPI3REF: Obtain Values For URI Parameters ** ** These are utility routines, useful to VFS implementations, that check ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** | | > > | | > > > > | > | | | > | 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 | /* ** CAPI3REF: Obtain Values For URI Parameters ** ** These are utility routines, useful to VFS implementations, that check ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** ** If F is the database filename pointer passed into the xOpen() method of ** a VFS implementation when the flags parameter to xOpen() has one or ** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and ** P is the name of the query parameter, then ** sqlite3_uri_parameter(F,P) returns the value of the P ** parameter if it exists or a NULL pointer if P does not appear as a ** query parameter on F. If P is a query parameter of F ** has no explicit value, then sqlite3_uri_parameter(F,P) returns ** a pointer to an empty string. ** ** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean ** parameter and returns true (1) or false (0) according to the value ** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the ** value of query parameter P is one of "yes", "true", or "on" in any ** case or if the value begins with a non-zero number. The ** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of ** query parameter P is one of "no", "false", or "off" in any case or ** if the value begins with a numeric zero. If P is not a query ** parameter on F or if the value of P is does not match any of the ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not ** exist. If the value of P is something other than an integer, then ** zero is returned. ** ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and ** is not a database file pathname pointer that SQLite passed into the xOpen ** VFS method, then the behavior of this routine is undefined and probably ** undesirable. */ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); /* |
| ︙ | ︙ | |||
4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 | ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. */ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Find the next prepared statement ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL ** then this interface returns a pointer to the first prepared statement ** associated with the database connection pDb. ^If no prepared statement | > > > > > > > > > | 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 | ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. */ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only ** ** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N ** of connection D is read-only, 0 if it is read/write, or -1 if N is not ** the name of a database on connection D. */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Find the next prepared statement ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL ** then this interface returns a pointer to the first prepared statement ** associated with the database connection pDb. ^If no prepared statement |
| ︙ | ︙ | |||
6206 6207 6208 6209 6210 6211 6212 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] ** handle invalid, and will not use it with any other sqlite3_pcache_methods2 ** functions. ** ** [[the xShrink() page cache method]] ** ^SQLite invokes the xShrink() method when it wants the page cache to ** free up as much of heap memory as possible. The page cache implementation | | | 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 |
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
** handle invalid, and will not use it with any other sqlite3_pcache_methods2
** functions.
**
** [[the xShrink() page cache method]]
** ^SQLite invokes the xShrink() method when it wants the page cache to
** free up as much of heap memory as possible. The page cache implementation
** is not obligated to free any memory, but well-behaved implementations should
** do their best.
*/
typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2;
struct sqlite3_pcache_methods2 {
int iVersion;
void *pArg;
int (*xInit)(void*);
|
| ︙ | ︙ | |||
6577 6578 6579 6580 6581 6582 6583 | void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** | | | | | > | 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 | void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** ** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications ** and extensions to compare the contents of two buffers containing UTF-8 ** strings in a case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ SQLITE_API int sqlite3_stricmp(const char *, const char *); SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: Error Logging Interface ** ** ^The [sqlite3_log()] interface writes a message into the error log ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. |
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
396 397 398 399 400 401 402 |
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
@ }
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@ vertical-align: top;
@ text-align: right;
@ padding: 0.2ex 2ex;
@ }
;
/* The following table contains bits of default CSS that must
** be included if they are not found in the application-defined
** CSS.
*/
|
| ︙ | ︙ | |||
809 810 811 812 813 814 815 816 817 818 819 820 821 822 |
@ color: red;
},
{ "ul.filelist",
"List of files in a timeline",
@ margin-top: 3px;
@ line-height: 100%;
},
{ 0,
0,
0
}
};
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
@ color: red;
},
{ "ul.filelist",
"List of files in a timeline",
@ margin-top: 3px;
@ line-height: 100%;
},
{ "div.sbsdiff",
"side-by-side diff display",
@ font-family: monospace;
@ font-size: smaller;
@ white-space: pre;
},
{ "div.udiff",
"context diff display",
@ font-family: monospace;
@ white-space: pre;
},
{ "span.diffchng",
"changes in a diff",
@ background-color: #c0c0ff;
},
{ "span.diffadd",
"added code in a diff",
@ background-color: #c0ffc0;
},
{ "span.diffrm",
"deleted in a diff",
@ background-color: #ffc8c8;
},
{ "span.diffhr",
"suppressed lines in a diff",
@ color: #0000ff;
},
{ "span.diffln",
"line nubmers in a diff",
@ color: #a0a0a0;
},
{ 0,
0,
0
}
};
/*
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
523 524 525 526 527 528 529 | blob_reset(&filename); tar_finish(pTar); } /* ** COMMAND: tarball* ** | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | blob_reset(&filename); tar_finish(pTar); } /* ** COMMAND: tarball* ** ** Usage: %fossil tarball VERSION OUTPUTFILE [--name DIRECTORYNAME] [-R|--repository REPO] ** ** Generate a compressed tarball for a specified version. If the --name ** option is used, its argument becomes the name of the top-level directory ** in the resulting tarball. If --name is omitted, the top-level directory ** named is derived from the project name, the check-in date and time, and ** the artifact ID of the check-in. */ |
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | ** This file contains code to implement the timeline web page ** */ #include <string.h> #include <time.h> #include "config.h" #include "timeline.h" | < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
** This file contains code to implement the timeline web page
**
*/
#include <string.h>
#include <time.h>
#include "config.h"
#include "timeline.h"
/*
** Shorten a UUID so that is the minimum length needed to contain
** at least one digit in the range 'a'..'f'. The minimum length is 10.
*/
static void shorten_uuid(char *zDest, const char *zSrc){
int i;
|
| ︙ | ︙ | |||
362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
char *zLink = mprintf("%s/timeline?u=%h&c=%t&nd",
g.zTop, zUser, zDate);
@ (user: <a href="%s(zLink)">%h(zUser)</a>%s(zTagList?",":"\051")
fossil_free(zLink);
}else{
@ (user: %h(zUser)%s(zTagList?",":"\051")
}
/* Generate the "tags: TAGLIST" at the end of the comment, together
** with hyperlinks to the tag list.
*/
if( zTagList ){
if( g.perm.History ){
int i;
| > > > > > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
char *zLink = mprintf("%s/timeline?u=%h&c=%t&nd",
g.zTop, zUser, zDate);
@ (user: <a href="%s(zLink)">%h(zUser)</a>%s(zTagList?",":"\051")
fossil_free(zLink);
}else{
@ (user: %h(zUser)%s(zTagList?",":"\051")
}
/* Generate a "detail" link for tags. */
if( zType[0]=='g' && g.perm.History ){
@ [<a href="%s(g.zTop)/info/%S(zUuid)">details</a>]
}
/* Generate the "tags: TAGLIST" at the end of the comment, together
** with hyperlinks to the tag list.
*/
if( zTagList ){
if( g.perm.History ){
int i;
|
| ︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
}
@ tags: %s(blob_str(&links)))
blob_reset(&links);
}else{
@ tags: %h(zTagList))
}
}
/* Generate extra hyperlinks at the end of the comment */
if( xExtra ){
xExtra(rid);
}
/* Generate the file-change list if requested */
| > | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
}
@ tags: %s(blob_str(&links)))
blob_reset(&links);
}else{
@ tags: %h(zTagList))
}
}
/* Generate extra hyperlinks at the end of the comment */
if( xExtra ){
xExtra(rid);
}
/* Generate the file-change list if requested */
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
*/
void ticket_init(void){
const char *zConfig;
Th_FossilInit();
zConfig = ticket_common_code();
Th_Eval(g.interp, 0, zConfig, -1);
}
/*
** Recreate the ticket table.
*/
void ticket_create_table(int separateConnection){
const char *zSql;
| > > > > > > > > > > | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
*/
void ticket_init(void){
const char *zConfig;
Th_FossilInit();
zConfig = ticket_common_code();
Th_Eval(g.interp, 0, zConfig, -1);
}
/*
** Create the subscript interpreter and load the "change" code.
*/
int ticket_change(void){
const char *zConfig;
Th_FossilInit();
zConfig = ticket_change_code();
return Th_Eval(g.interp, 0, zConfig, -1);
}
/*
** Recreate the ticket table.
*/
void ticket_create_table(int separateConnection){
const char *zSql;
|
| ︙ | ︙ | |||
485 486 487 488 489 490 491 |
fossil_panic("trouble committing ticket: %s", g.zErrMsg);
}
manifest_crosslink_begin();
manifest_crosslink(rid, &tktchng);
assert( blob_is_reset(&tktchng) );
manifest_crosslink_end();
}
| | | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
fossil_panic("trouble committing ticket: %s", g.zErrMsg);
}
manifest_crosslink_begin();
manifest_crosslink(rid, &tktchng);
assert( blob_is_reset(&tktchng) );
manifest_crosslink_end();
}
return ticket_change();
}
/*
** WEBPAGE: tktnew
** WEBPAGE: debug_tktnew
**
|
| ︙ | ︙ |
Changes to src/tktsetup.c.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
@ <table border="0" cellspacing="20">
setup_menu_entry("Table", "tktsetup_tab",
"Specify the schema of the \"ticket\" table in the database.");
setup_menu_entry("Timeline", "tktsetup_timeline",
"How to display ticket status in the timeline");
setup_menu_entry("Common", "tktsetup_com",
"Common TH1 code run before all ticket processing.");
setup_menu_entry("New Ticket Page", "tktsetup_newpage",
"HTML with embedded TH1 code for the \"new ticket\" webpage.");
setup_menu_entry("View Ticket Page", "tktsetup_viewpage",
"HTML with embedded TH1 code for the \"view ticket\" webpage.");
setup_menu_entry("Edit Ticket Page", "tktsetup_editpage",
"HTML with embedded TH1 code for the \"edit ticket\" webpage.");
setup_menu_entry("Report List Page", "tktsetup_reportlist",
| > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
@ <table border="0" cellspacing="20">
setup_menu_entry("Table", "tktsetup_tab",
"Specify the schema of the \"ticket\" table in the database.");
setup_menu_entry("Timeline", "tktsetup_timeline",
"How to display ticket status in the timeline");
setup_menu_entry("Common", "tktsetup_com",
"Common TH1 code run before all ticket processing.");
setup_menu_entry("Change", "tktsetup_change",
"The TH1 code run after a ticket is edited or created.");
setup_menu_entry("New Ticket Page", "tktsetup_newpage",
"HTML with embedded TH1 code for the \"new ticket\" webpage.");
setup_menu_entry("View Ticket Page", "tktsetup_viewpage",
"HTML with embedded TH1 code for the \"view ticket\" webpage.");
setup_menu_entry("Edit Ticket Page", "tktsetup_editpage",
"HTML with embedded TH1 code for the \"edit ticket\" webpage.");
setup_menu_entry("Report List Page", "tktsetup_reportlist",
|
| ︙ | ︙ | |||
236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
;
tktsetup_generic(
"Ticket Common Script",
"ticket-common",
zDefaultTicketCommon,
zDesc,
0,
0,
30
);
}
static const char zDefaultNew[] =
@ <th1>
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
;
tktsetup_generic(
"Ticket Common Script",
"ticket-common",
zDefaultTicketCommon,
zDesc,
0,
0,
30
);
}
static const char zDefaultTicketChange[] =
@ return
;
/*
** Return the ticket change code.
*/
const char *ticket_change_code(void){
return db_get("ticket-change", (char*)zDefaultTicketChange);
}
/*
** WEBPAGE: tktsetup_change
*/
void tktsetup_change_page(void){
static const char zDesc[] =
@ Enter TH1 script that runs after processing the ticket editing
@ and creation pages.
;
tktsetup_generic(
"Ticket Change Script",
"ticket-change",
zDefaultTicketChange,
zDesc,
0,
0,
30
);
}
static const char zDefaultNew[] =
@ <th1>
|
| ︙ | ︙ |
Changes to src/undo.c.
| ︙ | ︙ | |||
348 349 350 351 352 353 354 | undo_all_filesystem(0); } /* ** COMMAND: undo ** COMMAND: redo* ** | | | > > > > > | 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 |
undo_all_filesystem(0);
}
/*
** COMMAND: undo
** COMMAND: redo*
**
** Usage: %fossil undo ?OPTIONS? ?FILENAME...?
** or: %fossil redo ?OPTIONS? ?FILENAME...?
**
** Undo the changes to the working checkout caused by the most recent
** of the following operations:
**
** (1) fossil update (5) fossil stash apply
** (2) fossil merge (6) fossil stash drop
** (3) fossil revert (7) fossil stash goto
** (4) fossil stash pop
**
** If FILENAME is specified then restore the content of the named
** file(s) but otherwise leave the update or merge or revert in effect.
** The redo command undoes the effect of the most recent undo.
**
** If the --explain option is present, no changes are made and instead
** the undo or redo command explains what actions the undo or redo would
** have done had the --explain been omitted.
**
** A single level of undo/redo is supported. The undo/redo stack
** is cleared by the commit and checkout commands.
**
** Options:
** --explain do not make changes but show what would be done
**
** See also: commit, status
*/
void undo_cmd(void){
int isRedo = g.argv[1][0]=='r';
int undo_available;
int explainFlag = find_option("explain", 0, 0)!=0;
const char *zCmd = isRedo ? "redo" : "undo";
db_must_be_within_tree();
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 | g.argv = savedArgv; return internalConflictCnt; } /* ** COMMAND: update ** | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | g.argv = savedArgv; return internalConflictCnt; } /* ** COMMAND: update ** ** Usage: %fossil update ?OPTIONS? ?VERSION? ?FILES...? ** ** Change the version of the current checkout to VERSION. Any uncommitted ** changes are retained and applied to the new checkout. ** ** The VERSION argument can be a specific version or tag or branch name. ** If the VERSION argument is omitted, then the leaf of the subtree ** that begins at the current version is used, if there is only a single |
| ︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
**
** The -n or --nochange option causes this command to do a "dry run". It
** prints out what would have happened but does not actually make any
** changes to the current checkout or the repository.
**
** The -v or --verbose option prints status information about unchanged
** files in addition to those file that actually do change.
*/
void update_cmd(void){
int vid; /* Current version */
int tid=0; /* Target version - version we are changing to */
Stmt q;
int latestFlag; /* --latest. Pick the latest version if true */
int nochangeFlag; /* -n or --nochange. Do a dry run */
| > > > > > > > > | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
**
** The -n or --nochange option causes this command to do a "dry run". It
** prints out what would have happened but does not actually make any
** changes to the current checkout or the repository.
**
** The -v or --verbose option prints status information about unchanged
** files in addition to those file that actually do change.
**
** Options:
** --debug print debug information on stdout
** --latest acceptable in place of VERSION, update to latest version
** -n|--nochange do not perform changes but show what would be done
** -v|--verbose print status information about all files
**
** See also: revert
*/
void update_cmd(void){
int vid; /* Current version */
int tid=0; /* Target version - version we are changing to */
Stmt q;
int latestFlag; /* --latest. Pick the latest version if true */
int nochangeFlag; /* -n or --nochange. Do a dry run */
|
| ︙ | ︙ | |||
261 262 263 264 265 266 267 |
);
/*
** Add islink information
*/
db_multi_exec(
"UPDATE fv SET"
| | > | > | > | > | 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 |
);
/*
** 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));
|
| ︙ | ︙ | |||
323 324 325 326 327 328 329 | } /* ** Alter the content of the checkout so that it conforms with the ** target */ db_prepare(&q, | | > | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
}
/*
** 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 );
|
| ︙ | ︙ | |||
459 460 461 462 463 464 465 |
*/
if( !nochangeFlag ){
if( nConflict ){
if( internalUpdate ){
internalConflictCnt = nConflict;
nConflict = 0;
}else{
| | | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
*/
if( !nochangeFlag ){
if( nConflict ){
if( internalUpdate ){
internalConflictCnt = nConflict;
nConflict = 0;
}else{
fossil_warning("WARNING: %d merge conflicts", nConflict);
}
}
if( nOverwrite ){
fossil_warning("WARNING: %d unmanaged files were overwritten",
nOverwrite);
}
}
|
| ︙ | ︙ | |||
608 609 610 611 612 613 614 615 616 617 618 619 620 621 |
** the version associated with baseline REVISION if the -r flag
** appears.
**
** Revert all files if no file name is provided.
**
** If a file is reverted accidently, it can be restored using
** the "fossil undo" command.
*/
void revert_cmd(void){
const char *zFile;
const char *zRevision;
Blob record;
int i;
int errCode;
| > > > > > | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 |
** the version associated with baseline REVISION if the -r flag
** appears.
**
** Revert all files if no file name is provided.
**
** If a file is reverted accidently, it can be restored using
** the "fossil undo" command.
**
** Options:
** -r REVISION revert given FILE(s) back to given REVISION
**
** See also: redo, undo, update
*/
void revert_cmd(void){
const char *zFile;
const char *zRevision;
Blob record;
int i;
int errCode;
|
| ︙ | ︙ | |||
664 665 666 667 668 669 670 |
}
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);
| | > | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 |
}
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);
|
| ︙ | ︙ | |||
690 691 692 693 694 695 696 |
blob_write_to_file(&record, zFull);
}
file_wd_setexe(zFull, isExe);
fossil_print("REVERTED: %s\n", zFile);
mtime = file_wd_mtime(zFull);
db_multi_exec(
"UPDATE vfile"
| | | 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 |
blob_write_to_file(&record, zFull);
}
file_wd_setexe(zFull, isExe);
fossil_print("REVERTED: %s\n", zFile);
mtime = file_wd_mtime(zFull);
db_multi_exec(
"UPDATE vfile"
" SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid,"
" pathname=coalesce(origname,pathname), origname=NULL"
" WHERE pathname=%Q",
mtime, isExe, isLink, zFile
);
}
blob_reset(&record);
free(zFull);
}
db_finalize(&q);
undo_finish();
db_end_transaction(0);
}
|
Changes to src/url.c.
| ︙ | ︙ | |||
185 186 187 188 189 190 191 |
}
}else{
fossil_panic("unknown repository: %s", zUrl);
}
if( g.urlIsFile ){
Blob cfile;
dehttpize(zFile);
| | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
}
}else{
fossil_panic("unknown repository: %s", zUrl);
}
if( g.urlIsFile ){
Blob cfile;
dehttpize(zFile);
file_canonical_name(zFile, &cfile, 0);
free(zFile);
g.urlProtocol = "file";
g.urlPath = "";
g.urlName = mprintf("%b", &cfile);
g.urlCanonical = mprintf("file://%T", g.urlName);
blob_reset(&cfile);
}
|
| ︙ | ︙ | |||
263 264 265 266 267 268 269 |
*/
void url_enable_proxy(const char *zMsg){
const char *zProxy;
zProxy = zProxyOpt;
if( zProxy==0 ){
zProxy = db_get("proxy", 0);
if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
| | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
*/
void url_enable_proxy(const char *zMsg){
const char *zProxy;
zProxy = zProxyOpt;
if( zProxy==0 ){
zProxy = db_get("proxy", 0);
if( zProxy==0 || zProxy[0]==0 || is_truth(zProxy) ){
zProxy = fossil_getenv("http_proxy");
}
}
if( zProxy && zProxy[0] && !is_false(zProxy) ){
char *zOriginalUrl = g.urlCanonical;
char *zOriginalHost = g.urlHostname;
char *zOriginalUser = g.urlUser;
char *zOriginalPasswd = g.urlPasswd;
|
| ︙ | ︙ |
Changes to src/user.c.
| ︙ | ︙ | |||
322 323 324 325 326 327 328 |
}
}
if( g.localOpen && attempt_user(db_lget("default-user",0)) ) return;
if( attempt_user(db_get("default-user", 0)) ) return;
| | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
}
}
if( g.localOpen && attempt_user(db_lget("default-user",0)) ) return;
if( attempt_user(db_get("default-user", 0)) ) return;
if( attempt_user(fossil_getenv("USER")) ) return;
db_prepare(&s,
"SELECT uid, login FROM user"
" WHERE login NOT IN ('anonymous','nobody','reader','developer')"
);
if( db_step(&s)==SQLITE_ROW ){
g.userUid = db_column_int(&s, 0);
|
| ︙ | ︙ |
Changes to src/vfile.c.
| ︙ | ︙ | |||
188 189 190 191 192 193 194 |
if( notFileIsFatal ){
fossil_warning("not an ordinary file: %s", zName);
nErr++;
}
chnged = 1;
}
if( origSize!=currentSize ){
| | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
if( notFileIsFatal ){
fossil_warning("not an ordinary file: %s", zName);
nErr++;
}
chnged = 1;
}
if( origSize!=currentSize ){
if( chnged!=1 ){
/* A file size change is definitive - the file has changed. No
** need to check the mtime or sha1sum */
chnged = 1;
}
}else if( chnged==1 && rid!=0 && !isDeleted ){
/* File is believed to have changed but it is the same size.
** Double check that it really has changed by looking at content. */
|
| ︙ | ︙ | |||
333 334 335 336 337 338 339 |
db_finalize(&q);
db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid);
}
/*
** Check to see if the directory named in zPath is the top of a checkout.
** In other words, check to see if directory pPath contains a file named
| | > > > > > > > > > > > | 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 |
db_finalize(&q);
db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid);
}
/*
** Check to see if the directory named in zPath is the top of a checkout.
** In other words, check to see if directory pPath contains a file named
** "_FOSSIL_" or ".fslckout". Return true or false.
*/
int vfile_top_of_checkout(const char *zPath){
char *zFile;
int fileFound = 0;
zFile = mprintf("%s/_FOSSIL_", zPath);
fileFound = file_size(zFile)>=1024;
fossil_free(zFile);
if( !fileFound ){
zFile = mprintf("%s/.fslckout", zPath);
fileFound = file_size(zFile)>=1024;
fossil_free(zFile);
}
/* Check for ".fos" for legacy support. But the use of ".fos" as the
** per-checkout database name is deprecated. At some point, all support
** for ".fos" will end and this code should be removed. This comment
** added on 2012-02-04.
*/
if( !fileFound ){
zFile = mprintf("%s/.fos", zPath);
fileFound = file_size(zFile)>=1024;
fossil_free(zFile);
}
return fileFound;
}
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
591 592 593 594 595 596 597 598 599 600 601 602 603 604 |
*/
void wdiff_page(void){
char *zTitle;
int rid1, rid2;
const char *zPageName;
Manifest *pW1, *pW2 = 0;
Blob w1, w2, d;
login_check_credentials();
rid1 = atoi(PD("a","0"));
if( !g.perm.History ){ login_needed(); return; }
if( rid1==0 ) fossil_redirect_home();
rid2 = atoi(PD("b","0"));
zPageName = PD("name","");
| > | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
*/
void wdiff_page(void){
char *zTitle;
int rid1, rid2;
const char *zPageName;
Manifest *pW1, *pW2 = 0;
Blob w1, w2, d;
int diffFlags;
login_check_credentials();
rid1 = atoi(PD("a","0"));
if( !g.perm.History ){ login_needed(); return; }
if( rid1==0 ) fossil_redirect_home();
rid2 = atoi(PD("b","0"));
zPageName = PD("name","");
|
| ︙ | ︙ | |||
619 620 621 622 623 624 625 |
if( pW1==0 ) fossil_redirect_home();
blob_init(&w1, pW1->zWiki, -1);
blob_zero(&w2);
if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
blob_init(&w2, pW2->zWiki, -1);
}
blob_zero(&d);
| > | | | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
if( pW1==0 ) fossil_redirect_home();
blob_init(&w1, pW1->zWiki, -1);
blob_zero(&w2);
if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
blob_init(&w2, pW2->zWiki, -1);
}
blob_zero(&d);
diffFlags = construct_diff_flags(1,0);
text_diff(&w2, &w1, &d, diffFlags | DIFF_HTML | DIFF_LINENO);
@ <div class="udiff">
@ %s(blob_str(&d))
@ </div>
manifest_destroy(pW1);
manifest_destroy(pW2);
style_footer();
}
/*
** prepare()s pStmt with a query requesting:
|
| ︙ | ︙ |
Changes to src/winhttp.c.
| ︙ | ︙ | |||
594 595 596 597 598 599 600 |
zNotFound = find_option("notfound", 0, 1);
zLocalAuth = find_option("localauth", 0, 0);
zRepository = find_option("repository", "R", 1);
if( !zRepository ){
db_must_be_within_tree();
}else if( file_isdir(zRepository)==1 ){
g.zRepositoryName = mprintf("%s", zRepository);
| | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
zNotFound = find_option("notfound", 0, 1);
zLocalAuth = find_option("localauth", 0, 0);
zRepository = find_option("repository", "R", 1);
if( !zRepository ){
db_must_be_within_tree();
}else if( file_isdir(zRepository)==1 ){
g.zRepositoryName = mprintf("%s", zRepository);
file_simplify_name(g.zRepositoryName, -1, 0);
}else{
db_open_repository(zRepository);
}
db_close(0);
verify_all_options();
if( g.argc>4 ) fossil_fatal("to much arguments for create method.");
/* Build the fully-qualified path to the service binary file. */
|
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
return;
}
blob_zero(&content);
blob_zero(&hash);
blob_extract(pXfer->pIn, n, &content);
if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
/* Ignore files that have been shunned */
return;
}
if( isPriv && !g.perm.Private ){
/* Do not accept private files if not authorized */
return;
}
if( cloneFlag ){
if( pXfer->nToken==4 ){
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
pXfer->nDeltaRcvd++;
}else{
| > > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
return;
}
blob_zero(&content);
blob_zero(&hash);
blob_extract(pXfer->pIn, n, &content);
if( !cloneFlag && uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
/* Ignore files that have been shunned */
blob_reset(&content);
return;
}
if( isPriv && !g.perm.Private ){
/* Do not accept private files if not authorized */
blob_reset(&content);
return;
}
if( cloneFlag ){
if( pXfer->nToken==4 ){
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
pXfer->nDeltaRcvd++;
}else{
|
| ︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
if( content_get(srcid, &src)==0 ){
rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
0, isPriv);
pXfer->nDanglingFile++;
db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
if( !isPriv ) content_make_public(rid);
return;
}
pXfer->nDeltaRcvd++;
blob_delta_apply(&src, &content, &next);
blob_reset(&src);
blob_reset(&content);
content = next;
| > > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
if( content_get(srcid, &src)==0 ){
rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid,
0, isPriv);
pXfer->nDanglingFile++;
db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
if( !isPriv ) content_make_public(rid);
blob_reset(&src);
blob_reset(&content);
return;
}
pXfer->nDeltaRcvd++;
blob_delta_apply(&src, &content, &next);
blob_reset(&src);
blob_reset(&content);
content = next;
|
| ︙ | ︙ | |||
233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
/* Do not accept private files if not authorized */
return;
}
blob_zero(&content);
blob_extract(pXfer->pIn, szC, &content);
if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
/* Ignore files that have been shunned */
return;
}
if( pXfer->nToken==5 ){
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
pXfer->nDeltaRcvd++;
}else{
srcid = 0;
| > | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
/* Do not accept private files if not authorized */
return;
}
blob_zero(&content);
blob_extract(pXfer->pIn, szC, &content);
if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
/* Ignore files that have been shunned */
blob_reset(&content);
return;
}
if( pXfer->nToken==5 ){
srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv);
pXfer->nDeltaRcvd++;
}else{
srcid = 0;
|
| ︙ | ︙ | |||
418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
if( isPriv ) blob_append(pXfer->pOut, "private\n", -1);
blob_appendf(pXfer->pOut, "file %b %d\n", pUuid, size);
blob_append(pXfer->pOut, blob_buffer(&content), size);
pXfer->nFileSent++;
}else{
pXfer->nDeltaSent++;
}
}
remote_has(rid);
blob_reset(&uuid);
#if 0
if( blob_buffer(pXfer->pOut)[blob_size(pXfer->pOut)-1]!='\n' ){
blob_appendf(pXfer->pOut, "\n", 1);
}
| > | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
if( isPriv ) blob_append(pXfer->pOut, "private\n", -1);
blob_appendf(pXfer->pOut, "file %b %d\n", pUuid, size);
blob_append(pXfer->pOut, blob_buffer(&content), size);
pXfer->nFileSent++;
}else{
pXfer->nDeltaSent++;
}
blob_reset(&content);
}
remote_has(rid);
blob_reset(&uuid);
#if 0
if( blob_buffer(pXfer->pOut)[blob_size(pXfer->pOut)-1]!='\n' ){
blob_appendf(pXfer->pOut, "\n", 1);
}
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
377 378 379 380 381 382 383 | blob_reset(&filename); zip_close(pZip); } /* ** COMMAND: zip* ** | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | blob_reset(&filename); zip_close(pZip); } /* ** COMMAND: zip* ** ** Usage: %fossil zip VERSION OUTPUTFILE [--name DIRECTORYNAME] [-R|--repository REPO] ** ** Generate a ZIP archive for a specified version. If the --name option is ** used, it argument becomes the name of the top-level directory in the ** resulting ZIP archive. If --name is omitted, the top-level directory ** named is derived from the project name, the check-in date and time, and ** the artifact ID of the check-in. */ |
| ︙ | ︙ |
Added test/diff-test-1.wiki.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<title>Graph Test One</title>
This page contains list of URLs of interesting diffs.
Click on all URLs, one by one, to verify
the correct operation of the diff logic.
* <a href="../../../info/030035345c#chunk59" target="testwindow">
Multiple edits on a single line.</a> This is an SQLite version
update diff. It is a large diff and contains many other interesting
features. Scan the whole diff.
* <a href="../../../fdiff?v1=6da016415dc52d61&v2=af6df3466e3c4a88"
target="testwindow">Tricky alignment and multiple edits per line</a>.
* <a href="../../../fdiff?v1=7108d4748b111d23&v2=2303a98525b39d19#chunk3"
target="testwindow">Add a column to a table</a>
External:
* <a href="http://www.sqlite.org/src/fdiff?v1=aafcb21a74e41f9a&v2=a6d127dd05daf0f9#chunk3" target="testwindow">
Code indentation change.</a>
|
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> Verify correct name-change tracking behavior (no net changes) for: <blockquote><b> fossil test-name-changes --debug b120bc8b262ac 374920b20944b </b></blockquote> <li><p> | > > > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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> Click on each of the links in in the [./diff-test-1.wiki] document and verify that all diffs 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> |
| ︙ | ︙ |
Changes to win/Makefile.dmc.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | #SSL = -DFOSSIL_ENABLE_SSL=1 SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) | | | | | | 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 | #SSL = -DFOSSIL_ENABLE_SSL=1 SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c xfersetup_.c zip_.c OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ APPNAME = $(OBJDIR)\fossil$(E) all: $(APPNAME) $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link cd $(OBJDIR) $(DMDIR)\bin\link @link $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_tag json_timeline json_user json_wiki leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ translate$E: $(SRCDIR)\translate.c |
| ︙ | ︙ | |||
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h | > > > | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| ︙ | ︙ | |||
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | +translate$E $** > $@ $(OBJDIR)\json_branch$O : json_branch_.c json_branch.h $(TCC) -o$@ -c json_branch_.c json_branch_.c : $(SRCDIR)\json_branch.c +translate$E $** > $@ $(OBJDIR)\json_diff$O : json_diff_.c json_diff.h $(TCC) -o$@ -c json_diff_.c json_diff_.c : $(SRCDIR)\json_diff.c +translate$E $** > $@ $(OBJDIR)\json_login$O : json_login_.c json_login.h $(TCC) -o$@ -c json_login_.c json_login_.c : $(SRCDIR)\json_login.c +translate$E $** > $@ | > > > > > > > > > > > > > > > > > > | 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 | +translate$E $** > $@ $(OBJDIR)\json_branch$O : json_branch_.c json_branch.h $(TCC) -o$@ -c json_branch_.c json_branch_.c : $(SRCDIR)\json_branch.c +translate$E $** > $@ $(OBJDIR)\json_config$O : json_config_.c json_config.h $(TCC) -o$@ -c json_config_.c json_config_.c : $(SRCDIR)\json_config.c +translate$E $** > $@ $(OBJDIR)\json_diff$O : json_diff_.c json_diff.h $(TCC) -o$@ -c json_diff_.c json_diff_.c : $(SRCDIR)\json_diff.c +translate$E $** > $@ $(OBJDIR)\json_dir$O : json_dir_.c json_dir.h $(TCC) -o$@ -c json_dir_.c json_dir_.c : $(SRCDIR)\json_dir.c +translate$E $** > $@ $(OBJDIR)\json_finfo$O : json_finfo_.c json_finfo.h $(TCC) -o$@ -c json_finfo_.c json_finfo_.c : $(SRCDIR)\json_finfo.c +translate$E $** > $@ $(OBJDIR)\json_login$O : json_login_.c json_login.h $(TCC) -o$@ -c json_login_.c json_login_.c : $(SRCDIR)\json_login.c +translate$E $** > $@ |
| ︙ | ︙ | |||
670 671 672 673 674 675 676 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h | | | 691 692 693 694 695 696 697 698 699 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers |
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
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 | #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = gcc #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### The directories where the zlib include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "zlib-1.x.y" sub-directory of the # Fossil source code directory and the target zlib source directory. # | > > > > | | | | | 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 | #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = gcc #### Enable JSON (http://www.json.org) support using "cson" # # FOSSIL_ENABLE_JSON = 1 #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### The directories where the zlib include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "zlib-1.x.y" sub-directory of the # Fossil source code directory and the target zlib source directory. # ZINCDIR = $(SRCDIR)/../zlib-1.2.6 ZLIBDIR = $(SRCDIR)/../zlib-1.2.6 #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.0g/include OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.0g #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win | > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -Dpqueue_insert=pqueue_insert_fossil TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win |
| ︙ | ︙ | |||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 | TCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support (statically linked) ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 -DSTATIC_BUILD endif #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. We add the -static option here # so that we can build a static executable that will run in a # chroot jail. # | > > > > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | TCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support (statically linked) ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 -DSTATIC_BUILD endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 endif #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. We add the -static option here # so that we can build a static executable that will run in a # chroot jail. # |
| ︙ | ︙ | |||
138 139 140 141 142 143 144 | #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 else | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 else LIB += -lkernel32 -lws2_32 endif #### Tcl shell for use in running the fossil test suite. This is only # used for testing. # TCLSH = tclsh |
| ︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_login.c \ $(SRCDIR)/json_query.c \ $(SRCDIR)/json_report.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ | > > > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_config.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_dir.c \ $(SRCDIR)/json_finfo.c \ $(SRCDIR)/json_login.c \ $(SRCDIR)/json_query.c \ $(SRCDIR)/json_report.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ |
| ︙ | ︙ | |||
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_login_.c \ $(OBJDIR)/json_query_.c \ $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ | > > > | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_config_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_dir_.c \ $(OBJDIR)/json_finfo_.c \ $(OBJDIR)/json_login_.c \ $(OBJDIR)/json_query_.c \ $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ |
| ︙ | ︙ | |||
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_login.o \ $(OBJDIR)/json_query.o \ $(OBJDIR)/json_report.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ | > > > | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_config.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_dir.o \ $(OBJDIR)/json_finfo.o \ $(OBJDIR)/json_login.o \ $(OBJDIR)/json_query.o \ $(OBJDIR)/json_report.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ |
| ︙ | ︙ | |||
516 517 518 519 520 521 522 | setup: $(OBJDIR) $(APPNAME) $(MAKENSIS) ./fossil.nsi $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | setup: $(OBJDIR) $(APPNAME) $(MAKENSIS) ./fossil.nsi $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h echo Done >$(OBJDIR)/headers $(OBJDIR)/headers: Makefile Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
| ︙ | ︙ | |||
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | $(OBJDIR)/json_branch_.c: $(SRCDIR)/json_branch.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.o: $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c json_branch.h: $(OBJDIR)/headers $(OBJDIR)/json_diff_.c: $(SRCDIR)/json_diff.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.o: $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c json_diff.h: $(OBJDIR)/headers $(OBJDIR)/json_login_.c: $(SRCDIR)/json_login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.o: $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c json_login.h: $(OBJDIR)/headers | > > > > > > > > > > > > > > > > > > > > > | 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 860 861 862 863 864 865 866 867 868 | $(OBJDIR)/json_branch_.c: $(SRCDIR)/json_branch.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.o: $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c json_branch.h: $(OBJDIR)/headers $(OBJDIR)/json_config_.c: $(SRCDIR)/json_config.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_config.c >$(OBJDIR)/json_config_.c $(OBJDIR)/json_config.o: $(OBJDIR)/json_config_.c $(OBJDIR)/json_config.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_config.o -c $(OBJDIR)/json_config_.c json_config.h: $(OBJDIR)/headers $(OBJDIR)/json_diff_.c: $(SRCDIR)/json_diff.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.o: $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c json_diff.h: $(OBJDIR)/headers $(OBJDIR)/json_dir_.c: $(SRCDIR)/json_dir.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_dir.c >$(OBJDIR)/json_dir_.c $(OBJDIR)/json_dir.o: $(OBJDIR)/json_dir_.c $(OBJDIR)/json_dir.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_dir.o -c $(OBJDIR)/json_dir_.c json_dir.h: $(OBJDIR)/headers $(OBJDIR)/json_finfo_.c: $(SRCDIR)/json_finfo.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_finfo.c >$(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.o: $(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_finfo.o -c $(OBJDIR)/json_finfo_.c json_finfo.h: $(OBJDIR)/headers $(OBJDIR)/json_login_.c: $(SRCDIR)/json_login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.o: $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c json_login.h: $(OBJDIR)/headers |
| ︙ | ︙ | |||
1185 1186 1187 1188 1189 1190 1191 | zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE | | | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 | zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| ︙ | ︙ |
Changes to win/Makefile.mingw.mistachkin.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = gcc #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # | > > > > | | | | | | 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 | #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = gcc #### Enable JSON (http://www.json.org) support using "cson" # FOSSIL_ENABLE_JSON = 1 #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### The directories where the zlib include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "zlib-1.x.y" sub-directory of the # Fossil source code directory and the target zlib source directory. # ZINCDIR = $(SRCDIR)/../zlib-1.2.6 ZLIBDIR = $(SRCDIR)/../zlib-1.2.6 #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../openssl-1.0.0g/include OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.0g #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win | > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. # TCC = gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -Dpqueue_insert=pqueue_insert_fossil TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR) endif # With Tcl support ifdef FOSSIL_ENABLE_TCL ifdef FOSSIL_TCL_SOURCE TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win |
| ︙ | ︙ | |||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 | TCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support (statically linked) ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 -DSTATIC_BUILD endif #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. We add the -static option here # so that we can build a static executable that will run in a # chroot jail. # | > > > > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | TCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support (statically linked) ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 -DSTATIC_BUILD endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 endif #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other mandatory dependencies. We add the -static option here # so that we can build a static executable that will run in a # chroot jail. # |
| ︙ | ︙ | |||
138 139 140 141 142 143 144 | #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 else | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | #### These libraries MUST appear in the same order as they do for Tcl # or linking with it will not work (exact reason unknown). # ifdef FOSSIL_ENABLE_TCL LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32 else LIB += -lkernel32 -lws2_32 endif #### Tcl shell for use in running the fossil test suite. This is only # used for testing. # TCLSH = tclsh |
| ︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_login.c \ $(SRCDIR)/json_query.c \ $(SRCDIR)/json_report.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ | > > > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | $(SRCDIR)/http_ssl.c \ $(SRCDIR)/http_transport.c \ $(SRCDIR)/import.c \ $(SRCDIR)/info.c \ $(SRCDIR)/json.c \ $(SRCDIR)/json_artifact.c \ $(SRCDIR)/json_branch.c \ $(SRCDIR)/json_config.c \ $(SRCDIR)/json_diff.c \ $(SRCDIR)/json_dir.c \ $(SRCDIR)/json_finfo.c \ $(SRCDIR)/json_login.c \ $(SRCDIR)/json_query.c \ $(SRCDIR)/json_report.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ |
| ︙ | ︙ | |||
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_login_.c \ $(OBJDIR)/json_query_.c \ $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ | > > > | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | $(OBJDIR)/http_ssl_.c \ $(OBJDIR)/http_transport_.c \ $(OBJDIR)/import_.c \ $(OBJDIR)/info_.c \ $(OBJDIR)/json_.c \ $(OBJDIR)/json_artifact_.c \ $(OBJDIR)/json_branch_.c \ $(OBJDIR)/json_config_.c \ $(OBJDIR)/json_diff_.c \ $(OBJDIR)/json_dir_.c \ $(OBJDIR)/json_finfo_.c \ $(OBJDIR)/json_login_.c \ $(OBJDIR)/json_query_.c \ $(OBJDIR)/json_report_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ |
| ︙ | ︙ | |||
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_login.o \ $(OBJDIR)/json_query.o \ $(OBJDIR)/json_report.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ | > > > | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | $(OBJDIR)/http_ssl.o \ $(OBJDIR)/http_transport.o \ $(OBJDIR)/import.o \ $(OBJDIR)/info.o \ $(OBJDIR)/json.o \ $(OBJDIR)/json_artifact.o \ $(OBJDIR)/json_branch.o \ $(OBJDIR)/json_config.o \ $(OBJDIR)/json_diff.o \ $(OBJDIR)/json_dir.o \ $(OBJDIR)/json_finfo.o \ $(OBJDIR)/json_login.o \ $(OBJDIR)/json_query.o \ $(OBJDIR)/json_report.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ |
| ︙ | ︙ | |||
516 517 518 519 520 521 522 | setup: $(OBJDIR) $(APPNAME) $(MAKENSIS) ./fossil.nsi $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | setup: $(OBJDIR) $(APPNAME) $(MAKENSIS) ./fossil.nsi $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(MKINDEX) $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h echo Done >$(OBJDIR)/headers $(OBJDIR)/headers: Makefile Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
| ︙ | ︙ | |||
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | $(OBJDIR)/json_branch_.c: $(SRCDIR)/json_branch.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.o: $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c json_branch.h: $(OBJDIR)/headers $(OBJDIR)/json_diff_.c: $(SRCDIR)/json_diff.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.o: $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c json_diff.h: $(OBJDIR)/headers $(OBJDIR)/json_login_.c: $(SRCDIR)/json_login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.o: $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c json_login.h: $(OBJDIR)/headers | > > > > > > > > > > > > > > > > > > > > > | 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 860 861 862 863 864 865 866 867 868 | $(OBJDIR)/json_branch_.c: $(SRCDIR)/json_branch.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.o: $(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c json_branch.h: $(OBJDIR)/headers $(OBJDIR)/json_config_.c: $(SRCDIR)/json_config.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_config.c >$(OBJDIR)/json_config_.c $(OBJDIR)/json_config.o: $(OBJDIR)/json_config_.c $(OBJDIR)/json_config.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_config.o -c $(OBJDIR)/json_config_.c json_config.h: $(OBJDIR)/headers $(OBJDIR)/json_diff_.c: $(SRCDIR)/json_diff.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.o: $(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c json_diff.h: $(OBJDIR)/headers $(OBJDIR)/json_dir_.c: $(SRCDIR)/json_dir.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_dir.c >$(OBJDIR)/json_dir_.c $(OBJDIR)/json_dir.o: $(OBJDIR)/json_dir_.c $(OBJDIR)/json_dir.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_dir.o -c $(OBJDIR)/json_dir_.c json_dir.h: $(OBJDIR)/headers $(OBJDIR)/json_finfo_.c: $(SRCDIR)/json_finfo.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_finfo.c >$(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.o: $(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_finfo.o -c $(OBJDIR)/json_finfo_.c json_finfo.h: $(OBJDIR)/headers $(OBJDIR)/json_login_.c: $(SRCDIR)/json_login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.o: $(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c json_login.h: $(OBJDIR)/headers |
| ︙ | ︙ | |||
1185 1186 1187 1188 1189 1190 1191 | zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE | | | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 | zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| ︙ | ︙ |
Changes to win/Makefile.msc.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 | BCC = $(CC) $(CFLAGS) TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB) LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT3 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0 | | | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | BCC = $(CC) $(CFLAGS) TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) LIBS = $(ZLIB) ws2_32.lib advapi32.lib $(SSLLIB) LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT3 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c xfersetup_.c zip_.c OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\glob$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\json$O $(OX)\json_artifact$O $(OX)\json_branch$O $(OX)\json_config$O $(OX)\json_diff$O $(OX)\json_dir$O $(OX)\json_finfo$O $(OX)\json_login$O $(OX)\json_query$O $(OX)\json_report$O $(OX)\json_tag$O $(OX)\json_timeline$O $(OX)\json_user$O $(OX)\json_wiki$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\path$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\xfersetup$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O APPNAME = $(OX)\fossil$(E) all: $(OX) $(APPNAME) $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts |
| ︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | echo $(OX)\http_ssl.obj >> $@ echo $(OX)\http_transport.obj >> $@ echo $(OX)\import.obj >> $@ echo $(OX)\info.obj >> $@ echo $(OX)\json.obj >> $@ echo $(OX)\json_artifact.obj >> $@ echo $(OX)\json_branch.obj >> $@ echo $(OX)\json_diff.obj >> $@ echo $(OX)\json_login.obj >> $@ echo $(OX)\json_query.obj >> $@ echo $(OX)\json_report.obj >> $@ echo $(OX)\json_tag.obj >> $@ echo $(OX)\json_timeline.obj >> $@ echo $(OX)\json_user.obj >> $@ echo $(OX)\json_wiki.obj >> $@ | > > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | echo $(OX)\http_ssl.obj >> $@ echo $(OX)\http_transport.obj >> $@ echo $(OX)\import.obj >> $@ echo $(OX)\info.obj >> $@ echo $(OX)\json.obj >> $@ echo $(OX)\json_artifact.obj >> $@ echo $(OX)\json_branch.obj >> $@ echo $(OX)\json_config.obj >> $@ echo $(OX)\json_diff.obj >> $@ echo $(OX)\json_dir.obj >> $@ echo $(OX)\json_finfo.obj >> $@ echo $(OX)\json_login.obj >> $@ echo $(OX)\json_query.obj >> $@ echo $(OX)\json_report.obj >> $@ echo $(OX)\json_tag.obj >> $@ echo $(OX)\json_timeline.obj >> $@ echo $(OX)\json_user.obj >> $@ echo $(OX)\json_wiki.obj >> $@ |
| ︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h | > > > | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | realclean: -del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_dir$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h |
| ︙ | ︙ | |||
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | translate$E $** > $@ $(OX)\json_branch$O : json_branch_.c json_branch.h $(TCC) /Fo$@ -c json_branch_.c json_branch_.c : $(SRCDIR)\json_branch.c translate$E $** > $@ $(OX)\json_diff$O : json_diff_.c json_diff.h $(TCC) /Fo$@ -c json_diff_.c json_diff_.c : $(SRCDIR)\json_diff.c translate$E $** > $@ $(OX)\json_login$O : json_login_.c json_login.h $(TCC) /Fo$@ -c json_login_.c json_login_.c : $(SRCDIR)\json_login.c translate$E $** > $@ | > > > > > > > > > > > > > > > > > > | 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 | translate$E $** > $@ $(OX)\json_branch$O : json_branch_.c json_branch.h $(TCC) /Fo$@ -c json_branch_.c json_branch_.c : $(SRCDIR)\json_branch.c translate$E $** > $@ $(OX)\json_config$O : json_config_.c json_config.h $(TCC) /Fo$@ -c json_config_.c json_config_.c : $(SRCDIR)\json_config.c translate$E $** > $@ $(OX)\json_diff$O : json_diff_.c json_diff.h $(TCC) /Fo$@ -c json_diff_.c json_diff_.c : $(SRCDIR)\json_diff.c translate$E $** > $@ $(OX)\json_dir$O : json_dir_.c json_dir.h $(TCC) /Fo$@ -c json_dir_.c json_dir_.c : $(SRCDIR)\json_dir.c translate$E $** > $@ $(OX)\json_finfo$O : json_finfo_.c json_finfo.h $(TCC) /Fo$@ -c json_finfo_.c json_finfo_.c : $(SRCDIR)\json_finfo.c translate$E $** > $@ $(OX)\json_login$O : json_login_.c json_login.h $(TCC) /Fo$@ -c json_login_.c json_login_.c : $(SRCDIR)\json_login.c translate$E $** > $@ |
| ︙ | ︙ | |||
776 777 778 779 780 781 782 | $(OX)\zip$O : zip_.c zip.h $(TCC) /Fo$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h | | | 800 801 802 803 804 805 806 807 808 | $(OX)\zip$O : zip_.c zip.h $(TCC) /Fo$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers |
Changes to www/build.wiki.
1 2 3 4 | <title>Building and Installing Fossil</title> <h2>0.0 Using A Pre-compiled Binary</h2> | | | > > | | | > > | | 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 |
<title>Building and Installing Fossil</title>
<h2>0.0 Using A Pre-compiled Binary</h2>
<p>Released versions of fossil come with
<a href="http://www.fossil-scm.org/download.html">pre-compiled binaries and
a source archive</a> for that release. You can thus skip the following if you
want to run or build a release version of fossil. Just download
the appropriate package from the <a href="http://www.fossil-scm.org/download.html">downloads page</a>
and put it on your $PATH.
To uninstall, simply delete the binary.
To upgrade from an older release, just overwrite the older binary with
the newer one.</p>
<h2>0.1 Executive Summary</h2>
<p>Building and installing is very simple. Three steps:</p>
<ol>
<li> Download and unpack a source tarball or ZIP.
<li> <b>./configure; make</b>
<li> Move or copy the resulting "fossil" executable to someplace
on your $PATH.
</ol>
<p><hr>
<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 <em>latest</em> version directly from fossil's own fossil
repository. Additionally, source archives of <em>released</em> versions of
fossil are available from the <a href="http://www.fossil-scm.org/download.html">downloads page</a>.
To obtain a development version of fossil, 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.
|
| ︙ | ︙ |
Changes to www/changes.wiki.
1 2 3 4 5 6 7 8 |
<title>Change Log</title>
<h2>Changes For Version 1.21 (2011-12-13)</h2>
* Added side-by-side diffs in the command-line interface
* Automatically enable hyperlinks if the UserAgent string in the
HTTP header suggests that the requestor is a human and not a bot.
* Show only commonly used commands with "fossil help". Use
"fossil help --all" to see the complete list now.
| > > > > > > > > > > > > > > > > > > > > | 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 |
<title>Change Log</title>
<h2>Changes For Version 1.22 (2012-03-17)</h2>
* Greatly improved "diff" processing including the new --brief option,
partial line matching, colorized in-line diffs, and better performance.
* Promote "allow-symlinks" to a versionable setting
* Harden the CGI processing logic against DOS attacks
* Add the ability to run TH1 scripts after sync requests
* Store the repository name in _FOSSIL_ as it is type in the "open" command,
possibly as a relative pathname.
* Make ".fslckout" the alternative name for the "_FOSSIL_" file.
* Change the "ssh:" transfer method to allow all access regardless of
user permission.
* Improvements to the timeline messages associated with tag changes.
(Requires a "[/help/rebuild | fossil rebuild]" to take effect.)
* Various additions and fixes for the JSON API.
* Improved merge-with-rename handling.
* --cherrypick merges use their origin's commit message by default.
* Added support for multiple concurrent logins per user.
* Update to use SQLite version 3.7.11.
* Various minor bug fixes.
<h2>Changes For Version 1.21 (2011-12-13)</h2>
* Added side-by-side diffs in the command-line interface
* Automatically enable hyperlinks if the UserAgent string in the
HTTP header suggests that the requestor is a human and not a bot.
* Show only commonly used commands with "fossil help". Use
"fossil help --all" to see the complete list now.
|
| ︙ | ︙ |
Changes to www/stats.wiki.
1 2 3 4 5 6 | <title>Fossil Performance</title> <h1 align="center">Performance Statistics</h1> The questions will inevitably arise: How does Fossil perform? Does it use a lot of disk space or bandwidth? Is it scalable? | | > > | > > | > > | > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < | | | | | | > | > | | | | | | < | > > > | | | 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 | <title>Fossil Performance</title> <h1 align="center">Performance Statistics</h1> The questions will inevitably arise: How does Fossil perform? Does it use a lot of disk space or bandwidth? Is it scalable? In an attempt to answers these questions, this report looks at several projects that use fossil for configuration management and examines how well they are working. The following table is a summary of the results. (Last updated on 2012-02-26.) Explanation and analysis follows the table. <table border=1> <tr> <th>Project</th> <th>Number Of Artifacts</th> <th>Number Of Check-ins</th> <th>Project Duration<br>(as of 2009-08-23)</th> <th>Average Check-ins Per Day</th> <th>Uncompressed Size</th> <th>Repository Size</th> <th>Compression Ratio</th> <th>Clone Bandwidth</th> </tr> <tr align="center"> <td>[http://www.sqlite.org/src/timeline | SQLite] <td>41113 <td>9943 <td>4290 days<br>11.75 yrs <td>2.32 <td>2.09 GB <td>33.2 MB <td>63:1 <td>23.2 MB </tr> <tr align="center"> <td>[http://core.tcl.tk/tcl/timeline | TCL] <td>74806 <td>13541 <td>5085 days<br>13.92 yrs <td>2.66 <td>5.2 GB <td>86 MB <td>60:1 <td>67.0 MB </tr> <tr align="center"> <td>[/timeline | Fossil] <td>15561 <td>3764 <td>1681 days<br>4.6 yrs <td>2.24 <td>721 MB <td>18.8 MB <td>38:1 <td>12.0 MB </tr> <tr align="center"> <td>[http://www.sqlite.org/slt/timeline | SLT] <td>2174 <td>100 <td>1183 days<br>3.24 yrs <td>0.08 <td>1.94 GB <td>143 MB <td>12:1 <td>141 MB </tr> <tr align="center"> <td>[http://www.sqlite.org/th3.html | TH3] <td>5624 <td>1472 <td>1248 days<br>3.42 yrs <td>1.78 <td>252 MB <td>12.5 MB <td>20:1 <td>12.2 MB </tr> <tr align="center"> <td>[http://www.sqlite.org/docsrc/timeline | SQLite Docs] <td>3664 <td>1003 <td>1567 days<br>4.29 yrs <td>0.64 <td>108 MB <td>6.6 MB <td>16:1 <td>5.71 MB </tr> </table> <h2>Measured Attributes</h2> In Fossil, every version of every file, every wiki page, every change to every ticket, and every check-in is a separate "artifact". One way to think of a Fossil project is as a bag of artifacts. Of course, there is a lot more than this going on in Fossil. Many of the artifacts have meaning and are related to other artifacts. But at a low level (for example when synchronizing two instances of the same project) the only thing that matters is the unordered collection of artifacts. In fact, one of the key characteristics of Fossil is that the entire project history can be reconstructed simply by scanning the artifacts in an arbitrary order. The number of check-ins is the number of times that the "commit" command has been run. A single check-in might change a 3 or 4 files, or it might change dozens or hundreds of files. Regardless of the number of files changed, it still only counts as one check-in. The "Uncompressed Size" is the total size of all the artifacts within the repository assuming they were all uncompressed and stored separately on the disk. Fossil makes use of delta compression between related versions of the same file, and then uses zlib compression on the resulting deltas. The total resulting repository size is shown after the uncompressed size. For this chart, "fossil rebuild --compress" was run on each repository prior to measuring its compressed size. Repository sizes would typically be 20% larger without that rebuild. On the right end of the table, we show the "Clone Bandwidth". This is the total number of bytes sent from server back to the client. The number of bytes sent from client to server is neglible in comparison. These byte counts include HTTP protocol overhead. In the table and throughout this article, "GB" means gigabytes (10<sup><small>9</small></sup> bytes) not <a href="http://en.wikipedia.org/wiki/Gibibyte">gibibytes</a> (2<sup><small>30</small></sup> bytes). Similarly, "MB" and "KB" means megabytes and kilobytes, not mebibytes and kibibytes. <h2>Analysis And Supplimental Data</h2> Perhaps the two most interesting datapoints in the above table are SQLite and SLT. SQLite is a long-running project with long revision chains. Some of the files in SQLite have been edited over a thousand times. Each of these edits is stored as a delta, and hence the SQLite project gets excellent 63:1 compression. SLT, on the other hand, consists of many large (megabyte-sized) SQL scripts that have one or maybe two edits each. There is very little delta compression occurring and so the overall repository compression ratio is much lower. Note also that quite a bit more bandwidth is required to clone SLT than SQLite. For the first nine years of its development, SQLite was versioned by CVS. The resulting CVS repository measured over 320MB in size. So, the developers were surprised to see that this entire project could be cloned in fossil using only about 23.2MB of network traffic. (This 23.2MB includes all the changes to SQLite that have been made since the conversion from CVS. Of those changes are omitted, the clone bandwidth drops to 13MB.) The "sync" protocol used by fossil has turned out to be surprisingly efficient. A typical check-in on SQLite might use 3 or 4KB of network bandwidth total. Hardly worth measuring. The sync protocol is efficient enough that, once cloned, Fossil could easily be used over a dial-up connection. |
Changes to www/tech_overview.wiki.
1 2 3 4 5 6 7 8 9 | <title>Technical Overview</title> <h2 align="center"> A Technical Overview<br>Of The Design And Implementation<br>Of Fossil </h2> <h2>1.0 Introduction</h2> At its lowest level, a Fossil repository consists of an unordered set of immutable "artifacts". You might think of these artifacts as "files", | | < | | | | | < < | 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 | <title>Technical Overview</title> <h2 align="center"> A Technical Overview<br>Of The Design And Implementation<br>Of Fossil </h2> <h2>1.0 Introduction</h2> At its lowest level, a Fossil repository consists of an unordered set of immutable "artifacts". You might think of these artifacts as "files", since in many cases the artifacts exactly that. But other "control artifacts" are also included in the mix. These control artifacts define the relationships between artifacts - which files go together to form a particular version of the project, who checked in that version and when, what was the check-in comment, what wiki pages are included with the project, what are the edit histories of each wiki page, what bug reports or tickets are included, who contributed to the evolution of each ticket, and so forth. This low-level file format is called the "global state" of the repository, since this is the information that is synced to peer repositories using push and pull operations. The low-level file format is also called "enduring" since it is intended to last for many years. The details of the low-level, enduring, global file format are [./fileformat.wiki | described separately]. This article is about how Fossil is currently implemented. Instead of dealing with vague abstractions of "enduring file formats" as the [./fileformat.wiki | other document] does, this article provides some detail on how Fossil actually stores information on disk. <h2>2.0 Three Databases</h2> Fossil stores state information in [http://www.sqlite.org/ | SQLite] database files. SQLite keeps an entire relational database, including multiple tables and indices, in a single disk file. The SQLite library allows the database files to be efficiently queried and updated using the industry-standard SQL language. SQLite updates are atomic, so even in the event of a system crashes or power failure the repository content is protected. Fossil uses three separate classes of SQLite databases: <ol> <li>The configuration database <li>Repository databases <li>Checkout databases |
| ︙ | ︙ | |||
150 151 152 153 154 155 156 | of the artifacts that comprise the [./fileformat.wiki | enduring, global, shared state] of the project. The artifacts are stored as BLOBs, compressed using [http://www.zlib.net/ | zlib compression] and, where applicable, using [./delta_encoder_algorithm.wiki | delta compression]. The combination of zlib and delta compression results in a considerable space savings. For the SQLite project, at the time of this writing, | | | | > | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | of the artifacts that comprise the [./fileformat.wiki | enduring, global, shared state] of the project. The artifacts are stored as BLOBs, compressed using [http://www.zlib.net/ | zlib compression] and, where applicable, using [./delta_encoder_algorithm.wiki | delta compression]. The combination of zlib and delta compression results in a considerable space savings. For the SQLite project, at the time of this writing, the total size of all artifacts is over 2.0 GB but thanks to the combined zlib and delta compression, that content only takes up 32 MB of space in the repository database, for a compression ratio of about 64:1. The average size of a content BLOB in the database is around 500 bytes. Note that the zlib and delta compression is not an inherent part of the Fossil file format; it is just an optimization. The enduring file format for Fossil is the unordered set of artifacts. The compression techniques are just a detail of how the current implementation of Fossil happens to store these artifacts efficiently on disk. |
| ︙ | ︙ | |||
183 184 185 186 187 188 189 | works by reading the input git-fast-export stream and using it to construct corresponding artifacts which are then written into the repository database. <h4>2.2.2 Project Metadata</h4> The global project state information in the repository database is supplemented by computed metadata that makes querying the project state | | | | | 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 |
works by reading the input git-fast-export stream and using it to construct
corresponding artifacts which are then written into the repository database.
<h4>2.2.2 Project Metadata</h4>
The global project state information in the repository database is
supplemented by computed metadata that makes querying the project state
more efficient. Metadata includes information such as the following:
* The names for all files found in any checkin.
* All check-ins that modify a given file
* Parents and children of each checkin.
* Potential timeline rows.
* The names of all symbolic tags and the checkins they apply to.
* The names of all wiki pages and the artifacts that comprise each
wiki page.
* Attachments and the wiki pages or tickets they apply to.
* Current content of each ticket.
* Cross-references between tickets, checkins, and wiki pages.
The metadata is held in various SQL tables in the repository database.
The metadata is designed to facilitate queries for the various timelines and
reports that Fossil generates.
As the functionality of Fossil evolves,
the schema for the metadata can and does change.
But schema changes do no invalidate the repository. Remember that the
metadata contains no new information - only information that has been
extracted from the canonical artifacts and saved in a more useful form.
Hence, when the metadata schema changes, the prior metadata can be discarded
and the entire metadata corpus can be recomputed from the canonical
artifacts. That is what the
[/help/rebuild | fossil rebuild] command does.
|
| ︙ | ︙ | |||
271 272 273 274 275 276 277 | privileges on the remote repository. <h4>2.2.5 Shunned Artifact List</h4> The set of canonical artifacts for a project - the global state for the project - is intended to be an append-only database. In other words, new artifacts can be added but artifacts can never be removed. But | | | | | | | | 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 |
privileges on the remote repository.
<h4>2.2.5 Shunned Artifact List</h4>
The set of canonical artifacts for a project - the global state for the
project - is intended to be an append-only database. In other words,
new artifacts can be added but artifacts can never be removed. But
it sometimes happens that inappropriate content is mistakenly or
maliciously added to a repository. The only way to get rid of
the undesired content is to [./shunning.wiki | "shun"] it.
The "shun" table in the repository database records the SHA1 hash of
all shunned artifacts.
The shun table can be pushed or pulled using
the [/help/config | fossil config] command with the "shun" AREA argument.
The shun table is also copied during a [/help/clone | clone].
<h3>2.3 Checkout Databases</h3>
Unlike several other popular DVCSes, Fossil allows a single repository
to have multiple working checkouts. Each working checkout has a single
database in its root directory that records the state of that checkout.
The checkout database is named "_FOSSIL_" by default, but can be renamed
to ".fslckout" if desired. (Future versions of Fossil might make
".fslckout" the default name.) The checkout database records information
such as the following:
* The full pathname of the repository database file.
* The version that is currently checked out.
* Files that have been [/help/add | added],
[/help/rm | removed], or [/help/mv | renamed] but not
yet committed.
* The mtime and size of files as they were originally checked out,
|
| ︙ | ︙ |