Fossil SCM
Correct issue with open/closed tags by changing the closed column to a quasi-aggregate query, i.e. one which is a function of the argument to GROUP BY and not anything which varies within the group. This gives consistent results with the baseline branch ls command, but it introduces a MAJOR performance regression. Listing closed tags goes from 0.033s in the baseline to 1.882s, i.e. it takes 56 times longer.
Commit
b302f8935211984ec6e8801059f003cb959555ad
Parent
4e7d2ce121adf0c…
1 file changed
+14
-4
+14
-4
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -198,15 +198,25 @@ | ||
| 198 | 198 | */ |
| 199 | 199 | void branch_prepare_list_query(Stmt *pQuery, int brFlags){ |
| 200 | 200 | Blob sql = BLOB_INITIALIZER; |
| 201 | 201 | blob_zero(&sql); |
| 202 | 202 | |
| 203 | - /* Begin the query. */ | |
| 203 | + /* Begin the query. | |
| 204 | + * | |
| 205 | + * A branch is closed if it has no open leaves, where an open leaf is one not | |
| 206 | + * referenced by a closed tag. The design of the "closed" expression reflects | |
| 207 | + * this double negative logical structure. */ | |
| 204 | 208 | blob_append_sql(&sql, |
| 205 | 209 | "SELECT tagxref.value AS name" |
| 206 | 210 | ", max(event.mtime) AS mtime" |
| 207 | - ", %z AS closed" | |
| 211 | + ", NOT EXISTS" | |
| 212 | + " (SELECT 1" | |
| 213 | + " FROM tagxref AS tx1" | |
| 214 | + " WHERE value=tagxref.value" | |
| 215 | + " AND tagid=%d" | |
| 216 | + " AND rid IN leaf" | |
| 217 | + " AND NOT %z) AS closed" | |
| 208 | 218 | ", (SELECT tagxref.value" |
| 209 | 219 | " FROM plink CROSS JOIN tagxref" |
| 210 | 220 | " WHERE plink.pid=event.objid" |
| 211 | 221 | " AND tagxref.rid=plink.cid" |
| 212 | 222 | " AND tagxref.tagid=%d" |
| @@ -217,11 +227,11 @@ | ||
| 217 | 227 | " FROM tagxref, tag, event" |
| 218 | 228 | " WHERE tagxref.tagid=tag.tagid" |
| 219 | 229 | " AND tagxref.tagtype>0" |
| 220 | 230 | " AND tag.tagname='branch'" |
| 221 | 231 | " AND event.objid=tagxref.rid", |
| 222 | - leaf_is_closed_sql("tagxref.rid"), TAG_BRANCH); | |
| 232 | + TAG_BRANCH, leaf_is_closed_sql("tx1.rid"), TAG_BRANCH); | |
| 223 | 233 | |
| 224 | 234 | /* Group by name to implement the cicount column. */ |
| 225 | 235 | blob_append_sql(&sql, " GROUP BY name"); |
| 226 | 236 | |
| 227 | 237 | /* Apply open/closed filtering if requested. */ |
| @@ -375,11 +385,11 @@ | ||
| 375 | 385 | @ <thead><tr> |
| 376 | 386 | @ <th>Branch Name</th> |
| 377 | 387 | @ <th>Age</th> |
| 378 | 388 | @ <th>Check-ins</th> |
| 379 | 389 | if( (flags & BRL_OPEN_CLOSED_MASK) == BRL_BOTH ){ |
| 380 | - @ <th>Status</th> | |
| 390 | + @ <th>Status</th> | |
| 381 | 391 | } |
| 382 | 392 | @ <th>Resolution</th> |
| 383 | 393 | @ </tr></thead><tbody> |
| 384 | 394 | while( db_step(&q)==SQLITE_ROW ){ |
| 385 | 395 | const char *zBranch = db_column_text(&q, 0); |
| 386 | 396 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -198,15 +198,25 @@ | |
| 198 | */ |
| 199 | void branch_prepare_list_query(Stmt *pQuery, int brFlags){ |
| 200 | Blob sql = BLOB_INITIALIZER; |
| 201 | blob_zero(&sql); |
| 202 | |
| 203 | /* Begin the query. */ |
| 204 | blob_append_sql(&sql, |
| 205 | "SELECT tagxref.value AS name" |
| 206 | ", max(event.mtime) AS mtime" |
| 207 | ", %z AS closed" |
| 208 | ", (SELECT tagxref.value" |
| 209 | " FROM plink CROSS JOIN tagxref" |
| 210 | " WHERE plink.pid=event.objid" |
| 211 | " AND tagxref.rid=plink.cid" |
| 212 | " AND tagxref.tagid=%d" |
| @@ -217,11 +227,11 @@ | |
| 217 | " FROM tagxref, tag, event" |
| 218 | " WHERE tagxref.tagid=tag.tagid" |
| 219 | " AND tagxref.tagtype>0" |
| 220 | " AND tag.tagname='branch'" |
| 221 | " AND event.objid=tagxref.rid", |
| 222 | leaf_is_closed_sql("tagxref.rid"), TAG_BRANCH); |
| 223 | |
| 224 | /* Group by name to implement the cicount column. */ |
| 225 | blob_append_sql(&sql, " GROUP BY name"); |
| 226 | |
| 227 | /* Apply open/closed filtering if requested. */ |
| @@ -375,11 +385,11 @@ | |
| 375 | @ <thead><tr> |
| 376 | @ <th>Branch Name</th> |
| 377 | @ <th>Age</th> |
| 378 | @ <th>Check-ins</th> |
| 379 | if( (flags & BRL_OPEN_CLOSED_MASK) == BRL_BOTH ){ |
| 380 | @ <th>Status</th> |
| 381 | } |
| 382 | @ <th>Resolution</th> |
| 383 | @ </tr></thead><tbody> |
| 384 | while( db_step(&q)==SQLITE_ROW ){ |
| 385 | const char *zBranch = db_column_text(&q, 0); |
| 386 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -198,15 +198,25 @@ | |
| 198 | */ |
| 199 | void branch_prepare_list_query(Stmt *pQuery, int brFlags){ |
| 200 | Blob sql = BLOB_INITIALIZER; |
| 201 | blob_zero(&sql); |
| 202 | |
| 203 | /* Begin the query. |
| 204 | * |
| 205 | * A branch is closed if it has no open leaves, where an open leaf is one not |
| 206 | * referenced by a closed tag. The design of the "closed" expression reflects |
| 207 | * this double negative logical structure. */ |
| 208 | blob_append_sql(&sql, |
| 209 | "SELECT tagxref.value AS name" |
| 210 | ", max(event.mtime) AS mtime" |
| 211 | ", NOT EXISTS" |
| 212 | " (SELECT 1" |
| 213 | " FROM tagxref AS tx1" |
| 214 | " WHERE value=tagxref.value" |
| 215 | " AND tagid=%d" |
| 216 | " AND rid IN leaf" |
| 217 | " AND NOT %z) AS closed" |
| 218 | ", (SELECT tagxref.value" |
| 219 | " FROM plink CROSS JOIN tagxref" |
| 220 | " WHERE plink.pid=event.objid" |
| 221 | " AND tagxref.rid=plink.cid" |
| 222 | " AND tagxref.tagid=%d" |
| @@ -217,11 +227,11 @@ | |
| 227 | " FROM tagxref, tag, event" |
| 228 | " WHERE tagxref.tagid=tag.tagid" |
| 229 | " AND tagxref.tagtype>0" |
| 230 | " AND tag.tagname='branch'" |
| 231 | " AND event.objid=tagxref.rid", |
| 232 | TAG_BRANCH, leaf_is_closed_sql("tx1.rid"), TAG_BRANCH); |
| 233 | |
| 234 | /* Group by name to implement the cicount column. */ |
| 235 | blob_append_sql(&sql, " GROUP BY name"); |
| 236 | |
| 237 | /* Apply open/closed filtering if requested. */ |
| @@ -375,11 +385,11 @@ | |
| 385 | @ <thead><tr> |
| 386 | @ <th>Branch Name</th> |
| 387 | @ <th>Age</th> |
| 388 | @ <th>Check-ins</th> |
| 389 | if( (flags & BRL_OPEN_CLOSED_MASK) == BRL_BOTH ){ |
| 390 | @ <th>Status</th> |
| 391 | } |
| 392 | @ <th>Resolution</th> |
| 393 | @ </tr></thead><tbody> |
| 394 | while( db_step(&q)==SQLITE_ROW ){ |
| 395 | const char *zBranch = db_column_text(&q, 0); |
| 396 |