MDL-26842 make sure query parameter names are not reserved words in oracle driver

This commit is contained in:
Petr Skoda 2011-03-16 14:58:41 +01:00
parent 56babbcb76
commit 200b4556d7
3 changed files with 61 additions and 4 deletions

View File

@ -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.');
}

View File

@ -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);

View File

@ -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();