Fossil SCM
Add initial infrastructure for being able to resolve 'ckout' uniformly in certain contexts, per /chat discussion.
Commit
4d8c30265b3dc76d9fe559cb1c91aea018f0e520f07037fce09a101583611b6f
Parent
65d97f23f617a4c…
2 files changed
+1
-1
+49
-12
M
src/db.c
+1
-1
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -2204,11 +2204,11 @@ | ||
| 2204 | 2204 | while( n>0 && zPwd[n-1]=='/' ){ |
| 2205 | 2205 | n--; |
| 2206 | 2206 | zPwd[n] = 0; |
| 2207 | 2207 | } |
| 2208 | 2208 | g.zLocalRoot = mprintf("%s/", zPwd); |
| 2209 | - g.localOpen = 1; | |
| 2209 | + g.localOpen = db_lget_int("checkout", -1); | |
| 2210 | 2210 | db_open_repository(zDbName); |
| 2211 | 2211 | return 1; |
| 2212 | 2212 | } |
| 2213 | 2213 | } |
| 2214 | 2214 | if( bRootOnly ) break; |
| 2215 | 2215 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -2204,11 +2204,11 @@ | |
| 2204 | while( n>0 && zPwd[n-1]=='/' ){ |
| 2205 | n--; |
| 2206 | zPwd[n] = 0; |
| 2207 | } |
| 2208 | g.zLocalRoot = mprintf("%s/", zPwd); |
| 2209 | g.localOpen = 1; |
| 2210 | db_open_repository(zDbName); |
| 2211 | return 1; |
| 2212 | } |
| 2213 | } |
| 2214 | if( bRootOnly ) break; |
| 2215 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -2204,11 +2204,11 @@ | |
| 2204 | while( n>0 && zPwd[n-1]=='/' ){ |
| 2205 | n--; |
| 2206 | zPwd[n] = 0; |
| 2207 | } |
| 2208 | g.zLocalRoot = mprintf("%s/", zPwd); |
| 2209 | g.localOpen = db_lget_int("checkout", -1); |
| 2210 | db_open_repository(zDbName); |
| 2211 | return 1; |
| 2212 | } |
| 2213 | } |
| 2214 | if( bRootOnly ) break; |
| 2215 |
+49
-12
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -19,10 +19,23 @@ | ||
| 19 | 19 | */ |
| 20 | 20 | #include "config.h" |
| 21 | 21 | #include "name.h" |
| 22 | 22 | #include <assert.h> |
| 23 | 23 | |
| 24 | +#if INTERFACE | |
| 25 | +/* | |
| 26 | +** An upper boundary on RIDs, provided in order to be able to | |
| 27 | +** distinguish real RID values from RID_CKOUT and any future | |
| 28 | +** RID_... values. | |
| 29 | +*/ | |
| 30 | +#define RID_MAX 0x7ffffff0 | |
| 31 | +/* | |
| 32 | +** A "magic" RID representing the current checkout in some contexts. | |
| 33 | +*/ | |
| 34 | +#define RID_CKOUT (RID_MAX+1) | |
| 35 | +#endif | |
| 36 | + | |
| 24 | 37 | /* |
| 25 | 38 | ** Return TRUE if the string begins with something that looks roughly |
| 26 | 39 | ** like an ISO date/time string. The SQLite date/time functions will |
| 27 | 40 | ** have the final say-so about whether or not the date/time string is |
| 28 | 41 | ** well-formed. |
| @@ -165,11 +178,11 @@ | ||
| 165 | 178 | " WHERE tagid=%d AND tagtype>0" |
| 166 | 179 | " AND value=%Q AND rid=plink.pid), 1" |
| 167 | 180 | " FROM plink WHERE cid=%d AND isprim" |
| 168 | 181 | " UNION ALL " |
| 169 | 182 | " SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref " |
| 170 | - " WHERE tagid=%d AND tagtype>0" | |
| 183 | + " WHERE tagid=%d AND tagtype>0" | |
| 171 | 184 | " AND value=%Q AND rid=plink.pid)," |
| 172 | 185 | " 1+par.cnt" |
| 173 | 186 | " FROM plink, par" |
| 174 | 187 | " WHERE cid=par.pid AND isprim AND par.ex " |
| 175 | 188 | " LIMIT 100000 " |
| @@ -177,11 +190,11 @@ | ||
| 177 | 190 | " SELECT pid FROM par WHERE ex>=%d ORDER BY cnt DESC LIMIT 1", |
| 178 | 191 | TAG_BRANCH, zBr, ans, TAG_BRANCH, zBr, eType%2 |
| 179 | 192 | ); |
| 180 | 193 | fossil_free(zBr); |
| 181 | 194 | rc = db_step(&q); |
| 182 | - if( rc==SQLITE_ROW ){ | |
| 195 | + if( rc==SQLITE_ROW ){ | |
| 183 | 196 | ans = db_column_int(&q, 0); |
| 184 | 197 | } |
| 185 | 198 | db_finalize(&q); |
| 186 | 199 | if( eType==2 && ans>0 ){ |
| 187 | 200 | zBr = branch_of_rid(ans); |
| @@ -195,11 +208,11 @@ | ||
| 195 | 208 | ** Find the RID of the most recent object with symbolic tag zTag |
| 196 | 209 | ** and having a type that matches zType. |
| 197 | 210 | ** |
| 198 | 211 | ** Return 0 if there are no matches. |
| 199 | 212 | ** |
| 200 | -** This is a tricky query to do efficiently. | |
| 213 | +** This is a tricky query to do efficiently. | |
| 201 | 214 | ** If the tag is very common (ex: "trunk") then |
| 202 | 215 | ** we want to use the query identified below as Q1 - which searching |
| 203 | 216 | ** the most recent EVENT table entries for the most recent with the tag. |
| 204 | 217 | ** But if the tag is relatively scarce (anything other than "trunk", basically) |
| 205 | 218 | ** then we want to do the indexed search show below as Q2. |
| @@ -278,56 +291,73 @@ | ||
| 278 | 291 | ** If zType is NULL or "" or "*" then any type of artifact will serve. |
| 279 | 292 | ** If zType is "br" then find the first check-in of the named branch |
| 280 | 293 | ** rather than the last. |
| 281 | 294 | ** |
| 282 | 295 | ** zType is "ci" in most use cases since we are usually searching for |
| 283 | -** a check-in. | |
| 296 | +** a check-in. A value of "ci+" works like "ci" but adds these | |
| 297 | +** semantics: if zTag is "ckout" and a checkout is open, "ci+" causes | |
| 298 | +** RID_CKOUT to be returned, in which case g.localOpen will hold the | |
| 299 | +** RID of the checkout. Conversely, passing in the hash, or another | |
| 300 | +** symbolic name of the local checkout version, will always result in | |
| 301 | +** its RID being returned. | |
| 284 | 302 | ** |
| 285 | 303 | ** Note that the input zTag for types "t" and "e" is the artifact hash of |
| 286 | 304 | ** the ticket-change or technote-change artifact, not the randomly generated |
| 287 | 305 | ** hexadecimal identifier assigned to tickets and events. Those identifiers |
| 288 | 306 | ** live in a separate namespace. |
| 289 | 307 | */ |
| 290 | 308 | int symbolic_name_to_rid(const char *zTag, const char *zType){ |
| 291 | - int vid; | |
| 292 | 309 | int rid = 0; |
| 293 | 310 | int nTag; |
| 294 | 311 | int i; |
| 295 | 312 | int startOfBranch = 0; |
| 296 | 313 | const char *zXTag; /* zTag with optional [...] removed */ |
| 297 | 314 | int nXTag; /* Size of zXTag */ |
| 298 | 315 | const char *zDate; /* Expanded date-time string */ |
| 316 | + int isCheckin = 0; /* zType==ci = 1, zType==ci+ = 2 */ | |
| 299 | 317 | |
| 300 | 318 | if( zType==0 || zType[0]==0 ){ |
| 301 | 319 | zType = "*"; |
| 302 | 320 | }else if( zType[0]=='b' ){ |
| 303 | 321 | zType = "ci"; |
| 304 | 322 | startOfBranch = 1; |
| 305 | 323 | } |
| 306 | 324 | if( zTag==0 || zTag[0]==0 ) return 0; |
| 325 | + else if( 'c'==zType[0] ){ | |
| 326 | + if( fossil_strcmp(zType,"ci")==0 ){ | |
| 327 | + isCheckin = 1; | |
| 328 | + }else if( fossil_strcmp(zType,"ci+")==0 ){ | |
| 329 | + isCheckin = 2; | |
| 330 | + zType = "ci"; | |
| 331 | + } | |
| 332 | + } | |
| 307 | 333 | |
| 308 | 334 | /* special keyword: "tip" */ |
| 309 | - if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){ | |
| 335 | + if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || isCheckin!=0) ){ | |
| 310 | 336 | rid = db_int(0, |
| 311 | 337 | "SELECT objid" |
| 312 | 338 | " FROM event" |
| 313 | 339 | " WHERE type='ci'" |
| 314 | 340 | " ORDER BY event.mtime DESC" |
| 315 | 341 | ); |
| 316 | 342 | if( rid ) return rid; |
| 317 | 343 | } |
| 318 | 344 | |
| 319 | - /* special keywords: "prev", "previous", "current", and "next" */ | |
| 320 | - if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){ | |
| 345 | + /* special keywords: "prev", "previous", "current", "ckout", and | |
| 346 | + ** "next" */ | |
| 347 | + if( g.localOpen>0 && (zType[0]=='*' || isCheckin!=0) ){ | |
| 348 | + const int vid = g.localOpen; | |
| 321 | 349 | if( fossil_strcmp(zTag, "current")==0 ){ |
| 322 | 350 | rid = vid; |
| 323 | 351 | }else if( fossil_strcmp(zTag, "prev")==0 |
| 324 | 352 | || fossil_strcmp(zTag, "previous")==0 ){ |
| 325 | 353 | rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid); |
| 326 | 354 | }else if( fossil_strcmp(zTag, "next")==0 ){ |
| 327 | 355 | rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d" |
| 328 | 356 | " ORDER BY isprim DESC, mtime DESC", vid); |
| 357 | + }else if( isCheckin>1 && fossil_strcmp(zTag, "ckout")==0 ){ | |
| 358 | + rid = RID_CKOUT; | |
| 329 | 359 | } |
| 330 | 360 | if( rid ) return rid; |
| 331 | 361 | } |
| 332 | 362 | |
| 333 | 363 | /* Date and times */ |
| @@ -523,11 +553,11 @@ | ||
| 523 | 553 | && !is_trailing_punct(zTag[nTag-2]) |
| 524 | 554 | ){ |
| 525 | 555 | char *zNew = fossil_strndup(zTag, nTag-1); |
| 526 | 556 | rid = symbolic_name_to_rid(zNew,zType); |
| 527 | 557 | fossil_free(zNew); |
| 528 | - }else | |
| 558 | + }else | |
| 529 | 559 | if( nTag>5 |
| 530 | 560 | && is_trailing_punct(zTag[nTag-1]) |
| 531 | 561 | && is_trailing_punct(zTag[nTag-2]) |
| 532 | 562 | && !is_trailing_punct(zTag[nTag-3]) |
| 533 | 563 | ){ |
| @@ -588,11 +618,13 @@ | ||
| 588 | 618 | ** the full hash, which must eventually be free()d by the caller. |
| 589 | 619 | */ |
| 590 | 620 | int name_to_uuid2(const char *zName, const char *zType, char **pUuid){ |
| 591 | 621 | int rid = symbolic_name_to_rid(zName, zType); |
| 592 | 622 | if((rid>0) && pUuid){ |
| 593 | - *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 623 | + *pUuid = (rid<RID_MAX) | |
| 624 | + ? db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid) | |
| 625 | + : NULL; | |
| 594 | 626 | } |
| 595 | 627 | return rid; |
| 596 | 628 | } |
| 597 | 629 | |
| 598 | 630 | |
| @@ -623,30 +655,35 @@ | ||
| 623 | 655 | } |
| 624 | 656 | |
| 625 | 657 | /* |
| 626 | 658 | ** COMMAND: test-name-to-id |
| 627 | 659 | ** |
| 628 | -** Usage: %fossil test-name-to-id [--count N] NAME | |
| 660 | +** Usage: %fossil test-name-to-id [--count N] [--type ARTIFACT_TYPE] NAME | |
| 629 | 661 | ** |
| 630 | 662 | ** Convert a NAME to a full artifact ID. Repeat the conversion N |
| 631 | 663 | ** times (for timing purposes) if the --count option is given. |
| 632 | 664 | */ |
| 633 | 665 | void test_name_to_id(void){ |
| 634 | 666 | int i; |
| 635 | 667 | int n = 0; |
| 636 | 668 | Blob name; |
| 669 | + const char *zType; | |
| 670 | + | |
| 637 | 671 | db_must_be_within_tree(); |
| 672 | + if( (zType = find_option("type","t",1))==0 ){ | |
| 673 | + zType = "*"; | |
| 674 | + } | |
| 638 | 675 | for(i=2; i<g.argc; i++){ |
| 639 | 676 | if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){ |
| 640 | 677 | i++; |
| 641 | 678 | n = atoi(g.argv[i]); |
| 642 | 679 | continue; |
| 643 | 680 | } |
| 644 | 681 | do{ |
| 645 | 682 | blob_init(&name, g.argv[i], -1); |
| 646 | 683 | fossil_print("%s -> ", g.argv[i]); |
| 647 | - if( name_to_uuid(&name, 1, "*") ){ | |
| 684 | + if( name_to_uuid(&name, 1, zType) ){ | |
| 648 | 685 | fossil_print("ERROR: %s\n", g.zErrMsg); |
| 649 | 686 | fossil_error_reset(); |
| 650 | 687 | }else{ |
| 651 | 688 | fossil_print("%s\n", blob_buffer(&name)); |
| 652 | 689 | } |
| 653 | 690 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -19,10 +19,23 @@ | |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "name.h" |
| 22 | #include <assert.h> |
| 23 | |
| 24 | /* |
| 25 | ** Return TRUE if the string begins with something that looks roughly |
| 26 | ** like an ISO date/time string. The SQLite date/time functions will |
| 27 | ** have the final say-so about whether or not the date/time string is |
| 28 | ** well-formed. |
| @@ -165,11 +178,11 @@ | |
| 165 | " WHERE tagid=%d AND tagtype>0" |
| 166 | " AND value=%Q AND rid=plink.pid), 1" |
| 167 | " FROM plink WHERE cid=%d AND isprim" |
| 168 | " UNION ALL " |
| 169 | " SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref " |
| 170 | " WHERE tagid=%d AND tagtype>0" |
| 171 | " AND value=%Q AND rid=plink.pid)," |
| 172 | " 1+par.cnt" |
| 173 | " FROM plink, par" |
| 174 | " WHERE cid=par.pid AND isprim AND par.ex " |
| 175 | " LIMIT 100000 " |
| @@ -177,11 +190,11 @@ | |
| 177 | " SELECT pid FROM par WHERE ex>=%d ORDER BY cnt DESC LIMIT 1", |
| 178 | TAG_BRANCH, zBr, ans, TAG_BRANCH, zBr, eType%2 |
| 179 | ); |
| 180 | fossil_free(zBr); |
| 181 | rc = db_step(&q); |
| 182 | if( rc==SQLITE_ROW ){ |
| 183 | ans = db_column_int(&q, 0); |
| 184 | } |
| 185 | db_finalize(&q); |
| 186 | if( eType==2 && ans>0 ){ |
| 187 | zBr = branch_of_rid(ans); |
| @@ -195,11 +208,11 @@ | |
| 195 | ** Find the RID of the most recent object with symbolic tag zTag |
| 196 | ** and having a type that matches zType. |
| 197 | ** |
| 198 | ** Return 0 if there are no matches. |
| 199 | ** |
| 200 | ** This is a tricky query to do efficiently. |
| 201 | ** If the tag is very common (ex: "trunk") then |
| 202 | ** we want to use the query identified below as Q1 - which searching |
| 203 | ** the most recent EVENT table entries for the most recent with the tag. |
| 204 | ** But if the tag is relatively scarce (anything other than "trunk", basically) |
| 205 | ** then we want to do the indexed search show below as Q2. |
| @@ -278,56 +291,73 @@ | |
| 278 | ** If zType is NULL or "" or "*" then any type of artifact will serve. |
| 279 | ** If zType is "br" then find the first check-in of the named branch |
| 280 | ** rather than the last. |
| 281 | ** |
| 282 | ** zType is "ci" in most use cases since we are usually searching for |
| 283 | ** a check-in. |
| 284 | ** |
| 285 | ** Note that the input zTag for types "t" and "e" is the artifact hash of |
| 286 | ** the ticket-change or technote-change artifact, not the randomly generated |
| 287 | ** hexadecimal identifier assigned to tickets and events. Those identifiers |
| 288 | ** live in a separate namespace. |
| 289 | */ |
| 290 | int symbolic_name_to_rid(const char *zTag, const char *zType){ |
| 291 | int vid; |
| 292 | int rid = 0; |
| 293 | int nTag; |
| 294 | int i; |
| 295 | int startOfBranch = 0; |
| 296 | const char *zXTag; /* zTag with optional [...] removed */ |
| 297 | int nXTag; /* Size of zXTag */ |
| 298 | const char *zDate; /* Expanded date-time string */ |
| 299 | |
| 300 | if( zType==0 || zType[0]==0 ){ |
| 301 | zType = "*"; |
| 302 | }else if( zType[0]=='b' ){ |
| 303 | zType = "ci"; |
| 304 | startOfBranch = 1; |
| 305 | } |
| 306 | if( zTag==0 || zTag[0]==0 ) return 0; |
| 307 | |
| 308 | /* special keyword: "tip" */ |
| 309 | if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){ |
| 310 | rid = db_int(0, |
| 311 | "SELECT objid" |
| 312 | " FROM event" |
| 313 | " WHERE type='ci'" |
| 314 | " ORDER BY event.mtime DESC" |
| 315 | ); |
| 316 | if( rid ) return rid; |
| 317 | } |
| 318 | |
| 319 | /* special keywords: "prev", "previous", "current", and "next" */ |
| 320 | if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){ |
| 321 | if( fossil_strcmp(zTag, "current")==0 ){ |
| 322 | rid = vid; |
| 323 | }else if( fossil_strcmp(zTag, "prev")==0 |
| 324 | || fossil_strcmp(zTag, "previous")==0 ){ |
| 325 | rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid); |
| 326 | }else if( fossil_strcmp(zTag, "next")==0 ){ |
| 327 | rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d" |
| 328 | " ORDER BY isprim DESC, mtime DESC", vid); |
| 329 | } |
| 330 | if( rid ) return rid; |
| 331 | } |
| 332 | |
| 333 | /* Date and times */ |
| @@ -523,11 +553,11 @@ | |
| 523 | && !is_trailing_punct(zTag[nTag-2]) |
| 524 | ){ |
| 525 | char *zNew = fossil_strndup(zTag, nTag-1); |
| 526 | rid = symbolic_name_to_rid(zNew,zType); |
| 527 | fossil_free(zNew); |
| 528 | }else |
| 529 | if( nTag>5 |
| 530 | && is_trailing_punct(zTag[nTag-1]) |
| 531 | && is_trailing_punct(zTag[nTag-2]) |
| 532 | && !is_trailing_punct(zTag[nTag-3]) |
| 533 | ){ |
| @@ -588,11 +618,13 @@ | |
| 588 | ** the full hash, which must eventually be free()d by the caller. |
| 589 | */ |
| 590 | int name_to_uuid2(const char *zName, const char *zType, char **pUuid){ |
| 591 | int rid = symbolic_name_to_rid(zName, zType); |
| 592 | if((rid>0) && pUuid){ |
| 593 | *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 594 | } |
| 595 | return rid; |
| 596 | } |
| 597 | |
| 598 | |
| @@ -623,30 +655,35 @@ | |
| 623 | } |
| 624 | |
| 625 | /* |
| 626 | ** COMMAND: test-name-to-id |
| 627 | ** |
| 628 | ** Usage: %fossil test-name-to-id [--count N] NAME |
| 629 | ** |
| 630 | ** Convert a NAME to a full artifact ID. Repeat the conversion N |
| 631 | ** times (for timing purposes) if the --count option is given. |
| 632 | */ |
| 633 | void test_name_to_id(void){ |
| 634 | int i; |
| 635 | int n = 0; |
| 636 | Blob name; |
| 637 | db_must_be_within_tree(); |
| 638 | for(i=2; i<g.argc; i++){ |
| 639 | if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){ |
| 640 | i++; |
| 641 | n = atoi(g.argv[i]); |
| 642 | continue; |
| 643 | } |
| 644 | do{ |
| 645 | blob_init(&name, g.argv[i], -1); |
| 646 | fossil_print("%s -> ", g.argv[i]); |
| 647 | if( name_to_uuid(&name, 1, "*") ){ |
| 648 | fossil_print("ERROR: %s\n", g.zErrMsg); |
| 649 | fossil_error_reset(); |
| 650 | }else{ |
| 651 | fossil_print("%s\n", blob_buffer(&name)); |
| 652 | } |
| 653 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -19,10 +19,23 @@ | |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "name.h" |
| 22 | #include <assert.h> |
| 23 | |
| 24 | #if INTERFACE |
| 25 | /* |
| 26 | ** An upper boundary on RIDs, provided in order to be able to |
| 27 | ** distinguish real RID values from RID_CKOUT and any future |
| 28 | ** RID_... values. |
| 29 | */ |
| 30 | #define RID_MAX 0x7ffffff0 |
| 31 | /* |
| 32 | ** A "magic" RID representing the current checkout in some contexts. |
| 33 | */ |
| 34 | #define RID_CKOUT (RID_MAX+1) |
| 35 | #endif |
| 36 | |
| 37 | /* |
| 38 | ** Return TRUE if the string begins with something that looks roughly |
| 39 | ** like an ISO date/time string. The SQLite date/time functions will |
| 40 | ** have the final say-so about whether or not the date/time string is |
| 41 | ** well-formed. |
| @@ -165,11 +178,11 @@ | |
| 178 | " WHERE tagid=%d AND tagtype>0" |
| 179 | " AND value=%Q AND rid=plink.pid), 1" |
| 180 | " FROM plink WHERE cid=%d AND isprim" |
| 181 | " UNION ALL " |
| 182 | " SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref " |
| 183 | " WHERE tagid=%d AND tagtype>0" |
| 184 | " AND value=%Q AND rid=plink.pid)," |
| 185 | " 1+par.cnt" |
| 186 | " FROM plink, par" |
| 187 | " WHERE cid=par.pid AND isprim AND par.ex " |
| 188 | " LIMIT 100000 " |
| @@ -177,11 +190,11 @@ | |
| 190 | " SELECT pid FROM par WHERE ex>=%d ORDER BY cnt DESC LIMIT 1", |
| 191 | TAG_BRANCH, zBr, ans, TAG_BRANCH, zBr, eType%2 |
| 192 | ); |
| 193 | fossil_free(zBr); |
| 194 | rc = db_step(&q); |
| 195 | if( rc==SQLITE_ROW ){ |
| 196 | ans = db_column_int(&q, 0); |
| 197 | } |
| 198 | db_finalize(&q); |
| 199 | if( eType==2 && ans>0 ){ |
| 200 | zBr = branch_of_rid(ans); |
| @@ -195,11 +208,11 @@ | |
| 208 | ** Find the RID of the most recent object with symbolic tag zTag |
| 209 | ** and having a type that matches zType. |
| 210 | ** |
| 211 | ** Return 0 if there are no matches. |
| 212 | ** |
| 213 | ** This is a tricky query to do efficiently. |
| 214 | ** If the tag is very common (ex: "trunk") then |
| 215 | ** we want to use the query identified below as Q1 - which searching |
| 216 | ** the most recent EVENT table entries for the most recent with the tag. |
| 217 | ** But if the tag is relatively scarce (anything other than "trunk", basically) |
| 218 | ** then we want to do the indexed search show below as Q2. |
| @@ -278,56 +291,73 @@ | |
| 291 | ** If zType is NULL or "" or "*" then any type of artifact will serve. |
| 292 | ** If zType is "br" then find the first check-in of the named branch |
| 293 | ** rather than the last. |
| 294 | ** |
| 295 | ** zType is "ci" in most use cases since we are usually searching for |
| 296 | ** a check-in. A value of "ci+" works like "ci" but adds these |
| 297 | ** semantics: if zTag is "ckout" and a checkout is open, "ci+" causes |
| 298 | ** RID_CKOUT to be returned, in which case g.localOpen will hold the |
| 299 | ** RID of the checkout. Conversely, passing in the hash, or another |
| 300 | ** symbolic name of the local checkout version, will always result in |
| 301 | ** its RID being returned. |
| 302 | ** |
| 303 | ** Note that the input zTag for types "t" and "e" is the artifact hash of |
| 304 | ** the ticket-change or technote-change artifact, not the randomly generated |
| 305 | ** hexadecimal identifier assigned to tickets and events. Those identifiers |
| 306 | ** live in a separate namespace. |
| 307 | */ |
| 308 | int symbolic_name_to_rid(const char *zTag, const char *zType){ |
| 309 | int rid = 0; |
| 310 | int nTag; |
| 311 | int i; |
| 312 | int startOfBranch = 0; |
| 313 | const char *zXTag; /* zTag with optional [...] removed */ |
| 314 | int nXTag; /* Size of zXTag */ |
| 315 | const char *zDate; /* Expanded date-time string */ |
| 316 | int isCheckin = 0; /* zType==ci = 1, zType==ci+ = 2 */ |
| 317 | |
| 318 | if( zType==0 || zType[0]==0 ){ |
| 319 | zType = "*"; |
| 320 | }else if( zType[0]=='b' ){ |
| 321 | zType = "ci"; |
| 322 | startOfBranch = 1; |
| 323 | } |
| 324 | if( zTag==0 || zTag[0]==0 ) return 0; |
| 325 | else if( 'c'==zType[0] ){ |
| 326 | if( fossil_strcmp(zType,"ci")==0 ){ |
| 327 | isCheckin = 1; |
| 328 | }else if( fossil_strcmp(zType,"ci+")==0 ){ |
| 329 | isCheckin = 2; |
| 330 | zType = "ci"; |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | /* special keyword: "tip" */ |
| 335 | if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || isCheckin!=0) ){ |
| 336 | rid = db_int(0, |
| 337 | "SELECT objid" |
| 338 | " FROM event" |
| 339 | " WHERE type='ci'" |
| 340 | " ORDER BY event.mtime DESC" |
| 341 | ); |
| 342 | if( rid ) return rid; |
| 343 | } |
| 344 | |
| 345 | /* special keywords: "prev", "previous", "current", "ckout", and |
| 346 | ** "next" */ |
| 347 | if( g.localOpen>0 && (zType[0]=='*' || isCheckin!=0) ){ |
| 348 | const int vid = g.localOpen; |
| 349 | if( fossil_strcmp(zTag, "current")==0 ){ |
| 350 | rid = vid; |
| 351 | }else if( fossil_strcmp(zTag, "prev")==0 |
| 352 | || fossil_strcmp(zTag, "previous")==0 ){ |
| 353 | rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid); |
| 354 | }else if( fossil_strcmp(zTag, "next")==0 ){ |
| 355 | rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d" |
| 356 | " ORDER BY isprim DESC, mtime DESC", vid); |
| 357 | }else if( isCheckin>1 && fossil_strcmp(zTag, "ckout")==0 ){ |
| 358 | rid = RID_CKOUT; |
| 359 | } |
| 360 | if( rid ) return rid; |
| 361 | } |
| 362 | |
| 363 | /* Date and times */ |
| @@ -523,11 +553,11 @@ | |
| 553 | && !is_trailing_punct(zTag[nTag-2]) |
| 554 | ){ |
| 555 | char *zNew = fossil_strndup(zTag, nTag-1); |
| 556 | rid = symbolic_name_to_rid(zNew,zType); |
| 557 | fossil_free(zNew); |
| 558 | }else |
| 559 | if( nTag>5 |
| 560 | && is_trailing_punct(zTag[nTag-1]) |
| 561 | && is_trailing_punct(zTag[nTag-2]) |
| 562 | && !is_trailing_punct(zTag[nTag-3]) |
| 563 | ){ |
| @@ -588,11 +618,13 @@ | |
| 618 | ** the full hash, which must eventually be free()d by the caller. |
| 619 | */ |
| 620 | int name_to_uuid2(const char *zName, const char *zType, char **pUuid){ |
| 621 | int rid = symbolic_name_to_rid(zName, zType); |
| 622 | if((rid>0) && pUuid){ |
| 623 | *pUuid = (rid<RID_MAX) |
| 624 | ? db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid) |
| 625 | : NULL; |
| 626 | } |
| 627 | return rid; |
| 628 | } |
| 629 | |
| 630 | |
| @@ -623,30 +655,35 @@ | |
| 655 | } |
| 656 | |
| 657 | /* |
| 658 | ** COMMAND: test-name-to-id |
| 659 | ** |
| 660 | ** Usage: %fossil test-name-to-id [--count N] [--type ARTIFACT_TYPE] NAME |
| 661 | ** |
| 662 | ** Convert a NAME to a full artifact ID. Repeat the conversion N |
| 663 | ** times (for timing purposes) if the --count option is given. |
| 664 | */ |
| 665 | void test_name_to_id(void){ |
| 666 | int i; |
| 667 | int n = 0; |
| 668 | Blob name; |
| 669 | const char *zType; |
| 670 | |
| 671 | db_must_be_within_tree(); |
| 672 | if( (zType = find_option("type","t",1))==0 ){ |
| 673 | zType = "*"; |
| 674 | } |
| 675 | for(i=2; i<g.argc; i++){ |
| 676 | if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){ |
| 677 | i++; |
| 678 | n = atoi(g.argv[i]); |
| 679 | continue; |
| 680 | } |
| 681 | do{ |
| 682 | blob_init(&name, g.argv[i], -1); |
| 683 | fossil_print("%s -> ", g.argv[i]); |
| 684 | if( name_to_uuid(&name, 1, zType) ){ |
| 685 | fossil_print("ERROR: %s\n", g.zErrMsg); |
| 686 | fossil_error_reset(); |
| 687 | }else{ |
| 688 | fossil_print("%s\n", blob_buffer(&name)); |
| 689 | } |
| 690 |