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