Fossil SCM
Rework the previous check-in to fix incorrect backlinks' sources for the case when values are appended to a field (i.e. a value of J-card starts with '+'). Consider a reference to 77ab05a0e9 from [caeb7d672df20] for an example which was handled incorrectly by [668e45baff99].
Commit
4d5ded5eea57c709069682bb4d7babd6c1fa11a4ea8a5536488df47316bc0496
Parent
668e45baff990c0…
2 files changed
+5
+34
-20
+5
| --- src/blob.c | ||
| +++ src/blob.c | ||
| @@ -53,10 +53,15 @@ | ||
| 53 | 53 | /* |
| 54 | 54 | ** The buffer holding the blob data |
| 55 | 55 | */ |
| 56 | 56 | #define blob_buffer(X) ((X)->aData) |
| 57 | 57 | |
| 58 | +/* | |
| 59 | +** Number of elements that fits into the current blob's size | |
| 60 | +*/ | |
| 61 | +#define blob_count(X,elType) (blob_size(X)/sizeof(elType)) | |
| 62 | + | |
| 58 | 63 | /* |
| 59 | 64 | ** Append blob contents to another |
| 60 | 65 | */ |
| 61 | 66 | #define blob_appendb(dest, src) \ |
| 62 | 67 | blob_append((dest), blob_buffer(src), blob_size(src)) |
| 63 | 68 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -53,10 +53,15 @@ | |
| 53 | /* |
| 54 | ** The buffer holding the blob data |
| 55 | */ |
| 56 | #define blob_buffer(X) ((X)->aData) |
| 57 | |
| 58 | /* |
| 59 | ** Append blob contents to another |
| 60 | */ |
| 61 | #define blob_appendb(dest, src) \ |
| 62 | blob_append((dest), blob_buffer(src), blob_size(src)) |
| 63 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -53,10 +53,15 @@ | |
| 53 | /* |
| 54 | ** The buffer holding the blob data |
| 55 | */ |
| 56 | #define blob_buffer(X) ((X)->aData) |
| 57 | |
| 58 | /* |
| 59 | ** Number of elements that fits into the current blob's size |
| 60 | */ |
| 61 | #define blob_count(X,elType) (blob_size(X)/sizeof(elType)) |
| 62 | |
| 63 | /* |
| 64 | ** Append blob contents to another |
| 65 | */ |
| 66 | #define blob_appendb(dest, src) \ |
| 67 | blob_append((dest), blob_buffer(src), blob_size(src)) |
| 68 |
+34
-20
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -232,11 +232,14 @@ | ||
| 232 | 232 | for(i=0; (z = cgi_parameter_name(i))!=0; i++){ |
| 233 | 233 | Th_Store(z, P(z)); |
| 234 | 234 | } |
| 235 | 235 | } |
| 236 | 236 | |
| 237 | -struct TicketField { | |
| 237 | +/* | |
| 238 | +** Information about a single J-card | |
| 239 | +*/ | |
| 240 | +struct jCardInfo { | |
| 238 | 241 | char *zValue; |
| 239 | 242 | int mimetype; |
| 240 | 243 | int rid; |
| 241 | 244 | double mtime; |
| 242 | 245 | }; |
| @@ -250,11 +253,11 @@ | ||
| 250 | 253 | ** Parameter rid is the recordID for the ticket artifact in the BLOB table. |
| 251 | 254 | ** |
| 252 | 255 | ** Return the new rowid of the TICKET table entry. |
| 253 | 256 | */ |
| 254 | 257 | static int ticket_insert(const Manifest *p, const int rid, int tktid, |
| 255 | - struct TicketField *fields){ | |
| 258 | + Blob *fields){ | |
| 256 | 259 | Blob sql1; /* update or replace TICKET ... */ |
| 257 | 260 | Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */ |
| 258 | 261 | Blob sql3; /* list of values which correspond to the previous list */ |
| 259 | 262 | Stmt q; |
| 260 | 263 | int i, j; |
| @@ -381,21 +384,24 @@ | ||
| 381 | 384 | rid, BKLNK_TICKET, p->rDate, |
| 382 | 385 | /* existing backlinks must have been |
| 383 | 386 | * already deleted by the caller */ 0 ); |
| 384 | 387 | }else{ |
| 385 | 388 | /* update field's data with the most recent values */ |
| 386 | - struct TicketField *f = fields + j; | |
| 387 | - char *zOld = f->zValue; | |
| 388 | - if( zOld && zName[0]=='+' ){ | |
| 389 | - f->zValue = mprintf("%s%s", zOld, p->aField[i].zValue); | |
| 390 | - }else{ | |
| 391 | - f->zValue = fossil_strdup(p->aField[i].zValue); | |
| 392 | - } | |
| 393 | - if( zOld ) fossil_free(zOld); | |
| 394 | - f->mimetype = mimetype_tkt; | |
| 395 | - f->rid = rid; | |
| 396 | - f->mtime = p->rDate; | |
| 389 | + Blob *cards = fields + j; | |
| 390 | + struct jCardInfo card = { | |
| 391 | + fossil_strdup(p->aField[i].zValue), | |
| 392 | + mimetype_tkt, rid, p->rDate | |
| 393 | + }; | |
| 394 | + if( blob_size(cards) && zName[0]!='+' ){ | |
| 395 | + struct jCardInfo *x = (struct jCardInfo *)blob_buffer(cards); | |
| 396 | + struct jCardInfo *end = x + blob_count(cards,struct jCardInfo); | |
| 397 | + for(; x!=end; x++){ | |
| 398 | + fossil_free( x->zValue ); | |
| 399 | + } | |
| 400 | + blob_truncate(cards,0); | |
| 401 | + } | |
| 402 | + blob_append(cards, (const char*)(&card), sizeof(card)); | |
| 397 | 403 | } |
| 398 | 404 | } |
| 399 | 405 | } |
| 400 | 406 | return tktid; |
| 401 | 407 | } |
| @@ -431,11 +437,11 @@ | ||
| 431 | 437 | int tagid = tag_findid(zTag, 1); |
| 432 | 438 | Stmt q; |
| 433 | 439 | Manifest *pTicket; |
| 434 | 440 | int tktid, i; |
| 435 | 441 | int createFlag = 1; |
| 436 | - struct TicketField *fields; | |
| 442 | + Blob *fields; /* array of blobs; each blob holds array of jCardInfo */ | |
| 437 | 443 | |
| 438 | 444 | fossil_free(zTag); |
| 439 | 445 | getAllTicketFields(); |
| 440 | 446 | if( haveTicket==0 ) return; |
| 441 | 447 | tktid = db_int(0, "SELECT tkt_id FROM ticket WHERE tkt_uuid=%Q", zTktUuid); |
| @@ -443,11 +449,11 @@ | ||
| 443 | 449 | if( haveTicketChng ){ |
| 444 | 450 | db_multi_exec("DELETE FROM ticketchng WHERE tkt_id=%d;", tktid); |
| 445 | 451 | } |
| 446 | 452 | db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid); |
| 447 | 453 | tktid = 0; |
| 448 | - fields = fossil_malloc_zero( sizeof(fields[0]) * nField ); | |
| 454 | + fields = blobarray_new( nField ); | |
| 449 | 455 | db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid IN " |
| 450 | 456 | "(SELECT rid FROM tagxref WHERE tagid=%d)",BKLNK_TICKET, tagid); |
| 451 | 457 | db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid); |
| 452 | 458 | while( db_step(&q)==SQLITE_ROW ){ |
| 453 | 459 | int rid = db_column_int(&q, 0); |
| @@ -460,16 +466,24 @@ | ||
| 460 | 466 | createFlag = 0; |
| 461 | 467 | } |
| 462 | 468 | db_finalize(&q); |
| 463 | 469 | /* Extract backlinks from the most recent values of TICKET fields */ |
| 464 | 470 | for(i=0; i<nField; i++){ |
| 465 | - struct TicketField *f = fields + i; | |
| 466 | - if( f->zValue==0 ) continue; | |
| 467 | - backlink_extract(f->zValue,f->mimetype,f->rid,BKLNK_TICKET,f->mtime,0); | |
| 468 | - fossil_free(f->zValue); | |
| 471 | + Blob *cards = fields + i; | |
| 472 | + if( blob_size(cards) ){ | |
| 473 | + struct jCardInfo *x = (struct jCardInfo *)blob_buffer(cards); | |
| 474 | + struct jCardInfo *end = x + blob_count(cards,struct jCardInfo); | |
| 475 | + for(; x!=end; x++){ | |
| 476 | + assert( x->zValue ); | |
| 477 | + backlink_extract(x->zValue,x->mimetype, | |
| 478 | + x->rid,BKLNK_TICKET,x->mtime,0); | |
| 479 | + fossil_free( x->zValue ); | |
| 480 | + } | |
| 481 | + } | |
| 482 | + blob_truncate(cards,0); | |
| 469 | 483 | } |
| 470 | - fossil_free(fields); | |
| 484 | + blobarray_delete(fields,nField); | |
| 471 | 485 | } |
| 472 | 486 | |
| 473 | 487 | |
| 474 | 488 | /* |
| 475 | 489 | ** Create the TH1 interpreter and load the "common" code. |
| 476 | 490 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -232,11 +232,14 @@ | |
| 232 | for(i=0; (z = cgi_parameter_name(i))!=0; i++){ |
| 233 | Th_Store(z, P(z)); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | struct TicketField { |
| 238 | char *zValue; |
| 239 | int mimetype; |
| 240 | int rid; |
| 241 | double mtime; |
| 242 | }; |
| @@ -250,11 +253,11 @@ | |
| 250 | ** Parameter rid is the recordID for the ticket artifact in the BLOB table. |
| 251 | ** |
| 252 | ** Return the new rowid of the TICKET table entry. |
| 253 | */ |
| 254 | static int ticket_insert(const Manifest *p, const int rid, int tktid, |
| 255 | struct TicketField *fields){ |
| 256 | Blob sql1; /* update or replace TICKET ... */ |
| 257 | Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */ |
| 258 | Blob sql3; /* list of values which correspond to the previous list */ |
| 259 | Stmt q; |
| 260 | int i, j; |
| @@ -381,21 +384,24 @@ | |
| 381 | rid, BKLNK_TICKET, p->rDate, |
| 382 | /* existing backlinks must have been |
| 383 | * already deleted by the caller */ 0 ); |
| 384 | }else{ |
| 385 | /* update field's data with the most recent values */ |
| 386 | struct TicketField *f = fields + j; |
| 387 | char *zOld = f->zValue; |
| 388 | if( zOld && zName[0]=='+' ){ |
| 389 | f->zValue = mprintf("%s%s", zOld, p->aField[i].zValue); |
| 390 | }else{ |
| 391 | f->zValue = fossil_strdup(p->aField[i].zValue); |
| 392 | } |
| 393 | if( zOld ) fossil_free(zOld); |
| 394 | f->mimetype = mimetype_tkt; |
| 395 | f->rid = rid; |
| 396 | f->mtime = p->rDate; |
| 397 | } |
| 398 | } |
| 399 | } |
| 400 | return tktid; |
| 401 | } |
| @@ -431,11 +437,11 @@ | |
| 431 | int tagid = tag_findid(zTag, 1); |
| 432 | Stmt q; |
| 433 | Manifest *pTicket; |
| 434 | int tktid, i; |
| 435 | int createFlag = 1; |
| 436 | struct TicketField *fields; |
| 437 | |
| 438 | fossil_free(zTag); |
| 439 | getAllTicketFields(); |
| 440 | if( haveTicket==0 ) return; |
| 441 | tktid = db_int(0, "SELECT tkt_id FROM ticket WHERE tkt_uuid=%Q", zTktUuid); |
| @@ -443,11 +449,11 @@ | |
| 443 | if( haveTicketChng ){ |
| 444 | db_multi_exec("DELETE FROM ticketchng WHERE tkt_id=%d;", tktid); |
| 445 | } |
| 446 | db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid); |
| 447 | tktid = 0; |
| 448 | fields = fossil_malloc_zero( sizeof(fields[0]) * nField ); |
| 449 | db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid IN " |
| 450 | "(SELECT rid FROM tagxref WHERE tagid=%d)",BKLNK_TICKET, tagid); |
| 451 | db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid); |
| 452 | while( db_step(&q)==SQLITE_ROW ){ |
| 453 | int rid = db_column_int(&q, 0); |
| @@ -460,16 +466,24 @@ | |
| 460 | createFlag = 0; |
| 461 | } |
| 462 | db_finalize(&q); |
| 463 | /* Extract backlinks from the most recent values of TICKET fields */ |
| 464 | for(i=0; i<nField; i++){ |
| 465 | struct TicketField *f = fields + i; |
| 466 | if( f->zValue==0 ) continue; |
| 467 | backlink_extract(f->zValue,f->mimetype,f->rid,BKLNK_TICKET,f->mtime,0); |
| 468 | fossil_free(f->zValue); |
| 469 | } |
| 470 | fossil_free(fields); |
| 471 | } |
| 472 | |
| 473 | |
| 474 | /* |
| 475 | ** Create the TH1 interpreter and load the "common" code. |
| 476 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -232,11 +232,14 @@ | |
| 232 | for(i=0; (z = cgi_parameter_name(i))!=0; i++){ |
| 233 | Th_Store(z, P(z)); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | /* |
| 238 | ** Information about a single J-card |
| 239 | */ |
| 240 | struct jCardInfo { |
| 241 | char *zValue; |
| 242 | int mimetype; |
| 243 | int rid; |
| 244 | double mtime; |
| 245 | }; |
| @@ -250,11 +253,11 @@ | |
| 253 | ** Parameter rid is the recordID for the ticket artifact in the BLOB table. |
| 254 | ** |
| 255 | ** Return the new rowid of the TICKET table entry. |
| 256 | */ |
| 257 | static int ticket_insert(const Manifest *p, const int rid, int tktid, |
| 258 | Blob *fields){ |
| 259 | Blob sql1; /* update or replace TICKET ... */ |
| 260 | Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */ |
| 261 | Blob sql3; /* list of values which correspond to the previous list */ |
| 262 | Stmt q; |
| 263 | int i, j; |
| @@ -381,21 +384,24 @@ | |
| 384 | rid, BKLNK_TICKET, p->rDate, |
| 385 | /* existing backlinks must have been |
| 386 | * already deleted by the caller */ 0 ); |
| 387 | }else{ |
| 388 | /* update field's data with the most recent values */ |
| 389 | Blob *cards = fields + j; |
| 390 | struct jCardInfo card = { |
| 391 | fossil_strdup(p->aField[i].zValue), |
| 392 | mimetype_tkt, rid, p->rDate |
| 393 | }; |
| 394 | if( blob_size(cards) && zName[0]!='+' ){ |
| 395 | struct jCardInfo *x = (struct jCardInfo *)blob_buffer(cards); |
| 396 | struct jCardInfo *end = x + blob_count(cards,struct jCardInfo); |
| 397 | for(; x!=end; x++){ |
| 398 | fossil_free( x->zValue ); |
| 399 | } |
| 400 | blob_truncate(cards,0); |
| 401 | } |
| 402 | blob_append(cards, (const char*)(&card), sizeof(card)); |
| 403 | } |
| 404 | } |
| 405 | } |
| 406 | return tktid; |
| 407 | } |
| @@ -431,11 +437,11 @@ | |
| 437 | int tagid = tag_findid(zTag, 1); |
| 438 | Stmt q; |
| 439 | Manifest *pTicket; |
| 440 | int tktid, i; |
| 441 | int createFlag = 1; |
| 442 | Blob *fields; /* array of blobs; each blob holds array of jCardInfo */ |
| 443 | |
| 444 | fossil_free(zTag); |
| 445 | getAllTicketFields(); |
| 446 | if( haveTicket==0 ) return; |
| 447 | tktid = db_int(0, "SELECT tkt_id FROM ticket WHERE tkt_uuid=%Q", zTktUuid); |
| @@ -443,11 +449,11 @@ | |
| 449 | if( haveTicketChng ){ |
| 450 | db_multi_exec("DELETE FROM ticketchng WHERE tkt_id=%d;", tktid); |
| 451 | } |
| 452 | db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid); |
| 453 | tktid = 0; |
| 454 | fields = blobarray_new( nField ); |
| 455 | db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid IN " |
| 456 | "(SELECT rid FROM tagxref WHERE tagid=%d)",BKLNK_TICKET, tagid); |
| 457 | db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid); |
| 458 | while( db_step(&q)==SQLITE_ROW ){ |
| 459 | int rid = db_column_int(&q, 0); |
| @@ -460,16 +466,24 @@ | |
| 466 | createFlag = 0; |
| 467 | } |
| 468 | db_finalize(&q); |
| 469 | /* Extract backlinks from the most recent values of TICKET fields */ |
| 470 | for(i=0; i<nField; i++){ |
| 471 | Blob *cards = fields + i; |
| 472 | if( blob_size(cards) ){ |
| 473 | struct jCardInfo *x = (struct jCardInfo *)blob_buffer(cards); |
| 474 | struct jCardInfo *end = x + blob_count(cards,struct jCardInfo); |
| 475 | for(; x!=end; x++){ |
| 476 | assert( x->zValue ); |
| 477 | backlink_extract(x->zValue,x->mimetype, |
| 478 | x->rid,BKLNK_TICKET,x->mtime,0); |
| 479 | fossil_free( x->zValue ); |
| 480 | } |
| 481 | } |
| 482 | blob_truncate(cards,0); |
| 483 | } |
| 484 | blobarray_delete(fields,nField); |
| 485 | } |
| 486 | |
| 487 | |
| 488 | /* |
| 489 | ** Create the TH1 interpreter and load the "common" code. |
| 490 |