/* * Copyright 1999-2012 Alibaba Group. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * (created at 2011-7-4) */ package com.alibaba.cobar.parser.recognizer.mysql.syntax; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.EOF; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.IDENTIFIER; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_AS; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_BINARY; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_CHARACTER; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_COLLATE; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_COLUMN; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_DEFAULT; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_EXISTS; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_IF; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_IGNORE; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_INDEX; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_KEY; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_KEYS; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_NOT; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_ON; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_SET; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_TABLE; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_TO; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_UNSIGNED; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_USING; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_ZEROFILL; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.LITERAL_NULL; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.LITERAL_NUM_PURE_DIGIT; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.OP_EQUALS; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.PUNC_COMMA; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.PUNC_LEFT_PAREN; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.PUNC_RIGHT_PAREN; import java.sql.SQLSyntaxErrorException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.alibaba.cobar.parser.ast.expression.Expression; import com.alibaba.cobar.parser.ast.expression.primary.Identifier; import com.alibaba.cobar.parser.ast.expression.primary.literal.Literal; import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralString; import com.alibaba.cobar.parser.ast.fragment.ddl.ColumnDefinition; import com.alibaba.cobar.parser.ast.fragment.ddl.TableOptions; import com.alibaba.cobar.parser.ast.fragment.ddl.datatype.DataType; import com.alibaba.cobar.parser.ast.fragment.ddl.index.IndexColumnName; import com.alibaba.cobar.parser.ast.fragment.ddl.index.IndexDefinition; import com.alibaba.cobar.parser.ast.fragment.ddl.index.IndexOption; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLAlterTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLCreateIndexStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLCreateTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLDropIndexStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLDropTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLRenameTableStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLStatement; import com.alibaba.cobar.parser.ast.stmt.ddl.DDLTruncateStatement; import com.alibaba.cobar.parser.ast.stmt.dml.DMLSelectStatement; import com.alibaba.cobar.parser.ast.stmt.extension.ExtDDLCreatePolicy; import com.alibaba.cobar.parser.ast.stmt.extension.ExtDDLDropPolicy; import com.alibaba.cobar.parser.recognizer.mysql.lexer.MySQLLexer; import com.alibaba.cobar.parser.util.Pair; /** * @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a> */ public class MySQLDDLParser extends MySQLParser { protected MySQLExprParser exprParser; public MySQLDDLParser(MySQLLexer lexer, MySQLExprParser exprParser) { super(lexer); this.exprParser = exprParser; } private static enum SpecialIdentifier { TRUNCATE, TEMPORARY, DEFINER, KEY_BLOCK_SIZE, COMMENT, DYNAMIC, FIXED, BIT, DATE, TIME, TIMESTAMP, DATETIME, YEAR, TEXT, ENUM, ENGINE, AUTO_INCREMENT, AVG_ROW_LENGTH, CHECKSUM, CONNECTION, DATA, DELAY_KEY_WRITE, INSERT_METHOD, MAX_ROWS, MIN_ROWS, PACK_KEYS, PASSWORD, ROW_FORMAT, COMPRESSED, REDUNDANT, COMPACT, MODIFY, DISABLE, ENABLE, DISCARD, IMPORT, /** MySQL 5.1 legacy syntax */ CHARSET, /** EXTENSION syntax */ POLICY } private static final Map<String, SpecialIdentifier> specialIdentifiers = new HashMap<String, SpecialIdentifier>( 1, 1); static { specialIdentifiers.put("TRUNCATE", SpecialIdentifier.TRUNCATE); specialIdentifiers.put("TEMPORARY", SpecialIdentifier.TEMPORARY); specialIdentifiers.put("DEFINER", SpecialIdentifier.DEFINER); specialIdentifiers.put("KEY_BLOCK_SIZE", SpecialIdentifier.KEY_BLOCK_SIZE); specialIdentifiers.put("COMMENT", SpecialIdentifier.COMMENT); specialIdentifiers.put("DYNAMIC", SpecialIdentifier.DYNAMIC); specialIdentifiers.put("FIXED", SpecialIdentifier.FIXED); specialIdentifiers.put("BIT", SpecialIdentifier.BIT); specialIdentifiers.put("DATE", SpecialIdentifier.DATE); specialIdentifiers.put("TIME", SpecialIdentifier.TIME); specialIdentifiers.put("TIMESTAMP", SpecialIdentifier.TIMESTAMP); specialIdentifiers.put("DATETIME", SpecialIdentifier.DATETIME); specialIdentifiers.put("YEAR", SpecialIdentifier.YEAR); specialIdentifiers.put("TEXT", SpecialIdentifier.TEXT); specialIdentifiers.put("ENUM", SpecialIdentifier.ENUM); specialIdentifiers.put("ENGINE", SpecialIdentifier.ENGINE); specialIdentifiers.put("AUTO_INCREMENT", SpecialIdentifier.AUTO_INCREMENT); specialIdentifiers.put("AVG_ROW_LENGTH", SpecialIdentifier.AVG_ROW_LENGTH); specialIdentifiers.put("CHECKSUM", SpecialIdentifier.CHECKSUM); specialIdentifiers.put("CONNECTION", SpecialIdentifier.CONNECTION); specialIdentifiers.put("DATA", SpecialIdentifier.DATA); specialIdentifiers.put("DELAY_KEY_WRITE", SpecialIdentifier.DELAY_KEY_WRITE); specialIdentifiers.put("INSERT_METHOD", SpecialIdentifier.INSERT_METHOD); specialIdentifiers.put("MAX_ROWS", SpecialIdentifier.MAX_ROWS); specialIdentifiers.put("MIN_ROWS", SpecialIdentifier.MIN_ROWS); specialIdentifiers.put("PACK_KEYS", SpecialIdentifier.PACK_KEYS); specialIdentifiers.put("PASSWORD", SpecialIdentifier.PASSWORD); specialIdentifiers.put("ROW_FORMAT", SpecialIdentifier.ROW_FORMAT); specialIdentifiers.put("COMPRESSED", SpecialIdentifier.COMPRESSED); specialIdentifiers.put("REDUNDANT", SpecialIdentifier.REDUNDANT); specialIdentifiers.put("COMPACT", SpecialIdentifier.COMPACT); specialIdentifiers.put("MODIFY", SpecialIdentifier.MODIFY); specialIdentifiers.put("DISABLE", SpecialIdentifier.DISABLE); specialIdentifiers.put("ENABLE", SpecialIdentifier.ENABLE); specialIdentifiers.put("DISCARD", SpecialIdentifier.DISCARD); specialIdentifiers.put("IMPORT", SpecialIdentifier.IMPORT); specialIdentifiers.put("CHARSET", SpecialIdentifier.CHARSET); specialIdentifiers.put("POLICY", SpecialIdentifier.POLICY); } public DDLTruncateStatement truncate() throws SQLSyntaxErrorException { matchIdentifier("TRUNCATE"); if (lexer.token() == KW_TABLE) { lexer.nextToken(); } Identifier tb = identifier(); return new DDLTruncateStatement(tb); } /** * nothing has been pre-consumed */ public DDLStatement ddlStmt() throws SQLSyntaxErrorException { Identifier idTemp1; Identifier idTemp2; SpecialIdentifier siTemp; switch (lexer.token()) { case KW_ALTER: boolean ignore = false; if (lexer.nextToken() == KW_IGNORE) { ignore = true; lexer.nextToken(); } switch (lexer.token()) { case KW_TABLE: lexer.nextToken(); idTemp1 = identifier(); DDLAlterTableStatement alterTableStatement = new DDLAlterTableStatement(ignore, idTemp1); return alterTable(alterTableStatement); default: throw err("Only ALTER TABLE is supported"); } case KW_CREATE: switch (lexer.nextToken()) { case KW_UNIQUE: case KW_FULLTEXT: case KW_SPATIAL: lexer.nextToken(); case KW_INDEX: lexer.nextToken(); idTemp1 = identifier(); for (; lexer.token() != KW_ON; lexer.nextToken()); lexer.nextToken(); idTemp2 = identifier(); return new DDLCreateIndexStatement(idTemp1, idTemp2); case KW_TABLE: lexer.nextToken(); return createTable(false); case IDENTIFIER: siTemp = specialIdentifiers.get(lexer.stringValueUppercase()); if (siTemp != null) { switch (siTemp) { case TEMPORARY: lexer.nextToken(); match(KW_TABLE); return createTable(true); case POLICY: lexer.nextToken(); Identifier policyName = identifier(); match(PUNC_LEFT_PAREN); ExtDDLCreatePolicy policy = new ExtDDLCreatePolicy(policyName); for (int j = 0; lexer.token() != PUNC_RIGHT_PAREN; ++j) { if (j > 0) { match(PUNC_COMMA); } Integer id = lexer.integerValue().intValue(); match(LITERAL_NUM_PURE_DIGIT); Expression val = exprParser.expression(); policy.addProportion(id, val); } match(PUNC_RIGHT_PAREN); return policy; } } default: throw err("unsupported DDL for CREATE"); } case KW_DROP: switch (lexer.nextToken()) { case KW_INDEX: lexer.nextToken(); idTemp1 = identifier(); match(KW_ON); idTemp2 = identifier(); return new DDLDropIndexStatement(idTemp1, idTemp2); case KW_TABLE: lexer.nextToken(); return dropTable(false); case IDENTIFIER: siTemp = specialIdentifiers.get(lexer.stringValueUppercase()); if (siTemp != null) { switch (siTemp) { case TEMPORARY: lexer.nextToken(); match(KW_TABLE); return dropTable(true); case POLICY: lexer.nextToken(); Identifier policyName = identifier(); return new ExtDDLDropPolicy(policyName); } } default: throw err("unsupported DDL for DROP"); } case KW_RENAME: lexer.nextToken(); match(KW_TABLE); idTemp1 = identifier(); match(KW_TO); idTemp2 = identifier(); List<Pair<Identifier, Identifier>> list; if (lexer.token() != PUNC_COMMA) { list = new ArrayList<Pair<Identifier, Identifier>>(1); list.add(new Pair<Identifier, Identifier>(idTemp1, idTemp2)); return new DDLRenameTableStatement(list); } list = new LinkedList<Pair<Identifier, Identifier>>(); list.add(new Pair<Identifier, Identifier>(idTemp1, idTemp2)); for (; lexer.token() == PUNC_COMMA;) { lexer.nextToken(); idTemp1 = identifier(); match(KW_TO); idTemp2 = identifier(); list.add(new Pair<Identifier, Identifier>(idTemp1, idTemp2)); } return new DDLRenameTableStatement(list); case IDENTIFIER: SpecialIdentifier si = specialIdentifiers.get(lexer.stringValueUppercase()); if (si != null) { switch (si) { case TRUNCATE: return truncate(); } } default: throw err("unsupported DDL"); } } /** * <code>TABLE</code> has been consumed */ private DDLDropTableStatement dropTable(boolean temp) throws SQLSyntaxErrorException { boolean ifExists = false; if (lexer.token() == KW_IF) { lexer.nextToken(); match(KW_EXISTS); ifExists = true; } Identifier tb = identifier(); List<Identifier> list; if (lexer.token() != PUNC_COMMA) { list = new ArrayList<Identifier>(1); list.add(tb); } else { list = new LinkedList<Identifier>(); list.add(tb); for (; lexer.token() == PUNC_COMMA;) { lexer.nextToken(); tb = identifier(); list.add(tb); } } DDLDropTableStatement.Mode mode = DDLDropTableStatement.Mode.UNDEF; switch (lexer.token()) { case KW_RESTRICT: lexer.nextToken(); mode = DDLDropTableStatement.Mode.RESTRICT; break; case KW_CASCADE: lexer.nextToken(); mode = DDLDropTableStatement.Mode.CASCADE; break; } return new DDLDropTableStatement(list, temp, ifExists, mode); } /** * token of table name has been consumed * * @throws SQLSyntaxErrorException */ private DDLAlterTableStatement alterTable(DDLAlterTableStatement stmt) throws SQLSyntaxErrorException { TableOptions options = new TableOptions(); stmt.setTableOptions(options); Identifier id = null; Identifier id2 = null; Identifier id3 = null; ColumnDefinition colDef = null; IndexDefinition indexDef = null; Expression expr = null; for (int i = 0; lexer.token() != EOF; ++i) { if (i > 0) { match(PUNC_COMMA); } if (tableOptions(options)) { continue; } main_switch: switch (lexer.token()) { case KW_CONVERT: // | CONVERT TO CHARACTER SET charset_name [COLLATE // collation_name] lexer.nextToken(); match(KW_TO); match(KW_CHARACTER); match(KW_SET); id = identifier(); id2 = null; if (lexer.token() == KW_COLLATE) { lexer.nextToken(); id2 = identifier(); } stmt.setConvertCharset(new Pair<Identifier, Identifier>(id, id2)); break main_switch; case KW_RENAME: // | RENAME [TO] new_tbl_name if (lexer.nextToken() == KW_TO) { lexer.nextToken(); } id = identifier(); stmt.setRenameTo(id); break main_switch; case KW_DROP: drop_switch: switch (lexer.nextToken()) { case KW_INDEX: case KW_KEY: // | DROP {INDEX|KEY} index_name lexer.nextToken(); id = identifier(); stmt.addAlterSpecification(new DDLAlterTableStatement.DropIndex(id)); break drop_switch; case KW_PRIMARY: // | DROP PRIMARY KEY lexer.nextToken(); match(KW_KEY); stmt.addAlterSpecification(new DDLAlterTableStatement.DropPrimaryKey()); break drop_switch; case IDENTIFIER: // | DROP [COLUMN] col_name id = identifier(); stmt.addAlterSpecification(new DDLAlterTableStatement.DropColumn(id)); break drop_switch; case KW_COLUMN: // | DROP [COLUMN] col_name lexer.nextToken(); id = identifier(); stmt.addAlterSpecification(new DDLAlterTableStatement.DropColumn(id)); break drop_switch; default: throw new SQLSyntaxErrorException("ALTER TABLE error for DROP"); } break main_switch; case KW_CHANGE: // | CHANGE [COLUMN] old_col_name new_col_name column_definition // [FIRST|AFTER col_name] if (lexer.nextToken() == KW_COLUMN) { lexer.nextToken(); } id = identifier(); id2 = identifier(); colDef = columnDefinition(); if (lexer.token() == IDENTIFIER) { if ("FIRST".equals(lexer.stringValueUppercase())) { lexer.nextToken(); stmt.addAlterSpecification(new DDLAlterTableStatement.ChangeColumn(id, id2, colDef, null)); } else if ("AFTER".equals(lexer.stringValueUppercase())) { lexer.nextToken(); id3 = identifier(); stmt.addAlterSpecification(new DDLAlterTableStatement.ChangeColumn(id, id2, colDef, id3)); } else { stmt.addAlterSpecification(new DDLAlterTableStatement.ChangeColumn(id, id2, colDef)); } } else { stmt.addAlterSpecification(new DDLAlterTableStatement.ChangeColumn(id, id2, colDef)); } break main_switch; case KW_ALTER: // | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP // DEFAULT} if (lexer.nextToken() == KW_COLUMN) { lexer.nextToken(); } id = identifier(); switch (lexer.token()) { case KW_SET: lexer.nextToken(); match(KW_DEFAULT); expr = exprParser.expression(); stmt.addAlterSpecification(new DDLAlterTableStatement.AlterColumnDefaultVal(id, expr)); break; case KW_DROP: lexer.nextToken(); match(KW_DEFAULT); stmt.addAlterSpecification(new DDLAlterTableStatement.AlterColumnDefaultVal(id)); break; default: throw new SQLSyntaxErrorException("ALTER TABLE error for ALTER"); } break main_switch; case KW_ADD: add_switch: switch (lexer.nextToken()) { case IDENTIFIER: // | ADD [COLUMN] col_name column_definition [FIRST | AFTER // col_name ] id = identifier(); colDef = columnDefinition(); if (lexer.token() == IDENTIFIER) { if ("FIRST".equals(lexer.stringValueUppercase())) { lexer.nextToken(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef, null)); } else if ("AFTER".equals(lexer.stringValueUppercase())) { lexer.nextToken(); id2 = identifier(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef, id2)); } else { stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef)); } } else { stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef)); } break add_switch; case PUNC_LEFT_PAREN: // | ADD [COLUMN] (col_name column_definition,...) lexer.nextToken(); for (int j = 0; lexer.token() != PUNC_RIGHT_PAREN; ++j) { DDLAlterTableStatement.AddColumns addColumns = new DDLAlterTableStatement.AddColumns(); stmt.addAlterSpecification(addColumns); if (j > 0) { match(PUNC_COMMA); } id = identifier(); colDef = columnDefinition(); addColumns.addColumn(id, colDef); } match(PUNC_RIGHT_PAREN); break add_switch; case KW_COLUMN: if (lexer.nextToken() == PUNC_LEFT_PAREN) { // | ADD [COLUMN] (col_name column_definition,...) lexer.nextToken(); for (int j = 0; lexer.token() != PUNC_RIGHT_PAREN; ++j) { DDLAlterTableStatement.AddColumns addColumns = new DDLAlterTableStatement.AddColumns(); stmt.addAlterSpecification(addColumns); if (j > 0) { match(PUNC_COMMA); } id = identifier(); colDef = columnDefinition(); addColumns.addColumn(id, colDef); } match(PUNC_RIGHT_PAREN); } else { // | ADD [COLUMN] col_name column_definition [FIRST | // AFTER col_name ] id = identifier(); colDef = columnDefinition(); if (lexer.token() == IDENTIFIER) { if ("FIRST".equals(lexer.stringValueUppercase())) { lexer.nextToken(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef, null)); } else if ("AFTER".equals(lexer.stringValueUppercase())) { lexer.nextToken(); id2 = identifier(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef, id2)); } else { stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef)); } } else { stmt.addAlterSpecification(new DDLAlterTableStatement.AddColumn(id, colDef)); } } break add_switch; case KW_INDEX: case KW_KEY: // | ADD {INDEX|KEY} [index_name] [index_type] // (index_col_name,...) [index_option] ... id = null; if (lexer.nextToken() == IDENTIFIER) { id = identifier(); } indexDef = indexDefinition(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddIndex(id, indexDef)); break add_switch; case KW_PRIMARY: // | ADD PRIMARY KEY [index_type] (index_col_name,...) // [index_option] ... lexer.nextToken(); match(KW_KEY); indexDef = indexDefinition(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddPrimaryKey(indexDef)); break add_switch; case KW_UNIQUE: // | ADD UNIQUE [INDEX|KEY] [index_name] [index_type] // (index_col_name,...) [index_option] ... switch (lexer.nextToken()) { case KW_INDEX: case KW_KEY: lexer.nextToken(); } id = null; if (lexer.token() == IDENTIFIER) { id = identifier(); } indexDef = indexDefinition(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddUniqueKey(id, indexDef)); break add_switch; case KW_FULLTEXT: // | ADD FULLTEXT [INDEX|KEY] [index_name] // (index_col_name,...) [index_option] ... switch (lexer.nextToken()) { case KW_INDEX: case KW_KEY: lexer.nextToken(); } id = null; if (lexer.token() == IDENTIFIER) { id = identifier(); } indexDef = indexDefinition(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddFullTextIndex(id, indexDef)); break add_switch; case KW_SPATIAL: // | ADD SPATIAL [INDEX|KEY] [index_name] // (index_col_name,...) [index_option] ... switch (lexer.nextToken()) { case KW_INDEX: case KW_KEY: lexer.nextToken(); } id = null; if (lexer.token() == IDENTIFIER) { id = identifier(); } indexDef = indexDefinition(); stmt.addAlterSpecification(new DDLAlterTableStatement.AddSpatialIndex(id, indexDef)); break add_switch; default: throw new SQLSyntaxErrorException("ALTER TABLE error for ADD"); } break main_switch; case IDENTIFIER: SpecialIdentifier si = specialIdentifiers.get(lexer.stringValueUppercase()); if (si != null) { switch (si) { case IMPORT: // | IMPORT TABLESPACE lexer.nextToken(); matchIdentifier("TABLESPACE"); stmt.setImportTableSpace(true); break main_switch; case DISCARD: // | DISCARD TABLESPACE lexer.nextToken(); matchIdentifier("TABLESPACE"); stmt.setDiscardTableSpace(true); break main_switch; case ENABLE: // | ENABLE KEYS lexer.nextToken(); match(KW_KEYS); stmt.setEnableKeys(true); break main_switch; case DISABLE: // | DISABLE KEYS lexer.nextToken(); match(KW_KEYS); stmt.setDisableKeys(true); break main_switch; case MODIFY: // | MODIFY [COLUMN] col_name column_definition [FIRST | // AFTER col_name] if (lexer.nextToken() == KW_COLUMN) { lexer.nextToken(); } id = identifier(); colDef = columnDefinition(); if (lexer.token() == IDENTIFIER) { if ("FIRST".equals(lexer.stringValueUppercase())) { lexer.nextToken(); stmt.addAlterSpecification(new DDLAlterTableStatement.ModifyColumn(id, colDef, null)); } else if ("AFTER".equals(lexer.stringValueUppercase())) { lexer.nextToken(); id2 = identifier(); stmt.addAlterSpecification(new DDLAlterTableStatement.ModifyColumn(id, colDef, id2)); } else { stmt.addAlterSpecification(new DDLAlterTableStatement.ModifyColumn(id, colDef)); } } else { stmt.addAlterSpecification(new DDLAlterTableStatement.ModifyColumn(id, colDef)); } break main_switch; } } default: throw new SQLSyntaxErrorException("unknown ALTER specification"); } } return stmt; } /** * <code>TABLE</code> has been consumed */ private DDLCreateTableStatement createTable(boolean temp) throws SQLSyntaxErrorException { boolean ifNotExists = false; if (lexer.token() == KW_IF) { lexer.nextToken(); match(KW_NOT); match(KW_EXISTS); ifNotExists = true; } Identifier table = identifier(); DDLCreateTableStatement stmt = new DDLCreateTableStatement(temp, ifNotExists, table); createTableDefs(stmt); TableOptions options = new TableOptions(); stmt.setTableOptions(options); tableOptions(options); DDLCreateTableStatement.SelectOption selectOpt = null; switch (lexer.token()) { case KW_IGNORE: selectOpt = DDLCreateTableStatement.SelectOption.IGNORED; if (lexer.nextToken() == KW_AS) { lexer.nextToken(); } break; case KW_REPLACE: selectOpt = DDLCreateTableStatement.SelectOption.REPLACE; if (lexer.nextToken() == KW_AS) { lexer.nextToken(); } break; case KW_AS: lexer.nextToken(); case KW_SELECT: break; case EOF: return stmt; default: throw new SQLSyntaxErrorException("DDL CREATE TABLE statement not end properly"); } DMLSelectStatement select = new MySQLDMLSelectParser(lexer, exprParser).select(); stmt.setSelect(selectOpt, select); match(EOF); return stmt; } private void createTableDefs(DDLCreateTableStatement stmt) throws SQLSyntaxErrorException { if (lexer.token() != PUNC_LEFT_PAREN) { return; } match(PUNC_LEFT_PAREN); IndexDefinition indexDef; Identifier id; for (int i = 0; lexer.token() != PUNC_RIGHT_PAREN; ++i) { if (i > 0) { match(PUNC_COMMA); } switch (lexer.token()) { case KW_PRIMARY: lexer.nextToken(); match(KW_KEY); indexDef = indexDefinition(); stmt.setPrimaryKey(indexDef); break; case KW_INDEX: case KW_KEY: lexer.nextToken(); if (lexer.token() == IDENTIFIER) { id = identifier(); } else { id = null; } indexDef = indexDefinition(); stmt.addIndex(id, indexDef); break; case KW_UNIQUE: switch (lexer.nextToken()) { case KW_INDEX: case KW_KEY: lexer.nextToken(); break; } if (lexer.token() == IDENTIFIER) { id = identifier(); } else { id = null; } indexDef = indexDefinition(); stmt.addUniqueIndex(id, indexDef); break; case KW_FULLTEXT: switch (lexer.nextToken()) { case KW_INDEX: case KW_KEY: lexer.nextToken(); break; } if (lexer.token() == IDENTIFIER) { id = identifier(); } else { id = null; } indexDef = indexDefinition(); if (indexDef.getIndexType() != null) { throw new SQLSyntaxErrorException("FULLTEXT INDEX can specify no index_type"); } stmt.addFullTextIndex(id, indexDef); break; case KW_SPATIAL: switch (lexer.nextToken()) { case KW_INDEX: case KW_KEY: lexer.nextToken(); break; } if (lexer.token() == IDENTIFIER) { id = identifier(); } else { id = null; } indexDef = indexDefinition(); if (indexDef.getIndexType() != null) { throw new SQLSyntaxErrorException("SPATIAL INDEX can specify no index_type"); } stmt.addSpatialIndex(id, indexDef); break; case KW_CHECK: lexer.nextToken(); match(PUNC_LEFT_PAREN); Expression expr = exprParser.expression(); match(PUNC_RIGHT_PAREN); stmt.addCheck(expr); break; case IDENTIFIER: Identifier columnName = identifier(); ColumnDefinition columnDef = columnDefinition(); stmt.addColumnDefinition(columnName, columnDef); break; default: throw new SQLSyntaxErrorException("unsupportted column definition"); } } match(PUNC_RIGHT_PAREN); } // col_name column_definition // | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) // [index_option] ... // | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) // [index_option] ... // | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] // (index_col_name,...) [index_option] ... // | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...) // [index_option] ... // | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) // reference_definition // | CHECK (expr) private IndexDefinition indexDefinition() throws SQLSyntaxErrorException { IndexDefinition.IndexType indexType = null; List<IndexColumnName> columns = new ArrayList<IndexColumnName>(1); if (lexer.token() == KW_USING) { lexer.nextToken(); int tp = matchIdentifier("BTREE", "HASH"); indexType = tp == 0 ? IndexDefinition.IndexType.BTREE : IndexDefinition.IndexType.HASH; } match(PUNC_LEFT_PAREN); for (int i = 0; lexer.token() != PUNC_RIGHT_PAREN; ++i) { if (i > 0) match(PUNC_COMMA); IndexColumnName indexColumnName = indexColumnName(); columns.add(indexColumnName); } match(PUNC_RIGHT_PAREN); List<IndexOption> options = indexOptions(); return new IndexDefinition(indexType, columns, options); } private List<IndexOption> indexOptions() throws SQLSyntaxErrorException { List<IndexOption> list = null; for (;;) { main_switch: switch (lexer.token()) { case KW_USING: lexer.nextToken(); IndexOption.IndexType indexType = matchIdentifier("BTREE", "HASH") == 0 ? IndexOption.IndexType.BTREE : IndexOption.IndexType.HASH; if (list == null) { list = new ArrayList<IndexOption>(1); } list.add(new IndexOption(indexType)); break main_switch; case KW_WITH: lexer.nextToken(); matchIdentifier("PARSER"); Identifier id = identifier(); if (list == null) { list = new ArrayList<IndexOption>(1); } list.add(new IndexOption(id)); break main_switch; case IDENTIFIER: SpecialIdentifier si = specialIdentifiers.get(lexer.stringValueUppercase()); if (si != null) { switch (si) { case KEY_BLOCK_SIZE: lexer.nextToken(); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } Expression val = exprParser.expression(); if (list == null) { list = new ArrayList<IndexOption>(1); } list.add(new IndexOption(val)); break main_switch; case COMMENT: lexer.nextToken(); LiteralString string = (LiteralString) exprParser.expression(); if (list == null) { list = new ArrayList<IndexOption>(1); } list.add(new IndexOption(string)); break main_switch; } } default: return list; } } } private IndexColumnName indexColumnName() throws SQLSyntaxErrorException { // col_name [(length)] [ASC | DESC] Identifier colName = identifier(); Expression len = null; if (lexer.token() == PUNC_LEFT_PAREN) { lexer.nextToken(); len = exprParser.expression(); match(PUNC_RIGHT_PAREN); } switch (lexer.token()) { case KW_ASC: lexer.nextToken(); return new IndexColumnName(colName, len, true); case KW_DESC: lexer.nextToken(); return new IndexColumnName(colName, len, false); default: return new IndexColumnName(colName, len, true); } } // data_type: // | DATE // | TIME // | TIMESTAMP // | DATETIME // | YEAR // | spatial_type private DataType dataType() throws SQLSyntaxErrorException { DataType.DataTypeName typeName = null; boolean unsigned = false; boolean zerofill = false; /** for text only */ boolean binary = false; Expression length = null; Expression decimals = null; Identifier charSet = null; Identifier collation = null; List<Expression> collectionVals = null; typeName: switch (lexer.token()) { case KW_TINYINT: // | TINYINT[(length)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.TINYINT; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_SMALLINT: // | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.SMALLINT; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_MEDIUMINT: // | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.MEDIUMINT; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_INTEGER: case KW_INT: // | INT[(length)] [UNSIGNED] [ZEROFILL] // | INTEGER[(length)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.INT; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_BIGINT: // | BIGINT[(length)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.BIGINT; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_REAL: // | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.REAL; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_COMMA); decimals = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_DOUBLE: // | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.DOUBLE; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_COMMA); decimals = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_FLOAT: // | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.FLOAT; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_COMMA); decimals = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_NUMERIC: case KW_DECIMAL: case KW_DEC: // | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] // | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] typeName = DataType.DataTypeName.DECIMAL; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); if (lexer.token() == PUNC_COMMA) { match(PUNC_COMMA); decimals = exprParser.expression(); } match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_UNSIGNED) { unsigned = true; lexer.nextToken(); } if (lexer.token() == KW_ZEROFILL) { zerofill = true; lexer.nextToken(); } break typeName; case KW_CHAR: // | CHAR[(length)] [CHARACTER SET charset_name] [COLLATE // collation_name] typeName = DataType.DataTypeName.CHAR; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; case KW_VARCHAR: // | VARCHAR(length) [CHARACTER SET charset_name] [COLLATE // collation_name] typeName = DataType.DataTypeName.VARCHAR; lexer.nextToken(); match(PUNC_LEFT_PAREN); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; case KW_BINARY: // | BINARY[(length)] typeName = DataType.DataTypeName.BINARY; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } break typeName; case KW_VARBINARY: // | VARBINARY(length) typeName = DataType.DataTypeName.VARBINARY; lexer.nextToken(); match(PUNC_LEFT_PAREN); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); break typeName; case KW_TINYBLOB: typeName = DataType.DataTypeName.TINYBLOB; lexer.nextToken(); break typeName; case KW_BLOB: typeName = DataType.DataTypeName.BLOB; lexer.nextToken(); break typeName; case KW_MEDIUMBLOB: typeName = DataType.DataTypeName.MEDIUMBLOB; lexer.nextToken(); break typeName; case KW_LONGBLOB: typeName = DataType.DataTypeName.LONGBLOB; lexer.nextToken(); break typeName; case KW_TINYTEXT: // | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE // collation_name] typeName = DataType.DataTypeName.TINYTEXT; if (lexer.nextToken() == KW_BINARY) { lexer.nextToken(); binary = true; } if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; case KW_MEDIUMTEXT: // | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE // collation_name] typeName = DataType.DataTypeName.MEDIUMTEXT; if (lexer.nextToken() == KW_BINARY) { lexer.nextToken(); binary = true; } if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; case KW_LONGTEXT: // | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE // collation_name] typeName = DataType.DataTypeName.LONGTEXT; if (lexer.nextToken() == KW_BINARY) { lexer.nextToken(); binary = true; } if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; case KW_SET: // | SET(value1,value2,value3,...) [CHARACTER SET charset_name] // [COLLATE collation_name] typeName = DataType.DataTypeName.SET; lexer.nextToken(); match(PUNC_LEFT_PAREN); for (int i = 0; lexer.token() != PUNC_RIGHT_PAREN; ++i) { if (i > 0) match(PUNC_COMMA); else collectionVals = new ArrayList<Expression>(2); collectionVals.add(exprParser.expression()); } match(PUNC_RIGHT_PAREN); if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; case IDENTIFIER: SpecialIdentifier si = specialIdentifiers.get(lexer.stringValueUppercase()); if (si != null) { switch (si) { case BIT: // BIT[(length)] typeName = DataType.DataTypeName.BIT; if (lexer.nextToken() == PUNC_LEFT_PAREN) { lexer.nextToken(); length = exprParser.expression(); match(PUNC_RIGHT_PAREN); } break typeName; case DATE: typeName = DataType.DataTypeName.DATE; lexer.nextToken(); break typeName; case TIME: typeName = DataType.DataTypeName.TIME; lexer.nextToken(); break typeName; case TIMESTAMP: typeName = DataType.DataTypeName.TIMESTAMP; lexer.nextToken(); break typeName; case DATETIME: typeName = DataType.DataTypeName.DATETIME; lexer.nextToken(); break typeName; case YEAR: typeName = DataType.DataTypeName.YEAR; lexer.nextToken(); break typeName; case TEXT: // | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE // collation_name] typeName = DataType.DataTypeName.TEXT; if (lexer.nextToken() == KW_BINARY) { lexer.nextToken(); binary = true; } if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; case ENUM: // | ENUM(value1,value2,value3,...) [CHARACTER SET // charset_name] [COLLATE collation_name] typeName = DataType.DataTypeName.ENUM; lexer.nextToken(); match(PUNC_LEFT_PAREN); for (int i = 0; lexer.token() != PUNC_RIGHT_PAREN; ++i) { if (i > 0) match(PUNC_COMMA); else collectionVals = new ArrayList<Expression>(2); collectionVals.add(exprParser.expression()); } match(PUNC_RIGHT_PAREN); if (lexer.token() == KW_CHARACTER) { lexer.nextToken(); match(KW_SET); charSet = identifier(); } if (lexer.token() == KW_COLLATE) { lexer.nextToken(); collation = identifier(); } break typeName; } } default: return null; } return new DataType(typeName, unsigned, zerofill, binary, length, decimals, charSet, collation, collectionVals); } // column_definition: // data_type [NOT NULL | NULL] [DEFAULT default_value] // [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] // [COMMENT 'string'] // [COLUMN_FORMAT {FIXED|DYNAMIC|DEFAULT}] // [reference_definition] private ColumnDefinition columnDefinition() throws SQLSyntaxErrorException { DataType dataType = dataType(); boolean notNull = false; Expression defaultVal = null; boolean autoIncrement = false; ColumnDefinition.SpecialIndex sindex = null; ColumnDefinition.ColumnFormat format = null; LiteralString comment = null; if (lexer.token() == KW_NOT) { lexer.nextToken(); match(LITERAL_NULL); notNull = true; } else if (lexer.token() == LITERAL_NULL) { lexer.nextToken(); } if (lexer.token() == KW_DEFAULT) { lexer.nextToken(); defaultVal = exprParser.expression(); if (!(defaultVal instanceof Literal)) { throw new SQLSyntaxErrorException("default value of column must be a literal: " + defaultVal); } } if (lexer.token() == IDENTIFIER && "AUTO_INCREMENT".equals(lexer.stringValueUppercase())) { lexer.nextToken(); autoIncrement = true; } switch (lexer.token()) { case KW_UNIQUE: if (lexer.nextToken() == KW_KEY) { lexer.nextToken(); } sindex = ColumnDefinition.SpecialIndex.UNIQUE; break; case KW_PRIMARY: lexer.nextToken(); case KW_KEY: match(KW_KEY); sindex = ColumnDefinition.SpecialIndex.PRIMARY; break; } if (lexer.token() == IDENTIFIER && "COMMENT".equals(lexer.stringValueUppercase())) { lexer.nextToken(); comment = (LiteralString) exprParser.expression(); } if (lexer.token() == IDENTIFIER && "COLUMN_FORMAT".equals(lexer.stringValueUppercase())) { switch (lexer.nextToken()) { case KW_DEFAULT: lexer.nextToken(); format = ColumnDefinition.ColumnFormat.DEFAULT; break; case IDENTIFIER: SpecialIdentifier si = specialIdentifiers.get(lexer.stringValueUppercase()); if (si != null) { switch (si) { case FIXED: lexer.nextToken(); format = ColumnDefinition.ColumnFormat.FIXED; break; case DYNAMIC: lexer.nextToken(); format = ColumnDefinition.ColumnFormat.DYNAMIC; break; } } } } return new ColumnDefinition(dataType, notNull, defaultVal, autoIncrement, sindex, comment, format); } private boolean tableOptions(TableOptions options) throws SQLSyntaxErrorException { boolean matched = false; for (int i = 0;; ++i) { boolean comma = false; if (i > 0 && lexer.token() == PUNC_COMMA) { lexer.nextToken(); comma = true; } if (!tableOption(options)) { if (comma) { lexer.addCacheToke(PUNC_COMMA); } break; } else { matched = true; } } return matched; } private boolean tableOption(TableOptions options) throws SQLSyntaxErrorException { Identifier id = null; Expression expr = null; os: switch (lexer.token()) { case KW_CHARACTER: lexer.nextToken(); match(KW_SET); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } id = identifier(); options.setCharSet(id); break; case KW_COLLATE: lexer.nextToken(); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } id = identifier(); options.setCollation(id); break; case KW_DEFAULT: // | [DEFAULT] CHARSET [=] charset_name { MySQL 5.1 legacy} // | [DEFAULT] CHARACTER SET [=] charset_name // | [DEFAULT] COLLATE [=] collation_name switch (lexer.nextToken()) { case KW_CHARACTER: lexer.nextToken(); match(KW_SET); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } id = identifier(); options.setCharSet(id); break os; case KW_COLLATE: lexer.nextToken(); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } id = identifier(); options.setCollation(id); break os; case IDENTIFIER: SpecialIdentifier si = specialIdentifiers.get(lexer.stringValueUppercase()); if (si != null) { switch (si) { case CHARSET: lexer.nextToken(); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } id = identifier(); options.setCharSet(id); break os; } } default: lexer.addCacheToke(KW_DEFAULT); return false; } case KW_INDEX: // | INDEX DIRECTORY [=] 'absolute path to directory' lexer.nextToken(); if (lexer.token() == IDENTIFIER && "DIRECTORY".equals(lexer.stringValueUppercase())) { if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } options.setIndexDir((LiteralString) exprParser.expression()); break; } lexer.addCacheToke(KW_INDEX); return true; case KW_UNION: // | UNION [=] (tbl_name[,tbl_name]...) if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } match(PUNC_LEFT_PAREN); List<Identifier> union = new ArrayList<Identifier>(2); for (int j = 0; lexer.token() != PUNC_RIGHT_PAREN; ++j) { if (j > 0) match(PUNC_COMMA); id = identifier(); union.add(id); } match(PUNC_RIGHT_PAREN); options.setUnion(union); break os; case IDENTIFIER: SpecialIdentifier si = specialIdentifiers.get(lexer.stringValueUppercase()); if (si != null) { switch (si) { case CHARSET: // CHARSET [=] charset_name lexer.nextToken(); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } id = identifier(); options.setCharSet(id); break os; case ENGINE: // ENGINE [=] engine_name if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } id = identifier(); options.setEngine(id); break os; case AUTO_INCREMENT: // | AUTO_INCREMENT [=] value if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } expr = exprParser.expression(); options.setAutoIncrement(expr); break os; case AVG_ROW_LENGTH: // | AVG_ROW_LENGTH [=] value if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } expr = exprParser.expression(); options.setAvgRowLength(expr); break os; case CHECKSUM: // | CHECKSUM [=] {0 | 1} if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } switch (lexer.token()) { case LITERAL_BOOL_FALSE: lexer.nextToken(); options.setCheckSum(false); case LITERAL_BOOL_TRUE: lexer.nextToken(); options.setCheckSum(true); break; case LITERAL_NUM_PURE_DIGIT: int intVal = lexer.integerValue().intValue(); lexer.nextToken(); if (intVal == 0) { options.setCheckSum(false); } else { options.setCheckSum(true); } break; default: throw new SQLSyntaxErrorException("table option of CHECKSUM error"); } break os; case DELAY_KEY_WRITE: // | DELAY_KEY_WRITE [=] {0 | 1} if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } switch (lexer.token()) { case LITERAL_BOOL_FALSE: lexer.nextToken(); options.setDelayKeyWrite(false); case LITERAL_BOOL_TRUE: lexer.nextToken(); options.setDelayKeyWrite(true); break; case LITERAL_NUM_PURE_DIGIT: int intVal = lexer.integerValue().intValue(); lexer.nextToken(); if (intVal == 0) { options.setDelayKeyWrite(false); } else { options.setDelayKeyWrite(true); } break; default: throw new SQLSyntaxErrorException("table option of DELAY_KEY_WRITE error"); } break os; case COMMENT: // | COMMENT [=] 'string' if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } options.setComment((LiteralString) exprParser.expression()); break os; case CONNECTION: // | CONNECTION [=] 'connect_string' if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } options.setConnection((LiteralString) exprParser.expression()); break os; case DATA: // | DATA DIRECTORY [=] 'absolute path to directory' lexer.nextToken(); matchIdentifier("DIRECTORY"); if (lexer.token() == OP_EQUALS) { lexer.nextToken(); } options.setDataDir((LiteralString) exprParser.expression()); break os; case INSERT_METHOD: // | INSERT_METHOD [=] { NO | FIRST | LAST } if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } switch (matchIdentifier("NO", "FIRST", "LAST")) { case 0: options.setInsertMethod(TableOptions.InsertMethod.NO); break; case 1: options.setInsertMethod(TableOptions.InsertMethod.FIRST); break; case 2: options.setInsertMethod(TableOptions.InsertMethod.LAST); break; } break os; case KEY_BLOCK_SIZE: // | KEY_BLOCK_SIZE [=] value if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } options.setKeyBlockSize(exprParser.expression()); break os; case MAX_ROWS: // | MAX_ROWS [=] value if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } options.setMaxRows(exprParser.expression()); break os; case MIN_ROWS: // | MIN_ROWS [=] value if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } options.setMinRows(exprParser.expression()); break os; case PACK_KEYS: // | PACK_KEYS [=] {0 | 1 | DEFAULT} if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } switch (lexer.token()) { case LITERAL_BOOL_FALSE: lexer.nextToken(); options.setPackKeys(TableOptions.PackKeys.FALSE); break; case LITERAL_BOOL_TRUE: lexer.nextToken(); options.setPackKeys(TableOptions.PackKeys.TRUE); break; case LITERAL_NUM_PURE_DIGIT: int intVal = lexer.integerValue().intValue(); lexer.nextToken(); if (intVal == 0) { options.setPackKeys(TableOptions.PackKeys.FALSE); } else { options.setPackKeys(TableOptions.PackKeys.TRUE); } break; case KW_DEFAULT: lexer.nextToken(); options.setPackKeys(TableOptions.PackKeys.DEFAULT); break; default: throw new SQLSyntaxErrorException("table option of PACK_KEYS error"); } break os; case PASSWORD: // | PASSWORD [=] 'string' if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } options.setPassword((LiteralString) exprParser.expression()); break os; case ROW_FORMAT: // | ROW_FORMAT [=] // {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} if (lexer.nextToken() == OP_EQUALS) { lexer.nextToken(); } switch (lexer.token()) { case KW_DEFAULT: lexer.nextToken(); options.setRowFormat(TableOptions.RowFormat.DEFAULT); break os; case IDENTIFIER: SpecialIdentifier sid = specialIdentifiers.get(lexer.stringValueUppercase()); if (sid != null) { switch (sid) { case DYNAMIC: lexer.nextToken(); options.setRowFormat(TableOptions.RowFormat.DYNAMIC); break os; case FIXED: lexer.nextToken(); options.setRowFormat(TableOptions.RowFormat.FIXED); break os; case COMPRESSED: lexer.nextToken(); options.setRowFormat(TableOptions.RowFormat.COMPRESSED); break os; case REDUNDANT: lexer.nextToken(); options.setRowFormat(TableOptions.RowFormat.REDUNDANT); break os; case COMPACT: lexer.nextToken(); options.setRowFormat(TableOptions.RowFormat.COMPACT); break os; } } default: throw new SQLSyntaxErrorException("table option of ROW_FORMAT error"); } } } default: return false; } return true; } }