Permalink
Browse files

MDL-26842 make sure query parameter names are not reserved words in o…

…racle driver
  • Loading branch information...
skodak committed Mar 16, 2011
1 parent 56babbc commit 200b4556d705e262839dae3ae021883208f7050f
Showing with 61 additions and 4 deletions.
  1. +1 −1 lib/dml/moodle_database.php
  2. +35 −3 lib/dml/oci_native_moodle_database.php
  3. +25 −0 lib/dml/simpletest/testdml.php
@@ -521,7 +521,7 @@ protected function where_clause($table, array $conditions=null) {
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.');
}
@@ -340,6 +340,12 @@ public function get_last_error() {
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 @@ protected function parse_query($sql) {
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 @@ public function execute($sql, array $params=null) {
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 @@ public function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limit
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 @@ public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnu
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 @@ public function get_records_sql($sql, array $params=null, $limitfrom=0, $limitnu
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 @@ public function insert_record_raw($table, $params, $returnid=true, $bulk=false,
$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 @@ public function update_record_raw($table, $params, $bulk=false) {
$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 @@ public function set_field_select($table, $newfield, $newvalue, $select, array $p
$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 @@ public function delete_records_select($table, $select, 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_UPDATE);
$stmt = $this->parse_query($sql);
$this->bind_params($stmt, $params);
@@ -3711,6 +3711,31 @@ public function test_bound_param_types() {
$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();

0 comments on commit 200b455

Please sign in to comment.