@Override
    public void visit(LeafNode node) throws MetaException {
      int partColCount = partitionKeys.size();
      int partColIndex = LeafNode.getPartColIndexForFilter(node.keyName, partitionKeys, filterBuffer);
      if (filterBuffer.hasError()) {
        return;
      }

      FieldSchema partCol = partitionKeys.get(partColIndex);
      String colTypeStr = ColumnType.getTypeName(partCol.getType());
      FilterType colType = FilterType.fromType(colTypeStr);
      if (colType == FilterType.Invalid) {
        filterBuffer.setError("Filter pushdown not supported for type " + colTypeStr);
        return;
      }
      FilterType valType = FilterType.fromClass(node.value);
      Object nodeValue = node.value;
      if (valType == FilterType.Invalid) {
        filterBuffer.setError("Filter pushdown not supported for value " + node.value.getClass());
        return;
      }

      String nodeValue0 = "?";
      // if Filter.g does date parsing for quoted strings, we'd need to verify there's no
      // type mismatch when string col is filtered by a string that looks like date.
      if (colType == FilterType.Date) {
        try {
          nodeValue = MetaStoreUtils.normalizeDate((String) nodeValue);
          valType = FilterType.Date;
          if (dbType.isPOSTGRES() || dbType.isORACLE()) {
            nodeValue0 = "date '" + nodeValue + "'";
            nodeValue = null;
          }
        } catch (Exception e) {  // do nothing, handled below - types will mismatch
        }
      } else if (colType == FilterType.Timestamp) {
        if (dbType.isDERBY() || dbType.isMYSQL()) {
          filterBuffer.setError("Filter pushdown on timestamp not supported for " + dbType.dbType);
          return;
        }
        try {
          MetaStoreUtils.convertStringToTimestamp((String) nodeValue);
          valType = FilterType.Timestamp;
          if (dbType.isPOSTGRES() || dbType.isORACLE()) {
            nodeValue0 = "timestamp '" + nodeValue + "'";
            nodeValue = null;
          }
        } catch (Exception e) { //nodeValue could be '__HIVE_DEFAULT_PARTITION__'
        }
      }

      boolean isDefaultPartition = (valType == FilterType.String) && defaultPartName.equals(nodeValue);
      if ((colType != valType) && (!isDefaultPartition)) {
        // It's not clear how filtering for e.g. "stringCol > 5" should work (which side is
        // to be coerced?). Let the expression evaluation sort this one out, not metastore.
        filterBuffer.setError("Cannot push down filter for "
            + colTypeStr + " column and value " + nodeValue.getClass());
        return;
      }

      if (joins.isEmpty()) {
        // There's a fixed number of partition cols that we might have filters on. To avoid
        // joining multiple times for one column (if there are several filters on it), we will
        // keep numCols elements in the list, one for each column; we will fill it with nulls,
        // put each join at a corresponding index when necessary, and remove nulls in the end.
        for (int i = 0; i < partColCount; ++i) {
          joins.add(null);
        }
      }
      if (joins.get(partColIndex) == null) {
        joins.set(partColIndex, "inner join " + PARTITION_KEY_VALS + " \"FILTER" + partColIndex
            + "\" on \"FILTER"  + partColIndex + "\".\"PART_ID\" = " + PARTITIONS + ".\"PART_ID\""
            + " and \"FILTER" + partColIndex + "\".\"INTEGER_IDX\" = " + partColIndex);
      }

      // Build the filter and add parameters linearly; we are traversing leaf nodes LTR.
      String tableValue = "\"FILTER" + partColIndex + "\".\"PART_KEY_VAL\"";

      if (node.isReverseOrder && nodeValue != null) {
        params.add(nodeValue);
      }
      String tableColumn = tableValue;
      if ((colType != FilterType.String) && (!isDefaultPartition)) {
        // The underlying database field is varchar, we need to compare numbers.
        if (colType == FilterType.Integral) {
          tableValue = "cast(" + tableValue + " as decimal(21,0))";
        } else if (colType == FilterType.Date) {
        	tableValue = dbType.toDate(tableValue);
        } else if (colType == FilterType.Timestamp) {
          tableValue = dbType.toTimestamp(tableValue);
        }

        // Workaround for HIVE_DEFAULT_PARTITION - ignore it like JDO does, for now.
        String tableValue0 = tableValue;
        tableValue = "(case when " + tableColumn + " <> ?";
        params.add(defaultPartName);

        if (dbHasJoinCastBug) {
          // This is a workaround for DERBY-6358 and Oracle bug; it is pretty horrible.
          tableValue += (" and " + TBLS + ".\"TBL_NAME\" = ? and " + DBS + ".\"NAME\" = ? and "
              + DBS + ".\"CTLG_NAME\" = ? and "
              + "\"FILTER" + partColIndex + "\".\"PART_ID\" = " + PARTITIONS + ".\"PART_ID\" and "
                + "\"FILTER" + partColIndex + "\".\"INTEGER_IDX\" = " + partColIndex);
          params.add(tableName.toLowerCase());
          params.add(dbName.toLowerCase());
          params.add(catName.toLowerCase());
        }
        tableValue += " then " + tableValue0 + " else null end)";
      }

      if (!node.isReverseOrder && nodeValue != null) {
        params.add(nodeValue);
      }

      // The following syntax is required for using LIKE clause wildcards '_' and '%' as literals.
      if (node.operator == Operator.LIKE) {
        nodeValue0 = nodeValue0 + " ESCAPE '\\' ";
      }
      String filter = node.isReverseOrder
              ? nodeValue0 + " " + node.operator.getSqlOp() + " " + tableValue
              : tableValue + " " + node.operator.getSqlOp() + " " + nodeValue0;
      // For equals and not-equals filter, we can add partition name filter to improve performance.
      boolean isOpEquals = Operator.isEqualOperator(node.operator);
      boolean isOpNotEqual = Operator.isNotEqualOperator(node.operator);
      String nodeValueStr = node.value.toString();
      if (StringUtils.isNotEmpty(nodeValueStr) && (isOpEquals || isOpNotEqual)) {
        Map<String, String> partKeyToVal = new HashMap<>();
        partKeyToVal.put(partCol.getName(), nodeValueStr);
        String escapedNameFragment = Warehouse.makePartName(partKeyToVal, false);
        if (colType == FilterType.Date) {
          // Some engines like Pig will record both date and time values, in which case we need
          // match PART_NAME by like clause.
          escapedNameFragment += "%";
        }
        if (colType != FilterType.Date && partColCount == 1) {
          // Case where partition column type is not date and there is no other partition columns
          params.add(escapedNameFragment);
          filter += " and " + PARTITIONS + ".\"PART_NAME\"" + (isOpEquals ? " =? " : " !=? ");
        } else {
          if (partColCount == 1) {
            // Case where partition column type is date and there is no other partition columns
            params.add(escapedNameFragment);
          } else if (partColIndex + 1 == partColCount) {
            // Case where the partition column is at the end of the name.
            params.add("%/" + escapedNameFragment);
          } else if (partColIndex == 0) {
            // Case where the partition column is at the beginning of the name.
            params.add(escapedNameFragment + "/%");
          } else {
            // Case where the partition column is in the middle of the name.
            params.add("%/" + escapedNameFragment + "/%");
          }
          filter += " and " + PARTITIONS + ".\"PART_NAME\"" + (isOpEquals ? " like ? " : " not like ? ");
        }
      }

      filterBuffer.append("(" + filter + ")");
    }
Generate the ANSI SQL92 filter for the given expression tree
@param catName catalog name
@param dbName db name
@param tableName table name
@param partitionKeys partition keys
@param params the ordered parameters for the resulting expression
@param joins the joins necessary for the resulting expression
@return the string representation of the expression tree
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java