public static DecomposedPredicate decomposePredicate(
      JobConf jobConf,
      HBaseSerDe hBaseSerDe,
      ExprNodeDesc predicate) {
    ColumnMapping keyMapping = hBaseSerDe.getHBaseSerdeParam().getKeyColumnMapping();
    ColumnMapping tsMapping = hBaseSerDe.getHBaseSerdeParam().getTimestampColumnMapping();

    // converts 'BETWEEN' predicate to '<= AND >=' predicate
    predicate = convertBetweenToLTOrEqualAndGTOrEqual(predicate);

    IndexPredicateAnalyzer analyzer = HiveHBaseTableInputFormat.newIndexPredicateAnalyzer(
        keyMapping.columnName, keyMapping.isComparable(),
        tsMapping == null ? null : tsMapping.columnName);
    List<IndexSearchCondition> conditions = new ArrayList<IndexSearchCondition>();
    ExprNodeGenericFuncDesc pushedPredicate = null;
    ExprNodeGenericFuncDesc residualPredicate =
        (ExprNodeGenericFuncDesc)analyzer.analyzePredicate(predicate, conditions);

    for (List<IndexSearchCondition> searchConditions:
        HiveHBaseInputFormatUtil.decompose(conditions).values()) {
      int scSize = searchConditions.size();
      if (scSize < 1 || 2 < scSize) {
        // Either there was nothing which could be pushed down (size = 0),
        // there were complex predicates which we don't support yet.
        // Currently supported are one of the form:
        // 1. key < 20                        (size = 1)
        // 2. key = 20                        (size = 1)
        // 3. key < 20 and key > 10           (size = 2)
        // Add to residual
        residualPredicate =
                extractResidualCondition(analyzer, searchConditions, residualPredicate);
        continue;
      }
      if (scSize == 2 &&
          (searchConditions.get(0).getComparisonOp().equals(GenericUDFOPEqual.class.getName()) ||
              searchConditions.get(1).getComparisonOp().equals(GenericUDFOPEqual.class.getName()))) {
        // If one of the predicates is =, then any other predicate with it is illegal.
        // Add to residual
        residualPredicate =
                extractResidualCondition(analyzer, searchConditions, residualPredicate);
        continue;
      }
      boolean sameType = sameTypeIndexSearchConditions(searchConditions);
      if (!sameType) {
        // If type for column and constant are different, we currently do not support pushing them
        residualPredicate =
                extractResidualCondition(analyzer, searchConditions, residualPredicate);
        continue;
      }
      TypeInfo typeInfo = searchConditions.get(0).getColumnDesc().getTypeInfo();
      if (typeInfo.getCategory() == Category.PRIMITIVE && PrimitiveObjectInspectorUtils.getPrimitiveGrouping(
              ((PrimitiveTypeInfo) typeInfo).getPrimitiveCategory()) == PrimitiveGrouping.NUMERIC_GROUP) {
        // If the predicate is on a numeric column, and it specifies an
        // open range e.g. key < 20 , we do not support conversion, as negative
        // values are lexicographically stored after positive values and thus they
        // would be returned.
        if (scSize == 2) {
          boolean lowerBound = false;
          boolean upperBound = false;
          if (searchConditions.get(0).getComparisonOp().equals(GenericUDFOPEqualOrLessThan.class.getName()) ||
                searchConditions.get(0).getComparisonOp().equals(GenericUDFOPLessThan.class.getName())) {
            lowerBound = true;
          } else {
            upperBound = true;
          }
          if (searchConditions.get(1).getComparisonOp().equals(GenericUDFOPEqualOrGreaterThan.class.getName()) ||
                searchConditions.get(1).getComparisonOp().equals(GenericUDFOPGreaterThan.class.getName())) {
            upperBound = true;
          } else {
            lowerBound = true;
          }
          if (!upperBound || !lowerBound) {
            // Not valid range, add to residual
            residualPredicate =
                    extractResidualCondition(analyzer, searchConditions, residualPredicate);
            continue;
          }
        } else {
          // scSize == 1
          if (!searchConditions.get(0).getComparisonOp().equals(GenericUDFOPEqual.class.getName())) {
            // Not valid range, add to residual
            residualPredicate =
                    extractResidualCondition(analyzer, searchConditions, residualPredicate);
            continue;
          }
        }

        // In HBase, Keys are sorted lexicographically so the byte representation of negative values comes after the positive values
        // So don't pushdown the predicate if any constant value is a negative number.
        // if first condition constant value is less than 0 then don't pushdown the predicate
        if (((Number) searchConditions.get(0).getConstantDesc().getValue()).longValue() < 0 && scSize == 2) {
          residualPredicate = extractResidualCondition(analyzer, searchConditions, residualPredicate);
          continue;
        }
        // if second condition constant value is less than 0 then don't pushdown the predicate
        if (scSize == 2 && ((Number) searchConditions.get(1).getConstantDesc().getValue()).longValue() < 0) {
          residualPredicate = extractResidualCondition(analyzer, searchConditions, residualPredicate);
          continue;
        }
      }

      // This one can be pushed
      pushedPredicate =
              extractStorageHandlerCondition(analyzer, searchConditions, pushedPredicate);
    }

    DecomposedPredicate decomposedPredicate = new DecomposedPredicate();
    decomposedPredicate.pushedPredicate = pushedPredicate;
    decomposedPredicate.residualPredicate = residualPredicate;
    return decomposedPredicate;
  }
Utility method to add hbase-default.xml and hbase-site.xml properties to a new map
if they are not already present in the jobConf.
@param jobConf Job configuration
@param newJobProperties  Map to which new properties should be added
hbase-handler/src/java/org/apache/hadoop/hive/hbase/HBaseStorageHandler.java