📄 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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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 Log log = LogFactory.getLog( QueryTranslatorImpl.class );
private static final Log AST_LOG = LogFactory.getLog( "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 + -