MDL-73763 core : Index fixes for reference tables

This commit will add the index for the question_reference
and the question_set_reference table if its not already
added. This commit will also implement the logic of adding
the question area and component in the joins of the question
reference table in order to make sure any other plugin using
the qbank api does not conflict with each other.
This commit is contained in:
Marc-Alexandre Ghaly 2022-02-25 16:42:26 -05:00 committed by Safat Shahin
parent 0d0f09bc7f
commit c3ac868bf7
15 changed files with 89 additions and 25 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20211221" COMMENT="XMLDB file for core Moodle tables"
<XMLDB PATH="lib/db" VERSION="20220323" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
@ -1476,6 +1476,9 @@
<KEY NAME="usingcontextid" TYPE="foreign" FIELDS="usingcontextid" REFTABLE="context" REFFIELDS="id"/>
<KEY NAME="questionbankentryid" TYPE="foreign" FIELDS="questionbankentryid" REFTABLE="question_bank_entries" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="context-component-area-itemid" UNIQUE="true" FIELDS="usingcontextid, component, questionarea, itemid"/>
</INDEXES>
</TABLE>
<TABLE NAME="question_set_references" COMMENT="Records where groups of questions are used.">
<FIELDS>
@ -1492,6 +1495,9 @@
<KEY NAME="usingcontextid" TYPE="foreign" FIELDS="usingcontextid" REFTABLE="context" REFFIELDS="id"/>
<KEY NAME="questionscontextid" TYPE="foreign" FIELDS="questionscontextid" REFTABLE="context" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="context-component-area-itemid" UNIQUE="true" FIELDS="usingcontextid, component, questionarea, itemid"/>
</INDEXES>
</TABLE>
<TABLE NAME="question_answers" COMMENT="Answers, with a fractional grade (0-1) and feedback">
<FIELDS>

View File

@ -4253,5 +4253,37 @@ privatefiles,moodle|/user/files.php';
upgrade_main_savepoint(true, 2022031100.01);
}
if ($oldversion < 2022031800.01) {
// Define index to be added to question_references.
$table = new xmldb_table('question_references');
$index = new xmldb_index('context-component-area-itemid', XMLDB_INDEX_UNIQUE,
['usingcontextid', 'component', 'questionarea', 'itemid']);
// Conditionally launch add field id.
if (!$dbman->index_exists($table, $index)) {
$dbman->add_index($table, $index);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2022031800.01);
}
if ($oldversion < 2022031800.02) {
// Define index to be added to question_references.
$table = new xmldb_table('question_set_references');
$index = new xmldb_index('context-component-area-itemid', XMLDB_INDEX_UNIQUE,
['usingcontextid', 'component', 'questionarea', 'itemid']);
// Conditionally launch add field id.
if (!$dbman->index_exists($table, $index)) {
$dbman->add_index($table, $index);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2022031800.02);
}
return true;
}

View File

@ -435,7 +435,8 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
$data->tagname = $tag->name;
}
$tagstring = "{$data->tagid},{$data->tagname}";
$setreferencedata = $DB->get_record('question_set_references', ['itemid' => $slotid]);
$setreferencedata = $DB->get_record('question_set_references',
['itemid' => $slotid, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
$filtercondition = json_decode($setreferencedata->filtercondition);
$tagstrings = [];

View File

@ -70,7 +70,8 @@ class submit_question_version extends external_api {
$params = self::validate_parameters(self::execute_parameters(), $params);
$response = ['result' => false];
// Get the required data.
$referencedata = $DB->get_record('question_references', ['itemid' => $params['slotid']]);
$referencedata = $DB->get_record('question_references',
['itemid' => $params['slotid'], 'component' => 'mod_quiz', 'questionarea' => 'slot']);
$slotdata = $DB->get_record('quiz_slots', ['id' => $slotid]);
// Capability check.

View File

@ -400,7 +400,8 @@ class qbank_helper {
$alwaysuselatest->version = 0;
$alwaysuselatest->versionvalue = get_string('alwayslatest', 'quiz');
array_unshift($versionsoptions, $alwaysuselatest);
$referencedata = $DB->get_record('question_references', ['itemid' => $slotid]);
$referencedata = $DB->get_record('question_references',
['itemid' => $slotid, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
if (!isset($referencedata->version) || ($referencedata->version === null)) {
$currentversion = 0;
} else {

View File

@ -661,7 +661,8 @@ class structure {
foreach ($slots as $slot) {
if ($slot->qtype === null) {
// Check if the question is random.
if ($setreference = $DB->get_record('question_set_references', ['itemid' => $slot->slotid])) {
if ($setreference = $DB->get_record('question_set_references',
['itemid' => $slot->slotid, 'component' => 'mod_quiz', 'questionarea' => 'slot'])) {
$filtercondition = json_decode($setreference->filtercondition);
$slot->id = $slot->slotid;
$slot->category = $filtercondition->questioncategoryid;
@ -965,7 +966,8 @@ class structure {
$questionsetreference = $DB->get_record('question_set_references',
['component' => 'mod_quiz', 'questionarea' => 'slot', 'itemid' => $slot->id]);
if ($questionsetreference) {
$DB->delete_records('question_set_references', ['id' => $questionsetreference->id]);
$DB->delete_records('question_set_references',
['id' => $questionsetreference->id, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
}
$DB->delete_records('quiz_slots', array('id' => $slot->id));
for ($i = $slot->slot + 1; $i <= $maxslot; $i++) {

View File

@ -54,7 +54,8 @@ $PAGE->set_url($url);
$PAGE->set_pagelayout('admin');
$PAGE->add_body_class('limitedwidth');
$setreference = $DB->get_record('question_set_references', ['itemid' => $slot->id]);
$setreference = $DB->get_record('question_set_references',
['itemid' => $slot->id, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
$filterconditions = json_decode($setreference->filtercondition);
// Validate the question category.

View File

@ -1435,12 +1435,16 @@ function quiz_get_post_actions() {
function quiz_questions_in_use($questionids) {
global $DB;
list($test, $params) = $DB->get_in_or_equal($questionids);
$params['component'] = 'mod_quiz';
$params['questionarea'] = 'slot';
$sql = "SELECT qs.id
FROM {quiz_slots} qs
JOIN {question_references} qr ON qr.itemid = qs.id
JOIN {question_bank_entries} qbe ON qbe.id = qr.questionbankentryid
JOIN {question_versions} qv ON qv.questionbankentryid = qbe.id
WHERE qv.questionid $test";
WHERE qv.questionid $test
AND qr.component = ?
AND qr.questionarea = ?";
return $DB->record_exists_sql($sql, $params) || question_engine::questions_in_use(
$questionids, new qubaid_join('{quiz_attempts} quiza',
'quiza.uniqueid', 'quiza.preview = 0'));

View File

@ -2260,9 +2260,12 @@ function quiz_has_question_use($quiz, $slot) {
JOIN {question_bank_entries} qbe ON qbe.id = qre.questionbankentryid
JOIN {question_versions} qve ON qve.questionbankentryid = qbe.id
JOIN {question} q ON q.id = qve.questionid
WHERE slot.quizid = ? AND slot.slot = ?';
WHERE slot.quizid = ?
AND slot.slot = ?
AND qre.component = ?
AND qre.questionarea = ?';
$question = $DB->get_record_sql($sql, [$quiz->id, $slot]);
$question = $DB->get_record_sql($sql, [$quiz->id, $slot, 'mod_quiz', 'slot']);
if (!$question) {
return false;
@ -2306,9 +2309,11 @@ function quiz_add_quiz_question($questionid, $quiz, $page = 0, $maxmark = null)
FROM {quiz_slots} slot
JOIN {question_references} qr ON qr.itemid = slot.id
JOIN {question_bank_entries} qbe ON qbe.id = qr.questionbankentryid
WHERE slot.quizid = ?";
WHERE slot.quizid = ?
AND qr.component = ?
AND qr.questionarea = ?";
$questionslots = $DB->get_records_sql($sql, [$quiz->id]);
$questionslots = $DB->get_records_sql($sql, [$quiz->id, 'mod_quiz', 'slot']);
$currententry = get_question_bank_entry($questionid);
@ -2385,8 +2390,10 @@ function quiz_add_quiz_question($questionid, $quiz, $page = 0, $maxmark = null)
JOIN {question_references} qr ON qbe.id = qr.questionbankentryid AND qr.version = qv.version
JOIN {quiz_slots} qs ON qs.id = qr.itemid
WHERE q.id = ?
AND qs.id =?";
$qreferenceitem = $DB->get_record_sql($sql, [$questionid, $slotid]);
AND qs.id = ?
AND qr.component = ?
AND qr.questionarea = ?";
$qreferenceitem = $DB->get_record_sql($sql, [$questionid, $slotid, 'mod_quiz', 'slot']);
if (!$qreferenceitem) {
// Create a new reference record for questions created already.

View File

@ -706,8 +706,10 @@ class mod_quiz_structure_testcase extends advanced_testcase {
$sql = 'SELECT qsr.*
FROM {question_set_references} qsr
JOIN {quiz_slots} qs ON qs.id = qsr.itemid
WHERE qs.quizid = ?';
$randomq = $DB->get_record_sql($sql, [$quizobj->get_quizid()]);
WHERE qs.quizid = ?
AND qsr.component = ?
AND qsr.questionarea = ?';
$randomq = $DB->get_record_sql($sql, [$quizobj->get_quizid(), 'mod_quiz', 'slot']);
$structure->remove_slot(2);
@ -715,7 +717,8 @@ class mod_quiz_structure_testcase extends advanced_testcase {
$this->assert_quiz_layout(array(
array('TF1', 1, 'truefalse'),
), $structure);
$this->assertFalse($DB->record_exists('question_set_references', array('id' => $randomq->id)));
$this->assertFalse($DB->record_exists('question_set_references',
array('id' => $randomq->id, 'component' => 'mod_quiz', 'questionarea' => 'slot')));
}
/**

View File

@ -80,7 +80,8 @@ class mod_quiz_tags_testcase extends advanced_testcase {
$defaultcategory = question_get_default_category(context_course::instance($newcourseid)->id);
$this->assertEquals($defaultcategory->id, $question->categoryobject->id);
$randomincludingsubcategories = $DB->get_record('question_set_references', ['itemid' => reset($slots)->id]);
$randomincludingsubcategories = $DB->get_record('question_set_references',
['itemid' => reset($slots)->id, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
$filtercondition = json_decode($randomincludingsubcategories->filtercondition);
$this->assertEquals(0, $filtercondition->includingsubcategories);
}

View File

@ -88,8 +88,10 @@ class helper_test extends \advanced_testcase {
$q2d = $DB->get_record_sql("SELECT qsr.*
FROM {quiz_slots} qs
JOIN {question_set_references} qsr ON qsr.itemid = qs.id
WHERE qs.quizid = ?",
['quizid' => $this->quiz->id], MUST_EXIST);
WHERE qs.quizid = ?
AND qsr.component = ?
AND qsr.questionarea = ?",
[$this->quiz->id, 'mod_quiz', 'slot'], MUST_EXIST);
// The following 2 lines have to be after the quiz_add_random_questions() call above.
// Otherwise, quiz_add_random_questions() will to be "smart" and use them instead of creating a new "random" question.
@ -138,7 +140,8 @@ class helper_test extends \advanced_testcase {
$this->assertFalse($DB->record_exists('question', ['id' => $q2a->id]));
$this->assertTrue($DB->record_exists('question', ['id' => $q2b->id]));
$this->assertFalse($DB->record_exists('question', ['id' => $q2c->id]));
$this->assertTrue($DB->record_exists('question_set_references', ['id' => $q2d->id]));
$this->assertTrue($DB->record_exists('question_set_references',
['id' => $q2d->id, 'component' => 'mod_quiz', 'questionarea' => 'slot']));
}
/**

View File

@ -37,7 +37,7 @@ class helper {
$sql = 'SELECT COUNT(*) FROM (' . self::question_usage_sql() . ') quizid';
return $DB->count_records_sql($sql, [$question->id, $question->questionbankentryid]);
return $DB->count_records_sql($sql, [$question->id, $question->questionbankentryid, 'mod_quiz', 'slot']);
}
/**
@ -65,7 +65,9 @@ class helper {
JOIN {question_references} qr ON qr.itemid = slot.id
JOIN {question_bank_entries} qbe ON qbe.id = qr.questionbankentryid
JOIN {question_versions} qv ON qv.questionbankentryid = qbe.id
WHERE qv.questionbankentryid = ?)";
WHERE qv.questionbankentryid = ?
AND qr.component = ?
AND qr.questionarea = ?)";
return $sqlset;
}

View File

@ -84,7 +84,7 @@ class question_usage_table extends table_sql {
}
$sql = helper::question_usage_sql();
$params = [$this->question->id, $this->question->questionbankentryid];
$params = [$this->question->id, $this->question->questionbankentryid, 'mod_quiz', 'slot'];
if (!$this->is_downloading()) {
$this->rawdata = $DB->get_records_sql($sql, $params, $this->get_page_start(), $this->get_page_size());

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2022031800.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2022031800.02; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '4.0beta+ (Build: 20220318)'; // Human-friendly version name