Skip to content

Commit

Permalink
Merge branch 'm34_MDL-59635_Properly_Escape_Column_Names_Reserved_Wor…
Browse files Browse the repository at this point in the history
  • Loading branch information
junpataleta authored and David Monllao committed Sep 7, 2017
2 parents dd04df4 + ea34d02 commit 305f38d
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 6 deletions.
49 changes: 49 additions & 0 deletions lib/ddl/tests/ddl_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -2115,6 +2115,55 @@ public function test_object_name() {
}
}

/**
* Data provider for test_get_enc_quoted().
*
* @return array The type-value pair fixture.
*/
public function test_get_enc_quoted_provider() {
return array(
// Reserved: some examples from SQL-92.
[true, 'from'],
[true, 'table'],
[true, 'where'],
// Not reserved.
[false, 'my_awesome_column_name']
);
}

/**
* This is a test for sql_generator::getEncQuoted().
*
* @dataProvider test_get_enc_quoted_provider
* @param string $reserved Whether the column name is reserved or not.
* @param string $columnname The column name to be quoted, according to the value of $reserved.
**/
public function test_get_enc_quoted($reserved, $columnname) {
$DB = $this->tdb;
$gen = $DB->get_manager()->generator;

if (!$reserved) {
// No need to quote the column name.
$this->assertSame($columnname, $gen->getEncQuoted($columnname));
} else {
// Column name should be quoted.
$dbfamily = $DB->get_dbfamily();

switch ($dbfamily) {
case 'mysql':
$this->assertSame("`$columnname`", $gen->getEncQuoted($columnname));
break;
case 'mssql': // The Moodle connection runs under 'QUOTED_IDENTIFIER ON'.
case 'oracle':
case 'postgres':
case 'sqlite':
default:
$this->assertSame('"' . $columnname . '"', $gen->getEncQuoted($columnname));
break;
}
}
}

// Following methods are not supported == Do not test.
/*
public function testRenameIndex() {
Expand Down
3 changes: 2 additions & 1 deletion lib/dml/moodle_database.php
Original file line number Diff line number Diff line change
Expand Up @@ -2398,7 +2398,8 @@ public function replace_all_text($table, database_column_info $column, $search,
// NOTE: override this methods if following standard compliant SQL
// does not work for your driver.

$columnname = $column->name;
// Enclose the column name by the proper quotes if it's a reserved word.
$columnname = $this->get_manager()->generator->getEncQuoted($column->name);
$sql = "UPDATE {".$table."}
SET $columnname = REPLACE($columnname, ?, ?)
WHERE $columnname IS NOT NULL";
Expand Down
46 changes: 41 additions & 5 deletions lib/dml/tests/dml_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -4573,19 +4573,55 @@ public function test_replace_all_text() {
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('name', XMLDB_TYPE_CHAR, '20', null, null);
$table->add_field('intro', XMLDB_TYPE_TEXT, 'big', null, null);
// Add a CHAR field named using a word reserved for all the supported DB servers.
$table->add_field('where', XMLDB_TYPE_CHAR, '20', null, null, null, 'localhost');
// Add a TEXT field named using a word reserved for all the supported DB servers.
$table->add_field('from', XMLDB_TYPE_TEXT, 'big', null, null);
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$dbman->create_table($table);

$id1 = (string)$DB->insert_record($tablename, array('name' => null, 'intro' => null));
$id2 = (string)$DB->insert_record($tablename, array('name' => '', 'intro' => ''));
$id3 = (string)$DB->insert_record($tablename, array('name' => 'xxyy', 'intro' => 'vvzz'));
$id4 = (string)$DB->insert_record($tablename, array('name' => 'aa bb aa bb', 'intro' => 'cc dd cc aa'));
$id5 = (string)$DB->insert_record($tablename, array('name' => 'kkllll', 'intro' => 'kkllll'));
$fromfield = $dbman->generator->getEncQuoted('from');
$DB->execute("INSERT INTO {".$tablename."} (name,intro,$fromfield) VALUES (NULL,NULL,'localhost')");
$DB->execute("INSERT INTO {".$tablename."} (name,intro,$fromfield) VALUES ('','','localhost')");
$DB->execute("INSERT INTO {".$tablename."} (name,intro,$fromfield) VALUES ('xxyy','vvzz','localhost')");
$DB->execute("INSERT INTO {".$tablename."} (name,intro,$fromfield) VALUES ('aa bb aa bb','cc dd cc aa','localhost')");
$DB->execute("INSERT INTO {".$tablename."} (name,intro,$fromfield) VALUES ('kkllll','kkllll','localhost')");

$expected = $DB->get_records($tablename, array(), 'id ASC');
$idx = 1;
$id1 = $id2 = $id3 = $id4 = $id5 = 0;
foreach (array_keys($expected) as $identifier) {
${"id$idx"} = (string)$identifier;
$idx++;
}

$columns = $DB->get_columns($tablename);

// Replace should work even with columns named using a reserved word.
$this->assertEquals('C', $columns['where']->meta_type);
$this->assertEquals('localhost', $expected[$id1]->where);
$this->assertEquals('localhost', $expected[$id2]->where);
$this->assertEquals('localhost', $expected[$id3]->where);
$this->assertEquals('localhost', $expected[$id4]->where);
$this->assertEquals('localhost', $expected[$id5]->where);
$DB->replace_all_text($tablename, $columns['where'], 'localhost', '::1');
$result = $DB->get_records($tablename, array(), 'id ASC');
$expected[$id1]->where = '::1';
$expected[$id2]->where = '::1';
$expected[$id3]->where = '::1';
$expected[$id4]->where = '::1';
$expected[$id5]->where = '::1';
$this->assertEquals($expected, $result);
$this->assertEquals('X', $columns['from']->meta_type);
$DB->replace_all_text($tablename, $columns['from'], 'localhost', '127.0.0.1');
$result = $DB->get_records($tablename, array(), 'id ASC');
$expected[$id1]->from = '127.0.0.1';
$expected[$id2]->from = '127.0.0.1';
$expected[$id3]->from = '127.0.0.1';
$expected[$id4]->from = '127.0.0.1';
$expected[$id5]->from = '127.0.0.1';
$this->assertEquals($expected, $result);

$DB->replace_all_text($tablename, $columns['name'], 'aa', 'o');
$result = $DB->get_records($tablename, array(), 'id ASC');
$expected[$id4]->name = 'o bb o bb';
Expand Down

0 comments on commit 305f38d

Please sign in to comment.