This is an automated email from the ASF dual-hosted git repository.

mbudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 68f9ee0cc053130b2b3793aafc896c128e706aa5
Author: Mihai Budiu <[email protected]>
AuthorDate: Wed Aug 7 11:36:17 2024 -0700

    Handle the case where maximum scale is less than 6
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../apache/calcite/rel/type/RelDataTypeSystem.java | 25 +++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java 
b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java
index 0028cbbfd1..ccc9537d6f 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystem.java
@@ -294,22 +294,41 @@ public interface RelDataTypeSystem {
         int s1 = type1.getScale();
         int s2 = type2.getScale();
 
+        int six = Math.min(6, getMaxNumericScale());
         int d = p1 - s1 + s2;
-        int scale = Math.max(6, s1 + p2 + 1);
+        int scale = Math.max(six, s1 + p2 + 1);
         int precision = d + scale;
 
   // Rules from
   // 
https://learn.microsoft.com/en-us/sql/t-sql/data-types/precision-scale-and-length-transact-sql
-        int bound = getMaxNumericPrecision() - 6;  // 32 in the MS 
documentation
+        // Rules reproduced here in case the web page goes away.
+        // Note that in SQL server getMaxNumericPrecision() == 38 and
+        // getMaxNumericScale() > 6.
+        // In multiplication and division operations, we need precision - 
scale places to store
+        // the integral part of the result. The scale might be reduced using 
the following rules:
+        //
+        // - The resulting scale is reduced to min(scale, 38 - 
(precision-scale))
+        //   if the integral part is less than 32, because it can't be greater 
than
+        //   38 - (precision-scale). The result might be rounded in this case.
+        // - The scale isn't changed if it's less than 6 and if the integral 
part
+        //   is greater than 32. In this case, an overflow error might be 
raised if
+        //   it can't fit into decimal(38, scale).
+        // - The scale is set to 6 if it's greater than 6 and if the integral 
part
+        //   is greater than 32. In this case, both the integral part and 
scale would be
+        //   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
         if (precision <= bound) {
           scale = Math.min(scale, getMaxNumericScale() - (precision - scale));
         } else {
           // precision > bound
-          scale = Math.min(6, scale);
+          scale = Math.min(six, scale);
         }
 
         precision = Math.min(precision, getMaxNumericPrecision());
         assert precision > 0;
+        assert scale <= getMaxNumericScale();
 
         RelDataType ret;
         ret = typeFactory.

Reply via email to