MDL-19470 adding missing inline docs
[moodle.git] / lib / ddl / oracle_sql_generator.php
CommitLineData
d7444bfc 1<?php // $Id$
2
3///////////////////////////////////////////////////////////////////////////
4// //
5// NOTICE OF COPYRIGHT //
6// //
7// Moodle - Modular Object-Oriented Dynamic Learning Environment //
8// http://moodle.com //
9// //
ed55f668 10// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
d7444bfc 11// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
12// //
13// This program is free software; you can redistribute it and/or modify //
14// it under the terms of the GNU General Public License as published by //
15// the Free Software Foundation; either version 2 of the License, or //
16// (at your option) any later version. //
17// //
18// This program is distributed in the hope that it will be useful, //
19// but WITHOUT ANY WARRANTY; without even the implied warranty of //
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
21// GNU General Public License for more details: //
22// //
23// http://www.gnu.org/copyleft/gpl.html //
24// //
25///////////////////////////////////////////////////////////////////////////
26
f33e1ed4 27require_once($CFG->libdir.'/ddl/sql_generator.php');
28
d7444bfc 29/// This class generate SQL code to be used against Oracle
30/// It extends XMLDBgenerator so everything can be
31/// overriden as needed to generate correct SQL.
32
f33e1ed4 33class oracle_sql_generator extends sql_generator {
d7444bfc 34
35/// Only set values that are different from the defaults present in XMLDBgenerator
36
f33e1ed4 37 public $statement_end = "\n/"; // String to be automatically added at the end of each statement
0513f3bf 38 // Using "/" because the standard ";" isn't good for stored procedures (triggers)
39
f33e1ed4 40 public $number_type = 'NUMBER'; // Proper type for NUMBER(x) in this DB
d7444bfc 41
f33e1ed4 42 public $unsigned_allowed = false; // To define in the generator must handle unsigned information
43 public $default_for_char = ' '; // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
2efaf3f8 44 // Using this whitespace here because Oracle doesn't distinguish empty and null! :-(
d7444bfc 45
f33e1ed4 46 public $drop_default_value_required = true; //To specify if the generator must use some DEFAULT clause to drop defaults
47 public $drop_default_value = NULL; //The DEFAULT clause required to drop defaults
20c559dd 48
f33e1ed4 49 public $default_after_null = false; //To decide if the default clause of each field must go after the null clause
3a8c55c3 50
f33e1ed4 51 public $sequence_extra_code = true; //Does the generator need to add extra code to generate the sequence fields
52 public $sequence_name = ''; //Particular name for inline sequences in this generator
c562997f 53
f33e1ed4 54 public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
d7444bfc 55
f33e1ed4 56 public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY (COLUMNSPECS)'; //The SQL template to alter columns
19c8321e 57
d7444bfc 58 /**
20c559dd 59 * Creates one new XMLDBoci8po
d7444bfc 60 */
f33e1ed4 61 public function __construct($mdb) {
62 parent::__construct($mdb);
d7444bfc 63 }
64
be415e95 65 /**
66 * Reset a sequence to the id field of a table.
67 * @param string $table name of table
68 * @return bool true
69 * @throws dml_exception if error
70 */
71 public function reset_sequence($table) {
72 if (is_string($table)) {
73 $tablename = $table;
74 $xmldb_table = new xmldb_table($tablename);
75 } else {
76 $tablename = $table->getName();
77 $xmldb_table = $table;
78 }
79 // From http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/statements_2011.htm
80 $value = (int)$this->mdb->get_field_sql('SELECT MAX(id) FROM {'.$tablename.'}');
81 $value++;
2d2d79ef 82
be415e95 83 $seqname = $this->mdb->get_manager()->find_sequence_name($xmldb_table);
84
85 if (!$seqname) {
86 /// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method
87 $seqname = $this->getNameForObject($table, 'id', 'seq');
88 }
89
90 $this->mdb->change_database_structure("DROP SEQUENCE $seqname");
91 return $this->mdb->change_database_structure("CREATE SEQUENCE $seqname START WITH $value INCREMENT BY 1 NOMAXVALUE");
92 }
93
94
b922e86b 95 /**
96 * Given one correct xmldb_table, returns the SQL statements
97 * to create temporary table (inside one array)
98 */
99 public function getCreateTempTableSQL($xmldb_table) {
100 $sqlarr = $this->getCreateTableSQL($xmldb_table);
21a7e260 101 $sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE GLOBAL TEMPORARY TABLE $1 ON COMMIT PRESERVE ROWS', $sqlarr);
b922e86b 102 return $sqlarr;
103 }
104
105 /**
106 * Given one correct xmldb_table and the new name, returns the SQL statements
107 * to drop it (inside one array)
108 */
109 public function getDropTempTableSQL($xmldb_table) {
110 $sqlarr = $this->getDropTableSQL($xmldb_table);
111 $tablename = $xmldb_table->getName();
112 array_unshift($sqlarr, "TRUNCATE TABLE {".$tablename."}"); // oracle requires truncate before being able to drop a temp table
113 return $sqlarr;
114 }
115
d7444bfc 116 /**
117 * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
118 */
f33e1ed4 119 public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
d7444bfc 120
121 switch ($xmldb_type) {
122 case XMLDB_TYPE_INTEGER: // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
123 if (empty($xmldb_length)) {
124 $xmldb_length = 10;
125 }
126 $dbtype = 'NUMBER(' . $xmldb_length . ')';
127 break;
128 case XMLDB_TYPE_NUMBER:
129 $dbtype = $this->number_type;
4782a1f8 130 /// 38 is the max allowed
131 if ($xmldb_length > 38) {
132 $xmldb_length = 38;
133 }
d7444bfc 134 if (!empty($xmldb_length)) {
135 $dbtype .= '(' . $xmldb_length;
136 if (!empty($xmldb_decimals)) {
137 $dbtype .= ',' . $xmldb_decimals;
138 }
139 $dbtype .= ')';
140 }
141 break;
142 case XMLDB_TYPE_FLOAT:
143 $dbtype = 'NUMBER';
144 break;
145 case XMLDB_TYPE_CHAR:
146 $dbtype = 'VARCHAR2';
147 if (empty($xmldb_length)) {
148 $xmldb_length='255';
149 }
150 $dbtype .= '(' . $xmldb_length . ')';
151 break;
152 case XMLDB_TYPE_TEXT:
153 $dbtype = 'CLOB';
154 break;
155 case XMLDB_TYPE_BINARY:
156 $dbtype = 'BLOB';
157 break;
158 case XMLDB_TYPE_DATETIME:
159 $dbtype = 'DATE';
160 break;
161 }
162 return $dbtype;
163 }
164
d7444bfc 165 /**
166 * Returns the code needed to create one sequence for the xmldb_table and xmldb_field passes
167 */
f33e1ed4 168 public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
d7444bfc 169
20c559dd 170 $results = array();
171
465a8029 172 $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
eef868d1 173
465a8029 174 $sequence = "CREATE SEQUENCE " . $sequence_name;
d7444bfc 175 $sequence.= "\n START WITH 1";
176 $sequence.= "\n INCREMENT BY 1";
9dcc6300 177 $sequence.= "\n NOMAXVALUE";
d7444bfc 178
20c559dd 179 $results[] = $sequence;
180
181 $results = array_merge($results, $this->getCreateTriggerSQL ($xmldb_table, $xmldb_field));
182
183 return $results;
184 }
185
186 /**
187 * Returns the code needed to create one trigger for the xmldb_table and xmldb_field passed
188 */
f33e1ed4 189 public function getCreateTriggerSQL($xmldb_table, $xmldb_field) {
20c559dd 190
d7444bfc 191 $trigger_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'trg');
20c559dd 192 $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
eef868d1 193
1d5071a5 194 $trigger = "CREATE TRIGGER " . $trigger_name;
d7444bfc 195 $trigger.= "\n BEFORE INSERT";
9af19c72 196 $trigger.= "\nON " . $this->getTableName($xmldb_table);
d7444bfc 197 $trigger.= "\n FOR EACH ROW";
198 $trigger.= "\nBEGIN";
4782a1f8 199 $trigger.= "\n IF :new." . $this->getEncQuoted($xmldb_field->getName()) . ' IS NULL THEN';
b8851b80 200 $trigger.= "\n SELECT " . $sequence_name . '.nextval INTO :new.' . $this->getEncQuoted($xmldb_field->getName()) . " FROM dual;";
201 $trigger.= "\n END IF;";
0513f3bf 202 $trigger.= "\nEND;";
20c559dd 203
204 return array($trigger);
d7444bfc 205 }
206
3a8c55c3 207 /**
208 * Returns the code needed to drop one sequence for the xmldb_table and xmldb_field passed
209 * Can, optionally, specify if the underlying trigger will be also dropped
210 */
f33e1ed4 211 public function getDropSequenceSQL($xmldb_table, $xmldb_field, $include_trigger=false) {
3a8c55c3 212
2d2d79ef 213 $result = array();
eef868d1 214
2d2d79ef 215 if ($sequence_name = $this->getSequenceFromDB($xmldb_table)) {
216 $result[] = "DROP SEQUENCE " . $sequence_name;
217 }
3a8c55c3 218
2d2d79ef 219 if ($trigger_name = $this->getTriggerFromDB($xmldb_table) && $include_trigger) {
220 $result[] = "DROP TRIGGER " . $trigger_name;
3a8c55c3 221 }
2d2d79ef 222
3a8c55c3 223 return $result;
224 }
225
226 /**
227 * Returns the code (in array) needed to add one comment to the table
228 */
229 function getCommentSQL ($xmldb_table) {
230
9af19c72 231 $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
f33e1ed4 232 $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
d7444bfc 233
3a8c55c3 234 return array($comment);
235 }
d7444bfc 236
3a8c55c3 237 /**
238 * Returns the code (array of statements) needed to execute extra statements on table drop
239 */
f33e1ed4 240 public function getDropTableExtraSQL($xmldb_table) {
a8cb94f6 241 $xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
3a8c55c3 242 return $this->getDropSequenceSQL($xmldb_table, $xmldb_field, false);
243 }
d7444bfc 244
20c559dd 245 /**
246 * Returns the code (array of statements) needed to execute extra statements on table rename
247 */
f33e1ed4 248 public function getRenameTableExtraSQL($xmldb_table, $newname) {
20c559dd 249
250 $results = array();
251
a8cb94f6 252 $xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
20c559dd 253
5a08ca80 254 $oldseqname = $this->getSequenceFromDB($xmldb_table);
20c559dd 255 $newseqname = $this->getNameForObject($newname, $xmldb_field->getName(), 'seq');
256
257 /// Rename de sequence
258 $results[] = 'RENAME ' . $oldseqname . ' TO ' . $newseqname;
259
5a08ca80 260 $oldtriggername = $this->getTriggerFromDB($xmldb_table);
20c559dd 261 $newtriggername = $this->getNameForObject($newname, $xmldb_field->getName(), 'trg');
262
263 /// Drop old trigger
264 $results[] = "DROP TRIGGER " . $oldtriggername;
265
a8cb94f6 266 $newt = new xmldb_table($newname); /// Temp table for trigger code generation
20c559dd 267
268 /// Create new trigger
bb7e5c47 269 $results = array_merge($results, $this->getCreateTriggerSQL($newt, $xmldb_field));
270
271 /// Rename all the check constraints in the table
272 $oldtablename = $this->getTableName($xmldb_table);
273 $newtablename = $this->getTableName($newt);
274
275 $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
276 $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
277
278 if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
279 foreach ($constraints as $constraint) {
280 /// Drop the old constraint
281 $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
bb7e5c47 282 }
283 }
20c559dd 284
285 return $results;
286 }
287
19c8321e 288 /**
a8cb94f6 289 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to alter the field in the table
19c8321e 290 * Oracle has some severe limits:
291 * - clob and blob fields doesn't allow type to be specified
292 * - error is dropped if the null/not null clause is specified and hasn't changed
11b75afe 293 * - changes in precision/decimals of numeric fields drop an ORA-1440 error
19c8321e 294 */
4d3e94b4 295 public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
19c8321e 296
4d3e94b4 297 $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause;
298 $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause;
299 $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause;
11b75afe 300
301 $results = array(); /// To store all the needed SQL commands
302
303 /// Get the quoted name of the table and field
9af19c72 304 $tablename = $this->getTableName($xmldb_table);
ed55f668 305 $fieldname = $xmldb_field->getName();
11b75afe 306
307 /// Take a look to field metadata
0b2e23c4 308 $meta = $this->mdb->get_columns($xmldb_table->getName(), false);
11b75afe 309 $metac = $meta[$fieldname];
f33e1ed4 310 $oldmetatype = $metac->meta_type;
311
11b75afe 312 $oldlength = $metac->max_length;
313 /// To calculate the oldlength if the field is numeric, we need to perform one extra query
314 /// because ADOdb has one bug here. http://phplens.com/lens/lensforum/msgs.php?id=15883
315 if ($oldmetatype == 'N') {
316 $uppertablename = strtoupper($tablename);
317 $upperfieldname = strtoupper($fieldname);
245ac557 318 if ($col = $this->mdb->get_record_sql("SELECT cname, precision
319 FROM col
320 WHERE tname = ? AND cname = ?",
321 array($uppertablename, $upperfieldname))) {
11b75afe 322 $oldlength = $col->precision;
323 }
324 }
325 $olddecimals = empty($metac->scale) ? null : $metac->scale;
326 $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
812e363a 327 $olddefault = empty($metac->default_value) || strtoupper($metac->default_value) == 'NULL' ? null : $metac->default_value;
11b75afe 328
329 $typechanged = true; //By default, assume that the column type has changed
330 $precisionchanged = true; //By default, assume that the column precision has changed
331 $decimalchanged = true; //By default, assume that the column decimal has changed
332 $defaultchanged = true; //By default, assume that the column default has changed
333 $notnullchanged = true; //By default, assume that the column notnull has changed
334
335 $from_temp_fields = false; //By default don't assume we are going to use temporal fields
336
337 /// Detect if we are changing the type of the column
f33e1ed4 338 if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
11b75afe 339 ($xmldb_field->getType() == XMLDB_TYPE_NUMBER && $oldmetatype == 'N') ||
340 ($xmldb_field->getType() == XMLDB_TYPE_FLOAT && $oldmetatype == 'F') ||
f33e1ed4 341 ($xmldb_field->getType() == XMLDB_TYPE_CHAR && $oldmetatype == 'C') ||
342 ($xmldb_field->getType() == XMLDB_TYPE_TEXT && $oldmetatype == 'X') ||
11b75afe 343 ($xmldb_field->getType() == XMLDB_TYPE_BINARY && $oldmetatype == 'B')) {
344 $typechanged = false;
f33e1ed4 345 }
11b75afe 346 /// Detect if precision has changed
347 if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
348 ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
349 ($oldlength == -1) ||
350 ($xmldb_field->getLength() == $oldlength)) {
351 $precisionchanged = false;
352 }
353 /// Detect if decimal has changed
354 if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
355 ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
356 ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
357 ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
358 (!$xmldb_field->getDecimals()) ||
359 (!$olddecimals) ||
360 ($xmldb_field->getDecimals() == $olddecimals)) {
361 $decimalchanged = false;
362 }
363 /// Detect if we are changing the default
364 if (($xmldb_field->getDefault() === null && $olddefault === null) ||
365 ($xmldb_field->getDefault() === $olddefault) || //Check both equality and
366 ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) { //Equality with quotes because ADOdb returns the default with quotes
367 $defaultchanged = false;
368 }
812e363a 369
11b75afe 370 /// Detect if we are changing the nullability
371 if (($xmldb_field->getNotnull() === $oldnotnull)) {
372 $notnullchanged = false;
373 }
374
375 /// If type has changed or precision or decimal has changed and we are in one numeric field
376 /// - create one temp column with the new specs
377 /// - fill the new column with the values from the old one
378 /// - drop the old column
379 /// - rename the temp column to the original name
16a208f9 380 if (($typechanged) || (($oldmetatype == 'N' || $oldmetatype == 'I') && ($precisionchanged || $decimalchanged))) {
11b75afe 381 $tempcolname = $xmldb_field->getName() . '_alter_column_tmp';
382 /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
4d3e94b4 383 $skip_notnull_clause = true;
384 $skip_default_clause = true;
11b75afe 385 $xmldb_field->setName($tempcolname);
386 /// Create the temporal column
4d3e94b4 387 $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_type_clause, $skip_notnull_clause));
11b75afe 388 /// Copy contents from original col to the temporal one
389 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $fieldname;
390 /// Drop the old column
391 $xmldb_field->setName($fieldname); //Set back the original field name
392 $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
393 /// Rename the temp column to the original one
394 $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
395 /// Mark we have performed one change based in temp fields
396 $from_temp_fields = true;
397 /// Re-enable the notnull and default sections so the general AlterFieldSQL can use it
4d3e94b4 398 $skip_notnull_clause = false;
399 $skip_default_clause = false;
812e363a 400 /// Dissable the type section because we have done it with the temp field
4d3e94b4 401 $skip_type_clause = true;
599caff8 402 /// If new field is nullable, nullability hasn't changed
403 if (!$xmldb_field->getNotnull()) {
404 $notnullchanged = false;
405 }
406 /// If new field hasn't default, default hasn't changed
407 if ($xmldb_field->getDefault() === null) {
408 $defaultchanged = false;
409 }
11b75afe 410 }
411
412 /// If type and precision and decimals hasn't changed, prevent the type clause
413 if (!$typechanged && !$precisionchanged && !$decimalchanged) {
4d3e94b4 414 $skip_type_clause = true;
11b75afe 415 }
416
417 /// If NULL/NOT NULL hasn't changed
418 /// prevent null clause to be specified
419 if (!$notnullchanged) {
4d3e94b4 420 $skip_notnull_clause = true; /// Initially, prevent the notnull clause
11b75afe 421 /// But, if we have used the temp field and the new field is not null, then enforce the not null clause
422 if ($from_temp_fields && $xmldb_field->getNotnull()) {
4d3e94b4 423 $skip_notnull_clause = false;
11b75afe 424 }
425 }
426 /// If default hasn't changed
427 /// prevent default clause to be specified
428 if (!$defaultchanged) {
4d3e94b4 429 $skip_default_clause = true; /// Initially, prevent the default clause
11b75afe 430 /// But, if we have used the temp field and the new field has default clause, then enforce the default clause
f33e1ed4 431 if ($from_temp_fields) {
432 $default_clause = $this->getDefaultClause($xmldb_field);
433 if ($default_clause) {
4d3e94b4 434 $skip_notnull_clause = false;
f33e1ed4 435 }
11b75afe 436 }
437 }
438
439 /// If arriving here, something is not being skiped (type, notnull, default), calculate the standar AlterFieldSQL
4d3e94b4 440 if (!$skip_type_clause || !$skip_notnull_clause || !$skip_default_clause) {
441 $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_default_clause, $skip_notnull_clause));
11b75afe 442 return $results;
443 }
444
445 /// Finally return results
446 return $results;
19c8321e 447 }
448
f33e1ed4 449 /**
a8cb94f6 450 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to drop its enum
b899d9bf 451 * (usually invoked from getModifyEnumSQL()
2d2d79ef 452 *
453 * TODO: Moodle 2.1 - drop in Moodle 2.1
f33e1ed4 454 */
455 public function getDropEnumSQL($xmldb_table, $xmldb_field) {
3d74e77a 456 /// Let's introspect to know the real name of the check constraint
457 if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
458 $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
459 $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
460 /// All we have to do is to drop the check constraint
f33e1ed4 461 return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
3d74e77a 462 ' DROP CONSTRAINT ' . $constraint_name);
463 } else { /// Constraint not found. Nothing to do
464 return array();
465 }
f33e1ed4 466 }
b899d9bf 467
812e363a 468 /**
a8cb94f6 469 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to create its default
812e363a 470 * (usually invoked from getModifyDefaultSQL()
471 */
f33e1ed4 472 public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
812e363a 473 /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
474 /// is capable of handling defaults
475 return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
476 }
f33e1ed4 477
478 /**
a8cb94f6 479 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to drop its default
812e363a 480 * (usually invoked from getModifyDefaultSQL()
f33e1ed4 481 */
482 public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
812e363a 483 /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
484 /// is capable of handling defaults
485 return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
f33e1ed4 486 }
812e363a 487
bb7e5c47 488 /**
a8cb94f6 489 * Given one xmldb_table returns one array with all the check constrainsts
bb7e5c47 490 * in the table (fetched from DB)
4215e41e 491 * Optionally the function allows one xmldb_field to be specified in
492 * order to return only the check constraints belonging to one field.
bb7e5c47 493 * Each element contains the name of the constraint and its description
494 * If no check constraints are found, returns an empty array
2d2d79ef 495 *
496 * TODO: Moodle 2.1 - drop in Moodle 2.1
bb7e5c47 497 */
f33e1ed4 498 public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
bb7e5c47 499
500 $results = array();
501
502 $tablename = strtoupper($this->getTableName($xmldb_table));
503
245ac557 504 if ($constraints = $this->mdb->get_records_sql("SELECT lower(c.constraint_name) AS name, c.search_condition AS description
505 FROM user_constraints c
506 WHERE c.table_name = ?
507 AND c.constraint_type = 'C'
508 AND c.constraint_name not like 'SYS%'",
509 array($tablename))) {
bb7e5c47 510 foreach ($constraints as $constraint) {
511 $results[$constraint->name] = $constraint;
512 }
513 }
514
a347e5e4 515 /// Filter by the required field if specified
516 if ($xmldb_field) {
faa1a939 517 $filtered_results = array();
a347e5e4 518 $filter = $xmldb_field->getName();
faa1a939 519 /// Lets clean a bit each constraint description, looking for the filtered field
520 foreach ($results as $key => $result) {
521 /// description starts by "$filter IN" assume it's a constraint beloging to the field
522 if (preg_match("/^{$filter} IN/i", $result->description)) {
523 $filtered_results[$key] = $result;
524 }
525 }
526 /// Assign filtered results to the final results array
527 $results = $filtered_results;
a347e5e4 528 }
529
bb7e5c47 530 return $results;
531 }
532
abbd460f 533 /**
a8cb94f6 534 * Given one xmldb_table returns one string with the sequence of the table
abbd460f 535 * in the table (fetched from DB)
536 * The sequence name for oracle is calculated by looking the corresponding
537 * trigger and retrieving the sequence name from it (because sequences are
538 * independent elements)
539 * If no sequence is found, returns false
540 */
f33e1ed4 541 public function getSequenceFromDB($xmldb_table) {
abbd460f 542
926c6aa9 543 $tablename = strtoupper($this->getTableName($xmldb_table));
544 $prefixupper = strtoupper($this->prefix);
abbd460f 545 $sequencename = false;
546
245ac557 547 if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
548 FROM user_triggers
549 WHERE table_name = ? AND trigger_name LIKE ?",
550 array($tablename, "{$prefixupper}%_ID%_TRG"))) {
abbd460f 551 /// If trigger found, regexp it looking for the sequence name
552 preg_match('/.*SELECT (.*)\.nextval/i', $trigger->trigger_body, $matches);
553 if (isset($matches[1])) {
554 $sequencename = $matches[1];
555 }
556 }
557
558 return $sequencename;
559 }
560
5a08ca80 561 /**
a8cb94f6 562 * Given one xmldb_table returns one string with the trigger
5a08ca80 563 * in the table (fetched from DB)
564 * If no trigger is found, returns false
565 */
f33e1ed4 566 public function getTriggerFromDB($xmldb_table) {
5a08ca80 567
926c6aa9 568 $tablename = strtoupper($this->getTableName($xmldb_table));
569 $prefixupper = strtoupper($this->prefix);
5a08ca80 570 $triggername = false;
571
245ac557 572 if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
573 FROM user_triggers
574 WHERE table_name = ? AND trigger_name LIKE ?",
575 array($tablename, "{$prefixupper}%_ID%_TRG"))) {
5a08ca80 576 $triggername = $trigger->trigger_name;
577 }
578
579 return $triggername;
580 }
581
6210ae1d 582 /**
583 * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
584 * return if such name is currently in use (true) or no (false)
585 * (invoked from getNameForObject()
586 */
f33e1ed4 587 public function isNameInUse($object_name, $type, $table_name) {
6210ae1d 588 switch($type) {
589 case 'ix':
590 case 'uix':
591 case 'seq':
592 case 'trg':
245ac557 593 if ($check = $this->mdb->get_records_sql("SELECT object_name
594 FROM user_objects
595 WHERE lower(object_name) = ?", array(strtolower($object_name)))) {
6210ae1d 596 return true;
597 }
598 break;
599 case 'pk':
600 case 'uk':
601 case 'fk':
602 case 'ck':
245ac557 603 if ($check = $this->mdb->get_records_sql("SELECT constraint_name
604 FROM user_constraints
605 WHERE lower(constraint_name) = ?", array(strtolower($object_name)))) {
6210ae1d 606 return true;
607 }
608 break;
609 }
610 return false; //No name in use found
611 }
612
f33e1ed4 613 public function addslashes($s) {
614 // do not use php addslashes() because it depends on PHP quote settings!
615 $s = str_replace("'", "''", $s);
616 return $s;
617 }
618
d7444bfc 619 /**
620 * Returns an array of reserved words (lowercase) for this DB
621 */
f33e1ed4 622 public static function getReservedWords() {
6aa7885e 623 /// This file contains the reserved words for Oracle databases
624 /// from http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/ap_keywd.htm
d7444bfc 625 $reserved_words = array (
626 'access', 'add', 'all', 'alter', 'and', 'any',
627 'as', 'asc', 'audit', 'between', 'by', 'char',
628 'check', 'cluster', 'column', 'comment',
629 'compress', 'connect', 'create', 'current',
630 'date', 'decimal', 'default', 'delete', 'desc',
631 'distinct', 'drop', 'else', 'exclusive', 'exists',
632 'file', 'float', 'for', 'from', 'grant', 'group',
633 'having', 'identified', 'immediate', 'in',
634 'increment', 'index', 'initial', 'insert',
635 'integer', 'intersect', 'into', 'is', 'level',
636 'like', 'lock', 'long', 'maxextents', 'minus',
637 'mlslabel', 'mode', 'modify', 'noaudit',
638 'nocompress', 'not', 'nowait', 'null', 'number',
639 'of', 'offline', 'on', 'online', 'option', 'or',
640 'order', 'pctfree', 'prior', 'privileges',
641 'public', 'raw', 'rename', 'resource', 'revoke',
642 'row', 'rowid', 'rownum', 'rows', 'select',
643 'session', 'set', 'share', 'size', 'smallint',
644 'start', 'successful', 'synonym', 'sysdate',
645 'table', 'then', 'to', 'trigger', 'uid', 'union',
646 'unique', 'update', 'user', 'validate', 'values',
647 'varchar', 'varchar2', 'view', 'whenever',
648 'where', 'with'
eef868d1 649 );
d7444bfc 650 return $reserved_words;
651 }
652}
653
654?>