Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.375.2.2
diff -u -p -r1.375.2.2 forum.module
--- modules/forum/forum.module	2 Feb 2007 04:34:07 -0000	1.375.2.2
+++ modules/forum/forum.module	4 Feb 2007 21:57:09 -0000
@@ -392,7 +392,7 @@ function forum_form(&$node) {
   $form['title'] = array('#type' => 'textfield', '#title' => check_plain($type->title_label), '#default_value' => $node->title, '#required' => TRUE, '#weight' => -5);
 
   if ($node->nid) {
-    $forum_terms = taxonomy_node_get_terms_by_vocabulary(_forum_get_vid(), $node->nid);
+    $forum_terms = taxonomy_node_get_terms_by_vocabulary(_forum_get_vid(), $node);
     // if editing, give option to leave shadows
     $shadow = (count($forum_terms) > 1);
     $form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.69
diff -u -p -r1.69 system.install
--- modules/system/system.install	10 Jan 2007 23:22:34 -0000	1.69
+++ modules/system/system.install	4 Feb 2007 21:57:13 -0000
@@ -511,9 +511,11 @@ function system_install() {
       db_query("CREATE TABLE {term_node} (
         nid int unsigned NOT NULL default '0',
         tid int unsigned NOT NULL default '0',
+        vid int unsigned NOT NULL default '0',
         KEY nid (nid),
         KEY tid (tid),
-        PRIMARY KEY (tid,nid)
+        KEY tid (vid),
+        PRIMARY KEY (tid,nid,vid)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
       db_query("CREATE TABLE {term_relation} (
@@ -977,9 +979,11 @@ function system_install() {
       db_query("CREATE TABLE {term_node} (
         nid int_unsigned NOT NULL default '0',
         tid int_unsigned NOT NULL default '0',
-        PRIMARY KEY (tid,nid)
+        vid int_unsigned NOT NULL default '0',
+        PRIMARY KEY (tid,nid,vid)
       )");
       db_query("CREATE INDEX {term_node}_nid_idx ON {term_node} (nid)");
+      db_query("CREATE INDEX {term_node}_vid_idx ON {term_node} (vid)");
       db_query("CREATE INDEX {term_node}_tid_idx ON {term_node} (tid)");
 
       db_query("CREATE TABLE {term_relation} (
@@ -3515,6 +3519,21 @@ function system_update_1021() {
  * @todo Start this series of updates at 2000.
  */
 
+function system_update_2000() {
+  $ret = array();
+  // Add revision id to term-node relation.
+  db_add_column($ret, 'term_node', 'vid', 'int', array('default' => 0));
+  $ret[] = update_sql('ALTER TABLE {term_node} DROP PRIMARY KEY');
+  $ret[] = update_sql('ALTER TABLE {term_node} ADD PRIMARY KEY (tid,nid,vid)');
+  $ret[] = update_sql('ALTER TABLE {term_node} ADD KEY (vid)');
+  // Update all entries with the current revision number.
+  $nodes = db_query('SELECT nid,vid FROM {node}');
+  while ($node = db_fetch_object($nodes)) {
+    db_query('UPDATE {term_node} SET vid = %d WHERE nid = %d', $node->vid, $node->nid);
+  }
+  return $ret;
+}
+
 /**
  * @} End of "defgroup updates-5.0-to-x.x"
  * The next series of updates should start at 3000.
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.330.2.2
diff -u -p -r1.330.2.2 taxonomy.module
--- modules/taxonomy/taxonomy.module	25 Jan 2007 21:51:36 -0000	1.330.2.2
+++ modules/taxonomy/taxonomy.module	4 Feb 2007 21:57:13 -0000
@@ -665,7 +665,7 @@ function taxonomy_form_alter($form_id, &
 
     if (!isset($node->taxonomy)) {
       if ($node->nid) {
-        $terms = taxonomy_node_get_terms($node->nid);
+        $terms = taxonomy_node_get_terms($node);
       }
       else {
         $terms = array();
@@ -740,9 +740,19 @@ function taxonomy_form_alter($form_id, &
 
 /**
  * Find all terms associated with the given node, within one vocabulary.
+ * @param $param
+ *   The node object or the node id. If the node id is given the terms are taken from the current revision.
  */
-function taxonomy_node_get_terms_by_vocabulary($nid, $vid, $key = 'tid') {
-  $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.nid = %d ORDER BY weight', 't', 'tid'), $vid, $nid);
+function taxonomy_node_get_terms_by_vocabulary($param, $vid, $key = 'tid') {
+
+  if (is_object($param)) {
+    $node = $param;
+  }
+  else {
+    $node = db_fetch_object(db_query('SELECT nid, vid FROM {node} WHERE nid = %d', $param));
+  }
+
+  $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.nid = %d AND r.vid = %d ORDER BY weight', 't', 'tid'), $vid, $node->nid, $node->vid);
   $terms = array();
   while ($term = db_fetch_object($result)) {
     $terms[$term->$key] = $term;
@@ -752,18 +762,27 @@ function taxonomy_node_get_terms_by_voca
 
 /**
  * Find all terms associated with the given node, ordered by vocabulary and term weight.
+ * @param $param
+ *   The node object or the node id. If the node id is given the terms are taken from the current revision.
  */
-function taxonomy_node_get_terms($nid, $key = 'tid') {
+function taxonomy_node_get_terms($param, $key = 'tid') {
   static $terms;
 
-  if (!isset($terms[$nid])) {
-    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.nid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $nid);
-    $terms[$nid] = array();
+  if (is_object($param)) {
+    $node = $param;
+  }
+  else {
+    $node = db_fetch_object(db_query('SELECT nid, vid FROM {node} WHERE nid = %d', $param));
+  }
+
+  if (!isset($terms[$node->vid])) {
+    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.nid = %d AND r.vid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $node->nid, $node->vid);
+    $terms[$node->vid] = array();
     while ($term = db_fetch_object($result)) {
-      $terms[$nid][$term->$key] = $term;
+      $terms[$node->vid][$term->$key] = $term;
     }
   }
-  return $terms[$nid];
+  return $terms[$node->vid];
 }
 
 /**
@@ -787,9 +806,20 @@ function taxonomy_node_validate(&$node) 
 
 /**
  * Save term associations for a given node.
+ * @param $param
+ *   The node object or the node id. If the node id is given, the terms are associated with the current revision of the node.
  */
-function taxonomy_node_save($nid, $terms) {
-  taxonomy_node_delete($nid);
+function taxonomy_node_save($param, $terms) {
+
+  if (is_object($param)) {
+    $node = $param;
+  }
+  else {
+    $node = db_fetch_object(db_query('SELECT nid, vid FROM {node} WHERE nid = %d', $param));
+  }
+
+  // Delete terms associated with node revision.
+  taxonomy_node_delete_revision($node);
 
   // Free tagging vocabularies do not send their tids in the form,
   // so we'll detect them here and process them independently.
@@ -831,7 +861,7 @@ function taxonomy_node_save($nid, $terms
 
         // Defend against duplicate, differently cased tags
         if (!isset($inserted[$typed_term_tid])) {
-          db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $typed_term_tid);
+          db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $typed_term_tid);
           $inserted[$typed_term_tid] = TRUE;
         }
       }
@@ -843,15 +873,15 @@ function taxonomy_node_save($nid, $terms
       if (is_array($term)) {
         foreach ($term as $tid) {
           if ($tid) {
-            db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid);
+            db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $tid);
           }
         }
       }
       else if (is_object($term)) {
-        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term->tid);
+        db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $term->tid);
       }
       else if ($term) {
-        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
+        db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $node->nid, $node->vid, $term);
       }
     }
   }
@@ -859,9 +889,31 @@ function taxonomy_node_save($nid, $terms
 
 /**
  * Remove associations of a node to its terms.
+ * @param $param
+ *   The node object or the node id.
  */
-function taxonomy_node_delete($nid) {
-  db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
+function taxonomy_node_delete($param) {
+  if (is_numeric($param)) {
+    db_query('DELETE FROM {term_node} WHERE nid = %d', $param);
+  }
+  else {
+    db_query('DELETE FROM {term_node} WHERE nid = %d', $param->nid);
+  }
+}
+
+/**
+ * Remove associations of a node to its terms.
+ * @param $param
+ *   The node object or the node id. If the node id is given the current revision is deleted.
+ */
+function taxonomy_node_delete_revision($param) {
+  if (is_numeric($param)) {
+    $node = node_load($param);
+  }
+  else {
+    $node = $param;
+  }
+  db_query('DELETE FROM {term_node} WHERE vid = %d', $node->vid);
 }
 
 /**
@@ -1046,10 +1098,10 @@ function taxonomy_term_count_nodes($tid,
   if (!isset($count[$type])) {
     // $type == 0 always evaluates TRUE if $type is a string
     if (is_numeric($type)) {
-      $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 GROUP BY t.tid'));
+      $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid AND t.vid = n.vid WHERE n.status = 1 GROUP BY t.tid'));
     }
     else {
-      $result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 AND n.type = '%s' GROUP BY t.tid"), $type);
+      $result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid AND t.vid = n.vid WHERE n.status = 1 AND n.type = '%s' GROUP BY t.tid"), $type);
     }
     while ($term = db_fetch_object($result)) {
       $count[$type][$term->tid] = $term->c;
@@ -1227,14 +1279,14 @@ function taxonomy_select_nodes($tids = a
 
     if ($operator == 'or') {
       $str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids));
-      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 ORDER BY '. $order;
-      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1';
+      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid AND n.vid = t.vid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 ORDER BY '. $order;
+      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid AND n.vid = tn.vid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1';
     }
     else {
       $joins = '';
       $wheres = '';
       foreach ($descendant_tids as $index => $tids) {
-        $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid';
+        $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid AND n.vid = tn'. $index .'.vid';
         $wheres .= ' AND tn'. $index .'.tid IN ('. implode(',', $tids) .')';
       }
       $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY '. $order;
@@ -1276,22 +1328,32 @@ function taxonomy_render_nodes($result) 
 function taxonomy_nodeapi($node, $op, $arg = 0) {
   switch ($op) {
     case 'load':
-     $output['taxonomy'] = taxonomy_node_get_terms($node->nid);
+     $output['taxonomy'] = taxonomy_node_get_terms($node);
      return $output;
+
     case 'insert':
-      taxonomy_node_save($node->nid, $node->taxonomy);
+      taxonomy_node_save($node, $node->taxonomy);
       break;
+
     case 'update':
-      taxonomy_node_save($node->nid, $node->taxonomy);
+      taxonomy_node_save($node, $node->taxonomy);
       break;
+
     case 'delete':
-      taxonomy_node_delete($node->nid);
+      taxonomy_node_delete($node);
+      break;
+
+    case 'delete revision':
+      taxonomy_node_delete_revision($node);
       break;
+
     case 'validate':
       taxonomy_node_validate($node);
       break;
+
     case 'rss item':
       return taxonomy_rss_item($node);
+
     case 'update index':
       return taxonomy_node_update_index($node);
   }
