| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| options { |
| JAVA_UNICODE_ESCAPE = false; |
| ERROR_REPORTING = true; |
| STATIC = false; |
| // MULTI = true; |
| JDK_VERSION = "1.5"; |
| // VISITOR = true; |
| // BUILD_NODE_FILES = true; |
| // NODE_FACTORY = false; |
| // NODE_USES_PARSER = true; |
| // NODE_SCOPE_HOOK = true; |
| // NODE_PREFIX = "SQL"; |
| // DEBUG_PARSER = true; |
| // DEBUG_LOOKAHEAD = true; |
| // DEBUG_TOKEN_MANAGER = true; |
| LOOKAHEAD = 1; |
| // CHOICE_AMBIGUITY_CHECK = 3; |
| // OTHER_AMBIGUITY_CHECK = 3; |
| IGNORE_CASE = true; |
| } |
| PARSER_BEGIN(Parser) |
| |
| package org.ofbiz.sql; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javolution.util.FastList; |
| import javolution.util.FastMap; |
| import javolution.util.FastSet; |
| |
| @SuppressWarnings("all") |
| public final class Parser { |
| private boolean deleteSupportsUsing = true; |
| private boolean updateSupportsFrom = true; |
| |
| public Parser deleteSupportsUsing(boolean value) { |
| deleteSupportsUsing = value; |
| return this; |
| } |
| |
| public Parser updateSupportsFrom(boolean value) { |
| updateSupportsFrom = value; |
| return this; |
| } |
| |
| private Condition reduce(List<Condition> conditions, Joiner joiner) { |
| if (conditions.size() == 1) { |
| return conditions.get(0); |
| } |
| return new ConditionList(joiner, conditions); |
| } |
| } |
| |
| PARSER_END(Parser) |
| TOKEN_MGR_DECLS: { |
| private final FastList<Integer> stack = new FastList<Integer>(); |
| |
| void pushState(int newState) { |
| stack.add(curLexState); |
| SwitchTo(newState); |
| } |
| |
| void popState() { |
| SwitchTo(stack.removeLast()); |
| } |
| } |
| |
| TOKEN: { |
| <OPEN_PAREN: "("> |
| | <CLOSE_PAREN: ")"> |
| | <AND: "AND"> |
| | <OR: "OR"> |
| | <PERIOD: "."> |
| | <JOIN: "JOIN"> |
| | <LEFT: "LEFT"> |
| | <AS: "AS"> |
| | <COUNT: "COUNT"> |
| | <MAX: "MAX"> |
| | <MIN: "MIN"> |
| | <SUM: "SUM"> |
| | <AVG: "AVG"> |
| | <DISTINCT: "DISTINCT"> |
| | <WHERE: "WHERE"> |
| | <HAVING: "HAVING"> |
| | <GROUP: "GROUP"> |
| | <ORDER: "ORDER"> |
| | <INTERSECT: "INTERSECT"> |
| | <EXCEPT: "EXCEPT"> |
| | <UNION: "UNION"> |
| | <ALL: "ALL"> |
| | <BY: "BY"> |
| | <ON: "ON"> |
| | <USING: "USING"> |
| | <LIMIT: "LIMIT"> |
| | <OFFSET: "OFFSET"> |
| | <SELECT: "SELECT"> |
| | <DELETE: "DELETE"> |
| | <UPDATE: "UPDATE"> |
| | <INSERT: "INSERT"> |
| | <INDEX: "INDEX"> |
| | <UNIQUE: "UNIQUE"> |
| | <RELATION: "RELATION"> |
| | <EXCLUDE: "EXCLUDE"> |
| | <TYPE: "TYPE"> |
| | <TITLE: "TITLE"> |
| | <SET: "SET"> |
| | <FROM: "FROM"> |
| | <SEMI: ";"> |
| | <STAR: "*"> |
| | <COMMA: ","> |
| | <PLUS: "+"> |
| | <MINUS: "-"> |
| | <DESC: "DESC"> |
| | <ASC: "ASC"> |
| | <EQUALS: "="> |
| | <BETWEEN: "BETWEEN"> |
| | <INTO: "INTO"> |
| | <VALUES: "VALUES"> |
| | <CREATE: "CREATE"> |
| | <VIEW: "VIEW"> |
| | <IS: "IS"> |
| | <NOT: "NOT"> |
| | <NULL: "NULL"> |
| | <MAP: "MAP"> |
| | <NULLS: "NULLS"> |
| | <FIRST: "FIRST"> |
| | <LAST: "LAST"> |
| | <START_DQUOTE: "\""> { pushState(IN_DQUOTE); } |
| | <START_SQUOTE: "'"> { pushState(IN_SQUOTE); } |
| | <INTEGER: |
| "0" ( |
| "x" (["0"-"9","a"-"b"])+ |
| | (["0"-"7"])+ |
| ) |
| | ["1"-"9"] (["0"-"9"])* |
| > |
| | <NAME: ["a"-"z"] (["a"-"z","0"-"9","_","-"])*> |
| | <PARAMETER: "?" (["a"-"z"])+> |
| // | <WORD: (~["'", "\"", "/", " ", "\f", "\n", "\r", "\t", "*"])+> |
| } |
| |
| <DEFAULT> |
| SKIP: { |
| <SPACE: " " | "\f" | "\n" | "\r" | "\t"> |
| } |
| |
| <*> |
| MORE: { |
| <COMMENT_START: "/*"> { if (curLexState != IN_COMMENT) pushState(IN_COMMENT); } |
| } |
| |
| <IN_COMMENT> |
| MORE: { |
| <(~[])> |
| | <COMMENT_END: "*/"> { popState(); } |
| } |
| |
| <IN_DQUOTE,IN_SQUOTE> |
| TOKEN: { |
| <ESCAPED: "\\" ["r", "n", "b", "t", "f"]> |
| } |
| |
| <IN_DQUOTE> |
| TOKEN: { |
| <END_DQUOTE: "\""> { popState(); } |
| } |
| |
| <IN_SQUOTE> |
| TOKEN: { |
| <ESCAPE_SQUOTE: "''"> |
| | <END_SQUOTE: "'"> { popState(); } |
| } |
| |
| <DEFAULT,IN_DQUOTE,IN_SQUOTE> |
| TOKEN: { |
| <TEXT: (~[])> |
| } |
| |
| // ------------------- |
| |
| public List<SQLStatement<?>> SQLFile(): { |
| List<SQLStatement<?>> list = FastList.newInstance(); |
| SQLStatement<?> statement; |
| } { |
| ( |
| statement=Statement() ( <SEMI> )? |
| { list.add(statement); } |
| )* |
| <EOF> |
| { return list; } |
| } |
| |
| public SQLStatement StandaloneStatement(): { |
| SQLStatement statement; |
| } { |
| statement=Statement() ( <SEMI> )? <EOF> |
| { return statement; } |
| } |
| |
| public SQLView ViewStatement(): { |
| SQLView sqlView; |
| } { |
| <CREATE> <VIEW> sqlView=View() ( <SEMI> )? <EOF> |
| { return sqlView; } |
| } |
| |
| public SQLSelect SelectStatement(): { |
| SQLSelect sqlSelect; |
| } { |
| sqlSelect=Select() ( <SEMI> )? <EOF> { return sqlSelect; } |
| } |
| |
| public SQLDelete DeleteStatement(): { |
| SQLDelete sqlDelete; |
| } { |
| sqlDelete=Delete() ( <SEMI> )? <EOF> { return sqlDelete; } |
| } |
| |
| public SQLUpdate UpdateStatement(): { |
| SQLUpdate sqlUpdate; |
| } { |
| sqlUpdate=Update() ( <SEMI> )? <EOF> { return sqlUpdate; } |
| } |
| |
| public SQLInsert InsertStatement(): { |
| SQLInsert sqlInsert; |
| } { |
| sqlInsert=Insert() ( <SEMI> )? <EOF> { return sqlInsert; } |
| } |
| |
| public Condition Condition(): { |
| Condition c; |
| } { |
| c=ConditionExpression() <EOF> { return c; } |
| } |
| |
| public FieldAll parse_FieldAll(): { |
| FieldAll fieldAll; |
| } { |
| fieldAll=FieldAll() <EOF> { return fieldAll; } |
| } |
| |
| public FieldDef parse_FieldDef(): { |
| FieldDef fieldDef; |
| } { |
| fieldDef=FieldDef() <EOF> { return fieldDef; } |
| } |
| |
| public OrderByItem parse_OrderByItem(): { |
| OrderByItem item; |
| } { |
| item=OrderByItem() <EOF> { return item; } |
| } |
| |
| private SQLStatement Statement(): { |
| SQLStatement statement; |
| } { |
| ( |
| statement=Select() { return statement; } |
| | statement=Delete() { return statement; } |
| | statement=Update() { return statement; } |
| | statement=Insert() { return statement; } |
| | statement=Creates() { return statement; } |
| ) |
| } |
| |
| private SQLStatement Creates(): { |
| SQLStatement statement; |
| boolean isUnique = false; |
| } { |
| <CREATE> ( |
| <VIEW> statement=View() { return statement; } |
| | ( <UNIQUE> { isUnique = true; } )? |
| <INDEX> statement=Index(isUnique) { return statement; } |
| ) |
| } |
| |
| private SQLView View(): { |
| String name; |
| SQLSelect sqlSelect; |
| } { |
| name=NamePart() <AS> sqlSelect=Select() { return new SQLView(name, sqlSelect); } |
| } |
| |
| private SelectGroup SelectGroup(): { |
| boolean isDistinct = false; |
| List<String> groupBy = null; |
| Map<String, FieldDef> fieldDefs = FastMap.newInstance(); |
| List<FieldAll> fieldAlls = FastList.newInstance(); |
| Set<String> fieldAllAliases = FastSet.newInstance(); |
| Table table; |
| Condition whereCondition = null, havingCondition = null; |
| } { |
| <SELECT> (<DISTINCT> { isDistinct = true; })? ( |
| SelectField(fieldDefs, fieldAlls, fieldAllAliases) |
| ( <COMMA> SelectField(fieldDefs, fieldAlls, fieldAllAliases) )* |
| ) |
| <FROM> table=Table() |
| ( <WHERE> whereCondition=ConditionExpression() )? |
| ( <HAVING> havingCondition=ConditionExpression() )? |
| ( <GROUP> <BY> groupBy=FieldList() )? |
| { return new SelectGroup(isDistinct, fieldAlls, fieldDefs, table, whereCondition, havingCondition, groupBy); } |
| } |
| |
| private Unioned.Operator UnionOperator(): { |
| } { |
| <UNION> |
| ( <ALL> { return Unioned.Operator.UNION_ALL; } )? |
| { return Unioned.Operator.UNION; } |
| | <INTERSECT> |
| ( <ALL> { return Unioned.Operator.INTERSECT_ALL; } )? |
| { return Unioned.Operator.INTERSECT; } |
| | <EXCEPT> |
| ( <ALL> { return Unioned.Operator.EXCEPT_ALL; } )? |
| { return Unioned.Operator.EXCEPT; } |
| } |
| |
| private Unioned Unioned(): { |
| Unioned.Operator operator; |
| SelectGroup selectGroup; |
| Unioned next = null; |
| } { |
| operator=UnionOperator() selectGroup=SelectGroup() ( next=Unioned() )? |
| { return new Unioned(operator, selectGroup, next); } |
| } |
| |
| private SQLSelect Select(): { |
| boolean hadEarlyRelations = false; |
| Unioned unioned = null; |
| boolean isDistinct = false; |
| List<OrderByItem> orderBy = null; |
| List<String> groupBy = null; |
| Map<String, FieldDef> fieldDefs = FastMap.newInstance(); |
| List<FieldAll> fieldAlls = FastList.newInstance(); |
| Set<String> fieldAllAliases = FastSet.newInstance(); |
| Table table; |
| Map<String, Relation> relations = FastMap.newInstance(); |
| Condition whereCondition = null, havingCondition = null; |
| int offset = -1, limit = -1; |
| } { |
| <SELECT> (<DISTINCT> { isDistinct = true; })? ( |
| SelectField(fieldDefs, fieldAlls, fieldAllAliases) |
| ( <COMMA> SelectField(fieldDefs, fieldAlls, fieldAllAliases) )* |
| ) |
| <FROM> table=Table() |
| ( LOOKAHEAD(1) <RELATION> Relation(relations) { hadEarlyRelations = true; } )* |
| ( <WHERE> whereCondition=ConditionExpression() )? |
| ( <HAVING> havingCondition=ConditionExpression() )? |
| ( <GROUP> <BY> groupBy=FieldList() )? |
| ( unioned=Unioned() )? |
| ( LOOKAHEAD(1, {!hadEarlyRelations}) <RELATION> Relation(relations) )* |
| ( <ORDER> <BY> orderBy=OrderByList() )? |
| ( <OFFSET> offset=Integer() )? |
| ( <LIMIT> limit=Integer() )? |
| { return new SQLSelect(new SelectGroup(isDistinct, fieldAlls, fieldDefs, table, whereCondition, havingCondition, groupBy), unioned, relations, orderBy, offset, limit); } |
| } |
| |
| private void Relation(Map<String, Relation> relations): { |
| String type = null, title = null, entityName; |
| KeyMap keyMap; |
| List<KeyMap> keyMaps = FastList.newInstance(); |
| } { |
| ( <TYPE> type=NamePart() )? |
| ( <TITLE> title=NamePart() )? |
| <NAME> { entityName = getToken(0).image; } |
| <MAP> keyMap=PlainKeyMap() { keyMaps.add(keyMap); } ( |
| <COMMA> |
| keyMap=PlainKeyMap() { keyMaps.add(keyMap); } |
| )* |
| { |
| Relation relation = new Relation(type, title, entityName, keyMaps); |
| if (relations.containsKey(relation.getName())) throw new ParseException("Duplicate relation: " + relation); |
| relations.put(relation.getName(), relation); |
| } |
| } |
| |
| private KeyMap PlainKeyMap(): { |
| String left, right; |
| } { |
| left=NamePart() ( |
| <EQUALS> right=NamePart() { return new KeyMap(left, right); } |
| | { return new KeyMap(left, left); } |
| ) |
| } |
| |
| private SQLUpdate Update(): { |
| TableName tableName; |
| List<Table> tableList = null; |
| Condition whereCondition = null; |
| List<SetField> allSetFields = FastList.newInstance(); |
| List<SetField> setFields; |
| Joined joined = null; |
| } { |
| <UPDATE> tableName=TableName() |
| <SET> |
| setFields=SetField() { allSetFields.addAll(setFields); } |
| ( <COMMA> setFields=SetField() { allSetFields.addAll(setFields); } )* |
| ( LOOKAHEAD(<FROM>, {updateSupportsFrom}) <FROM> joined=JoinedRest(false, tableName) )? |
| ( <WHERE> whereCondition=ConditionExpression() )? |
| { return new SQLUpdate(new Table(tableName, joined), allSetFields, whereCondition); } |
| } |
| |
| private SQLDelete Delete(): { |
| TableName tableName; |
| List<Table> tableList = null; |
| Condition whereCondition = null; |
| Joined joined = null; |
| } { |
| <DELETE> <FROM> tableName=TableName() |
| ( LOOKAHEAD(<USING>, {deleteSupportsUsing}) <USING> joined=JoinedRest(false, tableName) )? |
| ( <WHERE> whereCondition=ConditionExpression() )? |
| { return new SQLDelete(new Table(tableName, joined), whereCondition); } |
| } |
| |
| private SQLIndex Index(boolean isUnique): { |
| String name, table, using = null; |
| ConstantValue value; |
| List<ConstantValue> values = FastList.newInstance(); |
| } { |
| name=NamePart() <ON> table=NamePart() |
| ( <USING> using=NamePart() )? |
| <OPEN_PAREN> |
| value=ConstantValue() { values.add(value); } |
| ( <COMMA> value=ConstantValue() { values.add(value); } )* |
| <CLOSE_PAREN> |
| { return new SQLIndex(isUnique, name, table, using, values); } |
| } |
| |
| private SQLInsert Insert(): { |
| TableName tableName; |
| List<String> columns = FastList.newInstance(); |
| String n; |
| InsertSource source; |
| } { |
| <INSERT> <INTO> tableName=TableName() ( |
| <OPEN_PAREN> |
| n=NamePart() { columns.add(n); } |
| ( <COMMA> n=NamePart() { columns.add(n); } )* |
| <CLOSE_PAREN> |
| )? |
| ( source=InsertValues() | source=Select() ) |
| { return new SQLInsert(tableName, source, columns); } |
| } |
| |
| private InsertValues InsertValues(): { |
| List<InsertRow> list = FastList.newInstance(); |
| InsertRow row; |
| } { |
| <VALUES> |
| row=InsertRow() { list.add(row); } |
| ( <COMMA> row=InsertRow() { list.add(row); } )* |
| { return new InsertValues(list); } |
| } |
| |
| private InsertRow InsertRow(): { |
| List<Value> list = FastList.newInstance(); |
| Value v; |
| } { |
| <OPEN_PAREN> |
| v=InsertValue() { list.add(v); } |
| ( <COMMA> v=InsertValue() { list.add(v); } )* |
| <CLOSE_PAREN> |
| { return new InsertRow(list); } |
| } |
| |
| private Value InsertValue(): { |
| Value v; |
| Integer i; |
| String s; |
| } { |
| v=ParameterValue() { return v; } |
| | i=Integer() { return new NumberValue<Integer>(i); } |
| | s=SQuoted() { return new StringValue(s); } |
| } |
| |
| private List<SetField> SetField(): { |
| List<SetField> setFields = FastList.newInstance(); |
| String n; |
| Value v; |
| List<String> columnList = FastList.newInstance(); |
| List<Value> valueList = FastList.newInstance(); |
| } { |
| ( |
| n=NamePart() <EQUALS> ( |
| v=Value() { setFields.add(new SetField(n, v)); } |
| | v=MathValue() { setFields.add(new SetField(n, v)); } |
| ) |
| | <OPEN_PAREN> |
| n=NamePart() { columnList.add(n); } |
| ( <COMMA> n=NamePart() { columnList.add(n); } )* |
| <CLOSE_PAREN> |
| <EQUALS> |
| <OPEN_PAREN> |
| ( v=Value() | v=MathValue() ) { valueList.add(v); } |
| ( <COMMA> (v=Value()|v=MathValue()) { valueList.add(v); } )* |
| <CLOSE_PAREN> { |
| if (columnList.size() != valueList.size()) throw new ParseException(); |
| for (int i = 0; i < columnList.size(); i++) { |
| setFields.add(new SetField(columnList.get(i), valueList.get(i))); |
| } |
| } |
| ) |
| { return setFields; } |
| } |
| |
| private Table Table(): { |
| TableName tableName; |
| Joined joined = null; |
| } { |
| tableName=TableName() |
| ( joined=Joined(tableName) )? |
| { return new Table(tableName, joined); } |
| } |
| |
| private Joined Joined(TableName leftTableName): { |
| Boolean isOptional; |
| Joined joined = null; |
| } { |
| isOptional=Joiner() joined=JoinedRest(isOptional, leftTableName) |
| { return joined; } |
| } |
| |
| private Joined JoinedRest(boolean isOptional, TableName leftTableName): { |
| TableName rightTableName; |
| List<KeyMap> keyMaps; |
| Joined joined = null; |
| } { |
| rightTableName=TableName() |
| keyMaps=KeyMaps(leftTableName.getAlias(), rightTableName.getAlias()) |
| ( joined=Joined(rightTableName) )? |
| { return new Joined(isOptional, rightTableName, keyMaps, joined); } |
| } |
| |
| private List<KeyMap> KeyMaps(String leftAlias, String rightAlias): { |
| List<KeyMap> keyMaps = FastList.newInstance(); |
| String n; |
| } { |
| ( |
| <ON> |
| KeyMap(keyMaps, leftAlias, rightAlias) |
| ( <AND> KeyMap(keyMaps, leftAlias, rightAlias) )* |
| | <USING> |
| n=NamePart() { keyMaps.add(new KeyMap(n, n)); } |
| ( <COMMA> n=NamePart() { keyMaps.add(new KeyMap(n, n)); } )* |
| ) |
| { return keyMaps; } |
| } |
| |
| private void KeyMap(List<KeyMap> keyMaps, String leftAlias, String rightAlias): { |
| String alias1, field1; |
| String alias2, field2; |
| } { |
| alias1=NamePart() <PERIOD> field1=NamePart() |
| <EQUALS> |
| alias2=NamePart() <PERIOD> field2=NamePart() { |
| if (alias1.equals(leftAlias)) { |
| if (!alias2.equals(rightAlias)) throw new ParseException("invalid right alias(" + alias2 + "), expected(" + rightAlias + ")"); |
| keyMaps.add(new KeyMap(field1, field2)); |
| } else if (alias1.equals(rightAlias)) { |
| if (!alias2.equals(leftAlias)) throw new ParseException("invalid left alias(" + alias2 + "), expected(" + leftAlias + ")"); |
| keyMaps.add(new KeyMap(field2, field1)); |
| } else { |
| throw new ParseException("invalid aliases, expected(" + leftAlias + " or " + rightAlias + ")"); |
| } |
| } |
| } |
| |
| private TableName TableName(): { |
| String tableName, alias = null; |
| } { |
| tableName=NamePart() |
| ( ( <AS> )? alias=NamePart() )? |
| { return new TableName(tableName, alias); } |
| } |
| |
| private Boolean Joiner(): { |
| } { |
| <LEFT> <JOIN> { return Boolean.TRUE; } |
| | <JOIN> { return Boolean.FALSE; } |
| } |
| |
| private void SelectField(Map<String, FieldDef> fieldDefs, List<FieldAll> fieldAlls, Set<String> fieldAllAliases): { |
| FieldAll fieldAll; |
| FieldDef fieldDef; |
| } { |
| LOOKAHEAD(3) fieldAll=FieldAll() { |
| if (fieldAllAliases.contains(fieldAll.getAlias())) throw new ParseException("Duplicate aliasAll(" + fieldAll.getAlias() + ")"); |
| fieldAlls.add(fieldAll); return; |
| } |
| | fieldDef=FieldDef() { |
| if (fieldDefs.containsKey(fieldDef.getDefaultName())) throw new ParseException("duplicate alias(" + fieldDef.getDefaultName() + ")"); |
| fieldDefs.put(fieldDef.getDefaultName(), fieldDef); |
| } |
| } |
| |
| private FieldAll FieldAll(): { |
| String n, exc; |
| Set<String> excludeList = FastSet.newInstance(); |
| } { |
| n=NamePart() <PERIOD> <STAR> ( |
| <EXCLUDE> <OPEN_PAREN> |
| exc=NamePart() { excludeList.add(exc); } |
| ( <COMMA> exc=NamePart() { excludeList.add(exc); } )* |
| <CLOSE_PAREN> |
| )? |
| { return new FieldAll(n, excludeList); } |
| } |
| |
| private StaticValue StaticValue(): { |
| StaticValue v; |
| String n, fieldName; |
| } { |
| ( |
| n=NamePart() ( |
| <PERIOD> fieldName=NamePart() { v = new FieldValue(n, fieldName); } |
| | v=FunctionCallRest(n) |
| | { v = new FieldValue(null, n); } |
| ) |
| | v=MathValue() |
| | LOOKAHEAD(5) v=CountAll() |
| | v=AggregateFunction() |
| ) { return v; } |
| } |
| |
| private FieldDef FieldDef(): { |
| StaticValue v; |
| String fieldAlias = null; |
| } { |
| v=StaticValue() ( <AS> fieldAlias=NamePart() )? { |
| return new FieldDef(v, fieldAlias); |
| } |
| } |
| |
| private CountAllFunction CountAll(): { |
| String n; |
| } { |
| <COUNT> <OPEN_PAREN> ( |
| n=NamePart() |
| | { n = null; } |
| ) <PERIOD> <STAR> <CLOSE_PAREN> |
| { return new CountAllFunction(n); } |
| } |
| |
| private StaticValue MathValue(): { |
| ConstantValue v; |
| List<ConstantValue> values = FastList.newInstance(); |
| String operator = null, newOperator; |
| } { |
| <OPEN_PAREN> v=ConstantValue() { values.add(v); } ( |
| newOperator=MathOperator() v=ConstantValue() { |
| if (operator == null) { |
| operator = newOperator; |
| } else if (!newOperator.equals(operator)) { |
| throw new ParseException("Different operators in complex alias(" + operator + ":" + newOperator + ")"); |
| } |
| values.add(v); |
| } |
| )* |
| <CLOSE_PAREN> { |
| if (values.size() == 1 && values.get(0) instanceof StaticValue) return (StaticValue) values.get(0); |
| return new MathValue(operator, values); |
| } |
| } |
| |
| private AggregateFunction AggregateFunction(): { |
| StaticValue v; |
| String name, n, fieldName; |
| boolean isDistinct = false; |
| } { |
| name=AggregateName() <OPEN_PAREN> |
| ( <DISTINCT> { isDistinct = true; } )? ( |
| n=NamePart() ( |
| <PERIOD> fieldName=NamePart() { v = new FieldValue(n, fieldName); } |
| | v=FunctionCallRest(n) |
| | { v = new FieldValue(null, n); } |
| ) |
| | v=MathValue() |
| ) <CLOSE_PAREN> |
| { return new AggregateFunction(name, isDistinct, v); } |
| } |
| |
| private FunctionCall FunctionCallRest(String name): { |
| Value arg; |
| List<Value> args = FastList.newInstance(); |
| } { |
| <OPEN_PAREN> ( |
| arg=Value() { args.add(arg); } |
| ( <COMMA> arg=Value() { args.add(arg); } )* |
| )? |
| <CLOSE_PAREN> |
| { return new FunctionCall(name, args); } |
| } |
| |
| private ConstantValue ConstantValue(): { |
| String n; |
| ConstantValue v; |
| int i; |
| String s; |
| } { |
| n=NamePart() ( |
| v=FunctionCallRest(n) { return v; } |
| | v=FieldValue(n) { return v; } |
| ) |
| | i=Integer() { return new NumberValue<Integer>(i); } |
| | s=SQuoted() { return new StringValue(s); } |
| | v=MathValue() { return v; } |
| } |
| |
| private String NamePart(): { |
| } { |
| <NAME> { return getToken(0).image; } |
| | <TYPE> { return getToken(0).image; } |
| } |
| |
| private String DQuoted(): { |
| StringBuilder sb = new StringBuilder(); |
| } { |
| <START_DQUOTE> ( |
| <TEXT> { sb.append(getToken(0).image); } |
| | <ESCAPED> { sb.append(getToken(0).image); } |
| )* <END_DQUOTE> |
| { return sb.toString(); } |
| } |
| |
| private String SQuoted(): { |
| StringBuilder sb = new StringBuilder(); |
| } { |
| <START_SQUOTE> ( |
| <TEXT> { sb.append(getToken(0).image); } |
| | <ESCAPED> { sb.append(getToken(0).image); } |
| | <ESCAPE_SQUOTE> { sb.append("'"); } |
| )* <END_SQUOTE> |
| { return sb.toString(); } |
| } |
| |
| private String Text(): { |
| StringBuilder sb = new StringBuilder(); |
| } { |
| ( <TEXT> { sb.append(getToken(0).image); } )+ |
| { return sb.toString(); } |
| } |
| |
| private List<String> FieldList(): { |
| List<String> list = FastList.newInstance(); |
| String n; |
| } { |
| n=NamePart() { list.add(n); } |
| ( <COMMA> n=NamePart() { list.add(n); } )* |
| { return list; } |
| } |
| |
| private FieldValue FieldValue(String fieldName): { |
| String s; |
| } { |
| ( <PERIOD> s=NamePart() { return new FieldValue(fieldName, s); } )? |
| { return new FieldValue(fieldName); } |
| } |
| |
| private List<OrderByItem> OrderByList(): { |
| List<OrderByItem> orderBy = FastList.newInstance(); |
| OrderByItem obi; |
| } { |
| obi=OrderByItem() { orderBy.add(obi); } |
| ( <COMMA> obi=OrderByItem() { orderBy.add(obi); } )* |
| { return orderBy; } |
| } |
| |
| public OrderByItem OrderByItem(): { |
| ConstantValue value; |
| OrderByItem.Order ordering = OrderByItem.Order.DEFAULT; |
| OrderByItem.Nulls nulls = OrderByItem.Nulls.DEFAULT; |
| } { |
| ( |
| ( |
| ( |
| <PLUS> { ordering = OrderByItem.Order.ASCENDING; } |
| | <MINUS> { ordering = OrderByItem.Order.DESCENDING; } |
| ) |
| value=ConstantValue() |
| ) |
| | value=ConstantValue() ( |
| <DESC> { ordering = OrderByItem.Order.DESCENDING; } |
| | <ASC> { ordering = OrderByItem.Order.ASCENDING; } |
| )? |
| ) |
| ( |
| <NULLS> ( |
| <FIRST> { nulls = OrderByItem.Nulls.FIRST; } |
| | <LAST> { nulls = OrderByItem.Nulls.LAST; } |
| ) |
| )? |
| { return new OrderByItem(ordering, nulls, value); } |
| } |
| |
| private Integer Integer(): { |
| } { |
| <INTEGER> { return Integer.decode(getToken(0).image); } |
| } |
| |
| private Value Value(): { |
| String n; |
| Value v; |
| int i; |
| String s; |
| } { |
| n=NamePart() ( |
| v=FunctionCallRest(n) { return v; } |
| | v=FieldValue(n) { return v; } |
| ) |
| | i=Integer() { return new NumberValue<Integer>(i); } |
| | s=SQuoted() { return new StringValue(s); } |
| } |
| |
| private Condition ConditionExpression(): { |
| Condition c; |
| } { |
| c=OrExpression() { return c; } |
| } |
| |
| private Condition AndExpression(): { |
| List<Condition> list = FastList.newInstance(); |
| Condition c; |
| } { |
| c=BooleanExpression() { list.add(c); } |
| ( <AND> c=BooleanExpression() { list.add(c); } )* |
| { return reduce(list, Joiner.AND); } |
| } |
| |
| private Condition OrExpression(): { |
| List<Condition> list = FastList.newInstance(); |
| Condition c; |
| } { |
| c=AndExpression() { list.add(c); } |
| ( <OR> c=AndExpression() { list.add(c); } )* |
| { return reduce(list, Joiner.OR); } |
| } |
| |
| private Value RightValue(): { |
| Value v; |
| } { |
| v=Value() { return v; } |
| | v=ParameterValue() { return v; } |
| } |
| |
| private ParameterValue ParameterValue(): { |
| } { |
| <PARAMETER> { return new ParameterValue(getToken(0).image.substring(1)); } |
| } |
| |
| private Condition BooleanExpression(): { |
| Value v1, v2, v, r1, r2; |
| String op; |
| Condition c; |
| List<Value> list = FastList.newInstance(); |
| } { |
| v1=Value() ( |
| <BETWEEN> r1=RightValue() <AND> r2=RightValue() |
| { return new BetweenCondition(v1, r1, r2); } |
| | <IS> ( |
| <NULL> { op = "="; v2 = Value.NULL; } |
| | <NOT> <NULL> { op = "!="; v2 = Value.NULL; } |
| ) |
| | op=ComparisonOperator() ( |
| v2=RightValue() |
| | <OPEN_PAREN> |
| v=RightValue() { list.add(v); } |
| ( |
| <COMMA> v=RightValue() { list.add(v); } |
| )* |
| <CLOSE_PAREN> |
| { return new ListCondition(v1, op, list); } |
| ) |
| ) |
| { return new BooleanCondition(v1, op, v2); } |
| | <OPEN_PAREN> c=ConditionExpression() <CLOSE_PAREN> { return c; } |
| } |
| |
| private String ComparisonOperator(): { |
| StringBuilder sb = new StringBuilder(); |
| String s; |
| } { |
| s=Text() { sb.append(s); } |
| ( |
| <EQUALS> { sb.append(getToken(0).image); } |
| ( s=Text() { sb.append(s); } )? |
| )* |
| { return sb.toString(); } |
| | <NAME> { return getToken(0).image; } |
| | <EQUALS> { return getToken(0).image; } |
| } |
| |
| private String MathOperator(): { |
| String s; |
| } { |
| s=Text() { return s; } |
| | <NAME> { return getToken(0).image; } |
| } |
| |
| private String AggregateName(): { |
| } { |
| <COUNT> { return getToken(0).image; } |
| | <MAX> { return getToken(0).image; } |
| | <MIN> { return getToken(0).image; } |
| | <SUM> { return getToken(0).image; } |
| | <AVG> { return getToken(0).image; } |
| | <FIRST> { return getToken(0).image; } |
| | <LAST> { return getToken(0).image; } |
| } |