View Javadoc

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