Merge branch 'MDL-29847_22' of git://github.com/timhunt/moodle into MOODLE_22_STABLE
[moodle.git] / lib / ddl / mssql_sql_generator.php
blob3c9b41de283c4c2b0a11c95e0f85604d20705741
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
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.
9 //
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/>.
19 /**
20 * MSSQL specific SQL code generator.
22 * @package core
23 * @subpackage ddl
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 defined('MOODLE_INTERNAL') || die();
31 require_once($CFG->libdir.'/ddl/sql_generator.php');
33 /// This class generate SQL code to be used against MSSQL
34 /// It extends XMLDBgenerator so everything can be
35 /// overridden as needed to generate correct SQL.
37 class mssql_sql_generator extends sql_generator {
39 /// Only set values that are different from the defaults present in XMLDBgenerator
41 public $statement_end = "\ngo"; // String to be automatically added at the end of each statement
43 public $number_type = 'DECIMAL'; // Proper type for NUMBER(x) in this DB
45 public $unsigned_allowed = false; // To define in the generator must handle unsigned information
46 public $default_for_char = ''; // To define the default to set for NOT NULLs CHARs without default (null=do nothing)
48 public $specify_nulls = true; //To force the generator if NULL clauses must be specified. It shouldn't be necessary
49 //but some mssql drivers require them or everything is created as NOT NULL :-(
51 public $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
52 public $sequence_name = 'IDENTITY(1,1)'; //Particular name for inline sequences in this generator
53 public $sequence_only = false; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
55 public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
57 public $add_table_comments = false; // Does the generator need to add code for table comments
59 public $concat_character = '+'; //Characters to be used as concatenation operator. If not defined
60 //MySQL CONCAT function will be use
62 public $rename_table_sql = "sp_rename 'OLDNAME', 'NEWNAME'"; //SQL sentence to rename one table, both
63 //OLDNAME and NEWNAME are dynamically replaced
65 public $rename_column_sql = "sp_rename 'TABLENAME.OLDFIELDNAME', 'NEWFIELDNAME', 'COLUMN'";
66 ///TABLENAME, OLDFIELDNAME and NEWFIELDNAME are dyanmically replaced
68 public $drop_index_sql = 'DROP INDEX TABLENAME.INDEXNAME'; //SQL sentence to drop one index
69 //TABLENAME, INDEXNAME are dynamically replaced
71 public $rename_index_sql = "sp_rename 'TABLENAME.OLDINDEXNAME', 'NEWINDEXNAME', 'INDEX'"; //SQL sentence to rename one index
72 //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dynamically replaced
74 public $rename_key_sql = null; //SQL sentence to rename one key
75 //TABLENAME, OLDKEYNAME, NEWKEYNAME are dynamically replaced
77 /**
78 * Reset a sequence to the id field of a table.
79 * @param string $table name of table or xmldb_table object
80 * @return array sql commands to execute
82 public function getResetSequenceSQL($table) {
84 if (is_string($table)) {
85 $table = new xmldb_table($table);
88 // From http://msdn.microsoft.com/en-us/library/ms176057.aspx
89 $value = (int)$this->mdb->get_field_sql('SELECT MAX(id) FROM {'. $table->getName() . '}');
90 if ($value == 0) {
91 $value = 1;
93 return array("DBCC CHECKIDENT ('" . $this->getTableName($table) . "', RESEED, $value)");
96 /**
97 * Given one xmldb_table, returns it's correct name, depending of all the parametrization
98 * Overridden to allow change of names in temp tables
100 * @param xmldb_table table whose name we want
101 * @param boolean to specify if the name must be quoted (if reserved word, only!)
102 * @return string the correct name of the table
104 public function getTableName(xmldb_table $xmldb_table, $quoted=true) {
105 /// Get the name, supporting special mssql names for temp tables
106 if ($this->temptables->is_temptable($xmldb_table->getName())) {
107 $tablename = $this->temptables->get_correct_name($xmldb_table->getName());
108 } else {
109 $tablename = $this->prefix . $xmldb_table->getName();
112 /// Apply quotes optionally
113 if ($quoted) {
114 $tablename = $this->getEncQuoted($tablename);
117 return $tablename;
122 * Given one correct xmldb_table, returns the SQL statements
123 * to create temporary table (inside one array)
125 public function getCreateTempTableSQL($xmldb_table) {
126 $this->temptables->add_temptable($xmldb_table->getName());
127 $sqlarr = $this->getCreateTableSQL($xmldb_table);
128 return $sqlarr;
132 * Given one correct xmldb_table and the new name, returns the SQL statements
133 * to drop it (inside one array)
135 public function getDropTempTableSQL($xmldb_table) {
136 $sqlarr = $this->getDropTableSQL($xmldb_table);
137 $this->temptables->delete_temptable($xmldb_table->getName());
138 return $sqlarr;
142 * Given one XMLDB Type, lenght and decimals, returns the DB proper SQL type
144 public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
146 switch ($xmldb_type) {
147 case XMLDB_TYPE_INTEGER: // From http://msdn.microsoft.com/library/en-us/tsqlref/ts_da-db_7msw.asp?frame=true
148 if (empty($xmldb_length)) {
149 $xmldb_length = 10;
151 if ($xmldb_length > 9) {
152 $dbtype = 'BIGINT';
153 } else if ($xmldb_length > 4) {
154 $dbtype = 'INTEGER';
155 } else {
156 $dbtype = 'SMALLINT';
158 break;
159 case XMLDB_TYPE_NUMBER:
160 $dbtype = $this->number_type;
161 if (!empty($xmldb_length)) {
162 /// 38 is the max allowed
163 if ($xmldb_length > 38) {
164 $xmldb_length = 38;
166 $dbtype .= '(' . $xmldb_length;
167 if (!empty($xmldb_decimals)) {
168 $dbtype .= ',' . $xmldb_decimals;
170 $dbtype .= ')';
172 break;
173 case XMLDB_TYPE_FLOAT:
174 $dbtype = 'FLOAT';
175 if (!empty($xmldb_decimals)) {
176 if ($xmldb_decimals < 6) {
177 $dbtype = 'REAL';
180 break;
181 case XMLDB_TYPE_CHAR:
182 $dbtype = 'NVARCHAR';
183 if (empty($xmldb_length)) {
184 $xmldb_length='255';
186 $dbtype .= '(' . $xmldb_length . ')';
187 break;
188 case XMLDB_TYPE_TEXT:
189 $dbtype = 'NTEXT';
190 break;
191 case XMLDB_TYPE_BINARY:
192 $dbtype = 'IMAGE';
193 break;
194 case XMLDB_TYPE_DATETIME:
195 $dbtype = 'DATETIME';
196 break;
198 return $dbtype;
202 * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop the field from the table
203 * MSSQL overwrites the standard sentence because it needs to do some extra work dropping the default and
204 * check constraints
206 public function getDropFieldSQL($xmldb_table, $xmldb_field) {
207 $results = array();
209 /// Get the quoted name of the table and field
210 $tablename = $this->getTableName($xmldb_table);
211 $fieldname = $this->getEncQuoted($xmldb_field->getName());
213 /// Look for any default constraint in this field and drop it
214 if ($defaultname = $this->getDefaultConstraintName($xmldb_table, $xmldb_field)) {
215 $results[] = 'ALTER TABLE ' . $tablename . ' DROP CONSTRAINT ' . $defaultname;
218 /// Look for any check constraint in this field and drop it
219 if ($drop_check = $this->getDropEnumSQL($xmldb_table, $xmldb_field)) {
220 $results = array_merge($results, $drop_check);
223 /// Build the standard alter table drop column
224 $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname;
226 return $results;
230 * Given one correct xmldb_field and the new name, returns the SQL statements
231 * to rename it (inside one array)
232 * MSSQL is special, so we overload the function here. It needs to
233 * drop the constraints BEFORE renaming the field
235 public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
237 $results = array(); //Array where all the sentences will be stored
239 /// Although this is checked in database_manager::rename_field() - double check
240 /// that we aren't trying to rename one "id" field. Although it could be
241 /// implemented (if adding the necessary code to rename sequences, defaults,
242 /// triggers... and so on under each getRenameFieldExtraSQL() function, it's
243 /// better to forbid it, mainly because this field is the default PK and
244 /// in the future, a lot of FKs can be pointing here. So, this field, more
245 /// or less, must be considered immutable!
246 if ($xmldb_field->getName() == 'id') {
247 return array();
250 /// Call to standard (parent) getRenameFieldSQL() function
251 $results = array_merge($results, parent::getRenameFieldSQL($xmldb_table, $xmldb_field, $newname));
253 return $results;
257 * Returns the code (array of statements) needed to execute extra statements on table rename
259 public function getRenameTableExtraSQL($xmldb_table, $newname) {
261 $results = array();
263 $newt = new xmldb_table($newname); //Temporal table for name calculations
265 $oldtablename = $this->getTableName($xmldb_table);
266 $newtablename = $this->getTableName($newt);
268 /// Rename all the check constraints in the table
269 $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
270 $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
272 if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
273 foreach ($constraints as $constraint) {
274 /// Drop the old constraint
275 $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
279 return $results;
283 * Given one xmldb_table and one xmldb_field, return the SQL statements needed to alter the field in the table
285 public function getAlterFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
287 $results = array(); /// To store all the needed SQL commands
289 /// Get the quoted name of the table and field
290 $tablename = $xmldb_table->getName();
291 $fieldname = $xmldb_field->getName();
293 /// Take a look to field metadata
294 $meta = $this->mdb->get_columns($tablename);
295 $metac = $meta[$fieldname];
296 $oldmetatype = $metac->meta_type;
298 $oldlength = $metac->max_length;
299 $olddecimals = empty($metac->scale) ? null : $metac->scale;
300 $oldnotnull = empty($metac->not_null) ? false : $metac->not_null;
301 //$olddefault = empty($metac->has_default) ? null : strtok($metac->default_value, ':');
303 $typechanged = true; //By default, assume that the column type has changed
304 $lengthchanged = true; //By default, assume that the column length has changed
306 /// Detect if we are changing the type of the column
307 if (($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') ||
308 ($xmldb_field->getType() == XMLDB_TYPE_NUMBER && $oldmetatype == 'N') ||
309 ($xmldb_field->getType() == XMLDB_TYPE_FLOAT && $oldmetatype == 'F') ||
310 ($xmldb_field->getType() == XMLDB_TYPE_CHAR && $oldmetatype == 'C') ||
311 ($xmldb_field->getType() == XMLDB_TYPE_TEXT && $oldmetatype == 'X') ||
312 ($xmldb_field->getType() == XMLDB_TYPE_BINARY && $oldmetatype == 'B')) {
313 $typechanged = false;
316 /// If the new field (and old) specs are for integer, let's be a bit more specific differentiating
317 /// types of integers. Else, some combinations can cause things like MDL-21868
318 if ($xmldb_field->getType() == XMLDB_TYPE_INTEGER && $oldmetatype == 'I') {
319 if ($xmldb_field->getLength() > 9) { // Convert our new lenghts to detailed meta types
320 $newmssqlinttype = 'I8';
321 } else if ($xmldb_field->getLength() > 4) {
322 $newmssqlinttype = 'I';
323 } else {
324 $newmssqlinttype = 'I2';
326 if ($metac->type == 'bigint') { // Convert current DB type to detailed meta type (our metatype is not enough!)
327 $oldmssqlinttype = 'I8';
328 } else if ($metac->type == 'smallint') {
329 $oldmssqlinttype = 'I2';
330 } else {
331 $oldmssqlinttype = 'I';
333 if ($newmssqlinttype != $oldmssqlinttype) { // Compare new and old meta types
334 $typechanged = true; // Change in meta type means change in type at all effects
338 /// Detect if we are changing the length of the column, not always necessary to drop defaults
339 /// if only the length changes, but it's safe to do it always
340 if ($xmldb_field->getLength() == $oldlength) {
341 $lengthchanged = false;
344 /// If type or length have changed drop the default if exists
345 if ($typechanged || $lengthchanged) {
346 $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field);
349 /// Some changes of type require multiple alter statements, because mssql lacks direct implicit cast between such types
350 /// Here it is the matrix: http://msdn.microsoft.com/en-us/library/ms187928(SQL.90).aspx
351 /// Going to store such intermediate alters in array of objects, storing all the info needed
352 $multiple_alter_stmt = array();
353 $targettype = $xmldb_field->getType();
355 if ($targettype == XMLDB_TYPE_TEXT && $oldmetatype == 'I') { // integer to text
356 $multiple_alter_stmt[0] = new stdClass; // needs conversion to varchar
357 $multiple_alter_stmt[0]->type = XMLDB_TYPE_CHAR;
358 $multiple_alter_stmt[0]->length = 255;
360 } else if ($targettype == XMLDB_TYPE_TEXT && $oldmetatype == 'N') { // decimal to text
361 $multiple_alter_stmt[0] = new stdClass; // needs conversion to varchar
362 $multiple_alter_stmt[0]->type = XMLDB_TYPE_CHAR;
363 $multiple_alter_stmt[0]->length = 255;
365 } else if ($targettype == XMLDB_TYPE_TEXT && $oldmetatype == 'F') { // float to text
366 $multiple_alter_stmt[0] = new stdClass; // needs conversion to varchar
367 $multiple_alter_stmt[0]->type = XMLDB_TYPE_CHAR;
368 $multiple_alter_stmt[0]->length = 255;
370 } else if ($targettype == XMLDB_TYPE_INTEGER && $oldmetatype == 'X') { // text to integer
371 $multiple_alter_stmt[0] = new stdClass; // needs conversion to varchar
372 $multiple_alter_stmt[0]->type = XMLDB_TYPE_CHAR;
373 $multiple_alter_stmt[0]->length = 255;
374 $multiple_alter_stmt[1] = new stdClass; // and also needs conversion to decimal
375 $multiple_alter_stmt[1]->type = XMLDB_TYPE_NUMBER; // without decimal positions
376 $multiple_alter_stmt[1]->length = 10;
378 } else if ($targettype == XMLDB_TYPE_NUMBER && $oldmetatype == 'X') { // text to decimal
379 $multiple_alter_stmt[0] = new stdClass; // needs conversion to varchar
380 $multiple_alter_stmt[0]->type = XMLDB_TYPE_CHAR;
381 $multiple_alter_stmt[0]->length = 255;
383 } else if ($targettype == XMLDB_TYPE_FLOAT && $oldmetatype == 'X') { // text to float
384 $multiple_alter_stmt[0] = new stdClass; // needs conversion to varchar
385 $multiple_alter_stmt[0]->type = XMLDB_TYPE_CHAR;
386 $multiple_alter_stmt[0]->length = 255;
389 /// Just prevent default clauses in this type of sentences for mssql and launch the parent one
390 if (empty($multiple_alter_stmt)) { // Direct implicit conversion allowed, launch it
391 $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field, NULL, true, NULL));
393 } else { // Direct implicit conversion forbidden, use the intermediate ones
394 $final_type = $xmldb_field->getType(); // Save final type and length
395 $final_length = $xmldb_field->getLength();
396 foreach ($multiple_alter_stmt as $alter) {
397 $xmldb_field->setType($alter->type); // Put our intermediate type and length and alter to it
398 $xmldb_field->setLength($alter->length);
399 $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field, NULL, true, NULL));
401 $xmldb_field->setType($final_type); // Set the final type and length and alter to it
402 $xmldb_field->setLength($final_length);
403 $results = array_merge($results, parent::getAlterFieldSQL($xmldb_table, $xmldb_field, NULL, true, NULL));
406 /// Finally, process the default clause to add it back if necessary
407 if ($typechanged || $lengthchanged) {
408 $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field));
411 /// Return results
412 return $results;
416 * Given one xmldb_table and one xmldb_field, return the SQL statements needed to modify the default of the field in the table
418 public function getModifyDefaultSQL($xmldb_table, $xmldb_field) {
419 /// MSSQL is a bit special with default constraints because it implements them as external constraints so
420 /// normal ALTER TABLE ALTER COLUMN don't work to change defaults. Because this, we have this method overloaded here
422 $results = array();
424 /// Decide if we are going to create/modify or to drop the default
425 if ($xmldb_field->getDefault() === null) {
426 $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop but, under some circumstances, re-enable
427 $default_clause = $this->getDefaultClause($xmldb_field);
428 if ($default_clause) { //If getDefaultClause() it must have one default, create it
429 $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field)); //Create/modify
431 } else {
432 $results = $this->getDropDefaultSQL($xmldb_table, $xmldb_field); //Drop (only if exists)
433 $results = array_merge($results, $this->getCreateDefaultSQL($xmldb_table, $xmldb_field)); //Create/modify
436 return $results;
440 * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its enum
441 * (usually invoked from getModifyEnumSQL()
443 * TODO: Moodle 2.1 - drop in Moodle 2.1
445 public function getDropEnumSQL($xmldb_table, $xmldb_field) {
446 /// Let's introspect to know the real name of the check constraint
447 if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
448 $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
449 $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
450 /// All we have to do is to drop the check constraint
451 return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
452 ' DROP CONSTRAINT ' . $constraint_name);
453 } else { /// Constraint not found. Nothing to do
454 return array();
459 * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its default
460 * (usually invoked from getModifyDefaultSQL()
462 public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
463 /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
465 $results = array();
467 /// Get the quoted name of the table and field
468 $tablename = $this->getTableName($xmldb_table);
469 $fieldname = $this->getEncQuoted($xmldb_field->getName());
471 /// Now, check if, with the current field attributes, we have to build one default
472 $default_clause = $this->getDefaultClause($xmldb_field);
473 if ($default_clause) {
474 /// We need to build the default (Moodle) default, so do it
475 $sql = 'ALTER TABLE ' . $tablename . ' ADD' . $default_clause . ' FOR ' . $fieldname;
476 $results[] = $sql;
479 return $results;
483 * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its default
484 * (usually invoked from getModifyDefaultSQL()
486 public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
487 /// MSSQL is a bit special and it requires the corresponding DEFAULT CONSTRAINT to be dropped
489 $results = array();
491 /// Get the quoted name of the table and field
492 $tablename = $this->getTableName($xmldb_table);
493 $fieldname = $this->getEncQuoted($xmldb_field->getName());
495 /// Look for the default contraint and, if found, drop it
496 if ($defaultname = $this->getDefaultConstraintName($xmldb_table, $xmldb_field)) {
497 $results[] = 'ALTER TABLE ' . $tablename . ' DROP CONSTRAINT ' . $defaultname;
500 return $results;
504 * Given one xmldb_table and one xmldb_field, returns the name of its default constraint in DB
505 * or false if not found
506 * This function should be considered internal and never used outside from generator
508 public function getDefaultConstraintName($xmldb_table, $xmldb_field) {
510 /// Get the quoted name of the table and field
511 $tablename = $this->getTableName($xmldb_table);
512 $fieldname = $xmldb_field->getName();
514 /// Look for any default constraint in this field and drop it
515 if ($default = $this->mdb->get_record_sql("SELECT id, object_name(cdefault) AS defaultconstraint
516 FROM syscolumns
517 WHERE id = object_id(?)
518 AND name = ?", array($tablename, $fieldname))) {
519 return $default->defaultconstraint;
520 } else {
521 return false;
526 * Given one xmldb_table returns one array with all the check constraints
527 * in the table (fetched from DB)
528 * Optionally the function allows one xmldb_field to be specified in
529 * order to return only the check constraints belonging to one field.
530 * Each element contains the name of the constraint and its description
531 * If no check constraints are found, returns an empty array
533 * TODO: Moodle 2.1 - drop in Moodle 2.1
535 public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
538 $results = array();
540 $tablename = $this->getTableName($xmldb_table);
542 if ($constraints = $this->mdb->get_records_sql("SELECT o.name, c.text AS description
543 FROM sysobjects o,
544 sysobjects p,
545 syscomments c
546 WHERE p.id = o.parent_obj
547 AND o.id = c.id
548 AND o.xtype = 'C'
549 AND p.name = ?", array($tablename))) {
550 foreach ($constraints as $constraint) {
551 $results[$constraint->name] = $constraint;
555 /// Filter by the required field if specified
556 if ($xmldb_field) {
557 $filtered_results = array();
558 $filter = $xmldb_field->getName();
559 /// Lets clean a bit each constraint description, looking for the filtered field
560 foreach ($results as $key => $result) {
561 $description = trim(preg_replace('/[\(\)]/', '', $result->description)); // Parenthesis out & trim
562 /// description starts by [$filter] assume it's a constraint belonging to the field
563 if (preg_match("/^\[{$filter}\]/i", $description)) {
564 $filtered_results[$key] = $result;
567 /// Assign filtered results to the final results array
568 $results = $filtered_results;
571 return $results;
575 * Given three strings (table name, list of fields (comma separated) and suffix),
576 * create the proper object name quoting it if necessary.
578 * IMPORTANT: This function must be used to CALCULATE NAMES of objects TO BE CREATED,
579 * NEVER TO GUESS NAMES of EXISTING objects!!!
581 * IMPORTANT: We are overriding this function for the MSSQL generator because objects
582 * belonging to temporary tables aren't searchable in the catalog neither in information
583 * schema tables. So, for temporary tables, we are going to add 4 randomly named "virtual"
584 * fields, so the generated names won't cause concurrency problems. Really nasty hack,
585 * but the alternative involves modifying all the creation table code to avoid naming
586 * constraints for temp objects and that will dupe a lot of code.
589 public function getNameForObject($tablename, $fields, $suffix='') {
590 if ($this->temptables->is_temptable($tablename)) { // Is temp table, inject random field names
591 $random = strtolower(random_string(12)); // 12cc to be split in 4 parts
592 $fields = $fields . ', ' . implode(', ', str_split($random, 3));
594 return parent::getNameForObject($tablename, $fields, $suffix); // Delegate to parent (common) algorithm
598 * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
599 * return if such name is currently in use (true) or no (false)
600 * (invoked from getNameForObject()
602 public function isNameInUse($object_name, $type, $table_name) {
603 switch($type) {
604 case 'seq':
605 case 'trg':
606 case 'pk':
607 case 'uk':
608 case 'fk':
609 case 'ck':
610 if ($check = $this->mdb->get_records_sql("SELECT name
611 FROM sysobjects
612 WHERE lower(name) = ?", array(strtolower($object_name)))) {
613 return true;
615 break;
616 case 'ix':
617 case 'uix':
618 if ($check = $this->mdb->get_records_sql("SELECT name
619 FROM sysindexes
620 WHERE lower(name) = ?", array(strtolower($object_name)))) {
621 return true;
623 break;
625 return false; //No name in use found
629 * Returns the code (in array) needed to add one comment to the table
631 public function getCommentSQL($xmldb_table) {
632 return array();
635 public function addslashes($s) {
636 // do not use php addslashes() because it depends on PHP quote settings!
637 $s = str_replace("'", "''", $s);
638 return $s;
642 * Returns an array of reserved words (lowercase) for this DB
644 public static function getReservedWords() {
645 /// This file contains the reserved words for MSSQL databases
646 /// from http://msdn2.microsoft.com/en-us/library/ms189822.aspx
647 $reserved_words = array (
648 'add', 'all', 'alter', 'and', 'any', 'as', 'asc', 'authorization',
649 'avg', 'backup', 'begin', 'between', 'break', 'browse', 'bulk',
650 'by', 'cascade', 'case', 'check', 'checkpoint', 'close', 'clustered',
651 'coalesce', 'collate', 'column', 'commit', 'committed', 'compute',
652 'confirm', 'constraint', 'contains', 'containstable', 'continue',
653 'controlrow', 'convert', 'count', 'create', 'cross', 'current',
654 'current_date', 'current_time', 'current_timestamp', 'current_user',
655 'cursor', 'database', 'dbcc', 'deallocate', 'declare', 'default', 'delete',
656 'deny', 'desc', 'disk', 'distinct', 'distributed', 'double', 'drop', 'dummy',
657 'dump', 'else', 'end', 'errlvl', 'errorexit', 'escape', 'except', 'exec',
658 'execute', 'exists', 'exit', 'external', 'fetch', 'file', 'fillfactor', 'floppy',
659 'for', 'foreign', 'freetext', 'freetexttable', 'from', 'full', 'function',
660 'goto', 'grant', 'group', 'having', 'holdlock', 'identity', 'identitycol',
661 'identity_insert', 'if', 'in', 'index', 'inner', 'insert', 'intersect', 'into',
662 'is', 'isolation', 'join', 'key', 'kill', 'left', 'level', 'like', 'lineno',
663 'load', 'max', 'min', 'mirrorexit', 'national', 'nocheck', 'nonclustered',
664 'not', 'null', 'nullif', 'of', 'off', 'offsets', 'on', 'once', 'only', 'open',
665 'opendatasource', 'openquery', 'openrowset', 'openxml', 'option', 'or', 'order',
666 'outer', 'over', 'percent', 'perm', 'permanent', 'pipe', 'pivot', 'plan', 'precision',
667 'prepare', 'primary', 'print', 'privileges', 'proc', 'procedure', 'processexit',
668 'public', 'raiserror', 'read', 'readtext', 'reconfigure', 'references',
669 'repeatable', 'replication', 'restore', 'restrict', 'return', 'revoke',
670 'right', 'rollback', 'rowcount', 'rowguidcol', 'rule', 'save', 'schema',
671 'select', 'serializable', 'session_user', 'set', 'setuser', 'shutdown', 'some',
672 'statistics', 'sum', 'system_user', 'table', 'tape', 'temp', 'temporary',
673 'textsize', 'then', 'to', 'top', 'tran', 'transaction', 'trigger', 'truncate',
674 'tsequal', 'uncommitted', 'union', 'unique', 'update', 'updatetext', 'use',
675 'user', 'values', 'varying', 'view', 'waitfor', 'when', 'where', 'while',
676 'with', 'work', 'writetext'
678 return $reserved_words;