Diff
Not logged in

Differences From:

File src/tag.c part of check-in [3b5514ed82] - The "tag" command allows tag artifacts to be inserted for creating and cancelling tags and properties. Timeline responds to bgcolor, br-bgcolor, comment, and user properties. by drh on 2007-09-22 15:50:14. [view]

To:

File src/tag.c part of check-in [09c4adeb6f] - Rework the tag system so that propagation to children is a property of each tag and does not depend on the tag name beginning with "br". Older tag artifacts might not work. The database will need to be rebuilt after upgrading to this version. by drh on 2007-09-22 23:41:29. [view]

@@ -32,34 +32,37 @@
 **
 ** This routine assumes that tagid is a tag that should be
 ** propagated and that the tag is already present in pid.
 **
-** If addFlag is true then the tag is added.  If false, then the
-** tag is removed.
+** If tagtype is 2 then the tag is being propagated from an
+** ancestor node.  If tagtype is 0 it means a branch tag is
+** being cancelled.
 */
 void tag_propagate(
   int pid,             /* Propagate the tag to children of this node */
   int tagid,           /* Tag to propagate */
-  int addFlag,         /* True to add the tag. False to delete it. */
+  int tagType,         /* 2 for a propagating tag.  0 for an antitag */
   const char *zValue,  /* Value of the tag.  Might be NULL */
   double mtime         /* Timestamp on the tag */
 ){
   PQueue queue;
   Stmt s, ins, eventupdate;
+
+  assert( tagType==0 || tagType==2 );
   pqueue_init(&queue);
   pqueue_insert(&queue, pid, 0.0);
   db_prepare(&s,
      "SELECT cid, plink.mtime,"
      "       coalesce(srcid=0 AND tagxref.mtime<:mtime, %d) AS doit"
      "  FROM plink LEFT JOIN tagxref ON cid=rid AND tagid=%d"
      " WHERE pid=:pid AND isprim",
-     addFlag, tagid
+     tagType!=0, tagid
   );
   db_bind_double(&s, ":mtime", mtime);
-  if( addFlag ){
+  if( tagType==2 ){
     db_prepare(&ins,
-       "REPLACE INTO tagxref(tagid, addFlag, srcid, value, mtime, rid)"
-       "VALUES(%d,1,0,%Q,:mtime,:rid)",
+       "REPLACE INTO tagxref(tagid, tagtype, srcid, value, mtime, rid)"
+       "VALUES(%d,2,0,%Q,:mtime,:rid)",
        tagid, zValue
     );
     db_bind_double(&ins, ":mtime", mtime);
   }else{
@@ -67,9 +70,9 @@
     db_prepare(&ins,
        "DELETE FROM tagxref WHERE tagid=%d AND rid=:rid", tagid
     );
   }
-  if( tagid==TAG_BR_BGCOLOR ){
+  if( tagid==TAG_BGCOLOR ){
     db_prepare(&eventupdate,
       "UPDATE event SET brbgcolor=%Q WHERE objid=:rid", zValue
     );
   }
@@ -83,9 +86,9 @@
         pqueue_insert(&queue, cid, mtime);
         db_bind_int(&ins, ":rid", cid);
         db_step(&ins);
         db_reset(&ins);
-        if( tagid==TAG_BR_BGCOLOR ){
+        if( tagid==TAG_BGCOLOR ){
           db_bind_int(&eventupdate, ":rid", cid);
           db_step(&eventupdate);
           db_reset(&eventupdate);
         }
@@ -95,9 +98,9 @@
   }
   pqueue_clear(&queue);
   db_finalize(&ins);
   db_finalize(&s);
-  if( tagid==TAG_BR_BGCOLOR ){
+  if( tagid==TAG_BGCOLOR ){
     db_finalize(&eventupdate);
   }
 }
 
@@ -106,19 +109,19 @@
 */
 void tag_propagate_all(int pid){
   Stmt q;
   db_prepare(&q,
-     "SELECT tagid, addflag, mtime, value FROM tagxref"
+     "SELECT tagid, tagtype, mtime, value FROM tagxref"
      " WHERE rid=%d"
-     "   AND (SELECT tagname FROM tag WHERE tagid=tagxref.tagid) LIKE 'br%'",
+     "   AND (tagtype=0 OR tagtype=2)",
      pid
   );
   while( db_step(&q)==SQLITE_ROW ){
     int tagid = db_column_int(&q, 0);
-    int addflag = db_column_int(&q, 1);
+    int tagtype = db_column_int(&q, 1);
     double mtime = db_column_double(&q, 2);
     const char *zValue = db_column_text(&q, 3);
-    tag_propagate(pid, tagid, addflag, zValue, mtime);
+    tag_propagate(pid, tagid, tagtype, zValue, mtime);
   }
   db_finalize(&q);
 }
 
@@ -140,104 +143,91 @@
 ** Insert a tag into the database.
 */
 void tag_insert(
   const char *zTag,        /* Name of the tag (w/o the "+" or "-" prefix */
-  int addFlag,             /* True to add.  False to remove */
+  int tagtype,             /* 0:cancel  1:singleton  2:propagated */
   const char *zValue,      /* Value if the tag is really a property */
   int srcId,               /* Artifact that contains this tag */
   double mtime,            /* Timestamp.  Use default if <=0.0 */
   int rid                  /* Artifact to which the tag is to attached */
 ){
   Stmt s;
+  const char *zCol;
   int tagid = tag_findid(zTag, 1);
   if( mtime<=0.0 ){
     mtime = db_double(0.0, "SELECT julianday('now')");
   }
   db_prepare(&s,
-    "REPLACE INTO tagxref(tagid,addFlag,srcId,value,mtime,rid)"
+    "REPLACE INTO tagxref(tagid,tagtype,srcId,value,mtime,rid)"
     " VALUES(%d,%d,%d,%Q,:mtime,%d)",
-    tagid, addFlag, srcId, zValue, rid
+    tagid, tagtype, srcId, zValue, rid
   );
   db_bind_double(&s, ":mtime", mtime);
   db_step(&s);
   db_finalize(&s);
-  if( addFlag==0 ){
+  if( tagtype==0 ){
     zValue = 0;
   }
+  zCol = 0;
   switch( tagid ){
     case TAG_BGCOLOR: {
-      db_multi_exec("UPDATE event SET bgcolor=%Q WHERE objid=%d", zValue, rid);
-      break;
-    }
-    case TAG_BR_BGCOLOR: {
-      db_multi_exec("UPDATE event SET brbgcolor=%Q WHERE objid=%d", zValue,rid);
+      if( tagtype==1 ){
+        zCol = "bgcolor";
+      }else{
+        zCol = "brbgcolor";
+      }
       break;
     }
     case TAG_COMMENT: {
-      db_multi_exec("UPDATE event SET ecomment=%Q WHERE objid=%d", zValue, rid);
+      zCol = "ecomment";
       break;
     }
     case TAG_USER: {
-      db_multi_exec("UPDATE event SET euser=%Q WHERE objid=%d", zValue, rid);
+      zCol = "euser";
       break;
     }
   }
-  if( strncmp(zTag, "br", 2)==0 ){
-    tag_propagate(rid, tagid, addFlag, zValue, mtime);
+  if( zCol ){
+    db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid);
+  }
+  if( tagtype==0 || tagtype==2 ){
+    tag_propagate(rid, tagid, tagtype, zValue, mtime);
   }
 }
 
 
 /*
-** COMMAND: test-addtag
-** %fossil test-addtag TAGNAME UUID ?VALUE?
+** COMMAND: test-tag
+** %fossil test-tag (+|*|-)TAGNAME UUID ?VALUE?
 **
-** Add a tag to the rebuildable tables of the local repository.
+** Add a tag or anti-tag to the rebuildable tables of the local repository.
 ** No tag artifact is created so the new tag is erased the next
 ** time the repository is rebuilt.  This routine is for testing
 ** use only.
 */
-void addtag_cmd(void){
+void testtag_cmd(void){
   const char *zTag;
   const char *zValue;
   int rid;
+  int tagtype;
   db_must_be_within_tree();
   if( g.argc!=4 && g.argc!=5 ){
     usage("TAGNAME UUID ?VALUE?");
   }
   zTag = g.argv[2];
+  switch( zTag[0] ){
+    case '+':  tagtype = 1;  break;
+    case '*':  tagtype = 2;  break;
+    case '-':  tagtype = 0;  break;
+    default:   fossil_fatal("tag should begin with '+', '*', or '-'");
+  }
   rid = name_to_rid(g.argv[3]);
   if( rid==0 ){
     fossil_fatal("no such object: %s", g.argv[3]);
   }
   zValue = g.argc==5 ? g.argv[4] : 0;
   db_begin_transaction();
-  tag_insert(zTag, 1, zValue, -1, 0.0, rid);
-  db_end_transaction(0);
-}
-/*
-** COMMAND: test-deltag
-** %fossil test-deltag TAGNAME UUID
-**
-** Cancel a tag to the rebuildable tables of the local repository.
-** No tag artifact is created so the cancellation is undone the next
-** time the repository is rebuilt.  This routine is for testing
-** use only.
-*/
-void deltag_cmd(void){
-  const char *zTag;
-  int rid;
-  db_must_be_within_tree();
-  if( g.argc!=4 ){
-    usage("TAGNAME UUID");
-  }
-  zTag = g.argv[2];
-  rid = name_to_rid(g.argv[3]);
-  if( rid==0 ){
-    fossil_fatal("no such object: %s", g.argv[3]);
-  }
-  db_begin_transaction();
-  tag_insert(zTag, 0, 0, -1, 0.0, rid);
+  tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
   db_end_transaction(0);
 }
 
 /*
@@ -247,17 +237,19 @@
 static void tag_add_artifact(
   const char *zTagname,       /* The tag to add or cancel */
   const char *zObjName,       /* Name of object attached to */
   const char *zValue,         /* Value for the tag.  Might be NULL */
-  int addFlag                 /* True to add.  false to cancel */
+  int tagtype                 /* 0:cancel 1:singleton 2:propagated */
 ){
   int rid;
   int nrid;
   char *zDate;
   Blob uuid;
   Blob ctrl;
   Blob cksum;
+  static const char zTagtype[] = { '-', '+', '*' };
 
+  assert( tagtype>=0 && tagtype<=2 );
   user_select();
   rid = name_to_rid(zObjName);
   blob_zero(&uuid);
   db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -269,10 +261,10 @@
   }
   zDate = db_text(0, "SELECT datetime('now')");
   zDate[10] = 'T';
   blob_appendf(&ctrl, "D %s\n", zDate);
-  blob_appendf(&ctrl, "T %c%F %b", addFlag ? '+' : '-', zTagname, &uuid);
-  if( addFlag && zValue && zValue[0] ){
+  blob_appendf(&ctrl, "T %c%F %b", zTagtype[tagtype], zTagname, &uuid);
+  if( tagtype && zValue && zValue[0] ){
     blob_appendf(&ctrl, " %F\n", zValue);
   }else{
     blob_appendf(&ctrl, "\n");
   }
@@ -293,8 +285,13 @@
 **
 **     %fossil tag add TAGNAME UUID ?VALUE?
 **
 **         Add a new tag or property to UUID.
+**
+**     %fossil tag branch TAGNAME UUID ?VALUE?
+**
+**         Add a new tag or property to UUID and make that
+**         tag propagate to all direct children.
 **
 **     %fossil tag delete TAGNAME UUID
 **
 **         Delete the tag TAGNAME from UUID
@@ -327,8 +324,17 @@
     zValue = g.argc==6 ? g.argv[5] : 0;
     tag_add_artifact(g.argv[3], g.argv[4], zValue, 1);
   }else
 
+  if( strncmp(g.argv[2],"branch",n)==0 ){
+    char *zValue;
+    if( g.argc!=5 && g.argc!=6 ){
+      usage("tag branch TAGNAME UUID ?VALUE?");
+    }
+    zValue = g.argc==6 ? g.argv[5] : 0;
+    tag_add_artifact(g.argv[3], g.argv[4], zValue, 2);
+  }else
+
   if( strncmp(g.argv[2],"delete",n)==0 ){
     if( g.argc!=5 ){
       usage("tag delete TAGNAME UUID");
     }
@@ -358,9 +364,9 @@
         "SELECT tagname"
         "  FROM tag"
         " WHERE EXISTS(SELECT 1 FROM tagxref"
         "               WHERE tagid=tag.tagid"
-        "                 AND addflag)"
+        "                 AND tagtype>0)"
         " ORDER BY tagname"
       );
       while( db_step(&q)==SQLITE_ROW ){
         printf("%s\n", db_column_text(&q, 0));
@@ -371,9 +377,9 @@
       db_prepare(&q,
         "SELECT tagname, value"
         "  FROM tagxref, tag"
         " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
-        "   AND addflag"
+        "   AND tagtype>0"
         " ORDER BY tagname",
         rid
       );
       while( db_step(&q)==SQLITE_ROW ){
@@ -395,6 +401,6 @@
   }
   return;
 
 tag_cmd_usage:
-  usage("add|delete|find|list ...");
+  usage("add|branch|delete|find|list ...");
 }