@Override
    public Object process(Node nd, Stack<Node> stack, NodeProcessorCtx procCtx,
        Object... nodeOutputs) throws SemanticException {
      PcrExprProcCtx ctx = (PcrExprProcCtx) procCtx;
      ExprNodeGenericFuncDesc fd = (ExprNodeGenericFuncDesc) nd;
      if (LOG.isDebugEnabled()) {
        String err = "Processing " + fd.getExprString() + " "
            + fd.getGenericUDF().getUdfName() + " outputs ";
        for (Object child : nodeOutputs) {
          NodeInfoWrapper wrapper = (NodeInfoWrapper) child;
          err += "{" + wrapper.state + ", " + wrapper.outExpr + "}, ";
        }
        LOG.debug(err);
      }

      if (FunctionRegistry.isOpNot(fd)) {
        return handleUdfNot(ctx, fd, nodeOutputs);
      } else if (FunctionRegistry.isOpAnd(fd)) {
        return handleUdfAnd(ctx, fd, nodeOutputs);
      } else if (FunctionRegistry.isOpOr(fd)) {
        return handleUdfOr(ctx, fd, nodeOutputs);
      } else if (FunctionRegistry.isIn(fd)) {
        List<ExprNodeDesc> children = fd.getChildren();
        // We should not remove the dynamic partition pruner generated synthetic predicates.
        for (int i = 1; i < children.size(); i++) {
          if (children.get(i) instanceof ExprNodeDynamicListDesc) {
            return new NodeInfoWrapper(WalkState.UNKNOWN, null, getOutExpr(fd, nodeOutputs));
          }
        }
        // Otherwise, handle like a normal generic UDF.
        return handleDeterministicUdf(ctx, fd, nodeOutputs);
      } else if (fd.getGenericUDF() instanceof GenericUDFStruct) {
        // Handle structs composed of partition columns,
        for (Object child : nodeOutputs) {
          NodeInfoWrapper wrapper = (NodeInfoWrapper) child;
          if (wrapper.state != WalkState.PART_COL) {
            return handleDeterministicUdf(ctx, fd, nodeOutputs); // Giving up.
          }
        }
        return new NodeInfoWrapper(WalkState.PART_COL_STRUCT, null, getOutExpr(fd, nodeOutputs));
      } else if (!FunctionRegistry.isConsistentWithinQuery(fd.getGenericUDF())) {
        // If it's a non-deterministic UDF, set unknown to true
        return new NodeInfoWrapper(WalkState.UNKNOWN, null, getOutExpr(fd, nodeOutputs));
      } else {
        return handleDeterministicUdf(ctx, fd, nodeOutputs);
      }
    }
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