/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.hql.internal.ast;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.hibernate.QueryException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.internal.JoinSequence;
import org.hibernate.engine.internal.ParameterBinder;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.CollectionProperties;
import org.hibernate.hql.internal.antlr.HqlSqlBaseWalker;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.hql.internal.ast.tree.AggregateNode;
import org.hibernate.hql.internal.ast.tree.AssignmentSpecification;
import org.hibernate.hql.internal.ast.tree.CastFunctionNode;
import org.hibernate.hql.internal.ast.tree.CollectionFunction;
import org.hibernate.hql.internal.ast.tree.ConstructorNode;
import org.hibernate.hql.internal.ast.tree.DeleteStatement;
import org.hibernate.hql.internal.ast.tree.DotNode;
import org.hibernate.hql.internal.ast.tree.EntityJoinFromElement;
import org.hibernate.hql.internal.ast.tree.FromClause;
import org.hibernate.hql.internal.ast.tree.FromElement;
import org.hibernate.hql.internal.ast.tree.FromElementFactory;
import org.hibernate.hql.internal.ast.tree.FromReferenceNode;
import org.hibernate.hql.internal.ast.tree.IdentNode;
import org.hibernate.hql.internal.ast.tree.IndexNode;
import org.hibernate.hql.internal.ast.tree.InsertStatement;
import org.hibernate.hql.internal.ast.tree.IntoClause;
import org.hibernate.hql.internal.ast.tree.MethodNode;
import org.hibernate.hql.internal.ast.tree.OperatorNode;
import org.hibernate.hql.internal.ast.tree.ParameterContainer;
import org.hibernate.hql.internal.ast.tree.ParameterNode;
import org.hibernate.hql.internal.ast.tree.QueryNode;
import org.hibernate.hql.internal.ast.tree.ResolvableNode;
import org.hibernate.hql.internal.ast.tree.RestrictableStatement;
import org.hibernate.hql.internal.ast.tree.ResultVariableRefNode;
import org.hibernate.hql.internal.ast.tree.SelectClause;
import org.hibernate.hql.internal.ast.tree.SelectExpression;
import org.hibernate.hql.internal.ast.tree.UpdateStatement;
import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.ASTUtil;
import org.hibernate.hql.internal.ast.util.AliasGenerator;
import org.hibernate.hql.internal.ast.util.JoinProcessor;
import org.hibernate.hql.internal.ast.util.LiteralProcessor;
import org.hibernate.hql.internal.ast.util.NodeTraverser;
import org.hibernate.hql.internal.ast.util.SessionFactoryHelper;
import org.hibernate.hql.internal.ast.util.SyntheticAndFactory;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.hql.spi.QueryTranslator;
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
import org.hibernate.param.NamedParameterSpecification;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.param.PositionalParameterSpecification;
import org.hibernate.param.VersionTypeSeedParameterSpecification;
import org.hibernate.persister.collection.CollectionPropertyNames;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.DbTimestampType;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
import org.hibernate.usertype.UserVersionType;

import antlr.ASTFactory;
import antlr.RecognitionException;
import antlr.SemanticException;
import antlr.collections.AST;

import static org.hibernate.hql.spi.QueryTranslator.ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED;

Implements methods used by the HQL->SQL tree transform grammar (a.k.a. the second phase).
  • Isolates the Hibernate API-specific code from the ANTLR generated code.
  • Handles the SQL fragments generated by the persisters in order to create the SELECT and FROM clauses, taking into account the joins and projections that are implied by the mappings (persister/queryable).
  • Uses SqlASTFactory to create customized AST nodes.
See Also:
  • SqlASTFactory
/** * Implements methods used by the HQL->SQL tree transform grammar (a.k.a. the second phase). * <ul> * <li>Isolates the Hibernate API-specific code from the ANTLR generated code.</li> * <li>Handles the SQL fragments generated by the persisters in order to create the SELECT and FROM clauses, * taking into account the joins and projections that are implied by the mappings (persister/queryable).</li> * <li>Uses SqlASTFactory to create customized AST nodes.</li> * </ul> * * @see SqlASTFactory */
public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, ParameterBinder.NamedParameterSource { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( HqlSqlWalker.class ); private final QueryTranslatorImpl queryTranslatorImpl; private final HqlParser hqlParser; private final SessionFactoryHelper sessionFactoryHelper; private final Map tokenReplacements; private final AliasGenerator aliasGenerator = new AliasGenerator(); private final LiteralProcessor literalProcessor; private final ParseErrorHandler parseErrorHandler; private final String collectionFilterRole; private FromClause currentFromClause; private SelectClause selectClause;
Maps each top-level result variable to its SelectExpression; (excludes result variables defined in subqueries)
/** * Maps each top-level result variable to its SelectExpression; * (excludes result variables defined in subqueries) */
private Map<String, SelectExpression> selectExpressionsByResultVariable = new HashMap<>(); private Set<Serializable> querySpaces = new HashSet<>(); private int parameterCount; private Map namedParameters; private Map positionalParameters; private ArrayList<ParameterSpecification> parameterSpecs = new ArrayList<>(); private int numberOfParametersInSetClause; private ArrayList assignmentSpecifications = new ArrayList(); private JoinType impliedJoinType = JoinType.INNER_JOIN; private boolean inEntityGraph;
Create a new tree transformer.
Params:
  • qti – Back pointer to the query translator implementation that is using this tree transform.
  • sfi – The session factory implementor where the Hibernate mappings can be found.
  • parser – A reference to the phase-1 parser
  • tokenReplacements – Registers the token replacement map with the walker. This map will be used to substitute function names and constants.
  • collectionRole – The collection role name of the collection used as the basis for the filter, NULL if this is not a collection filter compilation.
/** * Create a new tree transformer. * * @param qti Back pointer to the query translator implementation that is using this tree transform. * @param sfi The session factory implementor where the Hibernate mappings can be found. * @param parser A reference to the phase-1 parser * @param tokenReplacements Registers the token replacement map with the walker. This map will * be used to substitute function names and constants. * @param collectionRole The collection role name of the collection used as the basis for the * filter, NULL if this is not a collection filter compilation. */
public HqlSqlWalker( QueryTranslatorImpl qti, SessionFactoryImplementor sfi, HqlParser parser, Map tokenReplacements, String collectionRole) { setASTFactory( new SqlASTFactory( this ) ); // Initialize the error handling delegate. this.parseErrorHandler = new ErrorTracker( qti.getQueryString() ); this.queryTranslatorImpl = qti; this.sessionFactoryHelper = new SessionFactoryHelper( sfi ); this.literalProcessor = new LiteralProcessor( this ); this.tokenReplacements = tokenReplacements; this.collectionFilterRole = collectionRole; this.hqlParser = parser; } // handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private int traceDepth; @Override public void traceIn(String ruleName, AST tree) { if ( !LOG.isTraceEnabled() ) { return; } if ( inputState.guessing > 0 ) { return; } String prefix = StringHelper.repeat( '-', ( traceDepth++ * 2 ) ) + "-> "; String traceText = ruleName + " (" + buildTraceNodeName( tree ) + ")"; LOG.trace( prefix + traceText ); } private String buildTraceNodeName(AST tree) { return tree == null ? "???" : tree.getText() + " [" + TokenPrinters.SQL_TOKEN_PRINTER.getTokenTypeName( tree.getType() ) + "]"; } @Override public void traceOut(String ruleName, AST tree) { if ( !LOG.isTraceEnabled() ) { return; } if ( inputState.guessing > 0 ) { return; } String prefix = "<-" + StringHelper.repeat( '-', ( --traceDepth * 2 ) ) + " "; LOG.trace( prefix + ruleName ); } @Override protected void prepareFromClauseInputTree(AST fromClauseInput) { if ( !isSubQuery() ) { // // inject param specifications to account for dynamic filter param values // if ( ! getEnabledFilters().isEmpty() ) { // Iterator filterItr = getEnabledFilters().values().iterator(); // while ( filterItr.hasNext() ) { // FilterImpl filter = ( FilterImpl ) filterItr.next(); // if ( ! filter.getFilterDefinition().getParameterNames().isEmpty() ) { // Iterator paramItr = filter.getFilterDefinition().getParameterNames().iterator(); // while ( paramItr.hasNext() ) { // String parameterName = ( String ) paramItr.next(); // // currently param filters *only* work with single-column parameter types; // // if that limitation is ever lifted, this logic will need to change to account for that // ParameterNode collectionFilterKeyParameter = ( ParameterNode ) astFactory.create( PARAM, "?" ); // DynamicFilterParameterSpecification paramSpec = new DynamicFilterParameterSpecification( // filter.getName(), // parameterName, // filter.getFilterDefinition().getParameterType( parameterName ), // positionalParameterCount++ // ); // collectionFilterKeyParameter.setHqlParameterSpecification( paramSpec ); // parameterSpecs.add( paramSpec ); // } // } // } // } if ( isFilter() ) { // Handle collection-filter compilation. // IMPORTANT NOTE: This is modifying the INPUT (HQL) tree, not the output tree! QueryableCollection persister = sessionFactoryHelper.getCollectionPersister( collectionFilterRole ); Type collectionElementType = persister.getElementType(); if ( !collectionElementType.isEntityType() ) { throw new QueryException( "collection of values in filter: this" ); } String collectionElementEntityName = persister.getElementPersister().getEntityName(); ASTFactory inputAstFactory = hqlParser.getASTFactory(); AST fromElement = inputAstFactory.create( HqlTokenTypes.FILTER_ENTITY, collectionElementEntityName ); ASTUtil.createSibling( inputAstFactory, HqlTokenTypes.ALIAS, "this", fromElement ); fromClauseInput.addChild( fromElement ); // Show the modified AST. LOG.debug( "prepareFromClauseInputTree() : Filter - Added 'this' as a from element..." ); queryTranslatorImpl.showHqlAst( hqlParser.getAST() ); // Create a parameter specification for the collection filter... final Type collectionFilterKeyType = sessionFactoryHelper.requireQueryableCollection( collectionFilterRole ) .getKeyType(); final ParameterNode collectionFilterKeyParameter = (ParameterNode) astFactory.create( PARAM, "?" ); final CollectionFilterKeyParameterSpecification collectionFilterKeyParameterSpec = new CollectionFilterKeyParameterSpecification( collectionFilterRole, collectionFilterKeyType ); parameterCount++; collectionFilterKeyParameter.setHqlParameterSpecification( collectionFilterKeyParameterSpec ); parameterSpecs.add( collectionFilterKeyParameterSpec ); } } } public boolean isFilter() { return collectionFilterRole != null; } public String getCollectionFilterRole() { return collectionFilterRole; } public boolean isInEntityGraph() { return inEntityGraph; } public SessionFactoryHelper getSessionFactoryHelper() { return sessionFactoryHelper; } public Map getTokenReplacements() { return tokenReplacements; } public AliasGenerator getAliasGenerator() { return aliasGenerator; } public FromClause getCurrentFromClause() { return currentFromClause; } public ParseErrorHandler getParseErrorHandler() { return parseErrorHandler; } @Override public void reportError(RecognitionException e) { parseErrorHandler.reportError( e ); // Use the delegate. } @Override public void reportError(String s) { parseErrorHandler.reportError( s ); // Use the delegate. } @Override public void reportWarning(String s) { parseErrorHandler.reportWarning( s ); }
Returns the set of unique query spaces (a.k.a. table names) that occurred in the query.
Returns:A set of table names (Strings).
/** * Returns the set of unique query spaces (a.k.a. * table names) that occurred in the query. * * @return A set of table names (Strings). */
public Set<Serializable> getQuerySpaces() { return querySpaces; } @Override protected AST createFromElement(String path, AST alias, AST propertyFetch) throws SemanticException { FromElement fromElement = currentFromClause.addFromElement( path, alias ); fromElement.setAllPropertyFetch( propertyFetch != null ); return fromElement; } @Override protected AST createFromFilterElement(AST filterEntity, AST alias) throws SemanticException { FromElement fromElement = currentFromClause.addFromElement( filterEntity.getText(), alias ); FromClause fromClause = fromElement.getFromClause(); QueryableCollection persister = sessionFactoryHelper.getCollectionPersister( collectionFilterRole ); // Get the names of the columns used to link between the collection // owner and the collection elements. String[] keyColumnNames = persister.getKeyColumnNames(); String fkTableAlias = persister.isOneToMany() ? fromElement.getTableAlias() : fromClause.getAliasGenerator().createName( collectionFilterRole ); JoinSequence join = sessionFactoryHelper.createJoinSequence(); join.setRoot( persister, fkTableAlias ); if ( !persister.isOneToMany() ) { join.addJoin( (AssociationType) persister.getElementType(), fromElement.getTableAlias(), JoinType.INNER_JOIN, persister.getElementColumnNames( fkTableAlias ) ); } join.addCondition( fkTableAlias, keyColumnNames, " = ?" ); fromElement.setJoinSequence( join ); fromElement.setFilter( true ); LOG.debug( "createFromFilterElement() : processed filter FROM element." ); return fromElement; } @Override protected void createFromJoinElement( AST path, AST alias, int joinType, AST fetchNode, AST propertyFetch, AST with) throws SemanticException { boolean fetch = fetchNode != null; if ( fetch && isSubQuery() ) { throw new QueryException( "fetch not allowed in subquery from-elements" ); } // the incoming "path" can be either: // 1) an implicit join path (join p.address.city) // 2) an entity-join (join com.acme.User) // // so make the proper interpretation here... final EntityPersister entityJoinReferencedPersister = resolveEntityJoinReferencedPersister( path ); if ( entityJoinReferencedPersister != null ) { // `path` referenced an entity final EntityJoinFromElement join = createEntityJoin( entityJoinReferencedPersister, alias, joinType, propertyFetch, with ); ( (FromReferenceNode) path ).setFromElement( join ); } else { if ( path.getType() != SqlTokenTypes.DOT ) { throw new SemanticException( "Path expected for join!" ); } DotNode dot = (DotNode) path; JoinType hibernateJoinType = JoinProcessor.toHibernateJoinType( joinType ); dot.setJoinType( hibernateJoinType ); // Tell the dot node about the join type. dot.setFetch( fetch ); // Generate an explicit join for the root dot node. The implied joins will be collected and passed up // to the root dot node. dot.resolve( true, false, alias == null ? null : alias.getText() ); final FromElement fromElement; if ( dot.getDataType() != null && dot.getDataType().isComponentType() ) { if ( dot.getDataType().isAnyType() ) { throw new SemanticException( "An AnyType attribute cannot be join fetched" ); // ^^ because the discriminator (aka, the "meta columns") must be known to the SQL in // a non-parameterized way. } FromElementFactory factory = new FromElementFactory( getCurrentFromClause(), dot.getLhs().getFromElement(), dot.getPropertyPath(), alias == null ? null : alias.getText(), null, false ); fromElement = factory.createComponentJoin( (CompositeType) dot.getDataType() ); } else { fromElement = dot.getImpliedJoin(); fromElement.setAllPropertyFetch( propertyFetch != null ); if ( with != null ) { if ( fetch ) { throw new SemanticException( "with-clause not allowed on fetched associations; use filters" ); } handleWithFragment( fromElement, with ); } } if ( LOG.isDebugEnabled() ) { LOG.debug( "createFromJoinElement() : " + getASTPrinter().showAsString( fromElement, "-- join tree --" ) ); } } } private EntityPersister resolveEntityJoinReferencedPersister(AST path) { if ( path.getType() == IDENT ) { final IdentNode pathIdentNode = (IdentNode) path; String name = path.getText(); if ( name == null ) { name = pathIdentNode.getOriginalText(); } return sessionFactoryHelper.findEntityPersisterByName( name ); } else if ( path.getType() == DOT ) { final String pathText = ASTUtil.getPathText( path ); return sessionFactoryHelper.findEntityPersisterByName( pathText ); } return null; } @Override protected void finishFromClause(AST fromClause) throws SemanticException { ( (FromClause) fromClause ).finishInit(); } private EntityJoinFromElement createEntityJoin( EntityPersister entityPersister, AST aliasNode, int joinType, AST propertyFetch, AST with) throws SemanticException { final String alias = aliasNode == null ? null : aliasNode.getText(); LOG.debugf( "Creating entity-join FromElement [%s -> %s]", alias, entityPersister.getEntityName() ); EntityJoinFromElement join = new EntityJoinFromElement( this, getCurrentFromClause(), entityPersister, JoinProcessor.toHibernateJoinType( joinType ), propertyFetch != null, alias ); if ( with != null ) { handleWithFragment( join, with ); } return join; } private void handleWithFragment(FromElement fromElement, AST hqlWithNode) throws SemanticException { try { withClause( hqlWithNode ); AST hqlSqlWithNode = returnAST; if ( LOG.isDebugEnabled() ) { LOG.debug( "handleWithFragment() : " + getASTPrinter().showAsString( hqlSqlWithNode, "-- with clause --" ) ); } WithClauseVisitor visitor = new WithClauseVisitor( fromElement, queryTranslatorImpl ); NodeTraverser traverser = new NodeTraverser( visitor ); traverser.traverseDepthFirst( hqlSqlWithNode ); SqlGenerator sql = new SqlGenerator( getSessionFactoryHelper().getFactory() ); sql.whereExpr( hqlSqlWithNode.getFirstChild() ); fromElement.setWithClauseFragment( "(" + sql.getSQL() + ")" ); } catch (SemanticException e) { throw e; } catch (InvalidWithClauseException e) { throw e; } catch (Exception e) { throw new SemanticException( e.getMessage() ); } } private static class WithClauseVisitor implements NodeTraverser.VisitationStrategy { private final FromElement joinFragment; private final QueryTranslatorImpl queryTranslatorImpl; private FromElement referencedFromElement; private String joinAlias; public WithClauseVisitor(FromElement fromElement, QueryTranslatorImpl queryTranslatorImpl) { this.joinFragment = fromElement; this.queryTranslatorImpl = queryTranslatorImpl; } public void visit(AST node) { // TODO : currently expects that the individual with expressions apply to the same sql table join. // This may not be the case for joined-subclass where the property values // might be coming from different tables in the joined hierarchy. At some // point we should expand this to support that capability. However, that has // some difficulties: // 1) the biggest is how to handle ORs when the individual comparisons are // linked to different sql joins. // 2) here we would need to track each comparison individually, along with // the join alias to which it applies and then pass that information // back to the FromElement so it can pass it along to the JoinSequence if ( node instanceof DotNode ) { DotNode dotNode = (DotNode) node; FromElement fromElement = dotNode.getFromElement(); if ( referencedFromElement != null ) { // if ( fromElement != referencedFromElement ) { // throw new HibernateException( "with-clause referenced two different from-clause elements" ); // } } else { referencedFromElement = fromElement; joinAlias = extractAppliedAlias( dotNode ); // TODO : temporary // needed because currently persister is the one that // creates and renders the join fragments for inheritance // hierarchies... // if ( !joinAlias.equals( referencedFromElement.getTableAlias() ) ) { // throw new InvalidWithClauseException( // "with clause can only reference columns in the driving table", // queryTranslatorImpl.getQueryString() // ); // } } } else if ( node instanceof ParameterNode ) { applyParameterSpecification( ( (ParameterNode) node ).getHqlParameterSpecification() ); } else if ( node instanceof ParameterContainer ) { applyParameterSpecifications( (ParameterContainer) node ); } } private void applyParameterSpecifications(ParameterContainer parameterContainer) { if ( parameterContainer.hasEmbeddedParameters() ) { ParameterSpecification[] specs = parameterContainer.getEmbeddedParameters(); for ( ParameterSpecification spec : specs ) { applyParameterSpecification( spec ); } } } private void applyParameterSpecification(ParameterSpecification paramSpec) { joinFragment.addEmbeddedParameter( paramSpec ); } private String extractAppliedAlias(DotNode dotNode) { return dotNode.getText().substring( 0, dotNode.getText().indexOf( '.' ) ); } public FromElement getReferencedFromElement() { return referencedFromElement; } public String getJoinAlias() { return joinAlias; } }
Sets the current 'FROM' context.
Params:
  • fromNode – The new 'FROM' context.
  • inputFromNode – The from node from the input AST.
/** * Sets the current 'FROM' context. * * @param fromNode The new 'FROM' context. * @param inputFromNode The from node from the input AST. */
@Override protected void pushFromClause(AST fromNode, AST inputFromNode) { FromClause newFromClause = (FromClause) fromNode; newFromClause.setParentFromClause( currentFromClause ); currentFromClause = newFromClause; }
Returns to the previous 'FROM' context.
/** * Returns to the previous 'FROM' context. */
private void popFromClause() { currentFromClause = currentFromClause.getParentFromClause(); } @Override protected void lookupAlias(AST aliasRef) throws SemanticException { FromElement alias = currentFromClause.getFromElement( aliasRef.getText() ); FromReferenceNode aliasRefNode = (FromReferenceNode) aliasRef; aliasRefNode.setFromElement( alias ); } @Override protected void setImpliedJoinType(int joinType) { impliedJoinType = JoinProcessor.toHibernateJoinType( joinType ); } public JoinType getImpliedJoinType() { return impliedJoinType; } @Override protected AST lookupProperty(AST dot, boolean root, boolean inSelect) throws SemanticException { DotNode dotNode = (DotNode) dot; FromReferenceNode lhs = dotNode.getLhs(); AST rhs = lhs.getNextSibling(); // this used to be a switch statement based on the rhs's node type // expecting it to be SqlTokenTypes.ELEMENTS or // SqlTokenTypes.INDICES in the cases where the re-arranging is needed // // In such cases it additionally expects the RHS to be a CollectionFunction node. // // However, in my experience these assumptions sometimes did not works as sometimes the node // types come in with the node type WEIRD_IDENT. What this does now is to: // 1) see if the LHS is a collection // 2) see if the RHS is a reference to one of the "collection properties". // if both are true, we log a deprecation warning if ( lhs.getDataType() != null && lhs.getDataType().isCollectionType() ) { if ( CollectionProperties.isCollectionProperty( rhs.getText() ) ) { DeprecationLogger.DEPRECATION_LOGGER.logDeprecationOfCollectionPropertiesInHql( rhs.getText(), lhs.getPath() ); } // perform the re-arrangement if ( CollectionPropertyNames.COLLECTION_INDICES.equalsIgnoreCase( rhs.getText() ) || CollectionPropertyNames.COLLECTION_ELEMENTS.equalsIgnoreCase( rhs.getText() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debugf( "lookupProperty() %s => %s(%s)", dotNode.getPath(), rhs.getText(), lhs.getPath() ); } final CollectionFunction f; if ( rhs instanceof CollectionFunction ) { f = (CollectionFunction) rhs; } else { f = new CollectionFunction(); f.initialize( SqlTokenTypes.METHOD_CALL, rhs.getText() ); f.initialize( this ); } // Re-arrange the tree so that the collection function is the root and the lhs is the path. f.setFirstChild( lhs ); lhs.setNextSibling( null ); dotNode.setFirstChild( f ); resolve( lhs ); // Don't forget to resolve the argument! f.resolve( inSelect ); // Resolve the collection function now. return f; } } // otherwise, resolve the path and return it dotNode.resolveFirstChild(); return dotNode; } @Override protected boolean isNonQualifiedPropertyRef(AST ident) { final String identText = ident.getText(); if ( currentFromClause.isFromElementAlias( identText ) ) { return false; } List fromElements = currentFromClause.getExplicitFromElements(); if ( fromElements.size() == 1 ) { final FromElement fromElement = (FromElement) fromElements.get( 0 ); try { LOG.tracev( "Attempting to resolve property [{0}] as a non-qualified ref", identText ); return fromElement.getPropertyMapping( identText ).toType( identText ) != null; } catch (QueryException e) { // Should mean that no such property was found } } return false; } @Override protected AST lookupNonQualifiedProperty(AST property) throws SemanticException { final FromElement fromElement = (FromElement) currentFromClause.getExplicitFromElements().get( 0 ); AST syntheticDotNode = generateSyntheticDotNodeForNonQualifiedPropertyRef( property, fromElement ); return lookupProperty( syntheticDotNode, false, getCurrentClauseType() == HqlSqlTokenTypes.SELECT ); } private AST generateSyntheticDotNodeForNonQualifiedPropertyRef(AST property, FromElement fromElement) { AST dot = getASTFactory().create( DOT, "{non-qualified-property-ref}" ); // TODO : better way?!? ( (DotNode) dot ).setPropertyPath( ( (FromReferenceNode) property ).getPath() ); IdentNode syntheticAlias = (IdentNode) getASTFactory().create( IDENT, "{synthetic-alias}" ); syntheticAlias.setFromElement( fromElement ); syntheticAlias.setResolved(); dot.setFirstChild( syntheticAlias ); dot.addChild( property ); return dot; } @Override protected void processQuery(AST select, AST query) throws SemanticException { if ( LOG.isDebugEnabled() ) { LOG.debugf( "processQuery() : %s", query.toStringTree() ); } try { QueryNode qn = (QueryNode) query; // Was there an explicit select expression? boolean explicitSelect = select != null && select.getNumberOfChildren() > 0; // Add in the EntityGraph attribute nodes. if ( queryTranslatorImpl.getEntityGraphQueryHint() != null ) { final boolean oldInEntityGraph = inEntityGraph; try { inEntityGraph = true; qn.getFromClause().getFromElements().addAll( queryTranslatorImpl.getEntityGraphQueryHint().toFromElements( qn.getFromClause(), this ) ); } finally { inEntityGraph = oldInEntityGraph; } } if ( !explicitSelect ) { // No explicit select expression; render the id and properties // projection lists for every persister in the from clause into // a single 'token node'. //TODO: the only reason we need this stuff now is collection filters, // we should get rid of derived select clause completely! createSelectClauseFromFromClause( qn ); } else { // Use the explicitly declared select expression; determine the // return types indicated by each select token useSelectClause( select ); } // After that, process the JOINs. // Invoke a delegate to do the work, as this is farily complex. JoinProcessor joinProcessor = new JoinProcessor( this ); joinProcessor.processJoins( qn ); // Attach any mapping-defined "ORDER BY" fragments Iterator itr = qn.getFromClause().getProjectionList().iterator(); while ( itr.hasNext() ) { final FromElement fromElement = (FromElement) itr.next(); // if ( fromElement.isFetch() && fromElement.isCollectionJoin() ) { if ( fromElement.isFetch() && fromElement.getQueryableCollection() != null ) { // Does the collection referenced by this FromElement // specify an order-by attribute? If so, attach it to // the query's order-by if ( fromElement.getQueryableCollection().hasOrdering() ) { String orderByFragment = fromElement .getQueryableCollection() .getSQLOrderByString( fromElement.getCollectionTableAlias() ); qn.getOrderByClause().addOrderFragment( orderByFragment ); } if ( fromElement.getQueryableCollection().hasManyToManyOrdering() ) { String orderByFragment = fromElement.getQueryableCollection() .getManyToManyOrderByString( fromElement.getTableAlias() ); qn.getOrderByClause().addOrderFragment( orderByFragment ); } } } } finally { popFromClause(); } } protected void postProcessDML(RestrictableStatement statement) throws SemanticException { statement.getFromClause().resolve(); FromElement fromElement = (FromElement) statement.getFromClause().getFromElements().get( 0 ); Queryable persister = fromElement.getQueryable(); // Make #@%$^#^&# sure no alias is applied to the table name fromElement.setText( persister.getTableName() ); // // append any filter fragments; the EMPTY_MAP is used under the assumption that // // currently enabled filters should not affect this process // if ( persister.getDiscriminatorType() != null ) { // new SyntheticAndFactory( getASTFactory() ).addDiscriminatorWhereFragment( // statement, // persister, // java.util.Collections.EMPTY_MAP, // fromElement.getTableAlias() // ); // } if ( persister.getDiscriminatorType() != null || !queryTranslatorImpl.getEnabledFilters().isEmpty() ) { new SyntheticAndFactory( this ).addDiscriminatorWhereFragment( statement, persister, queryTranslatorImpl.getEnabledFilters(), fromElement.getTableAlias() ); } } @Override protected void postProcessUpdate(AST update) throws SemanticException { UpdateStatement updateStatement = (UpdateStatement) update; postProcessDML( updateStatement ); } @Override protected void postProcessDelete(AST delete) throws SemanticException { postProcessDML( (DeleteStatement) delete ); } @Override protected void postProcessInsert(AST insert) throws SemanticException, QueryException { InsertStatement insertStatement = (InsertStatement) insert; insertStatement.validate(); SelectClause selectClause = insertStatement.getSelectClause(); Queryable persister = insertStatement.getIntoClause().getQueryable(); if ( !insertStatement.getIntoClause().isExplicitIdInsertion() ) { // the insert did not explicitly reference the id. See if // 1) that is allowed // 2) whether we need to alter the SQL tree to account for id final IdentifierGenerator generator = persister.getIdentifierGenerator(); if ( !BulkInsertionCapableIdentifierGenerator.class.isInstance( generator ) ) { throw new QueryException( "Invalid identifier generator encountered for implicit id handling as part of bulk insertions" ); } final BulkInsertionCapableIdentifierGenerator capableGenerator = BulkInsertionCapableIdentifierGenerator.class.cast( generator ); if ( !capableGenerator.supportsBulkInsertionIdentifierGeneration() ) { throw new QueryException( "Identifier generator reported it does not support implicit id handling as part of bulk insertions" ); } final String fragment = capableGenerator.determineBulkInsertionIdentifierGenerationSelectFragment( sessionFactoryHelper.getFactory().getDialect() ); if ( fragment != null ) { // we got a fragment from the generator, so alter the sql tree... // // first, wrap the fragment as a node AST fragmentNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, fragment ); // next, rearrange the SQL tree to add the fragment node as the first select expression AST originalFirstSelectExprNode = selectClause.getFirstChild(); selectClause.setFirstChild( fragmentNode ); fragmentNode.setNextSibling( originalFirstSelectExprNode ); // finally, prepend the id column name(s) to the insert-spec insertStatement.getIntoClause().prependIdColumnSpec(); } } if ( sessionFactoryHelper.getFactory().getDialect().supportsParametersInInsertSelect() ) { AST child = selectClause.getFirstChild(); int i = 0; while ( child != null ) { if ( child instanceof ParameterNode ) { // infer the parameter type from the type listed in the INSERT INTO clause ( (ParameterNode) child ).setExpectedType( insertStatement.getIntoClause() .getInsertionTypes()[selectClause.getParameterPositions().get( i )] ); i++; } child = child.getNextSibling(); } } final boolean includeVersionProperty = persister.isVersioned() && !insertStatement.getIntoClause().isExplicitVersionInsertion() && persister.isVersionPropertyInsertable(); if ( includeVersionProperty ) { // We need to seed the version value as part of this bulk insert VersionType versionType = persister.getVersionType(); AST versionValueNode = null; if ( sessionFactoryHelper.getFactory().getDialect().supportsParametersInInsertSelect() ) { int[] sqlTypes = versionType.sqlTypes( sessionFactoryHelper.getFactory() ); if ( sqlTypes == null || sqlTypes.length == 0 ) { throw new IllegalStateException( versionType.getClass() + ".sqlTypes() returns null or empty array" ); } if ( sqlTypes.length > 1 ) { throw new IllegalStateException( versionType.getClass() + ".sqlTypes() returns > 1 element; only single-valued versions are allowed." ); } versionValueNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" ); ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType ); ( (ParameterNode) versionValueNode ).setHqlParameterSpecification( paramSpec ); parameterSpecs.add( 0, paramSpec ); if ( sessionFactoryHelper.getFactory().getDialect().requiresCastingOfParametersInSelectClause() ) { // we need to wrtap the param in a cast() MethodNode versionMethodNode = (MethodNode) getASTFactory().create( HqlSqlTokenTypes.METHOD_CALL, "(" ); AST methodIdentNode = getASTFactory().create( HqlSqlTokenTypes.IDENT, "cast" ); versionMethodNode.addChild( methodIdentNode ); versionMethodNode.initializeMethodNode( methodIdentNode, true ); AST castExprListNode = getASTFactory().create( HqlSqlTokenTypes.EXPR_LIST, "exprList" ); methodIdentNode.setNextSibling( castExprListNode ); castExprListNode.addChild( versionValueNode ); versionValueNode.setNextSibling( getASTFactory().create( HqlSqlTokenTypes.IDENT, sessionFactoryHelper.getFactory().getDialect().getTypeName( sqlTypes[0] ) ) ); processFunction( versionMethodNode, true ); versionValueNode = versionMethodNode; } } else { if ( isIntegral( versionType ) ) { try { Object seedValue = versionType.seed( null ); versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, seedValue.toString() ); } catch (Throwable t) { throw new QueryException( "could not determine seed value for version on bulk insert [" + versionType + "]" ); } } else if ( isDatabaseGeneratedTimestamp( versionType ) ) { String functionName = sessionFactoryHelper.getFactory() .getDialect() .getCurrentTimestampSQLFunctionName(); versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, functionName ); } else { throw new QueryException( "cannot handle version type [" + versionType + "] on bulk inserts with dialects not supporting parameterSpecs in insert-select statements" ); } } AST currentFirstSelectExprNode = selectClause.getFirstChild(); selectClause.setFirstChild( versionValueNode ); versionValueNode.setNextSibling( currentFirstSelectExprNode ); insertStatement.getIntoClause().prependVersionColumnSpec(); } if ( insertStatement.getIntoClause().isDiscriminated() ) { String sqlValue = insertStatement.getIntoClause().getQueryable().getDiscriminatorSQLValue(); AST discrimValue = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, sqlValue ); insertStatement.getSelectClause().addChild( discrimValue ); } } private boolean isDatabaseGeneratedTimestamp(Type type) { // currently only the Hibernate-supplied DbTimestampType is supported here return DbTimestampType.class.isAssignableFrom( type.getClass() ); } private boolean isIntegral(Type type) { return Long.class.isAssignableFrom( type.getReturnedClass() ) || Integer.class.isAssignableFrom( type.getReturnedClass() ) || long.class.isAssignableFrom( type.getReturnedClass() ) || int.class.isAssignableFrom( type.getReturnedClass() ); } private void useSelectClause(AST select) throws SemanticException { selectClause = (SelectClause) select; selectClause.initializeExplicitSelectClause( currentFromClause ); } private void createSelectClauseFromFromClause(QueryNode qn) throws SemanticException { AST select = astFactory.create( SELECT_CLAUSE, "{derived select clause}" ); AST sibling = qn.getFromClause(); qn.setFirstChild( select ); select.setNextSibling( sibling ); selectClause = (SelectClause) select; selectClause.initializeDerivedSelectClause( currentFromClause ); LOG.debug( "Derived SELECT clause created." ); } @Override protected void resolve(AST node) throws SemanticException { resolve(node, null); } @Override protected void resolve(AST node, AST predicateNode) throws SemanticException { if ( node != null ) { // This is called when it's time to fully resolve a path expression. ResolvableNode r = (ResolvableNode) node; if ( isInFunctionCall() ) { r.resolveInFunctionCall( false, true ); } else { r.resolve( false, true, null, null, predicateNode ); // Generate implicit joins, only if necessary. } } } @Override protected void resolveSelectExpression(AST node) throws SemanticException { // This is called when it's time to fully resolve a path expression. int type = node.getType(); switch ( type ) { case DOT: { DotNode dot = (DotNode) node; dot.resolveSelectExpression(); break; } case ALIAS_REF: { // Notify the FROM element that it is being referenced by the select. FromReferenceNode aliasRefNode = (FromReferenceNode) node; //aliasRefNode.resolve( false, false, aliasRefNode.getText() ); //TODO: is it kosher to do it here? aliasRefNode.resolve( false, false ); //TODO: is it kosher to do it here? FromElement fromElement = aliasRefNode.getFromElement(); if ( fromElement != null ) { fromElement.setIncludeSubclasses( true ); } break; } default: { break; } } } @Override protected void beforeSelectClause() throws SemanticException { // Turn off includeSubclasses on all FromElements. FromClause from = getCurrentFromClause(); List fromElements = from.getFromElements(); for ( Iterator iterator = fromElements.iterator(); iterator.hasNext(); ) { FromElement fromElement = (FromElement) iterator.next(); fromElement.setIncludeSubclasses( false ); } } @Override protected AST generatePositionalParameter(AST delimiterNode, AST numberNode) throws SemanticException { // todo : we check this multiple times if ( getSessionFactoryHelper().isStrictJPAQLComplianceEnabled() && namedParameters != null ) { throw new SemanticException( "Cannot mix positional and named parameters: " + queryTranslatorImpl.getQueryString() ); } if ( numberNode == null ) { throw new QueryException( String.format( Locale.ROOT, ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED, queryTranslatorImpl.getQueryString() ) ); } final String positionString = numberNode.getText(); final int label = Integer.parseInt( positionString ); trackPositionalParameterPositions( label ); final ParameterNode parameter = (ParameterNode) astFactory.create( PARAM, positionString ); parameter.setText( "?" ); final int queryParamtersPosition = isFilter() ? label : label - 1; final PositionalParameterSpecification paramSpec = new PositionalParameterSpecification( delimiterNode.getLine(), delimiterNode.getColumn(), label, queryParamtersPosition ); parameter.setHqlParameterSpecification( paramSpec ); parameterSpecs.add( paramSpec ); return parameter; } @SuppressWarnings("unchecked") private void trackPositionalParameterPositions(int label) { if ( positionalParameters == null ) { positionalParameters = new HashMap(); } final Integer loc = parameterCount++; final Object existingValue = positionalParameters.get( label ); if ( existingValue == null ) { positionalParameters.put( label, loc ); } else if ( existingValue instanceof Integer ) { final ArrayList list = new ArrayList(); positionalParameters.put( label, list ); list.add( existingValue ); list.add( loc ); } else { ( (List) existingValue ).add( loc ); } } @Override protected AST generateNamedParameter(AST delimiterNode, AST nameNode) throws SemanticException { if ( getSessionFactoryHelper().isStrictJPAQLComplianceEnabled() && positionalParameters != null ) { throw new SemanticException( "Cannot mix positional and named parameters: " + queryTranslatorImpl.getQueryString() ); } final String name = nameNode.getText(); trackNamedParameterPositions( name ); // create the node initially with the param name so that it shows // appropriately in the "original text" attribute final ParameterNode parameter = (ParameterNode) astFactory.create( NAMED_PARAM, name ); parameter.setText( "?" ); final NamedParameterSpecification paramSpec = new NamedParameterSpecification( delimiterNode.getLine(), delimiterNode.getColumn(), name ); parameter.setHqlParameterSpecification( paramSpec ); parameterSpecs.add( paramSpec ); return parameter; } @SuppressWarnings("unchecked") private void trackNamedParameterPositions(String name) { if ( namedParameters == null ) { namedParameters = new HashMap(); } final Integer loc = parameterCount++; final Object existingValue = namedParameters.get( name ); if ( existingValue == null ) { namedParameters.put( name, loc ); } else if ( existingValue instanceof Integer ) { ArrayList<Integer> list = new ArrayList<>( 4 ); list.add( (Integer) existingValue ); list.add( loc ); namedParameters.put( name, list ); } else { ( (List) existingValue ).add( loc ); } } @Override protected void processConstant(AST constant) throws SemanticException { literalProcessor.processConstant( constant, true ); // Use the delegate, resolve identifiers as FROM element aliases. } @Override protected void processBoolean(AST constant) throws SemanticException { literalProcessor.processBoolean( constant ); // Use the delegate. } @Override protected void processNumericLiteral(AST literal) { literalProcessor.processNumeric( literal ); } @Override protected void processIndex(AST indexOp) throws SemanticException { IndexNode indexNode = (IndexNode) indexOp; indexNode.resolve( true, true ); } @Override protected void processFunction(AST functionCall, boolean inSelect) throws SemanticException { MethodNode methodNode = (MethodNode) functionCall; methodNode.resolve( inSelect ); } @Override protected void processCastFunction(AST castFunctionCall, boolean inSelect) throws SemanticException { CastFunctionNode castFunctionNode = (CastFunctionNode) castFunctionCall; castFunctionNode.resolve( inSelect ); } @Override protected void processAggregation(AST node, boolean inSelect) throws SemanticException { AggregateNode aggregateNode = (AggregateNode) node; aggregateNode.resolve(); } @Override protected void processConstructor(AST constructor) throws SemanticException { ConstructorNode constructorNode = (ConstructorNode) constructor; constructorNode.prepare(); } @Override protected void setAlias(AST selectExpr, AST ident) { ( (SelectExpression) selectExpr ).setAlias( ident.getText() ); // only put the alias (i.e., result variable) in selectExpressionsByResultVariable // if is not defined in a subquery. if ( !isSubQuery() ) { selectExpressionsByResultVariable.put( ident.getText(), (SelectExpression) selectExpr ); } } @Override protected boolean isOrderExpressionResultVariableRef(AST orderExpressionNode) throws SemanticException { // ORDER BY is not supported in a subquery // TODO: should an exception be thrown if an ORDER BY is in a subquery? if ( !isSubQuery() && orderExpressionNode.getType() == IDENT && selectExpressionsByResultVariable.containsKey( orderExpressionNode.getText() ) ) { return true; } return false; } @Override protected void handleResultVariableRef(AST resultVariableRef) throws SemanticException { if ( isSubQuery() ) { throw new SemanticException( "References to result variables in subqueries are not supported." ); } ( (ResultVariableRefNode) resultVariableRef ).setSelectExpression( selectExpressionsByResultVariable.get( resultVariableRef.getText() ) ); }
Returns the locations of all occurrences of the named parameter.
/** * Returns the locations of all occurrences of the named parameter. */
public int[] getNamedParameterLocations(String name) throws QueryException { Object o = namedParameters.get( name ); if ( o == null ) { throw new QueryException( QueryTranslator.ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name, queryTranslatorImpl.getQueryString() ); } if ( o instanceof Integer ) { return new int[] {(Integer) o}; } else { return ArrayHelper.toIntArray( (ArrayList) o ); } } public void addQuerySpaces(Serializable[] spaces) { querySpaces.addAll( Arrays.asList( spaces ) ); } public Type[] getReturnTypes() { return selectClause.getQueryReturnTypes(); } public String[] getReturnAliases() { return selectClause.getQueryReturnAliases(); } public SelectClause getSelectClause() { return selectClause; } public FromClause getFinalFromClause() { FromClause top = currentFromClause; while ( top.getParentFromClause() != null ) { top = top.getParentFromClause(); } return top; } public boolean isShallowQuery() { // select clauses for insert statements should alwasy be treated as shallow return getStatementType() == INSERT || queryTranslatorImpl.isShallowQuery(); } public Map getEnabledFilters() { return queryTranslatorImpl.getEnabledFilters(); } public LiteralProcessor getLiteralProcessor() { return literalProcessor; } public ASTPrinter getASTPrinter() { return TokenPrinters.SQL_TOKEN_PRINTER; } public ArrayList<ParameterSpecification> getParameterSpecs() { return parameterSpecs; } public int getNumberOfParametersInSetClause() { return numberOfParametersInSetClause; } @Override protected void evaluateAssignment(AST eq) throws SemanticException { prepareLogicOperator( eq ); Queryable persister = getCurrentFromClause().getFromElement().getQueryable(); evaluateAssignment( eq, persister, -1 ); } private void evaluateAssignment(AST eq, Queryable persister, int targetIndex) { if ( persister.isMultiTable() ) { // no need to even collect this information if the persister is considered multi-table AssignmentSpecification specification = new AssignmentSpecification( eq, persister ); if ( targetIndex >= 0 ) { assignmentSpecifications.add( targetIndex, specification ); } else { assignmentSpecifications.add( specification ); } numberOfParametersInSetClause += specification.getParameters().length; } } public ArrayList getAssignmentSpecifications() { return assignmentSpecifications; } @Override protected AST createIntoClause(String path, AST propertySpec) throws SemanticException { Queryable persister = (Queryable) getSessionFactoryHelper().requireClassPersister( path ); IntoClause intoClause = (IntoClause) getASTFactory().create( INTO, persister.getEntityName() ); intoClause.setFirstChild( propertySpec ); intoClause.initialize( persister ); addQuerySpaces( persister.getQuerySpaces() ); return intoClause; } @Override protected void prepareVersioned(AST updateNode, AST versioned) throws SemanticException { UpdateStatement updateStatement = (UpdateStatement) updateNode; FromClause fromClause = updateStatement.getFromClause(); if ( versioned != null ) { // Make sure that the persister is versioned Queryable persister = fromClause.getFromElement().getQueryable(); if ( !persister.isVersioned() ) { throw new SemanticException( "increment option specified for update of non-versioned entity" ); } VersionType versionType = persister.getVersionType(); if ( versionType instanceof UserVersionType ) { throw new SemanticException( "user-defined version types not supported for increment option" ); } AST eq = getASTFactory().create( HqlSqlTokenTypes.EQ, "=" ); AST versionPropertyNode = generateVersionPropertyNode( persister ); eq.setFirstChild( versionPropertyNode ); AST versionIncrementNode = null; if ( isTimestampBasedVersion( versionType ) ) { versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" ); ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType ); ( (ParameterNode) versionIncrementNode ).setHqlParameterSpecification( paramSpec ); parameterSpecs.add( 0, paramSpec ); } else { // Not possible to simply re-use the versionPropertyNode here as it causes // OOM errors due to circularity :( versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PLUS, "+" ); versionIncrementNode.setFirstChild( generateVersionPropertyNode( persister ) ); versionIncrementNode.addChild( getASTFactory().create( HqlSqlTokenTypes.IDENT, "1" ) ); } eq.addChild( versionIncrementNode ); evaluateAssignment( eq, persister, 0 ); AST setClause = updateStatement.getSetClause(); AST currentFirstSetElement = setClause.getFirstChild(); setClause.setFirstChild( eq ); eq.setNextSibling( currentFirstSetElement ); } } private boolean isTimestampBasedVersion(VersionType versionType) { final Class javaType = versionType.getReturnedClass(); return Date.class.isAssignableFrom( javaType ) || Calendar.class.isAssignableFrom( javaType ); } private AST generateVersionPropertyNode(Queryable persister) throws SemanticException { String versionPropertyName = persister.getPropertyNames()[persister.getVersionProperty()]; AST versionPropertyRef = getASTFactory().create( HqlSqlTokenTypes.IDENT, versionPropertyName ); AST versionPropertyNode = lookupNonQualifiedProperty( versionPropertyRef ); resolve( versionPropertyNode ); return versionPropertyNode; } @Override protected void prepareLogicOperator(AST operator) throws SemanticException { ( (OperatorNode) operator ).initialize(); } @Override protected void prepareArithmeticOperator(AST operator) throws SemanticException { ( (OperatorNode) operator ).initialize(); } @Override protected void validateMapPropertyExpression(AST node) throws SemanticException { try { FromReferenceNode fromReferenceNode = (FromReferenceNode) node; QueryableCollection collectionPersister = fromReferenceNode.getFromElement().getQueryableCollection(); if ( !Map.class.isAssignableFrom( collectionPersister.getCollectionType().getReturnedClass() ) ) { throw new SemanticException( "node did not reference a map" ); } } catch (SemanticException se) { throw se; } catch (Throwable t) { throw new SemanticException( "node did not reference a map" ); } } public Set<String> getTreatAsDeclarationsByPath(String path) { return hqlParser.getTreatMap().get( path ); } public Dialect getDialect() { return sessionFactoryHelper.getFactory().getServiceRegistry().getService( JdbcServices.class ).getDialect(); } public static void panic() { throw new QueryException( "TreeWalker: panic" ); } }