Skip to content

Commit

Permalink
MDL-42865 Make XMLDB foreign key check more robust.
Browse files Browse the repository at this point in the history
Otherwise, installing one bad add-on can completely break this report.
  • Loading branch information
timhunt authored and Sam Hemelryk committed Nov 18, 2013
1 parent 8bd0487 commit 99b9368
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
Expand Up @@ -53,6 +53,8 @@ function init() {
'noviolatedforeignkeysfound' => 'tool_xmldb',
'violatedforeignkeysfound' => 'tool_xmldb',
'violations' => 'tool_xmldb',
'unknowntable' => 'tool_xmldb',
'unknownfield' => 'tool_xmldb',
));
}

Expand All @@ -75,13 +77,39 @@ protected function check_table(xmldb_table $xmldb_table, array $metacolumns) {
}
$o.=' <li>' . $this->str['key'] . ': ' . $xmldb_key->readableInfo() . ' ';

$reftable = $xmldb_key->getRefTable();
if (!$dbman->table_exists($reftable)) {
$o.='<font color="red">' . $this->str['unknowntable'] . '</font>';
// Add the missing index to the list
$violation = new stdClass();
$violation->string = 'fkunknowntable';
$violation->table = $xmldb_table;
$violation->key = $xmldb_key;
$violation->reftable = $reftable;
$violatedkeys[] = $violation;
continue;
}

// Work out the SQL to find key violations.
$keyfields = $xmldb_key->getFields();
$reffields = $xmldb_key->getRefFields();
$joinconditions = array();
$nullnessconditions = array();
$params = array();
foreach ($keyfields as $i => $field) {
if (!$dbman->field_exists($reftable, $reffields[$i])) {
$o.='<font color="red">' . $this->str['unknownfield'] . '</font>';
// Add the missing index to the list
$violation = new stdClass();
$violation->string = 'fkunknownfield';
$violation->table = $xmldb_table;
$violation->key = $xmldb_key;
$violation->reftable = $reftable;
$violation->reffield = $reffields[$i];
$violatedkeys[] = $violation;
continue 2;
}

$joinconditions[] = 't1.' . $field . ' = t2.' . $reffields[$i];
$xmldb_field = $xmldb_table->getField($field);
$default = $xmldb_field->getDefault();
Expand All @@ -97,7 +125,7 @@ protected function check_table(xmldb_table $xmldb_table, array $metacolumns) {
}
$nullnessconditions[] = 't2.id IS NULL';
$sql = 'SELECT count(1) FROM {' . $xmldb_table->getName() .
'} t1 LEFT JOIN {' . $xmldb_key->getRefTable() . '} t2 ON ' .
'} t1 LEFT JOIN {' . $reftable . '} t2 ON ' .
implode(' AND ', $joinconditions) . ' WHERE ' .
implode(' AND ', $nullnessconditions);

Expand All @@ -109,6 +137,7 @@ protected function check_table(xmldb_table $xmldb_table, array $metacolumns) {
$o.='<font color="red">' . $this->str['violations'] . '</font>';
// Add the missing index to the list
$violation = new stdClass;
$violation->string = 'fkviolationdetails';
$violation->table = $xmldb_table;
$violation->key = $xmldb_key;
$violation->numviolations = $violations;
Expand Down Expand Up @@ -145,8 +174,11 @@ protected function display_results(array $violatedkeys) {
$violation->tablename = $violation->table->getName();
$violation->keyname = $violation->key->getName();

$r.= ' <li>' .get_string('fkviolationdetails', 'tool_xmldb', $violation) .
'<pre>' . s($violation->sql) . '; ' . s($violation->sqlparams) . '</pre></li>';
$r.= ' <li>' .get_string($violation->string, 'tool_xmldb', $violation);
if (!empty($violation->sql)) {
$r.= '<pre>' . s($violation->sql) . '; ' . s($violation->sqlparams) . '</pre>';
}
$r.= '</li>';
}
$r.= ' </ul>';
} else {
Expand Down
4 changes: 4 additions & 0 deletions admin/tool/xmldb/lang/en/tool_xmldb.php
Expand Up @@ -106,6 +106,8 @@
$string['fieldsusedinkey'] = 'This field is used as key.';
$string['filemodifiedoutfromeditor'] = 'Warning: File locally modified while using the XMLDB Editor. Saving will overwrite local changes.';
$string['filenotwriteable'] = 'File not writeable';
$string['fkunknownfield'] = 'Foreign key {$a->keyname} on table {$a->tablename} points to a non-existent field {$a->reffield} in referenced table {$a->reftable}.';
$string['fkunknowntable'] = 'Foreign key {$a->keyname} on table {$a->tablename} points to a non-existent table {$a->reftable}.';
$string['fkviolationdetails'] = 'Foreign key {$a->keyname} on table {$a->tablename} is violated by {$a->numviolations} out of {$a->numrows} rows.';
$string['floatincorrectdecimals'] = 'Incorrect number of decimals for float field';
$string['floatincorrectlength'] = 'Incorrect length for float field';
Expand Down Expand Up @@ -183,6 +185,8 @@
$string['table'] = 'Table';
$string['tablenameempty'] = 'The table name cannot be empty';
$string['tables'] = 'Tables';
$string['unknownfield'] = 'Refers to an unknown field';
$string['unknowntable'] = 'Refers to an unknown table';
$string['unload'] = 'Unload';
$string['up'] = 'Up';
$string['view'] = 'View';
Expand Down

0 comments on commit 99b9368

Please sign in to comment.