/* * Copyright 1999-2018 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.parser; import java.math.BigInteger; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.expr.*; import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleArgumentExpr; import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr; import com.alibaba.druid.util.FnvHash; import com.alibaba.druid.util.JdbcConstants; public class SQLExprParser extends SQLParser { public final static String[] AGGREGATE_FUNCTIONS; public final static long[] AGGREGATE_FUNCTIONS_CODES; static { String[] strings = { "AVG", "COUNT", "MAX", "MIN", "STDDEV", "SUM" }; AGGREGATE_FUNCTIONS_CODES = FnvHash.fnv1a_64_lower(strings, true); AGGREGATE_FUNCTIONS = new String[AGGREGATE_FUNCTIONS_CODES.length]; for (String str : strings) { long hash = FnvHash.fnv1a_64_lower(str); int index = Arrays.binarySearch(AGGREGATE_FUNCTIONS_CODES, hash); AGGREGATE_FUNCTIONS[index] = str; } } protected String[] aggregateFunctions = AGGREGATE_FUNCTIONS; protected long[] aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES; public SQLExprParser(String sql){ super(sql); } public SQLExprParser(String sql, String dbType){ super(sql, dbType); } public SQLExprParser(Lexer lexer){ super(lexer); } public SQLExprParser(Lexer lexer, String dbType){ super(lexer, dbType); } public SQLExpr expr() { if (lexer.token == Token.STAR) { lexer.nextToken(); SQLExpr expr = new SQLAllColumnExpr(); if (lexer.token == Token.DOT) { lexer.nextToken(); accept(Token.STAR); return new SQLPropertyExpr(expr, "*"); } return expr; } SQLExpr expr = primary(); Token token = lexer.token; if (token == Token.COMMA) { return expr; } else if (token == Token.EQ) { expr = equalityRest2(expr); expr = andRest(expr); expr = orRest(expr); return expr; } else { return exprRest(expr); } } public SQLExpr exprRest(SQLExpr expr) { expr = bitXorRest(expr); expr = multiplicativeRest(expr); expr = additiveRest(expr); expr = shiftRest(expr); expr = bitAndRest(expr); expr = bitOrRest(expr); expr = inRest(expr); expr = relationalRest(expr); expr = equalityRest(expr); expr = andRest(expr); expr = orRest(expr); return expr; } public final SQLExpr bitXor() { SQLExpr expr = primary(); return bitXorRest(expr); } public SQLExpr bitXorRest(SQLExpr expr) { Token token = lexer.token; switch (token) { case CARET: { lexer.nextToken(); SQLBinaryOperator op; if (lexer.token == Token.EQ) { lexer.nextToken(); op = SQLBinaryOperator.BitwiseXorEQ; } else { op = SQLBinaryOperator.BitwiseXor; } SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, op, rightExp, dbType); expr = bitXorRest(expr); break; } case SUBGT:{ lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SubGt, rightExp, dbType); expr = bitXorRest(expr); break; } case LT_SUB_GT: { lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PG_ST_DISTANCE, rightExp, dbType); expr = bitXorRest(expr); break; } case SUBGTGT:{ lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SubGtGt, rightExp, dbType); expr = bitXorRest(expr); break; } case POUNDGT: { lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PoundGt, rightExp, dbType); expr = bitXorRest(expr); break; } case POUNDGTGT: { lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PoundGtGt, rightExp, dbType); expr = bitXorRest(expr); break; } case QUESQUES: { lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.QuesQues, rightExp, dbType); expr = bitXorRest(expr); break; } case QUESBAR: { lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.QuesBar, rightExp, dbType); expr = bitXorRest(expr); break; } case QUESAMP: { lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.QuesAmp, rightExp, dbType); expr = bitXorRest(expr); break; } default: break; } return expr; } public final SQLExpr multiplicative() { SQLExpr expr = bitXor(); return multiplicativeRest(expr); } public SQLExpr multiplicativeRest(SQLExpr expr) { final Token token = lexer.token; if (token == Token.STAR) { lexer.nextToken(); SQLExpr rightExp = bitXor(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Multiply, rightExp, getDbType()); expr = multiplicativeRest(expr); } else if (token == Token.SLASH) { lexer.nextToken(); SQLExpr rightExp = bitXor(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Divide, rightExp, getDbType()); expr = multiplicativeRest(expr); } else if (token == Token.PERCENT) { lexer.nextToken(); SQLExpr rightExp = bitXor(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Modulus, rightExp, getDbType()); expr = multiplicativeRest(expr); } else if (token == Token.DIV) { lexer.nextToken(); SQLExpr rightExp = bitXor(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.DIV, rightExp, getDbType()); expr = multiplicativeRest(expr); } else if (lexer.identifierEquals(FnvHash.Constants.MOD)) { Lexer.SavePoint savePoint = lexer.mark(); lexer.nextToken(); if (lexer.token == Token.COMMA) { lexer.reset(savePoint); return expr; } SQLExpr rightExp = primary(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.Modulus, rightExp, JdbcConstants.MYSQL); } return expr; } public SQLIntegerExpr integerExpr() { SQLIntegerExpr intExpr = new SQLIntegerExpr(lexer.integerValue()); accept(Token.LITERAL_INT); return intExpr; } public int parseIntValue() { if (lexer.token == Token.LITERAL_INT) { Number number = this.lexer.integerValue(); int intVal = ((Integer) number).intValue(); lexer.nextToken(); return intVal; } else { throw new ParserException("not int. " + lexer.info()); } } public SQLExpr primary() { List beforeComments = null; if (lexer.isKeepComments() && lexer.hasComment()) { beforeComments = lexer.readAndResetComments(); } SQLExpr sqlExpr = null; final Token tok = lexer.token; switch (tok) { case LPAREN: lexer.nextToken(); sqlExpr = expr(); if (lexer.token == Token.COMMA) { SQLListExpr listExpr = new SQLListExpr(); listExpr.addItem(sqlExpr); do { lexer.nextToken(); listExpr.addItem(expr()); } while (lexer.token == Token.COMMA); sqlExpr = listExpr; } if (sqlExpr instanceof SQLBinaryOpExpr) { ((SQLBinaryOpExpr) sqlExpr).setBracket(true); } accept(Token.RPAREN); if (lexer.token == Token.UNION && sqlExpr instanceof SQLQueryExpr) { SQLQueryExpr queryExpr = (SQLQueryExpr) sqlExpr; SQLSelectQuery query = this.createSelectParser().queryRest(queryExpr.getSubQuery().getQuery()); queryExpr.getSubQuery().setQuery(query); } break; case INSERT: lexer.nextToken(); if (lexer.token != Token.LPAREN) { throw new ParserException("syntax error. " + lexer.info()); } sqlExpr = new SQLIdentifierExpr("INSERT"); break; case IDENTIFIER: String ident = lexer.stringVal(); long hash_lower = lexer.hash_lower; lexer.nextToken(); if (hash_lower == FnvHash.Constants.DATE && (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.VARIANT) && (JdbcConstants.ORACLE.equals(dbType) || JdbcConstants.POSTGRESQL.equals(dbType) || JdbcConstants.MYSQL.equals(dbType))) { SQLExpr literal = this.primary(); SQLDateExpr dateExpr = new SQLDateExpr(); dateExpr.setLiteral(literal); sqlExpr = dateExpr; } else if (hash_lower == FnvHash.Constants.TIMESTAMP && (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.VARIANT) && !JdbcConstants.ORACLE.equals(dbType)) { SQLTimestampExpr dateExpr = new SQLTimestampExpr(lexer.stringVal()); lexer.nextToken(); sqlExpr = dateExpr; } else if (JdbcConstants.MYSQL.equalsIgnoreCase(dbType) && ident.startsWith("0x") && (ident.length() % 2) == 0) { sqlExpr = new SQLHexExpr(ident.substring(2)); } else { sqlExpr = new SQLIdentifierExpr(ident, hash_lower); } break; case NEW: throw new ParserException("TODO " + lexer.info()); case LITERAL_INT: sqlExpr = new SQLIntegerExpr(lexer.integerValue()); lexer.nextToken(); break; case LITERAL_FLOAT: sqlExpr = lexer.numberExpr(); lexer.nextToken(); break; case LITERAL_CHARS: { sqlExpr = new SQLCharExpr(lexer.stringVal()); lexer.nextToken(); if (JdbcConstants.MYSQL.equals(dbType)) { SQLMethodInvokeExpr concat = null; for (; ; ) { if (lexer.token == Token.LITERAL_ALIAS) { if (concat == null) { concat = new SQLMethodInvokeExpr("CONCAT"); concat.addParameter(sqlExpr); sqlExpr = concat; } String alias = lexer.stringVal(); lexer.nextToken(); SQLCharExpr concat_right = new SQLCharExpr(alias.substring(1, alias.length() - 1)); concat.addParameter(concat_right); } else if (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.LITERAL_NCHARS) { if (concat == null) { concat = new SQLMethodInvokeExpr("CONCAT"); concat.addParameter(sqlExpr); sqlExpr = concat; } String chars = lexer.stringVal(); lexer.nextToken(); SQLCharExpr concat_right = new SQLCharExpr(chars); concat.addParameter(concat_right); } else { break; } } } break; } case LITERAL_NCHARS: sqlExpr = new SQLNCharExpr(lexer.stringVal()); lexer.nextToken(); if (JdbcConstants.MYSQL.equals(dbType)) { SQLMethodInvokeExpr concat = null; for (; ; ) { if (lexer.token == Token.LITERAL_ALIAS) { if (concat == null) { concat = new SQLMethodInvokeExpr("CONCAT"); concat.addParameter(sqlExpr); sqlExpr = concat; } String alias = lexer.stringVal(); lexer.nextToken(); SQLCharExpr concat_right = new SQLCharExpr(alias.substring(1, alias.length() - 1)); concat.addParameter(concat_right); } else if (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.LITERAL_NCHARS) { if (concat == null) { concat = new SQLMethodInvokeExpr("CONCAT"); concat.addParameter(sqlExpr); sqlExpr = concat; } String chars = lexer.stringVal(); lexer.nextToken(); SQLCharExpr concat_right = new SQLCharExpr(chars); concat.addParameter(concat_right); } else { break; } } } break; case VARIANT: { String varName = lexer.stringVal(); lexer.nextToken(); if (varName.equals(":") && lexer.token == Token.IDENTIFIER && JdbcConstants.ORACLE.equals(dbType)) { String part2 = lexer.stringVal(); lexer.nextToken(); varName += part2; } SQLVariantRefExpr varRefExpr = new SQLVariantRefExpr(varName); if (varName.startsWith(":")) { varRefExpr.setIndex(lexer.nextVarIndex()); } 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(); } sqlExpr = varRefExpr; } break; case DEFAULT: sqlExpr = new SQLDefaultExpr(); lexer.nextToken(); break; case DUAL: case KEY: case DISTINCT: case LIMIT: case SCHEMA: case COLUMN: case IF: case END: case COMMENT: case COMPUTE: case ENABLE: case DISABLE: case INITIALLY: case SEQUENCE: case USER: case EXPLAIN: case WITH: case GRANT: case REPLACE: case INDEX: case MODEL: case PCTFREE: case INITRANS: case MAXTRANS: case SEGMENT: case CREATION: case IMMEDIATE: case DEFERRED: case STORAGE: case NEXT: case MINEXTENTS: case MAXEXTENTS: case MAXSIZE: case PCTINCREASE: case FLASH_CACHE: case CELL_FLASH_CACHE: case NONE: case LOB: case STORE: case ROW: case CHUNK: case CACHE: case NOCACHE: case LOGGING: case NOCOMPRESS: case KEEP_DUPLICATES: case EXCEPTIONS: case PURGE: case FULL: case TO: case IDENTIFIED: case PASSWORD: case BINARY: case WINDOW: case OFFSET: case SHARE: case START: case CONNECT: case MATCHED: case ERRORS: case REJECT: case UNLIMITED: case BEGIN: case EXCLUSIVE: case MODE: case ADVISE: case VIEW: case ESCAPE: case OVER: case ORDER: case CONSTRAINT: case TYPE: case OPEN: case REPEAT: case TABLE: case TRUNCATE: case EXCEPTION: case FUNCTION: case IDENTITY: case EXTRACT: case DESC: case DO: case GROUP: case MOD: case CONCAT: sqlExpr = new SQLIdentifierExpr(lexer.stringVal()); lexer.nextToken(); break; case CASE: SQLCaseExpr caseExpr = new SQLCaseExpr(); lexer.nextToken(); if (lexer.token != Token.WHEN) { caseExpr.setValueExpr(expr()); } accept(Token.WHEN); SQLExpr testExpr = expr(); accept(Token.THEN); SQLExpr valueExpr = expr(); SQLCaseExpr.Item caseItem = new SQLCaseExpr.Item(testExpr, valueExpr); caseExpr.addItem(caseItem); while (lexer.token == Token.WHEN) { lexer.nextToken(); testExpr = expr(); accept(Token.THEN); valueExpr = expr(); caseItem = new SQLCaseExpr.Item(testExpr, valueExpr); caseExpr.addItem(caseItem); } if (lexer.token == Token.ELSE) { lexer.nextToken(); caseExpr.setElseExpr(expr()); } accept(Token.END); sqlExpr = caseExpr; break; case EXISTS: lexer.nextToken(); accept(Token.LPAREN); sqlExpr = new SQLExistsExpr(createSelectParser().select()); accept(Token.RPAREN); break; case NOT: lexer.nextToken(); if (lexer.token == Token.EXISTS) { lexer.nextToken(); accept(Token.LPAREN); sqlExpr = new SQLExistsExpr(createSelectParser().select(), true); accept(Token.RPAREN); } else if (lexer.token == Token.LPAREN) { lexer.nextToken(); SQLExpr notTarget = expr(); accept(Token.RPAREN); notTarget = relationalRest(notTarget); sqlExpr = new SQLNotExpr(notTarget); return primaryRest(sqlExpr); } else { SQLExpr restExpr = relational(); sqlExpr = new SQLNotExpr(restExpr); } break; case SELECT: SQLQueryExpr queryExpr = new SQLQueryExpr( createSelectParser() .select()); sqlExpr = queryExpr; break; case CAST: lexer.nextToken(); accept(Token.LPAREN); SQLCastExpr cast = new SQLCastExpr(); cast.setExpr(expr()); accept(Token.AS); cast.setDataType(parseDataType(false)); accept(Token.RPAREN); sqlExpr = cast; break; case SUB: lexer.nextToken(); switch (lexer.token) { case LITERAL_INT: Number integerValue = lexer.integerValue(); if (integerValue instanceof Integer) { int intVal = ((Integer) integerValue).intValue(); if (intVal == Integer.MIN_VALUE) { integerValue = Long.valueOf(((long) intVal) * -1); } else { integerValue = Integer.valueOf(intVal * -1); } } else if (integerValue instanceof Long) { long longVal = ((Long) integerValue).longValue(); if (longVal == 2147483648L) { integerValue = Integer.valueOf((int) (((long) longVal) * -1)); } else { integerValue = Long.valueOf(longVal * -1); } } else { integerValue = ((BigInteger) integerValue).negate(); } sqlExpr = new SQLIntegerExpr(integerValue); lexer.nextToken(); break; case LITERAL_FLOAT: sqlExpr = lexer.numberExpr(true); lexer.nextToken(); break; case IDENTIFIER: // 当负号后面为字段的情况 sqlExpr = new SQLIdentifierExpr(lexer.stringVal()); lexer.nextToken(); if (lexer.token == Token.LPAREN || lexer.token == Token.LBRACKET) { sqlExpr = primaryRest(sqlExpr); } sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, sqlExpr); break; case QUES: { SQLVariantRefExpr variantRefExpr = new SQLVariantRefExpr("?"); variantRefExpr.setIndex(lexer.nextVarIndex()); sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, variantRefExpr); lexer.nextToken(); break; } case LPAREN: lexer.nextToken(); sqlExpr = expr(); accept(Token.RPAREN); sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, sqlExpr); break; case BANG: sqlExpr = expr(); sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, sqlExpr); break; default: throw new ParserException("TODO : " + lexer.info()); } break; case PLUS: lexer.nextToken(); switch (lexer.token) { case LITERAL_INT: sqlExpr = new SQLIntegerExpr(lexer.integerValue()); lexer.nextToken(); break; case LITERAL_FLOAT: sqlExpr = lexer.numberExpr(); lexer.nextToken(); break; case IDENTIFIER: // 当+号后面为字段的情况 sqlExpr = new SQLIdentifierExpr(lexer.stringVal()); sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Plus, sqlExpr); lexer.nextToken(); break; case LPAREN: lexer.nextToken(); sqlExpr = expr(); accept(Token.RPAREN); sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Plus, sqlExpr); break; case SUB: sqlExpr = expr(); sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Plus, sqlExpr); break; default: throw new ParserException("TODO " + lexer.info()); } break; case TILDE: lexer.nextToken(); SQLExpr unaryValueExpr = primary(); SQLUnaryExpr unary = new SQLUnaryExpr(SQLUnaryOperator.Compl, unaryValueExpr); sqlExpr = unary; break; case QUES: lexer.nextToken(); SQLVariantRefExpr quesVarRefExpr = new SQLVariantRefExpr("?"); quesVarRefExpr.setIndex(lexer.nextVarIndex()); sqlExpr = quesVarRefExpr; break; case LEFT: sqlExpr = new SQLIdentifierExpr("LEFT"); lexer.nextToken(); break; case RIGHT: sqlExpr = new SQLIdentifierExpr("RIGHT"); lexer.nextToken(); break; case DATABASE: sqlExpr = new SQLIdentifierExpr("DATABASE"); lexer.nextToken(); break; case LOCK: sqlExpr = new SQLIdentifierExpr("LOCK"); lexer.nextToken(); break; case NULL: sqlExpr = new SQLNullExpr(); lexer.nextToken(); break; case BANG: lexer.nextToken(); SQLExpr bangExpr = primary(); sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Not, bangExpr); break; case LITERAL_HEX: String hex = lexer.hexString(); sqlExpr = new SQLHexExpr(hex); lexer.nextToken(); break; case INTERVAL: sqlExpr = parseInterval(); break; case COLON: lexer.nextToken(); if (lexer.token == Token.LITERAL_ALIAS) { sqlExpr = new SQLVariantRefExpr(":\"" + lexer.stringVal() + "\""); lexer.nextToken(); } break; case ANY: sqlExpr = parseAny(); break; case SOME: sqlExpr = parseSome(); break; case ALL: sqlExpr = parseAll(); break; case LITERAL_ALIAS: sqlExpr = parseAliasExpr(lexer.stringVal()); lexer.nextToken(); break; case EOF: throw new EOFParserException(); case TRUE: lexer.nextToken(); sqlExpr = new SQLBooleanExpr(true); break; case FALSE: lexer.nextToken(); sqlExpr = new SQLBooleanExpr(false); break; case BITS: { String strVal = lexer.stringVal(); lexer.nextToken(); sqlExpr = new SQLBinaryExpr(strVal); break; } case SET: { Lexer.SavePoint savePoint = lexer.mark(); lexer.nextToken(); if (lexer.token() == Token.LPAREN) { sqlExpr = new SQLIdentifierExpr("SET"); } else { lexer.reset(savePoint); throw new ParserException("ERROR. " + lexer.info()); } break; } default: throw new ParserException("ERROR. " + lexer.info()); } SQLExpr expr = primaryRest(sqlExpr); if (beforeComments != null) { expr.addBeforeComment(beforeComments); } return expr; } protected SQLExpr parseAll() { SQLExpr sqlExpr; lexer.nextToken(); SQLAllExpr allExpr = new SQLAllExpr(); accept(Token.LPAREN); SQLSelect allSubQuery = createSelectParser().select(); allExpr.setSubQuery(allSubQuery); accept(Token.RPAREN); allSubQuery.setParent(allExpr); sqlExpr = allExpr; return sqlExpr; } protected SQLExpr parseSome() { SQLExpr sqlExpr; lexer.nextToken(); SQLSomeExpr someExpr = new SQLSomeExpr(); accept(Token.LPAREN); SQLSelect someSubQuery = createSelectParser().select(); someExpr.setSubQuery(someSubQuery); accept(Token.RPAREN); someSubQuery.setParent(someExpr); sqlExpr = someExpr; return sqlExpr; } protected SQLExpr parseAny() { SQLExpr sqlExpr; lexer.nextToken(); if (lexer.token == Token.LPAREN) { accept(Token.LPAREN); if (lexer.token == Token.ARRAY || lexer.token == Token.IDENTIFIER) { SQLExpr expr = this.expr(); SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr("ANY"); methodInvokeExpr.addParameter(expr); accept(Token.RPAREN); return methodInvokeExpr; } SQLSelect anySubQuery = createSelectParser().select(); SQLAnyExpr anyExpr = new SQLAnyExpr(anySubQuery); accept(Token.RPAREN); sqlExpr = anyExpr; } else { sqlExpr = new SQLIdentifierExpr("ANY"); } return sqlExpr; } protected SQLExpr parseAliasExpr(String alias) { return new SQLIdentifierExpr(alias); } protected SQLExpr parseInterval() { throw new ParserException("TODO. " + lexer.info()); } public SQLSelectParser createSelectParser() { return new SQLSelectParser(this); } public SQLExpr primaryRest(SQLExpr expr) { if (expr == null) { throw new IllegalArgumentException("expr"); } Token token = lexer.token; if (token == Token.OF) { if (expr instanceof SQLIdentifierExpr) { long hashCode64 = ((SQLIdentifierExpr) expr).hashCode64(); if (hashCode64 == FnvHash.Constants.CURRENT) { lexer.nextToken(); SQLName cursorName = this.name(); return new SQLCurrentOfCursorExpr(cursorName); } } } else if (token == Token.FOR) { if (expr instanceof SQLIdentifierExpr) { SQLIdentifierExpr idenExpr = (SQLIdentifierExpr) expr; if (idenExpr.hashCode64() == FnvHash.Constants.NEXTVAL) { lexer.nextToken(); SQLName seqName = this.name(); SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.NextVal); return seqExpr; } else if (idenExpr.hashCode64() == FnvHash.Constants.CURRVAL) { lexer.nextToken(); SQLName seqName = this.name(); SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.CurrVal); return seqExpr; } else if (idenExpr.hashCode64() == FnvHash.Constants.PREVVAL) { lexer.nextToken(); SQLName seqName = this.name(); SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.PrevVal); return seqExpr; } } } if (token == Token.DOT) { lexer.nextToken(); if (expr instanceof SQLCharExpr) { String text = ((SQLCharExpr) expr).getText(); expr = new SQLIdentifierExpr(text); } expr = dotRest(expr); return primaryRest(expr); } else if (lexer.identifierEquals(FnvHash.Constants.SETS) // && expr.getClass() == SQLIdentifierExpr.class // && "GROUPING".equalsIgnoreCase(((SQLIdentifierExpr) expr).getName())) { SQLGroupingSetExpr groupingSets = new SQLGroupingSetExpr(); lexer.nextToken(); accept(Token.LPAREN); for (; ; ) { SQLExpr item; if (lexer.token == Token.LPAREN) { lexer.nextToken(); SQLListExpr listExpr = new SQLListExpr(); this.exprList(listExpr.getItems(), listExpr); item = listExpr; accept(Token.RPAREN); } else { item = this.expr(); } item.setParent(groupingSets); groupingSets.addParameter(item); if (lexer.token == Token.RPAREN) { break; } accept(Token.COMMA); } this.exprList(groupingSets.getParameters(), groupingSets); accept(Token.RPAREN); return groupingSets; } else { if (lexer.token == Token.LPAREN) { return methodRest(expr, true); } } return expr; } protected SQLExpr parseExtract() { throw new ParserException("not supported."); } protected SQLExpr parsePosition() { throw new ParserException("not supported."); } protected SQLExpr parseMatch() { throw new ParserException("not supported."); } protected SQLExpr methodRest(SQLExpr expr, boolean acceptLPAREN) { if (acceptLPAREN) { accept(Token.LPAREN); } boolean distinct = false; if (lexer.token == Token.DISTINCT) { lexer.nextToken(); distinct = true; } String methodName = null; String aggMethodName = null; SQLMethodInvokeExpr methodInvokeExpr; SQLExpr owner = null; String trimOption = null; long hash_lower = 0L; if (expr instanceof SQLIdentifierExpr) { SQLIdentifierExpr identifierExpr = (SQLIdentifierExpr) expr; methodName = identifierExpr.getName(); hash_lower = identifierExpr.nameHashCode64(); if (hash_lower == FnvHash.Constants.TRIM) { if (lexer.identifierEquals(FnvHash.Constants.LEADING)) { trimOption = lexer.stringVal(); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.BOTH)) { trimOption = lexer.stringVal(); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.TRAILING)) { trimOption = lexer.stringVal(); lexer.nextToken(); } } else if (hash_lower == FnvHash.Constants.MATCH && JdbcConstants.MYSQL.equals(dbType)) { return parseMatch(); } else if (hash_lower == FnvHash.Constants.EXTRACT && JdbcConstants.MYSQL.equals(dbType)) { return parseExtract(); } else if (hash_lower == FnvHash.Constants.POSITION && JdbcConstants.MYSQL.equals(dbType)) { return parsePosition(); } else if (hash_lower == FnvHash.Constants.INT4 && JdbcConstants.POSTGRESQL.equals(dbType)) { PGTypeCastExpr castExpr = new PGTypeCastExpr(); castExpr.setExpr(this.expr()); castExpr.setDataType(new SQLDataTypeImpl(methodName)); accept(Token.RPAREN); return castExpr; } else if (hash_lower == FnvHash.Constants.VARBIT && JdbcConstants.POSTGRESQL.equals(dbType)) { PGTypeCastExpr castExpr = new PGTypeCastExpr(); SQLExpr len = this.primary(); castExpr.setDataType(new SQLDataTypeImpl(methodName, len)); accept(Token.RPAREN); castExpr.setExpr(this.expr()); return castExpr; } aggMethodName = getAggreateFunction(hash_lower); } else if (expr instanceof SQLPropertyExpr) { methodName = expr.toString(); aggMethodName = SQLUtils.normalize(methodName); hash_lower = FnvHash.fnv1a_64_lower(aggMethodName); aggMethodName = getAggreateFunction(hash_lower); owner = ((SQLPropertyExpr) expr).getOwner(); } else if (expr instanceof SQLDefaultExpr) { methodName = "DEFAULT"; } else if (expr instanceof SQLCharExpr) { methodName = ((SQLCharExpr) expr).getText(); } if (aggMethodName != null) { SQLAggregateExpr aggregateExpr = parseAggregateExpr(aggMethodName); if (distinct) { aggregateExpr.setOption(SQLAggregateOption.DISTINCT); } return aggregateExpr; } methodInvokeExpr = new SQLMethodInvokeExpr(methodName, hash_lower); if (owner != null) { methodInvokeExpr.setOwner(owner); } if (trimOption != null) { methodInvokeExpr.setTrimOption(trimOption); } Token token = lexer.token; if (token != Token.RPAREN && token != Token.FROM) { exprList(methodInvokeExpr.getParameters(), methodInvokeExpr); } if (hash_lower == FnvHash.Constants.EXIST && methodInvokeExpr.getParameters().size() == 1 && methodInvokeExpr.getParameters().get(0) instanceof SQLQueryExpr) { throw new ParserException("exists syntax error."); } if (lexer.token == Token.FROM) { lexer.nextToken(); SQLExpr from = this.expr(); methodInvokeExpr.setFrom(from); if (lexer.token == Token.FOR) { lexer.nextToken(); SQLExpr forExpr = expr(); methodInvokeExpr.setFor(forExpr); } } if (lexer.token == Token.USING || lexer.identifierEquals(FnvHash.Constants.USING)) { lexer.nextToken(); SQLExpr using; if (lexer.token == Token.STAR) { lexer.nextToken(); using = new SQLAllColumnExpr(); } else if (lexer.token == Token.BINARY) { using = new SQLIdentifierExpr(lexer.stringVal()); lexer.nextToken(); } else { using = this.primary(); } methodInvokeExpr.setUsing(using); } accept(Token.RPAREN); if (lexer.token == Token.OVER) { SQLAggregateExpr aggregateExpr = new SQLAggregateExpr(methodName); aggregateExpr.getArguments().addAll(methodInvokeExpr.getParameters()); over(aggregateExpr); return primaryRest(aggregateExpr); } return primaryRest(methodInvokeExpr); //throw new ParserException("not support token:" + lexer.token + ", " + lexer.info()); } protected SQLExpr dotRest(SQLExpr expr) { if (lexer.token == Token.STAR) { lexer.nextToken(); expr = new SQLPropertyExpr(expr, "*"); } else { String name; long hash_lower = 0L; if (lexer.token == Token.IDENTIFIER) { name = lexer.stringVal(); hash_lower = lexer.hash_lower; lexer.nextToken(); } else if (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.LITERAL_ALIAS) { name = lexer.stringVal(); lexer.nextToken(); } else if (lexer.getKeywods().containsValue(lexer.token)) { name = lexer.stringVal(); lexer.nextToken(); } else { throw new ParserException("error : " + lexer.info()); } if (lexer.token == Token.LPAREN) { boolean aggregate = hash_lower == FnvHash.Constants.WM_CONCAT && expr instanceof SQLIdentifierExpr && ((SQLIdentifierExpr) expr).nameHashCode64() == FnvHash.Constants.WMSYS; expr = methodRest(expr, name, aggregate); } else { expr = new SQLPropertyExpr(expr, name, hash_lower); } } expr = primaryRest(expr); return expr; } private SQLExpr methodRest(SQLExpr expr, String name, boolean aggregate) { lexer.nextToken(); if (lexer.token == Token.DISTINCT) { lexer.nextToken(); String aggreateMethodName = expr.toString() + "." + name; SQLAggregateExpr aggregateExpr = new SQLAggregateExpr(aggreateMethodName, SQLAggregateOption.DISTINCT); if (lexer.token == Token.RPAREN) { lexer.nextToken(); } else { if (lexer.token == Token.PLUS) { aggregateExpr.getArguments().add(new SQLIdentifierExpr("+")); lexer.nextToken(); } else { exprList(aggregateExpr.getArguments(), aggregateExpr); } accept(Token.RPAREN); } expr = aggregateExpr; } else if (aggregate) { SQLAggregateExpr methodInvokeExpr = new SQLAggregateExpr(name); methodInvokeExpr.setMethodName(expr.toString() + "." + name); if (lexer.token == Token.RPAREN) { lexer.nextToken(); } else { if (lexer.token == Token.PLUS) { methodInvokeExpr.addArgument(new SQLIdentifierExpr("+")); lexer.nextToken(); } else { exprList(methodInvokeExpr.getArguments(), methodInvokeExpr); } accept(Token.RPAREN); } expr = methodInvokeExpr; } else { SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(name); methodInvokeExpr.setOwner(expr); if (lexer.token == Token.RPAREN) { lexer.nextToken(); } else { if (lexer.token == Token.PLUS) { methodInvokeExpr.addParameter(new SQLIdentifierExpr("+")); lexer.nextToken(); } else { exprList(methodInvokeExpr.getParameters(), methodInvokeExpr); } accept(Token.RPAREN); } expr = methodInvokeExpr; } return expr; } public final SQLExpr groupComparisionRest(SQLExpr expr) { return expr; } public final void names(Collection exprCol) { names(exprCol, null); } public final void names(Collection exprCol, SQLObject parent) { if (lexer.token == Token.RBRACE) { return; } if (lexer.token == Token.EOF) { return; } SQLName name = name(); name.setParent(parent); exprCol.add(name); while (lexer.token == Token.COMMA) { lexer.nextToken(); name = name(); name.setParent(parent); exprCol.add(name); } } @Deprecated public final void exprList(Collection exprCol) { exprList(exprCol, null); } public final void exprList(Collection exprCol, SQLObject parent) { if (lexer.token == Token.RPAREN || lexer.token == Token.RBRACKET) { return; } if (lexer.token == Token.EOF) { return; } SQLExpr expr = expr(); expr.setParent(parent); exprCol.add(expr); while (lexer.token == Token.COMMA) { lexer.nextToken(); expr = expr(); expr.setParent(parent); exprCol.add(expr); } } public SQLName name() { String identName; long hash = 0; if (lexer.token == Token.LITERAL_ALIAS) { identName = lexer.stringVal(); lexer.nextToken(); } else if (lexer.token == Token.IDENTIFIER) { identName = lexer.stringVal(); char c0 = identName.charAt(0); if (c0 != '[') { hash = lexer.hash_lower(); } lexer.nextToken(); } else if (lexer.token == Token.LITERAL_CHARS) { identName = '\'' + lexer.stringVal() + '\''; lexer.nextToken(); } else if (lexer.token == Token.VARIANT) { identName = lexer.stringVal(); lexer.nextToken(); } else { switch (lexer.token) { case MODEL: case PCTFREE: case INITRANS: case MAXTRANS: case SEGMENT: case CREATION: case IMMEDIATE: case DEFERRED: case STORAGE: case NEXT: case MINEXTENTS: case MAXEXTENTS: case MAXSIZE: case PCTINCREASE: case FLASH_CACHE: case CELL_FLASH_CACHE: case NONE: case LOB: case STORE: case ROW: case CHUNK: case CACHE: case NOCACHE: case LOGGING: case NOCOMPRESS: case KEEP_DUPLICATES: case EXCEPTIONS: case PURGE: case INITIALLY: case END: case COMMENT: case ENABLE: case DISABLE: case SEQUENCE: case USER: case ANALYZE: case OPTIMIZE: case GRANT: case REVOKE: // binary有很多含义,lexer识别了这个token,实际上应该当做普通IDENTIFIER case BINARY: case OVER: case ORDER: case DO: case JOIN: case TYPE: case FUNCTION: case KEY: case SCHEMA: case INTERVAL: case EXPLAIN: case PARTITION: case SET: identName = lexer.stringVal(); lexer.nextToken(); break; default: throw new ParserException("error " + lexer.info()); } } SQLName name = new SQLIdentifierExpr(identName, hash); name = nameRest(name); return name; } public SQLName nameRest(SQLName name) { if (lexer.token == Token.DOT) { lexer.nextToken(); if (lexer.token == Token.KEY) { name = new SQLPropertyExpr(name, "KEY"); lexer.nextToken(); return name; } if (lexer.token != Token.LITERAL_ALIAS && lexer.token != Token.IDENTIFIER && (!lexer.getKeywods().containsValue(lexer.token))) { throw new ParserException("error, " + lexer.info()); } if (lexer.token == Token.LITERAL_ALIAS) { name = new SQLPropertyExpr(name, lexer.stringVal()); } else { name = new SQLPropertyExpr(name, lexer.stringVal()); } lexer.nextToken(); name = nameRest(name); } return name; } public boolean isAggreateFunction(String word) { long hash_lower = FnvHash.fnv1a_64_lower(word); return isAggreateFunction(hash_lower); } protected boolean isAggreateFunction(long hash_lower) { return Arrays.binarySearch(aggregateFunctionHashCodes, hash_lower) >= 0; } protected String getAggreateFunction(long hash_lower) { int index = Arrays.binarySearch(aggregateFunctionHashCodes, hash_lower); if (index < 0) { return null; } return aggregateFunctions[index]; } protected SQLAggregateExpr parseAggregateExpr(String methodName) { SQLAggregateExpr aggregateExpr; if (lexer.token == Token.ALL) { aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.ALL); lexer.nextToken(); } else if (lexer.token == Token.DISTINCT) { aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.DISTINCT); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.DEDUPLICATION)) { // just for nut aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.DEDUPLICATION); lexer.nextToken(); } else { aggregateExpr = new SQLAggregateExpr(methodName); } exprList(aggregateExpr.getArguments(), aggregateExpr); if (lexer.token != Token.RPAREN) { parseAggregateExprRest(aggregateExpr); } accept(Token.RPAREN); if (lexer.token == Token.OVER) { over(aggregateExpr); } return aggregateExpr; } protected void over(SQLAggregateExpr aggregateExpr) { lexer.nextToken(); SQLOver over = new SQLOver(); accept(Token.LPAREN); if (lexer.token == Token.PARTITION || lexer.identifierEquals("PARTITION")) { lexer.nextToken(); accept(Token.BY); if (lexer.token == (Token.LPAREN)) { lexer.nextToken(); exprList(over.getPartitionBy(), over); accept(Token.RPAREN); } else { exprList(over.getPartitionBy(), over); } } over.setOrderBy(parseOrderBy()); if (lexer.token == Token.OF) { lexer.nextToken(); SQLName of = this.name(); over.setOf(of); } SQLOver.WindowingType windowingType = null; if (lexer.identifierEquals(FnvHash.Constants.ROWS)) { windowingType = SQLOver.WindowingType.ROWS; } else if (lexer.identifierEquals(FnvHash.Constants.RANGE)) { windowingType = SQLOver.WindowingType.RANGE; } if (windowingType != null) { over.setWindowingType(windowingType); lexer.nextToken(); if (lexer.token == Token.BETWEEN) { lexer.nextToken(); SQLIntegerExpr rowsBegin = (SQLIntegerExpr) this.primary(); over.setWindowingBetweenBegin(rowsBegin); if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) { over.setWindowingBetweenBeginPreceding(true); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.FOLLOWING)) { over.setWindowingBetweenBeginFollowing(true); lexer.nextToken(); } accept(Token.AND); SQLIntegerExpr betweenEnd = (SQLIntegerExpr) this.primary(); over.setWindowingBetweenEnd(betweenEnd); if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) { over.setWindowingBetweenEndPreceding(true); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.FOLLOWING)) { over.setWindowingBetweenEndFollowing(true); lexer.nextToken(); } } else { if (lexer.identifierEquals(FnvHash.Constants.CURRENT)) { lexer.nextToken(); acceptIdentifier("ROW"); over.setWindowing(new SQLIdentifierExpr("CURRENT ROW")); } else if (lexer.identifierEquals(FnvHash.Constants.UNBOUNDED)) { lexer.nextToken(); over.setWindowing(new SQLIdentifierExpr("UNBOUNDED")); if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) { over.setWindowingPreceding(true); lexer.nextToken(); } else if (lexer.identifierEquals("FOLLOWING")) { over.setWindowingFollowing(true); lexer.nextToken(); } } else { SQLIntegerExpr rowsExpr = (SQLIntegerExpr) this.primary(); over.setWindowing(rowsExpr); if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) { over.setWindowingPreceding(true); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.FOLLOWING)) { over.setWindowingFollowing(true); lexer.nextToken(); } } } } accept(Token.RPAREN); aggregateExpr.setOver(over); } protected SQLAggregateExpr parseAggregateExprRest(SQLAggregateExpr aggregateExpr) { return aggregateExpr; } public SQLOrderBy parseOrderBy() { if (lexer.token == Token.ORDER) { SQLOrderBy orderBy = new SQLOrderBy(); lexer.nextToken(); if (lexer.identifierEquals(FnvHash.Constants.SIBLINGS)) { lexer.nextToken(); orderBy.setSibings(true); } accept(Token.BY); orderBy(orderBy.getItems(), orderBy); return orderBy; } return null; } public void orderBy(List items, SQLObject parent) { SQLSelectOrderByItem item = parseSelectOrderByItem(); item.setParent(parent); items.add(item); while (lexer.token == Token.COMMA) { lexer.nextToken(); item = parseSelectOrderByItem(); item.setParent(parent); items.add(item); } } public SQLSelectOrderByItem parseSelectOrderByItem() { SQLSelectOrderByItem item = new SQLSelectOrderByItem(); 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); } if (lexer.identifierEquals(FnvHash.Constants.NULLS)) { lexer.nextToken(); if (lexer.identifierEquals(FnvHash.Constants.FIRST)) { lexer.nextToken(); item.setNullsOrderType(SQLSelectOrderByItem.NullsOrderType.NullsFirst); } else if (lexer.identifierEquals(FnvHash.Constants.LAST)) { lexer.nextToken(); item.setNullsOrderType(SQLSelectOrderByItem.NullsOrderType.NullsLast); } else { throw new ParserException("TODO " + lexer.info()); } } return item; } public SQLUpdateSetItem parseUpdateSetItem() { SQLUpdateSetItem item = new SQLUpdateSetItem(); if (lexer.token == (Token.LPAREN)) { lexer.nextToken(); SQLListExpr list = new SQLListExpr(); this.exprList(list.getItems(), list); accept(Token.RPAREN); item.setColumn(list); } else { String identName; long hash; Token token = lexer.token(); if (token == Token.IDENTIFIER) { identName = lexer.stringVal(); hash = lexer.hash_lower(); } else if (token == Token.LITERAL_CHARS) { identName = '\'' + lexer.stringVal() + '\''; hash = 0; } else { identName = lexer.stringVal(); hash = 0; } lexer.nextTokenEq(); SQLExpr expr = new SQLIdentifierExpr(identName, hash); while (lexer.token() == Token.DOT) { lexer.nextToken(); String propertyName = lexer.stringVal(); lexer.nextTokenEq(); expr = new SQLPropertyExpr(expr, propertyName); } item.setColumn(expr); } if (lexer.token == Token.COLONEQ) { lexer.nextTokenValue(); } else if (lexer.token == Token.EQ) { lexer.nextTokenValue(); } else { throw new ParserException("syntax error, expect EQ, actual " + lexer.token + " " + lexer.info()); } item.setValue(this.expr()); return item; } public final SQLExpr bitAnd() { SQLExpr expr = shift(); return bitAndRest(expr); } public final SQLExpr bitAndRest(SQLExpr expr) { while (lexer.token == Token.AMP) { lexer.nextToken(); SQLExpr rightExp = shift(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BitwiseAnd, rightExp, getDbType()); } return expr; } public final SQLExpr bitOr() { SQLExpr expr = bitAnd(); return bitOrRest(expr); } public final SQLExpr bitOrRest(SQLExpr expr) { while (lexer.token == Token.BAR) { lexer.nextToken(); SQLBinaryOperator op = SQLBinaryOperator.BitwiseOr; if (lexer.token == Token.BAR) { lexer.nextToken(); op = SQLBinaryOperator.Concat; } SQLExpr rightExp = bitAnd(); expr = new SQLBinaryOpExpr(expr, op, rightExp, getDbType()); expr = bitAndRest(expr); } return expr; } public final SQLExpr equality() { SQLExpr expr = bitOr(); return equalityRest(expr); } private SQLExpr equalityRest2(SQLExpr expr) { SQLExpr rightExp; lexer.nextToken(); try { if (lexer.token == Token.LITERAL_INT) { rightExp = new SQLIntegerExpr(lexer.integerValue()); lexer.nextToken(); if (lexer.token == Token.AND || lexer.token == Token.RPAREN || lexer.token == Token.EOF || lexer.token == Token.OR) { return new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp, dbType); } rightExp = primaryRest(rightExp); rightExp = bitXorRest(rightExp); rightExp = multiplicativeRest(rightExp); rightExp = additiveRest(rightExp); rightExp = shiftRest(rightExp); rightExp = bitAndRest(rightExp); rightExp = bitOrRest(rightExp); rightExp = inRest(rightExp); rightExp = relationalRest(rightExp); } else { rightExp = bitOr(); } } catch (EOFParserException e) { throw new ParserException("EOF, " + expr + "=", e); } if (lexer.token == Token.COLONEQ) { lexer.nextToken(); SQLExpr colonExpr = expr(); rightExp = new SQLBinaryOpExpr(rightExp, SQLBinaryOperator.Assignment, colonExpr, dbType); } expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp, dbType); if (lexer.token == Token.IS || lexer.token == Token.BETWEEN) { expr = relationalRest(expr); } return expr; } public SQLExpr equalityRest(SQLExpr expr) { SQLExpr rightExp; final Token token = lexer.token; if (token == Token.EQ) { lexer.nextToken(); try { rightExp = bitOr(); } catch (EOFParserException e) { throw new ParserException("EOF, " + expr + "=", e); } if (lexer.token == Token.COLONEQ) { lexer.nextToken(); SQLExpr colonExpr = expr(); rightExp = new SQLBinaryOpExpr(rightExp, SQLBinaryOperator.Assignment, colonExpr, dbType); } expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp, dbType); } else if (lexer.token() == Token.EQGT) { lexer.nextToken(); rightExp = expr(); String argumentName = ((SQLIdentifierExpr) expr).getName(); return new OracleArgumentExpr(argumentName, rightExp); } else if (token == Token.BANGEQ || token == Token.CARETEQ) { lexer.nextToken(); rightExp = bitOr(); rightExp = equalityRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotEqual, rightExp, dbType); } else if (token == Token.COLONEQ) { lexer.nextToken(); rightExp = expr(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Assignment, rightExp, dbType); } if (lexer.token == Token.IS || lexer.token == Token.BETWEEN) { expr = relationalRest(expr); } return expr; } public final SQLExpr inRest(SQLExpr expr) { if (lexer.token == Token.IN) { lexer.nextTokenLParen(); SQLInListExpr inListExpr = new SQLInListExpr(expr); List targetList = inListExpr.getTargetList(); if (lexer.token == Token.LPAREN) { lexer.nextTokenValue(); if (lexer.token == Token.WITH) { SQLSelect select = this.createSelectParser().select(); SQLInSubQueryExpr queryExpr = new SQLInSubQueryExpr(select); queryExpr.setExpr(expr); accept(Token.RPAREN); return queryExpr; } for (;;) { SQLExpr item; if (lexer.token == Token.LITERAL_INT) { item = new SQLIntegerExpr(lexer.integerValue()); lexer.nextToken(); if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) { item = this.primaryRest(item); item = this.exprRest(item); } } else { item = this.expr(); } item.setParent(inListExpr); targetList.add(item); if (lexer.token == Token.COMMA) { lexer.nextTokenValue(); continue; } break; } accept(Token.RPAREN); } else { SQLExpr itemExpr = primary(); itemExpr.setParent(inListExpr); targetList.add(itemExpr); } expr = inListExpr; if (targetList.size() == 1) { SQLExpr targetExpr = targetList.get(0); if (targetExpr instanceof SQLQueryExpr) { SQLInSubQueryExpr inSubQueryExpr = new SQLInSubQueryExpr(); inSubQueryExpr.setExpr(inListExpr.getExpr()); inSubQueryExpr.setSubQuery(((SQLQueryExpr) targetExpr).getSubQuery()); expr = inSubQueryExpr; } } } return expr; } public final SQLExpr additive() { SQLExpr expr = multiplicative(); return additiveRest(expr); } public SQLExpr additiveRest(SQLExpr expr) { Token token = lexer.token; if (token == Token.PLUS) { lexer.nextToken(); SQLExpr rightExp = multiplicative(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Add, rightExp, dbType); expr = additiveRest(expr); } else if ((token == Token.BARBAR || token == Token.CONCAT) && !JdbcConstants.MYSQL.equals(dbType)) { lexer.nextToken(); SQLExpr rightExp = multiplicative(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Concat, rightExp, dbType); expr = additiveRest(expr); } else if (token == Token.SUB) { lexer.nextToken(); SQLExpr rightExp = multiplicative(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Subtract, rightExp, dbType); expr = additiveRest(expr); } return expr; } public final SQLExpr shift() { SQLExpr expr = additive(); return shiftRest(expr); } public SQLExpr shiftRest(SQLExpr expr) { if (lexer.token == Token.LTLT) { lexer.nextToken(); SQLExpr rightExp = additive(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LeftShift, rightExp, dbType); expr = shiftRest(expr); } else if (lexer.token == Token.GTGT) { lexer.nextToken(); SQLExpr rightExp = additive(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.RightShift, rightExp, dbType); expr = shiftRest(expr); } return expr; } public SQLExpr and() { SQLExpr expr = relational(); return andRest(expr); } public SQLExpr andRest(SQLExpr expr) { for (;;) { Token token = lexer.token; if (token == Token.AND) { if (lexer.isKeepComments() && lexer.hasComment()) { expr.addAfterComment(lexer.readAndResetComments()); } lexer.nextToken(); SQLExpr rightExp = relational(); if (lexer.token == Token.AND && lexer.isEnabled(SQLParserFeature.EnableSQLBinaryOpExprGroup)) { SQLBinaryOpExprGroup group = new SQLBinaryOpExprGroup(SQLBinaryOperator.BooleanAnd, dbType); group.add(expr); group.add(rightExp); if (lexer.isKeepComments() && lexer.hasComment()) { rightExp.addAfterComment(lexer.readAndResetComments()); } for (;;) { lexer.nextToken(); SQLExpr more = relational(); group.add(more); if (lexer.token == Token.AND) { if (lexer.isKeepComments() && lexer.hasComment()) { more.addAfterComment(lexer.readAndResetComments()); } continue; } break; } expr = group; } else { expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanAnd, rightExp, dbType); } } else if (token == Token.AMPAMP) { if (lexer.isKeepComments() && lexer.hasComment()) { expr.addAfterComment(lexer.readAndResetComments()); } lexer.nextToken(); SQLExpr rightExp = relational(); SQLBinaryOperator operator = JdbcConstants.POSTGRESQL.equals(dbType) ? SQLBinaryOperator.PG_And : SQLBinaryOperator.BooleanAnd; expr = new SQLBinaryOpExpr(expr, operator, rightExp, dbType); } else { break; } } return expr; } public SQLExpr or() { SQLExpr expr = and(); return orRest(expr); } public SQLExpr orRest(SQLExpr expr) { for (;;) { if (lexer.token == Token.OR) { lexer.nextToken(); SQLExpr rightExp = and(); if (lexer.token == Token.OR && lexer.isEnabled(SQLParserFeature.EnableSQLBinaryOpExprGroup)) { SQLBinaryOpExprGroup group = new SQLBinaryOpExprGroup(SQLBinaryOperator.BooleanOr, dbType); group.add(expr); group.add(rightExp); if (lexer.isKeepComments() && lexer.hasComment()) { rightExp.addAfterComment(lexer.readAndResetComments()); } for (;;) { lexer.nextToken(); SQLExpr more = and(); group.add(more); if (lexer.token == Token.OR) { if (lexer.isKeepComments() && lexer.hasComment()) { more.addAfterComment(lexer.readAndResetComments()); } continue; } break; } expr = group; } else { expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanOr, rightExp, dbType); } } else if (lexer.token == Token.BARBAR && JdbcConstants.MYSQL.equals(dbType)) { lexer.nextToken(); SQLExpr rightExp = and(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanOr, rightExp, dbType); } else if (lexer.token == Token.XOR) { lexer.nextToken(); SQLExpr rightExp = and(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanXor, rightExp, dbType); } else { break; } } return expr; } public SQLExpr relational() { SQLExpr expr = equality(); return relationalRest(expr); } public SQLExpr relationalRest(SQLExpr expr) { SQLExpr rightExp; Token token = lexer.token; if (token == Token.LT) { SQLBinaryOperator op = SQLBinaryOperator.LessThan; lexer.nextToken(); if (lexer.token == Token.EQ) { lexer.nextToken(); op = SQLBinaryOperator.LessThanOrEqual; } rightExp = bitOr(); expr = new SQLBinaryOpExpr(expr, op, rightExp, getDbType()); // expr = relationalRest(expr); } else if (token == Token.LTEQ) { lexer.nextToken(); rightExp = bitOr(); // rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LessThanOrEqual, rightExp, getDbType()); } else if (token == Token.LTEQGT) { lexer.nextToken(); rightExp = bitOr(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LessThanOrEqualOrGreaterThan, rightExp, getDbType()); } else if (token == Token.GT) { SQLBinaryOperator op = SQLBinaryOperator.GreaterThan; lexer.nextToken(); if (lexer.token == Token.EQ) { lexer.nextToken(); op = SQLBinaryOperator.GreaterThanOrEqual; } rightExp = bitOr(); expr = new SQLBinaryOpExpr(expr, op, rightExp, getDbType()); } else if (token == Token.GTEQ) { lexer.nextToken(); rightExp = bitOr(); // rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.GreaterThanOrEqual, rightExp, getDbType()); } else if (token == Token.BANGLT) { lexer.nextToken(); rightExp = bitOr(); // rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotLessThan, rightExp, getDbType()); } else if (token == Token.BANGGT) { lexer.nextToken(); rightExp = bitOr(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotGreaterThan, rightExp, getDbType()); } else if (token == Token.LTGT) { lexer.nextToken(); rightExp = bitOr(); // rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LessThanOrGreater, rightExp, getDbType()); } else if (token == Token.LIKE) { lexer.nextToken(); rightExp = bitOr(); // rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Like, rightExp, getDbType()); if (lexer.token == Token.ESCAPE) { lexer.nextToken(); rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Escape, rightExp, getDbType()); } } else if (lexer.identifierEquals(FnvHash.Constants.RLIKE)) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.RLike, rightExp, getDbType()); } else if (token == Token.ILIKE) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.ILike, rightExp, getDbType()); } else if (token == Token.MONKEYS_AT_AT) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.AT_AT, rightExp, getDbType()); } else if (token == Token.MONKEYS_AT_GT) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Array_Contains, rightExp, getDbType()); } else if (token == Token.LT_MONKEYS_AT) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Array_ContainedBy, rightExp, getDbType()); } else if (token == (Token.NOT)) { lexer.nextToken(); expr = notRationalRest(expr); } else if (token == Token.BETWEEN) { lexer.nextToken(); SQLExpr beginExpr = bitOr(); accept(Token.AND); SQLExpr endExpr = bitOr(); expr = new SQLBetweenExpr(expr, beginExpr, endExpr); } else if (token == (Token.IS)) { lexer.nextTokenNotOrNull(); SQLBinaryOperator op; if (lexer.token == Token.NOT) { op = SQLBinaryOperator.IsNot; lexer.nextTokenNotOrNull(); } else { op = SQLBinaryOperator.Is; } rightExp = primary(); expr = new SQLBinaryOpExpr(expr, op, rightExp, dbType); } else if (token == Token.IN) { expr = inRest(expr); } else if (lexer.identifierEquals(FnvHash.Constants.REGEXP)) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.RegExp, rightExp, JdbcConstants.MYSQL); } else if (JdbcConstants.POSTGRESQL.equals(lexer.dbType)) { if (lexer.identifierEquals(FnvHash.Constants.SIMILAR)) { lexer.nextToken(); accept(Token.TO); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SIMILAR_TO, rightExp, getDbType()); } else if (token == Token.TILDE) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Match, rightExp, getDbType()); } else if (token == Token.TILDE_STAR) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Match_Insensitive, rightExp, getDbType()); } else if (token == Token.BANG_TILDE) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Not_Match, rightExp, getDbType()); } else if (token == Token.BANG_TILDE_STAR) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Not_Match_POSIX_Regular_Match_Insensitive, rightExp, getDbType()); } else if (token == Token.TILDE_EQ) { lexer.nextToken(); rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SAME_AS, rightExp, getDbType()); } } if (lexer.token == Token.IS || lexer.token == Token.BETWEEN) { expr = relationalRest(expr); } return expr; } public SQLExpr notRationalRest(SQLExpr expr) { if (lexer.token == (Token.LIKE)) { lexer.nextToken(); SQLExpr rightExp = equality(); rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotLike, rightExp, getDbType()); if (lexer.token == Token.ESCAPE) { lexer.nextToken(); rightExp = expr(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Escape, rightExp, getDbType()); } } else if (lexer.token == Token.IN) { lexer.nextToken(); SQLInListExpr inListExpr = new SQLInListExpr(expr, true); if (lexer.token == Token.LPAREN) { lexer.nextToken(); exprList(inListExpr.getTargetList(), inListExpr); expr = inListExpr; accept(Token.RPAREN); } else { SQLExpr valueExpr = this.primary(); valueExpr.setParent(inListExpr); inListExpr.getTargetList().add(valueExpr); expr = inListExpr; } if (inListExpr.getTargetList().size() == 1) { SQLExpr targetExpr = inListExpr.getTargetList().get(0); if (targetExpr instanceof SQLQueryExpr) { SQLInSubQueryExpr inSubQueryExpr = new SQLInSubQueryExpr(); inSubQueryExpr.setNot(true); inSubQueryExpr.setExpr(inListExpr.getExpr()); inSubQueryExpr.setSubQuery(((SQLQueryExpr) targetExpr).getSubQuery()); expr = inSubQueryExpr; } } expr = relationalRest(expr); return expr; } else if (lexer.token == (Token.BETWEEN)) { lexer.nextToken(); SQLExpr beginExpr = bitOr(); accept(Token.AND); SQLExpr endExpr = bitOr(); expr = new SQLBetweenExpr(expr, true, beginExpr, endExpr); return expr; } else if (lexer.identifierEquals(FnvHash.Constants.RLIKE)) { lexer.nextToken(); SQLExpr rightExp = primary(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotRLike, rightExp, getDbType()); } else if (lexer.token == Token.ILIKE) { lexer.nextToken(); SQLExpr rightExp = primary(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotILike, rightExp, getDbType()); } else if (lexer.identifierEquals(FnvHash.Constants.REGEXP)) { lexer.nextToken(); SQLExpr rightExp = primary(); rightExp = relationalRest(rightExp); return new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotRegExp, rightExp, JdbcConstants.MYSQL); } else { throw new ParserException("TODO " + lexer.info()); } return expr; } public SQLDataType parseDataType() { return parseDataType(true); } public SQLDataType parseDataType(boolean restrict) { Token token = lexer.token; if (token == Token.DEFAULT || token == Token.NOT || token == Token.NULL) { return null; } SQLName typeExpr = name(); String typeName = typeExpr.toString(); if ("long".equalsIgnoreCase(typeName) // && lexer.identifierEquals("byte") // && JdbcConstants.MYSQL.equals(getDbType()) // ) { typeName += (' ' + lexer.stringVal()); lexer.nextToken(); } else if ("double".equalsIgnoreCase(typeName) && JdbcConstants.POSTGRESQL.equals(getDbType()) // ) { typeName += (' ' + lexer.stringVal()); lexer.nextToken(); } if (isCharType(typeName)) { SQLCharacterDataType charType = new SQLCharacterDataType(typeName); if (lexer.token == Token.LPAREN) { lexer.nextToken(); SQLExpr arg = this.expr(); arg.setParent(charType); charType.addArgument(arg); accept(Token.RPAREN); } charType = (SQLCharacterDataType) parseCharTypeRest(charType); if (lexer.token == Token.HINT) { List hints = this.parseHints(); charType.setHints(hints); } return charType; } if ("character".equalsIgnoreCase(typeName) && "varying".equalsIgnoreCase(lexer.stringVal())) { typeName += ' ' + lexer.stringVal(); lexer.nextToken(); } SQLDataType dataType = new SQLDataTypeImpl(typeName); dataType.setDbType(dbType); return parseDataTypeRest(dataType); } protected SQLDataType parseDataTypeRest(SQLDataType dataType) { if (lexer.token == Token.LPAREN) { lexer.nextToken(); exprList(dataType.getArguments(), dataType); accept(Token.RPAREN); } if (lexer.identifierEquals(FnvHash.Constants.PRECISION) && dataType.nameHashCode64() == FnvHash.Constants.DOUBLE) { lexer.nextToken(); dataType.setName("DOUBLE PRECISION"); } if (FnvHash.Constants.TIMESTAMP == dataType.nameHashCode64()) { if (lexer.identifierEquals(FnvHash.Constants.WITHOUT)) { lexer.nextToken(); acceptIdentifier("TIME"); acceptIdentifier("ZONE"); dataType.setWithTimeZone(false); } else if (lexer.token == Token.WITH) { lexer.nextToken(); acceptIdentifier("TIME"); acceptIdentifier("ZONE"); dataType.setWithTimeZone(true); } } return dataType; } protected boolean isCharType(String dataTypeName) { long hash = FnvHash.hashCode64(dataTypeName); return isCharType(hash); } protected boolean isCharType(long hash) { return hash == FnvHash.Constants.CHAR || hash == FnvHash.Constants.VARCHAR || hash == FnvHash.Constants.NCHAR || hash == FnvHash.Constants.NVARCHAR || hash == FnvHash.Constants.TINYTEXT || hash == FnvHash.Constants.TEXT || hash == FnvHash.Constants.MEDIUMTEXT || hash == FnvHash.Constants.LONGTEXT ; } protected SQLDataType parseCharTypeRest(SQLCharacterDataType charType) { if (lexer.token == Token.BINARY) { charType.setHasBinary(true); lexer.nextToken(); } if (lexer.identifierEquals(FnvHash.Constants.CHARACTER)) { lexer.nextToken(); accept(Token.SET); if (lexer.token != Token.IDENTIFIER && lexer.token != Token.LITERAL_CHARS && lexer.token != Token.BINARY) { throw new ParserException(lexer.info()); } charType.setCharSetName(lexer.stringVal()); lexer.nextToken(); } if (lexer.token == Token.BINARY) { charType.setHasBinary(true); lexer.nextToken(); } if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { lexer.nextToken(); if (lexer.token == Token.LITERAL_ALIAS) { charType.setCollate(lexer.stringVal()); } else if (lexer.token == Token.IDENTIFIER) { charType.setCollate(lexer.stringVal()); } else { throw new ParserException(); } lexer.nextToken(); } return charType; } public void accept(Token token) { if (lexer.token == token) { lexer.nextToken(); } else { throw new ParserException("syntax error, expect " + token + ", actual " + lexer.token + " " + lexer.info()); } } public SQLColumnDefinition parseColumn() { SQLColumnDefinition column = createColumnDefinition(); column.setName(name()); final Token token = lexer.token; if (token != Token.SET // && token != Token.DROP && token != Token.PRIMARY && token != Token.RPAREN) { column.setDataType(parseDataType()); } return parseColumnRest(column); } public SQLColumnDefinition createColumnDefinition() { SQLColumnDefinition column = new SQLColumnDefinition(); column.setDbType(dbType); return column; } public SQLColumnDefinition parseColumnRest(SQLColumnDefinition column) { if (lexer.token == Token.DEFAULT) { lexer.nextToken(); column.setDefaultExpr(bitOr()); return parseColumnRest(column); } if (lexer.token == Token.NOT) { lexer.nextToken(); accept(Token.NULL); SQLNotNullConstraint notNull = new SQLNotNullConstraint(); if (lexer.token == Token.HINT) { List hints = this.parseHints(); notNull.setHints(hints); } column.addConstraint(notNull); return parseColumnRest(column); } if (lexer.token == Token.NULL) { lexer.nextToken(); column.getConstraints().add(new SQLNullConstraint()); return parseColumnRest(column); } if (lexer.token == Token.PRIMARY) { lexer.nextToken(); accept(Token.KEY); column.addConstraint(new SQLColumnPrimaryKey()); return parseColumnRest(column); } if (lexer.token == Token.UNIQUE) { lexer.nextToken(); if (lexer.token == Token.KEY) { lexer.nextToken(); } column.addConstraint(new SQLColumnUniqueKey()); return parseColumnRest(column); } if (lexer.token == Token.KEY) { lexer.nextToken(); column.addConstraint(new SQLColumnUniqueKey()); return parseColumnRest(column); } if (lexer.token == Token.REFERENCES) { SQLColumnReference ref = parseReference(); column.addConstraint(ref); return parseColumnRest(column); } if (lexer.token == Token.CONSTRAINT) { lexer.nextToken(); SQLName name = this.name(); if (lexer.token == Token.PRIMARY) { lexer.nextToken(); accept(Token.KEY); SQLColumnPrimaryKey pk = new SQLColumnPrimaryKey(); pk.setName(name); column.addConstraint(pk); return parseColumnRest(column); } if (lexer.token == Token.UNIQUE) { lexer.nextToken(); SQLColumnUniqueKey uk = new SQLColumnUniqueKey(); uk.setName(name); column.addConstraint(uk); return parseColumnRest(column); } if (lexer.token == Token.REFERENCES) { SQLColumnReference ref = parseReference(); ref.setName(name); column.addConstraint(ref); return parseColumnRest(column); } if (lexer.token == Token.NOT) { lexer.nextToken(); accept(Token.NULL); SQLNotNullConstraint notNull = new SQLNotNullConstraint(); notNull.setName(name); column.addConstraint(notNull); return parseColumnRest(column); } if (lexer.token == Token.CHECK) { SQLColumnCheck check = parseColumnCheck(); check.setName(name); check.setParent(column); column.addConstraint(check); return parseColumnRest(column); } if (lexer.token == Token.DEFAULT) { lexer.nextToken(); SQLExpr expr = this.expr(); column.setDefaultExpr(expr); return parseColumnRest(column); } throw new ParserException("TODO : " + lexer.info()); } if (lexer.token == Token.CHECK) { SQLColumnCheck check = parseColumnCheck(); column.addConstraint(check); return parseColumnRest(column); } if (lexer.token == Token.COMMENT) { lexer.nextToken(); if (lexer.token == Token.LITERAL_ALIAS) { String alias = lexer.stringVal(); if (alias.length() > 2 && alias.charAt(0) == '"' && alias.charAt(alias.length() - 1) == '"') { alias = alias.substring(1, alias.length() - 1); } column.setComment(alias); lexer.nextToken(); } else { column.setComment(primary()); } return parseColumnRest(column); } return column; } private SQLColumnReference parseReference() { SQLColumnReference fk = new SQLColumnReference(); lexer.nextToken(); fk.setTable(this.name()); accept(Token.LPAREN); this.names(fk.getColumns(), fk); accept(Token.RPAREN); if (lexer.identifierEquals(FnvHash.Constants.MATCH)) { lexer.nextToken(); if (lexer.identifierEquals("FULL") || lexer.token() == Token.FULL) { fk.setReferenceMatch(SQLForeignKeyImpl.Match.FULL); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.PARTIAL)) { fk.setReferenceMatch(SQLForeignKeyImpl.Match.PARTIAL); lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.SIMPLE)) { fk.setReferenceMatch(SQLForeignKeyImpl.Match.SIMPLE); lexer.nextToken(); } else { throw new ParserException("TODO : " + lexer.info()); } } while (lexer.token() == Token.ON) { lexer.nextToken(); if (lexer.token() == Token.DELETE) { lexer.nextToken(); SQLForeignKeyImpl.Option option = parseReferenceOption(); fk.setOnDelete(option); } else if (lexer.token() == Token.UPDATE) { lexer.nextToken(); SQLForeignKeyImpl.Option option = parseReferenceOption(); fk.setOnUpdate(option); } else { throw new ParserException("syntax error, expect DELETE or UPDATE, actual " + lexer.token() + " " + lexer.info()); } } return fk; } protected SQLForeignKeyImpl.Option parseReferenceOption() { SQLForeignKeyImpl.Option option; if (lexer.token() == Token.RESTRICT || lexer.identifierEquals(FnvHash.Constants.RESTRICT)) { option = SQLForeignKeyImpl.Option.RESTRICT; lexer.nextToken(); } else if (lexer.identifierEquals(FnvHash.Constants.CASCADE)) { option = SQLForeignKeyImpl.Option.CASCADE; lexer.nextToken(); } else if (lexer.token() == Token.SET) { lexer.nextToken(); accept(Token.NULL); option = SQLForeignKeyImpl.Option.SET_NULL; } else if (lexer.identifierEquals(FnvHash.Constants.NO)) { lexer.nextToken(); if (lexer.identifierEquals(FnvHash.Constants.ACTION)) { option = SQLForeignKeyImpl.Option.NO_ACTION; lexer.nextToken(); } else { throw new ParserException("syntax error, expect ACTION, actual " + lexer.token() + " " + lexer.info()); } } else { throw new ParserException("syntax error, expect ACTION, actual " + lexer.token() + " " + lexer.info()); } return option; } protected SQLColumnCheck parseColumnCheck() { lexer.nextToken(); SQLExpr expr = this.expr(); SQLColumnCheck check = new SQLColumnCheck(expr); if (lexer.token == Token.DISABLE) { lexer.nextToken(); check.setEnable(false); } else if (lexer.token == Token.ENABLE) { lexer.nextToken(); check.setEnable(true); } else if (lexer.identifierEquals(FnvHash.Constants.VALIDATE)) { lexer.nextToken(); check.setValidate(Boolean.TRUE); } else if (lexer.identifierEquals(FnvHash.Constants.NOVALIDATE)) { lexer.nextToken(); check.setValidate(Boolean.FALSE); } else if (lexer.identifierEquals(FnvHash.Constants.RELY)) { lexer.nextToken(); check.setRely(Boolean.TRUE); } else if (lexer.identifierEquals(FnvHash.Constants.NORELY)) { lexer.nextToken(); check.setRely(Boolean.FALSE); } return check; } public SQLPrimaryKey parsePrimaryKey() { accept(Token.PRIMARY); accept(Token.KEY); SQLPrimaryKeyImpl pk = new SQLPrimaryKeyImpl(); accept(Token.LPAREN); orderBy(pk.getColumns(), pk); accept(Token.RPAREN); return pk; } public SQLUnique parseUnique() { accept(Token.UNIQUE); SQLUnique unique = new SQLUnique(); accept(Token.LPAREN); orderBy(unique.getColumns(), unique); accept(Token.RPAREN); if (lexer.token == Token.DISABLE) { lexer.nextToken(); unique.setEnable(false); } else if (lexer.token == Token.ENABLE) { lexer.nextToken(); unique.setEnable(true); } else if (lexer.identifierEquals(FnvHash.Constants.VALIDATE)) { lexer.nextToken(); unique.setValidate(Boolean.TRUE); } else if (lexer.identifierEquals(FnvHash.Constants.NOVALIDATE)) { lexer.nextToken(); unique.setValidate(Boolean.FALSE); } else if (lexer.identifierEquals(FnvHash.Constants.RELY)) { lexer.nextToken(); unique.setRely(Boolean.TRUE); } else if (lexer.identifierEquals(FnvHash.Constants.NORELY)) { lexer.nextToken(); unique.setRely(Boolean.FALSE); } return unique; } public SQLAssignItem parseAssignItem() { SQLAssignItem item = new SQLAssignItem(); SQLExpr var = primary(); if (var instanceof SQLIdentifierExpr) { var = new SQLVariantRefExpr(((SQLIdentifierExpr) var).getName()); } item.setTarget(var); if (lexer.token == Token.COLONEQ) { lexer.nextToken(); } else if (lexer.token == Token.TRUE || lexer.identifierEquals(FnvHash.Constants.TRUE)) { lexer.nextToken(); item.setValue(new SQLBooleanExpr(true)); return item; } else if (lexer.token == Token.ON) { lexer.nextToken(); item.setValue(new SQLIdentifierExpr("ON")); return item; } else { if (lexer.token == Token.EQ) { lexer.nextToken(); } else if (JdbcConstants.DB2.equals(dbType)) { // skip } else { accept(Token.EQ); } } if (lexer.token == Token.ON) { item.setValue(new SQLIdentifierExpr(lexer.stringVal())); lexer.nextToken(); } else { if (lexer.token == Token.ALL) { item.setValue(new SQLIdentifierExpr(lexer.stringVal())); lexer.nextToken(); } else { SQLExpr expr = expr(); if (lexer.token == Token.COMMA && JdbcConstants.POSTGRESQL.equals(dbType)) { SQLListExpr listExpr = new SQLListExpr(); listExpr.addItem(expr); expr.setParent(listExpr); do { lexer.nextToken(); SQLExpr listItem = this.expr(); listItem.setParent(listExpr); listExpr.addItem(listItem); } while (lexer.token == Token.COMMA); item.setValue(listExpr); } else { item.setValue(expr); } } } return item; } public List parseHints() { List hints = new ArrayList(); parseHints(hints); return hints; } @SuppressWarnings({ "unchecked", "rawtypes" }) public void parseHints(List hints) { if (lexer.token == Token.HINT) { SQLCommentHint hint = new SQLCommentHint(lexer.stringVal()); if (lexer.commentCount > 0) { hint.addBeforeComment(lexer.comments); } hints.add(hint); lexer.nextToken(); } } public SQLConstraint parseConstaint() { SQLName name = null; if (lexer.token == Token.CONSTRAINT) { lexer.nextToken(); name = this.name(); } SQLConstraint constraint; if (lexer.token == Token.PRIMARY) { constraint = parsePrimaryKey(); } else if (lexer.token == Token.UNIQUE) { constraint = parseUnique(); } else if (lexer.token == Token.KEY) { constraint = parseUnique(); } else if (lexer.token == Token.FOREIGN) { constraint = parseForeignKey(); } else if (lexer.token == Token.CHECK) { constraint = parseCheck(); } else { throw new ParserException("TODO : " + lexer.info()); } constraint.setName(name); return constraint; } public SQLCheck parseCheck() { accept(Token.CHECK); SQLCheck check = createCheck(); accept(Token.LPAREN); check.setExpr(this.expr()); accept(Token.RPAREN); return check; } protected SQLCheck createCheck() { return new SQLCheck(); } public SQLForeignKeyConstraint parseForeignKey() { accept(Token.FOREIGN); accept(Token.KEY); SQLForeignKeyImpl fk = createForeignKey(); accept(Token.LPAREN); this.names(fk.getReferencingColumns(), fk); accept(Token.RPAREN); accept(Token.REFERENCES); fk.setReferencedTableName(this.name()); if (lexer.token == Token.LPAREN) { lexer.nextToken(); this.names(fk.getReferencedColumns(), fk); accept(Token.RPAREN); } if (lexer.token == Token.ON) { lexer.nextToken(); accept(Token.DELETE); if (lexer.identifierEquals(FnvHash.Constants.CASCADE)) { lexer.nextToken(); fk.setOnDeleteCascade(true); } else { accept(Token.SET); accept(Token.NULL); fk.setOnDeleteSetNull(true); } } return fk; } protected SQLForeignKeyImpl createForeignKey() { return new SQLForeignKeyImpl(); } public SQLSelectItem parseSelectItem() { SQLExpr expr; boolean connectByRoot = false; Token token = lexer.token; if (token == Token.IDENTIFIER) { String ident = lexer.stringVal(); long hash_lower = lexer.hash_lower(); lexer.nextTokenComma(); if (hash_lower == FnvHash.Constants.CONNECT_BY_ROOT) { connectByRoot = true; expr = new SQLIdentifierExpr(lexer.stringVal()); lexer.nextToken(); } else if (FnvHash.Constants.DATE == hash_lower && lexer.token == Token.LITERAL_CHARS && (JdbcConstants.ORACLE.equals(getDbType()) || JdbcConstants.POSTGRESQL.equals(getDbType()))) { String literal = lexer.stringVal(); lexer.nextToken(); SQLDateExpr dateExpr = new SQLDateExpr(); dateExpr.setLiteral(literal); expr = dateExpr; } else { expr = new SQLIdentifierExpr(ident, hash_lower); } token = lexer.token; if (token == Token.DOT) { lexer.nextTokenIdent(); String name; long name_hash_lower; if (lexer.token == Token.STAR) { name = "*"; name_hash_lower = FnvHash.Constants.STAR; } else { name = lexer.stringVal(); name_hash_lower = lexer.hash_lower(); } lexer.nextTokenComma(); token = lexer.token; if (token == Token.LPAREN) { boolean aggregate = hash_lower == FnvHash.Constants.WMSYS && name_hash_lower == FnvHash.Constants.WM_CONCAT; expr = methodRest(expr, name, aggregate); token = lexer.token; } else { if (name_hash_lower == FnvHash.Constants.NEXTVAL) { expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.NextVal); } else if (name_hash_lower == FnvHash.Constants.CURRVAL) { expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.CurrVal); } else if (name_hash_lower == FnvHash.Constants.PREVVAL) { expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.PrevVal); } else { expr = new SQLPropertyExpr(expr, name, name_hash_lower); } } } if (token == Token.COMMA) { return new SQLSelectItem(expr, null, connectByRoot); } if (token == Token.AS) { lexer.nextToken(); String as = null; if (lexer.token != Token.COMMA && lexer.token != Token.FROM) { as = lexer.stringVal(); lexer.nextTokenComma(); if (lexer.token == Token.DOT) { lexer.nextToken(); as += '.' + lexer.stringVal(); lexer.nextToken(); } } return new SQLSelectItem(expr, as, connectByRoot); } if (token == Token.LITERAL_ALIAS) { String as = lexer.stringVal(); lexer.nextTokenComma(); return new SQLSelectItem(expr, as, connectByRoot); } if ((token == Token.IDENTIFIER && hash_lower != FnvHash.Constants.CURRENT) || token == Token.MODEL) { String as; if (lexer.hash_lower == FnvHash.Constants.FORCE && JdbcConstants.MYSQL.equals(dbType)) { String force = lexer.stringVal(); Lexer.SavePoint savePoint = lexer.mark(); lexer.nextToken(); if (lexer.token == Token.PARTITION) { lexer.reset(savePoint); as = null; } else { as = force; lexer.nextTokenComma(); } } else { as = lexer.stringVal(); lexer.nextTokenComma(); } return new SQLSelectItem(expr, as, connectByRoot); } if (token == Token.LPAREN) { lexer.nextToken(); expr = this.methodRest(expr, false); } else { expr = this.primaryRest(expr); } expr = this.exprRest(expr); } else if (token == Token.STAR) { expr = new SQLAllColumnExpr(); lexer.nextToken(); return new SQLSelectItem(expr, null, connectByRoot); } else if (token == Token.DO || token == Token.JOIN) { expr = this.name(); expr = this.exprRest(expr); } else { expr = expr(); } final String alias; switch (lexer.token) { case FULL: case MODEL: case TABLESPACE: alias = lexer.stringVal(); lexer.nextToken(); break; default: alias = as(); break; } SQLSelectItem selectItem = new SQLSelectItem(expr, alias, connectByRoot); if (lexer.token == Token.HINT && !lexer.isEnabled(SQLParserFeature.StrictForWall)) { String comment = "/*" + lexer.stringVal() + "*/"; selectItem.addAfterComment(comment); lexer.nextToken(); } return selectItem; } public SQLExpr parseGroupingSet() { String tmp = lexer.stringVal(); acceptIdentifier("GROUPING"); SQLGroupingSetExpr expr = new SQLGroupingSetExpr(); if (lexer.token == Token.SET || lexer.identifierEquals(FnvHash.Constants.SET)) { lexer.nextToken(); } else { return new SQLIdentifierExpr(tmp); } accept(Token.LPAREN); this.exprList(expr.getParameters(), expr); accept(Token.RPAREN); return expr; } protected SQLPartition parsePartition() { throw new ParserException("TODO"); } protected SQLPartitionBy parsePartitionBy() { throw new ParserException("TODO"); } public SQLPartitionValue parsePartitionValues() { if (lexer.token != Token.VALUES) { return null; } lexer.nextToken(); SQLPartitionValue values = null; if (lexer.token == Token.IN) { lexer.nextToken(); values = new SQLPartitionValue(SQLPartitionValue.Operator.In); accept(Token.LPAREN); this.exprList(values.getItems(), values); accept(Token.RPAREN); } else if (lexer.identifierEquals(FnvHash.Constants.LESS)) { lexer.nextToken(); acceptIdentifier("THAN"); values = new SQLPartitionValue(SQLPartitionValue.Operator.LessThan); if (lexer.identifierEquals(FnvHash.Constants.MAXVALUE)) { SQLIdentifierExpr maxValue = new SQLIdentifierExpr(lexer.stringVal()); lexer.nextToken(); maxValue.setParent(values); values.addItem(maxValue); } else { accept(Token.LPAREN); this.exprList(values.getItems(), values); accept(Token.RPAREN); } } else if (lexer.token == Token.LPAREN) { values = new SQLPartitionValue(SQLPartitionValue.Operator.List); lexer.nextToken(); this.exprList(values.getItems(), values); accept(Token.RPAREN); } return values; } protected static boolean isIdent(SQLExpr expr, String name) { if (expr instanceof SQLIdentifierExpr) { SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr; return identExpr.getName().equalsIgnoreCase(name); } return false; } public SQLLimit parseLimit() { if (lexer.token == Token.LIMIT) { lexer.nextTokenValue(); SQLLimit limit = new SQLLimit(); SQLExpr temp; if (lexer.token == Token.LITERAL_INT) { temp = new SQLIntegerExpr(lexer.integerValue()); lexer.nextTokenComma(); if (lexer.token != Token.COMMA && lexer.token != Token.EOF && lexer.token != Token.IDENTIFIER) { temp = this.primaryRest(temp); temp = this.exprRest(temp); } } else { temp = this.expr(); } if (lexer.token == (Token.COMMA)) { limit.setOffset(temp); lexer.nextTokenValue(); SQLExpr rowCount; if (lexer.token == Token.LITERAL_INT) { rowCount = new SQLIntegerExpr(lexer.integerValue()); lexer.nextToken(); if (lexer.token != Token.EOF && lexer.token != Token.IDENTIFIER) { rowCount = this.primaryRest(rowCount); rowCount = this.exprRest(rowCount); } } else { rowCount = this.expr(); } limit.setRowCount(rowCount); } else if (lexer.identifierEquals(FnvHash.Constants.OFFSET)) { limit.setRowCount(temp); lexer.nextToken(); limit.setOffset(this.expr()); } else { limit.setRowCount(temp); } return limit; } return null; } }