2222import org .apache .calcite .rel .type .RelDataTypeImpl ;
2323import org .apache .calcite .rel .type .RelDataTypeSystem ;
2424import org .apache .calcite .rel .type .RelProtoDataType ;
25+ import org .apache .calcite .rex .RexCallBinding ;
26+ import org .apache .calcite .rex .RexLiteral ;
2527import org .apache .calcite .sql .ExplicitOperatorBinding ;
2628import org .apache .calcite .sql .SqlCall ;
2729import org .apache .calcite .sql .SqlCallBinding ;
2830import org .apache .calcite .sql .SqlCollation ;
2931import org .apache .calcite .sql .SqlKind ;
3032import org .apache .calcite .sql .SqlNodeList ;
33+ import org .apache .calcite .sql .SqlNumericLiteral ;
3134import org .apache .calcite .sql .SqlOperatorBinding ;
3235import org .apache .calcite .sql .SqlUtil ;
3336import org .apache .calcite .sql .validate .SqlValidatorNamespace ;
3437import org .apache .calcite .util .Glossary ;
38+ import org .apache .calcite .util .Pair ;
39+ import org .apache .calcite .util .SqlNodeUtils ;
3540import org .apache .calcite .util .Util ;
3641
3742import org .apache .kylin .guava30 .shaded .common .base .Preconditions ;
@@ -54,19 +59,23 @@ public abstract class ReturnTypes {
5459 private ReturnTypes () {
5560 }
5661
57- /** Creates a return-type inference that applies a rule then a sequence of
62+ /**
63+ * Creates a return-type inference that applies a rule then a sequence of
5864 * rules, returning the first non-null result.
5965 *
60- * @see SqlReturnTypeInference#orElse(SqlReturnTypeInference) */
66+ * @see SqlReturnTypeInference#orElse(SqlReturnTypeInference)
67+ */
6168 public static SqlReturnTypeInferenceChain chain (
6269 SqlReturnTypeInference ... rules ) {
6370 return new SqlReturnTypeInferenceChain (rules );
6471 }
6572
66- /** Creates a return-type inference that applies a rule then a sequence of
73+ /**
74+ * Creates a return-type inference that applies a rule then a sequence of
6775 * transforms.
6876 *
69- * @see SqlReturnTypeInference#andThen(SqlTypeTransform) */
77+ * @see SqlReturnTypeInference#andThen(SqlTypeTransform)
78+ */
7079 public static SqlTypeTransformCascade cascade (SqlReturnTypeInference rule ,
7180 SqlTypeTransform ... transforms ) {
7281 return new SqlTypeTransformCascade (rule , transforms );
@@ -101,21 +110,25 @@ public static ExplicitReturnTypeInference explicit(SqlTypeName typeName,
101110 return explicit (RelDataTypeImpl .proto (typeName , precision , false ));
102111 }
103112
104- /** Returns a return-type inference that first transforms a binding and
113+ /**
114+ * Returns a return-type inference that first transforms a binding and
105115 * then applies an inference.
106116 *
107- * <p>{@link #stripOrderBy} is an example of {@code bindingTransform}. */
117+ * <p>{@link #stripOrderBy} is an example of {@code bindingTransform}.
118+ */
108119 public static SqlReturnTypeInference andThen (
109120 UnaryOperator <SqlOperatorBinding > bindingTransform ,
110121 SqlReturnTypeInference typeInference ) {
111122 return opBinding ->
112123 typeInference .inferReturnType (bindingTransform .apply (opBinding ));
113124 }
114125
115- /** Converts a binding of {@code FOO(x, y ORDER BY z)}
126+ /**
127+ * Converts a binding of {@code FOO(x, y ORDER BY z)}
116128 * or {@code FOO(x, y ORDER BY z SEPARATOR s)}
117129 * to a binding of {@code FOO(x, y)}.
118- * Used for {@code STRING_AGG} and {@code GROUP_CONCAT}. */
130+ * Used for {@code STRING_AGG} and {@code GROUP_CONCAT}.
131+ */
119132 public static SqlOperatorBinding stripOrderBy (
120133 SqlOperatorBinding operatorBinding ) {
121134 if (operatorBinding instanceof SqlCallBinding ) {
@@ -367,7 +380,7 @@ public static SqlCall stripSeparator(SqlCall call) {
367380 * Type-inference strategy whereby the result type of a call is a Char.
368381 */
369382 public static final SqlReturnTypeInference CHAR =
370- explicit (SqlTypeName .CHAR );
383+ explicit (SqlTypeName .CHAR );
371384
372385 /**
373386 * Type-inference strategy whereby the result type of a call is a nullable
@@ -686,11 +699,69 @@ public static SqlCall stripSeparator(SqlCall call) {
686699 */
687700 public static final SqlReturnTypeInference DECIMAL_PRODUCT = opBinding -> {
688701 RelDataTypeFactory typeFactory = opBinding .getTypeFactory ();
689- RelDataType type1 = opBinding . getOperandType ( 0 );
690- RelDataType type2 = opBinding . getOperandType ( 1 );
691- return typeFactory . getTypeSystem (). deriveDecimalMultiplyType ( typeFactory , type1 , type2 );
702+ Pair < RelDataType , RelDataType > result = getDecimalMultiplyBindingType ( opBinding , typeFactory );
703+ return typeFactory . getTypeSystem (). deriveDecimalMultiplyType ( typeFactory , result . left ,
704+ result . right );
692705 };
693706
707+ private static Pair <RelDataType , RelDataType > getDecimalMultiplyBindingType (SqlOperatorBinding opBinding ,
708+ RelDataTypeFactory typeFactory ) {
709+ if (opBinding instanceof SqlCallBinding ) {
710+ RelDataType type1 = createDecimalTypeOrDefault (typeFactory , (SqlCallBinding ) opBinding , 0 );
711+ RelDataType type2 = createDecimalTypeOrDefault (typeFactory , (SqlCallBinding ) opBinding , 1 );
712+ return Pair .of (type1 , type2 );
713+ }
714+ if (opBinding instanceof RexCallBinding ) {
715+ RelDataType type1 = createDecimalTypeOrDefault (typeFactory , (RexCallBinding ) opBinding , 0 );
716+ RelDataType type2 = createDecimalTypeOrDefault (typeFactory , (RexCallBinding ) opBinding , 1 );
717+ return Pair .of (type1 , type2 );
718+ }
719+ return Pair .of (opBinding .getOperandType (0 ), opBinding .getOperandType (1 ));
720+ }
721+
722+ private static RelDataType createDecimalTypeOrDefault (RelDataTypeFactory typeFactory ,
723+ RexCallBinding opBinding , int ordinal ) {
724+ RelDataType defaultType = opBinding .getOperandType (ordinal );
725+ try {
726+ if (!SqlNodeUtils .isNumericLiteral (opBinding , ordinal )) {
727+ return defaultType ;
728+ }
729+
730+ RexLiteral literal = (RexLiteral ) opBinding .operands ().get (ordinal );
731+
732+ if (SqlNodeUtils .isDecimalConstant (literal )) {
733+ return defaultType ;
734+ }
735+
736+ Long value = literal .getValueAs (Long .class );
737+ int length = (int ) Math .floor (Math .log10 (Math .abs (value ))) + 1 ;
738+ return typeFactory .createSqlType (SqlTypeName .DECIMAL , length , 0 );
739+ } catch (IllegalArgumentException | AssertionError e ) {
740+ return defaultType ;
741+ }
742+ }
743+
744+ private static RelDataType createDecimalTypeOrDefault (RelDataTypeFactory typeFactory ,
745+ SqlCallBinding opBinding , int ordinal ) {
746+ RelDataType defaultType = opBinding .getOperandType (ordinal );
747+ try {
748+ if (!SqlNodeUtils .isNumericLiteral (opBinding , ordinal )) {
749+ return defaultType ;
750+ }
751+
752+ SqlNumericLiteral literal =
753+ (SqlNumericLiteral ) opBinding .getCall ().getOperandList ().get (ordinal );
754+ // When parsing into a **SqlNode**, integers are converted to **DECIMAL** type.
755+ if (SqlNodeUtils .isDecimalConstant (literal )) {
756+ return typeFactory .createSqlType (SqlTypeName .DECIMAL , literal .getPrec (),
757+ literal .getScale ());
758+ }
759+ return defaultType ;
760+ } catch (IllegalArgumentException e ) {
761+ return defaultType ;
762+ }
763+ }
764+
694765 /**
695766 * Same as {@link #DECIMAL_PRODUCT} but returns with nullability if any of
696767 * the operands is nullable by using
@@ -746,7 +817,7 @@ public static SqlCall stripSeparator(SqlCall call) {
746817 * {@link org.apache.calcite.sql.type.SqlTypeTransforms#TO_NULLABLE}.
747818 */
748819 public static final SqlReturnTypeInference DOUBLE_QUOTIENT_NULLABLE =
749- DOUBLE_QUOTIENT .andThen (SqlTypeTransforms .TO_NULLABLE );
820+ DOUBLE_QUOTIENT .andThen (SqlTypeTransforms .TO_NULLABLE );
750821
751822 /**
752823 * Type-inference strategy whereby the result type of a call is
@@ -933,7 +1004,7 @@ public static SqlCall stripSeparator(SqlCall call) {
9331004 List <RelDataType > operandTypes = opBinding .collectOperandTypes ();
9341005 final RelDataTypeFactory typeFactory = opBinding .getTypeFactory ();
9351006 final RelDataTypeSystem typeSystem = typeFactory .getTypeSystem ();
936- for (RelDataType operandType : operandTypes ) {
1007+ for (RelDataType operandType : operandTypes ) {
9371008 int operandPrecision = operandType .getPrecision ();
9381009 amount = (long ) operandPrecision + amount ;
9391010 if (operandPrecision == RelDataType .PRECISION_NOT_SPECIFIED ) {
0 commit comments