=== modified file 'includes/database.inc'
--- includes/database.inc	2010-03-04 02:32:39 +0000
+++ includes/database.inc	2010-03-29 02:51:24 +0000
@@ -402,7 +402,7 @@
  */
 function db_distinct_field($table, $field, $query) {
   $matches = array();
-  if (!preg_match('/^SELECT\s*DISTINCT/i', $query, $matches)) {
+  if (!preg_match('/^SELECT\s*DISTINCT/i', $query, $matches) && db_distinct_allowed($query)) {
     // Only add distinct to the outer SELECT to avoid messing up subqueries.
     $query = preg_replace('/^SELECT/i', 'SELECT DISTINCT', $query);
   }
@@ -410,6 +410,90 @@
 }
 
 /**
+ * Helper function for db_distinct_field
+ *
+ * This tries to establish whether adding a DISTINCT to a query is allowed.
+ * It checks the ORDER BY clause for this, on non-mysql systems;
+ * if any fields in it are not present in the FROM clause, this is llegal in
+ * strict SQL92 dialects like PostgreSQL (and also illogical).
+ *
+ * This function should die as soon as db_distinct_field does.
+ *
+ * @param $query
+ *   SQL to check
+ * @return
+ *   FALSE if it is established that this query cannot be DISTINCT; TRUE otherwise.
+ *   The presence of 'DISTINCT' in $query has no effect on the return value.
+ */
+function db_distinct_allowed($query) {
+  global $db_type;
+  $distinct = TRUE;
+
+  if (strpos($db_type, 'mysql') !== 0 && preg_match('/ORDER\s+BY\s+(.*)$/is', $query, $ordermatches)) {
+
+    // Break the SELECT part down into different fields AND their aliases, since an 'ORDER BY' can be
+    // on a field, an alias (or an order number).
+    //if (preg_match('/^SELECT\s+(.+?)\s+FROM/is', $query, $matches)) { <-- this one is ok when calling from within db_distinct_field()
+    if (preg_match('/^SELECT\s+(?:DISTINCT\s+)?(.+?)\s+FROM/is', $query, $matches)) {
+      // Get fields.
+      // (Treat all commas as field separators, and all spaces as separating the field from the alias.
+      // It's imperfect, but it'll do for our purpose.
+      // We're just living with the imperfection of db_distinct_field() until the end of its lifetime, anyway.)
+      $f = explode(',', $matches[1]);
+      $fields = array_map("strtolower", preg_replace('/^\s*(\S+).*$/s', '$1', $f));
+      $fieldnames = array_map("_db_distinct_strip_tablealias", $fields);
+      // Add field aliases. (Or fieldnames again - we don't care about duplicates in $fields.)
+      $fields = array_merge($fields, array_map("strtolower", preg_replace('/^.*?(\S+)\s*$/s', '$1', $f)));
+
+      // Break ORDER clause apart into fields.
+      // (Instead of stripping off ' ASC' / ' DESC', strip off anything after a space, since we did that with $fields too.
+      // This will also get rid of a ' LIMIT n' directive that may be following the ORDER BY)
+      $orderfields = array_map("strtolower", preg_replace('/^\s*(\S+).*$/s', '$1', explode(',', $ordermatches[1])));
+
+      // Try to find all order fields in $fields
+      // If one field is not found there, do not add the DISTINCT.
+      foreach ($orderfields as $orderfield) {
+
+        if (!is_int($orderfield)) {
+          if (array_search($orderfield, $fields) === FALSE) {
+            // Not found. Extra check based on presence of a table alias:
+            if ($pos = strpos($orderfield, '.')) {
+              // look for <tablealias>.* in $fields
+              if (array_search(substr($orderfield, 0, $pos) . '.*', $fields) === FALSE) {
+                // 'order field' not found; bail
+                $distinct = FALSE;
+                break;
+              }
+            }
+            else {
+              // look for <any_alias>.$orderfield in $fields ==> for $orderfield in $fieldnames
+              if (array_search($orderfield, $fieldnames) === FALSE) {
+                // 'order field' not found; bail
+                $distinct = FALSE;
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return $distinct;
+}
+
+/**
+ * Helper function for db_distinct_allowed
+ */
+function _db_distinct_strip_tablealias($field) {
+  if ($pos = strpos($field, '.')) {
+    return substr($field, $pos + 1);
+  }
+  // Note: If $field started with a dot, that's just too bad.
+  return $field;
+}
+
+/**
  * Restrict a dynamic table, column or constraint name to safe characters.
  *
  * Only keeps alphanumeric and underscores.

=== modified file 'modules/node/node.module'

