Fossil SCM
Track the origin of tags and display that origin in the tag and properities information field of the "vinfo" page. Must "fossil rebuild" after this change.
Commit
08db9e11cb6f86f943893cc154bc86c6285ec7ab
Parent
2fa4df1e47f17f1…
5 files changed
+34
+27
-19
+4
-5
+3
-2
+9
-11
+34
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -257,10 +257,44 @@ | ||
| 257 | 257 | timeline_query_for_www(), TAG_NEWBRANCH |
| 258 | 258 | ); |
| 259 | 259 | www_print_timeline(&q, 0, brlist_extra); |
| 260 | 260 | db_finalize(&q); |
| 261 | 261 | @ <br clear="both"> |
| 262 | + @ <script> | |
| 263 | + @ function xin(id){ | |
| 264 | + @ } | |
| 265 | + @ function xout(id){ | |
| 266 | + @ } | |
| 267 | + @ </script> | |
| 268 | + style_footer(); | |
| 269 | +} | |
| 270 | + | |
| 271 | +/* | |
| 272 | +** WEBPAGE: symtaglist | |
| 273 | +** | |
| 274 | +** Show a timeline of all check-ins that have a primary symbolic tag. | |
| 275 | +*/ | |
| 276 | +void symtaglist_page(void){ | |
| 277 | + Stmt q; | |
| 278 | + | |
| 279 | + login_check_credentials(); | |
| 280 | + if( !g.okRead ){ login_needed(); return; } | |
| 281 | + | |
| 282 | + style_header("Tagged Check-ins"); | |
| 283 | + login_anonymous_available(); | |
| 284 | + @ <h2>Check-ins that have one or more primary symbolic tags</h2> | |
| 285 | + db_prepare(&q, | |
| 286 | + "%s AND blob.rid IN (SELECT rid FROM tagxref" | |
| 287 | + " WHERE tagtype>1 AND srcid>0" | |
| 288 | + " AND tagid IN (SELECT tagid FROM tag " | |
| 289 | + " WHERE tagname GLOB 'sym-*'))" | |
| 290 | + " ORDER BY event.mtime DESC", | |
| 291 | + timeline_query_for_www(), TAG_NEWBRANCH | |
| 292 | + ); | |
| 293 | + www_print_timeline(&q, 0, 0); | |
| 294 | + db_finalize(&q); | |
| 295 | + @ <br clear="both"> | |
| 262 | 296 | @ <script> |
| 263 | 297 | @ function xin(id){ |
| 264 | 298 | @ } |
| 265 | 299 | @ function xout(id){ |
| 266 | 300 | @ } |
| 267 | 301 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -257,10 +257,44 @@ | |
| 257 | timeline_query_for_www(), TAG_NEWBRANCH |
| 258 | ); |
| 259 | www_print_timeline(&q, 0, brlist_extra); |
| 260 | db_finalize(&q); |
| 261 | @ <br clear="both"> |
| 262 | @ <script> |
| 263 | @ function xin(id){ |
| 264 | @ } |
| 265 | @ function xout(id){ |
| 266 | @ } |
| 267 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -257,10 +257,44 @@ | |
| 257 | timeline_query_for_www(), TAG_NEWBRANCH |
| 258 | ); |
| 259 | www_print_timeline(&q, 0, brlist_extra); |
| 260 | db_finalize(&q); |
| 261 | @ <br clear="both"> |
| 262 | @ <script> |
| 263 | @ function xin(id){ |
| 264 | @ } |
| 265 | @ function xout(id){ |
| 266 | @ } |
| 267 | @ </script> |
| 268 | style_footer(); |
| 269 | } |
| 270 | |
| 271 | /* |
| 272 | ** WEBPAGE: symtaglist |
| 273 | ** |
| 274 | ** Show a timeline of all check-ins that have a primary symbolic tag. |
| 275 | */ |
| 276 | void symtaglist_page(void){ |
| 277 | Stmt q; |
| 278 | |
| 279 | login_check_credentials(); |
| 280 | if( !g.okRead ){ login_needed(); return; } |
| 281 | |
| 282 | style_header("Tagged Check-ins"); |
| 283 | login_anonymous_available(); |
| 284 | @ <h2>Check-ins that have one or more primary symbolic tags</h2> |
| 285 | db_prepare(&q, |
| 286 | "%s AND blob.rid IN (SELECT rid FROM tagxref" |
| 287 | " WHERE tagtype>1 AND srcid>0" |
| 288 | " AND tagid IN (SELECT tagid FROM tag " |
| 289 | " WHERE tagname GLOB 'sym-*'))" |
| 290 | " ORDER BY event.mtime DESC", |
| 291 | timeline_query_for_www(), TAG_NEWBRANCH |
| 292 | ); |
| 293 | www_print_timeline(&q, 0, 0); |
| 294 | db_finalize(&q); |
| 295 | @ <br clear="both"> |
| 296 | @ <script> |
| 297 | @ function xin(id){ |
| 298 | @ } |
| 299 | @ function xout(id){ |
| 300 | @ } |
| 301 |
+27
-19
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -269,45 +269,53 @@ | ||
| 269 | 269 | */ |
| 270 | 270 | static void showTags(int rid, const char *zNotGlob){ |
| 271 | 271 | Stmt q; |
| 272 | 272 | int cnt = 0; |
| 273 | 273 | db_prepare(&q, |
| 274 | - "SELECT tag.tagid, tagname, srcid, blob.uuid, value," | |
| 275 | - " datetime(tagxref.mtime,'localtime'), tagtype" | |
| 274 | + "SELECT tag.tagid, tagname, " | |
| 275 | + " (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d)," | |
| 276 | + " value, datetime(tagxref.mtime,'localtime'), tagtype," | |
| 277 | + " (SELECT uuid FROM blob WHERE rid=tagxref.origid)" | |
| 276 | 278 | " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" |
| 277 | - " LEFT JOIN blob ON blob.rid=tagxref.srcid" | |
| 278 | 279 | " WHERE tagxref.rid=%d AND tagname NOT GLOB '%s'" |
| 279 | - " ORDER BY tagname", rid, zNotGlob | |
| 280 | + " ORDER BY tagname", rid, rid, zNotGlob | |
| 280 | 281 | ); |
| 281 | 282 | while( db_step(&q)==SQLITE_ROW ){ |
| 282 | 283 | const char *zTagname = db_column_text(&q, 1); |
| 283 | - int srcid = db_column_int(&q, 2); | |
| 284 | - const char *zUuid = db_column_text(&q, 3); | |
| 285 | - const char *zValue = db_column_text(&q, 4); | |
| 286 | - const char *zDate = db_column_text(&q, 5); | |
| 287 | - int tagtype = db_column_int(&q, 6); | |
| 284 | + const char *zSrcUuid = db_column_text(&q, 2); | |
| 285 | + const char *zValue = db_column_text(&q, 3); | |
| 286 | + const char *zDate = db_column_text(&q, 4); | |
| 287 | + int tagtype = db_column_int(&q, 5); | |
| 288 | + const char *zOrigUuid = db_column_text(&q, 6); | |
| 288 | 289 | cnt++; |
| 289 | 290 | if( cnt==1 ){ |
| 290 | 291 | @ <div class="section">Tags And Properties</div> |
| 291 | 292 | @ <ul> |
| 292 | 293 | } |
| 293 | 294 | @ <li> |
| 294 | 295 | @ <b>%h(zTagname)</b> |
| 295 | - if( zValue ){ | |
| 296 | + if( tagtype==0 ){ | |
| 297 | + @ <i>cancelled. | |
| 298 | + }else if( zValue ){ | |
| 296 | 299 | @ = %h(zValue)<i> |
| 297 | - }else if( tagtype==0 ){ | |
| 298 | - @ <i>Cancelled | |
| 299 | - }else{ | |
| 300 | + }else { | |
| 300 | 301 | @ <i> |
| 301 | 302 | } |
| 302 | - if( srcid==0 ){ | |
| 303 | - @ Inherited | |
| 304 | - }else if( zUuid ){ | |
| 305 | - @ From | |
| 306 | - hyperlink_to_uuid(zUuid); | |
| 303 | + if( tagtype==2 ){ | |
| 304 | + if( zOrigUuid && zOrigUuid[0] ){ | |
| 305 | + @ inherited from | |
| 306 | + hyperlink_to_uuid(zOrigUuid); | |
| 307 | + }else{ | |
| 308 | + @ propagates to descendants | |
| 309 | + } | |
| 310 | + } | |
| 311 | + if( zSrcUuid && zSrcUuid[0] ){ | |
| 312 | + @ added by | |
| 313 | + hyperlink_to_uuid(zSrcUuid); | |
| 314 | + @ on %s(zDate) | |
| 307 | 315 | } |
| 308 | - @ on %s(zDate)</i> | |
| 316 | + @ </i> | |
| 309 | 317 | } |
| 310 | 318 | db_finalize(&q); |
| 311 | 319 | if( cnt ){ |
| 312 | 320 | @ </ul> |
| 313 | 321 | } |
| 314 | 322 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -269,45 +269,53 @@ | |
| 269 | */ |
| 270 | static void showTags(int rid, const char *zNotGlob){ |
| 271 | Stmt q; |
| 272 | int cnt = 0; |
| 273 | db_prepare(&q, |
| 274 | "SELECT tag.tagid, tagname, srcid, blob.uuid, value," |
| 275 | " datetime(tagxref.mtime,'localtime'), tagtype" |
| 276 | " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" |
| 277 | " LEFT JOIN blob ON blob.rid=tagxref.srcid" |
| 278 | " WHERE tagxref.rid=%d AND tagname NOT GLOB '%s'" |
| 279 | " ORDER BY tagname", rid, zNotGlob |
| 280 | ); |
| 281 | while( db_step(&q)==SQLITE_ROW ){ |
| 282 | const char *zTagname = db_column_text(&q, 1); |
| 283 | int srcid = db_column_int(&q, 2); |
| 284 | const char *zUuid = db_column_text(&q, 3); |
| 285 | const char *zValue = db_column_text(&q, 4); |
| 286 | const char *zDate = db_column_text(&q, 5); |
| 287 | int tagtype = db_column_int(&q, 6); |
| 288 | cnt++; |
| 289 | if( cnt==1 ){ |
| 290 | @ <div class="section">Tags And Properties</div> |
| 291 | @ <ul> |
| 292 | } |
| 293 | @ <li> |
| 294 | @ <b>%h(zTagname)</b> |
| 295 | if( zValue ){ |
| 296 | @ = %h(zValue)<i> |
| 297 | }else if( tagtype==0 ){ |
| 298 | @ <i>Cancelled |
| 299 | }else{ |
| 300 | @ <i> |
| 301 | } |
| 302 | if( srcid==0 ){ |
| 303 | @ Inherited |
| 304 | }else if( zUuid ){ |
| 305 | @ From |
| 306 | hyperlink_to_uuid(zUuid); |
| 307 | } |
| 308 | @ on %s(zDate)</i> |
| 309 | } |
| 310 | db_finalize(&q); |
| 311 | if( cnt ){ |
| 312 | @ </ul> |
| 313 | } |
| 314 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -269,45 +269,53 @@ | |
| 269 | */ |
| 270 | static void showTags(int rid, const char *zNotGlob){ |
| 271 | Stmt q; |
| 272 | int cnt = 0; |
| 273 | db_prepare(&q, |
| 274 | "SELECT tag.tagid, tagname, " |
| 275 | " (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d)," |
| 276 | " value, datetime(tagxref.mtime,'localtime'), tagtype," |
| 277 | " (SELECT uuid FROM blob WHERE rid=tagxref.origid)" |
| 278 | " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" |
| 279 | " WHERE tagxref.rid=%d AND tagname NOT GLOB '%s'" |
| 280 | " ORDER BY tagname", rid, rid, zNotGlob |
| 281 | ); |
| 282 | while( db_step(&q)==SQLITE_ROW ){ |
| 283 | const char *zTagname = db_column_text(&q, 1); |
| 284 | const char *zSrcUuid = db_column_text(&q, 2); |
| 285 | const char *zValue = db_column_text(&q, 3); |
| 286 | const char *zDate = db_column_text(&q, 4); |
| 287 | int tagtype = db_column_int(&q, 5); |
| 288 | const char *zOrigUuid = db_column_text(&q, 6); |
| 289 | cnt++; |
| 290 | if( cnt==1 ){ |
| 291 | @ <div class="section">Tags And Properties</div> |
| 292 | @ <ul> |
| 293 | } |
| 294 | @ <li> |
| 295 | @ <b>%h(zTagname)</b> |
| 296 | if( tagtype==0 ){ |
| 297 | @ <i>cancelled. |
| 298 | }else if( zValue ){ |
| 299 | @ = %h(zValue)<i> |
| 300 | }else { |
| 301 | @ <i> |
| 302 | } |
| 303 | if( tagtype==2 ){ |
| 304 | if( zOrigUuid && zOrigUuid[0] ){ |
| 305 | @ inherited from |
| 306 | hyperlink_to_uuid(zOrigUuid); |
| 307 | }else{ |
| 308 | @ propagates to descendants |
| 309 | } |
| 310 | } |
| 311 | if( zSrcUuid && zSrcUuid[0] ){ |
| 312 | @ added by |
| 313 | hyperlink_to_uuid(zSrcUuid); |
| 314 | @ on %s(zDate) |
| 315 | } |
| 316 | @ </i> |
| 317 | } |
| 318 | db_finalize(&q); |
| 319 | if( cnt ){ |
| 320 | @ </ul> |
| 321 | } |
| 322 |
+4
-5
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -501,11 +501,11 @@ | ||
| 501 | 501 | zUuid = 0; |
| 502 | 502 | }else{ |
| 503 | 503 | goto manifest_syntax_error; |
| 504 | 504 | } |
| 505 | 505 | defossilize(zName); |
| 506 | - if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' && zName[0]!='0' ){ | |
| 506 | + if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){ | |
| 507 | 507 | goto manifest_syntax_error; |
| 508 | 508 | } |
| 509 | 509 | if( validate16(&zName[1], strlen(&zName[1])) ){ |
| 510 | 510 | /* Do not allow tags whose names look like UUIDs */ |
| 511 | 511 | goto manifest_syntax_error; |
| @@ -948,14 +948,13 @@ | ||
| 948 | 948 | }else{ |
| 949 | 949 | tid = rid; |
| 950 | 950 | } |
| 951 | 951 | if( tid ){ |
| 952 | 952 | switch( m.aTag[i].zName[0] ){ |
| 953 | - case '+': type = 1; break; | |
| 954 | - case '*': type = 2; break; | |
| 955 | - case '-': type = 0; break; | |
| 956 | - case '0': type = -1; break; | |
| 953 | + case '-': type = 0; break; /* Cancel prior occurances */ | |
| 954 | + case '+': type = 1; break; /* Apply to target only */ | |
| 955 | + case '*': type = 2; break; /* Propagate to descendants */ | |
| 957 | 956 | default: |
| 958 | 957 | fossil_fatal("unknown tag type in manifest: %s", m.aTag); |
| 959 | 958 | return 0; |
| 960 | 959 | } |
| 961 | 960 | tag_insert(&m.aTag[i].zName[1], type, m.aTag[i].zValue, |
| 962 | 961 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -501,11 +501,11 @@ | |
| 501 | zUuid = 0; |
| 502 | }else{ |
| 503 | goto manifest_syntax_error; |
| 504 | } |
| 505 | defossilize(zName); |
| 506 | if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' && zName[0]!='0' ){ |
| 507 | goto manifest_syntax_error; |
| 508 | } |
| 509 | if( validate16(&zName[1], strlen(&zName[1])) ){ |
| 510 | /* Do not allow tags whose names look like UUIDs */ |
| 511 | goto manifest_syntax_error; |
| @@ -948,14 +948,13 @@ | |
| 948 | }else{ |
| 949 | tid = rid; |
| 950 | } |
| 951 | if( tid ){ |
| 952 | switch( m.aTag[i].zName[0] ){ |
| 953 | case '+': type = 1; break; |
| 954 | case '*': type = 2; break; |
| 955 | case '-': type = 0; break; |
| 956 | case '0': type = -1; break; |
| 957 | default: |
| 958 | fossil_fatal("unknown tag type in manifest: %s", m.aTag); |
| 959 | return 0; |
| 960 | } |
| 961 | tag_insert(&m.aTag[i].zName[1], type, m.aTag[i].zValue, |
| 962 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -501,11 +501,11 @@ | |
| 501 | zUuid = 0; |
| 502 | }else{ |
| 503 | goto manifest_syntax_error; |
| 504 | } |
| 505 | defossilize(zName); |
| 506 | if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){ |
| 507 | goto manifest_syntax_error; |
| 508 | } |
| 509 | if( validate16(&zName[1], strlen(&zName[1])) ){ |
| 510 | /* Do not allow tags whose names look like UUIDs */ |
| 511 | goto manifest_syntax_error; |
| @@ -948,14 +948,13 @@ | |
| 948 | }else{ |
| 949 | tid = rid; |
| 950 | } |
| 951 | if( tid ){ |
| 952 | switch( m.aTag[i].zName[0] ){ |
| 953 | case '-': type = 0; break; /* Cancel prior occurances */ |
| 954 | case '+': type = 1; break; /* Apply to target only */ |
| 955 | case '*': type = 2; break; /* Propagate to descendants */ |
| 956 | default: |
| 957 | fossil_fatal("unknown tag type in manifest: %s", m.aTag); |
| 958 | return 0; |
| 959 | } |
| 960 | tag_insert(&m.aTag[i].zName[1], type, m.aTag[i].zValue, |
| 961 |
+3
-2
| --- src/schema.c | ||
| +++ src/schema.c | ||
| @@ -290,14 +290,15 @@ | ||
| 290 | 290 | @ -- keep calling them tags because in many cases the value is ignored. |
| 291 | 291 | @ -- |
| 292 | 292 | @ CREATE TABLE tagxref( |
| 293 | 293 | @ tagid INTEGER REFERENCES tag, -- The tag that added or removed |
| 294 | 294 | @ tagtype INTEGER, -- 0:cancel 1:single 2:branch |
| 295 | -@ srcid INTEGER REFERENCES blob, -- Origin of the tag. 0 for propagated tags | |
| 295 | +@ srcid INTEGER REFERENCES blob, -- Artifact of tag. 0 for propagated tags | |
| 296 | +@ origid INTEGER REFERENCES blob, -- check-in holding propagated tag | |
| 296 | 297 | @ value TEXT, -- Value of the tag. Might be NULL. |
| 297 | 298 | @ mtime TIMESTAMP, -- Time of addition or removal |
| 298 | -@ rid INTEGER REFERENCE blob, -- Baseline that tag added/removed from | |
| 299 | +@ rid INTEGER REFERENCE blob, -- Artifact tag is applied to | |
| 299 | 300 | @ UNIQUE(rid, tagid) |
| 300 | 301 | @ ); |
| 301 | 302 | @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); |
| 302 | 303 | @ |
| 303 | 304 | @ -- Template for the TICKET table |
| 304 | 305 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -290,14 +290,15 @@ | |
| 290 | @ -- keep calling them tags because in many cases the value is ignored. |
| 291 | @ -- |
| 292 | @ CREATE TABLE tagxref( |
| 293 | @ tagid INTEGER REFERENCES tag, -- The tag that added or removed |
| 294 | @ tagtype INTEGER, -- 0:cancel 1:single 2:branch |
| 295 | @ srcid INTEGER REFERENCES blob, -- Origin of the tag. 0 for propagated tags |
| 296 | @ value TEXT, -- Value of the tag. Might be NULL. |
| 297 | @ mtime TIMESTAMP, -- Time of addition or removal |
| 298 | @ rid INTEGER REFERENCE blob, -- Baseline that tag added/removed from |
| 299 | @ UNIQUE(rid, tagid) |
| 300 | @ ); |
| 301 | @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); |
| 302 | @ |
| 303 | @ -- Template for the TICKET table |
| 304 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -290,14 +290,15 @@ | |
| 290 | @ -- keep calling them tags because in many cases the value is ignored. |
| 291 | @ -- |
| 292 | @ CREATE TABLE tagxref( |
| 293 | @ tagid INTEGER REFERENCES tag, -- The tag that added or removed |
| 294 | @ tagtype INTEGER, -- 0:cancel 1:single 2:branch |
| 295 | @ srcid INTEGER REFERENCES blob, -- Artifact of tag. 0 for propagated tags |
| 296 | @ origid INTEGER REFERENCES blob, -- check-in holding propagated tag |
| 297 | @ value TEXT, -- Value of the tag. Might be NULL. |
| 298 | @ mtime TIMESTAMP, -- Time of addition or removal |
| 299 | @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to |
| 300 | @ UNIQUE(rid, tagid) |
| 301 | @ ); |
| 302 | @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); |
| 303 | @ |
| 304 | @ -- Template for the TICKET table |
| 305 |
+9
-11
| --- src/tag.c | ||
| +++ src/tag.c | ||
| @@ -39,10 +39,11 @@ | ||
| 39 | 39 | */ |
| 40 | 40 | void tag_propagate( |
| 41 | 41 | int pid, /* Propagate the tag to children of this node */ |
| 42 | 42 | int tagid, /* Tag to propagate */ |
| 43 | 43 | int tagType, /* 2 for a propagating tag. 0 for an antitag */ |
| 44 | + int origId, /* Artifact of tag, when tagType==2 */ | |
| 44 | 45 | const char *zValue, /* Value of the tag. Might be NULL */ |
| 45 | 46 | double mtime /* Timestamp on the tag */ |
| 46 | 47 | ){ |
| 47 | 48 | PQueue queue; |
| 48 | 49 | Stmt s, ins, eventupdate; |
| @@ -58,13 +59,13 @@ | ||
| 58 | 59 | tagType!=0, tagid |
| 59 | 60 | ); |
| 60 | 61 | db_bind_double(&s, ":mtime", mtime); |
| 61 | 62 | if( tagType==2 ){ |
| 62 | 63 | db_prepare(&ins, |
| 63 | - "REPLACE INTO tagxref(tagid, tagtype, srcid, value, mtime, rid)" | |
| 64 | - "VALUES(%d,2,0,%Q,:mtime,:rid)", | |
| 65 | - tagid, zValue | |
| 64 | + "REPLACE INTO tagxref(tagid, tagtype, srcid, origid, value, mtime, rid)" | |
| 65 | + "VALUES(%d,2,0,%d,%Q,:mtime,:rid)", | |
| 66 | + tagid, origId, zValue | |
| 66 | 67 | ); |
| 67 | 68 | db_bind_double(&ins, ":mtime", mtime); |
| 68 | 69 | }else{ |
| 69 | 70 | zValue = 0; |
| 70 | 71 | db_prepare(&ins, |
| @@ -108,21 +109,22 @@ | ||
| 108 | 109 | ** Propagate all propagatable tags in pid to its children. |
| 109 | 110 | */ |
| 110 | 111 | void tag_propagate_all(int pid){ |
| 111 | 112 | Stmt q; |
| 112 | 113 | db_prepare(&q, |
| 113 | - "SELECT tagid, tagtype, mtime, value FROM tagxref" | |
| 114 | + "SELECT tagid, tagtype, mtime, value, origid FROM tagxref" | |
| 114 | 115 | " WHERE rid=%d" |
| 115 | 116 | " AND (tagtype=0 OR tagtype=2)", |
| 116 | 117 | pid |
| 117 | 118 | ); |
| 118 | 119 | while( db_step(&q)==SQLITE_ROW ){ |
| 119 | 120 | int tagid = db_column_int(&q, 0); |
| 120 | 121 | int tagtype = db_column_int(&q, 1); |
| 121 | 122 | double mtime = db_column_double(&q, 2); |
| 122 | 123 | const char *zValue = db_column_text(&q, 3); |
| 123 | - tag_propagate(pid, tagid, tagtype, zValue, mtime); | |
| 124 | + int origid = db_column_int(&q, 4); | |
| 125 | + tag_propagate(pid, tagid, tagtype, origid, zValue, mtime); | |
| 124 | 126 | } |
| 125 | 127 | db_finalize(&q); |
| 126 | 128 | } |
| 127 | 129 | |
| 128 | 130 | /* |
| @@ -142,11 +144,11 @@ | ||
| 142 | 144 | /* |
| 143 | 145 | ** Insert a tag into the database. |
| 144 | 146 | */ |
| 145 | 147 | void tag_insert( |
| 146 | 148 | const char *zTag, /* Name of the tag (w/o the "+" or "-" prefix */ |
| 147 | - int tagtype, /* 0:cancel 1:singleton 2:propagated -1:erase */ | |
| 149 | + int tagtype, /* 0:cancel 1:singleton 2:propagated */ | |
| 148 | 150 | const char *zValue, /* Value if the tag is really a property */ |
| 149 | 151 | int srcId, /* Artifact that contains this tag */ |
| 150 | 152 | double mtime, /* Timestamp. Use default if <=0.0 */ |
| 151 | 153 | int rid /* Artifact to which the tag is to attached */ |
| 152 | 154 | ){ |
| @@ -170,14 +172,10 @@ | ||
| 170 | 172 | db_finalize(&s); |
| 171 | 173 | if( rc==SQLITE_ROW ){ |
| 172 | 174 | /* Another entry that is more recent already exists. Do nothing */ |
| 173 | 175 | return; |
| 174 | 176 | } |
| 175 | - if( tagtype<0 ){ | |
| 176 | - return; | |
| 177 | - /* TBD: erase tags */ | |
| 178 | - } | |
| 179 | 177 | db_prepare(&s, |
| 180 | 178 | "REPLACE INTO tagxref(tagid,tagtype,srcId,value,mtime,rid)" |
| 181 | 179 | " VALUES(%d,%d,%d,%Q,:mtime,%d)", |
| 182 | 180 | tagid, tagtype, srcId, zValue, rid |
| 183 | 181 | ); |
| @@ -204,11 +202,11 @@ | ||
| 204 | 202 | } |
| 205 | 203 | if( zCol ){ |
| 206 | 204 | db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid); |
| 207 | 205 | } |
| 208 | 206 | if( tagtype==0 || tagtype==2 ){ |
| 209 | - tag_propagate(rid, tagid, tagtype, zValue, mtime); | |
| 207 | + tag_propagate(rid, tagid, tagtype, rid, zValue, mtime); | |
| 210 | 208 | } |
| 211 | 209 | } |
| 212 | 210 | |
| 213 | 211 | |
| 214 | 212 | /* |
| 215 | 213 |
| --- src/tag.c | |
| +++ src/tag.c | |
| @@ -39,10 +39,11 @@ | |
| 39 | */ |
| 40 | void tag_propagate( |
| 41 | int pid, /* Propagate the tag to children of this node */ |
| 42 | int tagid, /* Tag to propagate */ |
| 43 | int tagType, /* 2 for a propagating tag. 0 for an antitag */ |
| 44 | const char *zValue, /* Value of the tag. Might be NULL */ |
| 45 | double mtime /* Timestamp on the tag */ |
| 46 | ){ |
| 47 | PQueue queue; |
| 48 | Stmt s, ins, eventupdate; |
| @@ -58,13 +59,13 @@ | |
| 58 | tagType!=0, tagid |
| 59 | ); |
| 60 | db_bind_double(&s, ":mtime", mtime); |
| 61 | if( tagType==2 ){ |
| 62 | db_prepare(&ins, |
| 63 | "REPLACE INTO tagxref(tagid, tagtype, srcid, value, mtime, rid)" |
| 64 | "VALUES(%d,2,0,%Q,:mtime,:rid)", |
| 65 | tagid, zValue |
| 66 | ); |
| 67 | db_bind_double(&ins, ":mtime", mtime); |
| 68 | }else{ |
| 69 | zValue = 0; |
| 70 | db_prepare(&ins, |
| @@ -108,21 +109,22 @@ | |
| 108 | ** Propagate all propagatable tags in pid to its children. |
| 109 | */ |
| 110 | void tag_propagate_all(int pid){ |
| 111 | Stmt q; |
| 112 | db_prepare(&q, |
| 113 | "SELECT tagid, tagtype, mtime, value FROM tagxref" |
| 114 | " WHERE rid=%d" |
| 115 | " AND (tagtype=0 OR tagtype=2)", |
| 116 | pid |
| 117 | ); |
| 118 | while( db_step(&q)==SQLITE_ROW ){ |
| 119 | int tagid = db_column_int(&q, 0); |
| 120 | int tagtype = db_column_int(&q, 1); |
| 121 | double mtime = db_column_double(&q, 2); |
| 122 | const char *zValue = db_column_text(&q, 3); |
| 123 | tag_propagate(pid, tagid, tagtype, zValue, mtime); |
| 124 | } |
| 125 | db_finalize(&q); |
| 126 | } |
| 127 | |
| 128 | /* |
| @@ -142,11 +144,11 @@ | |
| 142 | /* |
| 143 | ** Insert a tag into the database. |
| 144 | */ |
| 145 | void tag_insert( |
| 146 | const char *zTag, /* Name of the tag (w/o the "+" or "-" prefix */ |
| 147 | int tagtype, /* 0:cancel 1:singleton 2:propagated -1:erase */ |
| 148 | const char *zValue, /* Value if the tag is really a property */ |
| 149 | int srcId, /* Artifact that contains this tag */ |
| 150 | double mtime, /* Timestamp. Use default if <=0.0 */ |
| 151 | int rid /* Artifact to which the tag is to attached */ |
| 152 | ){ |
| @@ -170,14 +172,10 @@ | |
| 170 | db_finalize(&s); |
| 171 | if( rc==SQLITE_ROW ){ |
| 172 | /* Another entry that is more recent already exists. Do nothing */ |
| 173 | return; |
| 174 | } |
| 175 | if( tagtype<0 ){ |
| 176 | return; |
| 177 | /* TBD: erase tags */ |
| 178 | } |
| 179 | db_prepare(&s, |
| 180 | "REPLACE INTO tagxref(tagid,tagtype,srcId,value,mtime,rid)" |
| 181 | " VALUES(%d,%d,%d,%Q,:mtime,%d)", |
| 182 | tagid, tagtype, srcId, zValue, rid |
| 183 | ); |
| @@ -204,11 +202,11 @@ | |
| 204 | } |
| 205 | if( zCol ){ |
| 206 | db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid); |
| 207 | } |
| 208 | if( tagtype==0 || tagtype==2 ){ |
| 209 | tag_propagate(rid, tagid, tagtype, zValue, mtime); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | |
| 214 | /* |
| 215 |
| --- src/tag.c | |
| +++ src/tag.c | |
| @@ -39,10 +39,11 @@ | |
| 39 | */ |
| 40 | void tag_propagate( |
| 41 | int pid, /* Propagate the tag to children of this node */ |
| 42 | int tagid, /* Tag to propagate */ |
| 43 | int tagType, /* 2 for a propagating tag. 0 for an antitag */ |
| 44 | int origId, /* Artifact of tag, when tagType==2 */ |
| 45 | const char *zValue, /* Value of the tag. Might be NULL */ |
| 46 | double mtime /* Timestamp on the tag */ |
| 47 | ){ |
| 48 | PQueue queue; |
| 49 | Stmt s, ins, eventupdate; |
| @@ -58,13 +59,13 @@ | |
| 59 | tagType!=0, tagid |
| 60 | ); |
| 61 | db_bind_double(&s, ":mtime", mtime); |
| 62 | if( tagType==2 ){ |
| 63 | db_prepare(&ins, |
| 64 | "REPLACE INTO tagxref(tagid, tagtype, srcid, origid, value, mtime, rid)" |
| 65 | "VALUES(%d,2,0,%d,%Q,:mtime,:rid)", |
| 66 | tagid, origId, zValue |
| 67 | ); |
| 68 | db_bind_double(&ins, ":mtime", mtime); |
| 69 | }else{ |
| 70 | zValue = 0; |
| 71 | db_prepare(&ins, |
| @@ -108,21 +109,22 @@ | |
| 109 | ** Propagate all propagatable tags in pid to its children. |
| 110 | */ |
| 111 | void tag_propagate_all(int pid){ |
| 112 | Stmt q; |
| 113 | db_prepare(&q, |
| 114 | "SELECT tagid, tagtype, mtime, value, origid FROM tagxref" |
| 115 | " WHERE rid=%d" |
| 116 | " AND (tagtype=0 OR tagtype=2)", |
| 117 | pid |
| 118 | ); |
| 119 | while( db_step(&q)==SQLITE_ROW ){ |
| 120 | int tagid = db_column_int(&q, 0); |
| 121 | int tagtype = db_column_int(&q, 1); |
| 122 | double mtime = db_column_double(&q, 2); |
| 123 | const char *zValue = db_column_text(&q, 3); |
| 124 | int origid = db_column_int(&q, 4); |
| 125 | tag_propagate(pid, tagid, tagtype, origid, zValue, mtime); |
| 126 | } |
| 127 | db_finalize(&q); |
| 128 | } |
| 129 | |
| 130 | /* |
| @@ -142,11 +144,11 @@ | |
| 144 | /* |
| 145 | ** Insert a tag into the database. |
| 146 | */ |
| 147 | void tag_insert( |
| 148 | const char *zTag, /* Name of the tag (w/o the "+" or "-" prefix */ |
| 149 | int tagtype, /* 0:cancel 1:singleton 2:propagated */ |
| 150 | const char *zValue, /* Value if the tag is really a property */ |
| 151 | int srcId, /* Artifact that contains this tag */ |
| 152 | double mtime, /* Timestamp. Use default if <=0.0 */ |
| 153 | int rid /* Artifact to which the tag is to attached */ |
| 154 | ){ |
| @@ -170,14 +172,10 @@ | |
| 172 | db_finalize(&s); |
| 173 | if( rc==SQLITE_ROW ){ |
| 174 | /* Another entry that is more recent already exists. Do nothing */ |
| 175 | return; |
| 176 | } |
| 177 | db_prepare(&s, |
| 178 | "REPLACE INTO tagxref(tagid,tagtype,srcId,value,mtime,rid)" |
| 179 | " VALUES(%d,%d,%d,%Q,:mtime,%d)", |
| 180 | tagid, tagtype, srcId, zValue, rid |
| 181 | ); |
| @@ -204,11 +202,11 @@ | |
| 202 | } |
| 203 | if( zCol ){ |
| 204 | db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid); |
| 205 | } |
| 206 | if( tagtype==0 || tagtype==2 ){ |
| 207 | tag_propagate(rid, tagid, tagtype, rid, zValue, mtime); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | |
| 212 | /* |
| 213 |