📄 querytranslatorimpl.java
字号:
// $Id: QueryTranslatorImpl.java 10000 2006-06-08 21:04:45Z steve.ebersole@jboss.com $package org.hibernate.hql.ast;import antlr.ANTLRException;import antlr.RecognitionException;import antlr.TokenStreamException;import antlr.collections.AST;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.hibernate.HibernateException;import org.hibernate.MappingException;import org.hibernate.QueryException;import org.hibernate.ScrollableResults;import org.hibernate.engine.QueryParameters;import org.hibernate.engine.RowSelection;import org.hibernate.engine.SessionFactoryImplementor;import org.hibernate.engine.SessionImplementor;import org.hibernate.event.EventSource;import org.hibernate.hql.FilterTranslator;import org.hibernate.hql.QueryExecutionRequestException;import org.hibernate.hql.ParameterTranslations;import org.hibernate.hql.antlr.HqlSqlTokenTypes;import org.hibernate.hql.antlr.HqlTokenTypes;import org.hibernate.hql.antlr.SqlTokenTypes;import org.hibernate.hql.ast.exec.BasicExecutor;import org.hibernate.hql.ast.exec.MultiTableDeleteExecutor;import org.hibernate.hql.ast.exec.MultiTableUpdateExecutor;import org.hibernate.hql.ast.exec.StatementExecutor;import org.hibernate.hql.ast.tree.FromElement;import org.hibernate.hql.ast.tree.InsertStatement;import org.hibernate.hql.ast.tree.QueryNode;import org.hibernate.hql.ast.tree.Statement;import org.hibernate.hql.ast.util.ASTPrinter;import org.hibernate.hql.ast.util.NodeTraverser;import org.hibernate.hql.ast.util.ASTUtil;import org.hibernate.loader.hql.QueryLoader;import org.hibernate.persister.entity.Queryable;import org.hibernate.type.Type;import org.hibernate.util.IdentitySet;import org.hibernate.util.StringHelper;import org.hibernate.util.ReflectHelper;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.ArrayList;/** * A QueryTranslator that uses an Antlr-based parser. * * @author Joshua Davis (pgmjsd@sourceforge.net) */public class QueryTranslatorImpl implements FilterTranslator { private static final Logger log = LoggerFactory.getLogger( QueryTranslatorImpl.class ); private static final Logger AST_LOG = LoggerFactory.getLogger( "org.hibernate.hql.ast.AST" ); private SessionFactoryImplementor factory; private final String queryIdentifier; private String hql; private boolean shallowQuery; private Map tokenReplacements; private Map enabledFilters; //TODO:this is only needed during compilation .. can we eliminate the instvar? private boolean compiled; private QueryLoader queryLoader; private StatementExecutor statementExecutor; private Statement sqlAst; private String sql; private ParameterTranslations paramTranslations; /** * Creates a new AST-based query translator. * * @param queryIdentifier The query-identifier (used in stats collection) * @param query The hql query to translate * @param enabledFilters Currently enabled filters * @param factory The session factory constructing this translator instance. */ public QueryTranslatorImpl( String queryIdentifier, String query, Map enabledFilters, SessionFactoryImplementor factory) { this.queryIdentifier = queryIdentifier; this.hql = query; this.compiled = false; this.shallowQuery = false; this.enabledFilters = enabledFilters; this.factory = factory; } /** * Compile a "normal" query. This method may be called multiple * times. Subsequent invocations are no-ops. * * @param replacements Defined query substitutions. * @param shallow Does this represent a shallow (scalar or entity-id) select? * @throws QueryException There was a problem parsing the query string. * @throws MappingException There was a problem querying defined mappings. */ public void compile( Map replacements, boolean shallow) throws QueryException, MappingException { doCompile( replacements, shallow, null ); } /** * Compile a filter. This method may be called multiple * times. Subsequent invocations are no-ops. * * @param collectionRole the role name of the collection used as the basis for the filter. * @param replacements Defined query substitutions. * @param shallow Does this represent a shallow (scalar or entity-id) select? * @throws QueryException There was a problem parsing the query string. * @throws MappingException There was a problem querying defined mappings. */ public void compile( String collectionRole, Map replacements, boolean shallow) throws QueryException, MappingException { doCompile( replacements, shallow, collectionRole ); } /** * Performs both filter and non-filter compiling. * * @param replacements Defined query substitutions. * @param shallow Does this represent a shallow (scalar or entity-id) select? * @param collectionRole the role name of the collection used as the basis for the filter, NULL if this * is not a filter. */ private synchronized void doCompile(Map replacements, boolean shallow, String collectionRole) { // If the query is already compiled, skip the compilation. if ( compiled ) { if ( log.isDebugEnabled() ) { log.debug( "compile() : The query is already compiled, skipping..." ); } return; } // Remember the parameters for the compilation. this.tokenReplacements = replacements; if ( tokenReplacements == null ) { tokenReplacements = new HashMap(); } this.shallowQuery = shallow; try { // PHASE 1 : Parse the HQL into an AST. HqlParser parser = parse( true ); // PHASE 2 : Analyze the HQL AST, and produce an SQL AST. HqlSqlWalker w = analyze( parser, collectionRole ); sqlAst = ( Statement ) w.getAST(); // at some point the generate phase needs to be moved out of here, // because a single object-level DML might spawn multiple SQL DML // command executions. // // Possible to just move the sql generation for dml stuff, but for // consistency-sake probably best to just move responsiblity for // the generation phase completely into the delegates // (QueryLoader/StatementExecutor) themselves. Also, not sure why // QueryLoader currently even has a dependency on this at all; does // it need it? Ideally like to see the walker itself given to the delegates directly... if ( sqlAst.needsExecutor() ) { statementExecutor = buildAppropriateStatementExecutor( w ); } else { // PHASE 3 : Generate the SQL. generate( ( QueryNode ) sqlAst ); queryLoader = new QueryLoader( this, factory, w.getSelectClause() ); } compiled = true; } catch ( QueryException qe ) { qe.setQueryString( hql ); throw qe; } catch ( RecognitionException e ) { // we do not actually propogate ANTLRExceptions as a cause, so // log it here for diagnostic purposes if ( log.isTraceEnabled() ) { log.trace( "converted antlr.RecognitionException", e ); } throw QuerySyntaxException.convert( e, hql ); } catch ( ANTLRException e ) { // we do not actually propogate ANTLRExceptions as a cause, so // log it here for diagnostic purposes if ( log.isTraceEnabled() ) { log.trace( "converted antlr.ANTLRException", e ); } throw new QueryException( e.getMessage(), hql ); } this.enabledFilters = null; //only needed during compilation phase... } private void generate(AST sqlAst) throws QueryException, RecognitionException { if ( sql == null ) { SqlGenerator gen = new SqlGenerator(factory); gen.statement( sqlAst ); sql = gen.getSQL(); if ( log.isDebugEnabled() ) { log.debug( "HQL: " + hql ); log.debug( "SQL: " + sql ); } gen.getParseErrorHandler().throwQueryException(); } } private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException { HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole ); AST hqlAst = parser.getAST(); // Transform the tree. w.statement( hqlAst ); if ( AST_LOG.isDebugEnabled() ) { ASTPrinter printer = new ASTPrinter( SqlTokenTypes.class ); AST_LOG.debug( printer.showAsString( w.getAST(), "--- SQL AST ---" ) ); } w.getParseErrorHandler().throwQueryException(); return w; } private HqlParser parse(boolean filter) throws TokenStreamException, RecognitionException { // Parse the query string into an HQL AST. HqlParser parser = HqlParser.getInstance( hql ); parser.setFilter( filter ); if ( log.isDebugEnabled() ) { log.debug( "parse() - HQL: " + hql ); } parser.statement(); AST hqlAst = parser.getAST(); JavaConstantConverter converter = new JavaConstantConverter(); NodeTraverser walker = new NodeTraverser( converter ); walker.traverseDepthFirst( hqlAst ); showHqlAst( hqlAst ); parser.getParseErrorHandler().throwQueryException(); return parser; } void showHqlAst(AST hqlAst) { if ( AST_LOG.isDebugEnabled() ) { ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class ); printer.setShowClassNames( false ); // The class names aren't interesting in the first tree. AST_LOG.debug( printer.showAsString( hqlAst, "--- HQL AST ---" ) ); } } private void errorIfDML() throws HibernateException { if ( sqlAst.needsExecutor() ) { throw new QueryExecutionRequestException( "Not supported for DML operations", hql ); } } private void errorIfSelect() throws HibernateException { if ( !sqlAst.needsExecutor() ) { throw new QueryExecutionRequestException( "Not supported for select queries", hql ); } } public String getQueryIdentifier() { return queryIdentifier; } public Statement getSqlAST() { return sqlAst; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -