|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00018 00033 defined('MOODLE_INTERNAL') || die(); 00034 00038 abstract class sql_generator { 00039 00044 00045 public $quote_string = '"'; // String used to quote names 00046 00047 public $statement_end = ';'; // String to be automatically added at the end of each statement 00048 00049 public $quote_all = false; // To decide if we want to quote all the names or only the reserved ones 00050 00051 public $integer_to_number = false; // To create all the integers as NUMBER(x) (also called DECIMAL, NUMERIC...) 00052 public $float_to_number = false; // To create all the floats as NUMBER(x) (also called DECIMAL, NUMERIC...) 00053 00054 public $number_type = 'NUMERIC'; // Proper type for NUMBER(x) in this DB 00055 00056 public $unsigned_allowed = true; // To define in the generator must handle unsigned information 00057 public $default_for_char = null; // To define the default to set for NOT NULLs CHARs without default (null=do nothing) 00058 00059 public $drop_default_value_required = false; //To specify if the generator must use some DEFAULT clause to drop defaults 00060 public $drop_default_value = ''; //The DEFAULT clause required to drop defaults 00061 00062 public $default_after_null = true; //To decide if the default clause of each field must go after the null clause 00063 00064 public $specify_nulls = false; //To force the generator if NULL clauses must be specified. It shouldn't be necessary 00065 //but some mssql drivers require them or everything is created as NOT NULL :-( 00066 00067 public $primary_key_name = null; //To force primary key names to one string (null=no force) 00068 00069 public $primary_keys = true; // Does the generator build primary keys 00070 public $unique_keys = false; // Does the generator build unique keys 00071 public $foreign_keys = false; // Does the generator build foreign keys 00072 00073 public $drop_primary_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop PKs 00074 // with automatic replace for TABLENAME and KEYNAME 00075 00076 public $drop_unique_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop UKs 00077 // with automatic replace for TABLENAME and KEYNAME 00078 00079 public $drop_foreign_key = 'ALTER TABLE TABLENAME DROP CONSTRAINT KEYNAME'; // Template to drop FKs 00080 // with automatic replace for TABLENAME and KEYNAME 00081 00082 public $sequence_extra_code = true; //Does the generator need to add extra code to generate the sequence fields 00083 public $sequence_name = 'auto_increment'; //Particular name for inline sequences in this generator 00084 public $sequence_name_small = false; //Different name for small (4byte) sequences or false if same 00085 public $sequence_only = false; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name publiciable 00086 00087 public $add_table_comments = true; // Does the generator need to add code for table comments 00088 00089 public $add_after_clause = false; // Does the generator need to add the after clause for fields 00090 00091 public $prefix_on_names = true; //Does the generator need to prepend the prefix to all the key/index/sequence/trigger/check names 00092 00093 public $names_max_length = 30; //Max length for key/index/sequence/trigger/check names (keep 30 for all!) 00094 00095 public $concat_character = '||'; //Characters to be used as concatenation operator. If not defined 00096 //MySQL CONCAT function will be used 00097 00098 public $rename_table_sql = 'ALTER TABLE OLDNAME RENAME TO NEWNAME'; //SQL sentence to rename one table, both 00099 //OLDNAME and NEWNAME are dynamically replaced 00100 00101 public $drop_table_sql = 'DROP TABLE TABLENAME'; //SQL sentence to drop one table 00102 //TABLENAME is dynamically replaced 00103 00104 public $alter_column_sql = 'ALTER TABLE TABLENAME ALTER COLUMN COLUMNSPECS'; //The SQL template to alter columns 00105 00106 public $alter_column_skip_default = false; //The generator will skip the default clause on alter columns 00107 00108 public $alter_column_skip_type = false; //The generator will skip the type clause on alter columns 00109 00110 public $alter_column_skip_notnull = false; //The generator will skip the null/notnull clause on alter columns 00111 00112 public $rename_column_sql = 'ALTER TABLE TABLENAME RENAME COLUMN OLDFIELDNAME TO NEWFIELDNAME'; 00114 00115 public $drop_index_sql = 'DROP INDEX INDEXNAME'; //SQL sentence to drop one index 00116 //TABLENAME, INDEXNAME are dynamically replaced 00117 00118 public $rename_index_sql = 'ALTER INDEX OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index 00119 //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dynamically replaced 00120 00121 public $rename_key_sql = 'ALTER TABLE TABLENAME CONSTRAINT OLDKEYNAME RENAME TO NEWKEYNAME'; //SQL sentence to rename one key 00122 //TABLENAME, OLDKEYNAME, NEWKEYNAME are dynamically replaced 00123 00124 public $prefix; // Prefix to be used for all the DB objects 00125 00126 public $reserved_words; // List of reserved words (in order to quote them properly) 00127 00128 public $mdb; 00129 00130 protected $temptables; // Control existing temptables 00131 00136 public function __construct($mdb, $temptables = null) { 00137 $this->prefix = $mdb->get_prefix(); 00138 $this->reserved_words = $this->getReservedWords(); 00139 $this->mdb = $mdb; // this creates circular reference - the other link must be unset when closing db 00140 $this->temptables = $temptables; 00141 } 00142 00146 public function dispose() { 00147 $this->mdb = null; 00148 } 00149 00153 public function getEndedStatements($input) { 00154 00155 if (is_array($input)) { 00156 foreach ($input as $key=>$content) { 00157 $input[$key] = $this->getEndedStatements($content); 00158 } 00159 return $input; 00160 } else { 00161 $input = trim($input).$this->statement_end; 00162 return $input; 00163 } 00164 } 00165 00172 public function table_exists($table) { 00173 if (is_string($table)) { 00174 $tablename = $table; 00175 } else { 00177 $tablename = $table->getName(); 00178 } 00179 00181 $tables = $this->mdb->get_tables(); 00182 $exists = in_array($tablename, $tables); 00183 00184 return $exists; 00185 } 00186 00190 public function getCreateStructureSQL($xmldb_structure) { 00191 $results = array(); 00192 00193 if ($tables = $xmldb_structure->getTables()) { 00194 foreach ($tables as $table) { 00195 $results = array_merge($results, $this->getCreateTableSQL($table)); 00196 } 00197 } 00198 00199 return $results; 00200 } 00201 00209 public function getTableName(xmldb_table $xmldb_table, $quoted=true) { 00211 $tablename = $this->prefix.$xmldb_table->getName(); 00212 00214 if ($quoted) { 00215 $tablename = $this->getEncQuoted($tablename); 00216 } 00217 00218 return $tablename; 00219 } 00220 00225 public function getCreateTableSQL($xmldb_table) { 00226 00227 $results = array(); //Array where all the sentences will be stored 00228 00230 $table = 'CREATE TABLE ' . $this->getTableName($xmldb_table) . ' ('; 00231 00232 if (!$xmldb_fields = $xmldb_table->getFields()) { 00233 return $results; 00234 } 00235 00236 $sequencefield = null; 00237 00239 foreach ($xmldb_fields as $xmldb_field) { 00240 if ($xmldb_field->getSequence()) { 00241 $sequencefield = $xmldb_field->getName(); 00242 } 00243 $table .= "\n " . $this->getFieldSQL($xmldb_table, $xmldb_field); 00244 $table .= ','; 00245 } 00247 if ($xmldb_keys = $xmldb_table->getKeys()) { 00248 foreach ($xmldb_keys as $xmldb_key) { 00249 if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) { 00250 $table .= "\nCONSTRAINT " . $keytext . ','; 00251 } 00253 if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE) { 00255 $xmldb_key->setType(XMLDB_KEY_UNIQUE); 00256 if ($keytext = $this->getKeySQL($xmldb_table, $xmldb_key)) { 00257 $table .= "\nCONSTRAINT " . $keytext . ','; 00258 } 00259 } 00261 if ($sequencefield and $xmldb_key->getType() == XMLDB_KEY_PRIMARY) { 00262 $field = reset($xmldb_key->getFields()); 00263 if ($sequencefield === $field) { 00264 $sequencefield = null; 00265 } 00266 } 00267 } 00268 } 00270 if ($sequencefield) { 00271 throw new ddl_exception('ddsequenceerror', $xmldb_table->getName()); 00272 } 00273 00275 $table = trim($table,','); 00276 $table .= "\n)"; 00277 00279 $results[] = $table; 00280 00282 if ($this->add_table_comments && $xmldb_table->getComment()) { 00283 $comment = $this->getCommentSQL($xmldb_table); 00285 $results = array_merge($results, $comment); 00286 } 00287 00289 if ($xmldb_indexes = $xmldb_table->getIndexes()) { 00290 foreach ($xmldb_indexes as $xmldb_index) { 00292 if ($indextext = $this->getCreateIndexSQL($xmldb_table, $xmldb_index)) { 00293 $results = array_merge($results, $indextext); 00294 } 00295 } 00296 } 00297 00299 if ($xmldb_keys = $xmldb_table->getKeys()) { 00300 foreach ($xmldb_keys as $xmldb_key) { 00303 if (!$this->getKeySQL($xmldb_table, $xmldb_key) || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) { 00305 $index = new xmldb_index('anyname'); 00306 $index->setFields($xmldb_key->getFields()); 00308 $createindex = false; //By default 00309 switch ($xmldb_key->getType()) { 00310 case XMLDB_KEY_UNIQUE: 00311 case XMLDB_KEY_FOREIGN_UNIQUE: 00312 $index->setUnique(true); 00313 $createindex = true; 00314 break; 00315 case XMLDB_KEY_FOREIGN: 00316 $index->setUnique(false); 00317 $createindex = true; 00318 break; 00319 } 00320 if ($createindex) { 00321 if ($indextext = $this->getCreateIndexSQL($xmldb_table, $index)) { 00323 $results = array_merge($results, $indextext); 00324 } 00325 } 00326 } 00327 } 00328 } 00329 00331 if ($this->sequence_extra_code) { 00333 foreach ($xmldb_fields as $xmldb_field) { 00334 if ($xmldb_field->getSequence()) { 00336 $sequence_sentences = $this->getCreateSequenceSQL($xmldb_table, $xmldb_field); 00338 $results = array_merge($results, $sequence_sentences); 00339 } 00340 } 00341 } 00342 00343 return $results; 00344 } 00345 00350 public function getCreateIndexSQL($xmldb_table, $xmldb_index) { 00351 if ($error = $xmldb_index->validateDefinition($xmldb_table)) { 00352 throw new coding_exception($error); 00353 } 00354 00355 $unique = ''; 00356 $suffix = 'ix'; 00357 if ($xmldb_index->getUnique()) { 00358 $unique = ' UNIQUE'; 00359 $suffix = 'uix'; 00360 } 00361 00362 $index = 'CREATE' . $unique . ' INDEX '; 00363 $index .= $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_index->getFields()), $suffix); 00364 $index .= ' ON ' . $this->getTableName($xmldb_table); 00365 $index .= ' (' . implode(', ', $this->getEncQuoted($xmldb_index->getFields())) . ')'; 00366 00367 return array($index); 00368 } 00369 00373 public function getFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL, $specify_nulls_clause = NULL, $specify_field_name = true) { 00374 if ($error = $xmldb_field->validateDefinition($xmldb_table)) { 00375 throw new coding_exception($error); 00376 } 00377 00378 $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause; 00379 $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause; 00380 $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause; 00381 $specify_nulls_clause = is_null($specify_nulls_clause) ? $this->specify_nulls : $specify_nulls_clause; 00382 00384 if ($this->integer_to_number) { 00385 if ($xmldb_field->getType() == XMLDB_TYPE_INTEGER) { 00386 $xmldb_field->setType(XMLDB_TYPE_NUMBER); 00387 } 00388 } 00390 if ($this->float_to_number) { 00391 if ($xmldb_field->getType() == XMLDB_TYPE_FLOAT) { 00392 $xmldb_field->setType(XMLDB_TYPE_NUMBER); 00393 } 00394 } 00395 00396 $field = ''; // Let's accumulate the whole expression based on params and settings 00398 if ($specify_field_name) { 00399 $field .= $this->getEncQuoted($xmldb_field->getName()); 00400 } 00402 if (!$skip_type_clause) { 00404 $field .= ' ' . $this->getTypeSQL($xmldb_field->getType(), $xmldb_field->getLength(), $xmldb_field->getDecimals()); 00405 } 00407 if ($this->unsigned_allowed && ($xmldb_field->getType() == XMLDB_TYPE_INTEGER || 00408 $xmldb_field->getType() == XMLDB_TYPE_NUMBER || 00409 $xmldb_field->getType() == XMLDB_TYPE_FLOAT)) { 00410 if ($xmldb_field->getUnsigned()) { 00411 $field .= ' unsigned'; 00412 } 00413 } 00415 $notnull = ''; 00417 if (!$skip_notnull_clause) { 00418 if ($xmldb_field->getNotNull()) { 00419 $notnull = ' NOT NULL'; 00420 } else { 00421 if ($specify_nulls_clause) { 00422 $notnull = ' NULL'; 00423 } 00424 } 00425 } 00427 $default_clause = ''; 00428 if (!$skip_default_clause) { //Only if we don't want to skip it 00429 $default_clause = $this->getDefaultClause($xmldb_field); 00430 } 00432 if ($this->default_after_null) { 00433 $field .= $notnull . $default_clause; 00434 } else { 00435 $field .= $default_clause . $notnull; 00436 } 00438 if ($xmldb_field->getSequence()) { 00439 if($xmldb_field->getLength()<=9 && $this->sequence_name_small) { 00440 $sequencename=$this->sequence_name_small; 00441 } else { 00442 $sequencename=$this->sequence_name; 00443 } 00444 $field .= ' ' . $sequencename; 00445 if ($this->sequence_only) { 00448 $sql = $this->getEncQuoted($xmldb_field->getName()) . ' ' . $sequencename; 00449 return $sql; 00450 } 00451 } 00452 return $field; 00453 } 00454 00458 public function getKeySQL($xmldb_table, $xmldb_key) { 00459 00460 $key = ''; 00461 00462 switch ($xmldb_key->getType()) { 00463 case XMLDB_KEY_PRIMARY: 00464 if ($this->primary_keys) { 00465 if ($this->primary_key_name !== null) { 00466 $key = $this->getEncQuoted($this->primary_key_name); 00467 } else { 00468 $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'pk'); 00469 } 00470 $key .= ' PRIMARY KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')'; 00471 } 00472 break; 00473 case XMLDB_KEY_UNIQUE: 00474 if ($this->unique_keys) { 00475 $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'uk'); 00476 $key .= ' UNIQUE (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')'; 00477 } 00478 break; 00479 case XMLDB_KEY_FOREIGN: 00480 case XMLDB_KEY_FOREIGN_UNIQUE: 00481 if ($this->foreign_keys) { 00482 $key = $this->getNameForObject($xmldb_table->getName(), implode(', ', $xmldb_key->getFields()), 'fk'); 00483 $key .= ' FOREIGN KEY (' . implode(', ', $this->getEncQuoted($xmldb_key->getFields())) . ')'; 00484 $key .= ' REFERENCES ' . $this->getEncQuoted($this->prefix . $xmldb_key->getRefTable()); 00485 $key .= ' (' . implode(', ', $this->getEncQuoted($xmldb_key->getRefFields())) . ')'; 00486 } 00487 break; 00488 } 00489 00490 return $key; 00491 } 00492 00496 public function getDefaultValue($xmldb_field) { 00497 00498 $default = null; 00499 00500 if ($xmldb_field->getDefault() !== NULL) { 00501 if ($xmldb_field->getType() == XMLDB_TYPE_CHAR || 00502 $xmldb_field->getType() == XMLDB_TYPE_TEXT) { 00503 if ($xmldb_field->getDefault() === '') { // If passing empty default, use the $default_for_char one instead 00504 $default = "'" . $this->default_for_char . "'"; 00505 } else { 00506 $default = "'" . $this->addslashes($xmldb_field->getDefault()) . "'"; 00507 } 00508 } else { 00509 $default = $xmldb_field->getDefault(); 00510 } 00511 } else { 00514 if ($this->default_for_char !== NULL && 00515 $xmldb_field->getType() == XMLDB_TYPE_CHAR && 00516 $xmldb_field->getNotNull()) { 00517 $default = "'" . $this->default_for_char . "'"; 00518 } else { 00521 if ($this->drop_default_value_required && 00522 $xmldb_field->getType() != XMLDB_TYPE_TEXT && 00523 $xmldb_field->getType() != XMLDB_TYPE_BINARY && !$xmldb_field->getNotNull()) { 00524 $default = $this->drop_default_value; 00525 } 00526 } 00527 } 00528 return $default; 00529 } 00530 00534 public function getDefaultClause($xmldb_field) { 00535 00536 $defaultvalue = $this->getDefaultValue ($xmldb_field); 00537 00538 if ($defaultvalue !== null) { 00539 return ' DEFAULT ' . $defaultvalue; 00540 } else { 00541 return null; 00542 } 00543 } 00544 00549 public function getRenameTableSQL($xmldb_table, $newname) { 00550 00551 $results = array(); //Array where all the sentences will be stored 00552 00553 $newt = new xmldb_table($newname); //Temporal table for name calculations 00554 00555 $rename = str_replace('OLDNAME', $this->getTableName($xmldb_table), $this->rename_table_sql); 00556 $rename = str_replace('NEWNAME', $this->getTableName($newt), $rename); 00557 00558 $results[] = $rename; 00559 00561 $extra_sentences = $this->getRenameTableExtraSQL($xmldb_table, $newname); 00562 $results = array_merge($results, $extra_sentences); 00563 00564 return $results; 00565 } 00566 00571 public function getDropTableSQL($xmldb_table) { 00572 00573 $results = array(); //Array where all the sentences will be stored 00574 00575 $drop = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_table_sql); 00576 00577 $results[] = $drop; 00578 00580 $extra_sentences = $this->getDropTableExtraSQL($xmldb_table); 00581 $results = array_merge($results, $extra_sentences); 00582 00583 return $results; 00584 } 00585 00589 public function getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) { 00590 00591 $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause; 00592 $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause; 00593 $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause; 00594 00595 $results = array(); 00596 00598 $tablename = $this->getTableName($xmldb_table); 00599 00601 $sql = $this->getFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, 00602 $skip_default_clause, 00603 $skip_notnull_clause); 00604 $altertable = 'ALTER TABLE ' . $tablename . ' ADD ' . $sql; 00606 if ($this->add_after_clause && $xmldb_field->getPrevious()) { 00607 $altertable .= ' AFTER ' . $this->getEncQuoted($xmldb_field->getPrevious()); 00608 } 00609 $results[] = $altertable; 00610 00611 return $results; 00612 } 00613 00617 public function getDropFieldSQL($xmldb_table, $xmldb_field) { 00618 00619 $results = array(); 00620 00622 $tablename = $this->getTableName($xmldb_table); 00623 $fieldname = $this->getEncQuoted($xmldb_field->getName()); 00624 00626 $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname; 00627 00628 return $results; 00629 } 00630 00634 public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) { 00635 00636 $skip_type_clause = is_null($skip_type_clause) ? $this->alter_column_skip_type : $skip_type_clause; 00637 $skip_default_clause = is_null($skip_default_clause) ? $this->alter_column_skip_default : $skip_default_clause; 00638 $skip_notnull_clause = is_null($skip_notnull_clause) ? $this->alter_column_skip_notnull : $skip_notnull_clause; 00639 00640 $results = array(); 00641 00643 $tablename = $this->getTableName($xmldb_table); 00644 $fieldname = $this->getEncQuoted($xmldb_field->getName()); 00645 00647 $alter = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->alter_column_sql); 00648 $colspec = $this->getFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, 00649 $skip_default_clause, 00650 $skip_notnull_clause, 00651 true); 00652 $alter = str_replace('COLUMNSPECS', $colspec, $alter); 00653 00655 if ($this->add_after_clause && $xmldb_field->getPrevious()) { 00656 $alter .= ' after ' . $this->getEncQuoted($xmldb_field->getPrevious()); 00657 } 00658 00660 $results[] = $alter; 00661 00662 return $results; 00663 } 00664 00668 public function getModifyDefaultSQL($xmldb_table, $xmldb_field) { 00669 00670 $results = array(); 00671 00673 $tablename = $this->getTableName($xmldb_table); 00674 $fieldname = $this->getEncQuoted($xmldb_field->getName()); 00675 00677 if ($xmldb_field->getDefault() === null) { 00678 $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop 00679 } else { 00680 $results = $this->getCreateDefaultSQL($xmldb_table, $xmldb_field); //Create/modify 00681 } 00682 00683 return $results; 00684 } 00685 00690 public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) { 00691 00692 $results = array(); //Array where all the sentences will be stored 00693 00701 if ($xmldb_field->getName() == 'id') { 00702 return array(); 00703 } 00704 00705 $rename = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_column_sql); 00706 $rename = str_replace('OLDFIELDNAME', $this->getEncQuoted($xmldb_field->getName()), $rename); 00707 $rename = str_replace('NEWFIELDNAME', $this->getEncQuoted($newname), $rename); 00708 00709 $results[] = $rename; 00710 00712 $extra_sentences = $this->getRenameFieldExtraSQL($xmldb_table, $xmldb_field, $newname); 00713 $results = array_merge($results, $extra_sentences); 00714 00715 return $results; 00716 } 00717 00722 public function getAddKeySQL($xmldb_table, $xmldb_key) { 00723 00724 $results = array(); 00725 00727 if ($keyclause = $this->getKeySQL($xmldb_table, $xmldb_key)) { 00728 $key = 'ALTER TABLE ' . $this->getTableName($xmldb_table) . 00729 ' ADD CONSTRAINT ' . $keyclause; 00730 $results[] = $key; 00731 } 00732 00735 if (!$keyclause || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) { 00737 if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN) { 00738 $indextype = XMLDB_INDEX_NOTUNIQUE; 00739 } else { 00740 $indextype = XMLDB_INDEX_UNIQUE; 00741 } 00742 $xmldb_index = new xmldb_index('anyname', $indextype, $xmldb_key->getFields()); 00743 if (!$this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) { 00744 $results = array_merge($results, $this->getAddIndexSQL($xmldb_table, $xmldb_index)); 00745 } 00746 } 00747 00749 if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) { 00751 $xmldb_key->setType(XMLDB_KEY_UNIQUE); 00752 $results = array_merge($results, $this->getAddKeySQL($xmldb_table, $xmldb_key)); 00753 } 00754 00756 return $results; 00757 } 00758 00762 public function getDropKeySQL($xmldb_table, $xmldb_key) { 00763 00764 $results = array(); 00765 00771 $dbkeyname = $this->mdb->get_manager()->find_key_name($xmldb_table, $xmldb_key); 00772 00774 $dropkey = false; 00775 switch ($xmldb_key->getType()) { 00776 case XMLDB_KEY_PRIMARY: 00777 if ($this->primary_keys) { 00778 $template = $this->drop_primary_key; 00779 $dropkey = true; 00780 } 00781 break; 00782 case XMLDB_KEY_UNIQUE: 00783 if ($this->unique_keys) { 00784 $template = $this->drop_unique_key; 00785 $dropkey = true; 00786 } 00787 break; 00788 case XMLDB_KEY_FOREIGN_UNIQUE: 00789 case XMLDB_KEY_FOREIGN: 00790 if ($this->foreign_keys) { 00791 $template = $this->drop_foreign_key; 00792 $dropkey = true; 00793 } 00794 break; 00795 } 00797 if ($dropkey) { 00799 $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $template); 00800 $dropsql = str_replace('KEYNAME', $dbkeyname, $dropsql); 00801 00802 $results[] = $dropsql; 00803 } 00804 00807 if (!$dropkey || $xmldb_key->getType() == XMLDB_KEY_FOREIGN) { 00809 $xmldb_index = new xmldb_index('anyname', XMLDB_INDEX_UNIQUE, $xmldb_key->getFields()); 00810 if ($this->mdb->get_manager()->index_exists($xmldb_table, $xmldb_index)) { 00811 $results = array_merge($results, $this->getDropIndexSQL($xmldb_table, $xmldb_index)); 00812 } 00813 } 00814 00816 if ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && $this->unique_keys) { 00818 $xmldb_key->setType(XMLDB_KEY_UNIQUE); 00819 $results = array_merge($results, $this->getDropKeySQL($xmldb_table, $xmldb_key)); 00820 } 00821 00823 return $results; 00824 } 00825 00831 public function getRenameKeySQL($xmldb_table, $xmldb_key, $newname) { 00832 00833 $results = array(); 00834 00836 $dbkeyname = $this->mdb->get_manager()->find_key_name($xmldb_table, $xmldb_key); 00837 00839 if (($xmldb_key->getType() == XMLDB_KEY_PRIMARY && !$this->primary_keys) || 00840 ($xmldb_key->getType() == XMLDB_KEY_UNIQUE && !$this->unique_keys) || 00841 ($xmldb_key->getType() == XMLDB_KEY_FOREIGN && !$this->foreign_keys) || 00842 ($xmldb_key->getType() == XMLDB_KEY_FOREIGN_UNIQUE && !$this->unique_keys && !$this->foreign_keys)) { 00844 $xmldb_index = new xmldb_index($xmldb_key->getName()); 00845 $xmldb_index->setFields($xmldb_key->getFields()); 00846 return $this->getRenameIndexSQL($xmldb_table, $xmldb_index, $newname); 00847 } 00848 00851 $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_key_sql); 00852 $renamesql = str_replace('OLDKEYNAME', $dbkeyname, $renamesql); 00853 $renamesql = str_replace('NEWKEYNAME', $newname, $renamesql); 00854 00856 if ($renamesql) { 00857 $results[] = $renamesql; 00858 } 00859 00860 return $results; 00861 } 00862 00866 public function getAddIndexSQL($xmldb_table, $xmldb_index) { 00867 00869 return $this->getCreateIndexSQL($xmldb_table, $xmldb_index); 00870 } 00871 00875 public function getDropIndexSQL($xmldb_table, $xmldb_index) { 00876 00877 $results = array(); 00878 00880 $dbindexname = $this->mdb->get_manager()->find_index_name($xmldb_table, $xmldb_index); 00881 00883 $dropsql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->drop_index_sql); 00884 $dropsql = str_replace('INDEXNAME', $this->getEncQuoted($dbindexname), $dropsql); 00885 00886 $results[] = $dropsql; 00887 00888 return $results; 00889 } 00890 00895 function getRenameIndexSQL($xmldb_table, $xmldb_index, $newname) { 00897 if (empty($this->rename_index_sql)) { 00898 return array(); 00899 } 00900 00902 $dbindexname = $this->mdb->get_manager()->find_index_name($xmldb_table, $xmldb_index); 00904 $renamesql = str_replace('TABLENAME', $this->getTableName($xmldb_table), $this->rename_index_sql); 00905 $renamesql = str_replace('OLDINDEXNAME', $this->getEncQuoted($dbindexname), $renamesql); 00906 $renamesql = str_replace('NEWINDEXNAME', $this->getEncQuoted($newname), $renamesql); 00907 00908 return array($renamesql); 00909 } 00910 00918 public function getNameForObject($tablename, $fields, $suffix='') { 00919 00920 $name = ''; 00921 00927 static $used_names = array(); 00928 00930 $tablearr = explode ('_', $tablename); 00931 foreach ($tablearr as $table) { 00932 $name .= substr(trim($table),0,4); 00933 } 00934 $name .= '_'; 00935 $fieldsarr = explode (',', $fields); 00936 foreach ($fieldsarr as $field) { 00937 $name .= substr(trim($field),0,3); 00938 } 00940 $name = $this->prefix . $name; 00941 00942 $name = substr(trim($name), 0, $this->names_max_length - 1 - strlen($suffix)); //Max names_max_length 00943 00945 $namewithsuffix = $name; 00946 if ($suffix) { 00947 $namewithsuffix = $namewithsuffix . '_' . $suffix; 00948 } 00949 00951 if (in_array($namewithsuffix, $used_names) || $this->isNameInUse($namewithsuffix, $suffix, $tablename)) { 00952 $counter = 2; 00954 if (strlen($namewithsuffix) < $this->names_max_length) { 00955 $newname = $name . $counter; 00957 } else { 00958 $newname = substr($name, 0, strlen($name)-1) . $counter; 00959 } 00960 $newnamewithsuffix = $newname; 00961 if ($suffix) { 00962 $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix; 00963 } 00965 while (in_array($newnamewithsuffix, $used_names) || $this->isNameInUse($newnamewithsuffix, $suffix, $tablename)) { 00966 $counter++; 00967 $newname = substr($name, 0, strlen($newname)-1) . $counter; 00968 $newnamewithsuffix = $newname; 00969 if ($suffix) { 00970 $newnamewithsuffix = $newnamewithsuffix . '_' . $suffix; 00971 } 00972 } 00973 $namewithsuffix = $newnamewithsuffix; 00974 } 00975 00977 $used_names[] = $namewithsuffix; 00978 00980 $namewithsuffix = $this->getEncQuoted($namewithsuffix); 00981 00982 return $namewithsuffix; 00983 } 00984 00989 public function getEncQuoted($input) { 00990 00991 if (is_array($input)) { 00992 foreach ($input as $key=>$content) { 00993 $input[$key] = $this->getEncQuoted($content); 00994 } 00995 return $input; 00996 } else { 00998 $input = strtolower($input); 01000 if ($this->quote_all || in_array($input, $this->reserved_words) || strpos($input, '-') !== false) { 01001 $input = $this->quote_string . $input . $this->quote_string; 01002 } 01003 return $input; 01004 } 01005 } 01006 01010 function getExecuteInsertSQL($statement) { 01011 01012 $results = array(); //Array where all the sentences will be stored 01013 01014 if ($sentences = $statement->getSentences()) { 01015 foreach ($sentences as $sentence) { 01017 $fields = $statement->getFieldsFromInsertSentence($sentence); 01019 $values = $statement->getValuesFromInsertSentence($sentence); 01021 foreach($values as $key => $value) { 01023 $value = trim($value,"'"); 01024 if (stristr($value, 'CONCAT') !== false){ 01026 preg_match("/CONCAT\s*\((.*)\)$/is", trim($value), $matches); 01027 if (isset($matches[1])) { 01028 $part = $matches[1]; 01030 $arr = xmldb_object::comma2array($part); 01031 if ($arr) { 01032 $value = $this->getConcatSQL($arr); 01033 } 01034 } 01035 } 01037 $value = $this->addslashes($value); 01039 $value = "'" . $value . "'"; 01041 $values[$key] = $value; 01042 } 01043 01045 foreach($fields as $key => $field) { 01046 $fields[$key] = $this->getEncQuoted($field); 01047 } 01049 $sql = 'INSERT INTO ' . $this->getEncQuoted($this->prefix . $statement->getTable()) . 01050 '(' . implode(', ', $fields) . ') ' . 01051 'VALUES (' . implode(', ', $values) . ')'; 01052 $results[] = $sql; 01053 } 01054 01055 } 01056 return $results; 01057 } 01058 01064 public function getConcatSQL($elements) { 01065 01067 foreach($elements as $key => $element) { 01068 $element = trim($element); 01069 if (substr($element, 0, 1) == '"' && 01070 substr($element, -1, 1) == '"') { 01071 $elements[$key] = "'" . trim($element, '"') . "'"; 01072 } 01073 } 01074 01076 return call_user_func_array(array($this->mdb, 'sql_concat'), $elements); 01077 } 01078 01083 public function getSequenceFromDB($xmldb_table) { 01084 return false; 01085 } 01086 01094 public function isNameInUse($object_name, $type, $table_name) { 01095 return false; //For generators not implementing introspection, 01096 //we always return with the name being free to be used 01097 } 01098 01099 01101 01107 public abstract function getResetSequenceSQL($tablename); 01108 01113 abstract public function getCreateTempTableSQL($xmldb_table); 01114 01119 abstract public function getDropTempTableSQL($xmldb_table); 01120 01124 public abstract function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null); 01125 01129 public function getRenameFieldExtraSQL($xmldb_table, $xmldb_field) { 01130 return array(); 01131 } 01132 01137 public function getCreateSequenceSQL($xmldb_table, $xmldb_field) { 01138 return array(); 01139 } 01140 01144 public abstract function getCommentSQL($xmldb_table); 01145 01149 public function getRenameTableExtraSQL($xmldb_table, $newname) { 01150 return array(); 01151 } 01152 01156 public function getDropTableExtraSQL($xmldb_table) { 01157 return array(); 01158 } 01159 01166 public abstract function getDropEnumSQL($xmldb_table, $xmldb_field); 01167 01174 public abstract function getDropDefaultSQL($xmldb_table, $xmldb_field); 01175 01183 public abstract function getCheckConstraintsFromDB($xmldb_table, $xmldb_field=null); 01184 01189 public abstract function getCreateDefaultSQL($xmldb_table, $xmldb_field); 01190 01196 public static function getReservedWords() { 01197 throw new coding_exception('getReservedWords() method needs to be overridden in each subclass of sql_generator'); 01198 } 01199 01205 public static function getAllReservedWords() { 01206 global $CFG; 01207 01208 $generators = array('mysql', 'postgres', 'oracle', 'mssql'); 01209 $reserved_words = array(); 01210 01211 foreach($generators as $generator) { 01212 $class = $generator . '_sql_generator'; 01213 require_once("$CFG->libdir/ddl/$class.php"); 01214 foreach (call_user_func(array($class, 'getReservedWords')) as $word) { 01215 $reserved_words[$word][] = $generator; 01216 } 01217 } 01218 ksort($reserved_words); 01219 return $reserved_words; 01220 } 01221 01222 public function addslashes($s) { 01223 // do not use php addslashes() because it depends on PHP quote settings! 01224 $s = str_replace('\\','\\\\',$s); 01225 $s = str_replace("\0","\\\0", $s); 01226 $s = str_replace("'", "\\'", $s); 01227 return $s; 01228 } 01229 }