Fossil SCM

merge trunk

jan.nijtmans 2013-12-30 20:57 UTC pending-review merge
Commit 02a0e8890e34d6f88ed3aad8419e2d840dc98362
+2 -2
--- src/attach.c
+++ src/attach.c
@@ -214,11 +214,11 @@
214214
}else{
215215
rid = content_put(pAttach);
216216
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
217217
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
218218
}
219
- manifest_crosslink(rid, pAttach);
219
+ manifest_crosslink(rid, pAttach, MC_NONE);
220220
}
221221
222222
223223
/*
224224
** WEBPAGE: attachadd
@@ -431,11 +431,11 @@
431431
blob_appendf(&manifest, "D %s\n", zDate);
432432
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
433433
md5sum_blob(&manifest, &cksum);
434434
blob_appendf(&manifest, "Z %b\n", &cksum);
435435
rid = content_put(&manifest);
436
- manifest_crosslink(rid, &manifest);
436
+ manifest_crosslink(rid, &manifest, MC_NONE);
437437
db_end_transaction(0);
438438
@ <p>The attachment below has been deleted.</p>
439439
}
440440
441441
if( P("del")
442442
--- src/attach.c
+++ src/attach.c
@@ -214,11 +214,11 @@
214 }else{
215 rid = content_put(pAttach);
216 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
217 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
218 }
219 manifest_crosslink(rid, pAttach);
220 }
221
222
223 /*
224 ** WEBPAGE: attachadd
@@ -431,11 +431,11 @@
431 blob_appendf(&manifest, "D %s\n", zDate);
432 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
433 md5sum_blob(&manifest, &cksum);
434 blob_appendf(&manifest, "Z %b\n", &cksum);
435 rid = content_put(&manifest);
436 manifest_crosslink(rid, &manifest);
437 db_end_transaction(0);
438 @ <p>The attachment below has been deleted.</p>
439 }
440
441 if( P("del")
442
--- src/attach.c
+++ src/attach.c
@@ -214,11 +214,11 @@
214 }else{
215 rid = content_put(pAttach);
216 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
217 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
218 }
219 manifest_crosslink(rid, pAttach, MC_NONE);
220 }
221
222
223 /*
224 ** WEBPAGE: attachadd
@@ -431,11 +431,11 @@
431 blob_appendf(&manifest, "D %s\n", zDate);
432 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
433 md5sum_blob(&manifest, &cksum);
434 blob_appendf(&manifest, "Z %b\n", &cksum);
435 rid = content_put(&manifest);
436 manifest_crosslink(rid, &manifest, MC_NONE);
437 db_end_transaction(0);
438 @ <p>The attachment below has been deleted.</p>
439 }
440
441 if( P("del")
442
+2 -2
--- src/branch.c
+++ src/branch.c
@@ -153,12 +153,12 @@
153153
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
154154
if( brid==0 ){
155155
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
156156
}
157157
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
158
- if( manifest_crosslink(brid, &branch)==0 ){
159
- fossil_fatal("unable to install new manifest");
158
+ if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
159
+ fossil_fatal("%s\n", g.zErrMsg);
160160
}
161161
assert( blob_is_reset(&branch) );
162162
content_deltify(rootid, brid, 0);
163163
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid);
164164
fossil_print("New branch: %s\n", zUuid);
165165
--- src/branch.c
+++ src/branch.c
@@ -153,12 +153,12 @@
153 brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
154 if( brid==0 ){
155 fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
156 }
157 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
158 if( manifest_crosslink(brid, &branch)==0 ){
159 fossil_fatal("unable to install new manifest");
160 }
161 assert( blob_is_reset(&branch) );
162 content_deltify(rootid, brid, 0);
163 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid);
164 fossil_print("New branch: %s\n", zUuid);
165
--- src/branch.c
+++ src/branch.c
@@ -153,12 +153,12 @@
153 brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
154 if( brid==0 ){
155 fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
156 }
157 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
158 if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
159 fossil_fatal("%s\n", g.zErrMsg);
160 }
161 assert( blob_is_reset(&branch) );
162 content_deltify(rootid, brid, 0);
163 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid);
164 fossil_print("New branch: %s\n", zUuid);
165
+25 -1
--- src/cgi.c
+++ src/cgi.c
@@ -270,10 +270,20 @@
270270
}
271271
272272
return 0;
273273
}
274274
#endif
275
+
276
+/*
277
+** Return true if the response should be sent with Content-Encoding: gzip.
278
+*/
279
+static int is_gzippable(void){
280
+ if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
281
+ return strncmp(zContentType, "text/", 5)==0
282
+ || strglob("application/*xml", zContentType)
283
+ || strglob("application/*javascript", zContentType);
284
+}
275285
276286
/*
277287
** Do a normal HTTP reply
278288
*/
279289
void cgi_reply(void){
@@ -348,10 +358,22 @@
348358
cgi_combine_header_and_body();
349359
blob_compress(&cgiContent[0], &cgiContent[0]);
350360
}
351361
352362
if( iReplyStatus != 304 ) {
363
+ if( is_gzippable() ){
364
+ int i;
365
+ gzip_begin(0);
366
+ for( i=0; i<2; i++ ){
367
+ int size = blob_size(&cgiContent[i]);
368
+ if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
369
+ blob_reset(&cgiContent[i]);
370
+ }
371
+ gzip_finish(&cgiContent[0]);
372
+ fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
373
+ fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
374
+ }
353375
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
354376
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
355377
}else{
356378
total_size = 0;
357379
}
@@ -1302,11 +1324,13 @@
13021324
while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
13031325
zVal[i] = 0;
13041326
for(i=0; zFieldName[i]; i++){
13051327
zFieldName[i] = fossil_tolower(zFieldName[i]);
13061328
}
1307
- if( fossil_strcmp(zFieldName,"content-length:")==0 ){
1329
+ if( fossil_strcmp(zFieldName,"accept-encoding:")==0 ){
1330
+ cgi_setenv("HTTP_ACCEPT_ENCODING", zVal);
1331
+ }else if( fossil_strcmp(zFieldName,"content-length:")==0 ){
13081332
cgi_setenv("CONTENT_LENGTH", zVal);
13091333
}else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
13101334
cgi_setenv("CONTENT_TYPE", zVal);
13111335
}else if( fossil_strcmp(zFieldName,"cookie:")==0 ){
13121336
cgi_setenv("HTTP_COOKIE", zVal);
13131337
--- src/cgi.c
+++ src/cgi.c
@@ -270,10 +270,20 @@
270 }
271
272 return 0;
273 }
274 #endif
 
 
 
 
 
 
 
 
 
 
275
276 /*
277 ** Do a normal HTTP reply
278 */
279 void cgi_reply(void){
@@ -348,10 +358,22 @@
348 cgi_combine_header_and_body();
349 blob_compress(&cgiContent[0], &cgiContent[0]);
350 }
351
352 if( iReplyStatus != 304 ) {
 
 
 
 
 
 
 
 
 
 
 
 
353 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
354 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
355 }else{
356 total_size = 0;
357 }
@@ -1302,11 +1324,13 @@
1302 while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
1303 zVal[i] = 0;
1304 for(i=0; zFieldName[i]; i++){
1305 zFieldName[i] = fossil_tolower(zFieldName[i]);
1306 }
1307 if( fossil_strcmp(zFieldName,"content-length:")==0 ){
 
 
1308 cgi_setenv("CONTENT_LENGTH", zVal);
1309 }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
1310 cgi_setenv("CONTENT_TYPE", zVal);
1311 }else if( fossil_strcmp(zFieldName,"cookie:")==0 ){
1312 cgi_setenv("HTTP_COOKIE", zVal);
1313
--- src/cgi.c
+++ src/cgi.c
@@ -270,10 +270,20 @@
270 }
271
272 return 0;
273 }
274 #endif
275
276 /*
277 ** Return true if the response should be sent with Content-Encoding: gzip.
278 */
279 static int is_gzippable(void){
280 if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
281 return strncmp(zContentType, "text/", 5)==0
282 || strglob("application/*xml", zContentType)
283 || strglob("application/*javascript", zContentType);
284 }
285
286 /*
287 ** Do a normal HTTP reply
288 */
289 void cgi_reply(void){
@@ -348,10 +358,22 @@
358 cgi_combine_header_and_body();
359 blob_compress(&cgiContent[0], &cgiContent[0]);
360 }
361
362 if( iReplyStatus != 304 ) {
363 if( is_gzippable() ){
364 int i;
365 gzip_begin(0);
366 for( i=0; i<2; i++ ){
367 int size = blob_size(&cgiContent[i]);
368 if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
369 blob_reset(&cgiContent[i]);
370 }
371 gzip_finish(&cgiContent[0]);
372 fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
373 fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
374 }
375 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
376 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
377 }else{
378 total_size = 0;
379 }
@@ -1302,11 +1324,13 @@
1324 while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
1325 zVal[i] = 0;
1326 for(i=0; zFieldName[i]; i++){
1327 zFieldName[i] = fossil_tolower(zFieldName[i]);
1328 }
1329 if( fossil_strcmp(zFieldName,"accept-encoding:")==0 ){
1330 cgi_setenv("HTTP_ACCEPT_ENCODING", zVal);
1331 }else if( fossil_strcmp(zFieldName,"content-length:")==0 ){
1332 cgi_setenv("CONTENT_LENGTH", zVal);
1333 }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
1334 cgi_setenv("CONTENT_TYPE", zVal);
1335 }else if( fossil_strcmp(zFieldName,"cookie:")==0 ){
1336 cgi_setenv("HTTP_COOKIE", zVal);
1337
+13 -3
--- src/checkin.c
+++ src/checkin.c
@@ -1377,11 +1377,14 @@
13771377
** allowed against a closed leaf.
13781378
**
13791379
** The --private option creates a private check-in that is never synced.
13801380
** Children of private check-ins are automatically private.
13811381
**
1382
-** the --tag option applies the symbolic tag name to the check-in.
1382
+** The --tag option applies the symbolic tag name to the check-in.
1383
+**
1384
+** The --sha1sum option detects edited files by computing each file's
1385
+** SHA1 hash rather than just checking for changes to its size or mtime.
13831386
**
13841387
** Options:
13851388
** --allow-conflict allow unresolved merge conflicts
13861389
** --allow-empty allow a commit with no changes
13871390
** --allow-fork allow the commit to fork
@@ -1397,10 +1400,12 @@
13971400
** --mimetype MIMETYPE mimetype of check-in comment
13981401
** -n|--dry-run If given, display instead of run actions
13991402
** --no-warnings omit all warnings about file contents
14001403
** --nosign do not attempt to sign this commit with gpg
14011404
** --private do not sync changes and their descendants
1405
+** --sha1sum verify file status using SHA1 hashing rather
1406
+** than relying on file mtimes
14021407
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
14031408
**
14041409
** See also: branch, changes, checkout, extra, sync
14051410
*/
14061411
void commit_cmd(void){
@@ -1410,10 +1415,11 @@
14101415
int nvid; /* Blob-id of the new check-in */
14111416
Blob comment; /* Check-in comment */
14121417
const char *zComment; /* Check-in comment */
14131418
Stmt q; /* Various queries */
14141419
char *zUuid; /* UUID of the new check-in */
1420
+ int useSha1sum = 0; /* True to verify file status using SHA1 hashing */
14151421
int noSign = 0; /* True to omit signing the manifest using GPG */
14161422
int isAMerge = 0; /* True if checking in a merge */
14171423
int noWarningFlag = 0; /* True if skipping all warnings */
14181424
int forceFlag = 0; /* Undocumented: Disables all checks */
14191425
int forceDelta = 0; /* Force a delta-manifest */
@@ -1441,10 +1447,11 @@
14411447
Blob ans;
14421448
char cReply;
14431449
14441450
memset(&sCiInfo, 0, sizeof(sCiInfo));
14451451
url_proxy_options();
1452
+ useSha1sum = find_option("sha1sum", 0, 0)!=0;
14461453
noSign = find_option("nosign",0,0)!=0;
14471454
forceDelta = find_option("delta",0,0)!=0;
14481455
forceBaseline = find_option("baseline",0,0)!=0;
14491456
if( forceDelta && forceBaseline ){
14501457
fossil_fatal("cannot use --delta and --baseline together");
@@ -1586,11 +1593,11 @@
15861593
*/
15871594
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
15881595
fossil_fatal("no such user: %s", g.zLogin);
15891596
}
15901597
1591
- hasChanges = unsaved_changes();
1598
+ hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0);
15921599
db_begin_transaction();
15931600
db_record_repository_filename(0);
15941601
if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
15951602
fossil_fatal("nothing has changed; use --allow-empty to override");
15961603
}
@@ -1816,11 +1823,14 @@
18161823
nvid = content_put(&manifest);
18171824
if( nvid==0 ){
18181825
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
18191826
}
18201827
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
1821
- manifest_crosslink(nvid, &manifest);
1828
+ if( manifest_crosslink(nvid, &manifest,
1829
+ dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
1830
+ fossil_fatal("%s\n", g.zErrMsg);
1831
+ }
18221832
assert( blob_is_reset(&manifest) );
18231833
content_deltify(vid, nvid, 0);
18241834
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
18251835
18261836
db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
18271837
--- src/checkin.c
+++ src/checkin.c
@@ -1377,11 +1377,14 @@
1377 ** allowed against a closed leaf.
1378 **
1379 ** The --private option creates a private check-in that is never synced.
1380 ** Children of private check-ins are automatically private.
1381 **
1382 ** the --tag option applies the symbolic tag name to the check-in.
 
 
 
1383 **
1384 ** Options:
1385 ** --allow-conflict allow unresolved merge conflicts
1386 ** --allow-empty allow a commit with no changes
1387 ** --allow-fork allow the commit to fork
@@ -1397,10 +1400,12 @@
1397 ** --mimetype MIMETYPE mimetype of check-in comment
1398 ** -n|--dry-run If given, display instead of run actions
1399 ** --no-warnings omit all warnings about file contents
1400 ** --nosign do not attempt to sign this commit with gpg
1401 ** --private do not sync changes and their descendants
 
 
1402 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1403 **
1404 ** See also: branch, changes, checkout, extra, sync
1405 */
1406 void commit_cmd(void){
@@ -1410,10 +1415,11 @@
1410 int nvid; /* Blob-id of the new check-in */
1411 Blob comment; /* Check-in comment */
1412 const char *zComment; /* Check-in comment */
1413 Stmt q; /* Various queries */
1414 char *zUuid; /* UUID of the new check-in */
 
1415 int noSign = 0; /* True to omit signing the manifest using GPG */
1416 int isAMerge = 0; /* True if checking in a merge */
1417 int noWarningFlag = 0; /* True if skipping all warnings */
1418 int forceFlag = 0; /* Undocumented: Disables all checks */
1419 int forceDelta = 0; /* Force a delta-manifest */
@@ -1441,10 +1447,11 @@
1441 Blob ans;
1442 char cReply;
1443
1444 memset(&sCiInfo, 0, sizeof(sCiInfo));
1445 url_proxy_options();
 
1446 noSign = find_option("nosign",0,0)!=0;
1447 forceDelta = find_option("delta",0,0)!=0;
1448 forceBaseline = find_option("baseline",0,0)!=0;
1449 if( forceDelta && forceBaseline ){
1450 fossil_fatal("cannot use --delta and --baseline together");
@@ -1586,11 +1593,11 @@
1586 */
1587 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
1588 fossil_fatal("no such user: %s", g.zLogin);
1589 }
1590
1591 hasChanges = unsaved_changes();
1592 db_begin_transaction();
1593 db_record_repository_filename(0);
1594 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
1595 fossil_fatal("nothing has changed; use --allow-empty to override");
1596 }
@@ -1816,11 +1823,14 @@
1816 nvid = content_put(&manifest);
1817 if( nvid==0 ){
1818 fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
1819 }
1820 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
1821 manifest_crosslink(nvid, &manifest);
 
 
 
1822 assert( blob_is_reset(&manifest) );
1823 content_deltify(vid, nvid, 0);
1824 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
1825
1826 db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
1827
--- src/checkin.c
+++ src/checkin.c
@@ -1377,11 +1377,14 @@
1377 ** allowed against a closed leaf.
1378 **
1379 ** The --private option creates a private check-in that is never synced.
1380 ** Children of private check-ins are automatically private.
1381 **
1382 ** The --tag option applies the symbolic tag name to the check-in.
1383 **
1384 ** The --sha1sum option detects edited files by computing each file's
1385 ** SHA1 hash rather than just checking for changes to its size or mtime.
1386 **
1387 ** Options:
1388 ** --allow-conflict allow unresolved merge conflicts
1389 ** --allow-empty allow a commit with no changes
1390 ** --allow-fork allow the commit to fork
@@ -1397,10 +1400,12 @@
1400 ** --mimetype MIMETYPE mimetype of check-in comment
1401 ** -n|--dry-run If given, display instead of run actions
1402 ** --no-warnings omit all warnings about file contents
1403 ** --nosign do not attempt to sign this commit with gpg
1404 ** --private do not sync changes and their descendants
1405 ** --sha1sum verify file status using SHA1 hashing rather
1406 ** than relying on file mtimes
1407 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1408 **
1409 ** See also: branch, changes, checkout, extra, sync
1410 */
1411 void commit_cmd(void){
@@ -1410,10 +1415,11 @@
1415 int nvid; /* Blob-id of the new check-in */
1416 Blob comment; /* Check-in comment */
1417 const char *zComment; /* Check-in comment */
1418 Stmt q; /* Various queries */
1419 char *zUuid; /* UUID of the new check-in */
1420 int useSha1sum = 0; /* True to verify file status using SHA1 hashing */
1421 int noSign = 0; /* True to omit signing the manifest using GPG */
1422 int isAMerge = 0; /* True if checking in a merge */
1423 int noWarningFlag = 0; /* True if skipping all warnings */
1424 int forceFlag = 0; /* Undocumented: Disables all checks */
1425 int forceDelta = 0; /* Force a delta-manifest */
@@ -1441,10 +1447,11 @@
1447 Blob ans;
1448 char cReply;
1449
1450 memset(&sCiInfo, 0, sizeof(sCiInfo));
1451 url_proxy_options();
1452 useSha1sum = find_option("sha1sum", 0, 0)!=0;
1453 noSign = find_option("nosign",0,0)!=0;
1454 forceDelta = find_option("delta",0,0)!=0;
1455 forceBaseline = find_option("baseline",0,0)!=0;
1456 if( forceDelta && forceBaseline ){
1457 fossil_fatal("cannot use --delta and --baseline together");
@@ -1586,11 +1593,11 @@
1593 */
1594 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
1595 fossil_fatal("no such user: %s", g.zLogin);
1596 }
1597
1598 hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0);
1599 db_begin_transaction();
1600 db_record_repository_filename(0);
1601 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
1602 fossil_fatal("nothing has changed; use --allow-empty to override");
1603 }
@@ -1816,11 +1823,14 @@
1823 nvid = content_put(&manifest);
1824 if( nvid==0 ){
1825 fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
1826 }
1827 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
1828 if( manifest_crosslink(nvid, &manifest,
1829 dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
1830 fossil_fatal("%s\n", g.zErrMsg);
1831 }
1832 assert( blob_is_reset(&manifest) );
1833 content_deltify(vid, nvid, 0);
1834 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
1835
1836 db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
1837
+4 -4
--- src/checkout.c
+++ src/checkout.c
@@ -28,16 +28,16 @@
2828
**
2929
** 0: There is an existing checkout but it is unmodified
3030
** 1: There is a modified checkout - there are unsaved changes
3131
** 2: There is no existing checkout
3232
*/
33
-int unsaved_changes(void){
33
+int unsaved_changes(unsigned int cksigFlags){
3434
int vid;
3535
db_must_be_within_tree();
3636
vid = db_lget_int("checkout",0);
3737
if( vid==0 ) return 2;
38
- vfile_check_signature(vid, CKSIG_ENOTFILE);
38
+ vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE);
3939
return db_exists("SELECT 1 FROM vfile WHERE chnged"
4040
" OR coalesce(origname!=pathname,0)");
4141
}
4242
4343
/*
@@ -200,11 +200,11 @@
200200
latestFlag = find_option("latest",0,0)!=0;
201201
promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
202202
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
203203
usage("VERSION|--latest ?--force? ?--keep?");
204204
}
205
- if( !forceFlag && unsaved_changes()==1 ){
205
+ if( !forceFlag && unsaved_changes(0)==1 ){
206206
fossil_fatal("there are unsaved changes in the current checkout");
207207
}
208208
if( forceFlag ){
209209
db_multi_exec("DELETE FROM vfile");
210210
prior = 0;
@@ -288,11 +288,11 @@
288288
** See also: open
289289
*/
290290
void close_cmd(void){
291291
int forceFlag = find_option("force","f",0)!=0;
292292
db_must_be_within_tree();
293
- if( !forceFlag && unsaved_changes()==1 ){
293
+ if( !forceFlag && unsaved_changes(0)==1 ){
294294
fossil_fatal("there are unsaved changes in the current checkout");
295295
}
296296
if( !forceFlag
297297
&& db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'",
298298
db_name("localdb"))
299299
--- src/checkout.c
+++ src/checkout.c
@@ -28,16 +28,16 @@
28 **
29 ** 0: There is an existing checkout but it is unmodified
30 ** 1: There is a modified checkout - there are unsaved changes
31 ** 2: There is no existing checkout
32 */
33 int unsaved_changes(void){
34 int vid;
35 db_must_be_within_tree();
36 vid = db_lget_int("checkout",0);
37 if( vid==0 ) return 2;
38 vfile_check_signature(vid, CKSIG_ENOTFILE);
39 return db_exists("SELECT 1 FROM vfile WHERE chnged"
40 " OR coalesce(origname!=pathname,0)");
41 }
42
43 /*
@@ -200,11 +200,11 @@
200 latestFlag = find_option("latest",0,0)!=0;
201 promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
202 if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
203 usage("VERSION|--latest ?--force? ?--keep?");
204 }
205 if( !forceFlag && unsaved_changes()==1 ){
206 fossil_fatal("there are unsaved changes in the current checkout");
207 }
208 if( forceFlag ){
209 db_multi_exec("DELETE FROM vfile");
210 prior = 0;
@@ -288,11 +288,11 @@
288 ** See also: open
289 */
290 void close_cmd(void){
291 int forceFlag = find_option("force","f",0)!=0;
292 db_must_be_within_tree();
293 if( !forceFlag && unsaved_changes()==1 ){
294 fossil_fatal("there are unsaved changes in the current checkout");
295 }
296 if( !forceFlag
297 && db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'",
298 db_name("localdb"))
299
--- src/checkout.c
+++ src/checkout.c
@@ -28,16 +28,16 @@
28 **
29 ** 0: There is an existing checkout but it is unmodified
30 ** 1: There is a modified checkout - there are unsaved changes
31 ** 2: There is no existing checkout
32 */
33 int unsaved_changes(unsigned int cksigFlags){
34 int vid;
35 db_must_be_within_tree();
36 vid = db_lget_int("checkout",0);
37 if( vid==0 ) return 2;
38 vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE);
39 return db_exists("SELECT 1 FROM vfile WHERE chnged"
40 " OR coalesce(origname!=pathname,0)");
41 }
42
43 /*
@@ -200,11 +200,11 @@
200 latestFlag = find_option("latest",0,0)!=0;
201 promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
202 if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
203 usage("VERSION|--latest ?--force? ?--keep?");
204 }
205 if( !forceFlag && unsaved_changes(0)==1 ){
206 fossil_fatal("there are unsaved changes in the current checkout");
207 }
208 if( forceFlag ){
209 db_multi_exec("DELETE FROM vfile");
210 prior = 0;
@@ -288,11 +288,11 @@
288 ** See also: open
289 */
290 void close_cmd(void){
291 int forceFlag = find_option("force","f",0)!=0;
292 db_must_be_within_tree();
293 if( !forceFlag && unsaved_changes(0)==1 ){
294 fossil_fatal("there are unsaved changes in the current checkout");
295 }
296 if( !forceFlag
297 && db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'",
298 db_name("localdb"))
299
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
9898
{ "timeline-plaintext", CONFIGSET_SKIN },
9999
{ "adunit", CONFIGSET_SKIN },
100100
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
101101
{ "adunit-omit-if-user", CONFIGSET_SKIN },
102102
{ "th1-setup", CONFIGSET_TH1 },
103
+ { "th1-uri-regexp", CONFIGSET_TH1 },
103104
104105
#ifdef FOSSIL_ENABLE_TCL
105106
{ "tcl", CONFIGSET_TH1 },
106107
{ "tcl-setup", CONFIGSET_TH1 },
107108
#endif
@@ -138,10 +139,12 @@
138139
139140
{ "@shun", CONFIGSET_SHUN },
140141
141142
{ "xfer-common-script", CONFIGSET_XFER },
142143
{ "xfer-push-script", CONFIGSET_XFER },
144
+ { "xfer-commit-script", CONFIGSET_XFER },
145
+ { "xfer-ticket-script", CONFIGSET_XFER },
143146
144147
};
145148
static int iConfig = 0;
146149
147150
/*
148151
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
98 { "timeline-plaintext", CONFIGSET_SKIN },
99 { "adunit", CONFIGSET_SKIN },
100 { "adunit-omit-if-admin", CONFIGSET_SKIN },
101 { "adunit-omit-if-user", CONFIGSET_SKIN },
102 { "th1-setup", CONFIGSET_TH1 },
 
103
104 #ifdef FOSSIL_ENABLE_TCL
105 { "tcl", CONFIGSET_TH1 },
106 { "tcl-setup", CONFIGSET_TH1 },
107 #endif
@@ -138,10 +139,12 @@
138
139 { "@shun", CONFIGSET_SHUN },
140
141 { "xfer-common-script", CONFIGSET_XFER },
142 { "xfer-push-script", CONFIGSET_XFER },
 
 
143
144 };
145 static int iConfig = 0;
146
147 /*
148
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
98 { "timeline-plaintext", CONFIGSET_SKIN },
99 { "adunit", CONFIGSET_SKIN },
100 { "adunit-omit-if-admin", CONFIGSET_SKIN },
101 { "adunit-omit-if-user", CONFIGSET_SKIN },
102 { "th1-setup", CONFIGSET_TH1 },
103 { "th1-uri-regexp", CONFIGSET_TH1 },
104
105 #ifdef FOSSIL_ENABLE_TCL
106 { "tcl", CONFIGSET_TH1 },
107 { "tcl-setup", CONFIGSET_TH1 },
108 #endif
@@ -138,10 +139,12 @@
139
140 { "@shun", CONFIGSET_SHUN },
141
142 { "xfer-common-script", CONFIGSET_XFER },
143 { "xfer-push-script", CONFIGSET_XFER },
144 { "xfer-commit-script", CONFIGSET_XFER },
145 { "xfer-ticket-script", CONFIGSET_XFER },
146
147 };
148 static int iConfig = 0;
149
150 /*
151
+2 -2
--- src/content.c
+++ src/content.c
@@ -388,11 +388,11 @@
388388
int i;
389389
390390
/* Parse the object rid itself */
391391
if( linkFlag ){
392392
content_get(rid, &content);
393
- manifest_crosslink(rid, &content);
393
+ manifest_crosslink(rid, &content, MC_NONE);
394394
assert( blob_is_reset(&content) );
395395
}
396396
397397
/* Parse all delta-manifests that depend on baseline-manifest rid */
398398
db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid);
@@ -405,11 +405,11 @@
405405
aChild[nChildUsed++] = child;
406406
}
407407
db_finalize(&q);
408408
for(i=0; i<nChildUsed; i++){
409409
content_get(aChild[i], &content);
410
- manifest_crosslink(aChild[i], &content);
410
+ manifest_crosslink(aChild[i], &content, MC_NONE);
411411
assert( blob_is_reset(&content) );
412412
}
413413
if( nChildUsed ){
414414
db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid);
415415
}
416416
--- src/content.c
+++ src/content.c
@@ -388,11 +388,11 @@
388 int i;
389
390 /* Parse the object rid itself */
391 if( linkFlag ){
392 content_get(rid, &content);
393 manifest_crosslink(rid, &content);
394 assert( blob_is_reset(&content) );
395 }
396
397 /* Parse all delta-manifests that depend on baseline-manifest rid */
398 db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid);
@@ -405,11 +405,11 @@
405 aChild[nChildUsed++] = child;
406 }
407 db_finalize(&q);
408 for(i=0; i<nChildUsed; i++){
409 content_get(aChild[i], &content);
410 manifest_crosslink(aChild[i], &content);
411 assert( blob_is_reset(&content) );
412 }
413 if( nChildUsed ){
414 db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid);
415 }
416
--- src/content.c
+++ src/content.c
@@ -388,11 +388,11 @@
388 int i;
389
390 /* Parse the object rid itself */
391 if( linkFlag ){
392 content_get(rid, &content);
393 manifest_crosslink(rid, &content, MC_NONE);
394 assert( blob_is_reset(&content) );
395 }
396
397 /* Parse all delta-manifests that depend on baseline-manifest rid */
398 db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid);
@@ -405,11 +405,11 @@
405 aChild[nChildUsed++] = child;
406 }
407 db_finalize(&q);
408 for(i=0; i<nChildUsed; i++){
409 content_get(aChild[i], &content);
410 manifest_crosslink(aChild[i], &content, MC_NONE);
411 assert( blob_is_reset(&content) );
412 }
413 if( nChildUsed ){
414 db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid);
415 }
416
+6 -1
--- src/db.c
+++ src/db.c
@@ -1418,11 +1418,11 @@
14181418
blob_appendf(&manifest, "U %F\n", g.zLogin);
14191419
md5sum_blob(&manifest, &hash);
14201420
blob_appendf(&manifest, "Z %b\n", &hash);
14211421
blob_reset(&hash);
14221422
rid = content_put(&manifest);
1423
- manifest_crosslink(rid, &manifest);
1423
+ manifest_crosslink(rid, &manifest, MC_NONE);
14241424
}
14251425
}
14261426
14271427
/*
14281428
** COMMAND: new*
@@ -2158,10 +2158,11 @@
21582158
#ifdef FOSSIL_ENABLE_TCL
21592159
{ "tcl", 0, 0, 0, "off" },
21602160
{ "tcl-setup", 0, 40, 0, "" },
21612161
#endif
21622162
{ "th1-setup", 0, 40, 0, "" },
2163
+ { "th1-uri-regexp",0, 40, 0, "" },
21632164
{ "web-browser", 0, 32, 0, "" },
21642165
{ "white-foreground", 0, 0, 0, "off" },
21652166
{ 0,0,0,0,0 }
21662167
};
21672168
@@ -2354,10 +2355,14 @@
23542355
** is empty and no extra setup is performed.
23552356
**
23562357
** th1-setup This is the setup script to be evaluated after creating
23572358
** and initializing the TH1 interpreter. By default, this
23582359
** is empty and no extra setup is performed.
2360
+**
2361
+** th1-uri-regexp Specify which URI's are allowed in HTTP requests from
2362
+** TH1 scripts. If empty, no HTTP requests are allowed
2363
+** whatsoever. The default is an empty string.
23592364
**
23602365
** web-browser A shell command used to launch your preferred
23612366
** web browser when given a URL as an argument.
23622367
** Defaults to "start" on windows, "open" on Mac,
23632368
** and "firefox" on Unix.
23642369
--- src/db.c
+++ src/db.c
@@ -1418,11 +1418,11 @@
1418 blob_appendf(&manifest, "U %F\n", g.zLogin);
1419 md5sum_blob(&manifest, &hash);
1420 blob_appendf(&manifest, "Z %b\n", &hash);
1421 blob_reset(&hash);
1422 rid = content_put(&manifest);
1423 manifest_crosslink(rid, &manifest);
1424 }
1425 }
1426
1427 /*
1428 ** COMMAND: new*
@@ -2158,10 +2158,11 @@
2158 #ifdef FOSSIL_ENABLE_TCL
2159 { "tcl", 0, 0, 0, "off" },
2160 { "tcl-setup", 0, 40, 0, "" },
2161 #endif
2162 { "th1-setup", 0, 40, 0, "" },
 
2163 { "web-browser", 0, 32, 0, "" },
2164 { "white-foreground", 0, 0, 0, "off" },
2165 { 0,0,0,0,0 }
2166 };
2167
@@ -2354,10 +2355,14 @@
2354 ** is empty and no extra setup is performed.
2355 **
2356 ** th1-setup This is the setup script to be evaluated after creating
2357 ** and initializing the TH1 interpreter. By default, this
2358 ** is empty and no extra setup is performed.
 
 
 
 
2359 **
2360 ** web-browser A shell command used to launch your preferred
2361 ** web browser when given a URL as an argument.
2362 ** Defaults to "start" on windows, "open" on Mac,
2363 ** and "firefox" on Unix.
2364
--- src/db.c
+++ src/db.c
@@ -1418,11 +1418,11 @@
1418 blob_appendf(&manifest, "U %F\n", g.zLogin);
1419 md5sum_blob(&manifest, &hash);
1420 blob_appendf(&manifest, "Z %b\n", &hash);
1421 blob_reset(&hash);
1422 rid = content_put(&manifest);
1423 manifest_crosslink(rid, &manifest, MC_NONE);
1424 }
1425 }
1426
1427 /*
1428 ** COMMAND: new*
@@ -2158,10 +2158,11 @@
2158 #ifdef FOSSIL_ENABLE_TCL
2159 { "tcl", 0, 0, 0, "off" },
2160 { "tcl-setup", 0, 40, 0, "" },
2161 #endif
2162 { "th1-setup", 0, 40, 0, "" },
2163 { "th1-uri-regexp",0, 40, 0, "" },
2164 { "web-browser", 0, 32, 0, "" },
2165 { "white-foreground", 0, 0, 0, "off" },
2166 { 0,0,0,0,0 }
2167 };
2168
@@ -2354,10 +2355,14 @@
2355 ** is empty and no extra setup is performed.
2356 **
2357 ** th1-setup This is the setup script to be evaluated after creating
2358 ** and initializing the TH1 interpreter. By default, this
2359 ** is empty and no extra setup is performed.
2360 **
2361 ** th1-uri-regexp Specify which URI's are allowed in HTTP requests from
2362 ** TH1 scripts. If empty, no HTTP requests are allowed
2363 ** whatsoever. The default is an empty string.
2364 **
2365 ** web-browser A shell command used to launch your preferred
2366 ** web browser when given a URL as an argument.
2367 ** Defaults to "start" on windows, "open" on Mac,
2368 ** and "firefox" on Unix.
2369
+6 -1
--- src/db.c
+++ src/db.c
@@ -1418,11 +1418,11 @@
14181418
blob_appendf(&manifest, "U %F\n", g.zLogin);
14191419
md5sum_blob(&manifest, &hash);
14201420
blob_appendf(&manifest, "Z %b\n", &hash);
14211421
blob_reset(&hash);
14221422
rid = content_put(&manifest);
1423
- manifest_crosslink(rid, &manifest);
1423
+ manifest_crosslink(rid, &manifest, MC_NONE);
14241424
}
14251425
}
14261426
14271427
/*
14281428
** COMMAND: new*
@@ -2158,10 +2158,11 @@
21582158
#ifdef FOSSIL_ENABLE_TCL
21592159
{ "tcl", 0, 0, 0, "off" },
21602160
{ "tcl-setup", 0, 40, 0, "" },
21612161
#endif
21622162
{ "th1-setup", 0, 40, 0, "" },
2163
+ { "th1-uri-regexp",0, 40, 0, "" },
21632164
{ "web-browser", 0, 32, 0, "" },
21642165
{ "white-foreground", 0, 0, 0, "off" },
21652166
{ 0,0,0,0,0 }
21662167
};
21672168
@@ -2354,10 +2355,14 @@
23542355
** is empty and no extra setup is performed.
23552356
**
23562357
** th1-setup This is the setup script to be evaluated after creating
23572358
** and initializing the TH1 interpreter. By default, this
23582359
** is empty and no extra setup is performed.
2360
+**
2361
+** th1-uri-regexp Specify which URI's are allowed in HTTP requests from
2362
+** TH1 scripts. If empty, no HTTP requests are allowed
2363
+** whatsoever. The default is an empty string.
23592364
**
23602365
** web-browser A shell command used to launch your preferred
23612366
** web browser when given a URL as an argument.
23622367
** Defaults to "start" on windows, "open" on Mac,
23632368
** and "firefox" on Unix.
23642369
--- src/db.c
+++ src/db.c
@@ -1418,11 +1418,11 @@
1418 blob_appendf(&manifest, "U %F\n", g.zLogin);
1419 md5sum_blob(&manifest, &hash);
1420 blob_appendf(&manifest, "Z %b\n", &hash);
1421 blob_reset(&hash);
1422 rid = content_put(&manifest);
1423 manifest_crosslink(rid, &manifest);
1424 }
1425 }
1426
1427 /*
1428 ** COMMAND: new*
@@ -2158,10 +2158,11 @@
2158 #ifdef FOSSIL_ENABLE_TCL
2159 { "tcl", 0, 0, 0, "off" },
2160 { "tcl-setup", 0, 40, 0, "" },
2161 #endif
2162 { "th1-setup", 0, 40, 0, "" },
 
2163 { "web-browser", 0, 32, 0, "" },
2164 { "white-foreground", 0, 0, 0, "off" },
2165 { 0,0,0,0,0 }
2166 };
2167
@@ -2354,10 +2355,14 @@
2354 ** is empty and no extra setup is performed.
2355 **
2356 ** th1-setup This is the setup script to be evaluated after creating
2357 ** and initializing the TH1 interpreter. By default, this
2358 ** is empty and no extra setup is performed.
 
 
 
 
2359 **
2360 ** web-browser A shell command used to launch your preferred
2361 ** web browser when given a URL as an argument.
2362 ** Defaults to "start" on windows, "open" on Mac,
2363 ** and "firefox" on Unix.
2364
--- src/db.c
+++ src/db.c
@@ -1418,11 +1418,11 @@
1418 blob_appendf(&manifest, "U %F\n", g.zLogin);
1419 md5sum_blob(&manifest, &hash);
1420 blob_appendf(&manifest, "Z %b\n", &hash);
1421 blob_reset(&hash);
1422 rid = content_put(&manifest);
1423 manifest_crosslink(rid, &manifest, MC_NONE);
1424 }
1425 }
1426
1427 /*
1428 ** COMMAND: new*
@@ -2158,10 +2158,11 @@
2158 #ifdef FOSSIL_ENABLE_TCL
2159 { "tcl", 0, 0, 0, "off" },
2160 { "tcl-setup", 0, 40, 0, "" },
2161 #endif
2162 { "th1-setup", 0, 40, 0, "" },
2163 { "th1-uri-regexp",0, 40, 0, "" },
2164 { "web-browser", 0, 32, 0, "" },
2165 { "white-foreground", 0, 0, 0, "off" },
2166 { 0,0,0,0,0 }
2167 };
2168
@@ -2354,10 +2355,14 @@
2355 ** is empty and no extra setup is performed.
2356 **
2357 ** th1-setup This is the setup script to be evaluated after creating
2358 ** and initializing the TH1 interpreter. By default, this
2359 ** is empty and no extra setup is performed.
2360 **
2361 ** th1-uri-regexp Specify which URI's are allowed in HTTP requests from
2362 ** TH1 scripts. If empty, no HTTP requests are allowed
2363 ** whatsoever. The default is an empty string.
2364 **
2365 ** web-browser A shell command used to launch your preferred
2366 ** web browser when given a URL as an argument.
2367 ** Defaults to "start" on windows, "open" on Mac,
2368 ** and "firefox" on Unix.
2369
+5 -5
--- src/diff.c
+++ src/diff.c
@@ -2179,26 +2179,26 @@
21792179
url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
21802180
}
21812181
url_add_parameter(&url, "log", showLog ? "1" : "0");
21822182
if( showLog ){
21832183
style_submenu_element("Hide Log", "Hide Log",
2184
- url_render(&url, "log", "0", 0, 0));
2184
+ "%s", url_render(&url, "log", "0", 0, 0));
21852185
}else{
21862186
style_submenu_element("Show Log", "Show Log",
2187
- url_render(&url, "log", "1", 0, 0));
2187
+ "%s", url_render(&url, "log", "1", 0, 0));
21882188
}
21892189
if( ann.bLimit ){
21902190
char *z1, *z2;
21912191
style_submenu_element("All Ancestors", "All Ancestors",
2192
- url_render(&url, "limit", "-1", 0, 0));
2192
+ "%s", url_render(&url, "limit", "-1", 0, 0));
21932193
z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
21942194
z2 = sqlite3_mprintf("%d", iLimit+20);
2195
- style_submenu_element(z1, z1, url_render(&url, "limit", z2, 0, 0));
2195
+ style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0));
21962196
}
21972197
if( iLimit>20 ){
21982198
style_submenu_element("20 Ancestors", "20 Ancestors",
2199
- url_render(&url, "limit", "20", 0, 0));
2199
+ "%s", url_render(&url, "limit", "20", 0, 0));
22002200
}
22012201
if( db_get_boolean("white-foreground", 0) ){
22022202
clr1 = 0xa04040;
22032203
clr2 = 0x4059a0;
22042204
}else{
22052205
--- src/diff.c
+++ src/diff.c
@@ -2179,26 +2179,26 @@
2179 url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
2180 }
2181 url_add_parameter(&url, "log", showLog ? "1" : "0");
2182 if( showLog ){
2183 style_submenu_element("Hide Log", "Hide Log",
2184 url_render(&url, "log", "0", 0, 0));
2185 }else{
2186 style_submenu_element("Show Log", "Show Log",
2187 url_render(&url, "log", "1", 0, 0));
2188 }
2189 if( ann.bLimit ){
2190 char *z1, *z2;
2191 style_submenu_element("All Ancestors", "All Ancestors",
2192 url_render(&url, "limit", "-1", 0, 0));
2193 z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
2194 z2 = sqlite3_mprintf("%d", iLimit+20);
2195 style_submenu_element(z1, z1, url_render(&url, "limit", z2, 0, 0));
2196 }
2197 if( iLimit>20 ){
2198 style_submenu_element("20 Ancestors", "20 Ancestors",
2199 url_render(&url, "limit", "20", 0, 0));
2200 }
2201 if( db_get_boolean("white-foreground", 0) ){
2202 clr1 = 0xa04040;
2203 clr2 = 0x4059a0;
2204 }else{
2205
--- src/diff.c
+++ src/diff.c
@@ -2179,26 +2179,26 @@
2179 url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
2180 }
2181 url_add_parameter(&url, "log", showLog ? "1" : "0");
2182 if( showLog ){
2183 style_submenu_element("Hide Log", "Hide Log",
2184 "%s", url_render(&url, "log", "0", 0, 0));
2185 }else{
2186 style_submenu_element("Show Log", "Show Log",
2187 "%s", url_render(&url, "log", "1", 0, 0));
2188 }
2189 if( ann.bLimit ){
2190 char *z1, *z2;
2191 style_submenu_element("All Ancestors", "All Ancestors",
2192 "%s", url_render(&url, "limit", "-1", 0, 0));
2193 z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
2194 z2 = sqlite3_mprintf("%d", iLimit+20);
2195 style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0));
2196 }
2197 if( iLimit>20 ){
2198 style_submenu_element("20 Ancestors", "20 Ancestors",
2199 "%s", url_render(&url, "limit", "20", 0, 0));
2200 }
2201 if( db_get_boolean("white-foreground", 0) ){
2202 clr1 = 0xa04040;
2203 clr2 = 0x4059a0;
2204 }else{
2205
+1 -1
--- src/event.c
+++ src/event.c
@@ -351,11 +351,11 @@
351351
md5sum_blob(&event, &cksum);
352352
blob_appendf(&event, "Z %b\n", &cksum);
353353
blob_reset(&cksum);
354354
nrid = content_put(&event);
355355
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
356
- manifest_crosslink(nrid, &event);
356
+ manifest_crosslink(nrid, &event, MC_NONE);
357357
assert( blob_is_reset(&event) );
358358
content_deltify(rid, nrid, 0);
359359
db_end_transaction(0);
360360
cgi_redirectf("event?name=%T", zEventId);
361361
}
362362
--- src/event.c
+++ src/event.c
@@ -351,11 +351,11 @@
351 md5sum_blob(&event, &cksum);
352 blob_appendf(&event, "Z %b\n", &cksum);
353 blob_reset(&cksum);
354 nrid = content_put(&event);
355 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
356 manifest_crosslink(nrid, &event);
357 assert( blob_is_reset(&event) );
358 content_deltify(rid, nrid, 0);
359 db_end_transaction(0);
360 cgi_redirectf("event?name=%T", zEventId);
361 }
362
--- src/event.c
+++ src/event.c
@@ -351,11 +351,11 @@
351 md5sum_blob(&event, &cksum);
352 blob_appendf(&event, "Z %b\n", &cksum);
353 blob_reset(&cksum);
354 nrid = content_put(&event);
355 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
356 manifest_crosslink(nrid, &event, MC_NONE);
357 assert( blob_is_reset(&event) );
358 content_deltify(rid, nrid, 0);
359 db_end_transaction(0);
360 cgi_redirectf("event?name=%T", zEventId);
361 }
362
+2 -2
--- src/finfo.c
+++ src/finfo.c
@@ -294,11 +294,11 @@
294294
url_initialize(&url, "finfo");
295295
if( brBg ) url_add_parameter(&url, "brbg", 0);
296296
if( uBg ) url_add_parameter(&url, "ubg", 0);
297297
baseCheckin = name_to_rid_www("ci");
298298
if( baseCheckin ) firstChngOnly = 1;
299
- if( firstChngOnly ) url_add_parameter(&url, "fco", "0");
299
+ if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");
300300
301301
zPrevDate[0] = 0;
302302
zFilename = PD("name","");
303303
url_add_parameter(&url, "name", zFilename);
304304
blob_zero(&sql);
@@ -362,11 +362,11 @@
362362
style_submenu_element("Full", "Show all changes","%s",
363363
url_render(&url, "fco", "0", 0, 0));
364364
}else{
365365
style_submenu_element("Simplified",
366366
"Show only first use of a change","%s",
367
- url_render(&url, "fco", "1", 0, 0));
367
+ url_render(&url, "fco", 0, 0, 0));
368368
}
369369
}
370370
db_prepare(&q, blob_str(&sql));
371371
if( P("showsql")!=0 ){
372372
@ <p>SQL: %h(blob_str(&sql))</p>
373373
--- src/finfo.c
+++ src/finfo.c
@@ -294,11 +294,11 @@
294 url_initialize(&url, "finfo");
295 if( brBg ) url_add_parameter(&url, "brbg", 0);
296 if( uBg ) url_add_parameter(&url, "ubg", 0);
297 baseCheckin = name_to_rid_www("ci");
298 if( baseCheckin ) firstChngOnly = 1;
299 if( firstChngOnly ) url_add_parameter(&url, "fco", "0");
300
301 zPrevDate[0] = 0;
302 zFilename = PD("name","");
303 url_add_parameter(&url, "name", zFilename);
304 blob_zero(&sql);
@@ -362,11 +362,11 @@
362 style_submenu_element("Full", "Show all changes","%s",
363 url_render(&url, "fco", "0", 0, 0));
364 }else{
365 style_submenu_element("Simplified",
366 "Show only first use of a change","%s",
367 url_render(&url, "fco", "1", 0, 0));
368 }
369 }
370 db_prepare(&q, blob_str(&sql));
371 if( P("showsql")!=0 ){
372 @ <p>SQL: %h(blob_str(&sql))</p>
373
--- src/finfo.c
+++ src/finfo.c
@@ -294,11 +294,11 @@
294 url_initialize(&url, "finfo");
295 if( brBg ) url_add_parameter(&url, "brbg", 0);
296 if( uBg ) url_add_parameter(&url, "ubg", 0);
297 baseCheckin = name_to_rid_www("ci");
298 if( baseCheckin ) firstChngOnly = 1;
299 if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");
300
301 zPrevDate[0] = 0;
302 zFilename = PD("name","");
303 url_add_parameter(&url, "name", zFilename);
304 blob_zero(&sql);
@@ -362,11 +362,11 @@
362 style_submenu_element("Full", "Show all changes","%s",
363 url_render(&url, "fco", "0", 0, 0));
364 }else{
365 style_submenu_element("Simplified",
366 "Show only first use of a change","%s",
367 url_render(&url, "fco", 0, 0, 0));
368 }
369 }
370 db_prepare(&q, blob_str(&sql));
371 if( P("showsql")!=0 ){
372 @ <p>SQL: %h(blob_str(&sql))</p>
373
+2 -2
--- src/gzip.c
+++ src/gzip.c
@@ -55,11 +55,11 @@
5555
blob_zero(&gzip.out);
5656
aHdr[0] = 0x1f;
5757
aHdr[1] = 0x8b;
5858
aHdr[2] = 8;
5959
aHdr[3] = 0;
60
- if( now==0 ){
60
+ if( now==-1 ){
6161
now = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0");
6262
}
6363
put32(&aHdr[4], now&0xffffffff);
6464
aHdr[8] = 2;
6565
aHdr[9] = 255;
@@ -126,15 +126,15 @@
126126
void test_gzip_cmd(void){
127127
Blob b;
128128
char *zOut;
129129
if( g.argc!=3 ) usage("FILENAME");
130130
sqlite3_open(":memory:", &g.db);
131
- gzip_begin(0);
131
+ gzip_begin(-1);
132132
blob_read_from_file(&b, g.argv[2]);
133133
zOut = mprintf("%s.gz", g.argv[2]);
134134
gzip_step(blob_buffer(&b), blob_size(&b));
135135
blob_reset(&b);
136136
gzip_finish(&b);
137137
blob_write_to_file(&b, zOut);
138138
blob_reset(&b);
139139
fossil_free(zOut);
140140
}
141141
--- src/gzip.c
+++ src/gzip.c
@@ -55,11 +55,11 @@
55 blob_zero(&gzip.out);
56 aHdr[0] = 0x1f;
57 aHdr[1] = 0x8b;
58 aHdr[2] = 8;
59 aHdr[3] = 0;
60 if( now==0 ){
61 now = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0");
62 }
63 put32(&aHdr[4], now&0xffffffff);
64 aHdr[8] = 2;
65 aHdr[9] = 255;
@@ -126,15 +126,15 @@
126 void test_gzip_cmd(void){
127 Blob b;
128 char *zOut;
129 if( g.argc!=3 ) usage("FILENAME");
130 sqlite3_open(":memory:", &g.db);
131 gzip_begin(0);
132 blob_read_from_file(&b, g.argv[2]);
133 zOut = mprintf("%s.gz", g.argv[2]);
134 gzip_step(blob_buffer(&b), blob_size(&b));
135 blob_reset(&b);
136 gzip_finish(&b);
137 blob_write_to_file(&b, zOut);
138 blob_reset(&b);
139 fossil_free(zOut);
140 }
141
--- src/gzip.c
+++ src/gzip.c
@@ -55,11 +55,11 @@
55 blob_zero(&gzip.out);
56 aHdr[0] = 0x1f;
57 aHdr[1] = 0x8b;
58 aHdr[2] = 8;
59 aHdr[3] = 0;
60 if( now==-1 ){
61 now = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0");
62 }
63 put32(&aHdr[4], now&0xffffffff);
64 aHdr[8] = 2;
65 aHdr[9] = 255;
@@ -126,15 +126,15 @@
126 void test_gzip_cmd(void){
127 Blob b;
128 char *zOut;
129 if( g.argc!=3 ) usage("FILENAME");
130 sqlite3_open(":memory:", &g.db);
131 gzip_begin(-1);
132 blob_read_from_file(&b, g.argv[2]);
133 zOut = mprintf("%s.gz", g.argv[2]);
134 gzip_step(blob_buffer(&b), blob_size(&b));
135 blob_reset(&b);
136 gzip_finish(&b);
137 blob_write_to_file(&b, zOut);
138 blob_reset(&b);
139 fossil_free(zOut);
140 }
141
+12 -13
--- src/http.c
+++ src/http.c
@@ -110,12 +110,11 @@
110110
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
111111
fossil_free(zEncoded);
112112
fossil_free(zCredentials);
113113
}
114114
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115
- blob_appendf(pHdr, "User-Agent: Fossil/" RELEASE_VERSION
116
- " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
115
+ blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
117116
if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
118117
if( g.fHttpTrace ){
119118
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
120119
}else{
121120
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
@@ -144,12 +143,12 @@
144143
char *zLine; /* A single line of the reply header */
145144
int i; /* Loop counter */
146145
int isError = 0; /* True if the reply is an error message */
147146
int isCompressed = 1; /* True if the reply is compressed */
148147
149
- if( transport_open() ){
150
- fossil_warning(transport_errmsg());
148
+ if( transport_open(GLOBAL_URL()) ){
149
+ fossil_warning(transport_errmsg(GLOBAL_URL()));
151150
return 1;
152151
}
153152
154153
/* Construct the login card and prepare the complete payload */
155154
blob_zero(&login);
@@ -191,22 +190,22 @@
191190
}
192191
193192
/*
194193
** Send the request to the server.
195194
*/
196
- transport_send(&hdr);
197
- transport_send(&payload);
195
+ transport_send(GLOBAL_URL(), &hdr);
196
+ transport_send(GLOBAL_URL(), &payload);
198197
blob_reset(&hdr);
199198
blob_reset(&payload);
200
- transport_flip();
199
+ transport_flip(GLOBAL_URL());
201200
202201
/*
203202
** Read and interpret the server reply
204203
*/
205204
closeConnection = 1;
206205
iLength = -1;
207
- while( (zLine = transport_receive_line())!=0 && zLine[0]!=0 ){
206
+ while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
208207
/* printf("[%s]\n", zLine); fflush(stdout); */
209208
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
210209
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
211210
if( rc!=200 && rc!=302 ){
212211
int ii;
@@ -255,11 +254,11 @@
255254
j -= 4;
256255
zLine[j] = 0;
257256
}
258257
fossil_print("redirect to %s\n", &zLine[i]);
259258
url_parse(&zLine[i], 0);
260
- transport_close();
259
+ transport_close(GLOBAL_URL());
261260
return http_exchange(pSend, pReply, useLogin, maxRedirect);
262261
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
263262
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
264263
isCompressed = 0;
265264
}else if( fossil_strnicmp(&zLine[14],
@@ -282,11 +281,11 @@
282281
/*
283282
** Extract the reply payload that follows the header
284283
*/
285284
blob_zero(pReply);
286285
blob_resize(pReply, iLength);
287
- iLength = transport_receive(blob_buffer(pReply), iLength);
286
+ iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
288287
blob_resize(pReply, iLength);
289288
if( isError ){
290289
char *z;
291290
int i, j;
292291
z = blob_str(pReply);
@@ -311,18 +310,18 @@
311310
**
312311
** For SSH we will leave the connection open.
313312
*/
314313
if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
315314
if( closeConnection ){
316
- transport_close();
315
+ transport_close(GLOBAL_URL());
317316
}else{
318
- transport_rewind();
317
+ transport_rewind(GLOBAL_URL());
319318
}
320319
return 0;
321320
322321
/*
323322
** Jump to here if an error is seen.
324323
*/
325324
write_err:
326
- transport_close();
325
+ transport_close(GLOBAL_URL());
327326
return 1;
328327
}
329328
--- src/http.c
+++ src/http.c
@@ -110,12 +110,11 @@
110 blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
111 fossil_free(zEncoded);
112 fossil_free(zCredentials);
113 }
114 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115 blob_appendf(pHdr, "User-Agent: Fossil/" RELEASE_VERSION
116 " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
117 if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
118 if( g.fHttpTrace ){
119 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
120 }else{
121 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
@@ -144,12 +143,12 @@
144 char *zLine; /* A single line of the reply header */
145 int i; /* Loop counter */
146 int isError = 0; /* True if the reply is an error message */
147 int isCompressed = 1; /* True if the reply is compressed */
148
149 if( transport_open() ){
150 fossil_warning(transport_errmsg());
151 return 1;
152 }
153
154 /* Construct the login card and prepare the complete payload */
155 blob_zero(&login);
@@ -191,22 +190,22 @@
191 }
192
193 /*
194 ** Send the request to the server.
195 */
196 transport_send(&hdr);
197 transport_send(&payload);
198 blob_reset(&hdr);
199 blob_reset(&payload);
200 transport_flip();
201
202 /*
203 ** Read and interpret the server reply
204 */
205 closeConnection = 1;
206 iLength = -1;
207 while( (zLine = transport_receive_line())!=0 && zLine[0]!=0 ){
208 /* printf("[%s]\n", zLine); fflush(stdout); */
209 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
210 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
211 if( rc!=200 && rc!=302 ){
212 int ii;
@@ -255,11 +254,11 @@
255 j -= 4;
256 zLine[j] = 0;
257 }
258 fossil_print("redirect to %s\n", &zLine[i]);
259 url_parse(&zLine[i], 0);
260 transport_close();
261 return http_exchange(pSend, pReply, useLogin, maxRedirect);
262 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
263 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
264 isCompressed = 0;
265 }else if( fossil_strnicmp(&zLine[14],
@@ -282,11 +281,11 @@
282 /*
283 ** Extract the reply payload that follows the header
284 */
285 blob_zero(pReply);
286 blob_resize(pReply, iLength);
287 iLength = transport_receive(blob_buffer(pReply), iLength);
288 blob_resize(pReply, iLength);
289 if( isError ){
290 char *z;
291 int i, j;
292 z = blob_str(pReply);
@@ -311,18 +310,18 @@
311 **
312 ** For SSH we will leave the connection open.
313 */
314 if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
315 if( closeConnection ){
316 transport_close();
317 }else{
318 transport_rewind();
319 }
320 return 0;
321
322 /*
323 ** Jump to here if an error is seen.
324 */
325 write_err:
326 transport_close();
327 return 1;
328 }
329
--- src/http.c
+++ src/http.c
@@ -110,12 +110,11 @@
110 blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
111 fossil_free(zEncoded);
112 fossil_free(zCredentials);
113 }
114 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
 
116 if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
117 if( g.fHttpTrace ){
118 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
119 }else{
120 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
@@ -144,12 +143,12 @@
143 char *zLine; /* A single line of the reply header */
144 int i; /* Loop counter */
145 int isError = 0; /* True if the reply is an error message */
146 int isCompressed = 1; /* True if the reply is compressed */
147
148 if( transport_open(GLOBAL_URL()) ){
149 fossil_warning(transport_errmsg(GLOBAL_URL()));
150 return 1;
151 }
152
153 /* Construct the login card and prepare the complete payload */
154 blob_zero(&login);
@@ -191,22 +190,22 @@
190 }
191
192 /*
193 ** Send the request to the server.
194 */
195 transport_send(GLOBAL_URL(), &hdr);
196 transport_send(GLOBAL_URL(), &payload);
197 blob_reset(&hdr);
198 blob_reset(&payload);
199 transport_flip(GLOBAL_URL());
200
201 /*
202 ** Read and interpret the server reply
203 */
204 closeConnection = 1;
205 iLength = -1;
206 while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
207 /* printf("[%s]\n", zLine); fflush(stdout); */
208 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
209 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
210 if( rc!=200 && rc!=302 ){
211 int ii;
@@ -255,11 +254,11 @@
254 j -= 4;
255 zLine[j] = 0;
256 }
257 fossil_print("redirect to %s\n", &zLine[i]);
258 url_parse(&zLine[i], 0);
259 transport_close(GLOBAL_URL());
260 return http_exchange(pSend, pReply, useLogin, maxRedirect);
261 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
262 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
263 isCompressed = 0;
264 }else if( fossil_strnicmp(&zLine[14],
@@ -282,11 +281,11 @@
281 /*
282 ** Extract the reply payload that follows the header
283 */
284 blob_zero(pReply);
285 blob_resize(pReply, iLength);
286 iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
287 blob_resize(pReply, iLength);
288 if( isError ){
289 char *z;
290 int i, j;
291 z = blob_str(pReply);
@@ -311,18 +310,18 @@
310 **
311 ** For SSH we will leave the connection open.
312 */
313 if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
314 if( closeConnection ){
315 transport_close(GLOBAL_URL());
316 }else{
317 transport_rewind(GLOBAL_URL());
318 }
319 return 0;
320
321 /*
322 ** Jump to here if an error is seen.
323 */
324 write_err:
325 transport_close(GLOBAL_URL());
326 return 1;
327 }
328
--- src/http_socket.c
+++ src/http_socket.c
@@ -131,29 +131,29 @@
131131
** g.urlName Name of the server. Ex: www.fossil-scm.org
132132
** g.urlPort TCP/IP port to use. Ex: 80
133133
**
134134
** Return the number of errors.
135135
*/
136
-int socket_open(void){
136
+int socket_open(UrlData *pUrlData){
137137
static struct sockaddr_in addr; /* The server address */
138138
static int addrIsInit = 0; /* True once addr is initialized */
139139
140140
socket_global_init();
141141
if( !addrIsInit ){
142142
addr.sin_family = AF_INET;
143
- addr.sin_port = htons(g.urlPort);
144
- *(int*)&addr.sin_addr = inet_addr(g.urlName);
143
+ addr.sin_port = htons(pUrlData->port);
144
+ *(int*)&addr.sin_addr = inet_addr(pUrlData->name);
145145
if( -1 == *(int*)&addr.sin_addr ){
146146
#ifndef FOSSIL_STATIC_LINK
147147
struct hostent *pHost;
148
- pHost = gethostbyname(g.urlName);
148
+ pHost = gethostbyname(pUrlData->name);
149149
if( pHost!=0 ){
150150
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
151151
}else
152152
#endif
153153
{
154
- socket_set_errmsg("can't resolve host name: %s", g.urlName);
154
+ socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
155155
return 1;
156156
}
157157
}
158158
addrIsInit = 1;
159159
@@ -167,11 +167,12 @@
167167
if( iSocket<0 ){
168168
socket_set_errmsg("cannot create a socket");
169169
return 1;
170170
}
171171
if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
172
- socket_set_errmsg("cannot connect to host %s:%d", g.urlName, g.urlPort);
172
+ socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
173
+ pUrlData->port);
173174
socket_close();
174175
return 1;
175176
}
176177
#if !defined(_WIN32)
177178
signal(SIGPIPE, SIG_IGN);
@@ -215,16 +216,16 @@
215216
/*
216217
** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
217218
** populated. For hostnames with more than one IP (or if overridden in
218219
** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
219220
*/
220
-void socket_ssh_resolve_addr(void){
221
+void socket_ssh_resolve_addr(UrlData *pUrlData){
221222
struct hostent *pHost; /* Used to make best effort for rcvfrom */
222223
struct sockaddr_in addr;
223224
224225
memset(&addr, 0, sizeof(addr));
225
- pHost = gethostbyname(g.urlName);
226
+ pHost = gethostbyname(pUrlData->name);
226227
if( pHost!=0 ){
227228
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
228229
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
229230
}
230231
}
231232
--- src/http_socket.c
+++ src/http_socket.c
@@ -131,29 +131,29 @@
131 ** g.urlName Name of the server. Ex: www.fossil-scm.org
132 ** g.urlPort TCP/IP port to use. Ex: 80
133 **
134 ** Return the number of errors.
135 */
136 int socket_open(void){
137 static struct sockaddr_in addr; /* The server address */
138 static int addrIsInit = 0; /* True once addr is initialized */
139
140 socket_global_init();
141 if( !addrIsInit ){
142 addr.sin_family = AF_INET;
143 addr.sin_port = htons(g.urlPort);
144 *(int*)&addr.sin_addr = inet_addr(g.urlName);
145 if( -1 == *(int*)&addr.sin_addr ){
146 #ifndef FOSSIL_STATIC_LINK
147 struct hostent *pHost;
148 pHost = gethostbyname(g.urlName);
149 if( pHost!=0 ){
150 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
151 }else
152 #endif
153 {
154 socket_set_errmsg("can't resolve host name: %s", g.urlName);
155 return 1;
156 }
157 }
158 addrIsInit = 1;
159
@@ -167,11 +167,12 @@
167 if( iSocket<0 ){
168 socket_set_errmsg("cannot create a socket");
169 return 1;
170 }
171 if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
172 socket_set_errmsg("cannot connect to host %s:%d", g.urlName, g.urlPort);
 
173 socket_close();
174 return 1;
175 }
176 #if !defined(_WIN32)
177 signal(SIGPIPE, SIG_IGN);
@@ -215,16 +216,16 @@
215 /*
216 ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
217 ** populated. For hostnames with more than one IP (or if overridden in
218 ** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
219 */
220 void socket_ssh_resolve_addr(void){
221 struct hostent *pHost; /* Used to make best effort for rcvfrom */
222 struct sockaddr_in addr;
223
224 memset(&addr, 0, sizeof(addr));
225 pHost = gethostbyname(g.urlName);
226 if( pHost!=0 ){
227 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
228 g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
229 }
230 }
231
--- src/http_socket.c
+++ src/http_socket.c
@@ -131,29 +131,29 @@
131 ** g.urlName Name of the server. Ex: www.fossil-scm.org
132 ** g.urlPort TCP/IP port to use. Ex: 80
133 **
134 ** Return the number of errors.
135 */
136 int socket_open(UrlData *pUrlData){
137 static struct sockaddr_in addr; /* The server address */
138 static int addrIsInit = 0; /* True once addr is initialized */
139
140 socket_global_init();
141 if( !addrIsInit ){
142 addr.sin_family = AF_INET;
143 addr.sin_port = htons(pUrlData->port);
144 *(int*)&addr.sin_addr = inet_addr(pUrlData->name);
145 if( -1 == *(int*)&addr.sin_addr ){
146 #ifndef FOSSIL_STATIC_LINK
147 struct hostent *pHost;
148 pHost = gethostbyname(pUrlData->name);
149 if( pHost!=0 ){
150 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
151 }else
152 #endif
153 {
154 socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
155 return 1;
156 }
157 }
158 addrIsInit = 1;
159
@@ -167,11 +167,12 @@
167 if( iSocket<0 ){
168 socket_set_errmsg("cannot create a socket");
169 return 1;
170 }
171 if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
172 socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
173 pUrlData->port);
174 socket_close();
175 return 1;
176 }
177 #if !defined(_WIN32)
178 signal(SIGPIPE, SIG_IGN);
@@ -215,16 +216,16 @@
216 /*
217 ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
218 ** populated. For hostnames with more than one IP (or if overridden in
219 ** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
220 */
221 void socket_ssh_resolve_addr(UrlData *pUrlData){
222 struct hostent *pHost; /* Used to make best effort for rcvfrom */
223 struct sockaddr_in addr;
224
225 memset(&addr, 0, sizeof(addr));
226 pHost = gethostbyname(pUrlData->name);
227 if( pHost!=0 ){
228 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
229 g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
230 }
231 }
232
+17 -15
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -183,11 +183,11 @@
183183
** g.urlName Name of the server. Ex: www.fossil-scm.org
184184
** g.urlPort TCP/IP port to use. Ex: 80
185185
**
186186
** Return the number of errors.
187187
*/
188
-int ssl_open(void){
188
+int ssl_open(UrlData *pUrlData){
189189
X509 *cert;
190190
int hasSavedCertificate = 0;
191191
int trusted = 0;
192192
unsigned long e;
193193
@@ -194,11 +194,11 @@
194194
ssl_global_init();
195195
196196
/* Get certificate for current server from global config and
197197
* (if we have it in config) add it to certificate store.
198198
*/
199
- cert = ssl_get_certificate(&trusted);
199
+ cert = ssl_get_certificate(pUrlData, &trusted);
200200
if ( cert!=NULL ){
201201
X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
202202
X509_free(cert);
203203
hasSavedCertificate = 1;
204204
}
@@ -205,11 +205,11 @@
205205
206206
iBio = BIO_new_ssl_connect(sslCtx);
207207
BIO_get_ssl(iBio, &ssl);
208208
209209
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
210
- if( !SSL_set_tlsext_host_name(ssl, g.urlName) ){
210
+ if( !SSL_set_tlsext_host_name(ssl, pUrlData->name) ){
211211
fossil_warning("WARNING: failed to set server name indication (SNI), "
212212
"continuing without it.\n");
213213
}
214214
#endif
215215
@@ -218,23 +218,25 @@
218218
ssl_set_errmsg("SSL: cannot open SSL (%s)",
219219
ERR_reason_error_string(ERR_get_error()));
220220
return 1;
221221
}
222222
223
- BIO_set_conn_hostname(iBio, g.urlName);
224
- BIO_set_conn_int_port(iBio, &g.urlPort);
223
+ BIO_set_conn_hostname(iBio, pUrlData->name);
224
+ BIO_set_conn_int_port(iBio, &pUrlData->port);
225225
226226
if( BIO_do_connect(iBio)<=0 ){
227227
ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
228
- g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
228
+ pUrlData->name, pUrlData->port,
229
+ ERR_reason_error_string(ERR_get_error()));
229230
ssl_close();
230231
return 1;
231232
}
232233
233234
if( BIO_do_handshake(iBio)<=0 ) {
234235
ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
235
- g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
236
+ pUrlData->name, pUrlData->port,
237
+ ERR_reason_error_string(ERR_get_error()));
236238
ssl_close();
237239
return 1;
238240
}
239241
/* Check if certificate is valid */
240242
cert = SSL_get_peer_certificate(ssl);
@@ -281,11 +283,11 @@
281283
" certificates list\n\n"
282284
"If you are not expecting this message, answer no and "
283285
"contact your server\nadministrator.\n\n"
284286
"Accept certificate for host %s (a=always/y/N)? ",
285287
X509_verify_cert_error_string(e), desc, warning,
286
- g.urlName);
288
+ pUrlData->name);
287289
BIO_free(mem);
288290
289291
prompt_user(prompt, &ans);
290292
free(prompt);
291293
cReply = blob_str(&ans)[0];
@@ -302,11 +304,11 @@
302304
&ans);
303305
cReply = blob_str(&ans)[0];
304306
trusted = ( cReply=='a' || cReply=='A' );
305307
blob_reset(&ans);
306308
}
307
- ssl_save_certificate(cert, trusted);
309
+ ssl_save_certificate(pUrlData, cert, trusted);
308310
}
309311
}
310312
311313
/* Set the Global.zIpAddr variable to the server we are talking to.
312314
** This is used to populate the ipaddr column of the rcvfrom table,
@@ -323,44 +325,44 @@
323325
}
324326
325327
/*
326328
** Save certificate to global config.
327329
*/
328
-void ssl_save_certificate(X509 *cert, int trusted){
330
+void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
329331
BIO *mem;
330332
char *zCert, *zHost;
331333
332334
mem = BIO_new(BIO_s_mem());
333335
PEM_write_bio_X509(mem, cert);
334336
BIO_write(mem, "", 1); /* nul-terminate mem buffer */
335337
BIO_get_mem_data(mem, &zCert);
336
- zHost = mprintf("cert:%s", g.urlName);
338
+ zHost = mprintf("cert:%s", pUrlData->name);
337339
db_set(zHost, zCert, 1);
338340
free(zHost);
339
- zHost = mprintf("trusted:%s", g.urlName);
341
+ zHost = mprintf("trusted:%s", pUrlData->name);
340342
db_set_int(zHost, trusted, 1);
341343
free(zHost);
342344
BIO_free(mem);
343345
}
344346
345347
/*
346348
** Get certificate for g.urlName from global config.
347349
** Return NULL if no certificate found.
348350
*/
349
-X509 *ssl_get_certificate(int *pTrusted){
351
+X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
350352
char *zHost, *zCert;
351353
BIO *mem;
352354
X509 *cert;
353355
354
- zHost = mprintf("cert:%s", g.urlName);
356
+ zHost = mprintf("cert:%s", pUrlData->name);
355357
zCert = db_get(zHost, NULL);
356358
free(zHost);
357359
if ( zCert==NULL )
358360
return NULL;
359361
360362
if ( pTrusted!=0 ){
361
- zHost = mprintf("trusted:%s", g.urlName);
363
+ zHost = mprintf("trusted:%s", pUrlData->name);
362364
*pTrusted = db_get_int(zHost, 0);
363365
free(zHost);
364366
}
365367
366368
mem = BIO_new(BIO_s_mem());
367369
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -183,11 +183,11 @@
183 ** g.urlName Name of the server. Ex: www.fossil-scm.org
184 ** g.urlPort TCP/IP port to use. Ex: 80
185 **
186 ** Return the number of errors.
187 */
188 int ssl_open(void){
189 X509 *cert;
190 int hasSavedCertificate = 0;
191 int trusted = 0;
192 unsigned long e;
193
@@ -194,11 +194,11 @@
194 ssl_global_init();
195
196 /* Get certificate for current server from global config and
197 * (if we have it in config) add it to certificate store.
198 */
199 cert = ssl_get_certificate(&trusted);
200 if ( cert!=NULL ){
201 X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
202 X509_free(cert);
203 hasSavedCertificate = 1;
204 }
@@ -205,11 +205,11 @@
205
206 iBio = BIO_new_ssl_connect(sslCtx);
207 BIO_get_ssl(iBio, &ssl);
208
209 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
210 if( !SSL_set_tlsext_host_name(ssl, g.urlName) ){
211 fossil_warning("WARNING: failed to set server name indication (SNI), "
212 "continuing without it.\n");
213 }
214 #endif
215
@@ -218,23 +218,25 @@
218 ssl_set_errmsg("SSL: cannot open SSL (%s)",
219 ERR_reason_error_string(ERR_get_error()));
220 return 1;
221 }
222
223 BIO_set_conn_hostname(iBio, g.urlName);
224 BIO_set_conn_int_port(iBio, &g.urlPort);
225
226 if( BIO_do_connect(iBio)<=0 ){
227 ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
228 g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
 
229 ssl_close();
230 return 1;
231 }
232
233 if( BIO_do_handshake(iBio)<=0 ) {
234 ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
235 g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
 
236 ssl_close();
237 return 1;
238 }
239 /* Check if certificate is valid */
240 cert = SSL_get_peer_certificate(ssl);
@@ -281,11 +283,11 @@
281 " certificates list\n\n"
282 "If you are not expecting this message, answer no and "
283 "contact your server\nadministrator.\n\n"
284 "Accept certificate for host %s (a=always/y/N)? ",
285 X509_verify_cert_error_string(e), desc, warning,
286 g.urlName);
287 BIO_free(mem);
288
289 prompt_user(prompt, &ans);
290 free(prompt);
291 cReply = blob_str(&ans)[0];
@@ -302,11 +304,11 @@
302 &ans);
303 cReply = blob_str(&ans)[0];
304 trusted = ( cReply=='a' || cReply=='A' );
305 blob_reset(&ans);
306 }
307 ssl_save_certificate(cert, trusted);
308 }
309 }
310
311 /* Set the Global.zIpAddr variable to the server we are talking to.
312 ** This is used to populate the ipaddr column of the rcvfrom table,
@@ -323,44 +325,44 @@
323 }
324
325 /*
326 ** Save certificate to global config.
327 */
328 void ssl_save_certificate(X509 *cert, int trusted){
329 BIO *mem;
330 char *zCert, *zHost;
331
332 mem = BIO_new(BIO_s_mem());
333 PEM_write_bio_X509(mem, cert);
334 BIO_write(mem, "", 1); /* nul-terminate mem buffer */
335 BIO_get_mem_data(mem, &zCert);
336 zHost = mprintf("cert:%s", g.urlName);
337 db_set(zHost, zCert, 1);
338 free(zHost);
339 zHost = mprintf("trusted:%s", g.urlName);
340 db_set_int(zHost, trusted, 1);
341 free(zHost);
342 BIO_free(mem);
343 }
344
345 /*
346 ** Get certificate for g.urlName from global config.
347 ** Return NULL if no certificate found.
348 */
349 X509 *ssl_get_certificate(int *pTrusted){
350 char *zHost, *zCert;
351 BIO *mem;
352 X509 *cert;
353
354 zHost = mprintf("cert:%s", g.urlName);
355 zCert = db_get(zHost, NULL);
356 free(zHost);
357 if ( zCert==NULL )
358 return NULL;
359
360 if ( pTrusted!=0 ){
361 zHost = mprintf("trusted:%s", g.urlName);
362 *pTrusted = db_get_int(zHost, 0);
363 free(zHost);
364 }
365
366 mem = BIO_new(BIO_s_mem());
367
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -183,11 +183,11 @@
183 ** g.urlName Name of the server. Ex: www.fossil-scm.org
184 ** g.urlPort TCP/IP port to use. Ex: 80
185 **
186 ** Return the number of errors.
187 */
188 int ssl_open(UrlData *pUrlData){
189 X509 *cert;
190 int hasSavedCertificate = 0;
191 int trusted = 0;
192 unsigned long e;
193
@@ -194,11 +194,11 @@
194 ssl_global_init();
195
196 /* Get certificate for current server from global config and
197 * (if we have it in config) add it to certificate store.
198 */
199 cert = ssl_get_certificate(pUrlData, &trusted);
200 if ( cert!=NULL ){
201 X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
202 X509_free(cert);
203 hasSavedCertificate = 1;
204 }
@@ -205,11 +205,11 @@
205
206 iBio = BIO_new_ssl_connect(sslCtx);
207 BIO_get_ssl(iBio, &ssl);
208
209 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
210 if( !SSL_set_tlsext_host_name(ssl, pUrlData->name) ){
211 fossil_warning("WARNING: failed to set server name indication (SNI), "
212 "continuing without it.\n");
213 }
214 #endif
215
@@ -218,23 +218,25 @@
218 ssl_set_errmsg("SSL: cannot open SSL (%s)",
219 ERR_reason_error_string(ERR_get_error()));
220 return 1;
221 }
222
223 BIO_set_conn_hostname(iBio, pUrlData->name);
224 BIO_set_conn_int_port(iBio, &pUrlData->port);
225
226 if( BIO_do_connect(iBio)<=0 ){
227 ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
228 pUrlData->name, pUrlData->port,
229 ERR_reason_error_string(ERR_get_error()));
230 ssl_close();
231 return 1;
232 }
233
234 if( BIO_do_handshake(iBio)<=0 ) {
235 ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
236 pUrlData->name, pUrlData->port,
237 ERR_reason_error_string(ERR_get_error()));
238 ssl_close();
239 return 1;
240 }
241 /* Check if certificate is valid */
242 cert = SSL_get_peer_certificate(ssl);
@@ -281,11 +283,11 @@
283 " certificates list\n\n"
284 "If you are not expecting this message, answer no and "
285 "contact your server\nadministrator.\n\n"
286 "Accept certificate for host %s (a=always/y/N)? ",
287 X509_verify_cert_error_string(e), desc, warning,
288 pUrlData->name);
289 BIO_free(mem);
290
291 prompt_user(prompt, &ans);
292 free(prompt);
293 cReply = blob_str(&ans)[0];
@@ -302,11 +304,11 @@
304 &ans);
305 cReply = blob_str(&ans)[0];
306 trusted = ( cReply=='a' || cReply=='A' );
307 blob_reset(&ans);
308 }
309 ssl_save_certificate(pUrlData, cert, trusted);
310 }
311 }
312
313 /* Set the Global.zIpAddr variable to the server we are talking to.
314 ** This is used to populate the ipaddr column of the rcvfrom table,
@@ -323,44 +325,44 @@
325 }
326
327 /*
328 ** Save certificate to global config.
329 */
330 void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
331 BIO *mem;
332 char *zCert, *zHost;
333
334 mem = BIO_new(BIO_s_mem());
335 PEM_write_bio_X509(mem, cert);
336 BIO_write(mem, "", 1); /* nul-terminate mem buffer */
337 BIO_get_mem_data(mem, &zCert);
338 zHost = mprintf("cert:%s", pUrlData->name);
339 db_set(zHost, zCert, 1);
340 free(zHost);
341 zHost = mprintf("trusted:%s", pUrlData->name);
342 db_set_int(zHost, trusted, 1);
343 free(zHost);
344 BIO_free(mem);
345 }
346
347 /*
348 ** Get certificate for g.urlName from global config.
349 ** Return NULL if no certificate found.
350 */
351 X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
352 char *zHost, *zCert;
353 BIO *mem;
354 X509 *cert;
355
356 zHost = mprintf("cert:%s", pUrlData->name);
357 zCert = db_get(zHost, NULL);
358 free(zHost);
359 if ( zCert==NULL )
360 return NULL;
361
362 if ( pTrusted!=0 ){
363 zHost = mprintf("trusted:%s", pUrlData->name);
364 *pTrusted = db_get_int(zHost, 0);
365 free(zHost);
366 }
367
368 mem = BIO_new(BIO_s_mem());
369
--- src/http_transport.c
+++ src/http_transport.c
@@ -52,13 +52,13 @@
5252
5353
5454
/*
5555
** Return the current transport error message.
5656
*/
57
-const char *transport_errmsg(void){
57
+const char *transport_errmsg(UrlData *pUrlData){
5858
#ifdef FOSSIL_ENABLE_SSL
59
- if( g.urlIsHttps ){
59
+ if( pUrlData->isHttps ){
6060
return ssl_errmsg();
6161
}
6262
#endif
6363
return socket_errmsg();
6464
}
@@ -86,47 +86,47 @@
8686
#endif
8787
8888
/*
8989
** SSH initialization of the transport layer
9090
*/
91
-int transport_ssh_open(void){
91
+int transport_ssh_open(UrlData *pUrlData){
9292
/* For SSH we need to create and run SSH fossil http
9393
** to talk to the remote machine.
9494
*/
9595
const char *zSsh; /* The base SSH command */
9696
Blob zCmd; /* The SSH command */
9797
char *zHost; /* The host name to contact */
9898
int n; /* Size of prefix string */
9999
100
- socket_ssh_resolve_addr();
100
+ socket_ssh_resolve_addr(pUrlData);
101101
zSsh = db_get("ssh-command", zDefaultSshCmd);
102102
blob_init(&zCmd, zSsh, -1);
103
- if( g.urlPort!=g.urlDfltPort && g.urlPort ){
103
+ if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
104104
#ifdef __MINGW32__
105
- blob_appendf(&zCmd, " -P %d", g.urlPort);
105
+ blob_appendf(&zCmd, " -P %d", pUrlData->port);
106106
#else
107
- blob_appendf(&zCmd, " -p %d", g.urlPort);
107
+ blob_appendf(&zCmd, " -p %d", pUrlData->port);
108108
#endif
109109
}
110110
if( g.fSshTrace ){
111111
fossil_force_newline();
112112
fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113113
}
114
- if( g.urlUser && g.urlUser[0] ){
115
- zHost = mprintf("%s@%s", g.urlUser, g.urlName);
114
+ if( pUrlData->user && pUrlData->user[0] ){
115
+ zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
116116
}else{
117
- zHost = mprintf("%s", g.urlName);
117
+ zHost = mprintf("%s", pUrlData->name);
118118
}
119119
n = blob_size(&zCmd);
120120
blob_append(&zCmd, " ", 1);
121121
shell_escape(&zCmd, zHost);
122122
blob_append(&zCmd, " ", 1);
123
- shell_escape(&zCmd, mprintf("%s", g.urlFossil));
123
+ shell_escape(&zCmd, mprintf("%s", pUrlData->fossil));
124124
blob_append(&zCmd, " test-http", 10);
125
- if( g.urlPath && g.urlPath[0] ){
125
+ if( pUrlData->path && pUrlData->path[0] ){
126126
blob_append(&zCmd, " ", 1);
127
- shell_escape(&zCmd, mprintf("%s", g.urlPath));
127
+ shell_escape(&zCmd, mprintf("%s", pUrlData->path));
128128
}
129129
if( g.fSshTrace ){
130130
fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131131
}
132132
free(zHost);
@@ -146,25 +146,25 @@
146146
** g.urlPort TCP/IP port. Ex: 80
147147
** g.urlIsHttps Use TLS for the connection
148148
**
149149
** Return the number of errors.
150150
*/
151
-int transport_open(void){
151
+int transport_open(UrlData *pUrlData){
152152
int rc = 0;
153153
if( transport.isOpen==0 ){
154
- if( g.urlIsSsh ){
155
- rc = transport_ssh_open();
154
+ if( pUrlData->isSsh ){
155
+ rc = transport_ssh_open(pUrlData);
156156
if( rc==0 ) transport.isOpen = 1;
157
- }else if( g.urlIsHttps ){
157
+ }else if( pUrlData->isHttps ){
158158
#ifdef FOSSIL_ENABLE_SSL
159
- rc = ssl_open();
159
+ rc = ssl_open(pUrlData);
160160
if( rc==0 ) transport.isOpen = 1;
161161
#else
162162
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
163163
rc = 1;
164164
#endif
165
- }else if( g.urlIsFile ){
165
+ }else if( pUrlData->isFile ){
166166
sqlite3_uint64 iRandId;
167167
sqlite3_randomness(sizeof(iRandId), &iRandId);
168168
transport.zOutFile = mprintf("%s-%llu-out.http",
169169
g.zRepositoryName, iRandId);
170170
transport.zInFile = mprintf("%s-%llu-in.http",
@@ -173,21 +173,21 @@
173173
if( transport.pFile==0 ){
174174
fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
175175
}
176176
transport.isOpen = 1;
177177
}else{
178
- rc = socket_open();
178
+ rc = socket_open(pUrlData);
179179
if( rc==0 ) transport.isOpen = 1;
180180
}
181181
}
182182
return rc;
183183
}
184184
185185
/*
186186
** Close the current connection
187187
*/
188
-void transport_close(void){
188
+void transport_close(UrlData *pUrlData){
189189
if( transport.isOpen ){
190190
free(transport.pBuf);
191191
transport.pBuf = 0;
192192
transport.nAlloc = 0;
193193
transport.nUsed = 0;
@@ -194,17 +194,17 @@
194194
transport.iCursor = 0;
195195
if( transport.pLog ){
196196
fclose(transport.pLog);
197197
transport.pLog = 0;
198198
}
199
- if( g.urlIsSsh ){
199
+ if( pUrlData->isSsh ){
200200
transport_ssh_close();
201
- }else if( g.urlIsHttps ){
201
+ }else if( pUrlData->isHttps ){
202202
#ifdef FOSSIL_ENABLE_SSL
203203
ssl_close();
204204
#endif
205
- }else if( g.urlIsFile ){
205
+ }else if( pUrlData->isFile ){
206206
if( transport.pFile ){
207207
fclose(transport.pFile);
208208
transport.pFile = 0;
209209
}
210210
file_delete(transport.zInFile);
@@ -219,28 +219,28 @@
219219
}
220220
221221
/*
222222
** Send content over the wire.
223223
*/
224
-void transport_send(Blob *toSend){
224
+void transport_send(UrlData *pUrlData, Blob *toSend){
225225
char *z = blob_buffer(toSend);
226226
int n = blob_size(toSend);
227227
transport.nSent += n;
228
- if( g.urlIsSsh ){
228
+ if( pUrlData->isSsh ){
229229
fwrite(z, 1, n, sshOut);
230230
fflush(sshOut);
231
- }else if( g.urlIsHttps ){
231
+ }else if( pUrlData->isHttps ){
232232
#ifdef FOSSIL_ENABLE_SSL
233233
int sent;
234234
while( n>0 ){
235235
sent = ssl_send(0, z, n);
236236
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
237237
if( sent<=0 ) break;
238238
n -= sent;
239239
}
240240
#endif
241
- }else if( g.urlIsFile ){
241
+ }else if( pUrlData->isFile ){
242242
fwrite(z, 1, n, transport.pFile);
243243
}else{
244244
int sent;
245245
while( n>0 ){
246246
sent = socket_send(0, z, n);
@@ -253,16 +253,16 @@
253253
254254
/*
255255
** This routine is called when the outbound message is complete and
256256
** it is time to being receiving a reply.
257257
*/
258
-void transport_flip(void){
259
- if( g.urlIsFile ){
258
+void transport_flip(UrlData *pUrlData){
259
+ if( pUrlData->isFile ){
260260
char *zCmd;
261261
fclose(transport.pFile);
262262
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
263
- g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
263
+ g.nameOfExe, pUrlData->name, transport.zOutFile, transport.zInFile
264264
);
265265
fossil_system(zCmd);
266266
free(zCmd);
267267
transport.pFile = fossil_fopen(transport.zInFile, "rb");
268268
}
@@ -282,21 +282,21 @@
282282
283283
/*
284284
** This routine is called when the inbound message has been received
285285
** and it is time to start sending again.
286286
*/
287
-void transport_rewind(void){
288
- if( g.urlIsFile ){
289
- transport_close();
287
+void transport_rewind(UrlData *pUrlData){
288
+ if( pUrlData->isFile ){
289
+ transport_close(pUrlData);
290290
}
291291
}
292292
293293
/*
294294
** Read N bytes of content directly from the wire and write into
295295
** the buffer.
296296
*/
297
-static int transport_fetch(char *zBuf, int N){
297
+static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){
298298
int got;
299299
if( sshIn ){
300300
int x;
301301
int wanted = N;
302302
got = 0;
@@ -304,17 +304,17 @@
304304
x = read(sshIn, &zBuf[got], wanted);
305305
if( x<=0 ) break;
306306
got += x;
307307
wanted -= x;
308308
}
309
- }else if( g.urlIsHttps ){
309
+ }else if( pUrlData->isHttps ){
310310
#ifdef FOSSIL_ENABLE_SSL
311311
got = ssl_receive(0, zBuf, N);
312312
#else
313313
got = 0;
314314
#endif
315
- }else if( g.urlIsFile ){
315
+ }else if( pUrlData->isFile ){
316316
got = fread(zBuf, 1, N, transport.pFile);
317317
}else{
318318
got = socket_receive(0, zBuf, N);
319319
}
320320
/* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
@@ -327,11 +327,11 @@
327327
328328
/*
329329
** Read N bytes of content from the wire and store in the supplied buffer.
330330
** Return the number of bytes actually received.
331331
*/
332
-int transport_receive(char *zBuf, int N){
332
+int transport_receive(UrlData *pUrlData, char *zBuf, int N){
333333
int onHand; /* Bytes current held in the transport buffer */
334334
int nByte = 0; /* Bytes of content received */
335335
336336
onHand = transport.nUsed - transport.iCursor;
337337
if( g.fSshTrace){
@@ -351,11 +351,11 @@
351351
N -= toMove;
352352
zBuf += toMove;
353353
nByte += toMove;
354354
}
355355
if( N>0 ){
356
- int got = transport_fetch(zBuf, N);
356
+ int got = transport_fetch(pUrlData, zBuf, N);
357357
if( got>0 ){
358358
nByte += got;
359359
transport.nRcvd += got;
360360
}
361361
}
@@ -366,11 +366,11 @@
366366
/*
367367
** Load up to N new bytes of content into the transport.pBuf buffer.
368368
** The buffer itself might be moved. And the transport.iCursor value
369369
** might be reset to 0.
370370
*/
371
-static void transport_load_buffer(int N){
371
+static void transport_load_buffer(UrlData *pUrlData, int N){
372372
int i, j;
373373
if( transport.nAlloc==0 ){
374374
transport.nAlloc = N;
375375
transport.pBuf = fossil_malloc( N );
376376
transport.iCursor = 0;
@@ -388,11 +388,11 @@
388388
transport.nAlloc = transport.nUsed + N;
389389
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
390390
transport.pBuf = pNew;
391391
}
392392
if( N>0 ){
393
- i = transport_fetch(&transport.pBuf[transport.nUsed], N);
393
+ i = transport_fetch(pUrlData, &transport.pBuf[transport.nUsed], N);
394394
if( i>0 ){
395395
transport.nRcvd += i;
396396
transport.nUsed += i;
397397
}
398398
}
@@ -404,18 +404,18 @@
404404
** from the received line and zero-terminate the result. Return a pointer
405405
** to the line.
406406
**
407407
** Each call to this routine potentially overwrites the returned buffer.
408408
*/
409
-char *transport_receive_line(void){
409
+char *transport_receive_line(UrlData *pUrlData){
410410
int i;
411411
int iStart;
412412
413413
i = iStart = transport.iCursor;
414414
while(1){
415415
if( i >= transport.nUsed ){
416
- transport_load_buffer(g.urlIsSsh ? 2 : 1000);
416
+ transport_load_buffer(pUrlData, pUrlData->isSsh ? 2 : 1000);
417417
i -= iStart;
418418
iStart = 0;
419419
if( i >= transport.nUsed ){
420420
transport.pBuf[i] = 0;
421421
transport.iCursor = i;
@@ -437,15 +437,15 @@
437437
}
438438
439439
/*
440440
** Global transport shutdown
441441
*/
442
-void transport_global_shutdown(void){
443
- if( g.urlIsSsh ){
442
+void transport_global_shutdown(UrlData *pUrlData){
443
+ if( pUrlData->isSsh ){
444444
transport_ssh_close();
445445
}
446
- if( g.urlIsHttps ){
446
+ if( pUrlData->isHttps ){
447447
#ifdef FOSSIL_ENABLE_SSL
448448
ssl_global_shutdown();
449449
#endif
450450
}else{
451451
socket_global_shutdown();
452452
--- src/http_transport.c
+++ src/http_transport.c
@@ -52,13 +52,13 @@
52
53
54 /*
55 ** Return the current transport error message.
56 */
57 const char *transport_errmsg(void){
58 #ifdef FOSSIL_ENABLE_SSL
59 if( g.urlIsHttps ){
60 return ssl_errmsg();
61 }
62 #endif
63 return socket_errmsg();
64 }
@@ -86,47 +86,47 @@
86 #endif
87
88 /*
89 ** SSH initialization of the transport layer
90 */
91 int transport_ssh_open(void){
92 /* For SSH we need to create and run SSH fossil http
93 ** to talk to the remote machine.
94 */
95 const char *zSsh; /* The base SSH command */
96 Blob zCmd; /* The SSH command */
97 char *zHost; /* The host name to contact */
98 int n; /* Size of prefix string */
99
100 socket_ssh_resolve_addr();
101 zSsh = db_get("ssh-command", zDefaultSshCmd);
102 blob_init(&zCmd, zSsh, -1);
103 if( g.urlPort!=g.urlDfltPort && g.urlPort ){
104 #ifdef __MINGW32__
105 blob_appendf(&zCmd, " -P %d", g.urlPort);
106 #else
107 blob_appendf(&zCmd, " -p %d", g.urlPort);
108 #endif
109 }
110 if( g.fSshTrace ){
111 fossil_force_newline();
112 fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113 }
114 if( g.urlUser && g.urlUser[0] ){
115 zHost = mprintf("%s@%s", g.urlUser, g.urlName);
116 }else{
117 zHost = mprintf("%s", g.urlName);
118 }
119 n = blob_size(&zCmd);
120 blob_append(&zCmd, " ", 1);
121 shell_escape(&zCmd, zHost);
122 blob_append(&zCmd, " ", 1);
123 shell_escape(&zCmd, mprintf("%s", g.urlFossil));
124 blob_append(&zCmd, " test-http", 10);
125 if( g.urlPath && g.urlPath[0] ){
126 blob_append(&zCmd, " ", 1);
127 shell_escape(&zCmd, mprintf("%s", g.urlPath));
128 }
129 if( g.fSshTrace ){
130 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131 }
132 free(zHost);
@@ -146,25 +146,25 @@
146 ** g.urlPort TCP/IP port. Ex: 80
147 ** g.urlIsHttps Use TLS for the connection
148 **
149 ** Return the number of errors.
150 */
151 int transport_open(void){
152 int rc = 0;
153 if( transport.isOpen==0 ){
154 if( g.urlIsSsh ){
155 rc = transport_ssh_open();
156 if( rc==0 ) transport.isOpen = 1;
157 }else if( g.urlIsHttps ){
158 #ifdef FOSSIL_ENABLE_SSL
159 rc = ssl_open();
160 if( rc==0 ) transport.isOpen = 1;
161 #else
162 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
163 rc = 1;
164 #endif
165 }else if( g.urlIsFile ){
166 sqlite3_uint64 iRandId;
167 sqlite3_randomness(sizeof(iRandId), &iRandId);
168 transport.zOutFile = mprintf("%s-%llu-out.http",
169 g.zRepositoryName, iRandId);
170 transport.zInFile = mprintf("%s-%llu-in.http",
@@ -173,21 +173,21 @@
173 if( transport.pFile==0 ){
174 fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
175 }
176 transport.isOpen = 1;
177 }else{
178 rc = socket_open();
179 if( rc==0 ) transport.isOpen = 1;
180 }
181 }
182 return rc;
183 }
184
185 /*
186 ** Close the current connection
187 */
188 void transport_close(void){
189 if( transport.isOpen ){
190 free(transport.pBuf);
191 transport.pBuf = 0;
192 transport.nAlloc = 0;
193 transport.nUsed = 0;
@@ -194,17 +194,17 @@
194 transport.iCursor = 0;
195 if( transport.pLog ){
196 fclose(transport.pLog);
197 transport.pLog = 0;
198 }
199 if( g.urlIsSsh ){
200 transport_ssh_close();
201 }else if( g.urlIsHttps ){
202 #ifdef FOSSIL_ENABLE_SSL
203 ssl_close();
204 #endif
205 }else if( g.urlIsFile ){
206 if( transport.pFile ){
207 fclose(transport.pFile);
208 transport.pFile = 0;
209 }
210 file_delete(transport.zInFile);
@@ -219,28 +219,28 @@
219 }
220
221 /*
222 ** Send content over the wire.
223 */
224 void transport_send(Blob *toSend){
225 char *z = blob_buffer(toSend);
226 int n = blob_size(toSend);
227 transport.nSent += n;
228 if( g.urlIsSsh ){
229 fwrite(z, 1, n, sshOut);
230 fflush(sshOut);
231 }else if( g.urlIsHttps ){
232 #ifdef FOSSIL_ENABLE_SSL
233 int sent;
234 while( n>0 ){
235 sent = ssl_send(0, z, n);
236 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
237 if( sent<=0 ) break;
238 n -= sent;
239 }
240 #endif
241 }else if( g.urlIsFile ){
242 fwrite(z, 1, n, transport.pFile);
243 }else{
244 int sent;
245 while( n>0 ){
246 sent = socket_send(0, z, n);
@@ -253,16 +253,16 @@
253
254 /*
255 ** This routine is called when the outbound message is complete and
256 ** it is time to being receiving a reply.
257 */
258 void transport_flip(void){
259 if( g.urlIsFile ){
260 char *zCmd;
261 fclose(transport.pFile);
262 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
263 g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
264 );
265 fossil_system(zCmd);
266 free(zCmd);
267 transport.pFile = fossil_fopen(transport.zInFile, "rb");
268 }
@@ -282,21 +282,21 @@
282
283 /*
284 ** This routine is called when the inbound message has been received
285 ** and it is time to start sending again.
286 */
287 void transport_rewind(void){
288 if( g.urlIsFile ){
289 transport_close();
290 }
291 }
292
293 /*
294 ** Read N bytes of content directly from the wire and write into
295 ** the buffer.
296 */
297 static int transport_fetch(char *zBuf, int N){
298 int got;
299 if( sshIn ){
300 int x;
301 int wanted = N;
302 got = 0;
@@ -304,17 +304,17 @@
304 x = read(sshIn, &zBuf[got], wanted);
305 if( x<=0 ) break;
306 got += x;
307 wanted -= x;
308 }
309 }else if( g.urlIsHttps ){
310 #ifdef FOSSIL_ENABLE_SSL
311 got = ssl_receive(0, zBuf, N);
312 #else
313 got = 0;
314 #endif
315 }else if( g.urlIsFile ){
316 got = fread(zBuf, 1, N, transport.pFile);
317 }else{
318 got = socket_receive(0, zBuf, N);
319 }
320 /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
@@ -327,11 +327,11 @@
327
328 /*
329 ** Read N bytes of content from the wire and store in the supplied buffer.
330 ** Return the number of bytes actually received.
331 */
332 int transport_receive(char *zBuf, int N){
333 int onHand; /* Bytes current held in the transport buffer */
334 int nByte = 0; /* Bytes of content received */
335
336 onHand = transport.nUsed - transport.iCursor;
337 if( g.fSshTrace){
@@ -351,11 +351,11 @@
351 N -= toMove;
352 zBuf += toMove;
353 nByte += toMove;
354 }
355 if( N>0 ){
356 int got = transport_fetch(zBuf, N);
357 if( got>0 ){
358 nByte += got;
359 transport.nRcvd += got;
360 }
361 }
@@ -366,11 +366,11 @@
366 /*
367 ** Load up to N new bytes of content into the transport.pBuf buffer.
368 ** The buffer itself might be moved. And the transport.iCursor value
369 ** might be reset to 0.
370 */
371 static void transport_load_buffer(int N){
372 int i, j;
373 if( transport.nAlloc==0 ){
374 transport.nAlloc = N;
375 transport.pBuf = fossil_malloc( N );
376 transport.iCursor = 0;
@@ -388,11 +388,11 @@
388 transport.nAlloc = transport.nUsed + N;
389 pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
390 transport.pBuf = pNew;
391 }
392 if( N>0 ){
393 i = transport_fetch(&transport.pBuf[transport.nUsed], N);
394 if( i>0 ){
395 transport.nRcvd += i;
396 transport.nUsed += i;
397 }
398 }
@@ -404,18 +404,18 @@
404 ** from the received line and zero-terminate the result. Return a pointer
405 ** to the line.
406 **
407 ** Each call to this routine potentially overwrites the returned buffer.
408 */
409 char *transport_receive_line(void){
410 int i;
411 int iStart;
412
413 i = iStart = transport.iCursor;
414 while(1){
415 if( i >= transport.nUsed ){
416 transport_load_buffer(g.urlIsSsh ? 2 : 1000);
417 i -= iStart;
418 iStart = 0;
419 if( i >= transport.nUsed ){
420 transport.pBuf[i] = 0;
421 transport.iCursor = i;
@@ -437,15 +437,15 @@
437 }
438
439 /*
440 ** Global transport shutdown
441 */
442 void transport_global_shutdown(void){
443 if( g.urlIsSsh ){
444 transport_ssh_close();
445 }
446 if( g.urlIsHttps ){
447 #ifdef FOSSIL_ENABLE_SSL
448 ssl_global_shutdown();
449 #endif
450 }else{
451 socket_global_shutdown();
452
--- src/http_transport.c
+++ src/http_transport.c
@@ -52,13 +52,13 @@
52
53
54 /*
55 ** Return the current transport error message.
56 */
57 const char *transport_errmsg(UrlData *pUrlData){
58 #ifdef FOSSIL_ENABLE_SSL
59 if( pUrlData->isHttps ){
60 return ssl_errmsg();
61 }
62 #endif
63 return socket_errmsg();
64 }
@@ -86,47 +86,47 @@
86 #endif
87
88 /*
89 ** SSH initialization of the transport layer
90 */
91 int transport_ssh_open(UrlData *pUrlData){
92 /* For SSH we need to create and run SSH fossil http
93 ** to talk to the remote machine.
94 */
95 const char *zSsh; /* The base SSH command */
96 Blob zCmd; /* The SSH command */
97 char *zHost; /* The host name to contact */
98 int n; /* Size of prefix string */
99
100 socket_ssh_resolve_addr(pUrlData);
101 zSsh = db_get("ssh-command", zDefaultSshCmd);
102 blob_init(&zCmd, zSsh, -1);
103 if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
104 #ifdef __MINGW32__
105 blob_appendf(&zCmd, " -P %d", pUrlData->port);
106 #else
107 blob_appendf(&zCmd, " -p %d", pUrlData->port);
108 #endif
109 }
110 if( g.fSshTrace ){
111 fossil_force_newline();
112 fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113 }
114 if( pUrlData->user && pUrlData->user[0] ){
115 zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
116 }else{
117 zHost = mprintf("%s", pUrlData->name);
118 }
119 n = blob_size(&zCmd);
120 blob_append(&zCmd, " ", 1);
121 shell_escape(&zCmd, zHost);
122 blob_append(&zCmd, " ", 1);
123 shell_escape(&zCmd, mprintf("%s", pUrlData->fossil));
124 blob_append(&zCmd, " test-http", 10);
125 if( pUrlData->path && pUrlData->path[0] ){
126 blob_append(&zCmd, " ", 1);
127 shell_escape(&zCmd, mprintf("%s", pUrlData->path));
128 }
129 if( g.fSshTrace ){
130 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131 }
132 free(zHost);
@@ -146,25 +146,25 @@
146 ** g.urlPort TCP/IP port. Ex: 80
147 ** g.urlIsHttps Use TLS for the connection
148 **
149 ** Return the number of errors.
150 */
151 int transport_open(UrlData *pUrlData){
152 int rc = 0;
153 if( transport.isOpen==0 ){
154 if( pUrlData->isSsh ){
155 rc = transport_ssh_open(pUrlData);
156 if( rc==0 ) transport.isOpen = 1;
157 }else if( pUrlData->isHttps ){
158 #ifdef FOSSIL_ENABLE_SSL
159 rc = ssl_open(pUrlData);
160 if( rc==0 ) transport.isOpen = 1;
161 #else
162 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
163 rc = 1;
164 #endif
165 }else if( pUrlData->isFile ){
166 sqlite3_uint64 iRandId;
167 sqlite3_randomness(sizeof(iRandId), &iRandId);
168 transport.zOutFile = mprintf("%s-%llu-out.http",
169 g.zRepositoryName, iRandId);
170 transport.zInFile = mprintf("%s-%llu-in.http",
@@ -173,21 +173,21 @@
173 if( transport.pFile==0 ){
174 fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
175 }
176 transport.isOpen = 1;
177 }else{
178 rc = socket_open(pUrlData);
179 if( rc==0 ) transport.isOpen = 1;
180 }
181 }
182 return rc;
183 }
184
185 /*
186 ** Close the current connection
187 */
188 void transport_close(UrlData *pUrlData){
189 if( transport.isOpen ){
190 free(transport.pBuf);
191 transport.pBuf = 0;
192 transport.nAlloc = 0;
193 transport.nUsed = 0;
@@ -194,17 +194,17 @@
194 transport.iCursor = 0;
195 if( transport.pLog ){
196 fclose(transport.pLog);
197 transport.pLog = 0;
198 }
199 if( pUrlData->isSsh ){
200 transport_ssh_close();
201 }else if( pUrlData->isHttps ){
202 #ifdef FOSSIL_ENABLE_SSL
203 ssl_close();
204 #endif
205 }else if( pUrlData->isFile ){
206 if( transport.pFile ){
207 fclose(transport.pFile);
208 transport.pFile = 0;
209 }
210 file_delete(transport.zInFile);
@@ -219,28 +219,28 @@
219 }
220
221 /*
222 ** Send content over the wire.
223 */
224 void transport_send(UrlData *pUrlData, Blob *toSend){
225 char *z = blob_buffer(toSend);
226 int n = blob_size(toSend);
227 transport.nSent += n;
228 if( pUrlData->isSsh ){
229 fwrite(z, 1, n, sshOut);
230 fflush(sshOut);
231 }else if( pUrlData->isHttps ){
232 #ifdef FOSSIL_ENABLE_SSL
233 int sent;
234 while( n>0 ){
235 sent = ssl_send(0, z, n);
236 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
237 if( sent<=0 ) break;
238 n -= sent;
239 }
240 #endif
241 }else if( pUrlData->isFile ){
242 fwrite(z, 1, n, transport.pFile);
243 }else{
244 int sent;
245 while( n>0 ){
246 sent = socket_send(0, z, n);
@@ -253,16 +253,16 @@
253
254 /*
255 ** This routine is called when the outbound message is complete and
256 ** it is time to being receiving a reply.
257 */
258 void transport_flip(UrlData *pUrlData){
259 if( pUrlData->isFile ){
260 char *zCmd;
261 fclose(transport.pFile);
262 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
263 g.nameOfExe, pUrlData->name, transport.zOutFile, transport.zInFile
264 );
265 fossil_system(zCmd);
266 free(zCmd);
267 transport.pFile = fossil_fopen(transport.zInFile, "rb");
268 }
@@ -282,21 +282,21 @@
282
283 /*
284 ** This routine is called when the inbound message has been received
285 ** and it is time to start sending again.
286 */
287 void transport_rewind(UrlData *pUrlData){
288 if( pUrlData->isFile ){
289 transport_close(pUrlData);
290 }
291 }
292
293 /*
294 ** Read N bytes of content directly from the wire and write into
295 ** the buffer.
296 */
297 static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){
298 int got;
299 if( sshIn ){
300 int x;
301 int wanted = N;
302 got = 0;
@@ -304,17 +304,17 @@
304 x = read(sshIn, &zBuf[got], wanted);
305 if( x<=0 ) break;
306 got += x;
307 wanted -= x;
308 }
309 }else if( pUrlData->isHttps ){
310 #ifdef FOSSIL_ENABLE_SSL
311 got = ssl_receive(0, zBuf, N);
312 #else
313 got = 0;
314 #endif
315 }else if( pUrlData->isFile ){
316 got = fread(zBuf, 1, N, transport.pFile);
317 }else{
318 got = socket_receive(0, zBuf, N);
319 }
320 /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
@@ -327,11 +327,11 @@
327
328 /*
329 ** Read N bytes of content from the wire and store in the supplied buffer.
330 ** Return the number of bytes actually received.
331 */
332 int transport_receive(UrlData *pUrlData, char *zBuf, int N){
333 int onHand; /* Bytes current held in the transport buffer */
334 int nByte = 0; /* Bytes of content received */
335
336 onHand = transport.nUsed - transport.iCursor;
337 if( g.fSshTrace){
@@ -351,11 +351,11 @@
351 N -= toMove;
352 zBuf += toMove;
353 nByte += toMove;
354 }
355 if( N>0 ){
356 int got = transport_fetch(pUrlData, zBuf, N);
357 if( got>0 ){
358 nByte += got;
359 transport.nRcvd += got;
360 }
361 }
@@ -366,11 +366,11 @@
366 /*
367 ** Load up to N new bytes of content into the transport.pBuf buffer.
368 ** The buffer itself might be moved. And the transport.iCursor value
369 ** might be reset to 0.
370 */
371 static void transport_load_buffer(UrlData *pUrlData, int N){
372 int i, j;
373 if( transport.nAlloc==0 ){
374 transport.nAlloc = N;
375 transport.pBuf = fossil_malloc( N );
376 transport.iCursor = 0;
@@ -388,11 +388,11 @@
388 transport.nAlloc = transport.nUsed + N;
389 pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
390 transport.pBuf = pNew;
391 }
392 if( N>0 ){
393 i = transport_fetch(pUrlData, &transport.pBuf[transport.nUsed], N);
394 if( i>0 ){
395 transport.nRcvd += i;
396 transport.nUsed += i;
397 }
398 }
@@ -404,18 +404,18 @@
404 ** from the received line and zero-terminate the result. Return a pointer
405 ** to the line.
406 **
407 ** Each call to this routine potentially overwrites the returned buffer.
408 */
409 char *transport_receive_line(UrlData *pUrlData){
410 int i;
411 int iStart;
412
413 i = iStart = transport.iCursor;
414 while(1){
415 if( i >= transport.nUsed ){
416 transport_load_buffer(pUrlData, pUrlData->isSsh ? 2 : 1000);
417 i -= iStart;
418 iStart = 0;
419 if( i >= transport.nUsed ){
420 transport.pBuf[i] = 0;
421 transport.iCursor = i;
@@ -437,15 +437,15 @@
437 }
438
439 /*
440 ** Global transport shutdown
441 */
442 void transport_global_shutdown(UrlData *pUrlData){
443 if( pUrlData->isSsh ){
444 transport_ssh_close();
445 }
446 if( pUrlData->isHttps ){
447 #ifdef FOSSIL_ENABLE_SSL
448 ssl_global_shutdown();
449 #endif
450 }else{
451 socket_global_shutdown();
452
+6 -6
--- src/info.c
+++ src/info.c
@@ -594,19 +594,19 @@
594594
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
595595
zPJ[jj] = '_';
596596
}
597597
}
598598
@ <tr><th>Timelines:</th><td>
599
- @ %z(href("%R/timeline?f=%S",zUuid))family</a>
599
+ @ %z(href("%R/timeline?f=%S&unhide",zUuid))family</a>
600600
if( zParent ){
601
- @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
601
+ @ | %z(href("%R/timeline?p=%S&unhide",zUuid))ancestors</a>
602602
}
603603
if( !isLeaf ){
604
- @ | %z(href("%R/timeline?d=%S",zUuid))descendants</a>
604
+ @ | %z(href("%R/timeline?d=%S&unhide",zUuid))descendants</a>
605605
}
606606
if( zParent && !isLeaf ){
607
- @ | %z(href("%R/timeline?dp=%S",zUuid))both</a>
607
+ @ | %z(href("%R/timeline?dp=%S&unhide",zUuid))both</a>
608608
}
609609
db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
610610
" WHERE rid=%d AND tagtype>0 "
611611
" AND tag.tagid=tagxref.tagid "
612612
" AND +tag.tagname GLOB 'sym-*'", rid);
@@ -1634,11 +1634,11 @@
16341634
objType = object_description(rid, 0, &downloadName);
16351635
style_submenu_element("Download", "Download",
16361636
"%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
16371637
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
16381638
style_submenu_element("Checkins Using", "Checkins Using",
1639
- "%R/timeline?uf=%s&n=200",zUuid);
1639
+ "%R/timeline?n=200&uf=%s",zUuid);
16401640
}
16411641
asText = P("txt")!=0;
16421642
zMime = mimetype_from_name(blob_str(&downloadName));
16431643
if( zMime ){
16441644
if( fossil_strcmp(zMime, "text/html")==0 ){
@@ -2195,11 +2195,11 @@
21952195
md5sum_blob(&ctrl, &cksum);
21962196
blob_appendf(&ctrl, "Z %b\n", &cksum);
21972197
db_begin_transaction();
21982198
g.markPrivate = content_is_private(rid);
21992199
nrid = content_put(&ctrl);
2200
- manifest_crosslink(nrid, &ctrl);
2200
+ manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
22012201
assert( blob_is_reset(&ctrl) );
22022202
db_end_transaction(0);
22032203
}
22042204
cgi_redirectf("ci?name=%s", zUuid);
22052205
}
22062206
--- src/info.c
+++ src/info.c
@@ -594,19 +594,19 @@
594 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
595 zPJ[jj] = '_';
596 }
597 }
598 @ <tr><th>Timelines:</th><td>
599 @ %z(href("%R/timeline?f=%S",zUuid))family</a>
600 if( zParent ){
601 @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
602 }
603 if( !isLeaf ){
604 @ | %z(href("%R/timeline?d=%S",zUuid))descendants</a>
605 }
606 if( zParent && !isLeaf ){
607 @ | %z(href("%R/timeline?dp=%S",zUuid))both</a>
608 }
609 db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
610 " WHERE rid=%d AND tagtype>0 "
611 " AND tag.tagid=tagxref.tagid "
612 " AND +tag.tagname GLOB 'sym-*'", rid);
@@ -1634,11 +1634,11 @@
1634 objType = object_description(rid, 0, &downloadName);
1635 style_submenu_element("Download", "Download",
1636 "%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
1637 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
1638 style_submenu_element("Checkins Using", "Checkins Using",
1639 "%R/timeline?uf=%s&n=200",zUuid);
1640 }
1641 asText = P("txt")!=0;
1642 zMime = mimetype_from_name(blob_str(&downloadName));
1643 if( zMime ){
1644 if( fossil_strcmp(zMime, "text/html")==0 ){
@@ -2195,11 +2195,11 @@
2195 md5sum_blob(&ctrl, &cksum);
2196 blob_appendf(&ctrl, "Z %b\n", &cksum);
2197 db_begin_transaction();
2198 g.markPrivate = content_is_private(rid);
2199 nrid = content_put(&ctrl);
2200 manifest_crosslink(nrid, &ctrl);
2201 assert( blob_is_reset(&ctrl) );
2202 db_end_transaction(0);
2203 }
2204 cgi_redirectf("ci?name=%s", zUuid);
2205 }
2206
--- src/info.c
+++ src/info.c
@@ -594,19 +594,19 @@
594 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
595 zPJ[jj] = '_';
596 }
597 }
598 @ <tr><th>Timelines:</th><td>
599 @ %z(href("%R/timeline?f=%S&unhide",zUuid))family</a>
600 if( zParent ){
601 @ | %z(href("%R/timeline?p=%S&unhide",zUuid))ancestors</a>
602 }
603 if( !isLeaf ){
604 @ | %z(href("%R/timeline?d=%S&unhide",zUuid))descendants</a>
605 }
606 if( zParent && !isLeaf ){
607 @ | %z(href("%R/timeline?dp=%S&unhide",zUuid))both</a>
608 }
609 db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
610 " WHERE rid=%d AND tagtype>0 "
611 " AND tag.tagid=tagxref.tagid "
612 " AND +tag.tagname GLOB 'sym-*'", rid);
@@ -1634,11 +1634,11 @@
1634 objType = object_description(rid, 0, &downloadName);
1635 style_submenu_element("Download", "Download",
1636 "%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
1637 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
1638 style_submenu_element("Checkins Using", "Checkins Using",
1639 "%R/timeline?n=200&uf=%s",zUuid);
1640 }
1641 asText = P("txt")!=0;
1642 zMime = mimetype_from_name(blob_str(&downloadName));
1643 if( zMime ){
1644 if( fossil_strcmp(zMime, "text/html")==0 ){
@@ -2195,11 +2195,11 @@
2195 md5sum_blob(&ctrl, &cksum);
2196 blob_appendf(&ctrl, "Z %b\n", &cksum);
2197 db_begin_transaction();
2198 g.markPrivate = content_is_private(rid);
2199 nrid = content_put(&ctrl);
2200 manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
2201 assert( blob_is_reset(&ctrl) );
2202 db_end_transaction(0);
2203 }
2204 cgi_redirectf("ci?name=%s", zUuid);
2205 }
2206
--- src/json_branch.c
+++ src/json_branch.c
@@ -291,12 +291,12 @@
291291
brid = content_put(&branch);
292292
if( brid==0 ){
293293
fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
294294
}
295295
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
296
- if( manifest_crosslink(brid, &branch)==0 ){
297
- fossil_fatal("unable to install new manifest");
296
+ if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
297
+ fossil_fatal("%s\n", g.zErrMsg);
298298
}
299299
assert( blob_is_reset(&branch) );
300300
content_deltify(rootid, brid, 0);
301301
if( zNewRid ){
302302
*zNewRid = brid;
303303
--- src/json_branch.c
+++ src/json_branch.c
@@ -291,12 +291,12 @@
291 brid = content_put(&branch);
292 if( brid==0 ){
293 fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
294 }
295 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
296 if( manifest_crosslink(brid, &branch)==0 ){
297 fossil_fatal("unable to install new manifest");
298 }
299 assert( blob_is_reset(&branch) );
300 content_deltify(rootid, brid, 0);
301 if( zNewRid ){
302 *zNewRid = brid;
303
--- src/json_branch.c
+++ src/json_branch.c
@@ -291,12 +291,12 @@
291 brid = content_put(&branch);
292 if( brid==0 ){
293 fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
294 }
295 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
296 if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
297 fossil_fatal("%s\n", g.zErrMsg);
298 }
299 assert( blob_is_reset(&branch) );
300 content_deltify(rootid, brid, 0);
301 if( zNewRid ){
302 *zNewRid = brid;
303
--- src/json_config.c
+++ src/json_config.c
@@ -53,16 +53,21 @@
5353
*/
5454
static const struct JsonConfigProperty {
5555
char const * name;
5656
int groupMask;
5757
} JsonConfigProperties[] = {
58
-{ "css", CONFIGSET_SKIN },
58
+{ "css", CONFIGSET_CSS },
5959
{ "header", CONFIGSET_SKIN },
6060
{ "footer", CONFIGSET_SKIN },
61
+{ "logo-mimetype", CONFIGSET_SKIN },
62
+{ "logo-image", CONFIGSET_SKIN },
63
+{ "background-mimetype", CONFIGSET_SKIN },
64
+{ "background-image", CONFIGSET_SKIN },
6165
{ "index-page", CONFIGSET_SKIN },
6266
{ "timeline-block-markup", CONFIGSET_SKIN },
6367
{ "timeline-max-comment", CONFIGSET_SKIN },
68
+{ "timeline-plaintext", CONFIGSET_SKIN },
6469
6570
{ "project-name", CONFIGSET_PROJ },
6671
{ "project-description", CONFIGSET_PROJ },
6772
{ "manifest", CONFIGSET_PROJ },
6873
{ "binary-glob", CONFIGSET_PROJ },
@@ -113,11 +118,11 @@
113118
if(0==(strcmp("all", zName))){
114119
confMask = CONFIGSET_ALL;
115120
}else if(0==(strcmp("project", zName))){
116121
confMask |= CONFIGSET_PROJ;
117122
}else if(0==(strcmp("skin", zName))){
118
- confMask |= CONFIGSET_SKIN;
123
+ confMask |= (CONFIGSET_CSS|CONFIGSET_SKIN);
119124
}else if(0==(strcmp("ticket", zName))){
120125
confMask |= CONFIGSET_TKT;
121126
}else if(0==(strcmp("skin-backup", zName))){
122127
optSkinBackups = 1;
123128
}else{
124129
--- src/json_config.c
+++ src/json_config.c
@@ -53,16 +53,21 @@
53 */
54 static const struct JsonConfigProperty {
55 char const * name;
56 int groupMask;
57 } JsonConfigProperties[] = {
58 { "css", CONFIGSET_SKIN },
59 { "header", CONFIGSET_SKIN },
60 { "footer", CONFIGSET_SKIN },
 
 
 
 
61 { "index-page", CONFIGSET_SKIN },
62 { "timeline-block-markup", CONFIGSET_SKIN },
63 { "timeline-max-comment", CONFIGSET_SKIN },
 
64
65 { "project-name", CONFIGSET_PROJ },
66 { "project-description", CONFIGSET_PROJ },
67 { "manifest", CONFIGSET_PROJ },
68 { "binary-glob", CONFIGSET_PROJ },
@@ -113,11 +118,11 @@
113 if(0==(strcmp("all", zName))){
114 confMask = CONFIGSET_ALL;
115 }else if(0==(strcmp("project", zName))){
116 confMask |= CONFIGSET_PROJ;
117 }else if(0==(strcmp("skin", zName))){
118 confMask |= CONFIGSET_SKIN;
119 }else if(0==(strcmp("ticket", zName))){
120 confMask |= CONFIGSET_TKT;
121 }else if(0==(strcmp("skin-backup", zName))){
122 optSkinBackups = 1;
123 }else{
124
--- src/json_config.c
+++ src/json_config.c
@@ -53,16 +53,21 @@
53 */
54 static const struct JsonConfigProperty {
55 char const * name;
56 int groupMask;
57 } JsonConfigProperties[] = {
58 { "css", CONFIGSET_CSS },
59 { "header", CONFIGSET_SKIN },
60 { "footer", CONFIGSET_SKIN },
61 { "logo-mimetype", CONFIGSET_SKIN },
62 { "logo-image", CONFIGSET_SKIN },
63 { "background-mimetype", CONFIGSET_SKIN },
64 { "background-image", CONFIGSET_SKIN },
65 { "index-page", CONFIGSET_SKIN },
66 { "timeline-block-markup", CONFIGSET_SKIN },
67 { "timeline-max-comment", CONFIGSET_SKIN },
68 { "timeline-plaintext", CONFIGSET_SKIN },
69
70 { "project-name", CONFIGSET_PROJ },
71 { "project-description", CONFIGSET_PROJ },
72 { "manifest", CONFIGSET_PROJ },
73 { "binary-glob", CONFIGSET_PROJ },
@@ -113,11 +118,11 @@
118 if(0==(strcmp("all", zName))){
119 confMask = CONFIGSET_ALL;
120 }else if(0==(strcmp("project", zName))){
121 confMask |= CONFIGSET_PROJ;
122 }else if(0==(strcmp("skin", zName))){
123 confMask |= (CONFIGSET_CSS|CONFIGSET_SKIN);
124 }else if(0==(strcmp("ticket", zName))){
125 confMask |= CONFIGSET_TKT;
126 }else if(0==(strcmp("skin-backup", zName))){
127 optSkinBackups = 1;
128 }else{
129
+16
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114114
#endif
115115
116116
/*
117117
** All global variables are in this structure.
118118
*/
119
+#define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
120
+
119121
struct Global {
120122
int argc; char **argv; /* Command-line arguments to the program */
121123
char *nameOfExe; /* Full path of executable. */
122124
const char *zErrlog; /* Log errors to this file, if not NULL */
123125
int isConst; /* True if the output is unchanging */
@@ -168,10 +170,14 @@
168170
int wikiFlags; /* Wiki conversion flags applied to %w and %W */
169171
char isHTTP; /* True if server/CGI modes, else assume CLI. */
170172
char javascriptHyperlink; /* If true, set href= using script, not HTML */
171173
Blob httpHeader; /* Complete text of the HTTP request header */
172174
175
+ /*
176
+ ** NOTE: These members MUST be kept in sync with those in the "UrlData"
177
+ ** structure defined in "url.c".
178
+ */
173179
int urlIsFile; /* True if a "file:" url */
174180
int urlIsHttps; /* True if a "https:" url */
175181
int urlIsSsh; /* True if an "ssh:" url */
176182
char *urlName; /* Hostname for http: or filename for file: */
177183
char *urlHostname; /* The HOST: parameter on http headers */
@@ -831,10 +837,20 @@
831837
const char *get_version(){
832838
static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
833839
MANIFEST_DATE " UTC";
834840
return version;
835841
}
842
+
843
+/*
844
+** This function returns the user-agent string for Fossil, for
845
+** use in HTTP(S) requests.
846
+*/
847
+const char *get_user_agent(){
848
+ static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
849
+ " " MANIFEST_VERSION ")";
850
+ return version;
851
+}
836852
837853
/*
838854
** COMMAND: version
839855
**
840856
** Usage: %fossil version ?-verbose|-v?
841857
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114 #endif
115
116 /*
117 ** All global variables are in this structure.
118 */
 
 
119 struct Global {
120 int argc; char **argv; /* Command-line arguments to the program */
121 char *nameOfExe; /* Full path of executable. */
122 const char *zErrlog; /* Log errors to this file, if not NULL */
123 int isConst; /* True if the output is unchanging */
@@ -168,10 +170,14 @@
168 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
169 char isHTTP; /* True if server/CGI modes, else assume CLI. */
170 char javascriptHyperlink; /* If true, set href= using script, not HTML */
171 Blob httpHeader; /* Complete text of the HTTP request header */
172
 
 
 
 
173 int urlIsFile; /* True if a "file:" url */
174 int urlIsHttps; /* True if a "https:" url */
175 int urlIsSsh; /* True if an "ssh:" url */
176 char *urlName; /* Hostname for http: or filename for file: */
177 char *urlHostname; /* The HOST: parameter on http headers */
@@ -831,10 +837,20 @@
831 const char *get_version(){
832 static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
833 MANIFEST_DATE " UTC";
834 return version;
835 }
 
 
 
 
 
 
 
 
 
 
836
837 /*
838 ** COMMAND: version
839 **
840 ** Usage: %fossil version ?-verbose|-v?
841
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114 #endif
115
116 /*
117 ** All global variables are in this structure.
118 */
119 #define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
120
121 struct Global {
122 int argc; char **argv; /* Command-line arguments to the program */
123 char *nameOfExe; /* Full path of executable. */
124 const char *zErrlog; /* Log errors to this file, if not NULL */
125 int isConst; /* True if the output is unchanging */
@@ -168,10 +170,14 @@
170 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
171 char isHTTP; /* True if server/CGI modes, else assume CLI. */
172 char javascriptHyperlink; /* If true, set href= using script, not HTML */
173 Blob httpHeader; /* Complete text of the HTTP request header */
174
175 /*
176 ** NOTE: These members MUST be kept in sync with those in the "UrlData"
177 ** structure defined in "url.c".
178 */
179 int urlIsFile; /* True if a "file:" url */
180 int urlIsHttps; /* True if a "https:" url */
181 int urlIsSsh; /* True if an "ssh:" url */
182 char *urlName; /* Hostname for http: or filename for file: */
183 char *urlHostname; /* The HOST: parameter on http headers */
@@ -831,10 +837,20 @@
837 const char *get_version(){
838 static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
839 MANIFEST_DATE " UTC";
840 return version;
841 }
842
843 /*
844 ** This function returns the user-agent string for Fossil, for
845 ** use in HTTP(S) requests.
846 */
847 const char *get_user_agent(){
848 static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
849 " " MANIFEST_VERSION ")";
850 return version;
851 }
852
853 /*
854 ** COMMAND: version
855 **
856 ** Usage: %fossil version ?-verbose|-v?
857
+16
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114114
#endif
115115
116116
/*
117117
** All global variables are in this structure.
118118
*/
119
+#define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
120
+
119121
struct Global {
120122
int argc; char **argv; /* Command-line arguments to the program */
121123
char *nameOfExe; /* Full path of executable. */
122124
const char *zErrlog; /* Log errors to this file, if not NULL */
123125
int isConst; /* True if the output is unchanging */
@@ -168,10 +170,14 @@
168170
int wikiFlags; /* Wiki conversion flags applied to %w and %W */
169171
char isHTTP; /* True if server/CGI modes, else assume CLI. */
170172
char javascriptHyperlink; /* If true, set href= using script, not HTML */
171173
Blob httpHeader; /* Complete text of the HTTP request header */
172174
175
+ /*
176
+ ** NOTE: These members MUST be kept in sync with those in the "UrlData"
177
+ ** structure defined in "url.c".
178
+ */
173179
int urlIsFile; /* True if a "file:" url */
174180
int urlIsHttps; /* True if a "https:" url */
175181
int urlIsSsh; /* True if an "ssh:" url */
176182
char *urlName; /* Hostname for http: or filename for file: */
177183
char *urlHostname; /* The HOST: parameter on http headers */
@@ -831,10 +837,20 @@
831837
const char *get_version(){
832838
static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
833839
MANIFEST_DATE " UTC";
834840
return version;
835841
}
842
+
843
+/*
844
+** This function returns the user-agent string for Fossil, for
845
+** use in HTTP(S) requests.
846
+*/
847
+const char *get_user_agent(){
848
+ static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
849
+ " " MANIFEST_VERSION ")";
850
+ return version;
851
+}
836852
837853
/*
838854
** COMMAND: version
839855
**
840856
** Usage: %fossil version ?-verbose|-v?
841857
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114 #endif
115
116 /*
117 ** All global variables are in this structure.
118 */
 
 
119 struct Global {
120 int argc; char **argv; /* Command-line arguments to the program */
121 char *nameOfExe; /* Full path of executable. */
122 const char *zErrlog; /* Log errors to this file, if not NULL */
123 int isConst; /* True if the output is unchanging */
@@ -168,10 +170,14 @@
168 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
169 char isHTTP; /* True if server/CGI modes, else assume CLI. */
170 char javascriptHyperlink; /* If true, set href= using script, not HTML */
171 Blob httpHeader; /* Complete text of the HTTP request header */
172
 
 
 
 
173 int urlIsFile; /* True if a "file:" url */
174 int urlIsHttps; /* True if a "https:" url */
175 int urlIsSsh; /* True if an "ssh:" url */
176 char *urlName; /* Hostname for http: or filename for file: */
177 char *urlHostname; /* The HOST: parameter on http headers */
@@ -831,10 +837,20 @@
831 const char *get_version(){
832 static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
833 MANIFEST_DATE " UTC";
834 return version;
835 }
 
 
 
 
 
 
 
 
 
 
836
837 /*
838 ** COMMAND: version
839 **
840 ** Usage: %fossil version ?-verbose|-v?
841
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114 #endif
115
116 /*
117 ** All global variables are in this structure.
118 */
119 #define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
120
121 struct Global {
122 int argc; char **argv; /* Command-line arguments to the program */
123 char *nameOfExe; /* Full path of executable. */
124 const char *zErrlog; /* Log errors to this file, if not NULL */
125 int isConst; /* True if the output is unchanging */
@@ -168,10 +170,14 @@
170 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
171 char isHTTP; /* True if server/CGI modes, else assume CLI. */
172 char javascriptHyperlink; /* If true, set href= using script, not HTML */
173 Blob httpHeader; /* Complete text of the HTTP request header */
174
175 /*
176 ** NOTE: These members MUST be kept in sync with those in the "UrlData"
177 ** structure defined in "url.c".
178 */
179 int urlIsFile; /* True if a "file:" url */
180 int urlIsHttps; /* True if a "https:" url */
181 int urlIsSsh; /* True if an "ssh:" url */
182 char *urlName; /* Hostname for http: or filename for file: */
183 char *urlHostname; /* The HOST: parameter on http headers */
@@ -831,10 +837,20 @@
837 const char *get_version(){
838 static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
839 MANIFEST_DATE " UTC";
840 return version;
841 }
842
843 /*
844 ** This function returns the user-agent string for Fossil, for
845 ** use in HTTP(S) requests.
846 */
847 const char *get_user_agent(){
848 static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
849 " " MANIFEST_VERSION ")";
850 return version;
851 }
852
853 /*
854 ** COMMAND: version
855 **
856 ** Usage: %fossil version ?-verbose|-v?
857
+39 -12
--- src/manifest.c
+++ src/manifest.c
@@ -42,10 +42,16 @@
4242
*/
4343
#define PERM_REG 0 /* regular file */
4444
#define PERM_EXE 1 /* executable */
4545
#define PERM_LNK 2 /* symlink */
4646
47
+/*
48
+** Flags for use with manifest_crosslink().
49
+*/
50
+#define MC_NONE 0 /* default handling */
51
+#define MC_PERMIT_HOOKS 1 /* permit hooks to execute */
52
+
4753
/*
4854
** A single F-card within a manifest
4955
*/
5056
struct ManifestFile {
5157
char *zName; /* Name of a file */
@@ -1650,34 +1656,41 @@
16501656
** Historical note: This routine original processed manifests only.
16511657
** Processing for other control artifacts was added later. The name
16521658
** of the routine, "manifest_crosslink", and the name of this source
16531659
** file, is a legacy of its original use.
16541660
*/
1655
-int manifest_crosslink(int rid, Blob *pContent){
1656
- int i;
1661
+int manifest_crosslink(int rid, Blob *pContent, int flags){
1662
+ int i, result = TH_OK;
16571663
Manifest *p;
16581664
Stmt q;
16591665
int parentid = 0;
1666
+ const char *zScript = 0;
1667
+ const char *zUuid = 0;
16601668
16611669
if( (p = manifest_cache_find(rid))!=0 ){
16621670
blob_reset(pContent);
16631671
}else if( (p = manifest_parse(pContent, rid, 0))==0 ){
16641672
assert( blob_is_reset(pContent) || pContent==0 );
1673
+ fossil_error(1, "syntax error in manifest");
16651674
return 0;
16661675
}
16671676
if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
16681677
manifest_destroy(p);
16691678
assert( blob_is_reset(pContent) );
1679
+ fossil_error(1, "no manifest");
16701680
return 0;
16711681
}
16721682
if( p->type==CFTYPE_MANIFEST && fetch_baseline(p, 0) ){
16731683
manifest_destroy(p);
16741684
assert( blob_is_reset(pContent) );
1685
+ fossil_error(1, "cannot fetch baseline manifest");
16751686
return 0;
16761687
}
16771688
db_begin_transaction();
16781689
if( p->type==CFTYPE_MANIFEST ){
1690
+ zScript = xfer_commit_code();
1691
+ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
16791692
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
16801693
char *zCom;
16811694
for(i=0; i<p->nParent; i++){
16821695
int pid = uuid_to_rid(p->azParent[i], 1);
16831696
db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
@@ -1768,11 +1781,11 @@
17681781
switch( p->aTag[i].zName[0] ){
17691782
case '-': type = 0; break; /* Cancel prior occurrences */
17701783
case '+': type = 1; break; /* Apply to target only */
17711784
case '*': type = 2; break; /* Propagate to descendants */
17721785
default:
1773
- fossil_fatal("unknown tag type in manifest: %s", p->aTag);
1786
+ fossil_error(1, "unknown tag type in manifest: %s", p->aTag);
17741787
return 0;
17751788
}
17761789
tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
17771790
rid, p->rDate, tid);
17781791
}
@@ -1870,10 +1883,12 @@
18701883
}
18711884
}
18721885
if( p->type==CFTYPE_TICKET ){
18731886
char *zTag;
18741887
1888
+ zScript = xfer_ticket_code();
1889
+ zUuid = p->zTicketUuid;
18751890
assert( manifest_crosslink_busy==1 );
18761891
zTag = mprintf("tkt-%s", p->zTicketUuid);
18771892
tag_insert(zTag, 1, 0, rid, p->rDate, rid);
18781893
free(zTag);
18791894
db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
@@ -1934,33 +1949,39 @@
19341949
if( p->type==CFTYPE_CONTROL ){
19351950
Blob comment;
19361951
int i;
19371952
const char *zName;
19381953
const char *zValue;
1939
- const char *zUuid;
1954
+ const char *zTagUuid;
19401955
int branchMove = 0;
19411956
blob_zero(&comment);
19421957
if( p->zComment ){
19431958
blob_appendf(&comment, " %s.", p->zComment);
19441959
}
19451960
/* Next loop expects tags to be sorted on UUID, so sort it. */
19461961
qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
19471962
for(i=0; i<p->nTag; i++){
1948
- zUuid = p->aTag[i].zUuid;
1949
- if( !zUuid ) continue;
1950
- if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){
1963
+ zTagUuid = p->aTag[i].zUuid;
1964
+ if( !zTagUuid ) continue;
1965
+ if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
19511966
blob_appendf(&comment,
19521967
" Edit [%S]:",
1953
- zUuid);
1968
+ zTagUuid);
19541969
branchMove = 0;
1970
+ if( db_exists("SELECT 1 FROM event, blob"
1971
+ " WHERE event.type='ci' AND event.objid=blob.rid"
1972
+ " AND blob.uuid='%s'", zTagUuid) ){
1973
+ zScript = xfer_commit_code();
1974
+ zUuid = zTagUuid;
1975
+ }
19551976
}
19561977
zName = p->aTag[i].zName;
19571978
zValue = p->aTag[i].zValue;
19581979
if( strcmp(zName, "*branch")==0 ){
19591980
blob_appendf(&comment,
1960
- " Move to branch [/timeline?r=%h&nd&dp=%S | %h].",
1961
- zValue, zUuid, zValue);
1981
+ " Move to branch [/timeline?r=%h&nd&dp=%S&unhide | %h].",
1982
+ zValue, zTagUuid, zValue);
19621983
branchMove = 1;
19631984
continue;
19641985
}else if( strcmp(zName, "*bgcolor")==0 ){
19651986
blob_appendf(&comment,
19661987
" Change branch background color to \"%h\".", zValue);
@@ -2021,17 +2042,23 @@
20212042
p->rDate, rid, p->zUser, blob_str(&comment)+1
20222043
);
20232044
blob_reset(&comment);
20242045
}
20252046
db_end_transaction(0);
2047
+ if( zScript && (flags & MC_PERMIT_HOOKS) ){
2048
+ result = xfer_run_common_script();
2049
+ if( result==TH_OK ){
2050
+ result = xfer_run_script(zScript, zUuid);
2051
+ }
2052
+ }
20262053
if( p->type==CFTYPE_MANIFEST ){
20272054
manifest_cache_insert(p);
20282055
}else{
20292056
manifest_destroy(p);
20302057
}
20312058
assert( blob_is_reset(pContent) );
2032
- return 1;
2059
+ return ( result!=TH_ERROR );
20332060
}
20342061
20352062
/*
20362063
** COMMAND: test-crosslink
20372064
**
@@ -2045,7 +2072,7 @@
20452072
Blob content;
20462073
db_find_and_open_repository(0, 0);
20472074
if( g.argc!=3 ) usage("RECORDID");
20482075
rid = name_to_rid(g.argv[2]);
20492076
content_get(rid, &content);
2050
- manifest_crosslink(rid, &content);
2077
+ manifest_crosslink(rid, &content, MC_NONE);
20512078
}
20522079
--- src/manifest.c
+++ src/manifest.c
@@ -42,10 +42,16 @@
42 */
43 #define PERM_REG 0 /* regular file */
44 #define PERM_EXE 1 /* executable */
45 #define PERM_LNK 2 /* symlink */
46
 
 
 
 
 
 
47 /*
48 ** A single F-card within a manifest
49 */
50 struct ManifestFile {
51 char *zName; /* Name of a file */
@@ -1650,34 +1656,41 @@
1650 ** Historical note: This routine original processed manifests only.
1651 ** Processing for other control artifacts was added later. The name
1652 ** of the routine, "manifest_crosslink", and the name of this source
1653 ** file, is a legacy of its original use.
1654 */
1655 int manifest_crosslink(int rid, Blob *pContent){
1656 int i;
1657 Manifest *p;
1658 Stmt q;
1659 int parentid = 0;
 
 
1660
1661 if( (p = manifest_cache_find(rid))!=0 ){
1662 blob_reset(pContent);
1663 }else if( (p = manifest_parse(pContent, rid, 0))==0 ){
1664 assert( blob_is_reset(pContent) || pContent==0 );
 
1665 return 0;
1666 }
1667 if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
1668 manifest_destroy(p);
1669 assert( blob_is_reset(pContent) );
 
1670 return 0;
1671 }
1672 if( p->type==CFTYPE_MANIFEST && fetch_baseline(p, 0) ){
1673 manifest_destroy(p);
1674 assert( blob_is_reset(pContent) );
 
1675 return 0;
1676 }
1677 db_begin_transaction();
1678 if( p->type==CFTYPE_MANIFEST ){
 
 
1679 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
1680 char *zCom;
1681 for(i=0; i<p->nParent; i++){
1682 int pid = uuid_to_rid(p->azParent[i], 1);
1683 db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
@@ -1768,11 +1781,11 @@
1768 switch( p->aTag[i].zName[0] ){
1769 case '-': type = 0; break; /* Cancel prior occurrences */
1770 case '+': type = 1; break; /* Apply to target only */
1771 case '*': type = 2; break; /* Propagate to descendants */
1772 default:
1773 fossil_fatal("unknown tag type in manifest: %s", p->aTag);
1774 return 0;
1775 }
1776 tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
1777 rid, p->rDate, tid);
1778 }
@@ -1870,10 +1883,12 @@
1870 }
1871 }
1872 if( p->type==CFTYPE_TICKET ){
1873 char *zTag;
1874
 
 
1875 assert( manifest_crosslink_busy==1 );
1876 zTag = mprintf("tkt-%s", p->zTicketUuid);
1877 tag_insert(zTag, 1, 0, rid, p->rDate, rid);
1878 free(zTag);
1879 db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
@@ -1934,33 +1949,39 @@
1934 if( p->type==CFTYPE_CONTROL ){
1935 Blob comment;
1936 int i;
1937 const char *zName;
1938 const char *zValue;
1939 const char *zUuid;
1940 int branchMove = 0;
1941 blob_zero(&comment);
1942 if( p->zComment ){
1943 blob_appendf(&comment, " %s.", p->zComment);
1944 }
1945 /* Next loop expects tags to be sorted on UUID, so sort it. */
1946 qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
1947 for(i=0; i<p->nTag; i++){
1948 zUuid = p->aTag[i].zUuid;
1949 if( !zUuid ) continue;
1950 if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){
1951 blob_appendf(&comment,
1952 " Edit [%S]:",
1953 zUuid);
1954 branchMove = 0;
 
 
 
 
 
 
1955 }
1956 zName = p->aTag[i].zName;
1957 zValue = p->aTag[i].zValue;
1958 if( strcmp(zName, "*branch")==0 ){
1959 blob_appendf(&comment,
1960 " Move to branch [/timeline?r=%h&nd&dp=%S | %h].",
1961 zValue, zUuid, zValue);
1962 branchMove = 1;
1963 continue;
1964 }else if( strcmp(zName, "*bgcolor")==0 ){
1965 blob_appendf(&comment,
1966 " Change branch background color to \"%h\".", zValue);
@@ -2021,17 +2042,23 @@
2021 p->rDate, rid, p->zUser, blob_str(&comment)+1
2022 );
2023 blob_reset(&comment);
2024 }
2025 db_end_transaction(0);
 
 
 
 
 
 
2026 if( p->type==CFTYPE_MANIFEST ){
2027 manifest_cache_insert(p);
2028 }else{
2029 manifest_destroy(p);
2030 }
2031 assert( blob_is_reset(pContent) );
2032 return 1;
2033 }
2034
2035 /*
2036 ** COMMAND: test-crosslink
2037 **
@@ -2045,7 +2072,7 @@
2045 Blob content;
2046 db_find_and_open_repository(0, 0);
2047 if( g.argc!=3 ) usage("RECORDID");
2048 rid = name_to_rid(g.argv[2]);
2049 content_get(rid, &content);
2050 manifest_crosslink(rid, &content);
2051 }
2052
--- src/manifest.c
+++ src/manifest.c
@@ -42,10 +42,16 @@
42 */
43 #define PERM_REG 0 /* regular file */
44 #define PERM_EXE 1 /* executable */
45 #define PERM_LNK 2 /* symlink */
46
47 /*
48 ** Flags for use with manifest_crosslink().
49 */
50 #define MC_NONE 0 /* default handling */
51 #define MC_PERMIT_HOOKS 1 /* permit hooks to execute */
52
53 /*
54 ** A single F-card within a manifest
55 */
56 struct ManifestFile {
57 char *zName; /* Name of a file */
@@ -1650,34 +1656,41 @@
1656 ** Historical note: This routine original processed manifests only.
1657 ** Processing for other control artifacts was added later. The name
1658 ** of the routine, "manifest_crosslink", and the name of this source
1659 ** file, is a legacy of its original use.
1660 */
1661 int manifest_crosslink(int rid, Blob *pContent, int flags){
1662 int i, result = TH_OK;
1663 Manifest *p;
1664 Stmt q;
1665 int parentid = 0;
1666 const char *zScript = 0;
1667 const char *zUuid = 0;
1668
1669 if( (p = manifest_cache_find(rid))!=0 ){
1670 blob_reset(pContent);
1671 }else if( (p = manifest_parse(pContent, rid, 0))==0 ){
1672 assert( blob_is_reset(pContent) || pContent==0 );
1673 fossil_error(1, "syntax error in manifest");
1674 return 0;
1675 }
1676 if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
1677 manifest_destroy(p);
1678 assert( blob_is_reset(pContent) );
1679 fossil_error(1, "no manifest");
1680 return 0;
1681 }
1682 if( p->type==CFTYPE_MANIFEST && fetch_baseline(p, 0) ){
1683 manifest_destroy(p);
1684 assert( blob_is_reset(pContent) );
1685 fossil_error(1, "cannot fetch baseline manifest");
1686 return 0;
1687 }
1688 db_begin_transaction();
1689 if( p->type==CFTYPE_MANIFEST ){
1690 zScript = xfer_commit_code();
1691 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
1692 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
1693 char *zCom;
1694 for(i=0; i<p->nParent; i++){
1695 int pid = uuid_to_rid(p->azParent[i], 1);
1696 db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
@@ -1768,11 +1781,11 @@
1781 switch( p->aTag[i].zName[0] ){
1782 case '-': type = 0; break; /* Cancel prior occurrences */
1783 case '+': type = 1; break; /* Apply to target only */
1784 case '*': type = 2; break; /* Propagate to descendants */
1785 default:
1786 fossil_error(1, "unknown tag type in manifest: %s", p->aTag);
1787 return 0;
1788 }
1789 tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
1790 rid, p->rDate, tid);
1791 }
@@ -1870,10 +1883,12 @@
1883 }
1884 }
1885 if( p->type==CFTYPE_TICKET ){
1886 char *zTag;
1887
1888 zScript = xfer_ticket_code();
1889 zUuid = p->zTicketUuid;
1890 assert( manifest_crosslink_busy==1 );
1891 zTag = mprintf("tkt-%s", p->zTicketUuid);
1892 tag_insert(zTag, 1, 0, rid, p->rDate, rid);
1893 free(zTag);
1894 db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
@@ -1934,33 +1949,39 @@
1949 if( p->type==CFTYPE_CONTROL ){
1950 Blob comment;
1951 int i;
1952 const char *zName;
1953 const char *zValue;
1954 const char *zTagUuid;
1955 int branchMove = 0;
1956 blob_zero(&comment);
1957 if( p->zComment ){
1958 blob_appendf(&comment, " %s.", p->zComment);
1959 }
1960 /* Next loop expects tags to be sorted on UUID, so sort it. */
1961 qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
1962 for(i=0; i<p->nTag; i++){
1963 zTagUuid = p->aTag[i].zUuid;
1964 if( !zTagUuid ) continue;
1965 if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
1966 blob_appendf(&comment,
1967 " Edit [%S]:",
1968 zTagUuid);
1969 branchMove = 0;
1970 if( db_exists("SELECT 1 FROM event, blob"
1971 " WHERE event.type='ci' AND event.objid=blob.rid"
1972 " AND blob.uuid='%s'", zTagUuid) ){
1973 zScript = xfer_commit_code();
1974 zUuid = zTagUuid;
1975 }
1976 }
1977 zName = p->aTag[i].zName;
1978 zValue = p->aTag[i].zValue;
1979 if( strcmp(zName, "*branch")==0 ){
1980 blob_appendf(&comment,
1981 " Move to branch [/timeline?r=%h&nd&dp=%S&unhide | %h].",
1982 zValue, zTagUuid, zValue);
1983 branchMove = 1;
1984 continue;
1985 }else if( strcmp(zName, "*bgcolor")==0 ){
1986 blob_appendf(&comment,
1987 " Change branch background color to \"%h\".", zValue);
@@ -2021,17 +2042,23 @@
2042 p->rDate, rid, p->zUser, blob_str(&comment)+1
2043 );
2044 blob_reset(&comment);
2045 }
2046 db_end_transaction(0);
2047 if( zScript && (flags & MC_PERMIT_HOOKS) ){
2048 result = xfer_run_common_script();
2049 if( result==TH_OK ){
2050 result = xfer_run_script(zScript, zUuid);
2051 }
2052 }
2053 if( p->type==CFTYPE_MANIFEST ){
2054 manifest_cache_insert(p);
2055 }else{
2056 manifest_destroy(p);
2057 }
2058 assert( blob_is_reset(pContent) );
2059 return ( result!=TH_ERROR );
2060 }
2061
2062 /*
2063 ** COMMAND: test-crosslink
2064 **
@@ -2045,7 +2072,7 @@
2072 Blob content;
2073 db_find_and_open_repository(0, 0);
2074 if( g.argc!=3 ) usage("RECORDID");
2075 rid = name_to_rid(g.argv[2]);
2076 content_get(rid, &content);
2077 manifest_crosslink(rid, &content, MC_NONE);
2078 }
2079
+1 -1
--- src/rebuild.c
+++ src/rebuild.c
@@ -250,11 +250,11 @@
250250
blob_copy(&copy, pBase);
251251
pUse = &copy;
252252
}
253253
if( zFNameFormat==0 ){
254254
/* We are doing "fossil rebuild" */
255
- manifest_crosslink(rid, pUse);
255
+ manifest_crosslink(rid, pUse, MC_NONE);
256256
}else{
257257
/* We are doing "fossil deconstruct" */
258258
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
259259
char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
260260
blob_write_to_file(pUse,zFile);
261261
--- src/rebuild.c
+++ src/rebuild.c
@@ -250,11 +250,11 @@
250 blob_copy(&copy, pBase);
251 pUse = &copy;
252 }
253 if( zFNameFormat==0 ){
254 /* We are doing "fossil rebuild" */
255 manifest_crosslink(rid, pUse);
256 }else{
257 /* We are doing "fossil deconstruct" */
258 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
259 char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
260 blob_write_to_file(pUse,zFile);
261
--- src/rebuild.c
+++ src/rebuild.c
@@ -250,11 +250,11 @@
250 blob_copy(&copy, pBase);
251 pUse = &copy;
252 }
253 if( zFNameFormat==0 ){
254 /* We are doing "fossil rebuild" */
255 manifest_crosslink(rid, pUse, MC_NONE);
256 }else{
257 /* We are doing "fossil deconstruct" */
258 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
259 char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
260 blob_write_to_file(pUse,zFile);
261
+1 -1
--- src/setup.c
+++ src/setup.c
@@ -812,11 +812,11 @@
812812
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
813813
login_verify_csrf_secret();
814814
db_set(zVar, zQ, 0);
815815
zVal = zQ;
816816
}
817
- @ <input type="text" name="%s(zQParm)" value="%h(zVal)" size="%d(width)"
817
+ @ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)"
818818
if( disabled ){
819819
@ disabled="disabled"
820820
}
821821
@ /> <b>%s(zLabel)</b>
822822
}
823823
--- src/setup.c
+++ src/setup.c
@@ -812,11 +812,11 @@
812 if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
813 login_verify_csrf_secret();
814 db_set(zVar, zQ, 0);
815 zVal = zQ;
816 }
817 @ <input type="text" name="%s(zQParm)" value="%h(zVal)" size="%d(width)"
818 if( disabled ){
819 @ disabled="disabled"
820 }
821 @ /> <b>%s(zLabel)</b>
822 }
823
--- src/setup.c
+++ src/setup.c
@@ -812,11 +812,11 @@
812 if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
813 login_verify_csrf_secret();
814 db_set(zVar, zQ, 0);
815 zVal = zQ;
816 }
817 @ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)"
818 if( disabled ){
819 @ disabled="disabled"
820 }
821 @ /> <b>%s(zLabel)</b>
822 }
823
+5 -1
--- src/shell.c
+++ src/shell.c
@@ -3036,11 +3036,14 @@
30363036
if( seenInterrupt ){
30373037
if( in!=0 ) break;
30383038
seenInterrupt = 0;
30393039
}
30403040
lineno++;
3041
- if( nSql==0 && _all_whitespace(zLine) ) continue;
3041
+ if( nSql==0 && _all_whitespace(zLine) ){
3042
+ if( p->echoOn ) printf("%s\n", zLine);
3043
+ continue;
3044
+ }
30423045
if( zLine && zLine[0]=='.' && nSql==0 ){
30433046
if( p->echoOn ) printf("%s\n", zLine);
30443047
rc = do_meta_command(zLine, p);
30453048
if( rc==2 ){ /* exit requested */
30463049
break;
@@ -3098,10 +3101,11 @@
30983101
}
30993102
errCnt++;
31003103
}
31013104
nSql = 0;
31023105
}else if( nSql && _all_whitespace(zSql) ){
3106
+ if( p->echoOn ) printf("%s\n", zSql);
31033107
nSql = 0;
31043108
}
31053109
}
31063110
if( nSql ){
31073111
if( !_all_whitespace(zSql) ){
31083112
--- src/shell.c
+++ src/shell.c
@@ -3036,11 +3036,14 @@
3036 if( seenInterrupt ){
3037 if( in!=0 ) break;
3038 seenInterrupt = 0;
3039 }
3040 lineno++;
3041 if( nSql==0 && _all_whitespace(zLine) ) continue;
 
 
 
3042 if( zLine && zLine[0]=='.' && nSql==0 ){
3043 if( p->echoOn ) printf("%s\n", zLine);
3044 rc = do_meta_command(zLine, p);
3045 if( rc==2 ){ /* exit requested */
3046 break;
@@ -3098,10 +3101,11 @@
3098 }
3099 errCnt++;
3100 }
3101 nSql = 0;
3102 }else if( nSql && _all_whitespace(zSql) ){
 
3103 nSql = 0;
3104 }
3105 }
3106 if( nSql ){
3107 if( !_all_whitespace(zSql) ){
3108
--- src/shell.c
+++ src/shell.c
@@ -3036,11 +3036,14 @@
3036 if( seenInterrupt ){
3037 if( in!=0 ) break;
3038 seenInterrupt = 0;
3039 }
3040 lineno++;
3041 if( nSql==0 && _all_whitespace(zLine) ){
3042 if( p->echoOn ) printf("%s\n", zLine);
3043 continue;
3044 }
3045 if( zLine && zLine[0]=='.' && nSql==0 ){
3046 if( p->echoOn ) printf("%s\n", zLine);
3047 rc = do_meta_command(zLine, p);
3048 if( rc==2 ){ /* exit requested */
3049 break;
@@ -3098,10 +3101,11 @@
3101 }
3102 errCnt++;
3103 }
3104 nSql = 0;
3105 }else if( nSql && _all_whitespace(zSql) ){
3106 if( p->echoOn ) printf("%s\n", zSql);
3107 nSql = 0;
3108 }
3109 }
3110 if( nSql ){
3111 if( !_all_whitespace(zSql) ){
3112
+204 -111
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -135,11 +135,11 @@
135135
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
136136
** [sqlite_version()] and [sqlite_source_id()].
137137
*/
138138
#define SQLITE_VERSION "3.8.3"
139139
#define SQLITE_VERSION_NUMBER 3008003
140
-#define SQLITE_SOURCE_ID "2013-12-17 16:32:56 93121d3097a43997af3c0de65bd9bd7663845fa2"
140
+#define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d"
141141
142142
/*
143143
** CAPI3REF: Run-Time Library Version Numbers
144144
** KEYWORDS: sqlite3_version, sqlite3_sourceid
145145
**
@@ -9098,11 +9098,11 @@
90989098
#define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */
90999099
#define OP_Null 26 /* synopsis: r[P2..P3]=NULL */
91009100
#define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */
91019101
#define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */
91029102
#define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */
9103
-#define OP_Copy 30 /* synopsis: r[P2@P3]=r[P1@P3] */
9103
+#define OP_Copy 30 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
91049104
#define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */
91059105
#define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */
91069106
#define OP_CollSeq 33
91079107
#define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */
91089108
#define OP_MustBeInt 35
@@ -9263,11 +9263,11 @@
92639263
92649264
/*
92659265
** Prototypes for the VDBE interface. See comments on the implementation
92669266
** for a description of what each of these routines does.
92679267
*/
9268
-SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*);
9268
+SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*);
92699269
SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
92709270
SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
92719271
SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
92729272
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
92739273
SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
@@ -11003,10 +11003,11 @@
1100311003
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
1100411004
** than the source table */
1100511005
int sortingIdx; /* Cursor number of the sorting index */
1100611006
int sortingIdxPTab; /* Cursor number of pseudo-table */
1100711007
int nSortingColumn; /* Number of columns in the sorting index */
11008
+ int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
1100811009
ExprList *pGroupBy; /* The group by clause */
1100911010
struct AggInfo_col { /* For each column used in source tables */
1101011011
Table *pTab; /* Source table */
1101111012
int iTable; /* Cursor number of the source table */
1101211013
int iColumn; /* Column number within the source table */
@@ -12452,12 +12453,11 @@
1245212453
SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
1245312454
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
1245412455
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
1245512456
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
1245612457
12457
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
12458
- defined(SQLITE_DEBUG_OS_TRACE)
12458
+#if defined(SQLITE_TEST)
1245912459
SQLITE_PRIVATE const char *sqlite3ErrName(int);
1246012460
#endif
1246112461
1246212462
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
1246312463
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
@@ -13776,10 +13776,13 @@
1377613776
Op *aOp; /* Space to hold the virtual machine's program */
1377713777
Mem *aMem; /* The memory locations */
1377813778
Mem **apArg; /* Arguments to currently executing user function */
1377913779
Mem *aColName; /* Column names to return */
1378013780
Mem *pResultSet; /* Pointer to an array of results */
13781
+#ifdef SQLITE_DEBUG
13782
+ Parse *pParse; /* Parsing context used to create this Vdbe */
13783
+#endif
1378113784
int nMem; /* Number of memory locations currently allocated */
1378213785
int nOp; /* Number of instructions in the program */
1378313786
int nOpAlloc; /* Number of slots allocated for aOp[] */
1378413787
int nLabel; /* Number of labels used */
1378513788
int *aLabel; /* Space to hold the labels */
@@ -15443,11 +15446,25 @@
1544315446
** really care if the VFS receives and understands the information since it
1544415447
** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
1544515448
** routine has no return value since the return value would be meaningless.
1544615449
*/
1544715450
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
15448
- DO_OS_MALLOC_TEST(id);
15451
+#ifdef SQLITE_TEST
15452
+ if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
15453
+ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
15454
+ ** is using a regular VFS, it is called after the corresponding
15455
+ ** transaction has been committed. Injecting a fault at this point
15456
+ ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
15457
+ ** but the transaction is committed anyway.
15458
+ **
15459
+ ** The core must call OsFileControl() though, not OsFileControlHint(),
15460
+ ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
15461
+ ** means the commit really has failed and an error should be returned
15462
+ ** to the user. */
15463
+ DO_OS_MALLOC_TEST(id);
15464
+ }
15465
+#endif
1544915466
return id->pMethods->xFileControl(id, op, pArg);
1545015467
}
1545115468
SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
1545215469
(void)id->pMethods->xFileControl(id, op, pArg);
1545315470
}
@@ -23098,11 +23115,11 @@
2309823115
/* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
2309923116
/* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
2310023117
/* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
2310123118
/* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
2310223119
/* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
23103
- /* 30 */ "Copy" OpHelp("r[P2@P3]=r[P1@P3]"),
23120
+ /* 30 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
2310423121
/* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
2310523122
/* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"),
2310623123
/* 33 */ "CollSeq" OpHelp(""),
2310723124
/* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
2310823125
/* 35 */ "MustBeInt" OpHelp(""),
@@ -61223,11 +61240,12 @@
6122361240
*/
6122461241
6122561242
/*
6122661243
** Create a new virtual database engine.
6122761244
*/
61228
-SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
61245
+SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
61246
+ sqlite3 *db = pParse->db;
6122961247
Vdbe *p;
6123061248
p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
6123161249
if( p==0 ) return 0;
6123261250
p->db = db;
6123361251
if( db->pVdbe ){
@@ -61235,10 +61253,13 @@
6123561253
}
6123661254
p->pNext = db->pVdbe;
6123761255
p->pPrev = 0;
6123861256
db->pVdbe = p;
6123961257
p->magic = VDBE_MAGIC_INIT;
61258
+#if SQLITE_DEBUG
61259
+ p->pParse = pParse;
61260
+#endif
6124061261
return p;
6124161262
}
6124261263
6124361264
/*
6124461265
** Remember the SQL string for a prepared statement.
@@ -61354,10 +61375,19 @@
6135461375
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
6135561376
pOp->zComment = 0;
6135661377
#endif
6135761378
#ifdef SQLITE_DEBUG
6135861379
if( p->db->flags & SQLITE_VdbeAddopTrace ){
61380
+ int jj, kk;
61381
+ Parse *pParse = p->pParse;
61382
+ for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
61383
+ struct yColCache *x = pParse->aColCache + jj;
61384
+ if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
61385
+ printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
61386
+ kk++;
61387
+ }
61388
+ if( kk ) printf("\n");
6135961389
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
6136061390
test_addop_breakpoint();
6136161391
}
6136261392
#endif
6136361393
#ifdef VDBE_PROFILE
@@ -62075,11 +62105,21 @@
6207562105
if( c=='4' ) return pOp->p4.i;
6207662106
return pOp->p5;
6207762107
}
6207862108
6207962109
/*
62080
-** Compute a string for the "comment" field of a VDBE opcode listing
62110
+** Compute a string for the "comment" field of a VDBE opcode listing.
62111
+**
62112
+** The Synopsis: field in comments in the vdbe.c source file gets converted
62113
+** to an extra string that is appended to the sqlite3OpcodeName(). In the
62114
+** absence of other comments, this synopsis becomes the comment on the opcode.
62115
+** Some translation occurs:
62116
+**
62117
+** "PX" -> "r[X]"
62118
+** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1
62119
+** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
62120
+** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
6208162121
*/
6208262122
static int displayComment(
6208362123
const Op *pOp, /* The opcode to be commented */
6208462124
const char *zP4, /* Previously obtained value for P4 */
6208562125
char *zTemp, /* Write result here */
@@ -62109,11 +62149,17 @@
6210962149
sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
6211062150
if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
6211162151
ii += 3;
6211262152
jj += sqlite3Strlen30(zTemp+jj);
6211362153
v2 = translateP(zSynopsis[ii], pOp);
62114
- if( v2>1 ) sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
62154
+ if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
62155
+ ii += 2;
62156
+ v2++;
62157
+ }
62158
+ if( v2>1 ){
62159
+ sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
62160
+ }
6211562161
}else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
6211662162
ii += 4;
6211762163
}
6211862164
}
6211962165
jj += sqlite3Strlen30(zTemp+jj);
@@ -62341,10 +62387,13 @@
6234162387
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
6234262388
displayComment(pOp, zP4, zCom, sizeof(zCom));
6234362389
#else
6234462390
zCom[0] = 0
6234562391
#endif
62392
+ /* NB: The sqlite3OpcodeName() function is implemented by code created
62393
+ ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
62394
+ ** information from the vdbe.c source text */
6234662395
fprintf(pOut, zFormat1, pc,
6234762396
sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
6234862397
zCom
6234962398
);
6235062399
fflush(pOut);
@@ -67401,11 +67450,11 @@
6740167450
}while( n-- );
6740267451
break;
6740367452
}
6740467453
6740567454
/* Opcode: Copy P1 P2 P3 * *
67406
-** Synopsis: r[P2@P3]=r[P1@P3]
67455
+** Synopsis: r[P2@P3+1]=r[P1@P3+1]
6740767456
**
6740867457
** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
6740967458
**
6741067459
** This instruction makes a deep copy of the value. A duplicate
6741167460
** is made of any string or blob constant. See also OP_SCopy.
@@ -68744,11 +68793,11 @@
6874468793
/* This is the common case where the desired content fits on the original
6874568794
** page - where the content is not on an overflow page */
6874668795
VdbeMemRelease(pDest);
6874768796
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
6874868797
}else{
68749
- /* This branch happens only when content is on overflow pages */
68798
+ /* This branch happens only when content is on overflow pages */
6875068799
t = aType[p2];
6875168800
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
6875268801
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
6875368802
|| (len = sqlite3VdbeSerialTypeLen(t))==0
6875468803
){
@@ -72862,11 +72911,11 @@
7286272911
sqlite3BtreeLeaveAll(db);
7286372912
goto blob_open_out;
7286472913
}
7286572914
}
7286672915
72867
- pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db);
72916
+ pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
7286872917
assert( pBlob->pStmt || db->mallocFailed );
7286972918
if( pBlob->pStmt ){
7287072919
Vdbe *v = (Vdbe *)pBlob->pStmt;
7287172920
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
7287272921
@@ -78416,10 +78465,15 @@
7841678465
** added to the column cache after this call are removed when the
7841778466
** corresponding pop occurs.
7841878467
*/
7841978468
SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
7842078469
pParse->iCacheLevel++;
78470
+#ifdef SQLITE_DEBUG
78471
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78472
+ printf("PUSH to %d\n", pParse->iCacheLevel);
78473
+ }
78474
+#endif
7842178475
}
7842278476
7842378477
/*
7842478478
** Remove from the column cache any entries that were added since the
7842578479
** the previous N Push operations. In other words, restore the cache
@@ -78429,10 +78483,15 @@
7842978483
int i;
7843078484
struct yColCache *p;
7843178485
assert( N>0 );
7843278486
assert( pParse->iCacheLevel>=N );
7843378487
pParse->iCacheLevel -= N;
78488
+#ifdef SQLITE_DEBUG
78489
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78490
+ printf("POP to %d\n", pParse->iCacheLevel);
78491
+ }
78492
+#endif
7843478493
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
7843578494
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
7843678495
cacheEntryClear(pParse, p);
7843778496
p->iReg = 0;
7843878497
}
@@ -78523,10 +78582,15 @@
7852378582
*/
7852478583
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
7852578584
int i;
7852678585
struct yColCache *p;
7852778586
78587
+#if SQLITE_DEBUG
78588
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78589
+ printf("CLEAR\n");
78590
+ }
78591
+#endif
7852878592
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
7852978593
if( p->iReg ){
7853078594
cacheEntryClear(pParse, p);
7853178595
p->iReg = 0;
7853278596
}
@@ -79659,11 +79723,21 @@
7965979723
if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
7966079724
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
7966179725
}else{
7966279726
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
7966379727
if( inReg!=target+i ){
79664
- sqlite3VdbeAddOp2(pParse->pVdbe, copyOp, inReg, target+i);
79728
+ VdbeOp *pOp;
79729
+ Vdbe *v = pParse->pVdbe;
79730
+ if( copyOp==OP_Copy
79731
+ && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
79732
+ && pOp->p1+pOp->p3+1==inReg
79733
+ && pOp->p2+pOp->p3+1==target+i
79734
+ ){
79735
+ pOp->p3++;
79736
+ }else{
79737
+ sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
79738
+ }
7966579739
}
7966679740
}
7966779741
}
7966879742
return n;
7966979743
}
@@ -83083,14 +83157,10 @@
8308383157
{
8308483158
int rc = SQLITE_OK;
8308583159
if( pExpr ){
8308683160
if( pExpr->op!=TK_ID ){
8308783161
rc = sqlite3ResolveExprNames(pName, pExpr);
83088
- if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
83089
- sqlite3ErrorMsg(pName->pParse, "invalid name: \"%s\"", pExpr->u.zToken);
83090
- return SQLITE_ERROR;
83091
- }
8309283162
}else{
8309383163
pExpr->op = TK_STRING;
8309483164
}
8309583165
}
8309683166
return rc;
@@ -89324,11 +89394,10 @@
8932489394
Vdbe *v = pParse->pVdbe;
8932589395
int j;
8932689396
Table *pTab = pIdx->pTable;
8932789397
int regBase;
8932889398
int nCol;
89329
- Index *pPk;
8933089399
8933189400
if( piPartIdxLabel ){
8933289401
if( pIdx->pPartIdxWhere ){
8933389402
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
8933489403
pParse->iPartIdxTab = iDataCur;
@@ -89338,20 +89407,13 @@
8933889407
*piPartIdxLabel = 0;
8933989408
}
8934089409
}
8934189410
nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
8934289411
regBase = sqlite3GetTempRange(pParse, nCol);
89343
- pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
8934489412
for(j=0; j<nCol; j++){
89345
- i16 idx = pIdx->aiColumn[j];
89346
- if( pPk ) idx = sqlite3ColumnOfIndex(pPk, idx);
89347
- if( idx<0 || idx==pTab->iPKey ){
89348
- sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regBase+j);
89349
- }else{
89350
- sqlite3VdbeAddOp3(v, OP_Column, iDataCur, idx, regBase+j);
89351
- sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[j], -1);
89352
- }
89413
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
89414
+ regBase+j);
8935389415
}
8935489416
if( regOut ){
8935589417
const char *zAff;
8935689418
if( pTab->pSelect
8935789419
|| OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
@@ -93982,51 +94044,53 @@
9398294044
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
9398394045
regIdx, pIdx->nKeyCol);
9398494046
9398594047
/* Generate code to handle collisions */
9398694048
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
93987
- if( HasRowid(pTab) ){
93988
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
93989
- /* Conflict only if the rowid of the existing index entry
93990
- ** is different from old-rowid */
93991
- if( isUpdate ){
93992
- sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
93993
- }
93994
- }else{
93995
- int x;
93996
- /* Extract the PRIMARY KEY from the end of the index entry and
93997
- ** store it in registers regR..regR+nPk-1 */
93998
- if( (isUpdate || onError==OE_Replace) && pIdx!=pPk ){
93999
- for(i=0; i<pPk->nKeyCol; i++){
94000
- x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94001
- sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94002
- VdbeComment((v, "%s.%s", pTab->zName,
94003
- pTab->aCol[pPk->aiColumn[i]].zName));
94004
- }
94005
- }
94006
- if( isUpdate ){
94007
- /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94008
- ** table, only conflict if the new PRIMARY KEY values are actually
94009
- ** different from the old.
94010
- **
94011
- ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94012
- ** of the matched index row are different from the original PRIMARY
94013
- ** KEY values of this row before the update. */
94014
- int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94015
- int op = OP_Ne;
94016
- int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94017
-
94018
- for(i=0; i<pPk->nKeyCol; i++){
94019
- char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94020
- x = pPk->aiColumn[i];
94021
- if( i==(pPk->nKeyCol-1) ){
94022
- addrJump = addrUniqueOk;
94023
- op = OP_Eq;
94024
- }
94025
- sqlite3VdbeAddOp4(v, op,
94026
- regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94027
- );
94049
+ if( isUpdate || onError==OE_Replace ){
94050
+ if( HasRowid(pTab) ){
94051
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
94052
+ /* Conflict only if the rowid of the existing index entry
94053
+ ** is different from old-rowid */
94054
+ if( isUpdate ){
94055
+ sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
94056
+ }
94057
+ }else{
94058
+ int x;
94059
+ /* Extract the PRIMARY KEY from the end of the index entry and
94060
+ ** store it in registers regR..regR+nPk-1 */
94061
+ if( pIdx!=pPk ){
94062
+ for(i=0; i<pPk->nKeyCol; i++){
94063
+ x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94064
+ sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94065
+ VdbeComment((v, "%s.%s", pTab->zName,
94066
+ pTab->aCol[pPk->aiColumn[i]].zName));
94067
+ }
94068
+ }
94069
+ if( isUpdate ){
94070
+ /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94071
+ ** table, only conflict if the new PRIMARY KEY values are actually
94072
+ ** different from the old.
94073
+ **
94074
+ ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94075
+ ** of the matched index row are different from the original PRIMARY
94076
+ ** KEY values of this row before the update. */
94077
+ int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94078
+ int op = OP_Ne;
94079
+ int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94080
+
94081
+ for(i=0; i<pPk->nKeyCol; i++){
94082
+ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94083
+ x = pPk->aiColumn[i];
94084
+ if( i==(pPk->nKeyCol-1) ){
94085
+ addrJump = addrUniqueOk;
94086
+ op = OP_Eq;
94087
+ }
94088
+ sqlite3VdbeAddOp4(v, op,
94089
+ regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94090
+ );
94091
+ }
9402894092
}
9402994093
}
9403094094
}
9403194095
9403294096
/* Generate code that executes if the new index entry is not unique */
@@ -99722,11 +99786,10 @@
9972299786
}
9972399787
}else if( eDest!=SRT_Exists ){
9972499788
/* If the destination is an EXISTS(...) expression, the actual
9972599789
** values returned by the SELECT are not required.
9972699790
*/
99727
- sqlite3ExprCacheClear(pParse);
9972899791
sqlite3ExprCodeExprList(pParse, pEList, regResult,
9972999792
(eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
9973099793
}
9973199794
nColumn = nResultCol;
9973299795
@@ -100689,11 +100752,11 @@
100689100752
** If an error occurs, return NULL and leave a message in pParse.
100690100753
*/
100691100754
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
100692100755
Vdbe *v = pParse->pVdbe;
100693100756
if( v==0 ){
100694
- v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
100757
+ v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
100695100758
#ifndef SQLITE_OMIT_TRACE
100696100759
if( v ){
100697100760
sqlite3VdbeAddOp0(v, OP_Trace);
100698100761
}
100699100762
#endif
@@ -102947,18 +103010,27 @@
102947103010
*/
102948103011
static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
102949103012
Vdbe *v = pParse->pVdbe;
102950103013
int i;
102951103014
struct AggInfo_func *pFunc;
102952
- if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){
102953
- return;
102954
- }
103015
+ int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
103016
+ if( nReg==0 ) return;
103017
+#ifdef SQLITE_DEBUG
103018
+ /* Verify that all AggInfo registers are within the range specified by
103019
+ ** AggInfo.mnReg..AggInfo.mxReg */
103020
+ assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
102955103021
for(i=0; i<pAggInfo->nColumn; i++){
102956
- sqlite3VdbeAddOp2(v, OP_Null, 0, pAggInfo->aCol[i].iMem);
103022
+ assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
103023
+ && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
102957103024
}
103025
+ for(i=0; i<pAggInfo->nFunc; i++){
103026
+ assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
103027
+ && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
103028
+ }
103029
+#endif
103030
+ sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
102958103031
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
102959
- sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
102960103032
if( pFunc->iDistinct>=0 ){
102961103033
Expr *pE = pFunc->pExpr;
102962103034
assert( !ExprHasProperty(pE, EP_xIsSelect) );
102963103035
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
102964103036
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -103000,11 +103072,10 @@
103000103072
int addrHitTest = 0;
103001103073
struct AggInfo_func *pF;
103002103074
struct AggInfo_col *pC;
103003103075
103004103076
pAggInfo->directMode = 1;
103005
- sqlite3ExprCacheClear(pParse);
103006103077
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
103007103078
int nArg;
103008103079
int addrNext = 0;
103009103080
int regAgg;
103010103081
ExprList *pList = pF->pExpr->x.pList;
@@ -103533,10 +103604,11 @@
103533103604
*/
103534103605
memset(&sNC, 0, sizeof(sNC));
103535103606
sNC.pParse = pParse;
103536103607
sNC.pSrcList = pTabList;
103537103608
sNC.pAggInfo = &sAggInfo;
103609
+ sAggInfo.mnReg = pParse->nMem+1;
103538103610
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
103539103611
sAggInfo.pGroupBy = pGroupBy;
103540103612
sqlite3ExprAnalyzeAggList(&sNC, pEList);
103541103613
sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
103542103614
if( pHaving ){
@@ -103547,10 +103619,11 @@
103547103619
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
103548103620
sNC.ncFlags |= NC_InAggFunc;
103549103621
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
103550103622
sNC.ncFlags &= ~NC_InAggFunc;
103551103623
}
103624
+ sAggInfo.mxReg = pParse->nMem;
103552103625
if( db->mallocFailed ) goto select_end;
103553103626
103554103627
/* Processing for aggregates with GROUP BY is very different and
103555103628
** much more complex than aggregates without a GROUP BY.
103556103629
*/
@@ -105451,11 +105524,11 @@
105451105524
pCol->affinity, &pValue);
105452105525
if( pValue ){
105453105526
sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
105454105527
}
105455105528
#ifndef SQLITE_OMIT_FLOATING_POINT
105456
- if( iReg>=0 && pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105529
+ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105457105530
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
105458105531
}
105459105532
#endif
105460105533
}
105461105534
}
@@ -105875,14 +105948,14 @@
105875105948
** be used eliminates some redundant opcodes.
105876105949
*/
105877105950
newmask = sqlite3TriggerColmask(
105878105951
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
105879105952
);
105880
- sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);
105953
+ /*sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);*/
105881105954
for(i=0; i<pTab->nCol; i++){
105882105955
if( i==pTab->iPKey ){
105883
- /*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
105956
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105884105957
}else{
105885105958
j = aXRef[i];
105886105959
if( j>=0 ){
105887105960
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
105888105961
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
@@ -105892,10 +105965,12 @@
105892105965
** a new.* reference in a trigger program.
105893105966
*/
105894105967
testcase( i==31 );
105895105968
testcase( i==32 );
105896105969
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
105970
+ }else{
105971
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105897105972
}
105898105973
}
105899105974
}
105900105975
105901105976
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
@@ -112004,10 +112079,11 @@
112004112079
*/
112005112080
if( pTerm==0
112006112081
&& saved_nEq==saved_nSkip
112007112082
&& saved_nEq+1<pProbe->nKeyCol
112008112083
&& pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
112084
+ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
112009112085
){
112010112086
LogEst nIter;
112011112087
pNew->u.btree.nEq++;
112012112088
pNew->u.btree.nSkip++;
112013112089
pNew->aLTerm[pNew->nLTerm++] = 0;
@@ -119722,12 +119798,11 @@
119722119798
119723119799
/*
119724119800
** Return a static string containing the name corresponding to the error code
119725119801
** specified in the argument.
119726119802
*/
119727
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
119728
- defined(SQLITE_DEBUG_OS_TRACE)
119803
+#if defined(SQLITE_TEST)
119729119804
SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
119730119805
const char *zName = 0;
119731119806
int i, origRc = rc;
119732119807
for(i=0; i<2 && zName==0; i++, rc &= 0xff){
119733119808
switch( rc ){
@@ -121300,10 +121375,12 @@
121300121375
#ifdef SQLITE_DEFAULT_LOCKING_MODE
121301121376
db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
121302121377
sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
121303121378
SQLITE_DEFAULT_LOCKING_MODE);
121304121379
#endif
121380
+
121381
+ if( rc ) sqlite3Error(db, rc, 0);
121305121382
121306121383
/* Enable the lookaside-malloc subsystem */
121307121384
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
121308121385
sqlite3GlobalConfig.nLookaside);
121309121386
@@ -131632,61 +131709,74 @@
131632131709
}
131633131710
131634131711
/* Step 2 */
131635131712
switch( z[1] ){
131636131713
case 'a':
131637
- stem(&z, "lanoita", "ate", m_gt_0) ||
131638
- stem(&z, "lanoit", "tion", m_gt_0);
131714
+ if( !stem(&z, "lanoita", "ate", m_gt_0) ){
131715
+ stem(&z, "lanoit", "tion", m_gt_0);
131716
+ }
131639131717
break;
131640131718
case 'c':
131641
- stem(&z, "icne", "ence", m_gt_0) ||
131642
- stem(&z, "icna", "ance", m_gt_0);
131719
+ if( !stem(&z, "icne", "ence", m_gt_0) ){
131720
+ stem(&z, "icna", "ance", m_gt_0);
131721
+ }
131643131722
break;
131644131723
case 'e':
131645131724
stem(&z, "rezi", "ize", m_gt_0);
131646131725
break;
131647131726
case 'g':
131648131727
stem(&z, "igol", "log", m_gt_0);
131649131728
break;
131650131729
case 'l':
131651
- stem(&z, "ilb", "ble", m_gt_0) ||
131652
- stem(&z, "illa", "al", m_gt_0) ||
131653
- stem(&z, "iltne", "ent", m_gt_0) ||
131654
- stem(&z, "ile", "e", m_gt_0) ||
131655
- stem(&z, "ilsuo", "ous", m_gt_0);
131730
+ if( !stem(&z, "ilb", "ble", m_gt_0)
131731
+ && !stem(&z, "illa", "al", m_gt_0)
131732
+ && !stem(&z, "iltne", "ent", m_gt_0)
131733
+ && !stem(&z, "ile", "e", m_gt_0)
131734
+ ){
131735
+ stem(&z, "ilsuo", "ous", m_gt_0);
131736
+ }
131656131737
break;
131657131738
case 'o':
131658
- stem(&z, "noitazi", "ize", m_gt_0) ||
131659
- stem(&z, "noita", "ate", m_gt_0) ||
131660
- stem(&z, "rota", "ate", m_gt_0);
131739
+ if( !stem(&z, "noitazi", "ize", m_gt_0)
131740
+ && !stem(&z, "noita", "ate", m_gt_0)
131741
+ ){
131742
+ stem(&z, "rota", "ate", m_gt_0);
131743
+ }
131661131744
break;
131662131745
case 's':
131663
- stem(&z, "msila", "al", m_gt_0) ||
131664
- stem(&z, "ssenevi", "ive", m_gt_0) ||
131665
- stem(&z, "ssenluf", "ful", m_gt_0) ||
131666
- stem(&z, "ssensuo", "ous", m_gt_0);
131746
+ if( !stem(&z, "msila", "al", m_gt_0)
131747
+ && !stem(&z, "ssenevi", "ive", m_gt_0)
131748
+ && !stem(&z, "ssenluf", "ful", m_gt_0)
131749
+ ){
131750
+ stem(&z, "ssensuo", "ous", m_gt_0);
131751
+ }
131667131752
break;
131668131753
case 't':
131669
- stem(&z, "itila", "al", m_gt_0) ||
131670
- stem(&z, "itivi", "ive", m_gt_0) ||
131671
- stem(&z, "itilib", "ble", m_gt_0);
131754
+ if( !stem(&z, "itila", "al", m_gt_0)
131755
+ && !stem(&z, "itivi", "ive", m_gt_0)
131756
+ ){
131757
+ stem(&z, "itilib", "ble", m_gt_0);
131758
+ }
131672131759
break;
131673131760
}
131674131761
131675131762
/* Step 3 */
131676131763
switch( z[0] ){
131677131764
case 'e':
131678
- stem(&z, "etaci", "ic", m_gt_0) ||
131679
- stem(&z, "evita", "", m_gt_0) ||
131680
- stem(&z, "ezila", "al", m_gt_0);
131765
+ if( !stem(&z, "etaci", "ic", m_gt_0)
131766
+ && !stem(&z, "evita", "", m_gt_0)
131767
+ ){
131768
+ stem(&z, "ezila", "al", m_gt_0);
131769
+ }
131681131770
break;
131682131771
case 'i':
131683131772
stem(&z, "itici", "ic", m_gt_0);
131684131773
break;
131685131774
case 'l':
131686
- stem(&z, "laci", "ic", m_gt_0) ||
131687
- stem(&z, "luf", "", m_gt_0);
131775
+ if( !stem(&z, "laci", "ic", m_gt_0) ){
131776
+ stem(&z, "luf", "", m_gt_0);
131777
+ }
131688131778
break;
131689131779
case 's':
131690131780
stem(&z, "ssen", "", m_gt_0);
131691131781
break;
131692131782
}
@@ -131723,13 +131813,15 @@
131723131813
if( z[2]=='a' ){
131724131814
if( m_gt_1(z+3) ){
131725131815
z += 3;
131726131816
}
131727131817
}else if( z[2]=='e' ){
131728
- stem(&z, "tneme", "", m_gt_1) ||
131729
- stem(&z, "tnem", "", m_gt_1) ||
131730
- stem(&z, "tne", "", m_gt_1);
131818
+ if( !stem(&z, "tneme", "", m_gt_1)
131819
+ && !stem(&z, "tnem", "", m_gt_1)
131820
+ ){
131821
+ stem(&z, "tne", "", m_gt_1);
131822
+ }
131731131823
}
131732131824
}
131733131825
break;
131734131826
case 'o':
131735131827
if( z[0]=='u' ){
@@ -131744,12 +131836,13 @@
131744131836
if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
131745131837
z += 3;
131746131838
}
131747131839
break;
131748131840
case 't':
131749
- stem(&z, "eta", "", m_gt_1) ||
131750
- stem(&z, "iti", "", m_gt_1);
131841
+ if( !stem(&z, "eta", "", m_gt_1) ){
131842
+ stem(&z, "iti", "", m_gt_1);
131843
+ }
131751131844
break;
131752131845
case 'u':
131753131846
if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
131754131847
z += 3;
131755131848
}
131756131849
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -135,11 +135,11 @@
135 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
136 ** [sqlite_version()] and [sqlite_source_id()].
137 */
138 #define SQLITE_VERSION "3.8.3"
139 #define SQLITE_VERSION_NUMBER 3008003
140 #define SQLITE_SOURCE_ID "2013-12-17 16:32:56 93121d3097a43997af3c0de65bd9bd7663845fa2"
141
142 /*
143 ** CAPI3REF: Run-Time Library Version Numbers
144 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
145 **
@@ -9098,11 +9098,11 @@
9098 #define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */
9099 #define OP_Null 26 /* synopsis: r[P2..P3]=NULL */
9100 #define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */
9101 #define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */
9102 #define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */
9103 #define OP_Copy 30 /* synopsis: r[P2@P3]=r[P1@P3] */
9104 #define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */
9105 #define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */
9106 #define OP_CollSeq 33
9107 #define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */
9108 #define OP_MustBeInt 35
@@ -9263,11 +9263,11 @@
9263
9264 /*
9265 ** Prototypes for the VDBE interface. See comments on the implementation
9266 ** for a description of what each of these routines does.
9267 */
9268 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*);
9269 SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
9270 SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
9271 SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
9272 SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
9273 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
@@ -11003,10 +11003,11 @@
11003 u8 useSortingIdx; /* In direct mode, reference the sorting index rather
11004 ** than the source table */
11005 int sortingIdx; /* Cursor number of the sorting index */
11006 int sortingIdxPTab; /* Cursor number of pseudo-table */
11007 int nSortingColumn; /* Number of columns in the sorting index */
 
11008 ExprList *pGroupBy; /* The group by clause */
11009 struct AggInfo_col { /* For each column used in source tables */
11010 Table *pTab; /* Source table */
11011 int iTable; /* Cursor number of the source table */
11012 int iColumn; /* Column number within the source table */
@@ -12452,12 +12453,11 @@
12452 SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
12453 SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
12454 SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
12455 SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
12456
12457 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
12458 defined(SQLITE_DEBUG_OS_TRACE)
12459 SQLITE_PRIVATE const char *sqlite3ErrName(int);
12460 #endif
12461
12462 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
12463 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
@@ -13776,10 +13776,13 @@
13776 Op *aOp; /* Space to hold the virtual machine's program */
13777 Mem *aMem; /* The memory locations */
13778 Mem **apArg; /* Arguments to currently executing user function */
13779 Mem *aColName; /* Column names to return */
13780 Mem *pResultSet; /* Pointer to an array of results */
 
 
 
13781 int nMem; /* Number of memory locations currently allocated */
13782 int nOp; /* Number of instructions in the program */
13783 int nOpAlloc; /* Number of slots allocated for aOp[] */
13784 int nLabel; /* Number of labels used */
13785 int *aLabel; /* Space to hold the labels */
@@ -15443,11 +15446,25 @@
15443 ** really care if the VFS receives and understands the information since it
15444 ** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
15445 ** routine has no return value since the return value would be meaningless.
15446 */
15447 SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
15448 DO_OS_MALLOC_TEST(id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15449 return id->pMethods->xFileControl(id, op, pArg);
15450 }
15451 SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
15452 (void)id->pMethods->xFileControl(id, op, pArg);
15453 }
@@ -23098,11 +23115,11 @@
23098 /* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
23099 /* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
23100 /* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
23101 /* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
23102 /* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
23103 /* 30 */ "Copy" OpHelp("r[P2@P3]=r[P1@P3]"),
23104 /* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
23105 /* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"),
23106 /* 33 */ "CollSeq" OpHelp(""),
23107 /* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
23108 /* 35 */ "MustBeInt" OpHelp(""),
@@ -61223,11 +61240,12 @@
61223 */
61224
61225 /*
61226 ** Create a new virtual database engine.
61227 */
61228 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
 
61229 Vdbe *p;
61230 p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
61231 if( p==0 ) return 0;
61232 p->db = db;
61233 if( db->pVdbe ){
@@ -61235,10 +61253,13 @@
61235 }
61236 p->pNext = db->pVdbe;
61237 p->pPrev = 0;
61238 db->pVdbe = p;
61239 p->magic = VDBE_MAGIC_INIT;
 
 
 
61240 return p;
61241 }
61242
61243 /*
61244 ** Remember the SQL string for a prepared statement.
@@ -61354,10 +61375,19 @@
61354 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
61355 pOp->zComment = 0;
61356 #endif
61357 #ifdef SQLITE_DEBUG
61358 if( p->db->flags & SQLITE_VdbeAddopTrace ){
 
 
 
 
 
 
 
 
 
61359 sqlite3VdbePrintOp(0, i, &p->aOp[i]);
61360 test_addop_breakpoint();
61361 }
61362 #endif
61363 #ifdef VDBE_PROFILE
@@ -62075,11 +62105,21 @@
62075 if( c=='4' ) return pOp->p4.i;
62076 return pOp->p5;
62077 }
62078
62079 /*
62080 ** Compute a string for the "comment" field of a VDBE opcode listing
 
 
 
 
 
 
 
 
 
 
62081 */
62082 static int displayComment(
62083 const Op *pOp, /* The opcode to be commented */
62084 const char *zP4, /* Previously obtained value for P4 */
62085 char *zTemp, /* Write result here */
@@ -62109,11 +62149,17 @@
62109 sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
62110 if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
62111 ii += 3;
62112 jj += sqlite3Strlen30(zTemp+jj);
62113 v2 = translateP(zSynopsis[ii], pOp);
62114 if( v2>1 ) sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
 
 
 
 
 
 
62115 }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
62116 ii += 4;
62117 }
62118 }
62119 jj += sqlite3Strlen30(zTemp+jj);
@@ -62341,10 +62387,13 @@
62341 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
62342 displayComment(pOp, zP4, zCom, sizeof(zCom));
62343 #else
62344 zCom[0] = 0
62345 #endif
 
 
 
62346 fprintf(pOut, zFormat1, pc,
62347 sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
62348 zCom
62349 );
62350 fflush(pOut);
@@ -67401,11 +67450,11 @@
67401 }while( n-- );
67402 break;
67403 }
67404
67405 /* Opcode: Copy P1 P2 P3 * *
67406 ** Synopsis: r[P2@P3]=r[P1@P3]
67407 **
67408 ** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
67409 **
67410 ** This instruction makes a deep copy of the value. A duplicate
67411 ** is made of any string or blob constant. See also OP_SCopy.
@@ -68744,11 +68793,11 @@
68744 /* This is the common case where the desired content fits on the original
68745 ** page - where the content is not on an overflow page */
68746 VdbeMemRelease(pDest);
68747 sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
68748 }else{
68749 /* This branch happens only when content is on overflow pages */
68750 t = aType[p2];
68751 if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
68752 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
68753 || (len = sqlite3VdbeSerialTypeLen(t))==0
68754 ){
@@ -72862,11 +72911,11 @@
72862 sqlite3BtreeLeaveAll(db);
72863 goto blob_open_out;
72864 }
72865 }
72866
72867 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db);
72868 assert( pBlob->pStmt || db->mallocFailed );
72869 if( pBlob->pStmt ){
72870 Vdbe *v = (Vdbe *)pBlob->pStmt;
72871 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
72872
@@ -78416,10 +78465,15 @@
78416 ** added to the column cache after this call are removed when the
78417 ** corresponding pop occurs.
78418 */
78419 SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
78420 pParse->iCacheLevel++;
 
 
 
 
 
78421 }
78422
78423 /*
78424 ** Remove from the column cache any entries that were added since the
78425 ** the previous N Push operations. In other words, restore the cache
@@ -78429,10 +78483,15 @@
78429 int i;
78430 struct yColCache *p;
78431 assert( N>0 );
78432 assert( pParse->iCacheLevel>=N );
78433 pParse->iCacheLevel -= N;
 
 
 
 
 
78434 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78435 if( p->iReg && p->iLevel>pParse->iCacheLevel ){
78436 cacheEntryClear(pParse, p);
78437 p->iReg = 0;
78438 }
@@ -78523,10 +78582,15 @@
78523 */
78524 SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
78525 int i;
78526 struct yColCache *p;
78527
 
 
 
 
 
78528 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78529 if( p->iReg ){
78530 cacheEntryClear(pParse, p);
78531 p->iReg = 0;
78532 }
@@ -79659,11 +79723,21 @@
79659 if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
79660 sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
79661 }else{
79662 int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
79663 if( inReg!=target+i ){
79664 sqlite3VdbeAddOp2(pParse->pVdbe, copyOp, inReg, target+i);
 
 
 
 
 
 
 
 
 
 
79665 }
79666 }
79667 }
79668 return n;
79669 }
@@ -83083,14 +83157,10 @@
83083 {
83084 int rc = SQLITE_OK;
83085 if( pExpr ){
83086 if( pExpr->op!=TK_ID ){
83087 rc = sqlite3ResolveExprNames(pName, pExpr);
83088 if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
83089 sqlite3ErrorMsg(pName->pParse, "invalid name: \"%s\"", pExpr->u.zToken);
83090 return SQLITE_ERROR;
83091 }
83092 }else{
83093 pExpr->op = TK_STRING;
83094 }
83095 }
83096 return rc;
@@ -89324,11 +89394,10 @@
89324 Vdbe *v = pParse->pVdbe;
89325 int j;
89326 Table *pTab = pIdx->pTable;
89327 int regBase;
89328 int nCol;
89329 Index *pPk;
89330
89331 if( piPartIdxLabel ){
89332 if( pIdx->pPartIdxWhere ){
89333 *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
89334 pParse->iPartIdxTab = iDataCur;
@@ -89338,20 +89407,13 @@
89338 *piPartIdxLabel = 0;
89339 }
89340 }
89341 nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
89342 regBase = sqlite3GetTempRange(pParse, nCol);
89343 pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
89344 for(j=0; j<nCol; j++){
89345 i16 idx = pIdx->aiColumn[j];
89346 if( pPk ) idx = sqlite3ColumnOfIndex(pPk, idx);
89347 if( idx<0 || idx==pTab->iPKey ){
89348 sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regBase+j);
89349 }else{
89350 sqlite3VdbeAddOp3(v, OP_Column, iDataCur, idx, regBase+j);
89351 sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[j], -1);
89352 }
89353 }
89354 if( regOut ){
89355 const char *zAff;
89356 if( pTab->pSelect
89357 || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
@@ -93982,51 +94044,53 @@
93982 sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
93983 regIdx, pIdx->nKeyCol);
93984
93985 /* Generate code to handle collisions */
93986 regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
93987 if( HasRowid(pTab) ){
93988 sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
93989 /* Conflict only if the rowid of the existing index entry
93990 ** is different from old-rowid */
93991 if( isUpdate ){
93992 sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
93993 }
93994 }else{
93995 int x;
93996 /* Extract the PRIMARY KEY from the end of the index entry and
93997 ** store it in registers regR..regR+nPk-1 */
93998 if( (isUpdate || onError==OE_Replace) && pIdx!=pPk ){
93999 for(i=0; i<pPk->nKeyCol; i++){
94000 x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94001 sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94002 VdbeComment((v, "%s.%s", pTab->zName,
94003 pTab->aCol[pPk->aiColumn[i]].zName));
94004 }
94005 }
94006 if( isUpdate ){
94007 /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94008 ** table, only conflict if the new PRIMARY KEY values are actually
94009 ** different from the old.
94010 **
94011 ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94012 ** of the matched index row are different from the original PRIMARY
94013 ** KEY values of this row before the update. */
94014 int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94015 int op = OP_Ne;
94016 int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94017
94018 for(i=0; i<pPk->nKeyCol; i++){
94019 char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94020 x = pPk->aiColumn[i];
94021 if( i==(pPk->nKeyCol-1) ){
94022 addrJump = addrUniqueOk;
94023 op = OP_Eq;
94024 }
94025 sqlite3VdbeAddOp4(v, op,
94026 regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94027 );
 
 
94028 }
94029 }
94030 }
94031
94032 /* Generate code that executes if the new index entry is not unique */
@@ -99722,11 +99786,10 @@
99722 }
99723 }else if( eDest!=SRT_Exists ){
99724 /* If the destination is an EXISTS(...) expression, the actual
99725 ** values returned by the SELECT are not required.
99726 */
99727 sqlite3ExprCacheClear(pParse);
99728 sqlite3ExprCodeExprList(pParse, pEList, regResult,
99729 (eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
99730 }
99731 nColumn = nResultCol;
99732
@@ -100689,11 +100752,11 @@
100689 ** If an error occurs, return NULL and leave a message in pParse.
100690 */
100691 SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
100692 Vdbe *v = pParse->pVdbe;
100693 if( v==0 ){
100694 v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
100695 #ifndef SQLITE_OMIT_TRACE
100696 if( v ){
100697 sqlite3VdbeAddOp0(v, OP_Trace);
100698 }
100699 #endif
@@ -102947,18 +103010,27 @@
102947 */
102948 static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
102949 Vdbe *v = pParse->pVdbe;
102950 int i;
102951 struct AggInfo_func *pFunc;
102952 if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){
102953 return;
102954 }
 
 
 
102955 for(i=0; i<pAggInfo->nColumn; i++){
102956 sqlite3VdbeAddOp2(v, OP_Null, 0, pAggInfo->aCol[i].iMem);
 
102957 }
 
 
 
 
 
 
102958 for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
102959 sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
102960 if( pFunc->iDistinct>=0 ){
102961 Expr *pE = pFunc->pExpr;
102962 assert( !ExprHasProperty(pE, EP_xIsSelect) );
102963 if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
102964 sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -103000,11 +103072,10 @@
103000 int addrHitTest = 0;
103001 struct AggInfo_func *pF;
103002 struct AggInfo_col *pC;
103003
103004 pAggInfo->directMode = 1;
103005 sqlite3ExprCacheClear(pParse);
103006 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
103007 int nArg;
103008 int addrNext = 0;
103009 int regAgg;
103010 ExprList *pList = pF->pExpr->x.pList;
@@ -103533,10 +103604,11 @@
103533 */
103534 memset(&sNC, 0, sizeof(sNC));
103535 sNC.pParse = pParse;
103536 sNC.pSrcList = pTabList;
103537 sNC.pAggInfo = &sAggInfo;
 
103538 sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
103539 sAggInfo.pGroupBy = pGroupBy;
103540 sqlite3ExprAnalyzeAggList(&sNC, pEList);
103541 sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
103542 if( pHaving ){
@@ -103547,10 +103619,11 @@
103547 assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
103548 sNC.ncFlags |= NC_InAggFunc;
103549 sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
103550 sNC.ncFlags &= ~NC_InAggFunc;
103551 }
 
103552 if( db->mallocFailed ) goto select_end;
103553
103554 /* Processing for aggregates with GROUP BY is very different and
103555 ** much more complex than aggregates without a GROUP BY.
103556 */
@@ -105451,11 +105524,11 @@
105451 pCol->affinity, &pValue);
105452 if( pValue ){
105453 sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
105454 }
105455 #ifndef SQLITE_OMIT_FLOATING_POINT
105456 if( iReg>=0 && pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105457 sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
105458 }
105459 #endif
105460 }
105461 }
@@ -105875,14 +105948,14 @@
105875 ** be used eliminates some redundant opcodes.
105876 */
105877 newmask = sqlite3TriggerColmask(
105878 pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
105879 );
105880 sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);
105881 for(i=0; i<pTab->nCol; i++){
105882 if( i==pTab->iPKey ){
105883 /*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
105884 }else{
105885 j = aXRef[i];
105886 if( j>=0 ){
105887 sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
105888 }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
@@ -105892,10 +105965,12 @@
105892 ** a new.* reference in a trigger program.
105893 */
105894 testcase( i==31 );
105895 testcase( i==32 );
105896 sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
 
 
105897 }
105898 }
105899 }
105900
105901 /* Fire any BEFORE UPDATE triggers. This happens before constraints are
@@ -112004,10 +112079,11 @@
112004 */
112005 if( pTerm==0
112006 && saved_nEq==saved_nSkip
112007 && saved_nEq+1<pProbe->nKeyCol
112008 && pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
 
112009 ){
112010 LogEst nIter;
112011 pNew->u.btree.nEq++;
112012 pNew->u.btree.nSkip++;
112013 pNew->aLTerm[pNew->nLTerm++] = 0;
@@ -119722,12 +119798,11 @@
119722
119723 /*
119724 ** Return a static string containing the name corresponding to the error code
119725 ** specified in the argument.
119726 */
119727 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
119728 defined(SQLITE_DEBUG_OS_TRACE)
119729 SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
119730 const char *zName = 0;
119731 int i, origRc = rc;
119732 for(i=0; i<2 && zName==0; i++, rc &= 0xff){
119733 switch( rc ){
@@ -121300,10 +121375,12 @@
121300 #ifdef SQLITE_DEFAULT_LOCKING_MODE
121301 db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
121302 sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
121303 SQLITE_DEFAULT_LOCKING_MODE);
121304 #endif
 
 
121305
121306 /* Enable the lookaside-malloc subsystem */
121307 setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
121308 sqlite3GlobalConfig.nLookaside);
121309
@@ -131632,61 +131709,74 @@
131632 }
131633
131634 /* Step 2 */
131635 switch( z[1] ){
131636 case 'a':
131637 stem(&z, "lanoita", "ate", m_gt_0) ||
131638 stem(&z, "lanoit", "tion", m_gt_0);
 
131639 break;
131640 case 'c':
131641 stem(&z, "icne", "ence", m_gt_0) ||
131642 stem(&z, "icna", "ance", m_gt_0);
 
131643 break;
131644 case 'e':
131645 stem(&z, "rezi", "ize", m_gt_0);
131646 break;
131647 case 'g':
131648 stem(&z, "igol", "log", m_gt_0);
131649 break;
131650 case 'l':
131651 stem(&z, "ilb", "ble", m_gt_0) ||
131652 stem(&z, "illa", "al", m_gt_0) ||
131653 stem(&z, "iltne", "ent", m_gt_0) ||
131654 stem(&z, "ile", "e", m_gt_0) ||
131655 stem(&z, "ilsuo", "ous", m_gt_0);
 
 
131656 break;
131657 case 'o':
131658 stem(&z, "noitazi", "ize", m_gt_0) ||
131659 stem(&z, "noita", "ate", m_gt_0) ||
131660 stem(&z, "rota", "ate", m_gt_0);
 
 
131661 break;
131662 case 's':
131663 stem(&z, "msila", "al", m_gt_0) ||
131664 stem(&z, "ssenevi", "ive", m_gt_0) ||
131665 stem(&z, "ssenluf", "ful", m_gt_0) ||
131666 stem(&z, "ssensuo", "ous", m_gt_0);
 
 
131667 break;
131668 case 't':
131669 stem(&z, "itila", "al", m_gt_0) ||
131670 stem(&z, "itivi", "ive", m_gt_0) ||
131671 stem(&z, "itilib", "ble", m_gt_0);
 
 
131672 break;
131673 }
131674
131675 /* Step 3 */
131676 switch( z[0] ){
131677 case 'e':
131678 stem(&z, "etaci", "ic", m_gt_0) ||
131679 stem(&z, "evita", "", m_gt_0) ||
131680 stem(&z, "ezila", "al", m_gt_0);
 
 
131681 break;
131682 case 'i':
131683 stem(&z, "itici", "ic", m_gt_0);
131684 break;
131685 case 'l':
131686 stem(&z, "laci", "ic", m_gt_0) ||
131687 stem(&z, "luf", "", m_gt_0);
 
131688 break;
131689 case 's':
131690 stem(&z, "ssen", "", m_gt_0);
131691 break;
131692 }
@@ -131723,13 +131813,15 @@
131723 if( z[2]=='a' ){
131724 if( m_gt_1(z+3) ){
131725 z += 3;
131726 }
131727 }else if( z[2]=='e' ){
131728 stem(&z, "tneme", "", m_gt_1) ||
131729 stem(&z, "tnem", "", m_gt_1) ||
131730 stem(&z, "tne", "", m_gt_1);
 
 
131731 }
131732 }
131733 break;
131734 case 'o':
131735 if( z[0]=='u' ){
@@ -131744,12 +131836,13 @@
131744 if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
131745 z += 3;
131746 }
131747 break;
131748 case 't':
131749 stem(&z, "eta", "", m_gt_1) ||
131750 stem(&z, "iti", "", m_gt_1);
 
131751 break;
131752 case 'u':
131753 if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
131754 z += 3;
131755 }
131756
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -135,11 +135,11 @@
135 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
136 ** [sqlite_version()] and [sqlite_source_id()].
137 */
138 #define SQLITE_VERSION "3.8.3"
139 #define SQLITE_VERSION_NUMBER 3008003
140 #define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d"
141
142 /*
143 ** CAPI3REF: Run-Time Library Version Numbers
144 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
145 **
@@ -9098,11 +9098,11 @@
9098 #define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */
9099 #define OP_Null 26 /* synopsis: r[P2..P3]=NULL */
9100 #define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */
9101 #define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */
9102 #define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */
9103 #define OP_Copy 30 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
9104 #define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */
9105 #define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */
9106 #define OP_CollSeq 33
9107 #define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */
9108 #define OP_MustBeInt 35
@@ -9263,11 +9263,11 @@
9263
9264 /*
9265 ** Prototypes for the VDBE interface. See comments on the implementation
9266 ** for a description of what each of these routines does.
9267 */
9268 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*);
9269 SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
9270 SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
9271 SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
9272 SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
9273 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
@@ -11003,10 +11003,11 @@
11003 u8 useSortingIdx; /* In direct mode, reference the sorting index rather
11004 ** than the source table */
11005 int sortingIdx; /* Cursor number of the sorting index */
11006 int sortingIdxPTab; /* Cursor number of pseudo-table */
11007 int nSortingColumn; /* Number of columns in the sorting index */
11008 int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
11009 ExprList *pGroupBy; /* The group by clause */
11010 struct AggInfo_col { /* For each column used in source tables */
11011 Table *pTab; /* Source table */
11012 int iTable; /* Cursor number of the source table */
11013 int iColumn; /* Column number within the source table */
@@ -12452,12 +12453,11 @@
12453 SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
12454 SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
12455 SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
12456 SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
12457
12458 #if defined(SQLITE_TEST)
 
12459 SQLITE_PRIVATE const char *sqlite3ErrName(int);
12460 #endif
12461
12462 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
12463 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
@@ -13776,10 +13776,13 @@
13776 Op *aOp; /* Space to hold the virtual machine's program */
13777 Mem *aMem; /* The memory locations */
13778 Mem **apArg; /* Arguments to currently executing user function */
13779 Mem *aColName; /* Column names to return */
13780 Mem *pResultSet; /* Pointer to an array of results */
13781 #ifdef SQLITE_DEBUG
13782 Parse *pParse; /* Parsing context used to create this Vdbe */
13783 #endif
13784 int nMem; /* Number of memory locations currently allocated */
13785 int nOp; /* Number of instructions in the program */
13786 int nOpAlloc; /* Number of slots allocated for aOp[] */
13787 int nLabel; /* Number of labels used */
13788 int *aLabel; /* Space to hold the labels */
@@ -15443,11 +15446,25 @@
15446 ** really care if the VFS receives and understands the information since it
15447 ** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
15448 ** routine has no return value since the return value would be meaningless.
15449 */
15450 SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
15451 #ifdef SQLITE_TEST
15452 if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
15453 /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
15454 ** is using a regular VFS, it is called after the corresponding
15455 ** transaction has been committed. Injecting a fault at this point
15456 ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
15457 ** but the transaction is committed anyway.
15458 **
15459 ** The core must call OsFileControl() though, not OsFileControlHint(),
15460 ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
15461 ** means the commit really has failed and an error should be returned
15462 ** to the user. */
15463 DO_OS_MALLOC_TEST(id);
15464 }
15465 #endif
15466 return id->pMethods->xFileControl(id, op, pArg);
15467 }
15468 SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
15469 (void)id->pMethods->xFileControl(id, op, pArg);
15470 }
@@ -23098,11 +23115,11 @@
23115 /* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
23116 /* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
23117 /* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
23118 /* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
23119 /* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
23120 /* 30 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
23121 /* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
23122 /* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"),
23123 /* 33 */ "CollSeq" OpHelp(""),
23124 /* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
23125 /* 35 */ "MustBeInt" OpHelp(""),
@@ -61223,11 +61240,12 @@
61240 */
61241
61242 /*
61243 ** Create a new virtual database engine.
61244 */
61245 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
61246 sqlite3 *db = pParse->db;
61247 Vdbe *p;
61248 p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
61249 if( p==0 ) return 0;
61250 p->db = db;
61251 if( db->pVdbe ){
@@ -61235,10 +61253,13 @@
61253 }
61254 p->pNext = db->pVdbe;
61255 p->pPrev = 0;
61256 db->pVdbe = p;
61257 p->magic = VDBE_MAGIC_INIT;
61258 #if SQLITE_DEBUG
61259 p->pParse = pParse;
61260 #endif
61261 return p;
61262 }
61263
61264 /*
61265 ** Remember the SQL string for a prepared statement.
@@ -61354,10 +61375,19 @@
61375 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
61376 pOp->zComment = 0;
61377 #endif
61378 #ifdef SQLITE_DEBUG
61379 if( p->db->flags & SQLITE_VdbeAddopTrace ){
61380 int jj, kk;
61381 Parse *pParse = p->pParse;
61382 for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
61383 struct yColCache *x = pParse->aColCache + jj;
61384 if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
61385 printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
61386 kk++;
61387 }
61388 if( kk ) printf("\n");
61389 sqlite3VdbePrintOp(0, i, &p->aOp[i]);
61390 test_addop_breakpoint();
61391 }
61392 #endif
61393 #ifdef VDBE_PROFILE
@@ -62075,11 +62105,21 @@
62105 if( c=='4' ) return pOp->p4.i;
62106 return pOp->p5;
62107 }
62108
62109 /*
62110 ** Compute a string for the "comment" field of a VDBE opcode listing.
62111 **
62112 ** The Synopsis: field in comments in the vdbe.c source file gets converted
62113 ** to an extra string that is appended to the sqlite3OpcodeName(). In the
62114 ** absence of other comments, this synopsis becomes the comment on the opcode.
62115 ** Some translation occurs:
62116 **
62117 ** "PX" -> "r[X]"
62118 ** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1
62119 ** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
62120 ** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
62121 */
62122 static int displayComment(
62123 const Op *pOp, /* The opcode to be commented */
62124 const char *zP4, /* Previously obtained value for P4 */
62125 char *zTemp, /* Write result here */
@@ -62109,11 +62149,17 @@
62149 sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
62150 if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
62151 ii += 3;
62152 jj += sqlite3Strlen30(zTemp+jj);
62153 v2 = translateP(zSynopsis[ii], pOp);
62154 if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
62155 ii += 2;
62156 v2++;
62157 }
62158 if( v2>1 ){
62159 sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
62160 }
62161 }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
62162 ii += 4;
62163 }
62164 }
62165 jj += sqlite3Strlen30(zTemp+jj);
@@ -62341,10 +62387,13 @@
62387 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
62388 displayComment(pOp, zP4, zCom, sizeof(zCom));
62389 #else
62390 zCom[0] = 0
62391 #endif
62392 /* NB: The sqlite3OpcodeName() function is implemented by code created
62393 ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
62394 ** information from the vdbe.c source text */
62395 fprintf(pOut, zFormat1, pc,
62396 sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
62397 zCom
62398 );
62399 fflush(pOut);
@@ -67401,11 +67450,11 @@
67450 }while( n-- );
67451 break;
67452 }
67453
67454 /* Opcode: Copy P1 P2 P3 * *
67455 ** Synopsis: r[P2@P3+1]=r[P1@P3+1]
67456 **
67457 ** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
67458 **
67459 ** This instruction makes a deep copy of the value. A duplicate
67460 ** is made of any string or blob constant. See also OP_SCopy.
@@ -68744,11 +68793,11 @@
68793 /* This is the common case where the desired content fits on the original
68794 ** page - where the content is not on an overflow page */
68795 VdbeMemRelease(pDest);
68796 sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
68797 }else{
68798 /* This branch happens only when content is on overflow pages */
68799 t = aType[p2];
68800 if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
68801 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
68802 || (len = sqlite3VdbeSerialTypeLen(t))==0
68803 ){
@@ -72862,11 +72911,11 @@
72911 sqlite3BtreeLeaveAll(db);
72912 goto blob_open_out;
72913 }
72914 }
72915
72916 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
72917 assert( pBlob->pStmt || db->mallocFailed );
72918 if( pBlob->pStmt ){
72919 Vdbe *v = (Vdbe *)pBlob->pStmt;
72920 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
72921
@@ -78416,10 +78465,15 @@
78465 ** added to the column cache after this call are removed when the
78466 ** corresponding pop occurs.
78467 */
78468 SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
78469 pParse->iCacheLevel++;
78470 #ifdef SQLITE_DEBUG
78471 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78472 printf("PUSH to %d\n", pParse->iCacheLevel);
78473 }
78474 #endif
78475 }
78476
78477 /*
78478 ** Remove from the column cache any entries that were added since the
78479 ** the previous N Push operations. In other words, restore the cache
@@ -78429,10 +78483,15 @@
78483 int i;
78484 struct yColCache *p;
78485 assert( N>0 );
78486 assert( pParse->iCacheLevel>=N );
78487 pParse->iCacheLevel -= N;
78488 #ifdef SQLITE_DEBUG
78489 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78490 printf("POP to %d\n", pParse->iCacheLevel);
78491 }
78492 #endif
78493 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78494 if( p->iReg && p->iLevel>pParse->iCacheLevel ){
78495 cacheEntryClear(pParse, p);
78496 p->iReg = 0;
78497 }
@@ -78523,10 +78582,15 @@
78582 */
78583 SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
78584 int i;
78585 struct yColCache *p;
78586
78587 #if SQLITE_DEBUG
78588 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78589 printf("CLEAR\n");
78590 }
78591 #endif
78592 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78593 if( p->iReg ){
78594 cacheEntryClear(pParse, p);
78595 p->iReg = 0;
78596 }
@@ -79659,11 +79723,21 @@
79723 if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
79724 sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
79725 }else{
79726 int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
79727 if( inReg!=target+i ){
79728 VdbeOp *pOp;
79729 Vdbe *v = pParse->pVdbe;
79730 if( copyOp==OP_Copy
79731 && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
79732 && pOp->p1+pOp->p3+1==inReg
79733 && pOp->p2+pOp->p3+1==target+i
79734 ){
79735 pOp->p3++;
79736 }else{
79737 sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
79738 }
79739 }
79740 }
79741 }
79742 return n;
79743 }
@@ -83083,14 +83157,10 @@
83157 {
83158 int rc = SQLITE_OK;
83159 if( pExpr ){
83160 if( pExpr->op!=TK_ID ){
83161 rc = sqlite3ResolveExprNames(pName, pExpr);
 
 
 
 
83162 }else{
83163 pExpr->op = TK_STRING;
83164 }
83165 }
83166 return rc;
@@ -89324,11 +89394,10 @@
89394 Vdbe *v = pParse->pVdbe;
89395 int j;
89396 Table *pTab = pIdx->pTable;
89397 int regBase;
89398 int nCol;
 
89399
89400 if( piPartIdxLabel ){
89401 if( pIdx->pPartIdxWhere ){
89402 *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
89403 pParse->iPartIdxTab = iDataCur;
@@ -89338,20 +89407,13 @@
89407 *piPartIdxLabel = 0;
89408 }
89409 }
89410 nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
89411 regBase = sqlite3GetTempRange(pParse, nCol);
 
89412 for(j=0; j<nCol; j++){
89413 sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
89414 regBase+j);
 
 
 
 
 
 
89415 }
89416 if( regOut ){
89417 const char *zAff;
89418 if( pTab->pSelect
89419 || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
@@ -93982,51 +94044,53 @@
94044 sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
94045 regIdx, pIdx->nKeyCol);
94046
94047 /* Generate code to handle collisions */
94048 regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
94049 if( isUpdate || onError==OE_Replace ){
94050 if( HasRowid(pTab) ){
94051 sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
94052 /* Conflict only if the rowid of the existing index entry
94053 ** is different from old-rowid */
94054 if( isUpdate ){
94055 sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
94056 }
94057 }else{
94058 int x;
94059 /* Extract the PRIMARY KEY from the end of the index entry and
94060 ** store it in registers regR..regR+nPk-1 */
94061 if( pIdx!=pPk ){
94062 for(i=0; i<pPk->nKeyCol; i++){
94063 x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94064 sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94065 VdbeComment((v, "%s.%s", pTab->zName,
94066 pTab->aCol[pPk->aiColumn[i]].zName));
94067 }
94068 }
94069 if( isUpdate ){
94070 /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94071 ** table, only conflict if the new PRIMARY KEY values are actually
94072 ** different from the old.
94073 **
94074 ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94075 ** of the matched index row are different from the original PRIMARY
94076 ** KEY values of this row before the update. */
94077 int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94078 int op = OP_Ne;
94079 int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94080
94081 for(i=0; i<pPk->nKeyCol; i++){
94082 char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94083 x = pPk->aiColumn[i];
94084 if( i==(pPk->nKeyCol-1) ){
94085 addrJump = addrUniqueOk;
94086 op = OP_Eq;
94087 }
94088 sqlite3VdbeAddOp4(v, op,
94089 regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94090 );
94091 }
94092 }
94093 }
94094 }
94095
94096 /* Generate code that executes if the new index entry is not unique */
@@ -99722,11 +99786,10 @@
99786 }
99787 }else if( eDest!=SRT_Exists ){
99788 /* If the destination is an EXISTS(...) expression, the actual
99789 ** values returned by the SELECT are not required.
99790 */
 
99791 sqlite3ExprCodeExprList(pParse, pEList, regResult,
99792 (eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
99793 }
99794 nColumn = nResultCol;
99795
@@ -100689,11 +100752,11 @@
100752 ** If an error occurs, return NULL and leave a message in pParse.
100753 */
100754 SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
100755 Vdbe *v = pParse->pVdbe;
100756 if( v==0 ){
100757 v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
100758 #ifndef SQLITE_OMIT_TRACE
100759 if( v ){
100760 sqlite3VdbeAddOp0(v, OP_Trace);
100761 }
100762 #endif
@@ -102947,18 +103010,27 @@
103010 */
103011 static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
103012 Vdbe *v = pParse->pVdbe;
103013 int i;
103014 struct AggInfo_func *pFunc;
103015 int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
103016 if( nReg==0 ) return;
103017 #ifdef SQLITE_DEBUG
103018 /* Verify that all AggInfo registers are within the range specified by
103019 ** AggInfo.mnReg..AggInfo.mxReg */
103020 assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
103021 for(i=0; i<pAggInfo->nColumn; i++){
103022 assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
103023 && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
103024 }
103025 for(i=0; i<pAggInfo->nFunc; i++){
103026 assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
103027 && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
103028 }
103029 #endif
103030 sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
103031 for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
 
103032 if( pFunc->iDistinct>=0 ){
103033 Expr *pE = pFunc->pExpr;
103034 assert( !ExprHasProperty(pE, EP_xIsSelect) );
103035 if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
103036 sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -103000,11 +103072,10 @@
103072 int addrHitTest = 0;
103073 struct AggInfo_func *pF;
103074 struct AggInfo_col *pC;
103075
103076 pAggInfo->directMode = 1;
 
103077 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
103078 int nArg;
103079 int addrNext = 0;
103080 int regAgg;
103081 ExprList *pList = pF->pExpr->x.pList;
@@ -103533,10 +103604,11 @@
103604 */
103605 memset(&sNC, 0, sizeof(sNC));
103606 sNC.pParse = pParse;
103607 sNC.pSrcList = pTabList;
103608 sNC.pAggInfo = &sAggInfo;
103609 sAggInfo.mnReg = pParse->nMem+1;
103610 sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
103611 sAggInfo.pGroupBy = pGroupBy;
103612 sqlite3ExprAnalyzeAggList(&sNC, pEList);
103613 sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
103614 if( pHaving ){
@@ -103547,10 +103619,11 @@
103619 assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
103620 sNC.ncFlags |= NC_InAggFunc;
103621 sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
103622 sNC.ncFlags &= ~NC_InAggFunc;
103623 }
103624 sAggInfo.mxReg = pParse->nMem;
103625 if( db->mallocFailed ) goto select_end;
103626
103627 /* Processing for aggregates with GROUP BY is very different and
103628 ** much more complex than aggregates without a GROUP BY.
103629 */
@@ -105451,11 +105524,11 @@
105524 pCol->affinity, &pValue);
105525 if( pValue ){
105526 sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
105527 }
105528 #ifndef SQLITE_OMIT_FLOATING_POINT
105529 if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105530 sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
105531 }
105532 #endif
105533 }
105534 }
@@ -105875,14 +105948,14 @@
105948 ** be used eliminates some redundant opcodes.
105949 */
105950 newmask = sqlite3TriggerColmask(
105951 pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
105952 );
105953 /*sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);*/
105954 for(i=0; i<pTab->nCol; i++){
105955 if( i==pTab->iPKey ){
105956 sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105957 }else{
105958 j = aXRef[i];
105959 if( j>=0 ){
105960 sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
105961 }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
@@ -105892,10 +105965,12 @@
105965 ** a new.* reference in a trigger program.
105966 */
105967 testcase( i==31 );
105968 testcase( i==32 );
105969 sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
105970 }else{
105971 sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105972 }
105973 }
105974 }
105975
105976 /* Fire any BEFORE UPDATE triggers. This happens before constraints are
@@ -112004,10 +112079,11 @@
112079 */
112080 if( pTerm==0
112081 && saved_nEq==saved_nSkip
112082 && saved_nEq+1<pProbe->nKeyCol
112083 && pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
112084 && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
112085 ){
112086 LogEst nIter;
112087 pNew->u.btree.nEq++;
112088 pNew->u.btree.nSkip++;
112089 pNew->aLTerm[pNew->nLTerm++] = 0;
@@ -119722,12 +119798,11 @@
119798
119799 /*
119800 ** Return a static string containing the name corresponding to the error code
119801 ** specified in the argument.
119802 */
119803 #if defined(SQLITE_TEST)
 
119804 SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
119805 const char *zName = 0;
119806 int i, origRc = rc;
119807 for(i=0; i<2 && zName==0; i++, rc &= 0xff){
119808 switch( rc ){
@@ -121300,10 +121375,12 @@
121375 #ifdef SQLITE_DEFAULT_LOCKING_MODE
121376 db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
121377 sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
121378 SQLITE_DEFAULT_LOCKING_MODE);
121379 #endif
121380
121381 if( rc ) sqlite3Error(db, rc, 0);
121382
121383 /* Enable the lookaside-malloc subsystem */
121384 setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
121385 sqlite3GlobalConfig.nLookaside);
121386
@@ -131632,61 +131709,74 @@
131709 }
131710
131711 /* Step 2 */
131712 switch( z[1] ){
131713 case 'a':
131714 if( !stem(&z, "lanoita", "ate", m_gt_0) ){
131715 stem(&z, "lanoit", "tion", m_gt_0);
131716 }
131717 break;
131718 case 'c':
131719 if( !stem(&z, "icne", "ence", m_gt_0) ){
131720 stem(&z, "icna", "ance", m_gt_0);
131721 }
131722 break;
131723 case 'e':
131724 stem(&z, "rezi", "ize", m_gt_0);
131725 break;
131726 case 'g':
131727 stem(&z, "igol", "log", m_gt_0);
131728 break;
131729 case 'l':
131730 if( !stem(&z, "ilb", "ble", m_gt_0)
131731 && !stem(&z, "illa", "al", m_gt_0)
131732 && !stem(&z, "iltne", "ent", m_gt_0)
131733 && !stem(&z, "ile", "e", m_gt_0)
131734 ){
131735 stem(&z, "ilsuo", "ous", m_gt_0);
131736 }
131737 break;
131738 case 'o':
131739 if( !stem(&z, "noitazi", "ize", m_gt_0)
131740 && !stem(&z, "noita", "ate", m_gt_0)
131741 ){
131742 stem(&z, "rota", "ate", m_gt_0);
131743 }
131744 break;
131745 case 's':
131746 if( !stem(&z, "msila", "al", m_gt_0)
131747 && !stem(&z, "ssenevi", "ive", m_gt_0)
131748 && !stem(&z, "ssenluf", "ful", m_gt_0)
131749 ){
131750 stem(&z, "ssensuo", "ous", m_gt_0);
131751 }
131752 break;
131753 case 't':
131754 if( !stem(&z, "itila", "al", m_gt_0)
131755 && !stem(&z, "itivi", "ive", m_gt_0)
131756 ){
131757 stem(&z, "itilib", "ble", m_gt_0);
131758 }
131759 break;
131760 }
131761
131762 /* Step 3 */
131763 switch( z[0] ){
131764 case 'e':
131765 if( !stem(&z, "etaci", "ic", m_gt_0)
131766 && !stem(&z, "evita", "", m_gt_0)
131767 ){
131768 stem(&z, "ezila", "al", m_gt_0);
131769 }
131770 break;
131771 case 'i':
131772 stem(&z, "itici", "ic", m_gt_0);
131773 break;
131774 case 'l':
131775 if( !stem(&z, "laci", "ic", m_gt_0) ){
131776 stem(&z, "luf", "", m_gt_0);
131777 }
131778 break;
131779 case 's':
131780 stem(&z, "ssen", "", m_gt_0);
131781 break;
131782 }
@@ -131723,13 +131813,15 @@
131813 if( z[2]=='a' ){
131814 if( m_gt_1(z+3) ){
131815 z += 3;
131816 }
131817 }else if( z[2]=='e' ){
131818 if( !stem(&z, "tneme", "", m_gt_1)
131819 && !stem(&z, "tnem", "", m_gt_1)
131820 ){
131821 stem(&z, "tne", "", m_gt_1);
131822 }
131823 }
131824 }
131825 break;
131826 case 'o':
131827 if( z[0]=='u' ){
@@ -131744,12 +131836,13 @@
131836 if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
131837 z += 3;
131838 }
131839 break;
131840 case 't':
131841 if( !stem(&z, "eta", "", m_gt_1) ){
131842 stem(&z, "iti", "", m_gt_1);
131843 }
131844 break;
131845 case 'u':
131846 if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
131847 z += 3;
131848 }
131849
+204 -111
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -135,11 +135,11 @@
135135
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
136136
** [sqlite_version()] and [sqlite_source_id()].
137137
*/
138138
#define SQLITE_VERSION "3.8.3"
139139
#define SQLITE_VERSION_NUMBER 3008003
140
-#define SQLITE_SOURCE_ID "2013-12-17 16:32:56 93121d3097a43997af3c0de65bd9bd7663845fa2"
140
+#define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d"
141141
142142
/*
143143
** CAPI3REF: Run-Time Library Version Numbers
144144
** KEYWORDS: sqlite3_version, sqlite3_sourceid
145145
**
@@ -9098,11 +9098,11 @@
90989098
#define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */
90999099
#define OP_Null 26 /* synopsis: r[P2..P3]=NULL */
91009100
#define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */
91019101
#define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */
91029102
#define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */
9103
-#define OP_Copy 30 /* synopsis: r[P2@P3]=r[P1@P3] */
9103
+#define OP_Copy 30 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
91049104
#define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */
91059105
#define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */
91069106
#define OP_CollSeq 33
91079107
#define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */
91089108
#define OP_MustBeInt 35
@@ -9263,11 +9263,11 @@
92639263
92649264
/*
92659265
** Prototypes for the VDBE interface. See comments on the implementation
92669266
** for a description of what each of these routines does.
92679267
*/
9268
-SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*);
9268
+SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*);
92699269
SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
92709270
SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
92719271
SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
92729272
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
92739273
SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
@@ -11003,10 +11003,11 @@
1100311003
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
1100411004
** than the source table */
1100511005
int sortingIdx; /* Cursor number of the sorting index */
1100611006
int sortingIdxPTab; /* Cursor number of pseudo-table */
1100711007
int nSortingColumn; /* Number of columns in the sorting index */
11008
+ int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
1100811009
ExprList *pGroupBy; /* The group by clause */
1100911010
struct AggInfo_col { /* For each column used in source tables */
1101011011
Table *pTab; /* Source table */
1101111012
int iTable; /* Cursor number of the source table */
1101211013
int iColumn; /* Column number within the source table */
@@ -12452,12 +12453,11 @@
1245212453
SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
1245312454
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
1245412455
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
1245512456
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
1245612457
12457
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
12458
- defined(SQLITE_DEBUG_OS_TRACE)
12458
+#if defined(SQLITE_TEST)
1245912459
SQLITE_PRIVATE const char *sqlite3ErrName(int);
1246012460
#endif
1246112461
1246212462
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
1246312463
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
@@ -13776,10 +13776,13 @@
1377613776
Op *aOp; /* Space to hold the virtual machine's program */
1377713777
Mem *aMem; /* The memory locations */
1377813778
Mem **apArg; /* Arguments to currently executing user function */
1377913779
Mem *aColName; /* Column names to return */
1378013780
Mem *pResultSet; /* Pointer to an array of results */
13781
+#ifdef SQLITE_DEBUG
13782
+ Parse *pParse; /* Parsing context used to create this Vdbe */
13783
+#endif
1378113784
int nMem; /* Number of memory locations currently allocated */
1378213785
int nOp; /* Number of instructions in the program */
1378313786
int nOpAlloc; /* Number of slots allocated for aOp[] */
1378413787
int nLabel; /* Number of labels used */
1378513788
int *aLabel; /* Space to hold the labels */
@@ -15443,11 +15446,25 @@
1544315446
** really care if the VFS receives and understands the information since it
1544415447
** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
1544515448
** routine has no return value since the return value would be meaningless.
1544615449
*/
1544715450
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
15448
- DO_OS_MALLOC_TEST(id);
15451
+#ifdef SQLITE_TEST
15452
+ if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
15453
+ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
15454
+ ** is using a regular VFS, it is called after the corresponding
15455
+ ** transaction has been committed. Injecting a fault at this point
15456
+ ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
15457
+ ** but the transaction is committed anyway.
15458
+ **
15459
+ ** The core must call OsFileControl() though, not OsFileControlHint(),
15460
+ ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
15461
+ ** means the commit really has failed and an error should be returned
15462
+ ** to the user. */
15463
+ DO_OS_MALLOC_TEST(id);
15464
+ }
15465
+#endif
1544915466
return id->pMethods->xFileControl(id, op, pArg);
1545015467
}
1545115468
SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
1545215469
(void)id->pMethods->xFileControl(id, op, pArg);
1545315470
}
@@ -23098,11 +23115,11 @@
2309823115
/* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
2309923116
/* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
2310023117
/* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
2310123118
/* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
2310223119
/* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
23103
- /* 30 */ "Copy" OpHelp("r[P2@P3]=r[P1@P3]"),
23120
+ /* 30 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
2310423121
/* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
2310523122
/* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"),
2310623123
/* 33 */ "CollSeq" OpHelp(""),
2310723124
/* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
2310823125
/* 35 */ "MustBeInt" OpHelp(""),
@@ -61223,11 +61240,12 @@
6122361240
*/
6122461241
6122561242
/*
6122661243
** Create a new virtual database engine.
6122761244
*/
61228
-SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
61245
+SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
61246
+ sqlite3 *db = pParse->db;
6122961247
Vdbe *p;
6123061248
p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
6123161249
if( p==0 ) return 0;
6123261250
p->db = db;
6123361251
if( db->pVdbe ){
@@ -61235,10 +61253,13 @@
6123561253
}
6123661254
p->pNext = db->pVdbe;
6123761255
p->pPrev = 0;
6123861256
db->pVdbe = p;
6123961257
p->magic = VDBE_MAGIC_INIT;
61258
+#if SQLITE_DEBUG
61259
+ p->pParse = pParse;
61260
+#endif
6124061261
return p;
6124161262
}
6124261263
6124361264
/*
6124461265
** Remember the SQL string for a prepared statement.
@@ -61354,10 +61375,19 @@
6135461375
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
6135561376
pOp->zComment = 0;
6135661377
#endif
6135761378
#ifdef SQLITE_DEBUG
6135861379
if( p->db->flags & SQLITE_VdbeAddopTrace ){
61380
+ int jj, kk;
61381
+ Parse *pParse = p->pParse;
61382
+ for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
61383
+ struct yColCache *x = pParse->aColCache + jj;
61384
+ if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
61385
+ printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
61386
+ kk++;
61387
+ }
61388
+ if( kk ) printf("\n");
6135961389
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
6136061390
test_addop_breakpoint();
6136161391
}
6136261392
#endif
6136361393
#ifdef VDBE_PROFILE
@@ -62075,11 +62105,21 @@
6207562105
if( c=='4' ) return pOp->p4.i;
6207662106
return pOp->p5;
6207762107
}
6207862108
6207962109
/*
62080
-** Compute a string for the "comment" field of a VDBE opcode listing
62110
+** Compute a string for the "comment" field of a VDBE opcode listing.
62111
+**
62112
+** The Synopsis: field in comments in the vdbe.c source file gets converted
62113
+** to an extra string that is appended to the sqlite3OpcodeName(). In the
62114
+** absence of other comments, this synopsis becomes the comment on the opcode.
62115
+** Some translation occurs:
62116
+**
62117
+** "PX" -> "r[X]"
62118
+** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1
62119
+** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
62120
+** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
6208162121
*/
6208262122
static int displayComment(
6208362123
const Op *pOp, /* The opcode to be commented */
6208462124
const char *zP4, /* Previously obtained value for P4 */
6208562125
char *zTemp, /* Write result here */
@@ -62109,11 +62149,17 @@
6210962149
sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
6211062150
if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
6211162151
ii += 3;
6211262152
jj += sqlite3Strlen30(zTemp+jj);
6211362153
v2 = translateP(zSynopsis[ii], pOp);
62114
- if( v2>1 ) sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
62154
+ if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
62155
+ ii += 2;
62156
+ v2++;
62157
+ }
62158
+ if( v2>1 ){
62159
+ sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
62160
+ }
6211562161
}else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
6211662162
ii += 4;
6211762163
}
6211862164
}
6211962165
jj += sqlite3Strlen30(zTemp+jj);
@@ -62341,10 +62387,13 @@
6234162387
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
6234262388
displayComment(pOp, zP4, zCom, sizeof(zCom));
6234362389
#else
6234462390
zCom[0] = 0
6234562391
#endif
62392
+ /* NB: The sqlite3OpcodeName() function is implemented by code created
62393
+ ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
62394
+ ** information from the vdbe.c source text */
6234662395
fprintf(pOut, zFormat1, pc,
6234762396
sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
6234862397
zCom
6234962398
);
6235062399
fflush(pOut);
@@ -67401,11 +67450,11 @@
6740167450
}while( n-- );
6740267451
break;
6740367452
}
6740467453
6740567454
/* Opcode: Copy P1 P2 P3 * *
67406
-** Synopsis: r[P2@P3]=r[P1@P3]
67455
+** Synopsis: r[P2@P3+1]=r[P1@P3+1]
6740767456
**
6740867457
** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
6740967458
**
6741067459
** This instruction makes a deep copy of the value. A duplicate
6741167460
** is made of any string or blob constant. See also OP_SCopy.
@@ -68744,11 +68793,11 @@
6874468793
/* This is the common case where the desired content fits on the original
6874568794
** page - where the content is not on an overflow page */
6874668795
VdbeMemRelease(pDest);
6874768796
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
6874868797
}else{
68749
- /* This branch happens only when content is on overflow pages */
68798
+ /* This branch happens only when content is on overflow pages */
6875068799
t = aType[p2];
6875168800
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
6875268801
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
6875368802
|| (len = sqlite3VdbeSerialTypeLen(t))==0
6875468803
){
@@ -72862,11 +72911,11 @@
7286272911
sqlite3BtreeLeaveAll(db);
7286372912
goto blob_open_out;
7286472913
}
7286572914
}
7286672915
72867
- pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db);
72916
+ pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
7286872917
assert( pBlob->pStmt || db->mallocFailed );
7286972918
if( pBlob->pStmt ){
7287072919
Vdbe *v = (Vdbe *)pBlob->pStmt;
7287172920
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
7287272921
@@ -78416,10 +78465,15 @@
7841678465
** added to the column cache after this call are removed when the
7841778466
** corresponding pop occurs.
7841878467
*/
7841978468
SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
7842078469
pParse->iCacheLevel++;
78470
+#ifdef SQLITE_DEBUG
78471
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78472
+ printf("PUSH to %d\n", pParse->iCacheLevel);
78473
+ }
78474
+#endif
7842178475
}
7842278476
7842378477
/*
7842478478
** Remove from the column cache any entries that were added since the
7842578479
** the previous N Push operations. In other words, restore the cache
@@ -78429,10 +78483,15 @@
7842978483
int i;
7843078484
struct yColCache *p;
7843178485
assert( N>0 );
7843278486
assert( pParse->iCacheLevel>=N );
7843378487
pParse->iCacheLevel -= N;
78488
+#ifdef SQLITE_DEBUG
78489
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78490
+ printf("POP to %d\n", pParse->iCacheLevel);
78491
+ }
78492
+#endif
7843478493
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
7843578494
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
7843678495
cacheEntryClear(pParse, p);
7843778496
p->iReg = 0;
7843878497
}
@@ -78523,10 +78582,15 @@
7852378582
*/
7852478583
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
7852578584
int i;
7852678585
struct yColCache *p;
7852778586
78587
+#if SQLITE_DEBUG
78588
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78589
+ printf("CLEAR\n");
78590
+ }
78591
+#endif
7852878592
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
7852978593
if( p->iReg ){
7853078594
cacheEntryClear(pParse, p);
7853178595
p->iReg = 0;
7853278596
}
@@ -79659,11 +79723,21 @@
7965979723
if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
7966079724
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
7966179725
}else{
7966279726
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
7966379727
if( inReg!=target+i ){
79664
- sqlite3VdbeAddOp2(pParse->pVdbe, copyOp, inReg, target+i);
79728
+ VdbeOp *pOp;
79729
+ Vdbe *v = pParse->pVdbe;
79730
+ if( copyOp==OP_Copy
79731
+ && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
79732
+ && pOp->p1+pOp->p3+1==inReg
79733
+ && pOp->p2+pOp->p3+1==target+i
79734
+ ){
79735
+ pOp->p3++;
79736
+ }else{
79737
+ sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
79738
+ }
7966579739
}
7966679740
}
7966779741
}
7966879742
return n;
7966979743
}
@@ -83083,14 +83157,10 @@
8308383157
{
8308483158
int rc = SQLITE_OK;
8308583159
if( pExpr ){
8308683160
if( pExpr->op!=TK_ID ){
8308783161
rc = sqlite3ResolveExprNames(pName, pExpr);
83088
- if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
83089
- sqlite3ErrorMsg(pName->pParse, "invalid name: \"%s\"", pExpr->u.zToken);
83090
- return SQLITE_ERROR;
83091
- }
8309283162
}else{
8309383163
pExpr->op = TK_STRING;
8309483164
}
8309583165
}
8309683166
return rc;
@@ -89324,11 +89394,10 @@
8932489394
Vdbe *v = pParse->pVdbe;
8932589395
int j;
8932689396
Table *pTab = pIdx->pTable;
8932789397
int regBase;
8932889398
int nCol;
89329
- Index *pPk;
8933089399
8933189400
if( piPartIdxLabel ){
8933289401
if( pIdx->pPartIdxWhere ){
8933389402
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
8933489403
pParse->iPartIdxTab = iDataCur;
@@ -89338,20 +89407,13 @@
8933889407
*piPartIdxLabel = 0;
8933989408
}
8934089409
}
8934189410
nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
8934289411
regBase = sqlite3GetTempRange(pParse, nCol);
89343
- pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
8934489412
for(j=0; j<nCol; j++){
89345
- i16 idx = pIdx->aiColumn[j];
89346
- if( pPk ) idx = sqlite3ColumnOfIndex(pPk, idx);
89347
- if( idx<0 || idx==pTab->iPKey ){
89348
- sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regBase+j);
89349
- }else{
89350
- sqlite3VdbeAddOp3(v, OP_Column, iDataCur, idx, regBase+j);
89351
- sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[j], -1);
89352
- }
89413
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
89414
+ regBase+j);
8935389415
}
8935489416
if( regOut ){
8935589417
const char *zAff;
8935689418
if( pTab->pSelect
8935789419
|| OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
@@ -93982,51 +94044,53 @@
9398294044
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
9398394045
regIdx, pIdx->nKeyCol);
9398494046
9398594047
/* Generate code to handle collisions */
9398694048
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
93987
- if( HasRowid(pTab) ){
93988
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
93989
- /* Conflict only if the rowid of the existing index entry
93990
- ** is different from old-rowid */
93991
- if( isUpdate ){
93992
- sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
93993
- }
93994
- }else{
93995
- int x;
93996
- /* Extract the PRIMARY KEY from the end of the index entry and
93997
- ** store it in registers regR..regR+nPk-1 */
93998
- if( (isUpdate || onError==OE_Replace) && pIdx!=pPk ){
93999
- for(i=0; i<pPk->nKeyCol; i++){
94000
- x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94001
- sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94002
- VdbeComment((v, "%s.%s", pTab->zName,
94003
- pTab->aCol[pPk->aiColumn[i]].zName));
94004
- }
94005
- }
94006
- if( isUpdate ){
94007
- /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94008
- ** table, only conflict if the new PRIMARY KEY values are actually
94009
- ** different from the old.
94010
- **
94011
- ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94012
- ** of the matched index row are different from the original PRIMARY
94013
- ** KEY values of this row before the update. */
94014
- int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94015
- int op = OP_Ne;
94016
- int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94017
-
94018
- for(i=0; i<pPk->nKeyCol; i++){
94019
- char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94020
- x = pPk->aiColumn[i];
94021
- if( i==(pPk->nKeyCol-1) ){
94022
- addrJump = addrUniqueOk;
94023
- op = OP_Eq;
94024
- }
94025
- sqlite3VdbeAddOp4(v, op,
94026
- regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94027
- );
94049
+ if( isUpdate || onError==OE_Replace ){
94050
+ if( HasRowid(pTab) ){
94051
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
94052
+ /* Conflict only if the rowid of the existing index entry
94053
+ ** is different from old-rowid */
94054
+ if( isUpdate ){
94055
+ sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
94056
+ }
94057
+ }else{
94058
+ int x;
94059
+ /* Extract the PRIMARY KEY from the end of the index entry and
94060
+ ** store it in registers regR..regR+nPk-1 */
94061
+ if( pIdx!=pPk ){
94062
+ for(i=0; i<pPk->nKeyCol; i++){
94063
+ x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94064
+ sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94065
+ VdbeComment((v, "%s.%s", pTab->zName,
94066
+ pTab->aCol[pPk->aiColumn[i]].zName));
94067
+ }
94068
+ }
94069
+ if( isUpdate ){
94070
+ /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94071
+ ** table, only conflict if the new PRIMARY KEY values are actually
94072
+ ** different from the old.
94073
+ **
94074
+ ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94075
+ ** of the matched index row are different from the original PRIMARY
94076
+ ** KEY values of this row before the update. */
94077
+ int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94078
+ int op = OP_Ne;
94079
+ int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94080
+
94081
+ for(i=0; i<pPk->nKeyCol; i++){
94082
+ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94083
+ x = pPk->aiColumn[i];
94084
+ if( i==(pPk->nKeyCol-1) ){
94085
+ addrJump = addrUniqueOk;
94086
+ op = OP_Eq;
94087
+ }
94088
+ sqlite3VdbeAddOp4(v, op,
94089
+ regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94090
+ );
94091
+ }
9402894092
}
9402994093
}
9403094094
}
9403194095
9403294096
/* Generate code that executes if the new index entry is not unique */
@@ -99722,11 +99786,10 @@
9972299786
}
9972399787
}else if( eDest!=SRT_Exists ){
9972499788
/* If the destination is an EXISTS(...) expression, the actual
9972599789
** values returned by the SELECT are not required.
9972699790
*/
99727
- sqlite3ExprCacheClear(pParse);
9972899791
sqlite3ExprCodeExprList(pParse, pEList, regResult,
9972999792
(eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
9973099793
}
9973199794
nColumn = nResultCol;
9973299795
@@ -100689,11 +100752,11 @@
100689100752
** If an error occurs, return NULL and leave a message in pParse.
100690100753
*/
100691100754
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
100692100755
Vdbe *v = pParse->pVdbe;
100693100756
if( v==0 ){
100694
- v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
100757
+ v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
100695100758
#ifndef SQLITE_OMIT_TRACE
100696100759
if( v ){
100697100760
sqlite3VdbeAddOp0(v, OP_Trace);
100698100761
}
100699100762
#endif
@@ -102947,18 +103010,27 @@
102947103010
*/
102948103011
static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
102949103012
Vdbe *v = pParse->pVdbe;
102950103013
int i;
102951103014
struct AggInfo_func *pFunc;
102952
- if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){
102953
- return;
102954
- }
103015
+ int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
103016
+ if( nReg==0 ) return;
103017
+#ifdef SQLITE_DEBUG
103018
+ /* Verify that all AggInfo registers are within the range specified by
103019
+ ** AggInfo.mnReg..AggInfo.mxReg */
103020
+ assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
102955103021
for(i=0; i<pAggInfo->nColumn; i++){
102956
- sqlite3VdbeAddOp2(v, OP_Null, 0, pAggInfo->aCol[i].iMem);
103022
+ assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
103023
+ && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
102957103024
}
103025
+ for(i=0; i<pAggInfo->nFunc; i++){
103026
+ assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
103027
+ && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
103028
+ }
103029
+#endif
103030
+ sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
102958103031
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
102959
- sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
102960103032
if( pFunc->iDistinct>=0 ){
102961103033
Expr *pE = pFunc->pExpr;
102962103034
assert( !ExprHasProperty(pE, EP_xIsSelect) );
102963103035
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
102964103036
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -103000,11 +103072,10 @@
103000103072
int addrHitTest = 0;
103001103073
struct AggInfo_func *pF;
103002103074
struct AggInfo_col *pC;
103003103075
103004103076
pAggInfo->directMode = 1;
103005
- sqlite3ExprCacheClear(pParse);
103006103077
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
103007103078
int nArg;
103008103079
int addrNext = 0;
103009103080
int regAgg;
103010103081
ExprList *pList = pF->pExpr->x.pList;
@@ -103533,10 +103604,11 @@
103533103604
*/
103534103605
memset(&sNC, 0, sizeof(sNC));
103535103606
sNC.pParse = pParse;
103536103607
sNC.pSrcList = pTabList;
103537103608
sNC.pAggInfo = &sAggInfo;
103609
+ sAggInfo.mnReg = pParse->nMem+1;
103538103610
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
103539103611
sAggInfo.pGroupBy = pGroupBy;
103540103612
sqlite3ExprAnalyzeAggList(&sNC, pEList);
103541103613
sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
103542103614
if( pHaving ){
@@ -103547,10 +103619,11 @@
103547103619
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
103548103620
sNC.ncFlags |= NC_InAggFunc;
103549103621
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
103550103622
sNC.ncFlags &= ~NC_InAggFunc;
103551103623
}
103624
+ sAggInfo.mxReg = pParse->nMem;
103552103625
if( db->mallocFailed ) goto select_end;
103553103626
103554103627
/* Processing for aggregates with GROUP BY is very different and
103555103628
** much more complex than aggregates without a GROUP BY.
103556103629
*/
@@ -105451,11 +105524,11 @@
105451105524
pCol->affinity, &pValue);
105452105525
if( pValue ){
105453105526
sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
105454105527
}
105455105528
#ifndef SQLITE_OMIT_FLOATING_POINT
105456
- if( iReg>=0 && pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105529
+ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105457105530
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
105458105531
}
105459105532
#endif
105460105533
}
105461105534
}
@@ -105875,14 +105948,14 @@
105875105948
** be used eliminates some redundant opcodes.
105876105949
*/
105877105950
newmask = sqlite3TriggerColmask(
105878105951
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
105879105952
);
105880
- sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);
105953
+ /*sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);*/
105881105954
for(i=0; i<pTab->nCol; i++){
105882105955
if( i==pTab->iPKey ){
105883
- /*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
105956
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105884105957
}else{
105885105958
j = aXRef[i];
105886105959
if( j>=0 ){
105887105960
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
105888105961
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
@@ -105892,10 +105965,12 @@
105892105965
** a new.* reference in a trigger program.
105893105966
*/
105894105967
testcase( i==31 );
105895105968
testcase( i==32 );
105896105969
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
105970
+ }else{
105971
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105897105972
}
105898105973
}
105899105974
}
105900105975
105901105976
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
@@ -112004,10 +112079,11 @@
112004112079
*/
112005112080
if( pTerm==0
112006112081
&& saved_nEq==saved_nSkip
112007112082
&& saved_nEq+1<pProbe->nKeyCol
112008112083
&& pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
112084
+ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
112009112085
){
112010112086
LogEst nIter;
112011112087
pNew->u.btree.nEq++;
112012112088
pNew->u.btree.nSkip++;
112013112089
pNew->aLTerm[pNew->nLTerm++] = 0;
@@ -119722,12 +119798,11 @@
119722119798
119723119799
/*
119724119800
** Return a static string containing the name corresponding to the error code
119725119801
** specified in the argument.
119726119802
*/
119727
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
119728
- defined(SQLITE_DEBUG_OS_TRACE)
119803
+#if defined(SQLITE_TEST)
119729119804
SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
119730119805
const char *zName = 0;
119731119806
int i, origRc = rc;
119732119807
for(i=0; i<2 && zName==0; i++, rc &= 0xff){
119733119808
switch( rc ){
@@ -121300,10 +121375,12 @@
121300121375
#ifdef SQLITE_DEFAULT_LOCKING_MODE
121301121376
db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
121302121377
sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
121303121378
SQLITE_DEFAULT_LOCKING_MODE);
121304121379
#endif
121380
+
121381
+ if( rc ) sqlite3Error(db, rc, 0);
121305121382
121306121383
/* Enable the lookaside-malloc subsystem */
121307121384
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
121308121385
sqlite3GlobalConfig.nLookaside);
121309121386
@@ -131632,61 +131709,74 @@
131632131709
}
131633131710
131634131711
/* Step 2 */
131635131712
switch( z[1] ){
131636131713
case 'a':
131637
- stem(&z, "lanoita", "ate", m_gt_0) ||
131638
- stem(&z, "lanoit", "tion", m_gt_0);
131714
+ if( !stem(&z, "lanoita", "ate", m_gt_0) ){
131715
+ stem(&z, "lanoit", "tion", m_gt_0);
131716
+ }
131639131717
break;
131640131718
case 'c':
131641
- stem(&z, "icne", "ence", m_gt_0) ||
131642
- stem(&z, "icna", "ance", m_gt_0);
131719
+ if( !stem(&z, "icne", "ence", m_gt_0) ){
131720
+ stem(&z, "icna", "ance", m_gt_0);
131721
+ }
131643131722
break;
131644131723
case 'e':
131645131724
stem(&z, "rezi", "ize", m_gt_0);
131646131725
break;
131647131726
case 'g':
131648131727
stem(&z, "igol", "log", m_gt_0);
131649131728
break;
131650131729
case 'l':
131651
- stem(&z, "ilb", "ble", m_gt_0) ||
131652
- stem(&z, "illa", "al", m_gt_0) ||
131653
- stem(&z, "iltne", "ent", m_gt_0) ||
131654
- stem(&z, "ile", "e", m_gt_0) ||
131655
- stem(&z, "ilsuo", "ous", m_gt_0);
131730
+ if( !stem(&z, "ilb", "ble", m_gt_0)
131731
+ && !stem(&z, "illa", "al", m_gt_0)
131732
+ && !stem(&z, "iltne", "ent", m_gt_0)
131733
+ && !stem(&z, "ile", "e", m_gt_0)
131734
+ ){
131735
+ stem(&z, "ilsuo", "ous", m_gt_0);
131736
+ }
131656131737
break;
131657131738
case 'o':
131658
- stem(&z, "noitazi", "ize", m_gt_0) ||
131659
- stem(&z, "noita", "ate", m_gt_0) ||
131660
- stem(&z, "rota", "ate", m_gt_0);
131739
+ if( !stem(&z, "noitazi", "ize", m_gt_0)
131740
+ && !stem(&z, "noita", "ate", m_gt_0)
131741
+ ){
131742
+ stem(&z, "rota", "ate", m_gt_0);
131743
+ }
131661131744
break;
131662131745
case 's':
131663
- stem(&z, "msila", "al", m_gt_0) ||
131664
- stem(&z, "ssenevi", "ive", m_gt_0) ||
131665
- stem(&z, "ssenluf", "ful", m_gt_0) ||
131666
- stem(&z, "ssensuo", "ous", m_gt_0);
131746
+ if( !stem(&z, "msila", "al", m_gt_0)
131747
+ && !stem(&z, "ssenevi", "ive", m_gt_0)
131748
+ && !stem(&z, "ssenluf", "ful", m_gt_0)
131749
+ ){
131750
+ stem(&z, "ssensuo", "ous", m_gt_0);
131751
+ }
131667131752
break;
131668131753
case 't':
131669
- stem(&z, "itila", "al", m_gt_0) ||
131670
- stem(&z, "itivi", "ive", m_gt_0) ||
131671
- stem(&z, "itilib", "ble", m_gt_0);
131754
+ if( !stem(&z, "itila", "al", m_gt_0)
131755
+ && !stem(&z, "itivi", "ive", m_gt_0)
131756
+ ){
131757
+ stem(&z, "itilib", "ble", m_gt_0);
131758
+ }
131672131759
break;
131673131760
}
131674131761
131675131762
/* Step 3 */
131676131763
switch( z[0] ){
131677131764
case 'e':
131678
- stem(&z, "etaci", "ic", m_gt_0) ||
131679
- stem(&z, "evita", "", m_gt_0) ||
131680
- stem(&z, "ezila", "al", m_gt_0);
131765
+ if( !stem(&z, "etaci", "ic", m_gt_0)
131766
+ && !stem(&z, "evita", "", m_gt_0)
131767
+ ){
131768
+ stem(&z, "ezila", "al", m_gt_0);
131769
+ }
131681131770
break;
131682131771
case 'i':
131683131772
stem(&z, "itici", "ic", m_gt_0);
131684131773
break;
131685131774
case 'l':
131686
- stem(&z, "laci", "ic", m_gt_0) ||
131687
- stem(&z, "luf", "", m_gt_0);
131775
+ if( !stem(&z, "laci", "ic", m_gt_0) ){
131776
+ stem(&z, "luf", "", m_gt_0);
131777
+ }
131688131778
break;
131689131779
case 's':
131690131780
stem(&z, "ssen", "", m_gt_0);
131691131781
break;
131692131782
}
@@ -131723,13 +131813,15 @@
131723131813
if( z[2]=='a' ){
131724131814
if( m_gt_1(z+3) ){
131725131815
z += 3;
131726131816
}
131727131817
}else if( z[2]=='e' ){
131728
- stem(&z, "tneme", "", m_gt_1) ||
131729
- stem(&z, "tnem", "", m_gt_1) ||
131730
- stem(&z, "tne", "", m_gt_1);
131818
+ if( !stem(&z, "tneme", "", m_gt_1)
131819
+ && !stem(&z, "tnem", "", m_gt_1)
131820
+ ){
131821
+ stem(&z, "tne", "", m_gt_1);
131822
+ }
131731131823
}
131732131824
}
131733131825
break;
131734131826
case 'o':
131735131827
if( z[0]=='u' ){
@@ -131744,12 +131836,13 @@
131744131836
if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
131745131837
z += 3;
131746131838
}
131747131839
break;
131748131840
case 't':
131749
- stem(&z, "eta", "", m_gt_1) ||
131750
- stem(&z, "iti", "", m_gt_1);
131841
+ if( !stem(&z, "eta", "", m_gt_1) ){
131842
+ stem(&z, "iti", "", m_gt_1);
131843
+ }
131751131844
break;
131752131845
case 'u':
131753131846
if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
131754131847
z += 3;
131755131848
}
131756131849
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -135,11 +135,11 @@
135 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
136 ** [sqlite_version()] and [sqlite_source_id()].
137 */
138 #define SQLITE_VERSION "3.8.3"
139 #define SQLITE_VERSION_NUMBER 3008003
140 #define SQLITE_SOURCE_ID "2013-12-17 16:32:56 93121d3097a43997af3c0de65bd9bd7663845fa2"
141
142 /*
143 ** CAPI3REF: Run-Time Library Version Numbers
144 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
145 **
@@ -9098,11 +9098,11 @@
9098 #define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */
9099 #define OP_Null 26 /* synopsis: r[P2..P3]=NULL */
9100 #define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */
9101 #define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */
9102 #define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */
9103 #define OP_Copy 30 /* synopsis: r[P2@P3]=r[P1@P3] */
9104 #define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */
9105 #define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */
9106 #define OP_CollSeq 33
9107 #define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */
9108 #define OP_MustBeInt 35
@@ -9263,11 +9263,11 @@
9263
9264 /*
9265 ** Prototypes for the VDBE interface. See comments on the implementation
9266 ** for a description of what each of these routines does.
9267 */
9268 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*);
9269 SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
9270 SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
9271 SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
9272 SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
9273 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
@@ -11003,10 +11003,11 @@
11003 u8 useSortingIdx; /* In direct mode, reference the sorting index rather
11004 ** than the source table */
11005 int sortingIdx; /* Cursor number of the sorting index */
11006 int sortingIdxPTab; /* Cursor number of pseudo-table */
11007 int nSortingColumn; /* Number of columns in the sorting index */
 
11008 ExprList *pGroupBy; /* The group by clause */
11009 struct AggInfo_col { /* For each column used in source tables */
11010 Table *pTab; /* Source table */
11011 int iTable; /* Cursor number of the source table */
11012 int iColumn; /* Column number within the source table */
@@ -12452,12 +12453,11 @@
12452 SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
12453 SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
12454 SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
12455 SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
12456
12457 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
12458 defined(SQLITE_DEBUG_OS_TRACE)
12459 SQLITE_PRIVATE const char *sqlite3ErrName(int);
12460 #endif
12461
12462 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
12463 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
@@ -13776,10 +13776,13 @@
13776 Op *aOp; /* Space to hold the virtual machine's program */
13777 Mem *aMem; /* The memory locations */
13778 Mem **apArg; /* Arguments to currently executing user function */
13779 Mem *aColName; /* Column names to return */
13780 Mem *pResultSet; /* Pointer to an array of results */
 
 
 
13781 int nMem; /* Number of memory locations currently allocated */
13782 int nOp; /* Number of instructions in the program */
13783 int nOpAlloc; /* Number of slots allocated for aOp[] */
13784 int nLabel; /* Number of labels used */
13785 int *aLabel; /* Space to hold the labels */
@@ -15443,11 +15446,25 @@
15443 ** really care if the VFS receives and understands the information since it
15444 ** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
15445 ** routine has no return value since the return value would be meaningless.
15446 */
15447 SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
15448 DO_OS_MALLOC_TEST(id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15449 return id->pMethods->xFileControl(id, op, pArg);
15450 }
15451 SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
15452 (void)id->pMethods->xFileControl(id, op, pArg);
15453 }
@@ -23098,11 +23115,11 @@
23098 /* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
23099 /* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
23100 /* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
23101 /* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
23102 /* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
23103 /* 30 */ "Copy" OpHelp("r[P2@P3]=r[P1@P3]"),
23104 /* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
23105 /* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"),
23106 /* 33 */ "CollSeq" OpHelp(""),
23107 /* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
23108 /* 35 */ "MustBeInt" OpHelp(""),
@@ -61223,11 +61240,12 @@
61223 */
61224
61225 /*
61226 ** Create a new virtual database engine.
61227 */
61228 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
 
61229 Vdbe *p;
61230 p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
61231 if( p==0 ) return 0;
61232 p->db = db;
61233 if( db->pVdbe ){
@@ -61235,10 +61253,13 @@
61235 }
61236 p->pNext = db->pVdbe;
61237 p->pPrev = 0;
61238 db->pVdbe = p;
61239 p->magic = VDBE_MAGIC_INIT;
 
 
 
61240 return p;
61241 }
61242
61243 /*
61244 ** Remember the SQL string for a prepared statement.
@@ -61354,10 +61375,19 @@
61354 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
61355 pOp->zComment = 0;
61356 #endif
61357 #ifdef SQLITE_DEBUG
61358 if( p->db->flags & SQLITE_VdbeAddopTrace ){
 
 
 
 
 
 
 
 
 
61359 sqlite3VdbePrintOp(0, i, &p->aOp[i]);
61360 test_addop_breakpoint();
61361 }
61362 #endif
61363 #ifdef VDBE_PROFILE
@@ -62075,11 +62105,21 @@
62075 if( c=='4' ) return pOp->p4.i;
62076 return pOp->p5;
62077 }
62078
62079 /*
62080 ** Compute a string for the "comment" field of a VDBE opcode listing
 
 
 
 
 
 
 
 
 
 
62081 */
62082 static int displayComment(
62083 const Op *pOp, /* The opcode to be commented */
62084 const char *zP4, /* Previously obtained value for P4 */
62085 char *zTemp, /* Write result here */
@@ -62109,11 +62149,17 @@
62109 sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
62110 if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
62111 ii += 3;
62112 jj += sqlite3Strlen30(zTemp+jj);
62113 v2 = translateP(zSynopsis[ii], pOp);
62114 if( v2>1 ) sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
 
 
 
 
 
 
62115 }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
62116 ii += 4;
62117 }
62118 }
62119 jj += sqlite3Strlen30(zTemp+jj);
@@ -62341,10 +62387,13 @@
62341 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
62342 displayComment(pOp, zP4, zCom, sizeof(zCom));
62343 #else
62344 zCom[0] = 0
62345 #endif
 
 
 
62346 fprintf(pOut, zFormat1, pc,
62347 sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
62348 zCom
62349 );
62350 fflush(pOut);
@@ -67401,11 +67450,11 @@
67401 }while( n-- );
67402 break;
67403 }
67404
67405 /* Opcode: Copy P1 P2 P3 * *
67406 ** Synopsis: r[P2@P3]=r[P1@P3]
67407 **
67408 ** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
67409 **
67410 ** This instruction makes a deep copy of the value. A duplicate
67411 ** is made of any string or blob constant. See also OP_SCopy.
@@ -68744,11 +68793,11 @@
68744 /* This is the common case where the desired content fits on the original
68745 ** page - where the content is not on an overflow page */
68746 VdbeMemRelease(pDest);
68747 sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
68748 }else{
68749 /* This branch happens only when content is on overflow pages */
68750 t = aType[p2];
68751 if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
68752 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
68753 || (len = sqlite3VdbeSerialTypeLen(t))==0
68754 ){
@@ -72862,11 +72911,11 @@
72862 sqlite3BtreeLeaveAll(db);
72863 goto blob_open_out;
72864 }
72865 }
72866
72867 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db);
72868 assert( pBlob->pStmt || db->mallocFailed );
72869 if( pBlob->pStmt ){
72870 Vdbe *v = (Vdbe *)pBlob->pStmt;
72871 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
72872
@@ -78416,10 +78465,15 @@
78416 ** added to the column cache after this call are removed when the
78417 ** corresponding pop occurs.
78418 */
78419 SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
78420 pParse->iCacheLevel++;
 
 
 
 
 
78421 }
78422
78423 /*
78424 ** Remove from the column cache any entries that were added since the
78425 ** the previous N Push operations. In other words, restore the cache
@@ -78429,10 +78483,15 @@
78429 int i;
78430 struct yColCache *p;
78431 assert( N>0 );
78432 assert( pParse->iCacheLevel>=N );
78433 pParse->iCacheLevel -= N;
 
 
 
 
 
78434 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78435 if( p->iReg && p->iLevel>pParse->iCacheLevel ){
78436 cacheEntryClear(pParse, p);
78437 p->iReg = 0;
78438 }
@@ -78523,10 +78582,15 @@
78523 */
78524 SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
78525 int i;
78526 struct yColCache *p;
78527
 
 
 
 
 
78528 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78529 if( p->iReg ){
78530 cacheEntryClear(pParse, p);
78531 p->iReg = 0;
78532 }
@@ -79659,11 +79723,21 @@
79659 if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
79660 sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
79661 }else{
79662 int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
79663 if( inReg!=target+i ){
79664 sqlite3VdbeAddOp2(pParse->pVdbe, copyOp, inReg, target+i);
 
 
 
 
 
 
 
 
 
 
79665 }
79666 }
79667 }
79668 return n;
79669 }
@@ -83083,14 +83157,10 @@
83083 {
83084 int rc = SQLITE_OK;
83085 if( pExpr ){
83086 if( pExpr->op!=TK_ID ){
83087 rc = sqlite3ResolveExprNames(pName, pExpr);
83088 if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
83089 sqlite3ErrorMsg(pName->pParse, "invalid name: \"%s\"", pExpr->u.zToken);
83090 return SQLITE_ERROR;
83091 }
83092 }else{
83093 pExpr->op = TK_STRING;
83094 }
83095 }
83096 return rc;
@@ -89324,11 +89394,10 @@
89324 Vdbe *v = pParse->pVdbe;
89325 int j;
89326 Table *pTab = pIdx->pTable;
89327 int regBase;
89328 int nCol;
89329 Index *pPk;
89330
89331 if( piPartIdxLabel ){
89332 if( pIdx->pPartIdxWhere ){
89333 *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
89334 pParse->iPartIdxTab = iDataCur;
@@ -89338,20 +89407,13 @@
89338 *piPartIdxLabel = 0;
89339 }
89340 }
89341 nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
89342 regBase = sqlite3GetTempRange(pParse, nCol);
89343 pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
89344 for(j=0; j<nCol; j++){
89345 i16 idx = pIdx->aiColumn[j];
89346 if( pPk ) idx = sqlite3ColumnOfIndex(pPk, idx);
89347 if( idx<0 || idx==pTab->iPKey ){
89348 sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regBase+j);
89349 }else{
89350 sqlite3VdbeAddOp3(v, OP_Column, iDataCur, idx, regBase+j);
89351 sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[j], -1);
89352 }
89353 }
89354 if( regOut ){
89355 const char *zAff;
89356 if( pTab->pSelect
89357 || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
@@ -93982,51 +94044,53 @@
93982 sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
93983 regIdx, pIdx->nKeyCol);
93984
93985 /* Generate code to handle collisions */
93986 regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
93987 if( HasRowid(pTab) ){
93988 sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
93989 /* Conflict only if the rowid of the existing index entry
93990 ** is different from old-rowid */
93991 if( isUpdate ){
93992 sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
93993 }
93994 }else{
93995 int x;
93996 /* Extract the PRIMARY KEY from the end of the index entry and
93997 ** store it in registers regR..regR+nPk-1 */
93998 if( (isUpdate || onError==OE_Replace) && pIdx!=pPk ){
93999 for(i=0; i<pPk->nKeyCol; i++){
94000 x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94001 sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94002 VdbeComment((v, "%s.%s", pTab->zName,
94003 pTab->aCol[pPk->aiColumn[i]].zName));
94004 }
94005 }
94006 if( isUpdate ){
94007 /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94008 ** table, only conflict if the new PRIMARY KEY values are actually
94009 ** different from the old.
94010 **
94011 ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94012 ** of the matched index row are different from the original PRIMARY
94013 ** KEY values of this row before the update. */
94014 int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94015 int op = OP_Ne;
94016 int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94017
94018 for(i=0; i<pPk->nKeyCol; i++){
94019 char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94020 x = pPk->aiColumn[i];
94021 if( i==(pPk->nKeyCol-1) ){
94022 addrJump = addrUniqueOk;
94023 op = OP_Eq;
94024 }
94025 sqlite3VdbeAddOp4(v, op,
94026 regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94027 );
 
 
94028 }
94029 }
94030 }
94031
94032 /* Generate code that executes if the new index entry is not unique */
@@ -99722,11 +99786,10 @@
99722 }
99723 }else if( eDest!=SRT_Exists ){
99724 /* If the destination is an EXISTS(...) expression, the actual
99725 ** values returned by the SELECT are not required.
99726 */
99727 sqlite3ExprCacheClear(pParse);
99728 sqlite3ExprCodeExprList(pParse, pEList, regResult,
99729 (eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
99730 }
99731 nColumn = nResultCol;
99732
@@ -100689,11 +100752,11 @@
100689 ** If an error occurs, return NULL and leave a message in pParse.
100690 */
100691 SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
100692 Vdbe *v = pParse->pVdbe;
100693 if( v==0 ){
100694 v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db);
100695 #ifndef SQLITE_OMIT_TRACE
100696 if( v ){
100697 sqlite3VdbeAddOp0(v, OP_Trace);
100698 }
100699 #endif
@@ -102947,18 +103010,27 @@
102947 */
102948 static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
102949 Vdbe *v = pParse->pVdbe;
102950 int i;
102951 struct AggInfo_func *pFunc;
102952 if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){
102953 return;
102954 }
 
 
 
102955 for(i=0; i<pAggInfo->nColumn; i++){
102956 sqlite3VdbeAddOp2(v, OP_Null, 0, pAggInfo->aCol[i].iMem);
 
102957 }
 
 
 
 
 
 
102958 for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
102959 sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
102960 if( pFunc->iDistinct>=0 ){
102961 Expr *pE = pFunc->pExpr;
102962 assert( !ExprHasProperty(pE, EP_xIsSelect) );
102963 if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
102964 sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -103000,11 +103072,10 @@
103000 int addrHitTest = 0;
103001 struct AggInfo_func *pF;
103002 struct AggInfo_col *pC;
103003
103004 pAggInfo->directMode = 1;
103005 sqlite3ExprCacheClear(pParse);
103006 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
103007 int nArg;
103008 int addrNext = 0;
103009 int regAgg;
103010 ExprList *pList = pF->pExpr->x.pList;
@@ -103533,10 +103604,11 @@
103533 */
103534 memset(&sNC, 0, sizeof(sNC));
103535 sNC.pParse = pParse;
103536 sNC.pSrcList = pTabList;
103537 sNC.pAggInfo = &sAggInfo;
 
103538 sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
103539 sAggInfo.pGroupBy = pGroupBy;
103540 sqlite3ExprAnalyzeAggList(&sNC, pEList);
103541 sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
103542 if( pHaving ){
@@ -103547,10 +103619,11 @@
103547 assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
103548 sNC.ncFlags |= NC_InAggFunc;
103549 sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
103550 sNC.ncFlags &= ~NC_InAggFunc;
103551 }
 
103552 if( db->mallocFailed ) goto select_end;
103553
103554 /* Processing for aggregates with GROUP BY is very different and
103555 ** much more complex than aggregates without a GROUP BY.
103556 */
@@ -105451,11 +105524,11 @@
105451 pCol->affinity, &pValue);
105452 if( pValue ){
105453 sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
105454 }
105455 #ifndef SQLITE_OMIT_FLOATING_POINT
105456 if( iReg>=0 && pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105457 sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
105458 }
105459 #endif
105460 }
105461 }
@@ -105875,14 +105948,14 @@
105875 ** be used eliminates some redundant opcodes.
105876 */
105877 newmask = sqlite3TriggerColmask(
105878 pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
105879 );
105880 sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);
105881 for(i=0; i<pTab->nCol; i++){
105882 if( i==pTab->iPKey ){
105883 /*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
105884 }else{
105885 j = aXRef[i];
105886 if( j>=0 ){
105887 sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
105888 }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
@@ -105892,10 +105965,12 @@
105892 ** a new.* reference in a trigger program.
105893 */
105894 testcase( i==31 );
105895 testcase( i==32 );
105896 sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
 
 
105897 }
105898 }
105899 }
105900
105901 /* Fire any BEFORE UPDATE triggers. This happens before constraints are
@@ -112004,10 +112079,11 @@
112004 */
112005 if( pTerm==0
112006 && saved_nEq==saved_nSkip
112007 && saved_nEq+1<pProbe->nKeyCol
112008 && pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
 
112009 ){
112010 LogEst nIter;
112011 pNew->u.btree.nEq++;
112012 pNew->u.btree.nSkip++;
112013 pNew->aLTerm[pNew->nLTerm++] = 0;
@@ -119722,12 +119798,11 @@
119722
119723 /*
119724 ** Return a static string containing the name corresponding to the error code
119725 ** specified in the argument.
119726 */
119727 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
119728 defined(SQLITE_DEBUG_OS_TRACE)
119729 SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
119730 const char *zName = 0;
119731 int i, origRc = rc;
119732 for(i=0; i<2 && zName==0; i++, rc &= 0xff){
119733 switch( rc ){
@@ -121300,10 +121375,12 @@
121300 #ifdef SQLITE_DEFAULT_LOCKING_MODE
121301 db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
121302 sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
121303 SQLITE_DEFAULT_LOCKING_MODE);
121304 #endif
 
 
121305
121306 /* Enable the lookaside-malloc subsystem */
121307 setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
121308 sqlite3GlobalConfig.nLookaside);
121309
@@ -131632,61 +131709,74 @@
131632 }
131633
131634 /* Step 2 */
131635 switch( z[1] ){
131636 case 'a':
131637 stem(&z, "lanoita", "ate", m_gt_0) ||
131638 stem(&z, "lanoit", "tion", m_gt_0);
 
131639 break;
131640 case 'c':
131641 stem(&z, "icne", "ence", m_gt_0) ||
131642 stem(&z, "icna", "ance", m_gt_0);
 
131643 break;
131644 case 'e':
131645 stem(&z, "rezi", "ize", m_gt_0);
131646 break;
131647 case 'g':
131648 stem(&z, "igol", "log", m_gt_0);
131649 break;
131650 case 'l':
131651 stem(&z, "ilb", "ble", m_gt_0) ||
131652 stem(&z, "illa", "al", m_gt_0) ||
131653 stem(&z, "iltne", "ent", m_gt_0) ||
131654 stem(&z, "ile", "e", m_gt_0) ||
131655 stem(&z, "ilsuo", "ous", m_gt_0);
 
 
131656 break;
131657 case 'o':
131658 stem(&z, "noitazi", "ize", m_gt_0) ||
131659 stem(&z, "noita", "ate", m_gt_0) ||
131660 stem(&z, "rota", "ate", m_gt_0);
 
 
131661 break;
131662 case 's':
131663 stem(&z, "msila", "al", m_gt_0) ||
131664 stem(&z, "ssenevi", "ive", m_gt_0) ||
131665 stem(&z, "ssenluf", "ful", m_gt_0) ||
131666 stem(&z, "ssensuo", "ous", m_gt_0);
 
 
131667 break;
131668 case 't':
131669 stem(&z, "itila", "al", m_gt_0) ||
131670 stem(&z, "itivi", "ive", m_gt_0) ||
131671 stem(&z, "itilib", "ble", m_gt_0);
 
 
131672 break;
131673 }
131674
131675 /* Step 3 */
131676 switch( z[0] ){
131677 case 'e':
131678 stem(&z, "etaci", "ic", m_gt_0) ||
131679 stem(&z, "evita", "", m_gt_0) ||
131680 stem(&z, "ezila", "al", m_gt_0);
 
 
131681 break;
131682 case 'i':
131683 stem(&z, "itici", "ic", m_gt_0);
131684 break;
131685 case 'l':
131686 stem(&z, "laci", "ic", m_gt_0) ||
131687 stem(&z, "luf", "", m_gt_0);
 
131688 break;
131689 case 's':
131690 stem(&z, "ssen", "", m_gt_0);
131691 break;
131692 }
@@ -131723,13 +131813,15 @@
131723 if( z[2]=='a' ){
131724 if( m_gt_1(z+3) ){
131725 z += 3;
131726 }
131727 }else if( z[2]=='e' ){
131728 stem(&z, "tneme", "", m_gt_1) ||
131729 stem(&z, "tnem", "", m_gt_1) ||
131730 stem(&z, "tne", "", m_gt_1);
 
 
131731 }
131732 }
131733 break;
131734 case 'o':
131735 if( z[0]=='u' ){
@@ -131744,12 +131836,13 @@
131744 if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
131745 z += 3;
131746 }
131747 break;
131748 case 't':
131749 stem(&z, "eta", "", m_gt_1) ||
131750 stem(&z, "iti", "", m_gt_1);
 
131751 break;
131752 case 'u':
131753 if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
131754 z += 3;
131755 }
131756
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -135,11 +135,11 @@
135 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
136 ** [sqlite_version()] and [sqlite_source_id()].
137 */
138 #define SQLITE_VERSION "3.8.3"
139 #define SQLITE_VERSION_NUMBER 3008003
140 #define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d"
141
142 /*
143 ** CAPI3REF: Run-Time Library Version Numbers
144 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
145 **
@@ -9098,11 +9098,11 @@
9098 #define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */
9099 #define OP_Null 26 /* synopsis: r[P2..P3]=NULL */
9100 #define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */
9101 #define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */
9102 #define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */
9103 #define OP_Copy 30 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
9104 #define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */
9105 #define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */
9106 #define OP_CollSeq 33
9107 #define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */
9108 #define OP_MustBeInt 35
@@ -9263,11 +9263,11 @@
9263
9264 /*
9265 ** Prototypes for the VDBE interface. See comments on the implementation
9266 ** for a description of what each of these routines does.
9267 */
9268 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*);
9269 SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
9270 SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
9271 SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
9272 SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
9273 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
@@ -11003,10 +11003,11 @@
11003 u8 useSortingIdx; /* In direct mode, reference the sorting index rather
11004 ** than the source table */
11005 int sortingIdx; /* Cursor number of the sorting index */
11006 int sortingIdxPTab; /* Cursor number of pseudo-table */
11007 int nSortingColumn; /* Number of columns in the sorting index */
11008 int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
11009 ExprList *pGroupBy; /* The group by clause */
11010 struct AggInfo_col { /* For each column used in source tables */
11011 Table *pTab; /* Source table */
11012 int iTable; /* Cursor number of the source table */
11013 int iColumn; /* Column number within the source table */
@@ -12452,12 +12453,11 @@
12453 SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
12454 SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
12455 SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
12456 SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
12457
12458 #if defined(SQLITE_TEST)
 
12459 SQLITE_PRIVATE const char *sqlite3ErrName(int);
12460 #endif
12461
12462 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
12463 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
@@ -13776,10 +13776,13 @@
13776 Op *aOp; /* Space to hold the virtual machine's program */
13777 Mem *aMem; /* The memory locations */
13778 Mem **apArg; /* Arguments to currently executing user function */
13779 Mem *aColName; /* Column names to return */
13780 Mem *pResultSet; /* Pointer to an array of results */
13781 #ifdef SQLITE_DEBUG
13782 Parse *pParse; /* Parsing context used to create this Vdbe */
13783 #endif
13784 int nMem; /* Number of memory locations currently allocated */
13785 int nOp; /* Number of instructions in the program */
13786 int nOpAlloc; /* Number of slots allocated for aOp[] */
13787 int nLabel; /* Number of labels used */
13788 int *aLabel; /* Space to hold the labels */
@@ -15443,11 +15446,25 @@
15446 ** really care if the VFS receives and understands the information since it
15447 ** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
15448 ** routine has no return value since the return value would be meaningless.
15449 */
15450 SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
15451 #ifdef SQLITE_TEST
15452 if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
15453 /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
15454 ** is using a regular VFS, it is called after the corresponding
15455 ** transaction has been committed. Injecting a fault at this point
15456 ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
15457 ** but the transaction is committed anyway.
15458 **
15459 ** The core must call OsFileControl() though, not OsFileControlHint(),
15460 ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
15461 ** means the commit really has failed and an error should be returned
15462 ** to the user. */
15463 DO_OS_MALLOC_TEST(id);
15464 }
15465 #endif
15466 return id->pMethods->xFileControl(id, op, pArg);
15467 }
15468 SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
15469 (void)id->pMethods->xFileControl(id, op, pArg);
15470 }
@@ -23098,11 +23115,11 @@
23115 /* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
23116 /* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
23117 /* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
23118 /* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
23119 /* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
23120 /* 30 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
23121 /* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
23122 /* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"),
23123 /* 33 */ "CollSeq" OpHelp(""),
23124 /* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
23125 /* 35 */ "MustBeInt" OpHelp(""),
@@ -61223,11 +61240,12 @@
61240 */
61241
61242 /*
61243 ** Create a new virtual database engine.
61244 */
61245 SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
61246 sqlite3 *db = pParse->db;
61247 Vdbe *p;
61248 p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
61249 if( p==0 ) return 0;
61250 p->db = db;
61251 if( db->pVdbe ){
@@ -61235,10 +61253,13 @@
61253 }
61254 p->pNext = db->pVdbe;
61255 p->pPrev = 0;
61256 db->pVdbe = p;
61257 p->magic = VDBE_MAGIC_INIT;
61258 #if SQLITE_DEBUG
61259 p->pParse = pParse;
61260 #endif
61261 return p;
61262 }
61263
61264 /*
61265 ** Remember the SQL string for a prepared statement.
@@ -61354,10 +61375,19 @@
61375 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
61376 pOp->zComment = 0;
61377 #endif
61378 #ifdef SQLITE_DEBUG
61379 if( p->db->flags & SQLITE_VdbeAddopTrace ){
61380 int jj, kk;
61381 Parse *pParse = p->pParse;
61382 for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
61383 struct yColCache *x = pParse->aColCache + jj;
61384 if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
61385 printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
61386 kk++;
61387 }
61388 if( kk ) printf("\n");
61389 sqlite3VdbePrintOp(0, i, &p->aOp[i]);
61390 test_addop_breakpoint();
61391 }
61392 #endif
61393 #ifdef VDBE_PROFILE
@@ -62075,11 +62105,21 @@
62105 if( c=='4' ) return pOp->p4.i;
62106 return pOp->p5;
62107 }
62108
62109 /*
62110 ** Compute a string for the "comment" field of a VDBE opcode listing.
62111 **
62112 ** The Synopsis: field in comments in the vdbe.c source file gets converted
62113 ** to an extra string that is appended to the sqlite3OpcodeName(). In the
62114 ** absence of other comments, this synopsis becomes the comment on the opcode.
62115 ** Some translation occurs:
62116 **
62117 ** "PX" -> "r[X]"
62118 ** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1
62119 ** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
62120 ** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
62121 */
62122 static int displayComment(
62123 const Op *pOp, /* The opcode to be commented */
62124 const char *zP4, /* Previously obtained value for P4 */
62125 char *zTemp, /* Write result here */
@@ -62109,11 +62149,17 @@
62149 sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
62150 if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
62151 ii += 3;
62152 jj += sqlite3Strlen30(zTemp+jj);
62153 v2 = translateP(zSynopsis[ii], pOp);
62154 if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
62155 ii += 2;
62156 v2++;
62157 }
62158 if( v2>1 ){
62159 sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
62160 }
62161 }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
62162 ii += 4;
62163 }
62164 }
62165 jj += sqlite3Strlen30(zTemp+jj);
@@ -62341,10 +62387,13 @@
62387 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
62388 displayComment(pOp, zP4, zCom, sizeof(zCom));
62389 #else
62390 zCom[0] = 0
62391 #endif
62392 /* NB: The sqlite3OpcodeName() function is implemented by code created
62393 ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
62394 ** information from the vdbe.c source text */
62395 fprintf(pOut, zFormat1, pc,
62396 sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
62397 zCom
62398 );
62399 fflush(pOut);
@@ -67401,11 +67450,11 @@
67450 }while( n-- );
67451 break;
67452 }
67453
67454 /* Opcode: Copy P1 P2 P3 * *
67455 ** Synopsis: r[P2@P3+1]=r[P1@P3+1]
67456 **
67457 ** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
67458 **
67459 ** This instruction makes a deep copy of the value. A duplicate
67460 ** is made of any string or blob constant. See also OP_SCopy.
@@ -68744,11 +68793,11 @@
68793 /* This is the common case where the desired content fits on the original
68794 ** page - where the content is not on an overflow page */
68795 VdbeMemRelease(pDest);
68796 sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
68797 }else{
68798 /* This branch happens only when content is on overflow pages */
68799 t = aType[p2];
68800 if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
68801 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
68802 || (len = sqlite3VdbeSerialTypeLen(t))==0
68803 ){
@@ -72862,11 +72911,11 @@
72911 sqlite3BtreeLeaveAll(db);
72912 goto blob_open_out;
72913 }
72914 }
72915
72916 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
72917 assert( pBlob->pStmt || db->mallocFailed );
72918 if( pBlob->pStmt ){
72919 Vdbe *v = (Vdbe *)pBlob->pStmt;
72920 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
72921
@@ -78416,10 +78465,15 @@
78465 ** added to the column cache after this call are removed when the
78466 ** corresponding pop occurs.
78467 */
78468 SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
78469 pParse->iCacheLevel++;
78470 #ifdef SQLITE_DEBUG
78471 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78472 printf("PUSH to %d\n", pParse->iCacheLevel);
78473 }
78474 #endif
78475 }
78476
78477 /*
78478 ** Remove from the column cache any entries that were added since the
78479 ** the previous N Push operations. In other words, restore the cache
@@ -78429,10 +78483,15 @@
78483 int i;
78484 struct yColCache *p;
78485 assert( N>0 );
78486 assert( pParse->iCacheLevel>=N );
78487 pParse->iCacheLevel -= N;
78488 #ifdef SQLITE_DEBUG
78489 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78490 printf("POP to %d\n", pParse->iCacheLevel);
78491 }
78492 #endif
78493 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78494 if( p->iReg && p->iLevel>pParse->iCacheLevel ){
78495 cacheEntryClear(pParse, p);
78496 p->iReg = 0;
78497 }
@@ -78523,10 +78582,15 @@
78582 */
78583 SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
78584 int i;
78585 struct yColCache *p;
78586
78587 #if SQLITE_DEBUG
78588 if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
78589 printf("CLEAR\n");
78590 }
78591 #endif
78592 for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
78593 if( p->iReg ){
78594 cacheEntryClear(pParse, p);
78595 p->iReg = 0;
78596 }
@@ -79659,11 +79723,21 @@
79723 if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
79724 sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
79725 }else{
79726 int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
79727 if( inReg!=target+i ){
79728 VdbeOp *pOp;
79729 Vdbe *v = pParse->pVdbe;
79730 if( copyOp==OP_Copy
79731 && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
79732 && pOp->p1+pOp->p3+1==inReg
79733 && pOp->p2+pOp->p3+1==target+i
79734 ){
79735 pOp->p3++;
79736 }else{
79737 sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
79738 }
79739 }
79740 }
79741 }
79742 return n;
79743 }
@@ -83083,14 +83157,10 @@
83157 {
83158 int rc = SQLITE_OK;
83159 if( pExpr ){
83160 if( pExpr->op!=TK_ID ){
83161 rc = sqlite3ResolveExprNames(pName, pExpr);
 
 
 
 
83162 }else{
83163 pExpr->op = TK_STRING;
83164 }
83165 }
83166 return rc;
@@ -89324,11 +89394,10 @@
89394 Vdbe *v = pParse->pVdbe;
89395 int j;
89396 Table *pTab = pIdx->pTable;
89397 int regBase;
89398 int nCol;
 
89399
89400 if( piPartIdxLabel ){
89401 if( pIdx->pPartIdxWhere ){
89402 *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
89403 pParse->iPartIdxTab = iDataCur;
@@ -89338,20 +89407,13 @@
89407 *piPartIdxLabel = 0;
89408 }
89409 }
89410 nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
89411 regBase = sqlite3GetTempRange(pParse, nCol);
 
89412 for(j=0; j<nCol; j++){
89413 sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
89414 regBase+j);
 
 
 
 
 
 
89415 }
89416 if( regOut ){
89417 const char *zAff;
89418 if( pTab->pSelect
89419 || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
@@ -93982,51 +94044,53 @@
94044 sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
94045 regIdx, pIdx->nKeyCol);
94046
94047 /* Generate code to handle collisions */
94048 regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
94049 if( isUpdate || onError==OE_Replace ){
94050 if( HasRowid(pTab) ){
94051 sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
94052 /* Conflict only if the rowid of the existing index entry
94053 ** is different from old-rowid */
94054 if( isUpdate ){
94055 sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
94056 }
94057 }else{
94058 int x;
94059 /* Extract the PRIMARY KEY from the end of the index entry and
94060 ** store it in registers regR..regR+nPk-1 */
94061 if( pIdx!=pPk ){
94062 for(i=0; i<pPk->nKeyCol; i++){
94063 x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
94064 sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
94065 VdbeComment((v, "%s.%s", pTab->zName,
94066 pTab->aCol[pPk->aiColumn[i]].zName));
94067 }
94068 }
94069 if( isUpdate ){
94070 /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
94071 ** table, only conflict if the new PRIMARY KEY values are actually
94072 ** different from the old.
94073 **
94074 ** For a UNIQUE index, only conflict if the PRIMARY KEY values
94075 ** of the matched index row are different from the original PRIMARY
94076 ** KEY values of this row before the update. */
94077 int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
94078 int op = OP_Ne;
94079 int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
94080
94081 for(i=0; i<pPk->nKeyCol; i++){
94082 char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
94083 x = pPk->aiColumn[i];
94084 if( i==(pPk->nKeyCol-1) ){
94085 addrJump = addrUniqueOk;
94086 op = OP_Eq;
94087 }
94088 sqlite3VdbeAddOp4(v, op,
94089 regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
94090 );
94091 }
94092 }
94093 }
94094 }
94095
94096 /* Generate code that executes if the new index entry is not unique */
@@ -99722,11 +99786,10 @@
99786 }
99787 }else if( eDest!=SRT_Exists ){
99788 /* If the destination is an EXISTS(...) expression, the actual
99789 ** values returned by the SELECT are not required.
99790 */
 
99791 sqlite3ExprCodeExprList(pParse, pEList, regResult,
99792 (eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
99793 }
99794 nColumn = nResultCol;
99795
@@ -100689,11 +100752,11 @@
100752 ** If an error occurs, return NULL and leave a message in pParse.
100753 */
100754 SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
100755 Vdbe *v = pParse->pVdbe;
100756 if( v==0 ){
100757 v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
100758 #ifndef SQLITE_OMIT_TRACE
100759 if( v ){
100760 sqlite3VdbeAddOp0(v, OP_Trace);
100761 }
100762 #endif
@@ -102947,18 +103010,27 @@
103010 */
103011 static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
103012 Vdbe *v = pParse->pVdbe;
103013 int i;
103014 struct AggInfo_func *pFunc;
103015 int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
103016 if( nReg==0 ) return;
103017 #ifdef SQLITE_DEBUG
103018 /* Verify that all AggInfo registers are within the range specified by
103019 ** AggInfo.mnReg..AggInfo.mxReg */
103020 assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
103021 for(i=0; i<pAggInfo->nColumn; i++){
103022 assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
103023 && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
103024 }
103025 for(i=0; i<pAggInfo->nFunc; i++){
103026 assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
103027 && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
103028 }
103029 #endif
103030 sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
103031 for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
 
103032 if( pFunc->iDistinct>=0 ){
103033 Expr *pE = pFunc->pExpr;
103034 assert( !ExprHasProperty(pE, EP_xIsSelect) );
103035 if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
103036 sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
@@ -103000,11 +103072,10 @@
103072 int addrHitTest = 0;
103073 struct AggInfo_func *pF;
103074 struct AggInfo_col *pC;
103075
103076 pAggInfo->directMode = 1;
 
103077 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
103078 int nArg;
103079 int addrNext = 0;
103080 int regAgg;
103081 ExprList *pList = pF->pExpr->x.pList;
@@ -103533,10 +103604,11 @@
103604 */
103605 memset(&sNC, 0, sizeof(sNC));
103606 sNC.pParse = pParse;
103607 sNC.pSrcList = pTabList;
103608 sNC.pAggInfo = &sAggInfo;
103609 sAggInfo.mnReg = pParse->nMem+1;
103610 sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
103611 sAggInfo.pGroupBy = pGroupBy;
103612 sqlite3ExprAnalyzeAggList(&sNC, pEList);
103613 sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
103614 if( pHaving ){
@@ -103547,10 +103619,11 @@
103619 assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
103620 sNC.ncFlags |= NC_InAggFunc;
103621 sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
103622 sNC.ncFlags &= ~NC_InAggFunc;
103623 }
103624 sAggInfo.mxReg = pParse->nMem;
103625 if( db->mallocFailed ) goto select_end;
103626
103627 /* Processing for aggregates with GROUP BY is very different and
103628 ** much more complex than aggregates without a GROUP BY.
103629 */
@@ -105451,11 +105524,11 @@
105524 pCol->affinity, &pValue);
105525 if( pValue ){
105526 sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
105527 }
105528 #ifndef SQLITE_OMIT_FLOATING_POINT
105529 if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
105530 sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
105531 }
105532 #endif
105533 }
105534 }
@@ -105875,14 +105948,14 @@
105948 ** be used eliminates some redundant opcodes.
105949 */
105950 newmask = sqlite3TriggerColmask(
105951 pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
105952 );
105953 /*sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);*/
105954 for(i=0; i<pTab->nCol; i++){
105955 if( i==pTab->iPKey ){
105956 sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105957 }else{
105958 j = aXRef[i];
105959 if( j>=0 ){
105960 sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
105961 }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
@@ -105892,10 +105965,12 @@
105965 ** a new.* reference in a trigger program.
105966 */
105967 testcase( i==31 );
105968 testcase( i==32 );
105969 sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
105970 }else{
105971 sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
105972 }
105973 }
105974 }
105975
105976 /* Fire any BEFORE UPDATE triggers. This happens before constraints are
@@ -112004,10 +112079,11 @@
112079 */
112080 if( pTerm==0
112081 && saved_nEq==saved_nSkip
112082 && saved_nEq+1<pProbe->nKeyCol
112083 && pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
112084 && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
112085 ){
112086 LogEst nIter;
112087 pNew->u.btree.nEq++;
112088 pNew->u.btree.nSkip++;
112089 pNew->aLTerm[pNew->nLTerm++] = 0;
@@ -119722,12 +119798,11 @@
119798
119799 /*
119800 ** Return a static string containing the name corresponding to the error code
119801 ** specified in the argument.
119802 */
119803 #if defined(SQLITE_TEST)
 
119804 SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
119805 const char *zName = 0;
119806 int i, origRc = rc;
119807 for(i=0; i<2 && zName==0; i++, rc &= 0xff){
119808 switch( rc ){
@@ -121300,10 +121375,12 @@
121375 #ifdef SQLITE_DEFAULT_LOCKING_MODE
121376 db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
121377 sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
121378 SQLITE_DEFAULT_LOCKING_MODE);
121379 #endif
121380
121381 if( rc ) sqlite3Error(db, rc, 0);
121382
121383 /* Enable the lookaside-malloc subsystem */
121384 setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
121385 sqlite3GlobalConfig.nLookaside);
121386
@@ -131632,61 +131709,74 @@
131709 }
131710
131711 /* Step 2 */
131712 switch( z[1] ){
131713 case 'a':
131714 if( !stem(&z, "lanoita", "ate", m_gt_0) ){
131715 stem(&z, "lanoit", "tion", m_gt_0);
131716 }
131717 break;
131718 case 'c':
131719 if( !stem(&z, "icne", "ence", m_gt_0) ){
131720 stem(&z, "icna", "ance", m_gt_0);
131721 }
131722 break;
131723 case 'e':
131724 stem(&z, "rezi", "ize", m_gt_0);
131725 break;
131726 case 'g':
131727 stem(&z, "igol", "log", m_gt_0);
131728 break;
131729 case 'l':
131730 if( !stem(&z, "ilb", "ble", m_gt_0)
131731 && !stem(&z, "illa", "al", m_gt_0)
131732 && !stem(&z, "iltne", "ent", m_gt_0)
131733 && !stem(&z, "ile", "e", m_gt_0)
131734 ){
131735 stem(&z, "ilsuo", "ous", m_gt_0);
131736 }
131737 break;
131738 case 'o':
131739 if( !stem(&z, "noitazi", "ize", m_gt_0)
131740 && !stem(&z, "noita", "ate", m_gt_0)
131741 ){
131742 stem(&z, "rota", "ate", m_gt_0);
131743 }
131744 break;
131745 case 's':
131746 if( !stem(&z, "msila", "al", m_gt_0)
131747 && !stem(&z, "ssenevi", "ive", m_gt_0)
131748 && !stem(&z, "ssenluf", "ful", m_gt_0)
131749 ){
131750 stem(&z, "ssensuo", "ous", m_gt_0);
131751 }
131752 break;
131753 case 't':
131754 if( !stem(&z, "itila", "al", m_gt_0)
131755 && !stem(&z, "itivi", "ive", m_gt_0)
131756 ){
131757 stem(&z, "itilib", "ble", m_gt_0);
131758 }
131759 break;
131760 }
131761
131762 /* Step 3 */
131763 switch( z[0] ){
131764 case 'e':
131765 if( !stem(&z, "etaci", "ic", m_gt_0)
131766 && !stem(&z, "evita", "", m_gt_0)
131767 ){
131768 stem(&z, "ezila", "al", m_gt_0);
131769 }
131770 break;
131771 case 'i':
131772 stem(&z, "itici", "ic", m_gt_0);
131773 break;
131774 case 'l':
131775 if( !stem(&z, "laci", "ic", m_gt_0) ){
131776 stem(&z, "luf", "", m_gt_0);
131777 }
131778 break;
131779 case 's':
131780 stem(&z, "ssen", "", m_gt_0);
131781 break;
131782 }
@@ -131723,13 +131813,15 @@
131813 if( z[2]=='a' ){
131814 if( m_gt_1(z+3) ){
131815 z += 3;
131816 }
131817 }else if( z[2]=='e' ){
131818 if( !stem(&z, "tneme", "", m_gt_1)
131819 && !stem(&z, "tnem", "", m_gt_1)
131820 ){
131821 stem(&z, "tne", "", m_gt_1);
131822 }
131823 }
131824 }
131825 break;
131826 case 'o':
131827 if( z[0]=='u' ){
@@ -131744,12 +131836,13 @@
131836 if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
131837 z += 3;
131838 }
131839 break;
131840 case 't':
131841 if( !stem(&z, "eta", "", m_gt_1) ){
131842 stem(&z, "iti", "", m_gt_1);
131843 }
131844 break;
131845 case 'u':
131846 if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
131847 z += 3;
131848 }
131849
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.8.3"
111111
#define SQLITE_VERSION_NUMBER 3008003
112
-#define SQLITE_SOURCE_ID "2013-12-17 16:32:56 93121d3097a43997af3c0de65bd9bd7663845fa2"
112
+#define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
118118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.3"
111 #define SQLITE_VERSION_NUMBER 3008003
112 #define SQLITE_SOURCE_ID "2013-12-17 16:32:56 93121d3097a43997af3c0de65bd9bd7663845fa2"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.3"
111 #define SQLITE_VERSION_NUMBER 3008003
112 #define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
+1 -1
--- src/tag.c
+++ src/tag.c
@@ -326,11 +326,11 @@
326326
}
327327
blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
328328
md5sum_blob(&ctrl, &cksum);
329329
blob_appendf(&ctrl, "Z %b\n", &cksum);
330330
nrid = content_put(&ctrl);
331
- manifest_crosslink(nrid, &ctrl);
331
+ manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
332332
assert( blob_is_reset(&ctrl) );
333333
}
334334
335335
/*
336336
** COMMAND: tag
337337
--- src/tag.c
+++ src/tag.c
@@ -326,11 +326,11 @@
326 }
327 blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
328 md5sum_blob(&ctrl, &cksum);
329 blob_appendf(&ctrl, "Z %b\n", &cksum);
330 nrid = content_put(&ctrl);
331 manifest_crosslink(nrid, &ctrl);
332 assert( blob_is_reset(&ctrl) );
333 }
334
335 /*
336 ** COMMAND: tag
337
--- src/tag.c
+++ src/tag.c
@@ -326,11 +326,11 @@
326 }
327 blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
328 md5sum_blob(&ctrl, &cksum);
329 blob_appendf(&ctrl, "Z %b\n", &cksum);
330 nrid = content_put(&ctrl);
331 manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
332 assert( blob_is_reset(&ctrl) );
333 }
334
335 /*
336 ** COMMAND: tag
337
+1 -1
--- src/tar.c
+++ src/tar.c
@@ -427,11 +427,11 @@
427427
Blob file;
428428
if( g.argc<3 ){
429429
usage("ARCHIVE FILE....");
430430
}
431431
sqlite3_open(":memory:", &g.db);
432
- tar_begin(0);
432
+ tar_begin(-1);
433433
for(i=3; i<g.argc; i++){
434434
blob_zero(&file);
435435
blob_read_from_file(&file, g.argv[i]);
436436
tar_add_file(g.argv[i], &file,
437437
file_wd_perm(g.argv[i]), file_wd_mtime(g.argv[i]));
438438
--- src/tar.c
+++ src/tar.c
@@ -427,11 +427,11 @@
427 Blob file;
428 if( g.argc<3 ){
429 usage("ARCHIVE FILE....");
430 }
431 sqlite3_open(":memory:", &g.db);
432 tar_begin(0);
433 for(i=3; i<g.argc; i++){
434 blob_zero(&file);
435 blob_read_from_file(&file, g.argv[i]);
436 tar_add_file(g.argv[i], &file,
437 file_wd_perm(g.argv[i]), file_wd_mtime(g.argv[i]));
438
--- src/tar.c
+++ src/tar.c
@@ -427,11 +427,11 @@
427 Blob file;
428 if( g.argc<3 ){
429 usage("ARCHIVE FILE....");
430 }
431 sqlite3_open(":memory:", &g.db);
432 tar_begin(-1);
433 for(i=3; i<g.argc; i++){
434 blob_zero(&file);
435 blob_read_from_file(&file, g.argv[i]);
436 tar_add_file(g.argv[i], &file,
437 file_wd_perm(g.argv[i]), file_wd_mtime(g.argv[i]));
438
+9 -3
--- src/th.c
+++ src/th.c
@@ -1876,18 +1876,18 @@
18761876
if( rc==TH_OK && eArgType==ARG_INTEGER ){
18771877
int iRes = 0;
18781878
switch( pExpr->pOp->eOp ) {
18791879
case OP_MULTIPLY: iRes = iLeft*iRight; break;
18801880
case OP_DIVIDE:
1881
- if(!iRight){
1881
+ if( !iRight ){
18821882
Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
18831883
return TH_ERROR;
18841884
}
18851885
iRes = iLeft/iRight;
18861886
break;
18871887
case OP_MODULUS:
1888
- if(!iRight){
1888
+ if( !iRight ){
18891889
Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft);
18901890
return TH_ERROR;
18911891
}
18921892
iRes = iLeft%iRight;
18931893
break;
@@ -1913,11 +1913,17 @@
19131913
}
19141914
Th_SetResultInt(interp, iRes);
19151915
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
19161916
switch( pExpr->pOp->eOp ) {
19171917
case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
1918
- case OP_DIVIDE: Th_SetResultDouble(interp, fLeft/fRight); break;
1918
+ case OP_DIVIDE:
1919
+ if( fRight==0.0 ){
1920
+ Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
1921
+ return TH_ERROR;
1922
+ }
1923
+ Th_SetResultDouble(interp, fLeft/fRight);
1924
+ break;
19191925
case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break;
19201926
case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break;
19211927
case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break;
19221928
case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break;
19231929
case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break;
19241930
--- src/th.c
+++ src/th.c
@@ -1876,18 +1876,18 @@
1876 if( rc==TH_OK && eArgType==ARG_INTEGER ){
1877 int iRes = 0;
1878 switch( pExpr->pOp->eOp ) {
1879 case OP_MULTIPLY: iRes = iLeft*iRight; break;
1880 case OP_DIVIDE:
1881 if(!iRight){
1882 Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
1883 return TH_ERROR;
1884 }
1885 iRes = iLeft/iRight;
1886 break;
1887 case OP_MODULUS:
1888 if(!iRight){
1889 Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft);
1890 return TH_ERROR;
1891 }
1892 iRes = iLeft%iRight;
1893 break;
@@ -1913,11 +1913,17 @@
1913 }
1914 Th_SetResultInt(interp, iRes);
1915 }else if( rc==TH_OK && eArgType==ARG_NUMBER ){
1916 switch( pExpr->pOp->eOp ) {
1917 case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
1918 case OP_DIVIDE: Th_SetResultDouble(interp, fLeft/fRight); break;
 
 
 
 
 
 
1919 case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break;
1920 case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break;
1921 case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break;
1922 case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break;
1923 case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break;
1924
--- src/th.c
+++ src/th.c
@@ -1876,18 +1876,18 @@
1876 if( rc==TH_OK && eArgType==ARG_INTEGER ){
1877 int iRes = 0;
1878 switch( pExpr->pOp->eOp ) {
1879 case OP_MULTIPLY: iRes = iLeft*iRight; break;
1880 case OP_DIVIDE:
1881 if( !iRight ){
1882 Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
1883 return TH_ERROR;
1884 }
1885 iRes = iLeft/iRight;
1886 break;
1887 case OP_MODULUS:
1888 if( !iRight ){
1889 Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft);
1890 return TH_ERROR;
1891 }
1892 iRes = iLeft%iRight;
1893 break;
@@ -1913,11 +1913,17 @@
1913 }
1914 Th_SetResultInt(interp, iRes);
1915 }else if( rc==TH_OK && eArgType==ARG_NUMBER ){
1916 switch( pExpr->pOp->eOp ) {
1917 case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
1918 case OP_DIVIDE:
1919 if( fRight==0.0 ){
1920 Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
1921 return TH_ERROR;
1922 }
1923 Th_SetResultDouble(interp, fLeft/fRight);
1924 break;
1925 case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break;
1926 case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break;
1927 case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break;
1928 case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break;
1929 case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break;
1930
+115
--- src/th_main.c
+++ src/th_main.c
@@ -827,10 +827,124 @@
827827
rc = TH_ERROR;
828828
}
829829
re_free(pRe);
830830
return rc;
831831
}
832
+
833
+/*
834
+** TH command: http ?-asynchronous? ?--? url ?payload?
835
+**
836
+** Perform an HTTP or HTTPS request for the specified URL. If a
837
+** payload is present, it will be interpreted as text/plain and
838
+** the POST method will be used; otherwise, the GET method will
839
+** be used. Upon success, if the -asynchronous option is used, an
840
+** empty string is returned as the result; otherwise, the response
841
+** from the server is returned as the result. Synchronous requests
842
+** are not currently implemented.
843
+*/
844
+#define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?"
845
+static int httpCmd(
846
+ Th_Interp *interp,
847
+ void *p,
848
+ int argc,
849
+ const char **argv,
850
+ int *argl
851
+){
852
+ int nArg = 1;
853
+ int fAsynchronous = 0;
854
+ const char *zType, *zRegexp;
855
+ Blob payload;
856
+ ReCompiled *pRe = 0;
857
+ UrlData urlData;
858
+
859
+ if( argc<2 || argc>5 ){
860
+ return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
861
+ }
862
+ if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){
863
+ fAsynchronous = 1; nArg++;
864
+ }
865
+ if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
866
+ if( nArg+1!=argc && nArg+2!=argc ){
867
+ return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
868
+ }
869
+ memset(&urlData, '\0', sizeof(urlData));
870
+ url_parse_local(argv[nArg], 0, &urlData);
871
+ if( urlData.isSsh || urlData.isFile ){
872
+ Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
873
+ return TH_ERROR;
874
+ }
875
+ zRegexp = db_get("th1-uri-regexp", 0);
876
+ if( zRegexp && zRegexp[0] ){
877
+ const char *zErr = re_compile(&pRe, zRegexp, 0);
878
+ if( zErr ){
879
+ Th_SetResult(interp, zErr, -1);
880
+ return TH_ERROR;
881
+ }
882
+ }
883
+ if( !pRe || !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){
884
+ Th_SetResult(interp, "url not allowed", -1);
885
+ re_free(pRe);
886
+ return TH_ERROR;
887
+ }
888
+ re_free(pRe);
889
+ blob_zero(&payload);
890
+ if( nArg+2==argc ){
891
+ blob_append(&payload, argv[nArg+1], argl[nArg+1]);
892
+ zType = "POST";
893
+ }else{
894
+ zType = "GET";
895
+ }
896
+ if( fAsynchronous ){
897
+ const char *zSep, *zParams;
898
+ Blob hdr;
899
+ zParams = strrchr(argv[nArg], '?');
900
+ if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){
901
+ zSep = "";
902
+ }else{
903
+ zSep = "/";
904
+ }
905
+ blob_zero(&hdr);
906
+ blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n",
907
+ zType, zSep, urlData.path, zParams ? zParams : "");
908
+ if( urlData.proxyAuth ){
909
+ blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth);
910
+ }
911
+ if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){
912
+ char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]);
913
+ char *zEncoded = encode64(zCredentials, -1);
914
+ blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded);
915
+ fossil_free(zEncoded);
916
+ fossil_free(zCredentials);
917
+ }
918
+ blob_appendf(&hdr, "Host: %s\r\n"
919
+ "User-Agent: %s\r\n", urlData.hostname, get_user_agent());
920
+ if( zType[0]=='P' ){
921
+ blob_appendf(&hdr, "Content-Type: application/x-www-form-urlencoded\r\n"
922
+ "Content-Length: %d\r\n\r\n", blob_size(&payload));
923
+ }else{
924
+ blob_appendf(&hdr, "\r\n");
925
+ }
926
+ if( transport_open(&urlData) ){
927
+ Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0);
928
+ blob_reset(&hdr);
929
+ blob_reset(&payload);
930
+ return TH_ERROR;
931
+ }
932
+ transport_send(&urlData, &hdr);
933
+ transport_send(&urlData, &payload);
934
+ blob_reset(&hdr);
935
+ blob_reset(&payload);
936
+ transport_close(&urlData);
937
+ Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */
938
+ return TH_OK;
939
+ }else{
940
+ Th_ErrorMessage(interp,
941
+ "synchronous requests are not yet implemented", 0, 0);
942
+ blob_reset(&payload);
943
+ return TH_ERROR;
944
+ }
945
+}
832946
833947
/*
834948
** Make sure the interpreter has been initialized. Initialize it if
835949
** it has not been already.
836950
**
@@ -855,10 +969,11 @@
855969
{"enable_output", enableOutputCmd, 0},
856970
{"hascap", hascapCmd, 0},
857971
{"hasfeature", hasfeatureCmd, 0},
858972
{"html", putsCmd, (void*)&aFlags[0]},
859973
{"htmlize", htmlizeCmd, 0},
974
+ {"http", httpCmd, 0},
860975
{"linecount", linecntCmd, 0},
861976
{"puts", putsCmd, (void*)&aFlags[1]},
862977
{"query", queryCmd, 0},
863978
{"randhex", randhexCmd, 0},
864979
{"regexp", regexpCmd, 0},
865980
--- src/th_main.c
+++ src/th_main.c
@@ -827,10 +827,124 @@
827 rc = TH_ERROR;
828 }
829 re_free(pRe);
830 return rc;
831 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
832
833 /*
834 ** Make sure the interpreter has been initialized. Initialize it if
835 ** it has not been already.
836 **
@@ -855,10 +969,11 @@
855 {"enable_output", enableOutputCmd, 0},
856 {"hascap", hascapCmd, 0},
857 {"hasfeature", hasfeatureCmd, 0},
858 {"html", putsCmd, (void*)&aFlags[0]},
859 {"htmlize", htmlizeCmd, 0},
 
860 {"linecount", linecntCmd, 0},
861 {"puts", putsCmd, (void*)&aFlags[1]},
862 {"query", queryCmd, 0},
863 {"randhex", randhexCmd, 0},
864 {"regexp", regexpCmd, 0},
865
--- src/th_main.c
+++ src/th_main.c
@@ -827,10 +827,124 @@
827 rc = TH_ERROR;
828 }
829 re_free(pRe);
830 return rc;
831 }
832
833 /*
834 ** TH command: http ?-asynchronous? ?--? url ?payload?
835 **
836 ** Perform an HTTP or HTTPS request for the specified URL. If a
837 ** payload is present, it will be interpreted as text/plain and
838 ** the POST method will be used; otherwise, the GET method will
839 ** be used. Upon success, if the -asynchronous option is used, an
840 ** empty string is returned as the result; otherwise, the response
841 ** from the server is returned as the result. Synchronous requests
842 ** are not currently implemented.
843 */
844 #define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?"
845 static int httpCmd(
846 Th_Interp *interp,
847 void *p,
848 int argc,
849 const char **argv,
850 int *argl
851 ){
852 int nArg = 1;
853 int fAsynchronous = 0;
854 const char *zType, *zRegexp;
855 Blob payload;
856 ReCompiled *pRe = 0;
857 UrlData urlData;
858
859 if( argc<2 || argc>5 ){
860 return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
861 }
862 if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){
863 fAsynchronous = 1; nArg++;
864 }
865 if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
866 if( nArg+1!=argc && nArg+2!=argc ){
867 return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
868 }
869 memset(&urlData, '\0', sizeof(urlData));
870 url_parse_local(argv[nArg], 0, &urlData);
871 if( urlData.isSsh || urlData.isFile ){
872 Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
873 return TH_ERROR;
874 }
875 zRegexp = db_get("th1-uri-regexp", 0);
876 if( zRegexp && zRegexp[0] ){
877 const char *zErr = re_compile(&pRe, zRegexp, 0);
878 if( zErr ){
879 Th_SetResult(interp, zErr, -1);
880 return TH_ERROR;
881 }
882 }
883 if( !pRe || !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){
884 Th_SetResult(interp, "url not allowed", -1);
885 re_free(pRe);
886 return TH_ERROR;
887 }
888 re_free(pRe);
889 blob_zero(&payload);
890 if( nArg+2==argc ){
891 blob_append(&payload, argv[nArg+1], argl[nArg+1]);
892 zType = "POST";
893 }else{
894 zType = "GET";
895 }
896 if( fAsynchronous ){
897 const char *zSep, *zParams;
898 Blob hdr;
899 zParams = strrchr(argv[nArg], '?');
900 if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){
901 zSep = "";
902 }else{
903 zSep = "/";
904 }
905 blob_zero(&hdr);
906 blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n",
907 zType, zSep, urlData.path, zParams ? zParams : "");
908 if( urlData.proxyAuth ){
909 blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth);
910 }
911 if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){
912 char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]);
913 char *zEncoded = encode64(zCredentials, -1);
914 blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded);
915 fossil_free(zEncoded);
916 fossil_free(zCredentials);
917 }
918 blob_appendf(&hdr, "Host: %s\r\n"
919 "User-Agent: %s\r\n", urlData.hostname, get_user_agent());
920 if( zType[0]=='P' ){
921 blob_appendf(&hdr, "Content-Type: application/x-www-form-urlencoded\r\n"
922 "Content-Length: %d\r\n\r\n", blob_size(&payload));
923 }else{
924 blob_appendf(&hdr, "\r\n");
925 }
926 if( transport_open(&urlData) ){
927 Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0);
928 blob_reset(&hdr);
929 blob_reset(&payload);
930 return TH_ERROR;
931 }
932 transport_send(&urlData, &hdr);
933 transport_send(&urlData, &payload);
934 blob_reset(&hdr);
935 blob_reset(&payload);
936 transport_close(&urlData);
937 Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */
938 return TH_OK;
939 }else{
940 Th_ErrorMessage(interp,
941 "synchronous requests are not yet implemented", 0, 0);
942 blob_reset(&payload);
943 return TH_ERROR;
944 }
945 }
946
947 /*
948 ** Make sure the interpreter has been initialized. Initialize it if
949 ** it has not been already.
950 **
@@ -855,10 +969,11 @@
969 {"enable_output", enableOutputCmd, 0},
970 {"hascap", hascapCmd, 0},
971 {"hasfeature", hasfeatureCmd, 0},
972 {"html", putsCmd, (void*)&aFlags[0]},
973 {"htmlize", htmlizeCmd, 0},
974 {"http", httpCmd, 0},
975 {"linecount", linecntCmd, 0},
976 {"puts", putsCmd, (void*)&aFlags[1]},
977 {"query", queryCmd, 0},
978 {"randhex", randhexCmd, 0},
979 {"regexp", regexpCmd, 0},
980
+19 -3
--- src/timeline.c
+++ src/timeline.c
@@ -1111,10 +1111,11 @@
11111111
if( zType[0]=='a' ){
11121112
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
11131113
}else{
11141114
tmFlags = TIMELINE_GRAPH;
11151115
}
1116
+ url_add_parameter(&url, "n", mprintf("%d", nEntry));
11161117
if( P("ng")!=0 || zSearch!=0 ){
11171118
tmFlags &= ~TIMELINE_GRAPH;
11181119
url_add_parameter(&url, "ng", 0);
11191120
}
11201121
if( P("brbg")!=0 ){
@@ -1231,10 +1232,23 @@
12311232
}
12321233
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
12331234
}
12341235
blob_appendf(&desc, " of %z[%.10s]</a>",
12351236
href("%R/info/%s", zUuid), zUuid);
1237
+ if( (tmFlags & TIMELINE_UNHIDE)==0 ){
1238
+ if( p_rid ){
1239
+ url_add_parameter(&url, "p", zUuid);
1240
+ }
1241
+ if( d_rid ){
1242
+ if( p_rid ){
1243
+ /* If both p= and d= are set, we don't have the uuid of d yet. */
1244
+ zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
1245
+ }
1246
+ url_add_parameter(&url, "d", zUuid);
1247
+ }
1248
+ timeline_submenu(&url, "Unhide", "unhide", "", 0);
1249
+ }
12361250
}else if( f_rid && g.perm.Read ){
12371251
/* If f= is present, ignore all other parameters other than n= */
12381252
char *zUuid;
12391253
db_multi_exec(
12401254
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
@@ -1248,17 +1262,19 @@
12481262
if( useDividers ) timeline_add_dividers(0, f_rid);
12491263
blob_appendf(&desc, "Parents and children of check-in ");
12501264
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
12511265
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
12521266
tmFlags |= TIMELINE_DISJOINT;
1267
+ if( (tmFlags & TIMELINE_UNHIDE)==0 ){
1268
+ url_add_parameter(&url, "f", zUuid);
1269
+ timeline_submenu(&url, "Unhide", "unhide", "", 0);
1270
+ }
12531271
}else{
12541272
/* Otherwise, a timeline based on a span of time */
12551273
int n;
12561274
const char *zEType = "timeline item";
12571275
char *zDate;
1258
- char *zNEntry = mprintf("%d", nEntry);
1259
- url_add_parameter(&url, "n", zNEntry);
12601276
if( zUses ){
12611277
blob_appendf(&sql, " AND event.objid IN usesfile ");
12621278
}
12631279
if( renameOnly ){
12641280
blob_appendf(&sql, " AND event.objid IN rnfile ");
@@ -1944,11 +1960,11 @@
19441960
" AND blob.rid=c.cid"
19451961
);
19461962
while( db_step(&q)==SQLITE_ROW ){
19471963
const char *zUuid = db_column_text(&q, 0);
19481964
@ <li>
1949
- @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1965
+ @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)&amp;unhide">%S(zUuid)</a>
19501966
}
19511967
db_finalize(&q);
19521968
style_footer();
19531969
}
19541970
19551971
--- src/timeline.c
+++ src/timeline.c
@@ -1111,10 +1111,11 @@
1111 if( zType[0]=='a' ){
1112 tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
1113 }else{
1114 tmFlags = TIMELINE_GRAPH;
1115 }
 
1116 if( P("ng")!=0 || zSearch!=0 ){
1117 tmFlags &= ~TIMELINE_GRAPH;
1118 url_add_parameter(&url, "ng", 0);
1119 }
1120 if( P("brbg")!=0 ){
@@ -1231,10 +1232,23 @@
1231 }
1232 if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
1233 }
1234 blob_appendf(&desc, " of %z[%.10s]</a>",
1235 href("%R/info/%s", zUuid), zUuid);
 
 
 
 
 
 
 
 
 
 
 
 
 
1236 }else if( f_rid && g.perm.Read ){
1237 /* If f= is present, ignore all other parameters other than n= */
1238 char *zUuid;
1239 db_multi_exec(
1240 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
@@ -1248,17 +1262,19 @@
1248 if( useDividers ) timeline_add_dividers(0, f_rid);
1249 blob_appendf(&desc, "Parents and children of check-in ");
1250 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1251 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
1252 tmFlags |= TIMELINE_DISJOINT;
 
 
 
 
1253 }else{
1254 /* Otherwise, a timeline based on a span of time */
1255 int n;
1256 const char *zEType = "timeline item";
1257 char *zDate;
1258 char *zNEntry = mprintf("%d", nEntry);
1259 url_add_parameter(&url, "n", zNEntry);
1260 if( zUses ){
1261 blob_appendf(&sql, " AND event.objid IN usesfile ");
1262 }
1263 if( renameOnly ){
1264 blob_appendf(&sql, " AND event.objid IN rnfile ");
@@ -1944,11 +1960,11 @@
1944 " AND blob.rid=c.cid"
1945 );
1946 while( db_step(&q)==SQLITE_ROW ){
1947 const char *zUuid = db_column_text(&q, 0);
1948 @ <li>
1949 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1950 }
1951 db_finalize(&q);
1952 style_footer();
1953 }
1954
1955
--- src/timeline.c
+++ src/timeline.c
@@ -1111,10 +1111,11 @@
1111 if( zType[0]=='a' ){
1112 tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
1113 }else{
1114 tmFlags = TIMELINE_GRAPH;
1115 }
1116 url_add_parameter(&url, "n", mprintf("%d", nEntry));
1117 if( P("ng")!=0 || zSearch!=0 ){
1118 tmFlags &= ~TIMELINE_GRAPH;
1119 url_add_parameter(&url, "ng", 0);
1120 }
1121 if( P("brbg")!=0 ){
@@ -1231,10 +1232,23 @@
1232 }
1233 if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
1234 }
1235 blob_appendf(&desc, " of %z[%.10s]</a>",
1236 href("%R/info/%s", zUuid), zUuid);
1237 if( (tmFlags & TIMELINE_UNHIDE)==0 ){
1238 if( p_rid ){
1239 url_add_parameter(&url, "p", zUuid);
1240 }
1241 if( d_rid ){
1242 if( p_rid ){
1243 /* If both p= and d= are set, we don't have the uuid of d yet. */
1244 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
1245 }
1246 url_add_parameter(&url, "d", zUuid);
1247 }
1248 timeline_submenu(&url, "Unhide", "unhide", "", 0);
1249 }
1250 }else if( f_rid && g.perm.Read ){
1251 /* If f= is present, ignore all other parameters other than n= */
1252 char *zUuid;
1253 db_multi_exec(
1254 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
@@ -1248,17 +1262,19 @@
1262 if( useDividers ) timeline_add_dividers(0, f_rid);
1263 blob_appendf(&desc, "Parents and children of check-in ");
1264 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1265 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
1266 tmFlags |= TIMELINE_DISJOINT;
1267 if( (tmFlags & TIMELINE_UNHIDE)==0 ){
1268 url_add_parameter(&url, "f", zUuid);
1269 timeline_submenu(&url, "Unhide", "unhide", "", 0);
1270 }
1271 }else{
1272 /* Otherwise, a timeline based on a span of time */
1273 int n;
1274 const char *zEType = "timeline item";
1275 char *zDate;
 
 
1276 if( zUses ){
1277 blob_appendf(&sql, " AND event.objid IN usesfile ");
1278 }
1279 if( renameOnly ){
1280 blob_appendf(&sql, " AND event.objid IN rnfile ");
@@ -1944,11 +1960,11 @@
1960 " AND blob.rid=c.cid"
1961 );
1962 while( db_step(&q)==SQLITE_ROW ){
1963 const char *zUuid = db_column_text(&q, 0);
1964 @ <li>
1965 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)&amp;unhide">%S(zUuid)</a>
1966 }
1967 db_finalize(&q);
1968 style_footer();
1969 }
1970
1971
+9 -4
--- src/tkt.c
+++ src/tkt.c
@@ -513,15 +513,16 @@
513513
}
514514
515515
/*
516516
** Write a ticket into the repository.
517517
*/
518
-static void ticket_put(
518
+static int ticket_put(
519519
Blob *pTicket, /* The text of the ticket change record */
520520
const char *zTktId, /* The ticket to which this change is applied */
521521
int needMod /* True if moderation is needed */
522522
){
523
+ int result;
523524
int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
524525
if( rid==0 ){
525526
fossil_fatal("trouble committing ticket: %s", g.zErrMsg);
526527
}
527528
if( needMod ){
@@ -533,13 +534,14 @@
533534
}else{
534535
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
535536
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
536537
}
537538
manifest_crosslink_begin();
538
- manifest_crosslink(rid, pTicket);
539
+ result = (manifest_crosslink(rid, pTicket, MC_PERMIT_HOOKS)==0);
539540
assert( blob_is_reset(pTicket) );
540541
manifest_crosslink_end();
542
+ return result;
541543
}
542544
543545
/*
544546
** Subscript command: submit_ticket
545547
**
@@ -1344,11 +1346,14 @@
13441346
}
13451347
blob_appendf(&tktchng, "K %s\n", zTktUuid);
13461348
blob_appendf(&tktchng, "U %F\n", zUser);
13471349
md5sum_blob(&tktchng, &cksum);
13481350
blob_appendf(&tktchng, "Z %b\n", &cksum);
1349
- ticket_put(&tktchng, zTktUuid, 0);
1350
- printf("ticket %s succeeded for %s\n",
1351
+ if( ticket_put(&tktchng, zTktUuid, 0) ){
1352
+ fossil_fatal("%s\n", g.zErrMsg);
1353
+ }else{
1354
+ fossil_print("ticket %s succeeded for %s\n",
13511355
(eCmd==set?"set":"add"),zTktUuid);
1356
+ }
13521357
}
13531358
}
13541359
}
13551360
--- src/tkt.c
+++ src/tkt.c
@@ -513,15 +513,16 @@
513 }
514
515 /*
516 ** Write a ticket into the repository.
517 */
518 static void ticket_put(
519 Blob *pTicket, /* The text of the ticket change record */
520 const char *zTktId, /* The ticket to which this change is applied */
521 int needMod /* True if moderation is needed */
522 ){
 
523 int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
524 if( rid==0 ){
525 fossil_fatal("trouble committing ticket: %s", g.zErrMsg);
526 }
527 if( needMod ){
@@ -533,13 +534,14 @@
533 }else{
534 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
535 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
536 }
537 manifest_crosslink_begin();
538 manifest_crosslink(rid, pTicket);
539 assert( blob_is_reset(pTicket) );
540 manifest_crosslink_end();
 
541 }
542
543 /*
544 ** Subscript command: submit_ticket
545 **
@@ -1344,11 +1346,14 @@
1344 }
1345 blob_appendf(&tktchng, "K %s\n", zTktUuid);
1346 blob_appendf(&tktchng, "U %F\n", zUser);
1347 md5sum_blob(&tktchng, &cksum);
1348 blob_appendf(&tktchng, "Z %b\n", &cksum);
1349 ticket_put(&tktchng, zTktUuid, 0);
1350 printf("ticket %s succeeded for %s\n",
 
 
1351 (eCmd==set?"set":"add"),zTktUuid);
 
1352 }
1353 }
1354 }
1355
--- src/tkt.c
+++ src/tkt.c
@@ -513,15 +513,16 @@
513 }
514
515 /*
516 ** Write a ticket into the repository.
517 */
518 static int ticket_put(
519 Blob *pTicket, /* The text of the ticket change record */
520 const char *zTktId, /* The ticket to which this change is applied */
521 int needMod /* True if moderation is needed */
522 ){
523 int result;
524 int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
525 if( rid==0 ){
526 fossil_fatal("trouble committing ticket: %s", g.zErrMsg);
527 }
528 if( needMod ){
@@ -533,13 +534,14 @@
534 }else{
535 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
536 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
537 }
538 manifest_crosslink_begin();
539 result = (manifest_crosslink(rid, pTicket, MC_PERMIT_HOOKS)==0);
540 assert( blob_is_reset(pTicket) );
541 manifest_crosslink_end();
542 return result;
543 }
544
545 /*
546 ** Subscript command: submit_ticket
547 **
@@ -1344,11 +1346,14 @@
1346 }
1347 blob_appendf(&tktchng, "K %s\n", zTktUuid);
1348 blob_appendf(&tktchng, "U %F\n", zUser);
1349 md5sum_blob(&tktchng, &cksum);
1350 blob_appendf(&tktchng, "Z %b\n", &cksum);
1351 if( ticket_put(&tktchng, zTktUuid, 0) ){
1352 fossil_fatal("%s\n", g.zErrMsg);
1353 }else{
1354 fossil_print("ticket %s succeeded for %s\n",
1355 (eCmd==set?"set":"add"),zTktUuid);
1356 }
1357 }
1358 }
1359 }
1360
+244 -184
--- src/url.c
+++ src/url.c
@@ -39,10 +39,34 @@
3939
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
4040
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
4141
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
4242
#define URL_PROMPTED 0x010 /* Prompted for PW already */
4343
44
+/*
45
+** The URL related data used with this subsystem.
46
+*/
47
+struct UrlData {
48
+ /*
49
+ ** NOTE: These members MUST be kept in sync with the related ones in the
50
+ ** "Global" structure defined in "main.c".
51
+ */
52
+ int isFile; /* True if a "file:" url */
53
+ int isHttps; /* True if a "https:" url */
54
+ int isSsh; /* True if an "ssh:" url */
55
+ char *name; /* Hostname for http: or filename for file: */
56
+ char *hostname; /* The HOST: parameter on http headers */
57
+ char *protocol; /* "http" or "https" */
58
+ int port; /* TCP port number for http: or https: */
59
+ int dfltPort; /* The default port for the given protocol */
60
+ char *path; /* Pathname for http: */
61
+ char *user; /* User id for http: */
62
+ char *passwd; /* Password for http: */
63
+ char *canonical; /* Canonical representation of the URL */
64
+ char *proxyAuth; /* Proxy-Authorizer: string */
65
+ char *fossil; /* The fossil query parameter on ssh: */
66
+ unsigned flags; /* Boolean flags controlling URL processing */
67
+};
4468
#endif /* INTERFACE */
4569
4670
4771
/*
4872
** Convert a string to lower-case.
@@ -51,10 +75,201 @@
5175
while( *z ){
5276
*z = fossil_tolower(*z);
5377
z++;
5478
}
5579
}
80
+
81
+/*
82
+** Parse the given URL. Populate members of the provided UrlData structure
83
+** as follows:
84
+**
85
+** isFile True if FILE:
86
+** isHttps True if HTTPS:
87
+** isSsh True if SSH:
88
+** protocol "http" or "https" or "file"
89
+** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
90
+** port TCP port number for HTTP or HTTPS.
91
+** dfltPort Default TCP port number (80 or 443).
92
+** path Path name for HTTP or HTTPS.
93
+** user Userid.
94
+** passwd Password.
95
+** hostname HOST:PORT or just HOST if port is the default.
96
+** canonical The URL in canonical form, omitting the password
97
+**
98
+*/
99
+void url_parse_local(
100
+ const char *zUrl,
101
+ unsigned int urlFlags,
102
+ UrlData *pUrlData
103
+){
104
+ int i, j, c;
105
+ char *zFile = 0;
106
+
107
+ if( zUrl==0 ){
108
+ zUrl = db_get("last-sync-url", 0);
109
+ if( zUrl==0 ) return;
110
+ if( pUrlData->passwd==0 ){
111
+ pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
112
+ }
113
+ }
114
+
115
+ if( strncmp(zUrl, "http://", 7)==0
116
+ || strncmp(zUrl, "https://", 8)==0
117
+ || strncmp(zUrl, "ssh://", 6)==0
118
+ ){
119
+ int iStart;
120
+ char *zLogin;
121
+ char *zExe;
122
+ char cQuerySep = '?';
123
+
124
+ pUrlData->isFile = 0;
125
+ if( zUrl[4]=='s' ){
126
+ pUrlData->isHttps = 1;
127
+ pUrlData->protocol = "https";
128
+ pUrlData->dfltPort = 443;
129
+ iStart = 8;
130
+ }else if( zUrl[0]=='s' ){
131
+ pUrlData->isSsh = 1;
132
+ pUrlData->protocol = "ssh";
133
+ pUrlData->dfltPort = 22;
134
+ pUrlData->fossil = "fossil";
135
+ iStart = 6;
136
+ }else{
137
+ pUrlData->isHttps = 0;
138
+ pUrlData->protocol = "http";
139
+ pUrlData->dfltPort = 80;
140
+ iStart = 7;
141
+ }
142
+ for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
143
+ if( c=='@' ){
144
+ /* Parse up the user-id and password */
145
+ for(j=iStart; j<i && zUrl[j]!=':'; j++){}
146
+ pUrlData->user = mprintf("%.*s", j-iStart, &zUrl[iStart]);
147
+ dehttpize(pUrlData->user);
148
+ if( j<i ){
149
+ if( ( urlFlags & URL_REMEMBER ) && pUrlData->isSsh==0 ){
150
+ urlFlags |= URL_ASK_REMEMBER_PW;
151
+ }
152
+ pUrlData->passwd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
153
+ dehttpize(pUrlData->passwd);
154
+ }
155
+ if( pUrlData->isSsh ){
156
+ urlFlags &= ~URL_ASK_REMEMBER_PW;
157
+ }
158
+ zLogin = mprintf("%t@", pUrlData->user);
159
+ for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
160
+ pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
161
+ i = j;
162
+ }else{
163
+ for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
164
+ pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
165
+ zLogin = mprintf("");
166
+ }
167
+ url_tolower(pUrlData->name);
168
+ if( c==':' ){
169
+ pUrlData->port = 0;
170
+ i++;
171
+ while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
172
+ pUrlData->port = pUrlData->port*10 + c - '0';
173
+ i++;
174
+ }
175
+ pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
176
+ }else{
177
+ pUrlData->port = pUrlData->dfltPort;
178
+ pUrlData->hostname = pUrlData->name;
179
+ }
180
+ dehttpize(pUrlData->name);
181
+ pUrlData->path = mprintf("%s", &zUrl[i]);
182
+ for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
183
+ if( pUrlData->path[i] ){
184
+ pUrlData->path[i] = 0;
185
+ i++;
186
+ }
187
+ zExe = mprintf("");
188
+ while( pUrlData->path[i]!=0 ){
189
+ char *zName, *zValue;
190
+ zName = &pUrlData->path[i];
191
+ zValue = zName;
192
+ while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
193
+ if( pUrlData->path[i]=='=' ){
194
+ pUrlData->path[i] = 0;
195
+ i++;
196
+ zValue = &pUrlData->path[i];
197
+ while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; }
198
+ }
199
+ if( pUrlData->path[i] ){
200
+ pUrlData->path[i] = 0;
201
+ i++;
202
+ }
203
+ if( fossil_strcmp(zName,"fossil")==0 ){
204
+ pUrlData->fossil = zValue;
205
+ dehttpize(pUrlData->fossil);
206
+ zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
207
+ cQuerySep = '&';
208
+ }
209
+ }
210
+
211
+ dehttpize(pUrlData->path);
212
+ if( pUrlData->dfltPort==pUrlData->port ){
213
+ pUrlData->canonical = mprintf(
214
+ "%s://%s%T%T%s",
215
+ pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
216
+ );
217
+ }else{
218
+ pUrlData->canonical = mprintf(
219
+ "%s://%s%T:%d%T%s",
220
+ pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
221
+ pUrlData->path, zExe
222
+ );
223
+ }
224
+ if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
225
+ free(zLogin);
226
+ }else if( strncmp(zUrl, "file:", 5)==0 ){
227
+ pUrlData->isFile = 1;
228
+ if( zUrl[5]=='/' && zUrl[6]=='/' ){
229
+ i = 7;
230
+ }else{
231
+ i = 5;
232
+ }
233
+ zFile = mprintf("%s", &zUrl[i]);
234
+ }else if( file_isfile(zUrl) ){
235
+ pUrlData->isFile = 1;
236
+ zFile = mprintf("%s", zUrl);
237
+ }else if( file_isdir(zUrl)==1 ){
238
+ zFile = mprintf("%s/FOSSIL", zUrl);
239
+ if( file_isfile(zFile) ){
240
+ pUrlData->isFile = 1;
241
+ }else{
242
+ free(zFile);
243
+ fossil_fatal("unknown repository: %s", zUrl);
244
+ }
245
+ }else{
246
+ fossil_fatal("unknown repository: %s", zUrl);
247
+ }
248
+ if( urlFlags ) pUrlData->flags = urlFlags;
249
+ if( pUrlData->isFile ){
250
+ Blob cfile;
251
+ dehttpize(zFile);
252
+ file_canonical_name(zFile, &cfile, 0);
253
+ free(zFile);
254
+ pUrlData->protocol = "file";
255
+ pUrlData->path = "";
256
+ pUrlData->name = mprintf("%b", &cfile);
257
+ pUrlData->canonical = mprintf("file://%T", pUrlData->name);
258
+ blob_reset(&cfile);
259
+ }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
260
+ url_prompt_for_password_local(pUrlData);
261
+ }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
262
+ if( isatty(fileno(stdin)) ){
263
+ if( save_password_prompt(pUrlData->passwd) ){
264
+ pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
265
+ }else{
266
+ pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
267
+ }
268
+ }
269
+ }
270
+}
56271
57272
/*
58273
** Parse the given URL, which describes a sync server. Populate variables
59274
** in the global "g" structure as follows:
60275
**
@@ -79,175 +294,11 @@
79294
**
80295
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
81296
**
82297
*/
83298
void url_parse(const char *zUrl, unsigned int urlFlags){
84
- int i, j, c;
85
- char *zFile = 0;
86
-
87
- if( zUrl==0 ){
88
- zUrl = db_get("last-sync-url", 0);
89
- if( zUrl==0 ) return;
90
- if( g.urlPasswd==0 ){
91
- g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
92
- }
93
- }
94
-
95
- if( strncmp(zUrl, "http://", 7)==0
96
- || strncmp(zUrl, "https://", 8)==0
97
- || strncmp(zUrl, "ssh://", 6)==0
98
- ){
99
- int iStart;
100
- char *zLogin;
101
- char *zExe;
102
- char cQuerySep = '?';
103
-
104
- g.urlIsFile = 0;
105
- if( zUrl[4]=='s' ){
106
- g.urlIsHttps = 1;
107
- g.urlProtocol = "https";
108
- g.urlDfltPort = 443;
109
- iStart = 8;
110
- }else if( zUrl[0]=='s' ){
111
- g.urlIsSsh = 1;
112
- g.urlProtocol = "ssh";
113
- g.urlDfltPort = 22;
114
- g.urlFossil = "fossil";
115
- iStart = 6;
116
- }else{
117
- g.urlIsHttps = 0;
118
- g.urlProtocol = "http";
119
- g.urlDfltPort = 80;
120
- iStart = 7;
121
- }
122
- for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
123
- if( c=='@' ){
124
- /* Parse up the user-id and password */
125
- for(j=iStart; j<i && zUrl[j]!=':'; j++){}
126
- g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
127
- dehttpize(g.urlUser);
128
- if( j<i ){
129
- if( ( urlFlags & URL_REMEMBER ) && g.urlIsSsh==0 ){
130
- urlFlags |= URL_ASK_REMEMBER_PW;
131
- }
132
- g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
133
- dehttpize(g.urlPasswd);
134
- }
135
- if( g.urlIsSsh ){
136
- urlFlags &= ~URL_ASK_REMEMBER_PW;
137
- }
138
- zLogin = mprintf("%t@", g.urlUser);
139
- for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
140
- g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
141
- i = j;
142
- }else{
143
- for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
144
- g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
145
- zLogin = mprintf("");
146
- }
147
- url_tolower(g.urlName);
148
- if( c==':' ){
149
- g.urlPort = 0;
150
- i++;
151
- while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
152
- g.urlPort = g.urlPort*10 + c - '0';
153
- i++;
154
- }
155
- g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
156
- }else{
157
- g.urlPort = g.urlDfltPort;
158
- g.urlHostname = g.urlName;
159
- }
160
- dehttpize(g.urlName);
161
- g.urlPath = mprintf("%s", &zUrl[i]);
162
- for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
163
- if( g.urlPath[i] ){
164
- g.urlPath[i] = 0;
165
- i++;
166
- }
167
- zExe = mprintf("");
168
- while( g.urlPath[i]!=0 ){
169
- char *zName, *zValue;
170
- zName = &g.urlPath[i];
171
- zValue = zName;
172
- while( g.urlPath[i] && g.urlPath[i]!='=' ){ i++; }
173
- if( g.urlPath[i]=='=' ){
174
- g.urlPath[i] = 0;
175
- i++;
176
- zValue = &g.urlPath[i];
177
- while( g.urlPath[i] && g.urlPath[i]!='&' ){ i++; }
178
- }
179
- if( g.urlPath[i] ){
180
- g.urlPath[i] = 0;
181
- i++;
182
- }
183
- if( fossil_strcmp(zName,"fossil")==0 ){
184
- g.urlFossil = zValue;
185
- dehttpize(g.urlFossil);
186
- zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
187
- cQuerySep = '&';
188
- }
189
- }
190
-
191
- dehttpize(g.urlPath);
192
- if( g.urlDfltPort==g.urlPort ){
193
- g.urlCanonical = mprintf(
194
- "%s://%s%T%T%s",
195
- g.urlProtocol, zLogin, g.urlName, g.urlPath, zExe
196
- );
197
- }else{
198
- g.urlCanonical = mprintf(
199
- "%s://%s%T:%d%T%s",
200
- g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath, zExe
201
- );
202
- }
203
- if( g.urlIsSsh && g.urlPath[1] ) g.urlPath++;
204
- free(zLogin);
205
- }else if( strncmp(zUrl, "file:", 5)==0 ){
206
- g.urlIsFile = 1;
207
- if( zUrl[5]=='/' && zUrl[6]=='/' ){
208
- i = 7;
209
- }else{
210
- i = 5;
211
- }
212
- zFile = mprintf("%s", &zUrl[i]);
213
- }else if( file_isfile(zUrl) ){
214
- g.urlIsFile = 1;
215
- zFile = mprintf("%s", zUrl);
216
- }else if( file_isdir(zUrl)==1 ){
217
- zFile = mprintf("%s/FOSSIL", zUrl);
218
- if( file_isfile(zFile) ){
219
- g.urlIsFile = 1;
220
- }else{
221
- free(zFile);
222
- fossil_fatal("unknown repository: %s", zUrl);
223
- }
224
- }else{
225
- fossil_fatal("unknown repository: %s", zUrl);
226
- }
227
- if( urlFlags ) g.urlFlags = urlFlags;
228
- if( g.urlIsFile ){
229
- Blob cfile;
230
- dehttpize(zFile);
231
- file_canonical_name(zFile, &cfile, 0);
232
- free(zFile);
233
- g.urlProtocol = "file";
234
- g.urlPath = "";
235
- g.urlName = mprintf("%b", &cfile);
236
- g.urlCanonical = mprintf("file://%T", g.urlName);
237
- blob_reset(&cfile);
238
- }else if( g.urlUser!=0 && g.urlPasswd==0 && (urlFlags & URL_PROMPT_PW) ){
239
- url_prompt_for_password();
240
- }else if( g.urlUser!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
241
- if( isatty(fileno(stdin)) ){
242
- if( save_password_prompt() ){
243
- g.urlFlags = urlFlags |= URL_REMEMBER_PW;
244
- }else{
245
- g.urlFlags = urlFlags &= ~URL_REMEMBER_PW;
246
- }
247
- }
248
- }
299
+ url_parse_local(zUrl, urlFlags, GLOBAL_URL());
249300
}
250301
251302
/*
252303
** COMMAND: test-urlparser
253304
**
@@ -439,35 +490,44 @@
439490
}
440491
return blob_str(&p->url);
441492
}
442493
443494
/*
444
-** Prompt the user for the password for g.urlUser. Store the result
445
-** in g.urlPasswd.
446
-*/
447
-void url_prompt_for_password(void){
448
- if( g.urlIsSsh || g.urlIsFile ) return;
449
- if( isatty(fileno(stdin))
450
- && (g.urlFlags & URL_PROMPT_PW)!=0
451
- && (g.urlFlags & URL_PROMPTED)==0
452
- ){
453
- g.urlFlags |= URL_PROMPTED;
454
- g.urlPasswd = prompt_for_user_password(g.urlUser);
455
- if( g.urlPasswd[0]
456
- && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
457
- ){
458
- if( save_password_prompt() ){
459
- g.urlFlags |= URL_REMEMBER_PW;
460
- }else{
461
- g.urlFlags &= ~URL_REMEMBER_PW;
495
+** Prompt the user for the password that corresponds to the "user" member of
496
+** the provided UrlData structure. Store the result into the "passwd" member
497
+** of the provided UrlData structure.
498
+*/
499
+void url_prompt_for_password_local(UrlData *pUrlData){
500
+ if( pUrlData->isSsh || pUrlData->isFile ) return;
501
+ if( isatty(fileno(stdin))
502
+ && (pUrlData->flags & URL_PROMPT_PW)!=0
503
+ && (pUrlData->flags & URL_PROMPTED)==0
504
+ ){
505
+ pUrlData->flags |= URL_PROMPTED;
506
+ pUrlData->passwd = prompt_for_user_password(pUrlData->user);
507
+ if( pUrlData->passwd[0]
508
+ && (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
509
+ ){
510
+ if( save_password_prompt(pUrlData->passwd) ){
511
+ pUrlData->flags |= URL_REMEMBER_PW;
512
+ }else{
513
+ pUrlData->flags &= ~URL_REMEMBER_PW;
462514
}
463515
}
464516
}else{
465517
fossil_fatal("missing or incorrect password for user \"%s\"",
466
- g.urlUser);
518
+ pUrlData->user);
467519
}
468520
}
521
+
522
+/*
523
+** Prompt the user for the password for g.urlUser. Store the result
524
+** in g.urlPasswd.
525
+*/
526
+void url_prompt_for_password(void){
527
+ url_prompt_for_password_local(GLOBAL_URL());
528
+}
469529
470530
/*
471531
** Remember the URL and password if requested.
472532
*/
473533
void url_remember(void){
474534
--- src/url.c
+++ src/url.c
@@ -39,10 +39,34 @@
39 #define URL_REMEMBER 0x002 /* Remember the url for later reuse */
40 #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
41 #define URL_REMEMBER_PW 0x008 /* Should remember pw */
42 #define URL_PROMPTED 0x010 /* Prompted for PW already */
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44 #endif /* INTERFACE */
45
46
47 /*
48 ** Convert a string to lower-case.
@@ -51,10 +75,201 @@
51 while( *z ){
52 *z = fossil_tolower(*z);
53 z++;
54 }
55 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
57 /*
58 ** Parse the given URL, which describes a sync server. Populate variables
59 ** in the global "g" structure as follows:
60 **
@@ -79,175 +294,11 @@
79 **
80 ** ssh://userid@host:port/path?fossil=path/to/fossil.exe
81 **
82 */
83 void url_parse(const char *zUrl, unsigned int urlFlags){
84 int i, j, c;
85 char *zFile = 0;
86
87 if( zUrl==0 ){
88 zUrl = db_get("last-sync-url", 0);
89 if( zUrl==0 ) return;
90 if( g.urlPasswd==0 ){
91 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
92 }
93 }
94
95 if( strncmp(zUrl, "http://", 7)==0
96 || strncmp(zUrl, "https://", 8)==0
97 || strncmp(zUrl, "ssh://", 6)==0
98 ){
99 int iStart;
100 char *zLogin;
101 char *zExe;
102 char cQuerySep = '?';
103
104 g.urlIsFile = 0;
105 if( zUrl[4]=='s' ){
106 g.urlIsHttps = 1;
107 g.urlProtocol = "https";
108 g.urlDfltPort = 443;
109 iStart = 8;
110 }else if( zUrl[0]=='s' ){
111 g.urlIsSsh = 1;
112 g.urlProtocol = "ssh";
113 g.urlDfltPort = 22;
114 g.urlFossil = "fossil";
115 iStart = 6;
116 }else{
117 g.urlIsHttps = 0;
118 g.urlProtocol = "http";
119 g.urlDfltPort = 80;
120 iStart = 7;
121 }
122 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
123 if( c=='@' ){
124 /* Parse up the user-id and password */
125 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
126 g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
127 dehttpize(g.urlUser);
128 if( j<i ){
129 if( ( urlFlags & URL_REMEMBER ) && g.urlIsSsh==0 ){
130 urlFlags |= URL_ASK_REMEMBER_PW;
131 }
132 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
133 dehttpize(g.urlPasswd);
134 }
135 if( g.urlIsSsh ){
136 urlFlags &= ~URL_ASK_REMEMBER_PW;
137 }
138 zLogin = mprintf("%t@", g.urlUser);
139 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
140 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
141 i = j;
142 }else{
143 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
144 g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
145 zLogin = mprintf("");
146 }
147 url_tolower(g.urlName);
148 if( c==':' ){
149 g.urlPort = 0;
150 i++;
151 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
152 g.urlPort = g.urlPort*10 + c - '0';
153 i++;
154 }
155 g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
156 }else{
157 g.urlPort = g.urlDfltPort;
158 g.urlHostname = g.urlName;
159 }
160 dehttpize(g.urlName);
161 g.urlPath = mprintf("%s", &zUrl[i]);
162 for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
163 if( g.urlPath[i] ){
164 g.urlPath[i] = 0;
165 i++;
166 }
167 zExe = mprintf("");
168 while( g.urlPath[i]!=0 ){
169 char *zName, *zValue;
170 zName = &g.urlPath[i];
171 zValue = zName;
172 while( g.urlPath[i] && g.urlPath[i]!='=' ){ i++; }
173 if( g.urlPath[i]=='=' ){
174 g.urlPath[i] = 0;
175 i++;
176 zValue = &g.urlPath[i];
177 while( g.urlPath[i] && g.urlPath[i]!='&' ){ i++; }
178 }
179 if( g.urlPath[i] ){
180 g.urlPath[i] = 0;
181 i++;
182 }
183 if( fossil_strcmp(zName,"fossil")==0 ){
184 g.urlFossil = zValue;
185 dehttpize(g.urlFossil);
186 zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
187 cQuerySep = '&';
188 }
189 }
190
191 dehttpize(g.urlPath);
192 if( g.urlDfltPort==g.urlPort ){
193 g.urlCanonical = mprintf(
194 "%s://%s%T%T%s",
195 g.urlProtocol, zLogin, g.urlName, g.urlPath, zExe
196 );
197 }else{
198 g.urlCanonical = mprintf(
199 "%s://%s%T:%d%T%s",
200 g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath, zExe
201 );
202 }
203 if( g.urlIsSsh && g.urlPath[1] ) g.urlPath++;
204 free(zLogin);
205 }else if( strncmp(zUrl, "file:", 5)==0 ){
206 g.urlIsFile = 1;
207 if( zUrl[5]=='/' && zUrl[6]=='/' ){
208 i = 7;
209 }else{
210 i = 5;
211 }
212 zFile = mprintf("%s", &zUrl[i]);
213 }else if( file_isfile(zUrl) ){
214 g.urlIsFile = 1;
215 zFile = mprintf("%s", zUrl);
216 }else if( file_isdir(zUrl)==1 ){
217 zFile = mprintf("%s/FOSSIL", zUrl);
218 if( file_isfile(zFile) ){
219 g.urlIsFile = 1;
220 }else{
221 free(zFile);
222 fossil_fatal("unknown repository: %s", zUrl);
223 }
224 }else{
225 fossil_fatal("unknown repository: %s", zUrl);
226 }
227 if( urlFlags ) g.urlFlags = urlFlags;
228 if( g.urlIsFile ){
229 Blob cfile;
230 dehttpize(zFile);
231 file_canonical_name(zFile, &cfile, 0);
232 free(zFile);
233 g.urlProtocol = "file";
234 g.urlPath = "";
235 g.urlName = mprintf("%b", &cfile);
236 g.urlCanonical = mprintf("file://%T", g.urlName);
237 blob_reset(&cfile);
238 }else if( g.urlUser!=0 && g.urlPasswd==0 && (urlFlags & URL_PROMPT_PW) ){
239 url_prompt_for_password();
240 }else if( g.urlUser!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
241 if( isatty(fileno(stdin)) ){
242 if( save_password_prompt() ){
243 g.urlFlags = urlFlags |= URL_REMEMBER_PW;
244 }else{
245 g.urlFlags = urlFlags &= ~URL_REMEMBER_PW;
246 }
247 }
248 }
249 }
250
251 /*
252 ** COMMAND: test-urlparser
253 **
@@ -439,35 +490,44 @@
439 }
440 return blob_str(&p->url);
441 }
442
443 /*
444 ** Prompt the user for the password for g.urlUser. Store the result
445 ** in g.urlPasswd.
446 */
447 void url_prompt_for_password(void){
448 if( g.urlIsSsh || g.urlIsFile ) return;
449 if( isatty(fileno(stdin))
450 && (g.urlFlags & URL_PROMPT_PW)!=0
451 && (g.urlFlags & URL_PROMPTED)==0
452 ){
453 g.urlFlags |= URL_PROMPTED;
454 g.urlPasswd = prompt_for_user_password(g.urlUser);
455 if( g.urlPasswd[0]
456 && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
457 ){
458 if( save_password_prompt() ){
459 g.urlFlags |= URL_REMEMBER_PW;
460 }else{
461 g.urlFlags &= ~URL_REMEMBER_PW;
 
462 }
463 }
464 }else{
465 fossil_fatal("missing or incorrect password for user \"%s\"",
466 g.urlUser);
467 }
468 }
 
 
 
 
 
 
 
 
469
470 /*
471 ** Remember the URL and password if requested.
472 */
473 void url_remember(void){
474
--- src/url.c
+++ src/url.c
@@ -39,10 +39,34 @@
39 #define URL_REMEMBER 0x002 /* Remember the url for later reuse */
40 #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
41 #define URL_REMEMBER_PW 0x008 /* Should remember pw */
42 #define URL_PROMPTED 0x010 /* Prompted for PW already */
43
44 /*
45 ** The URL related data used with this subsystem.
46 */
47 struct UrlData {
48 /*
49 ** NOTE: These members MUST be kept in sync with the related ones in the
50 ** "Global" structure defined in "main.c".
51 */
52 int isFile; /* True if a "file:" url */
53 int isHttps; /* True if a "https:" url */
54 int isSsh; /* True if an "ssh:" url */
55 char *name; /* Hostname for http: or filename for file: */
56 char *hostname; /* The HOST: parameter on http headers */
57 char *protocol; /* "http" or "https" */
58 int port; /* TCP port number for http: or https: */
59 int dfltPort; /* The default port for the given protocol */
60 char *path; /* Pathname for http: */
61 char *user; /* User id for http: */
62 char *passwd; /* Password for http: */
63 char *canonical; /* Canonical representation of the URL */
64 char *proxyAuth; /* Proxy-Authorizer: string */
65 char *fossil; /* The fossil query parameter on ssh: */
66 unsigned flags; /* Boolean flags controlling URL processing */
67 };
68 #endif /* INTERFACE */
69
70
71 /*
72 ** Convert a string to lower-case.
@@ -51,10 +75,201 @@
75 while( *z ){
76 *z = fossil_tolower(*z);
77 z++;
78 }
79 }
80
81 /*
82 ** Parse the given URL. Populate members of the provided UrlData structure
83 ** as follows:
84 **
85 ** isFile True if FILE:
86 ** isHttps True if HTTPS:
87 ** isSsh True if SSH:
88 ** protocol "http" or "https" or "file"
89 ** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
90 ** port TCP port number for HTTP or HTTPS.
91 ** dfltPort Default TCP port number (80 or 443).
92 ** path Path name for HTTP or HTTPS.
93 ** user Userid.
94 ** passwd Password.
95 ** hostname HOST:PORT or just HOST if port is the default.
96 ** canonical The URL in canonical form, omitting the password
97 **
98 */
99 void url_parse_local(
100 const char *zUrl,
101 unsigned int urlFlags,
102 UrlData *pUrlData
103 ){
104 int i, j, c;
105 char *zFile = 0;
106
107 if( zUrl==0 ){
108 zUrl = db_get("last-sync-url", 0);
109 if( zUrl==0 ) return;
110 if( pUrlData->passwd==0 ){
111 pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
112 }
113 }
114
115 if( strncmp(zUrl, "http://", 7)==0
116 || strncmp(zUrl, "https://", 8)==0
117 || strncmp(zUrl, "ssh://", 6)==0
118 ){
119 int iStart;
120 char *zLogin;
121 char *zExe;
122 char cQuerySep = '?';
123
124 pUrlData->isFile = 0;
125 if( zUrl[4]=='s' ){
126 pUrlData->isHttps = 1;
127 pUrlData->protocol = "https";
128 pUrlData->dfltPort = 443;
129 iStart = 8;
130 }else if( zUrl[0]=='s' ){
131 pUrlData->isSsh = 1;
132 pUrlData->protocol = "ssh";
133 pUrlData->dfltPort = 22;
134 pUrlData->fossil = "fossil";
135 iStart = 6;
136 }else{
137 pUrlData->isHttps = 0;
138 pUrlData->protocol = "http";
139 pUrlData->dfltPort = 80;
140 iStart = 7;
141 }
142 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
143 if( c=='@' ){
144 /* Parse up the user-id and password */
145 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
146 pUrlData->user = mprintf("%.*s", j-iStart, &zUrl[iStart]);
147 dehttpize(pUrlData->user);
148 if( j<i ){
149 if( ( urlFlags & URL_REMEMBER ) && pUrlData->isSsh==0 ){
150 urlFlags |= URL_ASK_REMEMBER_PW;
151 }
152 pUrlData->passwd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
153 dehttpize(pUrlData->passwd);
154 }
155 if( pUrlData->isSsh ){
156 urlFlags &= ~URL_ASK_REMEMBER_PW;
157 }
158 zLogin = mprintf("%t@", pUrlData->user);
159 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
160 pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
161 i = j;
162 }else{
163 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
164 pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
165 zLogin = mprintf("");
166 }
167 url_tolower(pUrlData->name);
168 if( c==':' ){
169 pUrlData->port = 0;
170 i++;
171 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
172 pUrlData->port = pUrlData->port*10 + c - '0';
173 i++;
174 }
175 pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
176 }else{
177 pUrlData->port = pUrlData->dfltPort;
178 pUrlData->hostname = pUrlData->name;
179 }
180 dehttpize(pUrlData->name);
181 pUrlData->path = mprintf("%s", &zUrl[i]);
182 for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
183 if( pUrlData->path[i] ){
184 pUrlData->path[i] = 0;
185 i++;
186 }
187 zExe = mprintf("");
188 while( pUrlData->path[i]!=0 ){
189 char *zName, *zValue;
190 zName = &pUrlData->path[i];
191 zValue = zName;
192 while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
193 if( pUrlData->path[i]=='=' ){
194 pUrlData->path[i] = 0;
195 i++;
196 zValue = &pUrlData->path[i];
197 while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; }
198 }
199 if( pUrlData->path[i] ){
200 pUrlData->path[i] = 0;
201 i++;
202 }
203 if( fossil_strcmp(zName,"fossil")==0 ){
204 pUrlData->fossil = zValue;
205 dehttpize(pUrlData->fossil);
206 zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
207 cQuerySep = '&';
208 }
209 }
210
211 dehttpize(pUrlData->path);
212 if( pUrlData->dfltPort==pUrlData->port ){
213 pUrlData->canonical = mprintf(
214 "%s://%s%T%T%s",
215 pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
216 );
217 }else{
218 pUrlData->canonical = mprintf(
219 "%s://%s%T:%d%T%s",
220 pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
221 pUrlData->path, zExe
222 );
223 }
224 if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
225 free(zLogin);
226 }else if( strncmp(zUrl, "file:", 5)==0 ){
227 pUrlData->isFile = 1;
228 if( zUrl[5]=='/' && zUrl[6]=='/' ){
229 i = 7;
230 }else{
231 i = 5;
232 }
233 zFile = mprintf("%s", &zUrl[i]);
234 }else if( file_isfile(zUrl) ){
235 pUrlData->isFile = 1;
236 zFile = mprintf("%s", zUrl);
237 }else if( file_isdir(zUrl)==1 ){
238 zFile = mprintf("%s/FOSSIL", zUrl);
239 if( file_isfile(zFile) ){
240 pUrlData->isFile = 1;
241 }else{
242 free(zFile);
243 fossil_fatal("unknown repository: %s", zUrl);
244 }
245 }else{
246 fossil_fatal("unknown repository: %s", zUrl);
247 }
248 if( urlFlags ) pUrlData->flags = urlFlags;
249 if( pUrlData->isFile ){
250 Blob cfile;
251 dehttpize(zFile);
252 file_canonical_name(zFile, &cfile, 0);
253 free(zFile);
254 pUrlData->protocol = "file";
255 pUrlData->path = "";
256 pUrlData->name = mprintf("%b", &cfile);
257 pUrlData->canonical = mprintf("file://%T", pUrlData->name);
258 blob_reset(&cfile);
259 }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
260 url_prompt_for_password_local(pUrlData);
261 }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
262 if( isatty(fileno(stdin)) ){
263 if( save_password_prompt(pUrlData->passwd) ){
264 pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
265 }else{
266 pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
267 }
268 }
269 }
270 }
271
272 /*
273 ** Parse the given URL, which describes a sync server. Populate variables
274 ** in the global "g" structure as follows:
275 **
@@ -79,175 +294,11 @@
294 **
295 ** ssh://userid@host:port/path?fossil=path/to/fossil.exe
296 **
297 */
298 void url_parse(const char *zUrl, unsigned int urlFlags){
299 url_parse_local(zUrl, urlFlags, GLOBAL_URL());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300 }
301
302 /*
303 ** COMMAND: test-urlparser
304 **
@@ -439,35 +490,44 @@
490 }
491 return blob_str(&p->url);
492 }
493
494 /*
495 ** Prompt the user for the password that corresponds to the "user" member of
496 ** the provided UrlData structure. Store the result into the "passwd" member
497 ** of the provided UrlData structure.
498 */
499 void url_prompt_for_password_local(UrlData *pUrlData){
500 if( pUrlData->isSsh || pUrlData->isFile ) return;
501 if( isatty(fileno(stdin))
502 && (pUrlData->flags & URL_PROMPT_PW)!=0
503 && (pUrlData->flags & URL_PROMPTED)==0
504 ){
505 pUrlData->flags |= URL_PROMPTED;
506 pUrlData->passwd = prompt_for_user_password(pUrlData->user);
507 if( pUrlData->passwd[0]
508 && (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
509 ){
510 if( save_password_prompt(pUrlData->passwd) ){
511 pUrlData->flags |= URL_REMEMBER_PW;
512 }else{
513 pUrlData->flags &= ~URL_REMEMBER_PW;
514 }
515 }
516 }else{
517 fossil_fatal("missing or incorrect password for user \"%s\"",
518 pUrlData->user);
519 }
520 }
521
522 /*
523 ** Prompt the user for the password for g.urlUser. Store the result
524 ** in g.urlPasswd.
525 */
526 void url_prompt_for_password(void){
527 url_prompt_for_password_local(GLOBAL_URL());
528 }
529
530 /*
531 ** Remember the URL and password if requested.
532 */
533 void url_remember(void){
534
+2 -2
--- src/user.c
+++ src/user.c
@@ -132,15 +132,15 @@
132132
}
133133
134134
/*
135135
** Prompt to save Fossil user password
136136
*/
137
-int save_password_prompt(){
137
+int save_password_prompt(const char *passwd){
138138
Blob x;
139139
char c;
140140
const char *old = db_get("last-sync-pw", 0);
141
- if( (old!=0) && fossil_strcmp(unobscure(old), g.urlPasswd)==0 ){
141
+ if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){
142142
return 0;
143143
}
144144
prompt_user("remember password (Y/n)? ", &x);
145145
c = blob_str(&x)[0];
146146
blob_reset(&x);
147147
--- src/user.c
+++ src/user.c
@@ -132,15 +132,15 @@
132 }
133
134 /*
135 ** Prompt to save Fossil user password
136 */
137 int save_password_prompt(){
138 Blob x;
139 char c;
140 const char *old = db_get("last-sync-pw", 0);
141 if( (old!=0) && fossil_strcmp(unobscure(old), g.urlPasswd)==0 ){
142 return 0;
143 }
144 prompt_user("remember password (Y/n)? ", &x);
145 c = blob_str(&x)[0];
146 blob_reset(&x);
147
--- src/user.c
+++ src/user.c
@@ -132,15 +132,15 @@
132 }
133
134 /*
135 ** Prompt to save Fossil user password
136 */
137 int save_password_prompt(const char *passwd){
138 Blob x;
139 char c;
140 const char *old = db_get("last-sync-pw", 0);
141 if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){
142 return 0;
143 }
144 prompt_user("remember password (Y/n)? ", &x);
145 c = blob_str(&x)[0];
146 blob_reset(&x);
147
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -294,11 +294,11 @@
294294
moderation_table_create();
295295
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
296296
}
297297
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
298298
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
299
- manifest_crosslink(nrid, pWiki);
299
+ manifest_crosslink(nrid, pWiki, MC_NONE);
300300
}
301301
302302
/*
303303
** Formal names and common names for the various wiki styles.
304304
*/
305305
--- src/wiki.c
+++ src/wiki.c
@@ -294,11 +294,11 @@
294 moderation_table_create();
295 db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
296 }
297 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
298 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
299 manifest_crosslink(nrid, pWiki);
300 }
301
302 /*
303 ** Formal names and common names for the various wiki styles.
304 */
305
--- src/wiki.c
+++ src/wiki.c
@@ -294,11 +294,11 @@
294 moderation_table_create();
295 db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
296 }
297 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
298 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
299 manifest_crosslink(nrid, pWiki, MC_NONE);
300 }
301
302 /*
303 ** Formal names and common names for the various wiki styles.
304 */
305
+77 -32
--- src/xfer.c
+++ src/xfer.c
@@ -191,11 +191,11 @@
191191
if( rid==0 ){
192192
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
193193
blob_reset(&content);
194194
}else{
195195
if( !isPriv ) content_make_public(rid);
196
- manifest_crosslink(rid, &content);
196
+ manifest_crosslink(rid, &content, MC_NONE);
197197
}
198198
assert( blob_is_reset(&content) );
199199
remote_has(rid);
200200
}
201201
@@ -820,33 +820,73 @@
820820
static void server_private_xfer_not_authorized(void){
821821
@ error not\sauthorized\sto\ssync\sprivate\scontent
822822
}
823823
824824
/*
825
-** Run the specified TH1 script, if any, and returns the return code or TH_OK
826
-** when there is no script.
827
-*/
828
-static int run_script(const char *zScript){
829
- if( !zScript ){
830
- return TH_OK; /* No script, return success. */
831
- }
832
- Th_FossilInit(TH_INIT_DEFAULT); /* Make sure TH1 is ready. */
833
- return Th_Eval(g.interp, 0, zScript, -1);
834
-}
835
-
836
-/*
837
-** Run the pre-transfer TH1 script, if any, and returns the return code.
838
-*/
839
-static int run_common_script(void){
840
- return run_script(db_get("xfer-common-script", 0));
841
-}
842
-
843
-/*
844
-** Run the post-push TH1 script, if any, and returns the return code.
845
-*/
846
-static int run_push_script(void){
847
- return run_script(db_get("xfer-push-script", 0));
825
+** Return the common TH1 code to evaluate prior to evaluating any other
826
+** TH1 transfer notification scripts.
827
+*/
828
+const char *xfer_common_code(void){
829
+ return db_get("xfer-common-script", 0);
830
+}
831
+
832
+/*
833
+** Return the TH1 code to evaluate when a push is processed.
834
+*/
835
+const char *xfer_push_code(void){
836
+ return db_get("xfer-push-script", 0);
837
+}
838
+
839
+/*
840
+** Return the TH1 code to evaluate when a commit is processed.
841
+*/
842
+const char *xfer_commit_code(void){
843
+ return db_get("xfer-commit-script", 0);
844
+}
845
+
846
+/*
847
+** Return the TH1 code to evaluate when a ticket change is processed.
848
+*/
849
+const char *xfer_ticket_code(void){
850
+ return db_get("xfer-ticket-script", 0);
851
+}
852
+
853
+/*
854
+** Run the specified TH1 script, if any, and returns 1 on error.
855
+*/
856
+int xfer_run_script(const char *zScript, const char *zUuid){
857
+ int result;
858
+ if( !zScript ) return TH_OK;
859
+ Th_FossilInit(TH_INIT_DEFAULT);
860
+ if( zUuid ){
861
+ result = Th_SetVar(g.interp, "uuid", -1, zUuid, -1);
862
+ if( result!=TH_OK ){
863
+ fossil_error(1, "%s", Th_GetResult(g.interp, 0));
864
+ return result;
865
+ }
866
+ }
867
+ result = Th_Eval(g.interp, 0, zScript, -1);
868
+ if( result!=TH_OK ){
869
+ fossil_error(1, "%s", Th_GetResult(g.interp, 0));
870
+ }
871
+ return result;
872
+}
873
+
874
+/*
875
+** Runs the pre-transfer TH1 script, if any, and returns its return code.
876
+** This script may be run multiple times. If the script performs actions
877
+** that cannot be redone, it should use an internal [if] guard similar to
878
+** the following:
879
+**
880
+** if {![info exists common_done]} {
881
+** # ... code here
882
+** set common_done 1
883
+** }
884
+*/
885
+int xfer_run_common_script(void){
886
+ Th_FossilInit(TH_INIT_DEFAULT);
887
+ return xfer_run_script(xfer_common_code(), 0);
848888
}
849889
850890
/*
851891
** If this variable is set, disable login checks. Used for debugging
852892
** only.
@@ -875,10 +915,11 @@
875915
int isClone = 0;
876916
int nGimme = 0;
877917
int size;
878918
int recvConfig = 0;
879919
char *zNow;
920
+ int result;
880921
881922
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
882923
fossil_redirect_home();
883924
}
884925
g.zLogin = "anonymous";
@@ -904,13 +945,14 @@
904945
db_begin_transaction();
905946
db_multi_exec(
906947
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
907948
);
908949
manifest_crosslink_begin();
909
- if( run_common_script()==TH_ERROR ){
950
+ result = xfer_run_common_script();
951
+ if( result==TH_ERROR ){
910952
cgi_reset_content();
911
- @ error common\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
953
+ @ error common\sscript\sfailed:\s%F(g.zErrMsg)
912954
nErr++;
913955
}
914956
while( blob_line(xfer.pIn, &xfer.line) ){
915957
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
916958
if( blob_size(&xfer.line)==0 ) continue;
@@ -1231,14 +1273,17 @@
12311273
}
12321274
blobarray_reset(xfer.aToken, xfer.nToken);
12331275
blob_reset(&xfer.line);
12341276
}
12351277
if( isPush ){
1236
- if( run_push_script()==TH_ERROR ){
1237
- cgi_reset_content();
1238
- @ error push\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
1239
- nErr++;
1278
+ if( result==TH_OK ){
1279
+ result = xfer_run_script(xfer_push_code(), 0);
1280
+ if( result==TH_ERROR ){
1281
+ cgi_reset_content();
1282
+ @ error push\sscript\sfailed:\s%F(g.zErrMsg)
1283
+ nErr++;
1284
+ }
12401285
}
12411286
request_phantoms(&xfer, 500);
12421287
}
12431288
if( isClone && nGimme==0 ){
12441289
/* The initial "clone" message from client to server contains no
@@ -1881,13 +1926,13 @@
18811926
18821927
fossil_force_newline();
18831928
fossil_print(
18841929
"%s finished with %lld bytes sent, %lld bytes received\n",
18851930
zOpType, nSent, nRcvd);
1886
- transport_close();
1887
- transport_global_shutdown();
1931
+ transport_close(GLOBAL_URL());
1932
+ transport_global_shutdown(GLOBAL_URL());
18881933
db_multi_exec("DROP TABLE onremote");
18891934
manifest_crosslink_end();
18901935
content_enable_dephantomize(1);
18911936
db_end_transaction(0);
18921937
return nErr;
18931938
}
18941939
--- src/xfer.c
+++ src/xfer.c
@@ -191,11 +191,11 @@
191 if( rid==0 ){
192 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
193 blob_reset(&content);
194 }else{
195 if( !isPriv ) content_make_public(rid);
196 manifest_crosslink(rid, &content);
197 }
198 assert( blob_is_reset(&content) );
199 remote_has(rid);
200 }
201
@@ -820,33 +820,73 @@
820 static void server_private_xfer_not_authorized(void){
821 @ error not\sauthorized\sto\ssync\sprivate\scontent
822 }
823
824 /*
825 ** Run the specified TH1 script, if any, and returns the return code or TH_OK
826 ** when there is no script.
827 */
828 static int run_script(const char *zScript){
829 if( !zScript ){
830 return TH_OK; /* No script, return success. */
831 }
832 Th_FossilInit(TH_INIT_DEFAULT); /* Make sure TH1 is ready. */
833 return Th_Eval(g.interp, 0, zScript, -1);
834 }
835
836 /*
837 ** Run the pre-transfer TH1 script, if any, and returns the return code.
838 */
839 static int run_common_script(void){
840 return run_script(db_get("xfer-common-script", 0));
841 }
842
843 /*
844 ** Run the post-push TH1 script, if any, and returns the return code.
845 */
846 static int run_push_script(void){
847 return run_script(db_get("xfer-push-script", 0));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
848 }
849
850 /*
851 ** If this variable is set, disable login checks. Used for debugging
852 ** only.
@@ -875,10 +915,11 @@
875 int isClone = 0;
876 int nGimme = 0;
877 int size;
878 int recvConfig = 0;
879 char *zNow;
 
880
881 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
882 fossil_redirect_home();
883 }
884 g.zLogin = "anonymous";
@@ -904,13 +945,14 @@
904 db_begin_transaction();
905 db_multi_exec(
906 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
907 );
908 manifest_crosslink_begin();
909 if( run_common_script()==TH_ERROR ){
 
910 cgi_reset_content();
911 @ error common\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
912 nErr++;
913 }
914 while( blob_line(xfer.pIn, &xfer.line) ){
915 if( blob_buffer(&xfer.line)[0]=='#' ) continue;
916 if( blob_size(&xfer.line)==0 ) continue;
@@ -1231,14 +1273,17 @@
1231 }
1232 blobarray_reset(xfer.aToken, xfer.nToken);
1233 blob_reset(&xfer.line);
1234 }
1235 if( isPush ){
1236 if( run_push_script()==TH_ERROR ){
1237 cgi_reset_content();
1238 @ error push\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
1239 nErr++;
 
 
 
1240 }
1241 request_phantoms(&xfer, 500);
1242 }
1243 if( isClone && nGimme==0 ){
1244 /* The initial "clone" message from client to server contains no
@@ -1881,13 +1926,13 @@
1881
1882 fossil_force_newline();
1883 fossil_print(
1884 "%s finished with %lld bytes sent, %lld bytes received\n",
1885 zOpType, nSent, nRcvd);
1886 transport_close();
1887 transport_global_shutdown();
1888 db_multi_exec("DROP TABLE onremote");
1889 manifest_crosslink_end();
1890 content_enable_dephantomize(1);
1891 db_end_transaction(0);
1892 return nErr;
1893 }
1894
--- src/xfer.c
+++ src/xfer.c
@@ -191,11 +191,11 @@
191 if( rid==0 ){
192 blob_appendf(&pXfer->err, "%s", g.zErrMsg);
193 blob_reset(&content);
194 }else{
195 if( !isPriv ) content_make_public(rid);
196 manifest_crosslink(rid, &content, MC_NONE);
197 }
198 assert( blob_is_reset(&content) );
199 remote_has(rid);
200 }
201
@@ -820,33 +820,73 @@
820 static void server_private_xfer_not_authorized(void){
821 @ error not\sauthorized\sto\ssync\sprivate\scontent
822 }
823
824 /*
825 ** Return the common TH1 code to evaluate prior to evaluating any other
826 ** TH1 transfer notification scripts.
827 */
828 const char *xfer_common_code(void){
829 return db_get("xfer-common-script", 0);
830 }
831
832 /*
833 ** Return the TH1 code to evaluate when a push is processed.
834 */
835 const char *xfer_push_code(void){
836 return db_get("xfer-push-script", 0);
837 }
838
839 /*
840 ** Return the TH1 code to evaluate when a commit is processed.
841 */
842 const char *xfer_commit_code(void){
843 return db_get("xfer-commit-script", 0);
844 }
845
846 /*
847 ** Return the TH1 code to evaluate when a ticket change is processed.
848 */
849 const char *xfer_ticket_code(void){
850 return db_get("xfer-ticket-script", 0);
851 }
852
853 /*
854 ** Run the specified TH1 script, if any, and returns 1 on error.
855 */
856 int xfer_run_script(const char *zScript, const char *zUuid){
857 int result;
858 if( !zScript ) return TH_OK;
859 Th_FossilInit(TH_INIT_DEFAULT);
860 if( zUuid ){
861 result = Th_SetVar(g.interp, "uuid", -1, zUuid, -1);
862 if( result!=TH_OK ){
863 fossil_error(1, "%s", Th_GetResult(g.interp, 0));
864 return result;
865 }
866 }
867 result = Th_Eval(g.interp, 0, zScript, -1);
868 if( result!=TH_OK ){
869 fossil_error(1, "%s", Th_GetResult(g.interp, 0));
870 }
871 return result;
872 }
873
874 /*
875 ** Runs the pre-transfer TH1 script, if any, and returns its return code.
876 ** This script may be run multiple times. If the script performs actions
877 ** that cannot be redone, it should use an internal [if] guard similar to
878 ** the following:
879 **
880 ** if {![info exists common_done]} {
881 ** # ... code here
882 ** set common_done 1
883 ** }
884 */
885 int xfer_run_common_script(void){
886 Th_FossilInit(TH_INIT_DEFAULT);
887 return xfer_run_script(xfer_common_code(), 0);
888 }
889
890 /*
891 ** If this variable is set, disable login checks. Used for debugging
892 ** only.
@@ -875,10 +915,11 @@
915 int isClone = 0;
916 int nGimme = 0;
917 int size;
918 int recvConfig = 0;
919 char *zNow;
920 int result;
921
922 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
923 fossil_redirect_home();
924 }
925 g.zLogin = "anonymous";
@@ -904,13 +945,14 @@
945 db_begin_transaction();
946 db_multi_exec(
947 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
948 );
949 manifest_crosslink_begin();
950 result = xfer_run_common_script();
951 if( result==TH_ERROR ){
952 cgi_reset_content();
953 @ error common\sscript\sfailed:\s%F(g.zErrMsg)
954 nErr++;
955 }
956 while( blob_line(xfer.pIn, &xfer.line) ){
957 if( blob_buffer(&xfer.line)[0]=='#' ) continue;
958 if( blob_size(&xfer.line)==0 ) continue;
@@ -1231,14 +1273,17 @@
1273 }
1274 blobarray_reset(xfer.aToken, xfer.nToken);
1275 blob_reset(&xfer.line);
1276 }
1277 if( isPush ){
1278 if( result==TH_OK ){
1279 result = xfer_run_script(xfer_push_code(), 0);
1280 if( result==TH_ERROR ){
1281 cgi_reset_content();
1282 @ error push\sscript\sfailed:\s%F(g.zErrMsg)
1283 nErr++;
1284 }
1285 }
1286 request_phantoms(&xfer, 500);
1287 }
1288 if( isClone && nGimme==0 ){
1289 /* The initial "clone" message from client to server contains no
@@ -1881,13 +1926,13 @@
1926
1927 fossil_force_newline();
1928 fossil_print(
1929 "%s finished with %lld bytes sent, %lld bytes received\n",
1930 zOpType, nSent, nRcvd);
1931 transport_close(GLOBAL_URL());
1932 transport_global_shutdown(GLOBAL_URL());
1933 db_multi_exec("DROP TABLE onremote");
1934 manifest_crosslink_end();
1935 content_enable_dephantomize(1);
1936 db_end_transaction(0);
1937 return nErr;
1938 }
1939
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -31,16 +31,63 @@
3131
if( !g.perm.Setup ){
3232
login_needed();
3333
}
3434
3535
style_header("Transfer Setup");
36
+
3637
@ <table border="0" cellspacing="20">
3738
setup_menu_entry("Common", "xfersetup_com",
3839
"Common TH1 code run before all transfer request processing.");
3940
setup_menu_entry("Push", "xfersetup_push",
4041
"Specific TH1 code to run after \"push\" transfer requests.");
42
+ setup_menu_entry("Commit", "xfersetup_commit",
43
+ "Specific TH1 code to run after processing a commit.");
44
+ setup_menu_entry("Ticket", "xfersetup_ticket",
45
+ "Specific TH1 code to run after processing a ticket change.");
4146
@ </table>
47
+
48
+ url_parse(0, 0);
49
+ if( g.urlProtocol ){
50
+ unsigned syncFlags;
51
+ const char *zButton;
52
+ char *zWarning;
53
+
54
+ if( db_get_boolean("dont-push", 0) ){
55
+ syncFlags = SYNC_PULL;
56
+ zButton = "Pull";
57
+ zWarning = 0;
58
+ }else{
59
+ syncFlags = SYNC_PUSH | SYNC_PULL;
60
+ zButton = "Synchronize";
61
+ zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
62
+ g.urlCanonical);
63
+ }
64
+ if( P("sync") ){
65
+ user_select();
66
+ url_enable_proxy(0);
67
+ client_sync(syncFlags, 0, 0);
68
+ }
69
+ @ <p>Press the %h(zButton) button below to synchronize with the
70
+ @ "%h(g.urlCanonical)" repository now. This may be useful when
71
+ @ testing the various transfer scripts.</p>
72
+ @ <p>You can use the "http -async" command in your scripts, but
73
+ @ make sure the "th1-uri-regexp" setting is set first.</p>
74
+ if( zWarning ){
75
+ @
76
+ @ <big><b>%h(zWarning)</b></big>
77
+ free(zWarning);
78
+ }
79
+ @
80
+ @ <blockquote>
81
+ @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
82
+ login_insert_csrf_secret();
83
+ @ <input type="submit" name="sync" value="%h(zButton)" />
84
+ @ </div></form>
85
+ @ </blockquote>
86
+ @
87
+ }
88
+
4289
style_footer();
4390
}
4491
4592
/*
4693
** Common implementation for the transfer setup editor pages.
@@ -140,9 +187,49 @@
140187
"Transfer Push Script",
141188
"xfer-push-script",
142189
zDefaultXferPush,
143190
zDesc,
144191
0,
192
+ 0,
193
+ 30
194
+ );
195
+}
196
+
197
+static const char *zDefaultXferCommit = 0;
198
+
199
+/*
200
+** WEBPAGE: xfersetup_commit
201
+*/
202
+void xfersetup_commit_page(void){
203
+ static const char zDesc[] =
204
+ @ Enter TH1 script that runs when a commit is processed.
205
+ ;
206
+ xfersetup_generic(
207
+ "Transfer Commit Script",
208
+ "xfer-commit-script",
209
+ zDefaultXferCommit,
210
+ zDesc,
211
+ 0,
212
+ 0,
213
+ 30
214
+ );
215
+}
216
+
217
+static const char *zDefaultXferTicket = 0;
218
+
219
+/*
220
+** WEBPAGE: xfersetup_ticket
221
+*/
222
+void xfersetup_ticket_page(void){
223
+ static const char zDesc[] =
224
+ @ Enter TH1 script that runs when a ticket change is processed.
225
+ ;
226
+ xfersetup_generic(
227
+ "Transfer Ticket Script",
228
+ "xfer-ticket-script",
229
+ zDefaultXferTicket,
230
+ zDesc,
231
+ 0,
145232
0,
146233
30
147234
);
148235
}
149236
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -31,16 +31,63 @@
31 if( !g.perm.Setup ){
32 login_needed();
33 }
34
35 style_header("Transfer Setup");
 
36 @ <table border="0" cellspacing="20">
37 setup_menu_entry("Common", "xfersetup_com",
38 "Common TH1 code run before all transfer request processing.");
39 setup_menu_entry("Push", "xfersetup_push",
40 "Specific TH1 code to run after \"push\" transfer requests.");
 
 
 
 
41 @ </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42 style_footer();
43 }
44
45 /*
46 ** Common implementation for the transfer setup editor pages.
@@ -140,9 +187,49 @@
140 "Transfer Push Script",
141 "xfer-push-script",
142 zDefaultXferPush,
143 zDesc,
144 0,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145 0,
146 30
147 );
148 }
149
--- src/xfersetup.c
+++ src/xfersetup.c
@@ -31,16 +31,63 @@
31 if( !g.perm.Setup ){
32 login_needed();
33 }
34
35 style_header("Transfer Setup");
36
37 @ <table border="0" cellspacing="20">
38 setup_menu_entry("Common", "xfersetup_com",
39 "Common TH1 code run before all transfer request processing.");
40 setup_menu_entry("Push", "xfersetup_push",
41 "Specific TH1 code to run after \"push\" transfer requests.");
42 setup_menu_entry("Commit", "xfersetup_commit",
43 "Specific TH1 code to run after processing a commit.");
44 setup_menu_entry("Ticket", "xfersetup_ticket",
45 "Specific TH1 code to run after processing a ticket change.");
46 @ </table>
47
48 url_parse(0, 0);
49 if( g.urlProtocol ){
50 unsigned syncFlags;
51 const char *zButton;
52 char *zWarning;
53
54 if( db_get_boolean("dont-push", 0) ){
55 syncFlags = SYNC_PULL;
56 zButton = "Pull";
57 zWarning = 0;
58 }else{
59 syncFlags = SYNC_PUSH | SYNC_PULL;
60 zButton = "Synchronize";
61 zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
62 g.urlCanonical);
63 }
64 if( P("sync") ){
65 user_select();
66 url_enable_proxy(0);
67 client_sync(syncFlags, 0, 0);
68 }
69 @ <p>Press the %h(zButton) button below to synchronize with the
70 @ "%h(g.urlCanonical)" repository now. This may be useful when
71 @ testing the various transfer scripts.</p>
72 @ <p>You can use the "http -async" command in your scripts, but
73 @ make sure the "th1-uri-regexp" setting is set first.</p>
74 if( zWarning ){
75 @
76 @ <big><b>%h(zWarning)</b></big>
77 free(zWarning);
78 }
79 @
80 @ <blockquote>
81 @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
82 login_insert_csrf_secret();
83 @ <input type="submit" name="sync" value="%h(zButton)" />
84 @ </div></form>
85 @ </blockquote>
86 @
87 }
88
89 style_footer();
90 }
91
92 /*
93 ** Common implementation for the transfer setup editor pages.
@@ -140,9 +187,49 @@
187 "Transfer Push Script",
188 "xfer-push-script",
189 zDefaultXferPush,
190 zDesc,
191 0,
192 0,
193 30
194 );
195 }
196
197 static const char *zDefaultXferCommit = 0;
198
199 /*
200 ** WEBPAGE: xfersetup_commit
201 */
202 void xfersetup_commit_page(void){
203 static const char zDesc[] =
204 @ Enter TH1 script that runs when a commit is processed.
205 ;
206 xfersetup_generic(
207 "Transfer Commit Script",
208 "xfer-commit-script",
209 zDefaultXferCommit,
210 zDesc,
211 0,
212 0,
213 30
214 );
215 }
216
217 static const char *zDefaultXferTicket = 0;
218
219 /*
220 ** WEBPAGE: xfersetup_ticket
221 */
222 void xfersetup_ticket_page(void){
223 static const char zDesc[] =
224 @ Enter TH1 script that runs when a ticket change is processed.
225 ;
226 xfersetup_generic(
227 "Transfer Ticket Script",
228 "xfer-ticket-script",
229 zDefaultXferTicket,
230 zDesc,
231 0,
232 0,
233 30
234 );
235 }
236
--- test/th1.test
+++ test/th1.test
@@ -65,5 +65,25 @@
6565
6666
###############################################################################
6767
6868
fossil test-th-eval --th-open-config "setting -strict -- --"
6969
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
70
+
71
+###############################################################################
72
+
73
+fossil test-th-eval "expr 42/0"
74
+test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
75
+
76
+###############################################################################
77
+
78
+fossil test-th-eval "expr 42/0.0"
79
+test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
80
+
81
+###############################################################################
82
+
83
+fossil test-th-eval "expr 42.0/0"
84
+test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
85
+
86
+###############################################################################
87
+
88
+fossil test-th-eval "expr 42.0/0.0"
89
+test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
7090
--- test/th1.test
+++ test/th1.test
@@ -65,5 +65,25 @@
65
66 ###############################################################################
67
68 fossil test-th-eval --th-open-config "setting -strict -- --"
69 test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
--- test/th1.test
+++ test/th1.test
@@ -65,5 +65,25 @@
65
66 ###############################################################################
67
68 fossil test-th-eval --th-open-config "setting -strict -- --"
69 test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
70
71 ###############################################################################
72
73 fossil test-th-eval "expr 42/0"
74 test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
75
76 ###############################################################################
77
78 fossil test-th-eval "expr 42/0.0"
79 test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
80
81 ###############################################################################
82
83 fossil test-th-eval "expr 42.0/0"
84 test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
85
86 ###############################################################################
87
88 fossil test-th-eval "expr 42.0/0.0"
89 test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
90
--- test/th1.test
+++ test/th1.test
@@ -65,5 +65,25 @@
6565
6666
###############################################################################
6767
6868
fossil test-th-eval --th-open-config "setting -strict -- --"
6969
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
70
+
71
+###############################################################################
72
+
73
+fossil test-th-eval "expr 42/0"
74
+test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
75
+
76
+###############################################################################
77
+
78
+fossil test-th-eval "expr 42/0.0"
79
+test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
80
+
81
+###############################################################################
82
+
83
+fossil test-th-eval "expr 42.0/0"
84
+test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
85
+
86
+###############################################################################
87
+
88
+fossil test-th-eval "expr 42.0/0.0"
89
+test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
7090
--- test/th1.test
+++ test/th1.test
@@ -65,5 +65,25 @@
65
66 ###############################################################################
67
68 fossil test-th-eval --th-open-config "setting -strict -- --"
69 test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
--- test/th1.test
+++ test/th1.test
@@ -65,5 +65,25 @@
65
66 ###############################################################################
67
68 fossil test-th-eval --th-open-config "setting -strict -- --"
69 test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
70
71 ###############################################################################
72
73 fossil test-th-eval "expr 42/0"
74 test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
75
76 ###############################################################################
77
78 fossil test-th-eval "expr 42/0.0"
79 test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
80
81 ###############################################################################
82
83 fossil test-th-eval "expr 42.0/0"
84 test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
85
86 ###############################################################################
87
88 fossil test-th-eval "expr 42.0/0.0"
89 test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
90
--- www/changes.wiki
+++ www/changes.wiki
@@ -32,10 +32,13 @@
3232
which does not store the URL or password when cloning.
3333
* Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open
3434
repository.
3535
* Fossil now hides check-ins that have the "hidden" tag in timeline webpages.
3636
* Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins.
37
+ * Advanced possibilities for commit and ticket change notifications over
38
+ http using TH1 scripting.
39
+ * Add --sha1sum option to "[/help?cmd=commit | fossil commit]" command.
3740
3841
<h2>Changes For Version 1.27 (2013-09-11)</h2>
3942
* Enhance the [/help?cmd=changes | fossil changes],
4043
[/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
4144
[/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
4245
--- www/changes.wiki
+++ www/changes.wiki
@@ -32,10 +32,13 @@
32 which does not store the URL or password when cloning.
33 * Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open
34 repository.
35 * Fossil now hides check-ins that have the "hidden" tag in timeline webpages.
36 * Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins.
 
 
 
37
38 <h2>Changes For Version 1.27 (2013-09-11)</h2>
39 * Enhance the [/help?cmd=changes | fossil changes],
40 [/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
41 [/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
42
--- www/changes.wiki
+++ www/changes.wiki
@@ -32,10 +32,13 @@
32 which does not store the URL or password when cloning.
33 * Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open
34 repository.
35 * Fossil now hides check-ins that have the "hidden" tag in timeline webpages.
36 * Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins.
37 * Advanced possibilities for commit and ticket change notifications over
38 http using TH1 scripting.
39 * Add --sha1sum option to "[/help?cmd=commit | fossil commit]" command.
40
41 <h2>Changes For Version 1.27 (2013-09-11)</h2>
42 * Enhance the [/help?cmd=changes | fossil changes],
43 [/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
44 [/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
45

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button