Fossil SCM

When SQLite detects that the repository associated with a checkout has been replaced by a clone (such that the RID values potentially change) then automatically adjust the content of the checkout database.

drh 2019-01-21 16:54 trunk merge
Commit fff37e624e2b634bfdd61c3eb2f6cd10ce4b2ebccf391753f1cc2567b332648d
+2 -2
--- src/add.c
+++ src/add.c
@@ -187,12 +187,12 @@
187187
zPath, filename_collation());
188188
}else{
189189
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
190190
int isExe = file_isexe(zFullname, RepoFILE);
191191
db_multi_exec(
192
- "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink)"
193
- "VALUES(%d,0,0,0,%Q,%d,%d)",
192
+ "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
193
+ "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
194194
vid, zPath, isExe, file_islink(0));
195195
fossil_free(zFullname);
196196
}
197197
if( db_changes() ){
198198
fossil_print("ADDED %s\n", zPath);
199199
--- src/add.c
+++ src/add.c
@@ -187,12 +187,12 @@
187 zPath, filename_collation());
188 }else{
189 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
190 int isExe = file_isexe(zFullname, RepoFILE);
191 db_multi_exec(
192 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink)"
193 "VALUES(%d,0,0,0,%Q,%d,%d)",
194 vid, zPath, isExe, file_islink(0));
195 fossil_free(zFullname);
196 }
197 if( db_changes() ){
198 fossil_print("ADDED %s\n", zPath);
199
--- src/add.c
+++ src/add.c
@@ -187,12 +187,12 @@
187 zPath, filename_collation());
188 }else{
189 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
190 int isExe = file_isexe(zFullname, RepoFILE);
191 db_multi_exec(
192 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
193 "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
194 vid, zPath, isExe, file_islink(0));
195 fossil_free(zFullname);
196 }
197 if( db_changes() ){
198 fossil_print("ADDED %s\n", zPath);
199
+12 -4
--- src/bisect.c
+++ src/bisect.c
@@ -286,10 +286,21 @@
286286
(db_column_int(&q, 4) && zGoodBad[0]!='C') ? " CURRENT" : "");
287287
}
288288
db_finalize(&q);
289289
}
290290
291
+
292
+/*
293
+** Reset the bisect subsystem.
294
+*/
295
+void bisect_reset(void){
296
+ db_multi_exec(
297
+ "DELETE FROM vvar WHERE name IN "
298
+ " ('bisect-good', 'bisect-bad', 'bisect-log')"
299
+ );
300
+}
301
+
291302
/*
292303
** COMMAND: bisect
293304
**
294305
** Usage: %fossil bisect SUBCOMMAND ...
295306
**
@@ -489,14 +500,11 @@
489500
}
490501
}else{
491502
usage("options ?NAME? ?VALUE?");
492503
}
493504
}else if( strncmp(zCmd, "reset", n)==0 ){
494
- db_multi_exec(
495
- "DELETE FROM vvar WHERE name IN "
496
- " ('bisect-good', 'bisect-bad', 'bisect-log')"
497
- );
505
+ bisect_reset();
498506
}else if( strcmp(zCmd, "ui")==0 ){
499507
char *newArgv[8];
500508
newArgv[0] = g.argv[0];
501509
newArgv[1] = "ui";
502510
newArgv[2] = "--page";
503511
--- src/bisect.c
+++ src/bisect.c
@@ -286,10 +286,21 @@
286 (db_column_int(&q, 4) && zGoodBad[0]!='C') ? " CURRENT" : "");
287 }
288 db_finalize(&q);
289 }
290
 
 
 
 
 
 
 
 
 
 
 
291 /*
292 ** COMMAND: bisect
293 **
294 ** Usage: %fossil bisect SUBCOMMAND ...
295 **
@@ -489,14 +500,11 @@
489 }
490 }else{
491 usage("options ?NAME? ?VALUE?");
492 }
493 }else if( strncmp(zCmd, "reset", n)==0 ){
494 db_multi_exec(
495 "DELETE FROM vvar WHERE name IN "
496 " ('bisect-good', 'bisect-bad', 'bisect-log')"
497 );
498 }else if( strcmp(zCmd, "ui")==0 ){
499 char *newArgv[8];
500 newArgv[0] = g.argv[0];
501 newArgv[1] = "ui";
502 newArgv[2] = "--page";
503
--- src/bisect.c
+++ src/bisect.c
@@ -286,10 +286,21 @@
286 (db_column_int(&q, 4) && zGoodBad[0]!='C') ? " CURRENT" : "");
287 }
288 db_finalize(&q);
289 }
290
291
292 /*
293 ** Reset the bisect subsystem.
294 */
295 void bisect_reset(void){
296 db_multi_exec(
297 "DELETE FROM vvar WHERE name IN "
298 " ('bisect-good', 'bisect-bad', 'bisect-log')"
299 );
300 }
301
302 /*
303 ** COMMAND: bisect
304 **
305 ** Usage: %fossil bisect SUBCOMMAND ...
306 **
@@ -489,14 +500,11 @@
500 }
501 }else{
502 usage("options ?NAME? ?VALUE?");
503 }
504 }else if( strncmp(zCmd, "reset", n)==0 ){
505 bisect_reset();
 
 
 
506 }else if( strcmp(zCmd, "ui")==0 ){
507 char *newArgv[8];
508 newArgv[0] = g.argv[0];
509 newArgv[1] = "ui";
510 newArgv[2] = "--page";
511
+8 -10
--- src/checkin.c
+++ src/checkin.c
@@ -307,12 +307,11 @@
307307
db_finalize(&q);
308308
309309
/* If C_MERGE, put merge contributors at the end of the report. */
310310
skipFiles:
311311
if( flags & C_MERGE ){
312
- db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
313
- " WHERE id<=0");
312
+ db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0" );
314313
while( db_step(&q)==SQLITE_ROW ){
315314
if( flags & C_COMMENT ){
316315
blob_append(report, "# ", 2);
317316
}
318317
if( flags & C_CLASSIFY ){
@@ -1635,14 +1634,13 @@
16351634
blob_appendf(pOut, "\n");
16361635
}
16371636
free(zDate);
16381637
16391638
db_prepare(&q,
1640
- "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
1641
- " FROM vmerge, blob"
1639
+ "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || mhash, merge"
1640
+ " FROM vmerge"
16421641
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
1643
- " AND blob.rid=vmerge.merge"
16441642
" ORDER BY 1");
16451643
while( db_step(&q)==SQLITE_ROW ){
16461644
const char *zCherrypickUuid = db_column_text(&q, 0);
16471645
int mid = db_column_int(&q, 1);
16481646
if( mid != vid ){
@@ -1667,11 +1665,11 @@
16671665
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
16681666
}
16691667
if( p->closeFlag ){
16701668
blob_appendf(pOut, "T +closed *\n");
16711669
}
1672
- db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
1670
+ db_prepare(&q, "SELECT mhash,merge FROM vmerge"
16731671
" WHERE id %s ORDER BY 1",
16741672
p->integrateFlag ? "IN(0,-4)" : "=(-4)");
16751673
while( db_step(&q)==SQLITE_ROW ){
16761674
const char *zIntegrateUuid = db_column_text(&q, 0);
16771675
int rid = db_column_int(&q, 1);
@@ -2400,11 +2398,12 @@
24002398
nrid = content_put(&content);
24012399
blob_reset(&content);
24022400
if( rid>0 ){
24032401
content_deltify(rid, &nrid, 1, 0);
24042402
}
2405
- db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
2403
+ db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d, mhash=NULL WHERE id=%d",
2404
+ nrid,nrid,id);
24062405
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
24072406
}
24082407
db_finalize(&q);
24092408
if( nConflict && !allowConflict ){
24102409
fossil_fatal("abort due to unresolved merge conflicts; "
@@ -2508,12 +2507,11 @@
25082507
}
25092508
assert( blob_is_reset(&manifest) );
25102509
content_deltify(vid, &nvid, 1, 0);
25112510
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
25122511
2513
- db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
2514
- " WHERE id=-4");
2512
+ db_prepare(&q, "SELECT mhash,merge FROM vmerge WHERE id=-4");
25152513
while( db_step(&q)==SQLITE_ROW ){
25162514
const char *zIntegrateUuid = db_column_text(&q, 0);
25172515
if( is_a_leaf(db_column_int(&q, 1)) ){
25182516
fossil_print("Closed: %s\n", zIntegrateUuid);
25192517
}else{
@@ -2535,11 +2533,11 @@
25352533
/* Update the vfile and vmerge tables */
25362534
db_multi_exec(
25372535
"DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
25382536
"DELETE FROM vmerge;"
25392537
"UPDATE vfile SET vid=%d;"
2540
- "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
2538
+ "UPDATE vfile SET rid=mrid, mhash=NULL, chnged=0, deleted=0, origname=NULL"
25412539
" WHERE is_selected(id);"
25422540
, vid, nvid
25432541
);
25442542
db_set_checkout(nvid);
25452543
25462544
--- src/checkin.c
+++ src/checkin.c
@@ -307,12 +307,11 @@
307 db_finalize(&q);
308
309 /* If C_MERGE, put merge contributors at the end of the report. */
310 skipFiles:
311 if( flags & C_MERGE ){
312 db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
313 " WHERE id<=0");
314 while( db_step(&q)==SQLITE_ROW ){
315 if( flags & C_COMMENT ){
316 blob_append(report, "# ", 2);
317 }
318 if( flags & C_CLASSIFY ){
@@ -1635,14 +1634,13 @@
1635 blob_appendf(pOut, "\n");
1636 }
1637 free(zDate);
1638
1639 db_prepare(&q,
1640 "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
1641 " FROM vmerge, blob"
1642 " WHERE (vmerge.id=-1 OR vmerge.id=-2)"
1643 " AND blob.rid=vmerge.merge"
1644 " ORDER BY 1");
1645 while( db_step(&q)==SQLITE_ROW ){
1646 const char *zCherrypickUuid = db_column_text(&q, 0);
1647 int mid = db_column_int(&q, 1);
1648 if( mid != vid ){
@@ -1667,11 +1665,11 @@
1667 blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
1668 }
1669 if( p->closeFlag ){
1670 blob_appendf(pOut, "T +closed *\n");
1671 }
1672 db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
1673 " WHERE id %s ORDER BY 1",
1674 p->integrateFlag ? "IN(0,-4)" : "=(-4)");
1675 while( db_step(&q)==SQLITE_ROW ){
1676 const char *zIntegrateUuid = db_column_text(&q, 0);
1677 int rid = db_column_int(&q, 1);
@@ -2400,11 +2398,12 @@
2400 nrid = content_put(&content);
2401 blob_reset(&content);
2402 if( rid>0 ){
2403 content_deltify(rid, &nrid, 1, 0);
2404 }
2405 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
 
2406 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
2407 }
2408 db_finalize(&q);
2409 if( nConflict && !allowConflict ){
2410 fossil_fatal("abort due to unresolved merge conflicts; "
@@ -2508,12 +2507,11 @@
2508 }
2509 assert( blob_is_reset(&manifest) );
2510 content_deltify(vid, &nvid, 1, 0);
2511 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
2512
2513 db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
2514 " WHERE id=-4");
2515 while( db_step(&q)==SQLITE_ROW ){
2516 const char *zIntegrateUuid = db_column_text(&q, 0);
2517 if( is_a_leaf(db_column_int(&q, 1)) ){
2518 fossil_print("Closed: %s\n", zIntegrateUuid);
2519 }else{
@@ -2535,11 +2533,11 @@
2535 /* Update the vfile and vmerge tables */
2536 db_multi_exec(
2537 "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
2538 "DELETE FROM vmerge;"
2539 "UPDATE vfile SET vid=%d;"
2540 "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
2541 " WHERE is_selected(id);"
2542 , vid, nvid
2543 );
2544 db_set_checkout(nvid);
2545
2546
--- src/checkin.c
+++ src/checkin.c
@@ -307,12 +307,11 @@
307 db_finalize(&q);
308
309 /* If C_MERGE, put merge contributors at the end of the report. */
310 skipFiles:
311 if( flags & C_MERGE ){
312 db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0" );
 
313 while( db_step(&q)==SQLITE_ROW ){
314 if( flags & C_COMMENT ){
315 blob_append(report, "# ", 2);
316 }
317 if( flags & C_CLASSIFY ){
@@ -1635,14 +1634,13 @@
1634 blob_appendf(pOut, "\n");
1635 }
1636 free(zDate);
1637
1638 db_prepare(&q,
1639 "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || mhash, merge"
1640 " FROM vmerge"
1641 " WHERE (vmerge.id=-1 OR vmerge.id=-2)"
 
1642 " ORDER BY 1");
1643 while( db_step(&q)==SQLITE_ROW ){
1644 const char *zCherrypickUuid = db_column_text(&q, 0);
1645 int mid = db_column_int(&q, 1);
1646 if( mid != vid ){
@@ -1667,11 +1665,11 @@
1665 blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
1666 }
1667 if( p->closeFlag ){
1668 blob_appendf(pOut, "T +closed *\n");
1669 }
1670 db_prepare(&q, "SELECT mhash,merge FROM vmerge"
1671 " WHERE id %s ORDER BY 1",
1672 p->integrateFlag ? "IN(0,-4)" : "=(-4)");
1673 while( db_step(&q)==SQLITE_ROW ){
1674 const char *zIntegrateUuid = db_column_text(&q, 0);
1675 int rid = db_column_int(&q, 1);
@@ -2400,11 +2398,12 @@
2398 nrid = content_put(&content);
2399 blob_reset(&content);
2400 if( rid>0 ){
2401 content_deltify(rid, &nrid, 1, 0);
2402 }
2403 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d, mhash=NULL WHERE id=%d",
2404 nrid,nrid,id);
2405 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
2406 }
2407 db_finalize(&q);
2408 if( nConflict && !allowConflict ){
2409 fossil_fatal("abort due to unresolved merge conflicts; "
@@ -2508,12 +2507,11 @@
2507 }
2508 assert( blob_is_reset(&manifest) );
2509 content_deltify(vid, &nvid, 1, 0);
2510 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
2511
2512 db_prepare(&q, "SELECT mhash,merge FROM vmerge WHERE id=-4");
 
2513 while( db_step(&q)==SQLITE_ROW ){
2514 const char *zIntegrateUuid = db_column_text(&q, 0);
2515 if( is_a_leaf(db_column_int(&q, 1)) ){
2516 fossil_print("Closed: %s\n", zIntegrateUuid);
2517 }else{
@@ -2535,11 +2533,11 @@
2533 /* Update the vfile and vmerge tables */
2534 db_multi_exec(
2535 "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
2536 "DELETE FROM vmerge;"
2537 "UPDATE vfile SET vid=%d;"
2538 "UPDATE vfile SET rid=mrid, mhash=NULL, chnged=0, deleted=0, origname=NULL"
2539 " WHERE is_selected(id);"
2540 , vid, nvid
2541 );
2542 db_set_checkout(nvid);
2543
2544
+88 -39
--- src/db.c
+++ src/db.c
@@ -1473,33 +1473,44 @@
14731473
** If zDbName is a valid local database file, open it and return
14741474
** true. If it is not a valid local database file, return 0.
14751475
*/
14761476
static int isValidLocalDb(const char *zDbName){
14771477
i64 lsize;
1478
- char *zVFileDef;
14791478
14801479
if( file_access(zDbName, F_OK) ) return 0;
14811480
lsize = file_size(zDbName, ExtFILE);
14821481
if( lsize%1024!=0 || lsize<4096 ) return 0;
14831482
db_open_or_attach(zDbName, "localdb");
1484
- zVFileDef = db_text(0, "SELECT sql FROM localdb.sqlite_master"
1485
- " WHERE name=='vfile'");
1486
- if( zVFileDef==0 ) return 0;
1483
+
1484
+ /* Check to see if the checkout database has the lastest schema changes.
1485
+ ** The most recent schema change (2019-01-19) is the addition of the
1486
+ ** vmerge.mhash and vfile.mhash fields. If the schema has the vmerge.mhash
1487
+ ** column, assume everything else is up-to-date.
1488
+ */
1489
+ if( db_table_has_column("localdb","vmerge","mhash") ){
1490
+ return 1; /* This is a checkout database with the latest schema */
1491
+ }
1492
+
1493
+ /* If there is no vfile table, then assume we have picked up something
1494
+ ** that is not even close to being a valid checkout database */
1495
+ if( !db_table_exists("localdb","vfile") ){
1496
+ return 0; /* Not a DB */
1497
+ }
14871498
14881499
/* If the "isexe" column is missing from the vfile table, then
14891500
** add it now. This code added on 2010-03-06. After all users have
14901501
** upgraded, this code can be safely deleted.
14911502
*/
1492
- if( sqlite3_strglob("* isexe *", zVFileDef)!=0 ){
1503
+ if( !db_table_has_column("localdb","vfile","isexe") ){
14931504
db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0");
14941505
}
14951506
14961507
/* If "islink"/"isLink" columns are missing from tables, then
14971508
** add them now. This code added on 2011-01-17 and 2011-08-27.
14981509
** After all users have upgraded, this code can be safely deleted.
14991510
*/
1500
- if( sqlite3_strglob("* islink *", zVFileDef)!=0 ){
1511
+ if( !db_table_has_column("localdb","vfile","isLink") ){
15011512
db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0");
15021513
if( db_local_table_exists_but_lacks_column("stashfile", "isLink") ){
15031514
db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOL DEFAULT 0");
15041515
}
15051516
if( db_local_table_exists_but_lacks_column("undo", "isLink") ){
@@ -1507,11 +1518,16 @@
15071518
}
15081519
if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){
15091520
db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0");
15101521
}
15111522
}
1512
- fossil_free(zVFileDef);
1523
+
1524
+ /* The design of the checkout database changed on 2019-01-19, adding the mhash
1525
+ ** column to vfile and vmerge and changing the UNIQUE index on vmerge into
1526
+ ** a PRIMARY KEY that includes the new mhash column. However, we must have
1527
+ ** the repository database at hand in order to do the migration, so that
1528
+ ** step is deferred. */
15131529
return 1;
15141530
}
15151531
15161532
/*
15171533
** Locate the root directory of the local repository tree. The root
@@ -1656,41 +1672,74 @@
16561672
/* Make a change to the CHECK constraint on the BLOB table for
16571673
** version 2.0 and later.
16581674
*/
16591675
rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
16601676
1661
- /* If the checkout database was opened first, then check to make
1662
- ** sure that the repository database that was just opened has not
1663
- ** be replaced by a clone of the same project, with different RID
1664
- ** values.
1665
- */
1666
- if( g.localOpen && !db_fingerprint_ok() ){
1667
- /* Uncomment the following when we are ready for automatic recovery: */
1668
-#if 0
1669
- stash_rid_renumbering_event();
1670
-#else
1671
- fossil_print(
1672
- "Oops. It looks like the repository database file located at\n"
1673
- " \"%s\"\n", zDbName
1674
- );
1675
- fossil_print(
1676
- "has been swapped with a clone that may have different\n"
1677
- "integer keys for the various artifacts. As of 2019-01-11,\n"
1678
- "we are working on enhancing Fossil to be able to deal with\n"
1679
- "that automatically, but we are not there yet. Sorry.\n\n"
1680
- );
1681
- fossil_print(
1682
- "As an interim workaround, try:\n"
1683
- " %s close --force\n"
1684
- " %s open \"%s\" --keep\n"
1685
- "Noting that any STASH and UNDO information "
1686
- "WILL BE IRREVOCABLY LOST.\n\n",
1687
- g.argv[0],
1688
- g.argv[0], zDbName
1689
- );
1690
- fossil_fatal("bad fingerprint");
1691
-#endif
1677
+ /* Additional checks that occur when opening the checkout database */
1678
+ if( g.localOpen ){
1679
+
1680
+ /* If the repository database that was just opened has been
1681
+ ** eplaced by a clone of the same project, with different RID
1682
+ ** values, then renumber the RID values stored in various tables
1683
+ ** of the checkout database, so that the repository and checkout
1684
+ ** databases align.
1685
+ */
1686
+ if( !db_fingerprint_ok() ){
1687
+ if( find_option("no-rid-adjust",0,0)!=0 ){
1688
+ /* The --no-rid-adjust command-line option bypasses the RID value
1689
+ ** updates. Intended for use during debugging, especially to be
1690
+ ** able to run "fossil sql" after a database swap. */
1691
+ fossil_print(
1692
+ "WARNING: repository change detected, but no adjust made.\n"
1693
+ );
1694
+ }else if( find_option("rid-renumber-dryrun",0,0)!=0 ){
1695
+ /* the --rid-renumber-dryrun option shows how RID values would be
1696
+ ** renumbered, but does not actually perform the renumbering.
1697
+ ** This is a debugging-only option. */
1698
+ vfile_rid_renumbering_event(1);
1699
+ exit(0);
1700
+ }else{
1701
+ char *z;
1702
+ stash_rid_renumbering_event();
1703
+ vfile_rid_renumbering_event(0);
1704
+ undo_reset();
1705
+ bisect_reset();
1706
+ z = db_fingerprint(0);
1707
+ db_lset("fingerprint", z);
1708
+ fossil_free(z);
1709
+ fossil_print(
1710
+ "WARNING: The repository database has been replaced by a clone.\n"
1711
+ "Bisect history and undo have been lost.\n"
1712
+ );
1713
+ }
1714
+ }
1715
+
1716
+ /* Make sure the checkout database schema migration of 2019-01-20
1717
+ ** has occurred.
1718
+ **
1719
+ ** The 2019-01-19 migration is the addition of the vmerge.mhash and
1720
+ ** vfile.mhash columns and making the vmerge.mhash column part of the
1721
+ ** PRIMARY KEY for vmerge.
1722
+ */
1723
+ if( !db_table_has_column("localdb", "vfile", "mhash") ){
1724
+ db_multi_exec("ALTER TABLE vfile ADD COLUMN mhash;");
1725
+ db_multi_exec(
1726
+ "UPDATE vfile"
1727
+ " SET mhash=(SELECT uuid FROM blob WHERE blob.rid=vfile.mrid)"
1728
+ " WHERE mrid!=rid;"
1729
+ );
1730
+ if( !db_table_has_column("localdb", "vmerge", "mhash") ){
1731
+ db_multi_exec("ALTER TABLE vmerge RENAME TO old_vmerge;");
1732
+ db_multi_exec(zLocalSchemaVmerge /*works-like:""*/);
1733
+ db_multi_exec(
1734
+ "INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
1735
+ " SELECT id, merge, blob.uuid FROM old_vmerge, blob"
1736
+ " WHERE old_vmerge.merge=blob.rid;"
1737
+ "DROP TABLE old_vmerge;"
1738
+ );
1739
+ }
1740
+ }
16921741
}
16931742
}
16941743
16951744
/*
16961745
** Return true if there have been any changes to the repository
@@ -2880,11 +2929,11 @@
28802929
#if defined(_WIN32) || defined(__CYGWIN__)
28812930
# define LOCALDB_NAME "./_FOSSIL_"
28822931
#else
28832932
# define LOCALDB_NAME "./.fslckout"
28842933
#endif
2885
- db_init_database(LOCALDB_NAME, zLocalSchema,
2934
+ db_init_database(LOCALDB_NAME, zLocalSchema, zLocalSchemaVmerge,
28862935
#ifdef FOSSIL_LOCAL_WAL
28872936
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
28882937
#endif
28892938
(char*)0);
28902939
db_delete_on_failure(LOCALDB_NAME);
28912940
--- src/db.c
+++ src/db.c
@@ -1473,33 +1473,44 @@
1473 ** If zDbName is a valid local database file, open it and return
1474 ** true. If it is not a valid local database file, return 0.
1475 */
1476 static int isValidLocalDb(const char *zDbName){
1477 i64 lsize;
1478 char *zVFileDef;
1479
1480 if( file_access(zDbName, F_OK) ) return 0;
1481 lsize = file_size(zDbName, ExtFILE);
1482 if( lsize%1024!=0 || lsize<4096 ) return 0;
1483 db_open_or_attach(zDbName, "localdb");
1484 zVFileDef = db_text(0, "SELECT sql FROM localdb.sqlite_master"
1485 " WHERE name=='vfile'");
1486 if( zVFileDef==0 ) return 0;
 
 
 
 
 
 
 
 
 
 
 
 
1487
1488 /* If the "isexe" column is missing from the vfile table, then
1489 ** add it now. This code added on 2010-03-06. After all users have
1490 ** upgraded, this code can be safely deleted.
1491 */
1492 if( sqlite3_strglob("* isexe *", zVFileDef)!=0 ){
1493 db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0");
1494 }
1495
1496 /* If "islink"/"isLink" columns are missing from tables, then
1497 ** add them now. This code added on 2011-01-17 and 2011-08-27.
1498 ** After all users have upgraded, this code can be safely deleted.
1499 */
1500 if( sqlite3_strglob("* islink *", zVFileDef)!=0 ){
1501 db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0");
1502 if( db_local_table_exists_but_lacks_column("stashfile", "isLink") ){
1503 db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOL DEFAULT 0");
1504 }
1505 if( db_local_table_exists_but_lacks_column("undo", "isLink") ){
@@ -1507,11 +1518,16 @@
1507 }
1508 if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){
1509 db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0");
1510 }
1511 }
1512 fossil_free(zVFileDef);
 
 
 
 
 
1513 return 1;
1514 }
1515
1516 /*
1517 ** Locate the root directory of the local repository tree. The root
@@ -1656,41 +1672,74 @@
1656 /* Make a change to the CHECK constraint on the BLOB table for
1657 ** version 2.0 and later.
1658 */
1659 rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
1660
1661 /* If the checkout database was opened first, then check to make
1662 ** sure that the repository database that was just opened has not
1663 ** be replaced by a clone of the same project, with different RID
1664 ** values.
1665 */
1666 if( g.localOpen && !db_fingerprint_ok() ){
1667 /* Uncomment the following when we are ready for automatic recovery: */
1668 #if 0
1669 stash_rid_renumbering_event();
1670 #else
1671 fossil_print(
1672 "Oops. It looks like the repository database file located at\n"
1673 " \"%s\"\n", zDbName
1674 );
1675 fossil_print(
1676 "has been swapped with a clone that may have different\n"
1677 "integer keys for the various artifacts. As of 2019-01-11,\n"
1678 "we are working on enhancing Fossil to be able to deal with\n"
1679 "that automatically, but we are not there yet. Sorry.\n\n"
1680 );
1681 fossil_print(
1682 "As an interim workaround, try:\n"
1683 " %s close --force\n"
1684 " %s open \"%s\" --keep\n"
1685 "Noting that any STASH and UNDO information "
1686 "WILL BE IRREVOCABLY LOST.\n\n",
1687 g.argv[0],
1688 g.argv[0], zDbName
1689 );
1690 fossil_fatal("bad fingerprint");
1691 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1692 }
1693 }
1694
1695 /*
1696 ** Return true if there have been any changes to the repository
@@ -2880,11 +2929,11 @@
2880 #if defined(_WIN32) || defined(__CYGWIN__)
2881 # define LOCALDB_NAME "./_FOSSIL_"
2882 #else
2883 # define LOCALDB_NAME "./.fslckout"
2884 #endif
2885 db_init_database(LOCALDB_NAME, zLocalSchema,
2886 #ifdef FOSSIL_LOCAL_WAL
2887 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
2888 #endif
2889 (char*)0);
2890 db_delete_on_failure(LOCALDB_NAME);
2891
--- src/db.c
+++ src/db.c
@@ -1473,33 +1473,44 @@
1473 ** If zDbName is a valid local database file, open it and return
1474 ** true. If it is not a valid local database file, return 0.
1475 */
1476 static int isValidLocalDb(const char *zDbName){
1477 i64 lsize;
 
1478
1479 if( file_access(zDbName, F_OK) ) return 0;
1480 lsize = file_size(zDbName, ExtFILE);
1481 if( lsize%1024!=0 || lsize<4096 ) return 0;
1482 db_open_or_attach(zDbName, "localdb");
1483
1484 /* Check to see if the checkout database has the lastest schema changes.
1485 ** The most recent schema change (2019-01-19) is the addition of the
1486 ** vmerge.mhash and vfile.mhash fields. If the schema has the vmerge.mhash
1487 ** column, assume everything else is up-to-date.
1488 */
1489 if( db_table_has_column("localdb","vmerge","mhash") ){
1490 return 1; /* This is a checkout database with the latest schema */
1491 }
1492
1493 /* If there is no vfile table, then assume we have picked up something
1494 ** that is not even close to being a valid checkout database */
1495 if( !db_table_exists("localdb","vfile") ){
1496 return 0; /* Not a DB */
1497 }
1498
1499 /* If the "isexe" column is missing from the vfile table, then
1500 ** add it now. This code added on 2010-03-06. After all users have
1501 ** upgraded, this code can be safely deleted.
1502 */
1503 if( !db_table_has_column("localdb","vfile","isexe") ){
1504 db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0");
1505 }
1506
1507 /* If "islink"/"isLink" columns are missing from tables, then
1508 ** add them now. This code added on 2011-01-17 and 2011-08-27.
1509 ** After all users have upgraded, this code can be safely deleted.
1510 */
1511 if( !db_table_has_column("localdb","vfile","isLink") ){
1512 db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0");
1513 if( db_local_table_exists_but_lacks_column("stashfile", "isLink") ){
1514 db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOL DEFAULT 0");
1515 }
1516 if( db_local_table_exists_but_lacks_column("undo", "isLink") ){
@@ -1507,11 +1518,16 @@
1518 }
1519 if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){
1520 db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0");
1521 }
1522 }
1523
1524 /* The design of the checkout database changed on 2019-01-19, adding the mhash
1525 ** column to vfile and vmerge and changing the UNIQUE index on vmerge into
1526 ** a PRIMARY KEY that includes the new mhash column. However, we must have
1527 ** the repository database at hand in order to do the migration, so that
1528 ** step is deferred. */
1529 return 1;
1530 }
1531
1532 /*
1533 ** Locate the root directory of the local repository tree. The root
@@ -1656,41 +1672,74 @@
1672 /* Make a change to the CHECK constraint on the BLOB table for
1673 ** version 2.0 and later.
1674 */
1675 rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
1676
1677 /* Additional checks that occur when opening the checkout database */
1678 if( g.localOpen ){
1679
1680 /* If the repository database that was just opened has been
1681 ** eplaced by a clone of the same project, with different RID
1682 ** values, then renumber the RID values stored in various tables
1683 ** of the checkout database, so that the repository and checkout
1684 ** databases align.
1685 */
1686 if( !db_fingerprint_ok() ){
1687 if( find_option("no-rid-adjust",0,0)!=0 ){
1688 /* The --no-rid-adjust command-line option bypasses the RID value
1689 ** updates. Intended for use during debugging, especially to be
1690 ** able to run "fossil sql" after a database swap. */
1691 fossil_print(
1692 "WARNING: repository change detected, but no adjust made.\n"
1693 );
1694 }else if( find_option("rid-renumber-dryrun",0,0)!=0 ){
1695 /* the --rid-renumber-dryrun option shows how RID values would be
1696 ** renumbered, but does not actually perform the renumbering.
1697 ** This is a debugging-only option. */
1698 vfile_rid_renumbering_event(1);
1699 exit(0);
1700 }else{
1701 char *z;
1702 stash_rid_renumbering_event();
1703 vfile_rid_renumbering_event(0);
1704 undo_reset();
1705 bisect_reset();
1706 z = db_fingerprint(0);
1707 db_lset("fingerprint", z);
1708 fossil_free(z);
1709 fossil_print(
1710 "WARNING: The repository database has been replaced by a clone.\n"
1711 "Bisect history and undo have been lost.\n"
1712 );
1713 }
1714 }
1715
1716 /* Make sure the checkout database schema migration of 2019-01-20
1717 ** has occurred.
1718 **
1719 ** The 2019-01-19 migration is the addition of the vmerge.mhash and
1720 ** vfile.mhash columns and making the vmerge.mhash column part of the
1721 ** PRIMARY KEY for vmerge.
1722 */
1723 if( !db_table_has_column("localdb", "vfile", "mhash") ){
1724 db_multi_exec("ALTER TABLE vfile ADD COLUMN mhash;");
1725 db_multi_exec(
1726 "UPDATE vfile"
1727 " SET mhash=(SELECT uuid FROM blob WHERE blob.rid=vfile.mrid)"
1728 " WHERE mrid!=rid;"
1729 );
1730 if( !db_table_has_column("localdb", "vmerge", "mhash") ){
1731 db_multi_exec("ALTER TABLE vmerge RENAME TO old_vmerge;");
1732 db_multi_exec(zLocalSchemaVmerge /*works-like:""*/);
1733 db_multi_exec(
1734 "INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
1735 " SELECT id, merge, blob.uuid FROM old_vmerge, blob"
1736 " WHERE old_vmerge.merge=blob.rid;"
1737 "DROP TABLE old_vmerge;"
1738 );
1739 }
1740 }
1741 }
1742 }
1743
1744 /*
1745 ** Return true if there have been any changes to the repository
@@ -2880,11 +2929,11 @@
2929 #if defined(_WIN32) || defined(__CYGWIN__)
2930 # define LOCALDB_NAME "./_FOSSIL_"
2931 #else
2932 # define LOCALDB_NAME "./.fslckout"
2933 #endif
2934 db_init_database(LOCALDB_NAME, zLocalSchema, zLocalSchemaVmerge,
2935 #ifdef FOSSIL_LOCAL_WAL
2936 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
2937 #endif
2938 (char*)0);
2939 db_delete_on_failure(LOCALDB_NAME);
2940
+2 -1
--- src/foci.c
+++ src/foci.c
@@ -121,12 +121,13 @@
121121
** (1) checkinID=?. visit only the single manifest specified.
122122
** (2) symName=? visit only the single manifest specified.
123123
*/
124124
static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
125125
int i;
126
- pIdxInfo->estimatedCost = 10000.0;
126
+ pIdxInfo->estimatedCost = 1000000000.0;
127127
for(i=0; i<pIdxInfo->nConstraint; i++){
128
+ if( !pIdxInfo->aConstraint[i].usable ) continue;
128129
if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
129130
&& (pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID
130131
|| pIdxInfo->aConstraint[i].iColumn==FOCI_SYMNAME)
131132
){
132133
if( pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID ){
133134
--- src/foci.c
+++ src/foci.c
@@ -121,12 +121,13 @@
121 ** (1) checkinID=?. visit only the single manifest specified.
122 ** (2) symName=? visit only the single manifest specified.
123 */
124 static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
125 int i;
126 pIdxInfo->estimatedCost = 10000.0;
127 for(i=0; i<pIdxInfo->nConstraint; i++){
 
128 if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
129 && (pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID
130 || pIdxInfo->aConstraint[i].iColumn==FOCI_SYMNAME)
131 ){
132 if( pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID ){
133
--- src/foci.c
+++ src/foci.c
@@ -121,12 +121,13 @@
121 ** (1) checkinID=?. visit only the single manifest specified.
122 ** (2) symName=? visit only the single manifest specified.
123 */
124 static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
125 int i;
126 pIdxInfo->estimatedCost = 1000000000.0;
127 for(i=0; i<pIdxInfo->nConstraint; i++){
128 if( !pIdxInfo->aConstraint[i].usable ) continue;
129 if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
130 && (pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID
131 || pIdxInfo->aConstraint[i].iColumn==FOCI_SYMNAME)
132 ){
133 if( pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID ){
134
--- src/json_status.c
+++ src/json_status.c
@@ -154,12 +154,11 @@
154154
155155
#if 0
156156
/* TODO: add "merged with" status. First need (A) to decide on a
157157
structure and (B) to set up some tests for the multi-merge
158158
case.*/
159
- db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
160
- " WHERE id<=0");
159
+ db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0");
161160
while( db_step(&q)==SQLITE_ROW ){
162161
const char *zLabel = "MERGED_WITH";
163162
switch( db_column_int(&q, 1) ){
164163
case -1: zLabel = "CHERRYPICK "; break;
165164
case -2: zLabel = "BACKOUT "; break;
166165
--- src/json_status.c
+++ src/json_status.c
@@ -154,12 +154,11 @@
154
155 #if 0
156 /* TODO: add "merged with" status. First need (A) to decide on a
157 structure and (B) to set up some tests for the multi-merge
158 case.*/
159 db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
160 " WHERE id<=0");
161 while( db_step(&q)==SQLITE_ROW ){
162 const char *zLabel = "MERGED_WITH";
163 switch( db_column_int(&q, 1) ){
164 case -1: zLabel = "CHERRYPICK "; break;
165 case -2: zLabel = "BACKOUT "; break;
166
--- src/json_status.c
+++ src/json_status.c
@@ -154,12 +154,11 @@
154
155 #if 0
156 /* TODO: add "merged with" status. First need (A) to decide on a
157 structure and (B) to set up some tests for the multi-merge
158 case.*/
159 db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0");
 
160 while( db_step(&q)==SQLITE_ROW ){
161 const char *zLabel = "MERGED_WITH";
162 switch( db_column_int(&q, 1) ){
163 case -1: zLabel = "CHERRYPICK "; break;
164 case -2: zLabel = "BACKOUT "; break;
165
+25 -10
--- src/merge.c
+++ src/merge.c
@@ -164,10 +164,20 @@
164164
free(zN);
165165
free(zV);
166166
}
167167
free(aChng);
168168
}
169
+
170
+/* Make an entry in the vmerge table for the given id, and rid.
171
+*/
172
+static void vmerge_insert(int id, int rid){
173
+ db_multi_exec(
174
+ "INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
175
+ "VALUES(%d,%d,(SELECT uuid FROM blob WHERE rid=%d))",
176
+ id, rid, rid
177
+ );
178
+}
169179
170180
/*
171181
** COMMAND: merge
172182
**
173183
** Usage: %fossil merge ?OPTIONS? ?VERSION?
@@ -594,12 +604,14 @@
594604
/* Copy content from idm over into idv. Overwrite idv. */
595605
fossil_print("UPDATE %s\n", zName);
596606
if( !dryRunFlag ){
597607
undo_save(zName);
598608
db_multi_exec(
599
- "UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d "
600
- " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, idv
609
+ "UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d,"
610
+ " mhash=CASE WHEN rid<>%d"
611
+ " THEN (SELECT uuid FROM blob WHERE blob.rid=%d) END"
612
+ " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, ridm, ridm, idv
601613
);
602614
vfile_to_disk(0, idv, 0, 0);
603615
}
604616
}
605617
db_finalize(&q);
@@ -664,12 +676,11 @@
664676
}
665677
blob_reset(&p);
666678
blob_reset(&m);
667679
blob_reset(&r);
668680
}
669
- db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)",
670
- idv,ridm);
681
+ vmerge_insert(idv, ridm);
671682
}
672683
db_finalize(&q);
673684
674685
/*
675686
** Drop files that are in P and V but not in M
@@ -786,12 +797,16 @@
786797
while( db_step(&q)==SQLITE_ROW ){
787798
int idm = db_column_int(&q, 0);
788799
const char *zName;
789800
char *zFullName;
790801
db_multi_exec(
791
- "REPLACE INTO vfile(vid,chnged,deleted,rid,mrid,isexe,islink,pathname)"
792
- " SELECT %d,%d,0,rid,mrid,isexe,islink,pathname FROM vfile WHERE id=%d",
802
+ "REPLACE INTO vfile(vid,chnged,deleted,rid,mrid,"
803
+ "isexe,islink,pathname,mhash)"
804
+ " SELECT %d,%d,0,rid,mrid,isexe,islink,pathname,"
805
+ "CASE WHEN rid<>mrid"
806
+ " THEN (SELECT uuid FROM blob WHERE blob.rid=vfile.mrid) END "
807
+ "FROM vfile WHERE id=%d",
793808
vid, integrateFlag?5:3, idm
794809
);
795810
zName = db_column_text(&q, 1);
796811
zFullName = mprintf("%s%s", g.zLocalRoot, zName);
797812
if( file_isfile_or_link(zFullName)
@@ -826,24 +841,24 @@
826841
/*
827842
** Clean up the mid and pid VFILE entries. Then commit the changes.
828843
*/
829844
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
830845
if( pickFlag ){
831
- db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-1,%d)",mid);
846
+ vmerge_insert(-1, mid);
832847
/* For a cherry-pick merge, make the default check-in comment the same
833848
** as the check-in comment on the check-in that is being merged in. */
834849
db_multi_exec(
835850
"REPLACE INTO vvar(name,value)"
836851
" SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
837852
" WHERE type='ci' AND objid=%d",
838853
mid
839854
);
840855
}else if( backoutFlag ){
841
- db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-2,%d)",pid);
856
+ vmerge_insert(-2, pid);
842857
}else if( integrateFlag ){
843
- db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid);
858
+ vmerge_insert(-4, mid);
844859
}else{
845
- db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);
860
+ vmerge_insert(0, mid);
846861
}
847862
if( !dryRunFlag ) undo_finish();
848863
db_end_transaction(dryRunFlag);
849864
}
850865
--- src/merge.c
+++ src/merge.c
@@ -164,10 +164,20 @@
164 free(zN);
165 free(zV);
166 }
167 free(aChng);
168 }
 
 
 
 
 
 
 
 
 
 
169
170 /*
171 ** COMMAND: merge
172 **
173 ** Usage: %fossil merge ?OPTIONS? ?VERSION?
@@ -594,12 +604,14 @@
594 /* Copy content from idm over into idv. Overwrite idv. */
595 fossil_print("UPDATE %s\n", zName);
596 if( !dryRunFlag ){
597 undo_save(zName);
598 db_multi_exec(
599 "UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d "
600 " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, idv
 
 
601 );
602 vfile_to_disk(0, idv, 0, 0);
603 }
604 }
605 db_finalize(&q);
@@ -664,12 +676,11 @@
664 }
665 blob_reset(&p);
666 blob_reset(&m);
667 blob_reset(&r);
668 }
669 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)",
670 idv,ridm);
671 }
672 db_finalize(&q);
673
674 /*
675 ** Drop files that are in P and V but not in M
@@ -786,12 +797,16 @@
786 while( db_step(&q)==SQLITE_ROW ){
787 int idm = db_column_int(&q, 0);
788 const char *zName;
789 char *zFullName;
790 db_multi_exec(
791 "REPLACE INTO vfile(vid,chnged,deleted,rid,mrid,isexe,islink,pathname)"
792 " SELECT %d,%d,0,rid,mrid,isexe,islink,pathname FROM vfile WHERE id=%d",
 
 
 
 
793 vid, integrateFlag?5:3, idm
794 );
795 zName = db_column_text(&q, 1);
796 zFullName = mprintf("%s%s", g.zLocalRoot, zName);
797 if( file_isfile_or_link(zFullName)
@@ -826,24 +841,24 @@
826 /*
827 ** Clean up the mid and pid VFILE entries. Then commit the changes.
828 */
829 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
830 if( pickFlag ){
831 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-1,%d)",mid);
832 /* For a cherry-pick merge, make the default check-in comment the same
833 ** as the check-in comment on the check-in that is being merged in. */
834 db_multi_exec(
835 "REPLACE INTO vvar(name,value)"
836 " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
837 " WHERE type='ci' AND objid=%d",
838 mid
839 );
840 }else if( backoutFlag ){
841 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-2,%d)",pid);
842 }else if( integrateFlag ){
843 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid);
844 }else{
845 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);
846 }
847 if( !dryRunFlag ) undo_finish();
848 db_end_transaction(dryRunFlag);
849 }
850
--- src/merge.c
+++ src/merge.c
@@ -164,10 +164,20 @@
164 free(zN);
165 free(zV);
166 }
167 free(aChng);
168 }
169
170 /* Make an entry in the vmerge table for the given id, and rid.
171 */
172 static void vmerge_insert(int id, int rid){
173 db_multi_exec(
174 "INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
175 "VALUES(%d,%d,(SELECT uuid FROM blob WHERE rid=%d))",
176 id, rid, rid
177 );
178 }
179
180 /*
181 ** COMMAND: merge
182 **
183 ** Usage: %fossil merge ?OPTIONS? ?VERSION?
@@ -594,12 +604,14 @@
604 /* Copy content from idm over into idv. Overwrite idv. */
605 fossil_print("UPDATE %s\n", zName);
606 if( !dryRunFlag ){
607 undo_save(zName);
608 db_multi_exec(
609 "UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d,"
610 " mhash=CASE WHEN rid<>%d"
611 " THEN (SELECT uuid FROM blob WHERE blob.rid=%d) END"
612 " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, ridm, ridm, idv
613 );
614 vfile_to_disk(0, idv, 0, 0);
615 }
616 }
617 db_finalize(&q);
@@ -664,12 +676,11 @@
676 }
677 blob_reset(&p);
678 blob_reset(&m);
679 blob_reset(&r);
680 }
681 vmerge_insert(idv, ridm);
 
682 }
683 db_finalize(&q);
684
685 /*
686 ** Drop files that are in P and V but not in M
@@ -786,12 +797,16 @@
797 while( db_step(&q)==SQLITE_ROW ){
798 int idm = db_column_int(&q, 0);
799 const char *zName;
800 char *zFullName;
801 db_multi_exec(
802 "REPLACE INTO vfile(vid,chnged,deleted,rid,mrid,"
803 "isexe,islink,pathname,mhash)"
804 " SELECT %d,%d,0,rid,mrid,isexe,islink,pathname,"
805 "CASE WHEN rid<>mrid"
806 " THEN (SELECT uuid FROM blob WHERE blob.rid=vfile.mrid) END "
807 "FROM vfile WHERE id=%d",
808 vid, integrateFlag?5:3, idm
809 );
810 zName = db_column_text(&q, 1);
811 zFullName = mprintf("%s%s", g.zLocalRoot, zName);
812 if( file_isfile_or_link(zFullName)
@@ -826,24 +841,24 @@
841 /*
842 ** Clean up the mid and pid VFILE entries. Then commit the changes.
843 */
844 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
845 if( pickFlag ){
846 vmerge_insert(-1, mid);
847 /* For a cherry-pick merge, make the default check-in comment the same
848 ** as the check-in comment on the check-in that is being merged in. */
849 db_multi_exec(
850 "REPLACE INTO vvar(name,value)"
851 " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
852 " WHERE type='ci' AND objid=%d",
853 mid
854 );
855 }else if( backoutFlag ){
856 vmerge_insert(-2, pid);
857 }else if( integrateFlag ){
858 vmerge_insert(-4, mid);
859 }else{
860 vmerge_insert(0, mid);
861 }
862 if( !dryRunFlag ) undo_finish();
863 db_end_transaction(dryRunFlag);
864 }
865
+37 -17
--- src/schema.c
+++ src/schema.c
@@ -2,11 +2,11 @@
22
** Copyright (c) 2007 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
7
-
7
+**
88
** This program is distributed in the hope that it will be useful,
99
** but without any warranty; without even the implied warranty of
1010
** merchantability or fitness for a particular purpose.
1111
**
1212
** Author contact information:
@@ -352,11 +352,11 @@
352352
@ --
353353
@ CREATE TABLE unsent(
354354
@ rid INTEGER PRIMARY KEY -- Record ID of the phantom
355355
@ );
356356
@
357
-@ -- Each baseline or manifest can have one or more tags. A tag
357
+@ -- Each artifact can have one or more tags. A tag
358358
@ -- is defined by a row in the next table.
359359
@ --
360360
@ -- Wiki pages are tagged with "wiki-NAME" where NAME is the name of
361361
@ -- the wiki page. Tickets changes are tagged with "ticket-UUID" where
362362
@ -- UUID is the indentifier of the ticket. Tags used to assign symbolic
@@ -377,11 +377,11 @@
377377
@ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH
378378
@ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED
379379
@ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT
380380
@ INSERT INTO tag VALUES(11,'note'); -- TAG_NOTE
381381
@
382
-@ -- Assignments of tags to baselines. Note that we allow tags to
382
+@ -- Assignments of tags to artifacts. Note that we allow tags to
383383
@ -- have values assigned to them. So we are not really dealing with
384384
@ -- tags here. These are really properties. But we are going to
385385
@ -- keep calling them tags because in many cases the value is ignored.
386386
@ --
387387
@ CREATE TABLE tagxref(
@@ -490,11 +490,11 @@
490490
#endif
491491
492492
/*
493493
** The schema for the local FOSSIL database file found at the root
494494
** of every check-out. This database contains the complete state of
495
-** the checkout.
495
+** the checkout. See also the addendum in zLocalSchemaVmerge[].
496496
*/
497497
const char zLocalSchema[] =
498498
@ -- The VVAR table holds miscellanous information about the local database
499499
@ -- in the form of name-value pairs. This is similar to the VAR table
500500
@ -- table in the repository except that this table holds information that
@@ -515,51 +515,71 @@
515515
@ -- current checkout.
516516
@ --
517517
@ -- The file.rid field is 0 for files or folders that have been
518518
@ -- added but not yet committed.
519519
@ --
520
-@ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
521
-@ -- been edited or which have been subjected to a 3-way merge.
522
-@ -- Vfile.chnged is 2 if the file has been replaced from a different
523
-@ -- version by the merge and 3 if the file has been added by a merge.
524
-@ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been
525
-@ -- done by an --integrate merge. The difference between vfile.chnged==3|5
526
-@ -- and a regular add is that with vfile.chnged==3|5 we know that the
527
-@ -- current version of the file is already in the repository.
520
+@ -- Vfile.chnged meaning:
521
+@ -- 0 File is unmodified
522
+@ -- 1 Manually edited and/or modified as part of a merge command
523
+@ -- 2 Replaced by a merge command
524
+@ -- 3 Added by a merge command
525
+@ -- 4,5 Same as 2,3 except merge using --integrate
528526
@ --
529527
@ CREATE TABLE vfile(
530528
@ id INTEGER PRIMARY KEY, -- ID of the checked out file
531
-@ vid INTEGER REFERENCES blob, -- The baseline this file is part of.
529
+@ vid INTEGER REFERENCES blob, -- The checkin this file is part of.
532530
@ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add
533531
@ deleted BOOLEAN DEFAULT 0, -- True if deleted
534532
@ isexe BOOLEAN, -- True if file should be executable
535533
@ islink BOOLEAN, -- True if file should be symlink
536534
@ rid INTEGER, -- Originally from this repository record
537535
@ mrid INTEGER, -- Based on this record due to a merge
538536
@ mtime INTEGER, -- Mtime of file on disk. sec since 1970
539537
@ pathname TEXT, -- Full pathname relative to root
540538
@ origname TEXT, -- Original pathname. NULL if unchanged
539
+@ mhash TEXT, -- Hash of mrid iff mrid!=rid
541540
@ UNIQUE(pathname,vid)
542541
@ );
543542
@
543
+@ -- Identifier for this file type.
544
+@ -- The integer is the same as 'FSLC'.
545
+@ PRAGMA application_id=252006674;
546
+;
547
+
548
+/* Additional local database initialization following the schema
549
+** enhancement of 2019-01-19, in which the mhash column was added
550
+** to vmerge and vfile.
551
+*/
552
+const char zLocalSchemaVmerge[] =
544553
@ -- This table holds a record of uncommitted merges in the local
545554
@ -- file tree. If a VFILE entry with id has merged with another
546555
@ -- record, there is an entry in this table with (id,merge) where
547556
@ -- merge is the RECORD table entry that the file merged against.
548557
@ -- An id of 0 or <-3 here means the version record itself. When
549558
@ -- id==(-1) that is a cherrypick merge, id==(-2) that is a
550559
@ -- backout merge and id==(-4) is a integrate merge.
560
+@ --
551561
@
552562
@ CREATE TABLE vmerge(
553563
@ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged
554564
@ merge INTEGER, -- Merged with this record
555
-@ UNIQUE(id, merge)
565
+@ mhash TEXT -- SHA1/SHA3 hash for merge object
556566
@ );
567
+@ CREATE UNIQUE INDEX vmergex1 ON vmerge(id,mhash);
568
+@
569
+@ -- The following trigger will prevent older versions of Fossil that
570
+@ -- do not know about the new vmerge.mhash column from updating the
571
+@ -- vmerge table. This must be done with a trigger, since legacy Fossil
572
+@ -- uses INSERT OR IGNORE to update vmerge, and the OR IGNORE will cause
573
+@ -- a NOT NULL constraint to be silently ignored.
557574
@
558
-@ -- Identifier for this file type.
559
-@ -- The integer is the same as 'FSLC'.
560
-@ PRAGMA application_id=252006674;
575
+@ CREATE TRIGGER vmerge_ck1 AFTER INSERT ON vmerge
576
+@ WHEN new.mhash IS NULL BEGIN
577
+@ SELECT raise(FAIL,
578
+@ 'trying to update a newer checkout with an older version of Fossil');
579
+@ END;
580
+@
561581
;
562582
563583
/*
564584
** The following table holds information about forum posts. It
565585
** is created on-demand whenever the manifest parser encounters
566586
--- src/schema.c
+++ src/schema.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2007 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -352,11 +352,11 @@
352 @ --
353 @ CREATE TABLE unsent(
354 @ rid INTEGER PRIMARY KEY -- Record ID of the phantom
355 @ );
356 @
357 @ -- Each baseline or manifest can have one or more tags. A tag
358 @ -- is defined by a row in the next table.
359 @ --
360 @ -- Wiki pages are tagged with "wiki-NAME" where NAME is the name of
361 @ -- the wiki page. Tickets changes are tagged with "ticket-UUID" where
362 @ -- UUID is the indentifier of the ticket. Tags used to assign symbolic
@@ -377,11 +377,11 @@
377 @ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH
378 @ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED
379 @ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT
380 @ INSERT INTO tag VALUES(11,'note'); -- TAG_NOTE
381 @
382 @ -- Assignments of tags to baselines. Note that we allow tags to
383 @ -- have values assigned to them. So we are not really dealing with
384 @ -- tags here. These are really properties. But we are going to
385 @ -- keep calling them tags because in many cases the value is ignored.
386 @ --
387 @ CREATE TABLE tagxref(
@@ -490,11 +490,11 @@
490 #endif
491
492 /*
493 ** The schema for the local FOSSIL database file found at the root
494 ** of every check-out. This database contains the complete state of
495 ** the checkout.
496 */
497 const char zLocalSchema[] =
498 @ -- The VVAR table holds miscellanous information about the local database
499 @ -- in the form of name-value pairs. This is similar to the VAR table
500 @ -- table in the repository except that this table holds information that
@@ -515,51 +515,71 @@
515 @ -- current checkout.
516 @ --
517 @ -- The file.rid field is 0 for files or folders that have been
518 @ -- added but not yet committed.
519 @ --
520 @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
521 @ -- been edited or which have been subjected to a 3-way merge.
522 @ -- Vfile.chnged is 2 if the file has been replaced from a different
523 @ -- version by the merge and 3 if the file has been added by a merge.
524 @ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been
525 @ -- done by an --integrate merge. The difference between vfile.chnged==3|5
526 @ -- and a regular add is that with vfile.chnged==3|5 we know that the
527 @ -- current version of the file is already in the repository.
528 @ --
529 @ CREATE TABLE vfile(
530 @ id INTEGER PRIMARY KEY, -- ID of the checked out file
531 @ vid INTEGER REFERENCES blob, -- The baseline this file is part of.
532 @ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add
533 @ deleted BOOLEAN DEFAULT 0, -- True if deleted
534 @ isexe BOOLEAN, -- True if file should be executable
535 @ islink BOOLEAN, -- True if file should be symlink
536 @ rid INTEGER, -- Originally from this repository record
537 @ mrid INTEGER, -- Based on this record due to a merge
538 @ mtime INTEGER, -- Mtime of file on disk. sec since 1970
539 @ pathname TEXT, -- Full pathname relative to root
540 @ origname TEXT, -- Original pathname. NULL if unchanged
 
541 @ UNIQUE(pathname,vid)
542 @ );
543 @
 
 
 
 
 
 
 
 
 
 
544 @ -- This table holds a record of uncommitted merges in the local
545 @ -- file tree. If a VFILE entry with id has merged with another
546 @ -- record, there is an entry in this table with (id,merge) where
547 @ -- merge is the RECORD table entry that the file merged against.
548 @ -- An id of 0 or <-3 here means the version record itself. When
549 @ -- id==(-1) that is a cherrypick merge, id==(-2) that is a
550 @ -- backout merge and id==(-4) is a integrate merge.
 
551 @
552 @ CREATE TABLE vmerge(
553 @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged
554 @ merge INTEGER, -- Merged with this record
555 @ UNIQUE(id, merge)
556 @ );
 
 
 
 
 
 
 
557 @
558 @ -- Identifier for this file type.
559 @ -- The integer is the same as 'FSLC'.
560 @ PRAGMA application_id=252006674;
 
 
 
561 ;
562
563 /*
564 ** The following table holds information about forum posts. It
565 ** is created on-demand whenever the manifest parser encounters
566
--- src/schema.c
+++ src/schema.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2007 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -352,11 +352,11 @@
352 @ --
353 @ CREATE TABLE unsent(
354 @ rid INTEGER PRIMARY KEY -- Record ID of the phantom
355 @ );
356 @
357 @ -- Each artifact can have one or more tags. A tag
358 @ -- is defined by a row in the next table.
359 @ --
360 @ -- Wiki pages are tagged with "wiki-NAME" where NAME is the name of
361 @ -- the wiki page. Tickets changes are tagged with "ticket-UUID" where
362 @ -- UUID is the indentifier of the ticket. Tags used to assign symbolic
@@ -377,11 +377,11 @@
377 @ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH
378 @ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED
379 @ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT
380 @ INSERT INTO tag VALUES(11,'note'); -- TAG_NOTE
381 @
382 @ -- Assignments of tags to artifacts. Note that we allow tags to
383 @ -- have values assigned to them. So we are not really dealing with
384 @ -- tags here. These are really properties. But we are going to
385 @ -- keep calling them tags because in many cases the value is ignored.
386 @ --
387 @ CREATE TABLE tagxref(
@@ -490,11 +490,11 @@
490 #endif
491
492 /*
493 ** The schema for the local FOSSIL database file found at the root
494 ** of every check-out. This database contains the complete state of
495 ** the checkout. See also the addendum in zLocalSchemaVmerge[].
496 */
497 const char zLocalSchema[] =
498 @ -- The VVAR table holds miscellanous information about the local database
499 @ -- in the form of name-value pairs. This is similar to the VAR table
500 @ -- table in the repository except that this table holds information that
@@ -515,51 +515,71 @@
515 @ -- current checkout.
516 @ --
517 @ -- The file.rid field is 0 for files or folders that have been
518 @ -- added but not yet committed.
519 @ --
520 @ -- Vfile.chnged meaning:
521 @ -- 0 File is unmodified
522 @ -- 1 Manually edited and/or modified as part of a merge command
523 @ -- 2 Replaced by a merge command
524 @ -- 3 Added by a merge command
525 @ -- 4,5 Same as 2,3 except merge using --integrate
 
 
526 @ --
527 @ CREATE TABLE vfile(
528 @ id INTEGER PRIMARY KEY, -- ID of the checked out file
529 @ vid INTEGER REFERENCES blob, -- The checkin this file is part of.
530 @ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add
531 @ deleted BOOLEAN DEFAULT 0, -- True if deleted
532 @ isexe BOOLEAN, -- True if file should be executable
533 @ islink BOOLEAN, -- True if file should be symlink
534 @ rid INTEGER, -- Originally from this repository record
535 @ mrid INTEGER, -- Based on this record due to a merge
536 @ mtime INTEGER, -- Mtime of file on disk. sec since 1970
537 @ pathname TEXT, -- Full pathname relative to root
538 @ origname TEXT, -- Original pathname. NULL if unchanged
539 @ mhash TEXT, -- Hash of mrid iff mrid!=rid
540 @ UNIQUE(pathname,vid)
541 @ );
542 @
543 @ -- Identifier for this file type.
544 @ -- The integer is the same as 'FSLC'.
545 @ PRAGMA application_id=252006674;
546 ;
547
548 /* Additional local database initialization following the schema
549 ** enhancement of 2019-01-19, in which the mhash column was added
550 ** to vmerge and vfile.
551 */
552 const char zLocalSchemaVmerge[] =
553 @ -- This table holds a record of uncommitted merges in the local
554 @ -- file tree. If a VFILE entry with id has merged with another
555 @ -- record, there is an entry in this table with (id,merge) where
556 @ -- merge is the RECORD table entry that the file merged against.
557 @ -- An id of 0 or <-3 here means the version record itself. When
558 @ -- id==(-1) that is a cherrypick merge, id==(-2) that is a
559 @ -- backout merge and id==(-4) is a integrate merge.
560 @ --
561 @
562 @ CREATE TABLE vmerge(
563 @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged
564 @ merge INTEGER, -- Merged with this record
565 @ mhash TEXT -- SHA1/SHA3 hash for merge object
566 @ );
567 @ CREATE UNIQUE INDEX vmergex1 ON vmerge(id,mhash);
568 @
569 @ -- The following trigger will prevent older versions of Fossil that
570 @ -- do not know about the new vmerge.mhash column from updating the
571 @ -- vmerge table. This must be done with a trigger, since legacy Fossil
572 @ -- uses INSERT OR IGNORE to update vmerge, and the OR IGNORE will cause
573 @ -- a NOT NULL constraint to be silently ignored.
574 @
575 @ CREATE TRIGGER vmerge_ck1 AFTER INSERT ON vmerge
576 @ WHEN new.mhash IS NULL BEGIN
577 @ SELECT raise(FAIL,
578 @ 'trying to update a newer checkout with an older version of Fossil');
579 @ END;
580 @
581 ;
582
583 /*
584 ** The following table holds information about forum posts. It
585 ** is created on-demand whenever the manifest parser encounters
586
+3 -3
--- src/update.c
+++ src/update.c
@@ -529,12 +529,11 @@
529529
/* Report on conflicts
530530
*/
531531
if( !dryRunFlag ){
532532
Stmt q;
533533
int nMerge = 0;
534
- db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
535
- " WHERE id<=0");
534
+ db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0");
536535
while( db_step(&q)==SQLITE_ROW ){
537536
const char *zLabel = "merge";
538537
switch( db_column_int(&q, 1) ){
539538
case -1: zLabel = "cherrypick merge"; break;
540539
case -2: zLabel = "backout merge"; break;
@@ -865,11 +864,12 @@
865864
file_setexe(zFull, rvPerm==PERM_EXE);
866865
fossil_print("REVERT %s\n", zFile);
867866
mtime = file_mtime(zFull, RepoFILE);
868867
db_multi_exec(
869868
"UPDATE vfile"
870
- " SET mtime=%lld, chnged=%d, deleted=0, isexe=%d, islink=%d,mrid=rid"
869
+ " SET mtime=%lld, chnged=%d, deleted=0, isexe=%d, islink=%d,"
870
+ " mrid=rid, mhash=NULL"
871871
" WHERE pathname=%Q OR origname=%Q",
872872
mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile
873873
);
874874
}
875875
blob_reset(&record);
876876
--- src/update.c
+++ src/update.c
@@ -529,12 +529,11 @@
529 /* Report on conflicts
530 */
531 if( !dryRunFlag ){
532 Stmt q;
533 int nMerge = 0;
534 db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
535 " WHERE id<=0");
536 while( db_step(&q)==SQLITE_ROW ){
537 const char *zLabel = "merge";
538 switch( db_column_int(&q, 1) ){
539 case -1: zLabel = "cherrypick merge"; break;
540 case -2: zLabel = "backout merge"; break;
@@ -865,11 +864,12 @@
865 file_setexe(zFull, rvPerm==PERM_EXE);
866 fossil_print("REVERT %s\n", zFile);
867 mtime = file_mtime(zFull, RepoFILE);
868 db_multi_exec(
869 "UPDATE vfile"
870 " SET mtime=%lld, chnged=%d, deleted=0, isexe=%d, islink=%d,mrid=rid"
 
871 " WHERE pathname=%Q OR origname=%Q",
872 mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile
873 );
874 }
875 blob_reset(&record);
876
--- src/update.c
+++ src/update.c
@@ -529,12 +529,11 @@
529 /* Report on conflicts
530 */
531 if( !dryRunFlag ){
532 Stmt q;
533 int nMerge = 0;
534 db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0");
 
535 while( db_step(&q)==SQLITE_ROW ){
536 const char *zLabel = "merge";
537 switch( db_column_int(&q, 1) ){
538 case -1: zLabel = "cherrypick merge"; break;
539 case -2: zLabel = "backout merge"; break;
@@ -865,11 +864,12 @@
864 file_setexe(zFull, rvPerm==PERM_EXE);
865 fossil_print("REVERT %s\n", zFile);
866 mtime = file_mtime(zFull, RepoFILE);
867 db_multi_exec(
868 "UPDATE vfile"
869 " SET mtime=%lld, chnged=%d, deleted=0, isexe=%d, islink=%d,"
870 " mrid=rid, mhash=NULL"
871 " WHERE pathname=%Q OR origname=%Q",
872 mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile
873 );
874 }
875 blob_reset(&record);
876
+130 -3
--- src/vfile.c
+++ src/vfile.c
@@ -88,12 +88,12 @@
8888
if( p==0 ) {
8989
db_end_transaction(1);
9090
return 0;
9191
}
9292
db_prepare(&ins,
93
- "INSERT INTO vfile(vid,isexe,islink,rid,mrid,pathname) "
94
- " VALUES(:vid,:isexe,:islink,:id,:id,:name)");
93
+ "INSERT INTO vfile(vid,isexe,islink,rid,mrid,pathname,mhash) "
94
+ " VALUES(:vid,:isexe,:islink,:id,:id,:name,NULL)");
9595
db_prepare(&ridq, "SELECT rid,size FROM blob WHERE uuid=:uuid");
9696
db_bind_int(&ins, ":vid", vid);
9797
manifest_file_rewind(p);
9898
nMissing = 0;
9999
while( (pFile = manifest_file_next(p,0))!=0 ){
@@ -242,11 +242,11 @@
242242
const char *zUuid = db_column_text(&q, 5);
243243
int nUuid = db_column_bytes(&q, 5);
244244
assert( origSize==currentSize );
245245
if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1;
246246
}
247
- if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){
247
+ if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4)){
248248
i64 desiredMtime;
249249
if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
250250
if( currentMtime!=desiredMtime ){
251251
file_set_mtime(zName, desiredMtime);
252252
currentMtime = file_mtime(zName, RepoFILE);
@@ -966,5 +966,132 @@
966966
blob_reset(&hash);
967967
vfile_aggregate_checksum_manifest(vid, &hash, &hash2);
968968
printf("manifest: %s\n", blob_str(&hash));
969969
printf("recorded: %s\n", blob_str(&hash2));
970970
}
971
+
972
+/*
973
+** This routine recomputes certain columns of the vfile and vmerge tables
974
+** when the associated repository is swapped out for a clone of the same
975
+** project, and the blob.rid value change. The following columns are
976
+** updated:
977
+**
978
+** vmerge.merge
979
+** vfile.vid
980
+** vfile.rid
981
+** vfile.mrid
982
+**
983
+** Also:
984
+**
985
+** vvar.value WHERE name='checkout'
986
+*/
987
+void vfile_rid_renumbering_event(int dryRun){
988
+ int oldVid;
989
+ int newVid;
990
+ char *zUnresolved;
991
+
992
+ oldVid = db_lget_int("checkout", 0);
993
+ newVid = db_int(0, "SELECT blob.rid FROM blob, vvar"
994
+ " WHERE blob.uuid=vvar.value"
995
+ " AND vvar.name='checkout-hash'");
996
+
997
+ /* The idMap table will make old RID values into new ones */
998
+ db_multi_exec(
999
+ "CREATE TEMP TABLE idMap(oldrid INTEGER PRIMARY KEY, newrid INT);\n"
1000
+ );
1001
+
1002
+ /* Add the RID value for the current check-out */
1003
+ db_multi_exec(
1004
+ "INSERT INTO idMap(oldrid, newrid) VALUES(%d,%d)",
1005
+ oldVid, newVid
1006
+ );
1007
+
1008
+ /* Add the RID values for any other check-ins that have been merged into
1009
+ ** the current check-out. */
1010
+ db_multi_exec(
1011
+ "INSERT OR IGNORE INTO idMap(oldrid, newrid)"
1012
+ " SELECT vmerge.merge, blob.rid FROM vmerge, blob"
1013
+ " WHERE blob.uuid=vmerge.mhash;"
1014
+ );
1015
+
1016
+ /* Add RID values for files in the current check-out */
1017
+ db_multi_exec(
1018
+ "CREATE TEMP TABLE hashoffile(name TEXT PRIMARY KEY, hash TEXT)"
1019
+ "WITHOUT ROWID;"
1020
+
1021
+ "INSERT INTO hashoffile(name,hash)"
1022
+ " SELECT filename, uuid FROM vvar, files_of_checkin(vvar.value)"
1023
+ " WHERE vvar.name='checkout-hash';"
1024
+
1025
+ "INSERT OR IGNORE INTO idMap(oldrid, newrid)"
1026
+ " SELECT vfile.rid, blob.rid FROM vfile, hashoffile, blob"
1027
+ " WHERE hashoffile.name=coalesce(vfile.origname,vfile.pathname)"
1028
+ " AND blob.uuid=hashoffile.hash;"
1029
+ );
1030
+
1031
+ /* Add RID values for merged-in files */
1032
+ db_multi_exec(
1033
+ "INSERT OR IGNORE INTO idMap(oldrid, newrid)"
1034
+ " SELECT vfile.mrid, blob.rid FROM vfile, blob"
1035
+ " WHERE blob.uuid=vfile.mhash;"
1036
+ );
1037
+
1038
+ if( dryRun ){
1039
+ Stmt q;
1040
+ db_prepare(&q, "SELECT oldrid, newrid, blob.uuid"
1041
+ " FROM idMap, blob WHERE blob.rid=idMap.newrid");
1042
+ while( db_step(&q)==SQLITE_ROW ){
1043
+ fossil_print("%8d -> %8d %.25s\n",
1044
+ db_column_int(&q,0),
1045
+ db_column_int(&q,1),
1046
+ db_column_text(&q,2));
1047
+ }
1048
+ db_finalize(&q);
1049
+ }
1050
+
1051
+ /* Verify that all RID values in the VFILE table and VMERGE table have
1052
+ ** been resolved. */
1053
+ zUnresolved = db_text("",
1054
+ "WITH allrid(x) AS ("
1055
+ " SELECT rid FROM vfile"
1056
+ " UNION SELECT mrid FROM vfile"
1057
+ " UNION SELECT merge FROM vmerge"
1058
+ " UNION SELECT %d"
1059
+ ")"
1060
+ "SELECT group_concat(x,' ') FROM allrid"
1061
+ " WHERE x NOT IN (SELECT oldrid FROM idMap);",
1062
+ oldVid
1063
+ );
1064
+ if( zUnresolved[0] ){
1065
+ fossil_fatal("Unresolved RID values: %s\n", zUnresolved);
1066
+ }
1067
+
1068
+ /* Make the changes to the VFILE and VMERGE tables */
1069
+ if( !dryRun ){
1070
+ db_multi_exec(
1071
+ "UPDATE vfile"
1072
+ " SET rid=(SELECT newrid FROM idMap WHERE oldrid=vfile.rid)"
1073
+ " WHERE vid=%d AND rid>0;", oldVid);
1074
+
1075
+ db_multi_exec(
1076
+ "UPDATE vfile"
1077
+ " SET mrid=(SELECT newrid FROM idMap WHERE oldrid=vfile.mrid)"
1078
+ " WHERE vid=%d AND mrid>0;", oldVid);
1079
+
1080
+ db_multi_exec(
1081
+ "UPDATE vfile"
1082
+ " SET vid=%d"
1083
+ " WHERE vid=%d", newVid, oldVid);
1084
+
1085
+ db_multi_exec(
1086
+ "UPDATE vmerge"
1087
+ " SET merge=(SELECT newrid FROM idMap WHERE oldrid=vmerge.merge);");
1088
+
1089
+ db_lset_int("checkout",newVid);
1090
+ }
1091
+
1092
+ /* Clear out the TEMP tables we constructed */
1093
+ db_multi_exec(
1094
+ "DROP TABLE idMap;"
1095
+ "DROP TABLE hashoffile;"
1096
+ );
1097
+}
9711098
--- src/vfile.c
+++ src/vfile.c
@@ -88,12 +88,12 @@
88 if( p==0 ) {
89 db_end_transaction(1);
90 return 0;
91 }
92 db_prepare(&ins,
93 "INSERT INTO vfile(vid,isexe,islink,rid,mrid,pathname) "
94 " VALUES(:vid,:isexe,:islink,:id,:id,:name)");
95 db_prepare(&ridq, "SELECT rid,size FROM blob WHERE uuid=:uuid");
96 db_bind_int(&ins, ":vid", vid);
97 manifest_file_rewind(p);
98 nMissing = 0;
99 while( (pFile = manifest_file_next(p,0))!=0 ){
@@ -242,11 +242,11 @@
242 const char *zUuid = db_column_text(&q, 5);
243 int nUuid = db_column_bytes(&q, 5);
244 assert( origSize==currentSize );
245 if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1;
246 }
247 if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){
248 i64 desiredMtime;
249 if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
250 if( currentMtime!=desiredMtime ){
251 file_set_mtime(zName, desiredMtime);
252 currentMtime = file_mtime(zName, RepoFILE);
@@ -966,5 +966,132 @@
966 blob_reset(&hash);
967 vfile_aggregate_checksum_manifest(vid, &hash, &hash2);
968 printf("manifest: %s\n", blob_str(&hash));
969 printf("recorded: %s\n", blob_str(&hash2));
970 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
971
--- src/vfile.c
+++ src/vfile.c
@@ -88,12 +88,12 @@
88 if( p==0 ) {
89 db_end_transaction(1);
90 return 0;
91 }
92 db_prepare(&ins,
93 "INSERT INTO vfile(vid,isexe,islink,rid,mrid,pathname,mhash) "
94 " VALUES(:vid,:isexe,:islink,:id,:id,:name,NULL)");
95 db_prepare(&ridq, "SELECT rid,size FROM blob WHERE uuid=:uuid");
96 db_bind_int(&ins, ":vid", vid);
97 manifest_file_rewind(p);
98 nMissing = 0;
99 while( (pFile = manifest_file_next(p,0))!=0 ){
@@ -242,11 +242,11 @@
242 const char *zUuid = db_column_text(&q, 5);
243 int nUuid = db_column_bytes(&q, 5);
244 assert( origSize==currentSize );
245 if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1;
246 }
247 if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4)){
248 i64 desiredMtime;
249 if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
250 if( currentMtime!=desiredMtime ){
251 file_set_mtime(zName, desiredMtime);
252 currentMtime = file_mtime(zName, RepoFILE);
@@ -966,5 +966,132 @@
966 blob_reset(&hash);
967 vfile_aggregate_checksum_manifest(vid, &hash, &hash2);
968 printf("manifest: %s\n", blob_str(&hash));
969 printf("recorded: %s\n", blob_str(&hash2));
970 }
971
972 /*
973 ** This routine recomputes certain columns of the vfile and vmerge tables
974 ** when the associated repository is swapped out for a clone of the same
975 ** project, and the blob.rid value change. The following columns are
976 ** updated:
977 **
978 ** vmerge.merge
979 ** vfile.vid
980 ** vfile.rid
981 ** vfile.mrid
982 **
983 ** Also:
984 **
985 ** vvar.value WHERE name='checkout'
986 */
987 void vfile_rid_renumbering_event(int dryRun){
988 int oldVid;
989 int newVid;
990 char *zUnresolved;
991
992 oldVid = db_lget_int("checkout", 0);
993 newVid = db_int(0, "SELECT blob.rid FROM blob, vvar"
994 " WHERE blob.uuid=vvar.value"
995 " AND vvar.name='checkout-hash'");
996
997 /* The idMap table will make old RID values into new ones */
998 db_multi_exec(
999 "CREATE TEMP TABLE idMap(oldrid INTEGER PRIMARY KEY, newrid INT);\n"
1000 );
1001
1002 /* Add the RID value for the current check-out */
1003 db_multi_exec(
1004 "INSERT INTO idMap(oldrid, newrid) VALUES(%d,%d)",
1005 oldVid, newVid
1006 );
1007
1008 /* Add the RID values for any other check-ins that have been merged into
1009 ** the current check-out. */
1010 db_multi_exec(
1011 "INSERT OR IGNORE INTO idMap(oldrid, newrid)"
1012 " SELECT vmerge.merge, blob.rid FROM vmerge, blob"
1013 " WHERE blob.uuid=vmerge.mhash;"
1014 );
1015
1016 /* Add RID values for files in the current check-out */
1017 db_multi_exec(
1018 "CREATE TEMP TABLE hashoffile(name TEXT PRIMARY KEY, hash TEXT)"
1019 "WITHOUT ROWID;"
1020
1021 "INSERT INTO hashoffile(name,hash)"
1022 " SELECT filename, uuid FROM vvar, files_of_checkin(vvar.value)"
1023 " WHERE vvar.name='checkout-hash';"
1024
1025 "INSERT OR IGNORE INTO idMap(oldrid, newrid)"
1026 " SELECT vfile.rid, blob.rid FROM vfile, hashoffile, blob"
1027 " WHERE hashoffile.name=coalesce(vfile.origname,vfile.pathname)"
1028 " AND blob.uuid=hashoffile.hash;"
1029 );
1030
1031 /* Add RID values for merged-in files */
1032 db_multi_exec(
1033 "INSERT OR IGNORE INTO idMap(oldrid, newrid)"
1034 " SELECT vfile.mrid, blob.rid FROM vfile, blob"
1035 " WHERE blob.uuid=vfile.mhash;"
1036 );
1037
1038 if( dryRun ){
1039 Stmt q;
1040 db_prepare(&q, "SELECT oldrid, newrid, blob.uuid"
1041 " FROM idMap, blob WHERE blob.rid=idMap.newrid");
1042 while( db_step(&q)==SQLITE_ROW ){
1043 fossil_print("%8d -> %8d %.25s\n",
1044 db_column_int(&q,0),
1045 db_column_int(&q,1),
1046 db_column_text(&q,2));
1047 }
1048 db_finalize(&q);
1049 }
1050
1051 /* Verify that all RID values in the VFILE table and VMERGE table have
1052 ** been resolved. */
1053 zUnresolved = db_text("",
1054 "WITH allrid(x) AS ("
1055 " SELECT rid FROM vfile"
1056 " UNION SELECT mrid FROM vfile"
1057 " UNION SELECT merge FROM vmerge"
1058 " UNION SELECT %d"
1059 ")"
1060 "SELECT group_concat(x,' ') FROM allrid"
1061 " WHERE x NOT IN (SELECT oldrid FROM idMap);",
1062 oldVid
1063 );
1064 if( zUnresolved[0] ){
1065 fossil_fatal("Unresolved RID values: %s\n", zUnresolved);
1066 }
1067
1068 /* Make the changes to the VFILE and VMERGE tables */
1069 if( !dryRun ){
1070 db_multi_exec(
1071 "UPDATE vfile"
1072 " SET rid=(SELECT newrid FROM idMap WHERE oldrid=vfile.rid)"
1073 " WHERE vid=%d AND rid>0;", oldVid);
1074
1075 db_multi_exec(
1076 "UPDATE vfile"
1077 " SET mrid=(SELECT newrid FROM idMap WHERE oldrid=vfile.mrid)"
1078 " WHERE vid=%d AND mrid>0;", oldVid);
1079
1080 db_multi_exec(
1081 "UPDATE vfile"
1082 " SET vid=%d"
1083 " WHERE vid=%d", newVid, oldVid);
1084
1085 db_multi_exec(
1086 "UPDATE vmerge"
1087 " SET merge=(SELECT newrid FROM idMap WHERE oldrid=vmerge.merge);");
1088
1089 db_lset_int("checkout",newVid);
1090 }
1091
1092 /* Clear out the TEMP tables we constructed */
1093 db_multi_exec(
1094 "DROP TABLE idMap;"
1095 "DROP TABLE hashoffile;"
1096 );
1097 }
1098

Keyboard Shortcuts

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