private StandardConvertletTable()

in core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java [122:401]


  private StandardConvertletTable() {
    super();

    // Register aliases (operators which have a different name but
    // identical behavior to other operators).
    addAlias(SqlLibraryOperators.LEN,
        SqlStdOperatorTable.CHAR_LENGTH);
    addAlias(SqlLibraryOperators.LENGTH,
        SqlStdOperatorTable.CHAR_LENGTH);
    addAlias(SqlStdOperatorTable.CHARACTER_LENGTH,
        SqlStdOperatorTable.CHAR_LENGTH);
    addAlias(SqlStdOperatorTable.IS_UNKNOWN,
        SqlStdOperatorTable.IS_NULL);
    addAlias(SqlStdOperatorTable.IS_NOT_UNKNOWN,
        SqlStdOperatorTable.IS_NOT_NULL);
    addAlias(SqlLibraryOperators.NULL_SAFE_EQUAL,
        SqlStdOperatorTable.IS_NOT_DISTINCT_FROM);
    addAlias(SqlStdOperatorTable.PERCENT_REMAINDER, SqlStdOperatorTable.MOD);
    addAlias(SqlLibraryOperators.IFNULL, SqlLibraryOperators.NVL);
    addAlias(SqlLibraryOperators.REGEXP_SUBSTR, SqlLibraryOperators.REGEXP_EXTRACT);
    addAlias(SqlLibraryOperators.ENDSWITH, SqlLibraryOperators.ENDS_WITH);
    addAlias(SqlLibraryOperators.STARTSWITH, SqlLibraryOperators.STARTS_WITH);
    addAlias(SqlLibraryOperators.BITAND_AGG, SqlStdOperatorTable.BIT_AND);
    addAlias(SqlLibraryOperators.BITOR_AGG, SqlStdOperatorTable.BIT_OR);

    // Register convertlets for specific objects.
    registerOp(CAST, this::convertCast);
    registerOp(SqlLibraryOperators.SAFE_CAST, this::convertCast);
    registerOp(SqlLibraryOperators.TRY_CAST, this::convertCast);
    registerOp(SqlLibraryOperators.INFIX_CAST, this::convertCast);
    registerOp(SqlStdOperatorTable.IS_DISTINCT_FROM,
        (cx, call) -> convertIsDistinctFrom(cx, call, false));
    registerOp(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
        (cx, call) -> convertIsDistinctFrom(cx, call, true));

    registerOp(SqlStdOperatorTable.PLUS, this::convertPlus);

    registerOp(SqlStdOperatorTable.MINUS,
        (cx, call) -> {
          final RexCall e =
              (RexCall) StandardConvertletTable.this.convertCall(cx, call);
          switch (e.getOperands().get(0).getType().getSqlTypeName()) {
          case DATE:
          case TIME:
          case TIMESTAMP:
            return convertDatetimeMinus(cx, SqlStdOperatorTable.MINUS_DATE,
                call);
          default:
            return e;
          }
        });

    // DATE(string) is equivalent to CAST(string AS DATE),
    // but other DATE variants are treated as regular functions.
    registerOp(SqlLibraryOperators.DATE,
        (cx, call) -> {
          final RexCall e =
              (RexCall) StandardConvertletTable.this.convertCall(cx, call);
          if (e.getOperands().size() == 1
              && SqlTypeUtil.isString(e.getOperands().get(0).getType())) {
            return cx.getRexBuilder().makeCast(
                e.getParserPosition(), e.type, e.getOperands().get(0));
          }
          return e;
        });

    registerOp(SqlLibraryOperators.DATETIME_TRUNC,
        new TruncConvertlet());
    registerOp(SqlLibraryOperators.TIMESTAMP_TRUNC,
        new TruncConvertlet());

    registerOp(SqlLibraryOperators.LTRIM,
        new TrimConvertlet(SqlTrimFunction.Flag.LEADING));
    registerOp(SqlLibraryOperators.RTRIM,
        new TrimConvertlet(SqlTrimFunction.Flag.TRAILING));

    registerOp(SqlLibraryOperators.GREATEST, new GreatestConvertlet());
    registerOp(SqlLibraryOperators.GREATEST_PG, new GreatestPgConvertlet());
    registerOp(SqlLibraryOperators.LEAST, new GreatestConvertlet());
    registerOp(SqlLibraryOperators.LEAST_PG, new GreatestPgConvertlet());
    registerOp(SqlLibraryOperators.SUBSTR_BIG_QUERY,
        new SubstrConvertlet(SqlLibrary.BIG_QUERY));
    registerOp(SqlLibraryOperators.SUBSTR_MYSQL,
        new SubstrConvertlet(SqlLibrary.MYSQL));
    registerOp(SqlLibraryOperators.SUBSTR_ORACLE,
        new SubstrConvertlet(SqlLibrary.ORACLE));
    registerOp(SqlLibraryOperators.SUBSTR_POSTGRESQL,
        new SubstrConvertlet(SqlLibrary.POSTGRESQL));

    registerOp(SqlLibraryOperators.DATE_ADD,
        new TimestampAddConvertlet());
    registerOp(SqlLibraryOperators.ADD_MONTHS,
        new TimestampAddConvertlet());
    registerOp(SqlLibraryOperators.DATE_ADD_SPARK,
        new TimestampAddConvertlet());
    registerOp(SqlLibraryOperators.DATE_DIFF,
        new TimestampDiffConvertlet());
    registerOp(SqlLibraryOperators.DATE_SUB,
        new TimestampSubConvertlet());
    registerOp(SqlLibraryOperators.DATE_SUB_SPARK,
        new TimestampSubConvertlet());
    registerOp(SqlLibraryOperators.DATETIME_ADD,
        new TimestampAddConvertlet());
    registerOp(SqlLibraryOperators.DATETIME_DIFF,
        new TimestampDiffConvertlet());
    registerOp(SqlLibraryOperators.DATETIME_SUB,
        new TimestampSubConvertlet());
    registerOp(SqlLibraryOperators.TIME_ADD,
        new TimestampAddConvertlet());
    registerOp(SqlLibraryOperators.TIME_DIFF,
        new TimestampDiffConvertlet());
    registerOp(SqlLibraryOperators.TIME_SUB,
        new TimestampSubConvertlet());
    registerOp(SqlLibraryOperators.TIMESTAMP_ADD2,
        new TimestampAddConvertlet());
    registerOp(SqlLibraryOperators.TIMESTAMP_DIFF3,
        new TimestampDiffConvertlet());
    registerOp(SqlLibraryOperators.TIMESTAMP_SUB,
        new TimestampSubConvertlet());

    QUANTIFY_OPERATORS.forEach(operator ->
        registerOp(operator, StandardConvertletTable::convertQuantifyOperator));

    registerOp(SqlLibraryOperators.NVL, StandardConvertletTable::convertNvl);
    registerOp(SqlLibraryOperators.NVL2, StandardConvertletTable::convertNvl2);
    registerOp(SqlLibraryOperators.DECODE,
        StandardConvertletTable::convertDecode);
    registerOp(SqlLibraryOperators.IF, StandardConvertletTable::convertIf);

    // Expand "x NOT LIKE y" into "NOT (x LIKE y)"
    registerOp(SqlStdOperatorTable.NOT_LIKE,
        (cx, call) -> cx.convertExpression(
            SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
                SqlStdOperatorTable.LIKE.createCall(SqlParserPos.ZERO,
                    call.getOperandList()))));

    // Expand "x NOT ILIKE y" into "NOT (x ILIKE y)"
    registerOp(SqlLibraryOperators.NOT_ILIKE,
        (cx, call) -> cx.convertExpression(
            SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
                SqlLibraryOperators.ILIKE.createCall(SqlParserPos.ZERO,
                    call.getOperandList()))));

    // Expand "x NOT RLIKE y" into "NOT (x RLIKE y)"
    registerOp(SqlLibraryOperators.NOT_RLIKE,
        (cx, call) -> cx.convertExpression(
            SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
                SqlLibraryOperators.RLIKE.createCall(SqlParserPos.ZERO,
                    call.getOperandList()))));

    // Expand "x NOT SIMILAR y" into "NOT (x SIMILAR y)"
    registerOp(SqlStdOperatorTable.NOT_SIMILAR_TO,
        (cx, call) -> cx.convertExpression(
            SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
                SqlStdOperatorTable.SIMILAR_TO.createCall(SqlParserPos.ZERO,
                    call.getOperandList()))));

    // Unary "+" has no effect, so expand "+ x" into "x".
    registerOp(SqlStdOperatorTable.UNARY_PLUS,
        (cx, call) -> cx.convertExpression(call.operand(0)));

    // "DOT"
    registerOp(SqlStdOperatorTable.DOT,
        (cx, call) -> cx.getRexBuilder().makeFieldAccess(
            cx.convertExpression(call.operand(0)),
            call.operand(1).toString(), false));
    // "ITEM"
    registerOp(SqlStdOperatorTable.ITEM, this::convertItem);
    // "AS" has no effect, so expand "x AS id" into "x".
    registerOp(SqlStdOperatorTable.AS,
        (cx, call) -> cx.convertExpression(call.operand(0)));

    // "MEASURE" has no effect, so expand "x AS MEASURE id" into "x".
    registerOp(SqlInternalOperators.MEASURE,
        (cx, call) -> cx.convertExpression(call.operand(0)));

    registerOp(SqlStdOperatorTable.CONVERT, this::convertCharset);
    registerOp(SqlLibraryOperators.CONVERT_ORACLE, this::convertCharset);
    registerOp(SqlStdOperatorTable.TRANSLATE, this::translateCharset);
    // "SQRT(x)" is equivalent to "POWER(x, .5)"
    registerOp(SqlStdOperatorTable.SQRT,
        (cx, call) -> cx.convertExpression(
            SqlStdOperatorTable.POWER.createCall(SqlParserPos.ZERO,
                call.operand(0),
                SqlLiteral.createExactNumeric("0.5", SqlParserPos.ZERO))));

    // "STRPOS(string, substring) is equivalent to
    // "POSITION(substring IN string)"
    registerOp(SqlLibraryOperators.STRPOS,
        (cx, call) -> cx.convertExpression(
            SqlStdOperatorTable.POSITION.createCall(SqlParserPos.ZERO,
                call.operand(1), call.operand(0))));

    // "INSTR(string, substring, position, occurrence) is equivalent to
    // "POSITION(substring, string, position, occurrence)"
    registerOp(SqlLibraryOperators.INSTR, StandardConvertletTable::convertInstr);

    // REVIEW jvs 24-Apr-2006: This only seems to be working from within a
    // windowed agg.  I have added an optimizer rule
    // org.apache.calcite.rel.rules.AggregateReduceFunctionsRule which handles
    // other cases post-translation.  The reason I did that was to defer the
    // implementation decision; e.g. we may want to push it down to a foreign
    // server directly rather than decomposed; decomposition is easier than
    // recognition.

    // Convert "avg(<expr>)" to "cast(sum(<expr>) / count(<expr>) as
    // <type>)". We don't need to handle the empty set specially, because
    // the SUM is already supposed to come out as NULL in cases where the
    // COUNT is zero, so the null check should take place first and prevent
    // division by zero. We need the cast because SUM and COUNT may use
    // different types, say BIGINT.
    //
    // Similarly STDDEV_POP and STDDEV_SAMP, VAR_POP and VAR_SAMP.
    registerOp(SqlStdOperatorTable.AVG,
        new AvgVarianceConvertlet(SqlKind.AVG));
    registerOp(SqlStdOperatorTable.STDDEV_POP,
        new AvgVarianceConvertlet(SqlKind.STDDEV_POP));
    registerOp(SqlStdOperatorTable.STDDEV_SAMP,
        new AvgVarianceConvertlet(SqlKind.STDDEV_SAMP));
    registerOp(SqlStdOperatorTable.STDDEV,
        new AvgVarianceConvertlet(SqlKind.STDDEV_SAMP));
    registerOp(SqlStdOperatorTable.VAR_POP,
        new AvgVarianceConvertlet(SqlKind.VAR_POP));
    registerOp(SqlStdOperatorTable.VAR_SAMP,
        new AvgVarianceConvertlet(SqlKind.VAR_SAMP));
    registerOp(SqlStdOperatorTable.VARIANCE,
        new AvgVarianceConvertlet(SqlKind.VAR_SAMP));
    registerOp(SqlStdOperatorTable.COVAR_POP,
        new RegrCovarianceConvertlet(SqlKind.COVAR_POP));
    registerOp(SqlStdOperatorTable.COVAR_SAMP,
        new RegrCovarianceConvertlet(SqlKind.COVAR_SAMP));
    registerOp(SqlStdOperatorTable.REGR_SXX,
        new RegrCovarianceConvertlet(SqlKind.REGR_SXX));
    registerOp(SqlStdOperatorTable.REGR_SYY,
        new RegrCovarianceConvertlet(SqlKind.REGR_SYY));

    final SqlRexConvertlet floorCeilConvertlet = new FloorCeilConvertlet();
    registerOp(SqlStdOperatorTable.FLOOR, floorCeilConvertlet);
    registerOp(SqlStdOperatorTable.CEIL, floorCeilConvertlet);
    registerOp(SqlStdOperatorTable.TIMESTAMP_ADD, new TimestampAddConvertlet());
    registerOp(SqlStdOperatorTable.TIMESTAMP_DIFF,
        new TimestampDiffConvertlet());

    registerOp(SqlStdOperatorTable.INTERVAL,
        StandardConvertletTable::convertInterval);

    // Convert "element(<expr>)" to "$element_slice(<expr>)", if the
    // expression is a multiset of scalars.
    if (false) {
      registerOp(SqlStdOperatorTable.ELEMENT,
          (cx, call) -> {
            assert call.operandCount() == 1;
            final SqlNode operand = call.operand(0);
            final RelDataType type =
                cx.getValidator().getValidatedNodeType(operand);
            if (!getComponentTypeOrThrow(type).isStruct()) {
              return cx.convertExpression(
                  SqlStdOperatorTable.ELEMENT_SLICE.createCall(
                      SqlParserPos.ZERO, operand));
            }

            // fallback on default behavior
            return StandardConvertletTable.this.convertCall(cx, call);
          });
    }

    // Convert "$element_slice(<expr>)" to "element(<expr>).field#0"
    if (false) {
      registerOp(SqlStdOperatorTable.ELEMENT_SLICE,
          (cx, call) -> {
            assert call.operandCount() == 1;
            final SqlNode operand = call.operand(0);
            final RexNode expr =
                cx.convertExpression(
                    SqlStdOperatorTable.ELEMENT.createCall(SqlParserPos.ZERO,
                        operand));
            return cx.getRexBuilder().makeFieldAccess(expr, 0);
          });
    }
  }