Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Updating from trunk to get the latest trunk fixes. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | annotate_links |
| Files: | files | file ages | folders |
| SHA1: |
b7f3a32d4e67a900c0ac5e9b2bec23d4 |
| User & Date: | viriketo 2012-04-04 16:20:14.923 |
Context
|
2012-04-05
| ||
| 14:05 | I make 'merge --baseline' not introduce a new parent in the merge checkin. I think it should behave like --cherrypick. check-in: ba402f33b2 user: viriketo tags: annotate_links | |
|
2012-04-04
| ||
| 16:20 | Updating from trunk to get the latest trunk fixes. check-in: b7f3a32d4e user: viriketo tags: annotate_links | |
| 16:19 | Fixing a jump on uninitialized data on web sbs diff. Noticed after having seen text file corruption in the web SBS, and traced by valgrind. check-in: 92b2a5c390 user: viriketo tags: annotate_links | |
|
2012-04-02
| ||
| 01:19 | Fix a bug in the previous check-in. check-in: b65ed0b106 user: drh tags: trunk | |
Changes
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;
}
});
|
| ︙ | ︙ | |||
237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
(function runAllTests(){
var testList = [
testHAI,
testIAmNobody,
testAnonymousLogin,
testAnonWiki,
testAnonLogout,
testExternalProcess,
testExternalProcessHandler
];
var i, f;
for( i = 0; i < testList.length; ++i ){
f = testList[i];
| > | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
(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];
|
| ︙ | ︙ |
Changes to ajax/index.html.
| ︙ | ︙ | |||
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
<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/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")' />
<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")' />
|
| ︙ | ︙ |
Changes to src/add.c.
| ︙ | ︙ | |||
239 240 241 242 243 244 245 |
/* 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) ){
|
| ︙ | ︙ |
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/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
|
| ︙ | ︙ |
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 ){
|
| ︙ | ︙ | |||
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);
|
| ︙ | ︙ | |||
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 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 |
}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...?
**
** Create a new version containing all of the changes in the current
** checkout. You will be prompted to enter a check-in comment unless
** the comment has been specified on the command-line using "-m" or a
** file containing the comment using -M. The editor defined in the
** "editor" fossil option (see %fossil help set) will be used, or from
** the "VISUAL" or "EDITOR" environment variables (in that order) if
** no editor is set.
**
** All files that have changed will be committed unless some subset of
** files is specified on the command line.
**
** The --branch option followed by a branch name causes the new
** check-in to be placed in a newly-created branch with the name
** passed to the --branch option.
**
** Use the --branchcolor option followed by a color name (ex:
** '#ffc0c0') to specify the background color of entries in the new
** branch when shown in the web timeline interface. The use of
** the --branchcolor option is not recommend. Instead, let Fossil
** choose the branch color automatically.
**
** The --bgcolor option works like --branchcolor but only sets the
** background color for a single check-in. Subsequent check-ins revert
** to the default color.
**
** A check-in is not permitted to fork unless the --force or -f
** option appears. A check-in is not allowed against a closed leaf.
**
** The --private option creates a private check-in that is never synced.
** Children of private check-ins are automatically private.
**
** the --tag option applies the symbolic tag name to the check-in.
**
** Options:
** --baseline use a baseline manifest in the commit process
** --bgcolor COLOR apply 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 */ | | > > | > | > | > > > > > | > > > > > > > | 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 |
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,
| | > | > | 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 1197 1198 1199 1200 1201 1202 1203 1204 1205 |
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.
| ︙ | ︙ | |||
148 149 150 151 152 153 154 |
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.
| ︙ | ︙ | |||
76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
int groupMask; /* Which config groups is it part of */
} aConfig[] = {
{ "css", CONFIGSET_SKIN },
{ "header", CONFIGSET_SKIN },
{ "footer", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", 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 },
| > > > > > > > > > | < < < < < > > > > > | 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 |
int groupMask; /* Which config groups is it part of */
} aConfig[] = {
{ "css", CONFIGSET_SKIN },
{ "header", CONFIGSET_SKIN },
{ "footer", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "index-page", CONFIGSET_SKIN },
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
#endif
{ "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 },
{ "@reportfmt", CONFIGSET_TKT },
{ "@user", CONFIGSET_USER },
{ "@concealed", CONFIGSET_ADDR },
{ "@shun", CONFIGSET_SHUN },
{ "xfer-common-script", CONFIGSET_XFER },
{ "xfer-push-script", CONFIGSET_XFER },
};
static int iConfig = 0;
/*
** Return name of first configuration property matching the given mask.
*/
const char *configure_first_name(int iMask){
|
| ︙ | ︙ |
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).
|
| ︙ | ︙ | |||
2208 2209 2210 2211 2212 2213 2214 | 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 | | > | < < | 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 |
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";
|
| ︙ | ︙ | |||
2246 2247 2248 2249 2250 2251 2252 |
assert( 0 == extra );
def = cson_value_double_empty;
tx = sizeof(cson_double_t);
reason = "cson_value:double";
break;
case CSON_TYPE_INTEGER:
assert( 0 == extra );
| < < < < < > > | 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 |
assert( 0 == extra );
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";
|
| ︙ | ︙ | |||
2646 2647 2648 2649 2650 2651 2652 |
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;
|
| ︙ | ︙ | |||
2861 2862 2863 2864 2865 2866 2867 |
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;
}
}
|
| ︙ | ︙ | |||
3140 3141 3142 3143 3144 3145 3146 |
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... */
|
| ︙ | ︙ | |||
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 |
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 );
|
| ︙ | ︙ | |||
3359 3360 3361 3362 3363 3364 3365 |
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 )
|
| ︙ | ︙ | |||
3382 3383 3384 3385 3386 3387 3388 |
;
++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 )
{
|
| ︙ | ︙ | |||
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;
|
| ︙ | ︙ | |||
5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 |
int rc = sqlite3_prepare_v2( db, sql, -1, &st, NULL );
if( 0 != rc ) return cson_rc.IOError /* FIXME: Better error code? */;
rc = cson_sqlite3_stmt_to_json( st, tgt, fat );
sqlite3_finalize( st );
return rc;
}
}
#if defined(__cplusplus)
} /*extern "C"*/
#endif
#undef MARKER
#endif /* CSON_ENABLE_SQLITE3 */
/* end file ./cson_sqlite3.c */
#endif /* FOSSIL_ENABLE_JSON */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 |
int rc = sqlite3_prepare_v2( db, sql, -1, &st, NULL );
if( 0 != rc ) return cson_rc.IOError /* FIXME: Better error code? */;
rc = cson_sqlite3_stmt_to_json( st, tgt, fat );
sqlite3_finalize( st );
return rc;
}
}
int cson_sqlite3_bind_value( sqlite3_stmt * st, int ndx, cson_value const * v )
{
int rc = 0;
char convertErr = 0;
if(!st) return cson_rc.ArgError;
else if( ndx < 1 ) {
rc = cson_rc.RangeError;
}
else if( cson_value_is_array(v) ){
cson_array * ar = cson_value_get_array(v);
unsigned int len = cson_array_length_get(ar);
unsigned int i;
assert(NULL != ar);
for( i = 0; !rc && (i < len); ++i ){
rc = cson_sqlite3_bind_value( st, (int)i+ndx,
cson_array_get(ar, i));
}
}
else if(!v || cson_value_is_null(v)){
rc = sqlite3_bind_null(st,ndx);
convertErr = 1;
}
else if( cson_value_is_double(v) ){
rc = sqlite3_bind_double( st, ndx, cson_value_get_double(v) );
convertErr = 1;
}
else if( cson_value_is_bool(v) ){
rc = sqlite3_bind_int( st, ndx, cson_value_get_bool(v) ? 1 : 0 );
convertErr = 1;
}
else if( cson_value_is_integer(v) ){
rc = sqlite3_bind_int64( st, ndx, cson_value_get_integer(v) );
convertErr = 1;
}
else if( cson_value_is_string(v) ){
cson_string const * s = cson_value_get_string(v);
rc = sqlite3_bind_text( st, ndx,
cson_string_cstr(s),
cson_string_length_bytes(s),
SQLITE_TRANSIENT);
convertErr = 1;
}
else {
rc = cson_rc.TypeError;
}
if(convertErr && rc) switch(rc){
case SQLITE_TOOBIG:
case SQLITE_RANGE: rc = cson_rc.RangeError; break;
case SQLITE_NOMEM: rc = cson_rc.AllocError; break;
case SQLITE_IOERR: rc = cson_rc.IOError; break;
default: rc = cson_rc.UnknownError; break;
};
return rc;
}
#if defined(__cplusplus)
} /*extern "C"*/
#endif
#undef MARKER
#endif /* CSON_ENABLE_SQLITE3 */
/* end file ./cson_sqlite3.c */
#endif /* FOSSIL_ENABLE_JSON */
|
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
|
| ︙ | ︙ | |||
2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 |
/**
A convenience wrapper around cson_sqlite3_stmt_to_json(), which
takes SQL instead of a sqlite3_stmt object. It has the same
return value and argument semantics as that function.
*/
int cson_sqlite3_sql_to_json( sqlite3 * db, cson_value ** tgt, char const * sql, char fat );
#if defined(__cplusplus)
} /*extern "C"*/
#endif
#endif /* CSON_ENABLE_SQLITE3 */
#endif /* WANDERINGHORSE_NET_CSON_SQLITE3_H_INCLUDED */
/* end file include/wh/cson/cson_sqlite3.h */
#endif /* FOSSIL_ENABLE_JSON */
| > > > > > > > > > > > > > > > > > > > | 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 |
/**
A convenience wrapper around cson_sqlite3_stmt_to_json(), which
takes SQL instead of a sqlite3_stmt object. It has the same
return value and argument semantics as that function.
*/
int cson_sqlite3_sql_to_json( sqlite3 * db, cson_value ** tgt, char const * sql, char fat );
/**
Binds a JSON value to a 1-based parameter index in a prepared SQL
statement. v must be NULL or one of one of the types (null, string,
integer, double, boolean, array). Booleans are bound as integer 0
or 1. NULL or null are bound as SQL NULL. Integers are bound as
64-bit ints. Strings are bound using sqlite3_bind_text() (as
opposed to text16), but we could/should arguably bind them as
blobs.
If v is an Array then ndx is is used as a starting position
(1-based) and each item in the array is bound to the next parameter
position (starting and ndx, though the array uses 0-based offsets).
TODO: add Object support for named parameters.
Returns 0 on success, non-0 on error.
*/
int cson_sqlite3_bind_value( sqlite3_stmt * st, int ndx, cson_value const * v );
#if defined(__cplusplus)
} /*extern "C"*/
#endif
#endif /* CSON_ENABLE_SQLITE3 */
#endif /* WANDERINGHORSE_NET_CSON_SQLITE3_H_INCLUDED */
/* end file include/wh/cson/cson_sqlite3.h */
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/db.c.
| ︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 |
if( g.argc!=3 ){
usage("PATHNAME");
}
if( db_open_local()==0 ){
fossil_fatal("not in a local checkout");
return;
}
| | | 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
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);
|
| ︙ | ︙ | |||
1696 1697 1698 1699 1700 1701 1702 |
*/
void db_record_repository_filename(const char *zName){
Blob full;
if( zName==0 ){
if( !g.localOpen ) return;
zName = db_repository_filename();
}
| | > > | > | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 |
*/
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
|
| ︙ | ︙ | |||
1747 1748 1749 1750 1751 1752 1753 |
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);
}
| | | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 |
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"
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
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;
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;
}
| > | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 |
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;
}
|
| ︙ | ︙ | |||
884 885 886 887 888 889 890 891 892 893 894 895 896 897 | 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 */ s.zLine = fossil_malloc( 10*width + 200 ); if( s.zLine==0 ) return; s.width = width; s.escHtml = escHtml; s.iStart = -1; s.iStart2 = 0; s.iEnd = -1; | > | 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 | 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.iStart2 = 0; s.iEnd = -1; |
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
**
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>
/*
** 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);
| > > > > > > > > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
**
** 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);
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
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 ){
| | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
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;
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
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);
| | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
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; }
|
| ︙ | ︙ |
Changes to src/doc.c.
| ︙ | ︙ | |||
602 603 604 605 606 607 608 |
if( blob_size(&logo)==0 ){
blob_init(&logo, (char*)aLogo, sizeof(aLogo));
}
cgi_set_content_type(zMime);
cgi_set_content(&logo);
g.isConst = 1;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
if( blob_size(&logo)==0 ){
blob_init(&logo, (char*)aLogo, sizeof(aLogo));
}
cgi_set_content_type(zMime);
cgi_set_content(&logo);
g.isConst = 1;
}
/*
** The default background image: a 16x16 white GIF
*/
static const unsigned char aBackground[] = {
71, 73, 70, 56, 57, 97, 16, 0, 16, 0,
240, 0, 0, 255, 255, 255, 0, 0, 0, 33,
254, 4, 119, 105, 115, 104, 0, 44, 0, 0,
0, 0, 16, 0, 16, 0, 0, 2, 14, 132,
143, 169, 203, 237, 15, 163, 156, 180, 218, 139,
179, 62, 5, 0, 59,
};
/*
** WEBPAGE: background
**
** Return the background image.
*/
void background_page(void){
Blob bgimg;
char *zMime;
zMime = db_get("background-mimetype", "image/gif");
blob_zero(&bgimg);
db_blob(&bgimg, "SELECT value FROM config WHERE name='background-image'");
if( blob_size(&bgimg)==0 ){
blob_init(&bgimg, (char*)aBackground, sizeof(aBackground));
}
cgi_set_content_type(zMime);
cgi_set_content(&bgimg);
g.isConst = 1;
}
|
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.
|
| ︙ | ︙ | |||
604 605 606 607 608 609 610 611 | /* ** 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 / */ | > > | > > > > > > > > > > > > > > > > > > > > | > | | 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 |
/*
** 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));
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 | 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;
|
| ︙ | ︙ | |||
751 752 753 754 755 756 757 |
** 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.
|
| ︙ | ︙ | |||
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
}
/*
** 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.
|
| ︙ | ︙ | |||
896 897 898 899 900 901 902 903 904 905 906 907 908 909 |
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.
|
| ︙ | ︙ | |||
928 929 930 931 932 933 934 | /************************************************************************** ** 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){
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
488 489 490 491 492 493 494 | } /* ** 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 |
| ︙ | ︙ | |||
510 511 512 513 514 515 516 |
}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{
|
| ︙ | ︙ | |||
539 540 541 542 543 544 545 | } /* ** 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. ** |
| ︙ | ︙ | |||
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
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;
}
/*
| > > > | | 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 |
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);
}
|
| ︙ | ︙ | |||
600 601 602 603 604 605 606 |
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);
|
| ︙ | ︙ | |||
776 777 778 779 780 781 782 |
}
}
}
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;
}
|
| ︙ | ︙ | |||
977 978 979 980 981 982 983 | /* ** 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 );
|
| ︙ | ︙ | |||
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 |
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{
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
| > > > > > > > | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
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
|
| ︙ | ︙ | |||
1216 1217 1218 1219 1220 1221 1222 |
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() );
}
|
| ︙ | ︙ | |||
1332 1333 1334 1335 1336 1337 1338 |
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){
| > | > | | 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 |
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
|
| ︙ | ︙ | |||
1473 1474 1475 1476 1477 1478 1479 | ** 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. ** */ | | | | | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 |
** 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);
|
| ︙ | ︙ | |||
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 |
}
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));
| > > > > > > > > > > > > > > > > > > > > | 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 |
}
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));
|
| ︙ | ︙ | |||
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 |
/*
** 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).
*/
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);
| > > > | 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 |
/*
** 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);
|
| ︙ | ︙ | |||
1811 1812 1813 1814 1815 1816 1817 |
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) ); \
|
| ︙ | ︙ | |||
1886 1887 1888 1889 1890 1891 1892 | 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
|
| ︙ | ︙ | |||
2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 |
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 |
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;
|
| ︙ | ︙ | |||
2184 2185 2186 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 |
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();
/* Impl in json_config.c. */
cson_value * json_page_config();
/*
** 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},
| > > > > > | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
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().
**
|
| ︙ | ︙ | |||
2293 2294 2295 2296 2297 2298 2299 |
rc = FSL_JSON_E_WRONG_MODE;
}
else{
rc = 0;
g.json.dispatchDepth = 1;
payload = (*pageDef->func)();
}
| | < < | < < < < < | | < < < | | | > > > > > > > > > > > > > > > > | | < > > < < < > | 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 |
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) )
|
| ︙ | ︙ | |||
2395 2396 2397 2398 2399 2400 2401 |
e.g. add g.errCode.
*/
fossil_exit(1);
}
return;
usage:
{
| | | | | | | | | 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 |
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.
| ︙ | ︙ | |||
79 80 81 82 83 84 85 |
** 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;
| | | | | | > | | < | | | < < < < > > > > > > > > | | < < < < < < < < < < < < < < < < < < < < < | 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 |
** 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){
|
| ︙ | ︙ | |||
221 222 223 224 225 226 227 |
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);
}
}
/*
|
| ︙ | ︙ | |||
256 257 258 259 260 261 262 |
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;
|
| ︙ | ︙ | |||
404 405 406 407 408 409 410 |
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 */
|
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.
|
| ︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
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){
|
| ︙ | ︙ | |||
107 108 109 110 111 112 113 |
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.
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
"Missing or invalid 'report' (-r) parameter.");
return NULL;
}
db_prepare(&q,"SELECT rn AS report,"
" owner AS owner,"
" title AS title,"
| | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
"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){
|
| ︙ | ︙ | |||
459 460 461 462 463 464 465 |
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) )){
|
| ︙ | ︙ | |||
516 517 518 519 520 521 522 |
** 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);
|
| ︙ | ︙ | |||
648 649 650 651 652 653 654 |
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 | ** 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 |
| ︙ | ︙ | |||
195 196 197 198 199 200 201 202 203 204 205 206 |
#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(!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.");
}
| > | | | > | | > | | > | | > > | | | > | > | | < | | | | | | | | | | | | > | > > > > > > | > > > > > > > > | | | | | > > > > > > > > > > | > < > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
#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;
|
| ︙ | ︙ | |||
354 355 356 357 358 359 360 |
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;
| | | | | | < | | 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 |
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 |
#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. */
|
| ︙ | ︙ | |||
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
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));
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;
}
| > > > > > | | | | 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 |
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);
}
|
| ︙ | ︙ | |||
339 340 341 342 343 344 345 |
/*
** 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 |
/*
** 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);
char fInvert = json_find_option_bool("invert",NULL,"i",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 %s GLOB %Q",
fInvert ? "NOT" : "", zGlob);
}else{
zGlob = json_find_option_cstr("like",NULL,"l");
if(zGlob && *zGlob){
blob_appendf(&sql," AND name %s LIKE %Q",
fInvert ? "NOT" : "",
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);
|
| ︙ | ︙ | |||
382 383 384 385 386 387 388 389 | assert(0 != g.json.resultCode); cson_value_free(listV); listV = NULL; end: db_finalize(&q); return listV; } #endif /* FOSSIL_ENABLE_JSON */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
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
|
| ︙ | ︙ | |||
928 929 930 931 932 933 934 | } } /* ** Flags passed into the 2nd argument of login_set/replace_capabilities(). */ #if INTERFACE | | < | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 |
}
}
/*
** Flags passed into the 2nd argument of login_set/replace_capabilities().
*/
#if INTERFACE
#define LOGIN_IGNORE_UV 0x01 /* Ignore "u" and "v" */
#endif
/*
** Adds all capability flags in zCap to g.perm.
*/
void login_set_capabilities(const char *zCap, unsigned flags){
int i;
|
| ︙ | ︙ | |||
976 977 978 979 980 981 982 |
case 't': g.perm.TktFmt = 1; break;
case 'b': g.perm.Attach = 1; break;
case 'x': g.perm.Private = 1; break;
/* The "u" privileges is a little different. It recursively
** inherits all privileges of the user named "reader" */
case 'u': {
| | | | | | 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 |
case 't': g.perm.TktFmt = 1; break;
case 'b': g.perm.Attach = 1; break;
case 'x': g.perm.Private = 1; break;
/* The "u" privileges is a little different. It recursively
** inherits all privileges of the user named "reader" */
case 'u': {
if( (flags & LOGIN_IGNORE_UV)==0 ){
const char *zUser;
zUser = db_text("", "SELECT cap FROM user WHERE login='reader'");
login_set_capabilities(zUser, flags | LOGIN_IGNORE_UV);
}
break;
}
/* The "v" privileges is a little different. It recursively
** inherits all privileges of the user named "developer" */
case 'v': {
if( (flags & LOGIN_IGNORE_UV)==0 ){
const char *zDev;
zDev = db_text("", "SELECT cap FROM user WHERE login='developer'");
login_set_capabilities(zDev, flags | LOGIN_IGNORE_UV);
}
break;
}
}
}
}
|
| ︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 |
* this %s(zUsername), or at least I don't know how to force it to.*/
@ <p><span class="loginError">
@ %s(zUsername) already exists.
@ </span></p>
}else{
char *zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login), 0);
int uid;
| < < < < < < < < < | < < < < < < < < | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 |
* this %s(zUsername), or at least I don't know how to force it to.*/
@ <p><span class="loginError">
@ %s(zUsername) already exists.
@ </span></p>
}else{
char *zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login), 0);
int uid;
db_multi_exec(
"INSERT INTO user(login,pw,cap,info)"
"VALUES(%B,%Q,%B,%B)",
&login, zPw, &caps, &contact
);
free(zPw);
/* The user is registered, now just log him in. */
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUsername);
login_set_user_cookie( zUsername, uid, NULL );
redirect_to_g();
}
}
}
/* Prepare the captcha. */
|
| ︙ | ︙ | |||
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 */
| | | | 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 |
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.
| ︙ | ︙ | |||
444 445 446 447 448 449 450 |
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"
| | < | | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
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) ){
|
| ︙ | ︙ | |||
1525 1526 1527 1528 1529 1530 1531 |
** 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 |
** 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:
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 62 63 64 65 66 | $(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_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 \ | > > | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | $(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 \ |
| ︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | $(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_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 \ | > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | $(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 \ |
| ︙ | ︙ | |||
247 248 249 250 251 252 253 254 255 256 257 258 259 260 | $(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_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 \ | > > | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | $(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 \ |
| ︙ | ︙ | |||
366 367 368 369 370 371 372 | 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 |
| ︙ | ︙ | |||
672 673 674 675 676 677 678 679 680 681 682 683 684 685 | $(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 | > > > > > > > > > > > > > > | 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_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.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 63 64 65 66 67 68 69 | import info json json_artifact json_branch json_config json_diff json_login json_query json_report json_tag json_timeline json_user json_wiki | > > | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 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 |
| ︙ | ︙ | |||
256 257 258 259 260 261 262 | 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"
|
| ︙ | ︙ | |||
465 466 467 468 469 470 471 | #### 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 |
| ︙ | ︙ | |||
608 609 610 611 612 613 614 |
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"
|
| ︙ | ︙ | |||
665 666 667 668 669 670 671 | #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"
|
| ︙ | ︙ | |||
752 753 754 755 756 757 758 759 760 761 762 763 764 765 | -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_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 | > > | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | -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 |
| ︙ | ︙ | |||
910 911 912 913 914 915 916 917 918 919 920 921 922 923 | -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_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 | > > | 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 | -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/merge3.c.
| ︙ | ︙ | |||
400 401 402 403 404 405 406 |
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 ){
| < < | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
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);
}
|
| ︙ | ︙ |
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;
|
| ︙ | ︙ | |||
271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
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){
| > > > > > > > > > > > > > > > > > > > > | 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 |
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){
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
82 83 84 85 86 87 88 |
setup_menu_entry("CSS", "setup_editcss",
"Edit the Cascading Style Sheet used by all pages of this repository");
setup_menu_entry("Header", "setup_header",
"Edit HTML text inserted at the top of every page");
setup_menu_entry("Footer", "setup_footer",
"Edit HTML text inserted at the bottom of every page");
setup_menu_entry("Logo", "setup_logo",
| | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
setup_menu_entry("CSS", "setup_editcss",
"Edit the Cascading Style Sheet used by all pages of this repository");
setup_menu_entry("Header", "setup_header",
"Edit HTML text inserted at the top of every page");
setup_menu_entry("Footer", "setup_footer",
"Edit HTML text inserted at the bottom of every page");
setup_menu_entry("Logo", "setup_logo",
"Change the logo and background images for the server");
setup_menu_entry("Shunned", "shun",
"Show artifacts that are shunned by this repository");
setup_menu_entry("Log", "rcvfromlist",
"A record of received artifacts and their sources");
setup_menu_entry("User-Log", "access_log",
"A record of login attempts");
setup_menu_entry("Stats", "stat",
|
| ︙ | ︙ | |||
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);
}
|
| ︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 |
db_end_transaction(0);
}
/*
** WEBPAGE: setup_logo
*/
void setup_logo(void){
| | > > > | | > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > | | | > | | | | > > > | > > > > > > > > > > > > > > > > > > > | < | | > | | > | | < | | 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 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 |
db_end_transaction(0);
}
/*
** WEBPAGE: setup_logo
*/
void setup_logo(void){
const char *zLogoMime = db_get("logo-mimetype","image/gif");
const char *aLogoImg = P("logoim");
int szLogoImg = atoi(PD("logoim:bytes","0"));
const char *zBgMime = db_get("background-mimetype","image/gif");
const char *aBgImg = P("bgim");
int szBgImg = atoi(PD("bgim:bytes","0"));
if( szLogoImg>0 ){
zLogoMime = PD("logoim:mimetype","image/gif");
}
if( szBgImg>0 ){
zBgMime = PD("bgim:mimetype","image/gif");
}
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
db_begin_transaction();
if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
Blob img;
Stmt ins;
blob_init(&img, aLogoImg, szLogoImg);
db_prepare(&ins,
"REPLACE INTO config(name,value,mtime)"
" VALUES('logo-image',:bytes,now())"
);
db_bind_blob(&ins, ":bytes", &img);
db_step(&ins);
db_finalize(&ins);
db_multi_exec(
"REPLACE INTO config(name,value,mtime) VALUES('logo-mimetype',%Q,now())",
zLogoMime
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}else if( P("clrlogo")!=0 ){
db_multi_exec(
"DELETE FROM config WHERE name IN "
"('logo-image','logo-mimetype')"
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}else if( P("setbg")!=0 && zBgMime && zBgMime[0] && szBgImg>0 ){
Blob img;
Stmt ins;
blob_init(&img, aBgImg, szBgImg);
db_prepare(&ins,
"REPLACE INTO config(name,value,mtime)"
" VALUES('background-image',:bytes,now())"
);
db_bind_blob(&ins, ":bytes", &img);
db_step(&ins);
db_finalize(&ins);
db_multi_exec(
"REPLACE INTO config(name,value,mtime)"
" VALUES('background-mimetype',%Q,now())",
zBgMime
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}else if( P("clrbg")!=0 ){
db_multi_exec(
"DELETE FROM config WHERE name IN "
"('background-image','background-mimetype')"
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}
style_header("Edit Project Logo And Background");
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
@ and looks like this:</p>
@ <blockquote><p><img src="%s(g.zTop)/logo" alt="logo" border="1" />
@ </p></blockquote>
@
@ <form action="%s(g.zTop)/setup_logo" method="post"
@ enctype="multipart/form-data"><div>
@ <p>The logo is accessible to all users at this URL:
@ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
@ The logo may or may not appear on each
@ page depending on the <a href="setup_editcss">CSS</a> and
@ <a href="setup_header">header setup</a>.
@ To change the logo image, use the following form:</p>
login_insert_csrf_secret();
@ Logo Image file:
@ <input type="file" name="logoim" size="60" accept="image/*" />
@ <p align="center">
@ <input type="submit" name="setlogo" value="Change Logo" />
@ <input type="submit" name="clrlogo" value="Revert To Default" /></p>
@ </div></form>
@ <hr />
@
@ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b>
@ and looks like this:</p>
@ <blockquote><p><img src="%s(g.zTop)/background" alt="background" border=1 />
@ </p></blockquote>
@
@ <form action="%s(g.zTop)/setup_logo" method="post"
@ enctype="multipart/form-data"><div>
@ <p>The background image is accessible to all users at this URL:
@ <a href="%s(g.zBaseURL)/background">%s(g.zBaseURL)/background</a>.
@ The background image may or may not appear on each
@ page depending on the <a href="setup_editcss">CSS</a> and
@ <a href="setup_header">header setup</a>.
@ To change the background image, use the following form:</p>
login_insert_csrf_secret();
@ Background image file:
@ <input type="file" name="bgim" size="60" accept="image/*" />
@ <p align="center">
@ <input type="submit" name="setbg" value="Change Background" />
@ <input type="submit" name="clrbg" value="Revert To Default" /></p>
@ </div></form>
@ <hr />
@
@ <p><span class="note">Note:</span> Your browser has probably cached these
@ images, so you may need to press the Reload button before changes will
@ take effect. </p>
style_footer();
db_end_transaction(0);
}
|
Changes to src/shell.c.
| ︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 | # define stifle_history(X) #endif #if defined(_WIN32) || defined(WIN32) # include <io.h> #define isatty(h) _isatty(h) #define access(f,m) _access((f),(m)) #else /* Make sure isatty() has a prototype. */ extern int isatty(int); #endif #if defined(_WIN32_WCE) | > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | # define stifle_history(X) #endif #if defined(_WIN32) || defined(WIN32) # include <io.h> #define isatty(h) _isatty(h) #define access(f,m) _access((f),(m)) #define popen(a,b) _popen((a),(b)) #define pclose(x) _pclose(x) #else /* Make sure isatty() has a prototype. */ extern int isatty(int); #endif #if defined(_WIN32_WCE) |
| ︙ | ︙ | |||
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
fprintf(pArg->out, "Page cache hits: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
fprintf(pArg->out, "Page cache misses: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
}
| > > > | 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 |
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
fprintf(pArg->out, "Page cache hits: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
fprintf(pArg->out, "Page cache misses: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
fprintf(pArg->out, "Page cache writes: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
}
|
| ︙ | ︙ | |||
1283 1284 1285 1286 1287 1288 1289 |
if( strcmp(zType, "table")==0 ){
sqlite3_stmt *pTableInfo = 0;
char *zSelect = 0;
char *zTableInfo = 0;
char *zTmp = 0;
int nRow = 0;
| < | | < < < | | 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 |
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);
/* Always quote the table name, even if it appears to be pure ascii,
** in case it is a keyword. Ex: INSERT INTO "table" ... */
zTmp = appendText(zTmp, zTable, '"');
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);
|
| ︙ | ︙ | |||
1996 1997 1998 1999 2000 2001 2002 |
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
"%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
}else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
if( p->out!=stdout ){
| > > > | > > > > > > > > > > | 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 |
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
"%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
}else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
if( p->out!=stdout ){
if( p->outfile[0]=='|' ){
pclose(p->out);
}else{
fclose(p->out);
}
}
if( strcmp(azArg[1],"stdout")==0 ){
p->out = stdout;
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
}else if( azArg[1][0]=='|' ){
p->out = popen(&azArg[1][1], "w");
if( p->out==0 ){
fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]);
p->out = stdout;
rc = 1;
}else{
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
}
}else{
p->out = fopen(azArg[1], "wb");
if( p->out==0 ){
fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
p->out = stdout;
rc = 1;
} else {
|
| ︙ | ︙ |
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.12. 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.12" #define SQLITE_VERSION_NUMBER 3007012 #define SQLITE_SOURCE_ID "2012-03-31 19:12:23 af602d87736b52802a4e760ffeeaa28112b99d9a" /* ** 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 |
| ︙ | ︙ | |||
5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 | ** ^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 |
| ︙ | ︙ | |||
6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 | ** </dd> ** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt> ** <dd>This parameter returns the number of pager cache misses that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 | > > > > > > > > > > > > | | 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 | ** </dd> ** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt> ** <dd>This parameter returns the number of pager cache misses that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. ** </dd> ** ** [[SQLITE_DBSTATUS_CACHE_WRITE]] ^(<dt>SQLITE_DBSTATUS_CACHE_WRITE</dt> ** <dd>This parameter returns the number of dirty cache entries that have ** been written to disk. Specifically, the number of pages written to the ** wal file in wal mode databases, or the number of pages written to the ** database file in rollback mode databases. Any pages written as part of ** transaction rollback or database recovery operations are not included. ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined). ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** ** ^(Each prepared statement maintains various ** [SQLITE_STMTSTATUS counters] that measure the number |
| ︙ | ︙ | |||
7135 7136 7137 7138 7139 7140 7141 | void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** | | | | | > | 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 | 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()]. |
| ︙ | ︙ | |||
8202 8203 8204 8205 8206 8207 8208 | 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*); | | | 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 | 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); |
| ︙ | ︙ | |||
8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 | 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*); | > > > | 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 | 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*); |
| ︙ | ︙ | |||
9869 9870 9871 9872 9873 9874 9875 |
struct FuncDestructor {
int nRef;
void (*xDestroy)(void *);
void *pUserData;
};
/*
| | > > | | > > | 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 |
struct FuncDestructor {
int nRef;
void (*xDestroy)(void *);
void *pUserData;
};
/*
** Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF
** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There
** are assert() statements in the code to verify this.
*/
#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 0x10 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x20 /* Built-in coalesce() or ifnull() function */
#define SQLITE_FUNC_LENGTH 0x40 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x80 /* Built-in typeof() function */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
** used to create the initializers for the FuncDef structures.
**
** FUNCTION(zName, nArg, iArg, bNC, xFunc)
** Used to create a scalar function definition of a function zName
|
| ︙ | ︙ | |||
9904 9905 9906 9907 9908 9909 9910 | ** that accepts nArg arguments and is implemented by a call to C ** function likeFunc. Argument pArg is cast to a (void *) and made ** available as the function user-data (sqlite3_user_data()). The ** FuncDef.flags variable is set to the value passed as the flags ** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ | | > > > | 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 |
** that accepts nArg arguments and is implemented by a call to C
** function likeFunc. Argument pArg is cast to a (void *) and made
** available as the function user-data (sqlite3_user_data()). The
** FuncDef.flags variable is set to the value passed as the flags
** parameter.
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
{nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
pArg, 0, xFunc, 0, 0, #zName, 0, 0}
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
|
| ︙ | ︙ | |||
10134 10135 10136 10137 10138 10139 10140 | Select *pSelect; /* NULL for tables. Points to definition if a view. */ u16 nRef; /* Number of pointers to this Table */ u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ #ifndef SQLITE_OMIT_CHECK | | | 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 | Select *pSelect; /* NULL for tables. Points to definition if a view. */ u16 nRef; /* Number of pointers to this Table */ u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ #ifndef SQLITE_OMIT_CHECK ExprList *pCheck; /* All CHECK constraints */ #endif #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE VTable *pVTable; /* List of VTable objects. */ int nModuleArg; /* Number of arguments to the module */ |
| ︙ | ︙ | |||
10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 |
** TK_TRIGGER: 1 -> new, 0 -> old */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
** TK_VARIABLE: variable number (always >= 1). */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
u8 flags2; /* Second set of flags. EP2_... */
u8 op2; /* If a TK_REGISTER, the original value of Expr.op */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
int nHeight; /* Height of the tree headed by this node */
#endif
};
| > | 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 |
** TK_TRIGGER: 1 -> new, 0 -> old */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
** TK_VARIABLE: variable number (always >= 1). */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
u8 flags2; /* Second set of flags. EP2_... */
u8 op2; /* If a TK_REGISTER, the original value of Expr.op */
/* If TK_COLUMN, the value of p5 for OP_Column */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
int nHeight; /* Height of the tree headed by this node */
#endif
};
|
| ︙ | ︙ | |||
10549 10550 10551 10552 10553 10554 10555 | #define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x0040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */ #define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */ #define EP_FixedDest 0x0200 /* Result needed in a specific register */ #define EP_IntValue 0x0400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */ | | | 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 | #define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x0040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */ #define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */ #define EP_FixedDest 0x0200 /* Result needed in a specific register */ #define EP_IntValue 0x0400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Hint 0x1000 /* Not used */ #define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */ #define EP_Static 0x8000 /* Held in memory not obtained from malloc() */ /* ** The following are the meanings of bits in the Expr.flags2 field. */ |
| ︙ | ︙ | |||
11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 | 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. */ | > | 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 | 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 */ Token constraintName;/* Name of the constraint currently being parsed */ #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. */ |
| ︙ | ︙ | |||
11136 11137 11138 11139 11140 11141 11142 |
*/
struct AuthContext {
const char *zAuthContext; /* Put saved Parse.zAuthContext here */
Parse *pParse; /* The Parse structure */
};
/*
| | > > | 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 |
*/
struct AuthContext {
const char *zAuthContext; /* Put saved Parse.zAuthContext here */
Parse *pParse; /* The Parse structure */
};
/*
** Bitfield flags for P5 value in various opcodes.
*/
#define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */
#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND 0x08 /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */
#define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
/*
* Each trigger present in the database schema is stored as an instance of
* struct Trigger.
*
* Pointers to instances of struct Trigger are stored in two ways.
* 1. In the "trigHash" hash table (part of the sqlite3* that represents the
|
| ︙ | ︙ | |||
11413 11414 11415 11416 11417 11418 11419 | # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) #endif /* ** Internal function prototypes */ | | | 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 | # 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); |
| ︙ | ︙ | |||
11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 |
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*);
| > | 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 |
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*);
|
| ︙ | ︙ | |||
11626 11627 11628 11629 11630 11631 11632 | #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *); #endif SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); | | | 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 | #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *, char *); #endif SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int); SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); |
| ︙ | ︙ | |||
11660 11661 11662 11663 11664 11665 11666 | 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); | | | 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 | 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 *); |
| ︙ | ︙ | |||
13458 13459 13460 13461 13462 13463 13464 |
/*
** Set *pCurrent to the total cache hits or misses encountered by all
** pagers the database handle is connected to. *pHighwater is always set
** to zero.
*/
case SQLITE_DBSTATUS_CACHE_HIT:
| | > > | 13530 13531 13532 13533 13534 13535 13536 13537 13538 13539 13540 13541 13542 13543 13544 13545 13546 13547 13548 13549 |
/*
** Set *pCurrent to the total cache hits or misses encountered by all
** pagers the database handle is connected to. *pHighwater is always set
** to zero.
*/
case SQLITE_DBSTATUS_CACHE_HIT:
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
int i;
int nRet = 0;
assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt ){
Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
}
}
|
| ︙ | ︙ | |||
21208 21209 21210 21211 21212 21213 21214 | /* Convenient short-hand */ #define UpperToLower sqlite3UpperToLower /* ** Some systems have stricmp(). Others have strcasecmp(). Because ** there is no consistency, we will define our own. ** | | > | | | < | | 21282 21283 21284 21285 21286 21287 21288 21289 21290 21291 21292 21293 21294 21295 21296 21297 21298 21299 21300 21301 21302 |
/* Convenient short-hand */
#define UpperToLower sqlite3UpperToLower
/*
** Some systems have stricmp(). Others have strcasecmp(). Because
** there is no consistency, we will define our own.
**
** IMPLEMENTATION-OF: R-30243-02494 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 *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){
|
| ︙ | ︙ | |||
25492 25493 25494 25495 25496 25497 25498 |
** 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;
| | | 25566 25567 25568 25569 25570 25571 25572 25573 25574 25575 25576 25577 25578 25579 25580 |
** 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 );
|
| ︙ | ︙ | |||
33676 33677 33678 33679 33680 33681 33682 33683 33684 33685 33686 33687 33688 33689 33690 33691 33692 33693 33694 33695 33696 33697 33698 33699 33700 33701 33702 33703 33704 33705 33706 33707 33708 33709 33710 33711 33712 33713 33714 33715 33716 33717 33718 |
){
osSleep(100); /* Wait a little before trying again */
}
sqlite3_free(pFile->zDeleteOnClose);
}
#endif
OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
OpenCounter(-1);
return rc ? SQLITE_OK
: winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
"winClose", pFile->zPath);
}
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
static int winRead(
sqlite3_file *id, /* File to read from */
void *pBuf, /* Write content into this buffer */
int amt, /* Number of bytes to read */
sqlite3_int64 offset /* Begin reading at this offset */
){
winFile *pFile = (winFile*)id; /* file handle */
DWORD nRead; /* Number of bytes actually read from file */
int nRetry = 0; /* Number of retrys */
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
if( seekWinFile(pFile, offset) ){
return SQLITE_FULL;
}
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
DWORD lastErrno;
if( retryIoerr(&nRetry, &lastErrno) ) continue;
pFile->lastErrno = lastErrno;
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winRead", pFile->zPath);
}
logIoerr(nRetry);
| > > > > > > > > > > > > > > | 33750 33751 33752 33753 33754 33755 33756 33757 33758 33759 33760 33761 33762 33763 33764 33765 33766 33767 33768 33769 33770 33771 33772 33773 33774 33775 33776 33777 33778 33779 33780 33781 33782 33783 33784 33785 33786 33787 33788 33789 33790 33791 33792 33793 33794 33795 33796 33797 33798 33799 33800 33801 33802 33803 33804 33805 33806 |
){
osSleep(100); /* Wait a little before trying again */
}
sqlite3_free(pFile->zDeleteOnClose);
}
#endif
OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
if( rc ){
pFile->h = NULL;
}
OpenCounter(-1);
return rc ? SQLITE_OK
: winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
"winClose", pFile->zPath);
}
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
static int winRead(
sqlite3_file *id, /* File to read from */
void *pBuf, /* Write content into this buffer */
int amt, /* Number of bytes to read */
sqlite3_int64 offset /* Begin reading at this offset */
){
#if !SQLITE_OS_WINCE
OVERLAPPED overlapped; /* The offset for ReadFile. */
#endif
winFile *pFile = (winFile*)id; /* file handle */
DWORD nRead; /* Number of bytes actually read from file */
int nRetry = 0; /* Number of retrys */
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
#if SQLITE_OS_WINCE
if( seekWinFile(pFile, offset) ){
return SQLITE_FULL;
}
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
#else
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) &&
osGetLastError()!=ERROR_HANDLE_EOF ){
#endif
DWORD lastErrno;
if( retryIoerr(&nRetry, &lastErrno) ) continue;
pFile->lastErrno = lastErrno;
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winRead", pFile->zPath);
}
logIoerr(nRetry);
|
| ︙ | ︙ | |||
33731 33732 33733 33734 33735 33736 33737 |
*/
static int winWrite(
sqlite3_file *id, /* File to write into */
const void *pBuf, /* The bytes to be written */
int amt, /* Number of bytes to write */
sqlite3_int64 offset /* Offset into the file to begin writing at */
){
| | > > > > > > > > > > > > > > > > > | > > > > > > > > | 33819 33820 33821 33822 33823 33824 33825 33826 33827 33828 33829 33830 33831 33832 33833 33834 33835 33836 33837 33838 33839 33840 33841 33842 33843 33844 33845 33846 33847 33848 33849 33850 33851 33852 33853 33854 33855 33856 33857 33858 33859 33860 33861 33862 33863 33864 33865 33866 33867 33868 33869 33870 33871 33872 33873 33874 33875 33876 33877 33878 33879 33880 33881 |
*/
static int winWrite(
sqlite3_file *id, /* File to write into */
const void *pBuf, /* The bytes to be written */
int amt, /* Number of bytes to write */
sqlite3_int64 offset /* Offset into the file to begin writing at */
){
int rc = 0; /* True if error has occured, else false */
winFile *pFile = (winFile*)id; /* File handle */
int nRetry = 0; /* Number of retries */
assert( amt>0 );
assert( pFile );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
#if SQLITE_OS_WINCE
rc = seekWinFile(pFile, offset);
if( rc==0 ){
#else
{
#endif
#if !SQLITE_OS_WINCE
OVERLAPPED overlapped; /* The offset for WriteFile. */
#endif
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
int nRem = amt; /* Number of bytes yet to be written */
DWORD nWrite; /* Bytes written by each WriteFile() call */
DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
#if !SQLITE_OS_WINCE
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
#endif
while( nRem>0 ){
#if SQLITE_OS_WINCE
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
#else
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
#endif
if( retryIoerr(&nRetry, &lastErrno) ) continue;
break;
}
if( nWrite<=0 ){
lastErrno = osGetLastError();
break;
}
#if !SQLITE_OS_WINCE
offset += nWrite;
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
#endif
aRem += nWrite;
nRem -= nWrite;
}
if( nRem>0 ){
pFile->lastErrno = lastErrno;
rc = 1;
}
|
| ︙ | ︙ | |||
38300 38301 38302 38303 38304 38305 38306 38307 38308 38309 38310 38311 38312 38313 | # 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. */ | > | 38413 38414 38415 38416 38417 38418 38419 38420 38421 38422 38423 38424 38425 38426 38427 | # 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. */ |
| ︙ | ︙ | |||
38380 38381 38382 38383 38384 38385 38386 38387 38388 38389 38390 38391 38392 38393 | 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 **********************/ | > > > > > > > | 38494 38495 38496 38497 38498 38499 38500 38501 38502 38503 38504 38505 38506 38507 38508 38509 38510 38511 38512 38513 38514 | 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 **********************/ |
| ︙ | ︙ | |||
39035 39036 39037 39038 39039 39040 39041 | int pageSize; /* Number of bytes in a page */ Pgno mxPgno; /* Maximum allowed size of the database */ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ | | | > > > > > > > > > | 39156 39157 39158 39159 39160 39161 39162 39163 39164 39165 39166 39167 39168 39169 39170 39171 39172 39173 39174 39175 39176 39177 39178 39179 39180 39181 39182 39183 39184 39185 39186 39187 39188 39189 39190 39191 39192 39193 39194 39195 39196 39197 | int pageSize; /* Number of bytes in a page */ Pgno mxPgno; /* Maximum allowed size of the database */ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ int aStat[3]; /* Total cache hits, misses and writes */ #ifdef SQLITE_TEST int nRead; /* Database pages read */ #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ #ifdef SQLITE_HAS_CODEC void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ void (*xCodecFree)(void*); /* Destructor for the codec */ void *pCodec; /* First argument to xCodec... methods */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ PCache *pPCache; /* Pointer to page cache object */ #ifndef SQLITE_OMIT_WAL Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif }; /* ** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains ** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS ** or CACHE_WRITE to sqlite3_db_status(). */ #define PAGER_STAT_HIT 0 #define PAGER_STAT_MISS 1 #define PAGER_STAT_WRITE 2 /* ** The following global variables hold counters used for ** testing purposes only. These variables do not exist in ** a non-testing build. These variables are not thread-safe. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */ |
| ︙ | ︙ | |||
41336 41337 41338 41339 41340 41341 41342 41343 41344 41345 41346 41347 41348 41349 41350 41351 41352 41353 41354 41355 41356 41357 41358 41359 41360 41361 41362 41363 |
static int pagerWalFrames(
Pager *pPager, /* Pager object */
PgHdr *pList, /* List of frames to log */
Pgno nTruncate, /* Database size after this commit */
int isCommit /* True if this is a commit */
){
int rc; /* Return code */
#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
PgHdr *p; /* For looping over pages */
#endif
assert( pPager->pWal );
assert( pList );
#ifdef SQLITE_DEBUG
/* Verify that the page list is in accending order */
for(p=pList; p && p->pDirty; p=p->pDirty){
assert( p->pgno < p->pDirty->pgno );
}
#endif
if( isCommit ){
/* If a WAL transaction is being committed, there is no point in writing
** any pages with page numbers greater than nTruncate into the WAL file.
** They will never be read by any client. So remove them from the pDirty
** list here. */
PgHdr *p;
PgHdr **ppNext = &pList;
for(p=pList; (*ppNext = p); p=p->pDirty){
| > > > | > > | > > > > | 41466 41467 41468 41469 41470 41471 41472 41473 41474 41475 41476 41477 41478 41479 41480 41481 41482 41483 41484 41485 41486 41487 41488 41489 41490 41491 41492 41493 41494 41495 41496 41497 41498 41499 41500 41501 41502 41503 41504 41505 41506 41507 41508 41509 41510 41511 41512 41513 |
static int pagerWalFrames(
Pager *pPager, /* Pager object */
PgHdr *pList, /* List of frames to log */
Pgno nTruncate, /* Database size after this commit */
int isCommit /* True if this is a commit */
){
int rc; /* Return code */
int nList; /* Number of pages in pList */
#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
PgHdr *p; /* For looping over pages */
#endif
assert( pPager->pWal );
assert( pList );
#ifdef SQLITE_DEBUG
/* Verify that the page list is in accending order */
for(p=pList; p && p->pDirty; p=p->pDirty){
assert( p->pgno < p->pDirty->pgno );
}
#endif
assert( pList->pDirty==0 || isCommit );
if( isCommit ){
/* If a WAL transaction is being committed, there is no point in writing
** any pages with page numbers greater than nTruncate into the WAL file.
** They will never be read by any client. So remove them from the pDirty
** list here. */
PgHdr *p;
PgHdr **ppNext = &pList;
nList = 0;
for(p=pList; (*ppNext = p); p=p->pDirty){
if( p->pgno<=nTruncate ){
ppNext = &p->pDirty;
nList++;
}
}
assert( pList );
}else{
nList = 1;
}
pPager->aStat[PAGER_STAT_WRITE] += nList;
if( pList->pgno==1 ) pager_write_changecounter(pList);
rc = sqlite3WalFrames(pPager->pWal,
pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
);
if( rc==SQLITE_OK && pPager->pBackup ){
PgHdr *p;
|
| ︙ | ︙ | |||
42428 42429 42430 42431 42432 42433 42434 42435 42436 42437 42438 42439 42440 42441 42442 |
*/
if( pgno==1 ){
memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
}
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
/* Update any backup objects copying the contents of this pager. */
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData);
PAGERTRACE(("STORE %d page %d hash(%08x)\n",
PAGERID(pPager), pgno, pager_pagehash(pList)));
IOTRACE(("PGOUT %p %d\n", pPager, pgno));
PAGER_INCR(sqlite3_pager_writedb_count);
| > < | 42567 42568 42569 42570 42571 42572 42573 42574 42575 42576 42577 42578 42579 42580 42581 42582 42583 42584 42585 42586 42587 42588 42589 |
*/
if( pgno==1 ){
memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
}
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
pPager->aStat[PAGER_STAT_WRITE]++;
/* Update any backup objects copying the contents of this pager. */
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData);
PAGERTRACE(("STORE %d page %d hash(%08x)\n",
PAGERID(pPager), pgno, pager_pagehash(pList)));
IOTRACE(("PGOUT %p %d\n", pPager, pgno));
PAGER_INCR(sqlite3_pager_writedb_count);
}else{
PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno));
}
pager_set_pagehash(pList);
pList = pList->pDirty;
}
|
| ︙ | ︙ | |||
43394 43395 43396 43397 43398 43399 43400 |
assert( (*ppPage)->pgno==pgno );
assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
if( (*ppPage)->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
| | | 43533 43534 43535 43536 43537 43538 43539 43540 43541 43542 43543 43544 43545 43546 43547 |
assert( (*ppPage)->pgno==pgno );
assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
if( (*ppPage)->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
pPager->aStat[PAGER_STAT_HIT]++;
return SQLITE_OK;
}else{
/* The pager cache has created a new page. Its content needs to
** be initialized. */
pPg = *ppPage;
|
| ︙ | ︙ | |||
43436 43437 43438 43439 43440 43441 43442 |
testcase( rc==SQLITE_NOMEM );
sqlite3EndBenignMalloc();
}
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
assert( pPg->pPager==pPager );
| | | 43575 43576 43577 43578 43579 43580 43581 43582 43583 43584 43585 43586 43587 43588 43589 |
testcase( rc==SQLITE_NOMEM );
sqlite3EndBenignMalloc();
}
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
assert( pPg->pPager==pPager );
pPager->aStat[PAGER_STAT_MISS]++;
rc = readDbPage(pPg);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
}
pager_set_pagehash(pPg);
}
|
| ︙ | ︙ | |||
44021 44022 44023 44024 44025 44026 44027 44028 44029 44030 44031 44032 44033 44034 |
/* If running in direct mode, write the contents of page 1 to the file. */
if( DIRECT_MODE ){
const void *zBuf;
assert( pPager->dbFileSize>0 );
CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
}
if( rc==SQLITE_OK ){
pPager->changeCountDone = 1;
}
}else{
pPager->changeCountDone = 1;
}
| > | 44160 44161 44162 44163 44164 44165 44166 44167 44168 44169 44170 44171 44172 44173 44174 |
/* If running in direct mode, write the contents of page 1 to the file. */
if( DIRECT_MODE ){
const void *zBuf;
assert( pPager->dbFileSize>0 );
CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
pPager->aStat[PAGER_STAT_WRITE]++;
}
if( rc==SQLITE_OK ){
pPager->changeCountDone = 1;
}
}else{
pPager->changeCountDone = 1;
}
|
| ︙ | ︙ | |||
44464 44465 44466 44467 44468 44469 44470 | static int a[11]; a[0] = sqlite3PcacheRefCount(pPager->pPCache); a[1] = sqlite3PcachePagecount(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize; a[4] = pPager->eState; a[5] = pPager->errCode; | | | | < > < < < < | > > > | | | 44604 44605 44606 44607 44608 44609 44610 44611 44612 44613 44614 44615 44616 44617 44618 44619 44620 44621 44622 44623 44624 44625 44626 44627 44628 44629 44630 44631 44632 44633 44634 44635 44636 44637 44638 44639 44640 44641 44642 44643 44644 44645 44646 44647 |
static int a[11];
a[0] = sqlite3PcacheRefCount(pPager->pPCache);
a[1] = sqlite3PcachePagecount(pPager->pPCache);
a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
a[4] = pPager->eState;
a[5] = pPager->errCode;
a[6] = pPager->aStat[PAGER_STAT_HIT];
a[7] = pPager->aStat[PAGER_STAT_MISS];
a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead;
a[10] = pPager->aStat[PAGER_STAT_WRITE];
return a;
}
#endif
/*
** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or
** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the
** current cache hit or miss count, according to the value of eStat. If the
** reset parameter is non-zero, the cache hit or miss count is zeroed before
** returning.
*/
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
|| eStat==SQLITE_DBSTATUS_CACHE_WRITE
);
assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS );
assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE );
assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 );
*pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT];
if( reset ){
pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0;
}
}
/*
** Return true if this is an in-memory pager.
*/
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
|
| ︙ | ︙ | |||
45235 45236 45237 45238 45239 45240 45241 45242 45243 45244 45245 45246 45247 45248 |
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
| > > > > > > > > > > > > > > | 45374 45375 45376 45377 45378 45379 45380 45381 45382 45383 45384 45385 45386 45387 45388 45389 45390 45391 45392 45393 45394 45395 45396 45397 45398 45399 45400 45401 |
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
|
| ︙ | ︙ | |||
47655 47656 47657 47658 47659 47660 47661 |
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 */
| | | 47808 47809 47810 47811 47812 47813 47814 47815 47816 47817 47818 47819 47820 47821 47822 |
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;
}
|
| ︙ | ︙ | |||
48325 48326 48327 48328 48329 48330 48331 48332 48333 48334 48335 48336 48337 48338 |
** 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
| > > > > > > > > > > > > | 48478 48479 48480 48481 48482 48483 48484 48485 48486 48487 48488 48489 48490 48491 48492 48493 48494 48495 48496 48497 48498 48499 48500 48501 48502 48503 |
** 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
|
| ︙ | ︙ | |||
51318 51319 51320 51321 51322 51323 51324 |
}
}
/* Rollback any active transaction and free the handle structure.
** The call to sqlite3BtreeRollback() drops any table-locks held by
** this handle.
*/
| | | 51483 51484 51485 51486 51487 51488 51489 51490 51491 51492 51493 51494 51495 51496 51497 |
}
}
/* 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 );
|
| ︙ | ︙ | |||
52556 52557 52558 52559 52560 52561 52562 52563 52564 52565 52566 52567 52568 52569 |
** 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++){
| > | 52721 52722 52723 52724 52725 52726 52727 52728 52729 52730 52731 52732 52733 52734 52735 |
** 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++){
|
| ︙ | ︙ | |||
52579 52580 52581 52582 52583 52584 52585 | ** 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. */ | | > | > | > | < < < < < < < | < | 52745 52746 52747 52748 52749 52750 52751 52752 52753 52754 52755 52756 52757 52758 52759 52760 52761 52762 52763 52764 52765 52766 52767 52768 52769 52770 52771 52772 |
** 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);
|
| ︙ | ︙ | |||
56070 56071 56072 56073 56074 56075 56076 | /* Assert that the caller has been consistent. If this cursor was opened ** expecting an index b-tree, then the caller should be inserting blob ** keys with no associated data. If the cursor was opened expecting an ** intkey table, the caller should be inserting integer keys with a ** blob of associated data. */ assert( (pKey==0)==(pCur->pKeyInfo==0) ); | < < < < < < < > > > > > > > > | 56231 56232 56233 56234 56235 56236 56237 56238 56239 56240 56241 56242 56243 56244 56245 56246 56247 56248 56249 56250 56251 56252 56253 56254 56255 56256 56257 56258 56259 56260 56261 56262 56263 56264 56265 |
/* Assert that the caller has been consistent. If this cursor was opened
** expecting an index b-tree, then the caller should be inserting blob
** keys with no associated data. If the cursor was opened expecting an
** intkey table, the caller should be inserting integer keys with a
** blob of associated data. */
assert( (pKey==0)==(pCur->pKeyInfo==0) );
/* Save the positions of any other cursors open on this table.
**
** In some cases, the call to btreeMoveto() below is a no-op. For
** example, when inserting data into a table with auto-generated integer
** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
** integer key to use. It then calls this function to actually insert the
** data into the intkey B-Tree. In this case btreeMoveto() recognizes
** that the cursor is already where it needs to be and returns without
** doing any work. To avoid thwarting these optimizations, it is important
** not to clear the cursor here.
*/
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
if( rc ) return rc;
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced (assuming this is a replace
** operation - if it is not, the following is a no-op). */
if( pCur->pKeyInfo==0 ){
invalidateIncrblobCursors(p, nKey, 0);
}
if( !loc ){
rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
if( rc ) return rc;
}
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
pPage = pCur->apPage[pCur->iPage];
|
| ︙ | ︙ | |||
56200 56201 56202 56203 56204 56205 56206 |
if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
|| NEVER(pCur->eState!=CURSOR_VALID)
){
return SQLITE_ERROR; /* Something has gone awry. */
}
| < < < < < < | 56362 56363 56364 56365 56366 56367 56368 56369 56370 56371 56372 56373 56374 56375 |
if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
|| NEVER(pCur->eState!=CURSOR_VALID)
){
return SQLITE_ERROR; /* Something has gone awry. */
}
iCellDepth = pCur->iPage;
iCellIdx = pCur->aiIdx[iCellDepth];
pPage = pCur->apPage[iCellDepth];
pCell = findCell(pPage, iCellIdx);
/* If the page containing the entry to delete is not a leaf page, move
** the cursor to the largest entry in the tree that is smaller than
|
| ︙ | ︙ | |||
56231 56232 56233 56234 56235 56236 56237 56238 56239 56240 56241 56242 56243 56244 | /* Save the positions of any other cursors open on this table before ** making any modifications. Make the page containing the entry to be ** deleted writable. Then free any overflow pages associated with the ** entry and finally remove the cell itself from within the page. */ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; rc = clearCell(pPage, pCell); dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor | > > > > > > > | 56387 56388 56389 56390 56391 56392 56393 56394 56395 56396 56397 56398 56399 56400 56401 56402 56403 56404 56405 56406 56407 |
/* Save the positions of any other cursors open on this table before
** making any modifications. Make the page containing the entry to be
** deleted writable. Then free any overflow pages associated with the
** entry and finally remove the cell itself from within the page.
*/
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
if( rc ) return rc;
/* If this is a delete operation to remove a row from a table b-tree,
** invalidate any incrblob cursors open on the row being deleted. */
if( pCur->pKeyInfo==0 ){
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
}
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
rc = clearCell(pPage, pCell);
dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc);
if( rc ) return rc;
/* If the cell deleted was not located on a leaf page, then the cursor
|
| ︙ | ︙ | |||
56512 56513 56514 56515 56516 56517 56518 |
*/
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
int rc;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
assert( p->inTrans==TRANS_WRITE );
| > > > | | | | < < < | 56675 56676 56677 56678 56679 56680 56681 56682 56683 56684 56685 56686 56687 56688 56689 56690 56691 56692 56693 56694 56695 |
*/
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
int rc;
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
assert( p->inTrans==TRANS_WRITE );
rc = saveAllCursors(pBt, (Pgno)iTable, 0);
if( SQLITE_OK==rc ){
/* Invalidate all incrblob cursors open on table iTable (assuming iTable
** is the root of a table b-tree - if it is not, the following call is
** a no-op). */
invalidateIncrblobCursors(p, 0, 1);
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
}
sqlite3BtreeLeave(p);
return rc;
}
/*
|
| ︙ | ︙ | |||
58119 58120 58121 58122 58123 58124 58125 |
while( *pp!=p ){
pp = &(*pp)->pNext;
}
*pp = p->pNext;
}
/* If a transaction is still open on the Btree, roll it back. */
| | | 58282 58283 58284 58285 58286 58287 58288 58289 58290 58291 58292 58293 58294 58295 58296 |
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 ){
|
| ︙ | ︙ | |||
58330 58331 58332 58333 58334 58335 58336 | #endif } /* ** Make sure pMem->z points to a writable allocation of at least ** n bytes. ** | < | > | | > > > > | 58493 58494 58495 58496 58497 58498 58499 58500 58501 58502 58503 58504 58505 58506 58507 58508 58509 58510 58511 58512 58513 58514 58515 58516 58517 58518 58519 58520 58521 58522 58523 58524 58525 58526 58527 |
#endif
}
/*
** Make sure pMem->z points to a writable allocation of at least
** n bytes.
**
** If the third argument passed to this function is true, then memory
** cell pMem must contain a string or blob. In this case the content is
** preserved. Otherwise, if the third parameter to this function is false,
** any current string or blob value may be discarded.
**
** This function sets the MEM_Dyn flag and clears any xDel callback.
** It also clears MEM_Ephem and MEM_Static. If the preserve flag is
** not set, Mem.n is zeroed.
*/
SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
assert( 1 >=
((pMem->zMalloc && pMem->zMalloc==pMem->z) ? 1 : 0) +
(((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) +
((pMem->flags&MEM_Ephem) ? 1 : 0) +
((pMem->flags&MEM_Static) ? 1 : 0)
);
assert( (pMem->flags&MEM_RowSet)==0 );
/* If the preserve flag is set to true, then the memory cell must already
** contain a valid string or blob value. */
assert( preserve==0 || pMem->flags&(MEM_Blob|MEM_Str) );
if( n<32 ) n = 32;
if( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){
if( preserve && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
preserve = 0;
}else{
|
| ︙ | ︙ | |||
60666 60667 60668 60669 60670 60671 60672 |
*/
if( pOp->p4type==P4_SUBPROGRAM ){
int nByte = (nSub+1)*sizeof(SubProgram*);
int j;
for(j=0; j<nSub; j++){
if( apSub[j]==pOp->p4.pProgram ) break;
}
| | | 60833 60834 60835 60836 60837 60838 60839 60840 60841 60842 60843 60844 60845 60846 60847 |
*/
if( pOp->p4type==P4_SUBPROGRAM ){
int nByte = (nSub+1)*sizeof(SubProgram*);
int j;
for(j=0; j<nSub; j++){
if( apSub[j]==pOp->p4.pProgram ) break;
}
if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
apSub = (SubProgram **)pSub->z;
apSub[nSub++] = pOp->p4.pProgram;
pSub->flags |= MEM_Blob;
pSub->n = nSub*sizeof(SubProgram*);
}
}
}
|
| ︙ | ︙ | |||
61429 61430 61431 61432 61433 61434 61435 | assert( cnt==db->activeVdbeCnt ); assert( nWrite==db->writeVdbeCnt ); } #else #define checkActiveVdbeCnt(x) #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < | 61596 61597 61598 61599 61600 61601 61602 61603 61604 61605 61606 61607 61608 61609 | 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. ** |
| ︙ | ︙ | |||
61619 61620 61621 61622 61623 61624 61625 |
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.
*/
| < | | 61760 61761 61762 61763 61764 61765 61766 61767 61768 61769 61770 61771 61772 61773 61774 |
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. */
|
| ︙ | ︙ | |||
61662 61663 61664 61665 61666 61667 61668 |
rc = vdbeCommit(db, p);
}
if( rc==SQLITE_BUSY && p->readOnly ){
sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
p->rc = rc;
| | | < | < | | 61802 61803 61804 61805 61806 61807 61808 61809 61810 61811 61812 61813 61814 61815 61816 61817 61818 61819 61820 61821 61822 61823 61824 61825 61826 61827 61828 61829 61830 61831 61832 61833 61834 61835 61836 61837 61838 61839 61840 61841 61842 61843 61844 61845 61846 61847 61848 61849 61850 61851 |
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.
|
| ︙ | ︙ | |||
66944 66945 66946 66947 66948 66949 66950 66951 66952 66953 66954 66955 66956 66957 |
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor,
** then the cache of the cursor is reset prior to extracting the column.
** The first OP_Column against a pseudo-table after the value of the content
** register has changed should have this bit set.
*/
case OP_Column: {
#if 0 /* local variables moved into u.an */
u32 payloadSize; /* Number of bytes in the record */
i64 payloadSize64; /* Number of bytes in the record */
int p1; /* P1 value of the opcode */
int p2; /* column number to retrieve */
| > > > > > | 67082 67083 67084 67085 67086 67087 67088 67089 67090 67091 67092 67093 67094 67095 67096 67097 67098 67099 67100 |
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor,
** then the cache of the cursor is reset prior to extracting the column.
** The first OP_Column against a pseudo-table after the value of the content
** register has changed should have this bit set.
**
** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
** the result is guaranteed to only be used as the argument of a length()
** or typeof() function, respectively. The loading of large blobs can be
** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
#if 0 /* local variables moved into u.an */
u32 payloadSize; /* Number of bytes in the record */
i64 payloadSize64; /* Number of bytes in the record */
int p1; /* P1 value of the opcode */
int p2; /* column number to retrieve */
|
| ︙ | ︙ | |||
67086 67087 67088 67089 67090 67091 67092 |
if( u.an.payloadSize <= (u32)u.an.avail ){
u.an.zRec = u.an.zData;
u.an.pC->aRow = (u8*)u.an.zData;
}else{
u.an.pC->aRow = 0;
}
}
| | | 67229 67230 67231 67232 67233 67234 67235 67236 67237 67238 67239 67240 67241 67242 67243 |
if( u.an.payloadSize <= (u32)u.an.avail ){
u.an.zRec = u.an.zData;
u.an.pC->aRow = (u8*)u.an.zData;
}else{
u.an.pC->aRow = 0;
}
}
/* The following assert is true in all cases except when
** the database file has been corrupted externally.
** assert( u.an.zRec!=0 || u.an.avail>=u.an.payloadSize || u.an.avail>=9 ); */
u.an.szHdr = getVarint32((u8*)u.an.zData, u.an.offset);
/* Make sure a corrupt database has not given us an oversize header.
** Do this now to avoid an oversize memory allocation.
**
|
| ︙ | ︙ | |||
67161 67162 67163 67164 67165 67166 67167 |
u.an.szField = sqlite3VdbeSerialTypeLen(u.an.t);
u.an.offset += u.an.szField;
if( u.an.offset<u.an.szField ){ /* True if u.an.offset overflows */
u.an.zIdx = &u.an.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
break;
}
}else{
| | | | | 67304 67305 67306 67307 67308 67309 67310 67311 67312 67313 67314 67315 67316 67317 67318 67319 67320 67321 67322 |
u.an.szField = sqlite3VdbeSerialTypeLen(u.an.t);
u.an.offset += u.an.szField;
if( u.an.offset<u.an.szField ){ /* True if u.an.offset overflows */
u.an.zIdx = &u.an.zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
break;
}
}else{
/* If u.an.i is less that u.an.nField, then there are fewer fields in this
** record than SetNumColumns indicated there are columns in the
** table. Set the u.an.offset for any extra columns not present in
** the record to 0. This tells code below to store the default value
** for the column instead of deserializing a value from the record.
*/
u.an.aOffset[u.an.i] = 0;
}
}
sqlite3VdbeMemRelease(&u.an.sMem);
u.an.sMem.flags = MEM_Null;
|
| ︙ | ︙ | |||
67195 67196 67197 67198 67199 67200 67201 67202 67203 67204 |
** then there are not enough fields in the record to satisfy the
** request. In this case, set the value NULL or to P4 if P4 is
** a pointer to a Mem object.
*/
if( u.an.aOffset[u.an.p2] ){
assert( rc==SQLITE_OK );
if( u.an.zRec ){
VdbeMemRelease(u.an.pDest);
sqlite3VdbeSerialGet((u8 *)&u.an.zRec[u.an.aOffset[u.an.p2]], u.an.aType[u.an.p2], u.an.pDest);
}else{
| > > > > > > > > > > > > > | | | > | | | | > | | 67338 67339 67340 67341 67342 67343 67344 67345 67346 67347 67348 67349 67350 67351 67352 67353 67354 67355 67356 67357 67358 67359 67360 67361 67362 67363 67364 67365 67366 67367 67368 67369 67370 67371 67372 67373 67374 67375 67376 67377 |
** then there are not enough fields in the record to satisfy the
** request. In this case, set the value NULL or to P4 if P4 is
** a pointer to a Mem object.
*/
if( u.an.aOffset[u.an.p2] ){
assert( rc==SQLITE_OK );
if( u.an.zRec ){
/* This is the common case where the whole row fits on a single page */
VdbeMemRelease(u.an.pDest);
sqlite3VdbeSerialGet((u8 *)&u.an.zRec[u.an.aOffset[u.an.p2]], u.an.aType[u.an.p2], u.an.pDest);
}else{
/* This branch happens only when the row overflows onto multiple pages */
u.an.t = u.an.aType[u.an.p2];
if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
&& ((u.an.t>=12 && (u.an.t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
){
/* Content is irrelevant for the typeof() function and for
** the length(X) function if X is a blob. So we might as well use
** bogus content rather than reading content from disk. NULL works
** for text and blob and whatever is in the u.an.payloadSize64 variable
** will work for everything else. */
u.an.zData = u.an.t<12 ? (char*)&u.an.payloadSize64 : 0;
}else{
u.an.len = sqlite3VdbeSerialTypeLen(u.an.t);
sqlite3VdbeMemMove(&u.an.sMem, u.an.pDest);
rc = sqlite3VdbeMemFromBtree(u.an.pCrsr, u.an.aOffset[u.an.p2], u.an.len, u.an.pC->isIndex,
&u.an.sMem);
if( rc!=SQLITE_OK ){
goto op_column_out;
}
u.an.zData = u.an.sMem.z;
}
sqlite3VdbeSerialGet((u8*)u.an.zData, u.an.t, u.an.pDest);
}
u.an.pDest->enc = encoding;
}else{
if( pOp->p4type==P4_MEM ){
sqlite3VdbeMemShallowCopy(u.an.pDest, pOp->p4.pMem, MEM_Static);
}else{
MemSetTypeFlag(u.an.pDest, MEM_Null);
|
| ︙ | ︙ | |||
67511 67512 67513 67514 67515 67516 67517 |
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;
| | < < | < | < | 67669 67670 67671 67672 67673 67674 67675 67676 67677 67678 67679 67680 67681 67682 67683 67684 67685 67686 67687 67688 |
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.
|
| ︙ | ︙ | |||
67545 67546 67547 67548 67549 67550 67551 67552 67553 67554 67555 67556 67557 67558 |
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 ){
| > > > > > | 67699 67700 67701 67702 67703 67704 67705 67706 67707 67708 67709 67710 67711 67712 67713 67714 67715 67716 67717 |
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
db->isTransactionSavepoint = 0;
rc = p->rc;
}else{
u.ar.iSavepoint = db->nSavepoint - u.ar.iSavepoint - 1;
if( u.ar.p1==SAVEPOINT_ROLLBACK ){
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 ){
|
| ︙ | ︙ | |||
67615 67616 67617 67618 67619 67620 67621 67622 67623 67624 67625 67626 67627 67628 67629 |
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;
| > > > | | | 67774 67775 67776 67777 67778 67779 67780 67781 67782 67783 67784 67785 67786 67787 67788 67789 67790 67791 67792 67793 67794 67795 67796 67797 67798 67799 67800 67801 67802 67803 67804 67805 67806 67807 67808 67809 |
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;
|
| ︙ | ︙ | |||
68699 68700 68701 68702 68703 68704 68705 |
}
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() */
| | | 68861 68862 68863 68864 68865 68866 68867 68868 68869 68870 68871 68872 68873 68874 68875 |
}
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 */
}
}
}
|
| ︙ | ︙ | |||
74819 74820 74821 74822 74823 74824 74825 |
SQLITE_PRIVATE Expr *sqlite3PExpr(
Parse *pParse, /* Parsing context */
int op, /* Expression opcode */
Expr *pLeft, /* Left operand */
Expr *pRight, /* Right operand */
const Token *pToken /* Argument token */
){
| > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 74981 74982 74983 74984 74985 74986 74987 74988 74989 74990 74991 74992 74993 74994 74995 74996 74997 74998 74999 75000 75001 75002 75003 75004 75005 75006 75007 75008 75009 75010 75011 75012 75013 75014 75015 75016 75017 75018 75019 75020 75021 75022 75023 75024 75025 75026 75027 75028 75029 75030 75031 75032 75033 75034 75035 75036 75037 75038 75039 75040 75041 75042 75043 |
SQLITE_PRIVATE Expr *sqlite3PExpr(
Parse *pParse, /* Parsing context */
int op, /* Expression opcode */
Expr *pLeft, /* Left operand */
Expr *pRight, /* Right operand */
const Token *pToken /* Argument token */
){
Expr *p;
if( op==TK_AND && pLeft && pRight ){
/* Take advantage of short-circuit false optimization for AND */
p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
}else{
p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
}
if( p ) {
sqlite3ExprCheckHeight(pParse, p->nHeight);
}
return p;
}
/*
** Return 1 if an expression must be FALSE in all cases and 0 if the
** expression might be true. This is an optimization. If is OK to
** return 0 here even if the expression really is always false (a
** false negative). But it is a bug to return 1 if the expression
** might be true in some rare circumstances (a false positive.)
**
** Note that if the expression is part of conditional for a
** LEFT JOIN, then we cannot determine at compile-time whether or not
** is it true or false, so always return 0.
*/
static int exprAlwaysFalse(Expr *p){
int v = 0;
if( ExprHasProperty(p, EP_FromJoin) ) return 0;
if( !sqlite3ExprIsInteger(p, &v) ) return 0;
return v==0;
}
/*
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
**
** If one side or the other of the AND is known to be false, then instead
** of returning an AND expression, just return a constant expression with
** a value of false.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
if( pLeft==0 ){
return pRight;
}else if( pRight==0 ){
return pLeft;
}else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0);
}else{
Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0);
sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight);
return pNew;
}
}
|
| ︙ | ︙ | |||
76367 76368 76369 76370 76371 76372 76373 |
/* First replace any existing entry.
**
** Actually, the way the column cache is currently used, we are guaranteed
** that the object will never already be in cache. Verify this guarantee.
*/
#ifndef NDEBUG
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
| < < < < < < < < < | 76561 76562 76563 76564 76565 76566 76567 76568 76569 76570 76571 76572 76573 76574 |
/* First replace any existing entry.
**
** Actually, the way the column cache is currently used, we are guaranteed
** that the object will never already be in cache. Verify this guarantee.
*/
#ifndef NDEBUG
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol );
}
#endif
/* Find an empty slot and replace it */
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg==0 ){
|
| ︙ | ︙ | |||
76510 76511 76512 76513 76514 76515 76516 | ** is called. If iColumn<0 then code is generated that extracts the rowid. */ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn( Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* Description of the table we are reading from */ int iColumn, /* Index of the table column */ int iTable, /* The cursor pointing to the table */ | | > > > > | > | 76695 76696 76697 76698 76699 76700 76701 76702 76703 76704 76705 76706 76707 76708 76709 76710 76711 76712 76713 76714 76715 76716 76717 76718 76719 76720 76721 76722 76723 76724 76725 76726 76727 76728 76729 |
** is called. If iColumn<0 then code is generated that extracts the rowid.
*/
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
Parse *pParse, /* Parsing and code generating context */
Table *pTab, /* Description of the table we are reading from */
int iColumn, /* Index of the table column */
int iTable, /* The cursor pointing to the table */
int iReg, /* Store results here */
u8 p5 /* P5 value for OP_Column */
){
Vdbe *v = pParse->pVdbe;
int i;
struct yColCache *p;
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){
p->lru = pParse->iCacheCnt++;
sqlite3ExprCachePinRegister(pParse, p->iReg);
return p->iReg;
}
}
assert( v!=0 );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
if( p5 ){
sqlite3VdbeChangeP5(v, p5);
}else{
sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
}
return iReg;
}
/*
** Clear all column cache entries.
*/
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
|
| ︙ | ︙ | |||
76653 76654 76655 76656 76657 76658 76659 |
case TK_COLUMN: {
if( pExpr->iTable<0 ){
/* This only happens when coding check constraints */
assert( pParse->ckBase>0 );
inReg = pExpr->iColumn + pParse->ckBase;
}else{
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
| | > | 76843 76844 76845 76846 76847 76848 76849 76850 76851 76852 76853 76854 76855 76856 76857 76858 |
case TK_COLUMN: {
if( pExpr->iTable<0 ){
/* This only happens when coding check constraints */
assert( pParse->ckBase>0 );
inReg = pExpr->iColumn + pParse->ckBase;
}else{
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
pExpr->iColumn, pExpr->iTable, target,
pExpr->op2);
}
break;
}
case TK_INTEGER: {
codeInteger(pParse, pExpr, 0, target);
break;
}
|
| ︙ | ︙ | |||
76930 76931 76932 76933 76934 76935 76936 76937 76938 76939 76940 76941 76942 76943 |
sqlite3VdbeResolveLabel(v, endCoalesce);
break;
}
if( pFarg ){
r1 = sqlite3GetTempRange(pParse, nFarg);
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
}else{
r1 = 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
| > > > > > > > > > > > > > > > > > > > | 77121 77122 77123 77124 77125 77126 77127 77128 77129 77130 77131 77132 77133 77134 77135 77136 77137 77138 77139 77140 77141 77142 77143 77144 77145 77146 77147 77148 77149 77150 77151 77152 77153 |
sqlite3VdbeResolveLabel(v, endCoalesce);
break;
}
if( pFarg ){
r1 = sqlite3GetTempRange(pParse, nFarg);
/* For length() and typeof() functions with a column argument,
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
** loading.
*/
if( (pDef->flags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
u8 exprOp;
assert( nFarg==1 );
assert( pFarg->a[0].pExpr!=0 );
exprOp = pFarg->a[0].pExpr->op;
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
testcase( pDef->flags==SQLITE_FUNC_LENGTH );
pFarg->a[0].pExpr->op2 = pDef->flags;
}
}
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
}else{
r1 = 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| ︙ | ︙ | |||
80135 80136 80137 80138 80139 80140 80141 80142 80143 80144 80145 80146 80147 80148 |
sqlite3_stmt *pStmt = 0; /* An SQL statement being run */
char *zSql; /* Text of the SQL statement */
Index *pPrevIdx = 0; /* Previous index in the loop */
int idx = 0; /* slot in pIdx->aSample[] for next sample */
int eType; /* Datatype of a sample */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
if( !sqlite3FindTable(db, "sqlite_stat3", zDb) ){
return SQLITE_OK;
}
zSql = sqlite3MPrintf(db,
"SELECT idx,count(*) FROM %Q.sqlite_stat3"
" GROUP BY idx", zDb);
| > | 80345 80346 80347 80348 80349 80350 80351 80352 80353 80354 80355 80356 80357 80358 80359 |
sqlite3_stmt *pStmt = 0; /* An SQL statement being run */
char *zSql; /* Text of the SQL statement */
Index *pPrevIdx = 0; /* Previous index in the loop */
int idx = 0; /* slot in pIdx->aSample[] for next sample */
int eType; /* Datatype of a sample */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
assert( db->lookaside.bEnabled==0 );
if( !sqlite3FindTable(db, "sqlite_stat3", zDb) ){
return SQLITE_OK;
}
zSql = sqlite3MPrintf(db,
"SELECT idx,count(*) FROM %Q.sqlite_stat3"
" GROUP BY idx", zDb);
|
| ︙ | ︙ | |||
80161 80162 80163 80164 80165 80166 80167 |
zIndex = (char *)sqlite3_column_text(pStmt, 0);
if( zIndex==0 ) continue;
nSample = sqlite3_column_int(pStmt, 1);
pIdx = sqlite3FindIndex(db, zIndex, zDb);
if( pIdx==0 ) continue;
assert( pIdx->nSample==0 );
pIdx->nSample = nSample;
| | | 80372 80373 80374 80375 80376 80377 80378 80379 80380 80381 80382 80383 80384 80385 80386 |
zIndex = (char *)sqlite3_column_text(pStmt, 0);
if( zIndex==0 ) continue;
nSample = sqlite3_column_int(pStmt, 1);
pIdx = sqlite3FindIndex(db, zIndex, zDb);
if( pIdx==0 ) continue;
assert( pIdx->nSample==0 );
pIdx->nSample = nSample;
pIdx->aSample = sqlite3DbMallocZero(db, nSample*sizeof(IndexSample));
pIdx->avgEq = pIdx->aiRowEst[1];
if( pIdx->aSample==0 ){
db->mallocFailed = 1;
sqlite3_finalize(pStmt);
return SQLITE_NOMEM;
}
}
|
| ︙ | ︙ | |||
80234 80235 80236 80237 80238 80239 80240 |
sqlite3_column_text(pStmt, 4)
);
int n = z ? sqlite3_column_bytes(pStmt, 4) : 0;
pSample->nByte = n;
if( n < 1){
pSample->u.z = 0;
}else{
| | | 80445 80446 80447 80448 80449 80450 80451 80452 80453 80454 80455 80456 80457 80458 80459 |
sqlite3_column_text(pStmt, 4)
);
int n = z ? sqlite3_column_bytes(pStmt, 4) : 0;
pSample->nByte = n;
if( n < 1){
pSample->u.z = 0;
}else{
pSample->u.z = sqlite3DbMallocRaw(db, n);
if( pSample->u.z==0 ){
db->mallocFailed = 1;
sqlite3_finalize(pStmt);
return SQLITE_NOMEM;
}
memcpy(pSample->u.z, z, n);
}
|
| ︙ | ︙ | |||
80310 80311 80312 80313 80314 80315 80316 80317 80318 80319 80320 80321 80322 80323 80324 |
sqlite3DbFree(db, zSql);
}
/* Load the statistics from the sqlite_stat3 table. */
#ifdef SQLITE_ENABLE_STAT3
if( rc==SQLITE_OK ){
rc = loadStat3(db, sInfo.zDatabase);
}
#endif
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}
return rc;
| > > > | 80521 80522 80523 80524 80525 80526 80527 80528 80529 80530 80531 80532 80533 80534 80535 80536 80537 80538 |
sqlite3DbFree(db, zSql);
}
/* Load the statistics from the sqlite_stat3 table. */
#ifdef SQLITE_ENABLE_STAT3
if( rc==SQLITE_OK ){
int lookasideEnabled = db->lookaside.bEnabled;
db->lookaside.bEnabled = 0;
rc = loadStat3(db, sInfo.zDatabase);
db->lookaside.bEnabled = lookasideEnabled;
}
#endif
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}
return rc;
|
| ︙ | ︙ | |||
81673 81674 81675 81676 81677 81678 81679 | /* Delete the Table structure itself. */ sqliteDeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); #ifndef SQLITE_OMIT_CHECK | | | 81887 81888 81889 81890 81891 81892 81893 81894 81895 81896 81897 81898 81899 81900 81901 | /* Delete the Table structure itself. */ sqliteDeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); #ifndef SQLITE_OMIT_CHECK sqlite3ExprListDelete(db, pTable->pCheck); #endif #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3VtabClear(db, pTable); #endif sqlite3DbFree(db, pTable); } |
| ︙ | ︙ | |||
82336 82337 82338 82339 82340 82341 82342 |
/*
** Add a new CHECK constraint to the table currently under construction.
*/
SQLITE_PRIVATE void sqlite3AddCheckConstraint(
Parse *pParse, /* Parsing context */
Expr *pCheckExpr /* The check expression */
){
| < | > > > | | 82550 82551 82552 82553 82554 82555 82556 82557 82558 82559 82560 82561 82562 82563 82564 82565 82566 82567 82568 82569 82570 82571 82572 82573 82574 |
/*
** Add a new CHECK constraint to the table currently under construction.
*/
SQLITE_PRIVATE void sqlite3AddCheckConstraint(
Parse *pParse, /* Parsing context */
Expr *pCheckExpr /* The check expression */
){
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
if( pTab && !IN_DECLARE_VTAB ){
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
if( pParse->constraintName.n ){
sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
}
}else
#endif
{
sqlite3ExprDelete(pParse->db, pCheckExpr);
}
}
/*
** Set the collation function of the most recently parsed table column
** to the CollSeq given.
*/
|
| ︙ | ︙ | |||
82614 82615 82616 82617 82618 82619 82620 82621 82622 82623 82624 82625 82626 82627 82628 82629 82630 |
#ifndef SQLITE_OMIT_CHECK
/* Resolve names in all CHECK constraint expressions.
*/
if( p->pCheck ){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
sSrc.a[0].zName = p->zName;
sSrc.a[0].pTab = p;
sSrc.a[0].iCursor = -1;
sNC.pParse = pParse;
sNC.pSrcList = &sSrc;
sNC.isCheck = 1;
| > > > > | | > | 82830 82831 82832 82833 82834 82835 82836 82837 82838 82839 82840 82841 82842 82843 82844 82845 82846 82847 82848 82849 82850 82851 82852 82853 82854 82855 82856 82857 82858 82859 82860 |
#ifndef SQLITE_OMIT_CHECK
/* Resolve names in all CHECK constraint expressions.
*/
if( p->pCheck ){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
ExprList *pList; /* List of all CHECK constraints */
int i; /* Loop counter */
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
sSrc.a[0].zName = p->zName;
sSrc.a[0].pTab = p;
sSrc.a[0].iCursor = -1;
sNC.pParse = pParse;
sNC.pSrcList = &sSrc;
sNC.isCheck = 1;
pList = p->pCheck;
for(i=0; i<pList->nExpr; i++){
if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
return;
}
}
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk.
** So do not write to the disk again. Extract the root page number
|
| ︙ | ︙ | |||
84176 84177 84178 84179 84180 84181 84182 | } exit_drop_index: sqlite3SrcListDelete(db, pName); } /* | | | | | | | > > > | < < > | | 84397 84398 84399 84400 84401 84402 84403 84404 84405 84406 84407 84408 84409 84410 84411 84412 84413 84414 84415 84416 84417 84418 84419 84420 84421 84422 84423 84424 84425 | } exit_drop_index: sqlite3SrcListDelete(db, pName); } /* ** pArray is a pointer to an array of objects. Each object in the ** array is szEntry bytes in size. This routine uses sqlite3DbRealloc() ** to extend the array so that there is space for a new object at the end. ** ** When this function is called, *pnEntry contains the current size of ** the array (in entries - so the allocation is ((*pnEntry) * szEntry) bytes ** in total). ** ** If the realloc() is successful (i.e. if no OOM condition occurs), the ** space allocated for the new object is zeroed, *pnEntry updated to ** reflect the new size of the array and a pointer to the new allocation ** returned. *pIdx is set to the index of the new array entry in this case. ** ** Otherwise, if the realloc() fails, *pIdx is set to -1, *pnEntry remains ** unchanged and a copy of pArray returned. */ 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 */ |
| ︙ | ︙ | |||
85785 85786 85787 85788 85789 85790 85791 |
/* Collect rowids of every row to be deleted.
*/
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
pWInfo = sqlite3WhereBegin(
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
);
if( pWInfo==0 ) goto delete_from_cleanup;
| | | 86008 86009 86010 86011 86012 86013 86014 86015 86016 86017 86018 86019 86020 86021 86022 |
/* Collect rowids of every row to be deleted.
*/
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
pWInfo = sqlite3WhereBegin(
pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
);
if( pWInfo==0 ) goto delete_from_cleanup;
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
}
sqlite3WhereEnd(pWInfo);
/* Delete every item whose key was written to the list during the
|
| ︙ | ︙ | |||
87605 87606 87607 87608 87609 87610 87611 |
FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ),
AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ),
FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ),
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
| | | | < | < | 87828 87829 87830 87831 87832 87833 87834 87835 87836 87837 87838 87839 87840 87841 87842 87843 87844 87845 87846 87847 87848 87849 87850 87851 87852 87853 87854 87855 87856 87857 |
FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ),
AGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize ),
FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ),
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
FUNCTION(round, 2, 0, 0, roundFunc ),
#endif
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
FUNCTION2(coalesce, -1, 0, 0, ifnullFunc, SQLITE_FUNC_COALESCE),
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION2(ifnull, 2, 0, 0, ifnullFunc, SQLITE_FUNC_COALESCE),
FUNCTION(random, 0, 0, 0, randomFunc ),
FUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
| ︙ | ︙ | |||
90059 90060 90061 90062 90063 90064 90065 90066 90067 90068 90069 90070 90071 90072 90073 90074 90075 | int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index *pIdx; /* Pointer to one of the indices */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int regOldRowid = (rowidChng && isUpdate) ? rowidChng : regRowid; v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; regData = regRowid + 1; /* Test all NOT NULL constraints. | > > | 90280 90281 90282 90283 90284 90285 90286 90287 90288 90289 90290 90291 90292 90293 90294 90295 90296 90297 90298 | int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index *pIdx; /* Pointer to one of the indices */ sqlite3 *db; /* Database connection */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int regOldRowid = (rowidChng && isUpdate) ? rowidChng : regRowid; db = pParse->db; v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; regData = regRowid + 1; /* Test all NOT NULL constraints. |
| ︙ | ︙ | |||
90094 90095 90096 90097 90098 90099 90100 |
case OE_Abort:
sqlite3MayAbort(pParse);
case OE_Rollback:
case OE_Fail: {
char *zMsg;
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
SQLITE_CONSTRAINT, onError, regData+i);
| | | 90317 90318 90319 90320 90321 90322 90323 90324 90325 90326 90327 90328 90329 90330 90331 |
case OE_Abort:
sqlite3MayAbort(pParse);
case OE_Rollback:
case OE_Fail: {
char *zMsg;
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
SQLITE_CONSTRAINT, onError, regData+i);
zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
pTab->zName, pTab->aCol[i].zName);
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
break;
}
case OE_Ignore: {
sqlite3VdbeAddOp2(v, OP_IsNull, regData+i, ignoreDest);
break;
|
| ︙ | ︙ | |||
90116 90117 90118 90119 90120 90121 90122 |
}
}
}
/* Test all CHECK constraints
*/
#ifndef SQLITE_OMIT_CHECK
| | | < > > > | | | > | > > > > > | | | > | 90339 90340 90341 90342 90343 90344 90345 90346 90347 90348 90349 90350 90351 90352 90353 90354 90355 90356 90357 90358 90359 90360 90361 90362 90363 90364 90365 90366 90367 90368 90369 90370 90371 90372 90373 |
}
}
}
/* Test all CHECK constraints
*/
#ifndef SQLITE_OMIT_CHECK
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
ExprList *pCheck = pTab->pCheck;
pParse->ckBase = regData;
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){
int allOk = sqlite3VdbeMakeLabel(v);
sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
if( onError==OE_Ignore ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
}else{
char *zConsName = pCheck->a[i].zName;
if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
if( zConsName ){
zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
}else{
zConsName = 0;
}
sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
}
sqlite3VdbeResolveLabel(v, allOk);
}
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
/* If we have an INTEGER PRIMARY KEY, make sure the primary key
** of the new record does not previously exist. Except, if this
** is an UPDATE and the primary key is not changing, that is OK.
*/
|
| ︙ | ︙ | |||
90183 90184 90185 90186 90187 90188 90189 |
**
** REPLACE INTO t(rowid) VALUES($newrowid)
**
** to run without a statement journal if there are no indexes on the
** table.
*/
Trigger *pTrigger = 0;
| | | 90415 90416 90417 90418 90419 90420 90421 90422 90423 90424 90425 90426 90427 90428 90429 |
**
** REPLACE INTO t(rowid) VALUES($newrowid)
**
** to run without a statement journal if there are no indexes on the
** table.
*/
Trigger *pTrigger = 0;
if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(
pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace
);
|
| ︙ | ︙ | |||
90272 90273 90274 90275 90276 90277 90278 |
case OE_Fail: {
int j;
StrAccum errMsg;
const char *zSep;
char *zErr;
sqlite3StrAccumInit(&errMsg, 0, 0, 200);
| | | 90504 90505 90506 90507 90508 90509 90510 90511 90512 90513 90514 90515 90516 90517 90518 |
case OE_Fail: {
int j;
StrAccum errMsg;
const char *zSep;
char *zErr;
sqlite3StrAccumInit(&errMsg, 0, 0, 200);
errMsg.db = db;
zSep = pIdx->nColumn>1 ? "columns " : "column ";
for(j=0; j<pIdx->nColumn; j++){
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
sqlite3StrAccumAppend(&errMsg, zSep, -1);
zSep = ", ";
sqlite3StrAccumAppend(&errMsg, zCol, -1);
}
|
| ︙ | ︙ | |||
90296 90297 90298 90299 90300 90301 90302 |
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
default: {
Trigger *pTrigger = 0;
assert( onError==OE_Replace );
sqlite3MultiWrite(pParse);
| | | 90528 90529 90530 90531 90532 90533 90534 90535 90536 90537 90538 90539 90540 90541 90542 |
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
default: {
Trigger *pTrigger = 0;
assert( onError==OE_Replace );
sqlite3MultiWrite(pParse);
if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
sqlite3GenerateRowDelete(
pParse, pTab, baseCur, regR, 0, pTrigger, OE_Replace
);
seenReplace = 1;
break;
|
| ︙ | ︙ | |||
90626 90627 90628 90629 90630 90631 90632 |
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
}
if( pSrcIdx==0 ){
return 0; /* pDestIdx has no corresponding index in pSrc */
}
}
#ifndef SQLITE_OMIT_CHECK
| | | 90858 90859 90860 90861 90862 90863 90864 90865 90866 90867 90868 90869 90870 90871 90872 |
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
}
if( pSrcIdx==0 ){
return 0; /* pDestIdx has no corresponding index in pSrc */
}
}
#ifndef SQLITE_OMIT_CHECK
if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck, pDest->pCheck) ){
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
}
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
/* Disallow the transfer optimization if the destination table constains
** any foreign key constraints. This is more restrictive than necessary.
** But the main beneficiary of the transfer optimization is the VACUUM
|
| ︙ | ︙ | |||
92315 92316 92317 92318 92319 92320 92321 |
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> */
| > > | | | > | 92547 92548 92549 92550 92551 92552 92553 92554 92555 92556 92557 92558 92559 92560 92561 92562 92563 92564 92565 92566 |
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);
|
| ︙ | ︙ | |||
92348 92349 92350 92351 92352 92353 92354 92355 92356 92357 92358 92359 92360 92361 |
}
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
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 92583 92584 92585 92586 92587 92588 92589 92590 92591 92592 92593 92594 92595 92596 92597 92598 92599 92600 92601 92602 92603 92604 92605 92606 92607 92608 92609 92610 92611 92612 92613 92614 92615 92616 92617 92618 92619 92620 92621 92622 92623 92624 |
}
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
|
| ︙ | ︙ | |||
92635 92636 92637 92638 92639 92640 92641 |
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.
*/
| | | 92898 92899 92900 92901 92902 92903 92904 92905 92906 92907 92908 92909 92910 92911 92912 |
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[] = {
|
| ︙ | ︙ | |||
92753 92754 92755 92756 92757 92758 92759 |
"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] ){
| < | 93016 93017 93018 93019 93020 93021 93022 93023 93024 93025 93026 93027 93028 93029 |
"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;
}
}
|
| ︙ | ︙ | |||
95669 95670 95671 95672 95673 95674 95675 | 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[] */ | > | | | > > > > > > > | 95931 95932 95933 95934 95935 95936 95937 95938 95939 95940 95941 95942 95943 95944 95945 95946 95947 95948 95949 95950 95951 95952 95953 95954 95955 |
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[] */
if( pEList ){
nCol = pEList->nExpr;
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
testcase( aCol==0 );
}else{
nCol = 0;
aCol = 0;
}
*pnCol = nCol;
*paCol = aCol;
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)
|| p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
if( (zName = pEList->a[i].zName)!=0 ){
|
| ︙ | ︙ | |||
98639 98640 98641 98642 98643 98644 98645 |
for(i=0; i<sAggInfo.nColumn; i++){
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
if( pCol->iSorterColumn>=j ){
int r1 = j + regBase;
int r2;
r2 = sqlite3ExprCodeGetColumn(pParse,
| | | 98909 98910 98911 98912 98913 98914 98915 98916 98917 98918 98919 98920 98921 98922 98923 |
for(i=0; i<sAggInfo.nColumn; i++){
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
if( pCol->iSorterColumn>=j ){
int r1 = j + regBase;
int r2;
r2 = sqlite3ExprCodeGetColumn(pParse,
pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
if( r1!=r2 ){
sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
}
j++;
}
}
regRecord = sqlite3GetTempReg(pParse);
|
| ︙ | ︙ | |||
101199 101200 101201 101202 101203 101204 101205 101206 101207 101208 101209 101210 101211 101212 101213 101214 101215 101216 101217 101218 101219 |
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;
}
| > > > > > > > > > > > > < < < < < < < < | 101469 101470 101471 101472 101473 101474 101475 101476 101477 101478 101479 101480 101481 101482 101483 101484 101485 101486 101487 101488 101489 101490 101491 101492 101493 101494 101495 101496 101497 101498 101499 101500 101501 101502 101503 101504 101505 101506 101507 101508 101509 101510 101511 101512 101513 101514 |
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"
|
| ︙ | ︙ | |||
103124 103125 103126 103127 103128 103129 103130 |
return 0;
}
#ifdef SQLITE_EBCDIC
if( *pnoCase ) return 0;
#endif
pList = pExpr->x.pList;
pLeft = pList->a[1].pExpr;
| > | > > | 103398 103399 103400 103401 103402 103403 103404 103405 103406 103407 103408 103409 103410 103411 103412 103413 103414 103415 |
return 0;
}
#ifdef SQLITE_EBCDIC
if( *pnoCase ) return 0;
#endif
pList = pExpr->x.pList;
pLeft = pList->a[1].pExpr;
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| IsVirtual(pLeft->pTab)
){
/* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
** be the name of an indexed column with TEXT affinity. */
return 0;
}
assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
pRight = pList->a[0].pExpr;
|
| ︙ | ︙ | |||
105541 105542 105543 105544 105545 105546 105547 |
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. */
| | > > | 105818 105819 105820 105821 105822 105823 105824 105825 105826 105827 105828 105829 105830 105831 105832 105833 105834 |
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
|
| ︙ | ︙ | |||
106238 106239 106240 106241 106242 106243 106244 | ** 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 */ | | < | 106517 106518 106519 106520 106521 106522 106523 106524 106525 106526 106527 106528 106529 106530 106531 |
** 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 */
|
| ︙ | ︙ | |||
106778 106779 106780 106781 106782 106783 106784 106785 106786 |
}
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 ){
| > > > > > > > > > > > > | > | > > | 107056 107057 107058 107059 107060 107061 107062 107063 107064 107065 107066 107067 107068 107069 107070 107071 107072 107073 107074 107075 107076 107077 107078 107079 107080 107081 107082 107083 107084 107085 107086 107087 107088 |
}
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;
|
| ︙ | ︙ | |||
106805 106806 106807 106808 106809 106810 106811 |
explainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
);
if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
int r;
r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
| | > > | > | 107098 107099 107100 107101 107102 107103 107104 107105 107106 107107 107108 107109 107110 107111 107112 107113 107114 107115 107116 107117 107118 107119 107120 107121 107122 107123 107124 107125 107126 107127 107128 107129 107130 107131 107132 107133 |
explainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
);
if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
int r;
r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
regRowid, 0);
sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
sqlite3VdbeCurrentAddr(v)+2, r, iSet);
}
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
/* The pSubWInfo->untestedTerms flag means that this OR term
** contained one or more AND term from a notReady table. The
** terms from the notReady table could not be tested and will
** need to be tested later.
*/
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
|
| ︙ | ︙ | |||
107479 107480 107481 107482 107483 107484 107485 |
** 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);
| | | 107775 107776 107777 107778 107779 107780 107781 107782 107783 107784 107785 107786 107787 107788 107789 |
** 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
|
| ︙ | ︙ | |||
107715 107716 107717 107718 107719 107720 107721 |
/*
** An instance of this structure is used to store the LIKE,
** GLOB, NOT LIKE, and NOT GLOB operators.
*/
struct LikeOp {
Token eOperator; /* "like" or "glob" or "regexp" */
| | | 108011 108012 108013 108014 108015 108016 108017 108018 108019 108020 108021 108022 108023 108024 108025 |
/*
** An instance of this structure is used to store the LIKE,
** GLOB, NOT LIKE, and NOT GLOB operators.
*/
struct LikeOp {
Token eOperator; /* "like" or "glob" or "regexp" */
int bNot; /* True if the NOT keyword is present */
};
/*
** An instance of the following structure describes the event of a
** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT,
** TK_DELETE, or TK_INSTEAD. If the event is of the form
**
|
| ︙ | ︙ | |||
107894 107895 107896 107897 107898 107899 107900 | #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 | | | | 108190 108191 108192 108193 108194 108195 108196 108197 108198 108199 108200 108201 108202 108203 108204 108205 | #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 627 #define YYNRULE 325 #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. */ |
| ︙ | ︙ | |||
107965 107966 107967 107968 107969 107970 107971 | ** 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. */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | > > | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 108554 108555 108556 108557 108558 108559 108560 108561 108562 108563 108564 108565 108566 108567 108568 108569 108570 108571 108572 108573 108574 108575 108576 108577 108578 108579 108580 108581 108582 108583 108584 108585 108586 108587 108588 108589 108590 108591 108592 108593 108594 108595 108596 108597 108598 108599 108600 108601 108602 108603 108604 108605 108606 108607 108608 108609 108610 108611 108612 108613 108614 108615 108616 108617 108618 108619 108620 108621 108622 108623 108624 108625 108626 108627 108628 108629 108630 108631 108632 108633 108634 108635 108636 108637 108638 108639 108640 108641 108642 108643 108644 108645 108646 108647 108648 108649 108650 108651 108652 108653 108654 108655 108656 108657 108658 108659 108660 108661 108662 108663 108664 108665 108666 108667 108668 108669 108670 108671 108672 108673 108674 108675 108676 108677 108678 108679 108680 108681 108682 108683 108684 108685 108686 108687 108688 108689 108690 108691 108692 108693 108694 108695 108696 108697 108698 108699 108700 108701 108702 108703 108704 108705 108706 108707 108708 108709 108710 108711 108712 108713 108714 108715 108716 108717 108718 108719 108720 108721 108722 108723 108724 108725 108726 108727 108728 108729 108730 108731 108732 108733 108734 108735 108736 108737 108738 108739 108740 108741 108742 |
** 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 (1561)
static const YYACTIONTYPE yy_action[] = {
/* 0 */ 310, 328, 573, 572, 15, 171, 185, 595, 56, 56,
/* 10 */ 56, 56, 49, 54, 54, 54, 54, 53, 53, 52,
/* 20 */ 52, 52, 51, 233, 52, 52, 52, 51, 233, 624,
/* 30 */ 588, 582, 56, 56, 56, 56, 314, 54, 54, 54,
/* 40 */ 54, 53, 53, 52, 52, 52, 51, 233, 299, 57,
/* 50 */ 58, 48, 580, 579, 581, 581, 55, 55, 56, 56,
/* 60 */ 56, 56, 569, 54, 54, 54, 54, 53, 53, 52,
/* 70 */ 52, 52, 51, 233, 310, 595, 326, 575, 663, 65,
/* 80 */ 33, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 90 */ 51, 233, 53, 53, 52, 52, 52, 51, 233, 489,
/* 100 */ 663, 440, 663, 235, 588, 582, 553, 297, 363, 59,
/* 110 */ 481, 67, 360, 1, 618, 351, 618, 620, 619, 207,
/* 120 */ 6, 441, 442, 57, 58, 48, 580, 579, 581, 581,
/* 130 */ 55, 55, 56, 56, 56, 56, 605, 54, 54, 54,
/* 140 */ 54, 53, 53, 52, 52, 52, 51, 233, 310, 223,
/* 150 */ 50, 47, 146, 598, 138, 281, 385, 276, 384, 168,
/* 160 */ 489, 552, 620, 619, 620, 619, 272, 214, 440, 411,
/* 170 */ 551, 604, 67, 165, 7, 618, 352, 353, 588, 582,
/* 180 */ 443, 569, 192, 618, 414, 617, 616, 668, 441, 336,
/* 190 */ 669, 62, 618, 599, 92, 382, 346, 57, 58, 48,
/* 200 */ 580, 579, 581, 581, 55, 55, 56, 56, 56, 56,
/* 210 */ 670, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 220 */ 51, 233, 310, 465, 232, 231, 373, 132, 514, 513,
/* 230 */ 617, 616, 617, 616, 398, 437, 411, 66, 280, 388,
/* 240 */ 411, 595, 439, 220, 438, 620, 619, 337, 569, 279,
/* 250 */ 201, 414, 588, 582, 166, 414, 546, 167, 68, 234,
/* 260 */ 599, 92, 620, 619, 599, 92, 19, 570, 570, 466,
/* 270 */ 564, 57, 58, 48, 580, 579, 581, 581, 55, 55,
/* 280 */ 56, 56, 56, 56, 598, 54, 54, 54, 54, 53,
/* 290 */ 53, 52, 52, 52, 51, 233, 310, 411, 524, 232,
/* 300 */ 231, 398, 593, 547, 559, 398, 348, 202, 175, 595,
/* 310 */ 399, 315, 414, 617, 616, 387, 272, 255, 347, 254,
/* 320 */ 558, 599, 74, 620, 619, 45, 588, 582, 235, 466,
/* 330 */ 617, 616, 511, 591, 591, 591, 557, 578, 402, 545,
/* 340 */ 600, 598, 570, 570, 601, 57, 58, 48, 580, 579,
/* 350 */ 581, 581, 55, 55, 56, 56, 56, 56, 550, 54,
/* 360 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 233,
/* 370 */ 310, 309, 411, 145, 566, 490, 213, 255, 347, 254,
/* 380 */ 196, 195, 194, 587, 586, 531, 600, 414, 235, 174,
/* 390 */ 601, 617, 616, 411, 620, 619, 599, 91, 547, 574,
/* 400 */ 588, 582, 50, 47, 146, 584, 583, 471, 414, 249,
/* 410 */ 565, 542, 186, 39, 304, 424, 562, 599, 16, 57,
/* 420 */ 58, 48, 580, 579, 581, 581, 55, 55, 56, 56,
/* 430 */ 56, 56, 585, 54, 54, 54, 54, 53, 53, 52,
/* 440 */ 52, 52, 51, 233, 310, 559, 290, 530, 529, 345,
/* 450 */ 533, 576, 540, 246, 170, 248, 411, 396, 411, 422,
/* 460 */ 199, 558, 617, 616, 165, 563, 50, 47, 146, 181,
/* 470 */ 498, 414, 166, 414, 588, 582, 269, 557, 166, 518,
/* 480 */ 599, 92, 599, 92, 561, 595, 469, 36, 173, 409,
/* 490 */ 517, 577, 577, 57, 58, 48, 580, 579, 581, 581,
/* 500 */ 55, 55, 56, 56, 56, 56, 338, 54, 54, 54,
/* 510 */ 54, 53, 53, 52, 52, 52, 51, 233, 310, 304,
/* 520 */ 423, 394, 526, 318, 869, 235, 167, 180, 473, 547,
/* 530 */ 503, 247, 474, 381, 378, 377, 409, 351, 577, 577,
/* 540 */ 409, 560, 577, 577, 376, 383, 364, 603, 588, 582,
/* 550 */ 620, 619, 502, 595, 409, 494, 577, 577, 409, 266,
/* 560 */ 577, 577, 421, 943, 422, 943, 198, 57, 58, 48,
/* 570 */ 580, 579, 581, 581, 55, 55, 56, 56, 56, 56,
/* 580 */ 315, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 590 */ 51, 233, 310, 390, 421, 942, 509, 942, 556, 145,
/* 600 */ 598, 391, 324, 262, 549, 264, 411, 425, 407, 573,
/* 610 */ 572, 12, 197, 143, 489, 50, 47, 146, 617, 616,
/* 620 */ 206, 414, 588, 582, 547, 429, 67, 212, 143, 618,
/* 630 */ 599, 73, 504, 505, 207, 434, 475, 475, 366, 425,
/* 640 */ 35, 57, 58, 48, 580, 579, 581, 581, 55, 55,
/* 650 */ 56, 56, 56, 56, 598, 54, 54, 54, 54, 53,
/* 660 */ 53, 52, 52, 52, 51, 233, 310, 260, 598, 569,
/* 670 */ 268, 615, 614, 613, 171, 411, 595, 11, 411, 350,
/* 680 */ 411, 32, 618, 953, 183, 419, 2, 627, 625, 330,
/* 690 */ 414, 352, 552, 414, 538, 414, 588, 582, 188, 599,
/* 700 */ 69, 551, 599, 94, 599, 97, 374, 544, 166, 618,
/* 710 */ 334, 359, 50, 47, 146, 57, 58, 48, 580, 579,
/* 720 */ 581, 581, 55, 55, 56, 56, 56, 56, 411, 54,
/* 730 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 233,
/* 740 */ 310, 411, 129, 414, 595, 22, 273, 156, 411, 566,
/* 750 */ 406, 213, 599, 95, 570, 570, 414, 327, 169, 332,
/* 760 */ 411, 618, 536, 414, 358, 599, 104, 483, 508, 356,
/* 770 */ 588, 582, 599, 103, 484, 414, 470, 357, 166, 618,
/* 780 */ 626, 2, 204, 323, 599, 105, 40, 528, 38, 57,
/* 790 */ 58, 48, 580, 579, 581, 581, 55, 55, 56, 56,
/* 800 */ 56, 56, 411, 54, 54, 54, 54, 53, 53, 52,
/* 810 */ 52, 52, 51, 233, 310, 411, 598, 414, 411, 260,
/* 820 */ 273, 273, 273, 273, 426, 305, 599, 106, 520, 519,
/* 830 */ 414, 411, 142, 414, 618, 618, 618, 618, 618, 599,
/* 840 */ 133, 339, 599, 134, 588, 582, 414, 21, 30, 316,
/* 850 */ 147, 459, 221, 170, 527, 599, 98, 222, 322, 321,
/* 860 */ 320, 141, 259, 57, 58, 48, 580, 579, 581, 581,
/* 870 */ 55, 55, 56, 56, 56, 56, 411, 54, 54, 54,
/* 880 */ 54, 53, 53, 52, 52, 52, 51, 233, 310, 411,
/* 890 */ 260, 414, 411, 458, 200, 35, 411, 358, 211, 228,
/* 900 */ 599, 102, 468, 519, 414, 618, 28, 414, 538, 501,
/* 910 */ 411, 414, 618, 599, 101, 358, 599, 93, 588, 582,
/* 920 */ 599, 100, 522, 618, 427, 414, 306, 271, 598, 380,
/* 930 */ 618, 602, 598, 452, 599, 77, 210, 57, 58, 48,
/* 940 */ 580, 579, 581, 581, 55, 55, 56, 56, 56, 56,
/* 950 */ 411, 54, 54, 54, 54, 53, 53, 52, 52, 52,
/* 960 */ 51, 233, 310, 411, 621, 414, 411, 127, 609, 270,
/* 970 */ 598, 365, 51, 233, 599, 96, 625, 330, 414, 618,
/* 980 */ 126, 414, 411, 618, 411, 253, 608, 599, 137, 27,
/* 990 */ 599, 136, 588, 582, 375, 260, 125, 414, 164, 414,
/* 1000 */ 371, 618, 279, 219, 542, 542, 599, 135, 599, 76,
/* 1010 */ 618, 57, 46, 48, 580, 579, 581, 581, 55, 55,
/* 1020 */ 56, 56, 56, 56, 411, 54, 54, 54, 54, 53,
/* 1030 */ 53, 52, 52, 52, 51, 233, 310, 411, 450, 414,
/* 1040 */ 411, 260, 542, 229, 285, 607, 479, 184, 599, 90,
/* 1050 */ 367, 122, 414, 476, 121, 414, 618, 170, 411, 353,
/* 1060 */ 618, 599, 89, 410, 599, 75, 588, 582, 472, 257,
/* 1070 */ 538, 120, 159, 414, 618, 14, 464, 158, 618, 157,
/* 1080 */ 461, 283, 599, 88, 449, 618, 58, 48, 580, 579,
/* 1090 */ 581, 581, 55, 55, 56, 56, 56, 56, 411, 54,
/* 1100 */ 54, 54, 54, 53, 53, 52, 52, 52, 51, 233,
/* 1110 */ 310, 411, 260, 414, 411, 592, 260, 118, 25, 400,
/* 1120 */ 10, 24, 599, 87, 117, 216, 414, 618, 349, 414,
/* 1130 */ 618, 618, 411, 319, 618, 599, 99, 555, 599, 86,
/* 1140 */ 588, 582, 4, 260, 457, 455, 115, 414, 251, 154,
/* 1150 */ 451, 108, 618, 110, 436, 448, 599, 17, 618, 218,
/* 1160 */ 107, 48, 580, 579, 581, 581, 55, 55, 56, 56,
/* 1170 */ 56, 56, 435, 54, 54, 54, 54, 53, 53, 52,
/* 1180 */ 52, 52, 51, 233, 44, 405, 217, 3, 411, 260,
/* 1190 */ 543, 415, 619, 445, 64, 149, 539, 237, 333, 329,
/* 1200 */ 203, 187, 408, 414, 618, 618, 420, 44, 405, 411,
/* 1210 */ 3, 618, 599, 85, 415, 619, 148, 227, 622, 179,
/* 1220 */ 313, 403, 312, 612, 414, 408, 611, 124, 417, 178,
/* 1230 */ 610, 564, 243, 599, 84, 537, 8, 176, 235, 416,
/* 1240 */ 294, 418, 623, 30, 403, 597, 411, 236, 293, 123,
/* 1250 */ 618, 41, 42, 532, 564, 205, 292, 275, 43, 413,
/* 1260 */ 412, 414, 395, 593, 507, 274, 31, 397, 291, 37,
/* 1270 */ 599, 83, 618, 491, 41, 42, 267, 411, 265, 618,
/* 1280 */ 618, 43, 413, 412, 596, 263, 593, 60, 618, 598,
/* 1290 */ 261, 618, 414, 618, 591, 591, 591, 590, 589, 13,
/* 1300 */ 618, 599, 72, 554, 235, 618, 44, 405, 256, 3,
/* 1310 */ 361, 172, 340, 415, 619, 230, 411, 591, 591, 591,
/* 1320 */ 590, 589, 13, 618, 408, 618, 182, 411, 286, 34,
/* 1330 */ 405, 414, 3, 411, 463, 411, 415, 619, 29, 331,
/* 1340 */ 599, 71, 414, 403, 392, 386, 284, 408, 414, 618,
/* 1350 */ 414, 599, 82, 564, 411, 462, 354, 599, 81, 599,
/* 1360 */ 80, 541, 250, 535, 282, 521, 403, 534, 516, 414,
/* 1370 */ 618, 618, 454, 41, 42, 411, 564, 618, 599, 70,
/* 1380 */ 43, 413, 412, 444, 515, 593, 242, 618, 325, 61,
/* 1390 */ 414, 277, 239, 620, 619, 238, 41, 42, 618, 599,
/* 1400 */ 18, 618, 512, 43, 413, 412, 511, 618, 593, 430,
/* 1410 */ 618, 411, 128, 510, 308, 226, 591, 591, 591, 590,
/* 1420 */ 589, 13, 215, 289, 618, 225, 414, 302, 301, 300,
/* 1430 */ 177, 298, 411, 564, 453, 599, 79, 224, 618, 591,
/* 1440 */ 591, 591, 590, 589, 13, 389, 492, 414, 150, 144,
/* 1450 */ 241, 393, 288, 191, 190, 193, 599, 78, 165, 240,
/* 1460 */ 414, 524, 487, 307, 618, 593, 618, 618, 486, 599,
/* 1470 */ 9, 163, 152, 485, 466, 372, 480, 162, 153, 370,
/* 1480 */ 161, 151, 209, 478, 258, 368, 477, 26, 160, 467,
/* 1490 */ 140, 362, 131, 119, 116, 456, 591, 591, 591, 155,
/* 1500 */ 114, 344, 343, 113, 112, 111, 447, 109, 130, 23,
/* 1510 */ 317, 433, 20, 432, 431, 428, 606, 594, 63, 189,
/* 1520 */ 404, 571, 255, 342, 244, 295, 287, 278, 311, 508,
/* 1530 */ 496, 497, 495, 235, 493, 568, 379, 355, 460, 245,
/* 1540 */ 341, 446, 303, 567, 5, 252, 548, 208, 139, 506,
/* 1550 */ 369, 401, 500, 499, 296, 525, 335, 488, 482, 523,
/* 1560 */ 233,
};
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, 88, 89, 90, 91, 92, 1,
/* 30 */ 49, 50, 77, 78, 79, 80, 155, 82, 83, 84,
/* 40 */ 85, 86, 87, 88, 89, 90, 91, 92, 15, 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, 1, 25,
/* 80 */ 25, 82, 83, 84, 85, 86, 87, 88, 89, 90,
/* 90 */ 91, 92, 86, 87, 88, 89, 90, 91, 92, 150,
/* 100 */ 23, 150, 25, 116, 49, 50, 177, 158, 227, 54,
/* 110 */ 161, 162, 231, 22, 165, 128, 165, 26, 27, 160,
/* 120 */ 22, 170, 171, 68, 69, 70, 71, 72, 73, 74,
/* 130 */ 75, 76, 77, 78, 79, 80, 23, 82, 83, 84,
/* 140 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 92,
/* 150 */ 221, 222, 223, 194, 97, 98, 99, 100, 101, 102,
/* 160 */ 150, 32, 26, 27, 26, 27, 109, 22, 150, 150,
/* 170 */ 41, 161, 162, 96, 76, 165, 217, 150, 49, 50,
/* 180 */ 229, 230, 172, 165, 165, 94, 95, 118, 170, 171,
/* 190 */ 118, 232, 165, 174, 175, 185, 237, 68, 69, 70,
/* 200 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
/* 210 */ 118, 82, 83, 84, 85, 86, 87, 88, 89, 90,
/* 220 */ 91, 92, 19, 11, 86, 87, 19, 24, 7, 8,
/* 230 */ 94, 95, 94, 95, 215, 97, 150, 22, 98, 220,
/* 240 */ 150, 26, 104, 216, 106, 26, 27, 229, 230, 109,
/* 250 */ 160, 165, 49, 50, 25, 165, 120, 50, 22, 197,
/* 260 */ 174, 175, 26, 27, 174, 175, 204, 129, 130, 57,
/* 270 */ 66, 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, 150, 94, 86,
/* 300 */ 87, 215, 98, 25, 12, 215, 220, 160, 118, 94,
/* 310 */ 220, 104, 165, 94, 95, 88, 109, 105, 106, 107,
/* 320 */ 28, 174, 175, 26, 27, 22, 49, 50, 116, 57,
/* 330 */ 94, 95, 103, 129, 130, 131, 44, 113, 46, 120,
/* 340 */ 113, 194, 129, 130, 117, 68, 69, 70, 71, 72,
/* 350 */ 73, 74, 75, 76, 77, 78, 79, 80, 177, 82,
/* 360 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
/* 370 */ 19, 163, 150, 95, 166, 167, 168, 105, 106, 107,
/* 380 */ 105, 106, 107, 49, 50, 88, 113, 165, 116, 118,
/* 390 */ 117, 94, 95, 150, 26, 27, 174, 175, 120, 23,
/* 400 */ 49, 50, 221, 222, 223, 71, 72, 21, 165, 16,
/* 410 */ 23, 166, 22, 136, 22, 23, 11, 174, 175, 68,
/* 420 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
/* 430 */ 79, 80, 98, 82, 83, 84, 85, 86, 87, 88,
/* 440 */ 89, 90, 91, 92, 19, 12, 224, 23, 23, 63,
/* 450 */ 205, 23, 23, 60, 25, 62, 150, 214, 150, 67,
/* 460 */ 22, 28, 94, 95, 96, 23, 221, 222, 223, 23,
/* 470 */ 23, 165, 25, 165, 49, 50, 23, 44, 25, 46,
/* 480 */ 174, 175, 174, 175, 23, 26, 100, 136, 25, 112,
/* 490 */ 57, 114, 115, 68, 69, 70, 71, 72, 73, 74,
/* 500 */ 75, 76, 77, 78, 79, 80, 97, 82, 83, 84,
/* 510 */ 85, 86, 87, 88, 89, 90, 91, 92, 19, 22,
/* 520 */ 23, 215, 23, 215, 138, 116, 50, 23, 30, 25,
/* 530 */ 36, 138, 34, 99, 100, 101, 112, 128, 114, 115,
/* 540 */ 112, 23, 114, 115, 110, 51, 48, 173, 49, 50,
/* 550 */ 26, 27, 58, 94, 112, 181, 114, 115, 112, 16,
/* 560 */ 114, 115, 22, 23, 67, 25, 160, 68, 69, 70,
/* 570 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
/* 580 */ 104, 82, 83, 84, 85, 86, 87, 88, 89, 90,
/* 590 */ 91, 92, 19, 19, 22, 23, 23, 25, 23, 95,
/* 600 */ 194, 27, 108, 60, 25, 62, 150, 67, 169, 170,
/* 610 */ 171, 35, 206, 207, 150, 221, 222, 223, 94, 95,
/* 620 */ 160, 165, 49, 50, 120, 161, 162, 206, 207, 165,
/* 630 */ 174, 175, 97, 98, 160, 241, 105, 106, 107, 67,
/* 640 */ 25, 68, 69, 70, 71, 72, 73, 74, 75, 76,
/* 650 */ 77, 78, 79, 80, 194, 82, 83, 84, 85, 86,
/* 660 */ 87, 88, 89, 90, 91, 92, 19, 150, 194, 230,
/* 670 */ 23, 7, 8, 9, 24, 150, 26, 35, 150, 219,
/* 680 */ 150, 25, 165, 142, 143, 144, 145, 0, 1, 2,
/* 690 */ 165, 217, 32, 165, 150, 165, 49, 50, 119, 174,
/* 700 */ 175, 41, 174, 175, 174, 175, 23, 120, 25, 165,
/* 710 */ 193, 237, 221, 222, 223, 68, 69, 70, 71, 72,
/* 720 */ 73, 74, 75, 76, 77, 78, 79, 80, 150, 82,
/* 730 */ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
/* 740 */ 19, 150, 22, 165, 94, 24, 150, 25, 150, 166,
/* 750 */ 167, 168, 174, 175, 129, 130, 165, 213, 35, 242,
/* 760 */ 150, 165, 27, 165, 150, 174, 175, 181, 182, 19,
/* 770 */ 49, 50, 174, 175, 188, 165, 23, 27, 25, 165,
/* 780 */ 144, 145, 160, 187, 174, 175, 135, 23, 137, 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, 194, 165, 150, 150,
/* 820 */ 150, 150, 150, 150, 247, 248, 174, 175, 190, 191,
/* 830 */ 165, 150, 118, 165, 165, 165, 165, 165, 165, 174,
/* 840 */ 175, 219, 174, 175, 49, 50, 165, 52, 126, 245,
/* 850 */ 246, 23, 238, 25, 23, 174, 175, 187, 187, 187,
/* 860 */ 187, 39, 193, 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, 23, 160, 25, 150, 150, 160, 52,
/* 900 */ 174, 175, 190, 191, 165, 165, 22, 165, 150, 29,
/* 910 */ 150, 165, 165, 174, 175, 150, 174, 175, 49, 50,
/* 920 */ 174, 175, 165, 165, 23, 165, 25, 25, 194, 52,
/* 930 */ 165, 174, 194, 193, 174, 175, 160, 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, 22, 150, 23,
/* 970 */ 194, 213, 91, 92, 174, 175, 1, 2, 165, 165,
/* 980 */ 22, 165, 150, 165, 150, 238, 150, 174, 175, 22,
/* 990 */ 174, 175, 49, 50, 52, 150, 22, 165, 102, 165,
/* 1000 */ 19, 165, 109, 238, 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, 150, 166, 205, 205, 150, 20, 24, 174, 175,
/* 1050 */ 43, 104, 165, 59, 53, 165, 165, 25, 150, 150,
/* 1060 */ 165, 174, 175, 150, 174, 175, 49, 50, 53, 138,
/* 1070 */ 150, 22, 104, 165, 165, 5, 1, 118, 165, 35,
/* 1080 */ 27, 205, 174, 175, 193, 165, 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, 150, 150, 165, 150, 150, 150, 108, 76, 150,
/* 1120 */ 22, 76, 174, 175, 127, 216, 165, 165, 25, 165,
/* 1130 */ 165, 165, 150, 213, 165, 174, 175, 150, 174, 175,
/* 1140 */ 49, 50, 22, 150, 23, 1, 119, 165, 16, 121,
/* 1150 */ 20, 108, 165, 119, 23, 193, 174, 175, 165, 193,
/* 1160 */ 127, 70, 71, 72, 73, 74, 75, 76, 77, 78,
/* 1170 */ 79, 80, 23, 82, 83, 84, 85, 86, 87, 88,
/* 1180 */ 89, 90, 91, 92, 19, 20, 193, 22, 150, 150,
/* 1190 */ 150, 26, 27, 128, 16, 15, 150, 140, 65, 3,
/* 1200 */ 164, 22, 37, 165, 165, 165, 4, 19, 20, 150,
/* 1210 */ 22, 165, 174, 175, 26, 27, 246, 180, 149, 6,
/* 1220 */ 249, 56, 249, 149, 165, 37, 149, 180, 149, 151,
/* 1230 */ 13, 66, 193, 174, 175, 150, 25, 151, 116, 159,
/* 1240 */ 199, 146, 147, 126, 56, 194, 150, 152, 200, 154,
/* 1250 */ 165, 86, 87, 88, 66, 160, 201, 150, 93, 94,
/* 1260 */ 95, 165, 123, 98, 150, 150, 124, 122, 202, 135,
/* 1270 */ 174, 175, 165, 150, 86, 87, 150, 150, 150, 165,
/* 1280 */ 165, 93, 94, 95, 203, 150, 98, 125, 165, 194,
/* 1290 */ 150, 165, 165, 165, 129, 130, 131, 132, 133, 134,
/* 1300 */ 165, 174, 175, 157, 116, 165, 19, 20, 150, 22,
/* 1310 */ 150, 118, 217, 26, 27, 225, 150, 129, 130, 131,
/* 1320 */ 132, 133, 134, 165, 37, 165, 157, 150, 210, 19,
/* 1330 */ 20, 165, 22, 150, 150, 150, 26, 27, 104, 244,
/* 1340 */ 174, 175, 165, 56, 121, 104, 210, 37, 165, 165,
/* 1350 */ 165, 174, 175, 66, 150, 150, 150, 174, 175, 174,
/* 1360 */ 175, 211, 150, 211, 210, 176, 56, 211, 176, 165,
/* 1370 */ 165, 165, 150, 86, 87, 150, 66, 165, 174, 175,
/* 1380 */ 93, 94, 95, 150, 184, 98, 150, 165, 47, 22,
/* 1390 */ 165, 176, 150, 26, 27, 150, 86, 87, 165, 174,
/* 1400 */ 175, 165, 178, 93, 94, 95, 103, 165, 98, 150,
/* 1410 */ 165, 150, 22, 176, 179, 228, 129, 130, 131, 132,
/* 1420 */ 133, 134, 5, 150, 165, 92, 165, 10, 11, 12,
/* 1430 */ 13, 14, 150, 66, 17, 174, 175, 228, 165, 129,
/* 1440 */ 130, 131, 132, 133, 134, 150, 184, 165, 31, 150,
/* 1450 */ 33, 150, 150, 86, 87, 172, 174, 175, 96, 42,
/* 1460 */ 165, 94, 176, 179, 165, 98, 165, 165, 176, 174,
/* 1470 */ 175, 156, 55, 176, 57, 18, 157, 156, 61, 157,
/* 1480 */ 156, 64, 157, 157, 235, 45, 236, 135, 156, 189,
/* 1490 */ 68, 157, 218, 189, 22, 199, 129, 130, 131, 156,
/* 1500 */ 192, 157, 18, 192, 192, 192, 199, 189, 218, 240,
/* 1510 */ 157, 40, 240, 157, 157, 38, 153, 166, 243, 196,
/* 1520 */ 226, 230, 105, 106, 107, 198, 209, 177, 111, 182,
/* 1530 */ 166, 177, 177, 116, 166, 230, 178, 239, 199, 209,
/* 1540 */ 209, 199, 148, 166, 196, 239, 208, 233, 172, 183,
/* 1550 */ 234, 191, 183, 183, 195, 174, 139, 186, 186, 174,
/* 1560 */ 92,
};
#define YY_SHIFT_USE_DFLT (-70)
#define YY_SHIFT_COUNT (418)
#define YY_SHIFT_MIN (-69)
#define YY_SHIFT_MAX (1484)
static const short yy_shift_ofst[] = {
/* 0 */ 975, 1188, 1417, 1188, 1287, 1287, 138, 138, 368, -19,
/* 10 */ 1287, 1287, 1287, 1287, 272, 524, 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, 524, 524, 213, 213, 459, 1122, 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, 6, -64, 524, 524, 524,
/* 110 */ 524, 524, 524, 524, 524, 524, 524, 524, 524, 524,
/* 120 */ 524, 524, 524, 386, 207, 524, 524, 524, 524, 524,
/* 130 */ 409, -13, 459, 881, 1468, -70, -70, -70, 1367, 57,
/* 140 */ 433, 433, 297, 236, 219, 136, 91, 572, 540, 524,
/* 150 */ 524, 524, 524, 524, 524, 524, 524, 524, 524, 524,
/* 160 */ 524, 524, 524, 524, 524, 524, 524, 524, 524, 524,
/* 170 */ 524, 524, 524, 524, 524, 524, 524, 524, 524, 524,
/* 180 */ 650, 650, 650, 687, 1122, 1122, 1122, -70, -70, -70,
/* 190 */ 204, 204, 434, 434, 494, 494, 494, 504, 446, 292,
/* 200 */ 442, 428, 424, 77, 377, 377, 377, 377, 531, 498,
/* 210 */ 377, 377, 278, 215, 227, 664, 722, 574, 574, 750,
/* 220 */ 722, 750, 229, 459, 660, 459, 660, 476, 660, 574,
/* 230 */ 651, 625, 625, 459, 579, 273, -18, 1477, 1193, 1193,
/* 240 */ 1471, 1471, 1193, 1472, 1422, 1117, 1484, 1484, 1484, 1484,
/* 250 */ 1193, 1457, 1117, 1472, 1422, 1422, 1193, 1457, 1352, 1440,
/* 260 */ 1193, 1193, 1457, 1193, 1457, 1193, 1457, 1390, 1241, 1241,
/* 270 */ 1241, 1362, 1341, 1333, 1333, 1390, 1241, 1303, 1241, 1341,
/* 280 */ 1241, 1241, 1223, 1234, 1223, 1234, 1223, 1234, 1193, 1193,
/* 290 */ 1134, 1162, 1145, 1142, 1139, 1117, 1122, 1211, 1217, 1217,
/* 300 */ 1213, 1213, 1213, 1213, -70, -70, -70, -70, -70, -70,
/* 310 */ 334, 393, 497, 392, 543, 275, 901, 98, 870, 828,
/* 320 */ 753, 683, 453, 447, 535, 221, 140, 429, 54, 1202,
/* 330 */ 1196, 1179, 1057, 1180, 1133, 1178, 1149, 1131, 1065, 1103,
/* 340 */ 1033, 1043, 1034, 1130, 1028, 1132, 1144, 1027, 1121, 1120,
/* 350 */ 1103, 1098, 997, 1045, 1042, 1009, 1053, 1044, 959, 1075,
/* 360 */ 1070, 1049, 968, 931, 1015, 1032, 1001, 994, 1007, 947,
/* 370 */ 1023, 1026, 981, 893, 896, 974, 942, 967, 958, 946,
/* 380 */ 945, 877, 902, 880, 884, 847, 822, 831, 764, 714,
/* 390 */ 735, 723, 720, 587, 615, 642, 656, 576, 615, 575,
/* 400 */ 518, 463, 461, 438, 405, 390, 387, 376, 303, 224,
/* 410 */ 271, 190, 92, 72, 69, 145, 113, 33, 28,
};
#define YY_REDUCE_USE_DFLT (-169)
#define YY_REDUCE_COUNT (309)
#define YY_REDUCE_MIN (-168)
#define YY_REDUCE_MAX (1394)
static const short yy_reduce_ofst[] = {
/* 0 */ 541, 90, 1095, 147, 86, 19, 18, -49, 10, 245,
/* 10 */ 308, 306, 243, 222, -41, -51, 181, -71, 394, 1295,
/* 20 */ 1282, 1261, 1225, 1204, 1185, 1183, 1177, 1166, 1127, 1096,
/* 30 */ 1059, 1038, 982, 964, 961, 948, 908, 890, 887, 874,
/* 40 */ 834, 832, 816, 813, 800, 760, 746, 742, 739, 726,
/* 50 */ 681, 668, 665, 652, 610, 598, 591, 578, 530, 528,
/* 60 */ 525, 456, 474, 464, 517, 439, -168, 208, 406, 491,
/* 70 */ 491, 491, 491, 491, 491, 491, 491, 491, 491, 491,
/* 80 */ 491, 491, 491, 491, 491, 491, 491, 491, 491, 491,
/* 90 */ 491, 491, 491, 491, 491, 491, 491, 491, 491, 491,
/* 100 */ 491, 491, 491, 491, 491, 491, 491, 1039, 909, 993,
/* 110 */ 966, 962, 891, 845, 740, 765, 920, 747, 27, 614,
/* 120 */ 673, 758, 669, -119, 586, 672, 671, 670, 596, 544,
/* 130 */ 622, 460, 583, 491, 491, 491, 491, 491, 757, 374,
/* 140 */ 712, 638, 913, 1302, 1301, 1299, 1273, 577, 577, 1259,
/* 150 */ 1245, 1242, 1236, 1233, 1222, 1212, 1206, 1205, 1184, 1160,
/* 160 */ 1158, 1140, 1135, 1128, 1126, 1123, 1115, 1114, 1107, 1085,
/* 170 */ 1046, 1040, 987, 969, 965, 913, 895, 836, 818, 814,
/* 180 */ 876, 839, 838, 636, 776, 738, 734, 604, 421, 62,
/* 190 */ 1385, 1381, 1372, 1371, 1370, 1369, 1366, 1338, 1359, 1360,
/* 200 */ 1359, 1359, 1359, 1376, 1359, 1359, 1359, 1359, 1316, 1314,
/* 210 */ 1359, 1359, 1338, 1377, 1348, 1394, 1342, 1331, 1330, 1306,
/* 220 */ 1339, 1298, 1358, 1368, 1355, 1364, 1354, 1347, 1350, 1317,
/* 230 */ 1294, 1305, 1291, 1351, 1327, 1323, 1363, 1275, 1357, 1356,
/* 240 */ 1272, 1269, 1353, 1290, 1318, 1307, 1313, 1312, 1311, 1308,
/* 250 */ 1344, 1343, 1296, 1274, 1304, 1300, 1334, 1332, 1250, 1249,
/* 260 */ 1326, 1325, 1324, 1322, 1321, 1319, 1315, 1284, 1297, 1292,
/* 270 */ 1286, 1283, 1262, 1209, 1187, 1235, 1237, 1224, 1215, 1200,
/* 280 */ 1192, 1189, 1156, 1154, 1152, 1136, 1150, 1118, 1169, 1146,
/* 290 */ 1090, 1081, 1066, 1055, 1048, 1041, 1051, 1080, 1086, 1078,
/* 300 */ 1079, 1077, 1074, 1069, 973, 971, 970, 1047, 1037, 1036,
};
static const YYACTIONTYPE yy_default[] = {
/* 0 */ 632, 864, 952, 952, 864, 864, 952, 952, 683, 754,
/* 10 */ 952, 952, 952, 862, 952, 952, 782, 782, 926, 952,
/* 20 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 30 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 40 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 50 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 60 */ 952, 952, 952, 952, 952, 952, 952, 671, 758, 788,
/* 70 */ 952, 952, 952, 952, 952, 952, 952, 952, 925, 927,
/* 80 */ 796, 795, 905, 769, 793, 786, 790, 865, 858, 859,
/* 90 */ 857, 861, 866, 952, 789, 825, 842, 824, 836, 841,
/* 100 */ 848, 840, 837, 827, 826, 828, 829, 952, 952, 952,
/* 110 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 120 */ 952, 952, 952, 658, 723, 952, 952, 952, 952, 952,
/* 130 */ 952, 952, 952, 830, 831, 845, 844, 843, 952, 952,
/* 140 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 150 */ 932, 930, 952, 877, 952, 952, 952, 952, 952, 952,
/* 160 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 170 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 638,
/* 180 */ 754, 754, 754, 632, 952, 952, 952, 944, 758, 748,
/* 190 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 200 */ 952, 952, 952, 683, 798, 737, 915, 917, 952, 898,
/* 210 */ 735, 660, 756, 673, 746, 640, 792, 771, 771, 910,
/* 220 */ 792, 910, 697, 952, 782, 952, 782, 694, 782, 771,
/* 230 */ 860, 952, 952, 952, 755, 746, 952, 937, 762, 762,
/* 240 */ 929, 929, 762, 804, 727, 792, 734, 734, 734, 734,
/* 250 */ 762, 655, 792, 804, 727, 727, 762, 655, 904, 902,
/* 260 */ 762, 762, 655, 762, 655, 762, 655, 870, 725, 725,
/* 270 */ 725, 683, 712, 874, 874, 870, 725, 697, 725, 712,
/* 280 */ 725, 725, 775, 770, 775, 770, 775, 770, 762, 762,
/* 290 */ 952, 787, 776, 785, 783, 792, 952, 715, 648, 648,
/* 300 */ 637, 637, 637, 637, 949, 949, 944, 699, 699, 681,
/* 310 */ 952, 952, 952, 952, 952, 952, 952, 879, 952, 952,
/* 320 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 330 */ 633, 939, 952, 952, 936, 952, 952, 952, 952, 797,
/* 340 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 350 */ 914, 952, 952, 952, 952, 952, 952, 952, 908, 952,
/* 360 */ 952, 952, 952, 952, 952, 901, 900, 952, 952, 952,
/* 370 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 952,
/* 380 */ 952, 952, 716, 952, 952, 952, 952, 952, 952, 952,
/* 390 */ 952, 952, 952, 952, 784, 952, 777, 952, 863, 952,
/* 400 */ 952, 952, 952, 952, 952, 952, 952, 952, 952, 740,
/* 410 */ 813, 952, 812, 816, 811, 665, 952, 646, 952, 629,
/* 420 */ 634, 948, 951, 950, 947, 946, 945, 940, 938, 935,
/* 430 */ 934, 933, 931, 928, 924, 883, 881, 888, 887, 886,
/* 440 */ 885, 884, 882, 880, 878, 799, 794, 791, 923, 876,
/* 450 */ 736, 733, 732, 654, 941, 907, 916, 803, 802, 805,
/* 460 */ 913, 912, 911, 909, 906, 893, 801, 800, 728, 868,
/* 470 */ 867, 657, 897, 896, 895, 899, 903, 894, 764, 656,
/* 480 */ 653, 662, 718, 724, 722, 721, 720, 719, 717, 664,
/* 490 */ 672, 682, 711, 696, 695, 873, 875, 872, 871, 704,
/* 500 */ 703, 709, 708, 707, 706, 705, 702, 701, 700, 693,
/* 510 */ 692, 698, 691, 714, 713, 710, 690, 731, 730, 729,
/* 520 */ 726, 689, 688, 687, 816, 686, 685, 822, 821, 809,
/* 530 */ 852, 751, 750, 749, 761, 760, 773, 772, 807, 806,
/* 540 */ 774, 759, 753, 752, 768, 767, 766, 765, 757, 747,
/* 550 */ 779, 781, 780, 778, 854, 763, 851, 922, 921, 920,
/* 560 */ 919, 918, 856, 855, 823, 820, 676, 677, 891, 890,
/* 570 */ 892, 889, 679, 678, 675, 674, 853, 742, 741, 849,
/* 580 */ 846, 838, 834, 850, 847, 839, 835, 833, 832, 818,
/* 590 */ 817, 815, 814, 810, 819, 667, 743, 739, 738, 808,
/* 600 */ 745, 744, 684, 680, 661, 659, 652, 650, 649, 651,
/* 610 */ 647, 645, 644, 643, 642, 641, 670, 669, 668, 666,
/* 620 */ 665, 639, 636, 635, 631, 630, 628,
};
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
**
** %fallback ID X Y Z.
**
|
| ︙ | ︙ | |||
108637 108638 108639 108640 108641 108642 108643 | "ecmd", "explain", "cmdx", "cmd", "transtype", "trans_opt", "nm", "savepoint_opt", "create_table", "create_table_args", "createkw", "temp", "ifnotexists", "dbnm", "columnlist", "conslist_opt", "select", "column", "columnid", "type", "carglist", "id", "ids", "typetoken", "typename", "signed", "plus_num", "minus_num", | | | 108931 108932 108933 108934 108935 108936 108937 108938 108939 108940 108941 108942 108943 108944 108945 | "ecmd", "explain", "cmdx", "cmd", "transtype", "trans_opt", "nm", "savepoint_opt", "create_table", "create_table_args", "createkw", "temp", "ifnotexists", "dbnm", "columnlist", "conslist_opt", "select", "column", "columnid", "type", "carglist", "id", "ids", "typetoken", "typename", "signed", "plus_num", "minus_num", "cname", "ccons", "term", "expr", "onconf", "sortorder", "autoinc", "idxlist_opt", "refargs", "defer_subclause", "refarg", "refact", "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", |
| ︙ | ︙ | |||
108717 108718 108719 108720 108721 108722 108723 | /* 46 */ "typetoken ::= typename", /* 47 */ "typetoken ::= typename LP signed RP", /* 48 */ "typetoken ::= typename LP signed COMMA signed RP", /* 49 */ "typename ::= ids", /* 50 */ "typename ::= typename ids", /* 51 */ "signed ::= plus_num", /* 52 */ "signed ::= minus_num", | | | | | 109011 109012 109013 109014 109015 109016 109017 109018 109019 109020 109021 109022 109023 109024 109025 109026 109027 109028 | /* 46 */ "typetoken ::= typename", /* 47 */ "typetoken ::= typename LP signed RP", /* 48 */ "typetoken ::= typename LP signed COMMA signed RP", /* 49 */ "typename ::= ids", /* 50 */ "typename ::= typename ids", /* 51 */ "signed ::= plus_num", /* 52 */ "signed ::= minus_num", /* 53 */ "carglist ::= carglist cname ccons", /* 54 */ "carglist ::=", /* 55 */ "cname ::= CONSTRAINT nm", /* 56 */ "cname ::=", /* 57 */ "ccons ::= DEFAULT term", /* 58 */ "ccons ::= DEFAULT LP expr RP", /* 59 */ "ccons ::= DEFAULT PLUS term", /* 60 */ "ccons ::= DEFAULT MINUS term", /* 61 */ "ccons ::= DEFAULT id", /* 62 */ "ccons ::= NULL onconf", /* 63 */ "ccons ::= NOT NULL onconf", |
| ︙ | ︙ | |||
108754 108755 108756 108757 108758 108759 108760 | /* 83 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", /* 84 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", /* 85 */ "init_deferred_pred_opt ::=", /* 86 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", /* 87 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", /* 88 */ "conslist_opt ::=", /* 89 */ "conslist_opt ::= COMMA conslist", | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | | | | | | | | | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 109110 109111 109112 109113 109114 109115 109116 109117 109118 109119 109120 109121 109122 109123 109124 109125 109126 109127 109128 109129 109130 109131 109132 109133 109134 109135 109136 109137 109138 109139 109140 109141 109142 109143 109144 109145 109146 109147 109148 109149 109150 109151 109152 109153 109154 109155 109156 109157 109158 109159 109160 109161 109162 109163 109164 109165 109166 109167 109168 109169 109170 109171 109172 109173 109174 109175 109176 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 109258 109259 109260 109261 109262 109263 109264 109265 109266 109267 109268 109269 109270 109271 109272 109273 109274 109275 109276 109277 109278 109279 109280 109281 109282 109283 109284 109285 109286 109287 109288 109289 109290 109291 109292 109293 109294 109295 109296 | /* 83 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", /* 84 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", /* 85 */ "init_deferred_pred_opt ::=", /* 86 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", /* 87 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", /* 88 */ "conslist_opt ::=", /* 89 */ "conslist_opt ::= COMMA conslist", /* 90 */ "conslist ::= conslist COMMA cname tcons", /* 91 */ "conslist ::= cname tcons", /* 92 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf", /* 93 */ "tcons ::= UNIQUE LP idxlist RP onconf", /* 94 */ "tcons ::= CHECK LP expr RP onconf", /* 95 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt", /* 96 */ "defer_subclause_opt ::=", /* 97 */ "defer_subclause_opt ::= defer_subclause", /* 98 */ "onconf ::=", /* 99 */ "onconf ::= ON CONFLICT resolvetype", /* 100 */ "orconf ::=", /* 101 */ "orconf ::= OR resolvetype", /* 102 */ "resolvetype ::= raisetype", /* 103 */ "resolvetype ::= IGNORE", /* 104 */ "resolvetype ::= REPLACE", /* 105 */ "cmd ::= DROP TABLE ifexists fullname", /* 106 */ "ifexists ::= IF EXISTS", /* 107 */ "ifexists ::=", /* 108 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select", /* 109 */ "cmd ::= DROP VIEW ifexists fullname", /* 110 */ "cmd ::= select", /* 111 */ "select ::= oneselect", /* 112 */ "select ::= select multiselect_op oneselect", /* 113 */ "multiselect_op ::= UNION", /* 114 */ "multiselect_op ::= UNION ALL", /* 115 */ "multiselect_op ::= EXCEPT|INTERSECT", /* 116 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", /* 117 */ "distinct ::= DISTINCT", /* 118 */ "distinct ::= ALL", /* 119 */ "distinct ::=", /* 120 */ "sclp ::= selcollist COMMA", /* 121 */ "sclp ::=", /* 122 */ "selcollist ::= sclp expr as", /* 123 */ "selcollist ::= sclp STAR", /* 124 */ "selcollist ::= sclp nm DOT STAR", /* 125 */ "as ::= AS nm", /* 126 */ "as ::= ids", /* 127 */ "as ::=", /* 128 */ "from ::=", /* 129 */ "from ::= FROM seltablist", /* 130 */ "stl_prefix ::= seltablist joinop", /* 131 */ "stl_prefix ::=", /* 132 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", /* 133 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", /* 134 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", /* 135 */ "dbnm ::=", /* 136 */ "dbnm ::= DOT nm", /* 137 */ "fullname ::= nm dbnm", /* 138 */ "joinop ::= COMMA|JOIN", /* 139 */ "joinop ::= JOIN_KW JOIN", /* 140 */ "joinop ::= JOIN_KW nm JOIN", /* 141 */ "joinop ::= JOIN_KW nm nm JOIN", /* 142 */ "on_opt ::= ON expr", /* 143 */ "on_opt ::=", /* 144 */ "indexed_opt ::=", /* 145 */ "indexed_opt ::= INDEXED BY nm", /* 146 */ "indexed_opt ::= NOT INDEXED", /* 147 */ "using_opt ::= USING LP inscollist RP", /* 148 */ "using_opt ::=", /* 149 */ "orderby_opt ::=", /* 150 */ "orderby_opt ::= ORDER BY sortlist", /* 151 */ "sortlist ::= sortlist COMMA expr sortorder", /* 152 */ "sortlist ::= expr sortorder", /* 153 */ "sortorder ::= ASC", /* 154 */ "sortorder ::= DESC", /* 155 */ "sortorder ::=", /* 156 */ "groupby_opt ::=", /* 157 */ "groupby_opt ::= GROUP BY nexprlist", /* 158 */ "having_opt ::=", /* 159 */ "having_opt ::= HAVING expr", /* 160 */ "limit_opt ::=", /* 161 */ "limit_opt ::= LIMIT expr", /* 162 */ "limit_opt ::= LIMIT expr OFFSET expr", /* 163 */ "limit_opt ::= LIMIT expr COMMA expr", /* 164 */ "cmd ::= DELETE FROM fullname indexed_opt where_opt", /* 165 */ "where_opt ::=", /* 166 */ "where_opt ::= WHERE expr", /* 167 */ "cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt", /* 168 */ "setlist ::= setlist COMMA nm EQ expr", /* 169 */ "setlist ::= nm EQ expr", /* 170 */ "cmd ::= insert_cmd INTO fullname inscollist_opt valuelist", /* 171 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select", /* 172 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES", /* 173 */ "insert_cmd ::= INSERT orconf", /* 174 */ "insert_cmd ::= REPLACE", /* 175 */ "valuelist ::= VALUES LP nexprlist RP", /* 176 */ "valuelist ::= valuelist COMMA LP exprlist RP", /* 177 */ "inscollist_opt ::=", /* 178 */ "inscollist_opt ::= LP inscollist RP", /* 179 */ "inscollist ::= inscollist COMMA nm", /* 180 */ "inscollist ::= nm", /* 181 */ "expr ::= term", /* 182 */ "expr ::= LP expr RP", /* 183 */ "term ::= NULL", /* 184 */ "expr ::= id", /* 185 */ "expr ::= JOIN_KW", /* 186 */ "expr ::= nm DOT nm", /* 187 */ "expr ::= nm DOT nm DOT nm", /* 188 */ "term ::= INTEGER|FLOAT|BLOB", /* 189 */ "term ::= STRING", /* 190 */ "expr ::= REGISTER", /* 191 */ "expr ::= VARIABLE", /* 192 */ "expr ::= expr COLLATE ids", /* 193 */ "expr ::= CAST LP expr AS typetoken RP", /* 194 */ "expr ::= ID LP distinct exprlist RP", /* 195 */ "expr ::= ID LP STAR RP", /* 196 */ "term ::= CTIME_KW", /* 197 */ "expr ::= expr AND expr", /* 198 */ "expr ::= expr OR expr", /* 199 */ "expr ::= expr LT|GT|GE|LE expr", /* 200 */ "expr ::= expr EQ|NE expr", /* 201 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", /* 202 */ "expr ::= expr PLUS|MINUS expr", /* 203 */ "expr ::= expr STAR|SLASH|REM expr", /* 204 */ "expr ::= expr CONCAT expr", /* 205 */ "likeop ::= LIKE_KW", /* 206 */ "likeop ::= NOT LIKE_KW", /* 207 */ "likeop ::= MATCH", /* 208 */ "likeop ::= NOT MATCH", /* 209 */ "expr ::= expr likeop expr", /* 210 */ "expr ::= expr likeop expr ESCAPE expr", /* 211 */ "expr ::= expr ISNULL|NOTNULL", /* 212 */ "expr ::= expr NOT NULL", /* 213 */ "expr ::= expr IS expr", /* 214 */ "expr ::= expr IS NOT expr", /* 215 */ "expr ::= NOT expr", /* 216 */ "expr ::= BITNOT expr", /* 217 */ "expr ::= MINUS expr", /* 218 */ "expr ::= PLUS expr", /* 219 */ "between_op ::= BETWEEN", /* 220 */ "between_op ::= NOT BETWEEN", /* 221 */ "expr ::= expr between_op expr AND expr", /* 222 */ "in_op ::= IN", /* 223 */ "in_op ::= NOT IN", /* 224 */ "expr ::= expr in_op LP exprlist RP", /* 225 */ "expr ::= LP select RP", /* 226 */ "expr ::= expr in_op LP select RP", /* 227 */ "expr ::= expr in_op nm dbnm", /* 228 */ "expr ::= EXISTS LP select RP", /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END", /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", /* 231 */ "case_exprlist ::= WHEN expr THEN expr", /* 232 */ "case_else ::= ELSE expr", /* 233 */ "case_else ::=", /* 234 */ "case_operand ::= expr", /* 235 */ "case_operand ::=", /* 236 */ "exprlist ::= nexprlist", /* 237 */ "exprlist ::=", /* 238 */ "nexprlist ::= nexprlist COMMA expr", /* 239 */ "nexprlist ::= expr", /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP", /* 241 */ "uniqueflag ::= UNIQUE", /* 242 */ "uniqueflag ::=", /* 243 */ "idxlist_opt ::=", /* 244 */ "idxlist_opt ::= LP idxlist RP", /* 245 */ "idxlist ::= idxlist COMMA nm collate sortorder", /* 246 */ "idxlist ::= nm collate sortorder", /* 247 */ "collate ::=", /* 248 */ "collate ::= COLLATE ids", /* 249 */ "cmd ::= DROP INDEX ifexists fullname", /* 250 */ "cmd ::= VACUUM", /* 251 */ "cmd ::= VACUUM nm", /* 252 */ "cmd ::= PRAGMA nm dbnm", /* 253 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", /* 254 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", /* 255 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", /* 256 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", /* 257 */ "nmnum ::= plus_num", /* 258 */ "nmnum ::= nm", /* 259 */ "nmnum ::= ON", /* 260 */ "nmnum ::= DELETE", /* 261 */ "nmnum ::= DEFAULT", /* 262 */ "plus_num ::= PLUS number", /* 263 */ "plus_num ::= number", /* 264 */ "minus_num ::= MINUS number", /* 265 */ "number ::= INTEGER|FLOAT", /* 266 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", /* 267 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", /* 268 */ "trigger_time ::= BEFORE", /* 269 */ "trigger_time ::= AFTER", /* 270 */ "trigger_time ::= INSTEAD OF", /* 271 */ "trigger_time ::=", /* 272 */ "trigger_event ::= DELETE|INSERT", /* 273 */ "trigger_event ::= UPDATE", /* 274 */ "trigger_event ::= UPDATE OF inscollist", /* 275 */ "foreach_clause ::=", /* 276 */ "foreach_clause ::= FOR EACH ROW", /* 277 */ "when_clause ::=", /* 278 */ "when_clause ::= WHEN expr", /* 279 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", /* 280 */ "trigger_cmd_list ::= trigger_cmd SEMI", /* 281 */ "trnm ::= nm", /* 282 */ "trnm ::= nm DOT nm", /* 283 */ "tridxby ::=", /* 284 */ "tridxby ::= INDEXED BY nm", /* 285 */ "tridxby ::= NOT INDEXED", /* 286 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", /* 287 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt valuelist", /* 288 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select", /* 289 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", /* 290 */ "trigger_cmd ::= select", /* 291 */ "expr ::= RAISE LP IGNORE RP", /* 292 */ "expr ::= RAISE LP raisetype COMMA nm RP", /* 293 */ "raisetype ::= ROLLBACK", /* 294 */ "raisetype ::= ABORT", /* 295 */ "raisetype ::= FAIL", /* 296 */ "cmd ::= DROP TRIGGER ifexists fullname", /* 297 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", /* 298 */ "cmd ::= DETACH database_kw_opt expr", /* 299 */ "key_opt ::=", /* 300 */ "key_opt ::= KEY expr", /* 301 */ "database_kw_opt ::= DATABASE", /* 302 */ "database_kw_opt ::=", /* 303 */ "cmd ::= REINDEX", /* 304 */ "cmd ::= REINDEX nm dbnm", /* 305 */ "cmd ::= ANALYZE", /* 306 */ "cmd ::= ANALYZE nm dbnm", /* 307 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", /* 308 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column", /* 309 */ "add_column_fullname ::= fullname", /* 310 */ "kwcolumn_opt ::=", /* 311 */ "kwcolumn_opt ::= COLUMNKW", /* 312 */ "cmd ::= create_vtab", /* 313 */ "cmd ::= create_vtab LP vtabarglist RP", /* 314 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", /* 315 */ "vtabarglist ::= vtabarg", /* 316 */ "vtabarglist ::= vtabarglist COMMA vtabarg", /* 317 */ "vtabarg ::=", /* 318 */ "vtabarg ::= vtabarg vtabargtoken", /* 319 */ "vtabargtoken ::= ANY", /* 320 */ "vtabargtoken ::= lp anylist RP", /* 321 */ "lp ::= LP", /* 322 */ "anylist ::=", /* 323 */ "anylist ::= anylist LP anylist RP", /* 324 */ "anylist ::= anylist ANY", }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. |
| ︙ | ︙ | |||
109436 109437 109438 109439 109440 109441 109442 |
{ 167, 1 },
{ 167, 4 },
{ 167, 6 },
{ 168, 1 },
{ 168, 2 },
{ 169, 1 },
{ 169, 1 },
| | | | | 109728 109729 109730 109731 109732 109733 109734 109735 109736 109737 109738 109739 109740 109741 109742 109743 109744 109745 |
{ 167, 1 },
{ 167, 4 },
{ 167, 6 },
{ 168, 1 },
{ 168, 2 },
{ 169, 1 },
{ 169, 1 },
{ 164, 3 },
{ 164, 0 },
{ 172, 2 },
{ 172, 0 },
{ 173, 2 },
{ 173, 4 },
{ 173, 3 },
{ 173, 3 },
{ 173, 2 },
{ 173, 2 },
{ 173, 3 },
|
| ︙ | ︙ | |||
109473 109474 109475 109476 109477 109478 109479 |
{ 181, 3 },
{ 181, 2 },
{ 184, 0 },
{ 184, 2 },
{ 184, 2 },
{ 159, 0 },
{ 159, 2 },
| | < < | 109765 109766 109767 109768 109769 109770 109771 109772 109773 109774 109775 109776 109777 109778 109779 109780 |
{ 181, 3 },
{ 181, 2 },
{ 184, 0 },
{ 184, 2 },
{ 184, 2 },
{ 159, 0 },
{ 159, 2 },
{ 185, 4 },
{ 185, 2 },
{ 186, 7 },
{ 186, 5 },
{ 186, 5 },
{ 186, 10 },
{ 188, 0 },
{ 188, 1 },
{ 176, 0 },
|
| ︙ | ︙ | |||
109785 109786 109787 109788 109789 109790 109791 |
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);
| | | | 110075 110076 110077 110078 110079 110080 110081 110082 110083 110084 110085 110086 110087 110088 110089 110090 |
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 113: /* multiselect_op ::= UNION */ yytestcase(yyruleno==113);
case 115: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==115);
{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 */
|
| ︙ | ︙ | |||
109828 109829 109830 109831 109832 109833 109834 |
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);
| | | | | | | | | | | | 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 |
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 96: /* defer_subclause_opt ::= */ yytestcase(yyruleno==96);
case 107: /* ifexists ::= */ yytestcase(yyruleno==107);
case 118: /* distinct ::= ALL */ yytestcase(yyruleno==118);
case 119: /* distinct ::= */ yytestcase(yyruleno==119);
case 219: /* between_op ::= BETWEEN */ yytestcase(yyruleno==219);
case 222: /* in_op ::= IN */ yytestcase(yyruleno==222);
{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 106: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==106);
case 117: /* distinct ::= DISTINCT */ yytestcase(yyruleno==117);
case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220);
case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223);
{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;
|
| ︙ | ︙ | |||
109877 109878 109879 109880 109881 109882 109883 |
case 39: /* id ::= INDEXED */ yytestcase(yyruleno==39);
case 40: /* ids ::= ID|STRING */ yytestcase(yyruleno==40);
case 41: /* nm ::= id */ yytestcase(yyruleno==41);
case 42: /* nm ::= STRING */ yytestcase(yyruleno==42);
case 43: /* nm ::= JOIN_KW */ yytestcase(yyruleno==43);
case 46: /* typetoken ::= typename */ yytestcase(yyruleno==46);
case 49: /* typename ::= ids */ yytestcase(yyruleno==49);
| | | | | | | | | | | | | | | | > > > > > > | 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 |
case 39: /* id ::= INDEXED */ yytestcase(yyruleno==39);
case 40: /* ids ::= ID|STRING */ yytestcase(yyruleno==40);
case 41: /* nm ::= id */ yytestcase(yyruleno==41);
case 42: /* nm ::= STRING */ yytestcase(yyruleno==42);
case 43: /* nm ::= JOIN_KW */ yytestcase(yyruleno==43);
case 46: /* typetoken ::= typename */ yytestcase(yyruleno==46);
case 49: /* typename ::= ids */ yytestcase(yyruleno==49);
case 125: /* as ::= AS nm */ yytestcase(yyruleno==125);
case 126: /* as ::= ids */ yytestcase(yyruleno==126);
case 136: /* dbnm ::= DOT nm */ yytestcase(yyruleno==136);
case 145: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==145);
case 248: /* collate ::= COLLATE ids */ yytestcase(yyruleno==248);
case 257: /* nmnum ::= plus_num */ yytestcase(yyruleno==257);
case 258: /* nmnum ::= nm */ yytestcase(yyruleno==258);
case 259: /* nmnum ::= ON */ yytestcase(yyruleno==259);
case 260: /* nmnum ::= DELETE */ yytestcase(yyruleno==260);
case 261: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==261);
case 262: /* plus_num ::= PLUS number */ yytestcase(yyruleno==262);
case 263: /* plus_num ::= number */ yytestcase(yyruleno==263);
case 264: /* minus_num ::= MINUS number */ yytestcase(yyruleno==264);
case 265: /* number ::= INTEGER|FLOAT */ yytestcase(yyruleno==265);
case 281: /* trnm ::= nm */ yytestcase(yyruleno==281);
{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 */
{
yygotominor.yy0.z = yymsp[-3].minor.yy0.z;
yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
}
break;
case 48: /* typetoken ::= typename LP signed COMMA signed RP */
{
yygotominor.yy0.z = yymsp[-5].minor.yy0.z;
yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
}
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 55: /* cname ::= CONSTRAINT nm */
{pParse->constraintName = yymsp[0].minor.yy0;}
break;
case 56: /* cname ::= */
{pParse->constraintName.n = 0;}
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);}
|
| ︙ | ︙ | |||
109988 109989 109990 109991 109992 109993 109994 |
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 */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
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 97: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==97);
case 99: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==99);
case 102: /* resolvetype ::= raisetype */ yytestcase(yyruleno==102);
{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 92: /* 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 93: /* 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 94: /* tcons ::= CHECK LP expr RP onconf */
{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy342.pExpr);}
break;
case 95: /* 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 98: /* onconf ::= */
{yygotominor.yy392 = OE_Default;}
break;
case 100: /* orconf ::= */
{yygotominor.yy258 = OE_Default;}
break;
case 101: /* orconf ::= OR resolvetype */
{yygotominor.yy258 = (u8)yymsp[0].minor.yy392;}
break;
case 103: /* resolvetype ::= IGNORE */
{yygotominor.yy392 = OE_Ignore;}
break;
case 104: /* resolvetype ::= REPLACE */
{yygotominor.yy392 = OE_Replace;}
break;
case 105: /* cmd ::= DROP TABLE ifexists fullname */
{
sqlite3DropTable(pParse, yymsp[0].minor.yy347, 0, yymsp[-1].minor.yy392);
}
break;
case 108: /* 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 109: /* cmd ::= DROP VIEW ifexists fullname */
{
sqlite3DropTable(pParse, yymsp[0].minor.yy347, 1, yymsp[-1].minor.yy392);
}
break;
case 110: /* 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 111: /* select ::= oneselect */
{yygotominor.yy159 = yymsp[0].minor.yy159;}
break;
case 112: /* 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 114: /* multiselect_op ::= UNION ALL */
{yygotominor.yy392 = TK_ALL;}
break;
case 116: /* 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 120: /* sclp ::= selcollist COMMA */
case 244: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==244);
{yygotominor.yy442 = yymsp[-1].minor.yy442;}
break;
case 121: /* sclp ::= */
case 149: /* orderby_opt ::= */ yytestcase(yyruleno==149);
case 156: /* groupby_opt ::= */ yytestcase(yyruleno==156);
case 237: /* exprlist ::= */ yytestcase(yyruleno==237);
case 243: /* idxlist_opt ::= */ yytestcase(yyruleno==243);
{yygotominor.yy442 = 0;}
break;
case 122: /* 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 123: /* selcollist ::= sclp STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
yygotominor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy442, p);
}
break;
case 124: /* 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 127: /* as ::= */
{yygotominor.yy0.n = 0;}
break;
case 128: /* from ::= */
{yygotominor.yy347 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy347));}
break;
case 129: /* from ::= FROM seltablist */
{
yygotominor.yy347 = yymsp[0].minor.yy347;
sqlite3SrcListShiftJoinType(yygotominor.yy347);
}
break;
case 130: /* 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 131: /* stl_prefix ::= */
{yygotominor.yy347 = 0;}
break;
case 132: /* 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 133: /* 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 134: /* 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 135: /* dbnm ::= */
case 144: /* indexed_opt ::= */ yytestcase(yyruleno==144);
{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
break;
case 137: /* fullname ::= nm dbnm */
{yygotominor.yy347 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
break;
case 138: /* joinop ::= COMMA|JOIN */
{ yygotominor.yy392 = JT_INNER; }
break;
case 139: /* joinop ::= JOIN_KW JOIN */
{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
break;
case 140: /* joinop ::= JOIN_KW nm JOIN */
{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
break;
case 141: /* joinop ::= JOIN_KW nm nm JOIN */
{ yygotominor.yy392 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
break;
case 142: /* on_opt ::= ON expr */
case 159: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==159);
case 166: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==166);
case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232);
case 234: /* case_operand ::= expr */ yytestcase(yyruleno==234);
{yygotominor.yy122 = yymsp[0].minor.yy342.pExpr;}
break;
case 143: /* on_opt ::= */
case 158: /* having_opt ::= */ yytestcase(yyruleno==158);
case 165: /* where_opt ::= */ yytestcase(yyruleno==165);
case 233: /* case_else ::= */ yytestcase(yyruleno==233);
case 235: /* case_operand ::= */ yytestcase(yyruleno==235);
{yygotominor.yy122 = 0;}
break;
case 146: /* indexed_opt ::= NOT INDEXED */
{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
break;
case 147: /* using_opt ::= USING LP inscollist RP */
case 178: /* inscollist_opt ::= LP inscollist RP */ yytestcase(yyruleno==178);
{yygotominor.yy180 = yymsp[-1].minor.yy180;}
break;
case 148: /* using_opt ::= */
case 177: /* inscollist_opt ::= */ yytestcase(yyruleno==177);
{yygotominor.yy180 = 0;}
break;
case 150: /* orderby_opt ::= ORDER BY sortlist */
case 157: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==157);
case 236: /* exprlist ::= nexprlist */ yytestcase(yyruleno==236);
{yygotominor.yy442 = yymsp[0].minor.yy442;}
break;
case 151: /* 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 152: /* 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 153: /* sortorder ::= ASC */
case 155: /* sortorder ::= */ yytestcase(yyruleno==155);
{yygotominor.yy392 = SQLITE_SO_ASC;}
break;
case 154: /* sortorder ::= DESC */
{yygotominor.yy392 = SQLITE_SO_DESC;}
break;
case 160: /* limit_opt ::= */
{yygotominor.yy64.pLimit = 0; yygotominor.yy64.pOffset = 0;}
break;
case 161: /* limit_opt ::= LIMIT expr */
{yygotominor.yy64.pLimit = yymsp[0].minor.yy342.pExpr; yygotominor.yy64.pOffset = 0;}
break;
case 162: /* limit_opt ::= LIMIT expr OFFSET expr */
{yygotominor.yy64.pLimit = yymsp[-2].minor.yy342.pExpr; yygotominor.yy64.pOffset = yymsp[0].minor.yy342.pExpr;}
break;
case 163: /* limit_opt ::= LIMIT expr COMMA expr */
{yygotominor.yy64.pOffset = yymsp[-2].minor.yy342.pExpr; yygotominor.yy64.pLimit = yymsp[0].minor.yy342.pExpr;}
break;
case 164: /* 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 167: /* 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 168: /* 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 169: /* 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 170: /* 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 171: /* 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 172: /* 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 173: /* insert_cmd ::= INSERT orconf */
{yygotominor.yy258 = yymsp[0].minor.yy258;}
break;
case 174: /* insert_cmd ::= REPLACE */
{yygotominor.yy258 = OE_Replace;}
break;
case 175: /* valuelist ::= VALUES LP nexprlist RP */
{
yygotominor.yy487.pList = yymsp[-1].minor.yy442;
yygotominor.yy487.pSelect = 0;
}
break;
case 176: /* 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 179: /* inscollist ::= inscollist COMMA nm */
{yygotominor.yy180 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy180,&yymsp[0].minor.yy0);}
break;
case 180: /* inscollist ::= nm */
{yygotominor.yy180 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
break;
case 181: /* expr ::= term */
{yygotominor.yy342 = yymsp[0].minor.yy342;}
break;
case 182: /* 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 183: /* term ::= NULL */
case 188: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==188);
case 189: /* term ::= STRING */ yytestcase(yyruleno==189);
{spanExpr(&yygotominor.yy342, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
break;
case 184: /* expr ::= id */
case 185: /* expr ::= JOIN_KW */ yytestcase(yyruleno==185);
{spanExpr(&yygotominor.yy342, pParse, TK_ID, &yymsp[0].minor.yy0);}
break;
case 186: /* 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 187: /* 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 190: /* 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 191: /* 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 192: /* 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 193: /* 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 194: /* 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 195: /* 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 196: /* 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 197: /* expr ::= expr AND expr */
case 198: /* expr ::= expr OR expr */ yytestcase(yyruleno==198);
case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199);
case 200: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==200);
case 201: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==201);
case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202);
case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203);
case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204);
{spanBinaryExpr(&yygotominor.yy342,pParse,yymsp[-1].major,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);}
break;
case 205: /* likeop ::= LIKE_KW */
case 207: /* likeop ::= MATCH */ yytestcase(yyruleno==207);
{yygotominor.yy318.eOperator = yymsp[0].minor.yy0; yygotominor.yy318.bNot = 0;}
break;
case 206: /* likeop ::= NOT LIKE_KW */
case 208: /* likeop ::= NOT MATCH */ yytestcase(yyruleno==208);
{yygotominor.yy318.eOperator = yymsp[0].minor.yy0; yygotominor.yy318.bNot = 1;}
break;
case 209: /* 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.bNot ) 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 210: /* 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.bNot ) 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 211: /* expr ::= expr ISNULL|NOTNULL */
{spanUnaryPostfix(&yygotominor.yy342,pParse,yymsp[0].major,&yymsp[-1].minor.yy342,&yymsp[0].minor.yy0);}
break;
case 212: /* expr ::= expr NOT NULL */
{spanUnaryPostfix(&yygotominor.yy342,pParse,TK_NOTNULL,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy0);}
break;
case 213: /* 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 214: /* 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 215: /* expr ::= NOT expr */
case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216);
{spanUnaryPrefix(&yygotominor.yy342,pParse,yymsp[-1].major,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
case 217: /* expr ::= MINUS expr */
{spanUnaryPrefix(&yygotominor.yy342,pParse,TK_UMINUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
case 218: /* expr ::= PLUS expr */
{spanUnaryPrefix(&yygotominor.yy342,pParse,TK_UPLUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);}
break;
case 221: /* 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 224: /* expr ::= expr in_op LP exprlist RP */
{
if( yymsp[-1].minor.yy442==0 ){
/* Expressions of the form
**
** expr1 IN ()
** expr1 NOT IN ()
**
|
| ︙ | ︙ | |||
110515 110516 110517 110518 110519 110520 110521 |
}
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;
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | | < < | | | | | | | | | | | | | | 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 110966 110967 110968 110969 110970 110971 110972 110973 110974 110975 110976 110977 110978 110979 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 111007 111008 111009 111010 111011 111012 111013 111014 111015 111016 111017 111018 111019 111020 111021 111022 111023 111024 111025 111026 111027 111028 111029 111030 111031 111032 111033 111034 111035 111036 111037 111038 111039 111040 111041 111042 111043 111044 111045 111046 111047 111048 111049 111050 111051 111052 111053 111054 111055 111056 111057 111058 111059 111060 111061 111062 111063 111064 111065 111066 111067 111068 111069 111070 111071 111072 111073 111074 111075 111076 111077 111078 111079 111080 111081 111082 111083 111084 111085 111086 111087 111088 111089 111090 111091 111092 111093 111094 111095 111096 111097 111098 111099 111100 111101 111102 111103 111104 111105 111106 111107 111108 111109 111110 111111 111112 111113 111114 111115 111116 111117 111118 111119 111120 111121 111122 111123 111124 111125 111126 111127 111128 111129 111130 111131 111132 111133 111134 111135 111136 111137 111138 111139 111140 111141 111142 111143 111144 111145 111146 111147 111148 111149 111150 111151 111152 111153 111154 111155 111156 111157 111158 111159 111160 111161 111162 111163 111164 111165 111166 111167 111168 111169 111170 111171 111172 111173 111174 111175 111176 111177 111178 111179 111180 111181 111182 111183 111184 111185 111186 111187 111188 111189 111190 111191 111192 111193 |
}
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 225: /* 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 226: /* 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 227: /* 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 228: /* 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 229: /* 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 230: /* 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 231: /* 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 238: /* nexprlist ::= nexprlist COMMA expr */
{yygotominor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[0].minor.yy342.pExpr);}
break;
case 239: /* nexprlist ::= expr */
{yygotominor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy342.pExpr);}
break;
case 240: /* 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 241: /* uniqueflag ::= UNIQUE */
case 294: /* raisetype ::= ABORT */ yytestcase(yyruleno==294);
{yygotominor.yy392 = OE_Abort;}
break;
case 242: /* uniqueflag ::= */
{yygotominor.yy392 = OE_None;}
break;
case 245: /* 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 246: /* 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 247: /* collate ::= */
{yygotominor.yy0.z = 0; yygotominor.yy0.n = 0;}
break;
case 249: /* cmd ::= DROP INDEX ifexists fullname */
{sqlite3DropIndex(pParse, yymsp[0].minor.yy347, yymsp[-1].minor.yy392);}
break;
case 250: /* cmd ::= VACUUM */
case 251: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==251);
{sqlite3Vacuum(pParse);}
break;
case 252: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
case 253: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
case 254: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
case 255: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
case 256: /* 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 266: /* 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 267: /* 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 268: /* trigger_time ::= BEFORE */
case 271: /* trigger_time ::= */ yytestcase(yyruleno==271);
{ yygotominor.yy392 = TK_BEFORE; }
break;
case 269: /* trigger_time ::= AFTER */
{ yygotominor.yy392 = TK_AFTER; }
break;
case 270: /* trigger_time ::= INSTEAD OF */
{ yygotominor.yy392 = TK_INSTEAD;}
break;
case 272: /* trigger_event ::= DELETE|INSERT */
case 273: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==273);
{yygotominor.yy410.a = yymsp[0].major; yygotominor.yy410.b = 0;}
break;
case 274: /* trigger_event ::= UPDATE OF inscollist */
{yygotominor.yy410.a = TK_UPDATE; yygotominor.yy410.b = yymsp[0].minor.yy180;}
break;
case 277: /* when_clause ::= */
case 299: /* key_opt ::= */ yytestcase(yyruleno==299);
{ yygotominor.yy122 = 0; }
break;
case 278: /* when_clause ::= WHEN expr */
case 300: /* key_opt ::= KEY expr */ yytestcase(yyruleno==300);
{ yygotominor.yy122 = yymsp[0].minor.yy342.pExpr; }
break;
case 279: /* 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 280: /* 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 282: /* 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 284: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
case 285: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
case 286: /* 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 287: /* 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 288: /* 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 289: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
{yygotominor.yy327 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy122);}
break;
case 290: /* trigger_cmd ::= select */
{yygotominor.yy327 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy159); }
break;
case 291: /* 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 292: /* 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 293: /* raisetype ::= ROLLBACK */
{yygotominor.yy392 = OE_Rollback;}
break;
case 295: /* raisetype ::= FAIL */
{yygotominor.yy392 = OE_Fail;}
break;
case 296: /* cmd ::= DROP TRIGGER ifexists fullname */
{
sqlite3DropTrigger(pParse,yymsp[0].minor.yy347,yymsp[-1].minor.yy392);
}
break;
case 297: /* 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 298: /* cmd ::= DETACH database_kw_opt expr */
{
sqlite3Detach(pParse, yymsp[0].minor.yy342.pExpr);
}
break;
case 303: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
case 304: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
case 305: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
case 306: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
case 307: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy347,&yymsp[0].minor.yy0);
}
break;
case 308: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
{
sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
}
break;
case 309: /* add_column_fullname ::= fullname */
{
pParse->db->lookaside.bEnabled = 0;
sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy347);
}
break;
case 312: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
case 313: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
case 314: /* 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 317: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
case 319: /* vtabargtoken ::= ANY */
case 320: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==320);
case 321: /* lp ::= LP */ yytestcase(yyruleno==321);
{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);
/* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
/* (10) trans_opt ::= */ yytestcase(yyruleno==10);
/* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
/* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
/* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
/* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
/* (25) cmd ::= create_table create_table_args */ yytestcase(yyruleno==25);
/* (34) columnlist ::= columnlist COMMA column */ yytestcase(yyruleno==34);
/* (35) columnlist ::= column */ yytestcase(yyruleno==35);
/* (44) type ::= */ yytestcase(yyruleno==44);
/* (51) signed ::= plus_num */ yytestcase(yyruleno==51);
/* (52) signed ::= minus_num */ yytestcase(yyruleno==52);
/* (53) carglist ::= carglist cname ccons */ yytestcase(yyruleno==53);
/* (54) carglist ::= */ yytestcase(yyruleno==54);
/* (62) ccons ::= NULL onconf */ yytestcase(yyruleno==62);
/* (90) conslist ::= conslist COMMA cname tcons */ yytestcase(yyruleno==90);
/* (91) conslist ::= cname tcons */ yytestcase(yyruleno==91);
/* (275) foreach_clause ::= */ yytestcase(yyruleno==275);
/* (276) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==276);
/* (283) tridxby ::= */ yytestcase(yyruleno==283);
/* (301) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==301);
/* (302) database_kw_opt ::= */ yytestcase(yyruleno==302);
/* (310) kwcolumn_opt ::= */ yytestcase(yyruleno==310);
/* (311) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==311);
/* (315) vtabarglist ::= vtabarg */ yytestcase(yyruleno==315);
/* (316) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==316);
/* (318) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==318);
/* (322) anylist ::= */ yytestcase(yyruleno==322);
/* (323) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==323);
/* (324) anylist ::= anylist ANY */ yytestcase(yyruleno==324);
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 ){
|
| ︙ | ︙ | |||
113172 113173 113174 113175 113176 113177 113178 |
sqlite3_free(db->lookaside.pStart);
}
sqlite3_free(db);
return SQLITE_OK;
}
/*
| | > > > | | > | | | 113464 113465 113466 113467 113468 113469 113470 113471 113472 113473 113474 113475 113476 113477 113478 113479 113480 113481 113482 113483 113484 113485 113486 113487 113488 113489 113490 113491 113492 113493 113494 |
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 ){
|
| ︙ | ︙ | |||
113239 113240 113241 113242 113243 113244 113245 |
/* 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",
};
| > > > > > > > | | | > | < | > > | 113535 113536 113537 113538 113539 113540 113541 113542 113543 113544 113545 113546 113547 113548 113549 113550 113551 113552 113553 113554 113555 113556 113557 113558 113559 113560 113561 113562 113563 |
/* 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.
|
| ︙ | ︙ | |||
113622 113623 113624 113625 113626 113627 113628 | db->xProfile = xProfile; db->pProfileArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_TRACE */ | | < | | 113927 113928 113929 113930 113931 113932 113933 113934 113935 113936 113937 113938 113939 113940 113941 113942 | 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 */ |
| ︙ | ︙ | |||
115015 115016 115017 115018 115019 115020 115021 |
}
/*
** 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;
| > | | < < < < < < < < | | | | | | | | | | | | | | | | | < | 115319 115320 115321 115322 115323 115324 115325 115326 115327 115328 115329 115330 115331 115332 115333 115334 115335 115336 115337 115338 115339 115340 115341 115342 115343 115344 115345 115346 115347 115348 115349 115350 115351 115352 115353 |
}
/*
** 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.
|
| ︙ | ︙ | |||
115337 115338 115339 115340 115341 115342 115343 115344 115345 115346 115347 115348 115349 |
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 filename of the database associated with a database
** connection.
*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
| > > > > > > > > > > > > > > > < < | | | | > > > > > > | | 115633 115634 115635 115636 115637 115638 115639 115640 115641 115642 115643 115644 115645 115646 115647 115648 115649 115650 115651 115652 115653 115654 115655 115656 115657 115658 115659 115660 115661 115662 115663 115664 115665 115666 115667 115668 115669 115670 115671 115672 115673 115674 115675 115676 115677 115678 |
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
**
|
| ︙ | ︙ | |||
115759 115760 115761 115762 115763 115764 115765 |
**
** FTS3 used to optionally store character offsets using a compile-time
** option. But that functionality is no longer supported.
**
** A doclist is stored like this:
**
** array {
| | | 116074 116075 116076 116077 116078 116079 116080 116081 116082 116083 116084 116085 116086 116087 116088 |
**
** FTS3 used to optionally store character offsets using a compile-time
** option. But that functionality is no longer supported.
**
** A doclist is stored like this:
**
** array {
** varint docid; (delta from previous doclist)
** array { (position list for column 0)
** varint position; (2 more than the delta from previous position)
** }
** array {
** varint POS_COLUMN; (marks start of position list for new column)
** varint column; (index of new column)
** array {
|
| ︙ | ︙ | |||
115790 115791 115792 115793 115794 115795 115796 | ** value: 123 5 9 1 1 14 35 0 234 72 0 ** ** The 123 value is the first docid. For column zero in this document ** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1 ** at D signals the start of a new column; the 1 at E indicates that the ** new column is column number 1. There are two positions at 12 and 45 ** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The | | | | 116105 116106 116107 116108 116109 116110 116111 116112 116113 116114 116115 116116 116117 116118 116119 116120 | ** value: 123 5 9 1 1 14 35 0 234 72 0 ** ** The 123 value is the first docid. For column zero in this document ** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1 ** at D signals the start of a new column; the 1 at E indicates that the ** new column is column number 1. There are two positions at 12 and 45 ** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The ** 234 at I is the delta to next docid (357). It has one position 70 ** (72-2) and then terminates with the 0 at K. ** ** A "position-list" is the list of positions for multiple columns for ** a single docid. A "column-list" is the set of positions for a single ** column. Hence, a position-list consists of one or more column-lists, ** a document record consists of a docid followed by a position-list and ** a doclist consists of one or more document records. ** |
| ︙ | ︙ | |||
115975 115976 115977 115978 115979 115980 115981 | ** 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. | < < < < | 116290 116291 116292 116293 116294 116295 116296 116297 116298 116299 116300 116301 116302 116303 | ** 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 ** |
| ︙ | ︙ | |||
116074 116075 116076 116077 116078 116079 116080 |
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 {
/*
| | | 116385 116386 116387 116388 116389 116390 116391 116392 116393 116394 116395 116396 116397 116398 116399 |
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
|
| ︙ | ︙ | |||
116155 116156 116157 116158 116159 116160 116161 116162 116163 116164 116165 116166 116167 116168 |
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 */
};
| > > > > > > > > > | 116466 116467 116468 116469 116470 116471 116472 116473 116474 116475 116476 116477 116478 116479 116480 116481 116482 116483 116484 116485 116486 116487 116488 |
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 */
};
|
| ︙ | ︙ | |||
116321 116322 116323 116324 116325 116326 116327 116328 116329 116330 116331 116332 116333 116334 | */ #define SizeofArray(X) ((int)(sizeof(X)/sizeof(X[0]))) #ifndef MIN # define MIN(x,y) ((x)<(y)?(x):(y)) #endif /* ** Maximum length of a varint encoded integer. The varint format is different ** from that used by SQLite, so the maximum length is 10, not 9. */ #define FTS3_VARINT_MAX 10 | > > > | 116641 116642 116643 116644 116645 116646 116647 116648 116649 116650 116651 116652 116653 116654 116655 116656 116657 | */ #define SizeofArray(X) ((int)(sizeof(X)/sizeof(X[0]))) #ifndef MIN # define MIN(x,y) ((x)<(y)?(x):(y)) #endif #ifndef MAX # define MAX(x,y) ((x)>(y)?(x):(y)) #endif /* ** Maximum length of a varint encoded integer. The varint format is different ** from that used by SQLite, so the maximum length is 10, not 9. */ #define FTS3_VARINT_MAX 10 |
| ︙ | ︙ | |||
116375 116376 116377 116378 116379 116380 116381 | ** false. */ #ifdef SQLITE_COVERAGE_TEST # define ALWAYS(x) (1) # define NEVER(X) (0) #else # define ALWAYS(x) (x) | | > | 116698 116699 116700 116701 116702 116703 116704 116705 116706 116707 116708 116709 116710 116711 116712 116713 116714 116715 116716 116717 116718 116719 116720 116721 116722 | ** false. */ #ifdef SQLITE_COVERAGE_TEST # define ALWAYS(x) (1) # define NEVER(X) (0) #else # define ALWAYS(x) (x) # define NEVER(x) (x) #endif /* ** Internal types used by SQLite. */ typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */ typedef short int i16; /* 2-byte (or larger) signed integer */ typedef unsigned int u32; /* 4-byte unsigned integer */ typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */ typedef sqlite3_int64 i64; /* 8-byte signed integer */ /* ** Macro used to suppress compiler warnings for unused parameters. */ #define UNUSED_PARAMETER(x) (void)(x) /* |
| ︙ | ︙ | |||
116446 116447 116448 116449 116450 116451 116452 116453 116454 116455 116456 | 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. */ | > > > | > > | < | | < < > | < > > > > > > > | | > | 116770 116771 116772 116773 116774 116775 116776 116777 116778 116779 116780 116781 116782 116783 116784 116785 116786 116787 116788 116789 116790 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 116833 116834 116835 116836 116837 116838 116839 116840 116841 116842 116843 116844 116845 116846 116847 116848 116849 116850 116851 116852 116853 116854 116855 116856 |
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 */
u8 bAutoincrmerge; /* True if automerge=1 */
u32 nLeafAdd; /* Number of leaf blocks added this trans */
/* Precompiled statements used by the implementation. Each of these
** statements is run and reset within a single virtual table API call.
*/
sqlite3_stmt *aStmt[37];
char *zReadExprlist;
char *zWriteExprlist;
int nNodeSize; /* Soft limit for node size */
u8 bFts4; /* True for FTS4, false for FTS3 */
u8 bHasStat; /* True if %_stat table exists */
u8 bHasDocsize; /* True if %_docsize table exists */
u8 bDescIdx; /* True if doclists are in reverse order */
u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
/*
** The following array of hash tables is used to buffer pending index
** updates during transactions. All pending updates buffered at any one
** time must share a common language-id (see the FTS4 langid= feature).
** The current language id is stored in variable iPrevLangid.
**
** 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.
**
** Variable nPendingData contains an estimate the memory consumed by the
** pending data structures, including hash table overhead, but not including
** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash
** tables are flushed to disk. Variable iPrevDocid is the docid of the most
** recently inserted record.
*/
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 */
|
| ︙ | ︙ | |||
116660 116661 116662 116663 116664 116665 116666 | 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 *); | | > | | | 116994 116995 116996 116997 116998 116999 117000 117001 117002 117003 117004 117005 117006 117007 117008 117009 117010 117011 117012 117013 117014 117015 117016 117017 117018 117019 117020 117021 117022 117023 117024 117025 117026 117027 117028 117029 117030 117031 |
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 *);
SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *, int *);
/* 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
|
| ︙ | ︙ | |||
116723 116724 116725 116726 116727 116728 116729 116730 116731 116732 116733 116734 116735 116736 116737 116738 116739 116740 116741 116742 116743 116744 116745 116746 116747 116748 116749 116750 116751 116752 116753 116754 116755 |
/* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */
char *zTerm; /* Pointer to term buffer */
int nTerm; /* Size of zTerm in bytes */
char *aDoclist; /* Pointer to doclist buffer */
int nDoclist; /* Size of aDoclist[] in bytes */
};
/* fts3.c */
SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64);
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
sqlite3_tokenizer **, char **
);
SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char);
/* fts3_snippet.c */
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 */
| > > > | > > > > | 117058 117059 117060 117061 117062 117063 117064 117065 117066 117067 117068 117069 117070 117071 117072 117073 117074 117075 117076 117077 117078 117079 117080 117081 117082 117083 117084 117085 117086 117087 117088 117089 117090 117091 117092 117093 117094 117095 117096 117097 117098 117099 117100 117101 117102 117103 117104 117105 117106 117107 117108 117109 117110 117111 117112 |
/* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */
char *zTerm; /* Pointer to term buffer */
int nTerm; /* Size of zTerm in bytes */
char *aDoclist; /* Pointer to doclist buffer */
int nDoclist; /* Size of aDoclist[] in bytes */
};
SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
/* fts3.c */
SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64);
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
sqlite3_tokenizer **, char **
);
SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char);
/* fts3_snippet.c */
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(
|
| ︙ | ︙ | |||
116952 116953 116954 116955 116956 116957 116958 116959 116960 116961 116962 116963 116964 116965 |
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;
}
| > | 117294 117295 117296 117297 117298 117299 117300 117301 117302 117303 117304 117305 117306 117307 117308 |
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;
}
|
| ︙ | ︙ | |||
117028 117029 117030 117031 117032 117033 117034 117035 117036 117037 117038 117039 117040 117041 117042 117043 117044 117045 |
*/
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(
| > > | > > > > > > > > > > > > > > > > > | 117371 117372 117373 117374 117375 117376 117377 117378 117379 117380 117381 117382 117383 117384 117385 117386 117387 117388 117389 117390 117391 117392 117393 117394 117395 117396 117397 117398 117399 117400 117401 117402 117403 117404 117405 117406 117407 117408 117409 117410 117411 117412 117413 117414 117415 117416 117417 117418 117419 117420 117421 117422 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 117451 |
*/
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);
}
sqlite3_free(zSql);
sqlite3_free(zCols);
*pRc = rc;
}
}
/*
** Create the %_stat table if it does not already exist.
*/
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){
fts3DbExec(pRc, p->db,
"CREATE TABLE IF NOT EXISTS %Q.'%q_stat'"
"(id INTEGER PRIMARY KEY, value BLOB);",
p->zDb, p->zName
);
if( (*pRc)==SQLITE_OK ) p->bHasStat = 1;
}
/*
** Create the backing store tables (%_content, %_segments and %_segdir)
** required by the FTS3 table passed as the only argument. This is done
** as part of the vtab xCreate() method.
**
** If the p->bHasDocsize boolean is true (indicating that this is an
** FTS4 table, not an FTS3 table) then also create the %_docsize and
** %_stat tables required by FTS4.
*/
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
);
|
| ︙ | ︙ | |||
117109 117110 117111 117112 117113 117114 117115 117116 |
);
if( p->bHasDocsize ){
fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
p->zDb, p->zName
);
}
if( p->bHasStat ){
| > | < < < | 117471 117472 117473 117474 117475 117476 117477 117478 117479 117480 117481 117482 117483 117484 117485 117486 117487 |
);
if( p->bHasDocsize ){
fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
p->zDb, p->zName
);
}
assert( p->bHasStat==p->bFts4 );
if( p->bHasStat ){
sqlite3Fts3CreateStatTable(&rc, p);
}
return rc;
}
/*
** Store the current database page-size in bytes in p->nPgsz.
**
|
| ︙ | ︙ | |||
117220 117221 117222 117223 117224 117225 117226 |
** The pointer returned points to memory obtained from sqlite3_malloc(). It
** is the callers responsibility to call sqlite3_free() to release this
** memory.
*/
static char *fts3QuoteId(char const *zInput){
int nRet;
char *zRet;
| | | 117580 117581 117582 117583 117584 117585 117586 117587 117588 117589 117590 117591 117592 117593 117594 |
** The pointer returned points to memory obtained from sqlite3_malloc(). It
** is the callers responsibility to call sqlite3_free() to release this
** memory.
*/
static char *fts3QuoteId(char const *zInput){
int nRet;
char *zRet;
nRet = 2 + (int)strlen(zInput)*2 + 1;
zRet = sqlite3_malloc(nRet);
if( zRet ){
int i;
char *z = zRet;
*(z++) = '"';
for(i=0; zInput[i]; i++){
if( zInput[i]=='"' ) *(z++) = '"';
|
| ︙ | ︙ | |||
117275 117276 117277 117278 117279 117280 117281 117282 117283 117284 117285 117286 117287 |
}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]);
}
| > > > > > | > | | 117635 117636 117637 117638 117639 117640 117641 117642 117643 117644 117645 117646 117647 117648 117649 117650 117651 117652 117653 117654 117655 117656 117657 117658 117659 117660 117661 117662 |
}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;
}
|
| ︙ | ︙ | |||
117325 117326 117327 117328 117329 117330 117331 117332 117333 117334 117335 117336 117337 117338 |
}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
| > > > | 117691 117692 117693 117694 117695 117696 117697 117698 117699 117700 117701 117702 117703 117704 117705 117706 117707 |
}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
|
| ︙ | ︙ | |||
117467 117468 117469 117470 117471 117472 117473 |
/* Loop through the returned columns. Set nStr to the number of bytes of
** space required to store a copy of each column name, including the
** nul-terminator byte. */
nCol = sqlite3_column_count(pStmt);
for(i=0; i<nCol; i++){
const char *zCol = sqlite3_column_name(pStmt, i);
| | | | 117836 117837 117838 117839 117840 117841 117842 117843 117844 117845 117846 117847 117848 117849 117850 117851 117852 117853 117854 117855 117856 117857 117858 117859 117860 117861 |
/* Loop through the returned columns. Set nStr to the number of bytes of
** space required to store a copy of each column name, including the
** nul-terminator byte. */
nCol = sqlite3_column_count(pStmt);
for(i=0; i<nCol; i++){
const char *zCol = sqlite3_column_name(pStmt, i);
nStr += (int)strlen(zCol) + 1;
}
/* Allocate and populate the array to return. */
azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
if( azCol==0 ){
rc = SQLITE_NOMEM;
}else{
char *p = (char *)&azCol[nCol];
for(i=0; i<nCol; i++){
const char *zCol = sqlite3_column_name(pStmt, i);
int n = (int)strlen(zCol)+1;
memcpy(p, zCol, n);
azCol[i] = p;
p += n;
}
}
sqlite3_finalize(pStmt);
|
| ︙ | ︙ | |||
117540 117541 117542 117543 117544 117545 117546 117547 117548 117549 117550 117551 117552 117553 |
/* 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;
| > | 117909 117910 117911 117912 117913 117914 117915 117916 117917 117918 117919 117920 117921 117922 117923 |
/* 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;
|
| ︙ | ︙ | |||
117589 117590 117591 117592 117593 117594 117595 |
int nOpt;
} aFts4Opt[] = {
{ "matchinfo", 9 }, /* 0 -> MATCHINFO */
{ "prefix", 6 }, /* 1 -> PREFIX */
{ "compress", 8 }, /* 2 -> COMPRESS */
{ "uncompress", 10 }, /* 3 -> UNCOMPRESS */
{ "order", 5 }, /* 4 -> ORDER */
| | > | 117959 117960 117961 117962 117963 117964 117965 117966 117967 117968 117969 117970 117971 117972 117973 117974 |
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++){
|
| ︙ | ︙ | |||
117643 117644 117645 117646 117647 117648 117649 |
){
*pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
rc = SQLITE_ERROR;
}
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
break;
| | < | > > > > > > > | 118014 118015 118016 118017 118018 118019 118020 118021 118022 118023 118024 118025 118026 118027 118028 118029 118030 118031 118032 118033 118034 118035 118036 118037 118038 118039 |
){
*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. */
|
| ︙ | ︙ | |||
117678 117679 117680 117681 117682 117683 117684 |
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);
| | > > | > > > > > > > > > > > | 118055 118056 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 |
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 ){
int k;
for(k=j; k<nCol; k++) aCol[k] = aCol[k+1];
nCol--;
break;
}
}
}
}
}
if( rc!=SQLITE_OK ) goto fts3_init_out;
if( nCol==0 ){
assert( nString==0 );
aCol[0] = "content";
nString = 8;
|
| ︙ | ︙ | |||
117724 117725 117726 117727 117728 117729 117730 117731 117732 117733 117734 117735 117736 117737 117738 117739 117740 |
p->nColumn = nCol;
p->nPendingData = 0;
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++){
| > > > > | 118114 118115 118116 118117 118118 118119 118120 118121 118122 118123 118124 118125 118126 118127 118128 118129 118130 118131 118132 118133 118134 |
p->nColumn = nCol;
p->nPendingData = 0;
p->azColumn = (char **)&p[1];
p->pTokenizer = pTokenizer;
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
p->bHasDocsize = (isFts4 && bNoDocsize==0);
p->bHasStat = isFts4;
p->bFts4 = isFts4;
p->bDescIdx = bDescIdx;
p->bAutoincrmerge = 0xff; /* 0xff means setting unknown */
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++){
|
| ︙ | ︙ | |||
117774 117775 117776 117777 117778 117779 117780 117781 117782 117783 117784 117785 117786 117787 117788 117789 117790 117791 117792 117793 117794 117795 117796 117797 117798 117799 117800 117801 117802 |
/* If this is an xCreate call, create the underlying tables in the
** database. TODO: For xConnect(), it could verify that said tables exist.
*/
if( isCreate ){
rc = fts3CreateTables(p);
}
/* Figure out the page-size for the database. This is required in order to
** estimate the cost of loading large doclists from the database. */
fts3DatabasePageSize(&rc, p);
p->nNodeSize = p->nPgsz-35;
/* Declare the table schema to SQLite. */
fts3DeclareVtab(&rc, p);
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);
}
| > > > > > > > > > > > | 118168 118169 118170 118171 118172 118173 118174 118175 118176 118177 118178 118179 118180 118181 118182 118183 118184 118185 118186 118187 118188 118189 118190 118191 118192 118193 118194 118195 118196 118197 118198 118199 118200 118201 118202 118203 118204 118205 118206 118207 |
/* If this is an xCreate call, create the underlying tables in the
** database. TODO: For xConnect(), it could verify that said tables exist.
*/
if( isCreate ){
rc = fts3CreateTables(p);
}
/* Check to see if a legacy fts3 table has been "upgraded" by the
** addition of a %_stat table so that it can use incremental merge.
*/
if( !isFts4 && !isCreate ){
int rc2 = SQLITE_OK;
fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2",
p->zDb, p->zName);
if( rc2==SQLITE_OK ) p->bHasStat = 1;
}
/* Figure out the page-size for the database. This is required in order to
** estimate the cost of loading large doclists from the database. */
fts3DatabasePageSize(&rc, p);
p->nNodeSize = p->nPgsz-35;
/* Declare the table schema to SQLite. */
fts3DeclareVtab(&rc, p);
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);
}
|
| ︙ | ︙ | |||
117840 117841 117842 117843 117844 117845 117846 117847 117848 117849 117850 117851 117852 117853 117854 117855 117856 117857 117858 |
** 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. */
| > > | | 118245 118246 118247 118248 118249 118250 118251 118252 118253 118254 118255 118256 118257 118258 118259 118260 118261 118262 118263 118264 118265 118266 118267 118268 118269 118270 118271 118272 118273 |
** 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;
}
|
| ︙ | ︙ | |||
117875 117876 117877 117878 117879 117880 117881 |
*/
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;
| > | > > > > > > > > | 118282 118283 118284 118285 118286 118287 118288 118289 118290 118291 118292 118293 118294 118295 118296 118297 118298 118299 118300 118301 118302 118303 118304 118305 118306 118307 118308 118309 118310 118311 118312 |
*/
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 ){
|
| ︙ | ︙ | |||
118766 118767 118768 118769 118770 118771 118772 |
fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2);
fts3PoslistCopy(&p, &p2);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}
}
*paOut = aOut;
| | | 119182 119183 119184 119185 119186 119187 119188 119189 119190 119191 119192 119193 119194 119195 119196 |
fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2);
fts3PoslistCopy(&p, &p2);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}
}
*paOut = aOut;
*pnOut = (int)(p-aOut);
assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 );
return SQLITE_OK;
}
/*
** This function does a "phrase" merge of two doclists. In a phrase merge,
** the output contains a copy of each position from the right-hand input
|
| ︙ | ︙ | |||
118830 118831 118832 118833 118834 118835 118836 |
fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1);
}else{
fts3PoslistCopy(0, &p2);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}
}
| | | 119246 119247 119248 119249 119250 119251 119252 119253 119254 119255 119256 119257 119258 119259 119260 |
fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1);
}else{
fts3PoslistCopy(0, &p2);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}
}
*pnRight = (int)(p - aOut);
}
/*
** Argument pList points to a position list nList bytes in size. This
** function checks to see if the position list contains any entries for
** a token in position 0 (of any column). If so, it writes argument iDelta
** to the output buffer pOut, followed by a position list consisting only
|
| ︙ | ︙ | |||
119032 119033 119034 119035 119036 119037 119038 119039 119040 119041 119042 119043 119044 119045 | ** 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 */ | > | 119448 119449 119450 119451 119452 119453 119454 119455 119456 119457 119458 119459 119460 119461 119462 | ** 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 */ |
| ︙ | ︙ | |||
119060 119061 119062 119063 119064 119065 119066 |
if( rc==SQLITE_OK && pSeg ){
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
}
}
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
if( rc==SQLITE_OK ){
| | | 119477 119478 119479 119480 119481 119482 119483 119484 119485 119486 119487 119488 119489 119490 119491 |
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);
|
| ︙ | ︙ | |||
119105 119106 119107 119108 119109 119110 119111 119112 119113 119114 119115 119116 119117 119118 119119 119120 119121 119122 119123 119124 119125 119126 119127 119128 |
/*
** 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 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 */
){
assert( iIndex>=0 && iIndex<p->nIndex );
assert( iLevel==FTS3_SEGCURSOR_ALL
|| iLevel==FTS3_SEGCURSOR_PENDING
|| iLevel>=0
);
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
assert( FTS3_SEGCURSOR_ALL<0 && FTS3_SEGCURSOR_PENDING<0 );
assert( isPrefix==0 || isScan==0 );
| > < < < < < | > | > > | 119522 119523 119524 119525 119526 119527 119528 119529 119530 119531 119532 119533 119534 119535 119536 119537 119538 119539 119540 119541 119542 119543 119544 119545 119546 119547 119548 119549 119550 119551 119552 119553 119554 119555 119556 119557 119558 119559 119560 119561 119562 119563 119564 119565 119566 119567 119568 119569 119570 119571 119572 119573 119574 119575 |
/*
** 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, /* Language-id to search */
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 */
){
assert( iIndex>=0 && iIndex<p->nIndex );
assert( iLevel==FTS3_SEGCURSOR_ALL
|| iLevel==FTS3_SEGCURSOR_PENDING
|| iLevel>=0
);
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
assert( FTS3_SEGCURSOR_ALL<0 && FTS3_SEGCURSOR_PENDING<0 );
assert( isPrefix==0 || isScan==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
|
| ︙ | ︙ | |||
119181 119182 119183 119184 119185 119186 119187 |
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;
| | | > | | | > > | | | 119597 119598 119599 119600 119601 119602 119603 119604 119605 119606 119607 119608 119609 119610 119611 119612 119613 119614 119615 119616 119617 119618 119619 119620 119621 119622 119623 119624 119625 119626 119627 119628 119629 119630 119631 119632 119633 119634 119635 |
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;
|
| ︙ | ︙ | |||
119357 119358 119359 119360 119361 119362 119363 | Fts3Table *p = (Fts3Table *)pCursor->pVtab; Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); | | | 119776 119777 119778 119779 119780 119781 119782 119783 119784 119785 119786 119787 119788 119789 119790 | 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); |
| ︙ | ︙ | |||
119382 119383 119384 119385 119386 119387 119388 |
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;
}
| > > > | | | 119801 119802 119803 119804 119805 119806 119807 119808 119809 119810 119811 119812 119813 119814 119815 119816 119817 119818 119819 |
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->bFts4, 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;
|
| ︙ | ︙ | |||
119454 119455 119456 119457 119458 119459 119460 119461 119462 119463 | *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 */ | > > > > > > > | | | | < | > > > > > > > > > > > > | | > | 119876 119877 119878 119879 119880 119881 119882 119883 119884 119885 119886 119887 119888 119889 119890 119891 119892 119893 119894 119895 119896 119897 119898 119899 119900 119901 119902 119903 119904 119905 119906 119907 119908 119909 119910 119911 119912 119913 119914 119915 119916 119917 119918 119919 119920 119921 119922 119923 119924 119925 119926 119927 119928 119929 119930 119931 119932 119933 119934 119935 |
*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;
}
|
| ︙ | ︙ | |||
119507 119508 119509 119510 119511 119512 119513 |
}
/*
** Implementation of xSync() method. Flush the contents of the pending-terms
** hash-table to the database.
*/
static int fts3SyncMethod(sqlite3_vtab *pVtab){
| > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > | | > | 119948 119949 119950 119951 119952 119953 119954 119955 119956 119957 119958 119959 119960 119961 119962 119963 119964 119965 119966 119967 119968 119969 119970 119971 119972 119973 119974 119975 119976 119977 119978 119979 119980 119981 119982 119983 119984 119985 119986 119987 119988 119989 119990 119991 119992 119993 119994 119995 119996 119997 119998 119999 120000 120001 120002 120003 120004 120005 120006 120007 120008 120009 120010 120011 120012 |
}
/*
** Implementation of xSync() method. Flush the contents of the pending-terms
** hash-table to the database.
*/
static int fts3SyncMethod(sqlite3_vtab *pVtab){
/* Following an incremental-merge operation, assuming that the input
** segments are not completely consumed (the usual case), they are updated
** in place to remove the entries that have already been merged. This
** involves updating the leaf block that contains the smallest unmerged
** entry and each block (if any) between the leaf and the root node. So
** if the height of the input segment b-trees is N, and input segments
** are merged eight at a time, updating the input segments at the end
** of an incremental-merge requires writing (8*(1+N)) blocks. N is usually
** small - often between 0 and 2. So the overhead of the incremental
** merge is somewhere between 8 and 24 blocks. To avoid this overhead
** dwarfing the actual productive work accomplished, the incremental merge
** is only attempted if it will write at least 64 leaf blocks. Hence
** nMinMerge.
**
** Of course, updating the input segments also involves deleting a bunch
** of blocks from the segments table. But this is not considered overhead
** as it would also be required by a crisis-merge that used the same input
** segments.
*/
const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */
Fts3Table *p = (Fts3Table*)pVtab;
int rc = sqlite3Fts3PendingTermsFlush(p);
if( rc==SQLITE_OK && p->bAutoincrmerge==1 && p->nLeafAdd>(nMinMerge/16) ){
int mxLevel = 0; /* Maximum relative level value in db */
int A; /* Incr-merge parameter A */
rc = sqlite3Fts3MaxLevel(p, &mxLevel);
assert( rc==SQLITE_OK || mxLevel==0 );
A = p->nLeafAdd * mxLevel;
A += (A/2);
if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, 8);
}
sqlite3Fts3SegmentsClose(p);
return rc;
}
/*
** Implementation of xBegin() method. This is a no-op.
*/
static int fts3BeginMethod(sqlite3_vtab *pVtab){
Fts3Table *p = (Fts3Table*)pVtab;
UNUSED_PARAMETER(pVtab);
assert( p->pSegments==0 );
assert( p->nPendingData==0 );
assert( p->inTransaction!=1 );
TESTONLY( p->inTransaction = 1 );
TESTONLY( p->mxSavepoint = -1; );
p->nLeafAdd = 0;
return SQLITE_OK;
}
/*
** Implementation of xCommit() method. This is a no-op. The contents of
** the pending-terms hash-table have already been flushed into the database
** by fts3SyncMethod().
|
| ︙ | ︙ | |||
119817 119818 119819 119820 119821 119822 119823 119824 119825 119826 119827 |
/*
** The xSavepoint() method.
**
** Flush the contents of the pending-terms table to disk.
*/
static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
UNUSED_PARAMETER(iSavepoint);
assert( ((Fts3Table *)pVtab)->inTransaction );
assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint );
TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
| > > | > > | 120293 120294 120295 120296 120297 120298 120299 120300 120301 120302 120303 120304 120305 120306 120307 120308 120309 120310 120311 120312 120313 120314 120315 |
/*
** The xSavepoint() method.
**
** Flush the contents of the pending-terms table to disk.
*/
static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
int rc = SQLITE_OK;
UNUSED_PARAMETER(iSavepoint);
assert( ((Fts3Table *)pVtab)->inTransaction );
assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint );
TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
rc = fts3SyncMethod(pVtab);
}
return rc;
}
/*
** The xRelease() method.
**
** This is a no-op.
*/
|
| ︙ | ︙ | |||
120181 120182 120183 120184 120185 120186 120187 |
char *p1 = aPoslist;
char *p2 = aOut;
assert( iPrev>=0 );
fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2);
sqlite3_free(aPoslist);
aPoslist = pList;
| | | 120661 120662 120663 120664 120665 120666 120667 120668 120669 120670 120671 120672 120673 120674 120675 |
char *p1 = aPoslist;
char *p2 = aOut;
assert( iPrev>=0 );
fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2);
sqlite3_free(aPoslist);
aPoslist = pList;
nPoslist = (int)(aOut - aPoslist);
if( nPoslist==0 ){
sqlite3_free(aPoslist);
pPhrase->doclist.pList = 0;
pPhrase->doclist.nList = 0;
return SQLITE_OK;
}
}
|
| ︙ | ︙ | |||
120225 120226 120227 120228 120229 120230 120231 |
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
}
pPhrase->doclist.pList = aOut;
if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
pPhrase->doclist.bFreeList = 1;
| | | 120705 120706 120707 120708 120709 120710 120711 120712 120713 120714 120715 120716 120717 120718 120719 |
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
}
pPhrase->doclist.pList = aOut;
if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
pPhrase->doclist.bFreeList = 1;
pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList);
}else{
sqlite3_free(aOut);
pPhrase->doclist.pList = 0;
pPhrase->doclist.nList = 0;
}
sqlite3_free(aPoslist);
}
|
| ︙ | ︙ | |||
120321 120322 120323 120324 120325 120326 120327 |
iDocid += (iMul * iDelta);
pNext = pDocid;
fts3PoslistCopy(0, &pDocid);
while( pDocid<pEnd && *pDocid==0 ) pDocid++;
iMul = (bDescIdx ? -1 : 1);
}
| | | | 120801 120802 120803 120804 120805 120806 120807 120808 120809 120810 120811 120812 120813 120814 120815 120816 120817 120818 120819 120820 120821 120822 120823 120824 120825 120826 120827 120828 120829 |
iDocid += (iMul * iDelta);
pNext = pDocid;
fts3PoslistCopy(0, &pDocid);
while( pDocid<pEnd && *pDocid==0 ) pDocid++;
iMul = (bDescIdx ? -1 : 1);
}
*pnList = (int)(pEnd - pNext);
*ppIter = pNext;
*piDocid = iDocid;
}else{
int iMul = (bDescIdx ? -1 : 1);
sqlite3_int64 iDelta;
fts3GetReverseVarint(&p, aDoclist, &iDelta);
*piDocid -= (iMul * iDelta);
if( p==aDoclist ){
*pbEof = 1;
}else{
char *pSave = p;
fts3ReversePoslist(aDoclist, &p);
*pnList = (int)(pSave - p);
}
*ppIter = p;
}
}
/*
** Attempt to move the phrase iterator to point to the next matching docid.
|
| ︙ | ︙ | |||
120395 120396 120397 120398 120399 120400 120401 |
if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
pDL->iDocid += iDelta;
}else{
pDL->iDocid -= iDelta;
}
pDL->pList = pIter;
fts3PoslistCopy(0, &pIter);
| | | 120875 120876 120877 120878 120879 120880 120881 120882 120883 120884 120885 120886 120887 120888 120889 |
if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
pDL->iDocid += iDelta;
}else{
pDL->iDocid -= iDelta;
}
pDL->pList = pIter;
fts3PoslistCopy(0, &pIter);
pDL->nList = (int)(pIter - pDL->pList);
/* pIter now points just past the 0x00 that terminates the position-
** list for document pDL->iDocid. However, if this position-list was
** edited in place by fts3EvalNearTrim(), then pIter may not actually
** point to the start of the next docid value. The following line deals
** with this case by advancing pIter past the zero-padding added by
** fts3EvalNearTrim(). */
|
| ︙ | ︙ | |||
120736 120737 120738 120739 120740 120741 120742 | int nToken = 0; int nOr = 0; /* Allocate a MultiSegReader for each token in the expression. */ fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); /* Determine which, if any, tokens in the expression should be deferred. */ | | | | | 121216 121217 121218 121219 121220 121221 121222 121223 121224 121225 121226 121227 121228 121229 121230 121231 121232 121233 121234 121235 121236 121237 121238 121239 121240 121241 121242 121243 121244 121245 121246 121247 121248 |
int nToken = 0;
int nOr = 0;
/* Allocate a MultiSegReader for each token in the expression. */
fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc);
/* Determine which, if any, tokens in the expression should be deferred. */
if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
Fts3TokenAndCost *aTC;
Fts3Expr **apOr;
aTC = (Fts3TokenAndCost *)sqlite3_malloc(
sizeof(Fts3TokenAndCost) * nToken
+ sizeof(Fts3Expr *) * nOr * 2
);
apOr = (Fts3Expr **)&aTC[nToken];
if( !aTC ){
rc = SQLITE_NOMEM;
}else{
int ii;
Fts3TokenAndCost *pTC = aTC;
Fts3Expr **ppOr = apOr;
fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc);
nToken = (int)(pTC-aTC);
nOr = (int)(ppOr-apOr);
if( rc==SQLITE_OK ){
rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken);
for(ii=0; rc==SQLITE_OK && ii<nOr; ii++){
rc = fts3EvalSelectDeferred(pCsr, apOr[ii], aTC, nToken);
}
}
|
| ︙ | ︙ | |||
120826 120827 120828 120829 120830 120831 120832 |
assert( pPhrase->doclist.pList );
p2 = pOut = pPhrase->doclist.pList;
res = fts3PoslistNearMerge(
&pOut, aTmp, nParam1, nParam2, paPoslist, &p2
);
if( res ){
| | | 121306 121307 121308 121309 121310 121311 121312 121313 121314 121315 121316 121317 121318 121319 121320 |
assert( pPhrase->doclist.pList );
p2 = pOut = pPhrase->doclist.pList;
res = fts3PoslistNearMerge(
&pOut, aTmp, nParam1, nParam2, paPoslist, &p2
);
if( res ){
nNew = (int)(pOut - pPhrase->doclist.pList) - 1;
assert( pPhrase->doclist.pList[nNew]=='\0' );
assert( nNew<=pPhrase->doclist.nList && nNew>0 );
memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
pPhrase->doclist.nList = nNew;
*paPoslist = pPhrase->doclist.pList;
*pnToken = pPhrase->nToken;
}
|
| ︙ | ︙ | |||
121551 121552 121553 121554 121555 121556 121557 121558 121559 121560 121561 121562 121563 121564 |
memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist));
for(i=0; i<pPhrase->nToken; i++){
fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr);
pPhrase->aToken[i].pSegcsr = 0;
}
}
}
/*
** Return SQLITE_CORRUPT_VTAB.
*/
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
return SQLITE_CORRUPT_VTAB;
| > | 122031 122032 122033 122034 122035 122036 122037 122038 122039 122040 122041 122042 122043 122044 122045 |
memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist));
for(i=0; i<pPhrase->nToken; i++){
fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr);
pPhrase->aToken[i].pSegcsr = 0;
}
}
}
/*
** Return SQLITE_CORRUPT_VTAB.
*/
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
return SQLITE_CORRUPT_VTAB;
|
| ︙ | ︙ | |||
121659 121660 121661 121662 121663 121664 121665 |
*pzErr = sqlite3_mprintf(
"wrong number of arguments to fts4aux constructor"
);
return SQLITE_ERROR;
}
zDb = argv[1];
| | | | 122140 122141 122142 122143 122144 122145 122146 122147 122148 122149 122150 122151 122152 122153 122154 122155 122156 |
*pzErr = sqlite3_mprintf(
"wrong number of arguments to fts4aux constructor"
);
return SQLITE_ERROR;
}
zDb = argv[1];
nDb = (int)strlen(zDb);
zFts3 = argv[3];
nFts3 = (int)strlen(zFts3);
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
if( rc!=SQLITE_OK ) return rc;
nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
p = (Fts3auxTable *)sqlite3_malloc(nByte);
if( !p ) return SQLITE_NOMEM;
|
| ︙ | ︙ | |||
121956 121957 121958 121959 121960 121961 121962 |
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;
}
| | | 122437 122438 122439 122440 122441 122442 122443 122444 122445 122446 122447 122448 122449 122450 122451 |
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);
|
| ︙ | ︙ | |||
122148 122149 122150 122151 122152 122153 122154 122155 122156 122157 122158 122159 122160 122161 |
** 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 */
| > | 122629 122630 122631 122632 122633 122634 122635 122636 122637 122638 122639 122640 122641 122642 122643 |
** 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 */
|
| ︙ | ︙ | |||
122183 122184 122185 122186 122187 122188 122189 122190 122191 122192 122193 122194 122195 122196 |
*/
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
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 122665 122666 122667 122668 122669 122670 122671 122672 122673 122674 122675 122676 122677 122678 122679 122680 122681 122682 122683 122684 122685 122686 122687 122688 122689 122690 122691 122692 122693 122694 122695 122696 122697 122698 122699 122700 122701 122702 122703 122704 122705 |
*/
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
|
| ︙ | ︙ | |||
122210 122211 122212 122213 122214 122215 122216 | sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; int rc; sqlite3_tokenizer_cursor *pCursor; Fts3Expr *pRet = 0; int nConsumed = 0; | | < < | 122719 122720 122721 122722 122723 122724 122725 122726 122727 122728 122729 122730 122731 122732 122733 122734 122735 122736 122737 122738 122739 |
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;
|
| ︙ | ︙ | |||
122324 122325 122326 122327 122328 122329 122330 | ** ** 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. */ | > | < | 122831 122832 122833 122834 122835 122836 122837 122838 122839 122840 122841 122842 122843 122844 122845 122846 122847 122848 |
**
** 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;
|
| ︙ | ︙ | |||
122801 122802 122803 122804 122805 122806 122807 122808 122809 122810 122811 122812 122813 122814 122815 122816 122817 122818 122819 122820 122821 |
** 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;
| > > > > < | 123308 123309 123310 123311 123312 123313 123314 123315 123316 123317 123318 123319 123320 123321 123322 123323 123324 123325 123326 123327 123328 123329 123330 123331 123332 123333 123334 123335 123336 123337 123338 123339 |
** 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);
|
| ︙ | ︙ | |||
123006 123007 123008 123009 123010 123011 123012 |
goto exprtest_out;
}
for(ii=0; ii<nCol; ii++){
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
}
rc = sqlite3Fts3ExprParse(
| | | 123516 123517 123518 123519 123520 123521 123522 123523 123524 123525 123526 123527 123528 123529 123530 |
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);
|
| ︙ | ︙ | |||
124055 124056 124057 124058 124059 124060 124061 124062 124063 124064 124065 124066 124067 124068 |
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(
| > | 124565 124566 124567 124568 124569 124570 124571 124572 124573 124574 124575 124576 124577 124578 124579 |
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(
|
| ︙ | ︙ | |||
124360 124361 124362 124363 124364 124365 124366 |
Tcl_IncrRefCount(pRet);
if( SQLITE_OK!=p->xCreate(zArg ? 1 : 0, &zArg, &pTokenizer) ){
zErr = "error in xCreate()";
goto finish;
}
pTokenizer->pModule = p;
| | < | 124871 124872 124873 124874 124875 124876 124877 124878 124879 124880 124881 124882 124883 124884 124885 124886 124887 124888 |
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));
|
| ︙ | ︙ | |||
124780 124781 124782 124783 124784 124785 124786 124787 124788 124789 124790 124791 124792 124793 |
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(
| > | 125290 125291 125292 125293 125294 125295 125296 125297 125298 125299 125300 125301 125302 125303 125304 |
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(
|
| ︙ | ︙ | |||
124821 124822 124823 124824 124825 124826 124827 124828 124829 124830 124831 124832 124833 124834 | #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <string.h> */ /* #include <assert.h> */ /* #include <stdlib.h> */ /* ** When full-text index nodes are loaded from disk, the buffer that they ** are loaded into has the following number of bytes of padding at the end ** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer ** of 920 bytes is allocated for it. ** ** This means that if we have a pointer into a buffer containing node data, | > > > | 125332 125333 125334 125335 125336 125337 125338 125339 125340 125341 125342 125343 125344 125345 125346 125347 125348 | #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* #include <string.h> */ /* #include <assert.h> */ /* #include <stdlib.h> */ #define FTS_MAX_APPENDABLE_HEIGHT 16 /* ** When full-text index nodes are loaded from disk, the buffer that they ** are loaded into has the following number of bytes of padding at the end ** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer ** of 920 bytes is allocated for it. ** ** This means that if we have a pointer into a buffer containing node data, |
| ︙ | ︙ | |||
124859 124860 124861 124862 124863 124864 124865 124866 124867 124868 124869 124870 124871 124872 | int test_fts3_node_chunk_threshold = (4*1024)*4; # define FTS3_NODE_CHUNKSIZE test_fts3_node_chunksize # define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold #else # define FTS3_NODE_CHUNKSIZE (4*1024) # define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4) #endif typedef struct PendingList PendingList; typedef struct SegmentNode SegmentNode; typedef struct SegmentWriter SegmentWriter; /* ** An instance of the following data structure is used to build doclists | > > > > > > > > > > > > > > > > > > > > > > > | 125373 125374 125375 125376 125377 125378 125379 125380 125381 125382 125383 125384 125385 125386 125387 125388 125389 125390 125391 125392 125393 125394 125395 125396 125397 125398 125399 125400 125401 125402 125403 125404 125405 125406 125407 125408 125409 |
int test_fts3_node_chunk_threshold = (4*1024)*4;
# define FTS3_NODE_CHUNKSIZE test_fts3_node_chunksize
# define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold
#else
# define FTS3_NODE_CHUNKSIZE (4*1024)
# define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4)
#endif
/*
** The two values that may be meaningfully bound to the :1 parameter in
** statements SQL_REPLACE_STAT and SQL_SELECT_STAT.
*/
#define FTS_STAT_DOCTOTAL 0
#define FTS_STAT_INCRMERGEHINT 1
#define FTS_STAT_AUTOINCRMERGE 2
/*
** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic
** and incremental merge operation that takes place. This is used for
** debugging FTS only, it should not usually be turned on in production
** systems.
*/
#ifdef FTS3_LOG_MERGES
static void fts3LogMerge(int nMerge, sqlite3_int64 iAbsLevel){
sqlite3_log(SQLITE_OK, "%d-way merge from level %d", nMerge, (int)iAbsLevel);
}
#else
#define fts3LogMerge(x, y)
#endif
typedef struct PendingList PendingList;
typedef struct SegmentNode SegmentNode;
typedef struct SegmentWriter SegmentWriter;
/*
** An instance of the following data structure is used to build doclists
|
| ︙ | ︙ | |||
125021 125022 125023 125024 125025 125026 125027 | #define SQL_SELECT_SEGDIR_MAX_LEVEL 15 #define SQL_DELETE_SEGDIR_LEVEL 16 #define SQL_DELETE_SEGMENTS_RANGE 17 #define SQL_CONTENT_INSERT 18 #define SQL_DELETE_DOCSIZE 19 #define SQL_REPLACE_DOCSIZE 20 #define SQL_SELECT_DOCSIZE 21 | | | | > > > | > > > > > > | 125558 125559 125560 125561 125562 125563 125564 125565 125566 125567 125568 125569 125570 125571 125572 125573 125574 125575 125576 125577 125578 125579 125580 125581 125582 125583 125584 125585 125586 125587 | #define SQL_SELECT_SEGDIR_MAX_LEVEL 15 #define SQL_DELETE_SEGDIR_LEVEL 16 #define SQL_DELETE_SEGMENTS_RANGE 17 #define SQL_CONTENT_INSERT 18 #define SQL_DELETE_DOCSIZE 19 #define SQL_REPLACE_DOCSIZE 20 #define SQL_SELECT_DOCSIZE 21 #define SQL_SELECT_STAT 22 #define SQL_REPLACE_STAT 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 #define SQL_FIND_MERGE_LEVEL 28 #define SQL_MAX_LEAF_NODE_ESTIMATE 29 #define SQL_DELETE_SEGDIR_ENTRY 30 #define SQL_SHIFT_SEGDIR_ENTRY 31 #define SQL_SELECT_SEGDIR 32 #define SQL_CHOMP_SEGDIR 33 #define SQL_SEGMENT_IS_APPENDABLE 34 #define SQL_SELECT_INDEXES 35 #define SQL_SELECT_MXLEVEL 36 /* ** 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. ** |
| ︙ | ︙ | |||
125056 125057 125058 125059 125060 125061 125062 | /* 2 */ "DELETE FROM %Q.'%q_content'", /* 3 */ "DELETE FROM %Q.'%q_segments'", /* 4 */ "DELETE FROM %Q.'%q_segdir'", /* 5 */ "DELETE FROM %Q.'%q_docsize'", /* 6 */ "DELETE FROM %Q.'%q_stat'", /* 7 */ "SELECT %s WHERE rowid=?", /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 125602 125603 125604 125605 125606 125607 125608 125609 125610 125611 125612 125613 125614 125615 125616 125617 125618 125619 125620 125621 125622 125623 125624 125625 125626 125627 125628 125629 125630 125631 125632 125633 125634 125635 125636 125637 125638 125639 125640 125641 125642 125643 125644 125645 125646 125647 125648 125649 125650 125651 125652 125653 125654 125655 125656 125657 125658 125659 125660 125661 125662 125663 125664 125665 125666 125667 125668 125669 125670 125671 125672 125673 125674 125675 125676 125677 125678 125679 125680 125681 125682 125683 125684 125685 125686 125687 125688 125689 125690 |
/* 2 */ "DELETE FROM %Q.'%q_content'",
/* 3 */ "DELETE FROM %Q.'%q_segments'",
/* 4 */ "DELETE FROM %Q.'%q_segdir'",
/* 5 */ "DELETE FROM %Q.'%q_docsize'",
/* 6 */ "DELETE FROM %Q.'%q_stat'",
/* 7 */ "SELECT %s WHERE rowid=?",
/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
/* 9 */ "REPLACE INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
/* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
/* Return segments in order from oldest to newest.*/
/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC",
/* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?"
"ORDER BY level DESC, idx ASC",
/* 14 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?",
/* 15 */ "SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?",
/* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
/* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
/* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%s)",
/* 19 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
/* 20 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
/* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
/* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=?",
/* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(?,?)",
/* 24 */ "",
/* 25 */ "",
/* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?",
/* 27 */ "SELECT DISTINCT level / (1024 * ?) FROM %Q.'%q_segdir'",
/* This statement is used to determine which level to read the input from
** when performing an incremental merge. It returns the absolute level number
** of the oldest level in the db that contains at least ? segments. Or,
** if no level in the FTS index contains more than ? segments, the statement
** returns zero rows. */
/* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?"
" ORDER BY (level %% 1024) ASC LIMIT 1",
/* Estimate the upper limit on the number of leaf nodes in a new segment
** created by merging the oldest :2 segments from absolute level :1. See
** function sqlite3Fts3Incrmerge() for details. */
/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
" FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
/* SQL_DELETE_SEGDIR_ENTRY
** Delete the %_segdir entry on absolute level :1 with index :2. */
/* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?",
/* SQL_SHIFT_SEGDIR_ENTRY
** Modify the idx value for the segment with idx=:3 on absolute level :2
** to :1. */
/* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?",
/* SQL_SELECT_SEGDIR
** Read a single entry from the %_segdir table. The entry from absolute
** level :1 with index value :2. */
/* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?",
/* SQL_CHOMP_SEGDIR
** Update the start_block (:1) and root (:2) fields of the %_segdir
** entry located on absolute level :3 with index :4. */
/* 33 */ "UPDATE %Q.'%q_segdir' SET start_block = ?, root = ?"
"WHERE level = ? AND idx = ?",
/* SQL_SEGMENT_IS_APPENDABLE
** Return a single row if the segment with end_block=? is appendable. Or
** no rows otherwise. */
/* 34 */ "SELECT 1 FROM %Q.'%q_segments' WHERE blockid=? AND block IS NULL",
/* SQL_SELECT_INDEXES
** Return the list of valid segment indexes for absolute level ? */
/* 35 */ "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC",
/* SQL_SELECT_MXLEVEL
** Return the largest relative level in the FTS index or indexes. */
/* 36 */ "SELECT max( 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 );
|
| ︙ | ︙ | |||
125119 125120 125121 125122 125123 125124 125125 125126 125127 125128 |
for(i=0; rc==SQLITE_OK && i<nParam; i++){
rc = sqlite3_bind_value(pStmt, i+1, apVal[i]);
}
}
*pp = pStmt;
return rc;
}
static int fts3SelectDocsize(
Fts3Table *pTab, /* FTS3 table handle */
| > < < < | < | < > > | > > > > > > > > > > > > | | 125713 125714 125715 125716 125717 125718 125719 125720 125721 125722 125723 125724 125725 125726 125727 125728 125729 125730 125731 125732 125733 125734 125735 125736 125737 125738 125739 125740 125741 125742 125743 125744 125745 125746 125747 125748 125749 125750 125751 125752 125753 125754 125755 125756 125757 125758 125759 125760 125761 125762 125763 125764 125765 125766 125767 125768 125769 125770 125771 125772 125773 125774 125775 125776 125777 125778 125779 125780 |
for(i=0; rc==SQLITE_OK && i<nParam; i++){
rc = sqlite3_bind_value(pStmt, i+1, apVal[i]);
}
}
*pp = pStmt;
return rc;
}
static int fts3SelectDocsize(
Fts3Table *pTab, /* FTS3 table handle */
sqlite3_int64 iDocid, /* Docid to bind for SQL_SELECT_DOCSIZE */
sqlite3_stmt **ppStmt /* OUT: Statement handle */
){
sqlite3_stmt *pStmt = 0; /* Statement requested from fts3SqlStmt() */
int rc; /* Return code */
rc = fts3SqlStmt(pTab, SQL_SELECT_DOCSIZE, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pStmt, 1, iDocid);
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB;
pStmt = 0;
}else{
rc = SQLITE_OK;
}
}
*ppStmt = pStmt;
return rc;
}
SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(
Fts3Table *pTab, /* Fts3 table handle */
sqlite3_stmt **ppStmt /* OUT: Statement handle */
){
sqlite3_stmt *pStmt = 0;
int rc;
rc = fts3SqlStmt(pTab, SQL_SELECT_STAT, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL);
if( sqlite3_step(pStmt)!=SQLITE_ROW
|| sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB
){
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB;
pStmt = 0;
}
}
*ppStmt = pStmt;
return rc;
}
SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(
Fts3Table *pTab, /* Fts3 table handle */
sqlite3_int64 iDocid, /* Docid to read size data for */
sqlite3_stmt **ppStmt /* OUT: Statement handle */
){
return fts3SelectDocsize(pTab, iDocid, ppStmt);
}
/*
** Similar to fts3SqlStmt(). Except, after binding the parameters in
** array apVal[] to the SQL statement identified by eStmt, the statement
** is executed.
**
|
| ︙ | ︙ | |||
125227 125228 125229 125230 125231 125232 125233 125234 125235 125236 125237 125238 125239 125240 125241 125242 125243 125244 125245 125246 125247 125248 125249 125250 125251 125252 125253 125254 |
}
}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[] */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > | | 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 125876 125877 125878 125879 125880 125881 125882 125883 125884 125885 125886 125887 125888 125889 125890 125891 125892 125893 125894 125895 125896 125897 125898 125899 125900 125901 125902 125903 125904 125905 125906 125907 125908 125909 125910 125911 125912 125913 125914 125915 125916 125917 125918 125919 125920 125921 125922 125923 125924 125925 125926 125927 125928 |
}
}else{
rc = SQLITE_OK;
}
return rc;
}
/*
** FTS maintains a separate indexes for each language-id (a 32-bit integer).
** Within each language id, a separate index is maintained to store the
** document terms, and each configured prefix size (configured the FTS
** "prefix=" option). And each index consists of multiple levels ("relative
** levels").
**
** All three of these values (the language id, the specific index and the
** level within the index) are encoded in 64-bit integer values stored
** in the %_segdir table on disk. This function is used to convert three
** separate component values into the single 64-bit integer value that
** can be used to query the %_segdir table.
**
** Specifically, each language-id/index combination is allocated 1024
** 64-bit integer level values ("absolute levels"). The main terms index
** for language-id 0 is allocate values 0-1023. The first prefix index
** (if any) for language-id 0 is allocated values 1024-2047. And so on.
** Language 1 indexes are allocated immediately following language 0.
**
** So, for a system with nPrefix prefix indexes configured, the block of
** absolute levels that corresponds to language-id iLangid and index
** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024).
*/
static sqlite3_int64 getAbsoluteLevel(
Fts3Table *p, /* FTS3 table handle */
int iLangid, /* Language id */
int iIndex, /* Index in p->aIndex[] */
int iLevel /* Level of segments */
){
sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */
assert( iLangid>=0 );
assert( p->nIndex>0 );
assert( iIndex>=0 && iIndex<p->nIndex );
iBase = ((sqlite3_int64)iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL;
return iBase + 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 (relative level) */
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_int64(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_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel));
}
}
*ppStmt = pStmt;
return rc;
}
|
| ︙ | ︙ | |||
125435 125436 125437 125438 125439 125440 125441 125442 125443 125444 125445 125446 125447 125448 |
** 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;
| > | 126080 126081 126082 126083 126084 126085 126086 126087 126088 126089 126090 126091 126092 126093 126094 |
** 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;
|
| ︙ | ︙ | |||
125464 125465 125466 125467 125468 125469 125470 |
** zText==0. In this case, add zero token entries to the hash table and
** return early. */
if( zText==0 ){
*pnWord = 0;
return SQLITE_OK;
}
| | < | 126110 126111 126112 126113 126114 126115 126116 126117 126118 126119 126120 126121 126122 126123 126124 126125 126126 126127 |
** 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;
|
| ︙ | ︙ | |||
125511 125512 125513 125514 125515 125516 125517 | } /* ** 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. */ | | > > > > > > | > > > > | 126156 126157 126158 126159 126160 126161 126162 126163 126164 126165 126166 126167 126168 126169 126170 126171 126172 126173 126174 126175 126176 126177 126178 126179 126180 126181 126182 126183 126184 126185 126186 126187 126188 126189 126190 126191 |
}
/*
** 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){
|
| ︙ | ︙ | |||
125551 125552 125553 125554 125555 125556 125557 | ** 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. */ | | > > > > > | > | 126206 126207 126208 126209 126210 126211 126212 126213 126214 126215 126216 126217 126218 126219 126220 126221 126222 126223 126224 126225 126226 126227 126228 126229 126230 126231 126232 126233 126234 126235 126236 126237 126238 126239 126240 126241 126242 126243 126244 126245 126246 126247 126248 126249 126250 |
** 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 */
|
| ︙ | ︙ | |||
125606 125607 125608 125609 125610 125611 125612 | ** ** 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]); | | | > > > > | 126267 126268 126269 126270 126271 126272 126273 126274 126275 126276 126277 126278 126279 126280 126281 126282 126283 126284 126285 126286 126287 |
**
** 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);
|
| ︙ | ︙ | |||
125667 125668 125669 125670 125671 125672 125673 125674 125675 125676 125677 125678 125679 125680 125681 125682 125683 125684 125685 125686 125687 125688 125689 125690 125691 125692 125693 |
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;
| > > > > > > > > > > > | | > > | | | | < < | > > > > | > > > | | 126332 126333 126334 126335 126336 126337 126338 126339 126340 126341 126342 126343 126344 126345 126346 126347 126348 126349 126350 126351 126352 126353 126354 126355 126356 126357 126358 126359 126360 126361 126362 126363 126364 126365 126366 126367 126368 126369 126370 126371 126372 126373 126374 126375 126376 126377 126378 126379 126380 126381 126382 126383 126384 126385 126386 126387 126388 126389 126390 126391 126392 126393 126394 126395 126396 126397 126398 126399 126400 126401 126402 126403 126404 126405 126406 126407 126408 126409 126410 126411 126412 126413 126414 126415 126416 126417 126418 126419 126420 126421 126422 126423 126424 126425 126426 126427 126428 126429 126430 126431 126432 126433 126434 126435 126436 126437 126438 126439 126440 126441 126442 126443 126444 126445 126446 126447 126448 126449 126450 |
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 ){
fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
*piIdx = 0;
}else{
*piIdx = iNext;
}
}
return rc;
|
| ︙ | ︙ | |||
125800 125801 125802 125803 125804 125805 125806 |
char **paBlob, /* OUT: Blob data in malloc'd buffer */
int *pnBlob, /* OUT: Size of blob data */
int *pnLoad /* OUT: Bytes actually loaded */
){
int rc; /* Return code */
/* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */
| | | 126483 126484 126485 126486 126487 126488 126489 126490 126491 126492 126493 126494 126495 126496 126497 |
char **paBlob, /* OUT: Blob data in malloc'd buffer */
int *pnBlob, /* OUT: Size of blob data */
int *pnLoad /* OUT: Bytes actually loaded */
){
int rc; /* Return code */
/* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */
assert( pnBlob );
if( p->pSegments ){
rc = sqlite3_blob_reopen(p->pSegments, iBlockid);
}else{
if( 0==p->zSegmentsTbl ){
p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName);
if( 0==p->zSegmentsTbl ) return SQLITE_NOMEM;
|
| ︙ | ︙ | |||
126141 126142 126143 126144 126145 126146 126147 |
){
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
int nOvfl = 0;
int ii;
int rc = SQLITE_OK;
int pgsz = p->nPgsz;
| | | 126824 126825 126826 126827 126828 126829 126830 126831 126832 126833 126834 126835 126836 126837 126838 |
){
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
int nOvfl = 0;
int ii;
int rc = SQLITE_OK;
int pgsz = p->nPgsz;
assert( p->bFts4 );
assert( pgsz>0 );
for(ii=0; rc==SQLITE_OK && ii<pMsr->nSegment; ii++){
Fts3SegReader *pReader = pMsr->apSegment[ii];
if( !fts3SegReaderIsPending(pReader)
&& !fts3SegReaderIsRootOnly(pReader)
){
|
| ︙ | ︙ | |||
126498 126499 126500 126501 126502 126503 126504 126505 126506 126507 126508 126509 126510 |
sqlite3_bind_int64(pStmt, 1, iBlock);
sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC);
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
}
return rc;
}
/*
** Insert a record into the %_segdir table.
*/
static int fts3WriteSegdir(
Fts3Table *p, /* Virtual table handle */
| > > > > > > > > > > > > > > > > > > > > > | | | 127181 127182 127183 127184 127185 127186 127187 127188 127189 127190 127191 127192 127193 127194 127195 127196 127197 127198 127199 127200 127201 127202 127203 127204 127205 127206 127207 127208 127209 127210 127211 127212 127213 127214 127215 127216 127217 127218 127219 127220 127221 127222 127223 127224 127225 127226 127227 127228 127229 127230 127231 127232 127233 |
sqlite3_bind_int64(pStmt, 1, iBlock);
sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC);
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
}
return rc;
}
/*
** Find the largest relative level number in the table. If successful, set
** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs,
** set *pnMax to zero and return an SQLite error code.
*/
SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){
int rc;
int mxLevel = 0;
sqlite3_stmt *pStmt = 0;
rc = fts3SqlStmt(p, SQL_SELECT_MXLEVEL, &pStmt, 0);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
mxLevel = sqlite3_column_int(pStmt, 0);
}
rc = sqlite3_reset(pStmt);
}
*pnMax = mxLevel;
return rc;
}
/*
** Insert a record into the %_segdir table.
*/
static int fts3WriteSegdir(
Fts3Table *p, /* Virtual table handle */
sqlite3_int64 iLevel, /* Value for "level" field (absolute level) */
int iIdx, /* Value for "idx" field */
sqlite3_int64 iStartBlock, /* Value for "start_block" field */
sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */
sqlite3_int64 iEndBlock, /* Value for "end_block" field */
char *zRoot, /* Blob value for "root" field */
int nRoot /* Number of bytes in buffer zRoot */
){
sqlite3_stmt *pStmt;
int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pStmt, 1, iLevel);
sqlite3_bind_int(pStmt, 2, iIdx);
sqlite3_bind_int64(pStmt, 3, iStartBlock);
sqlite3_bind_int64(pStmt, 4, iLeafEndBlock);
sqlite3_bind_int64(pStmt, 5, iEndBlock);
sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC);
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
|
| ︙ | ︙ | |||
126815 126816 126817 126818 126819 126820 126821 126822 126823 126824 126825 126826 126827 126828 |
if( nData>0 && nData+nReq>p->nNodeSize ){
int rc;
/* The current leaf node is full. Write it out to the database. */
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
if( rc!=SQLITE_OK ) return rc;
/* Add the current term to the interior node tree. The term added to
** the interior tree must:
**
** a) be greater than the largest term on the leaf node just written
** to the database (still available in pWriter->zTerm), and
**
| > | 127519 127520 127521 127522 127523 127524 127525 127526 127527 127528 127529 127530 127531 127532 127533 |
if( nData>0 && nData+nReq>p->nNodeSize ){
int rc;
/* The current leaf node is full. Write it out to the database. */
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
if( rc!=SQLITE_OK ) return rc;
p->nLeafAdd++;
/* Add the current term to the interior node tree. The term added to
** the interior tree must:
**
** a) be greater than the largest term on the leaf node just written
** to the database (still available in pWriter->zTerm), and
**
|
| ︙ | ︙ | |||
126898 126899 126900 126901 126902 126903 126904 | ** database. This function must be called after all terms have been added ** to the segment using fts3SegWriterAdd(). If successful, SQLITE_OK is ** returned. Otherwise, an SQLite error code. */ static int fts3SegWriterFlush( Fts3Table *p, /* Virtual table handle */ SegmentWriter *pWriter, /* SegmentWriter to flush to the db */ | | | 127603 127604 127605 127606 127607 127608 127609 127610 127611 127612 127613 127614 127615 127616 127617 |
** database. This function must be called after all terms have been added
** to the segment using fts3SegWriterAdd(). If successful, SQLITE_OK is
** returned. Otherwise, an SQLite error code.
*/
static int fts3SegWriterFlush(
Fts3Table *p, /* Virtual table handle */
SegmentWriter *pWriter, /* SegmentWriter to flush to the db */
sqlite3_int64 iLevel, /* Value for 'level' column of %_segdir */
int iIdx /* Value for 'idx' column of %_segdir */
){
int rc; /* Return code */
if( pWriter->pTree ){
sqlite3_int64 iLast = 0; /* Largest block id written to database */
sqlite3_int64 iLastLeaf; /* Largest leaf block id written to db */
char *zRoot = NULL; /* Pointer to buffer containing root node */
|
| ︙ | ︙ | |||
126923 126924 126925 126926 126927 126928 126929 126930 126931 126932 126933 126934 126935 126936 |
p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, zRoot, nRoot);
}
}else{
/* The entire tree fits on the root node. Write it to the segdir table. */
rc = fts3WriteSegdir(
p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData);
}
return rc;
}
/*
** Release all memory held by the SegmentWriter object passed as the
** first argument.
*/
| > | 127628 127629 127630 127631 127632 127633 127634 127635 127636 127637 127638 127639 127640 127641 127642 |
p, iLevel, iIdx, pWriter->iFirst, iLastLeaf, iLast, zRoot, nRoot);
}
}else{
/* The entire tree fits on the root node. Write it to the segdir table. */
rc = fts3WriteSegdir(
p, iLevel, iIdx, 0, 0, 0, pWriter->aData, pWriter->nData);
}
p->nLeafAdd++;
return rc;
}
/*
** Release all memory held by the SegmentWriter object passed as the
** first argument.
*/
|
| ︙ | ︙ | |||
126976 126977 126978 126979 126980 126981 126982 | ** 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. */ | | > > > > > > | | > | > > > > > > > > > > > > > > > > > > > > > > > > | | < | < < < < < < > | | > | > > | 127682 127683 127684 127685 127686 127687 127688 127689 127690 127691 127692 127693 127694 127695 127696 127697 127698 127699 127700 127701 127702 127703 127704 127705 127706 127707 127708 127709 127710 127711 127712 127713 127714 127715 127716 127717 127718 127719 127720 127721 127722 127723 127724 127725 127726 127727 127728 127729 127730 127731 127732 127733 127734 127735 127736 127737 127738 127739 127740 127741 127742 127743 127744 127745 127746 127747 127748 127749 127750 127751 127752 127753 127754 127755 127756 127757 127758 127759 127760 127761 127762 127763 127764 127765 127766 127767 127768 127769 127770 127771 127772 127773 127774 127775 127776 127777 127778 127779 127780 127781 127782 127783 127784 127785 127786 127787 127788 127789 127790 127791 127792 127793 127794 |
** 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,
sqlite3_int64 *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_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
sqlite3_bind_int64(pStmt, 2,
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
*pnMax = sqlite3_column_int64(pStmt, 0);
}
return sqlite3_reset(pStmt);
}
/*
** Delete all entries in the %_segments table associated with the segment
** opened with seg-reader pSeg. This function does not affect the contents
** of the %_segdir table.
*/
static int fts3DeleteSegment(
Fts3Table *p, /* FTS table handle */
Fts3SegReader *pSeg /* Segment to delete */
){
int rc = SQLITE_OK; /* Return code */
if( pSeg->iStartBlock ){
sqlite3_stmt *pDelete; /* SQL statement to delete rows */
rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDelete, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pDelete, 1, pSeg->iStartBlock);
sqlite3_bind_int64(pDelete, 2, pSeg->iEndBlock);
sqlite3_step(pDelete);
rc = sqlite3_reset(pDelete);
}
}
return rc;
}
/*
** This function is used after merging multiple segments into a single large
** segment to delete the old, now redundant, segment b-trees. Specifically,
** it:
**
** 1) Deletes all %_segments entries for the segments associated with
** each of the SegReader objects in the array passed as the third
** argument, and
**
** 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 = SQLITE_OK; /* Return Code */
int i; /* Iterator variable */
sqlite3_stmt *pDelete = 0; /* SQL statement to delete rows */
for(i=0; rc==SQLITE_OK && i<nReader; i++){
rc = fts3DeleteSegment(p, apSegment[i]);
}
if( rc!=SQLITE_OK ){
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_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
sqlite3_bind_int64(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_int64(
pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel)
);
}
}
if( rc==SQLITE_OK ){
sqlite3_step(pDelete);
rc = sqlite3_reset(pDelete);
}
|
| ︙ | ︙ | |||
127515 127516 127517 127518 127519 127520 127521 | ** 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. */ | | > > > > > | | | | | | | | | | | > > > | > > > > > > > > > > > > > > > > | 128249 128250 128251 128252 128253 128254 128255 128256 128257 128258 128259 128260 128261 128262 128263 128264 128265 128266 128267 128268 128269 128270 128271 128272 128273 128274 128275 128276 128277 128278 128279 128280 128281 128282 128283 128284 128285 128286 128287 128288 128289 128290 128291 128292 128293 128294 128295 128296 128297 128298 128299 128300 128301 128302 128303 128304 128305 128306 128307 128308 128309 128310 128311 128312 128313 128314 128315 128316 128317 128318 128319 128320 128321 128322 128323 128324 128325 128326 128327 128328 128329 128330 128331 128332 128333 128334 128335 128336 128337 128338 128339 128340 128341 128342 128343 128344 128345 128346 128347 128348 128349 128350 128351 128352 128353 128354 128355 128356 128357 128358 128359 128360 128361 128362 128363 128364 128365 128366 128367 128368 128369 128370 128371 |
** 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 */
sqlite3_int64 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);
/* Determine the auto-incr-merge setting if unknown. If enabled,
** estimate the number of leaf blocks of content to be written
*/
if( rc==SQLITE_OK && p->bHasStat
&& p->bAutoincrmerge==0xff && p->nLeafAdd>0
){
sqlite3_stmt *pStmt = 0;
rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
rc = sqlite3_step(pStmt);
p->bAutoincrmerge = (rc==SQLITE_ROW && sqlite3_column_int(pStmt, 0));
rc = sqlite3_reset(pStmt);
}
}
return rc;
}
/*
** Encode N integers as varints into a blob.
*/
static void fts3EncodeIntArray(
|
| ︙ | ︙ | |||
127710 127711 127712 127713 127714 127715 127716 |
if( *pRC ) return;
a = sqlite3_malloc( (sizeof(u32)+10)*nStat );
if( a==0 ){
*pRC = SQLITE_NOMEM;
return;
}
pBlob = (char*)&a[nStat];
| | > | 128468 128469 128470 128471 128472 128473 128474 128475 128476 128477 128478 128479 128480 128481 128482 128483 128484 128485 128486 128487 128488 |
if( *pRC ) return;
a = sqlite3_malloc( (sizeof(u32)+10)*nStat );
if( a==0 ){
*pRC = SQLITE_NOMEM;
return;
}
pBlob = (char*)&a[nStat];
rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0);
if( rc ){
sqlite3_free(a);
*pRC = rc;
return;
}
sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL);
if( sqlite3_step(pStmt)==SQLITE_ROW ){
fts3DecodeIntArray(nStat, a,
sqlite3_column_blob(pStmt, 0),
sqlite3_column_bytes(pStmt, 0));
}else{
memset(a, 0, sizeof(u32)*(nStat) );
}
|
| ︙ | ︙ | |||
127739 127740 127741 127742 127743 127744 127745 |
x = 0;
}else{
x = x + aSzIns[i] - aSzDel[i];
}
a[i+1] = x;
}
fts3EncodeIntArray(nStat, a, pBlob, &nBlob);
| | > | > > > > < | > > > > > > > > > | | | | | | | > > > > > | 128498 128499 128500 128501 128502 128503 128504 128505 128506 128507 128508 128509 128510 128511 128512 128513 128514 128515 128516 128517 128518 128519 128520 128521 128522 128523 128524 128525 128526 128527 128528 128529 128530 128531 128532 128533 128534 128535 128536 128537 128538 128539 128540 128541 128542 128543 128544 128545 128546 128547 128548 128549 128550 128551 128552 |
x = 0;
}else{
x = x + aSzIns[i] - aSzDel[i];
}
a[i+1] = x;
}
fts3EncodeIntArray(nStat, a, pBlob, &nBlob);
rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
if( rc ){
sqlite3_free(a);
*pRC = rc;
return;
}
sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL);
sqlite3_bind_blob(pStmt, 2, 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;
}
/*
|
| ︙ | ︙ | |||
127812 127813 127814 127815 127816 127817 127818 |
aSzIns = &aSz[p->nColumn+1];
aSzDel = &aSzIns[p->nColumn+1];
}
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
int iCol;
| > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 128589 128590 128591 128592 128593 128594 128595 128596 128597 128598 128599 128600 128601 128602 128603 128604 128605 128606 128607 128608 128609 128610 128611 128612 128613 128614 128615 128616 128617 128618 128619 128620 128621 128622 128623 128624 128625 128626 128627 128628 128629 128630 128631 128632 128633 128634 128635 128636 128637 128638 128639 128640 128641 128642 128643 128644 128645 128646 128647 128648 128649 128650 128651 128652 128653 128654 128655 128656 128657 128658 128659 128660 128661 128662 128663 128664 128665 128666 128667 128668 128669 128670 128671 128672 128673 128674 128675 128676 128677 128678 128679 128680 128681 128682 128683 128684 128685 128686 128687 128688 128689 128690 128691 128692 128693 128694 128695 128696 128697 128698 128699 128700 128701 128702 128703 128704 128705 128706 128707 128708 128709 128710 128711 128712 128713 128714 128715 128716 128717 128718 128719 128720 128721 128722 128723 128724 128725 128726 128727 128728 128729 128730 128731 128732 128733 128734 128735 128736 128737 128738 128739 128740 128741 128742 128743 128744 128745 128746 128747 128748 128749 128750 128751 128752 128753 128754 128755 128756 128757 128758 128759 128760 128761 128762 128763 128764 128765 128766 128767 128768 128769 128770 128771 128772 128773 128774 128775 128776 128777 128778 128779 128780 128781 128782 128783 128784 128785 128786 128787 128788 128789 128790 128791 128792 128793 128794 128795 128796 128797 128798 128799 128800 128801 128802 128803 128804 128805 128806 128807 128808 128809 128810 128811 128812 128813 128814 128815 128816 128817 128818 128819 128820 128821 128822 128823 128824 128825 128826 128827 128828 128829 128830 128831 128832 128833 128834 128835 128836 128837 128838 128839 128840 128841 128842 128843 128844 128845 128846 128847 128848 128849 128850 128851 128852 128853 128854 128855 128856 128857 128858 128859 128860 128861 128862 128863 128864 128865 128866 128867 128868 128869 128870 128871 128872 128873 128874 128875 128876 128877 128878 128879 128880 128881 128882 128883 128884 128885 128886 128887 128888 128889 128890 128891 128892 128893 128894 128895 128896 128897 128898 128899 128900 128901 128902 128903 128904 128905 128906 128907 128908 128909 128910 128911 128912 128913 128914 128915 128916 128917 128918 128919 128920 128921 128922 128923 128924 128925 128926 128927 128928 128929 128930 128931 128932 128933 128934 128935 128936 128937 128938 128939 128940 128941 128942 128943 128944 128945 128946 128947 128948 128949 128950 128951 128952 128953 128954 128955 128956 128957 128958 128959 128960 128961 128962 128963 128964 128965 128966 128967 128968 128969 128970 128971 128972 128973 128974 128975 128976 128977 128978 128979 128980 128981 128982 128983 128984 128985 128986 128987 128988 128989 128990 128991 128992 128993 128994 128995 128996 128997 128998 128999 129000 129001 129002 129003 129004 129005 129006 129007 129008 129009 129010 129011 129012 129013 129014 129015 129016 129017 129018 129019 129020 129021 129022 129023 129024 129025 129026 129027 129028 129029 129030 129031 129032 129033 129034 129035 129036 129037 129038 129039 129040 129041 129042 129043 129044 129045 129046 129047 129048 129049 129050 129051 129052 129053 129054 129055 129056 129057 129058 129059 129060 129061 129062 129063 129064 129065 129066 129067 129068 129069 129070 129071 129072 129073 129074 129075 129076 129077 129078 129079 129080 129081 129082 129083 129084 129085 129086 129087 129088 129089 129090 129091 129092 129093 129094 129095 129096 129097 129098 129099 129100 129101 129102 129103 129104 129105 129106 129107 129108 129109 129110 129111 129112 129113 129114 129115 129116 129117 129118 129119 129120 129121 129122 129123 129124 129125 129126 129127 129128 129129 129130 129131 129132 129133 129134 129135 129136 129137 129138 129139 129140 129141 129142 129143 129144 129145 129146 129147 129148 129149 129150 129151 129152 129153 129154 129155 129156 129157 129158 129159 129160 129161 129162 129163 129164 129165 129166 129167 129168 129169 129170 129171 129172 129173 129174 129175 129176 129177 129178 129179 129180 129181 129182 129183 129184 129185 129186 129187 129188 129189 129190 129191 129192 129193 129194 129195 129196 129197 129198 129199 129200 129201 129202 129203 129204 129205 129206 129207 129208 129209 129210 129211 129212 129213 129214 129215 129216 129217 129218 129219 129220 129221 129222 129223 129224 129225 129226 129227 129228 129229 129230 129231 129232 129233 129234 129235 129236 129237 129238 129239 129240 129241 129242 129243 129244 129245 129246 129247 129248 129249 129250 129251 129252 129253 129254 129255 129256 129257 129258 129259 129260 129261 129262 129263 129264 129265 129266 129267 129268 129269 129270 129271 129272 129273 129274 129275 129276 129277 129278 129279 129280 129281 129282 129283 129284 129285 129286 129287 129288 129289 129290 129291 129292 129293 129294 129295 129296 129297 129298 129299 129300 129301 129302 129303 129304 129305 129306 129307 129308 129309 129310 129311 129312 129313 129314 129315 129316 129317 129318 129319 129320 129321 129322 129323 129324 129325 129326 129327 129328 129329 129330 129331 129332 129333 129334 129335 129336 129337 129338 129339 129340 129341 129342 129343 129344 129345 129346 129347 129348 129349 129350 129351 129352 129353 129354 129355 129356 129357 129358 129359 129360 129361 129362 129363 129364 129365 129366 129367 129368 129369 129370 129371 129372 129373 129374 129375 129376 129377 129378 129379 129380 129381 129382 129383 129384 129385 129386 129387 129388 129389 129390 129391 129392 129393 129394 129395 129396 129397 129398 129399 129400 129401 129402 129403 129404 129405 129406 129407 129408 129409 129410 129411 129412 129413 129414 129415 129416 129417 129418 129419 129420 129421 129422 129423 129424 129425 129426 129427 129428 129429 129430 129431 129432 129433 129434 129435 129436 129437 129438 129439 129440 129441 129442 129443 129444 129445 129446 129447 129448 129449 129450 129451 129452 129453 129454 129455 129456 129457 129458 129459 129460 129461 129462 129463 129464 129465 129466 129467 129468 129469 129470 129471 129472 129473 129474 129475 129476 129477 129478 129479 129480 129481 129482 129483 129484 129485 129486 129487 129488 129489 129490 129491 129492 129493 129494 129495 129496 129497 129498 129499 129500 129501 129502 129503 129504 129505 129506 129507 129508 129509 129510 129511 129512 129513 129514 129515 129516 129517 129518 129519 129520 129521 129522 129523 129524 129525 129526 129527 129528 129529 129530 129531 129532 129533 129534 129535 129536 129537 129538 129539 129540 129541 129542 129543 129544 129545 129546 129547 129548 129549 129550 129551 129552 129553 129554 129555 129556 129557 129558 129559 129560 129561 129562 129563 129564 129565 129566 129567 129568 129569 129570 129571 129572 129573 129574 129575 129576 129577 129578 129579 129580 129581 129582 129583 129584 129585 129586 129587 129588 129589 129590 129591 129592 129593 129594 129595 129596 129597 129598 129599 129600 129601 129602 129603 129604 129605 129606 129607 129608 129609 129610 129611 129612 129613 129614 129615 129616 129617 129618 129619 129620 129621 129622 129623 129624 129625 129626 129627 129628 129629 129630 129631 129632 129633 129634 129635 129636 129637 129638 129639 129640 129641 129642 129643 129644 129645 129646 129647 129648 129649 129650 129651 129652 129653 129654 129655 129656 129657 129658 129659 129660 129661 129662 129663 129664 129665 129666 129667 129668 129669 129670 129671 129672 129673 129674 129675 129676 129677 129678 129679 129680 129681 129682 129683 129684 129685 129686 129687 129688 129689 129690 129691 129692 129693 129694 129695 129696 129697 129698 129699 129700 129701 129702 129703 129704 129705 129706 129707 129708 129709 129710 129711 129712 129713 129714 129715 129716 129717 129718 129719 129720 129721 129722 129723 129724 129725 129726 129727 129728 129729 129730 129731 129732 129733 129734 129735 129736 129737 129738 129739 129740 129741 129742 129743 129744 129745 129746 129747 129748 129749 129750 129751 129752 129753 129754 129755 129756 129757 129758 129759 129760 129761 129762 129763 129764 129765 129766 129767 129768 129769 129770 129771 129772 129773 129774 129775 129776 129777 129778 129779 129780 129781 129782 129783 129784 129785 129786 129787 129788 129789 129790 129791 129792 129793 129794 129795 129796 129797 129798 129799 129800 129801 129802 129803 129804 129805 129806 129807 129808 129809 129810 129811 129812 129813 129814 129815 129816 129817 129818 129819 129820 129821 129822 129823 129824 129825 129826 129827 129828 129829 129830 129831 129832 129833 129834 129835 129836 129837 129838 129839 129840 129841 129842 129843 129844 129845 129846 129847 129848 129849 129850 129851 129852 129853 129854 129855 129856 129857 129858 129859 129860 129861 129862 129863 129864 129865 129866 129867 129868 129869 129870 129871 129872 129873 129874 129875 129876 129877 129878 129879 129880 129881 129882 129883 129884 129885 129886 129887 129888 129889 129890 129891 129892 129893 129894 129895 129896 129897 129898 129899 129900 129901 129902 129903 129904 129905 129906 129907 129908 129909 129910 129911 129912 129913 129914 129915 129916 129917 129918 129919 129920 129921 129922 129923 129924 129925 129926 129927 129928 129929 129930 129931 129932 129933 129934 129935 129936 129937 129938 129939 129940 129941 129942 129943 129944 129945 129946 129947 129948 129949 129950 129951 129952 129953 129954 129955 129956 129957 129958 129959 129960 129961 129962 129963 129964 129965 129966 129967 129968 129969 129970 129971 129972 129973 129974 129975 129976 129977 129978 129979 129980 129981 129982 129983 129984 129985 129986 129987 129988 129989 129990 129991 129992 129993 129994 129995 129996 129997 129998 129999 130000 130001 130002 130003 130004 130005 130006 130007 130008 130009 130010 130011 130012 130013 130014 130015 130016 130017 130018 130019 130020 130021 130022 130023 130024 130025 130026 130027 130028 130029 130030 130031 130032 130033 130034 130035 130036 130037 130038 130039 130040 130041 130042 130043 130044 130045 130046 130047 130048 130049 130050 130051 130052 130053 130054 130055 130056 130057 130058 130059 130060 130061 130062 130063 130064 130065 130066 130067 130068 130069 130070 130071 130072 130073 130074 130075 130076 130077 130078 130079 130080 130081 130082 130083 130084 130085 130086 130087 130088 130089 130090 130091 130092 130093 130094 130095 130096 130097 130098 130099 130100 130101 130102 130103 130104 130105 130106 130107 130108 130109 130110 130111 130112 130113 130114 130115 130116 130117 130118 130119 130120 130121 130122 130123 130124 130125 130126 130127 130128 130129 130130 130131 130132 130133 130134 130135 130136 130137 130138 130139 130140 130141 130142 130143 130144 130145 130146 130147 130148 130149 130150 130151 130152 130153 130154 130155 130156 130157 130158 130159 130160 130161 130162 130163 130164 130165 130166 130167 130168 130169 130170 130171 130172 130173 130174 130175 130176 130177 130178 130179 130180 130181 130182 130183 130184 130185 130186 130187 130188 130189 130190 130191 130192 130193 130194 130195 130196 130197 130198 130199 130200 130201 130202 130203 130204 130205 130206 130207 130208 130209 130210 130211 130212 130213 130214 130215 130216 130217 130218 130219 130220 130221 130222 130223 130224 130225 130226 130227 130228 130229 130230 130231 130232 130233 130234 130235 130236 130237 130238 130239 130240 130241 130242 130243 130244 130245 130246 130247 130248 130249 130250 130251 130252 130253 130254 130255 130256 130257 130258 130259 130260 130261 130262 130263 130264 130265 130266 130267 130268 130269 130270 130271 130272 130273 130274 130275 130276 130277 130278 130279 130280 130281 130282 130283 130284 130285 130286 130287 130288 130289 130290 130291 130292 130293 130294 130295 130296 130297 130298 130299 130300 130301 130302 130303 130304 130305 130306 130307 130308 130309 130310 130311 130312 130313 130314 130315 130316 130317 130318 130319 130320 130321 130322 130323 130324 130325 130326 130327 130328 130329 130330 130331 130332 130333 130334 130335 130336 130337 130338 130339 130340 130341 130342 130343 130344 130345 130346 |
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);
pStmt = 0;
}else{
nEntry++;
for(iCol=0; iCol<=p->nColumn; iCol++){
aSzIns[iCol] += aSz[iCol];
}
}
}
if( p->bFts4 ){
fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry);
}
sqlite3_free(aSz);
if( pStmt ){
int rc2 = sqlite3_finalize(pStmt);
if( rc==SQLITE_OK ){
rc = rc2;
}
}
}
return rc;
}
/*
** This function opens a cursor used to read the input data for an
** incremental merge operation. Specifically, it opens a cursor to scan
** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute
** level iAbsLevel.
*/
static int fts3IncrmergeCsr(
Fts3Table *p, /* FTS3 table handle */
sqlite3_int64 iAbsLevel, /* Absolute level to open */
int nSeg, /* Number of segments to merge */
Fts3MultiSegReader *pCsr /* Cursor object to populate */
){
int rc; /* Return Code */
sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */
int nByte; /* Bytes allocated at pCsr->apSegment[] */
/* Allocate space for the Fts3MultiSegReader.aCsr[] array */
memset(pCsr, 0, sizeof(*pCsr));
nByte = sizeof(Fts3SegReader *) * nSeg;
pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte);
if( pCsr->apSegment==0 ){
rc = SQLITE_NOMEM;
}else{
memset(pCsr->apSegment, 0, nByte);
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0);
}
if( rc==SQLITE_OK ){
int i;
int rc2;
sqlite3_bind_int64(pStmt, 1, iAbsLevel);
assert( pCsr->nSegment==0 );
for(i=0; rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW && i<nSeg; i++){
rc = sqlite3Fts3SegReaderNew(i, 0,
sqlite3_column_int64(pStmt, 1), /* segdir.start_block */
sqlite3_column_int64(pStmt, 2), /* segdir.leaves_end_block */
sqlite3_column_int64(pStmt, 3), /* segdir.end_block */
sqlite3_column_blob(pStmt, 4), /* segdir.root */
sqlite3_column_bytes(pStmt, 4), /* segdir.root */
&pCsr->apSegment[i]
);
pCsr->nSegment++;
}
rc2 = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ) rc = rc2;
}
return rc;
}
typedef struct IncrmergeWriter IncrmergeWriter;
typedef struct NodeWriter NodeWriter;
typedef struct Blob Blob;
typedef struct NodeReader NodeReader;
/*
** An instance of the following structure is used as a dynamic buffer
** to build up nodes or other blobs of data in.
**
** The function blobGrowBuffer() is used to extend the allocation.
*/
struct Blob {
char *a; /* Pointer to allocation */
int n; /* Number of valid bytes of data in a[] */
int nAlloc; /* Allocated size of a[] (nAlloc>=n) */
};
/*
** This structure is used to build up buffers containing segment b-tree
** nodes (blocks).
*/
struct NodeWriter {
sqlite3_int64 iBlock; /* Current block id */
Blob key; /* Last key written to the current block */
Blob block; /* Current block image */
};
/*
** An object of this type contains the state required to create or append
** to an appendable b-tree segment.
*/
struct IncrmergeWriter {
int nLeafEst; /* Space allocated for leaf blocks */
int nWork; /* Number of leaf pages flushed */
sqlite3_int64 iAbsLevel; /* Absolute level of input segments */
int iIdx; /* Index of *output* segment in iAbsLevel+1 */
sqlite3_int64 iStart; /* Block number of first allocated block */
sqlite3_int64 iEnd; /* Block number of last allocated block */
NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT];
};
/*
** An object of the following type is used to read data from a single
** FTS segment node. See the following functions:
**
** nodeReaderInit()
** nodeReaderNext()
** nodeReaderRelease()
*/
struct NodeReader {
const char *aNode;
int nNode;
int iOff; /* Current offset within aNode[] */
/* Output variables. Containing the current node entry. */
sqlite3_int64 iChild; /* Pointer to child node */
Blob term; /* Current term */
const char *aDoclist; /* Pointer to doclist */
int nDoclist; /* Size of doclist in bytes */
};
/*
** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
** Otherwise, if the allocation at pBlob->a is not already at least nMin
** bytes in size, extend (realloc) it to be so.
**
** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a
** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc
** to reflect the new size of the pBlob->a[] buffer.
*/
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
int nAlloc = nMin;
char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc);
if( a ){
pBlob->nAlloc = nAlloc;
pBlob->a = a;
}else{
*pRc = SQLITE_NOMEM;
}
}
}
/*
** Attempt to advance the node-reader object passed as the first argument to
** the next entry on the node.
**
** Return an error code if an error occurs (SQLITE_NOMEM is possible).
** Otherwise return SQLITE_OK. If there is no next entry on the node
** (e.g. because the current entry is the last) set NodeReader->aNode to
** NULL to indicate EOF. Otherwise, populate the NodeReader structure output
** variables for the new entry.
*/
static int nodeReaderNext(NodeReader *p){
int bFirst = (p->term.n==0); /* True for first term on the node */
int nPrefix = 0; /* Bytes to copy from previous term */
int nSuffix = 0; /* Bytes to append to the prefix */
int rc = SQLITE_OK; /* Return code */
assert( p->aNode );
if( p->iChild && bFirst==0 ) p->iChild++;
if( p->iOff>=p->nNode ){
/* EOF */
p->aNode = 0;
}else{
if( bFirst==0 ){
p->iOff += sqlite3Fts3GetVarint32(&p->aNode[p->iOff], &nPrefix);
}
p->iOff += sqlite3Fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
if( rc==SQLITE_OK ){
memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
p->term.n = nPrefix+nSuffix;
p->iOff += nSuffix;
if( p->iChild==0 ){
p->iOff += sqlite3Fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
p->aDoclist = &p->aNode[p->iOff];
p->iOff += p->nDoclist;
}
}
}
assert( p->iOff<=p->nNode );
return rc;
}
/*
** Release all dynamic resources held by node-reader object *p.
*/
static void nodeReaderRelease(NodeReader *p){
sqlite3_free(p->term.a);
}
/*
** Initialize a node-reader object to read the node in buffer aNode/nNode.
**
** If successful, SQLITE_OK is returned and the NodeReader object set to
** point to the first entry on the node (if any). Otherwise, an SQLite
** error code is returned.
*/
static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){
memset(p, 0, sizeof(NodeReader));
p->aNode = aNode;
p->nNode = nNode;
/* Figure out if this is a leaf or an internal node. */
if( p->aNode[0] ){
/* An internal node. */
p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild);
}else{
p->iOff = 1;
}
return nodeReaderNext(p);
}
/*
** This function is called while writing an FTS segment each time a leaf o
** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed
** to be greater than the largest key on the node just written, but smaller
** than or equal to the first key that will be written to the next leaf
** node.
**
** The block id of the leaf node just written to disk may be found in
** (pWriter->aNodeWriter[0].iBlock) when this function is called.
*/
static int fts3IncrmergePush(
Fts3Table *p, /* Fts3 table handle */
IncrmergeWriter *pWriter, /* Writer object */
const char *zTerm, /* Term to write to internal node */
int nTerm /* Bytes at zTerm */
){
sqlite3_int64 iPtr = pWriter->aNodeWriter[0].iBlock;
int iLayer;
assert( nTerm>0 );
for(iLayer=1; ALWAYS(iLayer<FTS_MAX_APPENDABLE_HEIGHT); iLayer++){
sqlite3_int64 iNextPtr = 0;
NodeWriter *pNode = &pWriter->aNodeWriter[iLayer];
int rc = SQLITE_OK;
int nPrefix;
int nSuffix;
int nSpace;
/* Figure out how much space the key will consume if it is written to
** the current node of layer iLayer. Due to the prefix compression,
** the space required changes depending on which node the key is to
** be added to. */
nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
nSpace = sqlite3Fts3VarintLen(nPrefix);
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){
/* If the current node of layer iLayer contains zero keys, or if adding
** the key to it will not cause it to grow to larger than nNodeSize
** bytes in size, write the key here. */
Blob *pBlk = &pNode->block;
if( pBlk->n==0 ){
blobGrowBuffer(pBlk, p->nNodeSize, &rc);
if( rc==SQLITE_OK ){
pBlk->a[0] = (char)iLayer;
pBlk->n = 1 + sqlite3Fts3PutVarint(&pBlk->a[1], iPtr);
}
}
blobGrowBuffer(pBlk, pBlk->n + nSpace, &rc);
blobGrowBuffer(&pNode->key, nTerm, &rc);
if( rc==SQLITE_OK ){
if( pNode->key.n ){
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix);
}
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix);
memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix);
pBlk->n += nSuffix;
memcpy(pNode->key.a, zTerm, nTerm);
pNode->key.n = nTerm;
}
}else{
/* Otherwise, flush the the current node of layer iLayer to disk.
** Then allocate a new, empty sibling node. The key will be written
** into the parent of this node. */
rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n);
assert( pNode->block.nAlloc>=p->nNodeSize );
pNode->block.a[0] = (char)iLayer;
pNode->block.n = 1 + sqlite3Fts3PutVarint(&pNode->block.a[1], iPtr+1);
iNextPtr = pNode->iBlock;
pNode->iBlock++;
pNode->key.n = 0;
}
if( rc!=SQLITE_OK || iNextPtr==0 ) return rc;
iPtr = iNextPtr;
}
assert( 0 );
return 0;
}
/*
** Append a term and (optionally) doclist to the FTS segment node currently
** stored in blob *pNode. The node need not contain any terms, but the
** header must be written before this function is called.
**
** A node header is a single 0x00 byte for a leaf node, or a height varint
** followed by the left-hand-child varint for an internal node.
**
** The term to be appended is passed via arguments zTerm/nTerm. For a
** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal
** node, both aDoclist and nDoclist must be passed 0.
**
** If the size of the value in blob pPrev is zero, then this is the first
** term written to the node. Otherwise, pPrev contains a copy of the
** previous term. Before this function returns, it is updated to contain a
** copy of zTerm/nTerm.
**
** It is assumed that the buffer associated with pNode is already large
** enough to accommodate the new entry. The buffer associated with pPrev
** is extended by this function if requrired.
**
** If an error (i.e. OOM condition) occurs, an SQLite error code is
** returned. Otherwise, SQLITE_OK.
*/
static int fts3AppendToNode(
Blob *pNode, /* Current node image to append to */
Blob *pPrev, /* Buffer containing previous term written */
const char *zTerm, /* New term to write */
int nTerm, /* Size of zTerm in bytes */
const char *aDoclist, /* Doclist (or NULL) to write */
int nDoclist /* Size of aDoclist in bytes */
){
int rc = SQLITE_OK; /* Return code */
int bFirst = (pPrev->n==0); /* True if this is the first term written */
int nPrefix; /* Size of term prefix in bytes */
int nSuffix; /* Size of term suffix in bytes */
/* Node must have already been started. There must be a doclist for a
** leaf node, and there must not be a doclist for an internal node. */
assert( pNode->n>0 );
assert( (pNode->a[0]=='\0')==(aDoclist!=0) );
blobGrowBuffer(pPrev, nTerm, &rc);
if( rc!=SQLITE_OK ) return rc;
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
memcpy(pPrev->a, zTerm, nTerm);
pPrev->n = nTerm;
if( bFirst==0 ){
pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nPrefix);
}
pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nSuffix);
memcpy(&pNode->a[pNode->n], &zTerm[nPrefix], nSuffix);
pNode->n += nSuffix;
if( aDoclist ){
pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nDoclist);
memcpy(&pNode->a[pNode->n], aDoclist, nDoclist);
pNode->n += nDoclist;
}
assert( pNode->n<=pNode->nAlloc );
return SQLITE_OK;
}
/*
** Append the current term and doclist pointed to by cursor pCsr to the
** appendable b-tree segment opened for writing by pWriter.
**
** Return SQLITE_OK if successful, or an SQLite error code otherwise.
*/
static int fts3IncrmergeAppend(
Fts3Table *p, /* Fts3 table handle */
IncrmergeWriter *pWriter, /* Writer object */
Fts3MultiSegReader *pCsr /* Cursor containing term and doclist */
){
const char *zTerm = pCsr->zTerm;
int nTerm = pCsr->nTerm;
const char *aDoclist = pCsr->aDoclist;
int nDoclist = pCsr->nDoclist;
int rc = SQLITE_OK; /* Return code */
int nSpace; /* Total space in bytes required on leaf */
int nPrefix; /* Size of prefix shared with previous term */
int nSuffix; /* Size of suffix (nTerm - nPrefix) */
NodeWriter *pLeaf; /* Object used to write leaf nodes */
pLeaf = &pWriter->aNodeWriter[0];
nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
nSpace = sqlite3Fts3VarintLen(nPrefix);
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
/* If the current block is not empty, and if adding this term/doclist
** to the current block would make it larger than Fts3Table.nNodeSize
** bytes, write this block out to the database. */
if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
pWriter->nWork++;
/* Add the current term to the parent node. The term added to the
** parent must:
**
** a) be greater than the largest term on the leaf node just written
** to the database (still available in pLeaf->key), and
**
** b) be less than or equal to the term about to be added to the new
** leaf node (zTerm/nTerm).
**
** In other words, it must be the prefix of zTerm 1 byte longer than
** the common prefix (if any) of zTerm and pWriter->zTerm.
*/
if( rc==SQLITE_OK ){
rc = fts3IncrmergePush(p, pWriter, zTerm, nPrefix+1);
}
/* Advance to the next output block */
pLeaf->iBlock++;
pLeaf->key.n = 0;
pLeaf->block.n = 0;
nPrefix = 0;
nSuffix = nTerm;
nSpace = 1;
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
}
blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc);
if( rc==SQLITE_OK ){
if( pLeaf->block.n==0 ){
pLeaf->block.n = 1;
pLeaf->block.a[0] = '\0';
}
rc = fts3AppendToNode(
&pLeaf->block, &pLeaf->key, zTerm, nTerm, aDoclist, nDoclist
);
}
return rc;
}
/*
** This function is called to release all dynamic resources held by the
** merge-writer object pWriter, and if no error has occurred, to flush
** all outstanding node buffers held by pWriter to disk.
**
** If *pRc is not SQLITE_OK when this function is called, then no attempt
** is made to write any data to disk. Instead, this function serves only
** to release outstanding resources.
**
** Otherwise, if *pRc is initially SQLITE_OK and an error occurs while
** flushing buffers to disk, *pRc is set to an SQLite error code before
** returning.
*/
static void fts3IncrmergeRelease(
Fts3Table *p, /* FTS3 table handle */
IncrmergeWriter *pWriter, /* Merge-writer object */
int *pRc /* IN/OUT: Error code */
){
int i; /* Used to iterate through non-root layers */
int iRoot; /* Index of root in pWriter->aNodeWriter */
NodeWriter *pRoot; /* NodeWriter for root node */
int rc = *pRc; /* Error code */
/* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment
** root node. If the segment fits entirely on a single leaf node, iRoot
** will be set to 0. If the root node is the parent of the leaves, iRoot
** will be 1. And so on. */
for(iRoot=FTS_MAX_APPENDABLE_HEIGHT-1; iRoot>=0; iRoot--){
NodeWriter *pNode = &pWriter->aNodeWriter[iRoot];
if( pNode->block.n>0 ) break;
assert( *pRc || pNode->block.nAlloc==0 );
assert( *pRc || pNode->key.nAlloc==0 );
sqlite3_free(pNode->block.a);
sqlite3_free(pNode->key.a);
}
/* Empty output segment. This is a no-op. */
if( iRoot<0 ) return;
/* The entire output segment fits on a single node. Normally, this means
** the node would be stored as a blob in the "root" column of the %_segdir
** table. However, this is not permitted in this case. The problem is that
** space has already been reserved in the %_segments table, and so the
** start_block and end_block fields of the %_segdir table must be populated.
** And, by design or by accident, released versions of FTS cannot handle
** segments that fit entirely on the root node with start_block!=0.
**
** Instead, create a synthetic root node that contains nothing but a
** pointer to the single content node. So that the segment consists of a
** single leaf and a single interior (root) node.
**
** Todo: Better might be to defer allocating space in the %_segments
** table until we are sure it is needed.
*/
if( iRoot==0 ){
Blob *pBlock = &pWriter->aNodeWriter[1].block;
blobGrowBuffer(pBlock, 1 + FTS3_VARINT_MAX, &rc);
if( rc==SQLITE_OK ){
pBlock->a[0] = 0x01;
pBlock->n = 1 + sqlite3Fts3PutVarint(
&pBlock->a[1], pWriter->aNodeWriter[0].iBlock
);
}
iRoot = 1;
}
pRoot = &pWriter->aNodeWriter[iRoot];
/* Flush all currently outstanding nodes to disk. */
for(i=0; i<iRoot; i++){
NodeWriter *pNode = &pWriter->aNodeWriter[i];
if( pNode->block.n>0 && rc==SQLITE_OK ){
rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n);
}
sqlite3_free(pNode->block.a);
sqlite3_free(pNode->key.a);
}
/* Write the %_segdir record. */
if( rc==SQLITE_OK ){
rc = fts3WriteSegdir(p,
pWriter->iAbsLevel+1, /* level */
pWriter->iIdx, /* idx */
pWriter->iStart, /* start_block */
pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */
pWriter->iEnd, /* end_block */
pRoot->block.a, pRoot->block.n /* root */
);
}
sqlite3_free(pRoot->block.a);
sqlite3_free(pRoot->key.a);
*pRc = rc;
}
/*
** Compare the term in buffer zLhs (size in bytes nLhs) with that in
** zRhs (size in bytes nRhs) using memcmp. If one term is a prefix of
** the other, it is considered to be smaller than the other.
**
** Return -ve if zLhs is smaller than zRhs, 0 if it is equal, or +ve
** if it is greater.
*/
static int fts3TermCmp(
const char *zLhs, int nLhs, /* LHS of comparison */
const char *zRhs, int nRhs /* RHS of comparison */
){
int nCmp = MIN(nLhs, nRhs);
int res;
res = memcmp(zLhs, zRhs, nCmp);
if( res==0 ) res = nLhs - nRhs;
return res;
}
/*
** Query to see if the entry in the %_segments table with blockid iEnd is
** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before
** returning. Otherwise, set *pbRes to 0.
**
** Or, if an error occurs while querying the database, return an SQLite
** error code. The final value of *pbRes is undefined in this case.
**
** This is used to test if a segment is an "appendable" segment. If it
** is, then a NULL entry has been inserted into the %_segments table
** with blockid %_segdir.end_block.
*/
static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){
int bRes = 0; /* Result to set *pbRes to */
sqlite3_stmt *pCheck = 0; /* Statement to query database with */
int rc; /* Return code */
rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pCheck, 1, iEnd);
if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1;
rc = sqlite3_reset(pCheck);
}
*pbRes = bRes;
return rc;
}
/*
** This function is called when initializing an incremental-merge operation.
** It checks if the existing segment with index value iIdx at absolute level
** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the
** merge-writer object *pWriter is initialized to write to it.
**
** An existing segment can be appended to by an incremental merge if:
**
** * It was initially created as an appendable segment (with all required
** space pre-allocated), and
**
** * The first key read from the input (arguments zKey and nKey) is
** greater than the largest key currently stored in the potential
** output segment.
*/
static int fts3IncrmergeLoad(
Fts3Table *p, /* Fts3 table handle */
sqlite3_int64 iAbsLevel, /* Absolute level of input segments */
int iIdx, /* Index of candidate output segment */
const char *zKey, /* First key to write */
int nKey, /* Number of bytes in nKey */
IncrmergeWriter *pWriter /* Populate this object */
){
int rc; /* Return code */
sqlite3_stmt *pSelect = 0; /* SELECT to read %_segdir entry */
rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pSelect, 0);
if( rc==SQLITE_OK ){
sqlite3_int64 iStart = 0; /* Value of %_segdir.start_block */
sqlite3_int64 iLeafEnd = 0; /* Value of %_segdir.leaves_end_block */
sqlite3_int64 iEnd = 0; /* Value of %_segdir.end_block */
const char *aRoot = 0; /* Pointer to %_segdir.root buffer */
int nRoot = 0; /* Size of aRoot[] in bytes */
int rc2; /* Return code from sqlite3_reset() */
int bAppendable = 0; /* Set to true if segment is appendable */
/* Read the %_segdir entry for index iIdx absolute level (iAbsLevel+1) */
sqlite3_bind_int64(pSelect, 1, iAbsLevel+1);
sqlite3_bind_int(pSelect, 2, iIdx);
if( sqlite3_step(pSelect)==SQLITE_ROW ){
iStart = sqlite3_column_int64(pSelect, 1);
iLeafEnd = sqlite3_column_int64(pSelect, 2);
iEnd = sqlite3_column_int64(pSelect, 3);
nRoot = sqlite3_column_bytes(pSelect, 4);
aRoot = sqlite3_column_blob(pSelect, 4);
}else{
return sqlite3_reset(pSelect);
}
/* Check for the zero-length marker in the %_segments table */
rc = fts3IsAppendable(p, iEnd, &bAppendable);
/* Check that zKey/nKey is larger than the largest key the candidate */
if( rc==SQLITE_OK && bAppendable ){
char *aLeaf = 0;
int nLeaf = 0;
rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0);
if( rc==SQLITE_OK ){
NodeReader reader;
for(rc = nodeReaderInit(&reader, aLeaf, nLeaf);
rc==SQLITE_OK && reader.aNode;
rc = nodeReaderNext(&reader)
){
assert( reader.aNode );
}
if( fts3TermCmp(zKey, nKey, reader.term.a, reader.term.n)<=0 ){
bAppendable = 0;
}
nodeReaderRelease(&reader);
}
sqlite3_free(aLeaf);
}
if( rc==SQLITE_OK && bAppendable ){
/* It is possible to append to this segment. Set up the IncrmergeWriter
** object to do so. */
int i;
int nHeight = (int)aRoot[0];
NodeWriter *pNode;
pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
pWriter->iStart = iStart;
pWriter->iEnd = iEnd;
pWriter->iAbsLevel = iAbsLevel;
pWriter->iIdx = iIdx;
for(i=nHeight+1; i<FTS_MAX_APPENDABLE_HEIGHT; i++){
pWriter->aNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst;
}
pNode = &pWriter->aNodeWriter[nHeight];
pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight;
blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc);
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aRoot, nRoot);
pNode->block.n = nRoot;
}
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
NodeReader reader;
pNode = &pWriter->aNodeWriter[i];
rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
blobGrowBuffer(&pNode->key, reader.term.n, &rc);
if( rc==SQLITE_OK ){
memcpy(pNode->key.a, reader.term.a, reader.term.n);
pNode->key.n = reader.term.n;
if( i>0 ){
char *aBlock = 0;
int nBlock = 0;
pNode = &pWriter->aNodeWriter[i-1];
pNode->iBlock = reader.iChild;
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc);
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aBlock, nBlock);
pNode->block.n = nBlock;
}
sqlite3_free(aBlock);
}
}
nodeReaderRelease(&reader);
}
}
rc2 = sqlite3_reset(pSelect);
if( rc==SQLITE_OK ) rc = rc2;
}
return rc;
}
/*
** Determine the largest segment index value that exists within absolute
** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus
** one before returning SQLITE_OK. Or, if there are no segments at all
** within level iAbsLevel, set *piIdx to zero.
**
** If an error occurs, return an SQLite error code. The final value of
** *piIdx is undefined in this case.
*/
static int fts3IncrmergeOutputIdx(
Fts3Table *p, /* FTS Table handle */
sqlite3_int64 iAbsLevel, /* Absolute index of input segments */
int *piIdx /* OUT: Next free index at iAbsLevel+1 */
){
int rc;
sqlite3_stmt *pOutputIdx = 0; /* SQL used to find output index */
rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pOutputIdx, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pOutputIdx, 1, iAbsLevel+1);
sqlite3_step(pOutputIdx);
*piIdx = sqlite3_column_int(pOutputIdx, 0);
rc = sqlite3_reset(pOutputIdx);
}
return rc;
}
/*
** Allocate an appendable output segment on absolute level iAbsLevel+1
** with idx value iIdx.
**
** In the %_segdir table, a segment is defined by the values in three
** columns:
**
** start_block
** leaves_end_block
** end_block
**
** When an appendable segment is allocated, it is estimated that the
** maximum number of leaf blocks that may be required is the sum of the
** number of leaf blocks consumed by the input segments, plus the number
** of input segments, multiplied by two. This value is stored in stack
** variable nLeafEst.
**
** A total of 16*nLeafEst blocks are allocated when an appendable segment
** is created ((1 + end_block - start_block)==16*nLeafEst). The contiguous
** array of leaf nodes starts at the first block allocated. The array
** of interior nodes that are parents of the leaf nodes start at block
** (start_block + (1 + end_block - start_block) / 16). And so on.
**
** In the actual code below, the value "16" is replaced with the
** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT.
*/
static int fts3IncrmergeWriter(
Fts3Table *p, /* Fts3 table handle */
sqlite3_int64 iAbsLevel, /* Absolute level of input segments */
int iIdx, /* Index of new output segment */
Fts3MultiSegReader *pCsr, /* Cursor that data will be read from */
IncrmergeWriter *pWriter /* Populate this object */
){
int rc; /* Return Code */
int i; /* Iterator variable */
int nLeafEst = 0; /* Blocks allocated for leaf nodes */
sqlite3_stmt *pLeafEst = 0; /* SQL used to determine nLeafEst */
sqlite3_stmt *pFirstBlock = 0; /* SQL used to determine first block */
/* Calculate nLeafEst. */
rc = fts3SqlStmt(p, SQL_MAX_LEAF_NODE_ESTIMATE, &pLeafEst, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pLeafEst, 1, iAbsLevel);
sqlite3_bind_int64(pLeafEst, 2, pCsr->nSegment);
if( SQLITE_ROW==sqlite3_step(pLeafEst) ){
nLeafEst = sqlite3_column_int(pLeafEst, 0);
}
rc = sqlite3_reset(pLeafEst);
}
if( rc!=SQLITE_OK ) return rc;
/* Calculate the first block to use in the output segment */
rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pFirstBlock, 0);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pFirstBlock) ){
pWriter->iStart = sqlite3_column_int64(pFirstBlock, 0);
pWriter->iEnd = pWriter->iStart - 1;
pWriter->iEnd += nLeafEst * FTS_MAX_APPENDABLE_HEIGHT;
}
rc = sqlite3_reset(pFirstBlock);
}
if( rc!=SQLITE_OK ) return rc;
/* Insert the marker in the %_segments table to make sure nobody tries
** to steal the space just allocated. This is also used to identify
** appendable segments. */
rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0);
if( rc!=SQLITE_OK ) return rc;
pWriter->iAbsLevel = iAbsLevel;
pWriter->nLeafEst = nLeafEst;
pWriter->iIdx = iIdx;
/* Set up the array of NodeWriter objects */
for(i=0; i<FTS_MAX_APPENDABLE_HEIGHT; i++){
pWriter->aNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst;
}
return SQLITE_OK;
}
/*
** Remove an entry from the %_segdir table. This involves running the
** following two statements:
**
** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx
** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx
**
** The DELETE statement removes the specific %_segdir level. The UPDATE
** statement ensures that the remaining segments have contiguously allocated
** idx values.
*/
static int fts3RemoveSegdirEntry(
Fts3Table *p, /* FTS3 table handle */
sqlite3_int64 iAbsLevel, /* Absolute level to delete from */
int iIdx /* Index of %_segdir entry to delete */
){
int rc; /* Return code */
sqlite3_stmt *pDelete = 0; /* DELETE statement */
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_ENTRY, &pDelete, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pDelete, 1, iAbsLevel);
sqlite3_bind_int(pDelete, 2, iIdx);
sqlite3_step(pDelete);
rc = sqlite3_reset(pDelete);
}
return rc;
}
/*
** One or more segments have just been removed from absolute level iAbsLevel.
** Update the 'idx' values of the remaining segments in the level so that
** the idx values are a contiguous sequence starting from 0.
*/
static int fts3RepackSegdirLevel(
Fts3Table *p, /* FTS3 table handle */
sqlite3_int64 iAbsLevel /* Absolute level to repack */
){
int rc; /* Return code */
int *aIdx = 0; /* Array of remaining idx values */
int nIdx = 0; /* Valid entries in aIdx[] */
int nAlloc = 0; /* Allocated size of aIdx[] */
int i; /* Iterator variable */
sqlite3_stmt *pSelect = 0; /* Select statement to read idx values */
sqlite3_stmt *pUpdate = 0; /* Update statement to modify idx values */
rc = fts3SqlStmt(p, SQL_SELECT_INDEXES, &pSelect, 0);
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int64(pSelect, 1, iAbsLevel);
while( SQLITE_ROW==sqlite3_step(pSelect) ){
if( nIdx>=nAlloc ){
int *aNew;
nAlloc += 16;
aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int));
if( !aNew ){
rc = SQLITE_NOMEM;
break;
}
aIdx = aNew;
}
aIdx[nIdx++] = sqlite3_column_int(pSelect, 0);
}
rc2 = sqlite3_reset(pSelect);
if( rc==SQLITE_OK ) rc = rc2;
}
if( rc==SQLITE_OK ){
rc = fts3SqlStmt(p, SQL_SHIFT_SEGDIR_ENTRY, &pUpdate, 0);
}
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pUpdate, 2, iAbsLevel);
}
assert( p->bIgnoreSavepoint==0 );
p->bIgnoreSavepoint = 1;
for(i=0; rc==SQLITE_OK && i<nIdx; i++){
if( aIdx[i]!=i ){
sqlite3_bind_int(pUpdate, 3, aIdx[i]);
sqlite3_bind_int(pUpdate, 1, i);
sqlite3_step(pUpdate);
rc = sqlite3_reset(pUpdate);
}
}
p->bIgnoreSavepoint = 0;
sqlite3_free(aIdx);
return rc;
}
static void fts3StartNode(Blob *pNode, int iHeight, sqlite3_int64 iChild){
pNode->a[0] = (char)iHeight;
if( iChild ){
assert( pNode->nAlloc>=1+sqlite3Fts3VarintLen(iChild) );
pNode->n = 1 + sqlite3Fts3PutVarint(&pNode->a[1], iChild);
}else{
assert( pNode->nAlloc>=1 );
pNode->n = 1;
}
}
/*
** The first two arguments are a pointer to and the size of a segment b-tree
** node. The node may be a leaf or an internal node.
**
** This function creates a new node image in blob object *pNew by copying
** all terms that are greater than or equal to zTerm/nTerm (for leaf nodes)
** or greater than zTerm/nTerm (for internal nodes) from aNode/nNode.
*/
static int fts3TruncateNode(
const char *aNode, /* Current node image */
int nNode, /* Size of aNode in bytes */
Blob *pNew, /* OUT: Write new node image here */
const char *zTerm, /* Omit all terms smaller than this */
int nTerm, /* Size of zTerm in bytes */
sqlite3_int64 *piBlock /* OUT: Block number in next layer down */
){
NodeReader reader; /* Reader object */
Blob prev = {0, 0, 0}; /* Previous term written to new node */
int rc = SQLITE_OK; /* Return code */
int bLeaf = aNode[0]=='\0'; /* True for a leaf node */
/* Allocate required output space */
blobGrowBuffer(pNew, nNode, &rc);
if( rc!=SQLITE_OK ) return rc;
pNew->n = 0;
/* Populate new node buffer */
for(rc = nodeReaderInit(&reader, aNode, nNode);
rc==SQLITE_OK && reader.aNode;
rc = nodeReaderNext(&reader)
){
if( pNew->n==0 ){
int res = fts3TermCmp(reader.term.a, reader.term.n, zTerm, nTerm);
if( res<0 || (bLeaf==0 && res==0) ) continue;
fts3StartNode(pNew, (int)aNode[0], reader.iChild);
*piBlock = reader.iChild;
}
rc = fts3AppendToNode(
pNew, &prev, reader.term.a, reader.term.n,
reader.aDoclist, reader.nDoclist
);
if( rc!=SQLITE_OK ) break;
}
if( pNew->n==0 ){
fts3StartNode(pNew, (int)aNode[0], reader.iChild);
*piBlock = reader.iChild;
}
assert( pNew->n<=pNew->nAlloc );
nodeReaderRelease(&reader);
sqlite3_free(prev.a);
return rc;
}
/*
** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute
** level iAbsLevel. This may involve deleting entries from the %_segments
** table, and modifying existing entries in both the %_segments and %_segdir
** tables.
**
** SQLITE_OK is returned if the segment is updated successfully. Or an
** SQLite error code otherwise.
*/
static int fts3TruncateSegment(
Fts3Table *p, /* FTS3 table handle */
sqlite3_int64 iAbsLevel, /* Absolute level of segment to modify */
int iIdx, /* Index within level of segment to modify */
const char *zTerm, /* Remove terms smaller than this */
int nTerm /* Number of bytes in buffer zTerm */
){
int rc = SQLITE_OK; /* Return code */
Blob root = {0,0,0}; /* New root page image */
Blob block = {0,0,0}; /* Buffer used for any other block */
sqlite3_int64 iBlock = 0; /* Block id */
sqlite3_int64 iNewStart = 0; /* New value for iStartBlock */
sqlite3_int64 iOldStart = 0; /* Old value for iStartBlock */
sqlite3_stmt *pFetch = 0; /* Statement used to fetch segdir */
rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pFetch, 0);
if( rc==SQLITE_OK ){
int rc2; /* sqlite3_reset() return code */
sqlite3_bind_int64(pFetch, 1, iAbsLevel);
sqlite3_bind_int(pFetch, 2, iIdx);
if( SQLITE_ROW==sqlite3_step(pFetch) ){
const char *aRoot = sqlite3_column_blob(pFetch, 4);
int nRoot = sqlite3_column_bytes(pFetch, 4);
iOldStart = sqlite3_column_int64(pFetch, 1);
rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock);
}
rc2 = sqlite3_reset(pFetch);
if( rc==SQLITE_OK ) rc = rc2;
}
while( rc==SQLITE_OK && iBlock ){
char *aBlock = 0;
int nBlock = 0;
iNewStart = iBlock;
rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0);
if( rc==SQLITE_OK ){
rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock);
}
if( rc==SQLITE_OK ){
rc = fts3WriteSegment(p, iNewStart, block.a, block.n);
}
sqlite3_free(aBlock);
}
/* Variable iNewStart now contains the first valid leaf node. */
if( rc==SQLITE_OK && iNewStart ){
sqlite3_stmt *pDel = 0;
rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pDel, 1, iOldStart);
sqlite3_bind_int64(pDel, 2, iNewStart-1);
sqlite3_step(pDel);
rc = sqlite3_reset(pDel);
}
}
if( rc==SQLITE_OK ){
sqlite3_stmt *pChomp = 0;
rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pChomp, 1, iNewStart);
sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC);
sqlite3_bind_int64(pChomp, 3, iAbsLevel);
sqlite3_bind_int(pChomp, 4, iIdx);
sqlite3_step(pChomp);
rc = sqlite3_reset(pChomp);
}
}
sqlite3_free(root.a);
sqlite3_free(block.a);
return rc;
}
/*
** This function is called after an incrmental-merge operation has run to
** merge (or partially merge) two or more segments from absolute level
** iAbsLevel.
**
** Each input segment is either removed from the db completely (if all of
** its data was copied to the output segment by the incrmerge operation)
** or modified in place so that it no longer contains those entries that
** have been duplicated in the output segment.
*/
static int fts3IncrmergeChomp(
Fts3Table *p, /* FTS table handle */
sqlite3_int64 iAbsLevel, /* Absolute level containing segments */
Fts3MultiSegReader *pCsr, /* Chomp all segments opened by this cursor */
int *pnRem /* Number of segments not deleted */
){
int i;
int nRem = 0;
int rc = SQLITE_OK;
for(i=pCsr->nSegment-1; i>=0 && rc==SQLITE_OK; i--){
Fts3SegReader *pSeg = 0;
int j;
/* Find the Fts3SegReader object with Fts3SegReader.iIdx==i. It is hiding
** somewhere in the pCsr->apSegment[] array. */
for(j=0; ALWAYS(j<pCsr->nSegment); j++){
pSeg = pCsr->apSegment[j];
if( pSeg->iIdx==i ) break;
}
assert( j<pCsr->nSegment && pSeg->iIdx==i );
if( pSeg->aNode==0 ){
/* Seg-reader is at EOF. Remove the entire input segment. */
rc = fts3DeleteSegment(p, pSeg);
if( rc==SQLITE_OK ){
rc = fts3RemoveSegdirEntry(p, iAbsLevel, pSeg->iIdx);
}
*pnRem = 0;
}else{
/* The incremental merge did not copy all the data from this
** segment to the upper level. The segment is modified in place
** so that it contains no keys smaller than zTerm/nTerm. */
const char *zTerm = pSeg->zTerm;
int nTerm = pSeg->nTerm;
rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm);
nRem++;
}
}
if( rc==SQLITE_OK && nRem!=pCsr->nSegment ){
rc = fts3RepackSegdirLevel(p, iAbsLevel);
}
*pnRem = nRem;
return rc;
}
/*
** Store an incr-merge hint in the database.
*/
static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){
sqlite3_stmt *pReplace = 0;
int rc; /* Return code */
rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT);
sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC);
sqlite3_step(pReplace);
rc = sqlite3_reset(pReplace);
}
return rc;
}
/*
** Load an incr-merge hint from the database. The incr-merge hint, if one
** exists, is stored in the rowid==1 row of the %_stat table.
**
** If successful, populate blob *pHint with the value read from the %_stat
** table and return SQLITE_OK. Otherwise, if an error occurs, return an
** SQLite error code.
*/
static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){
sqlite3_stmt *pSelect = 0;
int rc;
pHint->n = 0;
rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pSelect, 0);
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT);
if( SQLITE_ROW==sqlite3_step(pSelect) ){
const char *aHint = sqlite3_column_blob(pSelect, 0);
int nHint = sqlite3_column_bytes(pSelect, 0);
if( aHint ){
blobGrowBuffer(pHint, nHint, &rc);
if( rc==SQLITE_OK ){
memcpy(pHint->a, aHint, nHint);
pHint->n = nHint;
}
}
}
rc2 = sqlite3_reset(pSelect);
if( rc==SQLITE_OK ) rc = rc2;
}
return rc;
}
/*
** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
** Otherwise, append an entry to the hint stored in blob *pHint. Each entry
** consists of two varints, the absolute level number of the input segments
** and the number of input segments.
**
** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs,
** set *pRc to an SQLite error code before returning.
*/
static void fts3IncrmergeHintPush(
Blob *pHint, /* Hint blob to append to */
i64 iAbsLevel, /* First varint to store in hint */
int nInput, /* Second varint to store in hint */
int *pRc /* IN/OUT: Error code */
){
blobGrowBuffer(pHint, pHint->n + 2*FTS3_VARINT_MAX, pRc);
if( *pRc==SQLITE_OK ){
pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], iAbsLevel);
pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], (i64)nInput);
}
}
/*
** Read the last entry (most recently pushed) from the hint blob *pHint
** and then remove the entry. Write the two values read to *piAbsLevel and
** *pnInput before returning.
**
** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does
** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB.
*/
static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
const int nHint = pHint->n;
int i;
i = pHint->n-2;
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
pHint->n = i;
i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
i += sqlite3Fts3GetVarint32(&pHint->a[i], pnInput);
if( i!=nHint ) return SQLITE_CORRUPT_VTAB;
return SQLITE_OK;
}
/*
** Attempt an incremental merge that writes nMerge leaf blocks.
**
** Incremental merges happen nMin segments at a time. The two
** segments to be merged are the nMin oldest segments (the ones with
** the smallest indexes) in the highest level that contains at least
** nMin segments. Multiple merges might occur in an attempt to write the
** quota of nMerge leaf blocks.
*/
SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
int rc; /* Return code */
int nRem = nMerge; /* Number of leaf pages yet to be written */
Fts3MultiSegReader *pCsr; /* Cursor used to read input data */
Fts3SegFilter *pFilter; /* Filter used with cursor pCsr */
IncrmergeWriter *pWriter; /* Writer object */
int nSeg = 0; /* Number of input segments */
sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */
Blob hint = {0, 0, 0}; /* Hint read from %_stat table */
int bDirtyHint = 0; /* True if blob 'hint' has been modified */
/* Allocate space for the cursor, filter and writer objects */
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
if( !pWriter ) return SQLITE_NOMEM;
pFilter = (Fts3SegFilter *)&pWriter[1];
pCsr = (Fts3MultiSegReader *)&pFilter[1];
rc = fts3IncrmergeHintLoad(p, &hint);
while( rc==SQLITE_OK && nRem>0 ){
const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex;
sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */
int bUseHint = 0; /* True if attempting to append */
/* Search the %_segdir table for the absolute level with the smallest
** relative level number that contains at least nMin segments, if any.
** If one is found, set iAbsLevel to the absolute level number and
** nSeg to nMin. If no level with at least nMin segments can be found,
** set nSeg to -1.
*/
rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
sqlite3_bind_int(pFindLevel, 1, nMin);
if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
nSeg = nMin;
}else{
nSeg = -1;
}
rc = sqlite3_reset(pFindLevel);
/* If the hint read from the %_stat table is not empty, check if the
** last entry in it specifies a relative level smaller than or equal
** to the level identified by the block above (if any). If so, this
** iteration of the loop will work on merging at the hinted level.
*/
if( rc==SQLITE_OK && hint.n ){
int nHint = hint.n;
sqlite3_int64 iHintAbsLevel = 0; /* Hint level */
int nHintSeg = 0; /* Hint number of segments */
rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
iAbsLevel = iHintAbsLevel;
nSeg = nHintSeg;
bUseHint = 1;
bDirtyHint = 1;
}else{
/* This undoes the effect of the HintPop() above - so that no entry
** is removed from the hint blob. */
hint.n = nHint;
}
}
/* If nSeg is less that zero, then there is no level with at least
** nMin segments and no hint in the %_stat table. No work to do.
** Exit early in this case. */
if( nSeg<0 ) break;
/* Open a cursor to iterate through the contents of the oldest nSeg
** indexes of absolute level iAbsLevel. If this cursor is opened using
** the 'hint' parameters, it is possible that there are less than nSeg
** segments available in level iAbsLevel. In this case, no work is
** done on iAbsLevel - fall through to the next iteration of the loop
** to start work on some other level. */
memset(pWriter, 0, nAlloc);
pFilter->flags = FTS3_SEGMENT_REQUIRE_POS;
if( rc==SQLITE_OK ){
rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr);
}
if( SQLITE_OK==rc && pCsr->nSegment==nSeg
&& SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter))
&& SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr))
){
int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */
rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx);
if( rc==SQLITE_OK ){
if( bUseHint && iIdx>0 ){
const char *zKey = pCsr->zTerm;
int nKey = pCsr->nTerm;
rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter);
}else{
rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter);
}
}
if( rc==SQLITE_OK && pWriter->nLeafEst ){
fts3LogMerge(nSeg, iAbsLevel);
do {
rc = fts3IncrmergeAppend(p, pWriter, pCsr);
if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
}while( rc==SQLITE_ROW );
/* Update or delete the input segments */
if( rc==SQLITE_OK ){
nRem -= (1 + pWriter->nWork);
rc = fts3IncrmergeChomp(p, iAbsLevel, pCsr, &nSeg);
if( nSeg!=0 ){
bDirtyHint = 1;
fts3IncrmergeHintPush(&hint, iAbsLevel, nSeg, &rc);
}
}
}
fts3IncrmergeRelease(p, pWriter, &rc);
}
sqlite3Fts3SegReaderFinish(pCsr);
}
/* Write the hint values into the %_stat table for the next incr-merger */
if( bDirtyHint && rc==SQLITE_OK ){
rc = fts3IncrmergeHintStore(p, &hint);
}
sqlite3_free(pWriter);
sqlite3_free(hint.a);
return rc;
}
/*
** Convert the text beginning at *pz into an integer and return
** its value. Advance *pz to point to the first character past
** the integer.
*/
static int fts3Getint(const char **pz){
const char *z = *pz;
int i = 0;
while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
*pz = z;
return i;
}
/*
** Process statements of the form:
**
** INSERT INTO table(table) VALUES('merge=A,B');
**
** A and B are integers that decode to be the number of leaf pages
** written for the merge, and the minimum number of segments on a level
** before it will be selected for a merge, respectively.
*/
static int fts3DoIncrmerge(
Fts3Table *p, /* FTS3 table handle */
const char *zParam /* Nul-terminated string containing "A,B" */
){
int rc;
int nMin = (FTS3_MERGE_COUNT / 2);
int nMerge = 0;
const char *z = zParam;
/* Read the first integer value */
nMerge = fts3Getint(&z);
/* If the first integer value is followed by a ',', read the second
** integer value. */
if( z[0]==',' && z[1]!='\0' ){
z++;
nMin = fts3Getint(&z);
}
if( z[0]!='\0' || nMin<2 ){
rc = SQLITE_ERROR;
}else{
rc = SQLITE_OK;
if( !p->bHasStat ){
assert( p->bFts4==0 );
sqlite3Fts3CreateStatTable(&rc, p);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts3Incrmerge(p, nMerge, nMin);
}
sqlite3Fts3SegmentsClose(p);
}
return rc;
}
/*
** Process statements of the form:
**
** INSERT INTO table(table) VALUES('automerge=X');
**
** where X is an integer. X==0 means to turn automerge off. X!=0 means
** turn it on. The setting is persistent.
*/
static int fts3DoAutoincrmerge(
Fts3Table *p, /* FTS3 table handle */
const char *zParam /* Nul-terminated string containing boolean */
){
int rc = SQLITE_OK;
sqlite3_stmt *pStmt = 0;
p->bAutoincrmerge = fts3Getint(&zParam)!=0;
if( !p->bHasStat ){
assert( p->bFts4==0 );
sqlite3Fts3CreateStatTable(&rc, p);
if( rc ) return rc;
}
rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
if( rc ) return rc;;
sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
return rc;
}
/*
** Return a 64-bit checksum for the FTS index entry specified by the
** arguments to this function.
*/
static u64 fts3ChecksumEntry(
const char *zTerm, /* Pointer to buffer containing term */
int nTerm, /* Size of zTerm in bytes */
int iLangid, /* Language id for current row */
int iIndex, /* Index (0..Fts3Table.nIndex-1) */
i64 iDocid, /* Docid for current row. */
int iCol, /* Column number */
int iPos /* Position */
){
int i;
u64 ret = (u64)iDocid;
ret += (ret<<3) + iLangid;
ret += (ret<<3) + iIndex;
ret += (ret<<3) + iCol;
ret += (ret<<3) + iPos;
for(i=0; i<nTerm; i++) ret += (ret<<3) + zTerm[i];
return ret;
}
/*
** Return a checksum of all entries in the FTS index that correspond to
** language id iLangid. The checksum is calculated by XORing the checksums
** of each individual entry (see fts3ChecksumEntry()) together.
**
** If successful, the checksum value is returned and *pRc set to SQLITE_OK.
** Otherwise, if an error occurs, *pRc is set to an SQLite error code. The
** return value is undefined in this case.
*/
static u64 fts3ChecksumIndex(
Fts3Table *p, /* FTS3 table handle */
int iLangid, /* Language id to return cksum for */
int iIndex, /* Index to cksum (0..p->nIndex-1) */
int *pRc /* OUT: Return code */
){
Fts3SegFilter filter;
Fts3MultiSegReader csr;
int rc;
u64 cksum = 0;
assert( *pRc==SQLITE_OK );
memset(&filter, 0, sizeof(filter));
memset(&csr, 0, sizeof(csr));
filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;
filter.flags |= FTS3_SEGMENT_SCAN;
rc = sqlite3Fts3SegReaderCursor(
p, iLangid, iIndex, FTS3_SEGCURSOR_ALL, 0, 0, 0, 1,&csr
);
if( rc==SQLITE_OK ){
rc = sqlite3Fts3SegReaderStart(p, &csr, &filter);
}
if( rc==SQLITE_OK ){
while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){
char *pCsr = csr.aDoclist;
char *pEnd = &pCsr[csr.nDoclist];
i64 iDocid = 0;
i64 iCol = 0;
i64 iPos = 0;
pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
while( pCsr<pEnd ){
i64 iVal = 0;
pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
if( pCsr<pEnd ){
if( iVal==0 || iVal==1 ){
iCol = 0;
iPos = 0;
if( iVal ){
pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
}else{
pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
iDocid += iVal;
}
}else{
iPos += (iVal - 2);
cksum = cksum ^ fts3ChecksumEntry(
csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid,
(int)iCol, (int)iPos
);
}
}
}
}
}
sqlite3Fts3SegReaderFinish(&csr);
*pRc = rc;
return cksum;
}
/*
** Check if the contents of the FTS index match the current contents of the
** content table. If no error occurs and the contents do match, set *pbOk
** to true and return SQLITE_OK. Or if the contents do not match, set *pbOk
** to false before returning.
**
** If an error occurs (e.g. an OOM or IO error), return an SQLite error
** code. The final value of *pbOk is undefined in this case.
*/
static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
int rc = SQLITE_OK; /* Return code */
u64 cksum1 = 0; /* Checksum based on FTS index contents */
u64 cksum2 = 0; /* Checksum based on %_content contents */
sqlite3_stmt *pAllLangid = 0; /* Statement to return all language-ids */
/* This block calculates the checksum according to the FTS index. */
rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int(pAllLangid, 1, p->nIndex);
while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){
int iLangid = sqlite3_column_int(pAllLangid, 0);
int i;
for(i=0; i<p->nIndex; i++){
cksum1 = cksum1 ^ fts3ChecksumIndex(p, iLangid, i, &rc);
}
}
rc2 = sqlite3_reset(pAllLangid);
if( rc==SQLITE_OK ) rc = rc2;
}
/* This block calculates the checksum according to the %_content table */
rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
if( rc==SQLITE_OK ){
sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule;
sqlite3_stmt *pStmt = 0;
char *zSql;
zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist);
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
i64 iDocid = sqlite3_column_int64(pStmt, 0);
int iLang = langidFromSelect(p, pStmt);
int iCol;
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1);
int nText = sqlite3_column_bytes(pStmt, iCol+1);
sqlite3_tokenizer_cursor *pT = 0;
rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText, &pT);
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(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos);
if( rc==SQLITE_OK ){
int i;
cksum2 = cksum2 ^ fts3ChecksumEntry(
zToken, nToken, iLang, 0, iDocid, iCol, iPos
);
for(i=1; i<p->nIndex; i++){
if( p->aIndex[i].nPrefix<=nToken ){
cksum2 = cksum2 ^ fts3ChecksumEntry(
zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos
);
}
}
}
}
if( pT ) pModule->xClose(pT);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
}
sqlite3_finalize(pStmt);
}
*pbOk = (cksum1==cksum2);
return rc;
}
/*
** Run the integrity-check. If no error occurs and the current contents of
** the FTS index are correct, return SQLITE_OK. Or, if the contents of the
** FTS index are incorrect, return SQLITE_CORRUPT_VTAB.
**
** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite
** error code.
**
** The integrity-check works as follows. For each token and indexed token
** prefix in the document set, a 64-bit checksum is calculated (by code
** in fts3ChecksumEntry()) based on the following:
**
** + The index number (0 for the main index, 1 for the first prefix
** index etc.),
** + The token (or token prefix) text itself,
** + The language-id of the row it appears in,
** + The docid of the row it appears in,
** + The column it appears in, and
** + The tokens position within that column.
**
** The checksums for all entries in the index are XORed together to create
** a single checksum for the entire index.
**
** The integrity-check code calculates the same checksum in two ways:
**
** 1. By scanning the contents of the FTS index, and
** 2. By scanning and tokenizing the content table.
**
** If the two checksums are identical, the integrity-check is deemed to have
** passed.
*/
static int fts3DoIntegrityCheck(
Fts3Table *p /* FTS3 table handle */
){
int rc;
int bOk = 0;
rc = fts3IntegrityCheck(p, &bOk);
if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_CORRUPT_VTAB;
return rc;
}
/*
** Handle a 'special' INSERT of the form:
**
** "INSERT INTO tbl(tbl) VALUES(<expr>)"
**
** Argument pVal contains the result of <expr>. Currently the only
** meaningful value to insert is the text 'optimize'.
*/
static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
int rc; /* Return Code */
const char *zVal = (const char *)sqlite3_value_text(pVal);
int nVal = sqlite3_value_bytes(pVal);
if( !zVal ){
return SQLITE_NOMEM;
}else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
rc = fts3DoOptimize(p, 0);
}else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){
rc = fts3DoRebuild(p);
}else if( nVal==15 && 0==sqlite3_strnicmp(zVal, "integrity-check", 15) ){
rc = fts3DoIntegrityCheck(p);
}else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
#ifdef SQLITE_TEST
}else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
p->nNodeSize = atoi(&zVal[9]);
rc = SQLITE_OK;
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
p->nMaxPendingData = atoi(&zVal[11]);
rc = SQLITE_OK;
|
| ︙ | ︙ | |||
127935 127936 127937 127938 127939 127940 127941 |
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;
| | < | 130401 130402 130403 130404 130405 130406 130407 130408 130409 130410 130411 130412 130413 130414 130415 130416 130417 130418 130419 130420 130421 |
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))
|
| ︙ | ︙ | |||
128042 128043 128044 128045 128046 128047 128048 |
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{
| < < | > > > > > > > > > > > > > > > > > > | 130507 130508 130509 130510 130511 130512 130513 130514 130515 130516 130517 130518 130519 130520 130521 130522 130523 130524 130525 130526 130527 130528 130529 130530 130531 130532 130533 130534 130535 130536 130537 130538 130539 130540 130541 130542 130543 130544 130545 130546 130547 130548 130549 130550 130551 130552 130553 130554 130555 130556 130557 130558 130559 130560 130561 130562 130563 130564 130565 130566 130567 130568 130569 130570 130571 130572 130573 130574 130575 130576 130577 130578 130579 130580 130581 130582 130583 130584 130585 |
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;
}
|
| ︙ | ︙ | |||
128159 128160 128161 128162 128163 128164 128165 128166 128167 128168 128169 128170 128171 128172 |
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 ) ){
| > | | | | 130640 130641 130642 130643 130644 130645 130646 130647 130648 130649 130650 130651 130652 130653 130654 130655 130656 130657 130658 130659 130660 130661 130662 130663 130664 130665 130666 130667 130668 130669 130670 130671 130672 130673 130674 |
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++;
}
if( p->bFts4 ){
fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
}
update_out:
sqlite3_free(aSzIns);
sqlite3Fts3SegmentsClose(p);
return rc;
|
| ︙ | ︙ | |||
128747 128748 128749 128750 128751 128752 128753 128754 128755 128756 128757 128758 128759 128760 |
** 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 */
| > | 131229 131230 131231 131232 131233 131234 131235 131236 131237 131238 131239 131240 131241 131242 131243 |
** 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 */
|
| ︙ | ︙ | |||
128782 128783 128784 128785 128786 128787 128788 |
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.
*/
| | < | 131265 131266 131267 131268 131269 131270 131271 131272 131273 131274 131275 131276 131277 131278 131279 131280 131281 131282 |
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; }
|
| ︙ | ︙ | |||
128846 128847 128848 128849 128850 128851 128852 |
}
return SQLITE_OK;
}
nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol);
/* Open a token cursor on the document. */
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
| | < | 131328 131329 131330 131331 131332 131333 131334 131335 131336 131337 131338 131339 131340 131341 131342 131343 131344 131345 |
}
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);
|
| ︙ | ︙ | |||
128872 128873 128874 128875 128876 128877 128878 |
}
break;
}
if( iCurrent<iPos ){ continue; }
if( !isShiftDone ){
int n = nDoc - iBegin;
| | > > | 131353 131354 131355 131356 131357 131358 131359 131360 131361 131362 131363 131364 131365 131366 131367 131368 131369 |
}
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) ){
|
| ︙ | ︙ | |||
129008 129009 129010 129011 129012 129013 129014 |
static int fts3MatchinfoCheck(
Fts3Table *pTab,
char cArg,
char **pzErr
){
if( (cArg==FTS3_MATCHINFO_NPHRASE)
|| (cArg==FTS3_MATCHINFO_NCOL)
| | | | 131491 131492 131493 131494 131495 131496 131497 131498 131499 131500 131501 131502 131503 131504 131505 131506 |
static int fts3MatchinfoCheck(
Fts3Table *pTab,
char cArg,
char **pzErr
){
if( (cArg==FTS3_MATCHINFO_NPHRASE)
|| (cArg==FTS3_MATCHINFO_NCOL)
|| (cArg==FTS3_MATCHINFO_NDOC && pTab->bFts4)
|| (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bFts4)
|| (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
|| (cArg==FTS3_MATCHINFO_LCS)
|| (cArg==FTS3_MATCHINFO_HITS)
){
return SQLITE_OK;
}
*pzErr = sqlite3_mprintf("unrecognized matchinfo request: %c", cArg);
|
| ︙ | ︙ | |||
129605 129606 129607 129608 129609 129610 129611 |
continue;
}
rc = SQLITE_NOMEM;
goto offsets_out;
}
/* Initialize a tokenizer iterator to iterate through column iCol. */
| > | > < | 132088 132089 132090 132091 132092 132093 132094 132095 132096 132097 132098 132099 132100 132101 132102 132103 132104 132105 |
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 */
|
| ︙ | ︙ | |||
132772 132773 132774 132775 132776 132777 132778 |
*pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
return SQLITE_ERROR;
}
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
/* Allocate the sqlite3_vtab structure */
| | | | 135256 135257 135258 135259 135260 135261 135262 135263 135264 135265 135266 135267 135268 135269 135270 135271 |
*pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
return SQLITE_ERROR;
}
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
/* Allocate the sqlite3_vtab structure */
nDb = (int)strlen(argv[1]);
nName = (int)strlen(argv[2]);
pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2);
if( !pRtree ){
return SQLITE_NOMEM;
}
memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
|
| ︙ | ︙ | |||
132868 132869 132870 132871 132872 132873 132874 |
char zCell[512];
int nCell = 0;
RtreeCell cell;
int jj;
nodeGetCell(&tree, &node, ii, &cell);
sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
| | | | 135352 135353 135354 135355 135356 135357 135358 135359 135360 135361 135362 135363 135364 135365 135366 135367 135368 135369 |
char zCell[512];
int nCell = 0;
RtreeCell cell;
int jj;
nodeGetCell(&tree, &node, ii, &cell);
sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
nCell = (int)strlen(zCell);
for(jj=0; jj<tree.nDim*2; jj++){
sqlite3_snprintf(512-nCell,&zCell[nCell]," %f",(double)cell.aCoord[jj].f);
nCell = (int)strlen(zCell);
}
if( zText ){
char *zTextNew = sqlite3_mprintf("%s {%s}", zText, zCell);
sqlite3_free(zText);
zText = zTextNew;
}else{
|
| ︙ | ︙ | |||
133614 133615 133616 133617 133618 133619 133620 | UChar32 c; int iInput = 0; int iOut = 0; *ppCursor = 0; | > > > | | 136098 136099 136100 136101 136102 136103 136104 136105 136106 136107 136108 136109 136110 136111 136112 136113 136114 136115 |
UChar32 c;
int iInput = 0;
int iOut = 0;
*ppCursor = 0;
if( zInput==0 ){
nInput = 0;
zInput = "";
}else if( nInput<0 ){
nInput = strlen(zInput);
}
nChar = nInput+1;
pCsr = (IcuCursor *)sqlite3_malloc(
sizeof(IcuCursor) + /* IcuCursor */
nChar * sizeof(UChar) + /* IcuCursor.aChar[] */
(nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */
|
| ︙ | ︙ |
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.12" #define SQLITE_VERSION_NUMBER 3007012 #define SQLITE_SOURCE_ID "2012-03-31 19:12:23 af602d87736b52802a4e760ffeeaa28112b99d9a" /* ** 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 |
| ︙ | ︙ | |||
4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 | ** ^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 |
| ︙ | ︙ | |||
5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 | ** </dd> ** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt> ** <dd>This parameter returns the number of pager cache misses that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 | > > > > > > > > > > > > | | 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 | ** </dd> ** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt> ** <dd>This parameter returns the number of pager cache misses that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. ** </dd> ** ** [[SQLITE_DBSTATUS_CACHE_WRITE]] ^(<dt>SQLITE_DBSTATUS_CACHE_WRITE</dt> ** <dd>This parameter returns the number of dirty cache entries that have ** been written to disk. Specifically, the number of pages written to the ** wal file in wal mode databases, or the number of pages written to the ** database file in rollback mode databases. Any pages written as part of ** transaction rollback or database recovery operations are not included. ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined). ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_MAX 9 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** ** ^(Each prepared statement maintains various ** [SQLITE_STMTSTATUS counters] that measure the number |
| ︙ | ︙ | |||
6585 6586 6587 6588 6589 6590 6591 | void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** | | | | | > | 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 | 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/stat.c.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
**
** This file contains code to implement the stat web page
**
*/
#include <string.h>
#include "config.h"
#include "stat.h"
/*
** WEBPAGE: stat
**
** Show statistics and global information about the repository.
*/
void stat_page(void){
| > > > > > > > > > > > > > > > > | 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 |
**
** This file contains code to implement the stat web page
**
*/
#include <string.h>
#include "config.h"
#include "stat.h"
/*
** For a sufficiently large integer, provide an alternative
** representation as MB or GB or TB.
*/
static void bigSizeName(int nOut, char *zOut, sqlite3_int64 v){
if( v<100000 ){
sqlite3_snprintf(nOut, zOut, "%lld bytes", v);
}else if( v<1000000000 ){
sqlite3_snprintf(nOut, zOut, "%lld bytes (%.1fMB)",
v, (double)v/1000000.0);
}else{
sqlite3_snprintf(nOut, zOut, "%lld bytes (%.1fGB)",
v, (double)v/1000000000.0);
}
}
/*
** WEBPAGE: stat
**
** Show statistics and global information about the repository.
*/
void stat_page(void){
|
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
@ <table class="label-value">
@ <tr><th>Repository Size:</th><td>
fsize = file_size(g.zRepositoryName);
| | | | | | 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 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
@ <table class="label-value">
@ <tr><th>Repository Size:</th><td>
fsize = file_size(g.zRepositoryName);
bigSizeName(sizeof(zBuf), zBuf, fsize);
@ %s(zBuf)
@ </td></tr>
if( !brief ){
@ <tr><th>Number Of Artifacts:</th><td>
n = db_int(0, "SELECT count(*) FROM blob");
m = db_int(0, "SELECT count(*) FROM delta");
@ %d(n) (stored as %d(n-m) full text and %d(m) delta blobs)
@ </td></tr>
if( n>0 ){
int a, b;
Stmt q;
@ <tr><th>Uncompressed Artifact Size:</th><td>
db_prepare(&q, "SELECT total(size), avg(size), max(size)"
" FROM blob WHERE size>0");
db_step(&q);
t = db_column_int64(&q, 0);
szAvg = db_column_int(&q, 1);
szMax = db_column_int(&q, 2);
db_finalize(&q);
bigSizeName(sizeof(zBuf), zBuf, t);
@ %d(szAvg) bytes average, %d(szMax) bytes max, %s(zBuf) total
@ </td></tr>
@ <tr><th>Compression Ratio:</th><td>
if( t/fsize < 5 ){
b = 10;
fsize /= 10;
}else{
b = 1;
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
811 812 813 814 815 816 817 |
}
}
/*
** WEBPAGE: style.css
*/
void page_style_css(void){
| | | | < | | | | < | < | > > | > > > > > > | > | 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 |
}
}
/*
** WEBPAGE: style.css
*/
void page_style_css(void){
Blob css;
int i;
cgi_set_content_type("text/css");
blob_init(&css, db_get("css",(char*)zDefaultCSS), -1);
/* add special missing definitions */
for(i=1; cssDefaultList[i].elementClass; i++){
if( strstr(blob_str(&css), cssDefaultList[i].elementClass)==0 ){
blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
cssDefaultList[i].comment,
cssDefaultList[i].elementClass,
cssDefaultList[i].value);
}
}
/* Process through TH1 in order to give an opportunity to substitute
** variables such as $baseurl.
*/
Th_Store("baseurl", g.zBaseURL);
Th_Store("home", g.zTop);
Th_Render(blob_str(&css));
/* Tell CGI that the content returned by this page is considered cacheable */
g.isConst = 1;
}
/*
** WEBPAGE: test_env
*/
void page_test_env(void){
|
| ︙ | ︙ |
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);
}
|
| ︙ | ︙ |
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. */
|
| ︙ | ︙ |
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 |
| ︙ | ︙ | |||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 | -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_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 | > > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | -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 |
| ︙ | ︙ | |||
363 364 365 366 367 368 369 370 371 372 373 374 375 376 | +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 $** > $@ | > > > > > > > > > > > > | 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_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 $** > $@ |
| ︙ | ︙ | |||
677 678 679 680 681 682 683 | $(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.
| ︙ | ︙ | |||
148 149 150 151 152 153 154 | #### 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 |
| ︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 | $(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_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 \ | > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | $(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 \ |
| ︙ | ︙ | |||
310 311 312 313 314 315 316 317 318 319 320 321 322 323 | $(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_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 \ | > > | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | $(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 \ |
| ︙ | ︙ | |||
407 408 409 410 411 412 413 414 415 416 417 418 419 420 | $(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_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 \ | > > | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | $(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 \ |
| ︙ | ︙ | |||
529 530 531 532 533 534 535 | 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 |
| ︙ | ︙ | |||
835 836 837 838 839 840 841 842 843 844 845 846 847 848 | $(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 | > > > > > > > > > > > > > > | 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_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 |
| ︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 | 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.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 | #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #### 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. |
| ︙ | ︙ | |||
148 149 150 151 152 153 154 | #### 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 |
| ︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 | $(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_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 \ | > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | $(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 \ |
| ︙ | ︙ | |||
310 311 312 313 314 315 316 317 318 319 320 321 322 323 | $(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_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 \ | > > | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | $(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 \ |
| ︙ | ︙ | |||
407 408 409 410 411 412 413 414 415 416 417 418 419 420 | $(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_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 \ | > > | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | $(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 \ |
| ︙ | ︙ | |||
529 530 531 532 533 534 535 | 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 |
| ︙ | ︙ | |||
835 836 837 838 839 840 841 842 843 844 845 846 847 848 | $(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 | > > > > > > > > > > > > > > | 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_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 |
| ︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 | 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 |
| ︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 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_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 >> $@ | > > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 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 >> $@ |
| ︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 | -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_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 | > > | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | -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 |
| ︙ | ︙ | |||
470 471 472 473 474 475 476 477 478 479 480 481 482 483 | 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 $** > $@ | > > > > > > > > > > > > | 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_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 $** > $@ |
| ︙ | ︙ | |||
784 785 786 787 788 789 790 | $(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 |
Added www/background.jpg.
cannot compute difference between binary files
Changes to www/changes.wiki.
1 2 | <title>Change Log</title> | | > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<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/mkdownload.tcl.
1 2 3 4 5 6 7 8 | #!/usr/bin/tclsh # # Run this script to build the "download.html" page. Also generate # the fossil_download_checksums.html page. # # set out [open download.html w] puts $out \ | | | | > > > > > > > > | > > | 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 |
#!/usr/bin/tclsh
#
# Run this script to build the "download.html" page. Also generate
# the fossil_download_checksums.html page.
#
#
set out [open download.html w]
puts $out \
{<!DOCTYPE html><html>
<head>
<title>Fossil: Timeline</title>
<link rel="stylesheet" href="/fossil/style.css" type="text/css"
media="screen">
</head>
<body>
<div class="header">
<div class="logo">
<img src="/fossil/logo" alt="logo">
<br /><nobr>Fossil</nobr>
</div>
<div class="title">Fossil Downloads</div>
</div>
<div class="mainmenu">
<a href='/fossil/doc/trunk/www/index.wiki'>Home</a>
<a href='/fossil/timeline'>Timeline</a>
<a href='/fossil/dir?ci=tip'>Files</a>
<a href='/fossil/brlist'>Branches</a>
<a href='/fossil/taglist'>Tags</a>
<a href='/fossil/reportlist'>Tickets</a>
<a href='/fossil/wiki'>Wiki</a>
</div>
<div class="content">
<p>
<center><font size=4>
<b>To install Fossil →</b> download the stand-alone executable
and put it on your $PATH.
</font><p><small>
|
| ︙ | ︙ |