Diff
Not logged in

Differences From:

File src/descendants.c part of check-in [7847b418bb] - Improvements to the way the update target is computed when saying "fossil update" without specifying what to update to. Avoid the "bad object id: 0" error. by drh on 2009-08-14 14:00:10. [view]

To:

File src/descendants.c part of check-in [7a2c37063a] - merge trunk into creole branch by bob on 2009-09-22 07:49:39. Also file src/descendants.c part of check-in [6953ca813c] - Performance improvements on the compute_leavs() routine. There is opportunity for further improvement in this area. by drh on 2009-08-27 15:00:33. [view]

@@ -32,9 +32,10 @@
 /*
 ** Create a temporary table named "leaves" if it does not
 ** already exist.  Load this table with the RID of all
 ** check-ins that are leaves which are decended from
-** check-in iBase.
+** check-in iBase.  If iBase==0, find all leaves within the
+** entire check-in hierarchy.
 **
 ** A "leaf" is a check-in that has no children in the same branch.
 **
 ** The closeMode flag determines behavior associated with the "closed"
@@ -50,13 +51,8 @@
 ** Show all leaves, use closeMode==1.  To show only closed leaves, use
 ** closeMode==2.
 */
 void compute_leaves(int iBase, int closeMode){
-  Bag seen;       /* Descendants seen */
-  Bag pending;    /* Unpropagated descendants */
-  Stmt q1;        /* Query to find children of a check-in */
-  Stmt isBr;      /* Query to check to see if a check-in starts a new branch */
-  Stmt ins;       /* INSERT statement for a new record */
 
   /* Create the LEAVES table if it does not already exist.  Make sure
   ** it is empty.
   */
@@ -67,82 +63,96 @@
     "DELETE FROM leaves;"
   );
 
   /* We are checking all descendants of iBase.  If iBase==0, then
-  ** change iBase to be the root of the entire check-in hierarchy.
+  ** use a short-cut to find all leaves anywhere in the hierarchy.
   */
   if( iBase<=0 ){
-    iBase = db_int(0, "SELECT objid FROM event WHERE type='ci'"
-                      " ORDER BY mtime LIMIT 1");
-    if( iBase==0 ) return;
-  }
-
-  /* Initialize the bags. */
-  bag_init(&seen);
-  bag_init(&pending);
-  bag_insert(&pending, iBase);
-
-  /* This query returns all non-branch-merge children of check-in :rid.
-  **
-  ** If a a child is a merge of a fork within the same branch, it is
-  ** returned.  Only merge children in different branches are excluded.
-  */
-  db_prepare(&q1,
-    "SELECT cid FROM plink"
-    " WHERE pid=:rid"
-    "   AND (isprim"
-    "        OR coalesce((SELECT value FROM tagxref"
-                      "   WHERE tagid=%d AND rid=plink.pid), 'trunk')"
-               "=coalesce((SELECT value FROM tagxref"
-                      "   WHERE tagid=%d AND rid=plink.cid), 'trunk'))",
-    TAG_BRANCH, TAG_BRANCH
-  );
-
-  /* This query returns a single row if check-in :rid is the first
-  ** check-in of a new branch.
-  */
-  db_prepare(&isBr,
-     "SELECT 1 FROM tagxref"
-     " WHERE rid=:rid AND tagid=%d AND tagtype=2"
-     "   AND srcid>0",
-     TAG_BRANCH
-  );
-
-  /* This statement inserts check-in :rid into the LEAVES table.
-  */
-  db_prepare(&ins, "INSERT OR IGNORE INTO leaves VALUES(:rid)");
+    db_multi_exec(
+      "INSERT OR IGNORE INTO leaves"
+      "  SELECT cid FROM plink"
+      "  EXCEPT"
+      "  SELECT pid FROM plink"
+      "   WHERE coalesce((SELECT value FROM tagxref"
+                         " WHERE tagid=%d AND rid=plink.pid),'trunk')"
+           " == coalesce((SELECT value FROM tagxref"
+                         " WHERE tagid=%d AND rid=plink.cid),'trunk');",
+      TAG_BRANCH, TAG_BRANCH
+    );
+  }else{
+    Bag seen;     /* Descendants seen */
+    Bag pending;  /* Unpropagated descendants */
+    Stmt q1;      /* Query to find children of a check-in */
+    Stmt isBr;    /* Query to check to see if a check-in starts a new branch */
+    Stmt ins;     /* INSERT statement for a new record */
+
+    /* Initialize the bags. */
+    bag_init(&seen);
+    bag_init(&pending);
+    bag_insert(&pending, iBase);
+
+    /* This query returns all non-branch-merge children of check-in :rid.
+    **
+    ** If a a child is a merge of a fork within the same branch, it is
+    ** returned.  Only merge children in different branches are excluded.
+    */
+    db_prepare(&q1,
+      "SELECT cid FROM plink"
+      " WHERE pid=:rid"
+      "   AND (isprim"
+      "        OR coalesce((SELECT value FROM tagxref"
+                        "   WHERE tagid=%d AND rid=plink.pid), 'trunk')"
+                 "=coalesce((SELECT value FROM tagxref"
+                        "   WHERE tagid=%d AND rid=plink.cid), 'trunk'))",
+      TAG_BRANCH, TAG_BRANCH
+    );
+
+    /* This query returns a single row if check-in :rid is the first
+    ** check-in of a new branch.
+    */
+    db_prepare(&isBr,
+       "SELECT 1 FROM tagxref"
+       " WHERE rid=:rid AND tagid=%d AND tagtype=2"
+       "   AND srcid>0",
+       TAG_BRANCH
+    );
+
+    /* This statement inserts check-in :rid into the LEAVES table.
+    */
+    db_prepare(&ins, "INSERT OR IGNORE INTO leaves VALUES(:rid)");
 
-  while( bag_count(&pending) ){
-    int rid = bag_first(&pending);
-    int cnt = 0;
-    bag_remove(&pending, rid);
-    db_bind_int(&q1, ":rid", rid);
-    while( db_step(&q1)==SQLITE_ROW ){
-      int cid = db_column_int(&q1, 0);
-      if( bag_insert(&seen, cid) ){
-        bag_insert(&pending, cid);
+    while( bag_count(&pending) ){
+      int rid = bag_first(&pending);
+      int cnt = 0;
+      bag_remove(&pending, rid);
+      db_bind_int(&q1, ":rid", rid);
+      while( db_step(&q1)==SQLITE_ROW ){
+        int cid = db_column_int(&q1, 0);
+        if( bag_insert(&seen, cid) ){
+          bag_insert(&pending, cid);
+        }
+        db_bind_int(&isBr, ":rid", cid);
+        if( db_step(&isBr)==SQLITE_DONE ){
+          cnt++;
+        }
+        db_reset(&isBr);
       }
-      db_bind_int(&isBr, ":rid", cid);
-      if( db_step(&isBr)==SQLITE_DONE ){
+      db_reset(&q1);
+      if( cnt==0 && !is_a_leaf(rid) ){
         cnt++;
       }
-      db_reset(&isBr);
-    }
-    db_reset(&q1);
-    if( cnt==0 && !is_a_leaf(rid) ){
-      cnt++;
+      if( cnt==0 ){
+        db_bind_int(&ins, ":rid", rid);
+        db_step(&ins);
+        db_reset(&ins);
+      }
     }
-    if( cnt==0 ){
-      db_bind_int(&ins, ":rid", rid);
-      db_step(&ins);
-      db_reset(&ins);
-    }
-  }
-  db_finalize(&ins);
-  db_finalize(&isBr);
-  db_finalize(&q1);
-  bag_clear(&pending);
-  bag_clear(&seen);
+    db_finalize(&ins);
+    db_finalize(&isBr);
+    db_finalize(&q1);
+    bag_clear(&pending);
+    bag_clear(&seen);
+  }
   if( closeMode==1 ){
     db_multi_exec(
       "DELETE FROM leaves WHERE rid IN"
       "  (SELECT leaves.rid FROM leaves, tagxref"