diff --git a/blocks/rss_client/edit_form.php b/blocks/rss_client/edit_form.php index 922734a3e24..e696c460ccc 100644 --- a/blocks/rss_client/edit_form.php +++ b/blocks/rss_client/edit_form.php @@ -54,7 +54,7 @@ class block_rss_client_edit_form extends block_edit_form { FROM {block_rss_client} WHERE userid = ? OR shared = 1 ORDER BY CASE WHEN preferredtitle = ? THEN ' . $DB->sql_compare_text('title', 64) . ' ELSE preferredtitle END ', - array($DB->sql_empty(), $USER->id, $DB->sql_empty())); + array('', $USER->id, '')); if ($rssfeeds) { $select = $mform->addElement('select', 'config_rssid', get_string('choosefeedlabel', 'block_rss_client'), $rssfeeds); $select->setMultiple(true); diff --git a/cohort/lib.php b/cohort/lib.php index 19441a51749..61d56c955ce 100644 --- a/cohort/lib.php +++ b/cohort/lib.php @@ -40,7 +40,6 @@ function cohort_add_cohort($cohort) { $cohort->idnumber = NULL; } if (!isset($cohort->description)) { - // sql_empty() does not belong here, this crazy Oracle hack is implemented in insert_record()! $cohort->description = ''; } if (!isset($cohort->descriptionformat)) { diff --git a/enrol/database/lib.php b/enrol/database/lib.php index 5a888596782..fc57b58358c 100644 --- a/enrol/database/lib.php +++ b/enrol/database/lib.php @@ -407,7 +407,7 @@ class enrol_database_plugin extends enrol_plugin { $localnotempty = ""; if ($localcoursefield !== 'id') { $localnotempty = "AND c.$localcoursefield <> :lcfe"; - $params['lcfe'] = $DB->sql_empty(); + $params['lcfe'] = ''; } $sql = "SELECT c.id, c.visible, c.$localcoursefield AS mapping, c.shortname FROM {course} c diff --git a/enrol/manual/locallib.php b/enrol/manual/locallib.php index 80631b24260..5c3e3459361 100644 --- a/enrol/manual/locallib.php +++ b/enrol/manual/locallib.php @@ -411,7 +411,7 @@ function enrol_manual_migrate_plugin_enrolments($enrol) { } // First delete potential role duplicates. - $params = array('id'=>$e->id, 'component'=>'enrol_'.$enrol, 'empty'=>$DB->sql_empty()); + $params = array('id'=>$e->id, 'component'=>'enrol_'.$enrol, 'empty'=>''); $sql = "SELECT ra.id FROM {role_assignments} ra JOIN {role_assignments} mra ON (mra.contextid = ra.contextid AND mra.userid = ra.userid AND mra.roleid = ra.roleid AND mra.component = :empty AND mra.itemid = 0) @@ -425,7 +425,7 @@ function enrol_manual_migrate_plugin_enrolments($enrol) { $sql = "UPDATE {role_assignments} SET itemid = 0, component = :empty WHERE itemid = :id AND component = :component"; - $params = array('empty'=>$DB->sql_empty(), 'id'=>$e->id, 'component'=>'enrol_'.$enrol); + $params = array('empty'=>'', 'id'=>$e->id, 'component'=>'enrol_'.$enrol); $DB->execute($sql, $params); // Delete potential enrol duplicates. diff --git a/enrol/manual/tests/lib_test.php b/enrol/manual/tests/lib_test.php index 9212b338190..77ffc6b6220 100644 --- a/enrol/manual/tests/lib_test.php +++ b/enrol/manual/tests/lib_test.php @@ -151,11 +151,11 @@ class enrol_manual_lib_testcase extends advanced_testcase { $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance1->id, 'userid'=>$user4->id, 'status'=>ENROL_USER_ACTIVE))); $this->assertEquals(4, $DB->count_records('user_enrolments', array('enrolid'=>$maninstance1->id))); $this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance1->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context1->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user2->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user3->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context1->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user4->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user1->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context1->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user2->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user3->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context1->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user4->id, 'roleid'=>$studentrole->id, 'contextid'=>$context1->id))); $this->assertEquals(5, $DB->count_records('role_assignments', array('contextid'=>$context1->id))); @@ -173,7 +173,7 @@ class enrol_manual_lib_testcase extends advanced_testcase { $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance3->id, 'userid'=>$user2->id, 'status'=>ENROL_USER_SUSPENDED))); $this->assertEquals(2, $DB->count_records('user_enrolments', array('enrolid'=>$maninstance3->id))); $this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance3->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context3->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context3->id))); $this->assertEquals(1, $DB->count_records('role_assignments', array('contextid'=>$context3->id))); @@ -187,10 +187,10 @@ class enrol_manual_lib_testcase extends advanced_testcase { $this->assertEquals(3, $DB->count_records('user_enrolments', array('enrolid'=>$maninstance4->id))); $this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance4->id))); $this->assertEquals(0, $DB->count_records('user_enrolments', array('enrolid'=>$xxxinstance4b->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context4->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user1->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context4->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user2->id, 'roleid'=>$studentrole->id, 'contextid'=>$context4->id))); - $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>$DB->sql_empty(), 'userid'=>$user4->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context4->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user1->id, 'roleid'=>$studentrole->id, 'contextid'=>$context4->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user1->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context4->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user2->id, 'roleid'=>$studentrole->id, 'contextid'=>$context4->id))); + $this->assertTrue($DB->record_exists('role_assignments', array('itemid'=>0, 'component'=>'', 'userid'=>$user4->id, 'roleid'=>$teacherrole->id, 'contextid'=>$context4->id))); $this->assertEquals(4, $DB->count_records('role_assignments', array('contextid'=>$context4->id))); diff --git a/enrol/meta/locallib.php b/enrol/meta/locallib.php index fa3125cb20e..3d16b0e2414 100644 --- a/enrol/meta/locallib.php +++ b/enrol/meta/locallib.php @@ -569,7 +569,7 @@ function enrol_meta_sync($courseid = NULL, $verbose = false) { } $enabled[$k] = 'enrol_'.$v; } - $enabled[] = $DB->sql_empty(); // manual assignments are replicated too + $enabled[] = ''; // manual assignments are replicated too $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e'); diff --git a/lib/accesslib.php b/lib/accesslib.php index 4b7432d6bea..7d179745e57 100644 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -1634,8 +1634,6 @@ function role_assign($roleid, $userid, $contextid, $component = '', $itemid = 0, } // Check for existing entry - // TODO: Revisit this sql_empty() use once Oracle bindings are improved. MDL-29765 - $component = ($component === '') ? $DB->sql_empty() : $component; $ras = $DB->get_records('role_assignments', array('roleid'=>$roleid, 'contextid'=>$context->id, 'userid'=>$userid, 'component'=>$component, 'itemid'=>$itemid), 'id'); if ($ras) { @@ -1748,10 +1746,6 @@ function role_unassign_all(array $params, $subcontexts = false, $includemanual = } } - // TODO: Revisit this sql_empty() use once Oracle bindings are improved. MDL-29765 - if (isset($params['component'])) { - $params['component'] = ($params['component'] === '') ? $DB->sql_empty() : $params['component']; - } $ras = $DB->get_records('role_assignments', $params); foreach($ras as $ra) { $DB->delete_records('role_assignments', array('id'=>$ra->id)); diff --git a/lib/blocklib.php b/lib/blocklib.php index f37441425e0..f96ae319203 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -587,8 +587,8 @@ class block_manager { 'pagetype' => $this->page->pagetype, ); if ($this->page->subpage === '') { - $params['subpage1'] = $DB->sql_empty(); - $params['subpage2'] = $DB->sql_empty(); + $params['subpage1'] = ''; + $params['subpage2'] = ''; } $sql = "SELECT bi.id, diff --git a/lib/datalib.php b/lib/datalib.php index 266877636b6..9d257480060 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -853,7 +853,8 @@ function get_courses_search($searchterms, $sort, $page, $recordsperpage, &$total if ($DB->get_dbfamily() == 'oracle') { $concat = $DB->sql_concat('c.summary', "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname'); } else { - $concat = $DB->sql_concat("COALESCE(c.summary, '". $DB->sql_empty() ."')", "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname'); + $concat = $DB->sql_concat("COALESCE(c.summary, :empty)", "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname'); + $params['empty'] = ''; } foreach ($searchterms as $searchterm) { diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php index 3dc9c55a864..c7753a50f2c 100644 --- a/lib/dml/moodle_database.php +++ b/lib/dml/moodle_database.php @@ -2012,12 +2012,14 @@ abstract class moodle_database { } /** - * Returns the empty string char used by every supported DB. To be used when - * we are searching for that values in our queries. Only Oracle uses this - * for now (will be out, once we migrate to proper NULLs if that days arrives) + * This used to return empty string replacement character. + * + * @deprecated use bound parameter with empty string instead + * * @return string An empty string. */ function sql_empty() { + debugging("sql_empty() is deprecated, please use empty string '' as sql parameter value instead", DEBUG_DEVELOPER); return ''; } @@ -2036,9 +2038,13 @@ abstract class moodle_database { * * ... AND fieldname = ''; * - * are being used. Final result should be: + * are being used. Final result for text fields should be: * - * ... AND ' . sql_isempty('tablename', 'fieldname', true/false, true/false); + * ... AND ' . sql_isempty('tablename', 'fieldname', true/false, true); + * + * and for varchar fields result should be: + * + * ... AND fieldname = :empty; "; $params['empty'] = ''; * * (see parameters description below) * @@ -2066,10 +2072,14 @@ abstract class moodle_database { * * ... AND fieldname != ''; * - * are being used. Final result should be: + * are being used. Final result for text fields should be: * * ... AND ' . sql_isnotempty('tablename', 'fieldname', true/false, true/false); * + * and for varchar fields result should be: + * + * ... AND fieldname != :empty; "; $params['empty'] = ''; + * * (see parameters description below) * * @param string $tablename Name of the table (without prefix). This is not used for now but can be diff --git a/lib/dml/oci_native_moodle_database.php b/lib/dml/oci_native_moodle_database.php index eaafb543439..012dc239732 100644 --- a/lib/dml/oci_native_moodle_database.php +++ b/lib/dml/oci_native_moodle_database.php @@ -52,9 +52,7 @@ class oci_native_moodle_database extends moodle_database { /** @var To store unique_session_id. Needed for temp tables unique naming.*/ private $unique_session_id; /** @var To cache locks support along the connection life.*/ - private $dblocks_supported = null; - /** @var To cache bitwise operations support along the connection life.*/ - private $bitwise_supported = null; + private $oci_package_installed = null; /** * Detects if all needed PHP stuff installed. @@ -129,7 +127,7 @@ class oci_native_moodle_database extends moodle_database { * @return string null means everything ok, string means problem found. */ public function diagnose() { - if (!$this->bitwise_supported() or !$this->session_lock_supported()) { + if (!$this->oci_package_installed()) { return 'Oracle PL/SQL Moodle support packages are not installed! Database administrator has to execute /lib/dml/oci_native_moodle_package.sql script.'; } return null; @@ -758,10 +756,27 @@ class oci_native_moodle_database extends moodle_database { */ private function oracle_dirty_hack ($table, $field, $value) { + // General bound parameter, just hack the spaces and pray it will work. + if (!$table) { + if ($value === '') { + return ' '; + } else if (is_bool($value)) { + return (int)$value; + } else { + return $value; + } + } + // Get metadata $columns = $this->get_columns($table); if (!isset($columns[$field])) { - return $value; + if ($value === '') { + return ' '; + } else if (is_bool($value)) { + return (int)$value; + } else { + return $value; + } } $column = $columns[$field]; @@ -778,7 +793,7 @@ class oci_native_moodle_database extends moodle_database { // In the opposite, when retrieving records from Oracle, we'll decode " " back to // empty strings to allow everything to work properly. DIRTY HACK. - // !! These paragraphs explain the rationale about the change for Moodle 2.0: + // !! These paragraphs explain the rationale about the change for Moodle 2.5: // // Before Moodle 2.0, we only used to apply this DIRTY HACK to NOT NULL columns, as // stated above, but it causes one problem in NULL columns where both empty strings @@ -791,19 +806,17 @@ class oci_native_moodle_database extends moodle_database { // to rely in NULL/empty/content contents without problems, until now that wasn't // possible at all. // - // No breakage with old data is expected as long as at the time of writing this - // (20090922) all the current uses of both sql_empty() and sql_isempty() has been - // revised in 2.0 and all them were being performed against NOT NULL columns, - // where nothing has changed (the DIRTY HACK was already being applied). + // One space DIRTY HACK is now applied automatically for all query parameters + // and results. The only problem is string concatenation where the glue must + // be specified as "' '" sql fragment. // // !! Conclusions: // - // From Moodle 2.0 onwards, ALL empty strings in Oracle DBs will be stored as + // From Moodle 2.5 onwards, ALL empty strings in Oracle DBs will be stored as // 1-whitespace char, ALL NULLs as NULLs and, obviously, content as content. And // those 1-whitespace chars will be converted back to empty strings by all the // get_field/record/set() functions transparently and any SQL needing direct handling - // of empties will need to use the sql_empty() and sql_isempty() helper functions. - // MDL-17491. + // of empties will have to use placeholders or sql_isempty() helper function. // If the field isn't VARCHAR or CLOB, skip if ($column->meta_type != 'C' and $column->meta_type != 'X') { @@ -1445,26 +1458,6 @@ class oci_native_moodle_database extends moodle_database { return ' FROM dual'; } - protected function bitwise_supported() { - if (isset($this->bitwise_supported)) { // Use cached value if available - return $this->bitwise_supported; - } - $sql = "SELECT 1 - FROM user_objects - WHERE object_type = 'PACKAGE BODY' - AND object_name = 'MOODLE_BITS' - AND status = 'VALID'"; - $this->query_start($sql, null, SQL_QUERY_AUX); - $stmt = $this->parse_query($sql); - $result = oci_execute($stmt, $this->commit_status); - $this->query_end($result, $stmt); - $records = null; - oci_fetch_all($stmt, $records, 0, -1, OCI_FETCHSTATEMENT_BY_ROW); - oci_free_statement($stmt); - $this->bitwise_supported = isset($records[0]) && reset($records[0]) ? true : false; - return $this->bitwise_supported; - } - public function sql_bitand($int1, $int2) { return 'bitand((' . $int1 . '), (' . $int2 . '))'; } @@ -1474,18 +1467,18 @@ class oci_native_moodle_database extends moodle_database { } public function sql_bitor($int1, $int2) { - // Use the MOODLE_BITS package if available - if ($this->bitwise_supported()) { - return 'MOODLE_BITS.BITOR(' . $int1 . ', ' . $int2 . ')'; + // Use the MOODLELIB package if available + if ($this->oci_package_installed()) { + return 'MOODLELIB.BITOR(' . $int1 . ', ' . $int2 . ')'; } // fallback to PHP bool operations, can break if using placeholders return '((' . $int1 . ') + (' . $int2 . ') - ' . $this->sql_bitand($int1, $int2) . ')'; } public function sql_bitxor($int1, $int2) { - // Use the MOODLE_BITS package if available - if ($this->bitwise_supported()) { - return 'MOODLE_BITS.BITXOR(' . $int1 . ', ' . $int2 . ')'; + // Use the MOODLELIB package if available + if ($this->oci_package_installed()) { + return 'MOODLELIB.BITXOR(' . $int1 . ', ' . $int2 . ')'; } // fallback to PHP bool operations, can break if using placeholders return '(' . $this->sql_bitor($int1, $int2) . ' - ' . $this->sql_bitand($int1, $int2) . ')'; @@ -1552,22 +1545,38 @@ class oci_native_moodle_database extends moodle_database { // NULLs and empty strings. So this function will cause some tests to fail. Hopefully // it's only a side case and it won't affect normal concatenation operations in Moodle. $arr = func_get_args(); + if ($this->oci_package_installed()) { + foreach ($arr as $k => $v) { + if (strpos($v, "'") === 0) { + continue; + } + $arr[$k] = "MOODLELIB.UNDO_DIRTY_HACK($v)"; + } + } $s = implode(' || ', $arr); if ($s === '') { - return " '' "; + return " ' ' "; } - return " $s "; + return " MOODLELIB.DIRTY_HACK($s) "; } public function sql_concat_join($separator="' '", $elements=array()) { - for ($n=count($elements)-1; $n > 0 ; $n--) { + if ($this->oci_package_installed()) { + foreach ($elements as $k => $v) { + if (strpos($v, "'") === 0) { + continue; + } + $elements[$k] = "MOODLELIB.UNDO_DIRTY_HACK($v)"; + } + } + for ($n = count($elements)-1; $n > 0 ; $n--) { array_splice($elements, $n, 0, $separator); } $s = implode(' || ', $elements); if ($s === '') { - return " '' "; + return " ' ' "; } - return " $s "; + return " MOODLELIB.DIRTY_HACK($s) "; } /** @@ -1577,36 +1586,41 @@ class oci_native_moodle_database extends moodle_database { return "INSTR(($haystack), ($needle))"; } + /** + * Returns the SQL to know if one field is empty. + * + * @param string $tablename Name of the table (without prefix). Not used for now but can be + * necessary in the future if we want to use some introspection using + * meta information against the DB. + * @param string $fieldname Name of the field we are going to check + * @param bool $nullablefield For specifying if the field is nullable (true) or no (false) in the DB. + * @param bool $textfield For specifying if it is a text (also called clob) field (true) or a varchar one (false) + * @return string the sql code to be added to check for empty values + */ public function sql_isempty($tablename, $fieldname, $nullablefield, $textfield) { if ($textfield) { - return " (".$this->sql_compare_text($fieldname)." = '".$this->sql_empty()."') "; + return " (".$this->sql_compare_text($fieldname)." = ' ') "; } else { - return " ($fieldname = '".$this->sql_empty()."') "; + return " ($fieldname = ' ') "; } } - /** - * Returns the empty string char used by every supported DB. To be used when - * we are searching for that values in our queries. Only Oracle uses this - * for now (will be out, once we migrate to proper NULLs if that days arrives) - * @return string A string with single whitespace. - */ - public function sql_empty() { - return ' '; - } - public function sql_order_by_text($fieldname, $numchars=32) { return 'dbms_lob.substr(' . $fieldname . ', ' . $numchars . ',1)'; } - public function session_lock_supported() { - if (isset($this->dblocks_supported)) { // Use cached value if available - return $this->dblocks_supported; + /** + * Is the required OCI server package installed? + * @return bool + */ + protected function oci_package_installed() { + if (isset($this->oci_package_installed)) { // Use cached value if available. + return $this->oci_package_installed; } $sql = "SELECT 1 FROM user_objects WHERE object_type = 'PACKAGE BODY' - AND object_name = 'MOODLE_LOCKS' + AND object_name = 'MOODLELIB' AND status = 'VALID'"; $this->query_start($sql, null, SQL_QUERY_AUX); $stmt = $this->parse_query($sql); @@ -1615,8 +1629,8 @@ class oci_native_moodle_database extends moodle_database { $records = null; oci_fetch_all($stmt, $records, 0, -1, OCI_FETCHSTATEMENT_BY_ROW); oci_free_statement($stmt); - $this->dblocks_supported = isset($records[0]) && reset($records[0]) ? true : false; - return $this->dblocks_supported; + $this->oci_package_installed = isset($records[0]) && reset($records[0]) ? true : false; + return $this->oci_package_installed; } /** @@ -1626,13 +1640,13 @@ class oci_native_moodle_database extends moodle_database { * @return void */ public function get_session_lock($rowid, $timeout) { - if (!$this->session_lock_supported()) { + if (!$this->oci_package_installed()) { return; } parent::get_session_lock($rowid, $timeout); $fullname = $this->dbname.'-'.$this->prefix.'-session-'.$rowid; - $sql = 'SELECT MOODLE_LOCKS.GET_LOCK(:lockname, :locktimeout) FROM DUAL'; + $sql = 'SELECT MOODLELIB.GET_LOCK(:lockname, :locktimeout) FROM DUAL'; $params = array('lockname' => $fullname , 'locktimeout' => $timeout); $this->query_start($sql, $params, SQL_QUERY_AUX); $stmt = $this->parse_query($sql); @@ -1646,7 +1660,7 @@ class oci_native_moodle_database extends moodle_database { } public function release_session_lock($rowid) { - if (!$this->session_lock_supported()) { + if (!$this->oci_package_installed()) { return; } if (!$this->used_for_db_sessions) { @@ -1657,7 +1671,7 @@ class oci_native_moodle_database extends moodle_database { $fullname = $this->dbname.'-'.$this->prefix.'-session-'.$rowid; $params = array('lockname' => $fullname); - $sql = 'SELECT MOODLE_LOCKS.RELEASE_LOCK(:lockname) FROM DUAL'; + $sql = 'SELECT MOODLELIB.RELEASE_LOCK(:lockname) FROM DUAL'; $this->query_start($sql, $params, SQL_QUERY_AUX); $stmt = $this->parse_query($sql); $this->bind_params($stmt, $params); diff --git a/lib/dml/oci_native_moodle_package.sql b/lib/dml/oci_native_moodle_package.sql index 2585f713d08..fed15f1ae6b 100644 --- a/lib/dml/oci_native_moodle_package.sql +++ b/lib/dml/oci_native_moodle_package.sql @@ -24,22 +24,30 @@ * This sql script generates various PL/SQL packages needed to provide * cross-db compatibility in the Moodle 2.x DB API with some operations * not natively supported by Oracle, namely: - * - MOODLE_LOCKS: Application locks used by Moodle DB sessions. It uses - * the DBMS_LOCK package so execution must be granted - * to the Moodle DB user by SYS to work properly. - * - MOODLE_BITS: To provide cross-db bitwise operations to be used by the - * sql_bitXXX() helper functions + * - locking: Application locks used by Moodle DB sessions. It uses + * the DBMS_LOCK package so execution must be granted + * to the Moodle DB user by SYS to work properly. + * - bit ops: To provide cross-db bitwise operations to be used by the + * sql_bitXXX() helper functions + * - one space hacks: One space empty string substitute hacks. */ -CREATE OR REPLACE PACKAGE MOODLE_BITS AS +CREATE OR REPLACE PACKAGE MOODLELIB AS FUNCTION BITOR (value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER; FUNCTION BITXOR(value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER; -END MOODLE_BITS; +FUNCTION GET_HANDLE (lock_name IN VARCHAR2) RETURN VARCHAR2; +FUNCTION GET_LOCK (lock_name IN VARCHAR2, lock_timeout IN INTEGER) RETURN INTEGER; +FUNCTION RELEASE_LOCK(lock_name IN VARCHAR2) RETURN INTEGER; + +FUNCTION DIRTY_HACK(somestring IN VARCHAR2) RETURN VARCHAR2; +FUNCTION UNDO_DIRTY_HACK(hackedstring IN VARCHAR2) RETURN VARCHAR2; + +END MOODLELIB; / -CREATE OR REPLACE PACKAGE BODY MOODLE_BITS AS +CREATE OR REPLACE PACKAGE BODY MOODLELIB AS FUNCTION BITOR(value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER IS @@ -50,23 +58,9 @@ END BITOR; FUNCTION BITXOR(value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER IS BEGIN - RETURN MOODLE_BITS.BITOR(value1,value2) - BITAND(value1,value2); + RETURN MOODLELIB.BITOR(value1,value2) - BITAND(value1,value2); END BITXOR; -END MOODLE_BITS; -/ - -CREATE OR REPLACE PACKAGE MOODLE_LOCKS AS - -FUNCTION GET_HANDLE (lock_name IN VARCHAR2) RETURN VARCHAR2; -FUNCTION GET_LOCK (lock_name IN VARCHAR2, lock_timeout IN INTEGER) RETURN INTEGER; -FUNCTION RELEASE_LOCK(lock_name IN VARCHAR2) RETURN INTEGER; - -END MOODLE_LOCKS; -/ - -CREATE OR REPLACE PACKAGE BODY MOODLE_LOCKS AS - FUNCTION GET_HANDLE(lock_name IN VARCHAR2) RETURN VARCHAR2 IS PRAGMA AUTONOMOUS_TRANSACTION; lock_handle VARCHAR2(128); @@ -107,5 +101,23 @@ BEGIN RETURN 1; END RELEASE_LOCK; -END MOODLE_LOCKS; -/ \ No newline at end of file +FUNCTION DIRTY_HACK(somestring IN VARCHAR2) RETURN VARCHAR2 IS + +BEGIN + IF somestring = '' THEN + RETURN ' '; + END IF; + RETURN somestring; +END DIRTY_HACK; + +FUNCTION UNDO_DIRTY_HACK(hackedstring IN VARCHAR2) RETURN VARCHAR2 IS + +BEGIN + IF hackedstring = ' ' THEN + RETURN ''; + END IF; + RETURN hackedstring; +END UNDO_DIRTY_HACK; + +END MOODLELIB; +/ diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php index 159424586af..01dc05d973f 100644 --- a/lib/dml/tests/dml_test.php +++ b/lib/dml/tests/dml_test.php @@ -3926,6 +3926,9 @@ class dml_testcase extends database_driver_testcase { $table = $this->get_test_table(); $tablename = $table->getName(); + $this->assertSame('', $DB->sql_empty()); // Since 2.5 the hack is applied automatically to all bound params. + $this->assertDebuggingCalled(); + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null); $table->add_field('namenotnull', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, 'default value'); @@ -3938,17 +3941,17 @@ class dml_testcase extends database_driver_testcase { $DB->insert_record($tablename, array('name'=>'lalala')); $DB->insert_record($tablename, array('name'=>0)); - $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = '".$DB->sql_empty()."'"); + $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('')); $this->assertEquals(count($records), 1); $record = reset($records); $this->assertEquals($record->name, ''); - $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnull = '".$DB->sql_empty()."'"); + $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnull = ?", array('')); $this->assertEquals(count($records), 1); $record = reset($records); $this->assertEquals($record->namenotnull, ''); - $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnullnodeflt = '".$DB->sql_empty()."'"); + $records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE namenotnullnodeflt = ?", array('')); $this->assertEquals(count($records), 4); $record = reset($records); $this->assertEquals($record->namenotnullnodeflt, ''); diff --git a/lib/upgrade.txt b/lib/upgrade.txt index c6bb4fecd60..2afe4866511 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -43,6 +43,10 @@ information provided here is intended especially for developers. course_category_show(), get_course_category(), create_course_category(), get_all_subcategories(), get_child_categories(), get_categories() +Database (DML) layer: +* $DB->sql_empty() is deprecated, you have to use sql parameters with empty values instead, + please note hardcoding of empty strings in SQL queries breaks execution in Oracle database. + YUI changes: * M.util.help_icon has been deprecated. Code should be updated to use moodle-core-popuphelp instead. To do so, remove any existing JS calls to M.util.help_icon from your PHP and ensure diff --git a/user/filters/text.php b/user/filters/text.php index 8be8f1fac25..b5e9a144d35 100644 --- a/user/filters/text.php +++ b/user/filters/text.php @@ -116,7 +116,7 @@ class user_filter_text extends user_filter_type { break; case 5: // empty $res = "$field = :$name"; - $params[$name] = $DB->sql_empty(); + $params[$name] = ''; break; default: return '';