3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
20 * Oracle specific SQL code generator.
24 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
25 * 2001-3001 Eloy Lafuente (stronk7) http://contiento.com
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 require_once($CFG->libdir.'/ddl/sql_generator.php');
31 /// This class generate SQL code to be used against Oracle
32 /// It extends XMLDBgenerator so everything can be
33 /// overriden as needed to generate correct SQL.
35 class oracle_sql_generator extends sql_generator {
37 /// Only set values that are different from the defaults present in XMLDBgenerator
39 public $statement_end = "\n/"; // String to be automatically added at the end of each statement
40 // Using "/" because the standard ";" isn't good for stored procedures (triggers)
42 public $number_type = 'NUMBER'; // Proper type for NUMBER(x) in this DB
44 public $unsigned_allowed = false; // To define in the generator must handle unsigned information
45 public $default_for_char = ' '; // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
46 // Using this whitespace here because Oracle doesn't distinguish empty and null! :-(
48 public $drop_default_value_required = true; //To specify if the generator must use some DEFAULT clause to drop defaults
49 public $drop_default_value = NULL; //The DEFAULT clause required to drop defaults
51 public $default_after_null = false; //To decide if the default clause of each field must go after the null clause
53 public $sequence_extra_code = true; //Does the generator need to add extra code to generate the sequence fields
54 public $sequence_name = ''; //Particular name for inline sequences in this generator
55 public $sequence_cache_size = 20; //Size of the sequences values cache (20 = Oracle Default)
57 public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
59 public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY (COLUMNSPECS)'; //The SQL template to alter columns
61 private $temptables; // Control existing temptables (oci_native_moodle_temptables object)
64 * Creates one new XMLDBoci8po
66 public function __construct($mdb, $temptables = null) {
67 $this->temptables = $temptables;
68 parent::__construct($mdb);
72 * Reset a sequence to the id field of a table.
73 * @param string $table name of table or xmldb_table object
74 * @return array sql commands to execute
76 public function getResetSequenceSQL($table) {
78 if (is_string($table)) {
80 $xmldb_table = new xmldb_table($tablename);
82 $tablename = $table->getName();
83 $xmldb_table = $table;
85 // From http://www.acs.ilstu.edu/docs/oracle/server.101/b10759/statements_2011.htm
86 $value = (int)$this->mdb->get_field_sql('SELECT MAX(id) FROM {'.$tablename.'}');
89 $seqname = $this->getSequenceFromDB($xmldb_table);
92 /// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method
93 $seqname = $this->getNameForObject($table, 'id', 'seq');
96 return array ("DROP SEQUENCE $seqname",
97 "CREATE SEQUENCE $seqname START WITH $value INCREMENT BY 1 NOMAXVALUE CACHE $this->sequence_cache_size");
101 * Given one xmldb_table, returns it's correct name, depending of all the parametrization
102 * Overriden to allow change of names in temp tables
104 * @param xmldb_table table whose name we want
105 * @param boolean to specify if the name must be quoted (if reserved word, only!)
106 * @return string the correct name of the table
108 public function getTableName(xmldb_table $xmldb_table, $quoted=true) {
109 /// Get the name, supporting special oci names for temp tables
110 if ($this->temptables->is_temptable($xmldb_table->getName())) {
111 $tablename = $this->temptables->get_correct_name($xmldb_table->getName());
113 $tablename = $this->prefix . $xmldb_table->getName();
116 /// Apply quotes optionally
118 $tablename = $this->getEncQuoted($tablename);
125 * Given one correct xmldb_table, returns the SQL statements
126 * to create temporary table (inside one array)
128 public function getCreateTempTableSQL($xmldb_table) {
129 $this->temptables->add_temptable($xmldb_table->getName());
130 $sqlarr = $this->getCreateTableSQL($xmldb_table);
131 $sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE GLOBAL TEMPORARY TABLE $1 ON COMMIT PRESERVE ROWS', $sqlarr);
136 * Given one correct xmldb_table and the new name, returns the SQL statements
137 * to drop it (inside one array)
139 public function getDropTempTableSQL($xmldb_table) {
140 $sqlarr = $this->getDropTableSQL($xmldb_table);
141 array_unshift($sqlarr, "TRUNCATE TABLE ". $this->getTableName($xmldb_table)); // oracle requires truncate before being able to drop a temp table
142 $this->temptables->delete_temptable($xmldb_table->getName());
147 * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
149 public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
151 switch ($xmldb_type) {
152 case XMLDB_TYPE_INTEGER: // From http://www.postgresql.org/docs/7.4/interactive/datatype.html
153 if (empty($xmldb_length)) {
156 $dbtype = 'NUMBER(' . $xmldb_length . ')';
158 case XMLDB_TYPE_FLOAT:
159 case XMLDB_TYPE_NUMBER:
160 $dbtype = $this->number_type;
161 /// 38 is the max allowed
162 if ($xmldb_length > 38) {
165 if (!empty($xmldb_length)) {
166 $dbtype .= '(' . $xmldb_length;
167 if (!empty($xmldb_decimals)) {
168 $dbtype .= ',' . $xmldb_decimals;
173 case XMLDB_TYPE_CHAR:
174 $dbtype = 'VARCHAR2';
175 if (empty($xmldb_length)) {
178 $dbtype .= '(' . $xmldb_length . ')';
180 case XMLDB_TYPE_TEXT:
183 case XMLDB_TYPE_BINARY:
186 case XMLDB_TYPE_DATETIME:
194 * Returns the code needed to create one sequence for the xmldb_table and xmldb_field passes
196 public function getCreateSequenceSQL($xmldb_table, $xmldb_field) {
200 $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
202 $sequence = "CREATE SEQUENCE $sequence_name START WITH 1 INCREMENT BY 1 NOMAXVALUE CACHE $this->sequence_cache_size";
204 $results[] = $sequence;
206 $results = array_merge($results, $this->getCreateTriggerSQL ($xmldb_table, $xmldb_field));
212 * Returns the code needed to create one trigger for the xmldb_table and xmldb_field passed
214 public function getCreateTriggerSQL($xmldb_table, $xmldb_field) {
216 $trigger_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'trg');
217 $sequence_name = $this->getNameForObject($xmldb_table->getName(), $xmldb_field->getName(), 'seq');
219 $trigger = "CREATE TRIGGER " . $trigger_name;
220 $trigger.= "\n BEFORE INSERT";
221 $trigger.= "\nON " . $this->getTableName($xmldb_table);
222 $trigger.= "\n FOR EACH ROW";
223 $trigger.= "\nBEGIN";
224 $trigger.= "\n IF :new." . $this->getEncQuoted($xmldb_field->getName()) . ' IS NULL THEN';
225 $trigger.= "\n SELECT " . $sequence_name . '.nextval INTO :new.' . $this->getEncQuoted($xmldb_field->getName()) . " FROM dual;";
226 $trigger.= "\n END IF;";
229 return array($trigger);
233 * Returns the code needed to drop one sequence for the xmldb_table and xmldb_field passed
234 * Can, optionally, specify if the underlying trigger will be also dropped
236 public function getDropSequenceSQL($xmldb_table, $xmldb_field, $include_trigger=false) {
240 if ($sequence_name = $this->getSequenceFromDB($xmldb_table)) {
241 $result[] = "DROP SEQUENCE " . $sequence_name;
244 if ($trigger_name = $this->getTriggerFromDB($xmldb_table) && $include_trigger) {
245 $result[] = "DROP TRIGGER " . $trigger_name;
252 * Returns the code (in array) needed to add one comment to the table
254 function getCommentSQL ($xmldb_table) {
256 $comment = "COMMENT ON TABLE " . $this->getTableName($xmldb_table);
257 $comment.= " IS '" . $this->addslashes(substr($xmldb_table->getComment(), 0, 250)) . "'";
259 return array($comment);
263 * Returns the code (array of statements) needed to execute extra statements on table drop
265 public function getDropTableExtraSQL($xmldb_table) {
266 $xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
267 return $this->getDropSequenceSQL($xmldb_table, $xmldb_field, false);
271 * Returns the code (array of statements) needed to execute extra statements on table rename
273 public function getRenameTableExtraSQL($xmldb_table, $newname) {
277 $xmldb_field = new xmldb_field('id'); // Fields having sequences should be exclusively, id.
279 $oldseqname = $this->getSequenceFromDB($xmldb_table);
280 $newseqname = $this->getNameForObject($newname, $xmldb_field->getName(), 'seq');
282 $oldtriggername = $this->getTriggerFromDB($xmldb_table);
283 $newtriggername = $this->getNameForObject($newname, $xmldb_field->getName(), 'trg');
285 /// Drop old trigger (first of all)
286 $results[] = "DROP TRIGGER " . $oldtriggername;
288 /// Rename the sequence, disablig CACHE before and enablig it later
289 /// to avoid consuming of values on rename
290 $results[] = 'ALTER SEQUENCE ' . $oldseqname . ' NOCACHE';
291 $results[] = 'RENAME ' . $oldseqname . ' TO ' . $newseqname;
292 $results[] = 'ALTER SEQUENCE ' . $newseqname . ' CACHE ' . $this->sequence_cache_size;
294 /// Create new trigger
295 $newt = new xmldb_table($newname); /// Temp table for trigger code generation
296 $results = array_merge($results, $this->getCreateTriggerSQL($newt, $xmldb_field));
298 /// Rename all the check constraints in the table
299 $oldtablename = $this->getTableName($xmldb_table);
300 $newtablename = $this->getTableName($newt);
302 $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
303 $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
305 if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
306 foreach ($constraints as $constraint) {
307 /// Drop the old constraint
308 $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
316 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to alter the field in the table
317 * Oracle has some severe limits:
318 * - clob and blob fields doesn't allow type to be specified
319 * - error is dropped if the null/not null clause is specified and hasn't changed
320 * - changes in precision/decimals of numeric fields drop an ORA-1440 error
322 public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
324 $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause;
325 $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause;
326 $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause;
328 $results = array(); /// To store all the needed SQL commands
330 /// Get the quoted name of the table and field
331 $tablename = $this->getTableName($xmldb_table);
332 $fieldname = $xmldb_field->getName();
334 /// Take a look to field metadata
335 $meta = $this->mdb->get_columns($xmldb_table->getName());
336 $metac = $meta[$fieldname];
337 $oldmetatype = $metac->meta_type;
339 $oldlength = $metac->max_length;
340 /// To calculate the oldlength if the field is numeric, we need to perform one extra query
341 /// because ADOdb has one bug here. http://phplens.com/lens/lensforum/msgs.php?id=15883
342 if ($oldmetatype == 'N') {
343 $uppertablename = strtoupper($tablename);
344 $upperfieldname = strtoupper($fieldname);
345 if ($col = $this->mdb->get_record_sql("SELECT cname, precision
347 WHERE tname = ? AND cname = ?",
348 array($uppertablename, $upperfieldname))) {
349 $oldlength = $col->precision;
352 $olddecimals = empty($metac->scale) ? null : $metac->scale;
353 $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
354 $olddefault = empty($metac->default_value) || strtoupper($metac->default_value) == 'NULL' ? null : $metac->default_value;
356 $typechanged = true; //By default, assume that the column type has changed
357 $precisionchanged = true; //By default, assume that the column precision has changed
358 $decimalchanged = true; //By default, assume that the column decimal has changed
359 $defaultchanged = true; //By default, assume that the column default has changed
360 $notnullchanged = true; //By default, assume that the column notnull has changed
362 $from_temp_fields = false; //By default don't assume we are going to use temporal fields
364 /// Detect if we are changing the type of the column
365 if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
366 ($xmldb_field->getType() == XMLDB_TYPE_NUMBER && $oldmetatype == 'N') ||
367 ($xmldb_field->getType() == XMLDB_TYPE_FLOAT && $oldmetatype == 'F') ||
368 ($xmldb_field->getType() == XMLDB_TYPE_CHAR && $oldmetatype == 'C') ||
369 ($xmldb_field->getType() == XMLDB_TYPE_TEXT && $oldmetatype == 'X') ||
370 ($xmldb_field->getType() == XMLDB_TYPE_BINARY && $oldmetatype == 'B')) {
371 $typechanged = false;
373 /// Detect if precision has changed
374 if (($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
375 ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
376 ($oldlength == -1) ||
377 ($xmldb_field->getLength() == $oldlength)) {
378 $precisionchanged = false;
380 /// Detect if decimal has changed
381 if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER) ||
382 ($xmldb_field->getType() == XMLDB_TYPE_CHAR) ||
383 ($xmldb_field->getType() == XMLDB_TYPE_TEXT) ||
384 ($xmldb_field->getType() == XMLDB_TYPE_BINARY) ||
385 (!$xmldb_field->getDecimals()) ||
387 ($xmldb_field->getDecimals() == $olddecimals)) {
388 $decimalchanged = false;
390 /// Detect if we are changing the default
391 if (($xmldb_field->getDefault() === null && $olddefault === null) ||
392 ($xmldb_field->getDefault() === $olddefault) || //Check both equality and
393 ("'" . $xmldb_field->getDefault() . "'" === $olddefault)) { //Equality with quotes because ADOdb returns the default with quotes
394 $defaultchanged = false;
397 /// Detect if we are changing the nullability
398 if (($xmldb_field->getNotnull() === $oldnotnull)) {
399 $notnullchanged = false;
402 /// If type has changed or precision or decimal has changed and we are in one numeric field
403 /// - create one temp column with the new specs
404 /// - fill the new column with the values from the old one
405 /// - drop the old column
406 /// - rename the temp column to the original name
407 if (($typechanged) || (($oldmetatype == 'N' || $oldmetatype == 'I') && ($precisionchanged || $decimalchanged))) {
408 $tempcolname = $xmldb_field->getName() . '_alter_column_tmp';
409 /// Prevent temp field to have both NULL/NOT NULL and DEFAULT constraints
410 $skip_notnull_clause = true;
411 $skip_default_clause = true;
412 $xmldb_field->setName($tempcolname);
413 // Drop the temp column, in case it exists (due to one previous failure in conversion)
414 // really ugly but we cannot enclose DDL into transaction :-(
415 if (isset($meta[$tempcolname])) {
416 $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
418 /// Create the temporal column
419 $results = array_merge($results, $this->getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_type_clause, $skip_notnull_clause));
420 /// Copy contents from original col to the temporal one
422 // From TEXT to integer/number we need explicit conversion
423 if ($oldmetatype == 'X' && $xmldb_field->GetType() == XMLDB_TYPE_INTEGER) {
424 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = CAST(' . $this->mdb->sql_compare_text($fieldname) . ' AS INT)';
425 } else if ($oldmetatype == 'X' && $xmldb_field->GetType() == XMLDB_TYPE_NUMBER) {
426 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = CAST(' . $this->mdb->sql_compare_text($fieldname) . ' AS NUMBER)';
428 // Normal cases, implicit conversion
430 $results[] = 'UPDATE ' . $tablename . ' SET ' . $tempcolname . ' = ' . $fieldname;
432 /// Drop the old column
433 $xmldb_field->setName($fieldname); //Set back the original field name
434 $results = array_merge($results, $this->getDropFieldSQL($xmldb_table, $xmldb_field));
435 /// Rename the temp column to the original one
436 $results[] = 'ALTER TABLE ' . $tablename . ' RENAME COLUMN ' . $tempcolname . ' TO ' . $fieldname;
437 /// Mark we have performed one change based in temp fields
438 $from_temp_fields = true;
439 /// Re-enable the notnull and default sections so the general AlterFieldSQL can use it
440 $skip_notnull_clause = false;
441 $skip_default_clause = false;
442 /// Dissable the type section because we have done it with the temp field
443 $skip_type_clause = true;
444 /// If new field is nullable, nullability hasn't changed
445 if (!$xmldb_field->getNotnull()) {
446 $notnullchanged = false;
448 /// If new field hasn't default, default hasn't changed
449 if ($xmldb_field->getDefault() === null) {
450 $defaultchanged = false;
454 /// If type and precision and decimals hasn't changed, prevent the type clause
455 if (!$typechanged && !$precisionchanged && !$decimalchanged) {
456 $skip_type_clause = true;
459 /// If NULL/NOT NULL hasn't changed
460 /// prevent null clause to be specified
461 if (!$notnullchanged) {
462 $skip_notnull_clause = true; /// Initially, prevent the notnull clause
463 /// But, if we have used the temp field and the new field is not null, then enforce the not null clause
464 if ($from_temp_fields && $xmldb_field->getNotnull()) {
465 $skip_notnull_clause = false;
468 /// If default hasn't changed
469 /// prevent default clause to be specified
470 if (!$defaultchanged) {
471 $skip_default_clause = true; /// Initially, prevent the default clause
472 /// But, if we have used the temp field and the new field has default clause, then enforce the default clause
473 if ($from_temp_fields) {
474 $default_clause = $this->getDefaultClause($xmldb_field);
475 if ($default_clause) {
476 $skip_notnull_clause = false;
481 /// If arriving here, something is not being skiped (type, notnull, default), calculate the standar AlterFieldSQL
482 if (!$skip_type_clause || !$skip_notnull_clause || !$skip_default_clause) {
483 $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_default_clause, $skip_notnull_clause));
487 /// Finally return results
492 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to drop its enum
493 * (usually invoked from getModifyEnumSQL()
495 * TODO: Moodle 2.1 - drop in Moodle 2.1
497 public function getDropEnumSQL($xmldb_table, $xmldb_field) {
498 /// Let's introspect to know the real name of the check constraint
499 if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
500 $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
501 $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
502 /// All we have to do is to drop the check constraint
503 return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
504 ' DROP CONSTRAINT ' . $constraint_name);
505 } else { /// Constraint not found. Nothing to do
511 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to create its default
512 * (usually invoked from getModifyDefaultSQL()
514 public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
515 /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
516 /// is capable of handling defaults
517 return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
521 * Given one xmldb_table and one xmldb_field, return the SQL statements needded to drop its default
522 * (usually invoked from getModifyDefaultSQL()
524 public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
525 /// Just a wrapper over the getAlterFieldSQL() function for Oracle that
526 /// is capable of handling defaults
527 return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
531 * Given one xmldb_table returns one array with all the check constrainsts
532 * in the table (fetched from DB)
533 * Optionally the function allows one xmldb_field to be specified in
534 * order to return only the check constraints belonging to one field.
535 * Each element contains the name of the constraint and its description
536 * If no check constraints are found, returns an empty array
538 * TODO: Moodle 2.1 - drop in Moodle 2.1
540 public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
544 $tablename = strtoupper($this->getTableName($xmldb_table));
546 if ($constraints = $this->mdb->get_records_sql("SELECT lower(c.constraint_name) AS name, c.search_condition AS description
547 FROM user_constraints c
548 WHERE c.table_name = ?
549 AND c.constraint_type = 'C'
550 AND c.constraint_name not like 'SYS%'",
551 array($tablename))) {
552 foreach ($constraints as $constraint) {
553 $results[$constraint->name] = $constraint;
557 /// Filter by the required field if specified
559 $filtered_results = array();
560 $filter = $xmldb_field->getName();
561 /// Lets clean a bit each constraint description, looking for the filtered field
562 foreach ($results as $key => $result) {
563 /// description starts by "$filter IN" assume it's a constraint beloging to the field
564 if (preg_match("/^{$filter} IN/i", $result->description)) {
565 $filtered_results[$key] = $result;
568 /// Assign filtered results to the final results array
569 $results = $filtered_results;
576 * Given one xmldb_table returns one string with the sequence of the table
577 * in the table (fetched from DB)
578 * The sequence name for oracle is calculated by looking the corresponding
579 * trigger and retrieving the sequence name from it (because sequences are
580 * independent elements)
581 * If no sequence is found, returns false
583 public function getSequenceFromDB($xmldb_table) {
585 $tablename = strtoupper($this->getTableName($xmldb_table));
586 $prefixupper = strtoupper($this->prefix);
587 $sequencename = false;
589 if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
591 WHERE table_name = ? AND trigger_name LIKE ?",
592 array($tablename, "{$prefixupper}%_ID%_TRG"))) {
593 /// If trigger found, regexp it looking for the sequence name
594 preg_match('/.*SELECT (.*)\.nextval/i', $trigger->trigger_body, $matches);
595 if (isset($matches[1])) {
596 $sequencename = $matches[1];
600 return $sequencename;
604 * Given one xmldb_table returns one string with the trigger
605 * in the table (fetched from DB)
606 * If no trigger is found, returns false
608 public function getTriggerFromDB($xmldb_table) {
610 $tablename = strtoupper($this->getTableName($xmldb_table));
611 $prefixupper = strtoupper($this->prefix);
612 $triggername = false;
614 if ($trigger = $this->mdb->get_record_sql("SELECT trigger_name, trigger_body
616 WHERE table_name = ? AND trigger_name LIKE ?",
617 array($tablename, "{$prefixupper}%_ID%_TRG"))) {
618 $triggername = $trigger->trigger_name;
625 * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
626 * return if such name is currently in use (true) or no (false)
627 * (invoked from getNameForObject()
629 public function isNameInUse($object_name, $type, $table_name) {
635 if ($check = $this->mdb->get_records_sql("SELECT object_name
637 WHERE lower(object_name) = ?", array(strtolower($object_name)))) {
645 if ($check = $this->mdb->get_records_sql("SELECT constraint_name
646 FROM user_constraints
647 WHERE lower(constraint_name) = ?", array(strtolower($object_name)))) {
652 return false; //No name in use found
655 public function addslashes($s) {
656 // do not use php addslashes() because it depends on PHP quote settings!
657 $s = str_replace("'", "''", $s);
662 * Returns an array of reserved words (lowercase) for this DB
664 public static function getReservedWords() {
665 /// This file contains the reserved words for Oracle databases
666 /// from http://download-uk.oracle.com/docs/cd/B10501_01/server.920/a96540/ap_keywd.htm
667 $reserved_words = array (
668 'access', 'add', 'all', 'alter', 'and', 'any',
669 'as', 'asc', 'audit', 'between', 'by', 'char',
670 'check', 'cluster', 'column', 'comment',
671 'compress', 'connect', 'create', 'current',
672 'date', 'decimal', 'default', 'delete', 'desc',
673 'distinct', 'drop', 'else', 'exclusive', 'exists',
674 'file', 'float', 'for', 'from', 'grant', 'group',
675 'having', 'identified', 'immediate', 'in',
676 'increment', 'index', 'initial', 'insert',
677 'integer', 'intersect', 'into', 'is', 'level',
678 'like', 'lock', 'long', 'maxextents', 'minus',
679 'mlslabel', 'mode', 'modify', 'noaudit',
680 'nocompress', 'not', 'nowait', 'null', 'number',
681 'of', 'offline', 'on', 'online', 'option', 'or',
682 'order', 'pctfree', 'prior', 'privileges',
683 'public', 'raw', 'rename', 'resource', 'revoke',
684 'row', 'rowid', 'rownum', 'rows', 'select',
685 'session', 'set', 'share', 'size', 'smallint',
686 'start', 'successful', 'synonym', 'sysdate',
687 'table', 'then', 'to', 'trigger', 'uid', 'union',
688 'unique', 'update', 'user', 'validate', 'values',
689 'varchar', 'varchar2', 'view', 'whenever',
692 return $reserved_words;