@Override
public Object process(Node nd, Stack<Node> stack, NodeProcessorCtx procCtx,
Object... nodeOutputs) throws SemanticException {
ExprNodeDesc newfd = null;
ExprNodeGenericFuncDesc fd = (ExprNodeGenericFuncDesc) nd;
boolean unknown = false;
if (FunctionRegistry.isOpAndOrNot(fd)) {
// do nothing because "And" and "Or" and "Not" supports null value
// evaluation
// NOTE: In the future all UDFs that treats null value as UNKNOWN (both
// in parameters and return
// values) should derive from a common base class UDFNullAsUnknown, so
// instead of listing the classes
// here we would test whether a class is derived from that base class.
// If All childs are null, set unknown to true
boolean isAllNull = true;
for (Object child : nodeOutputs) {
ExprNodeDesc child_nd = (ExprNodeDesc) child;
if (!(child_nd instanceof ExprNodeConstantDesc
&& ((ExprNodeConstantDesc) child_nd).getValue() == null)) {
isAllNull = false;
}
}
unknown = isAllNull;
} else if (!FunctionRegistry.isDeterministic(fd.getGenericUDF())) {
// If it's a non-deterministic UDF, set unknown to true
unknown = true;
} else {
// If any child is null, set unknown to true
for (Object child : nodeOutputs) {
ExprNodeDesc child_nd = (ExprNodeDesc) child;
if (child_nd instanceof ExprNodeConstantDesc
&& ((ExprNodeConstantDesc) child_nd).getValue() == null) {
unknown = true;
}
}
}
if (unknown) {
newfd = new ExprNodeConstantDesc(fd.getTypeInfo(), null);
} else {
// Create the list of children
ArrayList<ExprNodeDesc> children = new ArrayList<ExprNodeDesc>();
for (Object child : nodeOutputs) {
children.add((ExprNodeDesc) child);
}
// Create a copy of the function descriptor
newfd = new ExprNodeGenericFuncDesc(fd.getTypeInfo(), fd
.getGenericUDF(), children);
}
return newfd;
}