FromList fromList,
SubqueryList subqueryList,
Vector aggregateVector)
throws StandardException
{
TypeId outType;
TypeId inputType = null;
Class inputClass = null;
String inputTypeName = null;
Class inputInterfaceClass = null;
String inputInterfaceName = null;
DataTypeDescriptor dts = null;
TypeDescriptor resultType = null;
ClassFactory cf;
cf = getClassFactory();
classInspector = cf.getClassInspector();
instantiateAggDef();
/* Add ourselves to the aggregateVector before we do anything else */
aggregateVector.addElement(this);
super.bindExpression(
fromList, subqueryList,
aggregateVector);
if (operand != null)
{
/*
** Make sure that we don't have an aggregate
** IMMEDIATELY below us. Don't search below
** any ResultSetNodes.
*/
HasNodeVisitor visitor = new HasNodeVisitor(this.getClass(), ResultSetNode.class);
operand.accept(visitor);
if (visitor.hasNode())
{
throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_CONTAINS_AGGREGATE,
aggregateName);
}
/*
** Check the type of the operand. Make sure that the user
** defined aggregate can handle the operand datatype.
*/
dts = operand.getTypeServices();
/* Convert count(nonNullableColumn) to count(*) */
if (uad instanceof CountAggregateDefinition &&
!dts.isNullable())
{
setOperator(aggregateName);
setMethodName(aggregateName);
}
/*
** If we have a distinct, then the value expression
** MUST implement Orderable because we are going
** to process it using it as part of a sort.
*/
if (distinct)
{
/*
** For now, we check to see if orderable() returns
** true for this type. In the future we may need
** to check to see if the type implements Orderable
**
*/
if (!operand.getTypeId().orderable(cf))
{
throw StandardException.newException(SQLState.LANG_COLUMN_NOT_ORDERABLE_DURING_EXECUTION,
dts.getTypeId().getSQLTypeName());
}
}
/*
** Don't allow an untyped null
*/
if (operand instanceof UntypedNullConstantNode)
{
throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_BAD_TYPE_NULL, aggregateName);
}
}
/*
** Ask the aggregate definition whether it can handle
** the input datatype. If an exception is thrown,
** barf.
*/
try
{
aggregatorClassName = new StringBuffer();
resultType = uad.getAggregator(dts, aggregatorClassName);
} catch (Exception e)
{
//RESOLVE: would be a good idea to add some additional text to
// this error, like during getResultDataType on aggregate x
// maybe enhance this error everywhere (seems like execution
// should also add some text, at the very least saying during
// execution. see Compiltion/Generator/UserExpressionBuilder.java
throw StandardException.unexpectedUserException(e);
}
if (resultType == null)
{
throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_BAD_TYPE,
aggregateName,
operand.getTypeId().getSQLTypeName());
}
checkAggregatorClassName(aggregatorClassName.toString());
/*
** Try for a built in type matching the
** type name.
*/
TypeId compTypeId = TypeId.getBuiltInTypeId(resultType.getTypeName());
/*
** If not built in, it is probably a java type.
** Get the sql type descriptor for that.
*/
if (compTypeId == null)