Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -711,12 +711,12 @@ public static SqlCall stripSeparator(SqlCall call) {
* <p>This method serves as a dispatcher that routes to the appropriate handler
* based on the type of operator binding. It handles both SQL parse tree bindings
* (SqlCallBinding) and relational expression bindings (RexCallBinding), with a
* fallback for other binding types.</p>
* fallback for other binding types.
*
* <p>The method is crucial for decimal multiplication type inference because it
* needs to analyze the actual operand values (not just their declared types) to
* determine if integer literals should be converted to decimal types for proper
* decimal arithmetic.</p>
* decimal arithmetic.
*
* @param opBinding the operator binding containing operand information and types
* @param typeFactory the type factory used to create new data types if needed
Expand All @@ -742,15 +742,14 @@ private static Pair<RelDataType, RelDataType> getDecimalMultiplyBindingType(
*
* <p>This method handles relational expression bindings (RexCallBinding) where operands
* are represented as RexNode objects. It analyzes both the declared types and actual
* values to determine if type conversions are needed for proper decimal arithmetic.</p>
* values to determine if type conversions are needed for proper decimal arithmetic.
*
* <p>The method implements a comprehensive type inference strategy that considers:
* <ul>
* <li>Whether operands have decimal types or contain decimal constants</li>
* <li>Whether operands are numeric (including integer literals)</li>
* <li>Whether integer literals should be converted to decimal types</li>
* </ul>
* </p>
*
* <p>Key scenarios handled:
* <ul>
Expand All @@ -759,7 +758,6 @@ private static Pair<RelDataType, RelDataType> getDecimalMultiplyBindingType(
* <li>Integer × Decimal: integer may be converted to decimal</li>
* <li>Integer × Integer: no conversion, return original types</li>
* </ul>
* </p>
*
* @param opBinding the RexCallBinding containing RexNode operands
* @param typeFactory the type factory for creating new data types
Expand Down Expand Up @@ -811,7 +809,7 @@ private static Pair<RelDataType, RelDataType> getRelDataTypeRelDataTypePair(
* <p>This method is responsible for type conversion in relational expression scenarios
* where integer literals need to be promoted to decimal types for proper decimal arithmetic.
* The conversion is essential when multiplying integers with decimals to maintain
* precision and avoid unintended integer arithmetic.</p>
* precision and avoid unintended integer arithmetic.
*
* <p>Conversion logic:
* <ul>
Expand All @@ -820,7 +818,6 @@ private static Pair<RelDataType, RelDataType> getRelDataTypeRelDataTypePair(
* precision</li>
* <li>For other cases, return the default type unchanged</li>
* </ul>
* </p>
*
* <p>The precision calculation for converted integers uses the number of digits
* in the integer value. For example:
Expand All @@ -829,7 +826,6 @@ private static Pair<RelDataType, RelDataType> getRelDataTypeRelDataTypePair(
* <li>45 → DECIMAL(2, 0) (2 digits)</li>
* <li>0 → DECIMAL(1, 0) (special case)</li>
* </ul>
* </p>
*
* @param typeFactory the type factory for creating new DECIMAL types
* @param opBinding the RexCallBinding containing the operands
Expand Down Expand Up @@ -881,12 +877,12 @@ private static RelDataType createDecimalTypeOrDefault(RelDataTypeFactory typeFac
*
* <p>This method handles SQL parse tree bindings (SqlCallBinding) where operands
* are represented as SqlNode objects. It analyzes both the declared types and actual
* values to determine if type conversions are needed for proper decimal arithmetic.</p>
* values to determine if type conversions are needed for proper decimal arithmetic.
*
* <p>Similar to the RexCallBinding version, this method implements comprehensive
* type inference but operates on SqlNode objects instead of RexNode objects.
* The key difference is that during SQL parsing, integer literals are automatically
* converted to DECIMAL type, which affects the conversion logic.</p>
* converted to DECIMAL type, which affects the conversion logic.
*
* <p>Key scenarios handled:
* <ul>
Expand All @@ -895,7 +891,6 @@ private static RelDataType createDecimalTypeOrDefault(RelDataTypeFactory typeFac
* <li>Integer × Decimal: integer may be converted to decimal</li>
* <li>Integer × Integer: no conversion, return original types</li>
* </ul>
* </p>
*
* @param opBinding the SqlCallBinding containing SqlNode operands
* @param typeFactory the type factory for creating new data types
Expand Down Expand Up @@ -947,23 +942,21 @@ private static Pair<RelDataType, RelDataType> getRelDataTypeRelDataTypePair(
* <p>This method handles type conversion in SQL parse tree scenarios where numeric literals
* need to be processed for decimal arithmetic. Unlike the RexCallBinding version, this method
* operates on SqlNode objects where integer literals have already been converted to DECIMAL
* type during SQL parsing.</p>
* type during SQL parsing.
*
* <p>Key difference from RexCallBinding version:
* <ul>
* <li>During SQL parsing, integer literals are automatically converted to DECIMAL type</li>
* <li>This method primarily ensures proper precision and scale are preserved</li>
* <li>No need to manually calculate precision from integer values</li>
* </ul>
* </p>
*
* <p>Conversion logic:
* <ul>
* <li>If the operand is a numeric literal (DECIMAL or INTEGER), create DECIMAL type</li>
* <li>Use the literal's existing precision and scale information</li>
* <li>For non-literals, return the default type unchanged</li>
* </ul>
* </p>
*
* @param typeFactory the type factory for creating new DECIMAL types
* @param opBinding the SqlCallBinding containing SqlNode operands
Expand Down Expand Up @@ -1216,13 +1209,13 @@ private static RelDataType createDecimalTypeOrDefault(RelDataTypeFactory typeFac
* For example,
*
* <p>concat(cast('a' as varchar(2)), cast('b' as varchar(3)),cast('c' as varchar(2)))
* returns varchar(7).</p>
* returns varchar(7).
*
* <p>concat(cast('a' as varchar), cast('b' as varchar(2), cast('c' as varchar(2))))
* returns varchar.</p>
* returns varchar.
*
* <p>concat(cast('a' as varchar(65535)), cast('b' as varchar(2)), cast('c' as varchar(2)))
* returns varchar.</p>
* returns varchar.
*/
public static final SqlReturnTypeInference MULTIVALENT_STRING_SUM_PRECISION =
opBinding -> {
Expand Down
38 changes: 18 additions & 20 deletions core/src/main/java/org/apache/calcite/util/SqlNodeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
* <p>This class provides various static methods to analyze and validate SQL nodes,
* particularly focusing on numeric and decimal constant detection. It includes methods
* to check if nodes represent decimal constants, numeric literals, or complex expressions
* containing numeric values.</p>
* containing numeric values.
*
* <p>The utility supports both {@link SqlNode} (parse tree representation) and
* {@link RexNode} (relational expression representation) objects, providing consistent
* behavior across different stages of SQL processing.</p>
* behavior across different stages of SQL processing.
*/
public class SqlNodeUtils {

Expand All @@ -57,7 +57,7 @@ private SqlNodeUtils() {
*
* <p>A decimal constant is defined as a {@link SqlNumericLiteral} with DECIMAL type
* that is not an integer literal. This method specifically excludes integer values
* even if they are stored as DECIMAL type.</p>
* even if they are stored as DECIMAL type.
*
* @param node the SQL node to check, may be null
* @return true if the node is a decimal constant (non-integer DECIMAL), false otherwise
Expand All @@ -82,7 +82,7 @@ public static boolean isDecimalConstant(SqlNode node) {
* <p>Unlike {@link #isDecimalConstant(SqlNode)}, this method includes both decimal
* and integer values. During SQL parsing, integers are converted to DECIMAL type,
* so this method checks for DECIMAL type regardless of whether it's an integer
* or decimal value.</p>
* or decimal value.
*
* @param node the SQL node to check, may be null
* @return true if the node is a DECIMAL type numeric literal (including integers), false
Expand All @@ -107,7 +107,7 @@ public static boolean isDecimalOrIntegerConstant(SqlNode node) {
*
* <p>This method checks if the node is a {@link RexLiteral} with DECIMAL type
* or any approximate numeric type (like FLOAT, DOUBLE). Unlike the SqlNode
* version, this includes approximate numeric types as well.</p>
* version, this includes approximate numeric types as well.
*
* @param node the Rex node to check, may be null
* @return true if the node is a decimal or approximate numeric constant, false otherwise
Expand All @@ -126,7 +126,7 @@ public static boolean isDecimalConstant(RexNode node) {
* Checks if the given {@link SqlNode} is a numeric literal.
*
* <p>This is a simple type check that returns true if the node is an instance
* of {@link SqlNumericLiteral}, regardless of the specific numeric type.</p>
* of {@link SqlNumericLiteral}, regardless of the specific numeric type.
*
* @param node the SQL node to check, may be null
* @return true if the node is a numeric literal, false otherwise
Expand All @@ -140,7 +140,7 @@ public static boolean isNumericLiteral(SqlNode node) {
*
* <p>This method checks if the node is a {@link RexLiteral} with a numeric type.
* It uses {@link SqlTypeUtil#isNumeric(RelDataType)} to determine if the type
* is numeric, which includes all numeric types like INTEGER, DECIMAL, FLOAT, etc.</p>
* is numeric, which includes all numeric types like INTEGER, DECIMAL, FLOAT, etc.
*
* @param node the Rex node to check, may be null
* @return true if the node is a numeric literal, false otherwise
Expand All @@ -159,7 +159,7 @@ public static boolean isNumericLiteral(RexNode node) {
* is a numeric literal.
*
* <p>This method verifies that the operand is both a literal and has a numeric type.
* It's commonly used in operator validation to ensure operands are numeric literals.</p>
* It's commonly used in operator validation to ensure operands are numeric literals.
*
* @param binding the operator binding containing the operands
* @param ordinal the zero-based index of the operand to check
Expand All @@ -175,15 +175,15 @@ public static boolean isNumericLiteral(SqlOperatorBinding binding, int ordinal)
*
* <p>This method performs a deep analysis of the expression tree to determine if
* it contains only numeric literals and at least one decimal constant. It traverses
* binary arithmetic operations (like +, -, *, /) and checks all operands.</p>
* binary arithmetic operations (like +, -, *, /) and checks all operands.
*
* <p>The method returns true only if:
* <ul>
* <li>All leaf nodes in the expression are numeric literals</li>
* <li>At least one leaf node is a decimal constant</li>
* <li>All intermediate nodes are binary arithmetic operations</li>
* </ul>
* </p>
*
*
* <p>For example, this would return true for expressions like:
* <ul>
Expand All @@ -195,7 +195,6 @@ public static boolean isNumericLiteral(SqlOperatorBinding binding, int ordinal)
* <li>1 + 2 (no decimal constants)</li>
* <li>1.5 + column_name (contains non-literal)</li>
* </ul>
* </p>
*
* @param node the Rex node to check, may be null
* @return true if the expression contains only numeric literals and at least one decimal constant
Expand Down Expand Up @@ -257,10 +256,10 @@ public static boolean isDecimalConstantRexNode(RexNode node) {
*
* <p>This method performs a deep analysis of the expression tree to determine if
* it contains only numeric literals. It traverses binary arithmetic operations
* and checks all operands to ensure they are all numeric literals.</p>
* and checks all operands to ensure they are all numeric literals.
*
* <p>Unlike {@link #isDecimalConstantRexNode(RexNode)}, this method doesn't require
* at least one decimal constant - it accepts expressions with only integer literals as well.</p>
* at least one decimal constant - it accepts expressions with only integer literals as well.
*
* <p>For example, this would return true for expressions like:
* <ul>
Expand All @@ -273,7 +272,6 @@ public static boolean isDecimalConstantRexNode(RexNode node) {
* <li>1 + column_name (contains non-literal)</li>
* <li>function_call(5) (contains function call)</li>
* </ul>
* </p>
*
* @param node the Rex node to check, may be null
* @return true if the expression contains only numeric literals, false otherwise
Expand Down Expand Up @@ -316,14 +314,14 @@ public static boolean isNumericLiteralRexNode(RexNode node) {
*
* <p>This method is the SqlNode equivalent of {@link #isDecimalConstantRexNode(RexNode)}.
* It performs a deep analysis of the SQL expression tree to determine if
* it contains only numeric literals and at least one decimal constant.</p>
* it contains only numeric literals and at least one decimal constant.
*
* <p>The method traverses binary arithmetic operations and checks all operands.
* It returns true only if all leaf nodes are numeric literals and at least one
* is a decimal constant.</p>
* is a decimal constant.
*
* <p>This method is typically used during SQL parsing and validation stages,
* before the SQL is converted to relational expressions.</p>
* before the SQL is converted to relational expressions.
*
* @param node the SQL node to check, may be null
* @return true if the expression contains only numeric literals and at least one decimal constant
Expand Down Expand Up @@ -384,14 +382,14 @@ public static boolean isDecimalConstantSqlNode(SqlNode node) {
*
* <p>This method is the SqlNode equivalent of {@link #isNumericLiteralRexNode(RexNode)}.
* It performs a deep analysis of the SQL expression tree to determine if
* it contains only numeric literals.</p>
* it contains only numeric literals.
*
* <p>The method traverses binary arithmetic operations and checks all operands
* to ensure they are all numeric literals. It accepts expressions with both
* integer and decimal literals.</p>
* integer and decimal literals.
*
* <p>This method is typically used during SQL parsing and validation to identify
* constant expressions that can be evaluated at compile time.</p>
* constant expressions that can be evaluated at compile time.
*
* @param node the SQL node to check, may be null
* @return true if the expression contains only numeric literals, false otherwise
Expand Down
Loading