From 3da04607e1a6785c6b90c17bf1b4d0e09499e102 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Mon, 13 Sep 2010 09:09:58 +0000 Subject: [PATCH] MDL-19057 improved bit operations in oracle, new sql package setup code - all credit goes to Eloy Lafuente; installation instructions and diagnostics to be added later --- lib/dml/oci_native_moodle_database.php | 34 +++++++- lib/dml/oci_native_moodle_package.sql | 112 +++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 lib/dml/oci_native_moodle_package.sql diff --git a/lib/dml/oci_native_moodle_database.php b/lib/dml/oci_native_moodle_database.php index f4995d9436e..41bad544c9e 100644 --- a/lib/dml/oci_native_moodle_database.php +++ b/lib/dml/oci_native_moodle_database.php @@ -48,6 +48,7 @@ class oci_native_moodle_database extends moodle_database { private $unique_session_id; // To store unique_session_id. Needed for temp tables unique naming private $dblocks_supported = null; // To cache locks support along the connection life + private $bitwise_supported = null; // To cache bitwise operations support along the connection life /** @@ -1126,7 +1127,7 @@ class oci_native_moodle_database extends moodle_database { $stmt = $this->parse_query($sql); $descriptors = $this->bind_params($stmt, $params, $table); if ($returning) { - oci_bind_by_name($stmt, ":oracle_id", $id, -1, SQLT_INT); + oci_bind_by_name($stmt, ":oracle_id", $id, 10, SQLT_INT); } $result = oci_execute($stmt, $this->commit_status); $this->free_descriptors($descriptors); @@ -1366,6 +1367,27 @@ class oci_native_moodle_database extends moodle_database { return ' FROM dual'; } +// Bitwise operations + 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 . '))'; } @@ -1375,10 +1397,20 @@ 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 . ')'; + } + // 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 . ')'; + } + // fallback to PHP bool operations, can break if using placeholders return '(' . $this->sql_bitor($int1, $int2) . ' - ' . $this->sql_bitand($int1, $int2) . ')'; } diff --git a/lib/dml/oci_native_moodle_package.sql b/lib/dml/oci_native_moodle_package.sql new file mode 100644 index 00000000000..84eddd56332 --- /dev/null +++ b/lib/dml/oci_native_moodle_package.sql @@ -0,0 +1,112 @@ +-- This file is part of Moodle - http://moodle.org/ +-- +-- Moodle is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- Moodle is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with Moodle. If not, see . + +/** + * @package core + * @subpackage dml + * @copyright 2009 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @version 20091010 (plz, keep this updated for easier reference) + */ + +/** + * 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 + */ + +CREATE OR REPLACE PACKAGE MOODLE_BITS AS + +FUNCTION BITOR (value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER; +FUNCTION BITXOR(value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER; + +END MOODLE_BITS; +/ + +CREATE OR REPLACE PACKAGE BODY MOODLE_BITS AS + +FUNCTION BITOR(value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER IS + +BEGIN + RETURN value1 + value2 - BITAND(value1,value2); +END BITOR; + +FUNCTION BITXOR(value1 IN INTEGER, value2 IN INTEGER) RETURN INTEGER IS + +BEGIN + RETURN MOODLE_BITS.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); + +BEGIN + DBMS_LOCK.ALLOCATE_UNIQUE ( + lockname => lock_name, + lockhandle => lock_handle, + expiration_secs => 864000); + RETURN lock_handle; +END GET_HANDLE; + +FUNCTION GET_LOCK(lock_name IN VARCHAR2, lock_timeout IN INTEGER) RETURN INTEGER IS + lock_status NUMBER; +BEGIN + lock_status := DBMS_LOCK.REQUEST( + lockhandle => GET_HANDLE(lock_name), + lockmode => DBMS_LOCK.X_MODE, -- eXclusive + timeout => lock_timeout, + release_on_commit => FALSE); + CASE lock_status + WHEN 0 THEN NULL; + WHEN 2 THEN RAISE_APPLICATION_ERROR(-20000,'deadlock detected'); + WHEN 4 THEN RAISE_APPLICATION_ERROR(-20000,'lock already obtained'); + ELSE RAISE_APPLICATION_ERROR(-20000,'request lock failed - ' || lock_status); + END CASE; + RETURN 1; +END GET_LOCK; + +FUNCTION RELEASE_LOCK(lock_name IN VARCHAR2) RETURN INTEGER IS + lock_status NUMBER; +BEGIN + lock_status := DBMS_LOCK.RELEASE( + lockhandle => GET_HANDLE(lock_name)); + IF lock_status > 0 THEN + RAISE_APPLICATION_ERROR(-20000,'release lock failed - ' || lock_status); + END IF; + RETURN 1; +END RELEASE_LOCK; + +END MOODLE_LOCKS; +/ \ No newline at end of file