Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Change the schema of the vmerge table so that it remembers the hash of merged artifacts, not the RID. Schema updates are automatic, but once the update occurs, you are committed to using the newer version of Fossil moving forward. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | rid-renumbering |
| Files: | files | file ages | folders |
| SHA3-256: |
8977dfb03295226c720683a6756db000 |
| User & Date: | drh 2019-01-19 21:31:01.333 |
Context
|
2019-01-19
| ||
| 23:47 | Clean up some old comments on the schema. No code changes. check-in: f51856bed3 user: drh tags: rid-renumbering | |
| 21:31 | Change the schema of the vmerge table so that it remembers the hash of merged artifacts, not the RID. Schema updates are automatic, but once the update occurs, you are committed to using the newer version of Fossil moving forward. check-in: 8977dfb032 user: drh tags: rid-renumbering | |
| 18:29 | Enhance the stash so that it stores hashes and no long depends on RID value. Do this is a way that is backwards compatible and transparent to the user. After running any "stash" command using this version of Fossil or later, the schema will automatically update and the stash should survive a subsequent RID renumbering event in the repository without damage. check-in: ed06585f41 user: drh tags: trunk | |
Changes
Changes to src/checkin.c.
| ︙ | ︙ | |||
305 306 307 308 309 310 311 |
}
blob_reset(&rewrittenPathname);
db_finalize(&q);
/* If C_MERGE, put merge contributors at the end of the report. */
skipFiles:
if( flags & C_MERGE ){
| | < | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
}
blob_reset(&rewrittenPathname);
db_finalize(&q);
/* If C_MERGE, put merge contributors at the end of the report. */
skipFiles:
if( flags & C_MERGE ){
db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0" );
while( db_step(&q)==SQLITE_ROW ){
if( flags & C_COMMENT ){
blob_append(report, "# ", 2);
}
if( flags & C_CLASSIFY ){
const char *zClass;
switch( db_column_int(&q, 1) ){
|
| ︙ | ︙ | |||
1633 1634 1635 1636 1637 1638 1639 |
}
db_finalize(&q);
blob_appendf(pOut, "\n");
}
free(zDate);
db_prepare(&q,
| | | < | 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 |
}
db_finalize(&q);
blob_appendf(pOut, "\n");
}
free(zDate);
db_prepare(&q,
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || mhash, merge"
" FROM vmerge"
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
" ORDER BY 1");
while( db_step(&q)==SQLITE_ROW ){
const char *zCherrypickUuid = db_column_text(&q, 0);
int mid = db_column_int(&q, 1);
if( mid != vid ){
blob_appendf(pOut, "Q %s\n", zCherrypickUuid);
}
|
| ︙ | ︙ | |||
1665 1666 1667 1668 1669 1670 1671 |
if( zColor && zColor[0] ){
/* One-time background color */
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
}
if( p->closeFlag ){
blob_appendf(pOut, "T +closed *\n");
}
| | | 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 |
if( zColor && zColor[0] ){
/* One-time background color */
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
}
if( p->closeFlag ){
blob_appendf(pOut, "T +closed *\n");
}
db_prepare(&q, "SELECT mhash,merge FROM vmerge"
" WHERE id %s ORDER BY 1",
p->integrateFlag ? "IN(0,-4)" : "=(-4)");
while( db_step(&q)==SQLITE_ROW ){
const char *zIntegrateUuid = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref "
" WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){
|
| ︙ | ︙ | |||
2506 2507 2508 2509 2510 2511 2512 |
dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s", g.zErrMsg);
}
assert( blob_is_reset(&manifest) );
content_deltify(vid, &nvid, 1, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
| < | | 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 |
dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s", g.zErrMsg);
}
assert( blob_is_reset(&manifest) );
content_deltify(vid, &nvid, 1, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
db_prepare(&q, "SELECT mhash,merge FROM vmerge WHERE id=-4");
while( db_step(&q)==SQLITE_ROW ){
const char *zIntegrateUuid = db_column_text(&q, 0);
if( is_a_leaf(db_column_int(&q, 1)) ){
fossil_print("Closed: %s\n", zIntegrateUuid);
}else{
fossil_print("Not_Closed: %s (not a leaf any more)\n", zIntegrateUuid);
}
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 |
/*
** If zDbName is a valid local database file, open it and return
** true. If it is not a valid local database file, return 0.
*/
static int isValidLocalDb(const char *zDbName){
i64 lsize;
| < | > > > > > > > > | > > > | > | | | > > > > | 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 |
/*
** If zDbName is a valid local database file, open it and return
** true. If it is not a valid local database file, return 0.
*/
static int isValidLocalDb(const char *zDbName){
i64 lsize;
if( file_access(zDbName, F_OK) ) return 0;
lsize = file_size(zDbName, ExtFILE);
if( lsize%1024!=0 || lsize<4096 ) return 0;
db_open_or_attach(zDbName, "localdb");
/* Check to see if the checkout database has the lastest schema changes.
** The most recent schema change (2019-01-19) is the addition of the
** vmerge.mhash field. If the schema has that one column, assume
** everything else is up-to-date.
*/
if( db_table_has_column("localdb","vmerge","mhash") ){
return 1; /* This is a checkout database with the latest schema */
}
/* If there is no vfile table, then assume we have picked up something
** that is not even close to being a valid checkout database */
if( !db_table_exists("localdb","vfile") ){
return 0; /* Not a DB */
}
/* If the "isexe" column is missing from the vfile table, then
** add it now. This code added on 2010-03-06. After all users have
** upgraded, this code can be safely deleted.
*/
if( !db_table_has_column("localdb","vfile","isexe") ){
db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0");
}
/* If "islink"/"isLink" columns are missing from tables, then
** add them now. This code added on 2011-01-17 and 2011-08-27.
** After all users have upgraded, this code can be safely deleted.
*/
if( !db_table_has_column("localdb","vfile","isLink") ){
db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0");
if( db_local_table_exists_but_lacks_column("stashfile", "isLink") ){
db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOL DEFAULT 0");
}
if( db_local_table_exists_but_lacks_column("undo", "isLink") ){
db_multi_exec("ALTER TABLE undo ADD COLUMN isLink BOOLEAN DEFAULT 0");
}
if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){
db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0");
}
}
/* The design of the vmerge table changed on 2019-01-19, adding the mhash
** column and changing the UNIQUE index. However, we must ahve the
** repository database at hand in order to do the migration, so that
** step is deferred. */
return 1;
}
/*
** Locate the root directory of the local repository tree. The root
** directory is found by searching for a file named "_FOSSIL_" or ".fslckout"
** that contains a valid repository database.
|
| ︙ | ︙ | |||
1654 1655 1656 1657 1658 1659 1660 | } /* Make a change to the CHECK constraint on the BLOB table for ** version 2.0 and later. */ rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */ | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > | 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 |
}
/* Make a change to the CHECK constraint on the BLOB table for
** version 2.0 and later.
*/
rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */
/* Additional checks that occur when opening the checkout database */
if( g.localOpen ){
/* Ensure that the repository database that was just opened has not
** be replaced by a clone of the same project, with different RID
** values.
*/
if( !db_fingerprint_ok() ){
/* Uncomment the following when we are ready for automatic recovery: */
#if 0
stash_rid_renumbering_event();
#else
fossil_print(
"Oops. It looks like the repository database file located at\n"
" \"%s\"\n", zDbName
);
fossil_print(
"has been swapped with a clone that may have different\n"
"integer keys for the various artifacts. As of 2019-01-11,\n"
"we are working on enhancing Fossil to be able to deal with\n"
"that automatically, but we are not there yet. Sorry.\n\n"
);
fossil_print(
"As an interim workaround, try:\n"
" %s close --force\n"
" %s open \"%s\" --keep\n"
"Noting that any STASH and UNDO information "
"WILL BE IRREVOCABLY LOST.\n\n",
g.argv[0],
g.argv[0], zDbName
);
fossil_fatal("bad fingerprint");
#endif
}else
/* Make sure the checkout database schema migration of 2019-01-19
** (the addition of the vmerge.mhash column and making that columns
** part of the PRIMARY KEY) has occurred.
*/
if( !db_table_has_column("localdb", "vmerge", "mhash") ){
db_multi_exec("ALTER TABLE vmerge RENAME TO old_vmerge;");
db_multi_exec(zLocalSchemaVmerge /*works-like:""*/);
db_multi_exec(
"INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
" SELECT id, merge, blob.uuid FROM old_vmerge, blob"
" WHERE old_vmerge.merge=blob.rid;"
"DROP TABLE old_vmerge;"
);
}
}
}
/*
** Return true if there have been any changes to the repository
** database since it was opened.
**
|
| ︙ | ︙ | |||
2878 2879 2880 2881 2882 2883 2884 | } #if defined(_WIN32) || defined(__CYGWIN__) # define LOCALDB_NAME "./_FOSSIL_" #else # define LOCALDB_NAME "./.fslckout" #endif | | | 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 |
}
#if defined(_WIN32) || defined(__CYGWIN__)
# define LOCALDB_NAME "./_FOSSIL_"
#else
# define LOCALDB_NAME "./.fslckout"
#endif
db_init_database(LOCALDB_NAME, zLocalSchema, zLocalSchemaVmerge,
#ifdef FOSSIL_LOCAL_WAL
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
#endif
(char*)0);
db_delete_on_failure(LOCALDB_NAME);
db_open_local(0);
if( allowSymlinks>=0 ){
|
| ︙ | ︙ |
Changes to src/json_status.c.
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
cson_object_set( oPay, "errorCount", json_new_int( nErr ) );
db_finalize(&q);
#if 0
/* TODO: add "merged with" status. First need (A) to decide on a
structure and (B) to set up some tests for the multi-merge
case.*/
| < | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
cson_object_set( oPay, "errorCount", json_new_int( nErr ) );
db_finalize(&q);
#if 0
/* TODO: add "merged with" status. First need (A) to decide on a
structure and (B) to set up some tests for the multi-merge
case.*/
db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0");
while( db_step(&q)==SQLITE_ROW ){
const char *zLabel = "MERGED_WITH";
switch( db_column_int(&q, 1) ){
case -1: zLabel = "CHERRYPICK "; break;
case -2: zLabel = "BACKOUT "; break;
case -4: zLabel = "INTEGRATE "; break;
}
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
);
}
free(zN);
free(zV);
}
free(aChng);
}
/*
** COMMAND: merge
**
** Usage: %fossil merge ?OPTIONS? ?VERSION?
**
** The argument VERSION is a version that should be merged into the
| > > > > > > > > > > | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
);
}
free(zN);
free(zV);
}
free(aChng);
}
/* Make an entry in the vmerge table for the given id, and rid.
*/
static void vmerge_insert(int id, int rid){
db_multi_exec(
"INSERT OR IGNORE INTO vmerge(id,merge,mhash)"
"VALUES(%d,%d,(SELECT uuid FROM blob WHERE rid=%d))",
id, rid, rid
);
}
/*
** COMMAND: merge
**
** Usage: %fossil merge ?OPTIONS? ?VERSION?
**
** The argument VERSION is a version that should be merged into the
|
| ︙ | ︙ | |||
662 663 664 665 666 667 668 |
fossil_print("***** Cannot merge binary file %s\n", zName);
nConflict++;
}
blob_reset(&p);
blob_reset(&m);
blob_reset(&r);
}
| < | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 |
fossil_print("***** Cannot merge binary file %s\n", zName);
nConflict++;
}
blob_reset(&p);
blob_reset(&m);
blob_reset(&r);
}
vmerge_insert(idv, ridm);
}
db_finalize(&q);
/*
** Drop files that are in P and V but not in M
*/
db_prepare(&q,
|
| ︙ | ︙ | |||
824 825 826 827 828 829 830 |
}
/*
** Clean up the mid and pid VFILE entries. Then commit the changes.
*/
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
if( pickFlag ){
| | | | | | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 |
}
/*
** Clean up the mid and pid VFILE entries. Then commit the changes.
*/
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
if( pickFlag ){
vmerge_insert(-1, mid);
/* For a cherry-pick merge, make the default check-in comment the same
** as the check-in comment on the check-in that is being merged in. */
db_multi_exec(
"REPLACE INTO vvar(name,value)"
" SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
" WHERE type='ci' AND objid=%d",
mid
);
}else if( backoutFlag ){
vmerge_insert(-2, pid);
}else if( integrateFlag ){
vmerge_insert(-4, mid);
}else{
vmerge_insert(0, mid);
}
if( !dryRunFlag ) undo_finish();
db_end_transaction(dryRunFlag);
}
|
Changes to src/schema.c.
| ︙ | ︙ | |||
488 489 490 491 492 493 494 | # define TAG_PARENT 10 /* Change to parentage on a check-in */ # define TAG_NOTE 11 /* Extra text appended to a check-in comment */ #endif /* ** The schema for the local FOSSIL database file found at the root ** of every check-out. This database contains the complete state of | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | # define TAG_PARENT 10 /* Change to parentage on a check-in */ # define TAG_NOTE 11 /* Extra text appended to a check-in comment */ #endif /* ** The schema for the local FOSSIL database file found at the root ** of every check-out. This database contains the complete state of ** the checkout. See also the addendum in zLocalSchemaVmerge[]. */ const char zLocalSchema[] = @ -- The VVAR table holds miscellanous information about the local database @ -- in the form of name-value pairs. This is similar to the VAR table @ -- table in the repository except that this table holds information that @ -- is specific to the local checkout. @ -- |
| ︙ | ︙ | |||
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 @ pathname TEXT, -- Full pathname relative to root @ origname TEXT, -- Original pathname. NULL if unchanged @ UNIQUE(pathname,vid) @ ); @ @ -- This table holds a record of uncommitted merges in the local @ -- file tree. If a VFILE entry with id has merged with another @ -- record, there is an entry in this table with (id,merge) where @ -- merge is the RECORD table entry that the file merged against. @ -- An id of 0 or <-3 here means the version record itself. When @ -- id==(-1) that is a cherrypick merge, id==(-2) that is a @ -- backout merge and id==(-4) is a integrate merge. @ @ CREATE TABLE vmerge( @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged @ merge INTEGER, -- Merged with this record | > > > > > > > > > > > | > | > > > | > > > > > | > | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 @ pathname TEXT, -- Full pathname relative to root @ origname TEXT, -- Original pathname. NULL if unchanged @ UNIQUE(pathname,vid) @ ); @ @ -- Identifier for this file type. @ -- The integer is the same as 'FSLC'. @ PRAGMA application_id=252006674; ; /* Additional local database initialization following the schema ** enhancement of 2019-01-19, in which the mhash column was added ** to vmerge. */ const char zLocalSchemaVmerge[] = @ -- This table holds a record of uncommitted merges in the local @ -- file tree. If a VFILE entry with id has merged with another @ -- record, there is an entry in this table with (id,merge) where @ -- merge is the RECORD table entry that the file merged against. @ -- An id of 0 or <-3 here means the version record itself. When @ -- id==(-1) that is a cherrypick merge, id==(-2) that is a @ -- backout merge and id==(-4) is a integrate merge. @ -- @ @ CREATE TABLE vmerge( @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged @ merge INTEGER, -- Merged with this record @ mhash TEXT -- SHA1/SHA3 hash for merge object @ ); @ CREATE UNIQUE INDEX vmergex1 ON vmerge(id,mhash); @ @ -- The following trigger will prevent older versions of Fossil that @ -- do not know about the new vmerge.mhash column from updating the @ -- vmerge table. This must be done with a trigger, since legacy Fossil @ -- uses INSERT OR IGNORE to update vmerge, and the OR IGNORE will cause @ -- a NOT NULL constraint to be silently ignored. @ @ CREATE TRIGGER vmerge_ck1 AFTER INSERT ON vmerge @ WHEN new.mhash IS NULL BEGIN @ SELECT raise(FAIL, @ 'trying to update a newer checkout with an older version of Fossil'); @ END; @ ; /* ** The following table holds information about forum posts. It ** is created on-demand whenever the manifest parser encounters ** a forum-post artifact. */ |
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
527 528 529 530 531 532 533 |
}
/* Report on conflicts
*/
if( !dryRunFlag ){
Stmt q;
int nMerge = 0;
| < | | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
}
/* Report on conflicts
*/
if( !dryRunFlag ){
Stmt q;
int nMerge = 0;
db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0");
while( db_step(&q)==SQLITE_ROW ){
const char *zLabel = "merge";
switch( db_column_int(&q, 1) ){
case -1: zLabel = "cherrypick merge"; break;
case -2: zLabel = "backout merge"; break;
}
fossil_warning("uncommitted %s against %S.",
|
| ︙ | ︙ |