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.store.access.ColumnOrdering; 27 28 import org.apache.derby.iapi.sql.compile.AccessPath; 29 import org.apache.derby.iapi.sql.compile.Optimizable; 30 import org.apache.derby.iapi.sql.compile.OptimizableList; 31 import org.apache.derby.iapi.sql.compile.OptimizablePredicate; 32 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList; 33 import org.apache.derby.iapi.sql.compile.Optimizer; 34 import org.apache.derby.iapi.sql.compile.CostEstimate; 35 import org.apache.derby.iapi.sql.compile.Visitable; 36 import org.apache.derby.iapi.sql.compile.Visitor; 37 import org.apache.derby.iapi.sql.compile.RequiredRowOrdering; 38 import org.apache.derby.iapi.sql.compile.RowOrdering; 39 import org.apache.derby.iapi.sql.compile.C_NodeTypes; 40 41 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; 42 import org.apache.derby.iapi.reference.ClassName; 43 44 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 45 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext; 46 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; 47 import org.apache.derby.catalog.IndexDescriptor; 48 49 import org.apache.derby.iapi.sql.execute.ExecutionContext; 50 51 import org.apache.derby.iapi.sql.Activation; 52 import org.apache.derby.iapi.sql.LanguageFactory; 53 import org.apache.derby.iapi.sql.ResultColumnDescriptor; 54 import org.apache.derby.iapi.sql.ResultSet; 55 56 import org.apache.derby.iapi.error.StandardException; 57 58 import org.apache.derby.impl.sql.compile.ActivationClassBuilder; 59 import org.apache.derby.impl.sql.execute.AggregatorInfo; 60 import org.apache.derby.impl.sql.execute.AggregatorInfoList; 61 62 import org.apache.derby.iapi.services.compiler.MethodBuilder; 63 64 import org.apache.derby.iapi.services.sanity.SanityManager; 65 66 import org.apache.derby.iapi.services.io.FormatableArrayHolder; 67 import org.apache.derby.iapi.util.JBitSet; 68 69 import org.apache.derby.impl.sql.compile.MaxMinAggregateDefinition; 70 import org.apache.derby.iapi.services.classfile.VMOpcode; 71 72 import java.util.Vector ; 73 import java.util.Properties ; 74 75 76 97 public class GroupByNode extends SingleChildResultSetNode 98 { 99 102 GroupByList groupingList; 103 104 108 Vector aggregateVector; 109 110 114 private AggregatorInfoList aggInfo; 115 116 122 FromTable parent; 123 124 private boolean addDistinctAggregate; 125 private boolean singleInputRowOptimization; 126 private int addDistinctAggregateColumnNum; 127 128 private boolean isInSortedOrder; 130 131 144 public void init( 145 Object bottomPR, 146 Object groupingList, 147 Object aggregateVector, 148 Object tableProperties) 149 throws StandardException 150 { 151 super.init(bottomPR, tableProperties); 152 153 154 if (SanityManager.DEBUG) 155 { 156 SanityManager.ASSERT(((Vector ) aggregateVector).size() > 0, 157 "aggregateVector expected to be non-empty"); 158 if (!(childResult instanceof Optimizable)) 159 { 160 SanityManager.THROWASSERT("childResult, " + childResult.getClass().getName() + 161 ", expected to be instanceof Optimizable"); 162 } 163 if (!(childResult instanceof FromTable)) 164 { 165 SanityManager.THROWASSERT("childResult, " + childResult.getClass().getName() + 166 ", expected to be instanceof FromTable"); 167 } 168 } 169 170 ResultColumnList newBottomRCL; 171 this.groupingList = (GroupByList) groupingList; 172 this.aggregateVector = (Vector ) aggregateVector; 173 this.parent = this; 174 175 182 newBottomRCL = childResult.getResultColumns().copyListAndObjects(); 183 resultColumns = childResult.getResultColumns(); 184 childResult.setResultColumns(newBottomRCL); 185 186 191 addAggregates(); 192 193 198 if (! addDistinctAggregate && groupingList != null) 199 { 200 ColumnReference[] crs = 201 new ColumnReference[this.groupingList.size()]; 202 203 int glSize = this.groupingList.size(); 205 int index; 206 for (index = 0; index < glSize; index++) 207 { 208 GroupByColumn gc = 209 (GroupByColumn) this.groupingList.elementAt(index); 210 if (gc.getColumnExpression() instanceof ColumnReference) 211 { 212 crs[index] = (ColumnReference)gc.getColumnExpression(); 213 } 214 else 215 { 216 isInSortedOrder = false; 217 break; 218 } 219 220 } 221 if (index == glSize) { 222 isInSortedOrder = childResult.isOrderedOn(crs, true, (Vector )null); 223 } 224 } 225 } 226 227 232 boolean getIsInSortedOrder() 233 { 234 return isInSortedOrder; 235 } 236 237 243 private void addAggregates() 244 throws StandardException 245 { 246 addNewPRNode(); 247 addNewColumnsForAggregation(); 248 addDistinctAggregatesToOrderBy(); 249 } 250 251 255 private void addDistinctAggregatesToOrderBy() 256 { 257 int numDistinct = numDistinctAggregates(aggregateVector); 258 if (numDistinct != 0) 259 { 260 if (SanityManager.DEBUG) 261 { 262 SanityManager.ASSERT(numDistinct == 1, 263 "Should not have more than 1 distinct aggregate per Group By node"); 264 } 265 266 AggregatorInfo agg = null; 267 int count = aggInfo.size(); 268 for (int i = 0; i < count; i++) 269 { 270 agg = (AggregatorInfo) aggInfo.elementAt(i); 271 if (agg.isDistinct()) 272 { 273 break; 274 } 275 } 276 277 if (SanityManager.DEBUG) 278 { 279 SanityManager.ASSERT(agg != null && agg.isDistinct()); 280 } 281 282 addDistinctAggregate = true; 283 addDistinctAggregateColumnNum = agg.getInputColNum(); 284 } 285 } 286 287 293 private void addNewPRNode() 294 throws StandardException 295 { 296 299 parent = (FromTable) getNodeFactory().getNode( 300 C_NodeTypes.PROJECT_RESTRICT_NODE, 301 this, resultColumns, null, null, null, null, tableProperties, 308 getContextManager()); 309 310 311 314 childResult.setResultColumns((ResultColumnList) 315 getNodeFactory().getNode( 316 C_NodeTypes.RESULT_COLUMN_LIST, 317 getContextManager())); 318 319 322 resultColumns = (ResultColumnList) getNodeFactory().getNode( 323 C_NodeTypes.RESULT_COLUMN_LIST, 324 getContextManager()); 325 326 } 327 328 334 private void addUnAggColumns() throws StandardException 335 { 336 ResultColumnList bottomRCL = childResult.getResultColumns(); 337 ResultColumnList groupByRCL = resultColumns; 338 339 int sz = groupingList.size(); 340 for (int i = 0; i < sz; i++) 341 { 342 GroupByColumn gbc = (GroupByColumn) groupingList.elementAt(i); 343 ResultColumn newRC = (ResultColumn) getNodeFactory().getNode( 344 C_NodeTypes.RESULT_COLUMN, 345 "##UnaggColumn", 346 gbc.getColumnExpression(), 347 getContextManager()); 348 349 bottomRCL.addElement(newRC); 351 newRC.markGenerated(); 352 newRC.bindResultColumnToExpression(); 353 newRC.setVirtualColumnId(bottomRCL.size()); 354 355 ResultColumn gbRC = (ResultColumn) getNodeFactory().getNode( 357 C_NodeTypes.RESULT_COLUMN, 358 "##UnaggColumn", 359 gbc.getColumnExpression(), 360 getContextManager()); 361 groupByRCL.addElement(gbRC); 362 gbRC.markGenerated(); 363 gbRC.bindResultColumnToExpression(); 364 gbRC.setVirtualColumnId(groupByRCL.size()); 365 366 370 VirtualColumnNode vc = (VirtualColumnNode) getNodeFactory().getNode( 371 C_NodeTypes.VIRTUAL_COLUMN_NODE, 372 this, gbRC, 374 new Integer (groupByRCL.size()), 375 getContextManager()); 376 377 SubstituteExpressionVisitor se = 382 new SubstituteExpressionVisitor( 383 gbc.getColumnExpression(), 384 vc, 385 AggregateNode.class); 386 parent.getResultColumns().accept(se); 387 388 gbc.setColumnPosition(bottomRCL.size()); 390 } 391 } 392 393 432 private void addNewColumnsForAggregation() 433 throws StandardException 434 { 435 aggInfo = new AggregatorInfoList(); 436 if (groupingList != null) 437 { 438 addUnAggColumns(); 439 } 440 addAggregateColumns(); 441 } 442 443 449 private void addAggregateColumns() throws StandardException 450 { 451 DataDictionary dd = getDataDictionary(); 452 AggregateNode aggregate = null; 453 ColumnReference newColumnRef; 454 ResultColumn newRC; 455 ResultColumn tmpRC; 456 ResultColumn aggInputRC; 457 ResultColumnList bottomRCL = childResult.getResultColumns(); 458 ResultColumnList groupByRCL = resultColumns; 459 ResultColumnList aggRCL; 460 int aggregatorVColId; 461 int aggInputVColId; 462 int aggResultVColId; 463 464 470 LanguageFactory lf = getLanguageConnectionContext().getLanguageFactory(); 471 472 ReplaceAggregatesWithCRVisitor replaceAggsVisitor = 473 new ReplaceAggregatesWithCRVisitor( 474 (ResultColumnList) getNodeFactory().getNode( 475 C_NodeTypes.RESULT_COLUMN_LIST, 476 getContextManager()), 477 ((FromTable) childResult).getTableNumber()); 478 parent.getResultColumns().accept(replaceAggsVisitor); 479 480 483 int alSize = aggregateVector.size(); 484 for (int index = 0; index < alSize; index++) 485 { 486 aggregate = (AggregateNode) aggregateVector.elementAt(index); 487 488 492 newRC = (ResultColumn) getNodeFactory().getNode( 493 C_NodeTypes.RESULT_COLUMN, 494 "##aggregate result", 495 aggregate.getNewNullResultExpression(), 496 getContextManager()); 497 newRC.markGenerated(); 498 newRC.bindResultColumnToExpression(); 499 bottomRCL.addElement(newRC); 500 newRC.setVirtualColumnId(bottomRCL.size()); 501 aggResultVColId = newRC.getVirtualColumnId(); 502 503 509 newColumnRef = (ColumnReference) getNodeFactory().getNode( 510 C_NodeTypes.COLUMN_REFERENCE, 511 newRC.getName(), 512 null, 513 getContextManager()); 514 newColumnRef.setSource(newRC); 515 newColumnRef.setType(newRC.getExpressionType()); 516 newColumnRef.setNestingLevel(this.getLevel()); 517 newColumnRef.setSourceLevel(this.getLevel()); 518 tmpRC = (ResultColumn) getNodeFactory().getNode( 519 C_NodeTypes.RESULT_COLUMN, 520 newRC.getColumnName(), 521 newColumnRef, 522 getContextManager()); 523 tmpRC.markGenerated(); 524 tmpRC.bindResultColumnToExpression(); 525 groupByRCL.addElement(tmpRC); 526 tmpRC.setVirtualColumnId(groupByRCL.size()); 527 528 532 newColumnRef = aggregate.getGeneratedRef(); 533 newColumnRef.setSource(tmpRC); 534 535 540 newRC = aggregate.getNewExpressionResultColumn(dd); 541 newRC.markGenerated(); 542 newRC.bindResultColumnToExpression(); 543 bottomRCL.addElement(newRC); 544 newRC.setVirtualColumnId(bottomRCL.size()); 545 aggInputVColId = newRC.getVirtualColumnId(); 546 aggInputRC = newRC; 547 548 552 tmpRC = getColumnReference(newRC, dd); 553 groupByRCL.addElement(tmpRC); 554 tmpRC.setVirtualColumnId(groupByRCL.size()); 555 556 560 newRC = aggregate.getNewAggregatorResultColumn(dd); 561 newRC.markGenerated(); 562 newRC.bindResultColumnToExpression(); 563 bottomRCL.addElement(newRC); 564 newRC.setVirtualColumnId(bottomRCL.size()); 565 aggregatorVColId = newRC.getVirtualColumnId(); 566 567 571 tmpRC = getColumnReference(newRC, dd); 572 groupByRCL.addElement(tmpRC); 573 tmpRC.setVirtualColumnId(groupByRCL.size()); 574 575 580 aggRCL = (ResultColumnList) getNodeFactory().getNode( 581 C_NodeTypes.RESULT_COLUMN_LIST, 582 getContextManager()); 583 aggRCL.addElement(aggInputRC); 584 585 589 aggInfo.addElement(new AggregatorInfo( 590 aggregate.getAggregateName(), 591 aggregate.getAggregatorClassName(), 592 aggInputVColId - 1, aggResultVColId -1, aggregatorVColId - 1, aggregate.isDistinct(), 596 lf.getResultDescription(aggRCL.makeResultDescriptors(), "SELECT") 597 )); 598 } 599 } 600 601 608 public FromTable getParent() 609 { 610 return parent; 611 } 612 613 614 617 618 623 public CostEstimate optimizeIt( 624 Optimizer optimizer, 625 OptimizablePredicateList predList, 626 CostEstimate outerCost, 627 RowOrdering rowOrdering) 628 throws StandardException 629 { 630 CostEstimate childCost = ((Optimizable) childResult).optimizeIt( 632 optimizer, 633 predList, 634 outerCost, 635 rowOrdering); 636 637 CostEstimate retval = super.optimizeIt( 638 optimizer, 639 predList, 640 outerCost, 641 rowOrdering 642 ); 643 644 return retval; 645 } 646 647 652 public CostEstimate estimateCost(OptimizablePredicateList predList, 653 ConglomerateDescriptor cd, 654 CostEstimate outerCost, 655 Optimizer optimizer, 656 RowOrdering rowOrdering 657 ) 658 throws StandardException 659 { 660 CostEstimate childCost = ((Optimizable) childResult).estimateCost( 663 predList, 664 cd, 665 outerCost, 666 optimizer, 667 rowOrdering); 668 669 CostEstimate costEstimate = getCostEstimate(optimizer); 670 costEstimate.setCost(childCost.getEstimatedCost(), 671 childCost.rowCount(), 672 childCost.singleScanRowCount()); 673 674 return costEstimate; 675 } 676 677 682 683 public boolean pushOptPredicate(OptimizablePredicate optimizablePredicate) 684 throws StandardException 685 { 686 return ((Optimizable) childResult).pushOptPredicate(optimizablePredicate); 687 } 688 689 695 696 public String toString() 697 { 698 if (SanityManager.DEBUG) 699 { 700 return "singleInputRowOptimization: " + singleInputRowOptimization + "\n" + 701 childResult.toString() + "\n" + super.toString(); 702 } 703 else 704 { 705 return ""; 706 } 707 } 708 709 721 public boolean flattenableInFromSubquery(FromList fromList) 722 { 723 724 return false; 725 } 726 727 739 740 public ResultSetNode optimize(DataDictionary dataDictionary, 741 PredicateList predicates, 742 double outerRows) 743 throws StandardException 744 { 745 748 childResult = (FromTable) childResult.optimize( 749 dataDictionary, 750 predicates, 751 outerRows); 752 Optimizer optimizer = getOptimizer( 753 (FromList) getNodeFactory().getNode( 754 C_NodeTypes.FROM_LIST, 755 getNodeFactory().doJoinOrderOptimization(), 756 getContextManager()), 757 predicates, 758 dataDictionary, 759 (RequiredRowOrdering) null); 760 761 costEstimate = optimizer.newCostEstimate(); 764 765 costEstimate.setCost(childResult.getCostEstimate().getEstimatedCost(), 766 childResult.getCostEstimate().rowCount(), 767 childResult.getCostEstimate().singleScanRowCount()); 768 769 return this; 770 } 771 772 ResultColumnDescriptor[] makeResultDescriptors(ExecutionContext ec) 773 { 774 return childResult.makeResultDescriptors(ec); 775 } 776 777 786 public boolean isOneRowResultSet() throws StandardException 787 { 788 return ((groupingList == null) || (groupingList.size() == 0)); 790 } 791 792 799 public void generate(ActivationClassBuilder acb, 800 MethodBuilder mb) 801 throws StandardException 802 { 803 int orderingItem = 0; 804 int aggInfoItem = 0; 805 FormatableArrayHolder orderingHolder; 806 807 810 assignResultSetNumber(); 811 812 costEstimate = childResult.getFinalCostEstimate(); 814 815 824 orderingHolder = acb.getColumnOrdering(groupingList); 825 if (addDistinctAggregate) 826 { 827 orderingHolder = acb.addColumnToOrdering( 828 orderingHolder, 829 addDistinctAggregateColumnNum); 830 } 831 832 if (SanityManager.DEBUG) 833 { 834 if (SanityManager.DEBUG_ON("AggregateTrace")) 835 { 836 StringBuffer s = new StringBuffer (); 837 838 s.append("Group by column ordering is ("); 839 ColumnOrdering[] ordering = 840 (ColumnOrdering[])orderingHolder.getArray(ColumnOrdering.class); 841 842 for (int i = 0; i < ordering.length; i++) 843 { 844 s.append(ordering[i].getColumnId()); 845 s.append(" "); 846 } 847 s.append(")"); 848 SanityManager.DEBUG("AggregateTrace", s.toString()); 849 } 850 } 851 852 orderingItem = acb.addItem(orderingHolder); 853 854 858 if (SanityManager.DEBUG) 859 { 860 SanityManager.ASSERT(aggInfo != null, 861 "aggInfo not set up as expected"); 862 } 863 aggInfoItem = acb.addItem(aggInfo); 864 865 acb.pushGetResultSetFactoryExpression(mb); 866 867 childResult.generate(acb, mb); 869 mb.push(isInSortedOrder); 870 mb.push(aggInfoItem); 871 mb.push(orderingItem); 872 873 resultColumns.generateHolder(acb, mb); 874 875 mb.push(resultColumns.getTotalColumnSize()); 876 mb.push(resultSetNumber); 877 878 879 if ((groupingList == null) || (groupingList.size() == 0)) 880 { 881 genScalarAggregateResultSet(acb, mb); 882 } 883 884 else 885 { 886 genGroupedAggregateResultSet(acb, mb); 887 } 888 } 889 890 894 private void genScalarAggregateResultSet(ActivationClassBuilder acb, 895 MethodBuilder mb) 896 { 897 909 String resultSet = (addDistinctAggregate) ? "getDistinctScalarAggregateResultSet" : "getScalarAggregateResultSet"; 910 911 mb.push(singleInputRowOptimization); 912 mb.push(costEstimate.rowCount()); 913 mb.push(costEstimate.getEstimatedCost()); 914 915 mb.callMethod(VMOpcode.INVOKEINTERFACE, (String ) null, resultSet, 916 ClassName.NoPutResultSet, 10); 917 } 918 919 923 private void genGroupedAggregateResultSet(ActivationClassBuilder acb, 924 MethodBuilder mb) 925 throws StandardException 926 { 927 938 String resultSet = (addDistinctAggregate) ? "getDistinctGroupedAggregateResultSet" : "getGroupedAggregateResultSet"; 939 940 mb.push(costEstimate.rowCount()); 941 mb.push(costEstimate.getEstimatedCost()); 942 943 mb.callMethod(VMOpcode.INVOKEINTERFACE, (String ) null, resultSet, 944 ClassName.NoPutResultSet, 9); 945 946 } 947 948 964 private ResultColumn getColumnReference(ResultColumn targetRC, 965 DataDictionary dd) 966 throws StandardException 967 { 968 ColumnReference tmpColumnRef; 969 ResultColumn newRC; 970 971 tmpColumnRef = (ColumnReference) getNodeFactory().getNode( 972 C_NodeTypes.COLUMN_REFERENCE, 973 targetRC.getName(), 974 null, 975 getContextManager()); 976 tmpColumnRef.setSource(targetRC); 977 tmpColumnRef.setType(targetRC.getExpressionType()); 978 tmpColumnRef.setNestingLevel(this.getLevel()); 979 tmpColumnRef.setSourceLevel(this.getLevel()); 980 newRC = (ResultColumn) getNodeFactory().getNode( 981 C_NodeTypes.RESULT_COLUMN, 982 targetRC.getColumnName(), 983 tmpColumnRef, 984 getContextManager()); 985 newRC.markGenerated(); 986 newRC.bindResultColumnToExpression(); 987 return newRC; 988 } 989 990 1001 void considerPostOptimizeOptimizations(boolean selectHasPredicates) 1002 throws StandardException 1003 { 1004 1016 if (groupingList == null) 1017 { 1018 if (aggregateVector.size() == 1) 1019 { 1020 AggregateNode an = (AggregateNode) aggregateVector.elementAt(0); 1021 AggregateDefinition ad = an.getAggregateDefinition(); 1022 if (ad instanceof MaxMinAggregateDefinition) 1023 { 1024 if (an.getOperand() instanceof ColumnReference) 1025 { 1026 1029 ColumnReference[] crs = new ColumnReference[1]; 1030 crs[0] = (ColumnReference) an.getOperand(); 1031 1032 Vector tableVector = new Vector (); 1033 boolean minMaxOptimizationPossible = isOrderedOn(crs, false, tableVector); 1034 if (SanityManager.DEBUG) 1035 { 1036 SanityManager.ASSERT(tableVector.size() <= 1, "bad number of FromBaseTables returned by isOrderedOn() -- "+tableVector.size()); 1037 } 1038 1039 if (minMaxOptimizationPossible) 1040 { 1041 boolean ascIndex = true; 1042 int colNum = crs[0].getColumnNumber(); 1043 1044 1047 AccessPath accessPath= getTrulyTheBestAccessPath(); 1048 if (accessPath == null) 1049 return; 1050 IndexDescriptor id = accessPath. 1051 getConglomerateDescriptor(). 1052 getIndexDescriptor(); 1053 int[] keyColumns = id.baseColumnPositions(); 1054 boolean[] isAscending = id.isAscending(); 1055 for (int i = 0; i < keyColumns.length; i++) 1056 { 1057 1063 if (colNum == keyColumns[i]) 1064 { 1065 if (! isAscending[i]) 1066 ascIndex = false; 1067 break; 1068 } 1069 } 1070 FromBaseTable fbt = (FromBaseTable)tableVector.firstElement(); 1071 MaxMinAggregateDefinition temp = (MaxMinAggregateDefinition)ad; 1072 1073 1080 1081 if (((!temp.isMax()) && ascIndex) || 1082 ((temp.isMax()) && !ascIndex)) 1083 { 1084 fbt.disableBulkFetch(); 1085 singleInputRowOptimization = true; 1086 } 1087 1097 else if (!selectHasPredicates && 1098 ((temp.isMax() && ascIndex) || 1099 (!temp.isMax() && !ascIndex ))) 1100 { 1101 fbt.disableBulkFetch(); 1102 fbt.doSpecialMaxScan(); 1103 singleInputRowOptimization = true; 1104 } 1105 } 1106 } 1107 else if (an.getOperand() instanceof ConstantNode) 1108 { 1109 singleInputRowOptimization = true; 1110 } 1111 } 1112 } 1113 } 1114 } 1115} 1116 | Popular Tags |