phoenix5-hive/src/main/java/org/apache/phoenix/hive/ql/pushdown/PhoenixPredicateAnalyzer.java [200:532]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        || udf instanceof GenericUDFToChar || udf instanceof GenericUDFToVarchar
        || udf instanceof GenericUDFToDecimal || udf instanceof GenericUDFToDate
        || udf instanceof GenericUDFToUnixTimeStamp || udf instanceof GenericUDFToUtcTimestamp)
        && funcDesc.getChildren().size() == 1
                && funcDesc.getChildren().get(0) instanceof ExprNodeColumnDesc) {
            return expr.getChildren().get(0);
        }
        return expr;
    }

    private void processingBetweenOperator(ExprNodeGenericFuncDesc expr,
                                           List<PhoenixSearchCondition> searchConditions, Object...
                                                   nodeOutputs) {
        String[] fields = null;

        final boolean isNot = (Boolean) ((ExprNodeConstantDesc) nodeOutputs[0]).getValue();
        ExprNodeDesc columnNodeDesc = (ExprNodeDesc) nodeOutputs[1];

        if (columnNodeDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnNodeDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair((ExprNodeDesc)
                    nodeOutputs[1], (ExprNodeDesc) nodeOutputs[2]);
            columnNodeDesc = extracted[0];
        }
        addSearchConditionIfPossible(expr, searchConditions, fields, isNot, columnNodeDesc,
                Arrays.copyOfRange(nodeOutputs, 2, nodeOutputs.length));
    }

    private void addSearchConditionIfPossible(ExprNodeGenericFuncDesc expr,
                                              List<PhoenixSearchCondition> searchConditions,
                                              String[] fields,
                                              boolean isNot,
                                              ExprNodeDesc columnNodeDesc,
                                              Object[] nodeOutputs) {
        ExprNodeColumnDesc columnDesc;
        columnNodeDesc = getColumnExpr(columnNodeDesc);
        if (!(columnNodeDesc instanceof ExprNodeColumnDesc)) {
            return;
        }
        columnDesc = (ExprNodeColumnDesc) columnNodeDesc;

        String udfName = expr.getGenericUDF().getUdfName();
        ExprNodeConstantDesc[] constantDescs = null;
        if (nodeOutputs != null) {
            constantDescs = extractConstants(columnDesc, nodeOutputs);
            if (constantDescs == null) {
                return;
            }
        }

        searchConditions.add(new PhoenixSearchCondition(columnDesc, udfName, constantDescs,
                expr, fields, isNot));
    }

    private boolean isAcceptableConstants(ExprNodeDesc columnDesc, ExprNodeDesc constant) {
        // from(constant) -> to(columnDesc)
        return TypeInfoUtils.implicitConvertible(constant.getTypeInfo(), columnDesc.getTypeInfo());
    }

    private ExprNodeConstantDesc[] extractConstants(ExprNodeColumnDesc columnDesc, Object... nodeOutputs) {
        ExprNodeConstantDesc[] constantDescs = new ExprNodeConstantDesc[nodeOutputs.length];
        for (int i = 0; i < nodeOutputs.length; i++) {
            ExprNodeDesc[] extracted =
                    ExprNodeDescUtils.extractComparePair(columnDesc, (ExprNodeDesc) nodeOutputs[i]);
            if (extracted == null || !isAcceptableConstants(columnDesc, extracted[1])) {
                return null;
            }
            constantDescs[i] = (ExprNodeConstantDesc) extracted[1];
        }

        return constantDescs;
    }

    private void processingInOperator(ExprNodeGenericFuncDesc expr, List<PhoenixSearchCondition>
            searchConditions, boolean isNot, Object... nodeOutputs) {
        ExprNodeDesc columnDesc;
        String[] fields = null;

        if (LOG.isTraceEnabled()) {
            LOG.trace("Processing In Operator. nodeOutputs : " + new ArrayList<>(Arrays.asList(nodeOutputs)));
        }

        columnDesc = (ExprNodeDesc) nodeOutputs[0];
        if (columnDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair((ExprNodeDesc)
                    nodeOutputs[0], (ExprNodeDesc) nodeOutputs[1]);

            if (extracted == null) {    // adding for tez
                return;
            }

            if (LOG.isTraceEnabled()) {
                LOG.trace("nodeOutputs[0] : " + nodeOutputs[0] + ", nodeOutputs[1] : " +
                        nodeOutputs[1] + " => " + new ArrayList<>(Arrays.asList(extracted)));
            }

            columnDesc = extracted[0];
        }

        addSearchConditionIfPossible(expr, searchConditions, fields, isNot, columnDesc,
                Arrays.copyOfRange(nodeOutputs, 1, nodeOutputs.length));
    }

    private void processingNullOperator(ExprNodeGenericFuncDesc expr, List<PhoenixSearchCondition>
            searchConditions, Object... nodeOutputs) {
        ExprNodeDesc columnDesc = null;
        String[] fields = null;

        columnDesc = (ExprNodeDesc) nodeOutputs[0];
        if (columnDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair(columnDesc,
                    new ExprNodeConstantDesc());
            columnDesc = extracted[0];
        }

        addSearchConditionIfPossible(expr, searchConditions, fields, false, columnDesc, null);
    }

    private void processingNotNullOperator(ExprNodeGenericFuncDesc expr,
                                           List<PhoenixSearchCondition> searchConditions, Object...
                                                   nodeOutputs) {
        ExprNodeDesc columnDesc;
        String[] fields = null;

        columnDesc = (ExprNodeDesc) nodeOutputs[0];
        if (columnDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair(columnDesc,
                    new ExprNodeConstantDesc());
            columnDesc = extracted[0];
        }

        addSearchConditionIfPossible(expr, searchConditions, fields, true, columnDesc, null);
    }

    private ExprNodeDesc analyzeExpr(ExprNodeGenericFuncDesc expr, List<PhoenixSearchCondition>
            searchConditions, Object... nodeOutputs) throws SemanticException {

        if (FunctionRegistry.isOpAnd(expr)) {
            List<ExprNodeDesc> residuals = new ArrayList<>();
            // GenericUDFOPAnd can expect more than 2 arguments after HIVE-11398
            for (Object residual : nodeOutputs) {
                // The null value of nodeOutput means the predicate is pushed down to Phoenix. So
                // we don't need to add it to the residual predicate list
                if (null != residual) {
                    residuals.add((ExprNodeDesc) residual);
                }
            }
            if (residuals.size() == 0) {
                return null;
            } else  if (residuals.size() == 1) {
                return residuals.get(0);
            } else {
                return new ExprNodeGenericFuncDesc(
                    TypeInfoFactory.booleanTypeInfo,
                    FunctionRegistry.getGenericUDFForAnd(),
                    residuals);
            }
        }

        GenericUDF genericUDF = expr.getGenericUDF();
        if (!(genericUDF instanceof GenericUDFBaseCompare)) {
            // 2015-10-22 Added by JeongMin Ju : Processing Between/In Operator
            if (genericUDF instanceof GenericUDFBetween) {
                // In case of not between, The value of first element of nodeOutputs is true.
                // otherwise false.
                processingBetweenOperator(expr, searchConditions, nodeOutputs);
                return expr;
            } else if (genericUDF instanceof GenericUDFIn) {
                // In case of not in operator, in operator exist as child of not operator.
                processingInOperator(expr, searchConditions, false, nodeOutputs);
                return expr;
            } else if (genericUDF instanceof GenericUDFOPNot &&
                    ((ExprNodeGenericFuncDesc) expr.getChildren().get(0)).getGenericUDF()
                            instanceof GenericUDFIn) {
                // In case of not in operator, in operator exist as child of not operator.
                processingInOperator((ExprNodeGenericFuncDesc) expr.getChildren().get(0),
                        searchConditions, true, ((ExprNodeGenericFuncDesc) nodeOutputs[0])
                                .getChildren().toArray());
                return expr;
            } else if (genericUDF instanceof GenericUDFOPNull) {
                processingNullOperator(expr, searchConditions, nodeOutputs);
                return expr;
            } else if (genericUDF instanceof GenericUDFOPNotNull) {
                processingNotNullOperator(expr, searchConditions, nodeOutputs);
                return expr;
            } else {
                return expr;
            }
        }
        ExprNodeDesc expr1 = (ExprNodeDesc) nodeOutputs[0];
        ExprNodeDesc expr2 = (ExprNodeDesc) nodeOutputs[1];
        // We may need to peel off the GenericUDFBridge that is added by CBO or
        // user
        if (expr1.getTypeInfo().equals(expr2.getTypeInfo())) {
            expr1 = getColumnExpr(expr1);
            expr2 = getColumnExpr(expr2);
        }

        ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair(expr1, expr2);
        if (extracted == null || (extracted.length > 2 && !acceptsFields)) {
            return expr;
        }

        ExprNodeColumnDesc columnDesc;
        ExprNodeConstantDesc constantDesc;
        if (extracted[0] instanceof ExprNodeConstantDesc) {
            genericUDF = genericUDF.flip();
            columnDesc = (ExprNodeColumnDesc) extracted[1];
            constantDesc = (ExprNodeConstantDesc) extracted[0];
        } else {
            columnDesc = (ExprNodeColumnDesc) extracted[0];
            constantDesc = (ExprNodeConstantDesc) extracted[1];
        }

        Set<String> allowed = columnToUDFs.get(columnDesc.getColumn());
        if (allowed == null) {
            return expr;
        }

        String udfName = genericUDF.getUdfName();
        if (!allowed.contains(genericUDF.getUdfName())) {
            return expr;
        }

        String[] fields = null;
        if (extracted.length > 2) {
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) extracted[2];
            if (!isValidField(fieldDesc)) {
                return expr;
            }
            fields = ExprNodeDescUtils.extractFields(fieldDesc);
        }

        // We also need to update the expr so that the index query can be
        // generated.
        // Note that, hive does not support UDFToDouble etc in the query text.
        List<ExprNodeDesc> list = new ArrayList<ExprNodeDesc>();
        list.add(expr1);
        list.add(expr2);
        expr = new ExprNodeGenericFuncDesc(expr.getTypeInfo(), expr.getGenericUDF(), list);

        searchConditions.add(new PhoenixSearchCondition(columnDesc, udfName, constantDesc, expr,
                fields));

        // we converted the expression to a search condition, so
        // remove it from the residual predicate
        return fields == null ? null : expr;
    }

    private boolean isValidField(ExprNodeFieldDesc field) {
        return fieldValidator == null || fieldValidator.validate(field);
    }

    /**
     * Translates search conditions back to ExprNodeDesc form (as a left-deep
     * conjunction).
     *
     * @param searchConditions (typically produced by analyzePredicate)
     * @return ExprNodeGenericFuncDesc form of search conditions
     */
    public ExprNodeGenericFuncDesc translateSearchConditions(List<PhoenixSearchCondition>
                                                                     searchConditions) {

        ExprNodeGenericFuncDesc expr = null;

        for (PhoenixSearchCondition searchCondition : searchConditions) {
            if (expr == null) {
                expr = searchCondition.getComparisonExpr();
                continue;
            }

            List<ExprNodeDesc> children = new ArrayList<ExprNodeDesc>();
            children.add(expr);
            children.add(searchCondition.getComparisonExpr());
            expr = new ExprNodeGenericFuncDesc(TypeInfoFactory.booleanTypeInfo,
                FunctionRegistry.getGenericUDFForAnd(),
                children);
        }
        return expr;
    }

    public void setAcceptsFields(boolean acceptsFields) {
        this.acceptsFields = acceptsFields;
    }

    public static interface FieldValidator {
        boolean validate(ExprNodeFieldDesc exprNodeDesc);
    }

    public static PhoenixPredicateAnalyzer createAnalyzer(boolean equalOnly) {
        PhoenixPredicateAnalyzer analyzer = new PhoenixPredicateAnalyzer();
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqual");

        if (equalOnly) {
            return analyzer;
        }

        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic" +
                ".GenericUDFOPEqualOrGreaterThan");
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic" +
                ".GenericUDFOPEqualOrLessThan");
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPLessThan");
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPGreaterThan");

        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNotEqual");
        // apply !=
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFBetween");
        // apply (Not) Between
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFIn");        //
        // apply (Not) In
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFIn");        //
        // apply In
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNull");
        // apply Null
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNotNull");
        // apply Not Null

        return analyzer;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



phoenix5-hive4/src/main/java/org/apache/phoenix/hive/ql/pushdown/PhoenixPredicateAnalyzer.java [202:534]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        || udf instanceof GenericUDFToChar || udf instanceof GenericUDFToVarchar
        || udf instanceof GenericUDFToDecimal || udf instanceof GenericUDFToDate
        || udf instanceof GenericUDFToUnixTimeStamp || udf instanceof GenericUDFToUtcTimestamp)
        && funcDesc.getChildren().size() == 1
                && funcDesc.getChildren().get(0) instanceof ExprNodeColumnDesc) {
            return expr.getChildren().get(0);
        }
        return expr;
    }

    private void processingBetweenOperator(ExprNodeGenericFuncDesc expr,
                                           List<PhoenixSearchCondition> searchConditions, Object...
                                                   nodeOutputs) {
        String[] fields = null;

        final boolean isNot = (Boolean) ((ExprNodeConstantDesc) nodeOutputs[0]).getValue();
        ExprNodeDesc columnNodeDesc = (ExprNodeDesc) nodeOutputs[1];

        if (columnNodeDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnNodeDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair((ExprNodeDesc)
                    nodeOutputs[1], (ExprNodeDesc) nodeOutputs[2]);
            columnNodeDesc = extracted[0];
        }
        addSearchConditionIfPossible(expr, searchConditions, fields, isNot, columnNodeDesc,
                Arrays.copyOfRange(nodeOutputs, 2, nodeOutputs.length));
    }

    private void addSearchConditionIfPossible(ExprNodeGenericFuncDesc expr,
                                              List<PhoenixSearchCondition> searchConditions,
                                              String[] fields,
                                              boolean isNot,
                                              ExprNodeDesc columnNodeDesc,
                                              Object[] nodeOutputs) {
        ExprNodeColumnDesc columnDesc;
        columnNodeDesc = getColumnExpr(columnNodeDesc);
        if (!(columnNodeDesc instanceof ExprNodeColumnDesc)) {
            return;
        }
        columnDesc = (ExprNodeColumnDesc) columnNodeDesc;

        String udfName = expr.getGenericUDF().getUdfName();
        ExprNodeConstantDesc[] constantDescs = null;
        if (nodeOutputs != null) {
            constantDescs = extractConstants(columnDesc, nodeOutputs);
            if (constantDescs == null) {
                return;
            }
        }

        searchConditions.add(new PhoenixSearchCondition(columnDesc, udfName, constantDescs,
                expr, fields, isNot));
    }

    private boolean isAcceptableConstants(ExprNodeDesc columnDesc, ExprNodeDesc constant) {
        // from(constant) -> to(columnDesc)
        return TypeInfoUtils.implicitConvertible(constant.getTypeInfo(), columnDesc.getTypeInfo());
    }

    private ExprNodeConstantDesc[] extractConstants(ExprNodeColumnDesc columnDesc, Object... nodeOutputs) {
        ExprNodeConstantDesc[] constantDescs = new ExprNodeConstantDesc[nodeOutputs.length];
        for (int i = 0; i < nodeOutputs.length; i++) {
            ExprNodeDesc[] extracted =
                    ExprNodeDescUtils.extractComparePair(columnDesc, (ExprNodeDesc) nodeOutputs[i]);
            if (extracted == null || !isAcceptableConstants(columnDesc, extracted[1])) {
                return null;
            }
            constantDescs[i] = (ExprNodeConstantDesc) extracted[1];
        }

        return constantDescs;
    }

    private void processingInOperator(ExprNodeGenericFuncDesc expr, List<PhoenixSearchCondition>
            searchConditions, boolean isNot, Object... nodeOutputs) {
        ExprNodeDesc columnDesc;
        String[] fields = null;

        if (LOG.isTraceEnabled()) {
            LOG.trace("Processing In Operator. nodeOutputs : " + new ArrayList<>(Arrays.asList(nodeOutputs)));
        }

        columnDesc = (ExprNodeDesc) nodeOutputs[0];
        if (columnDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair((ExprNodeDesc)
                    nodeOutputs[0], (ExprNodeDesc) nodeOutputs[1]);

            if (extracted == null) {    // adding for tez
                return;
            }

            if (LOG.isTraceEnabled()) {
                LOG.trace("nodeOutputs[0] : " + nodeOutputs[0] + ", nodeOutputs[1] : " +
                        nodeOutputs[1] + " => " + new ArrayList<>(Arrays.asList(extracted)));
            }

            columnDesc = extracted[0];
        }

        addSearchConditionIfPossible(expr, searchConditions, fields, isNot, columnDesc,
                Arrays.copyOfRange(nodeOutputs, 1, nodeOutputs.length));
    }

    private void processingNullOperator(ExprNodeGenericFuncDesc expr, List<PhoenixSearchCondition>
            searchConditions, Object... nodeOutputs) {
        ExprNodeDesc columnDesc = null;
        String[] fields = null;

        columnDesc = (ExprNodeDesc) nodeOutputs[0];
        if (columnDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair(columnDesc,
                    new ExprNodeConstantDesc());
            columnDesc = extracted[0];
        }

        addSearchConditionIfPossible(expr, searchConditions, fields, false, columnDesc, null);
    }

    private void processingNotNullOperator(ExprNodeGenericFuncDesc expr,
                                           List<PhoenixSearchCondition> searchConditions, Object...
                                                   nodeOutputs) {
        ExprNodeDesc columnDesc;
        String[] fields = null;

        columnDesc = (ExprNodeDesc) nodeOutputs[0];
        if (columnDesc instanceof ExprNodeFieldDesc) {
            // rowKey field
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) columnDesc;
            fields = ExprNodeDescUtils.extractFields(fieldDesc);

            ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair(columnDesc,
                    new ExprNodeConstantDesc());
            columnDesc = extracted[0];
        }

        addSearchConditionIfPossible(expr, searchConditions, fields, true, columnDesc, null);
    }

    private ExprNodeDesc analyzeExpr(ExprNodeGenericFuncDesc expr, List<PhoenixSearchCondition>
            searchConditions, Object... nodeOutputs) throws SemanticException {

        if (FunctionRegistry.isOpAnd(expr)) {
            List<ExprNodeDesc> residuals = new ArrayList<>();
            // GenericUDFOPAnd can expect more than 2 arguments after HIVE-11398
            for (Object residual : nodeOutputs) {
                // The null value of nodeOutput means the predicate is pushed down to Phoenix. So
                // we don't need to add it to the residual predicate list
                if (null != residual) {
                    residuals.add((ExprNodeDesc) residual);
                }
            }
            if (residuals.size() == 0) {
                return null;
            } else  if (residuals.size() == 1) {
                return residuals.get(0);
            } else {
                return new ExprNodeGenericFuncDesc(
                    TypeInfoFactory.booleanTypeInfo,
                    FunctionRegistry.getGenericUDFForAnd(),
                    residuals);
            }
        }

        GenericUDF genericUDF = expr.getGenericUDF();
        if (!(genericUDF instanceof GenericUDFBaseCompare)) {
            // 2015-10-22 Added by JeongMin Ju : Processing Between/In Operator
            if (genericUDF instanceof GenericUDFBetween) {
                // In case of not between, The value of first element of nodeOutputs is true.
                // otherwise false.
                processingBetweenOperator(expr, searchConditions, nodeOutputs);
                return expr;
            } else if (genericUDF instanceof GenericUDFIn) {
                // In case of not in operator, in operator exist as child of not operator.
                processingInOperator(expr, searchConditions, false, nodeOutputs);
                return expr;
            } else if (genericUDF instanceof GenericUDFOPNot &&
                    ((ExprNodeGenericFuncDesc) expr.getChildren().get(0)).getGenericUDF()
                            instanceof GenericUDFIn) {
                // In case of not in operator, in operator exist as child of not operator.
                processingInOperator((ExprNodeGenericFuncDesc) expr.getChildren().get(0),
                        searchConditions, true, ((ExprNodeGenericFuncDesc) nodeOutputs[0])
                                .getChildren().toArray());
                return expr;
            } else if (genericUDF instanceof GenericUDFOPNull) {
                processingNullOperator(expr, searchConditions, nodeOutputs);
                return expr;
            } else if (genericUDF instanceof GenericUDFOPNotNull) {
                processingNotNullOperator(expr, searchConditions, nodeOutputs);
                return expr;
            } else {
                return expr;
            }
        }
        ExprNodeDesc expr1 = (ExprNodeDesc) nodeOutputs[0];
        ExprNodeDesc expr2 = (ExprNodeDesc) nodeOutputs[1];
        // We may need to peel off the GenericUDFBridge that is added by CBO or
        // user
        if (expr1.getTypeInfo().equals(expr2.getTypeInfo())) {
            expr1 = getColumnExpr(expr1);
            expr2 = getColumnExpr(expr2);
        }

        ExprNodeDesc[] extracted = ExprNodeDescUtils.extractComparePair(expr1, expr2);
        if (extracted == null || (extracted.length > 2 && !acceptsFields)) {
            return expr;
        }

        ExprNodeColumnDesc columnDesc;
        ExprNodeConstantDesc constantDesc;
        if (extracted[0] instanceof ExprNodeConstantDesc) {
            genericUDF = genericUDF.flip();
            columnDesc = (ExprNodeColumnDesc) extracted[1];
            constantDesc = (ExprNodeConstantDesc) extracted[0];
        } else {
            columnDesc = (ExprNodeColumnDesc) extracted[0];
            constantDesc = (ExprNodeConstantDesc) extracted[1];
        }

        Set<String> allowed = columnToUDFs.get(columnDesc.getColumn());
        if (allowed == null) {
            return expr;
        }

        String udfName = genericUDF.getUdfName();
        if (!allowed.contains(genericUDF.getUdfName())) {
            return expr;
        }

        String[] fields = null;
        if (extracted.length > 2) {
            ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) extracted[2];
            if (!isValidField(fieldDesc)) {
                return expr;
            }
            fields = ExprNodeDescUtils.extractFields(fieldDesc);
        }

        // We also need to update the expr so that the index query can be
        // generated.
        // Note that, hive does not support UDFToDouble etc in the query text.
        List<ExprNodeDesc> list = new ArrayList<ExprNodeDesc>();
        list.add(expr1);
        list.add(expr2);
        expr = new ExprNodeGenericFuncDesc(expr.getTypeInfo(), expr.getGenericUDF(), list);

        searchConditions.add(new PhoenixSearchCondition(columnDesc, udfName, constantDesc, expr,
                fields));

        // we converted the expression to a search condition, so
        // remove it from the residual predicate
        return fields == null ? null : expr;
    }

    private boolean isValidField(ExprNodeFieldDesc field) {
        return fieldValidator == null || fieldValidator.validate(field);
    }

    /**
     * Translates search conditions back to ExprNodeDesc form (as a left-deep
     * conjunction).
     *
     * @param searchConditions (typically produced by analyzePredicate)
     * @return ExprNodeGenericFuncDesc form of search conditions
     */
    public ExprNodeGenericFuncDesc translateSearchConditions(List<PhoenixSearchCondition>
                                                                     searchConditions) {

        ExprNodeGenericFuncDesc expr = null;

        for (PhoenixSearchCondition searchCondition : searchConditions) {
            if (expr == null) {
                expr = searchCondition.getComparisonExpr();
                continue;
            }

            List<ExprNodeDesc> children = new ArrayList<ExprNodeDesc>();
            children.add(expr);
            children.add(searchCondition.getComparisonExpr());
            expr = new ExprNodeGenericFuncDesc(TypeInfoFactory.booleanTypeInfo,
                FunctionRegistry.getGenericUDFForAnd(),
                children);
        }
        return expr;
    }

    public void setAcceptsFields(boolean acceptsFields) {
        this.acceptsFields = acceptsFields;
    }

    public static interface FieldValidator {
        boolean validate(ExprNodeFieldDesc exprNodeDesc);
    }

    public static PhoenixPredicateAnalyzer createAnalyzer(boolean equalOnly) {
        PhoenixPredicateAnalyzer analyzer = new PhoenixPredicateAnalyzer();
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqual");

        if (equalOnly) {
            return analyzer;
        }

        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic" +
                ".GenericUDFOPEqualOrGreaterThan");
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic" +
                ".GenericUDFOPEqualOrLessThan");
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPLessThan");
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPGreaterThan");

        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNotEqual");
        // apply !=
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFBetween");
        // apply (Not) Between
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFIn");        //
        // apply (Not) In
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFIn");        //
        // apply In
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNull");
        // apply Null
        analyzer.addComparisonOp("org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNotNull");
        // apply Not Null

        return analyzer;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



