| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 3 | //
 | 
        
           |  |  | 4 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 5 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 6 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 7 | // (at your option) any later version.
 | 
        
           |  |  | 8 | //
 | 
        
           |  |  | 9 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 12 | // GNU General Public License for more details.
 | 
        
           |  |  | 13 | //
 | 
        
           |  |  | 14 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 15 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | /**
 | 
        
           |  |  | 18 |  * Oracle specific SQL code generator.
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * @package    core_ddl
 | 
        
           |  |  | 21 |  * @copyright  1999 onwards Martin Dougiamas     http://dougiamas.com
 | 
        
           |  |  | 22 |  *             2001-3001 Eloy Lafuente (stronk7) http://contiento.com
 | 
        
           |  |  | 23 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 24 |  */
 | 
        
           |  |  | 25 |   | 
        
           |  |  | 26 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 | require_once($CFG->libdir.'/ddl/sql_generator.php');
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | /**
 | 
        
           |  |  | 31 |  * This class generate SQL code to be used against Oracle
 | 
        
           |  |  | 32 |  * It extends XMLDBgenerator so everything can be
 | 
        
           |  |  | 33 |  * overridden as needed to generate correct SQL.
 | 
        
           |  |  | 34 |  *
 | 
        
           |  |  | 35 |  * @package    core_ddl
 | 
        
           |  |  | 36 |  * @copyright  1999 onwards Martin Dougiamas     http://dougiamas.com
 | 
        
           |  |  | 37 |  *             2001-3001 Eloy Lafuente (stronk7) http://contiento.com
 | 
        
           |  |  | 38 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 39 |  */
 | 
        
           |  |  | 40 | class oracle_sql_generator extends sql_generator {
 | 
        
           |  |  | 41 |   | 
        
           |  |  | 42 |     // Only set values that are different from the defaults present in XMLDBgenerator
 | 
        
           |  |  | 43 |   | 
        
           |  |  | 44 |     /**
 | 
        
           |  |  | 45 |      * @var string To be automatically added at the end of each statement.
 | 
        
           |  |  | 46 |      * note: Using "/" because the standard ";" isn't good for stored procedures (triggers)
 | 
        
           |  |  | 47 |      */
 | 
        
           |  |  | 48 |     public $statement_end = "\n/";
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 |     /** @var string Proper type for NUMBER(x) in this DB. */
 | 
        
           |  |  | 51 |     public $number_type = 'NUMBER';
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 |     /**
 | 
        
           |  |  | 54 |      * @var string To define the default to set for NOT NULLs CHARs without default (null=do nothing).
 | 
        
           |  |  | 55 |      * note: Using this whitespace here because Oracle doesn't distinguish empty and null! :-(
 | 
        
           |  |  | 56 |      */
 | 
        
           |  |  | 57 |     public $default_for_char = ' ';
 | 
        
           |  |  | 58 |   | 
        
           |  |  | 59 |     /** @var bool To specify if the generator must use some DEFAULT clause to drop defaults.*/
 | 
        
           |  |  | 60 |     public $drop_default_value_required = true;
 | 
        
           |  |  | 61 |   | 
        
           |  |  | 62 |     /** @var string The DEFAULT clause required to drop defaults.*/
 | 
        
           |  |  | 63 |     public $drop_default_value = null;
 | 
        
           |  |  | 64 |   | 
        
           |  |  | 65 |     /** @var bool To decide if the default clause of each field must go after the null clause.*/
 | 
        
           |  |  | 66 |     public $default_after_null = false;
 | 
        
           |  |  | 67 |   | 
        
           |  |  | 68 |     /** @var bool True if the generator needs to add extra code to generate the sequence fields.*/
 | 
        
           |  |  | 69 |     public $sequence_extra_code = true;
 | 
        
           |  |  | 70 |   | 
        
           |  |  | 71 |     /** @var string The particular name for inline sequences in this generator.*/
 | 
        
           |  |  | 72 |     public $sequence_name = '';
 | 
        
           |  |  | 73 |   | 
        
           |  |  | 74 |     /** @var string The SQL template to alter columns where the 'TABLENAME' and 'COLUMNSPECS' keywords are dynamically replaced.*/
 | 
        
           |  |  | 75 |     public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY (COLUMNSPECS)';
 | 
        
           |  |  | 76 |   | 
        
           |  |  | 77 |     /** @var int var ugly Oracle hack - size of the sequences values cache (20 = Default)*/
 | 
        
           |  |  | 78 |     public $sequence_cache_size = 20;
 | 
        
           |  |  | 79 |   | 
        
           |  |  | 80 |     /**
 | 
        
           |  |  | 81 |      * Reset a sequence to the id field of a table.
 | 
        
           |  |  | 82 |      *
 | 
        
           |  |  | 83 |      * @param xmldb_table|string $table name of table or the table object.
 | 
        
           |  |  | 84 |      * @return array of sql statements
 | 
        
           |  |  | 85 |      */
 | 
        
           |  |  | 86 |     public function getResetSequenceSQL($table) {
 | 
        
           |  |  | 87 |   | 
        
           |  |  | 88 |         if (is_string($table)) {
 | 
        
           |  |  | 89 |             $tablename = $table;
 | 
        
           |  |  | 90 |             $xmldb_table = new xmldb_table($tablename);
 | 
        
           |  |  | 91 |         } else {
 | 
        
           |  |  | 92 |             $tablename = $table->getName();
 | 
        
           |  |  | 93 |             $xmldb_table = $table;
 | 
        
           |  |  | 94 |         }
 | 
        
           |  |  | 95 |         // From http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/statements_2011.htm
 | 
        
           |  |  | 96 |         $value = (int)$this->mdb->get_field_sql('SELECT MAX(id) FROM {'.$tablename.'}');
 | 
        
           |  |  | 97 |         $value++;
 | 
        
           |  |  | 98 |   | 
        
           |  |  | 99 |         $seqname = $this->getSequenceFromDB($xmldb_table);
 | 
        
           |  |  | 100 |   | 
        
           |  |  | 101 |         if (!$seqname) {
 | 
        
           |  |  | 102 |             // Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method
 | 
        
           |  |  | 103 |             $seqname = $this->getNameForObject($table, 'id', 'seq');
 | 
        
           |  |  | 104 |         }
 | 
        
           |  |  | 105 |   | 
        
           |  |  | 106 |         return array ("DROP SEQUENCE $seqname",
 | 
        
           |  |  | 107 |                       "CREATE SEQUENCE $seqname START WITH $value INCREMENT BY 1 NOMAXVALUE CACHE $this->sequence_cache_size");
 | 
        
           |  |  | 108 |     }
 | 
        
           |  |  | 109 |   | 
        
           |  |  | 110 |     /**
 | 
        
           |  |  | 111 |      * Given one xmldb_table, returns it's correct name, depending of all the parametrization
 | 
        
           |  |  | 112 |      * Overridden to allow change of names in temp tables
 | 
        
           |  |  | 113 |      *
 | 
        
           |  |  | 114 |      * @param xmldb_table table whose name we want
 | 
        
           |  |  | 115 |      * @param boolean to specify if the name must be quoted (if reserved word, only!)
 | 
        
           |  |  | 116 |      * @return string the correct name of the table
 | 
        
           |  |  | 117 |      */
 | 
        
           |  |  | 118 |     public function getTableName(xmldb_table $xmldb_table, $quoted=true) {
 | 
        
           |  |  | 119 |         // Get the name, supporting special oci names for temp tables
 | 
        
           |  |  | 120 |         if ($this->temptables->is_temptable($xmldb_table->getName())) {
 | 
        
           |  |  | 121 |             $tablename = $this->temptables->get_correct_name($xmldb_table->getName());
 | 
        
           |  |  | 122 |         } else {
 | 
        
           |  |  | 123 |             $tablename = $this->prefix . $xmldb_table->getName();
 | 
        
           |  |  | 124 |         }
 | 
        
           |  |  | 125 |   | 
        
           |  |  | 126 |         // Apply quotes optionally
 | 
        
           |  |  | 127 |         if ($quoted) {
 | 
        
           |  |  | 128 |             $tablename = $this->getEncQuoted($tablename);
 | 
        
           |  |  | 129 |         }
 | 
        
           |  |  | 130 |   | 
        
           |  |  | 131 |         return $tablename;
 | 
        
           |  |  | 132 |     }
 | 
        
           |  |  | 133 |   | 
        
           |  |  | 134 |     public function getCreateIndexSQL($xmldb_table, $xmldb_index) {
 | 
        
           |  |  | 135 |         if ($error = $xmldb_index->validateDefinition($xmldb_table)) {
 | 
        
           |  |  | 136 |             throw new coding_exception($error);
 | 
        
           |  |  | 137 |         }
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 |         $indexfields = $this->getEncQuoted($xmldb_index->getFields());
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 |         $unique = '';
 | 
        
           |  |  | 142 |         $suffix = 'ix';
 | 
        
           |  |  | 143 |         if ($xmldb_index->getUnique()) {
 | 
        
           |  |  | 144 |             $unique = ' UNIQUE';
 | 
        
           |  |  | 145 |             $suffix = 'uix';
 | 
        
           |  |  | 146 |   | 
        
           |  |  | 147 |             $nullablefields = $this->get_nullable_fields_in_index($xmldb_table, $xmldb_index);
 | 
        
           |  |  | 148 |             if ($nullablefields) {
 | 
        
           |  |  | 149 |                 // If this is a unique index with nullable fields, then we have to
 | 
        
           |  |  | 150 |                 // apply the work-around from https://community.oracle.com/message/9518046#9518046.
 | 
        
           |  |  | 151 |                 //
 | 
        
           |  |  | 152 |                 // For example if you have a unique index on the three columns
 | 
        
           |  |  | 153 |                 // (required, option1, option2) where the first one is non-null,
 | 
        
           |  |  | 154 |                 // and the others nullable, then the SQL will end up as
 | 
        
           |  |  | 155 |                 //
 | 
        
           |  |  | 156 |                 // CREATE UNIQUE INDEX index_name ON table_name (
 | 
        
           |  |  | 157 |                 // CASE WHEN option1 IS NOT NULL AND option2 IS NOT NULL THEN required ELSE NULL END,
 | 
        
           |  |  | 158 |                 // CASE WHEN option1 IS NOT NULL AND option2 IS NOT NULL THEN option1 ELSE NULL END,
 | 
        
           |  |  | 159 |                 // CASE WHEN option1 IS NOT NULL AND option2 IS NOT NULL THEN option2 ELSE NULL END)
 | 
        
           |  |  | 160 |                 //
 | 
        
           |  |  | 161 |                 // Basically Oracle behaves according to the standard if either
 | 
        
           |  |  | 162 |                 // none of the columns are NULL or all columns contain NULL. Therefore,
 | 
        
           |  |  | 163 |                 // if any column is NULL, we treat them all as NULL for the index.
 | 
        
           |  |  | 164 |                 $conditions = [];
 | 
        
           |  |  | 165 |                 foreach ($nullablefields as $fieldname) {
 | 
        
           |  |  | 166 |                     $conditions[] = $this->getEncQuoted($fieldname) .
 | 
        
           |  |  | 167 |                             ' IS NOT NULL';
 | 
        
           |  |  | 168 |                 }
 | 
        
           |  |  | 169 |                 $condition = implode(' AND ', $conditions);
 | 
        
           |  |  | 170 |   | 
        
           |  |  | 171 |                 $updatedindexfields = [];
 | 
        
           |  |  | 172 |                 foreach ($indexfields as $fieldname) {
 | 
        
           |  |  | 173 |                     $updatedindexfields[] = 'CASE WHEN ' . $condition . ' THEN ' .
 | 
        
           |  |  | 174 |                             $fieldname . ' ELSE NULL END';
 | 
        
           |  |  | 175 |                 }
 | 
        
           |  |  | 176 |                 $indexfields = $updatedindexfields;
 | 
        
           |  |  | 177 |             }
 | 
        
           |  |  | 178 |   | 
        
           |  |  | 179 |         }
 | 
        
           |  |  | 180 |   | 
        
           |  |  | 181 |         $index = 'CREATE' . $unique . ' INDEX ';
 | 
        
           |  |  | 182 |         $index .= $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_index->getFields()), $suffix);
 | 
        
           |  |  | 183 |         $index .= ' ON ' . $this->getTableName($xmldb_table);
 | 
        
           |  |  | 184 |         $index .= ' (' . implode(', ', $indexfields) . ')';
 | 
        
           |  |  | 185 |   | 
        
           |  |  | 186 |         return array($index);
 | 
        
           |  |  | 187 |     }
 | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 |     /**
 | 
        
           |  |  | 190 |      * Given one correct xmldb_table, returns the SQL statements
 | 
        
           |  |  | 191 |      * to create temporary table (inside one array).
 | 
        
           |  |  | 192 |      *
 | 
        
           |  |  | 193 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 194 |      * @return array of sql statements
 | 
        
           |  |  | 195 |      */
 | 
        
           |  |  | 196 |     public function getCreateTempTableSQL($xmldb_table) {
 | 
        
           |  |  | 197 |         $this->temptables->add_temptable($xmldb_table->getName());
 | 
        
           |  |  | 198 |         $sqlarr = $this->getCreateTableSQL($xmldb_table);
 | 
        
           |  |  | 199 |         $sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE GLOBAL TEMPORARY TABLE $1 ON COMMIT PRESERVE ROWS', $sqlarr);
 | 
        
           |  |  | 200 |         return $sqlarr;
 | 
        
           |  |  | 201 |     }
 | 
        
           |  |  | 202 |   | 
        
           |  |  | 203 |     /**
 | 
        
           |  |  | 204 |      * Given one correct xmldb_table, returns the SQL statements
 | 
        
           |  |  | 205 |      * to drop it (inside one array).
 | 
        
           |  |  | 206 |      *
 | 
        
           |  |  | 207 |      * @param xmldb_table $xmldb_table The table to drop.
 | 
        
           |  |  | 208 |      * @return array SQL statement(s) for dropping the specified table.
 | 
        
           |  |  | 209 |      */
 | 
        
           |  |  | 210 |     public function getDropTableSQL($xmldb_table) {
 | 
        
           |  |  | 211 |         $sqlarr = parent::getDropTableSQL($xmldb_table);
 | 
        
           |  |  | 212 |         if ($this->temptables->is_temptable($xmldb_table->getName())) {
 | 
        
           |  |  | 213 |             array_unshift($sqlarr, "TRUNCATE TABLE ". $this->getTableName($xmldb_table)); // oracle requires truncate before being able to drop a temp table
 | 
        
           |  |  | 214 |         }
 | 
        
           |  |  | 215 |         return $sqlarr;
 | 
        
           |  |  | 216 |     }
 | 
        
           |  |  | 217 |   | 
        
           |  |  | 218 |     /**
 | 
        
           |  |  | 219 |      * Given one XMLDB Type, length and decimals, returns the DB proper SQL type.
 | 
        
           |  |  | 220 |      *
 | 
        
           |  |  | 221 |      * @param int $xmldb_type The xmldb_type defined constant. XMLDB_TYPE_INTEGER and other XMLDB_TYPE_* constants.
 | 
        
           |  |  | 222 |      * @param int $xmldb_length The length of that data type.
 | 
        
           |  |  | 223 |      * @param int $xmldb_decimals The decimal places of precision of the data type.
 | 
        
           |  |  | 224 |      * @return string The DB defined data type.
 | 
        
           |  |  | 225 |      */
 | 
        
           |  |  | 226 |     public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
 | 
        
           |  |  | 227 |   | 
        
           |  |  | 228 |         switch ($xmldb_type) {
 | 
        
           |  |  | 229 |             case XMLDB_TYPE_INTEGER:    // See http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/sql_elements001.htm#sthref86.
 | 
        
           |  |  | 230 |                 if (empty($xmldb_length)) {
 | 
        
           |  |  | 231 |                     $xmldb_length = 10;
 | 
        
           |  |  | 232 |                 }
 | 
        
           |  |  | 233 |                 $dbtype = 'NUMBER(' .  $xmldb_length . ')';
 | 
        
           |  |  | 234 |                 break;
 | 
        
           |  |  | 235 |             case XMLDB_TYPE_FLOAT:
 | 
        
           |  |  | 236 |             case XMLDB_TYPE_NUMBER:
 | 
        
           |  |  | 237 |                 $dbtype = $this->number_type;
 | 
        
           |  |  | 238 |                 if (!empty($xmldb_length)) {
 | 
        
           |  |  | 239 |                     $dbtype .= '(' . $xmldb_length;
 | 
        
           |  |  | 240 |                     if (!empty($xmldb_decimals)) {
 | 
        
           |  |  | 241 |                         $dbtype .= ',' . $xmldb_decimals;
 | 
        
           |  |  | 242 |                     }
 | 
        
           |  |  | 243 |                     $dbtype .= ')';
 | 
        
           |  |  | 244 |                 }
 | 
        
           |  |  | 245 |                 break;
 | 
        
           |  |  | 246 |             case XMLDB_TYPE_CHAR:
 | 
        
           |  |  | 247 |                 // Do not use NVARCHAR2 here because it has hardcoded 1333 char limit,
 | 
        
           |  |  | 248 |                 // VARCHAR2 allows us to create larger fields that error out later during runtime
 | 
        
           |  |  | 249 |                 // only when too many non-ascii utf-8 chars present.
 | 
        
           |  |  | 250 |                 $dbtype = 'VARCHAR2';
 | 
        
           |  |  | 251 |                 if (empty($xmldb_length)) {
 | 
        
           |  |  | 252 |                     $xmldb_length='255';
 | 
        
           |  |  | 253 |                 }
 | 
        
           |  |  | 254 |                 $dbtype .= '(' . $xmldb_length . ' CHAR)'; // CHAR is required because BYTE is the default
 | 
        
           |  |  | 255 |                 break;
 | 
        
           |  |  | 256 |             case XMLDB_TYPE_TEXT:
 | 
        
           |  |  | 257 |                 $dbtype = 'CLOB';
 | 
        
           |  |  | 258 |                 break;
 | 
        
           |  |  | 259 |             case XMLDB_TYPE_BINARY:
 | 
        
           |  |  | 260 |                 $dbtype = 'BLOB';
 | 
        
           |  |  | 261 |                 break;
 | 
        
           |  |  | 262 |             case XMLDB_TYPE_DATETIME:
 | 
        
           |  |  | 263 |                 $dbtype = 'DATE';
 | 
        
           |  |  | 264 |                 break;
 | 
        
           |  |  | 265 |         }
 | 
        
           |  |  | 266 |         return $dbtype;
 | 
        
           |  |  | 267 |     }
 | 
        
           |  |  | 268 |   | 
        
           |  |  | 269 |     /**
 | 
        
           |  |  | 270 |      * Returns the code (array of statements) needed
 | 
        
           |  |  | 271 |      * to create one sequence for the xmldb_table and xmldb_field passed in.
 | 
        
           |  |  | 272 |      *
 | 
        
           |  |  | 273 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 274 |      * @param xmldb_field $xmldb_field The xmldb_field object instance.
 | 
        
           |  |  | 275 |      * @return array Array of SQL statements to create the sequence.
 | 
        
           |  |  | 276 |      */
 | 
        
           |  |  | 277 |     public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
 | 
        
           |  |  | 278 |   | 
        
           |  |  | 279 |         $results = array();
 | 
        
           |  |  | 280 |   | 
        
           |  |  | 281 |         $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
 | 
        
           |  |  | 282 |   | 
        
           |  |  | 283 |         $sequence = "CREATE SEQUENCE $sequence_name START WITH 1 INCREMENT BY 1 NOMAXVALUE CACHE $this->sequence_cache_size";
 | 
        
           |  |  | 284 |   | 
        
           |  |  | 285 |         $results[] = $sequence;
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 |         $results = array_merge($results, $this->getCreateTriggerSQL ($xmldb_table, $xmldb_field, $sequence_name));
 | 
        
           |  |  | 288 |   | 
        
           |  |  | 289 |         return $results;
 | 
        
           |  |  | 290 |     }
 | 
        
           |  |  | 291 |   | 
        
           |  |  | 292 |     /**
 | 
        
           |  |  | 293 |      * Returns the code needed to create one trigger for the xmldb_table and xmldb_field passed
 | 
        
           |  |  | 294 |      *
 | 
        
           |  |  | 295 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 296 |      * @param xmldb_field $xmldb_field The xmldb_field object instance.
 | 
        
           |  |  | 297 |      * @param string $sequence_name
 | 
        
           |  |  | 298 |      * @return array Array of SQL statements to create the sequence.
 | 
        
           |  |  | 299 |      */
 | 
        
           |  |  | 300 |     public function getCreateTriggerSQL($xmldb_table, $xmldb_field, $sequence_name) {
 | 
        
           |  |  | 301 |   | 
        
           |  |  | 302 |         $trigger_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'trg');
 | 
        
           |  |  | 303 |   | 
        
           |  |  | 304 |         $trigger = "CREATE TRIGGER " . $trigger_name;
 | 
        
           |  |  | 305 |         $trigger.= "\n    BEFORE INSERT";
 | 
        
           |  |  | 306 |         $trigger.= "\nON " . $this->getTableName($xmldb_table);
 | 
        
           |  |  | 307 |         $trigger.= "\n    FOR EACH ROW";
 | 
        
           |  |  | 308 |         $trigger.= "\nBEGIN";
 | 
        
           |  |  | 309 |         $trigger.= "\n    IF :new." . $this->getEncQuoted($xmldb_field->getName()) . ' IS NULL THEN';
 | 
        
           |  |  | 310 |         $trigger.= "\n        SELECT " . $sequence_name . '.nextval INTO :new.' . $this->getEncQuoted($xmldb_field->getName()) . " FROM dual;";
 | 
        
           |  |  | 311 |         $trigger.= "\n    END IF;";
 | 
        
           |  |  | 312 |         $trigger.= "\nEND;";
 | 
        
           |  |  | 313 |   | 
        
           |  |  | 314 |         return array($trigger);
 | 
        
           |  |  | 315 |     }
 | 
        
           |  |  | 316 |   | 
        
           |  |  | 317 |     /**
 | 
        
           |  |  | 318 |      * Returns the code needed to drop one sequence for the xmldb_table and xmldb_field passed
 | 
        
           |  |  | 319 |      * Can, optionally, specify if the underlying trigger will be also dropped
 | 
        
           |  |  | 320 |      *
 | 
        
           |  |  | 321 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 322 |      * @param xmldb_field $xmldb_field The xmldb_field object instance.
 | 
        
           |  |  | 323 |      * @param bool $include_trigger
 | 
        
           |  |  | 324 |      * @return array Array of SQL statements to create the sequence.
 | 
        
           |  |  | 325 |      */
 | 
        
           |  |  | 326 |     public function getDropSequenceSQL($xmldb_table, $xmldb_field, $include_trigger=false) {
 | 
        
           |  |  | 327 |   | 
        
           |  |  | 328 |         $result = array();
 | 
        
           |  |  | 329 |   | 
        
           |  |  | 330 |         if ($sequence_name = $this->getSequenceFromDB($xmldb_table)) {
 | 
        
           |  |  | 331 |             $result[] = "DROP SEQUENCE " . $sequence_name;
 | 
        
           |  |  | 332 |         }
 | 
        
           |  |  | 333 |   | 
        
           |  |  | 334 |         if ($trigger_name = $this->getTriggerFromDB($xmldb_table) && $include_trigger) {
 | 
        
           |  |  | 335 |             $result[] = "DROP TRIGGER " . $trigger_name;
 | 
        
           |  |  | 336 |         }
 | 
        
           |  |  | 337 |   | 
        
           |  |  | 338 |         return $result;
 | 
        
           |  |  | 339 |     }
 | 
        
           |  |  | 340 |   | 
        
           |  |  | 341 |     /**
 | 
        
           |  |  | 342 |      * Returns the code (array of statements) needed to add one comment to the table.
 | 
        
           |  |  | 343 |      *
 | 
        
           |  |  | 344 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 345 |      * @return array Array of SQL statements to add one comment to the table.
 | 
        
           |  |  | 346 |      */
 | 
        
           |  |  | 347 |     function getCommentSQL($xmldb_table) {
 | 
        
           |  |  | 348 |   | 
        
           |  |  | 349 |         $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
 | 
        
           |  |  | 350 |         $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
 | 
        
           |  |  | 351 |   | 
        
           |  |  | 352 |         return array($comment);
 | 
        
           |  |  | 353 |     }
 | 
        
           |  |  | 354 |   | 
        
           |  |  | 355 |     /**
 | 
        
           |  |  | 356 |      * Returns the code (array of statements) needed to execute extra statements on table drop
 | 
        
           |  |  | 357 |      *
 | 
        
           |  |  | 358 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 359 |      * @return array Array of extra SQL statements to drop a table.
 | 
        
           |  |  | 360 |      */
 | 
        
           |  |  | 361 |     public function getDropTableExtraSQL($xmldb_table) {
 | 
        
           |  |  | 362 |         $xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
 | 
        
           |  |  | 363 |         return $this->getDropSequenceSQL($xmldb_table, $xmldb_field, false);
 | 
        
           |  |  | 364 |     }
 | 
        
           |  |  | 365 |   | 
        
           |  |  | 366 |     /**
 | 
        
           |  |  | 367 |      * Returns the code (array of statements) needed to execute extra statements on table rename.
 | 
        
           |  |  | 368 |      *
 | 
        
           |  |  | 369 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 370 |      * @param string $newname The new name for the table.
 | 
        
           |  |  | 371 |      * @return array Array of extra SQL statements to rename a table.
 | 
        
           |  |  | 372 |      */
 | 
        
           |  |  | 373 |     public function getRenameTableExtraSQL($xmldb_table, $newname) {
 | 
        
           |  |  | 374 |   | 
        
           |  |  | 375 |         $results = array();
 | 
        
           |  |  | 376 |   | 
        
           |  |  | 377 |         $xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
 | 
        
           |  |  | 378 |   | 
        
           |  |  | 379 |         $oldseqname = $this->getSequenceFromDB($xmldb_table);
 | 
        
           |  |  | 380 |         $newseqname = $this->getNameForObject($newname, $xmldb_field->getName(), 'seq');
 | 
        
           |  |  | 381 |   | 
        
           |  |  | 382 |         $oldtriggername = $this->getTriggerFromDB($xmldb_table);
 | 
        
           |  |  | 383 |         $newtriggername = $this->getNameForObject($newname, $xmldb_field->getName(), 'trg');
 | 
        
           |  |  | 384 |   | 
        
           |  |  | 385 |         // Drop old trigger (first of all)
 | 
        
           |  |  | 386 |         $results[] = "DROP TRIGGER " . $oldtriggername;
 | 
        
           |  |  | 387 |   | 
        
           |  |  | 388 |         // Rename the sequence, disablig CACHE before and enablig it later
 | 
        
           |  |  | 389 |         // to avoid consuming of values on rename
 | 
        
           |  |  | 390 |         $results[] = 'ALTER SEQUENCE ' . $oldseqname . ' NOCACHE';
 | 
        
           |  |  | 391 |         $results[] = 'RENAME ' . $oldseqname . ' TO ' . $newseqname;
 | 
        
           |  |  | 392 |         $results[] = 'ALTER SEQUENCE ' . $newseqname . ' CACHE ' . $this->sequence_cache_size;
 | 
        
           |  |  | 393 |   | 
        
           |  |  | 394 |         // Create new trigger
 | 
        
           |  |  | 395 |         $newt = new xmldb_table($newname);     // Temp table for trigger code generation
 | 
        
           |  |  | 396 |         $results = array_merge($results, $this->getCreateTriggerSQL($newt, $xmldb_field, $newseqname));
 | 
        
           |  |  | 397 |   | 
        
           |  |  | 398 |         return $results;
 | 
        
           |  |  | 399 |     }
 | 
        
           |  |  | 400 |   | 
        
           |  |  | 401 |     /**
 | 
        
           |  |  | 402 |      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to alter the field in the table.
 | 
        
           |  |  | 403 |      *
 | 
        
           |  |  | 404 |      * Oracle has some severe limits:
 | 
        
           |  |  | 405 |      *     - clob and blob fields doesn't allow type to be specified
 | 
        
           |  |  | 406 |      *     - error is dropped if the null/not null clause is specified and hasn't changed
 | 
        
           |  |  | 407 |      *     - changes in precision/decimals of numeric fields drop an ORA-1440 error
 | 
        
           |  |  | 408 |      *
 | 
        
           |  |  | 409 |      * @param xmldb_table $xmldb_table The table related to $xmldb_field.
 | 
        
           |  |  | 410 |      * @param xmldb_field $xmldb_field The instance of xmldb_field to create the SQL from.
 | 
        
           |  |  | 411 |      * @param string $skip_type_clause The type clause on alter columns, NULL by default.
 | 
        
           |  |  | 412 |      * @param string $skip_default_clause The default clause on alter columns, NULL by default.
 | 
        
           |  |  | 413 |      * @param string $skip_notnull_clause The null/notnull clause on alter columns, NULL by default.
 | 
        
           |  |  | 414 |      * @return string The field altering SQL statement.
 | 
        
           |  |  | 415 |      */
 | 
        
           |  |  | 416 |     public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
 | 
        
           |  |  | 417 |   | 
        
           |  |  | 418 |         $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause;
 | 
        
           |  |  | 419 |         $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause;
 | 
        
           |  |  | 420 |         $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause;
 | 
        
           |  |  | 421 |   | 
        
           |  |  | 422 |         $results = array();     // To store all the needed SQL commands
 | 
        
           |  |  | 423 |   | 
        
           |  |  | 424 |         // Get the quoted name of the table and field
 | 
        
           |  |  | 425 |         $tablename = $this->getTableName($xmldb_table);
 | 
        
           |  |  | 426 |         $fieldname = $xmldb_field->getName();
 | 
        
           |  |  | 427 |   | 
        
           |  |  | 428 |         // Take a look to field metadata
 | 
        
           |  |  | 429 |         $meta = $this->mdb->get_columns($xmldb_table->getName());
 | 
        
           |  |  | 430 |         $metac = $meta[$fieldname];
 | 
        
           |  |  | 431 |         $oldmetatype = $metac->meta_type;
 | 
        
           |  |  | 432 |   | 
        
           |  |  | 433 |         $oldlength = $metac->max_length;
 | 
        
           |  |  | 434 |         // To calculate the oldlength if the field is numeric, we need to perform one extra query
 | 
        
           |  |  | 435 |         // because ADOdb has one bug here. http://phplens.com/lens/lensforum/msgs.php?id=15883
 | 
        
           |  |  | 436 |         if ($oldmetatype == 'N') {
 | 
        
           |  |  | 437 |             $uppertablename = strtoupper($tablename);
 | 
        
           |  |  | 438 |             $upperfieldname = strtoupper($fieldname);
 | 
        
           |  |  | 439 |             if ($col = $this->mdb->get_record_sql("SELECT cname, precision
 | 
        
           |  |  | 440 |                                                      FROM col
 | 
        
           |  |  | 441 |                                                      WHERE tname = ? AND cname = ?",
 | 
        
           |  |  | 442 |                                                   array($uppertablename, $upperfieldname))) {
 | 
        
           |  |  | 443 |                 $oldlength = $col->precision;
 | 
        
           |  |  | 444 |             }
 | 
        
           |  |  | 445 |         }
 | 
        
           |  |  | 446 |         $olddecimals = empty($metac->scale) ? null : $metac->scale;
 | 
        
           |  |  | 447 |         $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
 | 
        
           |  |  | 448 |         $olddefault = empty($metac->default_value) || strtoupper($metac->default_value) == 'NULL' ? null : $metac->default_value;
 | 
        
           |  |  | 449 |   | 
        
           |  |  | 450 |         $typechanged = true;  //By default, assume that the column type has changed
 | 
        
           |  |  | 451 |         $precisionchanged = true;  //By default, assume that the column precision has changed
 | 
        
           |  |  | 452 |         $decimalchanged = true;  //By default, assume that the column decimal has changed
 | 
        
           |  |  | 453 |         $defaultchanged = true;  //By default, assume that the column default has changed
 | 
        
           |  |  | 454 |         $notnullchanged = true;  //By default, assume that the column notnull has changed
 | 
        
           |  |  | 455 |   | 
        
           |  |  | 456 |         $from_temp_fields = false; //By default don't assume we are going to use temporal fields
 | 
        
           |  |  | 457 |   | 
        
           |  |  | 458 |         // Detect if we are changing the type of the column
 | 
        
           |  |  | 459 |         if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
 | 
        
           |  |  | 460 |             ($xmldb_field->getType() == XMLDB_TYPE_NUMBER  && $oldmetatype == 'N') ||
 | 
        
           |  |  | 461 |             ($xmldb_field->getType() == XMLDB_TYPE_FLOAT   && $oldmetatype == 'F') ||
 | 
        
           |  |  | 462 |             ($xmldb_field->getType() == XMLDB_TYPE_CHAR    && $oldmetatype == 'C') ||
 | 
        
           |  |  | 463 |             ($xmldb_field->getType() == XMLDB_TYPE_TEXT    && $oldmetatype == 'X') ||
 | 
        
           |  |  | 464 |             ($xmldb_field->getType() == XMLDB_TYPE_BINARY  && $oldmetatype == 'B')) {
 | 
        
           |  |  | 465 |             $typechanged = false;
 | 
        
           |  |  | 466 |         }
 | 
        
           |  |  | 467 |         // Detect if precision has changed
 | 
        
           |  |  | 468 |         if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
 | 
        
           |  |  | 469 |             ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
 | 
        
           |  |  | 470 |             ($oldlength == -1) ||
 | 
        
           |  |  | 471 |             ($xmldb_field->getLength() == $oldlength)) {
 | 
        
           |  |  | 472 |             $precisionchanged = false;
 | 
        
           |  |  | 473 |         }
 | 
        
           |  |  | 474 |         // Detect if decimal has changed
 | 
        
           |  |  | 475 |         if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
 | 
        
           |  |  | 476 |             ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
 | 
        
           |  |  | 477 |             ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
 | 
        
           |  |  | 478 |             ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
 | 
        
           |  |  | 479 |             (!$xmldb_field->getDecimals()) ||
 | 
        
           |  |  | 480 |             (!$olddecimals) ||
 | 
        
           |  |  | 481 |             ($xmldb_field->getDecimals() == $olddecimals)) {
 | 
        
           |  |  | 482 |             $decimalchanged = false;
 | 
        
           |  |  | 483 |         }
 | 
        
           |  |  | 484 |         // Detect if we are changing the default
 | 
        
           |  |  | 485 |         if (($xmldb_field->getDefault() === null && $olddefault === null) ||
 | 
        
           |  |  | 486 |             ($xmldb_field->getDefault() === $olddefault) ||             //Check both equality and
 | 
        
           |  |  | 487 |             ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) {  //Equality with quotes because ADOdb returns the default with quotes
 | 
        
           |  |  | 488 |             $defaultchanged = false;
 | 
        
           |  |  | 489 |         }
 | 
        
           |  |  | 490 |   | 
        
           |  |  | 491 |         // Detect if we are changing the nullability
 | 
        
           |  |  | 492 |         if (($xmldb_field->getNotnull() === $oldnotnull)) {
 | 
        
           |  |  | 493 |             $notnullchanged = false;
 | 
        
           |  |  | 494 |         }
 | 
        
           |  |  | 495 |   | 
        
           |  |  | 496 |         // If type has changed or precision or decimal has changed and we are in one numeric field
 | 
        
           |  |  | 497 |         //     - create one temp column with the new specs
 | 
        
           |  |  | 498 |         //     - fill the new column with the values from the old one
 | 
        
           |  |  | 499 |         //     - drop the old column
 | 
        
           |  |  | 500 |         //     - rename the temp column to the original name
 | 
        
           |  |  | 501 |         if (($typechanged) || (($oldmetatype == 'N' || $oldmetatype == 'I')  && ($precisionchanged || $decimalchanged))) {
 | 
        
           |  |  | 502 |             $tempcolname = $xmldb_field->getName() . '___tmp'; // Short tmp name, surely not conflicting ever
 | 
        
           |  |  | 503 |             if (strlen($tempcolname) > 30) { // Safeguard we don't excess the 30cc limit
 | 
        
           |  |  | 504 |                 $tempcolname = 'ongoing_alter_column_tmp';
 | 
        
           |  |  | 505 |             }
 | 
        
           |  |  | 506 |             // Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
 | 
        
           |  |  | 507 |             $skip_notnull_clause = true;
 | 
        
           |  |  | 508 |             $skip_default_clause = true;
 | 
        
           |  |  | 509 |             $xmldb_field->setName($tempcolname);
 | 
        
           |  |  | 510 |             // Drop the temp column, in case it exists (due to one previous failure in conversion)
 | 
        
           |  |  | 511 |             // really ugly but we cannot enclose DDL into transaction :-(
 | 
        
           |  |  | 512 |             if (isset($meta[$tempcolname])) {
 | 
        
           |  |  | 513 |                 $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
 | 
        
           |  |  | 514 |             }
 | 
        
           |  |  | 515 |             // Create the temporal column
 | 
        
           |  |  | 516 |             $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_type_clause, $skip_notnull_clause));
 | 
        
           |  |  | 517 |             // Copy contents from original col to the temporal one
 | 
        
           |  |  | 518 |   | 
        
           |  |  | 519 |             // From TEXT to integer/number we need explicit conversion
 | 
        
           |  |  | 520 |             if ($oldmetatype == 'X' && $xmldb_field->GetType() == XMLDB_TYPE_INTEGER) {
 | 
        
           |  |  | 521 |                 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = CAST(' . $this->mdb->sql_compare_text($fieldname) . ' AS INT)';
 | 
        
           |  |  | 522 |             } else if ($oldmetatype == 'X' && $xmldb_field->GetType() == XMLDB_TYPE_NUMBER) {
 | 
        
           |  |  | 523 |                 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = CAST(' . $this->mdb->sql_compare_text($fieldname) . ' AS NUMBER)';
 | 
        
           |  |  | 524 |   | 
        
           |  |  | 525 |             // Normal cases, implicit conversion
 | 
        
           |  |  | 526 |             } else {
 | 
        
           |  |  | 527 |                 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $fieldname;
 | 
        
           |  |  | 528 |             }
 | 
        
           |  |  | 529 |             // Drop the old column
 | 
        
           |  |  | 530 |             $xmldb_field->setName($fieldname); //Set back the original field name
 | 
        
           |  |  | 531 |             $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
 | 
        
           |  |  | 532 |             // Rename the temp column to the original one
 | 
        
           |  |  | 533 |             $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
 | 
        
           |  |  | 534 |             // Mark we have performed one change based in temp fields
 | 
        
           |  |  | 535 |             $from_temp_fields = true;
 | 
        
           |  |  | 536 |             // Re-enable the notnull and default sections so the general AlterFieldSQL can use it
 | 
        
           |  |  | 537 |             $skip_notnull_clause = false;
 | 
        
           |  |  | 538 |             $skip_default_clause = false;
 | 
        
           |  |  | 539 |             // Disable the type section because we have done it with the temp field
 | 
        
           |  |  | 540 |             $skip_type_clause = true;
 | 
        
           |  |  | 541 |             // If new field is nullable, nullability hasn't changed
 | 
        
           |  |  | 542 |             if (!$xmldb_field->getNotnull()) {
 | 
        
           |  |  | 543 |                 $notnullchanged = false;
 | 
        
           |  |  | 544 |             }
 | 
        
           |  |  | 545 |             // If new field hasn't default, default hasn't changed
 | 
        
           |  |  | 546 |             if ($xmldb_field->getDefault() === null) {
 | 
        
           |  |  | 547 |                 $defaultchanged = false;
 | 
        
           |  |  | 548 |             }
 | 
        
           |  |  | 549 |         }
 | 
        
           |  |  | 550 |   | 
        
           |  |  | 551 |         // If type and precision and decimals hasn't changed, prevent the type clause
 | 
        
           |  |  | 552 |         if (!$typechanged && !$precisionchanged && !$decimalchanged) {
 | 
        
           |  |  | 553 |             $skip_type_clause = true;
 | 
        
           |  |  | 554 |         }
 | 
        
           |  |  | 555 |   | 
        
           |  |  | 556 |         // If NULL/NOT NULL hasn't changed
 | 
        
           |  |  | 557 |         // prevent null clause to be specified
 | 
        
           |  |  | 558 |         if (!$notnullchanged) {
 | 
        
           |  |  | 559 |             $skip_notnull_clause = true;     // Initially, prevent the notnull clause
 | 
        
           |  |  | 560 |             // But, if we have used the temp field and the new field is not null, then enforce the not null clause
 | 
        
           |  |  | 561 |             if ($from_temp_fields &&  $xmldb_field->getNotnull()) {
 | 
        
           |  |  | 562 |                 $skip_notnull_clause = false;
 | 
        
           |  |  | 563 |             }
 | 
        
           |  |  | 564 |         }
 | 
        
           |  |  | 565 |         // If default hasn't changed
 | 
        
           |  |  | 566 |         // prevent default clause to be specified
 | 
        
           |  |  | 567 |         if (!$defaultchanged) {
 | 
        
           |  |  | 568 |             $skip_default_clause = true;     // Initially, prevent the default clause
 | 
        
           |  |  | 569 |             // But, if we have used the temp field and the new field has default clause, then enforce the default clause
 | 
        
           |  |  | 570 |             if ($from_temp_fields) {
 | 
        
           |  |  | 571 |                 $default_clause = $this->getDefaultClause($xmldb_field);
 | 
        
           |  |  | 572 |                 if ($default_clause) {
 | 
        
           |  |  | 573 |                     $skip_notnull_clause = false;
 | 
        
           |  |  | 574 |                 }
 | 
        
           |  |  | 575 |             }
 | 
        
           |  |  | 576 |         }
 | 
        
           |  |  | 577 |   | 
        
           |  |  | 578 |         // If arriving here, something is not being skipped (type, notnull, default), calculate the standard AlterFieldSQL
 | 
        
           |  |  | 579 |         if (!$skip_type_clause || !$skip_notnull_clause || !$skip_default_clause) {
 | 
        
           |  |  | 580 |             $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_default_clause, $skip_notnull_clause));
 | 
        
           |  |  | 581 |             return $results;
 | 
        
           |  |  | 582 |         }
 | 
        
           |  |  | 583 |   | 
        
           |  |  | 584 |         // Finally return results
 | 
        
           |  |  | 585 |         return $results;
 | 
        
           |  |  | 586 |     }
 | 
        
           |  |  | 587 |   | 
        
           |  |  | 588 |     /**
 | 
        
           |  |  | 589 |      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to add its default
 | 
        
           |  |  | 590 |      * (usually invoked from getModifyDefaultSQL()
 | 
        
           |  |  | 591 |      *
 | 
        
           |  |  | 592 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 593 |      * @param xmldb_field $xmldb_field The xmldb_field object instance.
 | 
        
           |  |  | 594 |      * @return array Array of SQL statements to create a field's default.
 | 
        
           |  |  | 595 |      */
 | 
        
           |  |  | 596 |     public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
 | 
        
           |  |  | 597 |         // Just a wrapper over the getAlterFieldSQL() function for Oracle that
 | 
        
           |  |  | 598 |         // is capable of handling defaults
 | 
        
           |  |  | 599 |         return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
 | 
        
           |  |  | 600 |     }
 | 
        
           |  |  | 601 |   | 
        
           |  |  | 602 |     /**
 | 
        
           |  |  | 603 |      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its default
 | 
        
           |  |  | 604 |      * (usually invoked from getModifyDefaultSQL()
 | 
        
           |  |  | 605 |      *
 | 
        
           |  |  | 606 |      * Note that this method may be dropped in future.
 | 
        
           |  |  | 607 |      *
 | 
        
           |  |  | 608 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 609 |      * @param xmldb_field $xmldb_field The xmldb_field object instance.
 | 
        
           |  |  | 610 |      * @return array Array of SQL statements to create a field's default.
 | 
        
           |  |  | 611 |      *
 | 
        
           |  |  | 612 |      * @todo MDL-31147 Moodle 2.1 - Drop getDropDefaultSQL()
 | 
        
           |  |  | 613 |      */
 | 
        
           |  |  | 614 |     public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
 | 
        
           |  |  | 615 |         // Just a wrapper over the getAlterFieldSQL() function for Oracle that
 | 
        
           |  |  | 616 |         // is capable of handling defaults
 | 
        
           |  |  | 617 |         return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
 | 
        
           |  |  | 618 |     }
 | 
        
           |  |  | 619 |   | 
        
           |  |  | 620 |     /**
 | 
        
           |  |  | 621 |      * Given one xmldb_table returns one string with the sequence of the table
 | 
        
           |  |  | 622 |      * in the table (fetched from DB)
 | 
        
           |  |  | 623 |      * The sequence name for oracle is calculated by looking the corresponding
 | 
        
           |  |  | 624 |      * trigger and retrieving the sequence name from it (because sequences are
 | 
        
           |  |  | 625 |      * independent elements)
 | 
        
           |  |  | 626 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 627 |      * @return string|bool If no sequence is found, returns false
 | 
        
           |  |  | 628 |      */
 | 
        
           |  |  | 629 |     public function getSequenceFromDB($xmldb_table) {
 | 
        
           |  |  | 630 |   | 
        
           |  |  | 631 |          $tablename    = strtoupper($this->getTableName($xmldb_table));
 | 
        
           |  |  | 632 |          $prefixupper  = strtoupper($this->prefix);
 | 
        
           |  |  | 633 |          $sequencename = false;
 | 
        
           |  |  | 634 |   | 
        
           |  |  | 635 |         if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
 | 
        
           |  |  | 636 |                                                      FROM user_triggers
 | 
        
           |  |  | 637 |                                                     WHERE table_name = ? AND trigger_name LIKE ?",
 | 
        
           |  |  | 638 |                                                   array($tablename, "{$prefixupper}%_ID%_TRG"))) {
 | 
        
           |  |  | 639 |             // If trigger found, regexp it looking for the sequence name
 | 
        
           |  |  | 640 |             preg_match('/.*SELECT (.*)\.nextval/i', $trigger->trigger_body, $matches);
 | 
        
           |  |  | 641 |             if (isset($matches[1])) {
 | 
        
           |  |  | 642 |                 $sequencename = $matches[1];
 | 
        
           |  |  | 643 |             }
 | 
        
           |  |  | 644 |         }
 | 
        
           |  |  | 645 |   | 
        
           |  |  | 646 |         return $sequencename;
 | 
        
           |  |  | 647 |     }
 | 
        
           |  |  | 648 |   | 
        
           |  |  | 649 |     /**
 | 
        
           |  |  | 650 |      * Given one xmldb_table returns one string with the trigger
 | 
        
           |  |  | 651 |      * in the table (fetched from DB)
 | 
        
           |  |  | 652 |      *
 | 
        
           |  |  | 653 |      * @param xmldb_table $xmldb_table The xmldb_table object instance.
 | 
        
           |  |  | 654 |      * @return string|bool If no trigger is found, returns false
 | 
        
           |  |  | 655 |      */
 | 
        
           |  |  | 656 |     public function getTriggerFromDB($xmldb_table) {
 | 
        
           |  |  | 657 |   | 
        
           |  |  | 658 |         $tablename   = strtoupper($this->getTableName($xmldb_table));
 | 
        
           |  |  | 659 |         $prefixupper = strtoupper($this->prefix);
 | 
        
           |  |  | 660 |         $triggername = false;
 | 
        
           |  |  | 661 |   | 
        
           |  |  | 662 |         if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
 | 
        
           |  |  | 663 |                                                      FROM user_triggers
 | 
        
           |  |  | 664 |                                                     WHERE table_name = ? AND trigger_name LIKE ?",
 | 
        
           |  |  | 665 |                                                   array($tablename, "{$prefixupper}%_ID%_TRG"))) {
 | 
        
           |  |  | 666 |             $triggername = $trigger->trigger_name;
 | 
        
           |  |  | 667 |         }
 | 
        
           |  |  | 668 |   | 
        
           |  |  | 669 |         return $triggername;
 | 
        
           |  |  | 670 |     }
 | 
        
           |  |  | 671 |   | 
        
           |  |  | 672 |     /**
 | 
        
           |  |  | 673 |      * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg).
 | 
        
           |  |  | 674 |      *
 | 
        
           |  |  | 675 |      * (MySQL requires the whole xmldb_table object to be specified, so we add it always)
 | 
        
           |  |  | 676 |      *
 | 
        
           |  |  | 677 |      * This is invoked from getNameForObject().
 | 
        
           |  |  | 678 |      * Only some DB have this implemented.
 | 
        
           |  |  | 679 |      *
 | 
        
           |  |  | 680 |      * @param string $object_name The object's name to check for.
 | 
        
           |  |  | 681 |      * @param string $type The object's type (pk, uk, fk, ck, ix, uix, seq, trg).
 | 
        
           |  |  | 682 |      * @param string $table_name The table's name to check in
 | 
        
           |  |  | 683 |      * @return bool If such name is currently in use (true) or no (false)
 | 
        
           |  |  | 684 |      */
 | 
        
           |  |  | 685 |     public function isNameInUse($object_name, $type, $table_name) {
 | 
        
           |  |  | 686 |         switch($type) {
 | 
        
           |  |  | 687 |             case 'ix':
 | 
        
           |  |  | 688 |             case 'uix':
 | 
        
           |  |  | 689 |             case 'seq':
 | 
        
           |  |  | 690 |             case 'trg':
 | 
        
           |  |  | 691 |                 if ($check = $this->mdb->get_records_sql("SELECT object_name
 | 
        
           |  |  | 692 |                                                             FROM user_objects
 | 
        
           |  |  | 693 |                                                            WHERE lower(object_name) = ?", array(strtolower($object_name)))) {
 | 
        
           |  |  | 694 |                     return true;
 | 
        
           |  |  | 695 |                 }
 | 
        
           |  |  | 696 |                 break;
 | 
        
           |  |  | 697 |             case 'pk':
 | 
        
           |  |  | 698 |             case 'uk':
 | 
        
           |  |  | 699 |             case 'fk':
 | 
        
           |  |  | 700 |             case 'ck':
 | 
        
           |  |  | 701 |                 if ($check = $this->mdb->get_records_sql("SELECT constraint_name
 | 
        
           |  |  | 702 |                                                             FROM user_constraints
 | 
        
           |  |  | 703 |                                                            WHERE lower(constraint_name) = ?", array(strtolower($object_name)))) {
 | 
        
           |  |  | 704 |                     return true;
 | 
        
           |  |  | 705 |                 }
 | 
        
           |  |  | 706 |                 break;
 | 
        
           |  |  | 707 |         }
 | 
        
           |  |  | 708 |         return false; //No name in use found
 | 
        
           |  |  | 709 |     }
 | 
        
           |  |  | 710 |   | 
        
           |  |  | 711 |     /**
 | 
        
           |  |  | 712 |      * Adds slashes to string.
 | 
        
           |  |  | 713 |      * @param string $s
 | 
        
           |  |  | 714 |      * @return string The escaped string.
 | 
        
           |  |  | 715 |      */
 | 
        
           |  |  | 716 |     public function addslashes($s) {
 | 
        
           |  |  | 717 |         // do not use php addslashes() because it depends on PHP quote settings!
 | 
        
           |  |  | 718 |         $s = str_replace("'",  "''", $s);
 | 
        
           |  |  | 719 |         return $s;
 | 
        
           |  |  | 720 |     }
 | 
        
           |  |  | 721 |   | 
        
           |  |  | 722 |     /**
 | 
        
           |  |  | 723 |      * Returns an array of reserved words (lowercase) for this DB
 | 
        
           |  |  | 724 |      * @return array An array of database specific reserved words
 | 
        
           |  |  | 725 |      */
 | 
        
           |  |  | 726 |     public static function getReservedWords() {
 | 
        
           |  |  | 727 |         // This file contains the reserved words for Oracle databases
 | 
        
           |  |  | 728 |         // from http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/ap_keywd.htm
 | 
        
           |  |  | 729 |         $reserved_words = array (
 | 
        
           |  |  | 730 |             'access', 'add', 'all', 'alter', 'and', 'any',
 | 
        
           |  |  | 731 |             'as', 'asc', 'audit', 'between', 'by', 'char',
 | 
        
           |  |  | 732 |             'check', 'cluster', 'column', 'comment',
 | 
        
           |  |  | 733 |             'compress', 'connect', 'create', 'current',
 | 
        
           |  |  | 734 |             'date', 'decimal', 'default', 'delete', 'desc',
 | 
        
           |  |  | 735 |             'distinct', 'drop', 'else', 'exclusive', 'exists',
 | 
        
           |  |  | 736 |             'file', 'float', 'for', 'from', 'grant', 'group',
 | 
        
           |  |  | 737 |             'having', 'identified', 'immediate', 'in',
 | 
        
           |  |  | 738 |             'increment', 'index', 'initial', 'insert',
 | 
        
           |  |  | 739 |             'integer', 'intersect', 'into', 'is', 'level',
 | 
        
           |  |  | 740 |             'like', 'lock', 'long', 'maxextents', 'minus',
 | 
        
           |  |  | 741 |             'mlslabel', 'mode', 'modify', 'nchar', 'nclob', 'noaudit',
 | 
        
           |  |  | 742 |             'nocompress', 'not', 'nowait', 'null', 'number', 'nvarchar2',
 | 
        
           |  |  | 743 |             'of', 'offline', 'on', 'online', 'option', 'or',
 | 
        
           |  |  | 744 |             'order', 'pctfree', 'prior', 'privileges',
 | 
        
           |  |  | 745 |             'public', 'raw', 'rename', 'resource', 'revoke',
 | 
        
           |  |  | 746 |             'row', 'rowid', 'rownum', 'rows', 'select',
 | 
        
           |  |  | 747 |             'session', 'set', 'share', 'size', 'smallint',
 | 
        
           |  |  | 748 |             'start', 'successful', 'synonym', 'sysdate',
 | 
        
           |  |  | 749 |             'table', 'then', 'to', 'trigger', 'uid', 'union',
 | 
        
           |  |  | 750 |             'unique', 'update', 'user', 'validate', 'values',
 | 
        
           |  |  | 751 |             'varchar', 'varchar2', 'view', 'whenever',
 | 
        
           |  |  | 752 |             'where', 'with'
 | 
        
           |  |  | 753 |         );
 | 
        
           |  |  | 754 |         return $reserved_words;
 | 
        
           |  |  | 755 |     }
 | 
        
           |  |  | 756 | }
 |