/* * Copyright 1999-2017 Alibaba Group Holding Ltd. * * 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. */ package com.alibaba.druid.sql.dialect.mysql.parser; import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.SQLOrderingSpecification; import com.alibaba.druid.sql.ast.SQLPartition; import com.alibaba.druid.sql.ast.SQLPartitionValue; import com.alibaba.druid.sql.ast.SQLSubPartition; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLHexExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryExpr; import com.alibaba.druid.sql.ast.expr.SQLUnaryOperator; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique; import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey; import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey.Match; import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey.Option; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlCharExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExtractExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalUnit; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr.SearchModifier; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.ast.SQLLimit; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; import com.alibaba.druid.util.JdbcConstants; public class MySqlExprParser extends SQLExprParser { public static String[] AGGREGATE_FUNCTIONS = { "AVG", "COUNT", "GROUP_CONCAT", "MAX", "MIN", "STDDEV", "SUM" }; public MySqlExprParser(Lexer lexer){ super(lexer, JdbcConstants.MYSQL); this.aggregateFunctions = AGGREGATE_FUNCTIONS; } public MySqlExprParser(String sql){ this(new MySqlLexer(sql)); this.lexer.nextToken(); } public MySqlExprParser(String sql, boolean keepComments){ this(new MySqlLexer(sql, true, keepComments)); this.lexer.nextToken(); } public SQLExpr relationalRest(SQLExpr expr) { if (identifierEquals("REGEXP")) { lexer.nextToken(); SQLExpr rightExp = equality(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.RegExp, rightExp, JdbcConstants.MYSQL); } return super.relationalRest(expr); } public SQLExpr multiplicativeRest(SQLExpr expr) { final Token token = lexer.token(); if (token == Token.IDENTIFIER && "MOD".equalsIgnoreCase(lexer.stringVal())) { lexer.nextToken(); SQLExpr rightExp = primary(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.Modulus, rightExp, JdbcConstants.MYSQL); } else if (token == Token.DIV) { lexer.nextToken(); SQLExpr rightExp = bitXor(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.DIV, rightExp, getDbType()); expr = multiplicativeRest(expr); } return super.multiplicativeRest(expr); } public SQLExpr notRationalRest(SQLExpr expr) { if (identifierEquals("REGEXP")) { lexer.nextToken(); SQLExpr rightExp = primary(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotRegExp, rightExp, JdbcConstants.MYSQL); } return super.notRationalRest(expr); } public SQLExpr primary() { final Token tok = lexer.token(); if (identifierEquals("outfile")) { lexer.nextToken(); SQLExpr file = primary(); SQLExpr expr = new MySqlOutFileExpr(file); return primaryRest(expr); } switch (tok) { case LITERAL_ALIAS: String aliasValue = lexer.stringVal(); lexer.nextToken(); return primaryRest(new SQLCharExpr(aliasValue)); case VARIANT: SQLVariantRefExpr varRefExpr = new SQLVariantRefExpr(lexer.stringVal()); lexer.nextToken(); if (varRefExpr.getName().equalsIgnoreCase("@@global")) { accept(Token.DOT); varRefExpr = new SQLVariantRefExpr(lexer.stringVal(), true); lexer.nextToken(); } else if (varRefExpr.getName().equals("@") && lexer.token() == Token.LITERAL_CHARS) { varRefExpr.setName("@'" + lexer.stringVal() + "'"); lexer.nextToken(); } else if (varRefExpr.getName().equals("@@") && lexer.token() == Token.LITERAL_CHARS) { varRefExpr.setName("@@'" + lexer.stringVal() + "'"); lexer.nextToken(); } return primaryRest(varRefExpr); case VALUES: lexer.nextToken(); if (lexer.token() != Token.LPAREN) { throw new ParserException("syntax error, illegal values clause"); } return this.methodRest(new SQLIdentifierExpr("VALUES"), true); case BINARY: lexer.nextToken(); if (lexer.token() == Token.COMMA || lexer.token() == Token.SEMI || lexer.token() == Token.EOF) { return new SQLIdentifierExpr("BINARY"); } else { SQLUnaryExpr binaryExpr = new SQLUnaryExpr(SQLUnaryOperator.BINARY, expr()); return primaryRest(binaryExpr); } case CACHE: case GROUP: lexer.nextToken(); return primaryRest(new SQLIdentifierExpr(lexer.stringVal())); default: return super.primary(); } } public final SQLExpr primaryRest(SQLExpr expr) { if (expr == null) { throw new IllegalArgumentException("expr"); } if (lexer.token() == Token.LITERAL_CHARS) { if (expr instanceof SQLIdentifierExpr) { SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr; String ident = identExpr.getName(); if (ident.equalsIgnoreCase("x")) { String charValue = lexer.stringVal(); lexer.nextToken(); expr = new SQLHexExpr(charValue); return primaryRest(expr); } else if (ident.equalsIgnoreCase("b")) { String charValue = lexer.stringVal(); lexer.nextToken(); expr = new SQLBinaryExpr(charValue); return primaryRest(expr); } else if (ident.startsWith("_")) { String charValue = lexer.stringVal(); lexer.nextToken(); MySqlCharExpr mysqlCharExpr = new MySqlCharExpr(charValue); mysqlCharExpr.setCharset(identExpr.getName()); if (identifierEquals("COLLATE")) { lexer.nextToken(); String collate = lexer.stringVal(); mysqlCharExpr.setCollate(collate); accept(Token.IDENTIFIER); } expr = mysqlCharExpr; return primaryRest(expr); } } else if (expr instanceof SQLCharExpr) { SQLMethodInvokeExpr concat = new SQLMethodInvokeExpr("CONCAT"); concat.addParameter(expr); do { String chars = lexer.stringVal(); concat.addParameter(new SQLCharExpr(chars)); lexer.nextToken(); } while (lexer.token() == Token.LITERAL_CHARS || lexer.token() == Token.LITERAL_ALIAS); expr = concat; } } else if (lexer.token() == Token.IDENTIFIER) { if (expr instanceof SQLHexExpr) { if ("USING".equalsIgnoreCase(lexer.stringVal())) { lexer.nextToken(); if (lexer.token() != Token.IDENTIFIER) { throw new ParserException("syntax error, illegal hex"); } String charSet = lexer.stringVal(); lexer.nextToken(); expr.getAttributes().put("USING", charSet); return primaryRest(expr); } } else if ("COLLATE".equalsIgnoreCase(lexer.stringVal())) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); } if (lexer.token() != Token.IDENTIFIER) { throw new ParserException("syntax error"); } String collate = lexer.stringVal(); lexer.nextToken(); SQLBinaryOpExpr binaryExpr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.COLLATE, new SQLIdentifierExpr(collate), JdbcConstants.MYSQL); expr = binaryExpr; return primaryRest(expr); } else if (expr instanceof SQLVariantRefExpr) { if ("COLLATE".equalsIgnoreCase(lexer.stringVal())) { lexer.nextToken(); if (lexer.token() != Token.IDENTIFIER) { throw new ParserException("syntax error"); } String collate = lexer.stringVal(); lexer.nextToken(); expr.putAttribute("COLLATE", collate); return primaryRest(expr); } } else if (expr instanceof SQLIntegerExpr) { SQLIntegerExpr intExpr = (SQLIntegerExpr) expr; String binaryString = lexer.stringVal(); if (intExpr.getNumber().intValue() == 0 && binaryString.startsWith("b")) { lexer.nextToken(); expr = new SQLBinaryExpr(binaryString.substring(1)); return primaryRest(expr); } } } if (lexer.token() == Token.LPAREN && expr instanceof SQLIdentifierExpr) { SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr; String ident = identExpr.getName(); if ("EXTRACT".equalsIgnoreCase(ident)) { lexer.nextToken(); if (lexer.token() != Token.IDENTIFIER) { throw new ParserException("syntax error"); } String unitVal = lexer.stringVal(); MySqlIntervalUnit unit = MySqlIntervalUnit.valueOf(unitVal.toUpperCase()); lexer.nextToken(); accept(Token.FROM); SQLExpr value = expr(); MySqlExtractExpr extract = new MySqlExtractExpr(); extract.setValue(value); extract.setUnit(unit); accept(Token.RPAREN); expr = extract; return primaryRest(expr); } else if ("SUBSTRING".equalsIgnoreCase(ident)) { lexer.nextToken(); SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(ident); for (;;) { SQLExpr param = expr(); methodInvokeExpr.addParameter(param); if (lexer.token() == Token.COMMA) { lexer.nextToken(); continue; } else if (lexer.token() == Token.FROM) { lexer.nextToken(); SQLExpr from = expr(); methodInvokeExpr.addParameter(from); if (lexer.token() == Token.FOR) { lexer.nextToken(); SQLExpr forExpr = expr(); methodInvokeExpr.addParameter(forExpr); } break; } else if (lexer.token() == Token.RPAREN) { break; } else { throw new ParserException("syntax error"); } } accept(Token.RPAREN); expr = methodInvokeExpr; return primaryRest(expr); } else if ("TRIM".equalsIgnoreCase(ident)) { lexer.nextToken(); SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(ident); if (lexer.token() == Token.IDENTIFIER) { String flagVal = lexer.stringVal(); if ("LEADING".equalsIgnoreCase(flagVal)) { lexer.nextToken(); methodInvokeExpr.getAttributes().put("TRIM_TYPE", "LEADING"); } else if ("BOTH".equalsIgnoreCase(flagVal)) { lexer.nextToken(); methodInvokeExpr.getAttributes().put("TRIM_TYPE", "BOTH"); } else if ("TRAILING".equalsIgnoreCase(flagVal)) { lexer.nextToken(); methodInvokeExpr.putAttribute("TRIM_TYPE", "TRAILING"); } } SQLExpr param = expr(); methodInvokeExpr.addParameter(param); if (lexer.token() == Token.FROM) { lexer.nextToken(); SQLExpr from = expr(); methodInvokeExpr.putAttribute("FROM", from); } accept(Token.RPAREN); expr = methodInvokeExpr; return primaryRest(expr); } else if ("MATCH".equalsIgnoreCase(ident)) { lexer.nextToken(); MySqlMatchAgainstExpr matchAgainstExpr = new MySqlMatchAgainstExpr(); if (lexer.token() == Token.RPAREN) { lexer.nextToken(); } else { exprList(matchAgainstExpr.getColumns(), matchAgainstExpr); accept(Token.RPAREN); } acceptIdentifier("AGAINST"); accept(Token.LPAREN); SQLExpr against = primary(); matchAgainstExpr.setAgainst(against); if (lexer.token() == Token.IN) { lexer.nextToken(); if (identifierEquals("NATURAL")) { lexer.nextToken(); acceptIdentifier("LANGUAGE"); acceptIdentifier("MODE"); if (lexer.token() == Token.WITH) { lexer.nextToken(); acceptIdentifier("QUERY"); acceptIdentifier("EXPANSION"); matchAgainstExpr.setSearchModifier(SearchModifier.IN_NATURAL_LANGUAGE_MODE_WITH_QUERY_EXPANSION); } else { matchAgainstExpr.setSearchModifier(SearchModifier.IN_NATURAL_LANGUAGE_MODE); } } else if (identifierEquals("BOOLEAN")) { lexer.nextToken(); acceptIdentifier("MODE"); matchAgainstExpr.setSearchModifier(SearchModifier.IN_BOOLEAN_MODE); } else { throw new ParserException("TODO"); } } else if (lexer.token() == Token.WITH) { throw new ParserException("TODO"); } accept(Token.RPAREN); expr = matchAgainstExpr; return primaryRest(expr); } else if (("CONVERT".equalsIgnoreCase(ident))||("CHAR".equalsIgnoreCase(ident))) { lexer.nextToken(); SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(ident); if (lexer.token() != Token.RPAREN) { exprList(methodInvokeExpr.getParameters(), methodInvokeExpr); } if (identifierEquals("USING")) { lexer.nextToken(); if (lexer.token() != Token.IDENTIFIER) { throw new ParserException("syntax error"); } String charset = lexer.stringVal(); lexer.nextToken(); methodInvokeExpr.putAttribute("USING", charset); } accept(Token.RPAREN); expr = methodInvokeExpr; return primaryRest(expr); } else if ("POSITION".equalsIgnoreCase(ident)) { accept(Token.LPAREN); SQLExpr subStr = this.primary(); accept(Token.IN); SQLExpr str = this.expr(); accept(Token.RPAREN); SQLMethodInvokeExpr locate = new SQLMethodInvokeExpr("LOCATE"); locate.addParameter(subStr); locate.addParameter(str); expr = locate; return primaryRest(expr); } } if (lexer.token() == Token.VARIANT && "@".equals(lexer.stringVal())) { lexer.nextToken(); MySqlUserName userName = new MySqlUserName(); if (expr instanceof SQLCharExpr) { userName.setUserName(((SQLCharExpr) expr).toString()); } else { userName.setUserName(((SQLIdentifierExpr) expr).getName()); } if (lexer.token() == Token.LITERAL_CHARS) { userName.setHost("'" + lexer.stringVal() + "'"); } else { userName.setHost(lexer.stringVal()); } lexer.nextToken(); return userName; } if (lexer.token() == Token.ERROR) { throw new ParserException("syntax error, token: " + lexer.token() + " " + lexer.stringVal() + ", pos : " + lexer.pos()); } return super.primaryRest(expr); } public SQLSelectParser createSelectParser() { return new MySqlSelectParser(this); } protected SQLExpr parseInterval() { accept(Token.INTERVAL); if (lexer.token() == Token.LPAREN) { lexer.nextToken(); SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr("INTERVAL"); if (lexer.token() != Token.RPAREN) { exprList(methodInvokeExpr.getParameters(), methodInvokeExpr); } accept(Token.RPAREN); // if (methodInvokeExpr.getParameters().size() == 1 // && lexer.token() == Token.IDENTIFIER) { SQLExpr value = methodInvokeExpr.getParameters().get(0); String unit = lexer.stringVal(); lexer.nextToken(); MySqlIntervalExpr intervalExpr = new MySqlIntervalExpr(); intervalExpr.setValue(value); intervalExpr.setUnit(MySqlIntervalUnit.valueOf(unit.toUpperCase())); return intervalExpr; } else { return primaryRest(methodInvokeExpr); } } else { SQLExpr value = expr(); if (lexer.token() != Token.IDENTIFIER) { throw new ParserException("Syntax error"); } String unit = lexer.stringVal(); lexer.nextToken(); MySqlIntervalExpr intervalExpr = new MySqlIntervalExpr(); intervalExpr.setValue(value); intervalExpr.setUnit(MySqlIntervalUnit.valueOf(unit.toUpperCase())); return intervalExpr; } } public SQLColumnDefinition parseColumn() { SQLColumnDefinition column = new SQLColumnDefinition(); column.setName(name()); column.setDataType(parseDataType()); return parseColumnRest(column); } public SQLColumnDefinition parseColumnRest(SQLColumnDefinition column) { if (lexer.token() == Token.ON) { lexer.nextToken(); accept(Token.UPDATE); SQLExpr expr = this.expr(); column.setOnUpdate(expr); } if (identifierEquals("CHARSET")) { lexer.nextToken(); MySqlCharExpr charSetCollateExpr=new MySqlCharExpr(); charSetCollateExpr.setCharset(lexer.stringVal()); lexer.nextToken(); if (identifierEquals("COLLATE")) { lexer.nextToken(); charSetCollateExpr.setCollate(lexer.stringVal()); lexer.nextToken(); } column.setCharsetExpr(charSetCollateExpr); return parseColumnRest(column); } if (identifierEquals("AUTO_INCREMENT")) { lexer.nextToken(); column.setAutoIncrement(true); return parseColumnRest(column); } if (identifierEquals("precision") && column.getDataType().getName().equalsIgnoreCase("double")) { lexer.nextToken(); } if (lexer.token() == Token.PARTITION) { throw new ParserException("syntax error " + lexer.token() + " " + lexer.stringVal()); } if (identifierEquals("STORAGE")) { lexer.nextToken(); SQLExpr expr = expr(); column.setStorage(expr); } if (lexer.token() == Token.AS) { lexer.nextToken(); accept(Token.LPAREN); SQLExpr expr = expr(); column.setAsExpr(expr); accept(Token.RPAREN); } if (identifierEquals("STORED")) { lexer.nextToken(); column.setSorted(true); } if (identifierEquals("VIRTUAL")) { lexer.nextToken(); column.setVirtual(true); } super.parseColumnRest(column); return column; } protected SQLDataType parseDataTypeRest(SQLDataType dataType) { super.parseDataTypeRest(dataType); if (identifierEquals("UNSIGNED")) { lexer.nextToken(); dataType.getAttributes().put("UNSIGNED", true); } if (identifierEquals("ZEROFILL")) { lexer.nextToken(); dataType.getAttributes().put("ZEROFILL", true); } return dataType; } public SQLExpr orRest(SQLExpr expr) { for (;;) { if (lexer.token() == Token.OR || lexer.token() == Token.BARBAR) { lexer.nextToken(); SQLExpr rightExp = and(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanOr, rightExp, JdbcConstants.MYSQL); } else if (lexer.token() == Token.XOR) { lexer.nextToken(); SQLExpr rightExp = and(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanXor, rightExp, JdbcConstants.MYSQL); } else { break; } } return expr; } public SQLExpr additiveRest(SQLExpr expr) { if (lexer.token() == Token.PLUS) { lexer.nextToken(); SQLExpr rightExp = multiplicative(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Add, rightExp, JdbcConstants.MYSQL); expr = additiveRest(expr); } else if (lexer.token() == Token.SUB) { lexer.nextToken(); SQLExpr rightExp = multiplicative(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Subtract, rightExp, JdbcConstants.MYSQL); expr = additiveRest(expr); } return expr; } public SQLAssignItem parseAssignItem() { SQLAssignItem item = new SQLAssignItem(); SQLExpr var = primary(); String ident = null; if (var instanceof SQLIdentifierExpr) { ident = ((SQLIdentifierExpr) var).getName(); if ("GLOBAL".equalsIgnoreCase(ident)) { ident = lexer.stringVal(); lexer.nextToken(); var = new SQLVariantRefExpr(ident, true); } else if ("SESSION".equalsIgnoreCase(ident)) { ident = lexer.stringVal(); lexer.nextToken(); var = new SQLVariantRefExpr(ident, false); } else { var = new SQLVariantRefExpr(ident); } } if ("NAMES".equalsIgnoreCase(ident)) { // skip } else if ("CHARACTER".equalsIgnoreCase(ident)) { var = new SQLIdentifierExpr("CHARACTER SET"); accept(Token.SET); if (lexer.token() == Token.EQ) { lexer.nextToken(); } } else { if (lexer.token() == Token.COLONEQ) { lexer.nextToken(); } else { accept(Token.EQ); } } if (lexer.token() == Token.ON) { lexer.nextToken(); item.setValue(new SQLIdentifierExpr("ON")); } else { item.setValue(this.expr()); } item.setTarget(var); return item; } public SQLName nameRest(SQLName name) { if (lexer.token() == Token.VARIANT && "@".equals(lexer.stringVal())) { lexer.nextToken(); MySqlUserName userName = new MySqlUserName(); userName.setUserName(((SQLIdentifierExpr) name).getName()); if (lexer.token() == Token.LITERAL_CHARS) { userName.setHost("'" + lexer.stringVal() + "'"); } else { userName.setHost(lexer.stringVal()); } lexer.nextToken(); return userName; } return super.nameRest(name); } @Override public MySqlPrimaryKey parsePrimaryKey() { accept(Token.PRIMARY); accept(Token.KEY); MySqlPrimaryKey primaryKey = new MySqlPrimaryKey(); if (identifierEquals("USING")) { lexer.nextToken(); primaryKey.setIndexType(lexer.stringVal()); lexer.nextToken(); } accept(Token.LPAREN); for (;;) { primaryKey.addColumn(this.expr()); if (!(lexer.token() == (Token.COMMA))) { break; } else { lexer.nextToken(); } } accept(Token.RPAREN); return primaryKey; } public MySqlUnique parseUnique() { accept(Token.UNIQUE); if (lexer.token() == Token.KEY) { lexer.nextToken(); } if (lexer.token() == Token.INDEX) { lexer.nextToken(); } MySqlUnique unique = new MySqlUnique(); if (lexer.token() != Token.LPAREN) { SQLName indexName = name(); unique.setIndexName(indexName); } //5.5语法 USING BTREE 放在index 名字后 if (identifierEquals("USING")) { lexer.nextToken(); unique.setIndexType(lexer.stringVal()); lexer.nextToken(); } accept(Token.LPAREN); for (;;) { SQLExpr column = this.expr(); if (lexer.token() == Token.ASC) { column = new MySqlOrderingExpr(column, SQLOrderingSpecification.ASC); lexer.nextToken(); } else if (lexer.token() == Token.DESC) { column = new MySqlOrderingExpr(column, SQLOrderingSpecification.DESC); lexer.nextToken(); } unique.addColumn(column); if (!(lexer.token() == (Token.COMMA))) { break; } else { lexer.nextToken(); } } accept(Token.RPAREN); if (identifierEquals("USING")) { lexer.nextToken(); unique.setIndexType(lexer.stringVal()); lexer.nextToken(); } return unique; } public MysqlForeignKey parseForeignKey() { accept(Token.FOREIGN); accept(Token.KEY); MysqlForeignKey fk = new MysqlForeignKey(); if (lexer.token() != Token.LPAREN) { SQLName indexName = name(); fk.setIndexName(indexName); } accept(Token.LPAREN); this.names(fk.getReferencingColumns()); accept(Token.RPAREN); accept(Token.REFERENCES); fk.setReferencedTableName(this.name()); accept(Token.LPAREN); this.names(fk.getReferencedColumns()); accept(Token.RPAREN); if (identifierEquals("MATCH")) { if (identifierEquals("FULL")) { fk.setReferenceMatch(Match.FULL); } else if (identifierEquals("PARTIAL")) { fk.setReferenceMatch(Match.PARTIAL); } else if (identifierEquals("SIMPLE")) { fk.setReferenceMatch(Match.SIMPLE); } } while (lexer.token() == Token.ON) { lexer.nextToken(); if (lexer.token() == Token.DELETE) { lexer.nextToken(); Option option = parseReferenceOption(); fk.setOnDelete(option); } else if (lexer.token() == Token.UPDATE) { lexer.nextToken(); Option option = parseReferenceOption(); fk.setOnUpdate(option); } else { throw new ParserException("syntax error, expect DELETE or UPDATE, actual " + lexer.token() + " " + lexer.stringVal()); } } return fk; } protected Option parseReferenceOption() { Option option; if (lexer.token() == Token.RESTRICT || identifierEquals("RESTRICT")) { option = Option.RESTRICT; lexer.nextToken(); } else if (identifierEquals("CASCADE")) { option = Option.CASCADE; lexer.nextToken(); } else if (lexer.token() == Token.SET) { lexer.nextToken(); accept(Token.NULL); option = Option.SET_NULL; } else if (identifierEquals("ON")) { lexer.nextToken(); if (identifierEquals("ACTION")) { option = Option.NO_ACTION; lexer.nextToken(); } else { throw new ParserException("syntax error, expect ACTION, actual " + lexer.token() + " " + lexer.stringVal()); } } else { throw new ParserException("syntax error, expect ACTION, actual " + lexer.token() + " " + lexer.stringVal()); } return option; } protected SQLAggregateExpr parseAggregateExprRest(SQLAggregateExpr aggregateExpr) { if (lexer.token() == Token.ORDER) { SQLOrderBy orderBy = this.parseOrderBy(); aggregateExpr.putAttribute("ORDER BY", orderBy); } if (identifierEquals("SEPARATOR")) { lexer.nextToken(); SQLExpr seperator = this.primary(); aggregateExpr.putAttribute("SEPARATOR", seperator); } return aggregateExpr; } public MySqlOrderingExpr parseSelectGroupByItem() { MySqlOrderingExpr item = new MySqlOrderingExpr(); item.setExpr(expr()); if (lexer.token() == Token.ASC) { lexer.nextToken(); item.setType(SQLOrderingSpecification.ASC); } else if (lexer.token() == Token.DESC) { lexer.nextToken(); item.setType(SQLOrderingSpecification.DESC); } return item; } public SQLPartition parsePartition() { accept(Token.PARTITION); SQLPartition partitionDef = new SQLPartition(); partitionDef.setName(this.name()); SQLPartitionValue values = this.parsePartitionValues(); if (values != null) { partitionDef.setValues(values); } for (;;) { boolean storage = false; if (identifierEquals("DATA")) { lexer.nextToken(); acceptIdentifier("DIRECTORY"); if (lexer.token() == Token.EQ) { lexer.nextToken(); } partitionDef.setDataDirectory(this.expr()); } else if (lexer.token() == Token.TABLESPACE) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); } SQLName tableSpace = this.name(); partitionDef.setTableSpace(tableSpace); } else if (lexer.token() == Token.INDEX) { lexer.nextToken(); acceptIdentifier("DIRECTORY"); if (lexer.token() == Token.EQ) { lexer.nextToken(); } partitionDef.setIndexDirectory(this.expr()); } else if (identifierEquals("MAX_ROWS")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); } SQLExpr maxRows = this.primary(); partitionDef.setMaxRows(maxRows); } else if (identifierEquals("MIN_ROWS")) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); } SQLExpr minRows = this.primary(); partitionDef.setMaxRows(minRows); } else if (identifierEquals("ENGINE") || // (storage = (lexer.token() == Token.STORAGE || identifierEquals("STORAGE")))) { if (storage) { lexer.nextToken(); } acceptIdentifier("ENGINE"); if (lexer.token() == Token.EQ) { lexer.nextToken(); } SQLName engine = this.name(); partitionDef.setEngine(engine); } else if (lexer.token() == Token.COMMENT) { lexer.nextToken(); if (lexer.token() == Token.EQ) { lexer.nextToken(); } SQLExpr comment = this.primary(); partitionDef.setComment(comment); } else { break; } } if (lexer.token() == Token.LPAREN) { lexer.nextToken(); for (;;) { acceptIdentifier("SUBPARTITION"); SQLName subPartitionName = this.name(); SQLSubPartition subPartition = new SQLSubPartition(); subPartition.setName(subPartitionName); partitionDef.addSubPartition(subPartition); if (lexer.token() == Token.COMMA) { lexer.nextToken(); continue; } break; } accept(Token.RPAREN); } return partitionDef; } }