From 200b4556d705e262839dae3ae021883208f7050f Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Wed, 16 Mar 2011 14:58:41 +0100 Subject: [PATCH] MDL-26842 make sure query parameter names are not reserved words in oracle driver --- lib/dml/moodle_database.php | 2 +- lib/dml/oci_native_moodle_database.php | 38 ++++++++++++++++++++++++-- lib/dml/simpletest/testdml.php | 25 +++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php index b21edf11abd..2d6b2be9ea1 100644 --- a/lib/dml/moodle_database.php +++ b/lib/dml/moodle_database.php @@ -521,7 +521,7 @@ abstract class moodle_database { if ($allowed_types & SQL_PARAMS_NAMED) { // Need to verify key names because they can contain, originally, // spaces and other forbidden chars when using sql_xxx() functions and friends. - $normkey = trim(preg_replace('/[^a-zA-Z0-9-_]/', '_', $key), '-_'); + $normkey = trim(preg_replace('/[^a-zA-Z0-9_-]/', '_', $key), '-_'); if ($normkey !== $key) { debugging('Invalid key found in the conditions array.'); } diff --git a/lib/dml/oci_native_moodle_database.php b/lib/dml/oci_native_moodle_database.php index 1ab255f9781..7c00db1bae7 100644 --- a/lib/dml/oci_native_moodle_database.php +++ b/lib/dml/oci_native_moodle_database.php @@ -340,6 +340,12 @@ class oci_native_moodle_database extends moodle_database { return $error; } + /** + * Prepare the statement for execution + * @throws dml_connection_exception + * @param string $sql + * @return resource + */ protected function parse_query($sql) { $stmt = oci_parse($this->oci, $sql); if ($stmt == false) { @@ -348,6 +354,24 @@ class oci_native_moodle_database extends moodle_database { return $stmt; } + /** + * Make sure there are no reserved words in param names... + * @param string $sql + * @param array $params + * @return array ($sql, $params) updated query and parameters + */ + protected function tweak_param_names($sql, array $params) { + if (empty($params)) { + return array($sql, $params); + } + $newparams = array(); + foreach ($params as $name=>$value) { + $newparams['o_'.$name] = $value; + } + $sql = preg_replace('/:([a-z0-9_-]+[$a-z0-9_-])/', ':o_$1', $sql); + return array($sql, $newparams); + } + /** * Return tables in database WITHOUT current prefix * @return array of table names in lowercase and without prefix @@ -940,6 +964,7 @@ class oci_native_moodle_database extends moodle_database { throw new coding_exception('moodle_database::execute() Multiple sql statements found or bound parameters not used properly in query!'); } + list($sql, $params) = $this->tweak_param_names($sql, $params); $this->query_start($sql, $params, SQL_QUERY_UPDATE); $stmt = $this->parse_query($sql); $this->bind_params($stmt, $params); @@ -1002,7 +1027,8 @@ class oci_native_moodle_database extends moodle_database { list($rawsql, $params) = $this->get_limit_sql($sql, $params, $limitfrom, $limitnum); - $this->query_start($sql, $params, SQL_QUERY_SELECT); + list($rawsql, $params) = $this->tweak_param_names($rawsql, $params); + $this->query_start($rawsql, $params, SQL_QUERY_SELECT); $stmt = $this->parse_query($rawsql); $this->bind_params($stmt, $params); $result = oci_execute($stmt, $this->commit_status); @@ -1035,7 +1061,8 @@ class oci_native_moodle_database extends moodle_database { list($rawsql, $params) = $this->get_limit_sql($sql, $params, $limitfrom, $limitnum); - $this->query_start($sql, $params, SQL_QUERY_SELECT); + list($rawsql, $params) = $this->tweak_param_names($rawsql, $params); + $this->query_start($rawsql, $params, SQL_QUERY_SELECT); $stmt = $this->parse_query($rawsql); $this->bind_params($stmt, $params); $result = oci_execute($stmt, $this->commit_status); @@ -1073,6 +1100,7 @@ class oci_native_moodle_database extends moodle_database { public function get_fieldset_sql($sql, array $params=null) { list($sql, $params, $type) = $this->fix_sql_params($sql, $params); + list($sql, $params) = $this->tweak_param_names($sql, $params); $this->query_start($sql, $params, SQL_QUERY_SELECT); $stmt = $this->parse_query($sql); $this->bind_params($stmt, $params); @@ -1135,11 +1163,12 @@ class oci_native_moodle_database extends moodle_database { $id = null; + list($sql, $params) = $this->tweak_param_names($sql, $params); $this->query_start($sql, $params, SQL_QUERY_INSERT); $stmt = $this->parse_query($sql); $descriptors = $this->bind_params($stmt, $params, $table); if ($returning) { - oci_bind_by_name($stmt, ":oracle_id", $id, 10, SQLT_INT); + oci_bind_by_name($stmt, ":o_oracle_id", $id, 10, SQLT_INT); // :o_ prefix added in tweak_param_names() } $result = oci_execute($stmt, $this->commit_status); $this->free_descriptors($descriptors); @@ -1246,6 +1275,7 @@ class oci_native_moodle_database extends moodle_database { $sql = "UPDATE {" . $table . "} SET $sets WHERE id=:id"; list($sql, $params, $type) = $this->fix_sql_params($sql, $params); + list($sql, $params) = $this->tweak_param_names($sql, $params); $this->query_start($sql, $params, SQL_QUERY_UPDATE); $stmt = $this->parse_query($sql); $descriptors = $this->bind_params($stmt, $params, $table); @@ -1335,6 +1365,7 @@ class oci_native_moodle_database extends moodle_database { $sql = "UPDATE {" . $table . "} SET $newsql $select"; list($sql, $params, $type) = $this->fix_sql_params($sql, $params); + list($sql, $params) = $this->tweak_param_names($sql, $params); $this->query_start($sql, $params, SQL_QUERY_UPDATE); $stmt = $this->parse_query($sql); $descriptors = $this->bind_params($stmt, $params, $table); @@ -1365,6 +1396,7 @@ class oci_native_moodle_database extends moodle_database { list($sql, $params, $type) = $this->fix_sql_params($sql, $params); + list($sql, $params) = $this->tweak_param_names($sql, $params); $this->query_start($sql, $params, SQL_QUERY_UPDATE); $stmt = $this->parse_query($sql); $this->bind_params($stmt, $params); diff --git a/lib/dml/simpletest/testdml.php b/lib/dml/simpletest/testdml.php index 8c8857261e1..0cc09da754b 100644 --- a/lib/dml/simpletest/testdml.php +++ b/lib/dml/simpletest/testdml.php @@ -3711,6 +3711,31 @@ class dml_test extends UnitTestCase { $this->assertEqual(1, count($records)); } + public function test_bound_param_reserved() { + $DB = $this->tdb; + $dbman = $DB->get_manager(); + + $table = $this->get_test_table(); + $tablename = $table->getName(); + + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + $dbman->create_table($table); + + $DB->insert_record($tablename, array('course' => '1')); + + // make sure reserved words do not cause fatal problems in query parameters + + $DB->execute("UPDATE {{$tablename}} SET course = 1 WHERE ID = :select", array('select'=>1)); + $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE course = :select", array('select'=>1)); + $rs = $DB->get_recordset_sql("SELECT * FROM {{$tablename}} WHERE course = :select", array('select'=>1)); + $rs->close(); + $DB->get_fieldset_sql("SELECT id FROM {{$tablename}} WHERE course = :select", array('select'=>1)); + $DB->set_field_select($tablename, 'course', '1', "id = :select", array('select'=>1)); + $DB->delete_records_select($tablename, "id = :select", array('select'=>1)); + } + public function test_limits_and_offsets() { $DB = $this->tdb; $dbman = $DB->get_manager();