1 package org.hibernate.hql.ast; 3 4 import antlr.ANTLRException; 5 import antlr.RecognitionException; 6 import antlr.TokenStreamException; 7 import antlr.collections.AST; 8 import org.apache.commons.logging.Log; 9 import org.apache.commons.logging.LogFactory; 10 import org.hibernate.HibernateException; 11 import org.hibernate.MappingException; 12 import org.hibernate.QueryException; 13 import org.hibernate.ScrollableResults; 14 import org.hibernate.engine.QueryParameters; 15 import org.hibernate.engine.SessionFactoryImplementor; 16 import org.hibernate.engine.SessionImplementor; 17 import org.hibernate.event.EventSource; 18 import org.hibernate.hql.FilterTranslator; 19 import org.hibernate.hql.antlr.HqlSqlTokenTypes; 20 import org.hibernate.hql.antlr.HqlTokenTypes; 21 import org.hibernate.hql.antlr.SqlTokenTypes; 22 import org.hibernate.hql.ast.exec.BasicExecutor; 23 import org.hibernate.hql.ast.exec.MultiTableDeleteExecutor; 24 import org.hibernate.hql.ast.exec.MultiTableUpdateExecutor; 25 import org.hibernate.hql.ast.exec.StatementExecutor; 26 import org.hibernate.hql.ast.tree.FromElement; 27 import org.hibernate.hql.ast.tree.InsertStatement; 28 import org.hibernate.hql.ast.tree.QueryNode; 29 import org.hibernate.hql.ast.tree.Statement; 30 import org.hibernate.hql.ast.util.ASTPrinter; 31 import org.hibernate.loader.hql.QueryLoader; 32 import org.hibernate.persister.entity.Queryable; 33 import org.hibernate.type.Type; 34 import org.hibernate.util.StringHelper; 35 36 import java.util.HashMap ; 37 import java.util.Iterator ; 38 import java.util.List ; 39 import java.util.Map ; 40 import java.util.Set ; 41 42 50 public class QueryTranslatorImpl implements FilterTranslator { 51 52 private static final Log log = LogFactory.getLog( QueryTranslatorImpl.class ); 53 private static final Log AST_LOG = LogFactory.getLog( "org.hibernate.hql.ast.AST" ); 54 55 private SessionFactoryImplementor factory; 56 57 private String hql; 58 private boolean shallowQuery; 59 private Map tokenReplacements; 60 private Map enabledFilters; 61 62 private boolean compiled; 63 private QueryLoader queryLoader; 64 private StatementExecutor statementExecutor; 65 66 private Statement sqlAst; 67 private String sql; 68 69 70 77 public QueryTranslatorImpl( 78 String query, 79 Map enabledFilters, 80 SessionFactoryImplementor factory) { 81 this.hql = query; 82 this.compiled = false; 83 this.shallowQuery = false; 84 this.enabledFilters = enabledFilters; 85 this.factory = factory; 86 } 87 88 97 public void compile( 98 Map replacements, 99 boolean shallow) throws QueryException, MappingException { 100 doCompile( replacements, shallow, null ); 101 } 102 103 113 public void compile( 114 String collectionRole, 115 Map replacements, 116 boolean shallow) throws QueryException, MappingException { 117 doCompile( replacements, shallow, collectionRole ); 118 } 119 120 public Statement getSqlAST() { 121 return sqlAst; 122 } 123 124 132 private synchronized void doCompile(Map replacements, boolean shallow, String collectionRole) { 133 if ( compiled ) { 135 if ( log.isDebugEnabled() ) { 136 log.debug( "compile() : The query is already compiled, skipping..." ); 137 } 138 return; 139 } 140 141 this.tokenReplacements = replacements; 143 if ( tokenReplacements == null ) { 144 tokenReplacements = new HashMap (); 145 } 146 this.shallowQuery = shallow; 147 148 try { 149 HqlParser parser = parse( true ); 151 152 HqlSqlWalker w = analyze( parser, collectionRole ); 154 155 sqlAst = ( Statement ) w.getAST(); 156 157 168 if ( sqlAst.needsExecutor() ) { 169 statementExecutor = buildAppropriateStatementExecutor( w ); 170 } 171 else { 172 generate( ( QueryNode ) sqlAst ); 174 queryLoader = new QueryLoader( this, factory, w.getSelectClause() ); 175 } 176 177 compiled = true; 178 } 179 catch ( QueryException qe ) { 180 qe.setQueryString( hql ); 181 throw qe; 182 } 183 catch ( RecognitionException e ) { 184 throw new QuerySyntaxException( e, hql ); 185 } 186 catch ( ANTLRException e ) { 187 QueryException qe = new QueryException( e.getMessage(), e ); 188 qe.setQueryString( hql ); 189 throw qe; 190 } 191 } 192 193 private void generate(AST sqlAst) throws QueryException, RecognitionException { 194 if ( sql == null ) { 195 SqlGenerator gen = new SqlGenerator(factory); 196 gen.statement( sqlAst ); 197 sql = gen.getSQL(); 198 if ( log.isDebugEnabled() ) { 199 log.debug( "HQL: " + hql ); 200 log.debug( "SQL: " + sql ); 201 } 202 gen.getParseErrorHandler().throwQueryException(); 203 } 204 } 205 206 private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException { 207 HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole ); 208 AST hqlAst = parser.getAST(); 209 210 w.statement( hqlAst ); 212 213 if ( AST_LOG.isDebugEnabled() ) { 214 ASTPrinter printer = new ASTPrinter( SqlTokenTypes.class ); 215 AST_LOG.debug( printer.showAsString( w.getAST(), "--- SQL AST ---" ) ); 216 } 217 218 w.getParseErrorHandler().throwQueryException(); 219 220 return w; 221 } 222 223 private HqlParser parse(boolean filter) throws TokenStreamException, RecognitionException { 224 HqlParser parser = HqlParser.getInstance( hql ); 226 parser.setFilter( filter ); 227 228 if ( log.isDebugEnabled() ) { 229 log.debug( "parse() - HQL: " + hql ); 230 } 231 parser.statement(); 232 233 AST hqlAst = parser.getAST(); 234 235 showHqlAst( hqlAst ); 236 237 parser.getParseErrorHandler().throwQueryException(); 238 return parser; 239 } 240 241 void showHqlAst(AST hqlAst) { 242 if ( AST_LOG.isDebugEnabled() ) { 243 ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class ); 244 printer.setShowClassNames( false ); AST_LOG.debug( printer.showAsString( hqlAst, "--- HQL AST ---" ) ); 246 } 247 } 248 249 private void errorIfDML() throws HibernateException { 250 if ( sqlAst.needsExecutor() ) { 251 throw new HibernateException( "Not supported for DML operations" ); 252 } 253 } 254 255 private void errorIfSelect() throws HibernateException { 256 if ( !sqlAst.needsExecutor() ) { 257 throw new HibernateException( "Not supported for select queries" ); 258 } 259 } 260 261 private HqlSqlWalker getWalker() { 262 return sqlAst.getWalker(); 263 } 264 265 270 public Type[] getReturnTypes() { 271 errorIfDML(); 272 return getWalker().getReturnTypes(); 273 } 274 275 public String [] getReturnAliases() { 276 errorIfDML(); 277 return getWalker().getReturnAliases(); 278 } 279 280 public String [][] getColumnNames() { 281 errorIfDML(); 282 return getWalker().getSelectClause().getColumnNames(); 283 } 284 285 public Set getQuerySpaces() { 286 return getWalker().getQuerySpaces(); 287 } 288 289 public List list(SessionImplementor session, QueryParameters queryParameters) 290 throws HibernateException { 291 errorIfDML(); 293 return queryLoader.list( session, queryParameters ); 294 } 295 296 299 public Iterator iterate(QueryParameters queryParameters, EventSource session) 300 throws HibernateException { 301 errorIfDML(); 303 return queryLoader.iterate( queryParameters, session ); 304 } 305 306 309 public ScrollableResults scroll(QueryParameters queryParameters, SessionImplementor session) 310 throws HibernateException { 311 errorIfDML(); 313 return queryLoader.scroll( queryParameters, session ); 314 } 315 316 public int executeUpdate(QueryParameters queryParameters, SessionImplementor session) 317 throws HibernateException { 318 errorIfSelect(); 319 return statementExecutor.execute( queryParameters, session ); 320 } 321 322 325 public String getSQLString() { 326 return sql; 327 } 328 329 331 public boolean isShallowQuery() { 332 return shallowQuery; 333 } 334 335 public String getQueryString() { 336 return hql; 337 } 338 339 public Map getEnabledFilters() { 340 return enabledFilters; 341 } 342 343 public int[] getNamedParameterLocs(String name) { 344 return getWalker().getNamedParameterLocations( name ); 345 } 346 347 public boolean containsCollectionFetches() { 348 errorIfDML(); 349 List collectionFetches = ( ( QueryNode ) sqlAst ).getFromClause().getCollectionFetches(); 350 return collectionFetches != null && collectionFetches.size() > 0; 351 } 352 353 public void validateScrollability() throws HibernateException { 354 358 errorIfDML(); 359 360 QueryNode query = ( QueryNode ) sqlAst; 361 362 List collectionFetches = query.getFromClause().getCollectionFetches(); 364 if ( collectionFetches.isEmpty() ) { 365 return; 366 } 367 368 if ( isShallowQuery() ) { 370 return; 371 } 372 373 if ( getReturnTypes().length > 1 ) { 376 throw new HibernateException( "cannot scroll with collection fetches and returned tuples" ); 377 } 378 379 FromElement owner = null; 380 Iterator itr = query.getSelectClause().getFromElementsForLoad().iterator(); 381 while ( itr.hasNext() ) { 382 final FromElement fromElement = ( FromElement ) itr.next(); 384 if ( fromElement.getOrigin() == null ) { 385 owner = fromElement; 386 break; 387 } 388 } 389 390 if ( owner == null ) { 391 throw new HibernateException( "unable to locate collection fetch(es) owner for scrollability checks" ); 392 } 393 394 398 AST primaryOrdering = query.getOrderByClause().getFirstChild(); 399 if ( primaryOrdering != null ) { 400 String [] idColNames = owner.getQueryable().getIdentifierColumnNames(); 402 String expectedPrimaryOrderSeq = StringHelper.join( 403 ", ", 404 StringHelper.qualify( owner.getTableAlias(), idColNames ) 405 ); 406 if ( !primaryOrdering.getText().startsWith( expectedPrimaryOrderSeq ) ) { 407 throw new HibernateException( "cannot scroll results with collection fetches which are not ordered primarily by the root entity's PK" ); 408 } 409 } 410 } 411 412 private StatementExecutor buildAppropriateStatementExecutor(HqlSqlWalker walker) { 413 Statement statement = ( Statement ) walker.getAST(); 414 if ( walker.getStatementType() == HqlSqlTokenTypes.DELETE ) { 415 FromElement fromElement = walker.getFinalFromClause().getFromElement(); 416 Queryable persister = fromElement.getQueryable(); 417 if ( persister.isMultiTable() ) { 418 return new MultiTableDeleteExecutor( walker ); 419 } 420 else { 421 return new BasicExecutor( walker, persister ); 422 } 423 } 424 else if ( walker.getStatementType() == HqlSqlTokenTypes.UPDATE ) { 425 FromElement fromElement = walker.getFinalFromClause().getFromElement(); 426 Queryable persister = fromElement.getQueryable(); 427 if ( persister.isMultiTable() ) { 428 return new MultiTableUpdateExecutor( walker ); 432 } 433 else { 434 return new BasicExecutor( walker, persister ); 435 } 436 } 437 else if ( walker.getStatementType() == HqlSqlTokenTypes.INSERT ) { 438 return new BasicExecutor( walker, ( ( InsertStatement ) statement ).getIntoClause().getQueryable() ); 439 } 440 else { 441 throw new QueryException( "Unexpected statement type" ); 442 } 443 } 444 } 445 | Popular Tags |