presto-hive/src/main/java/io/prestosql/plugin/hive/IonSqlQueryBuilder.java/IonSqlQueryBuilder/toPredicate
class IonSqlQueryBuilder:    private String toPredicate(Domain domain, Type type, int position)
    {
        checkArgument(domain.getType().isOrderable(), "Domain type must be orderable");

        if (domain.getValues().isNone()) {
            if (domain.isNullAllowed()) {
                return format("s._%d", position + 1) + " = '' ";
            }
            return "FALSE";
        }

        if (domain.getValues().isAll()) {
            if (domain.isNullAllowed()) {
                return "TRUE";
            }
            return format("s._%d", position + 1) + " <> '' ";
        }

        List<String> disjuncts = new ArrayList<>();
        List<Object> singleValues = new ArrayList<>();
        for (Range range : domain.getValues().getRanges().getOrderedRanges()) {
            checkState(!range.isAll());
            if (range.isSingleValue()) {
                singleValues.add(range.getLow().getValue());
                continue;
            }
            List<String> rangeConjuncts = new ArrayList<>();
            if (!range.getLow().isLowerUnbounded()) {
                switch (range.getLow().getBound()) {
                    case ABOVE:
                        rangeConjuncts.add(toPredicate(">", range.getLow().getValue(), type, position));
                        break;
                    case EXACTLY:
                        rangeConjuncts.add(toPredicate(">=", range.getLow().getValue(), type, position));
                        break;
                    case BELOW:
                        throw new IllegalArgumentException("Low marker should never use BELOW bound");
                    default:
                        throw new AssertionError("Unhandled bound: " + range.getLow().getBound());
                }
            }
            if (!range.getHigh().isUpperUnbounded()) {
                switch (range.getHigh().getBound()) {
                    case ABOVE:
                        throw new IllegalArgumentException("High marker should never use ABOVE bound");
                    case EXACTLY:
                        rangeConjuncts.add(toPredicate("<=", range.getHigh().getValue(), type, position));
                        break;
                    case BELOW:
                        rangeConjuncts.add(toPredicate("<", range.getHigh().getValue(), type, position));
                        break;
                    default:
                        throw new AssertionError("Unhandled bound: " + range.getHigh().getBound());
                }
            }
            // If rangeConjuncts is null, then the range was ALL, which should already have been checked for
            checkState(!rangeConjuncts.isEmpty());
            disjuncts.add("(" + Joiner.on(" AND ").join(rangeConjuncts) + ")");
        }

        // Add back all of the possible single values either as an equality or an IN predicate
        if (singleValues.size() == 1) {
            disjuncts.add(toPredicate("=", getOnlyElement(singleValues), type, position));
        }
        else if (singleValues.size() > 1) {
            List<String> values = new ArrayList<>();
            for (Object value : singleValues) {
                checkType(type);
                values.add(valueToQuery(type, value));
            }
            disjuncts.add(createColumn(type, position) + " IN (" + Joiner.on(",").join(values) + ")");
        }

        // Add nullability disjuncts
        checkState(!disjuncts.isEmpty());
        if (domain.isNullAllowed()) {
            disjuncts.add(format("s._%d", position + 1) + " = '' ");
        }

        return "(" + Joiner.on(" OR ").join(disjuncts) + ")";
    }