diff -Naur ../drupal/modules/taxonomy/taxonomy.module ./modules/taxonomy/taxonomy.module
--- ../drupal/modules/taxonomy/taxonomy.module	2007-12-06 13:16:38.000000000 -0500
+++ ./modules/taxonomy/taxonomy.module	2007-12-10 12:41:56.012473975 -0500
@@ -780,12 +780,25 @@
   static $terms;
 
   if (!isset($terms[$nid][$key])) {
-    $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][$key] = array();
-    while ($term = db_fetch_object($result)) {
-      $terms[$nid][$key][$term->$key] = $term;
+    // This caching breaks taxonomy access! The results of db_rewrite_sql will
+    // be cached, meaning the first user to load this node after a cache
+    // refresh will set the permissions for everyone. If you are using a module
+    // that does query rewriting on taxonomy queries, don't use this patch.
+    // If you're not sure whether or not this is the case, don't use this patch!
+    $cache_key = 'node::'. $nid. '::'. $key;
+    if ($cache = cache_get($cache_key, 'cache_taxonomy')) {
+      $terms[$nid][$key] = unserialize($cache->data);
+    }
+    else {
+      $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][$key] = array();
+      while ($term = db_fetch_object($result)) {
+        $terms[$nid][$key][$term->$key] = $term;
+      }
+      cache_set($cache_key, 'cache_taxonomy', serialize($terms[$nid][$key]));
     }
   }
+
   return $terms[$nid][$key];
 }
 
@@ -989,7 +1002,14 @@
  */
 function taxonomy_get_tree($vid, $parent = 0, $depth = -1, $max_depth = NULL) {
   static $children, $parents, $terms;
-
+  if ((0 === $parent) && (-1 === $depth)) {
+    if ($cache = cache_get('tree::'. $vid, 'cache_taxonomy')) {
+      return unserialize($cache->data);
+    }
+    else {
+      $cache_tree = TRUE;
+    }
+  }
   $depth++;
 
   // We cache trees, so it's not CPU-intensive to call get_tree() on a term
@@ -1023,6 +1043,10 @@
     }
   }
 
+  if ($cache_tree) {
+    cache_set('tree::'. $vid, 'cache_taxonomy', serialize($tree));
+  }
+
   return $tree ? $tree : array();
 }
 
@@ -1145,13 +1169,19 @@
   static $vocabularies = array();
 
   if (!array_key_exists($vid, $vocabularies)) {
-    $result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE v.vid = %d ORDER BY v.weight, v.name', $vid);
-    $node_types = array();
-    while ($voc = db_fetch_object($result)) {
-      $node_types[] = $voc->type;
-      unset($voc->type);
-      $voc->nodes = $node_types;
-      $vocabularies[$vid] = $voc;
+    if ($cache = cache_get('vocabulary::'. $vid, 'cache_taxonomy')) {
+      $vocabularies[$vid] = unserialize($cache->data);
+    }
+    else {
+      $result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE v.vid = %d ORDER BY v.weight, v.name', $vid);
+      $node_types = array();
+      while ($voc = db_fetch_object($result)) {
+        $node_types[] = $voc->type;
+        unset($voc->type);
+        $voc->nodes = $node_types;
+        $vocabularies[$vid] = $voc;
+        cache_set('vocabulary::'. $vid, 'cache_taxonomy', serialize($voc));
+      }
     }
   }
 
@@ -1171,7 +1201,13 @@
   static $terms = array();
 
   if (!isset($terms[$tid])) {
-    $terms[$tid] = db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
+    if ($cache = cache_get('term::'. $tid, 'cache_taxonomy')) {
+      $terms[$tid] = unserialize($cache->data);
+    }
+    else {
+      $terms[$tid] = db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
+      cache_set('term::'. $tid, 'cache_taxonomy', serialize($terms[$tid]));
+    }
   }
 
   return $terms[$tid];
@@ -1300,8 +1336,8 @@
 function taxonomy_nodeapi($node, $op, $arg = 0) {
   switch ($op) {
     case 'load':
-     $output['taxonomy'] = taxonomy_node_get_terms($node->nid);
-     return $output;
+      $output['taxonomy'] = taxonomy_node_get_terms($node->nid);
+      return $output;
     case 'insert':
       taxonomy_node_save($node->nid, $node->taxonomy);
       break;
