source: moodle/trunk/fuentes/lib/ddl/mysql_sql_generator.php @ 1331

Last change on this file since 1331 was 1331, checked in by jrpelegrina, 3 years ago

Updated to moodle 3.0.3

File size: 25.9 KB
Line 
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Mysql specific SQL code generator.
19 *
20 * @package    core_ddl
21 * @copyright  1999 onwards Martin Dougiamas     http://dougiamas.com
22 *             2001-3001 Eloy Lafuente (stronk7) http://contiento.com
23 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28require_once($CFG->libdir.'/ddl/sql_generator.php');
29
30/**
31 * This class generate SQL code to be used against MySQL
32 * It extends XMLDBgenerator so everything can be
33 * overridden as needed to generate correct SQL.
34 *
35 * @package    core_ddl
36 * @copyright  1999 onwards Martin Dougiamas     http://dougiamas.com
37 *             2001-3001 Eloy Lafuente (stronk7) http://contiento.com
38 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 */
40class mysql_sql_generator extends sql_generator {
41
42    // Only set values that are different from the defaults present in XMLDBgenerator
43
44    /** @var string Used to quote names. */
45    public $quote_string = '`';
46
47    /** @var string To define the default to set for NOT NULLs CHARs without default (null=do nothing).*/
48    public $default_for_char = '';
49
50    /** @var bool To specify if the generator must use some DEFAULT clause to drop defaults.*/
51    public $drop_default_value_required = true;
52
53    /** @var string The DEFAULT clause required to drop defaults.*/
54    public $drop_default_value = null;
55
56    /** @var string To force primary key names to one string (null=no force).*/
57    public $primary_key_name = '';
58
59    /** @var string Template to drop PKs. 'TABLENAME' and 'KEYNAME' will be replaced from this template.*/
60    public $drop_primary_key = 'ALTER TABLE TABLENAME DROP PRIMARY KEY';
61
62    /** @var string Template to drop UKs. 'TABLENAME' and 'KEYNAME' will be replaced from this template.*/
63    public $drop_unique_key = 'ALTER TABLE TABLENAME DROP KEY KEYNAME';
64
65    /** @var string Template to drop FKs. 'TABLENAME' and 'KEYNAME' will be replaced from this template.*/
66    public $drop_foreign_key = 'ALTER TABLE TABLENAME DROP FOREIGN KEY KEYNAME';
67
68    /** @var bool True if the generator needs to add extra code to generate the sequence fields.*/
69    public $sequence_extra_code = false;
70
71    /** @var string The particular name for inline sequences in this generator.*/
72    public $sequence_name = 'auto_increment';
73
74    public $add_after_clause = true; // Does the generator need to add the after clause for fields
75
76    /** @var string Characters to be used as concatenation operator.*/
77    public $concat_character = null;
78
79    /** @var string The SQL template to alter columns where the 'TABLENAME' and 'COLUMNSPECS' keywords are dynamically replaced.*/
80    public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY COLUMN COLUMNSPECS';
81
82    /** @var string SQL sentence to drop one index where 'TABLENAME', 'INDEXNAME' keywords are dynamically replaced.*/
83    public $drop_index_sql = 'ALTER TABLE TABLENAME DROP INDEX INDEXNAME';
84
85    /** @var string SQL sentence to rename one index where 'TABLENAME', 'OLDINDEXNAME' and 'NEWINDEXNAME' are dynamically replaced.*/
86    public $rename_index_sql = null;
87
88    /** @var string SQL sentence to rename one key 'TABLENAME', 'OLDKEYNAME' and 'NEWKEYNAME' are dynamically replaced.*/
89    public $rename_key_sql = null;
90
91    /** Maximum size of InnoDB row in Antelope file format */
92    const ANTELOPE_MAX_ROW_SIZE = 8126;
93
94    /**
95     * Reset a sequence to the id field of a table.
96     *
97     * @param xmldb_table|string $table name of table or the table object.
98     * @return array of sql statements
99     */
100    public function getResetSequenceSQL($table) {
101
102        if ($table instanceof xmldb_table) {
103            $tablename = $table->getName();
104        } else {
105            $tablename = $table;
106        }
107
108        // From http://dev.mysql.com/doc/refman/5.0/en/alter-table.html
109        $value = (int)$this->mdb->get_field_sql('SELECT MAX(id) FROM {'.$tablename.'}');
110        $value++;
111        return array("ALTER TABLE $this->prefix$tablename AUTO_INCREMENT = $value");
112    }
113
114    /**
115     * Calculate proximate row size when using InnoDB
116     * tables in Antelope row format.
117     *
118     * Note: the returned value is a bit higher to compensate for
119     *       errors and changes of column data types.
120     *
121     * @deprecated since Moodle 2.9 MDL-49723 - please do not use this function any more.
122     * @param xmldb_field[]|database_column_info[] $columns
123     * @return int approximate row size in bytes
124     */
125    public function guess_antolope_row_size(array $columns) {
126        debugging('guess_antolope_row_size() is deprecated, please use guess_antelope_row_size() instead.', DEBUG_DEVELOPER);
127        return $this->guess_antelope_row_size($columns);
128    }
129
130    /**
131     * Calculate proximate row size when using InnoDB tables in Antelope row format.
132     *
133     * Note: the returned value is a bit higher to compensate for errors and changes of column data types.
134     *
135     * @param xmldb_field[]|database_column_info[] $columns
136     * @return int approximate row size in bytes
137     */
138    public function guess_antelope_row_size(array $columns) {
139
140        if (empty($columns)) {
141            return 0;
142        }
143
144        $size = 0;
145        $first = reset($columns);
146
147        if (count($columns) > 1) {
148            // Do not start with zero because we need to cover changes of field types and
149            // this calculation is most probably not be accurate.
150            $size += 1000;
151        }
152
153        if ($first instanceof xmldb_field) {
154            foreach ($columns as $field) {
155                switch ($field->getType()) {
156                    case XMLDB_TYPE_TEXT:
157                        $size += 768;
158                        break;
159                    case XMLDB_TYPE_BINARY:
160                        $size += 768;
161                        break;
162                    case XMLDB_TYPE_CHAR:
163                        $bytes = $field->getLength() * 3;
164                        if ($bytes > 768) {
165                            $bytes = 768;
166                        }
167                        $size += $bytes;
168                        break;
169                    default:
170                        // Anything else is usually maximum 8 bytes.
171                        $size += 8;
172                }
173            }
174
175        } else if ($first instanceof database_column_info) {
176            foreach ($columns as $column) {
177                switch ($column->meta_type) {
178                    case 'X':
179                        $size += 768;
180                        break;
181                    case 'B':
182                        $size += 768;
183                        break;
184                    case 'C':
185                        $bytes = $column->max_length * 3;
186                        if ($bytes > 768) {
187                            $bytes = 768;
188                        }
189                        $size += $bytes;
190                        break;
191                    default:
192                        // Anything else is usually maximum 8 bytes.
193                        $size += 8;
194                }
195            }
196        }
197
198        return $size;
199    }
200
201    /**
202     * Given one correct xmldb_table, returns the SQL statements
203     * to create it (inside one array).
204     *
205     * @param xmldb_table $xmldb_table An xmldb_table instance.
206     * @return array An array of SQL statements, starting with the table creation SQL followed
207     * by any of its comments, indexes and sequence creation SQL statements.
208     */
209    public function getCreateTableSQL($xmldb_table) {
210        // First find out if want some special db engine.
211        $engine = $this->mdb->get_dbengine();
212        // Do we know collation?
213        $collation = $this->mdb->get_dbcollation();
214
215        // Do we need to use compressed format for rows?
216        $rowformat = "";
217        $size = $this->guess_antelope_row_size($xmldb_table->getFields());
218        if ($size > self::ANTELOPE_MAX_ROW_SIZE) {
219            if ($this->mdb->is_compressed_row_format_supported()) {
220                $rowformat = "\n ROW_FORMAT=Compressed";
221            }
222        }
223
224        $sqlarr = parent::getCreateTableSQL($xmldb_table);
225
226        // This is a very nasty hack that tries to use just one query per created table
227        // because MySQL is stupidly slow when modifying empty tables.
228        // Note: it is safer to inject everything on new lines because there might be some trailing -- comments.
229        $sqls = array();
230        $prevcreate = null;
231        $matches = null;
232        foreach ($sqlarr as $sql) {
233            if (preg_match('/^CREATE TABLE ([^ ]+)/', $sql, $matches)) {
234                $prevcreate = $matches[1];
235                $sql = preg_replace('/\s*\)\s*$/s', '/*keyblock*/)', $sql);
236                // Let's inject the extra MySQL tweaks here.
237                if ($engine) {
238                    $sql .= "\n ENGINE = $engine";
239                }
240                if ($collation) {
241                    if (strpos($collation, 'utf8_') === 0) {
242                        $sql .= "\n DEFAULT CHARACTER SET utf8";
243                    }
244                    $sql .= "\n DEFAULT COLLATE = $collation";
245                }
246                if ($rowformat) {
247                    $sql .= $rowformat;
248                }
249                $sqls[] = $sql;
250                continue;
251            }
252            if ($prevcreate) {
253                if (preg_match('/^ALTER TABLE '.$prevcreate.' COMMENT=(.*)$/s', $sql, $matches)) {
254                    $prev = array_pop($sqls);
255                    $prev .= "\n COMMENT=$matches[1]";
256                    $sqls[] = $prev;
257                    continue;
258                }
259                if (preg_match('/^CREATE INDEX ([^ ]+) ON '.$prevcreate.' (.*)$/s', $sql, $matches)) {
260                    $prev = array_pop($sqls);
261                    if (strpos($prev, '/*keyblock*/')) {
262                        $prev = str_replace('/*keyblock*/', "\n, KEY $matches[1] $matches[2]/*keyblock*/", $prev);
263                        $sqls[] = $prev;
264                        continue;
265                    } else {
266                        $sqls[] = $prev;
267                    }
268                }
269                if (preg_match('/^CREATE UNIQUE INDEX ([^ ]+) ON '.$prevcreate.' (.*)$/s', $sql, $matches)) {
270                    $prev = array_pop($sqls);
271                    if (strpos($prev, '/*keyblock*/')) {
272                        $prev = str_replace('/*keyblock*/', "\n, UNIQUE KEY $matches[1] $matches[2]/*keyblock*/", $prev);
273                        $sqls[] = $prev;
274                        continue;
275                    } else {
276                        $sqls[] = $prev;
277                    }
278                }
279            }
280            $prevcreate = null;
281            $sqls[] = $sql;
282        }
283
284        foreach ($sqls as $key => $sql) {
285            $sqls[$key] = str_replace('/*keyblock*/', "\n", $sql);
286        }
287
288        return $sqls;
289    }
290
291    /**
292     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to add the field to the table.
293     *
294     * @param xmldb_table $xmldb_table The table related to $xmldb_field.
295     * @param xmldb_field $xmldb_field The instance of xmldb_field to create the SQL from.
296     * @param string $skip_type_clause The type clause on alter columns, NULL by default.
297     * @param string $skip_default_clause The default clause on alter columns, NULL by default.
298     * @param string $skip_notnull_clause The null/notnull clause on alter columns, NULL by default.
299     * @return array The SQL statement for adding a field to the table.
300     */
301    public function getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause = NULL, $skip_default_clause = NULL, $skip_notnull_clause = NULL) {
302        $sqls = parent::getAddFieldSQL($xmldb_table, $xmldb_field, $skip_type_clause, $skip_default_clause, $skip_notnull_clause);
303
304        if ($this->table_exists($xmldb_table)) {
305            $tablename = $xmldb_table->getName();
306
307            $size = $this->guess_antelope_row_size($this->mdb->get_columns($tablename));
308            $size += $this->guess_antelope_row_size(array($xmldb_field));
309
310            if ($size > self::ANTELOPE_MAX_ROW_SIZE) {
311                if ($this->mdb->is_compressed_row_format_supported()) {
312                    $format = strtolower($this->mdb->get_row_format($tablename));
313                    if ($format === 'compact' or $format === 'redundant') {
314                        // Change the format before conversion so that we do not run out of space.
315                        array_unshift($sqls, "ALTER TABLE {$this->prefix}$tablename ROW_FORMAT=Compressed");
316                    }
317                }
318            }
319        }
320
321        return $sqls;
322    }
323
324    /**
325     * Given one correct xmldb_table, returns the SQL statements
326     * to create temporary table (inside one array).
327     *
328     * @param xmldb_table $xmldb_table The xmldb_table object instance.
329     * @return array of sql statements
330     */
331    public function getCreateTempTableSQL($xmldb_table) {
332        // Do we know collation?
333        $collation = $this->mdb->get_dbcollation();
334        $this->temptables->add_temptable($xmldb_table->getName());
335
336        $sqlarr = parent::getCreateTableSQL($xmldb_table);
337
338        // Let's inject the extra MySQL tweaks.
339        foreach ($sqlarr as $i=>$sql) {
340            if (strpos($sql, 'CREATE TABLE ') === 0) {
341                // We do not want the engine hack included in create table SQL.
342                $sqlarr[$i] = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sql);
343                if ($collation) {
344                    if (strpos($collation, 'utf8_') === 0) {
345                        $sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
346                    }
347                    $sqlarr[$i] .= " DEFAULT COLLATE $collation";
348                }
349            }
350        }
351
352        return $sqlarr;
353    }
354
355    /**
356     * Given one correct xmldb_table, returns the SQL statements
357     * to drop it (inside one array).
358     *
359     * @param xmldb_table $xmldb_table The table to drop.
360     * @return array SQL statement(s) for dropping the specified table.
361     */
362    public function getDropTableSQL($xmldb_table) {
363        $sqlarr = parent::getDropTableSQL($xmldb_table);
364        if ($this->temptables->is_temptable($xmldb_table->getName())) {
365            $sqlarr = preg_replace('/^DROP TABLE/', "DROP TEMPORARY TABLE", $sqlarr);
366            $this->temptables->delete_temptable($xmldb_table->getName());
367        }
368        return $sqlarr;
369    }
370
371    /**
372     * Given one XMLDB Type, length and decimals, returns the DB proper SQL type.
373     *
374     * @param int $xmldb_type The xmldb_type defined constant. XMLDB_TYPE_INTEGER and other XMLDB_TYPE_* constants.
375     * @param int $xmldb_length The length of that data type.
376     * @param int $xmldb_decimals The decimal places of precision of the data type.
377     * @return string The DB defined data type.
378     */
379    public function getTypeSQL($xmldb_type, $xmldb_length=null, $xmldb_decimals=null) {
380
381        switch ($xmldb_type) {
382            case XMLDB_TYPE_INTEGER:    // From http://mysql.com/doc/refman/5.0/en/numeric-types.html!
383                if (empty($xmldb_length)) {
384                    $xmldb_length = 10;
385                }
386                if ($xmldb_length > 9) {
387                    $dbtype = 'BIGINT';
388                } else if ($xmldb_length > 6) {
389                    $dbtype = 'INT';
390                } else if ($xmldb_length > 4) {
391                    $dbtype = 'MEDIUMINT';
392                } else if ($xmldb_length > 2) {
393                    $dbtype = 'SMALLINT';
394                } else {
395                    $dbtype = 'TINYINT';
396                }
397                $dbtype .= '(' . $xmldb_length . ')';
398                break;
399            case XMLDB_TYPE_NUMBER:
400                $dbtype = $this->number_type;
401                if (!empty($xmldb_length)) {
402                    $dbtype .= '(' . $xmldb_length;
403                    if (!empty($xmldb_decimals)) {
404                        $dbtype .= ',' . $xmldb_decimals;
405                    }
406                    $dbtype .= ')';
407                }
408                break;
409            case XMLDB_TYPE_FLOAT:
410                $dbtype = 'DOUBLE';
411                if (!empty($xmldb_decimals)) {
412                    if ($xmldb_decimals < 6) {
413                        $dbtype = 'FLOAT';
414                    }
415                }
416                if (!empty($xmldb_length)) {
417                    $dbtype .= '(' . $xmldb_length;
418                    if (!empty($xmldb_decimals)) {
419                        $dbtype .= ',' . $xmldb_decimals;
420                    } else {
421                        $dbtype .= ', 0'; // In MySQL, if length is specified, decimals are mandatory for FLOATs
422                    }
423                    $dbtype .= ')';
424                }
425                break;
426            case XMLDB_TYPE_CHAR:
427                $dbtype = 'VARCHAR';
428                if (empty($xmldb_length)) {
429                    $xmldb_length='255';
430                }
431                $dbtype .= '(' . $xmldb_length . ')';
432                if ($collation = $this->mdb->get_dbcollation()) {
433                    if (strpos($collation, 'utf8_') === 0) {
434                        $dbtype .= " CHARACTER SET utf8";
435                    }
436                    $dbtype .= " COLLATE $collation";
437                }
438                break;
439            case XMLDB_TYPE_TEXT:
440                $dbtype = 'LONGTEXT';
441                if ($collation = $this->mdb->get_dbcollation()) {
442                    if (strpos($collation, 'utf8_') === 0) {
443                        $dbtype .= " CHARACTER SET utf8";
444                    }
445                    $dbtype .= " COLLATE $collation";
446                }
447                break;
448            case XMLDB_TYPE_BINARY:
449                $dbtype = 'LONGBLOB';
450                break;
451            case XMLDB_TYPE_DATETIME:
452                $dbtype = 'DATETIME';
453        }
454        return $dbtype;
455    }
456
457    /**
458     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to add its default
459     * (usually invoked from getModifyDefaultSQL()
460     *
461     * @param xmldb_table $xmldb_table The xmldb_table object instance.
462     * @param xmldb_field $xmldb_field The xmldb_field object instance.
463     * @return array Array of SQL statements to create a field's default.
464     */
465    public function getCreateDefaultSQL($xmldb_table, $xmldb_field) {
466        // Just a wrapper over the getAlterFieldSQL() function for MySQL that
467        // is capable of handling defaults
468        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
469    }
470
471    /**
472     * Given one correct xmldb_field and the new name, returns the SQL statements
473     * to rename it (inside one array).
474     *
475     * @param xmldb_table $xmldb_table The table related to $xmldb_field.
476     * @param xmldb_field $xmldb_field The instance of xmldb_field to get the renamed field from.
477     * @param string $newname The new name to rename the field to.
478     * @return array The SQL statements for renaming the field.
479     */
480    public function getRenameFieldSQL($xmldb_table, $xmldb_field, $newname) {
481        // NOTE: MySQL is pretty different from the standard to justify this overloading.
482
483        // Need a clone of xmldb_field to perform the change leaving original unmodified
484        $xmldb_field_clone = clone($xmldb_field);
485
486        // Change the name of the field to perform the change
487        $xmldb_field_clone->setName($newname);
488
489        $fieldsql = $this->getFieldSQL($xmldb_table, $xmldb_field_clone);
490
491        $sql = 'ALTER TABLE ' . $this->getTableName($xmldb_table) . ' CHANGE ' .
492               $xmldb_field->getName() . ' ' . $fieldsql;
493
494        return array($sql);
495    }
496
497    /**
498     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its default
499     * (usually invoked from getModifyDefaultSQL()
500     *
501     * Note that this method may be dropped in future.
502     *
503     * @param xmldb_table $xmldb_table The xmldb_table object instance.
504     * @param xmldb_field $xmldb_field The xmldb_field object instance.
505     * @return array Array of SQL statements to create a field's default.
506     *
507     * @todo MDL-31147 Moodle 2.1 - Drop getDropDefaultSQL()
508     */
509    public function getDropDefaultSQL($xmldb_table, $xmldb_field) {
510        // Just a wrapper over the getAlterFieldSQL() function for MySQL that
511        // is capable of handling defaults
512        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
513    }
514
515    /**
516     * Returns the code (array of statements) needed to add one comment to the table.
517     *
518     * @param xmldb_table $xmldb_table The xmldb_table object instance.
519     * @return array Array of SQL statements to add one comment to the table.
520     */
521    function getCommentSQL ($xmldb_table) {
522        $comment = '';
523
524        if ($xmldb_table->getComment()) {
525            $comment .= 'ALTER TABLE ' . $this->getTableName($xmldb_table);
526            $comment .= " COMMENT='" . $this->addslashes(substr($xmldb_table->getComment(), 0, 60)) . "'";
527        }
528        return array($comment);
529    }
530
531    /**
532     * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg).
533     *
534     * (MySQL requires the whole xmldb_table object to be specified, so we add it always)
535     *
536     * This is invoked from getNameForObject().
537     * Only some DB have this implemented.
538     *
539     * @param string $object_name The object's name to check for.
540     * @param string $type The object's type (pk, uk, fk, ck, ix, uix, seq, trg).
541     * @param string $table_name The table's name to check in
542     * @return bool If such name is currently in use (true) or no (false)
543     */
544    public function isNameInUse($object_name, $type, $table_name) {
545
546        switch($type) {
547            case 'ix':
548            case 'uix':
549                // First of all, check table exists
550                $metatables = $this->mdb->get_tables();
551                if (isset($metatables[$table_name])) {
552                    // Fetch all the indexes in the table
553                    if ($indexes = $this->mdb->get_indexes($table_name)) {
554                        // Look for existing index in array
555                        if (isset($indexes[$object_name])) {
556                            return true;
557                        }
558                    }
559                }
560                break;
561        }
562        return false; //No name in use found
563    }
564
565
566    /**
567     * Returns an array of reserved words (lowercase) for this DB
568     * @return array An array of database specific reserved words
569     */
570    public static function getReservedWords() {
571        // This file contains the reserved words for MySQL databases
572        // from http://dev.mysql.com/doc/refman/6.0/en/reserved-words.html
573        $reserved_words = array (
574            'accessible', 'add', 'all', 'alter', 'analyze', 'and', 'as', 'asc',
575            'asensitive', 'before', 'between', 'bigint', 'binary',
576            'blob', 'both', 'by', 'call', 'cascade', 'case', 'change',
577            'char', 'character', 'check', 'collate', 'column',
578            'condition', 'connection', 'constraint', 'continue',
579            'convert', 'create', 'cross', 'current_date', 'current_time',
580            'current_timestamp', 'current_user', 'cursor', 'database',
581            'databases', 'day_hour', 'day_microsecond',
582            'day_minute', 'day_second', 'dec', 'decimal', 'declare',
583            'default', 'delayed', 'delete', 'desc', 'describe',
584            'deterministic', 'distinct', 'distinctrow', 'div', 'double',
585            'drop', 'dual', 'each', 'else', 'elseif', 'enclosed', 'escaped',
586            'exists', 'exit', 'explain', 'false', 'fetch', 'float', 'float4',
587            'float8', 'for', 'force', 'foreign', 'from', 'fulltext', 'grant',
588            'group', 'having', 'high_priority', 'hour_microsecond',
589            'hour_minute', 'hour_second', 'if', 'ignore', 'in', 'index',
590            'infile', 'inner', 'inout', 'insensitive', 'insert', 'int', 'int1',
591            'int2', 'int3', 'int4', 'int8', 'integer', 'interval', 'into', 'is',
592            'iterate', 'join', 'key', 'keys', 'kill', 'leading', 'leave', 'left',
593            'like', 'limit', 'linear', 'lines', 'load', 'localtime', 'localtimestamp',
594            'lock', 'long', 'longblob', 'longtext', 'loop', 'low_priority', 'master_heartbeat_period',
595            'master_ssl_verify_server_cert', 'match', 'mediumblob', 'mediumint', 'mediumtext',
596            'middleint', 'minute_microsecond', 'minute_second',
597            'mod', 'modifies', 'natural', 'not', 'no_write_to_binlog',
598            'null', 'numeric', 'on', 'optimize', 'option', 'optionally',
599            'or', 'order', 'out', 'outer', 'outfile', 'overwrite', 'precision', 'primary',
600            'procedure', 'purge', 'raid0', 'range', 'read', 'read_only', 'read_write', 'reads', 'real',
601            'references', 'regexp', 'release', 'rename', 'repeat', 'replace',
602            'require', 'restrict', 'return', 'revoke', 'right', 'rlike', 'schema',
603            'schemas', 'second_microsecond', 'select', 'sensitive',
604            'separator', 'set', 'show', 'smallint', 'soname', 'spatial',
605            'specific', 'sql', 'sqlexception', 'sqlstate', 'sqlwarning',
606            'sql_big_result', 'sql_calc_found_rows', 'sql_small_result',
607            'ssl', 'starting', 'straight_join', 'table', 'terminated', 'then',
608            'tinyblob', 'tinyint', 'tinytext', 'to', 'trailing', 'trigger', 'true',
609            'undo', 'union', 'unique', 'unlock', 'unsigned', 'update',
610            'upgrade', 'usage', 'use', 'using', 'utc_date', 'utc_time',
611            'utc_timestamp', 'values', 'varbinary', 'varchar', 'varcharacter',
612            'varying', 'when', 'where', 'while', 'with', 'write', 'x509',
613            'xor', 'year_month', 'zerofill'
614        );
615        return $reserved_words;
616    }
617}
Note: See TracBrowser for help on using the repository browser.