mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 07:56:06 +02:00
database MDL-24863
- added restricting text conditions to where_clause , it throws a dml_exception when detected. - also added to where_clause throwing dml_exception for field that doesn't exist in table. - added unit tests for text condition restricting. - added 2 unit tests for set_field_select() testing 'auto-casting params to int problem' fix
This commit is contained in:
parent
fa8f03efbb
commit
011bfd2a54
@ -442,6 +442,7 @@ $string['storedfileproblem'] = 'Unknown exception related to local files ({$a})'
|
||||
$string['tagdisabled'] = 'Tags are disabled!';
|
||||
$string['tagnotfound'] = 'The specified tag was not found in the database';
|
||||
$string['targetdatabasenotempty'] = 'The target database is not empty. Transfer aborted for safety reasons.';
|
||||
$string['textconditionsnotallowed'] = 'Comparisons of text column conditions are not allowed. Please use sql_compare_text() in your query.';
|
||||
$string['themenotinstall'] = 'This theme is not installed!';
|
||||
$string['TODO'] = 'TODO';
|
||||
$string['tokengenerationfailed'] = 'Cannot generate a new token.';
|
||||
|
@ -487,18 +487,31 @@ abstract class moodle_database {
|
||||
|
||||
/**
|
||||
* Returns SQL WHERE conditions.
|
||||
*
|
||||
* @param string $table - the table name that these conditions will be validated against.
|
||||
* @param array conditions - must not contain numeric indexes
|
||||
* @return array sql part and params
|
||||
*/
|
||||
protected function where_clause(array $conditions=null) {
|
||||
protected function where_clause($table, array $conditions=null) {
|
||||
$allowed_types = $this->allowed_param_types();
|
||||
if (empty($conditions)) {
|
||||
return array('', array());
|
||||
}
|
||||
$where = array();
|
||||
$params = array();
|
||||
|
||||
$columns = $this->get_columns($table);
|
||||
foreach ($conditions as $key=>$value) {
|
||||
if (!isset($columns[$key])) {
|
||||
$a = new stdClass();
|
||||
$a->fieldname = $key;
|
||||
$a->tablename = $table;
|
||||
throw new dml_exception('ddlfieldnotexist', $a);
|
||||
}
|
||||
$column = $columns[$key];
|
||||
if ($column->meta_type == 'X') {
|
||||
//ok so the column is a text column. sorry no text columns in the where clause conditions
|
||||
throw new dml_exception('textconditionsnotallowed', $conditions);
|
||||
}
|
||||
if (is_int($key)) {
|
||||
throw new dml_exception('invalidnumkey');
|
||||
}
|
||||
@ -921,7 +934,7 @@ abstract class moodle_database {
|
||||
* @throws dml_exception if error
|
||||
*/
|
||||
public function get_recordset($table, array $conditions=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->get_recordset_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
|
||||
}
|
||||
|
||||
@ -1020,7 +1033,7 @@ abstract class moodle_database {
|
||||
* @throws dml_exception if error
|
||||
*/
|
||||
public function get_records($table, array $conditions=null, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->get_records_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
|
||||
}
|
||||
|
||||
@ -1191,7 +1204,7 @@ abstract class moodle_database {
|
||||
* @throws dml_exception if error
|
||||
*/
|
||||
public function get_record($table, array $conditions, $fields='*', $strictness=IGNORE_MISSING) {
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->get_record_select($table, $select, $params, $fields, $strictness);
|
||||
}
|
||||
|
||||
@ -1272,7 +1285,7 @@ abstract class moodle_database {
|
||||
* @throws dml_exception if error
|
||||
*/
|
||||
public function get_field($table, $return, array $conditions, $strictness=IGNORE_MISSING) {
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->get_field_select($table, $return, $select, $params, $strictness);
|
||||
}
|
||||
|
||||
@ -1424,7 +1437,7 @@ abstract class moodle_database {
|
||||
* @throws dml_exception if error
|
||||
*/
|
||||
public function set_field($table, $newfield, $newvalue, array $conditions=null) {
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->set_field_select($table, $newfield, $newvalue, $select, $params);
|
||||
}
|
||||
|
||||
@ -1451,7 +1464,7 @@ abstract class moodle_database {
|
||||
* @throws dml_exception if error
|
||||
*/
|
||||
public function count_records($table, array $conditions=null) {
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->count_records_select($table, $select, $params);
|
||||
}
|
||||
|
||||
@ -1505,7 +1518,7 @@ abstract class moodle_database {
|
||||
* @throws dml_exception if error
|
||||
*/
|
||||
public function record_exists($table, array $conditions) {
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->record_exists_select($table, $select, $params);
|
||||
}
|
||||
|
||||
@ -1558,7 +1571,7 @@ abstract class moodle_database {
|
||||
if (is_null($conditions)) {
|
||||
return $this->execute("TRUNCATE TABLE {".$table."}");
|
||||
}
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->delete_records_select($table, $select, $params);
|
||||
}
|
||||
|
||||
|
@ -634,6 +634,7 @@ class dml_test extends UnitTestCase {
|
||||
$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_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, '0');
|
||||
$table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
|
||||
$table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
@ -694,6 +695,19 @@ class dml_test extends UnitTestCase {
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext' => '1');
|
||||
try {
|
||||
$rs = $DB->get_recordset($tablename, $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// notes:
|
||||
// * limits are tested in test_get_recordset_sql()
|
||||
// * where_clause() is used internally and is tested in test_get_records()
|
||||
@ -894,6 +908,7 @@ class dml_test extends UnitTestCase {
|
||||
|
||||
$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_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
@ -940,6 +955,19 @@ class dml_test extends UnitTestCase {
|
||||
$records = $DB->get_records($tablename, array('course' => false));
|
||||
$this->assertEqual(0, count($records));
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext' => '1');
|
||||
try {
|
||||
$records = $DB->get_records($tablename, $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// note: delegate limits testing to test_get_records_sql()
|
||||
}
|
||||
|
||||
@ -1251,6 +1279,7 @@ class dml_test extends UnitTestCase {
|
||||
|
||||
$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_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
@ -1276,6 +1305,19 @@ class dml_test extends UnitTestCase {
|
||||
$this->enable_debugging();
|
||||
$this->assertEqual(5, $DB->get_field($tablename, 'course', array('course' => 5), IGNORE_MISSING));
|
||||
$this->assertFalse($this->get_debugging() === '');
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext' => '1');
|
||||
try {
|
||||
$DB->get_field($tablename, 'course', $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function test_get_field_select() {
|
||||
@ -2018,6 +2060,8 @@ class dml_test extends UnitTestCase {
|
||||
|
||||
$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_field('onechar', XMLDB_TYPE_CHAR, '100', null, null, null);
|
||||
$table->add_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
@ -2060,6 +2104,19 @@ class dml_test extends UnitTestCase {
|
||||
$this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id2)));
|
||||
$this->assertEqual(5, $DB->get_field($tablename, 'course', array('id' => $id3)));
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext' => '1');
|
||||
try {
|
||||
$DB->set_field($tablename, 'onechar', 'frog', $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: All the nulls, booleans, empties, quoted and backslashes tests
|
||||
// go to set_field_select() because set_field() is just one wrapper over it
|
||||
}
|
||||
@ -2190,6 +2247,22 @@ class dml_test extends UnitTestCase {
|
||||
$DB->set_field_select($tablename, 'onebinary', $newblob, 'id = ?', array(1));
|
||||
$this->assertEqual($newclob, $DB->get_field($tablename, 'onetext', array('id' => 1)), 'Test "small" CLOB set_field (full contents output disabled)');
|
||||
$this->assertEqual($newblob, $DB->get_field($tablename, 'onebinary', array('id' => 1)), 'Test "small" BLOB set_field (full contents output disabled)');
|
||||
|
||||
// This is the failure from MDL-24863. This was giving an error on MSSQL,
|
||||
// which converts the '1' to an integer, which cannot then be compared with
|
||||
// onetext cast to a varchar. This should be fixed and working now.
|
||||
$newchar = 'frog';
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$params = array('onetext' => '1');
|
||||
try {
|
||||
$DB->set_field_select($tablename, 'onechar', $newchar, $DB->sql_compare_text('onetext') . ' = ?', $params);
|
||||
$this->assertTrue(true, 'No exceptions thrown with numerical text param comparison for text field.');
|
||||
} catch (dml_exception $e) {
|
||||
$this->assertFalse(true, 'We have an unexpected exception.');
|
||||
throw $e;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function test_count_records() {
|
||||
@ -2202,6 +2275,7 @@ class dml_test extends UnitTestCase {
|
||||
|
||||
$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_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
@ -2212,6 +2286,19 @@ class dml_test extends UnitTestCase {
|
||||
$DB->insert_record($tablename, array('course' => 5));
|
||||
|
||||
$this->assertEqual(3, $DB->count_records($tablename));
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext' => '1');
|
||||
try {
|
||||
$DB->count_records($tablename, $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function test_count_records_select() {
|
||||
@ -2266,6 +2353,7 @@ class dml_test extends UnitTestCase {
|
||||
|
||||
$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_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
@ -2276,6 +2364,19 @@ class dml_test extends UnitTestCase {
|
||||
|
||||
$this->assertTrue($DB->record_exists($tablename, array('course' => 3)));
|
||||
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext' => '1');
|
||||
try {
|
||||
$DB->record_exists($tablename, $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function test_record_exists_select() {
|
||||
@ -2327,6 +2428,7 @@ class dml_test extends UnitTestCase {
|
||||
|
||||
$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_field('onetext', XMLDB_TYPE_TEXT, 'big', null, null, null);
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
@ -2349,6 +2451,32 @@ class dml_test extends UnitTestCase {
|
||||
// delete all
|
||||
$this->assertTrue($DB->delete_records($tablename, array()));
|
||||
$this->assertEqual(0, $DB->count_records($tablename));
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext'=>'1');
|
||||
try {
|
||||
$DB->delete_records($tablename, $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// test for exception throwing on text conditions being compared. (MDL-24863, unwanted auto conversion of param to int)
|
||||
$conditions = array('onetext' => 1);
|
||||
try {
|
||||
$DB->delete_records($tablename, $conditions);
|
||||
$this->assertFalse(true, 'An Exception is missing, expected due to equating of text fields');
|
||||
} catch (dml_exception $e) {
|
||||
if ($e->errorcode == 'textconditionsnotallowed') {
|
||||
$this->assertTrue(true, 'The Expected exception was caught.');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function test_delete_records_select() {
|
||||
|
@ -335,7 +335,7 @@ class sqlite3_pdo_moodle_database extends pdo_moodle_database {
|
||||
if (is_null($conditions)) {
|
||||
return $this->execute("DELETE FROM {{$table}}");
|
||||
}
|
||||
list($select, $params) = $this->where_clause($conditions);
|
||||
list($select, $params) = $this->where_clause($table, $conditions);
|
||||
return $this->delete_records_select($table, $select, $params);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user