1 21 22 package org.apache.derby.impl.sql.compile; 23 24 import org.apache.derby.iapi.services.compiler.MethodBuilder; 25 26 import org.apache.derby.iapi.services.sanity.SanityManager; 27 import org.apache.derby.iapi.services.loader.ClassInspector; 28 import org.apache.derby.iapi.services.loader.ClassFactory; 29 30 import org.apache.derby.iapi.error.StandardException; 31 32 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 33 34 import org.apache.derby.iapi.sql.compile.CompilerContext; 35 import org.apache.derby.iapi.sql.compile.C_NodeTypes; 36 37 import org.apache.derby.iapi.types.DataTypeDescriptor; 38 import org.apache.derby.iapi.types.TypeId; 39 import org.apache.derby.iapi.reference.SQLState; 40 41 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 42 import org.apache.derby.iapi.sql.execute.ExecAggregator; 43 44 import org.apache.derby.iapi.error.StandardException; 45 import org.apache.derby.iapi.reference.SQLState; 46 47 import org.apache.derby.impl.sql.compile.ActivationClassBuilder; 48 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder; 49 50 import org.apache.derby.catalog.AliasInfo; 51 import org.apache.derby.catalog.TypeDescriptor; 52 53 import org.apache.derby.impl.sql.compile.CountAggregateDefinition; 54 import org.apache.derby.impl.sql.compile.MaxMinAggregateDefinition; 55 import org.apache.derby.impl.sql.compile.SumAvgAggregateDefinition; 56 57 import java.util.Vector ; 58 59 65 66 public class AggregateNode extends UnaryOperatorNode 67 { 68 private boolean distinct; 69 70 private AggregateDefinition uad; 71 private StringBuffer aggregatorClassName; 72 private String aggregateDefinitionClassName; 73 private Class aggregateDefinitionClass; 74 private ClassInspector classInspector; 75 private String aggregateName; 76 77 84 private ResultColumn generatedRC; 85 private ColumnReference generatedRef; 86 87 101 public void init 102 ( 103 Object operand, 104 Object uadClass, 105 Object distinct, 106 Object aggregateName 107 ) throws StandardException 108 { 109 super.init(operand); 110 this.aggregateName = (String ) aggregateName; 111 112 if (uadClass instanceof String ) 113 { 114 this.aggregateDefinitionClassName = (String ) uadClass; 115 this.distinct = ((Boolean ) distinct).booleanValue(); 116 } 117 else 118 { 119 this.aggregateDefinitionClass = (Class ) uadClass; 120 this.aggregateDefinitionClassName = 121 aggregateDefinitionClass.getName(); 122 123 if (!aggregateDefinitionClass.equals(MaxMinAggregateDefinition.class)) 125 { 126 this.distinct = ((Boolean ) distinct).booleanValue(); 127 } 128 } 129 } 130 131 148 public ValueNode replaceAggregatesWithColumnReferences(ResultColumnList rcl, int tableNumber) 149 throws StandardException 150 { 151 152 157 if (generatedRef == null) 158 { 159 String generatedColName; 160 CompilerContext cc = getCompilerContext(); 161 generatedColName ="SQLCol" + cc.getNextColumnNumber(); 162 generatedRC = (ResultColumn) getNodeFactory().getNode( 163 C_NodeTypes.RESULT_COLUMN, 164 generatedColName, 165 this, 166 getContextManager()); 167 generatedRC.markGenerated(); 168 169 172 if (getTypeServices() == null) 173 { 174 generatedRef = (ColumnReference) getNodeFactory().getNode( 175 C_NodeTypes.COLUMN_REFERENCE, 176 generatedColName, 177 null, 178 getContextManager()); 179 } 180 else 181 { 182 generatedRef = (ColumnReference) getNodeFactory().getNode( 183 C_NodeTypes.COLUMN_REFERENCE, 184 generatedRC.getName(), 185 null, 186 getContextManager()); 187 generatedRef.setType(this.getTypeServices()); 188 } 189 generatedRef.setNestingLevel(0); 191 generatedRef.setSourceLevel(0); 192 if (tableNumber != -1) 193 { 194 generatedRef.setTableNumber(tableNumber); 195 } 196 197 rcl.addResultColumn(generatedRC); 198 199 203 generatedRef.markGeneratedToReplaceAggregate(); 204 } 205 else 206 { 207 rcl.addResultColumn(generatedRC); 208 } 209 210 return generatedRef; 211 } 212 213 218 AggregateDefinition getAggregateDefinition() 219 { 220 return uad; 221 } 222 223 230 public ResultColumn getGeneratedRC() 231 { 232 if (SanityManager.DEBUG) 233 { 234 SanityManager.ASSERT(generatedRC != null, 235 "generatedRC is null. replaceAggregateWithColumnReference() "+ 236 "has not been called on this AggergateNode. Make sure "+ 237 "the node is under a ResultColumn as expected."); 238 } 239 240 return generatedRC; 241 } 242 243 250 public ColumnReference getGeneratedRef() 251 { 252 if (SanityManager.DEBUG) 253 { 254 SanityManager.ASSERT(generatedRef != null, 255 "generatedRef is null. replaceAggregateWithColumnReference() "+ 256 "has not been called on this AggergateNode. Make sure "+ 257 "the node is under a ResultColumn as expected."); 258 } 259 return generatedRef; 260 } 261 262 274 public ValueNode bindExpression( 275 FromList fromList, 276 SubqueryList subqueryList, 277 Vector aggregateVector) 278 throws StandardException 279 { 280 TypeId outType; 281 TypeId inputType = null; 282 Class inputClass = null; 283 String inputTypeName = null; 284 Class inputInterfaceClass = null; 285 String inputInterfaceName = null; 286 DataTypeDescriptor dts = null; 287 TypeDescriptor resultType = null; 288 ClassFactory cf; 289 290 cf = getClassFactory(); 291 classInspector = cf.getClassInspector(); 292 293 instantiateAggDef(); 294 295 296 aggregateVector.addElement(this); 297 298 super.bindExpression( 299 fromList, subqueryList, 300 aggregateVector); 301 302 if (operand != null) 303 { 304 309 HasNodeVisitor visitor = new HasNodeVisitor(this.getClass(), ResultSetNode.class); 310 operand.accept(visitor); 311 if (visitor.hasNode()) 312 { 313 throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_CONTAINS_AGGREGATE, 314 aggregateName); 315 } 316 317 321 dts = operand.getTypeServices(); 322 323 324 if (uad instanceof CountAggregateDefinition && 325 !dts.isNullable()) 326 { 327 setOperator(aggregateName); 328 setMethodName(aggregateName); 329 } 330 331 336 if (distinct) 337 { 338 344 if (!operand.getTypeId().orderable(cf)) 345 { 346 throw StandardException.newException(SQLState.LANG_COLUMN_NOT_ORDERABLE_DURING_EXECUTION, 347 dts.getTypeId().getSQLTypeName()); 348 } 349 350 } 351 352 355 if (operand instanceof UntypedNullConstantNode) 356 { 357 throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_BAD_TYPE_NULL, aggregateName); 358 } 359 } 360 361 366 try 367 { 368 aggregatorClassName = new StringBuffer (); 369 resultType = uad.getAggregator(dts, aggregatorClassName); 370 } catch (Exception e) 371 { 372 throw StandardException.unexpectedUserException(e); 378 } 379 380 if (resultType == null) 381 { 382 throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_BAD_TYPE, 383 aggregateName, 384 operand.getTypeId().getSQLTypeName()); 385 } 386 387 checkAggregatorClassName(aggregatorClassName.toString()); 388 389 393 TypeId compTypeId = TypeId.getBuiltInTypeId(resultType.getTypeName()); 394 398 if (compTypeId == null) 399 { 400 compTypeId = TypeId.getSQLTypeForJavaType(resultType.getTypeName()); 401 } 402 403 408 setType(new DataTypeDescriptor( 409 compTypeId, 410 resultType.getPrecision(), 411 resultType.getScale(), 412 resultType.isNullable(), 413 resultType.getMaximumWidth() 414 ) 415 ); 416 417 return this; 418 } 419 420 423 private void checkAggregatorClassName(String className) throws StandardException 424 { 425 className = verifyClassExist(className, false); 426 427 if (!classInspector.assignableTo(className, "org.apache.derby.iapi.sql.execute.ExecAggregator")) 428 { 429 throw StandardException.newException(SQLState.LANG_BAD_AGGREGATOR_CLASS2, 430 className, 431 aggregateName, 432 operand.getTypeId().getSQLTypeName()); 433 } 434 } 435 436 437 440 private void instantiateAggDef() throws StandardException 441 { 442 Class theClass = aggregateDefinitionClass; 443 444 if (theClass == null) 446 { 447 String aggClassName = aggregateDefinitionClassName; 448 aggClassName = verifyClassExist(aggClassName, false); 449 450 try 451 { 452 theClass = classInspector.getClass(aggClassName); 453 } 454 catch (Throwable t) 455 { 456 throw StandardException.unexpectedUserException(t); 457 } 458 } 459 460 Object instance = null; 462 try 463 { 464 instance = theClass.newInstance(); 465 } 466 catch (Throwable t) 467 { 468 throw StandardException.unexpectedUserException(t); 469 } 470 471 if (!(instance instanceof AggregateDefinition)) 472 { 473 throw StandardException.newException(SQLState.LANG_INVALID_USER_AGGREGATE_DEFINITION2, aggregateDefinitionClassName); 474 } 475 476 if (instance instanceof MaxMinAggregateDefinition) 477 { 478 MaxMinAggregateDefinition temp = (MaxMinAggregateDefinition)instance; 479 if (aggregateName.equals("MAX")) 480 temp.setMaxOrMin(true); 481 else 482 temp.setMaxOrMin(false); 483 } 484 485 if (instance instanceof SumAvgAggregateDefinition) 486 { 487 SumAvgAggregateDefinition temp1 = (SumAvgAggregateDefinition)instance; 488 if (aggregateName.equals("SUM")) 489 temp1.setSumOrAvg(true); 490 else 491 temp1.setSumOrAvg(false); 492 } 493 494 this.uad = (AggregateDefinition)instance; 495 496 setOperator(aggregateName); 497 setMethodName(aggregateDefinitionClassName); 498 499 } 500 501 506 public boolean isDistinct() 507 { 508 return distinct; 509 } 510 511 517 public String getAggregatorClassName() 518 { 519 return aggregatorClassName.toString(); 520 } 521 522 528 public String getAggregateName() 529 { 530 return aggregateName; 531 } 532 533 543 public ResultColumn getNewAggregatorResultColumn(DataDictionary dd) 544 throws StandardException 545 { 546 String className = aggregatorClassName.toString(); 547 548 TypeId compTypeId = TypeId.getSQLTypeForJavaType(className); 549 550 554 ConstantNode nullNode = getNullNode( 555 compTypeId, 556 getContextManager()); 558 nullNode.bindExpression( 559 null, null, null); 563 567 return (ResultColumn) getNodeFactory().getNode( 568 C_NodeTypes.RESULT_COLUMN, 569 aggregateName, 570 nullNode, 571 getContextManager()); 572 } 573 574 575 585 public ResultColumn getNewExpressionResultColumn(DataDictionary dd) 586 throws StandardException 587 { 588 ValueNode node; 589 595 node = (operand == null) ? 596 this.getNewNullResultExpression() : 597 operand; 598 599 return (ResultColumn) getNodeFactory().getNode( 600 C_NodeTypes.RESULT_COLUMN, 601 "##aggregate expression", 602 node, 603 getContextManager()); 604 } 605 606 614 public ValueNode getNewNullResultExpression() 615 throws StandardException 616 { 617 621 return getNullNode(this.getTypeId(), 622 getContextManager()); 623 } 624 625 635 public void generateExpression(ExpressionClassBuilder acb, 636 MethodBuilder mb) 637 throws StandardException 638 { 639 if (SanityManager.DEBUG) 640 { 641 SanityManager.THROWASSERT("generateExpression() should never "+ 642 "be called on an AggregateNode. "+ 643 "replaceAggregatesWithColumnReferences should have " + 644 "been called prior to generateExpression"); 645 } 646 } 647 648 653 public String toString() 654 { 655 if (SanityManager.DEBUG) 656 { 657 return "Aggregate: "+aggregateName+ 658 "\ndistinct: "+distinct+ 659 super.toString(); 660 } 661 else 662 { 663 return ""; 664 } 665 } 666 } 667 | Popular Tags |