MDL-34159 improve where_clause_list performance
authorPetr Škoda <commits@skodak.org>
Tue, 3 Jul 2012 18:00:21 +0000 (20:00 +0200)
committerPetr Škoda <commits@skodak.org>
Fri, 6 Jul 2012 05:57:20 +0000 (07:57 +0200)
lib/dml/moodle_database.php
lib/dml/tests/dml_test.php

index 48a992c..b44b740 100644 (file)
@@ -574,21 +574,38 @@ abstract class moodle_database {
      * @return array An array containing sql 'where' part and 'params'
      */
     protected function where_clause_list($field, array $values) {
+        if (empty($values)) {
+            return array("1 = 2", array());
+        }
+
+        // Note: Do not use get_in_or_equal() because it can not deal with bools and nulls.
+
         $params = array();
-        $select = array();
+        $select = "";
         $values = (array)$values;
         foreach ($values as $value) {
             if (is_bool($value)) {
                 $value = (int)$value;
             }
             if (is_null($value)) {
-                $select[] = "$field IS NULL";
+                $select = "$field IS NULL";
             } else {
-                $select[] = "$field = ?";
                 $params[] = $value;
             }
         }
-        $select = implode(" OR ", $select);
+        if ($params) {
+            if ($select !== "") {
+                $select = "$select OR ";
+            }
+            $count = count($params);
+            if ($count == 1) {
+                $select = $select."$field = ?";
+            } else {
+                $qs = str_repeat(',?', $count);
+                $qs = ltrim($qs, ',');
+                $select = $select."$field IN ($qs)";
+            }
+        }
         return array($select, $params);
     }
 
@@ -1034,10 +1051,6 @@ abstract class moodle_database {
      */
     public function get_recordset_list($table, $field, array $values, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
         list($select, $params) = $this->where_clause_list($field, $values);
-        if (empty($select)) {
-            $select = '1 = 2'; // Fake condition, won't return rows ever. MDL-17645
-            $params = array();
-        }
         return $this->get_recordset_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
     }
 
@@ -1132,10 +1145,6 @@ abstract class moodle_database {
      */
     public function get_records_list($table, $field, array $values, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
         list($select, $params) = $this->where_clause_list($field, $values);
-        if (empty($select)) {
-            // nothing to return
-            return array();
-        }
         return $this->get_records_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
     }
 
@@ -1662,10 +1671,6 @@ abstract class moodle_database {
      */
     public function delete_records_list($table, $field, array $values) {
         list($select, $params) = $this->where_clause_list($field, $values);
-        if (empty($select)) {
-            // nothing to delete
-            return true;
-        }
         return $this->delete_records_select($table, $select, $params);
     }
 
index a5ad8c2..2bb7270 100644 (file)
@@ -1137,7 +1137,7 @@ class dml_testcase extends database_driver_testcase {
         $tablename = $table->getName();
 
         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0');
         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
         $dbman->create_table($table);
@@ -1146,9 +1146,11 @@ class dml_testcase extends database_driver_testcase {
         $DB->insert_record($tablename, array('course' => 3));
         $DB->insert_record($tablename, array('course' => 5));
         $DB->insert_record($tablename, array('course' => 2));
+        $DB->insert_record($tablename, array('course' => null));
+        $DB->insert_record($tablename, array('course' => 1));
+        $DB->insert_record($tablename, array('course' => 0));
 
         $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
-
         $counter = 0;
         foreach ($rs as $record) {
             $counter++;
@@ -1156,6 +1158,54 @@ class dml_testcase extends database_driver_testcase {
         $this->assertEquals(3, $counter);
         $rs->close();
 
+        $rs = $DB->get_recordset_list($tablename, 'course', array(3));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(2, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(null));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(6, null));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(null, 5, 5, 5));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(2, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(true));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(false));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
         $rs = $DB->get_recordset_list($tablename, 'course',array()); // Must return 0 rows without conditions. MDL-17645
 
         $counter = 0;