1 package org.hibernate.hql.ast.tree; 3 4 import java.util.HashMap ; 5 import java.util.HashSet ; 6 import java.util.Iterator ; 7 import java.util.LinkedList ; 8 import java.util.List ; 9 import java.util.Map ; 10 import java.util.Set ; 11 12 import org.hibernate.hql.antlr.HqlSqlTokenTypes; 13 import org.hibernate.hql.ast.util.ASTIterator; 14 import org.hibernate.hql.ast.util.ASTUtil; 15 import org.hibernate.QueryException; 16 17 import antlr.SemanticException; 18 import antlr.collections.AST; 19 20 import org.apache.commons.logging.Log; 21 import org.apache.commons.logging.LogFactory; 22 23 28 public class FromClause extends HqlSqlWalkerNode implements HqlSqlTokenTypes, DisplayableNode { 29 private static Log log = LogFactory.getLog( FromClause.class ); 30 public static final int ROOT_LEVEL = 1; 31 32 private int level = ROOT_LEVEL; 33 private Set fromElements = new HashSet (); 34 private Map fromElementByClassAlias = new HashMap (); 35 private Map fromElementByTableAlias = new HashMap (); 36 private Map fromElementsByPath = new HashMap (); 37 38 42 private Map collectionJoinFromElementsByPath = new HashMap (); 43 46 private FromClause parentFromClause; 47 50 private Set childFromClauses; 51 54 private int fromElementCounter = 0; 55 58 private List impliedElements = new LinkedList (); 59 60 67 public FromElement addFromElement(String path, AST alias) throws SemanticException { 68 String classAlias = ( alias == null ) ? null : alias.getText(); 70 checkForDuplicateClassAlias( classAlias ); 71 FromElementFactory factory = new FromElementFactory( this, null, path, classAlias, null, false ); 72 return factory.addFromElement(); 73 } 74 75 void registerFromElement(FromElement element) { 76 fromElements.add( element ); 77 String classAlias = element.getClassAlias(); 78 if ( classAlias != null ) { 79 fromElementByClassAlias.put( classAlias, element ); 81 } 82 String tableAlias = element.getTableAlias(); 84 if ( tableAlias != null ) { 85 fromElementByTableAlias.put( tableAlias, element ); 86 } 87 } 88 89 void addDuplicateAlias(String alias, FromElement element) { 90 fromElementByClassAlias.put( alias, element ); 91 } 92 93 private void checkForDuplicateClassAlias(String classAlias) throws SemanticException { 94 if ( classAlias != null && fromElementByClassAlias.containsKey( classAlias ) ) { 95 throw new SemanticException( "Duplicate definition of alias '" 96 + classAlias + "'" ); 97 } 98 } 99 100 106 public FromElement getFromElement(String aliasOrClassName) { 107 FromElement fromElement = ( FromElement ) fromElementByClassAlias.get( aliasOrClassName ); 108 if ( fromElement == null && parentFromClause != null ) { 109 fromElement = parentFromClause.getFromElement( aliasOrClassName ); 110 } 111 return fromElement; 112 } 113 114 121 public boolean isFromElementAlias(String possibleAlias) { 122 boolean isAlias = fromElementByClassAlias.containsKey( possibleAlias ); 123 if ( !isAlias && parentFromClause != null ) { 124 isAlias = parentFromClause.isFromElementAlias( possibleAlias ); 126 } 127 return isAlias; 128 } 129 130 135 public List getFromElements() { 136 return ASTUtil.collectChildren( this, fromElementPredicate ); 137 } 138 139 public FromElement getFromElement() { 140 return (FromElement) getFromElements().get(0); 146 } 147 148 153 public List getProjectionList() { 154 return ASTUtil.collectChildren( this, projectionListPredicate ); 155 } 156 157 public List getCollectionFetches() { 158 return ASTUtil.collectChildren( this, collectionFetchPredicate ); 159 } 160 161 public boolean hasCollectionFecthes() { 162 return getCollectionFetches().size() > 0; 163 } 164 165 public List getExplicitFromElements() { 166 return ASTUtil.collectChildren( this, explicitFromPredicate ); 167 } 168 169 private static ASTUtil.FilterPredicate fromElementPredicate = new ASTUtil.IncludePredicate() { 170 public boolean include(AST node) { 171 FromElement fromElement = ( FromElement ) node; 172 return fromElement.isFromOrJoinFragment(); 173 } 174 }; 175 176 private static ASTUtil.FilterPredicate projectionListPredicate = new ASTUtil.IncludePredicate() { 177 public boolean include(AST node) { 178 FromElement fromElement = ( FromElement ) node; 179 return fromElement.inProjectionList(); 180 } 181 }; 182 183 private static ASTUtil.FilterPredicate collectionFetchPredicate = new ASTUtil.IncludePredicate() { 184 public boolean include(AST node) { 185 FromElement fromElement = ( FromElement ) node; 186 return fromElement.isFetch() && fromElement.getQueryableCollection() != null; 187 } 188 }; 189 190 private static ASTUtil.FilterPredicate explicitFromPredicate = new ASTUtil.IncludePredicate() { 191 public boolean include(AST node) { 192 final FromElement fromElement = ( FromElement ) node; 193 return !fromElement.isImplied(); 194 } 195 }; 196 197 FromElement findCollectionJoin(String path) { 198 return ( FromElement ) collectionJoinFromElementsByPath.get( path ); 199 } 200 201 205 FromElement findJoinByPath(String path) { 206 FromElement elem = findJoinByPathLocal( path ); 207 if ( elem == null && parentFromClause != null ) { 208 elem = parentFromClause.findJoinByPath( path ); 209 } 210 return elem; 211 } 212 213 FromElement findJoinByPathLocal(String path) { 214 Map joinsByPath = fromElementsByPath; 215 return ( FromElement ) joinsByPath.get( path ); 216 } 217 218 void addJoinByPathMap(String path, FromElement destination) { 219 if ( log.isDebugEnabled() ) { 220 log.debug( "addJoinByPathMap() : " + path + " -> " + destination ); 221 } 222 fromElementsByPath.put( path, destination ); 223 } 224 225 231 public boolean containsClassAlias(String alias) { 232 return fromElementByClassAlias.keySet().contains( alias ); 233 } 234 235 241 public boolean containsTableAlias(String alias) { 242 return fromElementByTableAlias.keySet().contains( alias ); 243 } 244 245 public String getDisplayText() { 246 return "FromClause{" + 247 "level=" + level + 248 ", fromElementCounter=" + fromElementCounter + 249 ", fromElements=" + fromElements.size() + 250 ", fromElementByClassAlias=" + fromElementByClassAlias.keySet() + 251 ", fromElementByTableAlias=" + fromElementByTableAlias.keySet() + 252 ", fromElementsByPath=" + fromElementsByPath.keySet() + 253 ", collectionJoinFromElementsByPath=" + collectionJoinFromElementsByPath.keySet() + 254 ", impliedElements=" + impliedElements + 255 "}"; 256 } 257 258 public void setParentFromClause(FromClause parentFromClause) { 259 this.parentFromClause = parentFromClause; 260 if ( parentFromClause != null ) { 261 level = parentFromClause.getLevel() + 1; 262 parentFromClause.addChild( this ); 263 } 264 } 265 266 private void addChild(FromClause fromClause) { 267 if ( childFromClauses == null ) { 268 childFromClauses = new HashSet (); 269 } 270 childFromClauses.add( fromClause ); 271 } 272 273 public FromClause locateChildFromClauseWithJoinByPath(String path) { 274 if ( childFromClauses != null && !childFromClauses.isEmpty() ) { 275 Iterator children = childFromClauses.iterator(); 276 while ( children.hasNext() ) { 277 FromClause child = ( FromClause ) children.next(); 278 if ( child.findJoinByPathLocal( path ) != null ) { 279 return child; 280 } 281 } 282 } 283 return null; 284 } 285 286 public void promoteJoin(FromElement elem) { 287 if ( log.isDebugEnabled() ) { 288 log.debug( "Promoting [" + elem + "] to [" + this + "]" ); 289 } 290 } 298 299 public boolean isSubQuery() { 300 return parentFromClause != null; 302 } 303 304 void addCollectionJoinFromElementByPath(String path, FromElement destination) { 305 if ( log.isDebugEnabled() ) { 306 log.debug( "addCollectionJoinFromElementByPath() : " + path + " -> " + destination ); 307 } 308 collectionJoinFromElementsByPath.put( path, destination ); } 310 311 public FromClause getParentFromClause() { 312 return parentFromClause; 313 } 314 315 public int getLevel() { 316 return level; 317 } 318 319 public int nextFromElementCounter() { 320 return fromElementCounter++; 321 } 322 323 public void resolve() { 324 ASTIterator iter = new ASTIterator( this.getFirstChild() ); 326 Set childrenInTree = new HashSet (); 327 while ( iter.hasNext() ) { 328 childrenInTree.add( iter.next() ); 329 } 330 for ( Iterator iterator = fromElements.iterator(); iterator.hasNext(); ) { 331 FromElement fromElement = ( FromElement ) iterator.next(); 332 if ( !childrenInTree.contains( fromElement ) ) { 333 throw new IllegalStateException ( "Element not in AST: " + fromElement ); 334 } 335 } 336 } 337 338 public void addImpliedFromElement(FromElement element) { 339 impliedElements.add( element ); 340 } 341 342 public String toString() { 343 return "FromClause{" + 344 "level=" + level + 345 "}"; 346 } 347 } 348 | Popular Tags |