? db_distinct.patch
? db_distinct_2.patch
? files
? sites/here.be.dragons.rtk0.net
Index: includes/database.mysql-common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.mysql-common.inc,v
retrieving revision 1.9
diff -u -p -r1.9 database.mysql-common.inc
--- includes/database.mysql-common.inc	26 Aug 2007 08:27:09 -0000	1.9
+++ includes/database.mysql-common.inc	2 Sep 2007 18:48:02 -0000
@@ -7,6 +7,51 @@
  */
 
 /**
+ * @ingroup database
+ * @{
+ */
+
+/**
+ * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to
+ * the SELECT list entry of the given query and the resulting query is returned.
+ * This function only applies the wrapper if a DISTINCT doesn't already exist in
+ * the query.
+ *
+ * @param $table Table containing the field to set as DISTINCT
+ * @param $field Field to set as DISTINCT
+ * @param $query Query to apply the wrapper to
+ * @return SQL query with the DISTINCT wrapper surrounding the given table.field.
+ */
+function db_distinct_field($table, $field, $query) {
+  /*
+   * Rewrite rule: (t: $table, f: $field)
+   *
+   * (1) SELECT .... FROM .... {some}_table t ....
+   *  => SELECT .... FROM .... (SELECT * FROM {some}_table GROUP BY f) t ....
+   *
+   * (2) Remove DISTINCT or DISTINCTROW
+   *     SELECT DISTINCT .... FROM ....
+   *  => SELECT          .... FROM ....
+   *
+   * (3) Remove pgsql specific syntax SELECT DISTINCT ON (...)
+   *     SELECT .... DISTINCT ON (....) ....
+   *  => SELECT ....                    ....
+   */
+
+  $query = preg_replace('/\s+DISTINCT(ROW)?(\s+ON\s*\([^\)]*\))?/si', "", $query);
+  if (preg_match('/(.*FROM\s+)(.*?\s)(\s*(WHERE|GROUP|HAVING|ORDER|LIMIT|FOR).*)/Asi', $query, $m)) {
+    $query = $m[1];
+    $query .= preg_replace('/([\{\w+\}]+)\s+(' . $table . ')\s/si', '(SELECT * FROM \1 GROUP BY ' . $field . ') \2 ', $m[2]);
+    $query .= $m[3];
+  }
+  return $query;
+}
+
+/**
+ * @} End of "ingroup database".
+ */
+
+/**
  * @ingroup schemaapi
  * @{
  */
@@ -482,4 +527,4 @@ function db_last_insert_id($table, $fiel
 
 /**
  * @} End of "ingroup schemaapi".
- */
\ No newline at end of file
+ */
Index: includes/database.mysql.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.mysql.inc,v
retrieving revision 1.79
diff -u -p -r1.79 database.mysql.inc
--- includes/database.mysql.inc	29 Aug 2007 18:38:55 -0000	1.79
+++ includes/database.mysql.inc	2 Sep 2007 18:48:02 -0000
@@ -379,24 +379,6 @@ function db_table_exists($table) {
 function db_column_exists($table, $column) {
   return db_fetch_object(db_query("SHOW COLUMNS FROM {%s} LIKE '%s'", $table, $column)) ? TRUE : FALSE;
 }
-
-/**
- * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to
- * the SELECT list entry of the given query and the resulting query is returned.
- * This function only applies the wrapper if a DISTINCT doesn't already exist in
- * the query.
- *
- * @param $table Table containing the field to set as DISTINCT
- * @param $field Field to set as DISTINCT
- * @param $query Query to apply the wrapper to
- * @return SQL query with the DISTINCT wrapper surrounding the given table.field.
- */
-function db_distinct_field($table, $field, $query) {
-  $field_to_select = 'DISTINCT('. $table .'.'. $field .')';
-  // (?<!text) is a negative look-behind (no need to rewrite queries that already use DISTINCT).
-  return preg_replace('/(SELECT.*)(?:'. $table .'\.|\s)(?<!DISTINCT\()(?<!DISTINCT\('. $table .'\.)'. $field .'(.*FROM )/AUsi', '\1 '. $field_to_select .'\2', $query);
-}
-
 /**
  * @} End of "ingroup database".
  */
Index: includes/database.mysqli.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.mysqli.inc,v
retrieving revision 1.43
diff -u -p -r1.43 database.mysqli.inc
--- includes/database.mysqli.inc	29 Aug 2007 18:38:55 -0000	1.43
+++ includes/database.mysqli.inc	2 Sep 2007 18:48:02 -0000
@@ -378,24 +378,6 @@ function db_table_exists($table) {
 function db_column_exists($table, $column) {
   return db_fetch_object(db_query("SHOW COLUMNS FROM {%s} LIKE '%s'", $table, $column)) ? TRUE : FALSE;
 }
-
-/**
- * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to
- * the SELECT list entry of the given query and the resulting query is returned.
- * This function only applies the wrapper if a DISTINCT doesn't already exist in
- * the query.
- *
- * @param $table Table containing the field to set as DISTINCT
- * @param $field Field to set as DISTINCT
- * @param $query Query to apply the wrapper to
- * @return SQL query with the DISTINCT wrapper surrounding the given table.field.
- */
-function db_distinct_field($table, $field, $query) {
-  $field_to_select = 'DISTINCT('. $table .'.'. $field .')';
-  // (?<!text) is a negative look-behind (no need to rewrite queries that already use DISTINCT).
-  return preg_replace('/(SELECT.*)(?:'. $table .'\.|\s)(?<!DISTINCT\()(?<!DISTINCT\('. $table .'\.)'. $field .'(.*FROM )/AUsi', '\1 '. $field_to_select .'\2', $query);
-}
-
 /**
  * @} End of "ingroup database".
  */
Index: includes/database.pgsql.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database.pgsql.inc,v
retrieving revision 1.57
diff -u -p -r1.57 database.pgsql.inc
--- includes/database.pgsql.inc	29 Aug 2007 18:38:55 -0000	1.57
+++ includes/database.pgsql.inc	2 Sep 2007 18:48:02 -0000
@@ -435,10 +435,26 @@ function db_check_setup() {
  * @return SQL query with the DISTINCT wrapper surrounding the given table.field.
  */
 function db_distinct_field($table, $field, $query) {
-  $field_to_select = 'DISTINCT ON ('. $table .'.'. $field .") $table.$field";
-  // (?<!text) is a negative look-behind (no need to rewrite queries that already use DISTINCT).
-  $query = preg_replace('/(SELECT.*)(?:'. $table .'\.|\s)(?<!DISTINCT\()(?<!DISTINCT\('. $table .'\.)'. $field .'(.*FROM )/AUsi', '\1 '. $field_to_select .'\2', $query);
-  $query = preg_replace('/(ORDER BY )(?!'. $table .'\.'. $field .')/', '\1'."$table.$field, ", $query);
+  // Rewrite rules:
+  //
+  // (1) SELECT .... FROM .... {some}_table t ....
+  //  => SELECT .... FROM .... (SELECT DISTINCT ON (primary_field) * FROM {some}_table) t ....
+  //
+  // (2) Don't rewrite SELECT DISTINCT ON (t.n)
+  //     SELECT DISTINCT ON (t.n) .... FROM .... {some}_table t ....
+  //  => SELECT DISTINCT ON (t.n) .... FROM .... {some}_table t ....
+  //
+  //     SELECT DISTINCT ON (n) .... FROM .... {some}_table t ....
+  //  => SELECT DISTINCT ON (t.n) .... FROM .... {some}_table t ....
+  //
+  // (3) SELECT DISTINCT ON (...., t.n, ....) .... FROM .... {some}_table t ....
+  //  => SELECT DISTINCT ON (...., t.n, ....) .... FROM .... (SELECT DISTINCT ON (f)// FROM {some}_table) t ....
+  if (!preg_match('/DISTINCT\s+ON\s*\(\s*('. $table .'\s*\.\s*)?'. $field .'\s*\)/si', $query)
+      && preg_match('/(.*FROM\s+)(.*?\s)(\s*(WHERE|GROUP|HAVING|ORDER|LIMIT|FOR).*)/Asi', $query, $m)) {
+    $query = $m[1];
+    $query .= preg_replace('/([\{\w+\}]+)\s+(' . $table . ')\s/Usi', '(SELECT DISTINCT ON (' . $field . ') * FROM \1) \2 ', $m[2]);
+    $query .= $m[3];
+  }
   return $query;
 }
 
