Skip to content

Commit

Permalink
[CALCITE-6598] In RelDataTypeSystem, deprecate methods getMaxNumericS…
Browse files Browse the repository at this point in the history
…cale and getMaxNumericPrecision

You should instead use methods getMaxScale(DECIMAL) and
getMaxPrecision(DECIMAL).

Because these methods are an SPI (callback), we have to
deprecate them in two phases.
 * In 1.38, the methods are deprecated, to dissuade
   people from calling them. But some people will have
   overridden them in their implementation of
   RelDataTypeSystem, so Calcite will continue to call
   them. If you have a custom type system, you should move
   your customizations to the getMaxPrecision(SqlTypeName)
   and have your getMaxNumericPrecision() call
   getMaxPrecision(DECIMAL). (Ditto getMaxScale.)
 * In 1.39, the methods will still be present and deprecated,
   but Calcite will no longer call them. You should remove
   all calls to the methods, and all overrides of the
   methods.
 * In 2.0, the methods will be removed.
  • Loading branch information
julianhyde committed Oct 5, 2024
1 parent 2ce9ba4 commit d59871d
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ public abstract static class RexExpander {
real8 = builder.getTypeFactory().createSqlType(SqlTypeName.DOUBLE);
}

private RelDataTypeSystem typeSystem() {
return builder.getTypeFactory().getTypeSystem();
}

/**
* This defaults to the utility method,
* {@link RexUtil#requiresDecimalExpansion(RexNode, boolean)} which checks
Expand Down Expand Up @@ -345,10 +349,10 @@ public boolean canExpand(RexCall call) {
* @param scale a scale from one to max precision - 1
* @return 10^scale as an exact numeric value
*/
@SuppressWarnings("deprecation") // [CALCITE-6598]
protected RexNode makeScaleFactor(int scale) {
assert scale > 0;
assert scale
< builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
assert scale < typeSystem().getMaxNumericPrecision();
return makeExactLiteral(powerOfTen(scale));
}

Expand All @@ -375,20 +379,20 @@ protected RexNode makeApproxScaleFactor(int scale) {
* @param scale a scale from 1 to max precision - 1
* @return 10^scale / 2 as an exact numeric value
*/
@SuppressWarnings("deprecation") // [CALCITE-6598]
protected RexNode makeRoundFactor(int scale) {
assert scale > 0;
assert scale
< builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
assert scale < typeSystem().getMaxNumericPrecision();
return makeExactLiteral(powerOfTen(scale) / 2);
}

/**
* Calculates a power of ten, as a long value.
*/
@SuppressWarnings("deprecation") // [CALCITE-6598]
protected long powerOfTen(int scale) {
assert scale >= 0;
assert scale
< builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
assert scale < typeSystem().getMaxNumericPrecision();
return BigInteger.TEN.pow(scale).longValue();
}

Expand All @@ -415,10 +419,10 @@ protected RexNode makeApproxLiteral(BigDecimal bd) {
* @param scale a value from zero to max precision - 1
* @return value * 10^scale as an exact numeric value
*/
@SuppressWarnings("deprecation") // [CALCITE-6598]
protected RexNode scaleUp(SqlParserPos pos, RexNode value, int scale) {
assert scale >= 0;
assert scale
< builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
assert scale < typeSystem().getMaxNumericPrecision();
if (scale == 0) {
return value;
}
Expand All @@ -440,9 +444,9 @@ protected RexNode scaleUp(SqlParserPos pos, RexNode value, int scale) {
* @return value/10^scale, rounded away from zero and returned as an
* exact numeric value
*/
@SuppressWarnings("deprecation") // [CALCITE-6598]
protected RexNode scaleDown(SqlParserPos pos, RexNode value, int scale) {
final int maxPrecision =
builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
final int maxPrecision = typeSystem().getMaxNumericPrecision();
assert scale >= 0 && scale <= maxPrecision;
if (scale == 0) {
return value;
Expand Down Expand Up @@ -485,10 +489,10 @@ protected RexNode scaleDown(SqlParserPos pos, RexNode value, int scale) {
* @param scale a value from zero to max precision
* @return value/10^scale as a double precision value
*/
@SuppressWarnings("deprecation") // [CALCITE-6598]
protected RexNode scaleDownDouble(SqlParserPos pos, RexNode value, int scale) {
assert scale >= 0;
assert scale
<= builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
assert scale <= typeSystem().getMaxNumericPrecision();
RexNode cast = ensureType(pos, real8, value);
if (scale == 0) {
return cast;
Expand Down Expand Up @@ -516,9 +520,10 @@ protected RexNode scaleDownDouble(SqlParserPos pos, RexNode value, int scale) {
* @return value * 10^scale, returned as an exact or approximate value
* corresponding to the input value
*/
protected RexNode ensureScale(SqlParserPos pos, RexNode value, int scale, int required) {
final RelDataTypeSystem typeSystem =
builder.getTypeFactory().getTypeSystem();
@SuppressWarnings("deprecation") // [CALCITE-6598]
protected RexNode ensureScale(SqlParserPos pos, RexNode value, int scale,
int required) {
final RelDataTypeSystem typeSystem = typeSystem();
final int maxPrecision = typeSystem.getMaxNumericPrecision();
assert scale <= maxPrecision && required <= maxPrecision;
assert required >= scale;
Expand Down Expand Up @@ -1038,6 +1043,7 @@ private FloorExpander(RexBuilder rexBuilder) {
super(rexBuilder);
}

@SuppressWarnings("deprecation") // [CALCITE-6598]
@Override public RexNode expand(RexCall call) {
assert call.getOperator() == SqlStdOperatorTable.FLOOR;
final SqlParserPos pos = call.getParserPosition();
Expand All @@ -1046,11 +1052,12 @@ private FloorExpander(RexBuilder rexBuilder) {
RexNode value = decodeValue(pos, decValue);
final RelDataTypeSystem typeSystem =
builder.getTypeFactory().getTypeSystem();
final int maxPrecision = typeSystem.getMaxNumericPrecision();

RexNode rewrite;
if (scale == 0) {
rewrite = decValue;
} else if (scale == typeSystem.getMaxNumericPrecision()) {
} else if (scale == maxPrecision) {
rewrite =
makeCase(
makeIsNegative(value),
Expand Down Expand Up @@ -1089,6 +1096,7 @@ private CeilExpander(RexBuilder rexBuilder) {
super(rexBuilder);
}

@SuppressWarnings("deprecation") // [CALCITE-6598]
@Override public RexNode expand(RexCall call) {
assert call.getOperator() == SqlStdOperatorTable.CEIL;
final SqlParserPos pos = call.getParserPosition();
Expand All @@ -1097,11 +1105,12 @@ private CeilExpander(RexBuilder rexBuilder) {
RexNode value = decodeValue(pos, decValue);
final RelDataTypeSystem typeSystem =
builder.getTypeFactory().getTypeSystem();
final int maxPrecision = typeSystem.getMaxNumericPrecision();

RexNode rewrite;
if (scale == 0) {
rewrite = decValue;
} else if (scale == typeSystem.getMaxNumericPrecision()) {
} else if (scale == maxPrecision) {
rewrite =
makeCase(
makeIsPositive(value),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ protected DelegatingTypeSystem(RelDataTypeSystem typeSystem) {
return typeSystem.getMinPrecision(typeName);
}

@SuppressWarnings("deprecation")
@Override public int getMaxNumericScale() {
return typeSystem.getMaxNumericScale();
}

@SuppressWarnings("deprecation")
@Override public int getMaxNumericPrecision() {
return typeSystem.getMaxNumericPrecision();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,61 @@ public interface RelDataTypeSystem {
*/
int getMinPrecision(SqlTypeName typeName);

/** Returns the maximum scale of a NUMERIC or DECIMAL type. And the default value is 19. */
int getMaxNumericScale();
/** Returns the maximum scale of a NUMERIC or DECIMAL type.
* Default value is 19.
*
* @deprecated Replaced by {@link #getMaxScale}(DECIMAL).
*
* <p>From Calcite release 1.38 onwards, instead of calling this method, you
* should call {@code getMaxScale(DECIMAL)}.
*
* <p>In Calcite release 1.38, if you wish to change the maximum
* scale of {@link SqlTypeName#DECIMAL} values, you should do two things:
*
* <ul>
* <li>Override the {@link #getMaxScale(SqlTypeName)} method,
* changing its behavior for {@code DECIMAL};
* <li>Make sure that the implementation of your
* {@code #getMaxNumericScale} method calls
* {@code getMaxScale(DECIMAL)}.
* </ul>
*
* <p>In Calcite release 1.39, Calcite will cease calling this method,
* and will remove the override of the method in
* {@link RelDataTypeSystemImpl}. You should remove all calls to
* and overrides of this method. */
@Deprecated // calcite will cease calling in 1.39, and removed before 2.0
default int getMaxNumericScale() {
return 19;
}

/** Returns the maximum precision of a NUMERIC or DECIMAL type. And the default value is 19. */
int getMaxNumericPrecision();
/** Returns the maximum precision of a NUMERIC or DECIMAL type.
* Default value is 19.
*
* @deprecated Replaced by {@link #getMaxScale}(DECIMAL).
*
* <p>From Calcite release 1.38 onwards, instead of calling this method, you
* should call {@code getMaxPrecision(DECIMAL)}.
*
* <p>In Calcite release 1.38, if you wish to change the maximum
* precision of {@link SqlTypeName#DECIMAL} values, you should do two things:
*
* <ul>
* <li>Override the {@link #getMaxPrecision(SqlTypeName)} method,
* changing its behavior for {@code DECIMAL};
* <li>Make sure that the implementation of your
* {@code #getMaxNumericPrecision} method calls
* {@code getMaxPrecision(DECIMAL)}.
* </ul>
*
* <p>In Calcite release 1.39, Calcite will cease calling this method,
* and will remove the override of the method in
* {@link RelDataTypeSystemImpl}. You should remove all calls to
* and overrides of this method. */
@Deprecated // calcite will cease calling in 1.39, and removed before 2.0
default int getMaxNumericPrecision() {
return getMaxPrecision(SqlTypeName.DECIMAL);
}

/** Returns the rounding behavior for numerical operations capable of discarding precision. */
RoundingMode roundingMode();
Expand Down Expand Up @@ -334,10 +384,11 @@ default boolean shouldUseDoubleMultiplication(RelDataTypeFactory typeFactory,
int s1 = type1.getScale();
int s2 = type2.getScale();

int six = Math.min(6, getMaxNumericScale());
final int maxScale = getMaxNumericScale();
int six = Math.min(6, maxScale);
int d = p1 - s1 + s2;
int scale = Math.max(six, s1 + p2 + 1);
scale = Math.min(scale, getMaxNumericScale());
scale = Math.min(scale, maxScale);
int precision = d + scale;

// Rules from
Expand All @@ -359,17 +410,18 @@ default boolean shouldUseDoubleMultiplication(RelDataTypeFactory typeFactory,
// reduced and resulting type is decimal(38, 6). The result might be rounded to
// 7 decimal places, or the overflow error is thrown if the integral part
// can't fit into 32 digits.
int bound = getMaxNumericPrecision() - six; // This was '32' in the MS documentation
final int maxPrecision = getMaxNumericPrecision();
int bound = maxPrecision - six; // This was '32' in the MS documentation
if (precision <= bound) {
scale = Math.min(scale, getMaxNumericPrecision() - (precision - scale));
scale = Math.min(scale, maxPrecision - (precision - scale));
} else {
// precision > bound
scale = Math.min(six, scale);
}

precision = Math.min(precision, getMaxNumericPrecision());
precision = Math.min(precision, maxPrecision);
assert precision > 0;
assert scale <= getMaxNumericScale();
assert scale <= maxScale;

RelDataType ret;
ret = typeFactory.
Expand Down Expand Up @@ -439,9 +491,12 @@ default boolean shouldUseDoubleMultiplication(RelDataTypeFactory typeFactory,
return type2;
}

int scale = Math.min(Math.max(s1, s2), getMaxNumericScale());
final int maxScale = getMaxNumericScale();
final int maxPrecision = getMaxNumericPrecision();

final int scale = Math.min(Math.max(s1, s2), maxScale);
int precision = Math.min(p1 - s1, p2 - s2) + Math.max(s1, s2);
precision = Math.min(precision, getMaxNumericPrecision());
precision = Math.min(precision, maxPrecision);
assert precision > 0;

return typeFactory.createSqlType(SqlTypeName.DECIMAL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.math.RoundingMode;

import static org.apache.calcite.sql.type.SqlTypeName.DEFAULT_INTERVAL_FRACTIONAL_SECOND_PRECISION;
import static org.apache.calcite.sql.type.SqlTypeName.MIN_INTERVAL_FRACTIONAL_SECOND_PRECISION;
import static org.apache.calcite.sql.type.SqlTypeName.MIN_INTERVAL_START_PRECISION;

/** Default implementation of
Expand All @@ -47,6 +46,7 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
@Override public int getMaxScale(SqlTypeName typeName) {
switch (typeName) {
case DECIMAL:
// from 1.39, this will be 'return 19;'
return getMaxNumericScale();
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
Expand Down Expand Up @@ -91,7 +91,7 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
case INTERVAL_MINUTE:
case INTERVAL_MINUTE_SECOND:
case INTERVAL_SECOND:
return MIN_INTERVAL_FRACTIONAL_SECOND_PRECISION;
return 0; // MIN_INTERVAL_FRACTIONAL_SECOND_PRECISION;
default:
return RelDataType.SCALE_NOT_SPECIFIED;
}
Expand All @@ -107,6 +107,7 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
case VARBINARY:
return RelDataType.PRECISION_NOT_SPECIFIED;
case DECIMAL:
// from 1.39, this will be 'return getMaxPrecision(typeName);'
return getMaxNumericPrecision();
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
Expand Down Expand Up @@ -182,6 +183,7 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
@Override public int getMaxPrecision(SqlTypeName typeName) {
switch (typeName) {
case DECIMAL:
// from 1.39, this will be 'return 19;'
return getMaxNumericPrecision();
case VARCHAR:
case CHAR:
Expand Down Expand Up @@ -255,10 +257,12 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
}
}

@SuppressWarnings("deprecation")
@Override public int getMaxNumericScale() {
return 19;
}

@SuppressWarnings("deprecation")
@Override public int getMaxNumericPrecision() {
return 19;
}
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/apache/calcite/rex/RexBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,7 @@ public RexLiteral makeLiteral(boolean b) {
/**
* Creates a numeric literal.
*/
@SuppressWarnings("deprecation") // [CALCITE-6598]
public RexLiteral makeExactLiteral(BigDecimal bd) {
RelDataType relType;
int scale = bd.scale();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public class RedshiftSqlDialect extends SqlDialect {
new RelDataTypeSystemImpl() {
@Override public int getMaxPrecision(SqlTypeName typeName) {
switch (typeName) {
case DECIMAL:
return 38;
case VARCHAR:
return 65535;
case CHAR:
Expand All @@ -48,11 +50,20 @@ public class RedshiftSqlDialect extends SqlDialect {
}

@Override public int getMaxNumericPrecision() {
return 38;
return getMaxPrecision(SqlTypeName.DECIMAL);
}

@Override public int getMaxScale(SqlTypeName typeName) {
switch (typeName) {
case DECIMAL:
return 37;
default:
return super.getMaxScale(typeName);
}
}

@Override public int getMaxNumericScale() {
return 37;
return getMaxScale(SqlTypeName.DECIMAL);
}
};

Expand Down
Loading

0 comments on commit d59871d

Please sign in to comment.