MDL-47176 qtype_match: Avoid sql_compare to solve problems with Oracle
authorPau Ferrer Ocaña <crazyserver@gmail.com>
Thu, 11 Dec 2014 11:38:36 +0000 (12:38 +0100)
committercrazyserver <crazyserver@gmail.com>
Fri, 12 Dec 2014 13:30:58 +0000 (14:30 +0100)
question/type/match/backup/moodle2/restore_qtype_match_plugin.class.php

index 8f8bcee..e40bea4 100644 (file)
@@ -34,6 +34,19 @@ defined('MOODLE_INTERNAL') || die();
  */
 class restore_qtype_match_plugin extends restore_qtype_plugin {
 
+    /**
+     * A simple answer, questiontext to id cache for a match answers.
+     * @var array
+     */
+    private $questionsubcache = array();
+
+    /**
+     * The id of the current question in the questionsubcache.
+     * @var int
+     */
+    private $questionsubcacheid = null;
+
+
     /**
      * Returns the paths to be handled by the plugin at question level.
      */
@@ -119,7 +132,6 @@ class restore_qtype_match_plugin extends restore_qtype_plugin {
             // Insert record.
             $newitemid = $DB->insert_record('qtype_match_subquestions', $data);
             // Create mapping (there are files and states based on this).
-            $this->set_mapping('qtype_match_subquestions', $oldid, $newitemid);
             if (isset($data->code)) {
                 $this->set_mapping('qtype_match_subquestion_codes', $data->code, $newitemid);
             }
@@ -128,18 +140,17 @@ class restore_qtype_match_plugin extends restore_qtype_plugin {
             // Match questions require mapping of qtype_match_subquestions, because
             // they are used by question_states->answer.
 
-            // Look for matching subquestion (by questionid, questiontext and answertext).
-            $sub = $DB->get_record_select('qtype_match_subquestions', 'questionid = ? AND ' .
-                    $DB->sql_compare_text('questiontext') . ' = ' .
-                    $DB->sql_compare_text('?').' AND answertext = ?',
-                            array($newquestionid, $data->questiontext, $data->answertext),
-                            'id', IGNORE_MULTIPLE);
+            // Have we cached the current question?
+            if ($this->questionsubcacheid !== $newquestionid) {
+                // The question changed, purge and start again!
+                $this->questionsubcache = array();
 
-            // Not able to find the answer, let's try cleaning the answertext
-            // of all the match subquestions in DB as slower fallback. MDL-36683 / MDL-30018.
-            if (!$sub) {
+                $params = array('question' => $newquestionid);
                 $potentialsubs = $DB->get_records('qtype_match_subquestions',
-                        array('questionid' => $newquestionid), '', 'id, questiontext, answertext');
+                    array('questionid' => $newquestionid), '', 'id, questiontext, answertext');
+
+                $this->questionsubcacheid = $newquestionid;
+                // Cache all cleaned answers and questiontext.
                 foreach ($potentialsubs as $potentialsub) {
                     // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
                     $cleanquestion = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is',
@@ -150,19 +161,18 @@ class restore_qtype_match_plugin extends restore_qtype_plugin {
                             '', $potentialsub->answertext); // Clean CTRL chars.
                     $cleananswer = preg_replace("/\r\n|\r/", "\n", $cleananswer); // Normalize line ending.
 
-                    if ($cleanquestion === $data->questiontext && $cleananswer == $data->answertext) {
-                        $sub = $potentialsub;
-                    }
+                    $this->questionsubcache[$cleanquestion][$cleananswer] = $potentialsub->id;
                 }
             }
 
-            // Found one. Let's create the mapping.
-            if ($sub) {
-                $this->set_mapping('qtype_match_subquestions', $oldid, $sub->id);
-            } else {
+            if (!isset($this->questionsubcache[$data->questiontext][$data->answertext])) {
                 throw new restore_step_exception('error_qtype_match_subquestion_missing_in_db', $data);
             }
+            $newitemid = $this->questionsubcache[$data->questiontext][$data->answertext];
         }
+
+        // Found one. Let's create the mapping.
+        $this->set_mapping('qtype_match_subquestions', $oldid, $newitemid);
     }
 
     public function recode_response($questionid, $sequencenumber, array $response) {