Methods Summary |
---|
private HqlSqlWalker | analyze(HqlParser parser, java.lang.String collectionRole)
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 org.hibernate.hql.ast.exec.StatementExecutor | buildAppropriateStatementExecutor(HqlSqlWalker walker)
Statement statement = ( Statement ) walker.getAST();
if ( walker.getStatementType() == HqlSqlTokenTypes.DELETE ) {
FromElement fromElement = walker.getFinalFromClause().getFromElement();
Queryable persister = fromElement.getQueryable();
if ( persister.isMultiTable() ) {
return new MultiTableDeleteExecutor( walker );
}
else {
return new BasicExecutor( walker, persister );
}
}
else if ( walker.getStatementType() == HqlSqlTokenTypes.UPDATE ) {
FromElement fromElement = walker.getFinalFromClause().getFromElement();
Queryable persister = fromElement.getQueryable();
if ( persister.isMultiTable() ) {
// even here, if only properties mapped to the "base table" are referenced
// in the set and where clauses, this could be handled by the BasicDelegate.
// TODO : decide if it is better performance-wise to perform that check, or to simply use the MultiTableUpdateDelegate
return new MultiTableUpdateExecutor( walker );
}
else {
return new BasicExecutor( walker, persister );
}
}
else if ( walker.getStatementType() == HqlSqlTokenTypes.INSERT ) {
return new BasicExecutor( walker, ( ( InsertStatement ) statement ).getIntoClause().getQueryable() );
}
else {
throw new QueryException( "Unexpected statement type" );
}
|
public java.util.List | collectSqlStrings()
ArrayList list = new ArrayList();
if ( isManipulationStatement() ) {
String[] sqlStatements = statementExecutor.getSqlStatements();
for ( int i = 0; i < sqlStatements.length; i++ ) {
list.add( sqlStatements[i] );
}
}
else {
list.add( sql );
}
return list;
|
public void | compile(java.util.Map replacements, boolean shallow)Compile a "normal" query. This method may be called multiple
times. Subsequent invocations are no-ops.
doCompile( replacements, shallow, null );
|
public void | compile(java.lang.String collectionRole, java.util.Map replacements, boolean shallow)Compile a filter. This method may be called multiple
times. Subsequent invocations are no-ops.
doCompile( replacements, shallow, collectionRole );
|
public boolean | containsCollectionFetches()
errorIfDML();
List collectionFetches = ( ( QueryNode ) sqlAst ).getFromClause().getCollectionFetches();
return collectionFetches != null && collectionFetches.size() > 0;
|
private synchronized void | doCompile(java.util.Map replacements, boolean shallow, java.lang.String collectionRole)Performs both filter and non-filter compiling.
// 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 | errorIfDML()
if ( sqlAst.needsExecutor() ) {
throw new QueryExecutionRequestException( "Not supported for DML operations", hql );
}
|
private void | errorIfSelect()
if ( !sqlAst.needsExecutor() ) {
throw new QueryExecutionRequestException( "Not supported for select queries", hql );
}
|
public int | executeUpdate(org.hibernate.engine.QueryParameters queryParameters, org.hibernate.engine.SessionImplementor session)
errorIfSelect();
return statementExecutor.execute( queryParameters, session );
|
private void | generate(antlr.collections.AST sqlAst)
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();
}
|
public java.lang.String[][] | getColumnNames()
errorIfDML();
return getWalker().getSelectClause().getColumnNames();
|
public java.util.Map | getEnabledFilters()
return enabledFilters;
|
public int[] | getNamedParameterLocs(java.lang.String name)
return getWalker().getNamedParameterLocations( name );
|
public org.hibernate.hql.ParameterTranslations | getParameterTranslations()
if ( paramTranslations == null ) {
paramTranslations = new ParameterTranslationsImpl( getWalker().getParameters() );
}
return paramTranslations;
|
public java.lang.String | getQueryIdentifier()
return queryIdentifier;
|
public java.util.Set | getQuerySpaces()
return getWalker().getQuerySpaces();
|
public java.lang.String | getQueryString()
return hql;
|
public java.lang.String[] | getReturnAliases()
errorIfDML();
return getWalker().getReturnAliases();
|
public org.hibernate.type.Type[] | getReturnTypes()Types of the return values of an iterate() style query.
errorIfDML();
return getWalker().getReturnTypes();
|
public java.lang.String | getSQLString()The SQL query string to be called; implemented by all subclasses
return sql;
|
public org.hibernate.hql.ast.tree.Statement | getSqlAST()
return sqlAst;
|
private HqlSqlWalker | getWalker()
return sqlAst.getWalker();
|
public boolean | isManipulationStatement()
return sqlAst.needsExecutor();
|
public boolean | isShallowQuery()
return shallowQuery;
|
public java.util.Iterator | iterate(org.hibernate.engine.QueryParameters queryParameters, org.hibernate.event.EventSource session)Return the query results as an iterator
// Delegate to the QueryLoader...
errorIfDML();
return queryLoader.iterate( queryParameters, session );
|
public java.util.List | list(org.hibernate.engine.SessionImplementor session, org.hibernate.engine.QueryParameters queryParameters)
// Delegate to the QueryLoader...
errorIfDML();
QueryNode query = ( QueryNode ) sqlAst;
boolean hasLimit = queryParameters.getRowSelection() != null && queryParameters.getRowSelection().definesLimits();
boolean needsDistincting = ( query.getSelectClause().isDistinct() || hasLimit ) && containsCollectionFetches();
QueryParameters queryParametersToUse;
if ( hasLimit && containsCollectionFetches() ) {
log.warn( "firstResult/maxResults specified with collection fetch; applying in memory!" );
RowSelection selection = new RowSelection();
selection.setFetchSize( queryParameters.getRowSelection().getFetchSize() );
selection.setTimeout( queryParameters.getRowSelection().getTimeout() );
queryParametersToUse = queryParameters.createCopyUsing( selection );
}
else {
queryParametersToUse = queryParameters;
}
List results = queryLoader.list( session, queryParametersToUse );
if ( needsDistincting ) {
int includedCount = -1;
// NOTE : firstRow is zero-based
int first = !hasLimit || queryParameters.getRowSelection().getFirstRow() == null
? 0
: queryParameters.getRowSelection().getFirstRow().intValue();
int max = !hasLimit || queryParameters.getRowSelection().getMaxRows() == null
? -1
: queryParameters.getRowSelection().getMaxRows().intValue();
int size = results.size();
List tmp = new ArrayList();
IdentitySet distinction = new IdentitySet();
for ( int i = 0; i < size; i++ ) {
final Object result = results.get( i );
if ( !distinction.add( result ) ) {
continue;
}
includedCount++;
if ( includedCount < first ) {
continue;
}
tmp.add( result );
// NOTE : ( max - 1 ) because first is zero-based while max is not...
if ( max >= 0 && ( includedCount - first ) >= ( max - 1 ) ) {
break;
}
}
results = tmp;
}
return results;
|
private HqlParser | parse(boolean filter)
// 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;
|
public org.hibernate.ScrollableResults | scroll(org.hibernate.engine.QueryParameters queryParameters, org.hibernate.engine.SessionImplementor session)Return the query results, as an instance of ScrollableResults
// Delegate to the QueryLoader...
errorIfDML();
return queryLoader.scroll( queryParameters, session );
|
void | showHqlAst(antlr.collections.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 ---" ) );
}
|
public void | validateScrollability()
// Impl Note: allows multiple collection fetches as long as the
// entire fecthed graph still "points back" to a single
// root entity for return
errorIfDML();
QueryNode query = ( QueryNode ) sqlAst;
// If there are no collection fetches, then no further checks are needed
List collectionFetches = query.getFromClause().getCollectionFetches();
if ( collectionFetches.isEmpty() ) {
return;
}
// A shallow query is ok (although technically there should be no fetching here...)
if ( isShallowQuery() ) {
return;
}
// Otherwise, we have a non-scalar select with defined collection fetch(es).
// Make sure that there is only a single root entity in the return (no tuples)
if ( getReturnTypes().length > 1 ) {
throw new HibernateException( "cannot scroll with collection fetches and returned tuples" );
}
FromElement owner = null;
Iterator itr = query.getSelectClause().getFromElementsForLoad().iterator();
while ( itr.hasNext() ) {
// should be the first, but just to be safe...
final FromElement fromElement = ( FromElement ) itr.next();
if ( fromElement.getOrigin() == null ) {
owner = fromElement;
break;
}
}
if ( owner == null ) {
throw new HibernateException( "unable to locate collection fetch(es) owner for scrollability checks" );
}
// This is not strictly true. We actually just need to make sure that
// it is ordered by root-entity PK and that that order-by comes before
// any non-root-entity ordering...
AST primaryOrdering = query.getOrderByClause().getFirstChild();
if ( primaryOrdering != null ) {
// TODO : this is a bit dodgy, come up with a better way to check this (plus see above comment)
String [] idColNames = owner.getQueryable().getIdentifierColumnNames();
String expectedPrimaryOrderSeq = StringHelper.join(
", ",
StringHelper.qualify( owner.getTableAlias(), idColNames )
);
if ( !primaryOrdering.getText().startsWith( expectedPrimaryOrderSeq ) ) {
throw new HibernateException( "cannot scroll results with collection fetches which are not ordered primarily by the root entity's PK" );
}
}
|