Hibernate SVN: r16332 - core/branches/SQL_GEN_REDESIGN/src/main/antlr/v3/order.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2009-04-14 13:12:42 -0400 (Tue, 14 Apr 2009)
New Revision: 16332
Added:
core/branches/SQL_GEN_REDESIGN/src/main/antlr/v3/order/OrderByParser.g
Log:
Added: core/branches/SQL_GEN_REDESIGN/src/main/antlr/v3/order/OrderByParser.g
===================================================================
--- core/branches/SQL_GEN_REDESIGN/src/main/antlr/v3/order/OrderByParser.g (rev 0)
+++ core/branches/SQL_GEN_REDESIGN/src/main/antlr/v3/order/OrderByParser.g 2009-04-14 17:12:42 UTC (rev 16332)
@@ -0,0 +1,410 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+grammar OrderByParser;
+
+options {
+ language = Java;
+ output = AST;
+ ASTLabelType = CommonTree;
+}
+
+tokens {
+ COLLATE;
+ ASCENDING;
+ DESCENDING;
+
+ ORDER_BY;
+ SORT_SPEC;
+ ORDER_SPEC;
+ SORT_KEY;
+ EXPR_LIST;
+ IDENT_LIST;
+ COLUMN_REF;
+
+ NUM_INTEGER_LITERAL;
+ NUM_LONG_LITERAL;
+ NUM_DOUBLE_LITERAL;
+ NUM_FLOAT_LITERAL;
+}
+
+@lexer::header {
+ package org.hibernate.sql.ast.ordering;
+}
+
+@lexer::members {
+}
+
+@parser::header {
+ package org.hibernate.sql.ast.ordering;
+
+ import org.hibernate.sql.Template;
+ import org.hibernate.dialect.function.SQLFunction;
+}
+
+@parser::members {
+ private final TranslationContext context;
+
+// public OrderByParserParser(TokenStream input, TranslationContext context) {
+// super( input );
+// this.context = context;
+// }
+
+ /**
+ * Process the given node as a quote identifier. These need to be quoted in the dialect-specific way.
+ *
+ * @param ident The quoted-identifier node.
+ *
+ * @return The processed node.
+ *
+ * @see org.hibernate.dialect.Dialect#quote
+ */
+ protected CommonTree quotedIdentifier(CommonTree ident) {
+ String quotedText = Template.TEMPLATE + "." + context.getDialect().quote( '`' + ident.getText() + '`' );
+ return createTreeNode( ident.getToken().getType(), quotedText );
+ }
+
+ /**
+ * Process the given node as a quote string.
+ *
+ * @param ident The quoted string. This is used from within function param recognition, and represents a
+ * SQL-quoted string.
+ *
+ * @return The processed node.
+ */
+ protected CommonTree quotedString(CommonTree ident) {
+ String quotedText = context.getDialect().quote( ident.getText() );
+ return createTreeNode( ident.getToken().getType(), quotedText );
+ }
+
+ /**
+ * A check to see if the text of the given node represents a known function name.
+ *
+ * @param ast The node whose text we want to check.
+ *
+ * @return True if the node's text is a known function name, false otherwise.
+ *
+ * @see org.hibernate.dialect.function.SQLFunctionRegistry
+ */
+ protected boolean isFunctionName(CommonToken token) {
+ return context.getSqlFunctionRegistry().hasFunction( token.getText() );
+ }
+
+ /**
+ * Process the given node as a function.
+ *
+ * @param The node representing the function invocation (including parameters as subtree components).
+ *
+ * @return The processed node.
+ */
+ protected CommonTree resolveFunction(CommonTree tree) {
+ // todo : handle sub functions?
+ Tree parameters = tree.getChild(0);
+ assert EXPR_LIST == parameters.getType();
+
+ final String functionName = tree.getText();
+ final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction( functionName );
+ if ( function == null ) {
+ String text = functionName;
+ if ( parameters.getChildCount() > 0 ) {
+ text+= '(';
+ for ( int i = 0, x = parameters.getChildCount(); i < x; i++ ) {
+ text+= parameters.getChild(i).getText();
+ if ( i < x ) {
+ text+= ", ";
+ }
+ }
+ text+= ')';
+ }
+ return createTreeNode( IDENT, text );
+ }
+ else {
+ ArrayList expressions = new ArrayList();
+ for ( int i = 0, x = parameters.getChildCount(); i < x; i++ ) {
+ expressions.add( parameters.getChild(i).getText() );
+ }
+ final String text = function.render( expressions, context.getSessionFactory() );
+ return createTreeNode( IDENT, text );
+ }
+ }
+
+ /**
+ * Process the given node as an IDENT. May represent either a column reference or a property reference.
+ *
+ * @param ident The node whose text represents either a column or property reference.
+ *
+ * @return The processed node.
+ */
+ protected CommonTree resolveIdent(CommonTree ident) {
+ String text = ident.getText();
+ String[] replacements;
+ try {
+ replacements = context.getColumnMapper().map( text );
+ }
+ catch( Throwable t ) {
+ replacements = null;
+ }
+
+ if ( replacements == null || replacements.length == 0 ) {
+ return createTreeNode( IDENT, Template.TEMPLATE + "." + text );
+ }
+ else if ( replacements.length == 1 ) {
+ return createTreeNode( IDENT, Template.TEMPLATE + "." + replacements[0] );
+ }
+ else {
+ final CommonTree root = createTreeNode( IDENT_LIST, "{ident list}" );
+ for ( int i = 0; i < replacements.length; i++ ) {
+ final String identText = Template.TEMPLATE + '.' + replacements[i];
+ root.addChild( createTreeNode( IDENT, identText ) );
+ }
+ return root;
+ }
+ }
+
+ private boolean validateIdentifierAsKeyword(String text) {
+ return validateLT( 1, text );
+ }
+
+ private boolean validateLT(int offset, String text) {
+ String text2Validate = retrieveLT( offset );
+ return text2Validate == null ? false : text2Validate.equalsIgnoreCase(text);
+ }
+
+ private String retrieveLT(int offset) {
+ if (null == input) {
+ return null;
+ }
+ Token token = input.LT(offset);
+ return token == null ? null : token.getText();
+ }
+
+ private CommonTree createTreeNode(int type, String text) {
+ return new CommonTree( CommonToken( type, text ) );
+ }
+}
+
+
+// Parser rules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+/**
+ * Main recognition rule for this grammar
+ */
+orderByFragment
+ : sortSpecification ( ',' sortSpecification )* -> ^( ORDER_BY sortSpecification+ )
+ ;
+
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>sort specification</tt>, which is essentially each thing upon which
+ * the results should be sorted.
+ */
+sortSpecification
+ : sortKey collationSpecification? orderingSpecification? -> ^( SORT_SPEC sortKey collationSpecification? orderingSpecification? )
+;
+
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>sort key</tt> which is the expression (column, function, etc) upon
+ * which to base the sorting.
+ */
+sortKey
+ : expression -> ^( SORT_KEY expression )
+;
+
+/**
+ * Reconition rule what this grammar recognizes as valid <tt>sort key</tt>.
+ */
+expression
+ : hardQuoteExpression
+ | ( IDENT ('.' IDENT)* OPEN_PAREN ) => functionCall
+ | simplePropertyPath
+ | i=IDENT -> {isFunctionName($i)}? { resolveFunction( i ) }
+ -> { resolveIdent( i ) }
+ ;
+
+hardQuoteExpression
+@after { $tree = quotedIdentifier( $tree ); }
+ : HARD_QUOTE IDENT HARD_QUOTE -> IDENT
+ ;
+
+/**
+ * Recognition rule for a function call
+ */
+functionCall
+@after { $tree = resolveFunction( $tree ); }
+ : functionName OPEN_PAREN functionParameterList CLOSE_PAREN -> ^( functionName functionParameterList )
+ ;
+
+/**
+ * A function-name is an IDENT followed by zero or more (DOT IDENT) sequences
+ */
+functionName returns [String nameText]
+ : i=IDENT { $nameText = $i.text; } ( '.' i=IDENT { $nameText += ( '.' + $i.text ); } )+
+ ;
+
+/**
+ * Recognition rule used to "wrap" all function parameters into an EXPR_LIST node
+ */
+functionParameterList
+ : functionParameter ( COMMA functionParameter )* -> ^( EXPR_LIST functionParameter+ )
+ ;
+
+
+/**
+ * Recognized function parameters.
+ */
+functionParameter :
+ expression
+ | numericLiteral
+ | qs=QUOTED_STRING -> { quotedString( $qs ) }
+;
+
+numericLiteral
+ : HEX_LITERAL
+ | OCTAL_LITERAL
+ | DECIMAL_LITERAL
+ | FLOATING_POINT_LITERAL
+ ;
+
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>collation specification</tt> used to allow specifying that sorting for
+ * the given {@link #sortSpecification} be treated within a specific character-set.
+ */
+collationSpecification! :
+ collateKeyword collationName -> { createTreeNode(COLLATE, $collationName.text) }
+;
+
+collateKeyword
+ : {(validateIdentifierAsKeyword("collate"))}?=> id=IDENT
+ -> COLLATE[$id]
+
+ ;
+
+/**
+ * The collation name wrt {@link #collationSpecification}. Namely, the character-set.
+ */
+collationName
+ : IDENT
+ ;
+
+/**
+ * Reconition rule for what ANSI SQL terms the <tt>ordering specification</tt>; <tt>ASCENDING</tt> or
+ * <tt>DESCENDING</tt>.
+ */
+orderingSpecification!
+ : ( 'asc' | 'ascending' ) -> { createTreeNode(ORDER_SPEC,"asc") }
+ | ( 'desc' | 'descending') -> { createTreeNode(ORDER_SPEC,"desc" ) }
+ ;
+
+/**
+ * A simple-property-path is an IDENT followed by one or more (DOT IDENT) sequences
+ */
+simplePropertyPath
+@after { $tree = resolveIdent($tree); }
+ : p=simplePropertyPathText -> { createTreeNode(IDENT, $p.pathText) }
+ ;
+
+simplePropertyPathText returns [String pathText]
+ : i=IDENT { $pathText = $i.text; } ( '.' i=IDENT { $pathText += ( '.' + $i.text ); } )+
+ ;
+
+
+
+// Lexer rules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+WS : (NEWLINE | SPACE | '\u000C') { $channel=HIDDEN; } ;
+
+fragment
+NEWLINE :
+ ( '\r' (options{greedy=true;}: '\n')? | '\n' )
+;
+
+fragment
+SPACE :
+ ' ' | '\t'
+;
+
+OPEN_PAREN : '(';
+CLOSE_PAREN : ')';
+
+COMMA : ',';
+
+HARD_QUOTE : '`';
+
+IDENT : ID ;
+
+fragment
+ID : ID_START_FRAGMENT ( ID_FRAGMENT )* ;
+
+fragment
+ID_START_FRAGMENT
+ : '_'
+ | '$'
+ | 'a'..'z'
+ | '\u0080'..'\ufffe'
+ ;
+
+fragment
+ID_FRAGMENT
+ : ID_START_FRAGMENT
+ | '0'..'9'
+ ;
+
+HEX_LITERAL : '0' ('x'|'X') ('0'..'9'|'a'..'f'|'A'..'F')+ INTEGRAL_TYPE_SUFFIX? ;
+
+OCTAL_LITERAL : '0' ('0'..'7')+ INTEGRAL_TYPE_SUFFIX? ;
+
+DECIMAL_LITERAL : ('0' | '1'..'9' '0'..'9'*) INTEGRAL_TYPE_SUFFIX? ;
+
+fragment
+INTEGRAL_TYPE_SUFFIX
+ : ('l'|'L')
+ ;
+
+FLOATING_POINT_LITERAL
+ : ('0'..'9')+ '.' ('0'..'9')* EXPONENT? FLOAT_TYPE_SUFFIX?
+ | '.' ('0'..'9')+ EXPONENT? FLOAT_TYPE_SUFFIX?
+ | ('0'..'9')+ EXPONENT FLOAT_TYPE_SUFFIX?
+ | ('0'..'9')+ FLOAT_TYPE_SUFFIX
+ ;
+
+fragment
+EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
+
+fragment
+FLOAT_TYPE_SUFFIX : ('f'|'F'|'d'|'D') ;
+
+QUOTED_STRING :
+ ('\'' (options{greedy=true;}: ~('\'' | '\r' | '\n') | '\'' '\'' | NEWLINE)* '\'' )+
+;
+
+/**
+ * Recognize either double-quote (") or back-tick (`) as delimiting a quoted identifier
+ */
+QUOTED_IDENT :
+ '"' (~('"' | '\r' | '\n') | '"' '"')+ '"'
+ | '`' (~('`' | '\r' | '\n') | '`' '`')+ '`'
+;
15 years, 7 months
Hibernate SVN: r16331 - validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2009-04-14 13:02:18 -0400 (Tue, 14 Apr 2009)
New Revision: 16331
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConfigurationImpl.java
Log:
Fixed problem when there is no validation.xml at all.
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConfigurationImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConfigurationImpl.java 2009-04-14 16:43:33 UTC (rev 16330)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ConfigurationImpl.java 2009-04-14 17:02:18 UTC (rev 16331)
@@ -199,19 +199,16 @@
}
ValidationConfigType config = getValidationConfig();
- if ( config == null ) {
- return;
- }
-
- // collect the paramters from the xml file
ParameterHolder xmlParameters = new ParameterHolder();
- setProviderClassFromXml( config, xmlParameters );
- setMessageInterpolatorFromXml( config, xmlParameters );
- setTraversableResolverFromXml( config, xmlParameters );
- setConstraintFactoryFromXml( config, xmlParameters );
- setMappingStreamsFromXml( config, xmlParameters );
- setPropertiesFromXml( config, xmlParameters );
-
+ if ( config != null ) {
+ // collect the paramters from the xml file
+ setProviderClassFromXml( config, xmlParameters );
+ setMessageInterpolatorFromXml( config, xmlParameters );
+ setTraversableResolverFromXml( config, xmlParameters );
+ setConstraintFactoryFromXml( config, xmlParameters );
+ setMappingStreamsFromXml( config, xmlParameters );
+ setPropertiesFromXml( config, xmlParameters );
+ }
applyXmlSettings( xmlParameters );
}
15 years, 7 months
Hibernate SVN: r16323 - core/branches/antlr3/src/main/antlr.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2009-04-14 12:41:44 -0400 (Tue, 14 Apr 2009)
New Revision: 16323
Removed:
core/branches/antlr3/src/main/antlr/hql.g
Log:
creating antlr3 branch
Deleted: core/branches/antlr3/src/main/antlr/hql.g
===================================================================
--- core/branches/antlr3/src/main/antlr/hql.g 2009-04-14 16:41:30 UTC (rev 16322)
+++ core/branches/antlr3/src/main/antlr/hql.g 2009-04-14 16:41:44 UTC (rev 16323)
@@ -1,883 +0,0 @@
-header
-{
-// $Id: hql.g 10163 2006-07-26 15:07:50Z steve.ebersole(a)jboss.com $
-
-package org.hibernate.hql.antlr;
-
-import org.hibernate.hql.ast.*;
-import org.hibernate.hql.ast.util.*;
-
-}
-/**
- * Hibernate Query Language Grammar
- * <br>
- * This grammar parses the query language for Hibernate (an Open Source, Object-Relational
- * mapping library). A partial BNF grammar description is available for reference here:
- * http://www.hibernate.org/Documentation/HQLBNF
- *
- * Text from the original reference BNF is prefixed with '//##'.
- * @author Joshua Davis (pgmjsd(a)sourceforge.net)
- */
-class HqlBaseParser extends Parser;
-
-options
-{
- exportVocab=Hql;
- buildAST=true;
- k=3; // For 'not like', 'not in', etc.
-}
-
-tokens
-{
- // -- HQL Keyword tokens --
- ALL="all";
- ANY="any";
- AND="and";
- AS="as";
- ASCENDING="asc";
- AVG="avg";
- BETWEEN="between";
- CLASS="class";
- COUNT="count";
- DELETE="delete";
- DESCENDING="desc";
- DOT;
- DISTINCT="distinct";
- ELEMENTS="elements";
- ESCAPE="escape";
- EXISTS="exists";
- FALSE="false";
- FETCH="fetch";
- FROM="from";
- FULL="full";
- GROUP="group";
- HAVING="having";
- IN="in";
- INDICES="indices";
- INNER="inner";
- INSERT="insert";
- INTO="into";
- IS="is";
- JOIN="join";
- LEFT="left";
- LIKE="like";
- MAX="max";
- MIN="min";
- NEW="new";
- NOT="not";
- NULL="null";
- OR="or";
- ORDER="order";
- OUTER="outer";
- PROPERTIES="properties";
- RIGHT="right";
- SELECT="select";
- SET="set";
- SOME="some";
- SUM="sum";
- TRUE="true";
- UNION="union";
- UPDATE="update";
- VERSIONED="versioned";
- WHERE="where";
-
- // -- SQL tokens --
- // These aren't part of HQL, but the SQL fragment parser uses the HQL lexer, so they need to be declared here.
- CASE="case";
- END="end";
- ELSE="else";
- THEN="then";
- WHEN="when";
- ON="on";
- WITH="with";
-
- // -- EJBQL tokens --
- BOTH="both";
- EMPTY="empty";
- LEADING="leading";
- MEMBER="member";
- OBJECT="object";
- OF="of";
- TRAILING="trailing";
-
- // -- Synthetic token types --
- AGGREGATE; // One of the aggregate functions (e.g. min, max, avg)
- ALIAS;
- CONSTRUCTOR;
- CASE2;
- EXPR_LIST;
- FILTER_ENTITY; // FROM element injected because of a filter expression (happens during compilation phase 2)
- IN_LIST;
- INDEX_OP;
- IS_NOT_NULL;
- IS_NULL; // Unary 'is null' operator.
- METHOD_CALL;
- NOT_BETWEEN;
- NOT_IN;
- NOT_LIKE;
- ORDER_ELEMENT;
- QUERY;
- RANGE;
- ROW_STAR;
- SELECT_FROM;
- UNARY_MINUS;
- UNARY_PLUS;
- VECTOR_EXPR; // ( x, y, z )
- WEIRD_IDENT; // Identifiers that were keywords when they came in.
-
- // Literal tokens.
- CONSTANT;
- NUM_DOUBLE;
- NUM_FLOAT;
- NUM_LONG;
- JAVA_CONSTANT;
-}
-
-{
- /** True if this is a filter query (allow no FROM clause). **/
- private boolean filter = false;
-
- /**
- * Sets the filter flag.
- * @param f True for a filter query, false for a normal query.
- */
- public void setFilter(boolean f) {
- filter = f;
- }
-
- /**
- * Returns true if this is a filter query, false if not.
- * @return true if this is a filter query, false if not.
- */
- public boolean isFilter() {
- return filter;
- }
-
- /**
- * This method is overriden in the sub class in order to provide the
- * 'keyword as identifier' hack.
- * @param token The token to retry as an identifier.
- * @param ex The exception to throw if it cannot be retried as an identifier.
- */
- public AST handleIdentifierError(Token token,RecognitionException ex) throws RecognitionException, TokenStreamException {
- // Base implementation: Just re-throw the exception.
- throw ex;
- }
-
- /**
- * This method looks ahead and converts . <token> into . IDENT when
- * appropriate.
- */
- public void handleDotIdent() throws TokenStreamException {
- }
-
- /**
- * Returns the negated equivalent of the expression.
- * @param x The expression to negate.
- */
- public AST negateNode(AST x) {
- // Just create a 'not' parent for the default behavior.
- return ASTUtil.createParent(astFactory, NOT, "not", x);
- }
-
- /**
- * Returns the 'cleaned up' version of a comparison operator sub-tree.
- * @param x The comparison operator to clean up.
- */
- public AST processEqualityExpression(AST x) throws RecognitionException {
- return x;
- }
-
- public void weakKeywords() throws TokenStreamException { }
-
- public void processMemberOf(Token n,AST p,ASTPair currentAST) { }
-
-}
-
-statement
- : ( updateStatement | deleteStatement | selectStatement | insertStatement )
- ;
-
-updateStatement
- : UPDATE^ (VERSIONED)?
- optionalFromTokenFromClause
- setClause
- (whereClause)?
- ;
-
-setClause
- : (SET^ assignment (COMMA! assignment)*)
- ;
-
-assignment
- : stateField EQ^ newValue
- ;
-
-// "state_field" is the term used in the EJB3 sample grammar; used here for easy reference.
-// it is basically a property ref
-stateField
- : path
- ;
-
-// this still needs to be defined in the ejb3 spec; additiveExpression is currently just a best guess,
-// although it is highly likely I would think that the spec may limit this even more tightly.
-newValue
- : concatenation
- ;
-
-deleteStatement
- : DELETE^
- (optionalFromTokenFromClause)
- (whereClause)?
- ;
-
-optionalFromTokenFromClause!
- : (FROM!)? f:path (a:asAlias)? {
- AST #range = #([RANGE, "RANGE"], #f, #a);
- #optionalFromTokenFromClause = #([FROM, "FROM"], #range);
- }
- ;
-
-selectStatement
- : queryRule {
- #selectStatement = #([QUERY,"query"], #selectStatement);
- }
- ;
-
-insertStatement
- // Would be nice if we could abstract the FromClause/FromElement logic
- // out such that it could be reused here; something analogous to
- // a "table" rule in sql-grammars
- : INSERT^ intoClause selectStatement
- ;
-
-intoClause
- : INTO^ path { weakKeywords(); } insertablePropertySpec
- ;
-
-insertablePropertySpec
- : OPEN! primaryExpression ( COMMA! primaryExpression )* CLOSE! {
- // Just need *something* to distinguish this on the hql-sql.g side
- #insertablePropertySpec = #([RANGE, "column-spec"], #insertablePropertySpec);
- }
- ;
-
-union
- : queryRule (UNION queryRule)*
- ;
-
-//## query:
-//## [selectClause] fromClause [whereClause] [groupByClause] [havingClause] [orderByClause];
-
-queryRule
- : selectFrom
- (whereClause)?
- (groupByClause)?
- (orderByClause)?
- ;
-
-selectFrom!
- : (s:selectClause)? (f:fromClause)? {
- // If there was no FROM clause and this is a filter query, create a from clause. Otherwise, throw
- // an exception because non-filter queries must have a FROM clause.
- if (#f == null) {
- if (filter) {
- #f = #([FROM,"{filter-implied FROM}"]);
- }
- else
- throw new SemanticException("FROM expected (non-filter queries must contain a FROM clause)");
- }
-
- // Create an artificial token so the 'FROM' can be placed
- // before the SELECT in the tree to make tree processing
- // simpler.
- #selectFrom = #([SELECT_FROM,"SELECT_FROM"],f,s);
- }
- ;
-
-//## selectClause:
-//## SELECT DISTINCT? selectedPropertiesList | ( NEW className OPEN selectedPropertiesList CLOSE );
-
-selectClause
- : SELECT^ // NOTE: The '^' after a token causes the corresponding AST node to be the root of the sub-tree.
- { weakKeywords(); } // Weak keywords can appear immediately after a SELECT token.
- (DISTINCT)? ( selectedPropertiesList | newExpression | selectObject )
- ;
-
-newExpression
- : (NEW! path) op:OPEN^ {#op.setType(CONSTRUCTOR);} selectedPropertiesList CLOSE!
- ;
-
-selectObject
- : OBJECT^ OPEN! identifier CLOSE!
- ;
-
-//## fromClause:
-//## FROM className AS? identifier ( ( COMMA className AS? identifier ) | ( joinType path AS? identifier ) )*;
-
-// NOTE: This *must* begin with the "FROM" token, otherwise the sub-query rule will be ambiguous
-// with the expression rule.
-// Also note: after a comma weak keywords are allowed and should be treated as identifiers.
-
-fromClause
- : FROM^ { weakKeywords(); } fromRange ( fromJoin | COMMA! { weakKeywords(); } fromRange )*
- ;
-
-//## joinType:
-//## ( ( 'left'|'right' 'outer'? ) | 'full' | 'inner' )? JOIN FETCH?;
-
-fromJoin
- : ( ( ( LEFT | RIGHT ) (OUTER)? ) | FULL | INNER )? JOIN^ (FETCH)?
- path (asAlias)? (propertyFetch)? (withClause)?
- ;
-
-withClause
- : WITH^ logicalExpression
- ;
-
-fromRange
- : fromClassOrOuterQueryPath
- | inClassDeclaration
- | inCollectionDeclaration
- | inCollectionElementsDeclaration
- ;
-
-fromClassOrOuterQueryPath!
- : c:path { weakKeywords(); } (a:asAlias)? (p:propertyFetch)? {
- #fromClassOrOuterQueryPath = #([RANGE, "RANGE"], #c, #a, #p);
- }
- ;
-
-inClassDeclaration!
- : a:alias IN! CLASS! c:path {
- #inClassDeclaration = #([RANGE, "RANGE"], #c, #a);
- }
- ;
-
-inCollectionDeclaration!
- : IN! OPEN! p:path CLOSE! a:alias {
- #inCollectionDeclaration = #([JOIN, "join"], [INNER, "inner"], #p, #a);
- }
- ;
-
-inCollectionElementsDeclaration!
- : a:alias IN! ELEMENTS! OPEN! p:path CLOSE! {
- #inCollectionElementsDeclaration = #([JOIN, "join"], [INNER, "inner"], #p, #a);
- }
- ;
-
-// Alias rule - Parses the optional 'as' token and forces an AST identifier node.
-asAlias
- : (AS!)? alias
- ;
-
-alias
- : a:identifier { #a.setType(ALIAS); }
- ;
-
-propertyFetch
- : FETCH ALL! PROPERTIES!
- ;
-
-//## groupByClause:
-//## GROUP_BY path ( COMMA path )*;
-
-groupByClause
- : GROUP^
- "by"! expression ( COMMA! expression )*
- (havingClause)?
- ;
-
-//## orderByClause:
-//## ORDER_BY selectedPropertiesList;
-
-orderByClause
- : ORDER^ "by"! orderElement ( COMMA! orderElement )*
- ;
-
-orderElement
- : expression ( ascendingOrDescending )?
- ;
-
-ascendingOrDescending
- : ( "asc" | "ascending" ) { #ascendingOrDescending.setType(ASCENDING); }
- | ( "desc" | "descending") { #ascendingOrDescending.setType(DESCENDING); }
- ;
-
-//## havingClause:
-//## HAVING logicalExpression;
-
-havingClause
- : HAVING^ logicalExpression
- ;
-
-//## whereClause:
-//## WHERE logicalExpression;
-
-whereClause
- : WHERE^ logicalExpression
- ;
-
-//## selectedPropertiesList:
-//## ( path | aggregate ) ( COMMA path | aggregate )*;
-
-selectedPropertiesList
- : aliasedExpression ( COMMA! aliasedExpression )*
- ;
-
-aliasedExpression
- : expression ( AS^ identifier )?
- ;
-
-// expressions
-// Note that most of these expressions follow the pattern
-// thisLevelExpression :
-// nextHigherPrecedenceExpression
-// (OPERATOR nextHigherPrecedenceExpression)*
-// which is a standard recursive definition for a parsing an expression.
-//
-// Operator precedence in HQL
-// lowest --> ( 7) OR
-// ( 6) AND, NOT
-// ( 5) equality: ==, <>, !=, is
-// ( 4) relational: <, <=, >, >=,
-// LIKE, NOT LIKE, BETWEEN, NOT BETWEEN, IN, NOT IN
-// ( 3) addition and subtraction: +(binary) -(binary)
-// ( 2) multiplication: * / %, concatenate: ||
-// highest --> ( 1) +(unary) -(unary)
-// [] () (method call) . (dot -- identifier qualification)
-// aggregate function
-// () (explicit parenthesis)
-//
-// Note that the above precedence levels map to the rules below...
-// Once you have a precedence chart, writing the appropriate rules as below
-// is usually very straightfoward
-
-logicalExpression
- : expression
- ;
-
-// Main expression rule
-expression
- : logicalOrExpression
- ;
-
-// level 7 - OR
-logicalOrExpression
- : logicalAndExpression ( OR^ logicalAndExpression )*
- ;
-
-// level 6 - AND, NOT
-logicalAndExpression
- : negatedExpression ( AND^ negatedExpression )*
- ;
-
-// NOT nodes aren't generated. Instead, the operator in the sub-tree will be
-// negated, if possible. Expressions without a NOT parent are passed through.
-negatedExpression!
-{ weakKeywords(); } // Weak keywords can appear in an expression, so look ahead.
- : NOT^ x:negatedExpression { #negatedExpression = negateNode(#x); }
- | y:equalityExpression { #negatedExpression = #y; }
- ;
-
-//## OP: EQ | LT | GT | LE | GE | NE | SQL_NE | LIKE;
-
-// level 5 - EQ, NE
-equalityExpression
- : x:relationalExpression (
- ( EQ^
- | is:IS^ { #is.setType(EQ); } (NOT! { #is.setType(NE); } )?
- | NE^
- | ne:SQL_NE^ { #ne.setType(NE); }
- ) y:relationalExpression)* {
- // Post process the equality expression to clean up 'is null', etc.
- #equalityExpression = processEqualityExpression(#equalityExpression);
- }
- ;
-
-// level 4 - LT, GT, LE, GE, LIKE, NOT LIKE, BETWEEN, NOT BETWEEN
-// NOTE: The NOT prefix for LIKE and BETWEEN will be represented in the
-// token type. When traversing the AST, use the token type, and not the
-// token text to interpret the semantics of these nodes.
-relationalExpression
- : concatenation (
- ( ( ( LT^ | GT^ | LE^ | GE^ ) additiveExpression )* )
- // Disable node production for the optional 'not'.
- | (n:NOT!)? (
- // Represent the optional NOT prefix using the token type by
- // testing 'n' and setting the token type accordingly.
- (i:IN^ {
- #i.setType( (n == null) ? IN : NOT_IN);
- #i.setText( (n == null) ? "in" : "not in");
- }
- inList)
- | (b:BETWEEN^ {
- #b.setType( (n == null) ? BETWEEN : NOT_BETWEEN);
- #b.setText( (n == null) ? "between" : "not between");
- }
- betweenList )
- | (l:LIKE^ {
- #l.setType( (n == null) ? LIKE : NOT_LIKE);
- #l.setText( (n == null) ? "like" : "not like");
- }
- concatenation likeEscape)
- | (MEMBER! (OF!)? p:path! {
- processMemberOf(n,#p,currentAST);
- } ) )
- )
- ;
-
-likeEscape
- : (ESCAPE^ concatenation)?
- ;
-
-inList
- : x:compoundExpr
- { #inList = #([IN_LIST,"inList"], #inList); }
- ;
-
-betweenList
- : concatenation AND! concatenation
- ;
-
-//level 4 - string concatenation
-concatenation
- : additiveExpression
- ( c:CONCAT^ { #c.setType(EXPR_LIST); #c.setText("concatList"); }
- additiveExpression
- ( CONCAT! additiveExpression )*
- { #concatenation = #([METHOD_CALL, "||"], #([IDENT, "concat"]), #c ); } )?
- ;
-
-// level 3 - binary plus and minus
-additiveExpression
- : multiplyExpression ( ( PLUS^ | MINUS^ ) multiplyExpression )*
- ;
-
-// level 2 - binary multiply and divide
-multiplyExpression
- : unaryExpression ( ( STAR^ | DIV^ ) unaryExpression )*
- ;
-
-// level 1 - unary minus, unary plus, not
-unaryExpression
- : MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
- | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
- | caseExpression
- | quantifiedExpression
- | atom
- ;
-
-caseExpression
- : CASE^ (whenClause)+ (elseClause)? END!
- | CASE^ { #CASE.setType(CASE2); } unaryExpression (altWhenClause)+ (elseClause)? END!
- ;
-
-whenClause
- : (WHEN^ logicalExpression THEN! unaryExpression)
- ;
-
-altWhenClause
- : (WHEN^ unaryExpression THEN! unaryExpression)
- ;
-
-elseClause
- : (ELSE^ unaryExpression)
- ;
-
-quantifiedExpression
- : ( SOME^ | EXISTS^ | ALL^ | ANY^ )
- ( identifier | collectionExpr | (OPEN! ( subQuery ) CLOSE!) )
- ;
-
-// level 0 - expression atom
-// ident qualifier ('.' ident ), array index ( [ expr ] ),
-// method call ( '.' ident '(' exprList ') )
-atom
- : primaryExpression
- (
- DOT^ identifier
- ( options { greedy=true; } :
- ( op:OPEN^ {#op.setType(METHOD_CALL);} exprList CLOSE! ) )?
- | lb:OPEN_BRACKET^ {#lb.setType(INDEX_OP);} expression CLOSE_BRACKET!
- )*
- ;
-
-// level 0 - the basic element of an expression
-primaryExpression
- : identPrimary ( options {greedy=true;} : DOT^ "class" )?
- | constant
- | COLON^ identifier
- // TODO: Add parens to the tree so the user can control the operator evaluation order.
- | OPEN! (expressionOrVector | subQuery) CLOSE!
- | PARAM^ (NUM_INT)?
- ;
-
-// This parses normal expression and a list of expressions separated by commas. If a comma is encountered
-// a parent VECTOR_EXPR node will be created for the list.
-expressionOrVector!
- : e:expression ( v:vectorExpr )? {
- // If this is a vector expression, create a parent node for it.
- if (#v != null)
- #expressionOrVector = #([VECTOR_EXPR,"{vector}"], #e, #v);
- else
- #expressionOrVector = #e;
- }
- ;
-
-vectorExpr
- : COMMA! expression (COMMA! expression)*
- ;
-
-// identifier, followed by member refs (dot ident), or method calls.
-// NOTE: handleDotIdent() is called immediately after the first IDENT is recognized because
-// the method looks a head to find keywords after DOT and turns them into identifiers.
-identPrimary
- : identifier { handleDotIdent(); }
- ( options { greedy=true; } : DOT^ ( identifier | ELEMENTS | o:OBJECT { #o.setType(IDENT); } ) )*
- ( options { greedy=true; } :
- ( op:OPEN^ { #op.setType(METHOD_CALL);} exprList CLOSE! )
- )?
- // Also allow special 'aggregate functions' such as count(), avg(), etc.
- | aggregate
- ;
-
-//## aggregate:
-//## ( aggregateFunction OPEN path CLOSE ) | ( COUNT OPEN STAR CLOSE ) | ( COUNT OPEN (DISTINCT | ALL) path CLOSE );
-
-//## aggregateFunction:
-//## COUNT | 'sum' | 'avg' | 'max' | 'min';
-
-aggregate
- : ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! additiveExpression CLOSE! { #aggregate.setType(AGGREGATE); }
- // Special case for count - It's 'parameters' can be keywords.
- | COUNT^ OPEN! ( STAR { #STAR.setType(ROW_STAR); } | ( ( DISTINCT | ALL )? ( path | collectionExpr ) ) ) CLOSE!
- | collectionExpr
- ;
-
-//## collection: ( OPEN query CLOSE ) | ( 'elements'|'indices' OPEN path CLOSE );
-
-collectionExpr
- : (ELEMENTS^ | INDICES^) OPEN! path CLOSE!
- ;
-
-// NOTE: compoundExpr can be a 'path' where the last token in the path is '.elements' or '.indicies'
-compoundExpr
- : collectionExpr
- | path
- | (OPEN! ( (expression (COMMA! expression)*) | subQuery ) CLOSE!)
- ;
-
-subQuery
- : union
- { #subQuery = #([QUERY,"query"], #subQuery); }
- ;
-
-exprList
-{
- AST trimSpec = null;
-}
- : (t:TRAILING {#trimSpec = #t;} | l:LEADING {#trimSpec = #l;} | b:BOTH {#trimSpec = #b;})?
- { if(#trimSpec != null) #trimSpec.setType(IDENT); }
- (
- expression ( (COMMA! expression)+ | FROM { #FROM.setType(IDENT); } expression | AS! identifier )?
- | FROM { #FROM.setType(IDENT); } expression
- )?
- { #exprList = #([EXPR_LIST,"exprList"], #exprList); }
- ;
-
-constant
- : NUM_INT
- | NUM_FLOAT
- | NUM_LONG
- | NUM_DOUBLE
- | QUOTED_STRING
- | NULL
- | TRUE
- | FALSE
- | EMPTY
- ;
-
-//## quantifiedExpression: 'exists' | ( expression 'in' ) | ( expression OP 'any' | 'some' ) collection;
-
-//## compoundPath: path ( OPEN_BRACKET expression CLOSE_BRACKET ( '.' path )? )*;
-
-//## path: identifier ( '.' identifier )*;
-
-path
- : identifier ( DOT^ { weakKeywords(); } identifier )*
- ;
-
-// Wraps the IDENT token from the lexer, in order to provide
-// 'keyword as identifier' trickery.
-identifier
- : IDENT
- exception
- catch [RecognitionException ex]
- {
- identifier_AST = handleIdentifierError(LT(1),ex);
- }
- ;
-
-// **** LEXER ******************************************************************
-
-/**
- * Hibernate Query Language Lexer
- * <br>
- * This lexer provides the HQL parser with tokens.
- * @author Joshua Davis (pgmjsd(a)sourceforge.net)
- */
-class HqlBaseLexer extends Lexer;
-
-options {
- exportVocab=Hql; // call the vocabulary "Hql"
- testLiterals = false;
- k=2; // needed for newline, and to distinguish '>' from '>='.
- // HHH-241 : Quoted strings don't allow unicode chars - This should fix it.
- charVocabulary='\u0000'..'\uFFFE'; // Allow any char but \uFFFF (16 bit -1, ANTLR's EOF character)
- caseSensitive = false;
- caseSensitiveLiterals = false;
-}
-
-// -- Declarations --
-{
- // NOTE: The real implementations are in the subclass.
- protected void setPossibleID(boolean possibleID) {}
-}
-
-// -- Keywords --
-
-EQ: '=';
-LT: '<';
-GT: '>';
-SQL_NE: "<>";
-NE: "!=" | "^=";
-LE: "<=";
-GE: ">=";
-
-COMMA: ',';
-
-OPEN: '(';
-CLOSE: ')';
-OPEN_BRACKET: '[';
-CLOSE_BRACKET: ']';
-
-CONCAT: "||";
-PLUS: '+';
-MINUS: '-';
-STAR: '*';
-DIV: '/';
-COLON: ':';
-PARAM: '?';
-
-IDENT options { testLiterals=true; }
- : ID_START_LETTER ( ID_LETTER )*
- {
- // Setting this flag allows the grammar to use keywords as identifiers, if necessary.
- setPossibleID(true);
- }
- ;
-
-protected
-ID_START_LETTER
- : '_'
- | '$'
- | 'a'..'z'
- | '\u0080'..'\ufffe' // HHH-558 : Allow unicode chars in identifiers
- ;
-
-protected
-ID_LETTER
- : ID_START_LETTER
- | '0'..'9'
- ;
-
-QUOTED_STRING
- : '\'' ( (ESCqs)=> ESCqs | ~'\'' )* '\''
- ;
-
-protected
-ESCqs
- :
- '\'' '\''
- ;
-
-WS : ( ' '
- | '\t'
- | '\r' '\n' { newline(); }
- | '\n' { newline(); }
- | '\r' { newline(); }
- )
- {$setType(Token.SKIP);} //ignore this token
- ;
-
-//--- From the Java example grammar ---
-// a numeric literal
-NUM_INT
- {boolean isDecimal=false; Token t=null;}
- : '.' {_ttype = DOT;}
- ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
- {
- if (t != null && t.getText().toUpperCase().indexOf('F')>=0)
- {
- _ttype = NUM_FLOAT;
- }
- else
- {
- _ttype = NUM_DOUBLE; // assume double
- }
- }
- )?
- | ( '0' {isDecimal = true;} // special case for just '0'
- ( ('x')
- ( // hex
- // the 'e'|'E' and float suffix stuff look
- // like hex digits, hence the (...)+ doesn't
- // know when to stop: ambig. ANTLR resolves
- // it correctly by matching immediately. It
- // is therefore ok to hush warning.
- options { warnWhenFollowAmbig=false; }
- : HEX_DIGIT
- )+
- | ('0'..'7')+ // octal
- )?
- | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
- )
- ( ('l') { _ttype = NUM_LONG; }
-
- // only check to see if it's a float if looks like decimal so far
- | {isDecimal}?
- ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
- | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
- | f4:FLOAT_SUFFIX {t=f4;}
- )
- {
- if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0)
- {
- _ttype = NUM_FLOAT;
- }
- else
- {
- _ttype = NUM_DOUBLE; // assume double
- }
- }
- )?
- ;
-
-// hexadecimal digit (again, note it's protected!)
-protected
-HEX_DIGIT
- : ('0'..'9'|'a'..'f')
- ;
-
-// a couple protected methods to assist in matching floating point numbers
-protected
-EXPONENT
- : ('e') ('+'|'-')? ('0'..'9')+
- ;
-
-protected
-FLOAT_SUFFIX
- : 'f'|'d'
- ;
-
15 years, 7 months