001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.sequencer.ddl.dialect.mysql; 017 018import static org.modeshape.sequencer.ddl.StandardDdlLexicon.DDL_EXPRESSION; 019import static org.modeshape.sequencer.ddl.StandardDdlLexicon.DDL_ORIGINAL_EXPRESSION; 020import static org.modeshape.sequencer.ddl.StandardDdlLexicon.DDL_START_CHAR_INDEX; 021import static org.modeshape.sequencer.ddl.StandardDdlLexicon.DDL_START_COLUMN_NUMBER; 022import static org.modeshape.sequencer.ddl.StandardDdlLexicon.DDL_START_LINE_NUMBER; 023import static org.modeshape.sequencer.ddl.StandardDdlLexicon.NEW_NAME; 024import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_ALGORITHM_STATEMENT; 025import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_DATABASE_STATEMENT; 026import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_DEFINER_STATEMENT; 027import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_EVENT_STATEMENT; 028import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_FUNCTION_STATEMENT; 029import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_LOGFILE_GROUP_STATEMENT; 030import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_PROCEDURE_STATEMENT; 031import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_SCHEMA_STATEMENT; 032import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_SERVER_STATEMENT; 033import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_TABLESPACE_STATEMENT; 034import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_ALTER_VIEW_STATEMENT; 035import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_DEFINER_STATEMENT; 036import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_EVENT_STATEMENT; 037import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_FUNCTION_STATEMENT; 038import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_INDEX_STATEMENT; 039import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_PROCEDURE_STATEMENT; 040import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_SERVER_STATEMENT; 041import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_TABLESPACE_STATEMENT; 042import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_CREATE_TRIGGER_STATEMENT; 043import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_DATABASE_STATEMENT; 044import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_EVENT_STATEMENT; 045import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_FUNCTION_STATEMENT; 046import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_INDEX_STATEMENT; 047import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_LOGFILE_GROUP_STATEMENT; 048import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_PROCEDURE_STATEMENT; 049import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_SERVER_STATEMENT; 050import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_TABLESPACE_STATEMENT; 051import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_DROP_TRIGGER_STATEMENT; 052import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_RENAME_DATABASE_STATEMENT; 053import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_RENAME_SCHEMA_STATEMENT; 054import static org.modeshape.sequencer.ddl.dialect.mysql.MySqlDdlLexicon.TYPE_RENAME_TABLE_STATEMENT; 055import java.util.ArrayList; 056import java.util.List; 057import org.modeshape.common.text.ParsingException; 058import org.modeshape.common.text.TokenStream; 059import org.modeshape.sequencer.ddl.DdlTokenStream; 060import org.modeshape.sequencer.ddl.StandardDdlParser; 061import org.modeshape.sequencer.ddl.datatype.DataType; 062import org.modeshape.sequencer.ddl.datatype.DataTypeParser; 063import org.modeshape.sequencer.ddl.node.AstNode; 064 065/** 066 * MySql-specific DDL Parser. Includes custom data types as well as custom DDL statements. 067 */ 068public class MySqlDdlParser extends StandardDdlParser implements MySqlDdlConstants, MySqlDdlConstants.MySqlStatementStartPhrases { 069 /** 070 * The MySQL parser identifier. 071 */ 072 public static final String ID = "MYSQL"; 073 074 static List<String[]> mysqlDataTypeStrings = new ArrayList<String[]>(); 075 /* 076 * =========================================================================================================================== 077 * Data Definition Statements 078 ALTER [DATABASE | EVENT | FUNCTION | SERVER | TABLE | VIEW] 079 CREATE [DATABASE | EVENT | FUNCTION | INDEX | PROCEDURE | SERVER | TABLE | TRIGGER | VIEW] 080 DROP [DATABASE | EVENT | FUNCTION | INDEX | PROCEDURE | SERVER | TABLE | TRIGGER | VIEW] 081 RENAME TABLE 082 */ 083 084 /* 085 * =========================================================================================================================== 086 * CREATE TABLE 087 088 CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name 089 (create_definition,...) 090 [table_options] 091 [partition_options] 092 093 Or: 094 095 CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name 096 [(create_definition,...)] 097 [table_options] 098 [partition_options] 099 select_statement 100 101 Or: 102 103 CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name 104 { LIKE old_tbl_name | (LIKE old_tbl_name) } 105 106 create_definition: 107 col_name column_definition 108 | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) 109 [index_option] ... 110 | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) 111 [index_option] ... 112 | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] 113 [index_name] [index_type] (index_col_name,...) 114 [index_option] ... 115 | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...) 116 [index_option] ... 117 | [CONSTRAINT [symbol]] FOREIGN KEY 118 [index_name] (index_col_name,...) reference_definition 119 | CHECK (expr) 120 121 column_definition: 122 data_type [NOT NULL | NULL] [DEFAULT default_value] 123 [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] 124 [COMMENT 'string'] 125 [COLUMN_FORMAT {FIXED|DYNAMIC|DEFAULT}] 126 [STORAGE {DISK|MEMORY|DEFAULT}] 127 [reference_definition] 128 129 index_col_name: 130 col_name [(length)] [ASC | DESC] 131 132 index_type: 133 USING {BTREE | HASH | RTREE} 134 135 index_option: 136 KEY_BLOCK_SIZE [=] value 137 | index_type 138 | WITH PARSER parser_name 139 140 reference_definition: 141 REFERENCES tbl_name (index_col_name,...) 142 [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] 143 [ON DELETE reference_option] 144 [ON UPDATE reference_option] 145 146 reference_option: 147 RESTRICT | CASCADE | SET NULL | NO ACTION 148 149 table_options: 150 table_option [[,] table_option] ... 151 152 table_option: 153 ENGINE [=] engine_name 154 | AUTO_INCREMENT [=] value 155 | AVG_ROW_LENGTH [=] value 156 | [DEFAULT] CHARACTER SET [=] charset_name 157 | CHECKSUM [=] {0 | 1} 158 | [DEFAULT] COLLATE [=] collation_name 159 | COMMENT [=] 'string' 160 | CONNECTION [=] 'connect_string' 161 | DATA DIRECTORY [=] 'absolute path to directory' 162 | DELAY_KEY_WRITE [=] {0 | 1} 163 | INDEX DIRECTORY [=] 'absolute path to directory' 164 | INSERT_METHOD [=] { NO | FIRST | LAST } 165 | KEY_BLOCK_SIZE [=] value 166 | MAX_ROWS [=] value 167 | MIN_ROWS [=] value 168 | PACK_KEYS [=] {0 | 1 | DEFAULT} 169 | PASSWORD [=] 'string' 170 | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} 171 | TABLESPACE tablespace_name [STORAGE {DISK|MEMORY|DEFAULT}] 172 | UNION [=] (tbl_name[,tbl_name]...) 173 174 partition_options: 175 PARTITION BY 176 { [LINEAR] HASH(expr) 177 | [LINEAR] KEY(column_list) 178 | RANGE(expr) 179 | LIST(expr) } 180 [PARTITIONS num] 181 [SUBPARTITION BY 182 { [LINEAR] HASH(expr) 183 | [LINEAR] KEY(column_list) } 184 [SUBPARTITIONS num] 185 ] 186 [(partition_definition [, partition_definition] ...)] 187 188 partition_definition: 189 PARTITION partition_name 190 [VALUES {LESS THAN {(expr) | MAXVALUE} | IN (value_list)}] 191 [[STORAGE] ENGINE [=] engine_name] 192 [COMMENT [=] 'comment_text' ] 193 [DATA DIRECTORY [=] 'data_dir'] 194 [INDEX DIRECTORY [=] 'index_dir'] 195 [MAX_ROWS [=] max_number_of_rows] 196 [MIN_ROWS [=] min_number_of_rows] 197 [TABLESPACE [=] tablespace_name] 198 [NODEGROUP [=] node_group_id] 199 [(subpartition_definition [, subpartition_definition] ...)] 200 201 subpartition_definition: 202 SUBPARTITION logical_name 203 [[STORAGE] ENGINE [=] engine_name] 204 [COMMENT [=] 'comment_text' ] 205 [DATA DIRECTORY [=] 'data_dir'] 206 [INDEX DIRECTORY [=] 'index_dir'] 207 [MAX_ROWS [=] max_number_of_rows] 208 [MIN_ROWS [=] min_number_of_rows] 209 [TABLESPACE [=] tablespace_name] 210 [NODEGROUP [=] node_group_id] 211 212 select_statement: 213 [IGNORE | REPLACE] [AS] SELECT ... (Some legal select statement) 214 215 216 * =========================================================================================================================== 217 */ 218 private static final String TERMINATOR = DEFAULT_TERMINATOR; 219 220 public MySqlDdlParser() { 221 initialize(); 222 } 223 224 /** 225 * {@inheritDoc} 226 * 227 * @see org.modeshape.sequencer.ddl.StandardDdlParser#getId() 228 */ 229 @Override 230 public String getId() { 231 return ID; 232 } 233 234 private void initialize() { 235 setDatatypeParser(new MySqlDataTypeParser()); 236 237 setDoUseTerminator(true); 238 239 setTerminator(TERMINATOR); 240 241 mysqlDataTypeStrings.addAll(MySqlDataTypes.CUSTOM_DATATYPE_START_PHRASES); 242 } 243 244 /** 245 * {@inheritDoc} 246 * 247 * @see org.modeshape.sequencer.ddl.StandardDdlParser#initializeTokenStream(org.modeshape.sequencer.ddl.DdlTokenStream) 248 */ 249 @Override 250 protected void initializeTokenStream( DdlTokenStream tokens ) { 251 super.initializeTokenStream(tokens); 252 tokens.registerKeyWords(CUSTOM_KEYWORDS); 253 tokens.registerKeyWords(MySqlDataTypes.CUSTOM_DATATYPE_START_WORDS); 254 tokens.registerStatementStartPhrase(ALTER_PHRASES); 255 tokens.registerStatementStartPhrase(CREATE_PHRASES); 256 tokens.registerStatementStartPhrase(DROP_PHRASES); 257 tokens.registerStatementStartPhrase(MISC_PHRASES); 258 } 259 260 /** 261 * {@inheritDoc} 262 * 263 * @see org.modeshape.sequencer.ddl.StandardDdlParser#parseCreateStatement(org.modeshape.sequencer.ddl.DdlTokenStream, 264 * org.modeshape.sequencer.ddl.node.AstNode) 265 */ 266 @Override 267 protected AstNode parseCreateStatement( DdlTokenStream tokens, 268 AstNode parentNode ) throws ParsingException { 269 assert tokens != null; 270 assert parentNode != null; 271 272 if (tokens.matches(STMT_CREATE_INDEX)) { 273 return parseStatement(tokens, MySqlStatementStartPhrases.STMT_CREATE_INDEX, parentNode, TYPE_CREATE_INDEX_STATEMENT); 274 } else if (tokens.matches(STMT_CREATE_UNIQUE_INDEX)) { 275 return parseStatement(tokens, 276 MySqlStatementStartPhrases.STMT_CREATE_UNIQUE_INDEX, 277 parentNode, 278 TYPE_CREATE_INDEX_STATEMENT); 279 } else if (tokens.matches(STMT_CREATE_FUNCTION)) { 280 return parseStatement(tokens, 281 MySqlStatementStartPhrases.STMT_CREATE_FUNCTION, 282 parentNode, 283 TYPE_CREATE_FUNCTION_STATEMENT); 284 } else if (tokens.matches(STMT_CREATE_PROCEDURE)) { 285 return parseStatement(tokens, 286 MySqlStatementStartPhrases.STMT_CREATE_PROCEDURE, 287 parentNode, 288 TYPE_CREATE_PROCEDURE_STATEMENT); 289 } else if (tokens.matches(STMT_CREATE_SERVER)) { 290 return parseStatement(tokens, MySqlStatementStartPhrases.STMT_CREATE_SERVER, parentNode, TYPE_CREATE_SERVER_STATEMENT); 291 } else if (tokens.matches(STMT_CREATE_TRIGGER)) { 292 return parseStatement(tokens, 293 MySqlStatementStartPhrases.STMT_CREATE_TRIGGER, 294 parentNode, 295 TYPE_CREATE_TRIGGER_STATEMENT); 296 } else if (tokens.matches(STMT_CREATE_EVENT)) { 297 return parseStatement(tokens, MySqlStatementStartPhrases.STMT_CREATE_EVENT, parentNode, TYPE_CREATE_EVENT_STATEMENT); 298 } else if (tokens.matches(STMT_CREATE_TABLESPACE)) { 299 return parseStatement(tokens, 300 MySqlStatementStartPhrases.STMT_CREATE_TABLESPACE, 301 parentNode, 302 TYPE_CREATE_TABLESPACE_STATEMENT); 303 } else if (tokens.matches(STMT_CREATE_DEFINER)) { 304 return parseStatement(tokens, 305 MySqlStatementStartPhrases.STMT_CREATE_DEFINER, 306 parentNode, 307 TYPE_CREATE_DEFINER_STATEMENT); 308 } 309 310 return super.parseCreateStatement(tokens, parentNode); 311 } 312 313 /** 314 * {@inheritDoc} 315 * 316 * @see org.modeshape.sequencer.ddl.StandardDdlParser#parseAlterStatement(org.modeshape.sequencer.ddl.DdlTokenStream, 317 * org.modeshape.sequencer.ddl.node.AstNode) 318 */ 319 @Override 320 protected AstNode parseAlterStatement( DdlTokenStream tokens, 321 AstNode parentNode ) throws ParsingException { 322 assert tokens != null; 323 assert parentNode != null; 324 325 if (tokens.matches(STMT_ALTER_ALGORITHM)) { 326 return parseStatement(tokens, STMT_ALTER_ALGORITHM, parentNode, TYPE_ALTER_ALGORITHM_STATEMENT); 327 } else if (tokens.matches(STMT_ALTER_DATABASE)) { 328 return parseStatement(tokens, STMT_ALTER_DATABASE, parentNode, TYPE_ALTER_DATABASE_STATEMENT); 329 } else if (tokens.matches(STMT_ALTER_DEFINER)) { 330 return parseStatement(tokens, STMT_ALTER_DEFINER, parentNode, TYPE_ALTER_DEFINER_STATEMENT); 331 } else if (tokens.matches(STMT_ALTER_EVENT)) { 332 return parseStatement(tokens, STMT_ALTER_EVENT, parentNode, TYPE_ALTER_EVENT_STATEMENT); 333 } else if (tokens.matches(STMT_ALTER_FUNCTION)) { 334 return parseStatement(tokens, STMT_ALTER_FUNCTION, parentNode, TYPE_ALTER_FUNCTION_STATEMENT); 335 } else if (tokens.matches(STMT_ALTER_LOGFILE_GROUP)) { 336 return parseStatement(tokens, STMT_ALTER_LOGFILE_GROUP, parentNode, TYPE_ALTER_LOGFILE_GROUP_STATEMENT); 337 } else if (tokens.matches(STMT_ALTER_PROCEDURE)) { 338 return parseStatement(tokens, STMT_ALTER_PROCEDURE, parentNode, TYPE_ALTER_PROCEDURE_STATEMENT); 339 } else if (tokens.matches(STMT_ALTER_SCHEMA)) { 340 return parseStatement(tokens, STMT_ALTER_SCHEMA, parentNode, TYPE_ALTER_SCHEMA_STATEMENT); 341 } else if (tokens.matches(STMT_ALTER_SERVER)) { 342 return parseStatement(tokens, STMT_ALTER_SERVER, parentNode, TYPE_ALTER_SERVER_STATEMENT); 343 } else if (tokens.matches(STMT_ALTER_TABLESPACE)) { 344 return parseStatement(tokens, STMT_ALTER_TABLESPACE, parentNode, TYPE_ALTER_TABLESPACE_STATEMENT); 345 } else if (tokens.matches(STMT_ALTER_SQL_SECURITY)) { 346 return parseStatement(tokens, STMT_ALTER_SQL_SECURITY, parentNode, TYPE_ALTER_VIEW_STATEMENT); 347 } else if (tokens.matches(STMT_ALTER_IGNORE_TABLE) || tokens.matches(STMT_ALTER_ONLINE_TABLE) 348 || tokens.matches(STMT_ALTER_ONLINE_IGNORE_TABLE) || tokens.matches(STMT_ALTER_OFFLINE_TABLE) 349 || tokens.matches(STMT_ALTER_OFFLINE_IGNORE_TABLE)) { 350 return parseAlterTableStatement(tokens, parentNode); 351 } 352 353 return super.parseAlterStatement(tokens, parentNode); 354 } 355 356 /** 357 * {@inheritDoc} 358 * 359 * @see org.modeshape.sequencer.ddl.StandardDdlParser#parseAlterTableStatement(org.modeshape.sequencer.ddl.DdlTokenStream, 360 * org.modeshape.sequencer.ddl.node.AstNode) 361 */ 362 @Override 363 protected AstNode parseAlterTableStatement( DdlTokenStream tokens, 364 AstNode parentNode ) throws ParsingException { 365 assert tokens != null; 366 assert parentNode != null; 367 // TODO: 368 // 369 /* 370 * 371 372 ALTER [ONLINE | OFFLINE] [IGNORE] TABLE tbl_name 373 alter_specification [, alter_specification] ... 374 375 alter_specification: 376 table_options 377 | ADD [COLUMN] col_name column_definition 378 [FIRST | AFTER col_name ] 379 | ADD [COLUMN] (col_name column_definition,...) 380 | ADD {INDEX|KEY} [index_name] 381 [index_type] (index_col_name,...) [index_option] ... 382 | ADD [CONSTRAINT [symbol]] PRIMARY KEY 383 [index_type] (index_col_name,...) [index_option] ... 384 | ADD [CONSTRAINT [symbol]] 385 UNIQUE [INDEX|KEY] [index_name] 386 [index_type] (index_col_name,...) [index_option] ... 387 | ADD FULLTEXT [INDEX|KEY] [index_name] 388 (index_col_name,...) [index_option] ... 389 | ADD SPATIAL [INDEX|KEY] [index_name] 390 (index_col_name,...) [index_option] ... 391 | ADD [CONSTRAINT [symbol]] 392 FOREIGN KEY [index_name] (index_col_name,...) 393 reference_definition 394 | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} 395 | CHANGE [COLUMN] old_col_name new_col_name column_definition 396 [FIRST|AFTER col_name] 397 | MODIFY [COLUMN] col_name column_definition 398 [FIRST | AFTER col_name] 399 | DROP [COLUMN] col_name 400 | DROP PRIMARY KEY 401 | DROP {INDEX|KEY} index_name 402 | DROP FOREIGN KEY fk_symbol 403 | DISABLE KEYS 404 | ENABLE KEYS 405 | RENAME [TO] new_tbl_name 406 | ORDER BY col_name [, col_name] ... 407 | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name] 408 | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name] 409 | DISCARD TABLESPACE 410 | IMPORT TABLESPACE 411 | partition_options 412 | ADD PARTITION (partition_definition) 413 | DROP PARTITION partition_names 414 | COALESCE PARTITION number 415 | REORGANIZE PARTITION [partition_names INTO (partition_definitions)] 416 | ANALYZE PARTITION partition_names 417 | CHECK PARTITION partition_names 418 | OPTIMIZE PARTITION partition_names 419 | REBUILD PARTITION partition_names 420 | REPAIR PARTITION partition_names 421 | REMOVE PARTITIONING 422 */ 423 424 return super.parseAlterTableStatement(tokens, parentNode); 425 } 426 427 /** 428 * {@inheritDoc} 429 * 430 * @see org.modeshape.sequencer.ddl.StandardDdlParser#parseCustomStatement(org.modeshape.sequencer.ddl.DdlTokenStream, 431 * org.modeshape.sequencer.ddl.node.AstNode) 432 */ 433 @Override 434 protected AstNode parseCustomStatement( DdlTokenStream tokens, 435 AstNode parentNode ) throws ParsingException { 436 assert tokens != null; 437 assert parentNode != null; 438 439 if (tokens.matches(STMT_RENAME_DATABASE)) { 440 markStartOfStatement(tokens); 441 442 // RENAME DATABASE db_name TO new_db_name; 443 tokens.consume(STMT_RENAME_DATABASE); 444 String oldName = parseName(tokens); 445 tokens.consume("TO"); 446 AstNode node = nodeFactory().node(oldName, parentNode, TYPE_RENAME_DATABASE_STATEMENT); 447 String newName = parseName(tokens); 448 node.setProperty(NEW_NAME, newName); 449 450 markEndOfStatement(tokens, node); 451 return node; 452 } else if (tokens.matches(STMT_RENAME_SCHEMA)) { 453 markStartOfStatement(tokens); 454 455 // RENAME SCHEMA schema_name TO new_schema_name; 456 tokens.consume(STMT_RENAME_SCHEMA); 457 String oldName = parseName(tokens); 458 tokens.consume("TO"); 459 AstNode node = nodeFactory().node(oldName, parentNode, TYPE_RENAME_SCHEMA_STATEMENT); 460 String newName = parseName(tokens); 461 node.setProperty(NEW_NAME, newName); 462 463 markEndOfStatement(tokens, node); 464 return node; 465 } else if (tokens.matches(STMT_RENAME_TABLE)) { 466 markStartOfStatement(tokens); 467 468 // RENAME TABLE old_table TO tmp_table, 469 // new_table TO old_table, 470 // tmp_table TO new_table; 471 tokens.consume(STMT_RENAME_TABLE); 472 473 String oldName = parseName(tokens); 474 tokens.consume("TO"); 475 String newName = parseName(tokens); 476 477 AstNode node = nodeFactory().node(oldName, parentNode, TYPE_RENAME_TABLE_STATEMENT); 478 node.setProperty(NEW_NAME, newName); 479 480 // IF NOT MULTIPLE RENAMES, FINISH AND RETURN 481 if (!tokens.matches(COMMA)) { 482 markEndOfStatement(tokens, node); 483 return node; 484 } 485 486 // Assume multiple renames 487 488 // Create list of nodes so we can re-set the expression of each to reflect ONE rename. 489 List<AstNode> nodes = new ArrayList<AstNode>(); 490 nodes.add(node); 491 492 while (tokens.matches(COMMA)) { 493 tokens.consume(COMMA); 494 oldName = parseName(tokens); 495 tokens.consume("TO"); 496 newName = parseName(tokens); 497 node = nodeFactory().node(oldName, parentNode, TYPE_RENAME_TABLE_STATEMENT); 498 node.setProperty(NEW_NAME, newName); 499 nodes.add(node); 500 } 501 502 markEndOfStatement(tokens, nodes.get(0)); 503 504 String originalExpression = (String)nodes.get(0).getProperty(DDL_EXPRESSION); 505 Object startLineNumber = nodes.get(0).getProperty(DDL_START_LINE_NUMBER); 506 Object startColumnNumber = nodes.get(0).getProperty(DDL_START_COLUMN_NUMBER); 507 Object startCharIndex = nodes.get(0).getProperty(DDL_START_CHAR_INDEX); 508 509 for (AstNode nextNode : nodes) { 510 oldName = nextNode.getName(); 511 newName = (String)nextNode.getProperty(NEW_NAME); 512 String express = "RENAME TABLE" + SPACE + oldName + SPACE + "TO" + SPACE + newName + SEMICOLON; 513 nextNode.setProperty(DDL_EXPRESSION, express); 514 nextNode.setProperty(DDL_ORIGINAL_EXPRESSION, originalExpression); 515 nextNode.setProperty(DDL_START_LINE_NUMBER, startLineNumber); 516 nextNode.setProperty(DDL_START_COLUMN_NUMBER, startColumnNumber); 517 nextNode.setProperty(DDL_START_CHAR_INDEX, startCharIndex); 518 } 519 520 return nodes.get(0); 521 } 522 523 return super.parseCustomStatement(tokens, parentNode); 524 } 525 526 /** 527 * {@inheritDoc} 528 * 529 * @see org.modeshape.sequencer.ddl.StandardDdlParser#parseDropStatement(org.modeshape.sequencer.ddl.DdlTokenStream, 530 * org.modeshape.sequencer.ddl.node.AstNode) 531 */ 532 @Override 533 protected AstNode parseDropStatement( DdlTokenStream tokens, 534 AstNode parentNode ) throws ParsingException { 535 assert tokens != null; 536 assert parentNode != null; 537 538 if (tokens.matches(STMT_DROP_DATABASE)) { 539 return parseStatement(tokens, STMT_DROP_DATABASE, parentNode, TYPE_DROP_DATABASE_STATEMENT); 540 } else if (tokens.matches(STMT_DROP_EVENT)) { 541 return parseStatement(tokens, STMT_DROP_EVENT, parentNode, TYPE_DROP_EVENT_STATEMENT); 542 } else if (tokens.matches(STMT_DROP_FUNCTION)) { 543 return parseStatement(tokens, STMT_DROP_FUNCTION, parentNode, TYPE_DROP_FUNCTION_STATEMENT); 544 } else if (tokens.matches(STMT_DROP_INDEX)) { 545 return parseStatement(tokens, STMT_DROP_INDEX, parentNode, TYPE_DROP_INDEX_STATEMENT); 546 } else if (tokens.matches(STMT_DROP_OFFLINE_INDEX)) { 547 return parseStatement(tokens, STMT_DROP_OFFLINE_INDEX, parentNode, TYPE_DROP_INDEX_STATEMENT); 548 } else if (tokens.matches(STMT_DROP_ONLINE_INDEX)) { 549 return parseStatement(tokens, STMT_DROP_ONLINE_INDEX, parentNode, TYPE_DROP_INDEX_STATEMENT); 550 } else if (tokens.matches(STMT_DROP_LOGFILE_GROUP)) { 551 return parseStatement(tokens, STMT_DROP_LOGFILE_GROUP, parentNode, TYPE_DROP_LOGFILE_GROUP_STATEMENT); 552 } else if (tokens.matches(STMT_DROP_PROCEDURE)) { 553 return parseStatement(tokens, STMT_DROP_PROCEDURE, parentNode, TYPE_DROP_PROCEDURE_STATEMENT); 554 } else if (tokens.matches(STMT_DROP_SERVER)) { 555 return parseStatement(tokens, STMT_DROP_SERVER, parentNode, TYPE_DROP_SERVER_STATEMENT); 556 } else if (tokens.matches(STMT_DROP_TABLESPACE)) { 557 return parseStatement(tokens, STMT_DROP_TABLESPACE, parentNode, TYPE_DROP_TABLESPACE_STATEMENT); 558 } else if (tokens.matches(STMT_DROP_TRIGGER)) { 559 return parseStatement(tokens, STMT_DROP_TRIGGER, parentNode, TYPE_DROP_TRIGGER_STATEMENT); 560 } 561 562 return super.parseDropStatement(tokens, parentNode); 563 } 564 565 /** 566 * {@inheritDoc} 567 * 568 * @see org.modeshape.sequencer.ddl.StandardDdlParser#getDataTypeStartWords() 569 */ 570 @Override 571 protected List<String> getCustomDataTypeStartWords() { 572 return MySqlDataTypes.CUSTOM_DATATYPE_START_WORDS; 573 } 574 575 // =========================================================================================================================== 576 // =========================================================================================================================== 577 class MySqlDataTypeParser extends DataTypeParser implements MySqlDdlConstants.MySqlDataTypes { 578 579 // NOTE THAT MYSQL allows "UNSIGNED" and "ZEROFILL" as options AFTER the datatype definition 580 // Need to override and do a CHECK for and CONSUME them. 581 582 /** 583 * {@inheritDoc} 584 * 585 * @see org.modeshape.sequencer.ddl.datatype.DataTypeParser#isCustomDataType(org.modeshape.sequencer.ddl.DdlTokenStream) 586 */ 587 @Override 588 protected boolean isCustomDataType( DdlTokenStream tokens ) throws ParsingException { 589 // Loop through the registered statement start string arrays and look for exact matches. 590 591 for (String[] stmts : mysqlDataTypeStrings) { 592 if (tokens.matches(stmts)) return true; 593 } 594 return super.isCustomDataType(tokens); 595 } 596 597 @Override 598 protected DataType parseApproxNumericType( DdlTokenStream tokens ) throws ParsingException { 599 DataType dType = super.parseApproxNumericType(tokens); 600 tokens.canConsume("UNSIGNED"); 601 tokens.canConsume("ZEROFILL"); 602 tokens.canConsume("UNSIGNED"); 603 return dType; 604 } 605 606 @Override 607 protected DataType parseBitStringType( DdlTokenStream tokens ) throws ParsingException { 608 return super.parseBitStringType(tokens); 609 } 610 611 @Override 612 protected DataType parseCharStringType( DdlTokenStream tokens ) throws ParsingException { 613 DataType result = super.parseCharStringType(tokens); 614 615 tokens.canConsume("FOR", "BIT", "DATA"); 616 617 return result; 618 } 619 620 @Override 621 protected DataType parseCustomType( DdlTokenStream tokens ) throws ParsingException { 622 DataType dataType = null; 623 624 if (tokens.matches(DTYPE_FIXED) || tokens.matches(DTYPE_DOUBLE)) { 625 dataType = new DataType(); 626 String typeName = tokens.consume(); 627 dataType.setName(typeName); 628 629 int precision = 0; 630 int scale = 0; 631 632 if (tokens.matches(L_PAREN)) { 633 consume(tokens, dataType, false, L_PAREN); 634 precision = (int)parseLong(tokens, dataType); 635 if (tokens.canConsume(COMMA)) { 636 scale = (int)parseLong(tokens, dataType); 637 } else { 638 scale = getDefaultScale(); 639 } 640 tokens.consume(R_PAREN); 641 } else { 642 precision = getDefaultPrecision(); 643 scale = getDefaultScale(); 644 } 645 dataType.setPrecision(precision); 646 dataType.setScale(scale); 647 } else if (tokens.matches(DTYPE_MEDIUMBLOB) || tokens.matches(DTYPE_LONGBLOB) || tokens.matches(DTYPE_BLOB) 648 || tokens.matches(DTYPE_TINYBLOB) || tokens.matches(DTYPE_YEAR) || tokens.matches(DTYPE_DATETIME) 649 || tokens.matches(DTYPE_BOOLEAN) || tokens.matches(DTYPE_BOOL)) { 650 String typeName = tokens.consume(); 651 dataType = new DataType(typeName); 652 } else if (tokens.matches(DTYPE_MEDIUMINT) || tokens.matches(DTYPE_TINYINT) || tokens.matches(DTYPE_VARBINARY) 653 || tokens.matches(DTYPE_BINARY) || tokens.matches(DTYPE_BIGINT)) { 654 String typeName = tokens.consume(); 655 dataType = new DataType(typeName); 656 long length = getDefaultLength(); 657 if (tokens.matches(L_PAREN)) { 658 length = parseBracketedLong(tokens, dataType); 659 } 660 dataType.setLength(length); 661 } else if (tokens.matches(DTYPE_NATIONAL_VARCHAR)) { 662 String typeName = getStatementTypeName(DTYPE_NATIONAL_VARCHAR); 663 dataType = new DataType(typeName); 664 tokens.consume(DTYPE_NATIONAL_VARCHAR); 665 long length = getDefaultLength(); 666 if (tokens.matches(L_PAREN)) { 667 length = parseBracketedLong(tokens, dataType); 668 } 669 dataType.setLength(length); 670 } else if (tokens.matches(DTYPE_MEDIUMTEXT) || tokens.matches(DTYPE_TEXT) || tokens.matches(DTYPE_LONGTEXT) 671 || tokens.matches(DTYPE_TINYTEXT)) { 672 String typeName = tokens.consume(); 673 dataType = new DataType(typeName); 674 tokens.canConsume("BINARY"); 675 tokens.canConsume("COLLATE", TokenStream.ANY_VALUE); 676 tokens.canConsume("CHARACTER", "SET", TokenStream.ANY_VALUE); 677 tokens.canConsume("COLLATE", TokenStream.ANY_VALUE); 678 } else if (tokens.matches(DTYPE_SET)) { 679 // SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] 680 String typeName = tokens.consume(); 681 dataType = new DataType(typeName); 682 683 tokens.consume(L_PAREN); 684 do { 685 tokens.consume(); 686 } while (tokens.canConsume(COMMA)); 687 tokens.consume(R_PAREN); 688 689 tokens.canConsume("COLLATE", TokenStream.ANY_VALUE); 690 tokens.canConsume("CHARACTER", "SET", TokenStream.ANY_VALUE); 691 tokens.canConsume("COLLATE", TokenStream.ANY_VALUE); 692 } else if (tokens.matches(DTYPE_ENUM)) { 693 // ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] 694 String typeName = tokens.consume(); 695 dataType = new DataType(typeName); 696 697 tokens.consume(L_PAREN); 698 do { 699 tokens.consume(); 700 } while (tokens.canConsume(COMMA)); 701 tokens.consume(R_PAREN); 702 703 tokens.canConsume("COLLATE", TokenStream.ANY_VALUE); 704 tokens.canConsume("CHARACTER", "SET", TokenStream.ANY_VALUE); 705 tokens.canConsume("COLLATE", TokenStream.ANY_VALUE); 706 } 707 708 if (dataType == null) { 709 dataType = super.parseCustomType(tokens); 710 } 711 712 // LOOKING for possible [UNSIGNED] [ZEROFILL] options 713 714 tokens.canConsume("UNSIGNED"); 715 tokens.canConsume("ZEROFILL"); 716 tokens.canConsume("UNSIGNED"); 717 718 return dataType; 719 } 720 721 @Override 722 protected DataType parseDateTimeType( DdlTokenStream tokens ) throws ParsingException { 723 return super.parseDateTimeType(tokens); 724 } 725 726 @Override 727 protected DataType parseExactNumericType( DdlTokenStream tokens ) throws ParsingException { 728 DataType dType = super.parseExactNumericType(tokens); 729 tokens.canConsume("UNSIGNED"); 730 tokens.canConsume("ZEROFILL"); 731 tokens.canConsume("UNSIGNED"); 732 return dType; 733 } 734 735 } 736 737}