mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
Merge branch 'w13_MDL-37742_m25_dirtyoracle' of git://github.com/skodak/moodle
Conflicts: lib/upgrade.txt
This commit is contained in:
commit
4efcfaa3ae
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)));
|
||||
|
||||
|
||||
|
@ -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');
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
/
|
||||
|
@ -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, '');
|
||||
|
@ -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
|
||||
|
@ -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 '';
|
||||
|
Loading…
x
Reference in New Issue
Block a user