diff -urp --strip-trailing-cr ../category/category_display/category_display.module ./category_display/category_display.module
--- ../category/category_display/category_display.module	2009-01-03 12:47:00.000000000 +0100
+++ ./category_display/category_display.module	2009-06-24 03:22:03.000000000 +0200
@@ -283,7 +283,7 @@ function category_display_toc_recurse($p
     $cat = category_get_container($is_cat ? $category->cnid : $category->cid);
     unset($cat->cid);
     unset($cat->title);
-    foreach ($cat as $key => $value) {
+    foreach ((array)$cat as $key => $value) {
       $category->$key = $value;
     }
 
diff -urp --strip-trailing-cr ../category/category.inc ./category.inc
--- ../category/category.inc	2009-01-03 12:47:00.000000000 +0100
+++ ./category.inc	2009-06-24 00:15:07.000000000 +0200
@@ -26,9 +26,12 @@ function category_get_category($cid, $re
   if (!is_numeric($cid)) {
     return FALSE;
   }
-  $query = 'SELECT c.*, n.title FROM {category} c INNER JOIN {node} n ON c.cid = n.nid';
-
-  return category_get_cached_item('get_category', $cid, 'cid', $query, 'c.cid = %d', FALSE, $reset);
+  $category = category_cache_op('get', $cid, 'cgcat');
+  if (!isset($category)) {
+    $category = db_fetch_object(db_query('SELECT c.*, n.title FROM {category} c INNER JOIN {node} n ON c.cid = n.nid WHERE c.cid = %d', $cid));
+    category_cache_op('set', $cid, 'cgcat', $category);
+  }
+  return $category;
 }
 
 /**
@@ -57,9 +60,9 @@ function category_get_category_by_name($
  * Return the container object matching a container ID.
  */
 function category_get_container($cnid) {
-  static $containers = array();
+  $cont = category_cache_op('get', $cnid, 'cgcont');
+  if (!isset($cont)) {
 
-  if (!array_key_exists($cnid, $containers)) {
     $result = db_query('SELECT cn.*, n.title, ct.type, cd.allowed_parent, c.description AS cont_description, c.weight AS cont_weight, c.depth AS cont_depth FROM {category} c INNER JOIN {category_cont} cn ON c.cid = cn.cid INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont_node_types} ct ON c.cid = ct.cid LEFT JOIN {category_cont_distant} cd ON c.cid = cd.cid WHERE c.cid = %d ORDER BY c.weight, n.title', $cnid);
     $node_types = array();
     $node_distant = array();
@@ -85,11 +88,11 @@ function category_get_container($cnid) {
       else {
         $cont->has_admin_title = TRUE;
       }
-      $containers[$cnid] = $cont;
     }
+    category_cache_op('set', $cnid, 'cgcont', $cont);
   }
 
-  return (isset($containers[$cnid]) ? $containers[$cnid] : NULL);
+  return (isset($cont) ? $cont : NULL);
 }
 
 /**
@@ -147,9 +150,15 @@ function category_is_cat_or_cont($nid, $
     return FALSE;
   }
 
-  $query = 'SELECT n.nid FROM {node} n INNER JOIN {category} c ON n.nid = c.cid';
-  $return = category_get_cached_item('is_cat_or_cont', $nid, 'nid', $query, 'n.nid = %d', FALSE, $reset);
-  return !empty($return->nid);
+  $is_coc = category_cache_op('get', $nid, 'cicoc');
+  if (!isset($is_coc)) {
+    $object = db_fetch_object(db_query('SELECT n.nid FROM {node} n INNER JOIN {category} c ON n.nid = c.cid WHERE n.nid = %d', $nid));
+    $is_coc = empty($object->nid) ? '0' : '1';
+
+    category_cache_op('set', $nid, 'cicoc', $is_coc);
+  }
+
+  return !empty($is_coc);
 }
 
 /**
@@ -193,35 +202,28 @@ function category_node_get_type($node, $
  * This function will return the parents in an indexed array sorted by the parents' weight and title.
  */
 function category_get_parents($cid, $key = 'cid', $distant = TRUE, $reset = FALSE) {
-  static $parents, $distant_parents;
 
   if (!$cid) {
     return array();
   }
 
-  if (($distant && !isset($distant_parents)) || (!$distant && !isset($parents)) || $reset) {
+  $cache_key = $distant ? 'cgpdist' : 'cgparent';
+  $parents = category_cache_op('get', 0, $cache_key);
+  if (!isset($parents)) {
+
     $distant_sql = $distant ? '' : ' AND (c.cnid = cc.cnid OR c.cnid = 0)';
     $result = db_query(db_rewrite_sql('SELECT c.*, h.cid AS child, n.title, cn.admin_title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.parent INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont} cn ON c.cid = cn.cid INNER JOIN {category} cc ON h.cid = cc.cid WHERE n.status = 1'. $distant_sql .' ORDER BY c.weight, n.title'), $cid);
-    if ($distant) {
-      $distant_parents = array();
-    }
-    else {
-      $parents = array();
-    }
+    $parents = array();
     while ($parent = db_fetch_object($result)) {
       if (empty($parent->admin_title)) {
         $parent->admin_title = $parent->title;
       }
-      if ($distant) {
-        $distant_parents[$parent->child][] = $parent;
-      }
-      else {
-        $parents[$parent->child][] = $parent;
-      }
+      $parents[$parent->child][] = $parent;
     }
+    category_cache_op('set', 0, $cache_key, $parents);
   }
 
-  return $distant ? (isset($distant_parents[$cid]) ? $distant_parents[$cid] : array()) : (isset($parents[$cid]) ? $parents[$cid] : array());
+  return (isset($parents[$cid]) ? $parents[$cid] : array());
 }
 
 /**
@@ -244,7 +246,6 @@ function category_get_parents_all($cid, 
  * Find all children of a category ID.
  */
 function category_get_children($cid, $cnid = 0, $key = 'cid', $reset = FALSE) {
-  static $children;
 
   if ($cnid) {
     $result = db_query(db_rewrite_sql('SELECT c.*, n.title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid WHERE h.parent = %d AND n.status = 1 AND c.cnid = %d ORDER BY c.weight, n.title'), $cid, $cnid);
@@ -256,13 +257,17 @@ function category_get_children($cid, $cn
 
     return $results;
   }
-  elseif (!isset($children) || $reset) {
+
+  $children = category_cache_op('get', 0, 'cgch'. $key);
+  if (!isset($children)) {
+
     $result = db_query(db_rewrite_sql('SELECT c.*, h.parent, n.title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid WHERE n.status = 1 ORDER BY c.weight, n.title'), $cid);
 
     $children = array();
     while ($category = db_fetch_object($result)) {
       $children[$category->parent][$category->$key] = $category;
     }
+    category_cache_op('set', 0, 'cgch'. $key, $children);
   }
 
   return isset($children[$cid]) ? $children[$cid] : array();
@@ -377,7 +382,6 @@ function category_location_down($node, $
  *   to have "depth" and "parents" attributes in addition to its normal ones.
  */
 function category_get_tree($cnid, $parent = NULL, $depth = -1, $max_depth = NULL, $distant = FALSE) {
-  static $children, $parents, $categories;
   $tree = array();
 
   if (empty($cnid) && $depth == -1) {
@@ -391,10 +395,17 @@ function category_get_tree($cnid, $paren
 
   // We cache trees, so it's not CPU-intensive to call get_tree() on a category
   // and its children, too.
-  if (!isset($children[$cnid])) {
+  $cache_key = $distant ? 'cgtdist' : 'cgtree';
+  $children = category_cache_op('get', $cnid, $cache_key .'ch');
+  if (isset($children)) {
+    $parents = category_cache_op('get', $cnid, $cache_key .'pa');
+    $categories = category_cache_op('get', $cnid, $cache_key .'ca');
+  }
+  else {
+
     $distant_sql = ($distant) ? '' : 'AND c.cnid = %d ';
 
-    $children[$cnid] = array();
+    $children = $parents = $categories = array();
     $result = db_query(db_rewrite_sql('SELECT c.cid, c.*, h.parent, n.title, cn.admin_title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont} cn ON c.cid = cn.cid LEFT JOIN {category} c2 ON h.parent = c2.cid WHERE (c2.cid IS NOT NULL OR h.parent = 0) AND n.status = 1 '. $distant_sql .'ORDER BY c.weight, n.title', 'n', 'nid'), $cnid);
 
     while ($category = db_fetch_object($result)) {
@@ -405,28 +416,31 @@ function category_get_tree($cnid, $paren
         }
       }
 
-      $children[$cnid][$category->parent][] = $category->cid;
-      $categories[$cnid][$category->cid] = $category;
-      $parents[$cnid][$category->cid][] = $category->parent;
+      $children[$category->parent][] = $category->cid;
+      $categories[$category->cid] = $category;
+      $parents[$category->cid][] = $category->parent;
     }
+  category_cache_op('set', $cnid, $cache_key .'ch', $children);
+  category_cache_op('set', $cnid, $cache_key .'pa', $parents);
+  category_cache_op('set', $cnid, $cache_key .'ca', $categories);
   }
 
-  $max_depth = (is_null($max_depth)) ? count($children[$cnid]) : $max_depth;
-  if ($children[$cnid][$parent]) {
-    foreach ($children[$cnid][$parent] as $child) {
+  $max_depth = (is_null($max_depth)) ? count($children) : $max_depth;
+  if ($children[$parent]) {
+    foreach ($children[$parent] as $child) {
       if ($max_depth > $depth) {
-        $cat = drupal_clone($categories[$cnid][$child]);
+        $cat = drupal_clone($categories[$child]);
         $cat->depth = $depth;
         // The "parent" attribute is not useful, as it would show one parent only.
         unset($cat->parent);
-        $cat->parents = $parents[$cnid][$child];
+        $cat->parents = $parents[$child];
 
         if (!$cat->cnid && empty($cat->admin_title)) {
           $cat->admin_title = $cat->title;
         }
         $tree[] = $cat;
 
-        if ($children[$cnid][$child]) {
+        if ($children[$child]) {
           $tree = array_merge($tree, category_get_tree($cnid, $child, $depth, $max_depth, $distant));
         }
       }
@@ -593,12 +607,16 @@ function category_node_type($op, $info) 
  */
 function category_get_related($cid, $key = 'cid') {
   if ($cid) {
+   $related = category_cache_op('get', $cid, 'cgrel'. $key);
+   if (!isset($related)) {
     $result = db_query(db_rewrite_sql('SELECT c.*, n.title, cid1, cid2 FROM {category_relation}, {category} c, {node} n WHERE (c.cid = cid1 OR c.cid = cid2) AND (cid1 = %d OR cid2 = %d) AND c.cid = n.nid AND c.cid != %d AND n.status = 1 ORDER BY c.weight, n.title'), $cid, $cid, $cid);
     $related = array();
     while ($category = db_fetch_object($result)) {
       $related[$category->$key] = $category;
     }
-    return $related;
+    category_cache_op('set', $cid, 'cgrel'. $key, $related);
+   }
+   return $related;
   }
   else {
     return array();
@@ -610,11 +628,15 @@ function category_get_related($cid, $key
  */
 function category_get_synonyms($cid) {
   if ($cid) {
+   $synonyms = category_cache_op('get', $cid, 'cgsyn');
+   if (!isset($synonyms)) {
     $result = db_query('SELECT name FROM {category_synonym} WHERE cid = %d', $cid);
     while ($synonym = db_fetch_array($result)) {
       $synonyms[] = $synonym['name'];
     }
-    return $synonyms ? $synonyms : array();
+    category_cache_op('set', $cid, 'cgsyn', $synonyms);
+   }
+   return $synonyms ? $synonyms : array();
   }
   else {
     return array();
@@ -803,9 +825,9 @@ function category_node_save(&$node, $is_
  * Given a category id, count the number of published nodes in it.
  */
 function category_category_count_nodes($cid, $type = 0) {
-  static $count;
 
-  if (!isset($count[$type])) {
+  $count = category_cache_op('get', 0, 'cccn'. $type);
+  if (!isset($count)) {
     // $type == 0 always evaluates true if $type is a string
     if (is_numeric($type)) {
       $result = db_query(db_rewrite_sql('SELECT c.cid, COUNT(n.nid) AS cnt FROM {category_node} c INNER JOIN {node} n ON c.nid = n.nid WHERE n.status = 1 GROUP BY c.cid'));
@@ -814,42 +836,51 @@ function category_category_count_nodes($
       $result = db_query(db_rewrite_sql("SELECT c.cid, COUNT(n.nid) AS cnt FROM {category_node} c INNER JOIN {node} n ON c.nid = n.nid WHERE n.status = 1 AND n.type = '%s' GROUP BY c.cid"), $type);
     }
     while ($category = db_fetch_object($result)) {
-      $count[$type][$category->cid] = $category->cnt;
+      $count[$category->cid] = $category->cnt;
     }
+    category_cache_op('set', 0, 'cccn'. $type, $count);
   }
 
-  return isset($count[$type][$cid]) ? $count[$type][$cid] : 0;
+  return isset($count[$cid]) ? $count[$cid] : 0;
 }
 
 /**
  * Find all categories associated to the given node, ordered by container and category weight.
  */
 function category_node_get_categories($nid, $key = 'cid', $reset = FALSE) {
-  static $categories = array();
 
-  if (!isset($categories[$nid]) || $reset) {
-    $categories[$nid] = array();
+   $categories = category_cache_op('get', $nid, 'ngcat'. $key);
+   if (!isset($categories)) {
+
+    $categories = array();
 
     $result = db_query(db_rewrite_sql('SELECT n.nid, r.nid AS node_id, c.*, n.title FROM {category} c INNER JOIN {category_node} r ON c.cid = r.cid INNER JOIN {category} cn ON c.cnid = cn.cid INNER JOIN {node} n ON c.cid = n.nid INNER JOIN {node} cnn ON cn.cid = cnn.nid WHERE n.status = 1 AND r.nid = %d ORDER BY cn.weight, cnn.title, c.weight, n.title'), $nid);
 
     while ($category = db_fetch_object($result)) {
-      $categories[$nid][$category->$key] = $category;
+      $categories[$category->$key] = $category;
     }
+   category_cache_op('set', $nid, 'ngcat'. $key, $categories);
   }
 
-  return $categories[$nid];
+  return $categories;
 }
 
 /**
  * Find all categories associated to the given node, within one container.
  */
 function category_node_get_categories_by_container($nid, $cnid, $key = 'cid') {
+
+ $categories = category_cache_op('get', $nid, 'ngcbc'. $key . $cnid);
+ if (!isset($categories)) {
+
   $result = db_query(db_rewrite_sql('SELECT c.*, n.title FROM {category} c INNER JOIN {category_node} r ON c.cid = r.cid INNER JOIN {node} n ON c.cid = n.nid WHERE c.cnid = %d AND r.nid = %d AND n.status = 1 ORDER BY c.weight'), $cnid, $nid);
   $categories = array();
   while ($category = db_fetch_object($result)) {
     $categories[$category->$key] = $category;
   }
-  return $categories;
+  category_cache_op('set', $nid, 'ngcbc'. $key . $cnid, $categories);
+ }
+ return $categories;
 }
 
 /**
@@ -861,6 +892,7 @@ function category_node_delete($nid, $is_
   if (!$is_legacy || !isset($legacy_calls[$nid])) {
     db_query('DELETE FROM {category_node} WHERE nid = %d', $nid);
 
+    category_cache_op('flush', $nid);
     $legacy_calls[$nid] = TRUE;
   }
 }
@@ -1424,14 +1456,19 @@ function category_get_wrapper_status($ty
  *   containers are found.
  */
 function category_get_distant_child_containers($cnid) {
+
+ $containers = category_cache_op('get', $cnid, 'cgdcc');
+ if (!isset($containers)) {
+
   $containers = array();
 
   $result = db_query('SELECT cid FROM {category_cont_distant} WHERE allowed_parent = \'%s\'', $cnid);
   while ($cont = db_fetch_object($result)) {
     $containers[$cont->cid] = $cont->cid;
   }
-
-  return $containers;
+  category_cache_op('set', $cnid, 'cgdcc',  $containers);
+ }
+ return $containers;
 }
 
 /**
@@ -1509,8 +1546,12 @@ function category_get_cached_item($type,
  *   does not exist or is not part of a category hierarchy.
  */
 function _category_get_depth($cid) {
-  $depth = 0;
   if ($cid) {
+
+   $depth = category_cache_op('get', $cid, 'cgdpth');
+   if (!isset($depth)) {
+
+    $depth = 0;
     while ($cid) {
       $result = db_query(db_rewrite_sql('SELECT h.parent FROM {category_hierarchy} h INNER JOIN {category} c ON h.cid = c.cid INNER JOIN {node} n ON h.cid = n.nid WHERE h.cid = %d ORDER BY c.weight, n.title'), $cid);
       $obj =  db_fetch_object($result);
@@ -1523,7 +1564,10 @@ function _category_get_depth($cid) {
       }
       $depth++;
     }
-    return $depth;
+
+   category_cache_op('set', $cid, 'cgdpth', $depth);
+   }
+   return $depth;
   }
   else {
     return 0;
@@ -1534,13 +1578,14 @@ function _category_get_depth($cid) {
  * Helper for category_category_count_nodes().
  */
 function _category_category_children($cid) {
-  static $children;
+  $children = category_cache_op('get', 0, 'cgchld');
 
   if (!isset($children)) {
     $result = db_query('SELECT cid, parent FROM {category_hierarchy}');
     while ($category = db_fetch_object($result)) {
       $children[$category->parent][] = $category->cid;
     }
+    category_cache_op('set', 0, 'cgchld', $children);
   }
   return $children[$cid] ? $children[$cid] : array();
 }
@@ -1551,3 +1596,70 @@ function _category_category_children($ci
 function _category_get_cid_from_category($category) {
   return $category->cid;
 }
+
+/**
+ * Central caching function for all kinds of node-related category data,
+ * so that all data for a given node may be loaded by single query from
+ * cache table into static variable, and then returned by various API
+ * functions without any queries needed. The cache is stored per-node,
+ * and flushed only when given node is saved or deleted. The key '0'
+ * is used for global summary-data, and flushed on every node save.
+ * While saving a category or container, we flush the whole cache, as
+ * this affects the whole hiearchy, and happens rarely.
+ *
+ * @param op
+ *   Operation to be performed - either 'get', 'set', or 'flush'
+ *
+ * @param nid
+ *   Node id to handle data for. 0 is general data, 'all' flushes all
+ *
+ * @param key
+ *   Name of data subset (usually which API function use it) for the given node
+ *
+ * @param data
+ *   Data for the 'set' operation (will get added to the existing per-node record)
+ */
+function category_cache_op($op, $nid, $key = '', $data = NULL) {
+
+  static $cache;
+  if (!isset($cache)) {
+    $cache = array();
+  }
+
+  // Flush cache if requested
+  if ($op == 'flush') {
+    if ($nid === 'all') {
+      // Total flush: Empty {cache_category} entirely
+      cache_clear_all('*', 'cache_category', TRUE);
+      $cache = array();
+    }
+    else {
+      // Node flush: Delete entries for given node, and for global data
+      cache_clear_all('c'. $nid, 'cache_category');
+      unset($cache[$nid]);
+      cache_clear_all('c0', 'cache_category');
+      unset($cache[0]);
+    }
+    return;
+  }
+
+  // Load existing record for given node, if not available
+  if (!isset($cache[$nid])) {
+    $entry = cache_get('c'. $nid, 'cache_category');
+    if ($entry) {
+      $cache[$nid] = unserialize($entry->data);
+    }
+    else {
+      $cache[$nid] = array();
+    }
+  }
+
+  // Save new data if required
+  if ($op == 'set') {
+    $cache[$nid][$key] = $data;
+    cache_set('c'. $nid, 'cache_category', serialize($cache[$nid]));
+  }
+
+  // Return data for given node/key combination
+  return isset($cache[$nid][$key]) ? $cache[$nid][$key] : NULL;
+}
diff -urp --strip-trailing-cr ../category/category.module ./category.module
--- ../category/category.module	2009-01-03 12:47:00.000000000 +0100
+++ ./category.module	2009-06-23 21:34:56.000000000 +0200
@@ -536,6 +536,7 @@ function category_update($node, $type = 
       }
     }
   }
+  category_cache_op('flush', 'all');
 }
 
 /**
@@ -559,6 +560,7 @@ function category_delete(&$node, $type =
     db_query('DELETE FROM {category_relation} WHERE cid1 = %d OR cid2 = %d', $node->nid, $node->nid);
     db_query('DELETE FROM {category_synonym} WHERE cid = %d', $node->nid);
   }
+  category_cache_op('flush', 'all');
 }
 
 /**
diff -urp --strip-trailing-cr ../category/contrib/category_views/category_views.module ./contrib/category_views/category_views.module
--- ../category/contrib/category_views/category_views.module	2009-01-03 12:48:00.000000000 +0100
+++ ./contrib/category_views/category_views.module	2009-06-23 23:03:19.000000000 +0200
@@ -143,6 +143,8 @@ function category_views_category_legacy(
  *   The views settings for the specified node.
  */
 function category_views_cont_load($nid) {
+ $container = category_cache_op('get', $nid, 'cvcld');
+ if (!isset($container)) {
   $container = new stdClass();
   $sql = db_query("SELECT * FROM {category_views} WHERE cid = %d", $nid);
   if ($result = db_fetch_object($sql)) {
@@ -150,8 +152,9 @@ function category_views_cont_load($nid) 
     if ($result->display_cont) $container->view_display['cont'] = 'cont';
     if ($result->display_cat) $container->view_display['cat'] = 'cat';
   }
-
-  return $container;
+  category_cache_op('set', $nid, 'cvcld', $container);
+ }
+ return $container;
 }
 
 /**
