/*
* 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;
}
}