diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e0e6fef13..1ff3650e9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ #### Bug Fixes - Fixed a bug where `AsyncJob.result("no_result")` sometimes silently returned without raising error for failed queries. +- Fixed a bug where `INTERVAL YEAR TO MONTH` values with zero months were displayed incorrectly (e.g. `INTERVAL '0-4' YEAR TO MONTH` instead of `INTERVAL '4-0' YEAR TO MONTH`) when using `snowflake-connector-python>=4.3.0`. #### Improvements diff --git a/src/snowflake/snowpark/_internal/type_utils.py b/src/snowflake/snowpark/_internal/type_utils.py index c016e0f0f0..b08e07d3c9 100644 --- a/src/snowflake/snowpark/_internal/type_utils.py +++ b/src/snowflake/snowpark/_internal/type_utils.py @@ -1764,11 +1764,11 @@ def format_year_month_interval_for_display( years = str(int(parts[0])) months = str(int(parts[1])) else: - # Format like "+2" or "-3" - if ( - start_field == YearMonthIntervalType.YEAR - and end_field == YearMonthIntervalType.YEAR - ): + # Format like "+2" or "-3" — a single number without a year-month dash. + # When start_field is YEAR the value represents years (connector >=4.3.0 + # omits the "-0" suffix when months=0). Only treat as months when the + # interval type starts at MONTH. + if start_field == YearMonthIntervalType.YEAR: years = str(int(remaining)) else: months = str(int(remaining)) diff --git a/tests/unit/test_datatype_mapper.py b/tests/unit/test_datatype_mapper.py index 62548a0a6f..3df7de666a 100644 --- a/tests/unit/test_datatype_mapper.py +++ b/tests/unit/test_datatype_mapper.py @@ -16,6 +16,9 @@ to_sql, to_sql_no_cast, ) +from snowflake.snowpark._internal.type_utils import ( + format_year_month_interval_for_display, +) from snowflake.snowpark._internal.udf_utils import generate_call_python_sp_sql from snowflake.snowpark.types import ( ArrayType, @@ -809,3 +812,86 @@ def test_schema_expression(): schema_expression(DayTimeIntervalType(), False) == "INTERVAL '1 01:01:01.0001' DAY TO SECOND" ) + + +@pytest.mark.parametrize( + "cell, start_field, end_field, expected", + [ + ( + "+1-6", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.MONTH, + "INTERVAL '1-6' YEAR TO MONTH", + ), + ( + "-2-3", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.MONTH, + "INTERVAL '-2-3' YEAR TO MONTH", + ), + ( + "+0-5", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.MONTH, + "INTERVAL '0-5' YEAR TO MONTH", + ), + ( + "+4", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.MONTH, + "INTERVAL '4-0' YEAR TO MONTH", + ), + ( + "-7", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.MONTH, + "INTERVAL '-7-0' YEAR TO MONTH", + ), + ( + "+12", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.MONTH, + "INTERVAL '12-0' YEAR TO MONTH", + ), + ( + "+4", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.YEAR, + "INTERVAL '4' YEAR", + ), + ( + "-1", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.YEAR, + "INTERVAL '-1' YEAR", + ), + ( + "+5", + YearMonthIntervalType.MONTH, + YearMonthIntervalType.MONTH, + "INTERVAL '5' MONTH", + ), + ( + "-12", + YearMonthIntervalType.MONTH, + YearMonthIntervalType.MONTH, + "INTERVAL '-12' MONTH", + ), + ( + "+5-0", + YearMonthIntervalType.YEAR, + YearMonthIntervalType.YEAR, + "INTERVAL '5' YEAR", + ), + ( + "+0-3", + YearMonthIntervalType.MONTH, + YearMonthIntervalType.MONTH, + "INTERVAL '3' MONTH", + ), + ], +) +def test_format_year_month_interval_for_display(cell, start_field, end_field, expected): + assert ( + format_year_month_interval_for_display(cell, start_field, end_field) == expected + )