mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 13:38:32 +01:00
MDL-83172 dml: Remove Oracle from LMS
This commit is contained in:
parent
f4f166695c
commit
c26cc0e005
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1,6 +1,5 @@
|
||||
**/yui/build/** -diff
|
||||
**/amd/build/** -diff
|
||||
lib/dml/oci_native_moodle_package.sql text eol=lf
|
||||
**.js.map -diff
|
||||
**-min.js -diff
|
||||
**.min.js -diff
|
||||
|
5
.upgradenotes/MDL-83172-2024112009513041.yml
Normal file
5
.upgradenotes/MDL-83172-2024112009513041.yml
Normal file
@ -0,0 +1,5 @@
|
||||
issueNumber: MDL-83172
|
||||
notes:
|
||||
core:
|
||||
- message: Oracle support has been removed in LMS, with the exception of report builder which will be handled in a separate issue (MDL-80173).
|
||||
type: removed
|
@ -217,7 +217,6 @@ $databases = array('mysqli' => moodle_database::get_driver_instance('mysqli', 'n
|
||||
'auroramysql' => moodle_database::get_driver_instance('auroramysql', 'native'),
|
||||
'mariadb'=> moodle_database::get_driver_instance('mariadb', 'native'),
|
||||
'pgsql' => moodle_database::get_driver_instance('pgsql', 'native'),
|
||||
'oci' => moodle_database::get_driver_instance('oci', 'native'),
|
||||
'sqlsrv' => moodle_database::get_driver_instance('sqlsrv', 'native'), // MS SQL*Server PHP driver
|
||||
);
|
||||
foreach ($databases as $type=>$database) {
|
||||
@ -561,7 +560,6 @@ do {
|
||||
if ($interactive) {
|
||||
cli_separator();
|
||||
cli_heading(get_string('dbprefix', 'install'));
|
||||
//TODO: solve somehow the prefix trouble for oci.
|
||||
if ($options['prefix'] !== '') {
|
||||
$prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
|
||||
} else {
|
||||
|
@ -4714,7 +4714,6 @@
|
||||
<VENDOR name="mysql" version="8.4" />
|
||||
<VENDOR name="postgres" version="14" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.2.0" level="required">
|
||||
</PHP>
|
||||
@ -4892,8 +4891,6 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
|
@ -91,7 +91,8 @@ if (!empty($hostid) && array_key_exists($hostid, $hosts)) {
|
||||
// this query is horrible and has to be remapped afterwards, because of the non-uniqueness
|
||||
// of the remoterep service (it has two plugins so far that use it)
|
||||
// it's possible to get a unique list back using a subquery with LIMIT but that would break oracle
|
||||
// so it's best to just do this small query and then remap the results afterwards
|
||||
// so it's best to just do this small query and then remap the results afterwards.
|
||||
// TODO: Optimise the query, as Oracle-specific constraints no longer apply.
|
||||
$sql = '
|
||||
SELECT DISTINCT
|
||||
' . $DB->sql_concat('r.plugintype', "'_'", 'r.pluginname', "'_'", 's.name') . ' AS uniqueid,
|
||||
|
@ -43,7 +43,6 @@ class helper {
|
||||
'native/mysqli' => \moodle_database::get_driver_instance('mysqli', 'native')->get_name(),
|
||||
'native/mariadb' => \moodle_database::get_driver_instance('mariadb', 'native')->get_name(),
|
||||
'native/pgsql' => \moodle_database::get_driver_instance('pgsql', 'native')->get_name(),
|
||||
'native/oci' => \moodle_database::get_driver_instance('oci', 'native')->get_name(),
|
||||
'native/sqlsrv' => \moodle_database::get_driver_instance('sqlsrv', 'native')->get_name()
|
||||
);
|
||||
}
|
||||
|
@ -1,153 +0,0 @@
|
||||
<?php
|
||||
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @package tool_xmldb
|
||||
* @copyright 2011 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class will check all the varchar2() columns
|
||||
* in the Moodle installed DB, looking for incorrect (INT)
|
||||
* length semanticas providing one SQL script to fix all
|
||||
* them by changing to cross-db (CHAR) length semantics.
|
||||
* See MDL-29322 for more details.
|
||||
*
|
||||
* @package tool_xmldb
|
||||
* @copyright 2011 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class check_oracle_semantics extends XMLDBCheckAction {
|
||||
|
||||
/**
|
||||
* Init method, every subclass will have its own
|
||||
*/
|
||||
function init() {
|
||||
$this->introstr = 'confirmcheckoraclesemantics';
|
||||
parent::init();
|
||||
|
||||
// Set own core attributes
|
||||
|
||||
// Set own custom attributes
|
||||
|
||||
// Get needed strings
|
||||
$this->loadStrings(array(
|
||||
'wrongoraclesemantics' => 'tool_xmldb',
|
||||
'nowrongoraclesemanticsfound' => 'tool_xmldb',
|
||||
'yeswrongoraclesemanticsfound' => 'tool_xmldb',
|
||||
'expected' => 'tool_xmldb',
|
||||
'actual' => 'tool_xmldb',
|
||||
));
|
||||
}
|
||||
|
||||
protected function check_table(xmldb_table $xmldb_table, array $metacolumns) {
|
||||
global $DB;
|
||||
$o = '';
|
||||
$wrong_fields = array();
|
||||
|
||||
// Get and process XMLDB fields
|
||||
if ($xmldb_fields = $xmldb_table->getFields()) {
|
||||
$o .= '<ul>';
|
||||
foreach ($xmldb_fields as $xmldb_field) {
|
||||
|
||||
// Get the type of the column, we only will process CHAR (VARCHAR2) ones
|
||||
if ($xmldb_field->getType() != XMLDB_TYPE_CHAR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$o.='<li>' . $this->str['field'] . ': ' . $xmldb_field->getName() . ' ';
|
||||
|
||||
// Get current semantic from dictionary, we only will process B (BYTE) ones
|
||||
// suplying the SQL code to change them to C (CHAR) semantic
|
||||
$params = array(
|
||||
'table_name' => core_text::strtoupper($DB->get_prefix() . $xmldb_table->getName()),
|
||||
'column_name' => core_text::strtoupper($xmldb_field->getName()),
|
||||
'data_type' => 'VARCHAR2');
|
||||
$currentsemantic = $DB->get_field_sql('
|
||||
SELECT char_used
|
||||
FROM user_tab_columns
|
||||
WHERE table_name = :table_name
|
||||
AND column_name = :column_name
|
||||
AND data_type = :data_type', $params);
|
||||
|
||||
// If using byte semantics, we'll need to change them to char semantics
|
||||
if ($currentsemantic == 'B') {
|
||||
$info = '(' . $this->str['expected'] . " 'CHAR', " . $this->str['actual'] . " 'BYTE')";
|
||||
$o .= '<font color="red">' . $this->str['wrong'] . " $info</font>";
|
||||
// Add the wrong field to the list
|
||||
$obj = new stdClass();
|
||||
$obj->table = $xmldb_table;
|
||||
$obj->field = $xmldb_field;
|
||||
$wrong_fields[] = $obj;
|
||||
} else {
|
||||
$o .= '<font color="green">' . $this->str['ok'] . '</font>';
|
||||
}
|
||||
$o .= '</li>';
|
||||
}
|
||||
$o .= '</ul>';
|
||||
}
|
||||
|
||||
return array($o, $wrong_fields);
|
||||
}
|
||||
|
||||
protected function display_results(array $wrong_fields) {
|
||||
global $DB;
|
||||
$dbman = $DB->get_manager();
|
||||
|
||||
$s = '';
|
||||
$r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
|
||||
$r.= ' <tr><td class="generalboxcontent">';
|
||||
$r.= ' <h2 class="main">' . $this->str['searchresults'] . '</h2>';
|
||||
$r.= ' <p class="centerpara">' . $this->str['wrongoraclesemantics'] . ': ' . count($wrong_fields) . '</p>';
|
||||
$r.= ' </td></tr>';
|
||||
$r.= ' <tr><td class="generalboxcontent">';
|
||||
|
||||
// If we have found wrong defaults inform about them
|
||||
if (count($wrong_fields)) {
|
||||
$r.= ' <p class="centerpara">' . $this->str['yeswrongoraclesemanticsfound'] . '</p>';
|
||||
$r.= ' <ul>';
|
||||
foreach ($wrong_fields as $obj) {
|
||||
$xmldb_table = $obj->table;
|
||||
$xmldb_field = $obj->field;
|
||||
|
||||
$r.= ' <li>' . $this->str['table'] . ': ' . $xmldb_table->getName() . '. ' .
|
||||
$this->str['field'] . ': ' . $xmldb_field->getName() . ', ' .
|
||||
$this->str['expected'] . ' ' . "'CHAR'" . ' ' .
|
||||
$this->str['actual'] . ' ' . "'BYTE'" . '</li>';
|
||||
|
||||
$sql = 'ALTER TABLE ' . $DB->get_prefix() . $xmldb_table->getName() . ' MODIFY ' .
|
||||
$xmldb_field->getName() . ' VARCHAR2(' . $xmldb_field->getLength() . ' CHAR)';
|
||||
$sql = $dbman->generator->getEndedStatements($sql);
|
||||
$s.= '<code>' . str_replace("\n", '<br />', $sql) . '</code><br />';
|
||||
}
|
||||
$r.= ' </ul>';
|
||||
// Add the SQL statements (all together)
|
||||
$r.= '<hr />' . $s;
|
||||
} else {
|
||||
$r.= ' <p class="centerpara">' . $this->str['nowrongoraclesemanticsfound'] . '</p>';
|
||||
}
|
||||
$r.= ' </td></tr>';
|
||||
$r.= ' <tr><td class="generalboxcontent">';
|
||||
// Add the complete log message
|
||||
$r.= ' <p class="centerpara">' . $this->str['completelogbelow'] . '</p>';
|
||||
$r.= ' </td></tr>';
|
||||
$r.= '</table>';
|
||||
|
||||
return $r;
|
||||
}
|
||||
}
|
@ -56,7 +56,6 @@ class main_view extends XMLDBAction {
|
||||
'checkdefaults' => 'tool_xmldb',
|
||||
'checkforeignkeys' => 'tool_xmldb',
|
||||
'checkbigints' => 'tool_xmldb',
|
||||
'checkoraclesemantics' => 'tool_xmldb',
|
||||
'reconcilefiles' => 'tool_xmldb',
|
||||
'doc' => 'tool_xmldb',
|
||||
'filemodifiedoutfromeditor' => 'tool_xmldb',
|
||||
@ -108,10 +107,6 @@ class main_view extends XMLDBAction {
|
||||
if ($DB->get_dbfamily() == 'mysql' || $DB->get_dbfamily() == 'postgres') {
|
||||
$b .= ' <a href="index.php?action=check_bigints&sesskey=' . sesskey() . '">[' . $this->str['checkbigints'] . ']</a>';
|
||||
}
|
||||
// The check semantics button (only for Oracle) MDL-29416
|
||||
if ($DB->get_dbfamily() == 'oracle') {
|
||||
$b .= ' <a href="index.php?action=check_oracle_semantics&sesskey=' . sesskey() . '">[' . $this->str['checkoraclesemantics'] . ']</a>';
|
||||
}
|
||||
$b .= ' <a href="index.php?action=check_foreign_keys&sesskey=' . sesskey() . '">[' . $this->str['checkforeignkeys'] . ']</a>';
|
||||
$b .= '</p>';
|
||||
// Send buttons to output
|
||||
|
@ -59,13 +59,6 @@ Once generated you can copy such statements and execute them safely with your fa
|
||||
|
||||
It\'s highly recommended to be running the latest (+ version) available of your Moodle release before executing the search of missing indexes.
|
||||
|
||||
This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
|
||||
$string['confirmcheckoraclesemantics'] = 'This functionality will search for <a href="https://tracker.moodle.org/browse/MDL-29322">Oracle varchar2 columns using BYTE semantics</a> in your Moodle server, generating (but not executing!) automatically the needed SQL statements to have all the columns converted to use CHAR semantics instead (better for cross-db compatibility and increased contents max. length).
|
||||
|
||||
Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).
|
||||
|
||||
It\'s highly recommended to be running the latest (+ version) available of your Moodle release before executing the search of BYTE semantics.
|
||||
|
||||
This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
|
||||
$string['confirmrevertchanges'] = 'Are you absolutely sure that you want to revert changes performed over:';
|
||||
$string['create'] = 'Create';
|
||||
@ -127,8 +120,6 @@ $string['checkforeignkeys'] = 'Check foreign keys';
|
||||
$string['check_foreign_keys'] = 'Look for foreign key violations';
|
||||
$string['checkindexes'] = 'Check indexes';
|
||||
$string['check_indexes'] = 'Look for missing DB indexes';
|
||||
$string['checkoraclesemantics'] = 'Check semantics';
|
||||
$string['check_oracle_semantics'] = 'Look for incorrect length semantics';
|
||||
$string['duplicateindexname'] = 'Duplicate index name';
|
||||
$string['incorrectfieldname'] = 'Incorrect name';
|
||||
$string['index'] = 'Index';
|
||||
@ -164,7 +155,6 @@ $string['noreftablespecified'] = 'Specified reference table not found';
|
||||
$string['noviolatedforeignkeysfound'] = 'No violated foreign keys found';
|
||||
$string['nowrongdefaultsfound'] = 'No inconsistent default values have been found, your DB does not need further actions.';
|
||||
$string['nowrongintsfound'] = 'No wrong integers have been found, your DB doesn\'t need further actions.';
|
||||
$string['nowrongoraclesemanticsfound'] = 'No Oracle columns using BYTE semantics have been found, your DB doesn\'t need further actions.';
|
||||
$string['numberincorrectdecimals'] = 'Incorrect number of decimals for number field';
|
||||
$string['numberincorrectlength'] = 'Incorrect length for number field';
|
||||
$string['numberincorrectwholepart'] = 'Too big whole number part for number field';
|
||||
@ -222,7 +212,6 @@ $string['wrongints'] = 'Wrong integers found';
|
||||
$string['wronglengthforenum'] = 'Incorrect length for enum field';
|
||||
$string['wrongnumberofreffields'] = 'Wrong number of reference fields';
|
||||
$string['wrongreservedwords'] = 'Currently used reserved words<br />(note that table names aren\'t important if using $CFG->prefix)';
|
||||
$string['wrongoraclesemantics'] = 'Wrong Oracle BYTE semantics found';
|
||||
$string['yesextraindexesfound'] = 'The following additional indexes were found.';
|
||||
$string['yesmissingindexesfound'] = '<p>Some missing indexes have been found in your DB. Here are their details and the needed SQL statements to be executed with your favourite SQL interface to create all of them. Remember to backup your data first!</p>
|
||||
<p>After doing that, it\'s highly recommended to execute this utility again to check that no more missing indexes are found.</p>';
|
||||
@ -230,6 +219,4 @@ $string['yeswrongdefaultsfound'] = '<p>Some inconsistent defaults have been foun
|
||||
<p>After doing that, it\'s highly recommended to execute this utility again to check that no more inconsistent defaults are found.</p>';
|
||||
$string['yeswrongintsfound'] = '<p>Some wrong integers have been found in your DB. Here are their details and the needed SQL statements to be executed with your favourite SQL interface to fix them. Remember to backup your data first!</p>
|
||||
<p>After fixing them, it is highly recommended to execute this utility again to check that no more wrong integers are found.</p>';
|
||||
$string['yeswrongoraclesemanticsfound'] = '<p>Some Oracle columns using BYTE semantics have been found in your DB. Here are their details and the needed SQL statements to be executed with your favourite SQL interface to convert them all. Remember to backup your data first!</p>
|
||||
<p>After doing that, it\'s highly recommended to execute this utility again to check that no more wrong semantics are found.</p>';
|
||||
$string['privacy:metadata'] = 'The XMLDB editor plugin does not store any personal data.';
|
||||
|
@ -532,7 +532,7 @@ class analysis {
|
||||
// Insert from the beginning.
|
||||
$remaining = array_splice($newcalculations, $batchsize);
|
||||
|
||||
// Sorry mssql and oracle, this will be slow.
|
||||
// Sorry mssql, this will be slow.
|
||||
$DB->insert_records('analytics_indicator_calc', $newcalculations);
|
||||
$newcalculations = $remaining;
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ final class model_test extends \advanced_testcase {
|
||||
$this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
|
||||
}
|
||||
|
||||
// 10000 should be enough to make oracle and mssql fail, if we want pgsql to fail we need around 70000
|
||||
// 10000 should be enough to make mssql fail, if we want pgsql to fail we need around 70000
|
||||
// users, that is a few minutes just to create the users.
|
||||
$nusers = 10000;
|
||||
|
||||
|
@ -55,7 +55,7 @@ $string['auth_dbsetupsqlhelp'] = 'SQL command for special database setup, often
|
||||
$string['auth_dbsuspenduser'] = 'Suspended user {$a->name} id {$a->id}';
|
||||
$string['auth_dbsuspendusererror'] = 'Error suspending user {$a}';
|
||||
$string['auth_dbsybasequoting'] = 'Use sybase quotes';
|
||||
$string['auth_dbsybasequotinghelp'] = 'Sybase style single quote escaping - needed for Oracle, MS SQL and some other databases. Do not use for MySQL!';
|
||||
$string['auth_dbsybasequotinghelp'] = 'Sybase style single quote escaping - needed for MS SQL and some other databases. Do not use for MySQL!';
|
||||
$string['auth_dbsyncuserstask'] = 'Synchronise users task';
|
||||
$string['auth_dbtable'] = 'Name of the table in the database';
|
||||
$string['auth_dbtable_key'] = 'Table';
|
||||
|
@ -80,11 +80,6 @@ final class db_test extends \advanced_testcase {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'oracle':
|
||||
set_config('type', 'oci8po', 'auth_db');
|
||||
set_config('sybasequoting', '1', 'auth_db');
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
set_config('type', 'postgres7', 'auth_db');
|
||||
$setupsql = "SET NAMES 'UTF-8'";
|
||||
|
@ -51,7 +51,6 @@
|
||||
"ext-mysqli": "Needed when Moodle uses MySQL or MariaDB database.",
|
||||
"ext-pgsql": "Needed when Moodle uses PostgreSQL database.",
|
||||
"ext-sqlsrv": "Needed when Moodle uses MS SQL Server database.",
|
||||
"ext-oci8": "Needed when Moodle uses Oracle database.",
|
||||
"ext-tokenizer": "Enabling Tokenizer PHP extension is recommended, it improves Moodle Networking functionality.",
|
||||
"ext-soap": "Enabling SOAP PHP extension is useful for web services and some plugins.",
|
||||
"ext-exif": "Enabling Exif PHP extension is recommended, it is used by Moodle to parse image meta data."
|
||||
|
@ -38,7 +38,7 @@ $CFG = new stdClass();
|
||||
// will be stored. This database must already have been created //
|
||||
// and a username/password created to access it. //
|
||||
|
||||
$CFG->dbtype = 'pgsql'; // 'pgsql', 'mariadb', 'mysqli', 'auroramysql', 'sqlsrv' or 'oci'
|
||||
$CFG->dbtype = 'pgsql'; // 'pgsql', 'mariadb', 'mysqli', 'auroramysql', or 'sqlsrv'
|
||||
$CFG->dblibrary = 'native'; // 'native' only at the moment
|
||||
$CFG->dbhost = 'localhost'; // eg 'localhost' or 'db.isp.com' or IP
|
||||
$CFG->dbname = 'moodle'; // database name, eg moodle
|
||||
@ -605,7 +605,7 @@ $CFG->admin = 'admin';
|
||||
//
|
||||
// Moodle 2.7 introduces a locking api for critical tasks (e.g. cron).
|
||||
// The default locking system to use is DB locking for Postgres, MySQL, MariaDB and
|
||||
// file locking for Oracle and SQLServer. If $CFG->preventfilelocking is set, then the
|
||||
// file locking for SQLServer. If $CFG->preventfilelocking is set, then the
|
||||
// default will always be DB locking. It can be manually set to one of the lock
|
||||
// factory classes listed below, or one of your own custom classes implementing the
|
||||
// \core\lock\lock_factory interface.
|
||||
|
@ -33,7 +33,7 @@ $string['dbpass'] = 'Database password';
|
||||
$string['dbsetupsql'] = 'Database setup command';
|
||||
$string['dbsetupsql_desc'] = 'SQL command for special database setup, often used to setup communication encoding - example for MySQL and PostgreSQL: <em>SET NAMES \'utf8\'</em>';
|
||||
$string['dbsybasequoting'] = 'Use sybase quotes';
|
||||
$string['dbsybasequoting_desc'] = 'Sybase style single quote escaping - needed for Oracle, MS SQL and some other databases. Do not use for MySQL!';
|
||||
$string['dbsybasequoting_desc'] = 'Sybase style single quote escaping - needed for MS SQL and some other databases. Do not use for MySQL!';
|
||||
$string['dbtype'] = 'Database driver';
|
||||
$string['dbtype_desc'] = 'ADOdb database driver name, type of the external database engine.';
|
||||
$string['dbuser'] = 'Database user';
|
||||
|
@ -82,11 +82,6 @@ final class sync_test extends \advanced_testcase {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'oracle':
|
||||
set_config('dbtype', 'oci8po', 'enrol_database');
|
||||
set_config('dbsybasequoting', '1', 'enrol_database');
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
set_config('dbtype', 'postgres7', 'enrol_database');
|
||||
$setupsql = "SET NAMES 'UTF-8'";
|
||||
|
@ -495,7 +495,6 @@ if ($config->stage == INSTALL_DATABASETYPE) {
|
||||
'auroramysql' => moodle_database::get_driver_instance('auroramysql', 'native'),
|
||||
'mariadb'=> moodle_database::get_driver_instance('mariadb', 'native'),
|
||||
'pgsql' => moodle_database::get_driver_instance('pgsql', 'native'),
|
||||
'oci' => moodle_database::get_driver_instance('oci', 'native'),
|
||||
'sqlsrv' => moodle_database::get_driver_instance('sqlsrv', 'native'), // MS SQL*Server PHP driver
|
||||
);
|
||||
|
||||
|
@ -986,7 +986,6 @@ $string['opensslrecommended'] = 'Installing the optional OpenSSL library is high
|
||||
$string['opensslrequired'] = 'The OpenSSL PHP extension is now required by Moodle to provide stronger cryptographic services.';
|
||||
$string['opentowebcrawlers'] = 'Open to search engines';
|
||||
$string['optionalmaintenancemessage'] = 'Optional maintenance message';
|
||||
$string['oracledatabaseinuse'] = 'Oracle DB support is to be removed. Moodle 4.5 will be the last version with Oracle DB support. For details, see the announcement on moodle.org <a href="https://moodle.org/mod/forum/discuss.php?d=456122">Oracle database support in LMS deprecation</a>.';
|
||||
$string['order1'] = 'First';
|
||||
$string['order2'] = 'Second';
|
||||
$string['order3'] = 'Third';
|
||||
|
@ -187,9 +187,6 @@ $string['nativemysqlihelp'] = '<p>The database is where most of the Moodle setti
|
||||
<p>The database name, username, and password are required fields; table prefix is optional.</p>
|
||||
<p>The database name may contain only alphanumeric characters, dollar ($) and underscore (_).</p>
|
||||
<p>If the database currently does not exist, and the user you specify has permission, Moodle will attempt to create a new database with the correct permissions and settings.</p>';
|
||||
$string['nativeoci'] = 'Oracle (native/oci)';
|
||||
$string['nativeocihelp'] = 'Now you need to configure the database where most Moodle data will be stored.
|
||||
This database must already have been created and a username and password created to access it. Table prefix is mandatory.';
|
||||
$string['nativepgsql'] = 'PostgreSQL (native/pgsql)';
|
||||
$string['nativepgsqlhelp'] = '<p>The database is where most of the Moodle settings and data are stored and must be configured here.</p>
|
||||
<p>The database name, username, password and table prefix are required fields.</p>
|
||||
@ -198,7 +195,6 @@ $string['nativesqlsrv'] = 'SQL*Server Microsoft (native/sqlsrv)';
|
||||
$string['nativesqlsrvhelp'] = 'Now you need to configure the database where most Moodle data will be stored.
|
||||
This database must already have been created and a username and password created to access it. Table prefix is mandatory.';
|
||||
$string['nativesqlsrvnodriver'] = 'Microsoft Drivers for SQL Server for PHP are not installed or not configured properly.';
|
||||
$string['ociextensionisnotpresentinphp'] = 'PHP has not been properly configured with the OCI8 extension so that it can communicate with Oracle. Please check your php.ini file or recompile PHP.';
|
||||
$string['pass'] = 'Pass';
|
||||
$string['paths'] = 'Paths';
|
||||
$string['pathserrcreatedataroot'] = 'Data directory ({$a->dataroot}) cannot be created by the installer.';
|
||||
|
@ -353,7 +353,7 @@ function behat_is_test_site() {
|
||||
* Fix variables for parallel behat testing.
|
||||
* - behat_wwwroot = behat_wwwroot{behatrunprocess}
|
||||
* - behat_dataroot = behat_dataroot{behatrunprocess}
|
||||
* - behat_prefix = behat_prefix.{behatrunprocess}_ (For oracle it will be firstletter of prefix and behatrunprocess)
|
||||
* - behat_prefix = behat_prefix.{behatrunprocess}
|
||||
**/
|
||||
function behat_update_vars_for_process() {
|
||||
global $CFG;
|
||||
@ -384,14 +384,8 @@ function behat_update_vars_for_process() {
|
||||
}
|
||||
|
||||
// Set behat_prefix for db, just suffix run process number, to avoid max length exceed.
|
||||
// For oracle only 2 letter prefix is possible.
|
||||
// NOTE: This will not work for parallel process > 9.
|
||||
if ($CFG->dbtype === 'oci') {
|
||||
$CFG->behat_prefix = substr($CFG->behat_prefix, 0, 1);
|
||||
$CFG->behat_prefix .= "{$behatrunprocess}";
|
||||
} else {
|
||||
$CFG->behat_prefix .= "{$behatrunprocess}_";
|
||||
}
|
||||
$CFG->behat_prefix .= "{$behatrunprocess}_";
|
||||
|
||||
if (!empty($CFG->behat_parallel_run[$behatrunprocess - 1])) {
|
||||
// Override allowed config vars.
|
||||
|
@ -423,15 +423,6 @@ abstract class context extends stdClass implements IteratorAggregate {
|
||||
ct.depth = temp.depth,
|
||||
ct.locked = temp.locked
|
||||
WHERE ct.id = temp.id";
|
||||
} else if ($dbfamily == 'oracle') {
|
||||
$updatesql = "UPDATE {context} ct
|
||||
SET (ct.path, ct.depth, ct.locked) =
|
||||
(SELECT temp.path, temp.depth, temp.locked
|
||||
FROM {context_temp} temp
|
||||
WHERE temp.id=ct.id)
|
||||
WHERE EXISTS (SELECT 'x'
|
||||
FROM {context_temp} temp
|
||||
WHERE temp.id = ct.id)";
|
||||
} else if ($dbfamily == 'postgres' || $dbfamily == 'mssql') {
|
||||
$updatesql = "UPDATE {context}
|
||||
SET path = temp.path,
|
||||
|
@ -136,7 +136,7 @@ class user_picture implements renderable {
|
||||
*
|
||||
* @param string $tableprefix name of database table prefix in query
|
||||
* @param null|array $extrafields extra fields to be included in result
|
||||
* Do not include TEXT columns because it would break SELECT DISTINCT in MSSQL and ORACLE.
|
||||
* Do not include TEXT columns because it would break SELECT DISTINCT in MSSQL.
|
||||
* @param string $idalias alias of id field
|
||||
* @param string $fieldprefix prefix to add to all columns in their aliases, does not apply to 'id'
|
||||
* @return string
|
||||
|
@ -733,21 +733,17 @@ function get_courses_search($searchterms, $sort, $page, $recordsperpage, &$total
|
||||
|
||||
$i = 0;
|
||||
|
||||
// Thanks Oracle for your non-ansi concat and type limits in coalesce. MDL-29912
|
||||
if ($DB->get_dbfamily() == 'oracle') {
|
||||
$concat = "(c.summary|| ' ' || c.fullname || ' ' || c.idnumber || ' ' || c.shortname)";
|
||||
} else {
|
||||
$concat = $DB->sql_concat("COALESCE(c.summary, '')", "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname');
|
||||
}
|
||||
$concat = $DB->sql_concat("COALESCE(c.summary, '')", "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname');
|
||||
|
||||
foreach ($searchterms as $searchterm) {
|
||||
$i++;
|
||||
|
||||
$NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
|
||||
/// will use it to simulate the "-" operator with LIKE clause
|
||||
// Initially we aren't going to perform NOT LIKE searches, only MSSQL
|
||||
// will use it to simulate the "-" operator with LIKE clause.
|
||||
$NOT = false;
|
||||
|
||||
/// Under Oracle and MSSQL, trim the + and - operators and perform
|
||||
/// simpler LIKE (or NOT LIKE) queries
|
||||
// Under MSSQL, trim the + and - operators and perform
|
||||
// simpler LIKE (or NOT LIKE) queries.
|
||||
if (!$DB->sql_regex_supported()) {
|
||||
if (substr($searchterm, 0, 1) == '-') {
|
||||
$NOT = true;
|
||||
@ -1107,7 +1103,7 @@ function get_my_remotecourses($userid=0) {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
|
||||
// we can not use SELECT DISTINCT + text field (summary) because of MS SQL and Oracle, subselect used therefore
|
||||
// We can not use SELECT DISTINCT + text field (summary) because of MS SQL, subselect used therefore.
|
||||
$sql = "SELECT c.id, c.remoteid, c.shortname, c.fullname,
|
||||
c.hostid, c.summary, c.summaryformat, c.categoryname AS cat_name,
|
||||
h.name AS hostname
|
||||
|
@ -1423,19 +1423,6 @@ function upgrade_block_set_my_user_parent_context(
|
||||
SET bi.parentcontextid = bic.contextid
|
||||
WHERE bi.id = bic.instanceid
|
||||
EOF;
|
||||
} else if ($dbfamily === 'oracle') {
|
||||
$sql = <<<EOF
|
||||
UPDATE {block_instances} bi
|
||||
SET (bi.parentcontextid) = (
|
||||
SELECT bic.contextid
|
||||
FROM {block_instance_context} bic
|
||||
WHERE bic.instanceid = bi.id
|
||||
) WHERE EXISTS (
|
||||
SELECT 'x'
|
||||
FROM {block_instance_context} bic
|
||||
WHERE bic.instanceid = bi.id
|
||||
)
|
||||
EOF;
|
||||
} else {
|
||||
// Postgres and sqlsrv.
|
||||
$sql = <<<EOF
|
||||
@ -1878,27 +1865,10 @@ function upgrade_change_binary_column_to_int(
|
||||
$dbman->add_field($table, $field);
|
||||
|
||||
// Copy the 'true' values from the old field to the new field.
|
||||
if ($DB->get_dbfamily() === 'oracle') {
|
||||
// It's tricky to use the binary column in the WHERE clause in Oracle DBs.
|
||||
// Let's go updating the records one by one. It's nasty, but it's only done for instances with Oracle DBs.
|
||||
// The normal SQL UPDATE statement will be used for other DBs.
|
||||
$columns = implode(', ', ['id', $tmpfieldname, $fieldname]);
|
||||
$records = $DB->get_recordset($tablename, null, '', $columns);
|
||||
if ($records->valid()) {
|
||||
foreach ($records as $record) {
|
||||
if (!$record->$tmpfieldname) {
|
||||
continue;
|
||||
}
|
||||
$DB->set_field($tablename, $fieldname, 1, ['id' => $record->id]);
|
||||
}
|
||||
}
|
||||
$records->close();
|
||||
} else {
|
||||
$sql = 'UPDATE {' . $tablename . '}
|
||||
SET ' . $fieldname . ' = 1
|
||||
WHERE ' . $tmpfieldname . ' = ?';
|
||||
$DB->execute($sql, [1]);
|
||||
}
|
||||
$sql = 'UPDATE {' . $tablename . '}
|
||||
SET ' . $fieldname . ' = 1
|
||||
WHERE ' . $tmpfieldname . ' = ?';
|
||||
$DB->execute($sql, [1]);
|
||||
|
||||
// Drop the old field.
|
||||
$oldfield = new xmldb_field($tmpfieldname);
|
||||
|
@ -1,756 +0,0 @@
|
||||
<?php
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Oracle specific SQL code generator.
|
||||
*
|
||||
* @package core_ddl
|
||||
* @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
|
||||
* 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/ddl/sql_generator.php');
|
||||
|
||||
/**
|
||||
* This class generate SQL code to be used against Oracle
|
||||
* It extends XMLDBgenerator so everything can be
|
||||
* overridden as needed to generate correct SQL.
|
||||
*
|
||||
* @package core_ddl
|
||||
* @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
|
||||
* 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class oracle_sql_generator extends sql_generator {
|
||||
|
||||
// Only set values that are different from the defaults present in XMLDBgenerator
|
||||
|
||||
/**
|
||||
* @var string To be automatically added at the end of each statement.
|
||||
* note: Using "/" because the standard ";" isn't good for stored procedures (triggers)
|
||||
*/
|
||||
public $statement_end = "\n/";
|
||||
|
||||
/** @var string Proper type for NUMBER(x) in this DB. */
|
||||
public $number_type = 'NUMBER';
|
||||
|
||||
/**
|
||||
* @var string To define the default to set for NOT NULLs CHARs without default (null=do nothing).
|
||||
* note: Using this whitespace here because Oracle doesn't distinguish empty and null! :-(
|
||||
*/
|
||||
public $default_for_char = ' ';
|
||||
|
||||
/** @var bool To specify if the generator must use some DEFAULT clause to drop defaults.*/
|
||||
public $drop_default_value_required = true;
|
||||
|
||||
/** @var string The DEFAULT clause required to drop defaults.*/
|
||||
public $drop_default_value = null;
|
||||
|
||||
/** @var bool To decide if the default clause of each field must go after the null clause.*/
|
||||
public $default_after_null = false;
|
||||
|
||||
/** @var bool True if the generator needs to add extra code to generate the sequence fields.*/
|
||||
public $sequence_extra_code = true;
|
||||
|
||||
/** @var string The particular name for inline sequences in this generator.*/
|
||||
public $sequence_name = '';
|
||||
|
||||
/** @var string The SQL template to alter columns where the 'TABLENAME' and 'COLUMNSPECS' keywords are dynamically replaced.*/
|
||||
public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY (COLUMNSPECS)';
|
||||
|
||||
/** @var int var ugly Oracle hack - size of the sequences values cache (20 = Default)*/
|
||||
public $sequence_cache_size = 20;
|
||||
|
||||
/**
|
||||
* Reset a sequence to the id field of a table.
|
||||
*
|
||||
* @param xmldb_table|string $table name of table or the table object.
|
||||
* @return array of sql statements
|
||||
*/
|
||||
public function getResetSequenceSQL($table) {
|
||||
|
||||
if (is_string($table)) {
|
||||
$tablename = $table;
|
||||
$xmldb_table = new xmldb_table($tablename);
|
||||
} else {
|
||||
$tablename = $table->getName();
|
||||
$xmldb_table = $table;
|
||||
}
|
||||
// From http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/statements_2011.htm
|
||||
$value = (int)$this->mdb->get_field_sql('SELECT MAX(id) FROM {'.$tablename.'}');
|
||||
$value++;
|
||||
|
||||
$seqname = $this->getSequenceFromDB($xmldb_table);
|
||||
|
||||
if (!$seqname) {
|
||||
// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method
|
||||
$seqname = $this->getNameForObject($table, 'id', 'seq');
|
||||
}
|
||||
|
||||
return array ("DROP SEQUENCE $seqname",
|
||||
"CREATE SEQUENCE $seqname START WITH $value INCREMENT BY 1 NOMAXVALUE CACHE $this->sequence_cache_size");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one xmldb_table, returns it's correct name, depending of all the parametrization
|
||||
* Overridden to allow change of names in temp tables
|
||||
*
|
||||
* @param xmldb_table table whose name we want
|
||||
* @param boolean to specify if the name must be quoted (if reserved word, only!)
|
||||
* @return string the correct name of the table
|
||||
*/
|
||||
public function getTableName(xmldb_table $xmldb_table, $quoted=true) {
|
||||
// Get the name, supporting special oci names for temp tables
|
||||
if ($this->temptables->is_temptable($xmldb_table->getName())) {
|
||||
$tablename = $this->temptables->get_correct_name($xmldb_table->getName());
|
||||
} else {
|
||||
$tablename = $this->prefix . $xmldb_table->getName();
|
||||
}
|
||||
|
||||
// Apply quotes optionally
|
||||
if ($quoted) {
|
||||
$tablename = $this->getEncQuoted($tablename);
|
||||
}
|
||||
|
||||
return $tablename;
|
||||
}
|
||||
|
||||
public function getCreateIndexSQL($xmldb_table, $xmldb_index) {
|
||||
if ($error = $xmldb_index->validateDefinition($xmldb_table)) {
|
||||
throw new coding_exception($error);
|
||||
}
|
||||
|
||||
$indexfields = $this->getEncQuoted($xmldb_index->getFields());
|
||||
|
||||
$unique = '';
|
||||
$suffix = 'ix';
|
||||
if ($xmldb_index->getUnique()) {
|
||||
$unique = ' UNIQUE';
|
||||
$suffix = 'uix';
|
||||
|
||||
$nullablefields = $this->get_nullable_fields_in_index($xmldb_table, $xmldb_index);
|
||||
if ($nullablefields) {
|
||||
// If this is a unique index with nullable fields, then we have to
|
||||
// apply the work-around from https://community.oracle.com/message/9518046#9518046.
|
||||
//
|
||||
// For example if you have a unique index on the three columns
|
||||
// (required, option1, option2) where the first one is non-null,
|
||||
// and the others nullable, then the SQL will end up as
|
||||
//
|
||||
// CREATE UNIQUE INDEX index_name ON table_name (
|
||||
// CASE WHEN option1 IS NOT NULL AND option2 IS NOT NULL THEN required ELSE NULL END,
|
||||
// CASE WHEN option1 IS NOT NULL AND option2 IS NOT NULL THEN option1 ELSE NULL END,
|
||||
// CASE WHEN option1 IS NOT NULL AND option2 IS NOT NULL THEN option2 ELSE NULL END)
|
||||
//
|
||||
// Basically Oracle behaves according to the standard if either
|
||||
// none of the columns are NULL or all columns contain NULL. Therefore,
|
||||
// if any column is NULL, we treat them all as NULL for the index.
|
||||
$conditions = [];
|
||||
foreach ($nullablefields as $fieldname) {
|
||||
$conditions[] = $this->getEncQuoted($fieldname) .
|
||||
' IS NOT NULL';
|
||||
}
|
||||
$condition = implode(' AND ', $conditions);
|
||||
|
||||
$updatedindexfields = [];
|
||||
foreach ($indexfields as $fieldname) {
|
||||
$updatedindexfields[] = 'CASE WHEN ' . $condition . ' THEN ' .
|
||||
$fieldname . ' ELSE NULL END';
|
||||
}
|
||||
$indexfields = $updatedindexfields;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$index = 'CREATE' . $unique . ' INDEX ';
|
||||
$index .= $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_index->getFields()), $suffix);
|
||||
$index .= ' ON ' . $this->getTableName($xmldb_table);
|
||||
$index .= ' (' . implode(', ', $indexfields) . ')';
|
||||
|
||||
return array($index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one correct xmldb_table, returns the SQL statements
|
||||
* to create temporary table (inside one array).
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @return array of sql statements
|
||||
*/
|
||||
public function getCreateTempTableSQL($xmldb_table) {
|
||||
$this->temptables->add_temptable($xmldb_table->getName());
|
||||
$sqlarr = $this->getCreateTableSQL($xmldb_table);
|
||||
$sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE GLOBAL TEMPORARY TABLE $1 ON COMMIT PRESERVE ROWS', $sqlarr);
|
||||
return $sqlarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one correct xmldb_table, returns the SQL statements
|
||||
* to drop it (inside one array).
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The table to drop.
|
||||
* @return array SQL statement(s) for dropping the specified table.
|
||||
*/
|
||||
public function getDropTableSQL($xmldb_table) {
|
||||
$sqlarr = parent::getDropTableSQL($xmldb_table);
|
||||
if ($this->temptables->is_temptable($xmldb_table->getName())) {
|
||||
array_unshift($sqlarr, "TRUNCATE TABLE ". $this->getTableName($xmldb_table)); // oracle requires truncate before being able to drop a temp table
|
||||
}
|
||||
return $sqlarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one XMLDB Type, length and decimals, returns the DB proper SQL type.
|
||||
*
|
||||
* @param int $xmldb_type The xmldb_type defined constant. XMLDB_TYPE_INTEGER and other XMLDB_TYPE_* constants.
|
||||
* @param int $xmldb_length The length of that data type.
|
||||
* @param int $xmldb_decimals The decimal places of precision of the data type.
|
||||
* @return string The DB defined data type.
|
||||
*/
|
||||
public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
|
||||
|
||||
switch ($xmldb_type) {
|
||||
case XMLDB_TYPE_INTEGER: // See http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/sql_elements001.htm#sthref86.
|
||||
if (empty($xmldb_length)) {
|
||||
$xmldb_length = 10;
|
||||
}
|
||||
$dbtype = 'NUMBER(' . $xmldb_length . ')';
|
||||
break;
|
||||
case XMLDB_TYPE_FLOAT:
|
||||
case XMLDB_TYPE_NUMBER:
|
||||
$dbtype = $this->number_type;
|
||||
if (!empty($xmldb_length)) {
|
||||
$dbtype .= '(' . $xmldb_length;
|
||||
if (!empty($xmldb_decimals)) {
|
||||
$dbtype .= ',' . $xmldb_decimals;
|
||||
}
|
||||
$dbtype .= ')';
|
||||
}
|
||||
break;
|
||||
case XMLDB_TYPE_CHAR:
|
||||
// Do not use NVARCHAR2 here because it has hardcoded 1333 char limit,
|
||||
// VARCHAR2 allows us to create larger fields that error out later during runtime
|
||||
// only when too many non-ascii utf-8 chars present.
|
||||
$dbtype = 'VARCHAR2';
|
||||
if (empty($xmldb_length)) {
|
||||
$xmldb_length='255';
|
||||
}
|
||||
$dbtype .= '(' . $xmldb_length . ' CHAR)'; // CHAR is required because BYTE is the default
|
||||
break;
|
||||
case XMLDB_TYPE_TEXT:
|
||||
$dbtype = 'CLOB';
|
||||
break;
|
||||
case XMLDB_TYPE_BINARY:
|
||||
$dbtype = 'BLOB';
|
||||
break;
|
||||
case XMLDB_TYPE_DATETIME:
|
||||
$dbtype = 'DATE';
|
||||
break;
|
||||
}
|
||||
return $dbtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code (array of statements) needed
|
||||
* to create one sequence for the xmldb_table and xmldb_field passed in.
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @param xmldb_field $xmldb_field The xmldb_field object instance.
|
||||
* @return array Array of SQL statements to create the sequence.
|
||||
*/
|
||||
public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
|
||||
|
||||
$results = array();
|
||||
|
||||
$sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
|
||||
|
||||
$sequence = "CREATE SEQUENCE $sequence_name START WITH 1 INCREMENT BY 1 NOMAXVALUE CACHE $this->sequence_cache_size";
|
||||
|
||||
$results[] = $sequence;
|
||||
|
||||
$results = array_merge($results, $this->getCreateTriggerSQL ($xmldb_table, $xmldb_field, $sequence_name));
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code needed to create one trigger for the xmldb_table and xmldb_field passed
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @param xmldb_field $xmldb_field The xmldb_field object instance.
|
||||
* @param string $sequence_name
|
||||
* @return array Array of SQL statements to create the sequence.
|
||||
*/
|
||||
public function getCreateTriggerSQL($xmldb_table, $xmldb_field, $sequence_name) {
|
||||
|
||||
$trigger_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'trg');
|
||||
|
||||
$trigger = "CREATE TRIGGER " . $trigger_name;
|
||||
$trigger.= "\n BEFORE INSERT";
|
||||
$trigger.= "\nON " . $this->getTableName($xmldb_table);
|
||||
$trigger.= "\n FOR EACH ROW";
|
||||
$trigger.= "\nBEGIN";
|
||||
$trigger.= "\n IF :new." . $this->getEncQuoted($xmldb_field->getName()) . ' IS NULL THEN';
|
||||
$trigger.= "\n SELECT " . $sequence_name . '.nextval INTO :new.' . $this->getEncQuoted($xmldb_field->getName()) . " FROM dual;";
|
||||
$trigger.= "\n END IF;";
|
||||
$trigger.= "\nEND;";
|
||||
|
||||
return array($trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code needed to drop one sequence for the xmldb_table and xmldb_field passed
|
||||
* Can, optionally, specify if the underlying trigger will be also dropped
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @param xmldb_field $xmldb_field The xmldb_field object instance.
|
||||
* @param bool $include_trigger
|
||||
* @return array Array of SQL statements to create the sequence.
|
||||
*/
|
||||
public function getDropSequenceSQL($xmldb_table, $xmldb_field, $include_trigger=false) {
|
||||
|
||||
$result = array();
|
||||
|
||||
if ($sequence_name = $this->getSequenceFromDB($xmldb_table)) {
|
||||
$result[] = "DROP SEQUENCE " . $sequence_name;
|
||||
}
|
||||
|
||||
if ($trigger_name = $this->getTriggerFromDB($xmldb_table) && $include_trigger) {
|
||||
$result[] = "DROP TRIGGER " . $trigger_name;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code (array of statements) needed to add one comment to the table.
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @return array Array of SQL statements to add one comment to the table.
|
||||
*/
|
||||
function getCommentSQL($xmldb_table) {
|
||||
|
||||
$comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
|
||||
$comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
|
||||
|
||||
return array($comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code (array of statements) needed to execute extra statements on table drop
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @return array Array of extra SQL statements to drop a table.
|
||||
*/
|
||||
public function getDropTableExtraSQL($xmldb_table) {
|
||||
$xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
|
||||
return $this->getDropSequenceSQL($xmldb_table, $xmldb_field, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code (array of statements) needed to execute extra statements on table rename.
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @param string $newname The new name for the table.
|
||||
* @return array Array of extra SQL statements to rename a table.
|
||||
*/
|
||||
public function getRenameTableExtraSQL($xmldb_table, $newname) {
|
||||
|
||||
$results = array();
|
||||
|
||||
$xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
|
||||
|
||||
$oldseqname = $this->getSequenceFromDB($xmldb_table);
|
||||
$newseqname = $this->getNameForObject($newname, $xmldb_field->getName(), 'seq');
|
||||
|
||||
$oldtriggername = $this->getTriggerFromDB($xmldb_table);
|
||||
$newtriggername = $this->getNameForObject($newname, $xmldb_field->getName(), 'trg');
|
||||
|
||||
// Drop old trigger (first of all)
|
||||
$results[] = "DROP TRIGGER " . $oldtriggername;
|
||||
|
||||
// Rename the sequence, disablig CACHE before and enablig it later
|
||||
// to avoid consuming of values on rename
|
||||
$results[] = 'ALTER SEQUENCE ' . $oldseqname . ' NOCACHE';
|
||||
$results[] = 'RENAME ' . $oldseqname . ' TO ' . $newseqname;
|
||||
$results[] = 'ALTER SEQUENCE ' . $newseqname . ' CACHE ' . $this->sequence_cache_size;
|
||||
|
||||
// Create new trigger
|
||||
$newt = new xmldb_table($newname); // Temp table for trigger code generation
|
||||
$results = array_merge($results, $this->getCreateTriggerSQL($newt, $xmldb_field, $newseqname));
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one xmldb_table and one xmldb_field, return the SQL statements needed to alter the field in the table.
|
||||
*
|
||||
* Oracle has some severe limits:
|
||||
* - clob and blob fields doesn't allow type to be specified
|
||||
* - error is dropped if the null/not null clause is specified and hasn't changed
|
||||
* - changes in precision/decimals of numeric fields drop an ORA-1440 error
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The table related to $xmldb_field.
|
||||
* @param xmldb_field $xmldb_field The instance of xmldb_field to create the SQL from.
|
||||
* @param string $skip_type_clause The type clause on alter columns, NULL by default.
|
||||
* @param string $skip_default_clause The default clause on alter columns, NULL by default.
|
||||
* @param string $skip_notnull_clause The null/notnull clause on alter columns, NULL by default.
|
||||
* @return string The field altering SQL statement.
|
||||
*/
|
||||
public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
|
||||
|
||||
$skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause;
|
||||
$skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause;
|
||||
$skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause;
|
||||
|
||||
$results = array(); // To store all the needed SQL commands
|
||||
|
||||
// Get the quoted name of the table and field
|
||||
$tablename = $this->getTableName($xmldb_table);
|
||||
$fieldname = $xmldb_field->getName();
|
||||
|
||||
// Take a look to field metadata
|
||||
$meta = $this->mdb->get_columns($xmldb_table->getName());
|
||||
$metac = $meta[$fieldname];
|
||||
$oldmetatype = $metac->meta_type;
|
||||
|
||||
$oldlength = $metac->max_length;
|
||||
// To calculate the oldlength if the field is numeric, we need to perform one extra query
|
||||
// because ADOdb has one bug here. http://phplens.com/lens/lensforum/msgs.php?id=15883
|
||||
if ($oldmetatype == 'N') {
|
||||
$uppertablename = strtoupper($tablename);
|
||||
$upperfieldname = strtoupper($fieldname);
|
||||
if ($col = $this->mdb->get_record_sql("SELECT cname, precision
|
||||
FROM col
|
||||
WHERE tname = ? AND cname = ?",
|
||||
array($uppertablename, $upperfieldname))) {
|
||||
$oldlength = $col->precision;
|
||||
}
|
||||
}
|
||||
$olddecimals = empty($metac->scale) ? null : $metac->scale;
|
||||
$oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
|
||||
$olddefault = empty($metac->default_value) || strtoupper($metac->default_value) == 'NULL' ? null : $metac->default_value;
|
||||
|
||||
$typechanged = true; //By default, assume that the column type has changed
|
||||
$precisionchanged = true; //By default, assume that the column precision has changed
|
||||
$decimalchanged = true; //By default, assume that the column decimal has changed
|
||||
$defaultchanged = true; //By default, assume that the column default has changed
|
||||
$notnullchanged = true; //By default, assume that the column notnull has changed
|
||||
|
||||
$from_temp_fields = false; //By default don't assume we are going to use temporal fields
|
||||
|
||||
// Detect if we are changing the type of the column
|
||||
if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_NUMBER && $oldmetatype == 'N') ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_FLOAT && $oldmetatype == 'F') ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_CHAR && $oldmetatype == 'C') ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_TEXT && $oldmetatype == 'X') ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_BINARY && $oldmetatype == 'B')) {
|
||||
$typechanged = false;
|
||||
}
|
||||
// Detect if precision has changed
|
||||
if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
|
||||
($oldlength == -1) ||
|
||||
($xmldb_field->getLength() == $oldlength)) {
|
||||
$precisionchanged = false;
|
||||
}
|
||||
// Detect if decimal has changed
|
||||
if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
|
||||
($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
|
||||
(!$xmldb_field->getDecimals()) ||
|
||||
(!$olddecimals) ||
|
||||
($xmldb_field->getDecimals() == $olddecimals)) {
|
||||
$decimalchanged = false;
|
||||
}
|
||||
// Detect if we are changing the default
|
||||
if (($xmldb_field->getDefault() === null && $olddefault === null) ||
|
||||
($xmldb_field->getDefault() === $olddefault) || //Check both equality and
|
||||
("'" . $xmldb_field->getDefault() . "'" === $olddefault)) { //Equality with quotes because ADOdb returns the default with quotes
|
||||
$defaultchanged = false;
|
||||
}
|
||||
|
||||
// Detect if we are changing the nullability
|
||||
if (($xmldb_field->getNotnull() === $oldnotnull)) {
|
||||
$notnullchanged = false;
|
||||
}
|
||||
|
||||
// If type has changed or precision or decimal has changed and we are in one numeric field
|
||||
// - create one temp column with the new specs
|
||||
// - fill the new column with the values from the old one
|
||||
// - drop the old column
|
||||
// - rename the temp column to the original name
|
||||
if (($typechanged) || (($oldmetatype == 'N' || $oldmetatype == 'I') && ($precisionchanged || $decimalchanged))) {
|
||||
$tempcolname = $xmldb_field->getName() . '___tmp'; // Short tmp name, surely not conflicting ever
|
||||
if (strlen($tempcolname) > 30) { // Safeguard we don't excess the 30cc limit
|
||||
$tempcolname = 'ongoing_alter_column_tmp';
|
||||
}
|
||||
// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
|
||||
$skip_notnull_clause = true;
|
||||
$skip_default_clause = true;
|
||||
$xmldb_field->setName($tempcolname);
|
||||
// Drop the temp column, in case it exists (due to one previous failure in conversion)
|
||||
// really ugly but we cannot enclose DDL into transaction :-(
|
||||
if (isset($meta[$tempcolname])) {
|
||||
$results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
|
||||
}
|
||||
// Create the temporal column
|
||||
$results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_type_clause, $skip_notnull_clause));
|
||||
// Copy contents from original col to the temporal one
|
||||
|
||||
// From TEXT to integer/number we need explicit conversion
|
||||
if ($oldmetatype == 'X' && $xmldb_field->GetType() == XMLDB_TYPE_INTEGER) {
|
||||
$results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = CAST(' . $this->mdb->sql_compare_text($fieldname) . ' AS INT)';
|
||||
} else if ($oldmetatype == 'X' && $xmldb_field->GetType() == XMLDB_TYPE_NUMBER) {
|
||||
$results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = CAST(' . $this->mdb->sql_compare_text($fieldname) . ' AS NUMBER)';
|
||||
|
||||
// Normal cases, implicit conversion
|
||||
} else {
|
||||
$results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $fieldname;
|
||||
}
|
||||
// Drop the old column
|
||||
$xmldb_field->setName($fieldname); //Set back the original field name
|
||||
$results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
|
||||
// Rename the temp column to the original one
|
||||
$results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
|
||||
// Mark we have performed one change based in temp fields
|
||||
$from_temp_fields = true;
|
||||
// Re-enable the notnull and default sections so the general AlterFieldSQL can use it
|
||||
$skip_notnull_clause = false;
|
||||
$skip_default_clause = false;
|
||||
// Disable the type section because we have done it with the temp field
|
||||
$skip_type_clause = true;
|
||||
// If new field is nullable, nullability hasn't changed
|
||||
if (!$xmldb_field->getNotnull()) {
|
||||
$notnullchanged = false;
|
||||
}
|
||||
// If new field hasn't default, default hasn't changed
|
||||
if ($xmldb_field->getDefault() === null) {
|
||||
$defaultchanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If type and precision and decimals hasn't changed, prevent the type clause
|
||||
if (!$typechanged && !$precisionchanged && !$decimalchanged) {
|
||||
$skip_type_clause = true;
|
||||
}
|
||||
|
||||
// If NULL/NOT NULL hasn't changed
|
||||
// prevent null clause to be specified
|
||||
if (!$notnullchanged) {
|
||||
$skip_notnull_clause = true; // Initially, prevent the notnull clause
|
||||
// But, if we have used the temp field and the new field is not null, then enforce the not null clause
|
||||
if ($from_temp_fields && $xmldb_field->getNotnull()) {
|
||||
$skip_notnull_clause = false;
|
||||
}
|
||||
}
|
||||
// If default hasn't changed
|
||||
// prevent default clause to be specified
|
||||
if (!$defaultchanged) {
|
||||
$skip_default_clause = true; // Initially, prevent the default clause
|
||||
// But, if we have used the temp field and the new field has default clause, then enforce the default clause
|
||||
if ($from_temp_fields) {
|
||||
$default_clause = $this->getDefaultClause($xmldb_field);
|
||||
if ($default_clause) {
|
||||
$skip_notnull_clause = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If arriving here, something is not being skipped (type, notnull, default), calculate the standard AlterFieldSQL
|
||||
if (!$skip_type_clause || !$skip_notnull_clause || !$skip_default_clause) {
|
||||
$results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_default_clause, $skip_notnull_clause));
|
||||
return $results;
|
||||
}
|
||||
|
||||
// Finally return results
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one xmldb_table and one xmldb_field, return the SQL statements needed to add its default
|
||||
* (usually invoked from getModifyDefaultSQL()
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @param xmldb_field $xmldb_field The xmldb_field object instance.
|
||||
* @return array Array of SQL statements to create a field's default.
|
||||
*/
|
||||
public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
|
||||
// Just a wrapper over the getAlterFieldSQL() function for Oracle that
|
||||
// is capable of handling defaults
|
||||
return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its default
|
||||
* (usually invoked from getModifyDefaultSQL()
|
||||
*
|
||||
* Note that this method may be dropped in future.
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @param xmldb_field $xmldb_field The xmldb_field object instance.
|
||||
* @return array Array of SQL statements to create a field's default.
|
||||
*
|
||||
* @todo MDL-31147 Moodle 2.1 - Drop getDropDefaultSQL()
|
||||
*/
|
||||
public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
|
||||
// Just a wrapper over the getAlterFieldSQL() function for Oracle that
|
||||
// is capable of handling defaults
|
||||
return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one xmldb_table returns one string with the sequence of the table
|
||||
* in the table (fetched from DB)
|
||||
* The sequence name for oracle is calculated by looking the corresponding
|
||||
* trigger and retrieving the sequence name from it (because sequences are
|
||||
* independent elements)
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @return string|bool If no sequence is found, returns false
|
||||
*/
|
||||
public function getSequenceFromDB($xmldb_table) {
|
||||
|
||||
$tablename = strtoupper($this->getTableName($xmldb_table));
|
||||
$prefixupper = strtoupper($this->prefix);
|
||||
$sequencename = false;
|
||||
|
||||
if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
|
||||
FROM user_triggers
|
||||
WHERE table_name = ? AND trigger_name LIKE ?",
|
||||
array($tablename, "{$prefixupper}%_ID%_TRG"))) {
|
||||
// If trigger found, regexp it looking for the sequence name
|
||||
preg_match('/.*SELECT (.*)\.nextval/i', $trigger->trigger_body, $matches);
|
||||
if (isset($matches[1])) {
|
||||
$sequencename = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $sequencename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one xmldb_table returns one string with the trigger
|
||||
* in the table (fetched from DB)
|
||||
*
|
||||
* @param xmldb_table $xmldb_table The xmldb_table object instance.
|
||||
* @return string|bool If no trigger is found, returns false
|
||||
*/
|
||||
public function getTriggerFromDB($xmldb_table) {
|
||||
|
||||
$tablename = strtoupper($this->getTableName($xmldb_table));
|
||||
$prefixupper = strtoupper($this->prefix);
|
||||
$triggername = false;
|
||||
|
||||
if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
|
||||
FROM user_triggers
|
||||
WHERE table_name = ? AND trigger_name LIKE ?",
|
||||
array($tablename, "{$prefixupper}%_ID%_TRG"))) {
|
||||
$triggername = $trigger->trigger_name;
|
||||
}
|
||||
|
||||
return $triggername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg).
|
||||
*
|
||||
* (MySQL requires the whole xmldb_table object to be specified, so we add it always)
|
||||
*
|
||||
* This is invoked from getNameForObject().
|
||||
* Only some DB have this implemented.
|
||||
*
|
||||
* @param string $object_name The object's name to check for.
|
||||
* @param string $type The object's type (pk, uk, fk, ck, ix, uix, seq, trg).
|
||||
* @param string $table_name The table's name to check in
|
||||
* @return bool If such name is currently in use (true) or no (false)
|
||||
*/
|
||||
public function isNameInUse($object_name, $type, $table_name) {
|
||||
switch($type) {
|
||||
case 'ix':
|
||||
case 'uix':
|
||||
case 'seq':
|
||||
case 'trg':
|
||||
if ($check = $this->mdb->get_records_sql("SELECT object_name
|
||||
FROM user_objects
|
||||
WHERE lower(object_name) = ?", array(strtolower($object_name)))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'pk':
|
||||
case 'uk':
|
||||
case 'fk':
|
||||
case 'ck':
|
||||
if ($check = $this->mdb->get_records_sql("SELECT constraint_name
|
||||
FROM user_constraints
|
||||
WHERE lower(constraint_name) = ?", array(strtolower($object_name)))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false; //No name in use found
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds slashes to string.
|
||||
* @param string $s
|
||||
* @return string The escaped string.
|
||||
*/
|
||||
public function addslashes($s) {
|
||||
// do not use php addslashes() because it depends on PHP quote settings!
|
||||
$s = str_replace("'", "''", $s);
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of reserved words (lowercase) for this DB
|
||||
* @return array An array of database specific reserved words
|
||||
*/
|
||||
public static function getReservedWords() {
|
||||
// This file contains the reserved words for Oracle databases
|
||||
// from http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/ap_keywd.htm
|
||||
$reserved_words = array (
|
||||
'access', 'add', 'all', 'alter', 'and', 'any',
|
||||
'as', 'asc', 'audit', 'between', 'by', 'char',
|
||||
'check', 'cluster', 'column', 'comment',
|
||||
'compress', 'connect', 'create', 'current',
|
||||
'date', 'decimal', 'default', 'delete', 'desc',
|
||||
'distinct', 'drop', 'else', 'exclusive', 'exists',
|
||||
'file', 'float', 'for', 'from', 'grant', 'group',
|
||||
'having', 'identified', 'immediate', 'in',
|
||||
'increment', 'index', 'initial', 'insert',
|
||||
'integer', 'intersect', 'into', 'is', 'level',
|
||||
'like', 'lock', 'long', 'maxextents', 'minus',
|
||||
'mlslabel', 'mode', 'modify', 'nchar', 'nclob', 'noaudit',
|
||||
'nocompress', 'not', 'nowait', 'null', 'number', 'nvarchar2',
|
||||
'of', 'offline', 'on', 'online', 'option', 'or',
|
||||
'order', 'pctfree', 'prior', 'privileges',
|
||||
'public', 'raw', 'rename', 'resource', 'revoke',
|
||||
'row', 'rowid', 'rownum', 'rows', 'select',
|
||||
'session', 'set', 'share', 'size', 'smallint',
|
||||
'start', 'successful', 'synonym', 'sysdate',
|
||||
'table', 'then', 'to', 'trigger', 'uid', 'union',
|
||||
'unique', 'update', 'user', 'validate', 'values',
|
||||
'varchar', 'varchar2', 'view', 'whenever',
|
||||
'where', 'with'
|
||||
);
|
||||
return $reserved_words;
|
||||
}
|
||||
}
|
@ -1393,7 +1393,7 @@ abstract class sql_generator {
|
||||
public static function getAllReservedWords() {
|
||||
global $CFG;
|
||||
|
||||
$generators = array('mysql', 'postgres', 'oracle', 'mssql');
|
||||
$generators = array('mysql', 'postgres', 'mssql');
|
||||
$reserved_words = array();
|
||||
|
||||
foreach($generators as $generator) {
|
||||
|
@ -2131,7 +2131,6 @@ final class ddl_test extends \database_driver_testcase {
|
||||
$rec = $DB->get_record($tablename, array('id'=>$id));
|
||||
$this->assertSame($maxstr, $rec->name);
|
||||
|
||||
// Following test is supposed to fail in oracle.
|
||||
$maxstr = '';
|
||||
for ($i=0; $i<xmldb_field::CHAR_MAX_LENGTH; $i++) {
|
||||
$maxstr .= '言'; // Random long string that should fix exactly the limit for one char column.
|
||||
@ -2147,11 +2146,7 @@ final class ddl_test extends \database_driver_testcase {
|
||||
$rec = $DB->get_record($tablename, array('id'=>$id));
|
||||
$this->assertSame($maxstr, $rec->name);
|
||||
} catch (dml_exception $e) {
|
||||
if ($DB->get_dbfamily() === 'oracle') {
|
||||
$this->fail('Oracle does not support text fields larger than 4000 bytes, this is not a big problem for mostly ascii based languages');
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$table = new xmldb_table('testtable');
|
||||
@ -2298,7 +2293,6 @@ final class ddl_test extends \database_driver_testcase {
|
||||
$this->assertSame("`$columnname`", $gen->getEncQuoted($columnname));
|
||||
break;
|
||||
case 'mssql': // The Moodle connection runs under 'QUOTED_IDENTIFIER ON'.
|
||||
case 'oracle':
|
||||
case 'postgres':
|
||||
case 'sqlite':
|
||||
default:
|
||||
@ -2360,7 +2354,6 @@ final class ddl_test extends \database_driver_testcase {
|
||||
$gen->getRenameFieldSQL($table, $field, $newcolumnname)
|
||||
);
|
||||
break;
|
||||
case 'oracle':
|
||||
case 'postgres':
|
||||
default:
|
||||
$this->assertSame(
|
||||
@ -2388,7 +2381,6 @@ final class ddl_test extends \database_driver_testcase {
|
||||
$gen->getRenameFieldSQL($table, $field, $newcolumnname)
|
||||
);
|
||||
break;
|
||||
case 'oracle':
|
||||
case 'postgres':
|
||||
default:
|
||||
$this->assertSame(
|
||||
|
@ -75,7 +75,7 @@ class auroramysql_native_moodle_database extends mysqli_native_moodle_database {
|
||||
* Returns more specific database driver type
|
||||
*
|
||||
* Returns more specific database driver type. Can be used before connect().
|
||||
* @return string db type mysqli, pgsql, oci, mssql, sqlsrv
|
||||
* @return string db type mysqli, pgsql, mssql, sqlsrv
|
||||
*/
|
||||
protected function get_dbtype(): ?string {
|
||||
return 'auroramysql';
|
||||
|
@ -68,7 +68,7 @@ class mariadb_native_moodle_database extends mysqli_native_moodle_database {
|
||||
/**
|
||||
* Returns more specific database driver type
|
||||
* Note: can be used before connect()
|
||||
* @return string db type mysqli, pgsql, oci, mssql, sqlsrv
|
||||
* @return string db type mysqli, pgsql, mssql, sqlsrv
|
||||
*/
|
||||
protected function get_dbtype() {
|
||||
return 'mariadb';
|
||||
|
@ -188,7 +188,7 @@ abstract class moodle_database {
|
||||
*
|
||||
* The loaded class is within lib/dml directory and of the form: $type.'_'.$library.'_moodle_database'
|
||||
*
|
||||
* @param string $type Database driver's type. (eg: mysqli, pgsql, mssql, sqldrv, oci, etc.)
|
||||
* @param string $type Database driver's type. (eg: mysqli, pgsql, mssql, sqldrv, etc.)
|
||||
* @param string $library Database driver's library (native, pdo, etc.)
|
||||
* @param bool $external True if this is an external database.
|
||||
* @return ?moodle_database driver object or null if error, for example of driver object see {@see mysqli_native_moodle_database}
|
||||
@ -219,14 +219,14 @@ abstract class moodle_database {
|
||||
/**
|
||||
* Returns the database family type. (This sort of describes the SQL 'dialect')
|
||||
* Note: can be used before connect()
|
||||
* @return string The db family name (mysql, postgres, mssql, oracle, etc.)
|
||||
* @return string The db family name (mysql, postgres, mssql, etc.)
|
||||
*/
|
||||
abstract public function get_dbfamily();
|
||||
|
||||
/**
|
||||
* Returns a more specific database driver type
|
||||
* Note: can be used before connect()
|
||||
* @return string The db type mysqli, pgsql, oci, mssql, sqlsrv
|
||||
* @return string The db type mysqli, pgsql, mssql, sqlsrv
|
||||
*/
|
||||
abstract protected function get_dbtype();
|
||||
|
||||
|
@ -135,7 +135,7 @@ class mysqli_native_moodle_database extends moodle_database {
|
||||
/**
|
||||
* Returns database family type - describes SQL dialect
|
||||
* Note: can be used before connect()
|
||||
* @return string db family name (mysql, postgres, mssql, oracle, etc.)
|
||||
* @return string db family name (mysql, postgres, mssql, etc.)
|
||||
*/
|
||||
public function get_dbfamily() {
|
||||
return 'mysql';
|
||||
@ -144,7 +144,7 @@ class mysqli_native_moodle_database extends moodle_database {
|
||||
/**
|
||||
* Returns more specific database driver type
|
||||
* Note: can be used before connect()
|
||||
* @return string db type mysqli, pgsql, oci, mssql, sqlsrv
|
||||
* @return string db type mysqli, pgsql, mssql, sqlsrv
|
||||
*/
|
||||
protected function get_dbtype() {
|
||||
return 'mysqli';
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,151 +0,0 @@
|
||||
-- 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @package core_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:
|
||||
* - 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.
|
||||
*
|
||||
* Moodle will not parse this file correctly if it uses Windows line endings.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
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 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;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE PACKAGE BODY MOODLELIB 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 MOODLELIB.BITOR(value1,value2) - BITAND(value1,value2);
|
||||
END BITXOR;
|
||||
|
||||
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;
|
||||
|
||||
FUNCTION UNDO_DIRTY_HACK(hackedstring IN VARCHAR2) RETURN VARCHAR2 IS
|
||||
|
||||
BEGIN
|
||||
IF hackedstring = ' ' THEN
|
||||
RETURN '';
|
||||
END IF;
|
||||
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;
|
||||
/
|
||||
|
||||
SHOW ERRORS
|
||||
/
|
@ -1,88 +0,0 @@
|
||||
<?php
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Oracle specific recordset.
|
||||
*
|
||||
* @package core_dml
|
||||
* @copyright 2008 Petr Skoda (http://skodak.org)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__.'/moodle_recordset.php');
|
||||
|
||||
class oci_native_moodle_recordset extends moodle_recordset {
|
||||
|
||||
protected $stmt;
|
||||
protected $current;
|
||||
|
||||
public function __construct($stmt) {
|
||||
$this->stmt = $stmt;
|
||||
$this->current = $this->fetch_next();
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
$this->close();
|
||||
}
|
||||
|
||||
private function fetch_next() {
|
||||
if (!$this->stmt) {
|
||||
return false;
|
||||
}
|
||||
if (!$row = oci_fetch_array($this->stmt, OCI_ASSOC + OCI_RETURN_NULLS + OCI_RETURN_LOBS)) {
|
||||
oci_free_statement($this->stmt);
|
||||
$this->stmt = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
unset($row['oracle_rownum']);
|
||||
array_walk($row, array('oci_native_moodle_database', 'onespace2empty'));
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function current(): stdClass {
|
||||
return (object)$this->current;
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key() {
|
||||
// return first column value as key
|
||||
if (!$this->current) {
|
||||
return false;
|
||||
}
|
||||
$key = reset($this->current);
|
||||
return $key;
|
||||
}
|
||||
|
||||
public function next(): void {
|
||||
$this->current = $this->fetch_next();
|
||||
}
|
||||
|
||||
public function valid(): bool {
|
||||
return !empty($this->current);
|
||||
}
|
||||
|
||||
public function close() {
|
||||
if ($this->stmt) {
|
||||
oci_free_statement($this->stmt);
|
||||
$this->stmt = null;
|
||||
}
|
||||
$this->current = null;
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* OCI specific temptables store. Needed because temporary tables
|
||||
* in Oracle are global (to all sessions), so we need to rename them
|
||||
* on the fly in order to get local (different for each session) table names.
|
||||
* Also used to be able to retrieve temp table names included in the get_tables()
|
||||
* method of the DB.
|
||||
*
|
||||
* @package core_dml
|
||||
* @copyright 2009 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__.'/moodle_temptables.php');
|
||||
|
||||
class oci_native_moodle_temptables extends moodle_temptables {
|
||||
|
||||
/** @var int To store unique_session_id. Needed for temp tables unique naming (upto 24cc) */
|
||||
protected $unique_session_id; //
|
||||
/** @var int To get incrementally different temptable names on each add_temptable() request */
|
||||
protected $counter;
|
||||
|
||||
/**
|
||||
* Creates new moodle_temptables instance
|
||||
* @param object moodle_database instance
|
||||
*/
|
||||
public function __construct($mdb, $unique_session_id) {
|
||||
$this->unique_session_id = $unique_session_id;
|
||||
$this->counter = 1;
|
||||
parent::__construct($mdb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one temptable to the store.
|
||||
*
|
||||
* Overridden because OCI only support global temptables, so we need to change completely the name, based
|
||||
* in unique session identifier, to get local-like temp tables support
|
||||
* tables before the prefix.
|
||||
*
|
||||
* Given one moodle temptable name (without prefix), add it to the store, with the
|
||||
* key being the original moodle name and the value being the real db temptable name
|
||||
* already prefixed
|
||||
*
|
||||
* Override and use this *only* if the database requires modification in the table name.
|
||||
*
|
||||
* @param string $tablename name without prefix of the table created as temptable
|
||||
*/
|
||||
public function add_temptable($tablename) {
|
||||
// TODO: throw exception if exists: if ($this->is_temptable...
|
||||
$this->temptables[$tablename] = $this->prefix . $this->unique_session_id . $this->counter;
|
||||
$this->counter++;
|
||||
}
|
||||
}
|
@ -87,7 +87,7 @@ class pgsql_native_moodle_database extends moodle_database {
|
||||
/**
|
||||
* Returns database family type - describes SQL dialect
|
||||
* Note: can be used before connect()
|
||||
* @return string db family name (mysql, postgres, mssql, oracle, etc.)
|
||||
* @return string db family name (mysql, postgres, mssql, etc.)
|
||||
*/
|
||||
public function get_dbfamily() {
|
||||
return 'postgres';
|
||||
@ -96,7 +96,7 @@ class pgsql_native_moodle_database extends moodle_database {
|
||||
/**
|
||||
* Returns more specific database driver type
|
||||
* Note: can be used before connect()
|
||||
* @return string db type mysqli, pgsql, oci, mssql, sqlsrv
|
||||
* @return string db type mysqli, pgsql, mssql, sqlsrv
|
||||
*/
|
||||
protected function get_dbtype() {
|
||||
return 'pgsql';
|
||||
|
@ -50,7 +50,7 @@ class sqlite3_pdo_moodle_database extends pdo_moodle_database {
|
||||
/**
|
||||
* Returns database family type - describes SQL dialect
|
||||
* Note: can be used before connect()
|
||||
* @return string db family name (mysql, postgres, mssql, oracle, etc.)
|
||||
* @return string db family name (mysql, postgres, mssql, etc.)
|
||||
*/
|
||||
public function get_dbfamily() {
|
||||
return 'sqlite';
|
||||
@ -59,7 +59,7 @@ class sqlite3_pdo_moodle_database extends pdo_moodle_database {
|
||||
/**
|
||||
* Returns more specific database driver type
|
||||
* Note: can be used before connect()
|
||||
* @return string db type mysqli, pgsql, oci, mssql, sqlsrv
|
||||
* @return string db type mysqli, pgsql, mssql, sqlsrv
|
||||
*/
|
||||
protected function get_dbtype() {
|
||||
return 'sqlite3';
|
||||
|
@ -102,7 +102,7 @@ class sqlsrv_native_moodle_database extends moodle_database {
|
||||
/**
|
||||
* Returns database family type - describes SQL dialect
|
||||
* Note: can be used before connect()
|
||||
* @return string db family name (mysql, postgres, mssql, sqlsrv, oracle, etc.)
|
||||
* @return string db family name (mysql, postgres, mssql, sqlsrv, etc.)
|
||||
*/
|
||||
public function get_dbfamily() {
|
||||
return 'mssql';
|
||||
@ -111,7 +111,7 @@ class sqlsrv_native_moodle_database extends moodle_database {
|
||||
/**
|
||||
* Returns more specific database driver type
|
||||
* Note: can be used before connect()
|
||||
* @return string db type mysqli, pgsql, oci, mssql, sqlsrv
|
||||
* @return string db type mysqli, pgsql, mssql, sqlsrv
|
||||
*/
|
||||
protected function get_dbtype() {
|
||||
return 'sqlsrv';
|
||||
|
@ -573,150 +573,6 @@ EOD;
|
||||
$this->assertSame(strtok('?'), 'b');
|
||||
}
|
||||
|
||||
public function test_tweak_param_names(): void {
|
||||
|
||||
// Note the tweak_param_names() method is only available in the oracle driver,
|
||||
// hence we look for expected results indirectly, by testing various DML methods.
|
||||
// with some "extreme" conditions causing the tweak to happen.
|
||||
$DB = $this->tdb;
|
||||
$dbman = $this->tdb->get_manager();
|
||||
|
||||
$table = $this->get_test_table();
|
||||
$tablename = $table->getName();
|
||||
|
||||
// Prepare some long column names.
|
||||
$intnearmax = str_pad('long_int_columnname_near_', \xmldb_field::NAME_MAX_LENGTH - 1, 'x');
|
||||
$decnearmax = str_pad('long_dec_columnname_near_', \xmldb_field::NAME_MAX_LENGTH - 1, 'x');
|
||||
$strnearmax = str_pad('long_str_columnname_near_', \xmldb_field::NAME_MAX_LENGTH - 1, 'x');
|
||||
$intmax = str_pad('long_int_columnname_max', \xmldb_field::NAME_MAX_LENGTH, 'x');
|
||||
$decmax = str_pad('long_dec_columnname_max', \xmldb_field::NAME_MAX_LENGTH, 'x');
|
||||
$strmax = str_pad('long_str_columnname_max', \xmldb_field::NAME_MAX_LENGTH, 'x');
|
||||
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
// Add some correct columns with \xmldb_field::NAME_MAX_LENGTH minus 1 chars in the name.
|
||||
$table->add_field($intnearmax, XMLDB_TYPE_INTEGER, '10');
|
||||
$table->add_field($decnearmax, XMLDB_TYPE_NUMBER, '10,2');
|
||||
$table->add_field($strnearmax, XMLDB_TYPE_CHAR, '100');
|
||||
// Add some correct columns with xmldb_table::NAME_MAX_LENGTH chars in the name.
|
||||
$table->add_field($intmax, XMLDB_TYPE_INTEGER, '10');
|
||||
$table->add_field($decmax, XMLDB_TYPE_NUMBER, '10,2');
|
||||
$table->add_field($strmax, XMLDB_TYPE_CHAR, '100');
|
||||
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
|
||||
$dbman->create_table($table);
|
||||
|
||||
$this->assertTrue($dbman->table_exists($tablename));
|
||||
|
||||
// Test insert record.
|
||||
$rec1 = new \stdClass();
|
||||
$rec1->{$intnearmax} = 62;
|
||||
$rec1->{$decnearmax} = 62.62;
|
||||
$rec1->{$strnearmax} = '62';
|
||||
$rec1->{$intmax} = 63;
|
||||
$rec1->{$decmax} = 63.63;
|
||||
$rec1->{$strmax} = '63';
|
||||
|
||||
// Insert_record().
|
||||
$rec1->id = $DB->insert_record($tablename, $rec1);
|
||||
$this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
|
||||
|
||||
// Update_record().
|
||||
$DB->update_record($tablename, $rec1);
|
||||
$this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
|
||||
|
||||
// Set_field().
|
||||
$rec1->{$intnearmax} = 620;
|
||||
$DB->set_field($tablename, $intnearmax, $rec1->{$intnearmax},
|
||||
array('id' => $rec1->id, $intnearmax => 62));
|
||||
$rec1->{$decnearmax} = 620.62;
|
||||
$DB->set_field($tablename, $decnearmax, $rec1->{$decnearmax},
|
||||
array('id' => $rec1->id, $decnearmax => 62.62));
|
||||
$rec1->{$strnearmax} = '620';
|
||||
$DB->set_field($tablename, $strnearmax, $rec1->{$strnearmax},
|
||||
array('id' => $rec1->id, $strnearmax => '62'));
|
||||
$rec1->{$intmax} = 630;
|
||||
$DB->set_field($tablename, $intmax, $rec1->{$intmax},
|
||||
array('id' => $rec1->id, $intmax => 63));
|
||||
$rec1->{$decmax} = 630.63;
|
||||
$DB->set_field($tablename, $decmax, $rec1->{$decmax},
|
||||
array('id' => $rec1->id, $decmax => 63.63));
|
||||
$rec1->{$strmax} = '630';
|
||||
$DB->set_field($tablename, $strmax, $rec1->{$strmax},
|
||||
array('id' => $rec1->id, $strmax => '63'));
|
||||
$this->assertEquals($rec1, $DB->get_record($tablename, array('id' => $rec1->id)));
|
||||
|
||||
// Delete_records().
|
||||
$rec2 = $DB->get_record($tablename, array('id' => $rec1->id));
|
||||
$rec2->id = $DB->insert_record($tablename, $rec2);
|
||||
$this->assertEquals(2, $DB->count_records($tablename));
|
||||
$DB->delete_records($tablename, (array) $rec2);
|
||||
$this->assertEquals(1, $DB->count_records($tablename));
|
||||
|
||||
// Get_recordset().
|
||||
$rs = $DB->get_recordset($tablename, (array) $rec1);
|
||||
$iterations = 0;
|
||||
foreach ($rs as $rec2) {
|
||||
$iterations++;
|
||||
}
|
||||
$rs->close();
|
||||
$this->assertEquals(1, $iterations);
|
||||
$this->assertEquals($rec1, $rec2);
|
||||
|
||||
// Get_records().
|
||||
$recs = $DB->get_records($tablename, (array) $rec1);
|
||||
$this->assertCount(1, $recs);
|
||||
$this->assertEquals($rec1, reset($recs));
|
||||
|
||||
// Get_fieldset_select().
|
||||
$select = "id = :id AND
|
||||
$intnearmax = :$intnearmax AND
|
||||
$decnearmax = :$decnearmax AND
|
||||
$strnearmax = :$strnearmax AND
|
||||
$intmax = :$intmax AND
|
||||
$decmax = :$decmax AND
|
||||
$strmax = :$strmax";
|
||||
$fields = $DB->get_fieldset_select($tablename, $intnearmax, $select, (array)$rec1);
|
||||
$this->assertCount(1, $fields);
|
||||
$this->assertEquals($rec1->{$intnearmax}, reset($fields));
|
||||
$fields = $DB->get_fieldset_select($tablename, $decnearmax, $select, (array)$rec1);
|
||||
$this->assertEquals($rec1->{$decnearmax}, reset($fields));
|
||||
$fields = $DB->get_fieldset_select($tablename, $strnearmax, $select, (array)$rec1);
|
||||
$this->assertEquals($rec1->{$strnearmax}, reset($fields));
|
||||
$fields = $DB->get_fieldset_select($tablename, $intmax, $select, (array)$rec1);
|
||||
$this->assertEquals($rec1->{$intmax}, reset($fields));
|
||||
$fields = $DB->get_fieldset_select($tablename, $decmax, $select, (array)$rec1);
|
||||
$this->assertEquals($rec1->{$decmax}, reset($fields));
|
||||
$fields = $DB->get_fieldset_select($tablename, $strmax, $select, (array)$rec1);
|
||||
$this->assertEquals($rec1->{$strmax}, reset($fields));
|
||||
|
||||
// Overlapping placeholders (progressive str_replace).
|
||||
$nearmaxparam = str_pad('allowed_long_param', \xmldb_field::NAME_MAX_LENGTH - 1, 'x');
|
||||
$maxparam = str_pad('allowed_long_param', \xmldb_field::NAME_MAX_LENGTH, 'x');
|
||||
$overlapselect = "id = :p AND
|
||||
$intnearmax = :param1 AND
|
||||
$decnearmax = :param2 AND
|
||||
$strnearmax = :{$nearmaxparam} AND
|
||||
$intmax = :{$maxparam} AND
|
||||
$decmax = :param_ AND
|
||||
$strmax = :param__";
|
||||
$overlapparams = array(
|
||||
'p' => $rec1->id,
|
||||
'param1' => $rec1->{$intnearmax},
|
||||
'param2' => $rec1->{$decnearmax},
|
||||
$nearmaxparam => $rec1->{$strnearmax},
|
||||
$maxparam => $rec1->{$intmax},
|
||||
'param_' => $rec1->{$decmax},
|
||||
'param__' => $rec1->{$strmax});
|
||||
$recs = $DB->get_records_select($tablename, $overlapselect, $overlapparams);
|
||||
$this->assertCount(1, $recs);
|
||||
$this->assertEquals($rec1, reset($recs));
|
||||
|
||||
// Execute().
|
||||
$DB->execute("DELETE FROM {{$tablename}} WHERE $select", (array)$rec1);
|
||||
$this->assertEquals(0, $DB->count_records($tablename));
|
||||
}
|
||||
|
||||
public function test_get_tables(): void {
|
||||
$DB = $this->tdb;
|
||||
$dbman = $this->tdb->get_manager();
|
||||
@ -4084,8 +3940,8 @@ EOD;
|
||||
$DB->insert_record($tablename, array('name'=>'aaaa', 'description'=>'aaaacccccccccccccccccc'));
|
||||
$DB->insert_record($tablename, array('name'=>'xxxx', 'description'=>'123456789a123456789b123456789c123456789d'));
|
||||
|
||||
// Only some supported databases truncate TEXT fields for comparisons, currently MSSQL and Oracle.
|
||||
$dbtruncatestextfields = ($DB->get_dbfamily() == 'mssql' || $DB->get_dbfamily() == 'oracle');
|
||||
// Only some supported databases truncate TEXT fields for comparisons, currently MSSQL.
|
||||
$dbtruncatestextfields = ($DB->get_dbfamily() == 'mssql');
|
||||
|
||||
if ($dbtruncatestextfields) {
|
||||
// Ensure truncation behaves as expected.
|
||||
@ -4162,7 +4018,7 @@ EOD;
|
||||
if ($family === 'mysql' or $family === 'mssql') {
|
||||
$this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages. This is usually caused by accent insensitive default collation.");
|
||||
} else {
|
||||
// This should not happen, PostgreSQL and Oracle do not support accent insensitive uniqueness.
|
||||
// This should not happen, PostgreSQL does not support accent insensitive uniqueness.
|
||||
$this->fail("Unique index is accent insensitive, this may cause problems for non-ascii languages.");
|
||||
}
|
||||
throw($e);
|
||||
@ -4414,7 +4270,8 @@ EOD;
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
// Regarding 1300 length - all drivers except Oracle support larger values (2K+), but this hits a limit on Oracle.
|
||||
// Regarding the 1300 length - all supported drivers allow larger values (2K+),
|
||||
// previously limited by Oracle, which no longer applies as Oracle support has been removed.
|
||||
$DB->insert_record($tablename, [
|
||||
'charshort' => 'áéíóú',
|
||||
'charlong' => str_repeat('A', 512),
|
||||
@ -5070,9 +4927,9 @@ EOD;
|
||||
$DB->insert_record($tablename, array('course' => 2, 'content' => 'universe', 'name'=>'abc'));
|
||||
|
||||
// Test grouping by expressions in the query. MDL-26819. Note that there are 4 ways:
|
||||
// - By column position (GROUP by 1) - Not supported by mssql & oracle
|
||||
// - By column position (GROUP by 1) - Not supported by mssql
|
||||
// - By column name (GROUP by course) - Supported by all, but leading to wrong results
|
||||
// - By column alias (GROUP by casecol) - Not supported by mssql & oracle
|
||||
// - By column alias (GROUP by casecol) - Not supported by mssql
|
||||
// - By complete expression (GROUP BY CASE ...) - 100% cross-db, this test checks it
|
||||
$sql = "SELECT (CASE WHEN course = 3 THEN 1 ELSE 0 END) AS casecol,
|
||||
COUNT(1) AS countrecs,
|
||||
|
@ -25,7 +25,7 @@ use core\router\response\not_found_response;
|
||||
* This library contains all the Data Manipulation Language (DML) functions
|
||||
* used to interact with the DB. All the dunctions in this library must be
|
||||
* generic and work against the major number of RDBMS possible. This is the
|
||||
* list of currently supported and tested DBs: mysql, postresql, mssql, oracle
|
||||
* list of currently supported and tested DBs: mysql, postresql, and mssql.
|
||||
*
|
||||
* This library is automatically included by Moodle core so you never need to
|
||||
* include it yourself.
|
||||
@ -322,10 +322,6 @@ function setup_DB() {
|
||||
$CFG->dbtype = 'pgsql';
|
||||
break;
|
||||
|
||||
case 'oci8po':
|
||||
$CFG->dbtype = 'oci';
|
||||
break;
|
||||
|
||||
case 'mysql' :
|
||||
$CFG->dbtype = 'mysqli';
|
||||
break;
|
||||
|
@ -809,7 +809,7 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
|
||||
}
|
||||
}
|
||||
|
||||
// Note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why
|
||||
// Note: we can not use DISTINCT + text fields due to MS limitations, that is why
|
||||
// we have the subselect there.
|
||||
$sql = "SELECT $coursefields $ccselect $timeaccessselect
|
||||
FROM {course} c
|
||||
@ -1124,7 +1124,7 @@ function enrol_get_all_users_courses($userid, $onlyactive = false, $fields = nul
|
||||
$ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
|
||||
$params['contextlevel'] = CONTEXT_COURSE;
|
||||
|
||||
//note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there
|
||||
//note: we can not use DISTINCT + text fields due to MS limitations, that is why we have the subselect there
|
||||
$sql = "SELECT $coursefields $ccselect
|
||||
FROM {course} c
|
||||
JOIN (SELECT DISTINCT e.courseid
|
||||
|
@ -36,7 +36,6 @@
|
||||
* 1=>array('dbtype'=>'mysqli', 'dbhost'=>'localhost', 'dbname'=>'moodle', 'dbuser'=>'root', 'dbpass'=>'', 'prefix'=>'phpu2_'),
|
||||
* 2=>array('dbtype'=>'pgsql', 'dbhost'=>'localhost', 'dbname'=>'moodle', 'dbuser'=>'postgres', 'dbpass'=>'', 'prefix'=>'phpu2_'),
|
||||
* 3=>array('dbtype'=>'sqlsrv', 'dbhost'=>'127.0.0.1', 'dbname'=>'moodle', 'dbuser'=>'sa', 'dbpass'=>'', 'prefix'=>'phpu2_'),
|
||||
* 4=>array('dbtype'=>'oci', 'dbhost'=>'127.0.0.1', 'dbname'=>'XE', 'dbuser'=>'sa', 'dbpass'=>'', 'prefix'=>'t_'),
|
||||
* );
|
||||
* define('PHPUNIT_TEST_DRIVER')=1; //number is index in the previous array
|
||||
*
|
||||
|
@ -422,7 +422,7 @@ function search_generate_SQL($parsetree, $datafield, $metafield, $mainidfield, $
|
||||
$type = $parsetree[$i]->getType();
|
||||
$value = $parsetree[$i]->getValue();
|
||||
|
||||
/// Under Oracle and MSSQL, transform TOKEN searches into STRING searches and trim +- chars
|
||||
// Under MSSQL, transform TOKEN searches into STRING searches and trim +- chars.
|
||||
if (!$DB->sql_regex_supported()) {
|
||||
$value = trim($value, '+-');
|
||||
if ($type == TOKEN_EXACT) {
|
||||
|
@ -274,7 +274,7 @@ class flexible_table {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use text sorting functions for this column (required for text columns with Oracle).
|
||||
* Use text sorting functions for this column.
|
||||
* Be warned that you cannot use this with column aliases. You can only do this
|
||||
* with real columns. See MDL-40481 for an example.
|
||||
* @param string column name
|
||||
|
@ -393,20 +393,6 @@ abstract class testing_util {
|
||||
}
|
||||
$rs->close();
|
||||
return $empties;
|
||||
} else if ($dbfamily === 'oracle') {
|
||||
$sequences = self::get_sequencenames();
|
||||
$sequences = array_map('strtoupper', $sequences);
|
||||
$lookup = array_flip($sequences);
|
||||
$empties = [];
|
||||
[$seqs, $params] = $DB->get_in_or_equal($sequences);
|
||||
$sql = "SELECT sequence_name FROM user_sequences WHERE last_number = 1 AND sequence_name $seqs";
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $seq) {
|
||||
$table = $lookup[$seq->sequence_name];
|
||||
$empties[$table] = $table;
|
||||
}
|
||||
$rs->close();
|
||||
return $empties;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
@ -528,48 +514,6 @@ abstract class testing_util {
|
||||
if ($queries) {
|
||||
$DB->change_database_structure(implode(';', $queries));
|
||||
}
|
||||
} else if ($dbfamily === 'oracle') {
|
||||
$sequences = self::get_sequencenames();
|
||||
$sequences = array_map('strtoupper', $sequences);
|
||||
$lookup = array_flip($sequences);
|
||||
|
||||
$current = [];
|
||||
[$seqs, $params] = $DB->get_in_or_equal($sequences);
|
||||
$sql = "SELECT sequence_name, last_number FROM user_sequences WHERE sequence_name $seqs";
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $seq) {
|
||||
$table = $lookup[$seq->sequence_name];
|
||||
$current[$table] = $seq->last_number;
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
foreach ($data as $table => $records) {
|
||||
// If table is not modified then no need to do anything.
|
||||
if (!isset($updatedtables[$table])) {
|
||||
continue;
|
||||
}
|
||||
if (isset($structure[$table]['id']) && $structure[$table]['id']->auto_increment) {
|
||||
$lastrecord = end($records);
|
||||
if ($lastrecord) {
|
||||
$nextid = $lastrecord->id + 1;
|
||||
} else {
|
||||
$nextid = 1;
|
||||
}
|
||||
if (!isset($current[$table])) {
|
||||
$DB->get_manager()->reset_sequence($table);
|
||||
} else if ($nextid == $current[$table]) {
|
||||
continue;
|
||||
}
|
||||
// Reset as fast as possible.
|
||||
// Alternatively we could use http://stackoverflow.com/questions/51470/how-do-i-reset-a-sequence-in-oracle.
|
||||
$seqname = $sequences[$table];
|
||||
$cachesize = $DB->get_manager()->generator->sequence_cache_size;
|
||||
$DB->change_database_structure("DROP SEQUENCE $seqname");
|
||||
$DB->change_database_structure(
|
||||
"CREATE SEQUENCE $seqname START WITH $nextid INCREMENT BY 1 NOMAXVALUE CACHE $cachesize",
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Note: does mssql support any kind of faster reset?
|
||||
// This also implies mssql will not use unique sequence values.
|
||||
|
@ -2137,7 +2137,7 @@ EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if database family used is using one of the specified, else skip. (mysql, postgres, mssql, oracle, etc.)
|
||||
* Checks if database family used is using one of the specified, else skip. (mysql, postgres, mssql, etc.)
|
||||
*
|
||||
* @Given /^database family used is one of the following:$/
|
||||
* @param TableNode $databasefamilies list of database.
|
||||
|
@ -92,10 +92,6 @@ final class environment_test extends \advanced_testcase {
|
||||
// If we're on a 32-bit system, skip 64-bit check. 32-bit PHP has PHP_INT_SIZE set to 4.
|
||||
$this->markTestSkipped('64-bit check is not necessary for unit testing.');
|
||||
}
|
||||
if ($result->info === 'oracle_database_usage') {
|
||||
// If we're on a system that uses the Oracle database, skip the Oracle check.
|
||||
$this->markTestSkipped('Oracle database check is not necessary for unit testing.');
|
||||
}
|
||||
}
|
||||
$info = "{$result->part}:{$result->info}";
|
||||
$this->assertTrue($result->getStatus(), "Problem detected in environment ($info), fix all warnings and errors!");
|
||||
|
@ -1390,38 +1390,6 @@ final class upgradelib_test extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the check_oracle_usage check when the Moodle instance is not using Oracle as a database architecture.
|
||||
*
|
||||
* @covers ::check_oracle_usage
|
||||
*/
|
||||
public function test_check_oracle_usage_is_not_used(): void {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$CFG->dbtype = 'pgsql';
|
||||
|
||||
$result = new environment_results('custom_checks');
|
||||
$this->assertNull(check_oracle_usage($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the check_oracle_usage check when the Moodle instance is using Oracle as a database architecture.
|
||||
*
|
||||
* @covers ::check_oracle_usage
|
||||
*/
|
||||
public function test_check_oracle_usage_is_used(): void {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$CFG->dbtype = 'oci';
|
||||
|
||||
$result = new environment_results('custom_checks');
|
||||
$this->assertInstanceOf(environment_results::class, check_oracle_usage($result));
|
||||
$this->assertEquals('oracle_database_usage', $result->getInfo());
|
||||
$this->assertFalse($result->getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider of usermenu items.
|
||||
*
|
||||
|
@ -2831,29 +2831,6 @@ function check_mod_assignment(environment_results $result): ?environment_results
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the Oracle database is currently being used and warn if so.
|
||||
*
|
||||
* The Oracle database support will be removed in a future version (4.5) as it is no longer supported by PHP.
|
||||
*
|
||||
* @param environment_results $result object to update, if relevant
|
||||
* @return environment_results|null updated results or null if the current database is not Oracle.
|
||||
*
|
||||
* @see https://tracker.moodle.org/browse/MDL-80166 for further information.
|
||||
*/
|
||||
function check_oracle_usage(environment_results $result): ?environment_results {
|
||||
global $CFG;
|
||||
|
||||
// Checking database type.
|
||||
if ($CFG->dbtype === 'oci') {
|
||||
$result->setInfo('oracle_database_usage');
|
||||
$result->setFeedbackStr('oracledatabaseinuse');
|
||||
return $result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if asynchronous backups are enabled.
|
||||
*
|
||||
|
@ -48,7 +48,6 @@ class xmldb_field extends xmldb_object {
|
||||
|
||||
/**
|
||||
* Note:
|
||||
* - Oracle: VARCHAR2 has a limit of 4000 bytes
|
||||
* - SQL Server: NVARCHAR has a limit of 40000 chars
|
||||
* - MySQL: VARCHAR 65,535 chars
|
||||
* - PostgreSQL: no limit
|
||||
|
@ -454,6 +454,7 @@ class provider implements
|
||||
|
||||
// Oracle does not support UNION on text fields, therefore we must get the itemdescription
|
||||
// and valuevalue after doing the union by joining on the result.
|
||||
// TODO: Optimise the query, as Oracle-specific constraints no longer apply.
|
||||
$sql = "
|
||||
SELECT q.*,
|
||||
|
||||
|
@ -5929,7 +5929,7 @@ function forum_get_posts_by_user($user, array $courses, $musthaveaccess = false,
|
||||
|
||||
// Prepare SQL to both count and search.
|
||||
// We alias user.id to useridx because we forum_posts already has a userid field and not aliasing this would break
|
||||
// oracle and mssql.
|
||||
// mssql.
|
||||
$userfieldsapi = \core_user\fields::for_userpic();
|
||||
$userfields = $userfieldsapi->get_sql('u', false, '', 'useridx', false)->selects;
|
||||
$countsql = 'SELECT COUNT(*) ';
|
||||
|
@ -1494,11 +1494,12 @@ function glossary_search($course, $searchterms, $extended = 0, $glossary = NULL)
|
||||
foreach ($searchterms as $searchterm) {
|
||||
$i++;
|
||||
|
||||
$NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
|
||||
/// will use it to simulate the "-" operator with LIKE clause
|
||||
// Initially we aren't going to perform NOT LIKE searches, only MSSQL
|
||||
// will use it to simulate the "-" operator with LIKE clause.
|
||||
$NOT = false;
|
||||
|
||||
/// Under Oracle and MSSQL, trim the + and - operators and perform
|
||||
/// simpler LIKE (or NOT LIKE) queries
|
||||
// Under MSSQL, trim the + and - operators and perform
|
||||
// simpler LIKE (or NOT LIKE) queries
|
||||
if (!$DB->sql_regex_supported()) {
|
||||
if (substr($searchterm, 0, 1) == '-') {
|
||||
$NOT = true;
|
||||
@ -3815,7 +3816,7 @@ function glossary_get_search_terms_sql(array $terms, $fullsearch = true, $glossa
|
||||
foreach ($terms as $searchterm) {
|
||||
$i++;
|
||||
|
||||
$not = false; // Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
|
||||
$not = false; // Initially we aren't going to perform NOT LIKE searches, only MSSQL
|
||||
// will use it to simulate the "-" operator with LIKE clause.
|
||||
|
||||
if (empty($fullsearch)) {
|
||||
@ -3827,7 +3828,7 @@ function glossary_get_search_terms_sql(array $terms, $fullsearch = true, $glossa
|
||||
}
|
||||
$params['emptychar' . $i] = '';
|
||||
|
||||
// Under Oracle and MSSQL, trim the + and - operators and perform simpler LIKE (or NOT LIKE) queries.
|
||||
// Under MSSQL, trim the + and - operators and perform simpler LIKE (or NOT LIKE) queries.
|
||||
if (!$DB->sql_regex_supported()) {
|
||||
if (substr($searchterm, 0, 1) === '-') {
|
||||
$not = true;
|
||||
|
@ -108,7 +108,7 @@ final class provider_test extends provider_testcase {
|
||||
// (note this is only effective with databases not using fed (+1000) sequences
|
||||
// per table, like postgres and mysql do, rendering this useless. In any
|
||||
// case better to have the situation covered by some DBs,
|
||||
// like sqlsrv or oracle than by none).
|
||||
// like sqlsrv than by none).
|
||||
$this->getDataGenerator()->create_module('label', ['course' => $this->course->id]);
|
||||
|
||||
$contextlist = provider::get_contexts_for_userid($this->user->id);
|
||||
|
@ -497,8 +497,7 @@ class provider implements
|
||||
$userid
|
||||
);
|
||||
|
||||
// The layout column causes the union in the following query to fail on Oracle, it also appears to not be used.
|
||||
// So we can filter the return values to be only those used to generate the data, this will have the benefit
|
||||
// Filtering the return values to be only those used to generate the data, this will have the benefit
|
||||
// improving performance on all databases as we will no longer be returning a text field for each row.
|
||||
$attemptfields = 'qa.id, qa.quiz, qa.userid, qa.attempt, qa.uniqueid, qa.preview, qa.state, qa.timestart, ' .
|
||||
'qa.timefinish, qa.timemodified, qa.timemodifiedoffline, qa.timecheckstate, qa.sumgrades, ' .
|
||||
|
@ -129,6 +129,7 @@ class qbank_helper {
|
||||
-- version we could consider digging the old code out of git history from
|
||||
-- just before the commit that added this comment.
|
||||
-- For relevant question_bank_entries, this gets the latest non-draft slot number.
|
||||
-- TODO: Optimise the query, as Oracle-specific constraints no longer apply.
|
||||
LEFT JOIN (
|
||||
SELECT lv.questionbankentryid,
|
||||
MAX(CASE WHEN lv.status <> :draft THEN lv.version END) AS usableversion,
|
||||
|
@ -800,7 +800,6 @@ function quiz_update_open_attempts(array $conditions) {
|
||||
* Each database handles updates with inner joins differently:
|
||||
* - mysql does not allow a FROM clause
|
||||
* - postgres and mssql allow FROM but handle table aliases differently
|
||||
* - oracle requires a subquery
|
||||
*
|
||||
* Different code for each database.
|
||||
*/
|
||||
@ -827,7 +826,7 @@ function quiz_update_open_attempts(array $conditions) {
|
||||
JOIN ( $quizausersql ) quizauser ON quizauser.id = quiza.id
|
||||
WHERE $attemptselect";
|
||||
} else {
|
||||
// oracle, sqlite and others
|
||||
// Sqlite and others.
|
||||
$updatesql = "UPDATE {quiz_attempts} quiza
|
||||
SET timecheckstate = (
|
||||
SELECT $timecheckstatesql
|
||||
|
@ -102,7 +102,7 @@ Feature: View activity completion in the SCORM activity
|
||||
And I wait until "Score: 33" "text" exists
|
||||
And I switch to the main frame
|
||||
# We need to get some time till the last item is marked as done (or it won't be ready in slow databases).
|
||||
# This could be a pause of a few seconds (working ok in super-slow oracle docker database), but re-visiting
|
||||
# This could be a pause of a few seconds, but re-visiting
|
||||
# any of the pages seems to be doing the work too under that very same slow environment.
|
||||
And I click on "Par?" "list_item"
|
||||
And I switch to "scorm_object" iframe
|
||||
|
@ -92,7 +92,7 @@ final class qformat_xml_import_export_test extends advanced_testcase {
|
||||
$xml = preg_replace('~(?<=<!-- question: )([0-9]+)(?= -->)~', '0', $xml);
|
||||
|
||||
// Deal with how different databases output numbers. Only match when only thing in a tag.
|
||||
$xml = preg_replace("~>.0000000<~", '>0<', $xml); // How Oracle outputs 0.0000000.
|
||||
$xml = preg_replace("~>.0000000<~", '>0<', $xml); // Needed by MS SQL Server database.
|
||||
$xml = preg_replace("~(\.(:?[0-9]*[1-9])?)0*<~", '$1<', $xml); // Other cases of trailing 0s
|
||||
$xml = preg_replace("~([0-9]).<~", '$1<', $xml); // Stray . in 1. after last step.
|
||||
|
||||
|
@ -421,6 +421,7 @@ class core_tag_area {
|
||||
|
||||
// Find all tags that are related to the tags being moved and make sure they are present in the target tagcoll.
|
||||
// This query is a little complicated because Oracle does not allow to run SELECT DISTINCT on CLOB fields.
|
||||
// TODO: Optimise the query, as Oracle-specific constraints no longer apply.
|
||||
$sql = "SELECT name, rawname, description, descriptionformat, userid, isstandard, flag, timemodified ".
|
||||
"FROM {tag} WHERE id IN ".
|
||||
"(SELECT r.id ".
|
||||
@ -455,6 +456,7 @@ class core_tag_area {
|
||||
|
||||
// Find all tags that are used for this itemtype/component and are not present in the target tag collection.
|
||||
// This query is a little complicated because Oracle does not allow to run SELECT DISTINCT on CLOB fields.
|
||||
// TODO: Optimise the query, as Oracle-specific constraints no longer apply.
|
||||
$sql = "SELECT id, name, rawname, description, descriptionformat, userid, isstandard, flag, timemodified
|
||||
FROM {tag} WHERE id IN
|
||||
(SELECT t.id
|
||||
|
@ -536,7 +536,7 @@ class fields {
|
||||
$DB->sql_equal($fieldalias . '.shortname', $placeholder, false) . "
|
||||
LEFT JOIN {user_info_data} $dataalias ON $dataalias.fieldid = $fieldalias.id
|
||||
AND $dataalias.userid = {$usertable}id";
|
||||
// For Oracle we need to convert the field into a usable format.
|
||||
// For sqlsrv we need to convert the field into a usable format.
|
||||
$fieldsql = $DB->sql_compare_text($dataalias . '.data', 255);
|
||||
$selects .= ", $fieldsql AS $prefix$field";
|
||||
$mappings[$field] = $fieldsql;
|
||||
@ -613,7 +613,7 @@ class fields {
|
||||
}
|
||||
|
||||
if (core_text::strlen($chunk) > 0) {
|
||||
// If content is just whitespace, add to elements directly (also Oracle doesn't support passing ' ' as param).
|
||||
// If content is just whitespace, add it directly to elements to handle it appropriately.
|
||||
if (preg_match('/^\s+$/', $chunk)) {
|
||||
$elements[] = "'$chunk'";
|
||||
} else {
|
||||
|
@ -330,8 +330,8 @@ class participants_search {
|
||||
$wheresjoin = ' AND NOT ';
|
||||
|
||||
// Some of the $where conditions may begin with `NOT` which results in `AND NOT NOT ...`.
|
||||
// To prevent this from breaking on Oracle the inner WHERE clause is wrapped in brackets, making it
|
||||
// `AND NOT (NOT ...)` which is valid in all DBs.
|
||||
// To ensure consistent SQL syntax across databases, the inner WHERE clause is wrapped in brackets,
|
||||
// making it `AND NOT (NOT ...)`, which is valid and improves readability.
|
||||
$wheres = array_map(function($where) {
|
||||
return "({$where})";
|
||||
}, $wheres);
|
||||
|
Loading…
x
Reference in New Issue
Block a user