private Object handleDeterministicUdf(PcrExprProcCtx ctx,
        ExprNodeGenericFuncDesc fd, Object... nodeOutputs)
        throws SemanticException {
      Boolean has_part_col = checkForPartColsAndUnknown(nodeOutputs);
      if (has_part_col == null) {
        return new NodeInfoWrapper(WalkState.UNKNOWN, null, getOutExpr(fd, nodeOutputs));
      }

      if (has_part_col && fd.getTypeInfo().getCategory() == Category.PRIMITIVE) {
        //  we need to evaluate result for every pruned partition
        if (fd.getTypeInfo().equals(TypeInfoFactory.booleanTypeInfo)) {
          // if the return type of the GenericUDF is boolean and all partitions agree on
          // a result, we update the state of the node to be TRUE of FALSE
          Boolean[] results = new Boolean[ctx.getPartList().size()];
          for (int i = 0; i < ctx.getPartList().size(); i++) {
            results[i] = (Boolean) evalExprWithPart(fd, ctx.getPartList().get(i));
          }
          return getResultWrapFromResults(results, fd, nodeOutputs);
        }

        // the case that return type of the GenericUDF is not boolean, and if not all partition
        // agree on result, we make the node UNKNOWN. If they all agree, we replace the node
        // to be a CONSTANT node with value to be the agreed result.
        Object[] results = new Object[ctx.getPartList().size()];
        for (int i = 0; i < ctx.getPartList().size(); i++) {
          results[i] = evalExprWithPart(fd, ctx.getPartList().get(i));
        }
        Object result = ifResultsAgree(results);
        if (result == null) {
          // if the result is not boolean and not all partition agree on the
          // result, we don't remove the condition. Potentially, it can miss
          // the case like "where ds % 3 == 1 or ds % 3 == 2"
          // TODO: handle this case by making result vector to handle all
          // constant values.
          return new NodeInfoWrapper(WalkState.UNKNOWN, null, getOutExpr(fd, nodeOutputs));
        }
        return new NodeInfoWrapper(
            WalkState.CONSTANT, null, new ExprNodeConstantDesc(fd.getTypeInfo(), result));
      }

      // Try to fold, otherwise return the expression itself
      final ExprNodeGenericFuncDesc desc = getOutExpr(fd, nodeOutputs);
      final ExprNodeDesc foldedDesc = ConstantPropagateProcFactory.foldExpr(desc);
     
      if (foldedDesc instanceof ExprNodeConstantDesc) {
        ExprNodeConstantDesc constant = (ExprNodeConstantDesc) foldedDesc;
        
        if (Boolean.TRUE.equals(constant.getValue())) {
          return new NodeInfoWrapper(WalkState.TRUE, null, constant);
        } else if (Boolean.FALSE.equals(constant.getValue())) {
          return new NodeInfoWrapper(WalkState.FALSE, null, constant);
        } else {
          return new NodeInfoWrapper(WalkState.CONSTANT, null, constant);
        }
      }
      return new NodeInfoWrapper(WalkState.CONSTANT, null, desc);
    }
Processor for Generic functions

If it is AND, OR or NOT, we replace the node to be the constant true or
false if we are sure the result from children, or cut one of the child
if we know partial results. In case of both child has a result vector,
we calculate the result vector for the node. If all partitions agree on
a result, we replace the node with constant true or false. Otherwise, we
pass the vector result. For other Generic functions, if it is non-deterministic
we simply pass it (with children adjusted based on results from children).
If it is deterministic, we evaluate result vector if any of the children
is partition column. Otherwise, we pass it as it is.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/pcr/PcrExprProcFactory.java