1 21 22 package org.apache.derby.impl.sql.compile; 23 24 import org.apache.derby.iapi.services.context.ContextManager; 25 26 import org.apache.derby.iapi.services.compiler.MethodBuilder; 27 28 import org.apache.derby.iapi.services.sanity.SanityManager; 29 30 import org.apache.derby.iapi.error.StandardException; 31 32 import org.apache.derby.iapi.sql.compile.Optimizable; 33 import org.apache.derby.iapi.sql.compile.OptimizablePredicate; 34 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList; 35 import org.apache.derby.iapi.sql.compile.Optimizer; 36 import org.apache.derby.iapi.sql.compile.Visitable; 37 import org.apache.derby.iapi.sql.compile.Visitor; 38 import org.apache.derby.iapi.sql.compile.CostEstimate; 39 import org.apache.derby.iapi.sql.compile.RowOrdering; 40 import org.apache.derby.iapi.sql.compile.C_NodeTypes; 41 42 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 43 import org.apache.derby.iapi.sql.dictionary.TableDescriptor; 44 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; 45 46 import org.apache.derby.iapi.types.TypeId; 47 import org.apache.derby.iapi.types.DataTypeDescriptor; 48 49 import org.apache.derby.iapi.reference.SQLState; 50 import org.apache.derby.iapi.reference.ClassName; 51 52 import org.apache.derby.iapi.sql.Activation; 53 import org.apache.derby.iapi.sql.ResultSet; 54 55 import org.apache.derby.iapi.store.access.TransactionController; 56 57 import org.apache.derby.iapi.services.loader.GeneratedMethod; 58 59 import org.apache.derby.impl.sql.compile.ActivationClassBuilder; 60 61 import org.apache.derby.iapi.util.JBitSet; 62 import org.apache.derby.iapi.util.PropertyUtil; 63 import org.apache.derby.iapi.services.classfile.VMOpcode; 64 65 import java.util.Properties ; 66 import java.util.Vector ; 67 68 78 79 public class JoinNode extends TableOperatorNode 80 { 81 82 public static final int INNERJOIN = 1; 83 public static final int CROSSJOIN = 2; 84 public static final int LEFTOUTERJOIN = 3; 85 public static final int RIGHTOUTERJOIN = 4; 86 public static final int FULLOUTERJOIN = 5; 87 public static final int UNIONJOIN = 6; 88 89 private boolean optimized; 90 91 private PredicateList leftPredicateList; 92 private PredicateList rightPredicateList; 93 94 protected boolean flattenableJoin = true; 95 Vector aggregateVector; 96 SubqueryList subqueryList; 97 ValueNode joinClause; 98 boolean joinClauseNormalized; 99 PredicateList joinPredicates; 100 ResultColumnList usingClause; 101 Properties joinOrderStrategyProperties; 103 104 105 118 public void init( 119 Object leftResult, 120 Object rightResult, 121 Object onClause, 122 Object usingClause, 123 Object selectList, 124 Object tableProperties, 125 Object joinOrderStrategyProperties) 126 throws StandardException 127 { 128 super.init(leftResult, rightResult, tableProperties); 129 resultColumns = (ResultColumnList) selectList; 130 joinClause = (ValueNode) onClause; 131 joinClauseNormalized = false; 132 this.usingClause = (ResultColumnList) usingClause; 133 this.joinOrderStrategyProperties = (Properties )joinOrderStrategyProperties; 134 135 138 if (resultColumns != null) 139 { 140 141 if (SanityManager.DEBUG) 142 { 143 SanityManager.ASSERT((leftResultSet.getReferencedTableMap() != null && 144 rightResultSet.getReferencedTableMap() != null) || 145 (leftResultSet.getReferencedTableMap() == null && 146 rightResultSet.getReferencedTableMap() == null), 147 "left and right referencedTableMaps are expected to either both be non-null or both be null"); 148 } 149 150 151 if (leftResultSet.getReferencedTableMap() != null) 152 { 153 referencedTableMap = (JBitSet) leftResultSet.getReferencedTableMap().clone(); 154 referencedTableMap.or((JBitSet) rightResultSet.getReferencedTableMap()); 155 } 156 } 157 joinPredicates = (PredicateList) getNodeFactory().getNode( 158 C_NodeTypes.PREDICATE_LIST, 159 getContextManager()); 160 } 161 162 165 166 171 public CostEstimate optimizeIt( 172 Optimizer optimizer, 173 OptimizablePredicateList predList, 174 CostEstimate outerCost, 175 RowOrdering rowOrdering) 176 throws StandardException 177 { 178 optimizer.trace(Optimizer.CALLING_ON_JOIN_NODE, 0, 0, 0.0, null); 179 180 updateBestPlanMap(ADD_PLAN, this); 191 192 204 205 206 207 leftResultSet = optimizeSource( 210 optimizer, 211 leftResultSet, 212 getLeftPredicateList(), 213 outerCost); 214 215 223 for (int index = joinPredicates.size() - 1; index >= 0; index --) 225 { 226 JBitSet curBitSet; 227 Predicate predicate; 228 229 predicate = (Predicate) joinPredicates.elementAt(index); 230 if (! predicate.getPushable()) 231 { 232 continue; 233 } 234 joinPredicates.removeElementAt(index); 235 getRightPredicateList().addElement(predicate); 236 } 237 238 rightResultSet = optimizeSource( 239 optimizer, 240 rightResultSet, 241 getRightPredicateList(), 242 leftResultSet.getCostEstimate()); 243 244 costEstimate = getCostEstimate(optimizer); 245 246 250 costEstimate.setCost( 251 leftResultSet.getCostEstimate().getEstimatedCost() + 252 rightResultSet.getCostEstimate().getEstimatedCost(), 253 rightResultSet.getCostEstimate().rowCount(), 254 rightResultSet.getCostEstimate().rowCount()); 255 256 262 adjustNumberOfRowsReturned(costEstimate); 263 264 267 getCurrentAccessPath(). 268 getJoinStrategy(). 269 estimateCost( 270 this, 271 predList, 272 (ConglomerateDescriptor) null, 273 outerCost, 274 optimizer, 275 costEstimate 276 ); 277 278 optimizer.considerCost(this, predList, costEstimate, outerCost); 279 280 281 if ( (! optimized) && (subqueryList != null)) 282 { 283 286 subqueryList.optimize(optimizer.getDataDictionary(), 287 costEstimate.rowCount()); 288 subqueryList.modifyAccessPaths(); 289 } 290 291 optimized = true; 292 293 return costEstimate; 294 } 295 296 301 302 public boolean pushOptPredicate(OptimizablePredicate optimizablePredicate) 303 throws StandardException 304 { 305 if (SanityManager.DEBUG) 306 { 307 SanityManager.ASSERT(optimizablePredicate instanceof Predicate, 308 "optimizablePredicate expected to be instanceof Predicate"); 309 SanityManager.ASSERT(! optimizablePredicate.hasSubquery() && 310 ! optimizablePredicate.hasMethodCall(), 311 "optimizablePredicate either has a subquery or a method call"); 312 } 313 314 315 joinPredicates.addPredicate((Predicate) optimizablePredicate); 316 317 320 RemapCRsVisitor rcrv = new RemapCRsVisitor(true); 321 ((Predicate) optimizablePredicate).getAndNode().accept(rcrv); 322 323 return true; 324 } 325 326 331 public Optimizable modifyAccessPath(JBitSet outerTables) throws StandardException 332 { 333 super.modifyAccessPath(outerTables); 334 335 339 if (SanityManager.DEBUG) 340 { 341 if (getLeftPredicateList().size() != 0) 342 { 343 SanityManager.THROWASSERT( 344 "getLeftPredicateList().size() expected to be 0, not " + 345 getLeftPredicateList().size()); 346 } 347 if (getRightPredicateList().size() != 0) 348 { 349 SanityManager.THROWASSERT( 350 "getRightPredicateList().size() expected to be 0, not " + 351 getRightPredicateList().size()); 352 } 353 } 354 355 return this; 356 } 357 358 359 365 protected void adjustNumberOfRowsReturned(CostEstimate costEstimate) 366 { 367 } 368 369 381 public ResultColumnList getAllResultColumns(TableName allTableName) 382 throws StandardException 383 { 384 389 if (usingClause == null) 390 { 391 return getAllResultColumnsNoUsing(allTableName); 392 } 393 394 399 ResultSetNode logicalLeftRS = getLogicalLeftResultSet(); 400 401 ResultColumnList joinRCL = logicalLeftRS.getAllResultColumns( 403 null). 404 getJoinColumns(usingClause); 405 406 ResultColumnList leftRCL = leftResultSet.getAllResultColumns(allTableName); 408 ResultColumnList rightRCL = rightResultSet.getAllResultColumns(allTableName); 409 410 414 if (leftRCL != null) 415 { 416 leftRCL.removeJoinColumns(usingClause); 417 } 418 if (rightRCL != null) 419 { 420 rightRCL.removeJoinColumns(usingClause); 421 } 422 423 430 if (leftRCL == null) 431 { 432 rightRCL.resetVirtualColumnIds(); 433 return rightRCL; 434 } 435 else if (rightRCL == null) 436 { 437 leftRCL.resetVirtualColumnIds(); 438 return leftRCL; 439 } 440 else 441 { 442 445 if (SanityManager.DEBUG) 446 { 447 if (allTableName != null) 448 { 449 SanityManager.THROWASSERT( 450 "allTableName (" + allTableName + 451 ") expected to be null"); 452 } 453 } 454 joinRCL.destructiveAppend(leftRCL); 455 joinRCL.destructiveAppend(rightRCL); 456 joinRCL.resetVirtualColumnIds(); 457 return joinRCL; 458 } 459 } 460 461 475 private ResultColumnList getAllResultColumnsNoUsing(TableName allTableName) 476 throws StandardException 477 { 478 ResultColumnList leftRCL = leftResultSet.getAllResultColumns(allTableName); 479 ResultColumnList rightRCL = rightResultSet.getAllResultColumns(allTableName); 480 483 if (leftRCL == null) 484 { 485 return rightRCL; 486 } 487 else if (rightRCL == null) 488 { 489 return leftRCL; 490 } 491 else 492 { 493 496 if (SanityManager.DEBUG) 497 { 498 if (allTableName != null) 499 { 500 SanityManager.THROWASSERT( 501 "allTableName (" + allTableName + 502 ") expected to be null"); 503 } 504 } 505 506 ResultColumnList tempList = 508 (ResultColumnList) getNodeFactory().getNode( 509 C_NodeTypes.RESULT_COLUMN_LIST, 510 getContextManager()); 511 tempList.nondestructiveAppend(leftRCL); 512 tempList.nondestructiveAppend(rightRCL); 513 return tempList; 514 } 515 } 516 517 530 531 public ResultColumn getMatchingColumn(ColumnReference columnReference) throws StandardException 532 { 533 537 ResultSetNode logicalLeftRS = getLogicalLeftResultSet(); 538 ResultSetNode logicalRightRS = getLogicalRightResultSet(); 539 ResultColumn leftRC = null; 540 ResultColumn resultColumn = null; 541 ResultColumn rightRC = null; 542 ResultColumn usingRC = null; 543 544 leftRC = logicalLeftRS.getMatchingColumn(columnReference); 545 546 if (leftRC != null) 547 { 548 resultColumn = leftRC; 549 550 551 if (usingClause != null) 552 { 553 usingRC = usingClause.getResultColumn(leftRC.getName()); 554 } 555 } 556 557 560 if (usingRC == null) 561 { 562 rightRC = logicalRightRS.getMatchingColumn(columnReference); 563 } 564 565 if (rightRC != null) 566 { 567 571 if (leftRC != null) 572 { 573 throw StandardException.newException(SQLState.LANG_AMBIGUOUS_COLUMN_NAME, 574 columnReference.getSQLColumnName()); 575 } 576 resultColumn = rightRC; 577 } 578 579 586 if (resultColumns != null) 587 { 588 int rclSize = resultColumns.size(); 589 for (int index = 0; index < rclSize; index++) 590 { 591 ResultColumn rc = (ResultColumn) resultColumns.elementAt(index); 592 VirtualColumnNode vcn = (VirtualColumnNode) rc.getExpression(); 593 if (resultColumn == vcn.getSourceColumn()) 594 { 595 resultColumn = rc; 596 break; 597 } 598 } 599 } 600 601 return resultColumn; 602 } 603 604 614 public void bindResultColumns(FromList fromListParam) 615 throws StandardException 616 { 617 super.bindResultColumns(fromListParam); 618 619 620 buildRCL(); 621 622 631 deferredBindExpressions(fromListParam); 632 } 633 634 660 661 public void bindResultColumns(TableDescriptor targetTableDescriptor, 662 FromVTI targetVTI, 663 ResultColumnList targetColumnList, 664 DMLStatementNode statement, 665 FromList fromListParam) 666 throws StandardException 667 { 668 super.bindResultColumns(targetTableDescriptor, 669 targetVTI, 670 targetColumnList, statement, 671 fromListParam); 672 673 674 buildRCL(); 675 676 685 deferredBindExpressions(fromListParam); 686 } 687 688 694 695 private void buildRCL() throws StandardException 696 { 697 701 if (resultColumns != null) 702 { 703 return; 704 } 705 706 ResultColumnList leftRCL; 707 ResultColumnList rightRCL; 708 ResultColumnList tmpRCL; 709 710 713 resultColumns = leftResultSet.getResultColumns(); 714 leftRCL = resultColumns.copyListAndObjects(); 715 leftResultSet.setResultColumns(leftRCL); 716 717 721 resultColumns.genVirtualColumnNodes(leftResultSet, leftRCL, false); 722 723 727 if (this instanceof HalfOuterJoinNode && ((HalfOuterJoinNode)this).isRightOuterJoin()) 728 { 729 resultColumns.setNullability(true); 730 } 731 732 733 tmpRCL = rightResultSet.getResultColumns(); 734 rightRCL = tmpRCL.copyListAndObjects(); 735 rightResultSet.setResultColumns(rightRCL); 736 737 741 tmpRCL.genVirtualColumnNodes(rightResultSet, rightRCL, false); 742 tmpRCL.adjustVirtualColumnIds(resultColumns.size()); 743 744 748 if (this instanceof HalfOuterJoinNode && !((HalfOuterJoinNode)this).isRightOuterJoin()) 749 { 750 tmpRCL.setNullability(true); 751 } 752 753 756 resultColumns.nondestructiveAppend(tmpRCL); 757 } 758 759 private void deferredBindExpressions(FromList fromListParam) 760 throws StandardException 761 { 762 763 subqueryList = (SubqueryList) getNodeFactory().getNode( 764 C_NodeTypes.SUBQUERY_LIST, 765 getContextManager()); 766 aggregateVector = new Vector (); 767 768 769 if (joinClause != null) 770 { 771 776 FromList fromList = (FromList) getNodeFactory().getNode( 777 C_NodeTypes.FROM_LIST, 778 getNodeFactory().doJoinOrderOptimization(), 779 getContextManager()); 780 fromList.addElement((FromTable) leftResultSet); 781 fromList.addElement((FromTable) rightResultSet); 782 783 790 fromListParam.insertElementAt(rightResultSet, 0); 791 fromListParam.insertElementAt(leftResultSet, 0); 792 joinClause = joinClause.bindExpression( 793 fromListParam, subqueryList, 794 aggregateVector); 795 796 800 try { 801 joinClause = joinClause.bindExpression( 802 fromList, subqueryList, 803 aggregateVector); 804 } catch (StandardException se) { 805 if (se.getSQLState().equals(SQLState.LANG_COLUMN_NOT_FOUND)) 806 throw StandardException.newException(SQLState.LANG_DB2_ON_CLAUSE_INVALID); 807 throw se; 808 } 809 810 811 if (subqueryList.size() > 0) 812 throw StandardException.newException(SQLState.LANG_DB2_ON_CLAUSE_INVALID); 813 819 if (aggregateVector.size() > 0) 820 { 821 throw StandardException.newException(SQLState.LANG_NO_AGGREGATES_IN_ON_CLAUSE); 822 } 823 824 fromListParam.removeElementAt(0); 825 fromListParam.removeElementAt(0); 826 } 827 828 else if (usingClause != null) 829 { 830 840 joinClause = (AndNode) getNodeFactory().getNode( 841 C_NodeTypes.AND_NODE, 842 null, 843 null, 844 getContextManager()); 845 AndNode currAnd = (AndNode) joinClause; 846 ValueNode trueNode = (ValueNode) getNodeFactory().getNode( 847 C_NodeTypes.BOOLEAN_CONSTANT_NODE, 848 Boolean.TRUE, 849 getContextManager()); 850 851 int usingSize = usingClause.size(); 852 for (int index = 0; index < usingSize; index++) 853 { 854 BinaryComparisonOperatorNode equalsNode; 855 ColumnReference leftCR; 856 ColumnReference rightCR; 857 ResultColumn rc = (ResultColumn) usingClause.elementAt(index); 858 859 862 if (currAnd.getLeftOperand() != null) 863 { 864 currAnd.setRightOperand( 865 (AndNode) getNodeFactory().getNode( 866 C_NodeTypes.AND_NODE, 867 null, 868 null, 869 getContextManager())); 870 currAnd = (AndNode) currAnd.getRightOperand(); 871 } 872 873 874 fromListParam.insertElementAt(leftResultSet, 0); 875 leftCR = (ColumnReference) getNodeFactory().getNode( 876 C_NodeTypes.COLUMN_REFERENCE, 877 rc.getName(), 878 ((FromTable) leftResultSet).getTableName(), 879 getContextManager()); 880 leftCR = (ColumnReference) leftCR.bindExpression( 881 fromListParam, subqueryList, 882 aggregateVector); 883 fromListParam.removeElementAt(0); 884 885 886 fromListParam.insertElementAt(rightResultSet, 0); 887 rightCR = (ColumnReference) getNodeFactory().getNode( 888 C_NodeTypes.COLUMN_REFERENCE, 889 rc.getName(), 890 ((FromTable) rightResultSet).getTableName(), 891 getContextManager()); 892 rightCR = (ColumnReference) rightCR.bindExpression( 893 fromListParam, subqueryList, 894 aggregateVector); 895 fromListParam.removeElementAt(0); 896 897 898 equalsNode = (BinaryComparisonOperatorNode) 899 getNodeFactory().getNode( 900 C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE, 901 leftCR, 902 rightCR, 903 getContextManager()); 904 equalsNode.bindComparisonOperator(); 905 906 currAnd.setLeftOperand(equalsNode); 907 913 currAnd.setRightOperand(trueNode); 914 currAnd.postBindFixup(); 915 } 916 } 917 918 if (joinClause != null) 919 { 920 923 if (joinClause.requiresTypeFromContext()) 924 { 925 joinClause.setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID, true)); 926 } 927 928 937 TypeId joinTypeId = joinClause.getTypeId(); 938 939 942 if (joinTypeId.userType()) 943 { 944 joinClause = joinClause.genSQLJavaSQLTree(); 945 } 946 947 if (! joinClause.getTypeServices().getTypeId().equals( 948 TypeId.BOOLEAN_ID)) 949 { 950 throw StandardException.newException(SQLState.LANG_NON_BOOLEAN_JOIN_CLAUSE, 951 joinClause.getTypeServices().getTypeId().getSQLTypeName() 952 ); 953 } 954 } 955 } 956 957 958 982 public ResultSetNode preprocess(int numTables, 983 GroupByList gbl, 984 FromList fromList) 985 throws StandardException 986 { 987 ResultSetNode newTreeTop; 988 989 newTreeTop = super.preprocess(numTables, gbl, fromList); 990 991 996 if (joinClause != null) 997 { 998 normExpressions(); 999 1000 1001 if (subqueryList != null) 1002 { 1003 1015 joinClause.preprocess( 1016 numTables, 1017 (FromList) getNodeFactory().getNode( 1018 C_NodeTypes.FROM_LIST, 1019 getNodeFactory().doJoinOrderOptimization(), 1020 getContextManager()), 1021 (SubqueryList) getNodeFactory().getNode( 1022 C_NodeTypes.SUBQUERY_LIST, 1023 getContextManager()), 1024 (PredicateList) getNodeFactory().getNode( 1025 C_NodeTypes.PREDICATE_LIST, 1026 getContextManager())); 1027 } 1028 1029 1030 joinPredicates.pullExpressions(numTables, joinClause); 1031 joinPredicates.categorize(); 1032 joinClause = null; 1033 } 1034 1035 return newTreeTop; 1036 } 1037 1038 1042 void projectResultColumns() throws StandardException 1043 { 1044 leftResultSet.projectResultColumns(); 1045 rightResultSet.projectResultColumns(); 1046 resultColumns.pullVirtualIsReferenced(); 1047 super.projectResultColumns(); 1048 } 1049 1050 1054 public void normExpressions() 1055 throws StandardException 1056 { 1057 if (joinClauseNormalized == true) return; 1058 1059 1065 joinClause = joinClause.eliminateNots(false); 1066 if (SanityManager.DEBUG) 1067 { 1068 if (!(joinClause.verifyEliminateNots()) ) 1069 { 1070 joinClause.treePrint(); 1071 SanityManager.THROWASSERT( 1072 "joinClause in invalid form: " + joinClause); 1073 } 1074 } 1075 joinClause = joinClause.putAndsOnTop(); 1076 if (SanityManager.DEBUG) 1077 { 1078 if (! ((joinClause instanceof AndNode) && 1079 (joinClause.verifyPutAndsOnTop())) ) 1080 { 1081 joinClause.treePrint(); 1082 SanityManager.THROWASSERT( 1083 "joinClause in invalid form: " + joinClause); 1084 } 1085 } 1086 1090 joinClause = joinClause.changeToCNF(false); 1091 if (SanityManager.DEBUG) 1092 { 1093 if (! ((joinClause instanceof AndNode) && 1094 (joinClause.verifyChangeToCNF())) ) 1095 { 1096 joinClause.treePrint(); 1097 SanityManager.THROWASSERT( 1098 "joinClause in invalid form: " + joinClause); 1099 } 1100 } 1101 1102 joinClauseNormalized = true; 1103 } 1104 1105 1116 public void pushExpressions(PredicateList outerPredicateList) 1117 throws StandardException 1118 { 1119 FromTable leftFromTable = (FromTable) leftResultSet; 1120 FromTable rightFromTable = (FromTable) rightResultSet; 1121 1122 1126 if (SanityManager.DEBUG) 1127 { 1128 if (this instanceof HalfOuterJoinNode) 1129 { 1130 SanityManager.THROWASSERT( 1131 "JN.pushExpressions() not expected to be called for " + 1132 getClass().getName()); 1133 } 1134 } 1135 1136 1147 pushExpressionsToLeft(outerPredicateList); 1149 leftFromTable.pushExpressions(getLeftPredicateList()); 1150 pushExpressionsToRight(outerPredicateList); 1152 rightFromTable.pushExpressions(getRightPredicateList()); 1153 grabJoinPredicates(outerPredicateList); 1155 1156 1160 if (SanityManager.DEBUG) 1161 { 1162 if (getLeftPredicateList().size() != 0) 1163 { 1164 SanityManager.THROWASSERT( 1165 "getLeftPredicateList().size() expected to be 0, not " + 1166 getLeftPredicateList().size()); 1167 } 1168 if (getRightPredicateList().size() != 0) 1169 { 1170 SanityManager.THROWASSERT( 1171 "getRightPredicateList().size() expected to be 0, not " + 1172 getRightPredicateList().size()); 1173 } 1174 } 1175 } 1176 1177 protected void pushExpressionsToLeft(PredicateList outerPredicateList) 1178 throws StandardException 1179 { 1180 FromTable leftFromTable = (FromTable) leftResultSet; 1181 1182 JBitSet leftReferencedTableMap = leftFromTable.getReferencedTableMap(); 1183 1184 1187 for (int index = outerPredicateList.size() - 1; index >= 0; index --) 1189 { 1190 JBitSet curBitSet; 1191 Predicate predicate; 1192 1193 predicate = (Predicate) outerPredicateList.elementAt(index); 1194 if (! predicate.getPushable()) 1195 { 1196 continue; 1197 } 1198 1199 curBitSet = predicate.getReferencedSet(); 1200 1201 1202 if (leftReferencedTableMap.contains(curBitSet)) 1203 { 1204 1205 getLeftPredicateList().addPredicate(predicate); 1206 1207 1224 RemapCRsVisitor rcrv = new RemapCRsVisitor(true); 1225 predicate.getAndNode().accept(rcrv); 1226 predicate.getAndNode().accept(rcrv); 1227 1228 1229 outerPredicateList.removeElementAt(index); 1230 } 1231 } 1232 } 1233 1234 private void pushExpressionsToRight(PredicateList outerPredicateList) 1235 throws StandardException 1236 { 1237 FromTable rightFromTable = (FromTable) rightResultSet; 1238 1239 JBitSet rightReferencedTableMap = rightFromTable.getReferencedTableMap(); 1240 1241 1244 for (int index = outerPredicateList.size() - 1; index >= 0; index --) 1246 { 1247 JBitSet curBitSet; 1248 Predicate predicate; 1249 1250 predicate = (Predicate) outerPredicateList.elementAt(index); 1251 if (! predicate.getPushable()) 1252 { 1253 continue; 1254 } 1255 1256 curBitSet = predicate.getReferencedSet(); 1257 1258 1259 if (rightReferencedTableMap.contains(curBitSet)) 1260 { 1261 1262 getRightPredicateList().addPredicate(predicate); 1263 1264 1281 RemapCRsVisitor rcrv = new RemapCRsVisitor(true); 1282 predicate.getAndNode().accept(rcrv); 1283 predicate.getAndNode().accept(rcrv); 1284 1285 1286 outerPredicateList.removeElementAt(index); 1287 } 1288 } 1289 } 1290 1291 private void grabJoinPredicates(PredicateList outerPredicateList) 1292 throws StandardException 1293 { 1294 FromTable leftFromTable = (FromTable) leftResultSet; 1295 FromTable rightFromTable = (FromTable) rightResultSet; 1296 1297 JBitSet leftReferencedTableMap = leftFromTable.getReferencedTableMap(); 1298 JBitSet rightReferencedTableMap = rightFromTable.getReferencedTableMap(); 1299 1300 1301 for (int index = outerPredicateList.size() - 1; index >= 0; index --) 1303 { 1304 JBitSet curBitSet; 1305 Predicate predicate; 1306 1307 predicate = (Predicate) outerPredicateList.elementAt(index); 1308 if (! predicate.getPushable()) 1309 { 1310 continue; 1311 } 1312 1313 curBitSet = predicate.getReferencedSet(); 1314 1315 1316 JBitSet innerBitSet = (JBitSet) rightReferencedTableMap.clone(); 1317 innerBitSet.or(leftReferencedTableMap); 1318 if (innerBitSet.contains(curBitSet)) 1319 { 1320 1321 joinPredicates.addPredicate(predicate); 1322 1323 1340 RemapCRsVisitor rcrv = new RemapCRsVisitor(true); 1341 predicate.getAndNode().accept(rcrv); 1342 predicate.getAndNode().accept(rcrv); 1343 1344 1345 outerPredicateList.removeElementAt(index); 1346 } 1347 } 1348 } 1349 1350 1368 public FromList flatten(ResultColumnList rcl, 1369 PredicateList outerPList, 1370 SubqueryList sql, 1371 GroupByList gbl) 1372 1373 throws StandardException 1374 { 1375 1379 if (SanityManager.DEBUG) 1380 { 1381 if (this instanceof HalfOuterJoinNode) 1382 { 1383 SanityManager.THROWASSERT( 1384 "JN.flatten() not expected to be called for " + 1385 getClass().getName()); 1386 } 1387 } 1388 1389 1394 FromList fromList = (FromList) getNodeFactory().getNode( 1395 C_NodeTypes.FROM_LIST, 1396 getNodeFactory().doJoinOrderOptimization(), 1397 getContextManager()); 1398 fromList.addElement((FromTable) leftResultSet); 1399 fromList.addElement((FromTable) rightResultSet); 1400 1401 1402 resultColumns.setRedundant(); 1403 1404 1408 rcl.remapColumnReferencesToExpressions(); 1409 outerPList.remapColumnReferencesToExpressions(); 1410 if (gbl != null) 1411 { 1412 gbl.remapColumnReferencesToExpressions(); 1413 } 1414 1415 if (joinPredicates.size() > 0) 1416 { 1417 outerPList.destructiveAppend(joinPredicates); 1418 } 1419 1420 if (subqueryList != null && subqueryList.size() > 0) 1421 { 1422 sql.destructiveAppend(subqueryList); 1423 } 1424 1425 return fromList; 1426 } 1427 1428 1431 public boolean LOJ_reorderable(int numTables) 1432 throws StandardException 1433 { 1434 return false; 1435 } 1436 1437 1448 public FromTable transformOuterJoins(ValueNode predicateTree, int numTables) 1449 throws StandardException 1450 { 1451 1452 if (predicateTree == null) 1453 { 1454 return this; 1455 } 1456 1457 1458 leftResultSet = ((FromTable) leftResultSet).transformOuterJoins(predicateTree, numTables); 1459 rightResultSet = ((FromTable) rightResultSet).transformOuterJoins(predicateTree, numTables); 1460 1461 return this; 1462 } 1463 1464 1476 public void generate(ActivationClassBuilder acb, 1477 MethodBuilder mb) 1478 throws StandardException 1479 { 1480 generateCore(acb, mb, INNERJOIN, null, null); 1481 } 1482 1483 1488 public void generateCore(ActivationClassBuilder acb, 1489 MethodBuilder mb, 1490 int joinType) 1491 throws StandardException 1492 { 1493 generateCore(acb, mb, joinType, joinClause, subqueryList); 1494 } 1495 1496 1507 protected void generateCore(ActivationClassBuilder acb, 1508 MethodBuilder mb, 1509 int joinType, 1510 ValueNode joinClause, 1511 SubqueryList subquerys) 1512 throws StandardException 1513 { 1514 1515 if (joinPredicates != null) 1516 { 1517 joinClause = joinPredicates.restorePredicates(); 1518 joinPredicates = null; 1519 } 1520 1521 1524 assignResultSetNumber(); 1525 1526 1529 if (subquerys != null && subquerys.size() > 0) 1530 { 1531 subquerys.setPointOfAttachment(resultSetNumber); 1532 } 1533 1534 1536 1537 1540 String joinResultSetString; 1541 1542 if (joinType == LEFTOUTERJOIN) 1543 { 1544 joinResultSetString = 1545 ((Optimizable) rightResultSet).getTrulyTheBestAccessPath(). 1546 getJoinStrategy().halfOuterJoinResultSetMethodName(); 1547 } 1548 else 1549 { 1550 joinResultSetString = 1551 ((Optimizable) rightResultSet).getTrulyTheBestAccessPath(). 1552 getJoinStrategy().joinResultSetMethodName(); 1553 } 1554 1555 acb.pushGetResultSetFactoryExpression(mb); 1556 int nargs = getJoinArguments(acb, mb, joinClause); 1557 mb.callMethod(VMOpcode.INVOKEINTERFACE, (String ) null, joinResultSetString, ClassName.NoPutResultSet, nargs); 1558 } 1559 1560 1571 private int getJoinArguments(ActivationClassBuilder acb, 1572 MethodBuilder mb, 1573 ValueNode joinClause) 1574 throws StandardException 1575 { 1576 int numArgs = getNumJoinArguments(); 1577 1578 leftResultSet.generate(acb, mb); mb.push(leftResultSet.resultColumns.size()); rightResultSet.generate(acb, mb); mb.push(rightResultSet.resultColumns.size()); 1583 costEstimate = getFinalCostEstimate(); 1585 1586 1594 1602 if (joinClause == null) 1604 { 1605 mb.pushNull(ClassName.GeneratedMethod); } 1607 else 1608 { 1609 MethodBuilder userExprFun = acb.newUserExprFun(); 1613 1614 1616 1620 joinClause.generate(acb, userExprFun); 1621 userExprFun.methodReturn(); 1622 1623 userExprFun.complete(); 1625 1626 acb.pushMethodReference(mb, userExprFun); } 1634 1635 mb.push(resultSetNumber); 1637 addOuterJoinArguments(acb, mb); 1638 1639 oneRowRightSide(acb, mb); 1641 1642 mb.push(costEstimate.rowCount()); 1644 1645 mb.push(costEstimate.getEstimatedCost()); 1647 1648 if (joinOrderStrategyProperties != null) 1652 mb.push(PropertyUtil.sortProperties(joinOrderStrategyProperties)); 1653 else 1654 mb.pushNull("java.lang.String"); 1655 1656 return numArgs; 1657 1658 } 1659 1660 1669 public CostEstimate getFinalCostEstimate() 1670 throws StandardException 1671 { 1672 if (finalCostEstimate != null) 1674 return finalCostEstimate; 1675 1676 CostEstimate leftCE = leftResultSet.getFinalCostEstimate(); 1677 CostEstimate rightCE = rightResultSet.getFinalCostEstimate(); 1678 1679 finalCostEstimate = getNewCostEstimate(); 1680 finalCostEstimate.setCost( 1681 leftCE.getEstimatedCost() + rightCE.getEstimatedCost(), 1682 rightCE.rowCount(), 1683 rightCE.rowCount()); 1684 1685 return finalCostEstimate; 1686 } 1687 1688 protected void oneRowRightSide(ActivationClassBuilder acb, 1689 MethodBuilder mb) 1690 throws StandardException 1691 { 1692 mb.push(rightResultSet.isOneRowResultSet()); 1693 mb.push(rightResultSet.isNotExists()); } 1695 1696 1700 protected int getNumJoinArguments() 1701 { 1702 return 11; 1703 } 1704 1705 1716 protected int addOuterJoinArguments(ActivationClassBuilder acb, 1717 MethodBuilder mb) 1718 throws StandardException 1719 { 1720 return 0; 1721 } 1722 1723 1730 public static String joinTypeToString(int joinType) 1731 { 1732 switch(joinType) 1733 { 1734 case INNERJOIN: 1735 return "INNER JOIN"; 1736 1737 case CROSSJOIN: 1738 return "CROSS JOIN"; 1739 1740 case LEFTOUTERJOIN: 1741 return "LEFT OUTER JOIN"; 1742 1743 case RIGHTOUTERJOIN: 1744 return "RIGHT OUTER JOIN"; 1745 1746 case FULLOUTERJOIN: 1747 return "FULL OUTER JOIN"; 1748 1749 case UNIONJOIN: 1750 return "UNION JOIN"; 1751 1752 default: 1753 if (SanityManager.DEBUG) 1754 { 1755 SanityManager.ASSERT(false, "Unexpected joinType"); 1756 } 1757 return null; 1758 } 1759 } 1760 1761 protected PredicateList getLeftPredicateList() throws StandardException 1762 { 1763 if (leftPredicateList == null) 1764 leftPredicateList = (PredicateList) getNodeFactory().getNode( 1765 C_NodeTypes.PREDICATE_LIST, 1766 getContextManager()); 1767 1768 return leftPredicateList; 1769 } 1770 1771 protected PredicateList getRightPredicateList() throws StandardException 1772 { 1773 if (rightPredicateList == null) 1774 rightPredicateList = (PredicateList) getNodeFactory().getNode( 1775 C_NodeTypes.PREDICATE_LIST, 1776 getContextManager()); 1777 1778 return rightPredicateList; 1779 } 1780 1781 1788 public int updateTargetLockMode() 1789 { 1790 1794 return TransactionController.MODE_RECORD; 1795 } 1796 1797 1800 void notFlattenableJoin() 1801 { 1802 flattenableJoin = false; 1803 leftResultSet.notFlattenableJoin(); 1804 rightResultSet.notFlattenableJoin(); 1805 } 1806 1807 1813 public boolean isFlattenableJoinNode() 1814 { 1815 return flattenableJoin; 1816 } 1817 1818 1833 boolean isOrderedOn(ColumnReference[] crs, boolean permuteOrdering, Vector fbtVector) 1834 throws StandardException 1835 { 1836 1837 return leftResultSet.isOrderedOn(crs, permuteOrdering, fbtVector); 1838 } 1839 1840 1846 1847 public void printSubNodes(int depth) 1848 { 1849 if (SanityManager.DEBUG) 1850 { 1851 super.printSubNodes(depth); 1852 1853 if (subqueryList != null) 1854 { 1855 printLabel(depth, "subqueryList: "); 1856 subqueryList.treePrint(depth + 1); 1857 } 1858 1859 if (joinClause != null) 1860 { 1861 printLabel(depth, "joinClause: "); 1862 joinClause.treePrint(depth + 1); 1863 } 1864 1865 if (joinPredicates.size() != 0) 1866 { 1867 printLabel(depth, "joinPredicates: "); 1868 joinPredicates.treePrint(depth + 1); 1869 } 1870 1871 if (usingClause != null) 1872 { 1873 printLabel(depth, "usingClause: "); 1874 usingClause.treePrint(depth + 1); 1875 } 1876 } 1877 } 1878 1879 void setSubqueryList(SubqueryList subqueryList) 1880 { 1881 this.subqueryList = subqueryList; 1882 } 1883 1884 void setAggregateVector(Vector aggregateVector) 1885 { 1886 this.aggregateVector = aggregateVector; 1887 } 1888 1889 1895 ResultSetNode getLogicalLeftResultSet() 1896 { 1897 return leftResultSet; 1898 } 1899 1900 1906 ResultSetNode getLogicalRightResultSet() 1907 { 1908 return rightResultSet; 1909 } 1910 1911 1919 public Visitable accept(Visitor v) 1920 throws StandardException 1921 { 1922 if (v.skipChildren(this)) 1923 { 1924 return v.visit(this); 1925 } 1926 1927 Visitable returnNode = super.accept(v); 1928 1929 if (resultColumns != null && !v.stopTraversal()) 1930 { 1931 resultColumns = (ResultColumnList)resultColumns.accept(v); 1932 } 1933 1934 if (joinClause != null && !v.stopTraversal()) 1935 { 1936 joinClause = (ValueNode)joinClause.accept(v); 1937 } 1938 1939 if (usingClause != null && !v.stopTraversal()) 1940 { 1941 usingClause = (ResultColumnList)usingClause.accept(v); 1942 } 1943 1944 return returnNode; 1945 } 1946 1947 public JBitSet LOJgetReferencedTables(int numTables) 1953 throws StandardException 1954 { 1955 JBitSet map = new JBitSet(numTables); 1956 1957 map = (JBitSet) leftResultSet.LOJgetReferencedTables(numTables); 1958 if (map == null) return null; 1959 else map.or((JBitSet) rightResultSet.LOJgetReferencedTables(numTables)); 1960 1961 return map; 1962 } 1963 1964} 1965 | Popular Tags |