IGNITE-23141 Sql. Add execution test to verify numeric type coercion in binary comparison and arithmetic (#4382)

diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/BaseTypeCheckExecutionTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/BaseTypeCheckExecutionTest.java
new file mode 100644
index 0000000..af33a14
--- /dev/null
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/BaseTypeCheckExecutionTest.java
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.sql.engine.exec.coercion;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import org.apache.ignite.internal.sql.engine.InternalSqlRow;
+import org.apache.ignite.internal.sql.engine.framework.DataProvider;
+import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
+import org.apache.ignite.internal.sql.engine.framework.TestCluster;
+import org.apache.ignite.internal.sql.engine.framework.TestNode;
+import org.apache.ignite.internal.sql.engine.planner.datatypes.utils.TypePair;
+import org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
+import org.apache.ignite.internal.sql.engine.util.CursorUtils;
+import org.apache.ignite.internal.sql.engine.util.SqlTestUtils;
+import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
+import org.apache.ignite.internal.type.DecimalNativeType;
+import org.apache.ignite.internal.type.NativeType;
+import org.apache.ignite.internal.type.NativeTypes;
+import org.apache.ignite.internal.util.Pair;
+import org.apache.ignite.sql.ColumnMetadata;
+import org.apache.ignite.sql.ColumnType;
+import org.apache.ignite.sql.ResultSetMetadata;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.jetbrains.annotations.Nullable;
+
+/** Base class for check execution results of numeric operations. */
+class BaseTypeCheckExecutionTest extends BaseIgniteAbstractTest {
+    /** Data provider with reduced objets, helpful to avoid overflow on arithmetic operations. */
+    static DataProvider<Object[]> dataProviderReduced(TypePair typePair) {
+        Object val1 = generateReducedValueByType(typePair.first());
+        Object val2 = generateReducedValueByType(typePair.second());
+
+        return DataProvider.fromRow(new Object[]{0, val1, val2}, 1);
+    }
+
+    /** Data provider for multiplication operations. */
+    static DataProvider<Object[]> multDivDataProvider(TypePair typePair) {
+        Object val1 = generateReducedValueByType(typePair.first());
+        Object val2 = generateConstantValueByType(typePair.second());
+
+        return DataProvider.fromRow(new Object[]{0, val1, val2}, 1);
+    }
+
+    /** Data provider with constant second object. */
+    static DataProvider<Object[]> dataProviderStrict(TypePair typePair) {
+        Object val1 = SqlTestUtils.generateValueByType(typePair.first());
+        Object val2 = generateConstantValueByType(typePair.second(), "1");
+
+        return DataProvider.fromRow(new Object[]{0, val1, val2}, 1);
+    }
+
+    /** Data provider without any restrictions, call directly {@link SqlTestUtils#generateValueByType}. */
+    static DataProvider<Object[]> dataProvider(TypePair typePair) {
+        Object val1 = SqlTestUtils.generateValueByType(typePair.first());
+        Object val2 = SqlTestUtils.generateValueByType(typePair.second());
+
+        return DataProvider.fromRow(new Object[]{0, val1, val2}, 1);
+    }
+
+    private static @Nullable Object generateReducedValueByType(NativeType nativeType) {
+        ColumnType type = nativeType.spec().asColumnType();
+
+        switch (type) {
+            case INT8:
+                return (byte) (((byte) SqlTestUtils.generateValueByType(type, 0, 0)) / 2);
+            case INT16:
+                return (short) (((short) SqlTestUtils.generateValueByType(type, 0, 0)) / 2);
+            case INT32:
+                return ((int) SqlTestUtils.generateValueByType(type, 0, 0)) / 2;
+            case INT64:
+                return (((long) SqlTestUtils.generateValueByType(type, 0, 0)) / 2);
+            case FLOAT:
+            case DOUBLE:
+                return SqlTestUtils.generateValueByType(type, 0, 0);
+            case DECIMAL:
+                int scale = ((DecimalNativeType) nativeType).scale();
+                int precision = ((DecimalNativeType) nativeType).precision();
+                return ((BigDecimal) SqlTestUtils.generateValueByType(type, precision, scale))
+                        .divide(BigDecimal.valueOf(2), RoundingMode.HALF_DOWN).setScale(scale, RoundingMode.HALF_DOWN);
+            default:
+                throw new IllegalArgumentException("unsupported type " + type);
+        }
+    }
+
+    private static Object generateConstantValueByType(NativeType type, String numericBase) {
+        ColumnType type0 = type.spec().asColumnType();
+        switch (type0) {
+            case INT8:
+                return Byte.valueOf(numericBase);
+            case INT16:
+                return Short.valueOf(numericBase);
+            case INT32:
+                return Integer.valueOf(numericBase);
+            case INT64:
+                return Long.valueOf(numericBase);
+            case FLOAT:
+                return Float.valueOf(numericBase);
+            case DOUBLE:
+                return Double.valueOf(numericBase);
+            case DECIMAL:
+                int scale = ((DecimalNativeType) type).scale();
+                int precision = ((DecimalNativeType) type).precision();
+                assert precision >= scale : "unexpected precision/scale, precision=" + precision + ", scale=" + scale;
+
+                BigDecimal bd = new BigDecimal(numericBase);
+                return bd.setScale(scale, RoundingMode.UNNECESSARY);
+            default:
+                throw new AssertionError("Unexpected type: " + type0);
+        }
+    }
+
+    private static Object generateConstantValueByType(NativeType type) {
+        return generateConstantValueByType(type, "2");
+    }
+
+    static ClusterWrapper testCluster(TypePair typePair, DataProvider<Object[]> dataProvider) {
+        TestCluster cluster = TestBuilders.cluster().nodes("N1")
+                .addTable().name("T")
+                .addKeyColumn("id", NativeTypes.INT32)
+                .addColumn("C1", typePair.first())
+                .addColumn("C2", typePair.second())
+                .end()
+                .dataProvider("N1", "T", TestBuilders.tableScan(dataProvider))
+                .build();
+
+        return new ClusterWrapper(cluster);
+    }
+
+    static class ClusterWrapper implements AutoCloseable {
+        private final TestCluster cluster;
+
+        ClusterWrapper(TestCluster cluster) {
+            this.cluster = cluster;
+
+            cluster.start();
+        }
+
+        void process(String sql, Matcher<Object> resultMatcher) {
+            TestNode gatewayNode = cluster.node("N1");
+            QueryPlan plan = gatewayNode.prepare(sql);
+            ResultSetMetadata resultMeta = plan.metadata();
+            ColumnMetadata colMeta = resultMeta.columns().get(0);
+
+            for (InternalSqlRow row : CursorUtils.getAllFromCursor(gatewayNode.executePlan(plan))) {
+                assertNotNull(row);
+                assertNotNull(row.get(0), "Await not null object");
+                assertThat(new Pair<>(row.get(0), colMeta), resultMatcher);
+            }
+        }
+
+        @Override
+        public void close() throws Exception {
+            cluster.stop();
+        }
+    }
+
+    /** Return results matcher, compare return type, precision and scale with analyzed object. */
+    static Matcher<Object> checkReturnResult() {
+        return new BaseMatcher<>() {
+            private Object result;
+            private ColumnMetadata meta;
+            private int precision;
+            private int scale;
+
+            @Override
+            public boolean matches(Object actual) {
+                assert actual != null;
+
+                Pair<Object, ColumnMetadata> pair = (Pair<Object, ColumnMetadata>) actual;
+
+                result = pair.getFirst();
+                meta = pair.getSecond();
+
+                if (result instanceof BigDecimal) {
+                    precision = ((BigDecimal) result).precision();
+                    scale = ((BigDecimal) result).scale();
+                }
+
+                boolean checkPrecisionScale = (result.getClass() != Float.class)
+                        && (result.getClass() != Double.class)
+                        && (result.getClass() != Boolean.class);
+
+                boolean precisionScaleMatched = true;
+
+                if (checkPrecisionScale) {
+                    // Expected that precision and scale of return result is satisfy the return metadata boundaries.
+                    precisionScaleMatched = precision <= meta.precision() && scale <= meta.scale();
+                }
+
+                return meta.type().javaClass() == result.getClass() && precisionScaleMatched;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Column metadata: " + meta);
+            }
+
+            @Override
+            public void describeMismatch(Object item, Description description) {
+                description.appendText("Type: " + result.getClass() + ", precision=" + precision + ", scale=" + scale);
+            }
+        };
+    }
+}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/NumericBinaryOperationsExecutionTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/NumericBinaryOperationsExecutionTest.java
new file mode 100644
index 0000000..13ac23f
--- /dev/null
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/NumericBinaryOperationsExecutionTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.sql.engine.exec.coercion;
+
+import java.util.Set;
+import org.apache.ignite.internal.sql.engine.planner.datatypes.utils.NumericPair;
+import org.apache.ignite.internal.type.DecimalNativeType;
+import org.apache.ignite.internal.type.NativeType;
+import org.apache.ignite.internal.type.NativeTypes;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+/** Check execution and return results for numeric arithmetics. */
+public class NumericBinaryOperationsExecutionTest extends BaseTypeCheckExecutionTest {
+    private static final Set<NativeType> APPROXIMATE_NUMERIC_TYPES = Set.of(NativeTypes.DOUBLE, NativeTypes.FLOAT);
+
+    @ParameterizedTest
+    @EnumSource
+    public void sumOp(NumericPair typePair) throws Exception {
+        String sql = "SELECT c1 + c2 FROM t";
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProviderReduced(typePair))) {
+            testCluster.process(sql, checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void subtractOp(NumericPair typePair) throws Exception {
+        String sql = "SELECT c1 - c2 FROM t";
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProviderReduced(typePair))) {
+            testCluster.process(sql, checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void multOp(NumericPair typePair) throws Exception {
+        String sql = "SELECT c1 * c2 FROM t";
+        try (ClusterWrapper testCluster = testCluster(typePair, multDivDataProvider(typePair))) {
+            testCluster.process(sql, checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void divOp(NumericPair typePair) throws Exception {
+        String sql = "SELECT c1 / c2 FROM t";
+        Assumptions.assumeFalse(typePair.first() instanceof DecimalNativeType || typePair.second() instanceof DecimalNativeType,
+                "need to be fixed after: https://issues.apache.org/jira/browse/IGNITE-23171");
+
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProviderStrict(typePair))) {
+            testCluster.process(sql, checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void moduloOp(NumericPair typePair) throws Exception {
+        // Need to be fixed after: https://issues.apache.org/jira/browse/IGNITE-23349
+        if (APPROXIMATE_NUMERIC_TYPES.contains(typePair.first()) || APPROXIMATE_NUMERIC_TYPES.contains(typePair.second())) {
+            return;
+        }
+
+        String sql = "SELECT c1 % c2 FROM t";
+
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProvider(typePair))) {
+            testCluster.process(sql, checkReturnResult());
+        }
+    }
+}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/NumericComparisonExecutionTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/NumericComparisonExecutionTest.java
new file mode 100644
index 0000000..87aa9ad
--- /dev/null
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/coercion/NumericComparisonExecutionTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.sql.engine.exec.coercion;
+
+import org.apache.ignite.internal.sql.engine.planner.datatypes.utils.NumericPair;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+/** Check execution results for numeric comparisons. */
+public class NumericComparisonExecutionTest extends BaseTypeCheckExecutionTest {
+    @ParameterizedTest
+    @EnumSource
+    public void comparisonEq(NumericPair typePair) throws Exception {
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProvider(typePair))) {
+            testCluster.process("SELECT c1 = c2 FROM t", checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void comparisonLessEq(NumericPair typePair) throws Exception {
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProvider(typePair))) {
+            testCluster.process("SELECT c1 <= c2 FROM t", checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void comparisonGreatEq(NumericPair typePair) throws Exception {
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProvider(typePair))) {
+            testCluster.process("SELECT c1 >= c2 FROM t", checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void comparisonLess(NumericPair typePair) throws Exception {
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProvider(typePair))) {
+            testCluster.process("SELECT c1 < c2 FROM t", checkReturnResult());
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource
+    public void comparisonGreat(NumericPair typePair) throws Exception {
+        try (ClusterWrapper testCluster = testCluster(typePair, dataProvider(typePair))) {
+            testCluster.process("SELECT c1 < c2 FROM t", checkReturnResult());
+        }
+    }
+}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/BaseTypeCoercionTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/BaseTypeCoercionTest.java
index 92b1d27..0fc1eda 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/BaseTypeCoercionTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/BaseTypeCoercionTest.java
@@ -18,11 +18,11 @@
 package org.apache.ignite.internal.sql.engine.planner.datatypes;
 
 import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+import static org.apache.ignite.internal.sql.engine.util.TypeUtils.native2relationalType;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.instanceOf;
 
 import java.math.BigDecimal;
-import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -31,6 +31,7 @@
 import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.type.BasicSqlType;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
 import org.apache.ignite.internal.sql.engine.planner.AbstractPlannerTest;
@@ -43,7 +44,6 @@
 import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
 import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.apache.ignite.internal.sql.engine.util.SqlTestUtils;
-import org.apache.ignite.internal.sql.engine.util.TypeUtils;
 import org.apache.ignite.internal.type.DecimalNativeType;
 import org.apache.ignite.internal.type.NativeType;
 import org.apache.ignite.internal.type.NativeTypeSpec;
@@ -53,12 +53,11 @@
 import org.hamcrest.Matchers;
 import org.junit.jupiter.params.provider.Arguments;
 
-abstract class BaseTypeCoercionTest extends AbstractPlannerTest {
-
-    static Stream<Arguments> allNumericPairs() {
-        return Arrays.stream(NumericPair.values()).map(Arguments::of);
-    }
-
+/** Base class for testing types coercion. */
+public class BaseTypeCoercionTest extends AbstractPlannerTest {
+    /**
+     * Ensures that object mapping doesn't miss any type pair from {@link NumericPair}.
+     */
     static void checkIncludesAllNumericTypePairs(Stream<Arguments> args) {
         EnumSet<NumericPair> remainingPairs = EnumSet.allOf(NumericPair.class);
 
@@ -138,6 +137,33 @@
         };
     }
 
+    static Matcher<IgniteRel> operandsWithResultMatcher(Matcher<RexNode> first, Matcher<RexNode> second, Matcher<Object> result) {
+        return new BaseMatcher<>() {
+            @Override
+            public boolean matches(Object actual) {
+                RexNode comparison = ((ProjectableFilterableTableScan) actual).projects().get(0);
+
+                assertThat(comparison, instanceOf(RexCall.class));
+
+                RexCall comparisonCall = (RexCall) comparison;
+
+                RexNode leftOperand = comparisonCall.getOperands().get(0);
+                RexNode rightOperand = comparisonCall.getOperands().get(1);
+
+                assertThat(leftOperand, first);
+                assertThat(rightOperand, second);
+                assertThat(actual, result);
+
+                return true;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+
+            }
+        };
+    }
+
     /**
      * Creates a matcher to verify that given expression has expected return type, but it is not CAST operator.
      *
@@ -146,7 +172,7 @@
      */
     static Matcher<RexNode> ofTypeWithoutCast(NativeType type) {
         IgniteTypeFactory typeFactory = Commons.typeFactory();
-        RelDataType sqlType = TypeUtils.native2relationalType(typeFactory, type);
+        RelDataType sqlType = native2relationalType(typeFactory, type);
 
         return new BaseMatcher<>() {
             @Override
@@ -175,7 +201,7 @@
      */
     static Matcher<RexNode> castTo(NativeType type) {
         IgniteTypeFactory typeFactory = Commons.typeFactory();
-        RelDataType sqlType = TypeUtils.native2relationalType(typeFactory, type);
+        RelDataType sqlType = native2relationalType(typeFactory, type);
 
         return new BaseMatcher<>() {
             @Override
@@ -197,14 +223,92 @@
         };
     }
 
+    private static Matcher<Object> ofType(NativeType type) {
+        return new BaseMatcher<>() {
+            BasicSqlType expectedType;
+            BasicSqlType relRowType;
+
+            @Override
+            public boolean matches(Object actual) {
+                assert actual != null;
+
+                ProjectableFilterableTableScan scan = (ProjectableFilterableTableScan) actual;
+
+                RelDataType rowType = scan.getRowType();
+
+                assert rowType.getFieldList().size() == 1;
+
+                relRowType = (BasicSqlType) rowType.getFieldList().get(0).getType();
+
+                expectedType = (BasicSqlType) native2relationalType(Commons.typeFactory(), type);
+
+                return SqlTypeUtil.equalSansNullability(relRowType, expectedType);
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                if (expectedType != null && relRowType != null) {
+                    description.appendText("Expected type: " + expectedType + ", but found: " + relRowType);
+                }
+            }
+        };
+    }
+
     static TestCaseBuilder forTypePair(TypePair typePair) {
         return new TestCaseBuilder(typePair);
     }
 
+    static TestCaseBuilderEx forTypePairEx(TypePair typePair) {
+        return new TestCaseBuilderEx(typePair);
+    }
+
     /**
      * Not really a builder, but provides DSL-like API to describe test case.
      */
-    static class TestCaseBuilder {
+    static class TestCaseBuilderEx {
+        private final TypePair pair;
+        private Matcher<?> firstOpMatcher;
+        private Matcher<?> secondOpMatcher;
+
+        private TestCaseBuilderEx(TypePair pair) {
+            this.pair = pair;
+        }
+
+        TestCaseBuilderEx firstOpMatches(Matcher<?> operandMatcher) {
+            firstOpMatcher = operandMatcher;
+
+            return this;
+        }
+
+        TestCaseBuilderEx firstOpBeSame() {
+            firstOpMatcher = ofTypeWithoutCast(pair.first());
+
+            return this;
+        }
+
+        TestCaseBuilderEx secondOpMatches(Matcher<?> operandMatcher) {
+            secondOpMatcher = operandMatcher;
+            return this;
+        }
+
+        TestCaseBuilderEx secondOpBeSame() {
+            secondOpMatcher = ofTypeWithoutCast(pair.second());
+            return this;
+        }
+
+        Arguments resultWillBe(NativeType type) {
+            return Arguments.of(pair, firstOpMatcher, secondOpMatcher, ofType(type));
+        }
+
+        Arguments checkResult(NativeType type) {
+            return Arguments.of(pair, ofTypeWithoutCast(pair.first()), ofTypeWithoutCast(pair.second()), ofType(type));
+        }
+    }
+
+    /**
+     * Not really a builder, but provides DSL-like API to describe test case.
+     */
+    public static class TestCaseBuilder {
         private final TypePair pair;
         private Matcher<?> firstOpMatcher;
 
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericBinaryOperationsTypeCoercionTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericBinaryOperationsTypeCoercionTest.java
index e757227..c1ae2a3 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericBinaryOperationsTypeCoercionTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericBinaryOperationsTypeCoercionTest.java
@@ -24,6 +24,7 @@
 import org.apache.ignite.internal.sql.engine.planner.datatypes.utils.TypePair;
 import org.apache.ignite.internal.sql.engine.planner.datatypes.utils.Types;
 import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
+import org.apache.ignite.internal.type.NativeTypes;
 import org.hamcrest.Matcher;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -40,54 +41,69 @@
 
     // No any type changes for `addition` operation from planner perspective.
     @ParameterizedTest
-    @MethodSource("allNumericPairs")
-    public void additionOp(NumericPair pair) throws Exception {
-        IgniteSchema schema = createSchemaWithTwoColumnTable(pair.first(), pair.second());
+    @MethodSource("plusMinusArgs")
+    public void additionOp(
+            TypePair typePair,
+            Matcher<RexNode> firstOperandMatcher,
+            Matcher<RexNode> secondOperandMatcher,
+            Matcher<Object> resultsMatcher
+    ) throws Exception {
+        IgniteSchema schema = createSchemaWithTwoColumnTable(typePair.first(), typePair.second());
 
-        Matcher<RexNode> first = ofTypeWithoutCast(pair.first());
-        Matcher<RexNode> second = ofTypeWithoutCast(pair.second());
-
-        assertPlan("SELECT c1 + c2 FROM t", schema, operandMatcher(first, second)::matches, List.of());
-        assertPlan("SELECT c2 + c1 FROM t", schema, operandMatcher(second, first)::matches, List.of());
+        assertPlan("SELECT c1 + c2 FROM t", schema,
+                operandsWithResultMatcher(firstOperandMatcher, secondOperandMatcher, resultsMatcher)::matches, List.of());
+        assertPlan("SELECT c2 + c1 FROM t", schema,
+                operandsWithResultMatcher(secondOperandMatcher, firstOperandMatcher, resultsMatcher)::matches, List.of());
     }
 
     // No any type changes for `subtraction` operation from planner perspective.
     @ParameterizedTest
-    @MethodSource("allNumericPairs")
-    public void subtractionOp(NumericPair pair) throws Exception {
-        IgniteSchema schema = createSchemaWithTwoColumnTable(pair.first(), pair.second());
+    @MethodSource("plusMinusArgs")
+    public void subtractionOp(
+            TypePair typePair,
+            Matcher<RexNode> firstOperandMatcher,
+            Matcher<RexNode> secondOperandMatcher,
+            Matcher<Object> resultsMatcher
+    ) throws Exception {
+        IgniteSchema schema = createSchemaWithTwoColumnTable(typePair.first(), typePair.second());
 
-        Matcher<RexNode> first = ofTypeWithoutCast(pair.first());
-        Matcher<RexNode> second = ofTypeWithoutCast(pair.second());
-
-        assertPlan("SELECT c1 - c2 FROM t", schema, operandMatcher(first, second)::matches, List.of());
-        assertPlan("SELECT c2 - c1 FROM t", schema, operandMatcher(second, first)::matches, List.of());
+        assertPlan("SELECT c1 - c2 FROM t", schema,
+                operandsWithResultMatcher(firstOperandMatcher, secondOperandMatcher, resultsMatcher)::matches, List.of());
+        assertPlan("SELECT c2 - c1 FROM t", schema,
+                operandsWithResultMatcher(secondOperandMatcher, firstOperandMatcher, resultsMatcher)::matches, List.of());
     }
 
     // No any type changes for `division` operation from planner perspective.
     @ParameterizedTest
-    @MethodSource("allNumericPairs")
-    public void divisionOp(NumericPair pair) throws Exception {
-        IgniteSchema schema = createSchemaWithTwoColumnTable(pair.first(), pair.second());
+    @MethodSource("divArgs")
+    public void divisionOp(
+            TypePair typePair,
+            Matcher<RexNode> firstOperandMatcher,
+            Matcher<RexNode> secondOperandMatcher,
+            Matcher<Object> resultsMatcher
+    ) throws Exception {
+        IgniteSchema schema = createSchemaWithTwoColumnTable(typePair.first(), typePair.second());
 
-        Matcher<RexNode> first = ofTypeWithoutCast(pair.first());
-        Matcher<RexNode> second = ofTypeWithoutCast(pair.second());
-
-        assertPlan("SELECT c1 / c2 FROM t", schema, operandMatcher(first, second)::matches, List.of());
-        assertPlan("SELECT c2 / c1 FROM t", schema, operandMatcher(second, first)::matches, List.of());
+        assertPlan("SELECT c1 / c2 FROM t", schema,
+                operandsWithResultMatcher(firstOperandMatcher, secondOperandMatcher, resultsMatcher)::matches, List.of());
+        assertPlan("SELECT c2 / c1 FROM t", schema, operandMatcher(secondOperandMatcher, firstOperandMatcher)::matches, List.of());
     }
 
     // No any type changes for `multiplication` operation from planner perspective.
     @ParameterizedTest
-    @MethodSource("allNumericPairs")
-    public void multiplicationOp(NumericPair pair) throws Exception {
-        IgniteSchema schema = createSchemaWithTwoColumnTable(pair.first(), pair.second());
+    @MethodSource("multArgs")
+    public void multiplicationOp(
+            TypePair typePair,
+            Matcher<RexNode> firstOperandMatcher,
+            Matcher<RexNode> secondOperandMatcher,
+            Matcher<Object> resultsMatcher
+    ) throws Exception {
+        IgniteSchema schema = createSchemaWithTwoColumnTable(typePair.first(), typePair.second());
 
-        Matcher<RexNode> first = ofTypeWithoutCast(pair.first());
-        Matcher<RexNode> second = ofTypeWithoutCast(pair.second());
-
-        assertPlan("SELECT c1 * c2 FROM t", schema, operandMatcher(first, second)::matches, List.of());
-        assertPlan("SELECT c2 * c1 FROM t", schema, operandMatcher(second, first)::matches, List.of());
+        assertPlan("SELECT c1 * c2 FROM t", schema,
+                operandsWithResultMatcher(firstOperandMatcher, secondOperandMatcher, resultsMatcher)::matches, List.of());
+        assertPlan("SELECT c2 * c1 FROM t", schema,
+                operandsWithResultMatcher(secondOperandMatcher, firstOperandMatcher, resultsMatcher)::matches, List.of());
     }
 
     // Have the following casts for modulo operation:
@@ -99,516 +115,1059 @@
     public void moduloOp(
             TypePair typePair,
             Matcher<RexNode> firstOperandMatcher,
-            Matcher<RexNode> secondOperandMatcher
+            Matcher<RexNode> secondOperandMatcher,
+            Matcher<Object> resultsMatcher
     ) throws Exception {
         IgniteSchema schema = createSchemaWithTwoColumnTable(typePair.first(), typePair.second());
 
-        assertPlan("SELECT c1 % c2 FROM t", schema, operandMatcher(firstOperandMatcher, secondOperandMatcher)::matches, List.of());
-        assertPlan("SELECT c2 % c1 FROM t", schema, operandMatcher(secondOperandMatcher, firstOperandMatcher)::matches, List.of());
+        assertPlan("SELECT c1 % c2 FROM t", schema,
+                operandsWithResultMatcher(firstOperandMatcher, secondOperandMatcher, resultsMatcher)::matches, List.of());
+        assertPlan("SELECT c2 % c1 FROM t", schema,
+                operandMatcher(secondOperandMatcher, firstOperandMatcher)::matches, List.of());
     }
 
     /**
      * This test ensures that {@link #moduloArgs()} doesn't miss any type pair from {@link NumericPair}.
      */
     @Test
-    void moduloArgsIncludesAllTypePairs() {
+    void checkAllTypePairs() {
         checkIncludesAllNumericTypePairs(moduloArgs());
+        checkIncludesAllNumericTypePairs(plusMinusArgs());
+        checkIncludesAllNumericTypePairs(multArgs());
+        checkIncludesAllNumericTypePairs(divArgs());
     }
 
     private static Stream<Arguments> moduloArgs() {
         return Stream.of(
-                forTypePair(NumericPair.TINYINT_TINYINT)
+                forTypePairEx(NumericPair.TINYINT_TINYINT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT8),
 
-                forTypePair(NumericPair.TINYINT_SMALLINT)
+                forTypePairEx(NumericPair.TINYINT_SMALLINT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT16),
 
-                forTypePair(NumericPair.TINYINT_INT)
+                forTypePairEx(NumericPair.TINYINT_INT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT32),
 
-                forTypePair(NumericPair.TINYINT_BIGINT)
+                forTypePairEx(NumericPair.TINYINT_BIGINT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT64),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_1_0)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_1_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_1_0),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_2_1)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_4_3)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_4_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_2_0)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_0),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_3_1)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_5_3)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_5_0)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_0),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_6_1)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_1),
 
-                forTypePair(NumericPair.TINYINT_DECIMAL_8_3)
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_6_3),
 
-                forTypePair(NumericPair.TINYINT_REAL)
+                forTypePairEx(NumericPair.TINYINT_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_10_7),
 
-                forTypePair(NumericPair.TINYINT_DOUBLE)
+                forTypePairEx(NumericPair.TINYINT_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_18_15),
 
 
-                forTypePair(NumericPair.SMALLINT_SMALLINT)
+                forTypePairEx(NumericPair.SMALLINT_SMALLINT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT16),
 
-                forTypePair(NumericPair.SMALLINT_INT)
+                forTypePairEx(NumericPair.SMALLINT_INT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT32),
 
-                forTypePair(NumericPair.SMALLINT_BIGINT)
+                forTypePairEx(NumericPair.SMALLINT_BIGINT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT64),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_1_0)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_1_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_1_0),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_2_1)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_4_3)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_4_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_2_0)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_0),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_3_1)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_5_3)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_5_0)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_0),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_6_1)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_6_1),
 
-                forTypePair(NumericPair.SMALLINT_DECIMAL_8_3)
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_8_3),
 
-                forTypePair(NumericPair.SMALLINT_REAL)
+                forTypePairEx(NumericPair.SMALLINT_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_12_7),
 
-                forTypePair(NumericPair.SMALLINT_DOUBLE)
+                forTypePairEx(NumericPair.SMALLINT_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_20_15),
 
 
-                forTypePair(NumericPair.INT_INT)
+                forTypePairEx(NumericPair.INT_INT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT32),
 
-                forTypePair(NumericPair.INT_BIGINT)
+                forTypePairEx(NumericPair.INT_BIGINT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT64),
 
-                forTypePair(NumericPair.INT_DECIMAL_1_0)
+                forTypePairEx(NumericPair.INT_DECIMAL_1_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_1_0),
 
-                forTypePair(NumericPair.INT_DECIMAL_2_1)
+                forTypePairEx(NumericPair.INT_DECIMAL_2_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.INT_DECIMAL_4_3)
+                forTypePairEx(NumericPair.INT_DECIMAL_4_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.INT_DECIMAL_2_0)
+                forTypePairEx(NumericPair.INT_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_0),
 
-                forTypePair(NumericPair.INT_DECIMAL_3_1)
+                forTypePairEx(NumericPair.INT_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.INT_DECIMAL_5_3)
+                forTypePairEx(NumericPair.INT_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.INT_DECIMAL_5_0)
+                forTypePairEx(NumericPair.INT_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_0),
 
-                forTypePair(NumericPair.INT_DECIMAL_6_1)
+                forTypePairEx(NumericPair.INT_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_6_1),
 
-                forTypePair(NumericPair.INT_DECIMAL_8_3)
+                forTypePairEx(NumericPair.INT_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_8_3),
 
-                forTypePair(NumericPair.INT_REAL)
+                forTypePairEx(NumericPair.INT_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_14_7),
 
-                forTypePair(NumericPair.INT_DOUBLE)
+                forTypePairEx(NumericPair.INT_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_25_15),
 
 
-                forTypePair(NumericPair.BIGINT_BIGINT)
+                forTypePairEx(NumericPair.BIGINT_BIGINT)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(NativeTypes.INT64),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_1_0)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_1_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_1_0),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_2_1)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_4_3)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_4_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_2_0)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_0),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_3_1)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_5_3)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_5_0)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_0),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_6_1)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_6_1),
 
-                forTypePair(NumericPair.BIGINT_DECIMAL_8_3)
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_8_3),
 
-                forTypePair(NumericPair.BIGINT_REAL)
+                forTypePairEx(NumericPair.BIGINT_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_14_7),
 
-                forTypePair(NumericPair.BIGINT_DOUBLE)
+                forTypePairEx(NumericPair.BIGINT_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_30_15),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_1_0)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_1_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_1_0),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_2_1)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_4_3)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_4_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_2_0)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_0),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_3_1)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_5_3)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_5_0)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_0),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_1_0_REAL)
+                forTypePairEx(NumericPair.DECIMAL_1_0_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_8_7),
 
-                forTypePair(NumericPair.DECIMAL_1_0_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_1_0_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_16_15),
 
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_2_1)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_4_3)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_4_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_2_0)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_3_1)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_5_3)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_5_0)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_1),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_2_1_REAL)
+                forTypePairEx(NumericPair.DECIMAL_2_1_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_8_7),
 
-                forTypePair(NumericPair.DECIMAL_2_1_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_2_1_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_16_15),
 
 
-                forTypePair(NumericPair.DECIMAL_4_3_DECIMAL_4_3)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_4_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_4_3_DECIMAL_2_0)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_4_3_DECIMAL_3_1)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_4_3_DECIMAL_5_3)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_4_3_DECIMAL_5_0)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_4_3_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_4_3_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_4_3),
 
-                forTypePair(NumericPair.DECIMAL_4_3_REAL)
+                forTypePairEx(NumericPair.DECIMAL_4_3_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_8_7),
 
-                forTypePair(NumericPair.DECIMAL_4_3_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_4_3_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_16_15),
 
 
-                forTypePair(NumericPair.DECIMAL_2_0_DECIMAL_2_0)
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_2_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_2_0),
 
-                forTypePair(NumericPair.DECIMAL_2_0_DECIMAL_3_1)
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.DECIMAL_2_0_DECIMAL_5_3)
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_2_0_DECIMAL_5_0)
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_0),
 
-                forTypePair(NumericPair.DECIMAL_2_0_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.DECIMAL_2_0_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_2_0_REAL)
+                forTypePairEx(NumericPair.DECIMAL_2_0_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_9_7),
 
-                forTypePair(NumericPair.DECIMAL_2_0_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_2_0_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_17_15),
 
 
-                forTypePair(NumericPair.DECIMAL_3_1_DECIMAL_3_1)
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_3_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.DECIMAL_3_1_DECIMAL_5_3)
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_3_1_DECIMAL_5_0)
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.DECIMAL_3_1_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_3_1),
 
-                forTypePair(NumericPair.DECIMAL_3_1_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_3_1_REAL)
+                forTypePairEx(NumericPair.DECIMAL_3_1_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_9_7),
 
-                forTypePair(NumericPair.DECIMAL_3_1_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_3_1_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_17_15),
 
 
-                forTypePair(NumericPair.DECIMAL_5_3_DECIMAL_5_3)
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_5_3_DECIMAL_5_0)
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_5_3_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_5_3_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_3),
 
-                forTypePair(NumericPair.DECIMAL_5_3_REAL)
+                forTypePairEx(NumericPair.DECIMAL_5_3_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_9_7),
 
-                forTypePair(NumericPair.DECIMAL_5_3_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_5_3_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_17_15),
 
 
-                forTypePair(NumericPair.DECIMAL_5_0_DECIMAL_5_0)
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_5_0)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_5_0),
 
-                forTypePair(NumericPair.DECIMAL_5_0_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_6_1),
 
-                forTypePair(NumericPair.DECIMAL_5_0_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_8_3),
 
-                forTypePair(NumericPair.DECIMAL_5_0_REAL)
+                forTypePairEx(NumericPair.DECIMAL_5_0_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_12_7),
 
-                forTypePair(NumericPair.DECIMAL_5_0_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_5_0_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_20_15),
 
 
-                forTypePair(NumericPair.DECIMAL_6_1_DECIMAL_6_1)
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_6_1)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_6_1),
 
-                forTypePair(NumericPair.DECIMAL_6_1_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_8_3),
 
-                forTypePair(NumericPair.DECIMAL_6_1_REAL)
+                forTypePairEx(NumericPair.DECIMAL_6_1_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_12_7),
 
-                forTypePair(NumericPair.DECIMAL_6_1_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_6_1_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_20_15),
 
 
-                forTypePair(NumericPair.DECIMAL_8_3_DECIMAL_8_3)
+                forTypePairEx(NumericPair.DECIMAL_8_3_DECIMAL_8_3)
                         .firstOpBeSame()
-                        .secondOpBeSame(),
+                        .secondOpBeSame()
+                        .resultWillBe(Types.DECIMAL_8_3),
 
-                forTypePair(NumericPair.DECIMAL_8_3_REAL)
+                forTypePairEx(NumericPair.DECIMAL_8_3_REAL)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_14_7)),
+                        .secondOpMatches(castTo(Types.DECIMAL_14_7))
+                        .resultWillBe(Types.DECIMAL_12_7),
 
-                forTypePair(NumericPair.DECIMAL_8_3_DOUBLE)
+                forTypePairEx(NumericPair.DECIMAL_8_3_DOUBLE)
                         .firstOpBeSame()
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_20_15),
 
 
-                forTypePair(NumericPair.REAL_REAL)
+                forTypePairEx(NumericPair.REAL_REAL)
                         .firstOpMatches(castTo(Types.DECIMAL_14_7))
-                        .secondOpMatches(castTo((Types.DECIMAL_14_7))),
+                        .secondOpMatches(castTo((Types.DECIMAL_14_7)))
+                        .resultWillBe(Types.DECIMAL_14_7),
 
-                forTypePair(NumericPair.REAL_DOUBLE)
+                forTypePairEx(NumericPair.REAL_DOUBLE)
                         .firstOpMatches(castTo(Types.DECIMAL_14_7))
-                        .secondOpMatches(castTo(Types.DECIMAL_30_15)),
+                        .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_22_15),
 
 
-                forTypePair(NumericPair.DOUBLE_DOUBLE)
+                forTypePairEx(NumericPair.DOUBLE_DOUBLE)
                         .firstOpMatches(castTo(Types.DECIMAL_30_15))
                         .secondOpMatches(castTo(Types.DECIMAL_30_15))
+                        .resultWillBe(Types.DECIMAL_30_15)
+        );
+    }
+
+    private static Stream<Arguments> plusMinusArgs() {
+        return Stream.of(
+                forTypePairEx(NumericPair.TINYINT_TINYINT).checkResult(NativeTypes.INT8),
+                forTypePairEx(NumericPair.TINYINT_SMALLINT).checkResult(NativeTypes.INT16),
+                forTypePairEx(NumericPair.TINYINT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.TINYINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_1_0).checkResult(Types.DECIMAL_4_0),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_1).checkResult(Types.DECIMAL_5_1),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_4_3).checkResult(Types.DECIMAL_7_3),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_0).checkResult(Types.DECIMAL_4_0),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_3_1).checkResult(Types.DECIMAL_5_1),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_3).checkResult(Types.DECIMAL_7_3),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.TINYINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.TINYINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.SMALLINT_SMALLINT).checkResult(NativeTypes.INT16),
+                forTypePairEx(NumericPair.SMALLINT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.SMALLINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_1_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_4_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_3_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.SMALLINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.SMALLINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.INT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.INT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.INT_DECIMAL_1_0).checkResult(Types.DECIMAL_11_0),
+                forTypePairEx(NumericPair.INT_DECIMAL_2_1).checkResult(Types.DECIMAL_12_1),
+                forTypePairEx(NumericPair.INT_DECIMAL_4_3).checkResult(Types.DECIMAL_14_3),
+                forTypePairEx(NumericPair.INT_DECIMAL_2_0).checkResult(Types.DECIMAL_11_0),
+                forTypePairEx(NumericPair.INT_DECIMAL_3_1).checkResult(Types.DECIMAL_12_1),
+                forTypePairEx(NumericPair.INT_DECIMAL_5_3).checkResult(Types.DECIMAL_14_3),
+                forTypePairEx(NumericPair.INT_DECIMAL_5_0).checkResult(Types.DECIMAL_11_0),
+                forTypePairEx(NumericPair.INT_DECIMAL_6_1).checkResult(Types.DECIMAL_12_1),
+                forTypePairEx(NumericPair.INT_DECIMAL_8_3).checkResult(Types.DECIMAL_14_3),
+                forTypePairEx(NumericPair.INT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.INT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.BIGINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_1_0).checkResult(Types.DECIMAL_20_0),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_1).checkResult(Types.DECIMAL_21_1),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_4_3).checkResult(Types.DECIMAL_23_3),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_0).checkResult(Types.DECIMAL_20_0),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_3_1).checkResult(Types.DECIMAL_21_1),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_3).checkResult(Types.DECIMAL_23_3),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_0).checkResult(Types.DECIMAL_20_0),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_6_1).checkResult(Types.DECIMAL_21_1),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_8_3).checkResult(Types.DECIMAL_23_3),
+                forTypePairEx(NumericPair.BIGINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.BIGINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_1_0).checkResult(Types.DECIMAL_2_0),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_1).checkResult(Types.DECIMAL_3_1),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_4_3).checkResult(Types.DECIMAL_5_3),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_0).checkResult(Types.DECIMAL_3_0),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_3_1).checkResult(Types.DECIMAL_4_1),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_3).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_1_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_1).checkResult(Types.DECIMAL_3_1),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_4_3).checkResult(Types.DECIMAL_5_3),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_0).checkResult(Types.DECIMAL_4_1),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_3_1).checkResult(Types.DECIMAL_4_1),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_3).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_0).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_2_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_4_3).checkResult(Types.DECIMAL_5_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_2_0).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_3_1).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_3).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_0).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_6_1).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_2_0).checkResult(Types.DECIMAL_3_0),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_3_1).checkResult(Types.DECIMAL_4_1),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_3).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_2_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_3_1).checkResult(Types.DECIMAL_4_1),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_3).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_0).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_3_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_3).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_0).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_6_1).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_5_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_5_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_5_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_6_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_6_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_8_3_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_8_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_8_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.REAL_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.REAL_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DOUBLE_DOUBLE).checkResult(NativeTypes.DOUBLE)
+        );
+    }
+
+    private static Stream<Arguments> multArgs() {
+        return Stream.of(
+                forTypePairEx(NumericPair.TINYINT_TINYINT).checkResult(NativeTypes.INT8),
+                forTypePairEx(NumericPair.TINYINT_SMALLINT).checkResult(NativeTypes.INT16),
+                forTypePairEx(NumericPair.TINYINT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.TINYINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_1_0).checkResult(Types.DECIMAL_4_0),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_1).checkResult(Types.DECIMAL_5_1),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_4_3).checkResult(Types.DECIMAL_7_3),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_0).checkResult(Types.DECIMAL_5_0),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_3_1).checkResult(Types.DECIMAL_6_1),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_3).checkResult(Types.DECIMAL_8_3),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_0).checkResult(Types.DECIMAL_8_0),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_6_1).checkResult(Types.DECIMAL_9_1),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_8_3).checkResult(Types.DECIMAL_11_3),
+                forTypePairEx(NumericPair.TINYINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.TINYINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.SMALLINT_SMALLINT).checkResult(NativeTypes.INT16),
+                forTypePairEx(NumericPair.SMALLINT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.SMALLINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_1_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_4_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_0).checkResult(Types.DECIMAL_7_0),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_3_1).checkResult(Types.DECIMAL_8_1),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_3).checkResult(Types.DECIMAL_10_3),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_0).checkResult(Types.DECIMAL_10_0),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_6_1).checkResult(Types.DECIMAL_11_1),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_8_3).checkResult(Types.DECIMAL_13_3),
+                forTypePairEx(NumericPair.SMALLINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.SMALLINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.INT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.INT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.INT_DECIMAL_1_0).checkResult(Types.DECIMAL_11_0),
+                forTypePairEx(NumericPair.INT_DECIMAL_2_1).checkResult(Types.DECIMAL_12_1),
+                forTypePairEx(NumericPair.INT_DECIMAL_4_3).checkResult(Types.DECIMAL_14_3),
+                forTypePairEx(NumericPair.INT_DECIMAL_2_0).checkResult(Types.DECIMAL_12_0),
+                forTypePairEx(NumericPair.INT_DECIMAL_3_1).checkResult(Types.DECIMAL_13_1),
+                forTypePairEx(NumericPair.INT_DECIMAL_5_3).checkResult(Types.DECIMAL_15_3),
+                forTypePairEx(NumericPair.INT_DECIMAL_5_0).checkResult(Types.DECIMAL_15_0),
+                forTypePairEx(NumericPair.INT_DECIMAL_6_1).checkResult(Types.DECIMAL_16_1),
+                forTypePairEx(NumericPair.INT_DECIMAL_8_3).checkResult(Types.DECIMAL_18_3),
+                forTypePairEx(NumericPair.INT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.INT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.BIGINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_1_0).checkResult(Types.DECIMAL_20_0),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_1).checkResult(Types.DECIMAL_21_1),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_4_3).checkResult(Types.DECIMAL_23_3),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_0).checkResult(Types.DECIMAL_21_0),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_3_1).checkResult(Types.DECIMAL_22_1),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_3).checkResult(Types.DECIMAL_24_3),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_0).checkResult(Types.DECIMAL_24_0),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_6_1).checkResult(Types.DECIMAL_25_1),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_8_3).checkResult(Types.DECIMAL_27_3),
+                forTypePairEx(NumericPair.BIGINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.BIGINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_1_0).checkResult(Types.DECIMAL_2_0),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_1).checkResult(Types.DECIMAL_3_1),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_4_3).checkResult(Types.DECIMAL_5_3),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_0).checkResult(Types.DECIMAL_3_0),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_3_1).checkResult(Types.DECIMAL_4_1),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_3).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_0).checkResult(Types.DECIMAL_6_0),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_6_1).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_8_3).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_1_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_1).checkResult(Types.DECIMAL_4_2),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_4_3).checkResult(Types.DECIMAL_6_4),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_0).checkResult(Types.DECIMAL_4_1),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_3_1).checkResult(Types.DECIMAL_5_2),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_3).checkResult(Types.DECIMAL_7_4),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_0).checkResult(Types.DECIMAL_7_1),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_6_1).checkResult(Types.DECIMAL_8_2),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_8_3).checkResult(Types.DECIMAL_10_4),
+                forTypePairEx(NumericPair.DECIMAL_2_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_4_3).checkResult(Types.DECIMAL_8_6),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_2_0).checkResult(Types.DECIMAL_6_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_3_1).checkResult(Types.DECIMAL_7_4),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_3).checkResult(Types.DECIMAL_9_6),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_0).checkResult(Types.DECIMAL_9_3),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_6_1).checkResult(Types.DECIMAL_10_4),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_8_3).checkResult(Types.DECIMAL_12_6),
+                forTypePairEx(NumericPair.DECIMAL_4_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_2_0).checkResult(Types.DECIMAL_4_0),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_3_1).checkResult(Types.DECIMAL_5_1),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_3).checkResult(Types.DECIMAL_7_3),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_0).checkResult(Types.DECIMAL_7_0),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_6_1).checkResult(Types.DECIMAL_8_1),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_8_3).checkResult(Types.DECIMAL_10_3),
+                forTypePairEx(NumericPair.DECIMAL_2_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_3_1).checkResult(Types.DECIMAL_6_2),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_3).checkResult(Types.DECIMAL_8_4),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_0).checkResult(Types.DECIMAL_8_1),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_6_1).checkResult(Types.DECIMAL_9_2),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_8_3).checkResult(Types.DECIMAL_11_4),
+                forTypePairEx(NumericPair.DECIMAL_3_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_3).checkResult(Types.DECIMAL_10_6),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_0).checkResult(Types.DECIMAL_10_3),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_6_1).checkResult(Types.DECIMAL_11_4),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_8_3).checkResult(Types.DECIMAL_13_6),
+                forTypePairEx(NumericPair.DECIMAL_5_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_5_0).checkResult(Types.DECIMAL_10_0),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_6_1).checkResult(Types.DECIMAL_11_1),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_8_3).checkResult(Types.DECIMAL_13_3),
+                forTypePairEx(NumericPair.DECIMAL_5_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_6_1).checkResult(Types.DECIMAL_12_2),
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_8_3).checkResult(Types.DECIMAL_14_4),
+                forTypePairEx(NumericPair.DECIMAL_6_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_6_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_8_3_DECIMAL_8_3).checkResult(Types.DECIMAL_16_6),
+                forTypePairEx(NumericPair.DECIMAL_8_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_8_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.REAL_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.REAL_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DOUBLE_DOUBLE).checkResult(NativeTypes.DOUBLE)
+        );
+    }
+
+    private static Stream<Arguments> divArgs() {
+        return Stream.of(
+                forTypePairEx(NumericPair.TINYINT_TINYINT).checkResult(NativeTypes.INT8),
+                forTypePairEx(NumericPair.TINYINT_SMALLINT).checkResult(NativeTypes.INT16),
+                forTypePairEx(NumericPair.TINYINT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.TINYINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_1_0).checkResult(Types.DECIMAL_9_6),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_1).checkResult(Types.DECIMAL_10_6),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_4_3).checkResult(Types.DECIMAL_12_6),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_2_0).checkResult(Types.DECIMAL_9_6),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_3_1).checkResult(Types.DECIMAL_10_6),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_3).checkResult(Types.DECIMAL_12_6),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_5_0).checkResult(Types.DECIMAL_9_6),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_6_1).checkResult(Types.DECIMAL_11_7),
+                forTypePairEx(NumericPair.TINYINT_DECIMAL_8_3).checkResult(Types.DECIMAL_15_9),
+                forTypePairEx(NumericPair.TINYINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.TINYINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.SMALLINT_SMALLINT).checkResult(NativeTypes.INT16),
+                forTypePairEx(NumericPair.SMALLINT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.SMALLINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_1_0).checkResult(Types.DECIMAL_11_6),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_1).checkResult(Types.DECIMAL_12_6),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_4_3).checkResult(Types.DECIMAL_14_6),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_2_0).checkResult(Types.DECIMAL_11_6),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_3_1).checkResult(Types.DECIMAL_12_6),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_3).checkResult(Types.DECIMAL_14_6),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_5_0).checkResult(Types.DECIMAL_11_6),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_6_1).checkResult(Types.DECIMAL_13_7),
+                forTypePairEx(NumericPair.SMALLINT_DECIMAL_8_3).checkResult(Types.DECIMAL_17_9),
+                forTypePairEx(NumericPair.SMALLINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.SMALLINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.INT_INT).checkResult(NativeTypes.INT32),
+                forTypePairEx(NumericPair.INT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.INT_DECIMAL_1_0).checkResult(Types.DECIMAL_16_6),
+                forTypePairEx(NumericPair.INT_DECIMAL_2_1).checkResult(Types.DECIMAL_17_6),
+                forTypePairEx(NumericPair.INT_DECIMAL_4_3).checkResult(Types.DECIMAL_19_6),
+                forTypePairEx(NumericPair.INT_DECIMAL_2_0).checkResult(Types.DECIMAL_16_6),
+                forTypePairEx(NumericPair.INT_DECIMAL_3_1).checkResult(Types.DECIMAL_17_6),
+                forTypePairEx(NumericPair.INT_DECIMAL_5_3).checkResult(Types.DECIMAL_19_6),
+                forTypePairEx(NumericPair.INT_DECIMAL_5_0).checkResult(Types.DECIMAL_16_6),
+                forTypePairEx(NumericPair.INT_DECIMAL_6_1).checkResult(Types.DECIMAL_18_7),
+                forTypePairEx(NumericPair.INT_DECIMAL_8_3).checkResult(Types.DECIMAL_22_9),
+                forTypePairEx(NumericPair.INT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.INT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.BIGINT_BIGINT).checkResult(NativeTypes.INT64),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_1_0).checkResult(Types.DECIMAL_25_6),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_1).checkResult(Types.DECIMAL_26_6),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_4_3).checkResult(Types.DECIMAL_28_6),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_2_0).checkResult(Types.DECIMAL_25_6),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_3_1).checkResult(Types.DECIMAL_26_6),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_3).checkResult(Types.DECIMAL_28_6),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_5_0).checkResult(Types.DECIMAL_25_6),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_6_1).checkResult(Types.DECIMAL_27_7),
+                forTypePairEx(NumericPair.BIGINT_DECIMAL_8_3).checkResult(Types.DECIMAL_31_9),
+                forTypePairEx(NumericPair.BIGINT_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.BIGINT_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_1_0).checkResult(Types.DECIMAL_7_6),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_1).checkResult(Types.DECIMAL_8_6),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_4_3).checkResult(Types.DECIMAL_10_6),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_2_0).checkResult(Types.DECIMAL_7_6),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_3_1).checkResult(Types.DECIMAL_8_6),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_3).checkResult(Types.DECIMAL_10_6),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_5_0).checkResult(Types.DECIMAL_7_6),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_6_1).checkResult(Types.DECIMAL_9_7),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DECIMAL_8_3).checkResult(Types.DECIMAL_13_9),
+                forTypePairEx(NumericPair.DECIMAL_1_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_1_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_1).checkResult(Types.DECIMAL_8_6),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_4_3).checkResult(Types.DECIMAL_10_6),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_2_0).checkResult(Types.DECIMAL_7_6),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_3_1).checkResult(Types.DECIMAL_8_6),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_3).checkResult(Types.DECIMAL_11_7),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_5_0).checkResult(Types.DECIMAL_8_7),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_6_1).checkResult(Types.DECIMAL_10_8),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DECIMAL_8_3).checkResult(Types.DECIMAL_14_10),
+                forTypePairEx(NumericPair.DECIMAL_2_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_2_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_4_3).checkResult(Types.DECIMAL_12_8),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_2_0).checkResult(Types.DECIMAL_7_6),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_3_1).checkResult(Types.DECIMAL_9_7),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_3).checkResult(Types.DECIMAL_13_9),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_5_0).checkResult(Types.DECIMAL_10_9),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_6_1).checkResult(Types.DECIMAL_12_10),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DECIMAL_8_3).checkResult(Types.DECIMAL_16_12),
+                forTypePairEx(NumericPair.DECIMAL_4_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_4_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_2_0).checkResult(Types.DECIMAL_8_6),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_3_1).checkResult(Types.DECIMAL_9_6),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_3).checkResult(Types.DECIMAL_11_6),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_5_0).checkResult(Types.DECIMAL_8_6),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_6_1).checkResult(Types.DECIMAL_10_7),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DECIMAL_8_3).checkResult(Types.DECIMAL_14_9),
+                forTypePairEx(NumericPair.DECIMAL_2_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_2_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_3_1).checkResult(Types.DECIMAL_9_6),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_3).checkResult(Types.DECIMAL_12_7),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_5_0).checkResult(Types.DECIMAL_9_7),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_6_1).checkResult(Types.DECIMAL_11_8),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DECIMAL_8_3).checkResult(Types.DECIMAL_15_10),
+                forTypePairEx(NumericPair.DECIMAL_3_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_3_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_3).checkResult(Types.DECIMAL_14_9),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_5_0).checkResult(Types.DECIMAL_11_9),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_6_1).checkResult(Types.DECIMAL_13_10),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DECIMAL_8_3).checkResult(Types.DECIMAL_17_12),
+                forTypePairEx(NumericPair.DECIMAL_5_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_5_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_5_0).checkResult(Types.DECIMAL_11_6),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_6_1).checkResult(Types.DECIMAL_13_7),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DECIMAL_8_3).checkResult(Types.DECIMAL_17_9),
+                forTypePairEx(NumericPair.DECIMAL_5_0_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_5_0_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_6_1).checkResult(Types.DECIMAL_14_8),
+                forTypePairEx(NumericPair.DECIMAL_6_1_DECIMAL_8_3).checkResult(Types.DECIMAL_18_10),
+                forTypePairEx(NumericPair.DECIMAL_6_1_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_6_1_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DECIMAL_8_3_DECIMAL_8_3).checkResult(Types.DECIMAL_20_12),
+                forTypePairEx(NumericPair.DECIMAL_8_3_REAL).checkResult(NativeTypes.DOUBLE),
+                forTypePairEx(NumericPair.DECIMAL_8_3_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.REAL_REAL).checkResult(NativeTypes.FLOAT),
+                forTypePairEx(NumericPair.REAL_DOUBLE).checkResult(NativeTypes.DOUBLE),
+
+                forTypePairEx(NumericPair.DOUBLE_DOUBLE).checkResult(NativeTypes.DOUBLE)
         );
     }
 }
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/utils/Types.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/utils/Types.java
index 1dba339..3433656 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/utils/Types.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/utils/Types.java
@@ -29,41 +29,151 @@
 public final class Types {
 
     public static final NativeType DECIMAL_1_0 = NativeTypes.decimalOf(1, 0);
-    public static final NativeType DECIMAL_2_1 = NativeTypes.decimalOf(2, 1);
-    public static final NativeType DECIMAL_4_3 = NativeTypes.decimalOf(4, 3);
 
     public static final NativeType DECIMAL_2_0 = NativeTypes.decimalOf(2, 0);
-    public static final NativeType DECIMAL_3_1 = NativeTypes.decimalOf(3, 1);
-    public static final NativeType DECIMAL_4_2 = NativeTypes.decimalOf(4, 2);
-    public static final NativeType DECIMAL_5_3 = NativeTypes.decimalOf(5, 3);
-    public static final NativeType DECIMAL_18_16 = NativeTypes.decimalOf(18, 16);
-    public static final NativeType DECIMAL_20_18 = NativeTypes.decimalOf(20, 18);
+    public static final NativeType DECIMAL_2_1 = NativeTypes.decimalOf(2, 1);
 
     public static final NativeType DECIMAL_3_0 = NativeTypes.decimalOf(3, 0);
-    public static final NativeType DECIMAL_4_1 = NativeTypes.decimalOf(4, 1);
-    public static final NativeType DECIMAL_6_3 = NativeTypes.decimalOf(6, 3);
-    public static final NativeType DECIMAL_19_16 = NativeTypes.decimalOf(19, 16);
+    public static final NativeType DECIMAL_3_1 = NativeTypes.decimalOf(3, 1);
 
     public static final NativeType DECIMAL_4_0 = NativeTypes.decimalOf(4, 0);
-    public static final NativeType DECIMAL_20_16 = NativeTypes.decimalOf(20, 16);
+    public static final NativeType DECIMAL_4_1 = NativeTypes.decimalOf(4, 1);
+    public static final NativeType DECIMAL_4_2 = NativeTypes.decimalOf(4, 2);
+    public static final NativeType DECIMAL_4_3 = NativeTypes.decimalOf(4, 3);
 
     public static final NativeType DECIMAL_5_0 = NativeTypes.decimalOf(5, 0);
-    public static final NativeType DECIMAL_6_1 = NativeTypes.decimalOf(6, 1);
-    public static final NativeType DECIMAL_8_3 = NativeTypes.decimalOf(8, 3);
-    public static final NativeType DECIMAL_21_16 = NativeTypes.decimalOf(21, 16);
+    public static final NativeType DECIMAL_5_1 = NativeTypes.decimalOf(5, 1);
+    public static final NativeType DECIMAL_5_2 = NativeTypes.decimalOf(5, 2);
+    public static final NativeType DECIMAL_5_3 = NativeTypes.decimalOf(5, 3);
 
-    public static final NativeType DECIMAL_14_7 = NativeTypes.decimalOf(14, 7);
+    public static final NativeType DECIMAL_6_0 = NativeTypes.decimalOf(6, 0);
+    public static final NativeType DECIMAL_6_1 = NativeTypes.decimalOf(6, 1);
+    public static final NativeType DECIMAL_6_2 = NativeTypes.decimalOf(6, 2);
+    public static final NativeType DECIMAL_6_3 = NativeTypes.decimalOf(6, 3);
+    public static final NativeType DECIMAL_6_4 = NativeTypes.decimalOf(6, 4);
+
+    public static final NativeType DECIMAL_7_0 = NativeTypes.decimalOf(7, 0);
+    public static final NativeType DECIMAL_7_1 = NativeTypes.decimalOf(7, 1);
+    public static final NativeType DECIMAL_7_3 = NativeTypes.decimalOf(7, 3);
+    public static final NativeType DECIMAL_7_4 = NativeTypes.decimalOf(7, 4);
+    public static final NativeType DECIMAL_7_6 = NativeTypes.decimalOf(7, 6);
+
+    public static final NativeType DECIMAL_8_0 = NativeTypes.decimalOf(8, 0);
+    public static final NativeType DECIMAL_8_1 = NativeTypes.decimalOf(8, 1);
+    public static final NativeType DECIMAL_8_2 = NativeTypes.decimalOf(8, 2);
+    public static final NativeType DECIMAL_8_3 = NativeTypes.decimalOf(8, 3);
+    public static final NativeType DECIMAL_8_4 = NativeTypes.decimalOf(8, 4);
+    public static final NativeType DECIMAL_8_6 = NativeTypes.decimalOf(8, 6);
+    public static final NativeType DECIMAL_8_7 = NativeTypes.decimalOf(8, 7);
+
+    public static final NativeType DECIMAL_9_1 = NativeTypes.decimalOf(9, 1);
+    public static final NativeType DECIMAL_9_2 = NativeTypes.decimalOf(9, 2);
+    public static final NativeType DECIMAL_9_3 = NativeTypes.decimalOf(9, 3);
+    public static final NativeType DECIMAL_9_6 = NativeTypes.decimalOf(9, 6);
+    public static final NativeType DECIMAL_9_7 = NativeTypes.decimalOf(9, 7);
 
     public static final NativeType DECIMAL_10_0 = NativeTypes.decimalOf(10, 0);
+    public static final NativeType DECIMAL_10_3 = NativeTypes.decimalOf(10, 3);
+    public static final NativeType DECIMAL_10_4 = NativeTypes.decimalOf(10, 4);
+    public static final NativeType DECIMAL_10_6 = NativeTypes.decimalOf(10, 6);
+    public static final NativeType DECIMAL_10_7 = NativeTypes.decimalOf(10, 7);
+    public static final NativeType DECIMAL_10_8 = NativeTypes.decimalOf(10, 8);
+    public static final NativeType DECIMAL_10_9 = NativeTypes.decimalOf(10, 9);
+
+    public static final NativeType DECIMAL_11_0 = NativeTypes.decimalOf(11, 0);
     public static final NativeType DECIMAL_11_1 = NativeTypes.decimalOf(11, 1);
+    public static final NativeType DECIMAL_11_3 = NativeTypes.decimalOf(11, 3);
+    public static final NativeType DECIMAL_11_4 = NativeTypes.decimalOf(11, 4);
+    public static final NativeType DECIMAL_11_6 = NativeTypes.decimalOf(11, 6);
+    public static final NativeType DECIMAL_11_7 = NativeTypes.decimalOf(11, 7);
+    public static final NativeType DECIMAL_11_8 = NativeTypes.decimalOf(11, 8);
+    public static final NativeType DECIMAL_11_9 = NativeTypes.decimalOf(11, 9);
+
+    public static final NativeType DECIMAL_12_0 = NativeTypes.decimalOf(12, 0);
+    public static final NativeType DECIMAL_12_1 = NativeTypes.decimalOf(12, 1);
+    public static final NativeType DECIMAL_12_2 = NativeTypes.decimalOf(12, 2);
+    public static final NativeType DECIMAL_12_6 = NativeTypes.decimalOf(12, 6);
+    public static final NativeType DECIMAL_12_7 = NativeTypes.decimalOf(12, 7);
+    public static final NativeType DECIMAL_12_8 = NativeTypes.decimalOf(12, 8);
+    public static final NativeType DECIMAL_12_10 = NativeTypes.decimalOf(12, 10);
+
+    public static final NativeType DECIMAL_13_1 = NativeTypes.decimalOf(13, 1);
     public static final NativeType DECIMAL_13_3 = NativeTypes.decimalOf(13, 3);
+    public static final NativeType DECIMAL_13_6 = NativeTypes.decimalOf(13, 6);
+    public static final NativeType DECIMAL_13_7 = NativeTypes.decimalOf(13, 7);
+    public static final NativeType DECIMAL_13_9 = NativeTypes.decimalOf(13, 9);
+    public static final NativeType DECIMAL_13_10 = NativeTypes.decimalOf(13, 10);
+
+    public static final NativeType DECIMAL_14_3 = NativeTypes.decimalOf(14, 3);
+    public static final NativeType DECIMAL_14_4 = NativeTypes.decimalOf(14, 4);
+    public static final NativeType DECIMAL_14_6 = NativeTypes.decimalOf(14, 6);
+    public static final NativeType DECIMAL_14_7 = NativeTypes.decimalOf(14, 7);
+    public static final NativeType DECIMAL_14_8 = NativeTypes.decimalOf(14, 8);
+    public static final NativeType DECIMAL_14_9 = NativeTypes.decimalOf(14, 9);
+    public static final NativeType DECIMAL_14_10 = NativeTypes.decimalOf(14, 10);
+
+    public static final NativeType DECIMAL_15_0 = NativeTypes.decimalOf(15, 0);
+    public static final NativeType DECIMAL_15_3 = NativeTypes.decimalOf(15, 3);
+    public static final NativeType DECIMAL_15_9 = NativeTypes.decimalOf(15, 9);
+    public static final NativeType DECIMAL_15_10 = NativeTypes.decimalOf(15, 10);
+
+    public static final NativeType DECIMAL_16_1 = NativeTypes.decimalOf(16, 1);
+    public static final NativeType DECIMAL_16_6 = NativeTypes.decimalOf(16, 6);
+    public static final NativeType DECIMAL_16_12 = NativeTypes.decimalOf(16, 12);
+    public static final NativeType DECIMAL_16_15 = NativeTypes.decimalOf(16, 15);
+
+    public static final NativeType DECIMAL_17_6 = NativeTypes.decimalOf(17, 6);
+    public static final NativeType DECIMAL_17_9 = NativeTypes.decimalOf(17, 9);
+    public static final NativeType DECIMAL_17_12 = NativeTypes.decimalOf(17, 12);
+    public static final NativeType DECIMAL_17_15 = NativeTypes.decimalOf(17, 15);
+
+    public static final NativeType DECIMAL_18_3 = NativeTypes.decimalOf(18, 3);
+    public static final NativeType DECIMAL_18_7 = NativeTypes.decimalOf(18, 7);
+    public static final NativeType DECIMAL_18_10 = NativeTypes.decimalOf(18, 10);
+    public static final NativeType DECIMAL_18_15 = NativeTypes.decimalOf(18, 15);
+    public static final NativeType DECIMAL_18_16 = NativeTypes.decimalOf(18, 16);
+
+    public static final NativeType DECIMAL_19_0 = NativeTypes.decimalOf(19, 0);
+    public static final NativeType DECIMAL_19_6 = NativeTypes.decimalOf(19, 6);
+    public static final NativeType DECIMAL_19_16 = NativeTypes.decimalOf(19, 16);
+
+    public static final NativeType DECIMAL_20_0 = NativeTypes.decimalOf(20, 0);
+    public static final NativeType DECIMAL_20_1 = NativeTypes.decimalOf(20, 1);
+    public static final NativeType DECIMAL_20_12 = NativeTypes.decimalOf(20, 12);
+    public static final NativeType DECIMAL_20_15 = NativeTypes.decimalOf(20, 15);
+    public static final NativeType DECIMAL_20_16 = NativeTypes.decimalOf(20, 16);
+    public static final NativeType DECIMAL_20_18 = NativeTypes.decimalOf(20, 18);
+
+    public static final NativeType DECIMAL_21_0 = NativeTypes.decimalOf(21, 0);
+    public static final NativeType DECIMAL_21_1 = NativeTypes.decimalOf(21, 1);
+    public static final NativeType DECIMAL_21_16 = NativeTypes.decimalOf(21, 16);
+
+    public static final NativeType DECIMAL_22_1 = NativeTypes.decimalOf(22, 1);
+    public static final NativeType DECIMAL_22_3 = NativeTypes.decimalOf(22, 3);
+    public static final NativeType DECIMAL_22_9 = NativeTypes.decimalOf(22, 9);
+    public static final NativeType DECIMAL_22_15 = NativeTypes.decimalOf(22, 15);
+
+    public static final NativeType DECIMAL_23_3 = NativeTypes.decimalOf(23, 3);
+
+    public static final NativeType DECIMAL_24_0 = NativeTypes.decimalOf(24, 0);
+    public static final NativeType DECIMAL_24_3 = NativeTypes.decimalOf(24, 3);
+
+    public static final NativeType DECIMAL_25_1 = NativeTypes.decimalOf(25, 1);
+    public static final NativeType DECIMAL_25_6 = NativeTypes.decimalOf(25, 6);
+    public static final NativeType DECIMAL_25_15 = NativeTypes.decimalOf(25, 15);
+
+    public static final NativeType DECIMAL_26_6 = NativeTypes.decimalOf(26, 6);
     public static final NativeType DECIMAL_26_16 = NativeTypes.decimalOf(26, 16);
 
+    public static final NativeType DECIMAL_27_3 = NativeTypes.decimalOf(27, 3);
+    public static final NativeType DECIMAL_27_7 = NativeTypes.decimalOf(27, 7);
+
+    public static final NativeType DECIMAL_28_6 = NativeTypes.decimalOf(28, 6);
+
     public static final NativeType DECIMAL_30_15 = NativeTypes.decimalOf(30, 15);
 
-    public static final NativeType DECIMAL_19_0 = NativeTypes.decimalOf(19, 0);
-    public static final NativeType DECIMAL_20_1 = NativeTypes.decimalOf(20, 1);
-    public static final NativeType DECIMAL_22_3 = NativeTypes.decimalOf(22, 3);
+    public static final NativeType DECIMAL_31_9 = NativeTypes.decimalOf(31, 9);
+
     public static final NativeType DECIMAL_35_16 = NativeTypes.decimalOf(35, 16);
 
     public static final NativeType DECIMAL_MAX_18 = NativeTypes.decimalOf(CatalogUtils.MAX_DECIMAL_PRECISION, 18);