MDL-39038 nasty workaround for Oracle NULL concats

This commit is contained in:
Petr Škoda 2013-04-08 23:16:55 +02:00
parent 422f68fb86
commit 031a6de97a
3 changed files with 73 additions and 36 deletions

View File

@ -1540,43 +1540,57 @@ class oci_native_moodle_database extends moodle_database {
}
public function sql_concat() {
// NOTE: Oracle concat implementation isn't ANSI compliant when using NULLs (the result of
// any concatenation with NULL must return NULL) because of his inability to differentiate
// 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 === '') {
if (empty($arr)) {
return " ' ' ";
}
return " MOODLELIB.DIRTY_HACK($s) ";
foreach ($arr as $k => $v) {
if ($v === "' '") {
$arr[$k] = "'*OCISP*'"; // New mega hack.
}
}
$s = $this->recursive_concat($arr);
return " MOODLELIB.UNDO_MEGA_HACK($s) ";
}
public function sql_concat_join($separator="' '", $elements=array()) {
if ($this->oci_package_installed()) {
foreach ($elements as $k => $v) {
if (strpos($v, "'") === 0) {
continue;
}
$elements[$k] = "MOODLELIB.UNDO_DIRTY_HACK($v)";
public function sql_concat_join($separator="' '", $elements = array()) {
if ($separator === "' '") {
$separator = "'*OCISP*'"; // New mega hack.
}
foreach ($elements as $k => $v) {
if ($v === "' '") {
$elements[$k] = "'*OCISP*'"; // New mega hack.
}
}
for ($n = count($elements)-1; $n > 0 ; $n--) {
array_splice($elements, $n, 0, $separator);
}
$s = implode(' || ', $elements);
if ($s === '') {
if (empty($elements)) {
return " ' ' ";
}
return " MOODLELIB.DIRTY_HACK($s) ";
$s = $this->recursive_concat($elements);
return " MOODLELIB.UNDO_MEGA_HACK($s) ";
}
/**
* Mega hacky magic to work around crazy Oracle NULL concats.
* @param array $args
* @return string
*/
protected function recursive_concat(array $args) {
$count = count($args);
if ($count == 1) {
$arg = reset($args);
return $arg;
}
if ($count == 2) {
$args[] = "' '";
// No return here intentionally.
}
$first = array_shift($args);
$second = array_shift($args);
$third = $this->recursive_concat($args);
return "MOODLELIB.TRICONCAT($first, $second, $third)";
}
/**

View File

@ -41,8 +41,9 @@ 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;
FUNCTION UNDO_MEGA_HACK(hackedstring IN VARCHAR2) RETURN VARCHAR2;
FUNCTION TRICONCAT(string1 IN VARCHAR2, string2 IN VARCHAR2, string3 IN VARCHAR2) RETURN VARCHAR2;
END MOODLELIB;
/
@ -101,15 +102,6 @@ BEGIN
RETURN 1;
END RELEASE_LOCK;
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
@ -119,5 +111,36 @@ BEGIN
RETURN hackedstring;
END UNDO_DIRTY_HACK;
FUNCTION UNDO_MEGA_HACK(hackedstring IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
IF hackedstring IS NULL THEN
RETURN hackedstring;
END IF;
RETURN REPLACE(hackedstring, '*OCISP*', ' ');
END UNDO_MEGA_HACK;
FUNCTION TRICONCAT(string1 IN VARCHAR2, string2 IN VARCHAR2, string3 IN VARCHAR2) RETURN VARCHAR2 IS
stringresult VARCHAR2(1333);
BEGIN
IF string1 IS NULL THEN
RETURN NULL;
END IF;
IF string2 IS NULL THEN
RETURN NULL;
END IF;
IF string3 IS NULL THEN
RETURN NULL;
END IF;
stringresult := CONCAT(CONCAT(MOODLELIB.UNDO_DIRTY_HACK(string1), MOODLELIB.UNDO_DIRTY_HACK(string2)), MOODLELIB.UNDO_DIRTY_HACK(string3));
IF stringresult IS NULL THEN
RETURN ' ';
END IF;
RETURN stringresult;
END;
END MOODLELIB;
/

View File

@ -3796,7 +3796,7 @@ class dml_testcase extends database_driver_testcase {
$this->assertEquals('123456', $DB->get_field_sql($sql, $params));
// float, null and strings
$params = array(123.45, null, 'test');
$this->assertNull($DB->get_field_sql($sql, $params), 'ANSI behaviour: Concatenating NULL must return NULL - But in Oracle :-(. [%s]'); // Concatenate NULL with anything result = NULL
$this->assertNull($DB->get_field_sql($sql, $params)); // Concatenate NULL with anything result = NULL
// Testing fieldnames + values and also integer fieldnames
$table = $this->get_test_table();