docs: @Nullable
    private static DimFilter toSimpleLeafFilter(
        final PlannerContext plannerContext,
        final DruidQuerySignature querySignature,
        final RexNode rexNode
    )
    {
      final SqlKind kind = rexNode.getKind();
  
      if (kind == SqlKind.IS_TRUE || kind == SqlKind.IS_NOT_FALSE) {
        return toSimpleLeafFilter(
            plannerContext,
            querySignature,
            Iterables.getOnlyElement(((RexCall) rexNode).getOperands())
        );
      } else if (kind == SqlKind.IS_FALSE || kind == SqlKind.IS_NOT_TRUE) {
        return new NotDimFilter(
            toSimpleLeafFilter(
                plannerContext,
                querySignature,
                Iterables.getOnlyElement(((RexCall) rexNode).getOperands())
            )
        );
      } else if (kind == SqlKind.IS_NULL || kind == SqlKind.IS_NOT_NULL) {
        final RexNode operand = Iterables.getOnlyElement(((RexCall) rexNode).getOperands());
  
        // operand must be translatable to a SimpleExtraction to be simple-filterable
        final DruidExpression druidExpression =
            toDruidExpression(plannerContext, querySignature.getRowSignature(), operand);
  
        if (druidExpression == null) {
          return null;
        }
  
        final DimFilter equalFilter;
        if (druidExpression.isSimpleExtraction()) {
          equalFilter = new SelectorDimFilter(
              druidExpression.getSimpleExtraction().getColumn(),
              NullHandling.defaultStringValue(),
              druidExpression.getSimpleExtraction().getExtractionFn()
          );
        } else {
          final VirtualColumn virtualColumn = querySignature.getOrCreateVirtualColumnForExpression(
              plannerContext,
              druidExpression,
              operand.getType().getSqlTypeName()
          );
          if (virtualColumn == null) {
            return null;
          }
          equalFilter = new SelectorDimFilter(
              virtualColumn.getOutputName(),
              NullHandling.defaultStringValue(),
              null
          );
        }
  
        return kind == SqlKind.IS_NOT_NULL ? new NotDimFilter(equalFilter) : equalFilter;
      } else if (kind == SqlKind.EQUALS
                 || kind == SqlKind.NOT_EQUALS
                 || kind == SqlKind.GREATER_THAN
                 || kind == SqlKind.GREATER_THAN_OR_EQUAL
                 || kind == SqlKind.LESS_THAN
                 || kind == SqlKind.LESS_THAN_OR_EQUAL) {
        final List<RexNode> operands = ((RexCall) rexNode).getOperands();
        Preconditions.checkState(operands.size() == 2, "WTF?! Expected 2 operands, got[%,d]", operands.size());
        boolean flip = false;
        RexNode lhs = operands.get(0);
        RexNode rhs = operands.get(1);
  
        if (lhs.getKind() == SqlKind.LITERAL && rhs.getKind() != SqlKind.LITERAL) {
          // swap lhs, rhs
          RexNode x = lhs;
          lhs = rhs;
          rhs = x;
          flip = true;
        }
  
        // Flip operator, maybe.
        final SqlKind flippedKind;
  
        if (flip) {
          switch (kind) {
            case EQUALS:
            case NOT_EQUALS:
              flippedKind = kind;
              break;
            case GREATER_THAN:
              flippedKind = SqlKind.LESS_THAN;
              break;
            case GREATER_THAN_OR_EQUAL:
              flippedKind = SqlKind.LESS_THAN_OR_EQUAL;
              break;
            case LESS_THAN:
              flippedKind = SqlKind.GREATER_THAN;
              break;
            case LESS_THAN_OR_EQUAL:
              flippedKind = SqlKind.GREATER_THAN_OR_EQUAL;
              break;
            default:
              throw new ISE("WTF?! Kind[%s] not expected here", kind);
          }
        } else {
          flippedKind = kind;
        }
  
        // rhs must be a literal
        if (rhs.getKind() != SqlKind.LITERAL) {
          return null;
        }
  
        // Translate lhs to a DruidExpression.
        final DruidExpression lhsExpression = toDruidExpression(plannerContext, querySignature.getRowSignature(), lhs);
        if (lhsExpression == null) {
          return null;
        }
  
        // Special handling for filters on FLOOR(__time TO granularity).
        final Granularity queryGranularity = toQueryGranularity(lhsExpression, plannerContext.getExprMacroTable());
        if (queryGranularity != null) {
          // lhs is FLOOR(__time TO granularity); rhs must be a timestamp
          final long rhsMillis = Calcites.calciteDateTimeLiteralToJoda(rhs, plannerContext.getTimeZone()).getMillis();
          return buildTimeFloorFilter(ColumnHolder.TIME_COLUMN_NAME, queryGranularity, flippedKind, rhsMillis);
        }
  
        final String column;
        final ExtractionFn extractionFn;
        if (lhsExpression.isSimpleExtraction()) {
          column = lhsExpression.getSimpleExtraction().getColumn();
          extractionFn = lhsExpression.getSimpleExtraction().getExtractionFn();
        } else {
          VirtualColumn virtualLhs = querySignature.getOrCreateVirtualColumnForExpression(
              plannerContext,
              lhsExpression,
              lhs.getType().getSqlTypeName()
          );
          if (virtualLhs == null) {
            return null;
          }
          column = virtualLhs.getOutputName();
          extractionFn = null;
        }
  
        if (column.equals(ColumnHolder.TIME_COLUMN_NAME) && extractionFn instanceof TimeFormatExtractionFn) {
          // Check if we can strip the extractionFn and convert the filter to a direct filter on __time.
          // This allows potential conversion to query-level "intervals" later on, which is ideal for Druid queries.
  
          final Granularity granularity = ExtractionFns.toQueryGranularity(extractionFn);
          if (granularity != null) {
            // lhs is FLOOR(__time TO granularity); rhs must be a timestamp
            final long rhsMillis = Calcites.calciteDateTimeLiteralToJoda(rhs, plannerContext.getTimeZone()).getMillis();
            final Interval rhsInterval = granularity.bucket(DateTimes.utc(rhsMillis));
  
            // Is rhs aligned on granularity boundaries?
            final boolean rhsAligned = rhsInterval.getStartMillis() == rhsMillis;
  
            // Create a BoundRefKey that strips the extractionFn and compares __time as a number.
            final BoundRefKey boundRefKey = new BoundRefKey(column, null, StringComparators.NUMERIC);
  
            return getBoundTimeDimFilter(flippedKind, boundRefKey, rhsInterval, rhsAligned);
          }
        }
  
        final String val;
        final RexLiteral rhsLiteral = (RexLiteral) rhs;
        if (SqlTypeName.NUMERIC_TYPES.contains(rhsLiteral.getTypeName())) {
          val = String.valueOf(RexLiteral.value(rhsLiteral));
        } else if (SqlTypeName.CHAR_TYPES.contains(rhsLiteral.getTypeName())) {
          val = String.valueOf(RexLiteral.stringValue(rhsLiteral));
        } else if (SqlTypeName.TIMESTAMP == rhsLiteral.getTypeName() || SqlTypeName.DATE == rhsLiteral.getTypeName()) {
          val = String.valueOf(
              Calcites.calciteDateTimeLiteralToJoda(
                  rhsLiteral,
                  plannerContext.getTimeZone()
              ).getMillis()
          );
        } else {
          // Don't know how to filter on this kind of literal.
          return null;
        }
  
        // Numeric lhs needs a numeric comparison.
        final StringComparator comparator = Calcites.getStringComparatorForSqlTypeName(lhs.getType().getSqlTypeName());
        final BoundRefKey boundRefKey = new BoundRefKey(column, extractionFn, comparator);
        final DimFilter filter;
  
        // Always use BoundDimFilters, to simplify filter optimization later (it helps to remember the comparator).
        switch (flippedKind) {
          case EQUALS:
            filter = Bounds.equalTo(boundRefKey, val);
            break;
          case NOT_EQUALS:
            filter = new NotDimFilter(Bounds.equalTo(boundRefKey, val));
            break;
          case GREATER_THAN:
            filter = Bounds.greaterThan(boundRefKey, val);
            break;
          case GREATER_THAN_OR_EQUAL:
            filter = Bounds.greaterThanOrEqualTo(boundRefKey, val);
            break;
          case LESS_THAN:
            filter = Bounds.lessThan(boundRefKey, val);
            break;
          case LESS_THAN_OR_EQUAL:
            filter = Bounds.lessThanOrEqualTo(boundRefKey, val);
            break;
          default:
            throw new IllegalStateException("WTF?! Shouldn't have got here...");
        }
  
        return filter;
      } else if (rexNode instanceof RexCall) {
        final SqlOperator operator = ((RexCall) rexNode).getOperator();
  
        final SqlOperatorConversion conversion =
            plannerContext.getOperatorTable().lookupOperatorConversion(operator);
  
        if (conversion == null) {
          return null;
        } else {
          DimFilter filter =
              conversion.toDruidFilter(plannerContext, querySignature, rexNode);
          if (filter != null) {
            return filter;
          }
          return null;
        }
      }
      return null;
    }