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.
Commit
fff37e624e2b634bfdd61c3eb2f6cd10ce4b2ebccf391753f1cc2567b332648d
Parent
8f2ec29248de7a7…
10 files changed
+2
-2
+12
-4
+8
-10
+88
-39
+2
-1
+1
-2
+25
-10
+37
-17
+3
-3
+130
-3
+2
-2
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -187,12 +187,12 @@ | ||
| 187 | 187 | zPath, filename_collation()); |
| 188 | 188 | }else{ |
| 189 | 189 | char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath); |
| 190 | 190 | int isExe = file_isexe(zFullname, RepoFILE); |
| 191 | 191 | 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)", | |
| 194 | 194 | vid, zPath, isExe, file_islink(0)); |
| 195 | 195 | fossil_free(zFullname); |
| 196 | 196 | } |
| 197 | 197 | if( db_changes() ){ |
| 198 | 198 | fossil_print("ADDED %s\n", zPath); |
| 199 | 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)" |
| 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 @@ | ||
| 286 | 286 | (db_column_int(&q, 4) && zGoodBad[0]!='C') ? " CURRENT" : ""); |
| 287 | 287 | } |
| 288 | 288 | db_finalize(&q); |
| 289 | 289 | } |
| 290 | 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 | + | |
| 291 | 302 | /* |
| 292 | 303 | ** COMMAND: bisect |
| 293 | 304 | ** |
| 294 | 305 | ** Usage: %fossil bisect SUBCOMMAND ... |
| 295 | 306 | ** |
| @@ -489,14 +500,11 @@ | ||
| 489 | 500 | } |
| 490 | 501 | }else{ |
| 491 | 502 | usage("options ?NAME? ?VALUE?"); |
| 492 | 503 | } |
| 493 | 504 | }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(); | |
| 498 | 506 | }else if( strcmp(zCmd, "ui")==0 ){ |
| 499 | 507 | char *newArgv[8]; |
| 500 | 508 | newArgv[0] = g.argv[0]; |
| 501 | 509 | newArgv[1] = "ui"; |
| 502 | 510 | newArgv[2] = "--page"; |
| 503 | 511 |
| --- 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 @@ | ||
| 307 | 307 | db_finalize(&q); |
| 308 | 308 | |
| 309 | 309 | /* If C_MERGE, put merge contributors at the end of the report. */ |
| 310 | 310 | skipFiles: |
| 311 | 311 | 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" ); | |
| 314 | 313 | while( db_step(&q)==SQLITE_ROW ){ |
| 315 | 314 | if( flags & C_COMMENT ){ |
| 316 | 315 | blob_append(report, "# ", 2); |
| 317 | 316 | } |
| 318 | 317 | if( flags & C_CLASSIFY ){ |
| @@ -1635,14 +1634,13 @@ | ||
| 1635 | 1634 | blob_appendf(pOut, "\n"); |
| 1636 | 1635 | } |
| 1637 | 1636 | free(zDate); |
| 1638 | 1637 | |
| 1639 | 1638 | 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" | |
| 1642 | 1641 | " WHERE (vmerge.id=-1 OR vmerge.id=-2)" |
| 1643 | - " AND blob.rid=vmerge.merge" | |
| 1644 | 1642 | " ORDER BY 1"); |
| 1645 | 1643 | while( db_step(&q)==SQLITE_ROW ){ |
| 1646 | 1644 | const char *zCherrypickUuid = db_column_text(&q, 0); |
| 1647 | 1645 | int mid = db_column_int(&q, 1); |
| 1648 | 1646 | if( mid != vid ){ |
| @@ -1667,11 +1665,11 @@ | ||
| 1667 | 1665 | blob_appendf(pOut, "T +bgcolor * %F\n", zColor); |
| 1668 | 1666 | } |
| 1669 | 1667 | if( p->closeFlag ){ |
| 1670 | 1668 | blob_appendf(pOut, "T +closed *\n"); |
| 1671 | 1669 | } |
| 1672 | - db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" | |
| 1670 | + db_prepare(&q, "SELECT mhash,merge FROM vmerge" | |
| 1673 | 1671 | " WHERE id %s ORDER BY 1", |
| 1674 | 1672 | p->integrateFlag ? "IN(0,-4)" : "=(-4)"); |
| 1675 | 1673 | while( db_step(&q)==SQLITE_ROW ){ |
| 1676 | 1674 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 1677 | 1675 | int rid = db_column_int(&q, 1); |
| @@ -2400,11 +2398,12 @@ | ||
| 2400 | 2398 | nrid = content_put(&content); |
| 2401 | 2399 | blob_reset(&content); |
| 2402 | 2400 | if( rid>0 ){ |
| 2403 | 2401 | content_deltify(rid, &nrid, 1, 0); |
| 2404 | 2402 | } |
| 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); | |
| 2406 | 2405 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); |
| 2407 | 2406 | } |
| 2408 | 2407 | db_finalize(&q); |
| 2409 | 2408 | if( nConflict && !allowConflict ){ |
| 2410 | 2409 | fossil_fatal("abort due to unresolved merge conflicts; " |
| @@ -2508,12 +2507,11 @@ | ||
| 2508 | 2507 | } |
| 2509 | 2508 | assert( blob_is_reset(&manifest) ); |
| 2510 | 2509 | content_deltify(vid, &nvid, 1, 0); |
| 2511 | 2510 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); |
| 2512 | 2511 | |
| 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"); | |
| 2515 | 2513 | while( db_step(&q)==SQLITE_ROW ){ |
| 2516 | 2514 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 2517 | 2515 | if( is_a_leaf(db_column_int(&q, 1)) ){ |
| 2518 | 2516 | fossil_print("Closed: %s\n", zIntegrateUuid); |
| 2519 | 2517 | }else{ |
| @@ -2535,11 +2533,11 @@ | ||
| 2535 | 2533 | /* Update the vfile and vmerge tables */ |
| 2536 | 2534 | db_multi_exec( |
| 2537 | 2535 | "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);" |
| 2538 | 2536 | "DELETE FROM vmerge;" |
| 2539 | 2537 | "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" | |
| 2541 | 2539 | " WHERE is_selected(id);" |
| 2542 | 2540 | , vid, nvid |
| 2543 | 2541 | ); |
| 2544 | 2542 | db_set_checkout(nvid); |
| 2545 | 2543 | |
| 2546 | 2544 |
| --- 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 |
M
src/db.c
+88
-39
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1473,33 +1473,44 @@ | ||
| 1473 | 1473 | ** If zDbName is a valid local database file, open it and return |
| 1474 | 1474 | ** true. If it is not a valid local database file, return 0. |
| 1475 | 1475 | */ |
| 1476 | 1476 | static int isValidLocalDb(const char *zDbName){ |
| 1477 | 1477 | i64 lsize; |
| 1478 | - char *zVFileDef; | |
| 1479 | 1478 | |
| 1480 | 1479 | if( file_access(zDbName, F_OK) ) return 0; |
| 1481 | 1480 | lsize = file_size(zDbName, ExtFILE); |
| 1482 | 1481 | if( lsize%1024!=0 || lsize<4096 ) return 0; |
| 1483 | 1482 | 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 | + } | |
| 1487 | 1498 | |
| 1488 | 1499 | /* If the "isexe" column is missing from the vfile table, then |
| 1489 | 1500 | ** add it now. This code added on 2010-03-06. After all users have |
| 1490 | 1501 | ** upgraded, this code can be safely deleted. |
| 1491 | 1502 | */ |
| 1492 | - if( sqlite3_strglob("* isexe *", zVFileDef)!=0 ){ | |
| 1503 | + if( !db_table_has_column("localdb","vfile","isexe") ){ | |
| 1493 | 1504 | db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0"); |
| 1494 | 1505 | } |
| 1495 | 1506 | |
| 1496 | 1507 | /* If "islink"/"isLink" columns are missing from tables, then |
| 1497 | 1508 | ** add them now. This code added on 2011-01-17 and 2011-08-27. |
| 1498 | 1509 | ** After all users have upgraded, this code can be safely deleted. |
| 1499 | 1510 | */ |
| 1500 | - if( sqlite3_strglob("* islink *", zVFileDef)!=0 ){ | |
| 1511 | + if( !db_table_has_column("localdb","vfile","isLink") ){ | |
| 1501 | 1512 | db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0"); |
| 1502 | 1513 | if( db_local_table_exists_but_lacks_column("stashfile", "isLink") ){ |
| 1503 | 1514 | db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOL DEFAULT 0"); |
| 1504 | 1515 | } |
| 1505 | 1516 | if( db_local_table_exists_but_lacks_column("undo", "isLink") ){ |
| @@ -1507,11 +1518,16 @@ | ||
| 1507 | 1518 | } |
| 1508 | 1519 | if( db_local_table_exists_but_lacks_column("undo_vfile", "islink") ){ |
| 1509 | 1520 | db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOL DEFAULT 0"); |
| 1510 | 1521 | } |
| 1511 | 1522 | } |
| 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. */ | |
| 1513 | 1529 | return 1; |
| 1514 | 1530 | } |
| 1515 | 1531 | |
| 1516 | 1532 | /* |
| 1517 | 1533 | ** Locate the root directory of the local repository tree. The root |
| @@ -1656,41 +1672,74 @@ | ||
| 1656 | 1672 | /* Make a change to the CHECK constraint on the BLOB table for |
| 1657 | 1673 | ** version 2.0 and later. |
| 1658 | 1674 | */ |
| 1659 | 1675 | rebuild_schema_update_2_0(); /* Do the Fossil-2.0 schema updates */ |
| 1660 | 1676 | |
| 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 | + } | |
| 1692 | 1741 | } |
| 1693 | 1742 | } |
| 1694 | 1743 | |
| 1695 | 1744 | /* |
| 1696 | 1745 | ** Return true if there have been any changes to the repository |
| @@ -2880,11 +2929,11 @@ | ||
| 2880 | 2929 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 2881 | 2930 | # define LOCALDB_NAME "./_FOSSIL_" |
| 2882 | 2931 | #else |
| 2883 | 2932 | # define LOCALDB_NAME "./.fslckout" |
| 2884 | 2933 | #endif |
| 2885 | - db_init_database(LOCALDB_NAME, zLocalSchema, | |
| 2934 | + db_init_database(LOCALDB_NAME, zLocalSchema, zLocalSchemaVmerge, | |
| 2886 | 2935 | #ifdef FOSSIL_LOCAL_WAL |
| 2887 | 2936 | "COMMIT; PRAGMA journal_mode=WAL; BEGIN;", |
| 2888 | 2937 | #endif |
| 2889 | 2938 | (char*)0); |
| 2890 | 2939 | db_delete_on_failure(LOCALDB_NAME); |
| 2891 | 2940 |
| --- 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 @@ | ||
| 121 | 121 | ** (1) checkinID=?. visit only the single manifest specified. |
| 122 | 122 | ** (2) symName=? visit only the single manifest specified. |
| 123 | 123 | */ |
| 124 | 124 | static int fociBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ |
| 125 | 125 | int i; |
| 126 | - pIdxInfo->estimatedCost = 10000.0; | |
| 126 | + pIdxInfo->estimatedCost = 1000000000.0; | |
| 127 | 127 | for(i=0; i<pIdxInfo->nConstraint; i++){ |
| 128 | + if( !pIdxInfo->aConstraint[i].usable ) continue; | |
| 128 | 129 | if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ |
| 129 | 130 | && (pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID |
| 130 | 131 | || pIdxInfo->aConstraint[i].iColumn==FOCI_SYMNAME) |
| 131 | 132 | ){ |
| 132 | 133 | if( pIdxInfo->aConstraint[i].iColumn==FOCI_CHECKINID ){ |
| 133 | 134 |
| --- 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 |
+1
-2
| --- src/json_status.c | ||
| +++ src/json_status.c | ||
| @@ -154,12 +154,11 @@ | ||
| 154 | 154 | |
| 155 | 155 | #if 0 |
| 156 | 156 | /* TODO: add "merged with" status. First need (A) to decide on a |
| 157 | 157 | structure and (B) to set up some tests for the multi-merge |
| 158 | 158 | 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"); | |
| 161 | 160 | while( db_step(&q)==SQLITE_ROW ){ |
| 162 | 161 | const char *zLabel = "MERGED_WITH"; |
| 163 | 162 | switch( db_column_int(&q, 1) ){ |
| 164 | 163 | case -1: zLabel = "CHERRYPICK "; break; |
| 165 | 164 | case -2: zLabel = "BACKOUT "; break; |
| 166 | 165 |
| --- 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 @@ | ||
| 164 | 164 | free(zN); |
| 165 | 165 | free(zV); |
| 166 | 166 | } |
| 167 | 167 | free(aChng); |
| 168 | 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 | +} | |
| 169 | 179 | |
| 170 | 180 | /* |
| 171 | 181 | ** COMMAND: merge |
| 172 | 182 | ** |
| 173 | 183 | ** Usage: %fossil merge ?OPTIONS? ?VERSION? |
| @@ -594,12 +604,14 @@ | ||
| 594 | 604 | /* Copy content from idm over into idv. Overwrite idv. */ |
| 595 | 605 | fossil_print("UPDATE %s\n", zName); |
| 596 | 606 | if( !dryRunFlag ){ |
| 597 | 607 | undo_save(zName); |
| 598 | 608 | 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 | |
| 601 | 613 | ); |
| 602 | 614 | vfile_to_disk(0, idv, 0, 0); |
| 603 | 615 | } |
| 604 | 616 | } |
| 605 | 617 | db_finalize(&q); |
| @@ -664,12 +676,11 @@ | ||
| 664 | 676 | } |
| 665 | 677 | blob_reset(&p); |
| 666 | 678 | blob_reset(&m); |
| 667 | 679 | blob_reset(&r); |
| 668 | 680 | } |
| 669 | - db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)", | |
| 670 | - idv,ridm); | |
| 681 | + vmerge_insert(idv, ridm); | |
| 671 | 682 | } |
| 672 | 683 | db_finalize(&q); |
| 673 | 684 | |
| 674 | 685 | /* |
| 675 | 686 | ** Drop files that are in P and V but not in M |
| @@ -786,12 +797,16 @@ | ||
| 786 | 797 | while( db_step(&q)==SQLITE_ROW ){ |
| 787 | 798 | int idm = db_column_int(&q, 0); |
| 788 | 799 | const char *zName; |
| 789 | 800 | char *zFullName; |
| 790 | 801 | 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", | |
| 793 | 808 | vid, integrateFlag?5:3, idm |
| 794 | 809 | ); |
| 795 | 810 | zName = db_column_text(&q, 1); |
| 796 | 811 | zFullName = mprintf("%s%s", g.zLocalRoot, zName); |
| 797 | 812 | if( file_isfile_or_link(zFullName) |
| @@ -826,24 +841,24 @@ | ||
| 826 | 841 | /* |
| 827 | 842 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 828 | 843 | */ |
| 829 | 844 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 830 | 845 | if( pickFlag ){ |
| 831 | - db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-1,%d)",mid); | |
| 846 | + vmerge_insert(-1, mid); | |
| 832 | 847 | /* For a cherry-pick merge, make the default check-in comment the same |
| 833 | 848 | ** as the check-in comment on the check-in that is being merged in. */ |
| 834 | 849 | db_multi_exec( |
| 835 | 850 | "REPLACE INTO vvar(name,value)" |
| 836 | 851 | " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event" |
| 837 | 852 | " WHERE type='ci' AND objid=%d", |
| 838 | 853 | mid |
| 839 | 854 | ); |
| 840 | 855 | }else if( backoutFlag ){ |
| 841 | - db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-2,%d)",pid); | |
| 856 | + vmerge_insert(-2, pid); | |
| 842 | 857 | }else if( integrateFlag ){ |
| 843 | - db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid); | |
| 858 | + vmerge_insert(-4, mid); | |
| 844 | 859 | }else{ |
| 845 | - db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid); | |
| 860 | + vmerge_insert(0, mid); | |
| 846 | 861 | } |
| 847 | 862 | if( !dryRunFlag ) undo_finish(); |
| 848 | 863 | db_end_transaction(dryRunFlag); |
| 849 | 864 | } |
| 850 | 865 |
| --- 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 @@ | ||
| 2 | 2 | ** Copyright (c) 2007 D. Richard Hipp |
| 3 | 3 | ** |
| 4 | 4 | ** This program is free software; you can redistribute it and/or |
| 5 | 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | - | |
| 7 | +** | |
| 8 | 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | 9 | ** but without any warranty; without even the implied warranty of |
| 10 | 10 | ** merchantability or fitness for a particular purpose. |
| 11 | 11 | ** |
| 12 | 12 | ** Author contact information: |
| @@ -352,11 +352,11 @@ | ||
| 352 | 352 | @ -- |
| 353 | 353 | @ CREATE TABLE unsent( |
| 354 | 354 | @ rid INTEGER PRIMARY KEY -- Record ID of the phantom |
| 355 | 355 | @ ); |
| 356 | 356 | @ |
| 357 | -@ -- Each baseline or manifest can have one or more tags. A tag | |
| 357 | +@ -- Each artifact can have one or more tags. A tag | |
| 358 | 358 | @ -- is defined by a row in the next table. |
| 359 | 359 | @ -- |
| 360 | 360 | @ -- Wiki pages are tagged with "wiki-NAME" where NAME is the name of |
| 361 | 361 | @ -- the wiki page. Tickets changes are tagged with "ticket-UUID" where |
| 362 | 362 | @ -- UUID is the indentifier of the ticket. Tags used to assign symbolic |
| @@ -377,11 +377,11 @@ | ||
| 377 | 377 | @ INSERT INTO tag VALUES(8, 'branch'); -- TAG_BRANCH |
| 378 | 378 | @ INSERT INTO tag VALUES(9, 'closed'); -- TAG_CLOSED |
| 379 | 379 | @ INSERT INTO tag VALUES(10,'parent'); -- TAG_PARENT |
| 380 | 380 | @ INSERT INTO tag VALUES(11,'note'); -- TAG_NOTE |
| 381 | 381 | @ |
| 382 | -@ -- Assignments of tags to baselines. Note that we allow tags to | |
| 382 | +@ -- Assignments of tags to artifacts. Note that we allow tags to | |
| 383 | 383 | @ -- have values assigned to them. So we are not really dealing with |
| 384 | 384 | @ -- tags here. These are really properties. But we are going to |
| 385 | 385 | @ -- keep calling them tags because in many cases the value is ignored. |
| 386 | 386 | @ -- |
| 387 | 387 | @ CREATE TABLE tagxref( |
| @@ -490,11 +490,11 @@ | ||
| 490 | 490 | #endif |
| 491 | 491 | |
| 492 | 492 | /* |
| 493 | 493 | ** The schema for the local FOSSIL database file found at the root |
| 494 | 494 | ** of every check-out. This database contains the complete state of |
| 495 | -** the checkout. | |
| 495 | +** the checkout. See also the addendum in zLocalSchemaVmerge[]. | |
| 496 | 496 | */ |
| 497 | 497 | const char zLocalSchema[] = |
| 498 | 498 | @ -- The VVAR table holds miscellanous information about the local database |
| 499 | 499 | @ -- in the form of name-value pairs. This is similar to the VAR table |
| 500 | 500 | @ -- table in the repository except that this table holds information that |
| @@ -515,51 +515,71 @@ | ||
| 515 | 515 | @ -- current checkout. |
| 516 | 516 | @ -- |
| 517 | 517 | @ -- The file.rid field is 0 for files or folders that have been |
| 518 | 518 | @ -- added but not yet committed. |
| 519 | 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. | |
| 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 | |
| 528 | 526 | @ -- |
| 529 | 527 | @ CREATE TABLE vfile( |
| 530 | 528 | @ 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. | |
| 532 | 530 | @ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add |
| 533 | 531 | @ deleted BOOLEAN DEFAULT 0, -- True if deleted |
| 534 | 532 | @ isexe BOOLEAN, -- True if file should be executable |
| 535 | 533 | @ islink BOOLEAN, -- True if file should be symlink |
| 536 | 534 | @ rid INTEGER, -- Originally from this repository record |
| 537 | 535 | @ mrid INTEGER, -- Based on this record due to a merge |
| 538 | 536 | @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 |
| 539 | 537 | @ pathname TEXT, -- Full pathname relative to root |
| 540 | 538 | @ origname TEXT, -- Original pathname. NULL if unchanged |
| 539 | +@ mhash TEXT, -- Hash of mrid iff mrid!=rid | |
| 541 | 540 | @ UNIQUE(pathname,vid) |
| 542 | 541 | @ ); |
| 543 | 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[] = | |
| 544 | 553 | @ -- This table holds a record of uncommitted merges in the local |
| 545 | 554 | @ -- file tree. If a VFILE entry with id has merged with another |
| 546 | 555 | @ -- record, there is an entry in this table with (id,merge) where |
| 547 | 556 | @ -- merge is the RECORD table entry that the file merged against. |
| 548 | 557 | @ -- An id of 0 or <-3 here means the version record itself. When |
| 549 | 558 | @ -- id==(-1) that is a cherrypick merge, id==(-2) that is a |
| 550 | 559 | @ -- backout merge and id==(-4) is a integrate merge. |
| 560 | +@ -- | |
| 551 | 561 | @ |
| 552 | 562 | @ CREATE TABLE vmerge( |
| 553 | 563 | @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged |
| 554 | 564 | @ merge INTEGER, -- Merged with this record |
| 555 | -@ UNIQUE(id, merge) | |
| 565 | +@ mhash TEXT -- SHA1/SHA3 hash for merge object | |
| 556 | 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. | |
| 557 | 574 | @ |
| 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 | +@ | |
| 561 | 581 | ; |
| 562 | 582 | |
| 563 | 583 | /* |
| 564 | 584 | ** The following table holds information about forum posts. It |
| 565 | 585 | ** is created on-demand whenever the manifest parser encounters |
| 566 | 586 |
| --- 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 @@ | ||
| 529 | 529 | /* Report on conflicts |
| 530 | 530 | */ |
| 531 | 531 | if( !dryRunFlag ){ |
| 532 | 532 | Stmt q; |
| 533 | 533 | 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"); | |
| 536 | 535 | while( db_step(&q)==SQLITE_ROW ){ |
| 537 | 536 | const char *zLabel = "merge"; |
| 538 | 537 | switch( db_column_int(&q, 1) ){ |
| 539 | 538 | case -1: zLabel = "cherrypick merge"; break; |
| 540 | 539 | case -2: zLabel = "backout merge"; break; |
| @@ -865,11 +864,12 @@ | ||
| 865 | 864 | file_setexe(zFull, rvPerm==PERM_EXE); |
| 866 | 865 | fossil_print("REVERT %s\n", zFile); |
| 867 | 866 | mtime = file_mtime(zFull, RepoFILE); |
| 868 | 867 | db_multi_exec( |
| 869 | 868 | "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" | |
| 871 | 871 | " WHERE pathname=%Q OR origname=%Q", |
| 872 | 872 | mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile |
| 873 | 873 | ); |
| 874 | 874 | } |
| 875 | 875 | blob_reset(&record); |
| 876 | 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 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 @@ | ||
| 88 | 88 | if( p==0 ) { |
| 89 | 89 | db_end_transaction(1); |
| 90 | 90 | return 0; |
| 91 | 91 | } |
| 92 | 92 | 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)"); | |
| 95 | 95 | db_prepare(&ridq, "SELECT rid,size FROM blob WHERE uuid=:uuid"); |
| 96 | 96 | db_bind_int(&ins, ":vid", vid); |
| 97 | 97 | manifest_file_rewind(p); |
| 98 | 98 | nMissing = 0; |
| 99 | 99 | while( (pFile = manifest_file_next(p,0))!=0 ){ |
| @@ -242,11 +242,11 @@ | ||
| 242 | 242 | const char *zUuid = db_column_text(&q, 5); |
| 243 | 243 | int nUuid = db_column_bytes(&q, 5); |
| 244 | 244 | assert( origSize==currentSize ); |
| 245 | 245 | if( !hname_verify_file_hash(zName, zUuid, nUuid) ) chnged = 1; |
| 246 | 246 | } |
| 247 | - if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){ | |
| 247 | + if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4)){ | |
| 248 | 248 | i64 desiredMtime; |
| 249 | 249 | if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){ |
| 250 | 250 | if( currentMtime!=desiredMtime ){ |
| 251 | 251 | file_set_mtime(zName, desiredMtime); |
| 252 | 252 | currentMtime = file_mtime(zName, RepoFILE); |
| @@ -966,5 +966,132 @@ | ||
| 966 | 966 | blob_reset(&hash); |
| 967 | 967 | vfile_aggregate_checksum_manifest(vid, &hash, &hash2); |
| 968 | 968 | printf("manifest: %s\n", blob_str(&hash)); |
| 969 | 969 | printf("recorded: %s\n", blob_str(&hash2)); |
| 970 | 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 | +} | |
| 971 | 1098 |
| --- 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 |