diff --git a/lib/ddl/tests/ddl_test.php b/lib/ddl/tests/ddl_test.php index edf62587b50..1fbec981908 100644 --- a/lib/ddl/tests/ddl_test.php +++ b/lib/ddl/tests/ddl_test.php @@ -2115,6 +2115,55 @@ class core_ddl_testcase extends database_driver_testcase { } } + /** + * 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() { diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php index 3dd35869b15..874182345be 100644 --- a/lib/dml/moodle_database.php +++ b/lib/dml/moodle_database.php @@ -2398,7 +2398,8 @@ abstract class moodle_database { // 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"; diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php index 849fbf3e25b..87865851c35 100644 --- a/lib/dml/tests/dml_test.php +++ b/lib/dml/tests/dml_test.php @@ -4573,19 +4573,55 @@ class core_dml_testcase extends database_driver_testcase { $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';