| 1 22 package org.jboss.ejb.plugins.cmp.jdbc; 23 24 import java.io.StringReader ; 25 import java.util.ArrayList ; 26 import java.util.HashMap ; 27 import java.util.HashSet ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.Set ; 32 33 import org.jboss.ejb.plugins.cmp.ejbql.ASTAbs; 34 import org.jboss.ejb.plugins.cmp.ejbql.ASTAbstractSchema; 35 import org.jboss.ejb.plugins.cmp.ejbql.ASTBooleanLiteral; 36 import org.jboss.ejb.plugins.cmp.ejbql.ASTCollectionMemberDeclaration; 37 import org.jboss.ejb.plugins.cmp.ejbql.ASTConcat; 38 import org.jboss.ejb.plugins.cmp.ejbql.ASTEJBQL; 39 import org.jboss.ejb.plugins.cmp.ejbql.ASTEntityComparison; 40 import org.jboss.ejb.plugins.cmp.ejbql.ASTFrom; 41 import org.jboss.ejb.plugins.cmp.ejbql.ASTIdentifier; 42 import org.jboss.ejb.plugins.cmp.ejbql.ASTIsEmpty; 43 import org.jboss.ejb.plugins.cmp.ejbql.ASTLCase; 44 import org.jboss.ejb.plugins.cmp.ejbql.ASTLength; 45 import org.jboss.ejb.plugins.cmp.ejbql.ASTLocate; 46 import org.jboss.ejb.plugins.cmp.ejbql.ASTMemberOf; 47 import org.jboss.ejb.plugins.cmp.ejbql.ASTNullComparison; 48 import org.jboss.ejb.plugins.cmp.ejbql.ASTOrderBy; 49 import org.jboss.ejb.plugins.cmp.ejbql.ASTParameter; 50 import org.jboss.ejb.plugins.cmp.ejbql.ASTPath; 51 import org.jboss.ejb.plugins.cmp.ejbql.ASTRangeVariableDeclaration; 52 import org.jboss.ejb.plugins.cmp.ejbql.ASTSelect; 53 import org.jboss.ejb.plugins.cmp.ejbql.ASTSqrt; 54 import org.jboss.ejb.plugins.cmp.ejbql.ASTSubstring; 55 import org.jboss.ejb.plugins.cmp.ejbql.ASTUCase; 56 import org.jboss.ejb.plugins.cmp.ejbql.ASTValueClassComparison; 57 import org.jboss.ejb.plugins.cmp.ejbql.ASTWhere; 58 import org.jboss.ejb.plugins.cmp.ejbql.BasicVisitor; 59 import org.jboss.ejb.plugins.cmp.ejbql.Catalog; 60 import org.jboss.ejb.plugins.cmp.ejbql.EJBQLParser; 61 import org.jboss.ejb.plugins.cmp.ejbql.EJBQLTypes; 62 import org.jboss.ejb.plugins.cmp.ejbql.JBossQLParser; 63 import org.jboss.ejb.plugins.cmp.ejbql.Node; 64 import org.jboss.ejb.plugins.cmp.ejbql.SimpleNode; 65 import org.jboss.ejb.plugins.cmp.ejbql.ASTLimitOffset; 66 import org.jboss.ejb.plugins.cmp.ejbql.ASTCount; 67 import org.jboss.ejb.plugins.cmp.ejbql.SelectFunction; 68 import org.jboss.ejb.plugins.cmp.ejbql.ASTExactNumericLiteral; 69 import org.jboss.ejb.plugins.cmp.ejbql.ASTMax; 70 import org.jboss.ejb.plugins.cmp.ejbql.ASTMin; 71 import org.jboss.ejb.plugins.cmp.ejbql.ASTAvg; 72 import org.jboss.ejb.plugins.cmp.ejbql.ASTSum; 73 import org.jboss.ejb.plugins.cmp.ejbql.ASTWhereConditionalTerm; 74 import org.jboss.ejb.plugins.cmp.ejbql.ASTMod; 75 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMPFieldBridge; 76 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge; 77 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge; 78 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge; 79 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractEntityBridge; 80 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData; 81 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData; 82 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCTypeMappingMetaData; 83 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQueryMetaData; 84 import org.jboss.ejb.plugins.cmp.bridge.CMPFieldBridge; 85 import org.jboss.ejb.EntityPersistenceStore; 86 import org.jboss.deployment.DeploymentException; 87 88 95 public final class JDBCEJBQLCompiler extends BasicVisitor implements QLCompiler 96 { 97 private final Catalog catalog; 99 private Class returnType; 100 private Class [] parameterTypes; 101 private JDBCReadAheadMetaData readAhead; 102 private boolean lazyResultSetLoading; 103 104 private AliasManager aliasManager; 106 107 private Set declaredPaths = new HashSet (); 109 private Set ctermJoinPaths = new HashSet (); 110 private Set allJoinPaths = new HashSet (); 111 private Map ctermCollectionMemberJoinPaths = new HashMap (); 112 private Map allCollectionMemberJoinPaths = new HashMap (); 113 private Map ctermLeftJoinPaths = new HashMap (); 114 private Map allLeftJoinPaths = new HashMap (); 115 116 private JDBCTypeMappingMetaData typeMapping; 118 private JDBCTypeFactory typeFactory; 119 private boolean subquerySupported; 120 121 private boolean forceDistinct; 123 private String sql; 124 private int offsetParam; 125 private int offsetValue; 126 private int limitParam; 127 private int limitValue; 128 private JDBCStoreManager selectManager; 129 private Object selectObject; 130 private List inputParameters = new ArrayList (); 131 132 135 private List leftJoinCMRList = new ArrayList (); 136 private StringBuffer onFindCMRJoin; 137 138 private boolean countCompositePk; 139 private String selectAlias; 140 private boolean selectDistinct; 141 142 public JDBCEJBQLCompiler(Catalog catalog) 143 { 144 this.catalog = catalog; 145 } 146 147 public void compileEJBQL(String ejbql, 148 Class returnType, 149 Class [] parameterTypes, 150 JDBCQueryMetaData metadata) throws Exception  151 { 152 reset(); 154 155 this.returnType = returnType; 157 this.parameterTypes = parameterTypes; 158 this.readAhead = metadata.getReadAhead(); 159 this.lazyResultSetLoading = metadata.isLazyResultSetLoading(); 160 161 EJBQLParser parser = new EJBQLParser(new StringReader (SQLUtil.EMPTY_STRING)); 163 164 try 165 { 166 ASTEJBQL ejbqlNode; 168 ejbqlNode = parser.parse(catalog, parameterTypes, ejbql); 169 170 sql = ejbqlNode.jjtAccept(this, new StringBuffer ()).toString(); 172 } 173 catch(Exception e) 174 { 175 reset(); 177 throw e; 178 } 179 catch(Error e) 180 { 181 reset(); 183 throw e; 184 } 185 } 186 187 public void compileJBossQL(String ejbql, 188 Class returnType, 189 Class [] parameterTypes, 190 JDBCQueryMetaData metadata) 191 throws Exception  192 { 193 reset(); 195 196 this.returnType = returnType; 198 this.parameterTypes = parameterTypes; 199 this.readAhead = metadata.getReadAhead(); 200 this.lazyResultSetLoading = metadata.isLazyResultSetLoading(); 201 202 JBossQLParser parser = new JBossQLParser(new StringReader (SQLUtil.EMPTY_STRING)); 204 205 try 206 { 207 ASTEJBQL ejbqlNode; 209 ejbqlNode = parser.parse(catalog, parameterTypes, ejbql); 210 211 sql = ejbqlNode.jjtAccept(this, new StringBuffer ()).toString(); 213 } 214 catch(Exception e) 215 { 216 reset(); 218 throw e; 219 } 220 catch(Error e) 221 { 222 reset(); 224 throw e; 225 } 226 } 227 228 private void reset() 229 { 230 returnType = null; 231 parameterTypes = null; 232 readAhead = null; 233 inputParameters.clear(); 234 declaredPaths.clear(); 235 clearPerTermJoinPaths(); 236 allJoinPaths.clear(); 237 allCollectionMemberJoinPaths.clear(); 238 allLeftJoinPaths.clear(); 239 selectObject = null; 240 selectManager = null; 241 typeFactory = null; 242 typeMapping = null; 243 aliasManager = null; 244 subquerySupported = true; 245 forceDistinct = false; 246 limitParam = 0; 247 limitValue = 0; 248 offsetParam = 0; 249 offsetValue = 0; 250 leftJoinCMRList.clear(); 251 onFindCMRJoin = null; 252 countCompositePk = false; 253 selectAlias = null; 254 selectDistinct = false; 255 } 256 257 public String getSQL() 258 { 259 return sql; 260 } 261 262 public int getOffsetValue() 263 { 264 return offsetValue; 265 } 266 267 public int getOffsetParam() 268 { 269 return offsetParam; 270 } 271 272 public int getLimitValue() 273 { 274 return limitValue; 275 } 276 277 public int getLimitParam() 278 { 279 return limitParam; 280 } 281 282 public boolean isSelectEntity() 283 { 284 return selectObject instanceof JDBCEntityBridge; 285 } 286 287 public JDBCAbstractEntityBridge getSelectEntity() 288 { 289 return (JDBCAbstractEntityBridge) selectObject; 290 } 291 292 public boolean isSelectField() 293 { 294 return selectObject instanceof JDBCCMPFieldBridge; 295 } 296 297 public JDBCFieldBridge getSelectField() 298 { 299 return (JDBCCMPFieldBridge) selectObject; 300 } 301 302 public SelectFunction getSelectFunction() 303 { 304 return (SelectFunction) selectObject; 305 } 306 307 public EntityPersistenceStore getStoreManager() 308 { 309 return selectManager; 310 } 311 312 public List getInputParameters() 313 { 314 return inputParameters; 315 } 316 317 public List getLeftJoinCMRList() 318 { 319 return leftJoinCMRList; 320 } 321 322 public boolean isSelectDistinct() 323 { 324 return selectDistinct; 325 } 326 327 public Object visit(SimpleNode node, Object data) 328 { 329 throw new RuntimeException ("Internal error: Found unknown node type in " + 330 "EJB-QL abstract syntax tree: node=" + node); 331 } 332 333 private void setTypeFactory(JDBCTypeFactory typeFactory) 334 { 335 this.typeFactory = typeFactory; 336 this.typeMapping = typeFactory.getTypeMapping(); 337 aliasManager = new AliasManager(typeMapping.getAliasHeaderPrefix(), 338 typeMapping.getAliasHeaderSuffix(), 339 typeMapping.getAliasMaxLength()); 340 subquerySupported = typeMapping.isSubquerySupported(); 341 } 342 343 private Class getParameterType(int index) 344 { 345 int zeroBasedIndex = index - 1; 346 Class [] params = parameterTypes; 347 if(zeroBasedIndex < params.length) 348 { 349 return params[zeroBasedIndex]; 350 } 351 return null; 352 } 353 354 private void verifyParameterEntityType(int number, 356 JDBCEntityBridge entity) 357 { 358 Class parameterType = getParameterType(number); 359 Class remoteClass = entity.getMetaData().getRemoteClass(); 360 Class localClass = entity.getMetaData().getLocalClass(); 361 if(( 362 localClass == null || 363 !localClass.isAssignableFrom(parameterType) 364 ) && 365 ( 366 remoteClass == null || 367 !remoteClass.isAssignableFrom(parameterType) 368 )) 369 { 370 371 throw new IllegalStateException ("Only like types can be " + 372 "compared: from entity=" + 373 entity.getEntityName() + 374 " to parameter type=" + parameterType); 375 } 376 } 377 378 private void compareEntity(boolean not, 379 Node fromNode, 380 Node toNode, 381 StringBuffer buf) 382 { 383 buf.append('('); 384 if(not) 385 { 386 buf.append(SQLUtil.NOT).append('('); 387 } 388 389 String fromAlias; 390 JDBCEntityBridge fromEntity; 391 ASTPath fromPath = (ASTPath) fromNode; 392 addJoinPath(fromPath); 393 fromAlias = aliasManager.getAlias(fromPath.getPath()); 394 fromEntity = (JDBCEntityBridge) fromPath.getEntity(); 395 396 if(toNode instanceof ASTParameter) 397 { 398 ASTParameter toParam = (ASTParameter) toNode; 399 400 verifyParameterEntityType(toParam.number, fromEntity); 402 403 inputParameters.addAll(QueryParameter.createParameters(toParam.number - 1, fromEntity)); 404 405 SQLUtil.getWhereClause(fromEntity.getPrimaryKeyFields(), fromAlias, buf); 406 } 407 else 408 { 409 String toAlias; 410 JDBCEntityBridge toEntity; 411 ASTPath toPath = (ASTPath) toNode; 412 addJoinPath(toPath); 413 toAlias = aliasManager.getAlias(toPath.getPath()); 414 toEntity = (JDBCEntityBridge) toPath.getEntity(); 415 416 if(!fromEntity.equals(toEntity)) 418 { 419 throw new IllegalStateException ("Only like types can be " + 420 "compared: from entity=" + 421 fromEntity.getEntityName() + 422 " to entity=" + toEntity.getEntityName()); 423 } 424 425 SQLUtil.getSelfCompareWhereClause(fromEntity.getPrimaryKeyFields(), fromAlias, toAlias, buf); 426 } 427 428 if(not) 429 { 430 buf.append(')'); 431 } 432 buf.append(')'); 433 } 434 435 private void existsClause(ASTPath path, StringBuffer buf, boolean not) 436 { 437 if(!path.isCMRField()) 438 { 439 throw new IllegalArgumentException ("path must be a cmr field"); 440 } 441 442 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge) path.getCMRField(); 443 String pathStr = path.getPath(path.size() - 2); 444 String parentAlias = aliasManager.getAlias(pathStr); 445 446 if(!subquerySupported) 448 { 449 addLeftJoinPath(pathStr, path); 451 forceDistinct = true; 452 453 addJoinPath(path); 454 455 if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) 456 { 457 JDBCEntityBridge childEntity = (JDBCEntityBridge) cmrField.getRelatedEntity(); 458 String childAlias = aliasManager.getAlias(path.getPath()); 459 SQLUtil.getIsNullClause(!not, childEntity.getPrimaryKeyFields(), childAlias, buf); 460 } 461 else 462 { 463 String relationTableAlias = aliasManager.getRelationTableAlias(path.getPath()); 464 SQLUtil.getIsNullClause(!not, cmrField.getTableKeyFields(), relationTableAlias, buf); 465 } 466 return; 467 } 468 469 if(not) 470 { 471 buf.append(SQLUtil.NOT); 472 } 473 buf.append(SQLUtil.EXISTS).append('('); 474 475 if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) 476 { 477 JDBCEntityBridge childEntity = (JDBCEntityBridge) cmrField.getRelatedEntity(); 478 String childAlias = aliasManager.getAlias(path.getPath()); 479 480 buf.append(SQLUtil.SELECT); 481 482 SQLUtil.getColumnNamesClause(childEntity.getPrimaryKeyFields(), childAlias, buf) 483 .append(SQLUtil.FROM) 484 .append(childEntity.getQualifiedTableName()).append(' ').append(childAlias) 485 .append(SQLUtil.WHERE); 486 SQLUtil.getJoinClause(cmrField, parentAlias, childAlias, buf); 487 } 488 else 489 { 490 String relationTableAlias = aliasManager.getRelationTableAlias(path.getPath()); 491 buf.append(SQLUtil.SELECT); 492 SQLUtil.getColumnNamesClause(cmrField.getTableKeyFields(), relationTableAlias, buf) 493 .append(SQLUtil.FROM) 494 .append(cmrField.getQualifiedTableName()) 495 .append(' ') 496 .append(relationTableAlias) 497 .append(SQLUtil.WHERE); 498 SQLUtil.getRelationTableJoinClause(cmrField, parentAlias, relationTableAlias, buf); 499 } 500 501 buf.append(')'); 502 } 503 504 public Object visit(ASTEJBQL node, Object data) 505 { 506 Node selectNode = node.jjtGetChild(0); 507 Node fromNode = node.jjtGetChild(1); 508 Node whereNode = null; 509 Node orderByNode = null; 510 Node limitNode = null; 511 512 for(int childNode = 2; childNode < node.jjtGetNumChildren(); childNode++) 513 { 514 Node temp = node.jjtGetChild(childNode); 515 if(temp instanceof ASTWhere) 516 { 517 whereNode = temp; 518 } 519 else if(temp instanceof ASTOrderBy) 520 { 521 orderByNode = temp; 522 } 523 else if(temp instanceof ASTLimitOffset) 524 { 525 limitNode = temp; 526 } 527 } 528 529 StringBuffer select = new StringBuffer (); 531 selectNode.jjtAccept(this, select); 532 533 Set selectJoinPaths = new HashSet (ctermJoinPaths); 537 Map selectCollectionMemberJoinPaths = new HashMap (ctermCollectionMemberJoinPaths); 538 Map selectLeftJoinPaths = new HashMap (ctermLeftJoinPaths); 539 540 StringBuffer where = new StringBuffer (); 542 if(whereNode != null) 543 { 544 whereNode.jjtAccept(this, where); 545 } 546 547 ctermJoinPaths = selectJoinPaths; 549 ctermCollectionMemberJoinPaths = selectCollectionMemberJoinPaths; 550 ctermLeftJoinPaths = selectLeftJoinPaths; 551 552 StringBuffer orderBy = new StringBuffer (); 554 if(orderByNode != null) 555 { 556 orderByNode.jjtAccept(this, orderBy); 557 558 for(int i = 0; i < orderByNode.jjtGetNumChildren(); i++) 560 { 561 Node orderByPath = orderByNode.jjtGetChild(i); 562 ASTPath path = (ASTPath) orderByPath.jjtGetChild(0); 563 if(!isSelected(path)) 564 { 565 select.append(SQLUtil.COMMA); 566 path.jjtAccept(this, select); 567 } 568 } 569 } 570 571 if(limitNode != null) 572 { 573 limitNode.jjtAccept(this, null); 574 } 575 576 StringBuffer from = new StringBuffer (50); 577 fromNode.jjtAccept(this, from); 578 579 StringBuffer fromThetaJoin = new StringBuffer (); 580 createThetaJoin(fromThetaJoin); 581 582 if(where.length() != 0 && fromThetaJoin.length() != 0) 583 { 584 where.insert(0, '(') 585 .append(')') 586 .append(SQLUtil.AND) 587 .append(fromThetaJoin); 588 } 589 else if(fromThetaJoin.length() != 0) 590 { 591 where.append(fromThetaJoin.toString()); 592 } 593 594 selectDistinct = isDistinct(selectNode); 595 596 if(lazyResultSetLoading) 598 { 599 StringBuffer buf = new StringBuffer (200); 600 if(isSelectEntity()) 601 { 602 final JDBCFieldBridge[] pkFields = getSelectEntity().getPrimaryKeyFields(); 603 if(pkFields.length == 1) 604 { 605 buf.append('(').append(SQLUtil.SELECT).append("count("); 606 if(selectDistinct) 607 { 608 buf.append(SQLUtil.DISTINCT); 609 } 610 SQLUtil.getColumnNamesClause(pkFields, selectAlias, buf); 611 buf.append(')').append(SQLUtil.FROM); 612 buf.append(from); 613 if(where.length() > 0) 614 { 615 buf.append(SQLUtil.WHERE).append(where); 616 } 617 buf.append("), "); 618 select.insert(0, buf); 619 } 620 else 621 { 622 buf.append('(').append(SQLUtil.SELECT).append("count(*)").append(SQLUtil.FROM) 623 .append('(') 624 .append(SQLUtil.SELECT); 625 626 if(selectDistinct) 627 { 628 buf.append(SQLUtil.DISTINCT); 629 } 630 631 SQLUtil.getColumnNamesClause(pkFields, selectAlias, buf); 632 buf.append(SQLUtil.FROM).append(from); 633 634 if(where.length() > 0) 635 { 636 buf.append(SQLUtil.WHERE).append(where); 637 } 638 buf.append(") t_count), "); 639 select.insert(0, buf); 640 } 641 } 642 else if(isSelectField()) 643 { 644 buf.append('(').append(SQLUtil.SELECT).append("count("); 645 if(selectDistinct) 646 { 647 buf.append(SQLUtil.DISTINCT); 648 } 649 buf.append(select).append(')').append(SQLUtil.FROM); 650 buf.append(from); 651 if(where.length() > 0) 652 { 653 buf.append(SQLUtil.WHERE).append(where); 654 } 655 buf.append("), "); 656 select.insert(0, buf); 657 } 658 } 659 660 if(selectDistinct) 662 { 663 select.insert(0, SQLUtil.DISTINCT); 664 } 665 666 StringBuffer buf = (StringBuffer ) data; 667 if(selectManager.getMetaData().hasRowLocking()) 668 { 669 JDBCFunctionMappingMetaData rowLockingTemplate = typeMapping.getRowLockingTemplate(); 670 Object args[] = new Object []{ 671 select, 672 from, 673 where.length() == 0 ? null : where, 674 orderBy.length() == 0 ? null : orderBy 675 }; 676 rowLockingTemplate.getFunctionSql(args, buf); 677 } 678 else 679 { 680 buf.append(SQLUtil.SELECT) 681 .append(select) 682 .append(SQLUtil.FROM) 683 .append(from); 684 685 if(where.length() > 0) 686 { 687 buf.append(SQLUtil.WHERE) 688 .append(where); 689 } 690 691 if(orderBy.length() != 0) 692 { 693 buf.append(SQLUtil.ORDERBY) 694 .append(orderBy); 695 } 696 } 697 698 if(countCompositePk) 700 { 701 buf.insert(0, "SELECT COUNT(*) FROM (").append(") t_count"); 702 } 703 704 return buf; 705 } 706 707 public Object visit(ASTFrom node, Object data) 708 { 709 StringBuffer buf = (StringBuffer ) data; 710 711 node.jjtGetChild(0).jjtAccept(this, buf); 712 for(int i = 1; i < node.jjtGetNumChildren(); i++) 713 { 714 buf.append(SQLUtil.COMMA); 715 node.jjtGetChild(i).jjtAccept(this, buf); 716 } 717 718 if(!allJoinPaths.isEmpty()) 720 { 721 for(Iterator iter = allJoinPaths.iterator(); iter.hasNext();) 722 { 723 ASTPath path = (ASTPath) iter.next(); 724 for(int i = 0; i < path.size(); i++) 725 { 726 declareTables(path, i, buf); 727 } 728 } 729 } 730 731 if(!allCollectionMemberJoinPaths.isEmpty()) 733 { 734 for(Iterator iter = allCollectionMemberJoinPaths.values().iterator(); iter.hasNext();) 735 { 736 ASTPath path = (ASTPath) iter.next(); 737 for(int i = 0; i < path.size() - 1; i++) 739 { 740 declareTables(path, i, buf); 741 } 742 } 743 } 744 745 if(!allLeftJoinPaths.isEmpty()) 747 { 748 Set allLeftJoins = new HashSet (); 749 for(Iterator iter = allLeftJoinPaths.values().iterator(); iter.hasNext();) 750 { 751 allLeftJoins.addAll((Set ) iter.next()); 752 } 753 754 for(Iterator iter = allLeftJoins.iterator(); iter.hasNext();) 756 { 757 ASTPath path = (ASTPath) iter.next(); 758 for(int i = 0; i < path.size() - 1; i++) 760 { 761 declareTables(path, i, buf); 762 } 763 } 764 } 765 766 return buf; 767 } 768 769 private void declareTables(ASTPath path, int i, StringBuffer buf) 770 { 771 if(!path.isCMRField(i) || declaredPaths.contains(path.getPath(i))) 772 { 773 return; 774 } 775 776 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge) path.getCMRField(i); 777 JDBCEntityBridge entity = (JDBCEntityBridge) path.getEntity(i); 778 779 buf.append(SQLUtil.COMMA) 780 .append(entity.getQualifiedTableName()) 781 .append(' ') 782 .append(aliasManager.getAlias(path.getPath(i))); 783 leftJoins(path.getPath(i), buf); 784 785 if(cmrField.getRelationMetaData().isTableMappingStyle()) 786 { 787 String relationTableAlias = aliasManager.getRelationTableAlias(path.getPath(i)); 788 buf.append(SQLUtil.COMMA) 789 .append(cmrField.getQualifiedTableName()) 790 .append(' ') 791 .append(relationTableAlias); 792 } 793 794 declaredPaths.add(path.getPath(i)); 795 } 796 797 private void leftJoins(String parentPath, StringBuffer buf) 798 { 799 Set paths = (Set ) ctermLeftJoinPaths.get(parentPath); 800 if(subquerySupported || paths == null) 801 { 802 return; 803 } 804 805 for(Iterator iter = paths.iterator(); iter.hasNext();) 806 { 807 ASTPath path = (ASTPath) iter.next(); 808 809 |