Fossil SCM
Show short UUID collisions also for tickets and not just ticket changes. Reported on ML.
Commit
0066d6c6a9afe510e3b26ae4c123e692b1717496
Parent
b37a28228c3788c…
2 files changed
+17
-15
+70
-1
+17
-15
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1893,31 +1893,33 @@ | ||
| 1893 | 1893 | int rid; |
| 1894 | 1894 | int rc; |
| 1895 | 1895 | |
| 1896 | 1896 | zName = P("name"); |
| 1897 | 1897 | if( zName==0 ) fossil_redirect_home(); |
| 1898 | - if( validate16(zName, strlen(zName)) ){ | |
| 1899 | - if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ | |
| 1900 | - tktview_page(); | |
| 1901 | - return; | |
| 1902 | - } | |
| 1903 | - if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){ | |
| 1898 | + blob_set(&uuid, zName); | |
| 1899 | + rc = name_to_uuid3(&uuid, -1, "*"); | |
| 1900 | + if( rc==1 ){ | |
| 1901 | + if( validate16(zName, strlen(zName)) && | |
| 1902 | + db_exists("SELECT 1 FROM tag" | |
| 1903 | + " WHERE tagname GLOB 'event-%q*'", zName) ){ | |
| 1904 | 1904 | event_page(); |
| 1905 | 1905 | return; |
| 1906 | - } | |
| 1907 | - } | |
| 1908 | - blob_set(&uuid, zName); | |
| 1909 | - rc = name_to_uuid(&uuid, -1, "*"); | |
| 1910 | - if( rc==1 ){ | |
| 1911 | - style_header("No Such Object"); | |
| 1912 | - @ <p>No such object: %h(zName)</p> | |
| 1913 | - style_footer(); | |
| 1914 | - return; | |
| 1906 | + }else{ | |
| 1907 | + style_header("No Such Object"); | |
| 1908 | + @ <p>No such object: %h(zName)</p> | |
| 1909 | + style_footer(); | |
| 1910 | + return; | |
| 1911 | + } | |
| 1915 | 1912 | }else if( rc==2 ){ |
| 1916 | 1913 | cgi_set_parameter("src","info"); |
| 1917 | 1914 | ambiguous_page(); |
| 1918 | 1915 | return; |
| 1916 | + }else if( rc==3 && validate16(zName, strlen(zName)) ){ | |
| 1917 | + if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ | |
| 1918 | + tktview_page(); | |
| 1919 | + return; | |
| 1920 | + } | |
| 1919 | 1921 | } |
| 1920 | 1922 | zName = blob_str(&uuid); |
| 1921 | 1923 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName); |
| 1922 | 1924 | if( rid==0 ){ |
| 1923 | 1925 | style_header("Broken Link"); |
| 1924 | 1926 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1893,31 +1893,33 @@ | |
| 1893 | int rid; |
| 1894 | int rc; |
| 1895 | |
| 1896 | zName = P("name"); |
| 1897 | if( zName==0 ) fossil_redirect_home(); |
| 1898 | if( validate16(zName, strlen(zName)) ){ |
| 1899 | if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ |
| 1900 | tktview_page(); |
| 1901 | return; |
| 1902 | } |
| 1903 | if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){ |
| 1904 | event_page(); |
| 1905 | return; |
| 1906 | } |
| 1907 | } |
| 1908 | blob_set(&uuid, zName); |
| 1909 | rc = name_to_uuid(&uuid, -1, "*"); |
| 1910 | if( rc==1 ){ |
| 1911 | style_header("No Such Object"); |
| 1912 | @ <p>No such object: %h(zName)</p> |
| 1913 | style_footer(); |
| 1914 | return; |
| 1915 | }else if( rc==2 ){ |
| 1916 | cgi_set_parameter("src","info"); |
| 1917 | ambiguous_page(); |
| 1918 | return; |
| 1919 | } |
| 1920 | zName = blob_str(&uuid); |
| 1921 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName); |
| 1922 | if( rid==0 ){ |
| 1923 | style_header("Broken Link"); |
| 1924 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1893,31 +1893,33 @@ | |
| 1893 | int rid; |
| 1894 | int rc; |
| 1895 | |
| 1896 | zName = P("name"); |
| 1897 | if( zName==0 ) fossil_redirect_home(); |
| 1898 | blob_set(&uuid, zName); |
| 1899 | rc = name_to_uuid3(&uuid, -1, "*"); |
| 1900 | if( rc==1 ){ |
| 1901 | if( validate16(zName, strlen(zName)) && |
| 1902 | db_exists("SELECT 1 FROM tag" |
| 1903 | " WHERE tagname GLOB 'event-%q*'", zName) ){ |
| 1904 | event_page(); |
| 1905 | return; |
| 1906 | }else{ |
| 1907 | style_header("No Such Object"); |
| 1908 | @ <p>No such object: %h(zName)</p> |
| 1909 | style_footer(); |
| 1910 | return; |
| 1911 | } |
| 1912 | }else if( rc==2 ){ |
| 1913 | cgi_set_parameter("src","info"); |
| 1914 | ambiguous_page(); |
| 1915 | return; |
| 1916 | }else if( rc==3 && validate16(zName, strlen(zName)) ){ |
| 1917 | if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){ |
| 1918 | tktview_page(); |
| 1919 | return; |
| 1920 | } |
| 1921 | } |
| 1922 | zName = blob_str(&uuid); |
| 1923 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName); |
| 1924 | if( rid==0 ){ |
| 1925 | style_header("Broken Link"); |
| 1926 |
+70
-1
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -266,10 +266,30 @@ | ||
| 266 | 266 | } |
| 267 | 267 | } |
| 268 | 268 | return rid; |
| 269 | 269 | } |
| 270 | 270 | |
| 271 | +/* | |
| 272 | +** Return the ticket id from the ticket table if found. If more than one | |
| 273 | +** is found, return -1 to indicate ambiguity. | |
| 274 | +*/ | |
| 275 | +int symbolic_name_to_tktid(const char *zTag){ | |
| 276 | + int tktid = 0; | |
| 277 | + Stmt q; | |
| 278 | + | |
| 279 | + if( strlen(zTag)>=4 && | |
| 280 | + strlen(zTag)<=UUID_SIZE && validate16(zTag, strlen(zTag)) ) { | |
| 281 | + db_prepare(&q, "SELECT tkt_id FROM ticket" | |
| 282 | + " WHERE tkt_uuid GLOB '%s*'", zTag ); | |
| 283 | + if( db_step(&q)==SQLITE_ROW ){ | |
| 284 | + tktid = db_column_int(&q, 0); | |
| 285 | + if( db_step(&q)==SQLITE_ROW ) tktid = -1; | |
| 286 | + } | |
| 287 | + db_finalize(&q); | |
| 288 | + } | |
| 289 | + return tktid; | |
| 290 | +} | |
| 271 | 291 | |
| 272 | 292 | /* |
| 273 | 293 | ** This routine takes a user-entered UUID which might be in mixed |
| 274 | 294 | ** case and might only be a prefix of the full UUID and converts it |
| 275 | 295 | ** into the full-length UUID in canonical form. |
| @@ -318,11 +338,38 @@ | ||
| 318 | 338 | *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 319 | 339 | } |
| 320 | 340 | return rid; |
| 321 | 341 | } |
| 322 | 342 | |
| 323 | - | |
| 343 | +/* | |
| 344 | +** This routine is similar to name_to_uuid() except it also accounts for | |
| 345 | +** collisions in tickets which don't have an entry in blob (only associated | |
| 346 | +** ticket changes). | |
| 347 | +** Return 0 if rid is found. Return 1 if neither rid nor tkt_id is found. | |
| 348 | +** Return 2 if name is ambiguous. Return 3 if tkt_id is found. | |
| 349 | +*/ | |
| 350 | +int name_to_uuid3(Blob *pName, int iErrPriority, const char *zType){ | |
| 351 | + char *zName = blob_str(pName); | |
| 352 | + int tkt_id = 0; | |
| 353 | + int rid = symbolic_name_to_rid(zName, zType); | |
| 354 | + if( zType && zType[0]=='*' ){ | |
| 355 | + tkt_id = symbolic_name_to_tktid(zName); | |
| 356 | + } | |
| 357 | + if( rid<0 || tkt_id<0 || (rid>0 && tkt_id>0) ){ | |
| 358 | + fossil_error(iErrPriority, "ambiguous name: %s", zName); | |
| 359 | + return 2; | |
| 360 | + }else if( rid==0 && tkt_id==0 ){ | |
| 361 | + fossil_error(iErrPriority, "not found: %s", zName); | |
| 362 | + return 1; | |
| 363 | + }else if( tkt_id>0 ){ | |
| 364 | + return 3; | |
| 365 | + }else{ | |
| 366 | + blob_reset(pName); | |
| 367 | + db_blob(pName, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 368 | + return 0; | |
| 369 | + } | |
| 370 | +} | |
| 324 | 371 | |
| 325 | 372 | /* |
| 326 | 373 | ** COMMAND: test-name-to-id |
| 327 | 374 | ** |
| 328 | 375 | ** Convert a name to a full artifact ID. |
| @@ -406,10 +453,32 @@ | ||
| 406 | 453 | int rid = db_column_int(&q, 1); |
| 407 | 454 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 408 | 455 | @ %s(zUuid)</a> - |
| 409 | 456 | object_description(rid, 0, 0); |
| 410 | 457 | @ </p></li> |
| 458 | + } | |
| 459 | + db_finalize(&q); | |
| 460 | + db_prepare(&q, " SELECT tkt_rid, tkt_uuid, title" | |
| 461 | + " FROM ticket, ticketchng" | |
| 462 | + " WHERE ticket.tkt_id = ticketchng.tkt_id" | |
| 463 | + " AND tkt_uuid GLOB '%q*'" | |
| 464 | + " GROUP BY tkt_uuid" | |
| 465 | + " ORDER BY tkt_ctime DESC", z); | |
| 466 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 467 | + int rid = db_column_int(&q, 0); | |
| 468 | + const char *zUuid = db_column_text(&q, 1); | |
| 469 | + const char *zTitle = db_column_text(&q, 2); | |
| 470 | + @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> | |
| 471 | + @ %s(zUuid)</a> - | |
| 472 | + @ <ul></ul> | |
| 473 | + @ Ticket | |
| 474 | + hyperlink_to_uuid(zUuid); | |
| 475 | + @ - %s(zTitle). | |
| 476 | + @ <ul><li> | |
| 477 | + object_description(rid, 0, 0); | |
| 478 | + @ </li></ul> | |
| 479 | + @ </p></li> | |
| 411 | 480 | } |
| 412 | 481 | @ </ol> |
| 413 | 482 | db_finalize(&q); |
| 414 | 483 | style_footer(); |
| 415 | 484 | } |
| 416 | 485 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -266,10 +266,30 @@ | |
| 266 | } |
| 267 | } |
| 268 | return rid; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | /* |
| 273 | ** This routine takes a user-entered UUID which might be in mixed |
| 274 | ** case and might only be a prefix of the full UUID and converts it |
| 275 | ** into the full-length UUID in canonical form. |
| @@ -318,11 +338,38 @@ | |
| 318 | *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 319 | } |
| 320 | return rid; |
| 321 | } |
| 322 | |
| 323 | |
| 324 | |
| 325 | /* |
| 326 | ** COMMAND: test-name-to-id |
| 327 | ** |
| 328 | ** Convert a name to a full artifact ID. |
| @@ -406,10 +453,32 @@ | |
| 406 | int rid = db_column_int(&q, 1); |
| 407 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 408 | @ %s(zUuid)</a> - |
| 409 | object_description(rid, 0, 0); |
| 410 | @ </p></li> |
| 411 | } |
| 412 | @ </ol> |
| 413 | db_finalize(&q); |
| 414 | style_footer(); |
| 415 | } |
| 416 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -266,10 +266,30 @@ | |
| 266 | } |
| 267 | } |
| 268 | return rid; |
| 269 | } |
| 270 | |
| 271 | /* |
| 272 | ** Return the ticket id from the ticket table if found. If more than one |
| 273 | ** is found, return -1 to indicate ambiguity. |
| 274 | */ |
| 275 | int symbolic_name_to_tktid(const char *zTag){ |
| 276 | int tktid = 0; |
| 277 | Stmt q; |
| 278 | |
| 279 | if( strlen(zTag)>=4 && |
| 280 | strlen(zTag)<=UUID_SIZE && validate16(zTag, strlen(zTag)) ) { |
| 281 | db_prepare(&q, "SELECT tkt_id FROM ticket" |
| 282 | " WHERE tkt_uuid GLOB '%s*'", zTag ); |
| 283 | if( db_step(&q)==SQLITE_ROW ){ |
| 284 | tktid = db_column_int(&q, 0); |
| 285 | if( db_step(&q)==SQLITE_ROW ) tktid = -1; |
| 286 | } |
| 287 | db_finalize(&q); |
| 288 | } |
| 289 | return tktid; |
| 290 | } |
| 291 | |
| 292 | /* |
| 293 | ** This routine takes a user-entered UUID which might be in mixed |
| 294 | ** case and might only be a prefix of the full UUID and converts it |
| 295 | ** into the full-length UUID in canonical form. |
| @@ -318,11 +338,38 @@ | |
| 338 | *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 339 | } |
| 340 | return rid; |
| 341 | } |
| 342 | |
| 343 | /* |
| 344 | ** This routine is similar to name_to_uuid() except it also accounts for |
| 345 | ** collisions in tickets which don't have an entry in blob (only associated |
| 346 | ** ticket changes). |
| 347 | ** Return 0 if rid is found. Return 1 if neither rid nor tkt_id is found. |
| 348 | ** Return 2 if name is ambiguous. Return 3 if tkt_id is found. |
| 349 | */ |
| 350 | int name_to_uuid3(Blob *pName, int iErrPriority, const char *zType){ |
| 351 | char *zName = blob_str(pName); |
| 352 | int tkt_id = 0; |
| 353 | int rid = symbolic_name_to_rid(zName, zType); |
| 354 | if( zType && zType[0]=='*' ){ |
| 355 | tkt_id = symbolic_name_to_tktid(zName); |
| 356 | } |
| 357 | if( rid<0 || tkt_id<0 || (rid>0 && tkt_id>0) ){ |
| 358 | fossil_error(iErrPriority, "ambiguous name: %s", zName); |
| 359 | return 2; |
| 360 | }else if( rid==0 && tkt_id==0 ){ |
| 361 | fossil_error(iErrPriority, "not found: %s", zName); |
| 362 | return 1; |
| 363 | }else if( tkt_id>0 ){ |
| 364 | return 3; |
| 365 | }else{ |
| 366 | blob_reset(pName); |
| 367 | db_blob(pName, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 368 | return 0; |
| 369 | } |
| 370 | } |
| 371 | |
| 372 | /* |
| 373 | ** COMMAND: test-name-to-id |
| 374 | ** |
| 375 | ** Convert a name to a full artifact ID. |
| @@ -406,10 +453,32 @@ | |
| 453 | int rid = db_column_int(&q, 1); |
| 454 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 455 | @ %s(zUuid)</a> - |
| 456 | object_description(rid, 0, 0); |
| 457 | @ </p></li> |
| 458 | } |
| 459 | db_finalize(&q); |
| 460 | db_prepare(&q, " SELECT tkt_rid, tkt_uuid, title" |
| 461 | " FROM ticket, ticketchng" |
| 462 | " WHERE ticket.tkt_id = ticketchng.tkt_id" |
| 463 | " AND tkt_uuid GLOB '%q*'" |
| 464 | " GROUP BY tkt_uuid" |
| 465 | " ORDER BY tkt_ctime DESC", z); |
| 466 | while( db_step(&q)==SQLITE_ROW ){ |
| 467 | int rid = db_column_int(&q, 0); |
| 468 | const char *zUuid = db_column_text(&q, 1); |
| 469 | const char *zTitle = db_column_text(&q, 2); |
| 470 | @ <li><p><a href="%s(g.zTop)/%T(zSrc)/%s(zUuid)"> |
| 471 | @ %s(zUuid)</a> - |
| 472 | @ <ul></ul> |
| 473 | @ Ticket |
| 474 | hyperlink_to_uuid(zUuid); |
| 475 | @ - %s(zTitle). |
| 476 | @ <ul><li> |
| 477 | object_description(rid, 0, 0); |
| 478 | @ </li></ul> |
| 479 | @ </p></li> |
| 480 | } |
| 481 | @ </ol> |
| 482 | db_finalize(&q); |
| 483 | style_footer(); |
| 484 | } |
| 485 |