Fossil SCM
Change compute_direct_ancestors() to use a recursive common table expression.
Commit
6599d097298da9e670df505a32618f1c78e752e7
Parent
6d84c6325e905d2…
2 files changed
+10
-25
+2
-2
+10
-25
| --- src/descendants.c | ||
| +++ src/descendants.c | ||
| @@ -180,44 +180,29 @@ | ||
| 180 | 180 | rid, rid, directOnly ? "AND plink.isPrim" : "", N |
| 181 | 181 | ); |
| 182 | 182 | } |
| 183 | 183 | |
| 184 | 184 | /* |
| 185 | -** Compute up to N direct ancestors (merge ancestors do not count) | |
| 185 | +** Compute all direct ancestors (merge ancestors do not count) | |
| 186 | 186 | ** for the check-in rid and put them in a table named "ancestor". |
| 187 | 187 | ** Label each generation with consecutive integers going backwards |
| 188 | 188 | ** in time such that rid has the smallest generation number and the oldest |
| 189 | 189 | ** direct ancestor as the largest generation number. |
| 190 | 190 | */ |
| 191 | -void compute_direct_ancestors(int rid, int N){ | |
| 192 | - Stmt ins; | |
| 193 | - Stmt q; | |
| 194 | - int gen = 0; | |
| 191 | +void compute_direct_ancestors(int rid){ | |
| 195 | 192 | db_multi_exec( |
| 196 | 193 | "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER UNIQUE NOT NULL," |
| 197 | 194 | " generation INTEGER PRIMARY KEY);" |
| 198 | 195 | "DELETE FROM ancestor;" |
| 199 | - "INSERT INTO ancestor VALUES(%d, 0);", rid | |
| 200 | - ); | |
| 201 | - db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)"); | |
| 202 | - db_prepare(&q, | |
| 203 | - "SELECT pid FROM plink" | |
| 204 | - " WHERE cid=:rid AND isprim" | |
| 205 | - ); | |
| 206 | - while( (N--)>0 ){ | |
| 207 | - db_bind_int(&q, ":rid", rid); | |
| 208 | - if( db_step(&q)!=SQLITE_ROW ) break; | |
| 209 | - rid = db_column_int(&q, 0); | |
| 210 | - db_reset(&q); | |
| 211 | - gen++; | |
| 212 | - db_bind_int(&ins, ":rid", rid); | |
| 213 | - db_bind_int(&ins, ":gen", gen); | |
| 214 | - db_step(&ins); | |
| 215 | - db_reset(&ins); | |
| 216 | - } | |
| 217 | - db_finalize(&ins); | |
| 218 | - db_finalize(&q); | |
| 196 | + "WITH RECURSIVE g(x,i) AS (" | |
| 197 | + " VALUES(%d,1)" | |
| 198 | + " UNION ALL" | |
| 199 | + " SELECT plink.pid, g.i+1 FROM plink, g" | |
| 200 | + " WHERE plink.cid=g.x AND plink.isprim)" | |
| 201 | + "INSERT INTO ancestor(rid,generation) SELECT x,i FROM g;", | |
| 202 | + rid | |
| 203 | + ); | |
| 219 | 204 | } |
| 220 | 205 | |
| 221 | 206 | /* |
| 222 | 207 | ** Compute the "mtime" of the file given whose blob.rid is "fid" that |
| 223 | 208 | ** is part of check-in "vid". The mtime will be the mtime on vid or |
| 224 | 209 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -180,44 +180,29 @@ | |
| 180 | rid, rid, directOnly ? "AND plink.isPrim" : "", N |
| 181 | ); |
| 182 | } |
| 183 | |
| 184 | /* |
| 185 | ** Compute up to N direct ancestors (merge ancestors do not count) |
| 186 | ** for the check-in rid and put them in a table named "ancestor". |
| 187 | ** Label each generation with consecutive integers going backwards |
| 188 | ** in time such that rid has the smallest generation number and the oldest |
| 189 | ** direct ancestor as the largest generation number. |
| 190 | */ |
| 191 | void compute_direct_ancestors(int rid, int N){ |
| 192 | Stmt ins; |
| 193 | Stmt q; |
| 194 | int gen = 0; |
| 195 | db_multi_exec( |
| 196 | "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER UNIQUE NOT NULL," |
| 197 | " generation INTEGER PRIMARY KEY);" |
| 198 | "DELETE FROM ancestor;" |
| 199 | "INSERT INTO ancestor VALUES(%d, 0);", rid |
| 200 | ); |
| 201 | db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)"); |
| 202 | db_prepare(&q, |
| 203 | "SELECT pid FROM plink" |
| 204 | " WHERE cid=:rid AND isprim" |
| 205 | ); |
| 206 | while( (N--)>0 ){ |
| 207 | db_bind_int(&q, ":rid", rid); |
| 208 | if( db_step(&q)!=SQLITE_ROW ) break; |
| 209 | rid = db_column_int(&q, 0); |
| 210 | db_reset(&q); |
| 211 | gen++; |
| 212 | db_bind_int(&ins, ":rid", rid); |
| 213 | db_bind_int(&ins, ":gen", gen); |
| 214 | db_step(&ins); |
| 215 | db_reset(&ins); |
| 216 | } |
| 217 | db_finalize(&ins); |
| 218 | db_finalize(&q); |
| 219 | } |
| 220 | |
| 221 | /* |
| 222 | ** Compute the "mtime" of the file given whose blob.rid is "fid" that |
| 223 | ** is part of check-in "vid". The mtime will be the mtime on vid or |
| 224 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -180,44 +180,29 @@ | |
| 180 | rid, rid, directOnly ? "AND plink.isPrim" : "", N |
| 181 | ); |
| 182 | } |
| 183 | |
| 184 | /* |
| 185 | ** Compute all direct ancestors (merge ancestors do not count) |
| 186 | ** for the check-in rid and put them in a table named "ancestor". |
| 187 | ** Label each generation with consecutive integers going backwards |
| 188 | ** in time such that rid has the smallest generation number and the oldest |
| 189 | ** direct ancestor as the largest generation number. |
| 190 | */ |
| 191 | void compute_direct_ancestors(int rid){ |
| 192 | db_multi_exec( |
| 193 | "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER UNIQUE NOT NULL," |
| 194 | " generation INTEGER PRIMARY KEY);" |
| 195 | "DELETE FROM ancestor;" |
| 196 | "WITH RECURSIVE g(x,i) AS (" |
| 197 | " VALUES(%d,1)" |
| 198 | " UNION ALL" |
| 199 | " SELECT plink.pid, g.i+1 FROM plink, g" |
| 200 | " WHERE plink.cid=g.x AND plink.isprim)" |
| 201 | "INSERT INTO ancestor(rid,generation) SELECT x,i FROM g;", |
| 202 | rid |
| 203 | ); |
| 204 | } |
| 205 | |
| 206 | /* |
| 207 | ** Compute the "mtime" of the file given whose blob.rid is "fid" that |
| 208 | ** is part of check-in "vid". The mtime will be the mtime on vid or |
| 209 |
+2
-2
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -2299,11 +2299,11 @@ | ||
| 2299 | 2299 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 2300 | 2300 | fossil_redirect_home(); |
| 2301 | 2301 | } |
| 2302 | 2302 | |
| 2303 | 2303 | /* compute the annotation */ |
| 2304 | - compute_direct_ancestors(mid, 10000000); | |
| 2304 | + compute_direct_ancestors(mid); | |
| 2305 | 2305 | annotate_file(&ann, fnid, mid, iLimit, annFlags); |
| 2306 | 2306 | zCI = ann.aVers[0].zMUuid; |
| 2307 | 2307 | |
| 2308 | 2308 | /* generate the web page */ |
| 2309 | 2309 | style_header("Annotation For %h", zFilename); |
| @@ -2505,11 +2505,11 @@ | ||
| 2505 | 2505 | cid = db_lget_int("checkout", 0); |
| 2506 | 2506 | if( cid == 0 ){ |
| 2507 | 2507 | fossil_fatal("Not in a checkout"); |
| 2508 | 2508 | } |
| 2509 | 2509 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2510 | - compute_direct_ancestors(cid, 1000000); | |
| 2510 | + compute_direct_ancestors(cid); | |
| 2511 | 2511 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " |
| 2512 | 2512 | " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" |
| 2513 | 2513 | " ORDER BY ancestor.generation ASC LIMIT 1", |
| 2514 | 2514 | fid, fnid); |
| 2515 | 2515 | if( mid==0 ){ |
| 2516 | 2516 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -2299,11 +2299,11 @@ | |
| 2299 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 2300 | fossil_redirect_home(); |
| 2301 | } |
| 2302 | |
| 2303 | /* compute the annotation */ |
| 2304 | compute_direct_ancestors(mid, 10000000); |
| 2305 | annotate_file(&ann, fnid, mid, iLimit, annFlags); |
| 2306 | zCI = ann.aVers[0].zMUuid; |
| 2307 | |
| 2308 | /* generate the web page */ |
| 2309 | style_header("Annotation For %h", zFilename); |
| @@ -2505,11 +2505,11 @@ | |
| 2505 | cid = db_lget_int("checkout", 0); |
| 2506 | if( cid == 0 ){ |
| 2507 | fossil_fatal("Not in a checkout"); |
| 2508 | } |
| 2509 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2510 | compute_direct_ancestors(cid, 1000000); |
| 2511 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " |
| 2512 | " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" |
| 2513 | " ORDER BY ancestor.generation ASC LIMIT 1", |
| 2514 | fid, fnid); |
| 2515 | if( mid==0 ){ |
| 2516 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -2299,11 +2299,11 @@ | |
| 2299 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 2300 | fossil_redirect_home(); |
| 2301 | } |
| 2302 | |
| 2303 | /* compute the annotation */ |
| 2304 | compute_direct_ancestors(mid); |
| 2305 | annotate_file(&ann, fnid, mid, iLimit, annFlags); |
| 2306 | zCI = ann.aVers[0].zMUuid; |
| 2307 | |
| 2308 | /* generate the web page */ |
| 2309 | style_header("Annotation For %h", zFilename); |
| @@ -2505,11 +2505,11 @@ | |
| 2505 | cid = db_lget_int("checkout", 0); |
| 2506 | if( cid == 0 ){ |
| 2507 | fossil_fatal("Not in a checkout"); |
| 2508 | } |
| 2509 | if( iLimit<=0 ) iLimit = 1000000000; |
| 2510 | compute_direct_ancestors(cid); |
| 2511 | mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor " |
| 2512 | " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid" |
| 2513 | " ORDER BY ancestor.generation ASC LIMIT 1", |
| 2514 | fid, fnid); |
| 2515 | if( mid==0 ){ |
| 2516 |