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 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge) path.getCMRField(); 810 String parentAlias = aliasManager.getAlias(parentPath); 811 812 if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) 813 { 814 JDBCEntityBridge childEntity = (JDBCEntityBridge) cmrField.getRelatedEntity(); 815 String childAlias = aliasManager.getAlias(path.getPath()); 816 817 buf.append(SQLUtil.LEFT_JOIN) 818 .append(childEntity.getQualifiedTableName()) 819 .append(' ') 820 .append(childAlias) 821 .append(SQLUtil.ON); 822 SQLUtil.getJoinClause(cmrField, parentAlias, childAlias, buf); 823 } 824 else 825 { 826 String relationTableAlias = aliasManager.getRelationTableAlias(path.getPath()); 827 buf.append(SQLUtil.LEFT_JOIN) 828 .append(cmrField.getQualifiedTableName()) 829 .append(' ') 830 .append(relationTableAlias) 831 .append(SQLUtil.ON); 832 SQLUtil.getRelationTableJoinClause(cmrField, parentAlias, relationTableAlias, buf); 833 } 834 } 835 } 836 837 private void createThetaJoin(StringBuffer buf) 838 { 839 Set joinedAliases = new HashSet (); 840 if(!ctermJoinPaths.isEmpty()) 842 { 843 for(Iterator iter = ctermJoinPaths.iterator(); iter.hasNext();) 844 { 845 ASTPath path = (ASTPath) iter.next(); 846 for(int i = 0; i < path.size(); i++) 847 { 848 createThetaJoin(path, i, joinedAliases, buf); 849 } 850 } 851 } 852 853 if(!ctermCollectionMemberJoinPaths.isEmpty()) 855 { 856 for(Iterator iter = ctermCollectionMemberJoinPaths.entrySet().iterator(); iter.hasNext();) 857 { 858 Map.Entry entry = (Map.Entry ) iter.next(); 859 String childAlias = (String ) entry.getKey(); 860 ASTPath path = (ASTPath) entry.getValue(); 861 862 createThetaJoin(path, path.size() - 1, joinedAliases, childAlias, buf); 864 865 for(int i = 0; i < path.size() - 1; i++) 867 { 868 createThetaJoin(path, i, joinedAliases, buf); 869 } 870 } 871 } 872 873 if(!ctermLeftJoinPaths.isEmpty()) 875 { 876 Set allLeftJoins = new HashSet (); 877 for(Iterator iter = ctermLeftJoinPaths.values().iterator(); iter.hasNext();) 878 { 879 allLeftJoins.addAll((Set ) iter.next()); 880 } 881 882 for(Iterator iter = allLeftJoins.iterator(); iter.hasNext();) 884 { 885 ASTPath path = (ASTPath) iter.next(); 886 for(int i = 0; i < path.size() - 1; i++) 888 { 889 createThetaJoin(path, i, joinedAliases, buf); 890 } 891 } 892 } 893 } 894 895 private void createThetaJoin(ASTPath path, 896 int i, 897 Set joinedAliases, 898 StringBuffer buf) 899 { 900 String childAlias = aliasManager.getAlias(path.getPath(i)); 901 createThetaJoin(path, i, joinedAliases, childAlias, buf); 902 } 903 904 private void createThetaJoin(ASTPath path, 905 int i, 906 Set joinedAliases, 907 String childAlias, 908 StringBuffer buf) 909 { 910 if(!path.isCMRField(i) || joinedAliases.contains(childAlias)) 911 { 912 return; 913 } 914 915 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge) path.getCMRField(i); 916 String parentAlias = aliasManager.getAlias(path.getPath(i - 1)); 917 918 if(joinedAliases.size() > 0) 919 { 920 buf.append(SQLUtil.AND); 921 } 922 923 if(cmrField.getRelationMetaData().isForeignKeyMappingStyle()) 924 { 925 SQLUtil.getJoinClause(cmrField, parentAlias, childAlias, buf); 926 } 927 else 928 { 929 String relationTableAlias = aliasManager.getRelationTableAlias(path.getPath(i)); 930 931 SQLUtil.getRelationTableJoinClause(cmrField, parentAlias, relationTableAlias, buf) 933 .append(SQLUtil.AND); 934 SQLUtil.getRelationTableJoinClause(cmrField.getRelatedCMRField(), childAlias, relationTableAlias, buf); 936 } 937 938 joinedAliases.add(childAlias); 939 } 940 941 942 public Object visit(ASTCollectionMemberDeclaration node, Object data) 943 { 944 StringBuffer buf = (StringBuffer ) data; 945 946 ASTPath path = (ASTPath) node.jjtGetChild(0); 948 949 declaredPaths.add(path.getPath()); 951 952 JDBCEntityBridge entity = (JDBCEntityBridge) path.getEntity(); 954 955 ASTIdentifier id = (ASTIdentifier) node.jjtGetChild(1); 957 958 String alias = aliasManager.getAlias(id.identifier); 960 961 addCollectionMemberJoinPath(alias, path); 963 964 aliasManager.addAlias(path.getPath(), alias); 966 967 buf.append(entity.getQualifiedTableName()); 968 buf.append(' '); 969 buf.append(alias); 970 leftJoins(path.getPath(), buf); 971 972 if(onFindCMRJoin != null && alias.equals(selectAlias)) 973 { 974 buf.append(onFindCMRJoin); 975 onFindCMRJoin = null; 976 } 977 978 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge) path.getCMRField(); 980 if(cmrField.getRelationMetaData().isTableMappingStyle()) 981 { 982 String relationTableAlias = aliasManager.getRelationTableAlias(path.getPath()); 983 buf.append(SQLUtil.COMMA) 984 .append(cmrField.getQualifiedTableName()) 985 .append(' ') 986 .append(relationTableAlias); 987 } 988 989 return buf; 990 } 991 992 public Object visit(ASTRangeVariableDeclaration node, Object data) 993 { 994 StringBuffer buf = (StringBuffer ) data; 995 996 ASTAbstractSchema schema = (ASTAbstractSchema) node.jjtGetChild(0); 997 JDBCEntityBridge entity = (JDBCEntityBridge) schema.entity; 998 ASTIdentifier id = (ASTIdentifier) node.jjtGetChild(1); 999 1000 String alias = aliasManager.getAlias(id.identifier); 1001 buf.append(entity.getQualifiedTableName()) 1002 .append(' ') 1003 .append(alias); 1004 leftJoins(id.identifier, buf); 1005 1006 if(onFindCMRJoin != null && alias.equals(selectAlias)) 1007 { 1008 buf.append(onFindCMRJoin); 1009 onFindCMRJoin = null; 1010 } 1011 1012 return buf; 1013 } 1014 1015 public Object visit(ASTSelect node, Object data) 1016 { 1017 StringBuffer buf = (StringBuffer ) data; 1018 1019 Node child0 = node.jjtGetChild(0); 1020 ASTPath path; 1021 if(child0 instanceof ASTPath) 1022 { 1023 path = (ASTPath) child0; 1024 1025 if(path.isCMPField()) 1026 { 1027 JDBCCMPFieldBridge selectField = (JDBCCMPFieldBridge) path.getCMPField(); 1029 selectManager = (JDBCStoreManager) selectField.getManager(); 1030 selectObject = selectField; 1031 setTypeFactory(selectManager.getJDBCTypeFactory()); 1032 1033 addJoinPath(path); 1034 selectAlias = aliasManager.getAlias(path.getPath(path.size() - 2)); 1035 SQLUtil.getColumnNamesClause(selectField, selectAlias, buf); 1036 } 1037 else 1038 { 1039 JDBCEntityBridge selectEntity = (JDBCEntityBridge) path.getEntity(); 1041 selectManager = (JDBCStoreManager) selectEntity.getManager(); 1042 selectObject = selectEntity; 1043 setTypeFactory(selectManager.getJDBCTypeFactory()); 1044 selectEntity(path, buf); 1045 } 1046 } 1047 else 1048 { 1049 path = getPathFromChildren(child0); 1051 1052 if(path == null) 1053 { 1054 throw new IllegalStateException ("The function in SELECT clause does not contain a path expression."); 1055 } 1056 1057 if(path.isCMPField()) 1058 { 1059 JDBCCMPFieldBridge selectField = (JDBCCMPFieldBridge) path.getCMPField(); 1060 selectManager = (JDBCStoreManager) selectField.getManager(); 1061 } 1062 else if(path.isCMRField()) 1063 { 1064 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge) path.getCMRField(); 1065 selectManager = (JDBCStoreManager) cmrField.getEntity().getManager(); 1066 addJoinPath(path); 1067 } 1068 else 1069 { 1070 final JDBCEntityBridge entity = (JDBCEntityBridge) path.getEntity(); 1071 selectManager = (JDBCStoreManager) entity.getManager(); 1072 addJoinPath(path); 1073 } 1074 1075 setTypeFactory(selectManager.getJDBCTypeFactory()); 1076 selectObject = child0; 1077 child0.jjtAccept(this, buf); 1078 } 1079 1080 return buf; 1081 } 1082 1083 1086 public Object visit(ASTWhere node, Object data) 1087 { 1088 node.jjtGetChild(0).jjtAccept(this, data); 1089 return data; 1090 } 1091 1092 public Object visit(ASTNullComparison node, Object data) 1093 { 1094 StringBuffer buf = (StringBuffer ) data; 1095 1096 final Node child0 = node.jjtGetChild(0); 1097 if(child0 instanceof ASTPath) 1098 { 1099 ASTPath path = (ASTPath) child0; 1100 1101 if(path.isCMRField()) 1102 { 1103 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge) path.getCMRField(); 1104 if(cmrField.getRelationMetaData().isTableMappingStyle()) 1105 { 1106 existsClause(path, buf, !node.not); 1107 return buf; 1108 } 1109 } 1110 1111 String alias = aliasManager.getAlias(path.getPath(path.size() - 2)); 1112 JDBCFieldBridge field = (JDBCFieldBridge) path.getField(); 1113 1114 if(field.getJDBCType() == null) 1119 { 1120 existsClause(path, buf, !node.not); 1121 return buf; 1122 } 1123 1124 if(path.fieldList.size() > 2) 1126 { 1127 for(int i = 0; i < path.fieldList.size(); ++i) 1128 { 1129 Object pathEl = path.fieldList.get(i); 1130 if(pathEl instanceof JDBCCMRFieldBridge) 1131 { 1132 addJoinPath(path); 1133 break; 1134 } 1135 } 1136 } 1137 1138 buf = SQLUtil.getIsNullClause(node.not, field, alias, buf); 1139 } 1140 else if(child0 instanceof ASTParameter) 1141 { 1142 ASTParameter param = (ASTParameter) child0; 1143 Class type = getParameterType(param.number); 1144 1145 QueryParameter queryParam = new QueryParameter(param.number - 1, typeFactory.getJDBCType(type)); 1146 inputParameters.add(queryParam); 1147 1148 buf.append("? IS "); 1149 if(node.not) 1150 { 1151 buf.append(SQLUtil.NOT); 1152 } 1153 buf.append(SQLUtil.NULL); 1154 } 1155 else 1156 { 1157 throw new IllegalStateException ("Unexpected node in IS NULL clause: " + node); 1158 } 1159 1160 return buf; 1161 } 1162 1163 public Object visit(ASTIsEmpty node, Object data) 1164 { 1165 StringBuffer buf = (StringBuffer ) data; 1166 ASTPath path = (ASTPath) node.jjtGetChild(0); 1167 1168 existsClause(path, buf, !node.not); 1169 return buf; 1170 } 1171 1172 1175 public Object visit(ASTMemberOf node, Object data) 1176 { 1177 StringBuffer buf = (StringBuffer ) data; 1178 1179 ASTPath toPath = (ASTPath) node.jjtGetChild(1); 1181 1182 JDBCCMRFieldBridge toCMRField = (JDBCCMRFieldBridge) toPath.getCMRField(); 1183 1184 JDBCEntityBridge toChildEntity = (JDBCEntityBridge) toPath.getEntity(); 1185 1186 String pathStr = toPath.getPath(toPath.size() - 2); 1187 String toParentAlias = aliasManager.getAlias(pathStr); 1188 String toChildAlias = aliasManager.getAlias(toPath.getPath()); 1189 String relationTableAlias = null; 1190 if(toCMRField.getRelationMetaData().isTableMappingStyle()) 1191 { 1192 relationTableAlias = aliasManager.getRelationTableAlias(toPath.getPath()); 1193 } 1194 1195 String fromAlias = null; 1197 int fromParamNumber = -1; 1198 if(node.jjtGetChild(0) instanceof ASTParameter) 1199 { 1200 ASTParameter fromParam = (ASTParameter) node.jjtGetChild(0); 1201 1202 verifyParameterEntityType(fromParam.number, toChildEntity); 1204 1205 fromParamNumber = fromParam.number; 1206 } 1207 else 1208 { 1209 ASTPath fromPath = (ASTPath) node.jjtGetChild(0); 1210 addJoinPath(fromPath); 1211 1212 JDBCEntityBridge fromEntity = (JDBCEntityBridge) fromPath.getEntity(); 1213 fromAlias = aliasManager.getAlias(fromPath.getPath()); 1214 1215 if(!fromEntity.equals(toChildEntity)) 1217 { 1218 throw new IllegalStateException ("Only like types can be " + 1219 "compared: from entity=" + 1220 fromEntity.getEntityName() + 1221 " to entity=" + toChildEntity.getEntityName()); 1222 } 1223 } 1224 1225 addLeftJoinPath(pathStr, toPath); 1227 1228 if(!subquerySupported) 1230 { 1231 addJoinPath(toPath); 1232 1233 if(node.not) 1235 { 1236 buf.append(SQLUtil.NOT); 1237 } 1238 buf.append('('); 1239 1240 if(relationTableAlias == null) 1241 { 1242 SQLUtil.getIsNullClause(true, toChildEntity.getPrimaryKeyFields(), toChildAlias, buf); 1243 } 1244 else 1245 { 1246 SQLUtil.getIsNullClause(true, toCMRField.getTableKeyFields(), relationTableAlias, buf); 1247 } 1248 } 1249 else 1250 { 1251 if(node.not) 1253 { 1254 buf.append(SQLUtil.NOT); 1255 } 1256 1257 buf.append(SQLUtil.EXISTS).append('('); 1258 1259 if(relationTableAlias == null) 1260 { 1261 buf.append(SQLUtil.SELECT); 1262 SQLUtil.getColumnNamesClause(toChildEntity.getPrimaryKeyFields(), toChildAlias, buf) 1263 .append(SQLUtil.FROM) 1264 .append(toChildEntity.getQualifiedTableName()) 1265 .append(' ') 1266 .append(toChildAlias) 1267 .append(SQLUtil.WHERE); 1268 SQLUtil.getJoinClause(toCMRField, toParentAlias, toChildAlias, buf); 1269 } 1270 else 1271 { 1272 buf.append(SQLUtil.SELECT); 1273 SQLUtil.getColumnNamesClause(toCMRField.getRelatedCMRField().getTableKeyFields(), relationTableAlias, buf) 1274 .append(SQLUtil.FROM) 1275 .append(toCMRField.getQualifiedTableName()) 1276 .append(' ') 1277 .append(relationTableAlias) 1278 .append(SQLUtil.WHERE); 1279 SQLUtil.getRelationTableJoinClause(toCMRField, toParentAlias, relationTableAlias, buf); 1280 } 1281 } 1282 1283 buf.append(SQLUtil.AND); 1284 1285 if(fromAlias != null) 1287 { 1288 if(relationTableAlias == null) 1290 { 1291 SQLUtil.getSelfCompareWhereClause(toChildEntity.getPrimaryKeyFields(), 1292 toChildAlias, 1293 fromAlias, 1294 buf); 1295 } 1296 else 1297 { 1298 SQLUtil.getRelationTableJoinClause(toCMRField.getRelatedCMRField(), 1299 fromAlias, 1300 relationTableAlias, 1301 buf); 1302 } 1303 } 1304 else 1305 { 1306 inputParameters.addAll(QueryParameter.createParameters(fromParamNumber - 1, 1308 toChildEntity)); 1309 1310 if(relationTableAlias == null) 1312 { 1313 SQLUtil.getWhereClause(toChildEntity.getPrimaryKeyFields(), toChildAlias, buf); 1314 } 1315 else 1316 { 1317 SQLUtil.getWhereClause(toCMRField.getRelatedCMRField().getTableKeyFields(), 1318 relationTableAlias, 1319 buf); 1320 } 1321 } 1322 1323 buf.append(')'); 1324 1325 return buf; 1326 } 1327 1328 public Object visit(ASTValueClassComparison node, Object data) 1329 { 1330 StringBuffer buf = (StringBuffer ) data; 1331 1332 boolean not = (node.opp.equals(SQLUtil.NOT_EQUAL)); 1333 String comparison = node.opp; 1334 buf.append('('); 1335 if(not) 1336 { 1337 buf.append(SQLUtil.NOT).append('('); 1338 comparison = "="; 1339 } 1340 1341 ASTPath fromPath = (ASTPath) node.jjtGetChild(0); 1343 addJoinPath(fromPath); 1344 String fromAlias = aliasManager.getAlias(fromPath.getPath(fromPath.size() - 2)); 1345 JDBCCMPFieldBridge fromCMPField = (JDBCCMPFieldBridge) fromPath.getCMPField(); 1346 1347 Node toNode = node.jjtGetChild(1); 1348 if(toNode instanceof ASTParameter) 1349 { 1350 ASTParameter toParam = (ASTParameter) toNode; 1351 1352 Class parameterType = getParameterType(toParam.number); 1354 if(!(fromCMPField.getFieldType().equals(parameterType))) 1355 { 1356 throw new IllegalStateException ("Only like types can be " + 1357 "compared: from CMP field=" + 1358 fromCMPField.getFieldType() + 1359 " to parameter=" + parameterType); 1360 } 1361 1362 inputParameters.addAll(QueryParameter.createParameters(toParam.number - 1, fromCMPField)); 1363 SQLUtil.getWhereClause(fromCMPField.getJDBCType(), fromAlias, comparison, buf); 1364 } 1365 else 1366 { 1367 ASTPath toPath = (ASTPath) toNode; 1368 addJoinPath(toPath); 1369 String toAlias = aliasManager.getAlias(toPath.getPath(toPath.size() - 2)); 1370 JDBCCMPFieldBridge toCMPField = (JDBCCMPFieldBridge) toPath.getCMPField(); 1371 1372 if(!(fromCMPField.getFieldType().equals(toCMPField.getFieldType()))) 1374 { 1375 throw new IllegalStateException ("Only like types can be " + 1376 "compared: from CMP field=" + 1377 fromCMPField.getFieldType() + 1378 " to CMP field=" + toCMPField.getFieldType()); 1379 } 1380 1381 SQLUtil.getSelfCompareWhereClause(fromCMPField, toCMPField, fromAlias, toAlias, comparison, buf); 1382 } 1383 1384 return (not ? buf.append(')') : buf).append(')'); 1385 } 1386 1387 1390 public Object visit(ASTEntityComparison node, Object data) 1391 { 1392 StringBuffer buf = (StringBuffer ) data; 1393 Node arg0 = node.jjtGetChild(0); 1394 Node arg1 = node.jjtGetChild(1); 1395 if(node.opp.equals(SQLUtil.NOT_EQUAL)) 1396 { 1397 compareEntity(true, arg0, arg1, buf); 1398 } 1399 else 1400 { 1401 compareEntity(false, arg0, arg1, buf); 1402 } 1403 return buf; 1404 } 1405 1406 1409 public Object visit(ASTConcat node, Object data) 1410 { 1411 StringBuffer buf = (StringBuffer ) data; 1412 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.CONCAT); 1413 Object [] args = new Object []{ 1414 new NodeStringWrapper(node.jjtGetChild(0)), 1415 new NodeStringWrapper(node.jjtGetChild(1)), 1416 }; 1417 function.getFunctionSql(args, buf); 1418 return buf; 1419 } 1420 1421 1424 public Object visit(ASTSubstring node, Object data) 1425 { 1426 StringBuffer buf = (StringBuffer ) data; 1427 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.SUBSTRING); 1428 Object [] args = new Object []{ 1429 new NodeStringWrapper(node.jjtGetChild(0)), 1430 new NodeStringWrapper(node.jjtGetChild(1)), 1431 new NodeStringWrapper(node.jjtGetChild(2)), 1432 }; 1433 function.getFunctionSql(args, buf); 1434 return buf; 1435 } 1436 1437 1440 public Object visit(ASTLCase node, Object data) 1441 { 1442 StringBuffer buf = (StringBuffer ) data; 1443 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.LCASE); 1444 Object [] args = new Object []{ 1445 new NodeStringWrapper(node.jjtGetChild(0)), 1446 }; 1447 function.getFunctionSql(args, buf); 1448 return buf; 1449 } 1450 1451 1454 public Object visit(ASTUCase node, Object data) 1455 { 1456 StringBuffer buf = (StringBuffer ) data; 1457 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.UCASE); 1458 Object [] args = new Object []{ 1459 new NodeStringWrapper(node.jjtGetChild(0)), 1460 }; 1461 function.getFunctionSql(args, buf); 1462 return buf; 1463 } 1464 1465 1468 public Object visit(ASTLength node, Object data) 1469 { 1470 StringBuffer buf = (StringBuffer ) data; 1471 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.LENGTH); 1472 Object [] args = new Object []{ 1473 new NodeStringWrapper(node.jjtGetChild(0)), 1474 }; 1475 function.getFunctionSql(args, buf); 1476 return buf; 1477 } 1478 1479 1482 public Object visit(ASTLocate node, Object data) 1483 { 1484 StringBuffer buf = (StringBuffer ) data; 1485 1486 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.LOCATE); 1487 Object [] args = new Object [3]; 1488 args[0] = new NodeStringWrapper(node.jjtGetChild(0)); 1489 args[1] = new NodeStringWrapper(node.jjtGetChild(1)); 1490 if(node.jjtGetNumChildren() == 3) 1491 { 1492 args[2] = new NodeStringWrapper(node.jjtGetChild(2)); 1493 } 1494 else 1495 { 1496 args[2] = "1"; 1497 } 1498 1499 function.getFunctionSql(args, buf); 1501 return buf; 1502 } 1503 1504 1507 public Object visit(ASTAbs node, Object data) 1508 { 1509 StringBuffer buf = (StringBuffer ) data; 1510 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.ABS); 1511 Object [] args = new Object []{ 1512 new NodeStringWrapper(node.jjtGetChild(0)), 1513 }; 1514 function.getFunctionSql(args, buf); 1515 return buf; 1516 } 1517 1518 1521 public Object visit(ASTMod node, Object data) 1522 { 1523 StringBuffer buf = (StringBuffer ) data; 1524 JDBCFunctionMappingMetaData function = JDBCTypeMappingMetaData.MOD_FUNC; 1526 Object [] args = new Object []{ 1527 new NodeStringWrapper(node.jjtGetChild(0)), 1528 new NodeStringWrapper(node.jjtGetChild(1)), 1529 }; 1530 function.getFunctionSql(args, buf); 1531 return buf; 1532 } 1533 1534 1537 public Object visit(ASTSqrt node, Object data) 1538 { 1539 StringBuffer buf = (StringBuffer ) data; 1540 JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.SQRT); 1541 Object [] args = new Object []{ 1542 new NodeStringWrapper(node.jjtGetChild(0)) 1543 }; 1544 function.getFunctionSql(args, buf); 1545 return buf; 1546 } 1547 1548 public Object visit(ASTCount node, Object data) 1549 { 1550 StringBuffer buf = (StringBuffer ) data; 1551 node.setResultType(returnType); 1552 1553 Object args[]; 1554 final ASTPath cntPath = (ASTPath) node.jjtGetChild(0); 1555 if(cntPath.isCMPField()) 1556 { 1557 args = new Object []{node.distinct, new NodeStringWrapper(cntPath)}; 1558 } 1559 else 1560 { 1561 JDBCEntityBridge entity = (JDBCEntityBridge) cntPath.getEntity(); 1562 final JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields(); 1563 if(pkFields.length > 1) 1564 { 1565 countCompositePk = true; 1566 forceDistinct = node.distinct.length() > 0; 1567 selectEntity(cntPath, buf); 1568 return buf; 1569 } 1570 else 1571 { 1572 1573 final String alias = aliasManager.getAlias(cntPath.getPath()); 1574 StringBuffer keyColumn = new StringBuffer (20); 1575 SQLUtil.getColumnNamesClause(pkFields[0], alias, keyColumn); 1576 args = new Object []{node.distinct, keyColumn.toString()}; 1577 } 1578 } 1579 1580 return JDBCTypeMappingMetaData.COUNT_FUNC.getFunctionSql(args, buf); 1581 } 1582 1583 public Object visit(ASTMax node, Object data) 1584 { 1585 node.setResultType(returnType); 1586 StringBuffer buf = (StringBuffer ) data; 1587 Object [] args = new Object []{ 1588 node.distinct, 1589 new NodeStringWrapper(node.jjtGetChild(0)) 1590 }; 1591 return JDBCTypeMappingMetaData.MAX_FUNC.getFunctionSql(args, buf); 1592 } 1593 1594 public Object visit(ASTMin node, Object data) 1595 { 1596 node.setResultType(returnType); 1597 StringBuffer buf = (StringBuffer ) data; 1598 Object [] args = new Object []{ 1599 node.distinct, 1600 new NodeStringWrapper(node.jjtGetChild(0)) 1601 }; 1602 return JDBCTypeMappingMetaData.MIN_FUNC.getFunctionSql(args, buf); 1603 } 1604 1605 public Object visit(ASTAvg node, Object data) 1606 { 1607 node.setResultType(returnType); 1608 StringBuffer buf = (StringBuffer ) data; 1609 Object [] args = new Object []{ 1610 node.distinct, 1611 new NodeStringWrapper(node.jjtGetChild(0)), 1612 }; 1613 return JDBCTypeMappingMetaData.AVG_FUNC.getFunctionSql(args, buf); 1614 } 1615 1616 public Object visit(ASTSum node, Object data) 1617 { 1618 node.setResultType(returnType); 1619 StringBuffer buf = (StringBuffer ) data; 1620 Object [] args = new Object []{ 1621 node.distinct, 1622 new NodeStringWrapper(node.jjtGetChild(0)) 1623 }; 1624 return JDBCTypeMappingMetaData.SUM_FUNC.getFunctionSql(args, buf); 1625 } 1626 1627 1630 public Object visit(ASTPath node, Object data) 1631 { 1632 StringBuffer buf = (StringBuffer ) data; 1633 if(!node.isCMPField()) 1634 { 1635 throw new IllegalStateException ("Can only visit cmp valued path " + 1636 "node. Should have been handled at a higher level."); 1637 } 1638 1639 JDBCCMPFieldBridge cmpField = (JDBCCMPFieldBridge) node.getCMPField(); 1640 1641 switch(node.type) 1643 { 1644 case EJBQLTypes.ENTITY_TYPE: 1645 case EJBQLTypes.VALUE_CLASS_TYPE: 1646 if(cmpField.getJDBCType().hasMapper()) 1647 { 1648 break; 1649 } 1650 case EJBQLTypes.UNKNOWN_TYPE: 1651 throw new IllegalStateException ("Can not visit multi-column path " + 1652 "node. Should have been handled at a higher level."); 1653 } 1654 1655 addJoinPath(node); 1656 String alias = aliasManager.getAlias(node.getPath(node.size() - 2)); 1657 SQLUtil.getColumnNamesClause(cmpField, alias, buf); 1658 return buf; 1659 } 1660 1661 public Object visit(ASTAbstractSchema node, Object data) 1662 { 1663 throw new IllegalStateException ("Can not visit abstract schema node. " + 1664 "Should have been handled at a higher level."); 1665 } 1666 1667 1670 public Object visit(ASTParameter node, Object data) 1671 { 1672 StringBuffer buf = (StringBuffer ) data; 1673 Class type = getParameterType(node.number); 1674 1675 int ejbqlType = EJBQLTypes.getEJBQLType(type); 1677 if(ejbqlType == EJBQLTypes.ENTITY_TYPE || 1678 ejbqlType == EJBQLTypes.VALUE_CLASS_TYPE || 1679 ejbqlType == EJBQLTypes.UNKNOWN_TYPE) 1680 { 1681 throw new IllegalStateException ("Can not visit multi-column " + 1682 "parameter node. Should have been handled at a higher level."); 1683 } 1684 1685 QueryParameter param = new QueryParameter(node.number - 1, typeFactory.getJDBCType(type)); 1686 inputParameters.add(param); 1687 buf.append('?'); 1688 return buf; 1689 } 1690 1691 1694 public Object visit(ASTBooleanLiteral node, Object data) 1695 { 1696 StringBuffer buf = (StringBuffer ) data; 1697 if(node.value) 1698 { 1699 buf.append(typeMapping.getTrueMapping()); 1700 } 1701 else 1702 { 1703 buf.append(typeMapping.getFalseMapping()); 1704 } 1705 return data; 1706 } 1707 1708 public Object visit(ASTLimitOffset node, Object data) 1709 { 1710 int child = 0; 1711 if(node.hasOffset) 1712 { 1713 Node offsetNode = node.jjtGetChild(child++); 1714 if(offsetNode instanceof ASTParameter) 1715 { 1716 ASTParameter param = (ASTParameter) offsetNode; 1717 Class parameterType = getParameterType(param.number); 1718 if(int.class != parameterType && Integer .class != parameterType) 1719 { 1720 throw new UnsupportedOperationException ("OFFSET parameter must be an int"); 1721 } 1722 offsetParam = param.number; 1723 } 1724 else 1725 { 1726 ASTExactNumericLiteral param = (ASTExactNumericLiteral) offsetNode; 1727 offsetValue = (int) param.value; 1728 } 1729 } 1730 if(node.hasLimit) 1731 { 1732 Node limitNode = node.jjtGetChild(child); 1733 if(limitNode instanceof ASTParameter) 1734 { 1735 ASTParameter param = (ASTParameter) limitNode; 1736 Class parameterType = getParameterType(param.number); 1737 if(int.class != parameterType && Integer .class != parameterType) 1738 { 1739 throw new UnsupportedOperationException ("LIMIT parameter must be an int"); 1740 } 1741 limitParam = param.number; 1742 } 1743 else 1744 { 1745 ASTExactNumericLiteral param = (ASTExactNumericLiteral) limitNode; 1746 limitValue = (int) param.value; 1747 } 1748 } 1749 return data; 1750 } 1751 1752 public Object visit(ASTWhereConditionalTerm node, Object data) 1753 { 1754 clearPerTermJoinPaths(); 1756 1757 StringBuffer buf = (StringBuffer ) data; 1758 buf.append('('); 1759 for(int i = 0; i < node.jjtGetNumChildren(); ++i) 1760 { 1761 node.jjtGetChild(i).jjtAccept(this, data); 1762 } 1763 1764 StringBuffer thetaJoin = new StringBuffer (); 1765 createThetaJoin(thetaJoin); 1766 1767 if(thetaJoin.length() > 0) 1768 { 1769 buf.append(SQLUtil.AND).append(thetaJoin.toString()); 1770 } 1771 1772 buf.append(')'); 1773 return data; 1774 } 1775 1776 1783 private final class NodeStringWrapper 1784 { 1785 final Node node; 1786 1787 public NodeStringWrapper(Node node) 1788 { 1789 this.node = node; 1790 } 1791 1792 public String toString() 1793 { 1794 return node.jjtAccept(JDBCEJBQLCompiler.this, new StringBuffer ()).toString(); 1795 } 1796 } 1797 1798 1804 private ASTPath getPathFromChildren(Node selectFunction) 1805 { 1806 for(int childInd = 0; childInd < selectFunction.jjtGetNumChildren(); ++childInd) 1807 { 1808 Node child = selectFunction.jjtGetChild(childInd); 1809 if(child instanceof ASTPath) 1810 { 1811 return (ASTPath) child; 1812 } 1813 else if(child instanceof SelectFunction) 1814 { 1815 Node path = getPathFromChildren(child); 1816 if(path != null) 1817 { 1818 return (ASTPath) path; 1819 } 1820 } 1821 } 1822 return null; 1823 } 1824 1825 1831 private boolean isSelected(ASTPath path) 1832 { 1833 boolean selected = false; 1834 1835 CMPFieldBridge cmpField = path.getCMPField(); 1836 if(selectObject instanceof JDBCCMPFieldBridge && cmpField == selectObject) 1837 { 1838 selected = true; 1839 } 1840 else if(selectObject instanceof JDBCEntityBridge) 1841 { 1842 JDBCEntityBridge entity = (JDBCEntityBridge) selectObject; 1843 JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields(); 1844 for(int pkInd = 0; pkInd < pkFields.length; ++pkInd) 1845 { 1846 if(pkFields[pkInd] == cmpField) 1847 { 1848 selected = true; 1849 break; 1850 } 1851 } 1852 } 1853 else if(selectObject instanceof SelectFunction) 1854 { 1855 Node funcNode = (Node) selectObject; 1856 ASTPath fieldPath = getPathFromChildren(funcNode); 1857 if(fieldPath.getCMPField() == cmpField) 1858 { 1859 selected = true; 1860 } 1861 } 1862 1863 return selected; 1864 } 1865 1866 private void selectEntity(ASTPath path, StringBuffer buf) 1867 { 1868 JDBCEntityBridge selectEntity = (JDBCEntityBridge) path.getEntity(); 1869 1870 StringBuffer columnNamesClause = new StringBuffer (200); 1871 addJoinPath(path); 1872 selectAlias = aliasManager.getAlias(path.getPath()); 1873 1874 SQLUtil.getColumnNamesClause(selectEntity.getPrimaryKeyFields(), selectAlias, columnNamesClause); 1877 1878 if(readAhead.isOnFind()) 1879 { 1880 String eagerLoadGroupName = readAhead.getEagerLoadGroup(); 1881 boolean[] loadGroupMask = selectEntity.getLoadGroupMask(eagerLoadGroupName); 1882 SQLUtil.appendColumnNamesClause(selectEntity.getTableFields(), loadGroupMask, selectAlias, columnNamesClause); 1883 1884 try 1885 { 1886 leftJoinCMRList = JDBCAbstractQueryCommand.getLeftJoinCMRNodes( 1887 selectEntity, path.getPath(), readAhead.getLeftJoins(), declaredPaths); 1888 } 1889 catch(DeploymentException e) 1890 { 1891 throw new IllegalStateException (e.getMessage()); 1892 } 1893 1894 if(!leftJoinCMRList.isEmpty()) 1895 { 1896 onFindCMRJoin = new StringBuffer (100); 1897 JDBCAbstractQueryCommand.leftJoinCMRNodes(selectAlias, leftJoinCMRList, aliasManager, onFindCMRJoin); 1898 JDBCAbstractQueryCommand.appendLeftJoinCMRColumnNames(leftJoinCMRList, aliasManager, columnNamesClause); 1899 } 1900 } 1901 buf.append(columnNamesClause); 1902 } 1903 1904 private void addJoinPath(ASTPath path) 1905 { 1906 ctermJoinPaths.add(path); 1907 allJoinPaths.add(path); 1908 } 1909 1910 private void addCollectionMemberJoinPath(String alias, ASTPath path) 1911 { 1912 ctermCollectionMemberJoinPaths.put(alias, path); 1913 allCollectionMemberJoinPaths.put(alias, path); 1914 } 1915 1916 private void addLeftJoinPath(String pathStr, ASTPath path) 1917 { 1918 Set set = (Set ) ctermLeftJoinPaths.get(pathStr); 1919 if(set == null) 1920 { 1921 set = new HashSet (); 1922 ctermLeftJoinPaths.put(pathStr, set); 1923 } 1924 set.add(path); 1925 1926 set = (Set ) allLeftJoinPaths.get(pathStr); 1927 if(set == null) 1928 { 1929 set = new HashSet (); 1930 allLeftJoinPaths.put(pathStr, set); 1931 } 1932 set.add(path); 1933 } 1934 1935 private void clearPerTermJoinPaths() 1936 { 1937 ctermJoinPaths.clear(); 1938 ctermCollectionMemberJoinPaths.clear(); 1939 ctermLeftJoinPaths.clear(); 1940 } 1941 1942 private boolean isDistinct(Node selectNode) 1943 { 1944 return ((ASTSelect) selectNode).distinct || returnType.equals(Set .class) || forceDistinct; 1945 } 1946} 1947 | Popular Tags |