Merge branch 'w13_MDL-37742_m25_dirtyoracle' of git://github.com/skodak/moodle

Conflicts:
	lib/upgrade.txt
This commit is contained in:
Eloy Lafuente (stronk7) 2013-03-26 23:04:48 +01:00
commit 4efcfaa3ae
15 changed files with 163 additions and 126 deletions

View File

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

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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