/******************************************************************************* * Copyright (c) 1998, 2008 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ // Added 20/12/2000 JED. Define the package for the class grammar JPQL; options { k = 3; // This is the number of tokens to look ahead to superClass = 'org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser'; } tokens { ABS='abs'; ALL='all'; AND='and'; ANY='any'; AS='as'; ASC='asc'; AVG='avg'; BETWEEN='between'; BOTH='both'; BY='by'; CASE='case'; COALESCE='coalesce'; CONCAT='concat'; COUNT='count'; CURRENT_DATE='current_date'; CURRENT_TIME='current_time'; CURRENT_TIMESTAMP='current_timestamp'; DESC='desc'; DELETE='delete'; DISTINCT='distinct'; ELSE='else'; EMPTY='empty'; END='end'; ENTRY='entry'; ESCAPE='escape'; EXISTS='exists'; FALSE='false'; FETCH='fetch'; FUNC='func'; FROM='from'; GROUP='group'; HAVING='having'; IN='in'; INDEX='index'; INNER='inner'; IS='is'; JOIN='join'; KEY='key'; LEADING='leading'; LEFT='left'; LENGTH='length'; LIKE='like'; LOCATE='locate'; LOWER='lower'; MAX='max'; MEMBER='member'; MIN='min'; MOD='mod'; NEW='new'; NOT='not'; NULL='null'; NULLIF='nullif'; OBJECT='object'; OF='of'; OR='or'; ORDER='order'; OUTER='outer'; SELECT='select'; SET='set'; SIZE='size'; SQRT='sqrt'; SOME='some'; SUBSTRING='substring'; SUM='sum'; THEN='then'; TRAILING='trailing'; TREAT='treat'; TRIM='trim'; TRUE='true'; TYPE='type'; UNKNOWN='unknown'; UPDATE='update'; UPPER='upper'; VALUE='value'; WHEN='when'; WHERE='where'; } @header { package org.eclipse.persistence.internal.jpa.parsing.jpql.antlr; import java.util.List; import java.util.ArrayList; import static org.eclipse.persistence.internal.jpa.parsing.NodeFactory.*; import org.eclipse.persistence.internal.jpa.parsing.jpql.InvalidIdentifierException; import org.eclipse.persistence.exceptions.JPQLException; } @lexer::header { package org.eclipse.persistence.internal.jpa.parsing.jpql.antlr; import org.eclipse.persistence.internal.jpa.parsing.jpql.InvalidIdentifierStartException; } @members{ /** The root node of the parsed EJBQL query. */ private Object queryRoot; /** Flag indicating whether aggregates are allowed. */ private boolean aggregatesAllowed = false; /** */ protected void setAggregatesAllowed(boolean allowed) { this.aggregatesAllowed = allowed; } /** */ protected boolean aggregatesAllowed() { return aggregatesAllowed; } /** */ protected void validateAbstractSchemaName(Token token) throws RecognitionException { String text = token.getText(); if (!isValidJavaIdentifier(token.getText())) { throw new InvalidIdentifierException(token); } } /** */ protected void validateAttributeName(Token token) throws RecognitionException { String text = token.getText(); if (!isValidJavaIdentifier(token.getText())) { throw new InvalidIdentifierException(token); } } /** */ protected boolean isValidJavaIdentifier(String text) { if ((text == null) || text.equals("")) return false; // check first char if (!Character.isJavaIdentifierStart(text.charAt(0))) return false; // check remaining characters for (int i = 1; i < text.length(); i++) { if (!Character.isJavaIdentifierPart(text.charAt(i))) { return false; } } return true; } protected String convertStringLiteral(String text) { // skip leading and trailing quotes String literal = text.substring(1, text.length() - 1); // convert ''s to 's while (true) { int index = literal.indexOf("''"); if (index == -1) { break; } literal = literal.substring(0, index) + literal.substring(index + 1, literal.length()); } return literal; } /** */ public Object getRootNode() { return queryRoot; } } document : root = selectStatement {queryRoot = $root.node;} | root = updateStatement {queryRoot = $root.node;} | root = deleteStatement {queryRoot = $root.node;} ; selectStatement returns [Object node] @init { node = null; } : select = selectClause from = fromClause (where = whereClause)? (groupBy = groupByClause)? (having = havingClause)? (orderBy = orderByClause)? EOF { $node = factory.newSelectStatement(0, 0, $select.node, $from.node, $where.node, $groupBy.node, $having.node, $orderBy.node); } ; //================================================ updateStatement returns [Object node] @init { node = null; } : update = updateClause set = setClause (where = whereClause)? EOF { $node = factory.newUpdateStatement(0, 0, $update.node, $set.node, $where.node); } ; updateClause returns [Object node] @init { node = null; } : u = UPDATE schema = abstractSchemaName ((AS)? ident = IDENT )? { String schemaName = null; if ($ident != null){ schemaName = $ident.getText(); } $node = factory.newUpdateClause($u.getLine(), $u.getCharPositionInLine(), $schema.schema, schemaName); } ; setClause returns [Object node] scope{ List assignments; } @init { node = null; $setClause::assignments = new ArrayList(); } : t = SET n = setAssignmentClause { $setClause::assignments.add($n.node); } (COMMA n = setAssignmentClause { $setClause::assignments.add($n.node); } )* { $node = factory.newSetClause($t.getLine(), $t.getCharPositionInLine(), $setClause::assignments); } ; setAssignmentClause returns [Object node] @init { node = null; } @after{ $node = factory.newSetAssignmentClause($t.getLine(), $t.getCharPositionInLine(), $target.node, $value.node); } : target = setAssignmentTarget t=EQUALS value = newValue ; setAssignmentTarget returns [Object node] @init { node = null; } : n = attribute { $node = $n.node;} | n = pathExpression {$node = $n.node;} ; newValue returns [Object node] @init { node = null; } : n = scalarExpression {$node = $n.node;} | n1 = NULL { $node = factory.newNullLiteral($n1.getLine(), $n1.getCharPositionInLine()); } ; //================================================ deleteStatement returns [Object node] @init { node = null; } : delete = deleteClause (where = whereClause)? EOF { $node = factory.newDeleteStatement(0, 0, $delete.node, $where.node); } ; deleteClause returns [Object node] scope{ String variable; } @init { node = null; $deleteClause::variable = null; } : t=DELETE FROM schema = abstractSchemaName ((AS)? ident=IDENT { $deleteClause::variable = $ident.getText(); })? { $node = factory.newDeleteClause($t.getLine(), $t.getCharPositionInLine(), $schema.schema, $deleteClause::variable); } ; //================================================ selectClause returns [Object node] scope{ boolean distinct; List exprs; List idents; } @init { node = null; $selectClause::distinct = false; $selectClause::exprs = new ArrayList(); $selectClause::idents = new ArrayList(); } : t=SELECT (DISTINCT { $selectClause::distinct = true; })? { setAggregatesAllowed(true); } n = selectItem { $selectClause::exprs.add($n.expr); $selectClause::idents.add($n.ident); } ( COMMA n = selectItem { $selectClause::exprs.add($n.expr); $selectClause::idents.add($n.ident); } )* { setAggregatesAllowed(false); $node = factory.newSelectClause($t.getLine(), $t.getCharPositionInLine(), $selectClause::distinct, $selectClause::exprs, $selectClause::idents); } ; selectItem returns [Object expr, Object ident] : e = selectExpression ((AS)? identifier = IDENT)? { $expr = $e.node; if ($identifier == null){ $ident = null; } else { $ident = $identifier.getText(); } } ; selectExpression returns [Object node] @init { node = null; } : n = aggregateExpression {$node = $n.node;} | n = scalarExpression {$node = $n.node;} | OBJECT LEFT_ROUND_BRACKET n = variableAccessOrTypeConstant RIGHT_ROUND_BRACKET {$node = $n.node;} | n = constructorExpression {$node = $n.node;} | n = mapEntryExpression {$node = $n.node;} ; mapEntryExpression returns [Object node] @init { node = null; } : l = ENTRY LEFT_ROUND_BRACKET n = variableAccessOrTypeConstant RIGHT_ROUND_BRACKET { $node = factory.newMapEntry($l.getLine(), $l.getCharPositionInLine(), $n.node);} ; pathExprOrVariableAccess returns [Object node] @init { node = null; } : n = qualifiedIdentificationVariable {$node = $n.node;} (d=DOT right = attribute { $node = factory.newDot($d.getLine(), $d.getCharPositionInLine(), $node, $right.node); } )* ; qualifiedIdentificationVariable returns [Object node] @init { node = null; } : n = variableAccessOrTypeConstant {$node = $n.node;} | l = KEY LEFT_ROUND_BRACKET n = variableAccessOrTypeConstant RIGHT_ROUND_BRACKET { $node = factory.newKey($l.getLine(), $l.getCharPositionInLine(), $n.node); } | l = VALUE LEFT_ROUND_BRACKET n = variableAccessOrTypeConstant RIGHT_ROUND_BRACKET { $node = $n.node;} ; aggregateExpression returns [Object node] scope{ boolean distinct; } @init { node = null; $aggregateExpression::distinct = false; } : t1=AVG LEFT_ROUND_BRACKET (DISTINCT { $aggregateExpression::distinct = true; })? n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newAvg($t1.getLine(), $t1.getCharPositionInLine(), $aggregateExpression::distinct, $n.node); } | t2=MAX LEFT_ROUND_BRACKET (DISTINCT { $aggregateExpression::distinct = true; })? n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newMax($t2.getLine(), $t2.getCharPositionInLine(), $aggregateExpression::distinct, $n.node); } | t3=MIN LEFT_ROUND_BRACKET (DISTINCT { $aggregateExpression::distinct = true; })? n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newMin($t3.getLine(), $t3.getCharPositionInLine(), $aggregateExpression::distinct, $n.node); } | t4=SUM LEFT_ROUND_BRACKET (DISTINCT { $aggregateExpression::distinct = true; })? n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newSum($t4.getLine(), $t4.getCharPositionInLine(), $aggregateExpression::distinct, $n.node); } | t5=COUNT LEFT_ROUND_BRACKET (DISTINCT { $aggregateExpression::distinct = true; })? n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newCount($t5.getLine(), $t5.getCharPositionInLine(), $aggregateExpression::distinct, $n.node); } ; constructorExpression returns [Object node] scope{ List args; } @init { node = null; $constructorExpression::args = new ArrayList(); } : t = NEW className = constructorName LEFT_ROUND_BRACKET n = constructorItem {$constructorExpression::args.add($n.node); } ( COMMA n = constructorItem { $constructorExpression::args.add($n.node); } )* RIGHT_ROUND_BRACKET { $node = factory.newConstructor($t.getLine(), $t.getCharPositionInLine(), $className.className, $constructorExpression::args); } ; constructorName returns [String className] scope{ StringBuffer buf; } @init { className = null; $constructorName::buf = new StringBuffer(); } : i1=IDENT { $constructorName::buf.append($i1.getText()); } ( DOT i2=IDENT { $constructorName::buf.append('.').append($i2.getText()); })* { $className = $constructorName::buf.toString(); } ; constructorItem returns [Object node] @init { node = null; } : n = scalarExpression {$node = $n.node;} | n = aggregateExpression {$node = $n.node;} ; fromClause returns [Object node] scope{ List varDecls; } @init { node = null; $fromClause::varDecls = new ArrayList(); } : t=FROM identificationVariableDeclaration[$fromClause::varDecls] (COMMA ( identificationVariableDeclaration[$fromClause::varDecls] | n = collectionMemberDeclaration {$fromClause::varDecls.add($n.node); } ) )* { $node = factory.newFromClause($t.getLine(), $t.getCharPositionInLine(), $fromClause::varDecls); } ; identificationVariableDeclaration [List varDecls] : node = rangeVariableDeclaration { varDecls.add($node.node); } ( node = join { $varDecls.add($node.node); } )* ; rangeVariableDeclaration returns [Object node] @init { node = null; } : schema = abstractSchemaName (AS)? i=IDENT { $node = factory.newRangeVariableDecl($i.getLine(), $i.getCharPositionInLine(), $schema.schema, $i.getText()); } ; // Non-terminal abstractSchemaName first matches any token to allow abstract // schema names that are keywords (such as order, etc.). // Method validateAbstractSchemaName throws an exception if the text of the // token is not a valid Java identifier. abstractSchemaName returns [String schema] @init { schema = null; } : ident=. { $schema = $ident.getText(); validateAbstractSchemaName($ident); } ; join returns [Object node] @init { node = null; } : outerJoin = joinSpec ( n = joinAssociationPathExpression (AS)? i=IDENT { $node = factory.newJoinVariableDecl($i.getLine(), $i.getCharPositionInLine(), $outerJoin.outer, $n.node, $i.getText(), null); } | TREAT LEFT_ROUND_BRACKET n = joinAssociationPathExpression AS castClass = IDENT RIGHT_ROUND_BRACKET (AS)? i=IDENT { $node = factory.newJoinVariableDecl($i.getLine(), $i.getCharPositionInLine(), $outerJoin.outer, $n.node, $i.getText(), $castClass.getText()); } | t=FETCH n = joinAssociationPathExpression { $node = factory.newFetchJoin($t.getLine(), $t.getCharPositionInLine(), $outerJoin.outer, $n.node); } ) ; joinSpec returns [boolean outer] @init { outer = false; } : (LEFT (OUTER)? { $outer = true; } | INNER )? JOIN ; collectionMemberDeclaration returns [Object node] @init { node = null; } : t=IN LEFT_ROUND_BRACKET n = collectionValuedPathExpression RIGHT_ROUND_BRACKET (AS)? i=IDENT { $node = factory.newCollectionMemberVariableDecl( $t.getLine(), $t.getCharPositionInLine(), $n.node, $i.getText()); } ; collectionValuedPathExpression returns [Object node] @init { node = null; } : n = pathExpression {$node = $n.node;} ; associationPathExpression returns [Object node] @init { node = null; } : n = pathExpression {$node = $n.node;} ; joinAssociationPathExpression returns [Object node] @init { node = null; } : n = qualifiedIdentificationVariable {$node = $n.node;} (d=DOT right = attribute { $node = factory.newDot($d.getLine(), $d.getCharPositionInLine(), $node, $right.node); } )+ ; singleValuedPathExpression returns [Object node] @init { node = null; } : n = pathExpression {$node = $n.node;} ; stateFieldPathExpression returns [Object node] @init { node = null; } : n = pathExpression {$node = $n.node;} ; pathExpression returns [Object node] @init { node = null; } : n = qualifiedIdentificationVariable {$node = $n.node;} (d=DOT right = attribute { $node = factory.newDot($d.getLine(), $d.getCharPositionInLine(), $node, $right.node); } )+ ; // Non-terminal attribute first matches any token to allow abstract // schema names that are keywords (such as order, etc.). // Method validateAttributeName throws an exception if the text of the // token is not a valid Java identifier. attribute returns [Object node] @init { node = null; } : i=. { validateAttributeName($i); $node = factory.newAttribute($i.getLine(), $i.getCharPositionInLine(), $i.getText()); } ; variableAccessOrTypeConstant returns [Object node] @init { node = null; } : i=IDENT { $node = factory.newVariableAccessOrTypeConstant($i.getLine(), $i.getCharPositionInLine(), $i.getText()); } ; whereClause returns [Object node] @init { node = null; } : t=WHERE n = conditionalExpression { $node = factory.newWhereClause($t.getLine(), $t.getCharPositionInLine(), $n.node); } ; conditionalExpression returns [Object node] @init { node = null; } : n = conditionalTerm {$node = $n.node;} (t=OR right = conditionalTerm { $node = factory.newOr($t.getLine(), $t.getCharPositionInLine(), $node, $right.node); } )* ; conditionalTerm returns [Object node] @init { node = null; } : n = conditionalFactor {$node = $n.node;} (t=AND right = conditionalFactor { $node = factory.newAnd($t.getLine(), $t.getCharPositionInLine(), $node, $right.node); } )* ; conditionalFactor returns [Object node] @init { node = null; } : (n=NOT)? ( n1 = conditionalPrimary { $node = $n1.node; if ($n != null) { $node = factory.newNot($n.getLine(), $n.getCharPositionInLine(), $n1.node); } } | n1 = existsExpression[(n!=null)] {$node = $n1.node;} ) ; conditionalPrimary returns [Object node] @init { node = null; } : (LEFT_ROUND_BRACKET conditionalExpression) => LEFT_ROUND_BRACKET n = conditionalExpression RIGHT_ROUND_BRACKET {$node = $n.node;} | n = simpleConditionalExpression {$node = $n.node;} ; simpleConditionalExpression returns [Object node] @init { node = null; } : left = arithmeticExpression n = simpleConditionalExpressionRemainder[$left.node] {$node = $n.node;} | left = nonArithmeticScalarExpression n = simpleConditionalExpressionRemainder[$left.node] {$node = $n.node;} ; simpleConditionalExpressionRemainder [Object left] returns [Object node] @init { node = null; } : n = comparisonExpression[left] {$node = $n.node;} | (n1=NOT)? n = conditionWithNotExpression[(n1!=null), left] {$node = $n.node;} | IS (n2=NOT)? n = isExpression[(n2!=null), left] {$node = $n.node;} ; conditionWithNotExpression [boolean not, Object left] returns [Object node] @init { node = null; } : n = betweenExpression[not, left] {$node = $n.node;} | n = likeExpression[not, left] {$node = $n.node;} | n= inExpression[not, left] {$node = $n.node;} | n= collectionMemberExpression[not, left] {$node = $n.node;} ; isExpression [boolean not, Object left] returns [Object node] @init { node = null; } : n = nullComparisonExpression[not, left] {$node = $n.node;} | n = emptyCollectionComparisonExpression[not, left] {$node = $n.node;} ; betweenExpression [boolean not, Object left] returns [Object node] @init { node = null; } : t=BETWEEN lowerBound = scalarOrSubSelectExpression AND upperBound = scalarOrSubSelectExpression { $node = factory.newBetween($t.getLine(), $t.getCharPositionInLine(), $not, $left, $lowerBound.node, $upperBound.node); } ; inExpression [boolean not, Object left] returns [Object node] scope{ List items; } @init { node = null; $inExpression::items = new ArrayList(); } : t = IN n = inputParameter { $node = factory.newIn($t.getLine(), $t.getCharPositionInLine(), $not, $left, $n.node); } | t=IN LEFT_ROUND_BRACKET ( itemNode = scalarOrSubSelectExpression { $inExpression::items.add($itemNode.node); } ( COMMA itemNode = scalarOrSubSelectExpression { $inExpression::items.add($itemNode.node); } )* { $node = factory.newIn($t.getLine(), $t.getCharPositionInLine(), $not, $left, $inExpression::items); } | subqueryNode = subquery { $node = factory.newIn($t.getLine(), $t.getCharPositionInLine(), $not, $left, $subqueryNode.node); } ) RIGHT_ROUND_BRACKET ; likeExpression [boolean not, Object left] returns [Object node] @init { node = null; } : t=LIKE pattern = scalarOrSubSelectExpression (escapeChars = escape)? { $node = factory.newLike($t.getLine(), $t.getCharPositionInLine(), $not, $left, $pattern.node, $escapeChars.node); } ; escape returns [Object node] @init { node = null; } : t=ESCAPE escapeClause = scalarExpression { $node = factory.newEscape($t.getLine(), $t.getCharPositionInLine(), $escapeClause.node); } ; nullComparisonExpression [boolean not, Object left] returns [Object node] @init { node = null; } : t= NULL { $node = factory.newIsNull($t.getLine(), $t.getCharPositionInLine(), $not, $left); } ; emptyCollectionComparisonExpression [boolean not, Object left] returns [Object node] @init { node = null; } : t= EMPTY { $node = factory.newIsEmpty($t.getLine(), $t.getCharPositionInLine(), $not, $left); } ; collectionMemberExpression [boolean not, Object left] returns [Object node] @init { node = null; } : t= MEMBER (OF)? n = collectionValuedPathExpression { $node = factory.newMemberOf($t.getLine(), $t.getCharPositionInLine(), $not, $left, $n.node); } ; existsExpression [boolean not] returns [Object node] @init { node = null; } : t=EXISTS LEFT_ROUND_BRACKET subqueryNode = subquery RIGHT_ROUND_BRACKET { $node = factory.newExists($t.getLine(), $t.getCharPositionInLine(), $not, $subqueryNode.node); } ; comparisonExpression [Object left] returns [Object node] @init { node = null; } : t1=EQUALS n = comparisonExpressionRightOperand { $node = factory.newEquals($t1.getLine(), $t1.getCharPositionInLine(), $left, $n.node); } | t2=NOT_EQUAL_TO n = comparisonExpressionRightOperand { $node = factory.newNotEquals($t2.getLine(), $t2.getCharPositionInLine(), $left, $n.node); } | t3=GREATER_THAN n = comparisonExpressionRightOperand { $node = factory.newGreaterThan($t3.getLine(), $t3.getCharPositionInLine(), $left, $n.node); } | t4=GREATER_THAN_EQUAL_TO n = comparisonExpressionRightOperand { $node = factory.newGreaterThanEqual($t4.getLine(), $t4.getCharPositionInLine(), $left, $n.node); } | t5=LESS_THAN n = comparisonExpressionRightOperand { $node = factory.newLessThan($t5.getLine(), $t5.getCharPositionInLine(), $left, $n.node); } | t6=LESS_THAN_EQUAL_TO n = comparisonExpressionRightOperand { $node = factory.newLessThanEqual($t6.getLine(), $t6.getCharPositionInLine(), $left, $n.node); } ; comparisonExpressionRightOperand returns [Object node] @init { node = null; } : n = arithmeticExpression {$node = $n.node;} | n = nonArithmeticScalarExpression {$node = $n.node;} | n = anyOrAllExpression {$node = $n.node;} ; arithmeticExpression returns [Object node] @init { node = null; } : n = simpleArithmeticExpression {$node = $n.node;} | LEFT_ROUND_BRACKET n = subquery RIGHT_ROUND_BRACKET {$node = $n.node;} ; simpleArithmeticExpression returns [Object node] @init { node = null; } : n = arithmeticTerm {$node = $n.node;} ( p=PLUS right = arithmeticTerm { $node = factory.newPlus($p.getLine(), $p.getCharPositionInLine(), $node, $right.node); } | m=MINUS right = arithmeticTerm { $node = factory.newMinus($m.getLine(), $m.getCharPositionInLine(), $node, $right.node); } )* ; arithmeticTerm returns [Object node] @init { node = null; } : n = arithmeticFactor {$node = $n.node;} ( m=MULTIPLY right = arithmeticFactor { $node = factory.newMultiply($m.getLine(), $m.getCharPositionInLine(), $node, $right.node); } | d=DIVIDE right = arithmeticFactor { $node = factory.newDivide($d.getLine(), $d.getCharPositionInLine(), $node, $right.node); } )* ; arithmeticFactor returns [Object node] @init { node = null; } : p=PLUS n = arithmeticPrimary {$node = factory.newUnaryPlus($p.getLine(), $p.getCharPositionInLine(), $n.node); } | m=MINUS n = arithmeticPrimary { $node = factory.newUnaryMinus($m.getLine(), $m.getCharPositionInLine(), $n.node); } | n = arithmeticPrimary {$node = $n.node;} ; arithmeticPrimary returns [Object node] @init { node = null; } : { aggregatesAllowed() }? n = aggregateExpression {$node = $n.node;} | n = pathExprOrVariableAccess {$node = $n.node;} | n = inputParameter {$node = $n.node;} | n = caseExpression {$node = $n.node;} | n = functionsReturningNumerics {$node = $n.node;} | LEFT_ROUND_BRACKET n = simpleArithmeticExpression RIGHT_ROUND_BRACKET {$node = $n.node;} | n = literalNumeric {$node = $n.node;} ; scalarExpression returns [Object node] @init {node = null; } : n = simpleArithmeticExpression {$node = $n.node;} | n = nonArithmeticScalarExpression {$node = $n.node;} ; scalarOrSubSelectExpression returns [Object node] @init {node = null; } : n = arithmeticExpression {$node = $n.node;} | n = nonArithmeticScalarExpression {$node = $n.node;} ; nonArithmeticScalarExpression returns [Object node] @init {node = null; } : n = functionsReturningDatetime {$node = $n.node;} | n = functionsReturningStrings {$node = $n.node;} | n = literalString {$node = $n.node;} | n = literalBoolean {$node = $n.node;} | n = literalTemporal {$node = $n.node;} | n = entityTypeExpression {$node = $n.node;} ; anyOrAllExpression returns [Object node] @init { node = null; } : a=ALL LEFT_ROUND_BRACKET n = subquery RIGHT_ROUND_BRACKET { $node = factory.newAll($a.getLine(), $a.getCharPositionInLine(), $n.node); } | y=ANY LEFT_ROUND_BRACKET n = subquery RIGHT_ROUND_BRACKET { $node = factory.newAny($y.getLine(), $y.getCharPositionInLine(), $n.node); } | s=SOME LEFT_ROUND_BRACKET n = subquery RIGHT_ROUND_BRACKET { $node = factory.newSome($s.getLine(), $s.getCharPositionInLine(), $n.node); } ; entityTypeExpression returns [Object node] @init {node = null;} : n = typeDiscriminator {$node = $n.node;} ; typeDiscriminator returns [Object node] @init {node = null;} : a = TYPE LEFT_ROUND_BRACKET n = variableOrSingleValuedPath RIGHT_ROUND_BRACKET { $node = factory.newType($a.getLine(), $a.getCharPositionInLine(), $n.node);} | c = TYPE LEFT_ROUND_BRACKET n = inputParameter RIGHT_ROUND_BRACKET { $node = factory.newType($c.getLine(), $c.getCharPositionInLine(), $n.node);} ; caseExpression returns [Object node] @init {node = null;} : n = simpleCaseExpression {$node = $n.node;} | n = generalCaseExpression {$node = $n.node;} | n = coalesceExpression {$node = $n.node;} | n = nullIfExpression {$node = $n.node;} ; simpleCaseExpression returns [Object node] scope{ List whens; } @init { node = null; $simpleCaseExpression::whens = new ArrayList(); } : a = CASE c = caseOperand w = simpleWhenClause {$simpleCaseExpression::whens.add($w.node);} (w = simpleWhenClause {$simpleCaseExpression::whens.add($w.node);})* ELSE e = scalarExpression END { $node = factory.newCaseClause($a.getLine(), $a.getCharPositionInLine(), $c.node, $simpleCaseExpression::whens, $e.node); } ; generalCaseExpression returns [Object node] scope{ List whens; } @init { node = null; $generalCaseExpression::whens = new ArrayList(); } : a = CASE w = whenClause {$generalCaseExpression::whens.add($w.node);} (w = whenClause {$generalCaseExpression::whens.add($w.node);})* ELSE e = scalarExpression END { $node = factory.newCaseClause($a.getLine(), $a.getCharPositionInLine(), null, $generalCaseExpression::whens, $e.node); } ; coalesceExpression returns [Object node] scope{ List primaries; } @init { node = null; $coalesceExpression::primaries = new ArrayList(); } : c = COALESCE LEFT_ROUND_BRACKET p = scalarExpression {$coalesceExpression::primaries.add($p.node);} (COMMA s = scalarExpression {$coalesceExpression::primaries.add($s.node);})+ RIGHT_ROUND_BRACKET { $node = factory.newCoalesceClause($c.getLine(), $c.getCharPositionInLine(), $coalesceExpression::primaries); } ; nullIfExpression returns [Object node] @init {node = null;} : n = NULLIF LEFT_ROUND_BRACKET l = scalarExpression COMMA r = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newNullIfClause($n.getLine(), $n.getCharPositionInLine(), $l.node, $r.node); } ; caseOperand returns [Object node] @init {node = null;} : n = stateFieldPathExpression {$node = $n.node;} | n = typeDiscriminator {$node = $n.node;} ; whenClause returns [Object node] @init {node = null;} : w = WHEN c = conditionalExpression THEN a = scalarExpression { $node = factory.newWhenClause($w.getLine(), $w.getCharPositionInLine(), $c.node, $a.node); } ; simpleWhenClause returns [Object node] @init {node = null;} : w = WHEN c = scalarExpression THEN a = scalarExpression { $node = factory.newWhenClause($w.getLine(), $w.getCharPositionInLine(), $c.node, $a.node); } ; variableOrSingleValuedPath returns [Object node] @init {node = null;} : n = singleValuedPathExpression {$node = $n.node;} | n = variableAccessOrTypeConstant {$node = $n.node;} ; stringPrimary returns [Object node] @init { node = null; } : n = literalString {$node = $n.node;} | n = functionsReturningStrings {$node = $n.node;} | n = inputParameter {$node = $n.node;} | n = stateFieldPathExpression {$node = $n.node;} ; // Literals and Low level stuff literal returns [Object node] @init { node = null; } : n = literalNumeric {$node = $n.node;} | n = literalBoolean {$node = $n.node;} | n = literalString {$node = $n.node;} ; literalNumeric returns [Object node] @init { node = null; } : i=INTEGER_LITERAL { $node = factory.newIntegerLiteral($i.getLine(), $i.getCharPositionInLine(), Integer.valueOf($i.getText())); } | l=LONG_LITERAL { String text = l.getText(); // skip the tailing 'l' text = text.substring(0, text.length() - 1); $node = factory.newLongLiteral($l.getLine(), $l.getCharPositionInLine(), Long.valueOf(text)); } | f=FLOAT_LITERAL { $node = factory.newFloatLiteral($f.getLine(), $f.getCharPositionInLine(), Float.valueOf($f.getText())); } | d=DOUBLE_LITERAL { $node = factory.newDoubleLiteral($d.getLine(), $d.getCharPositionInLine(), Double.valueOf($d.getText())); } ; literalBoolean returns [Object node] @init { node = null; } : t=TRUE { $node = factory.newBooleanLiteral($t.getLine(), $t.getCharPositionInLine(), Boolean.TRUE); } | f=FALSE { $node = factory.newBooleanLiteral($f.getLine(), $f.getCharPositionInLine(), Boolean.FALSE); } ; literalString returns [Object node] @init { node = null; } : d=STRING_LITERAL_DOUBLE_QUOTED { $node = factory.newStringLiteral($d.getLine(), $d.getCharPositionInLine(), convertStringLiteral($d.getText())); } | s=STRING_LITERAL_SINGLE_QUOTED { $node = factory.newStringLiteral($s.getLine(), $s.getCharPositionInLine(), convertStringLiteral($s.getText())); } ; literalTemporal returns [Object node] @init { node = null; } : d = DATE_LITERAL {$node = factory.newDateLiteral($d.getLine(), $d.getCharPositionInLine(), $d.getText()); } | d = TIME_LITERAL {$node = factory.newTimeLiteral($d.getLine(), $d.getCharPositionInLine(), $d.getText()); } | d = TIMESTAMP_LITERAL {$node = factory.newTimeStampLiteral($d.getLine(), $d.getCharPositionInLine(), $d.getText()); } ; inputParameter returns [Object node] @init { node = null; } : p=POSITIONAL_PARAM { // skip the leading ? String text = $p.getText().substring(1); $node = factory.newPositionalParameter($p.getLine(), $p.getCharPositionInLine(), text); } | n=NAMED_PARAM { // skip the leading : String text = $n.getText().substring(1); $node = factory.newNamedParameter($n.getLine(), $n.getCharPositionInLine(), text); } ; functionsReturningNumerics returns [Object node] @init { node = null; } : n = abs {$node = $n.node;} | n = length {$node = $n.node;} | n = mod {$node = $n.node;} | n = sqrt {$node = $n.node;} | n = locate {$node = $n.node;} | n = size {$node = $n.node;} | n = index {$node = $n.node;} | n = func {$node = $n.node;} ; functionsReturningDatetime returns [Object node] @init { node = null; } : d=CURRENT_DATE { $node = factory.newCurrentDate($d.getLine(), $d.getCharPositionInLine()); } | t=CURRENT_TIME { $node = factory.newCurrentTime($t.getLine(), $t.getCharPositionInLine()); } | ts=CURRENT_TIMESTAMP { $node = factory.newCurrentTimestamp($ts.getLine(), $ts.getCharPositionInLine()); } ; functionsReturningStrings returns [Object node] @init { node = null; } : n = concat {$node = $n.node;} | n = substring {$node = $n.node;} | n = trim {$node = $n.node;} | n = upper {$node = $n.node;} | n = lower {$node = $n.node;} ; // Functions returning strings concat returns [Object node] scope { List items; } @init { node = null; $concat::items = new ArrayList(); } : c=CONCAT LEFT_ROUND_BRACKET firstArg = scalarExpression {$concat::items.add($firstArg.node);} (COMMA arg = scalarExpression {$concat::items.add($arg.node);})+ RIGHT_ROUND_BRACKET { $node = factory.newConcat($c.getLine(), $c.getCharPositionInLine(), $concat::items); } ; substring returns [Object node] @init { node = null; lengthNode = null; } : s=SUBSTRING LEFT_ROUND_BRACKET string = scalarExpression COMMA start = scalarExpression (COMMA lengthNode = scalarExpression)? RIGHT_ROUND_BRACKET { if (lengthNode != null){ $node = factory.newSubstring($s.getLine(), $s.getCharPositionInLine(), $string.node, $start.node, $lengthNode.node); } else { $node = factory.newSubstring($s.getLine(), $s.getCharPositionInLine(), $string.node, $start.node, null); } } ; trim returns [Object node] @init { node = null; trimSpecIndicator = TrimSpecification.BOTH; } : t=TRIM LEFT_ROUND_BRACKET (trimSpecIndicator = trimSpec trimCharNode = trimChar FROM)? n = stringPrimary RIGHT_ROUND_BRACKET { $node = factory.newTrim($t.getLine(), $t.getCharPositionInLine(), $trimSpecIndicator.trimSpec, $trimCharNode.node, $n.node); } ; trimSpec returns [TrimSpecification trimSpec] @init { trimSpec = TrimSpecification.BOTH; } : LEADING { $trimSpec = TrimSpecification.LEADING; } | TRAILING { $trimSpec = TrimSpecification.TRAILING; } | BOTH { $trimSpec = TrimSpecification.BOTH; } | // empty rule ; trimChar returns [Object node] @init { node = null; } : n = literalString {$node = $n.node;} | n = inputParameter {$node = $n.node;} | // empty rule ; upper returns [Object node] @init { node = null; } : u=UPPER LEFT_ROUND_BRACKET n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newUpper($u.getLine(), $u.getCharPositionInLine(), $n.node); } ; lower returns [Object node] @init { node = null; } : l=LOWER LEFT_ROUND_BRACKET n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newLower($l.getLine(), $l.getCharPositionInLine(), $n.node); } ; // Functions returning numerics abs returns [Object node] @init { node = null; } : a=ABS LEFT_ROUND_BRACKET n = simpleArithmeticExpression RIGHT_ROUND_BRACKET { $node = factory.newAbs($a.getLine(), $a.getCharPositionInLine(), $n.node); } ; length returns [Object node] @init { node = null; } : l=LENGTH LEFT_ROUND_BRACKET n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newLength($l.getLine(), $l.getCharPositionInLine(), $n.node); } ; locate returns [Object node] @init { node = null; } : l=LOCATE LEFT_ROUND_BRACKET pattern = scalarExpression COMMA n = scalarExpression ( COMMA startPos = scalarExpression )? RIGHT_ROUND_BRACKET { $node = factory.newLocate($l.getLine(), $l.getCharPositionInLine(), $pattern.node, $n.node, $startPos.node); } ; size returns [Object node] @init { node = null; } : s=SIZE LEFT_ROUND_BRACKET n = collectionValuedPathExpression RIGHT_ROUND_BRACKET { $node = factory.newSize($s.getLine(), $s.getCharPositionInLine(), $n.node);} ; mod returns [Object node] @init { node = null; } : m=MOD LEFT_ROUND_BRACKET left = scalarExpression COMMA right = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newMod($m.getLine(), $m.getCharPositionInLine(), $left.node, $right.node); } ; sqrt returns [Object node] @init { node = null; } : s=SQRT LEFT_ROUND_BRACKET n = scalarExpression RIGHT_ROUND_BRACKET { $node = factory.newSqrt($s.getLine(), $s.getCharPositionInLine(), $n.node); } ; index returns [Object node] @init { node = null; } : s=INDEX LEFT_ROUND_BRACKET n = variableAccessOrTypeConstant RIGHT_ROUND_BRACKET { $node = factory.newIndex($s.getLine(), $s.getCharPositionInLine(), $n.node); } ; // custom function func returns [Object node] scope{ List exprs; } @init { node = null; $func::exprs = new ArrayList(); } : f=FUNC LEFT_ROUND_BRACKET name = STRING_LITERAL_SINGLE_QUOTED (COMMA n = newValue { $func::exprs.add($n.node); } )* RIGHT_ROUND_BRACKET {$node = factory.newFunc($f.getLine(), $f.getCharPositionInLine(), $name.getText(), $func::exprs);} ; subquery returns [Object node] @init { node = null; } : select = simpleSelectClause from = subqueryFromClause (where = whereClause)? (groupBy = groupByClause)? (having = havingClause)? { $node = factory.newSubquery(0, 0, $select.node, $from.node, $where.node, $groupBy.node, $having.node); } ; simpleSelectClause returns [Object node] scope{ boolean distinct; } @init { node = null; $simpleSelectClause::distinct = false; } : s=SELECT (DISTINCT { $simpleSelectClause::distinct = true; })? n = simpleSelectExpression { List exprs = new ArrayList(); exprs.add($n.node); $node = factory.newSelectClause($s.getLine(), $s.getCharPositionInLine(), $simpleSelectClause::distinct, exprs); } ; simpleSelectExpression returns [Object node] @init { node = null; } : n = singleValuedPathExpression {$node = $n.node;} | n = aggregateExpression {$node = $n.node;} | n = variableAccessOrTypeConstant {$node = $n.node;} ; subqueryFromClause returns [Object node] scope{ List varDecls; } @init { node = null; $subqueryFromClause::varDecls = new ArrayList(); } : f=FROM subselectIdentificationVariableDeclaration[$subqueryFromClause::varDecls] ( COMMA subselectIdentificationVariableDeclaration[$subqueryFromClause::varDecls] | c = collectionMemberDeclaration {$subqueryFromClause::varDecls.add($c.node);} )* { $node = factory.newFromClause($f.getLine(), $f.getCharPositionInLine(), $subqueryFromClause::varDecls); } ; subselectIdentificationVariableDeclaration [List varDecls] @init { Object node; } : identificationVariableDeclaration[varDecls] | n = associationPathExpression (AS)? i=IDENT (join { varDecls.add($n.node); } )* { $varDecls.add(factory.newVariableDecl($i.getLine(), $i.getCharPositionInLine(), $n.node, $i.getText())); } | n = collectionMemberDeclaration { $varDecls.add($n.node); } ; orderByClause returns [Object node] scope{ List items; } @init { node = null; $orderByClause::items = new ArrayList(); } : o=ORDER BY { setAggregatesAllowed(true); } n = orderByItem { $orderByClause::items.add($n.node); } (COMMA n = orderByItem { $orderByClause::items.add($n.node); })* { setAggregatesAllowed(false); $node = factory.newOrderByClause($o.getLine(), $o.getCharPositionInLine(), $orderByClause::items); } ; orderByItem returns [Object node] @init { node = null; } : n = scalarExpression ( a=ASC { $node = factory.newAscOrdering($a.getLine(), $a.getCharPositionInLine(), $n.node); } | d=DESC { $node = factory.newDescOrdering($d.getLine(), $d.getCharPositionInLine(), $n.node); } | // empty rule { $node = factory.newAscOrdering(0, 0, $n.node); } ) ; groupByClause returns [Object node] scope{ List items; } @init { node = null; $groupByClause::items = new ArrayList(); } : g=GROUP BY n = scalarExpression { $groupByClause::items.add($n.node); } (COMMA n = scalarExpression { $groupByClause::items.add($n.node); } )* { $node = factory.newGroupByClause($g.getLine(), $g.getCharPositionInLine(), $groupByClause::items); } ; havingClause returns [Object node] @init { node = null; } : h=HAVING { setAggregatesAllowed(true); } n = conditionalExpression { setAggregatesAllowed(false); $node = factory.newHavingClause($h.getLine(), $h.getCharPositionInLine(), $n.node); } ; DOT : '.' ; WS : (' ' | '\t' | '\n' | '\r')+ { skip(); } ; LEFT_ROUND_BRACKET : '(' ; LEFT_CURLY_BRACKET : '{' ; RIGHT_ROUND_BRACKET : ')' ; RIGHT_CURLY_BRACKET : '}' ; COMMA : ',' ; IDENT : TEXTCHAR ; fragment TEXTCHAR : ('a'..'z' | 'A'..'Z' | '_' | '$' | '`' | '~' | '@' | '#' | '%' | '^' | '&' | '|' | '[' | ']' | ';' c1='\u0080'..'\uFFFE' { if (!Character.isJavaIdentifierStart(c1)) { throw new InvalidIdentifierStartException(c1, getLine(), getCharPositionInLine()); } } ) ('a'..'z' | '_' | '$' | '0'..'9' | c2='\u0080'..'\uFFFE' { if (!Character.isJavaIdentifierPart(c2)) { throw new InvalidIdentifierStartException(c2, getLine(), getCharPositionInLine()); } } )* ; HEX_LITERAL : '0' ('x'|'X') HEX_DIGIT+ ; INTEGER_LITERAL : MINUS? ('0' | '1'..'9' '0'..'9'*) ; LONG_LITERAL : INTEGER_LITERAL INTEGER_SUFFIX; OCTAL_LITERAL : MINUS? '0' ('0'..'7')+ ; // hexadecimal digit fragment HEX_DIGIT : ('0'..'9'|'a'..'f' | 'A'..'F') ; fragment INTEGER_SUFFIX : ('l'|'L') ; fragment NUMERIC_DIGITS : MINUS? ('0'..'9')+ '.' ('0'..'9')* | MINUS? '.' ('0'..'9')+ | MINUS? ('0'..'9')+ ; DOUBLE_LITERAL : NUMERIC_DIGITS DOUBLE_SUFFIX? ; FLOAT_LITERAL : NUMERIC_DIGITS EXPONENT FLOAT_SUFFIX? | NUMERIC_DIGITS FLOAT_SUFFIX ; // a couple protected methods to assist in matching floating point numbers fragment EXPONENT : ('e' | 'E') ('+'|'-')? ('0'..'9')+ ; fragment FLOAT_SUFFIX : 'f' ; DATE_LITERAL : LEFT_CURLY_BRACKET ('d') (' ' | '\t')+ '\'' DATE_STRING '\'' (' ' | '\t')* RIGHT_CURLY_BRACKET ; TIME_LITERAL : LEFT_CURLY_BRACKET ('t') (' ' | '\t')+ '\'' TIME_STRING '\'' (' ' | '\t')* RIGHT_CURLY_BRACKET ; TIMESTAMP_LITERAL : LEFT_CURLY_BRACKET ('ts') (' ' | '\t')+ '\'' DATE_STRING ' ' TIME_STRING '\'' (' ' | '\t')* RIGHT_CURLY_BRACKET ; DATE_STRING : '0'..'9' '0'..'9' '0'..'9' '0'..'9' '-' '0'..'9' '0'..'9' '-' '0'..'9' '0'..'9' ; TIME_STRING : '0'..'9' ('0'..'9')? ':' '0'..'9' '0'..'9' ':' '0'..'9' '0'..'9' '.' '0'..'9'* ; fragment DOUBLE_SUFFIX : 'd' ; EQUALS : '=' ; GREATER_THAN : '>' ; GREATER_THAN_EQUAL_TO : '>=' ; LESS_THAN : '<' ; LESS_THAN_EQUAL_TO : '<=' ; NOT_EQUAL_TO : '<>' | '!=' ; MULTIPLY : '*' ; DIVIDE : '/' ; PLUS : '+' ; MINUS : '-' ; POSITIONAL_PARAM : '?' ('1'..'9') ('0'..'9')* ; NAMED_PARAM : ':' TEXTCHAR ; // Added Jan 9, 2001 JED // string literals STRING_LITERAL_DOUBLE_QUOTED : '"' (~ ('"'))* '"' ; STRING_LITERAL_SINGLE_QUOTED : '\'' (~ ('\'') | ('\'\''))* '\'' ;