private static ExprNodeDesc shortcutFunction()

in ql/src/java/org/apache/hadoop/hive/ql/optimizer/ConstantPropagateProcFactory.java [558:764]


  private static ExprNodeDesc shortcutFunction(GenericUDF udf, List<ExprNodeDesc> newExprs,
    Operator<? extends Serializable> op) throws UDFArgumentException {
    if (udf instanceof GenericUDFOPEqual) {
     assert newExprs.size() == 2;
     boolean foundUDFInFirst = false;
     ExprNodeGenericFuncDesc caseOrWhenexpr = null;
     if (newExprs.get(0) instanceof ExprNodeGenericFuncDesc) {
       caseOrWhenexpr = (ExprNodeGenericFuncDesc) newExprs.get(0);
       if (caseOrWhenexpr.getGenericUDF() instanceof GenericUDFWhen) {
         foundUDFInFirst = true;
       }
     }
     if (!foundUDFInFirst && newExprs.get(1) instanceof ExprNodeGenericFuncDesc) {
       caseOrWhenexpr = (ExprNodeGenericFuncDesc) newExprs.get(1);
       if (!(caseOrWhenexpr.getGenericUDF() instanceof GenericUDFWhen)) {
         return null;
       }
     }
     if (null == caseOrWhenexpr) {
       // we didn't find case or when udf
       return null;
     }
     GenericUDF childUDF = caseOrWhenexpr.getGenericUDF();
      List<ExprNodeDesc> children = new ArrayList(caseOrWhenexpr.getChildren());
     int i;
     if (childUDF instanceof GenericUDFWhen) {
       for (i = 1; i < children.size(); i+=2) {
        children.set(i, ExprNodeGenericFuncDesc.newInstance(new GenericUDFOPEqual(),
            Lists.newArrayList(children.get(i),newExprs.get(foundUDFInFirst ? 1 : 0))));
      }
       if(children.size() % 2 == 1) {
         i = children.size()-1;
         children.set(i, ExprNodeGenericFuncDesc.newInstance(new GenericUDFOPEqual(),
             Lists.newArrayList(children.get(i),newExprs.get(foundUDFInFirst ? 1 : 0))));
       }
       // after constant folding of child expression the return type of UDFWhen might have changed,
       // so recreate the expression
       ExprNodeGenericFuncDesc newCaseOrWhenExpr = ExprNodeGenericFuncDesc.newInstance(childUDF,
           caseOrWhenexpr.getFuncText(), children);
       return newCaseOrWhenExpr;
     } else {
       // cant happen
       return null;
     }
    }

    if (udf instanceof GenericUDFOPAnd) {
      final BitSet positionsToRemove = new BitSet();
      final List<ExprNodeDesc> notNullExprs = new ArrayList<ExprNodeDesc>();
      final List<Integer> notNullExprsPositions = new ArrayList<Integer>();
      final List<ExprNodeDesc> compareExprs = new ArrayList<ExprNodeDesc>();
      for (int i = 0; i < newExprs.size(); i++) {
        ExprNodeDesc childExpr = newExprs.get(i);
        if (childExpr instanceof ExprNodeConstantDesc) {
          ExprNodeConstantDesc c = (ExprNodeConstantDesc) childExpr;
          if (Boolean.TRUE.equals(c.getValue())) {
            // if true, prune it
            positionsToRemove.set(i);
          } else {
            if (Boolean.FALSE.equals(c.getValue())) {
              // if false, return false
              return childExpr;
            }
          }
        } else if (childExpr instanceof ExprNodeGenericFuncDesc &&
                ((ExprNodeGenericFuncDesc)childExpr).getGenericUDF() instanceof GenericUDFOPNotNull &&
                childExpr.getChildren().get(0) instanceof ExprNodeColumnDesc) {
          notNullExprs.add(childExpr.getChildren().get(0));
          notNullExprsPositions.add(i);
        } else if (childExpr instanceof ExprNodeGenericFuncDesc &&
              ((ExprNodeGenericFuncDesc)childExpr).getGenericUDF() instanceof GenericUDFBaseCompare &&
              !(((ExprNodeGenericFuncDesc)childExpr).getGenericUDF() instanceof GenericUDFOPNotEqual) &&
              childExpr.getChildren().size() == 2) {
          // Try to fold (key <op> 86) and (key is not null) to (key <op> 86)
          // where <op> can be "=", ">=", "<=", ">", "<".
          // Note: (key <> 86) and (key is not null) cannot be folded
          ExprNodeColumnDesc colDesc = ExprNodeDescUtils.getColumnExpr(childExpr.getChildren().get(0));
          if (null == colDesc) {
            colDesc = ExprNodeDescUtils.getColumnExpr(childExpr.getChildren().get(1));
          }
          if (colDesc != null) {
            compareExprs.add(colDesc);
          }
        }
      }
      // Try to fold (key = 86) and (key is not null) to (key = 86)
      for (int i = 0; i < notNullExprs.size(); i++) {
        for (ExprNodeDesc other : compareExprs) {
          if (notNullExprs.get(i).isSame(other)) {
            positionsToRemove.set(notNullExprsPositions.get(i));
            break;
          }
        }
      }
      // Remove unnecessary expressions
      int pos = 0;
      int removed = 0;
      while ((pos = positionsToRemove.nextSetBit(pos)) != -1) {
        newExprs.remove(pos - removed);
        pos++;
        removed++;
      }
      if (newExprs.size() == 0) {
        return new ExprNodeConstantDesc(TypeInfoFactory.booleanTypeInfo, Boolean.TRUE);
      }
      if (newExprs.size() == 1) {
        return newExprs.get(0);
      }
    }

    if (udf instanceof GenericUDFOPOr) {
      final BitSet positionsToRemove = new BitSet();
      for (int i = 0; i < newExprs.size(); i++) {
        ExprNodeDesc childExpr = newExprs.get(i);
        if (childExpr instanceof ExprNodeConstantDesc) {
          ExprNodeConstantDesc c = (ExprNodeConstantDesc) childExpr;
          if (Boolean.FALSE.equals(c.getValue())) {
            // if false, prune it
            positionsToRemove.set(i);
          } else
          if (Boolean.TRUE.equals(c.getValue())) {
            // if true return true
            return childExpr;
          }
        }
      }
      int pos = 0;
      int removed = 0;
      while ((pos = positionsToRemove.nextSetBit(pos)) != -1) {
        newExprs.remove(pos - removed);
        pos++;
        removed++;
      }
      if (newExprs.size() == 0) {
        return new ExprNodeConstantDesc(TypeInfoFactory.booleanTypeInfo, Boolean.FALSE);
      }
      if (newExprs.size() == 1) {
        return newExprs.get(0);
      }
    }

    if (udf instanceof GenericUDFWhen) {
      if (!(newExprs.size() == 2 || newExprs.size() == 3)) {
        // In general, when can have unlimited # of branches,
        // we currently only handle either 1 or 2 branch.
        return null;
      }
      ExprNodeDesc thenExpr = newExprs.get(1);
      ExprNodeDesc elseExpr = newExprs.size() == 3 ? newExprs.get(2) :
        new ExprNodeConstantDesc(newExprs.get(1).getTypeInfo(),null);

      ExprNodeDesc whenExpr = newExprs.get(0);
      if (whenExpr instanceof ExprNodeConstantDesc) {
        Boolean whenVal = (Boolean)((ExprNodeConstantDesc) whenExpr).getValue();
        return (whenVal == null || Boolean.FALSE.equals(whenVal)) ? elseExpr : thenExpr;
      }

      if (thenExpr instanceof ExprNodeConstantDesc && elseExpr instanceof ExprNodeConstantDesc) {
        ExprNodeConstantDesc constThen = (ExprNodeConstantDesc) thenExpr;
        ExprNodeConstantDesc constElse = (ExprNodeConstantDesc) elseExpr;
        Object thenVal = constThen.getValue();
        Object elseVal = constElse.getValue();
        if (thenVal == null) {
          if (elseVal == null) {
            // both branches are null.
            return thenExpr;
          } else if (op instanceof FilterOperator) {
            // we can still fold, since here null is equivalent to false.
            return Boolean.TRUE.equals(elseVal) ?
              ExprNodeGenericFuncDesc.newInstance(new GenericUDFOPNot(), newExprs.subList(0, 1)) : Boolean.FALSE.equals(elseVal) ?
              elseExpr : null;
          } else {
            // can't do much, expression is not in context of filter, so we can't treat null as equivalent to false here.
            return null;
          }
        } else if (elseVal == null && op instanceof FilterOperator) {
          return Boolean.TRUE.equals(thenVal) ? whenExpr : Boolean.FALSE.equals(thenVal) ? thenExpr : null;
        } else if(thenVal.equals(elseVal)){
          return thenExpr;
        } else if (thenVal instanceof Boolean && elseVal instanceof Boolean) {
          List<ExprNodeDesc> children = new ArrayList<>();
          children.add(whenExpr);
          children.add(new ExprNodeConstantDesc(false));
          ExprNodeGenericFuncDesc func = ExprNodeGenericFuncDesc.newInstance(new GenericUDFCoalesce(),
              children);
          if (Boolean.TRUE.equals(thenVal)) {
            return func;
          } else {
            List<ExprNodeDesc> exprs = new ArrayList<>();
            exprs.add(func);
            return ExprNodeGenericFuncDesc.newInstance(new GenericUDFOPNot(), exprs);
          }
        } else {
          return null;
        }
      }
    }

    if (udf instanceof GenericUDFUnixTimeStamp) {
      if (newExprs.size() >= 1) {
        // unix_timestamp(args) -> to_unix_timestamp(args)
        return ExprNodeGenericFuncDesc.newInstance(new GenericUDFToUnixTimeStamp(), newExprs);
      }
    }

    return null;
  }