diff --git a/CHANGELOG.md b/CHANGELOG.md index 42efb25dcb5..cb714d8879a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - Fixed a bug in query generation from set operations that allowed generation of duplicate queries when children have common subqueries. - Fixed a bug in `session.get_session_stage` that referenced a non-existing stage after switching database or schema. - Fixed a bug where calling `DataFrame.to_snowpark_pandas_dataframe` without explicitly initializing the Snowpark pandas plugin caused an error. +- Fixed a bug where using the `explode` function in dynamic table creation caused a SQL compilation error due to improper boolean type casting on the `outer` parameter. ### Snowpark Local Testing Updates diff --git a/src/snowflake/snowpark/_internal/analyzer/analyzer.py b/src/snowflake/snowpark/_internal/analyzer/analyzer.py index 0c6c64554de..6567754d229 100644 --- a/src/snowflake/snowpark/_internal/analyzer/analyzer.py +++ b/src/snowflake/snowpark/_internal/analyzer/analyzer.py @@ -151,7 +151,7 @@ from snowflake.snowpark._internal.error_message import SnowparkClientExceptionMessages from snowflake.snowpark._internal.telemetry import TelemetryField from snowflake.snowpark._internal.utils import quote_name -from snowflake.snowpark.types import _NumericType +from snowflake.snowpark.types import BooleanType, _NumericType ARRAY_BIND_THRESHOLD = 512 @@ -605,7 +605,7 @@ def table_function_expression_extractor( sql = named_arguments_function( expr.func_name, { - key: self.analyze( + key: self.to_sql_try_avoid_cast( value, df_aliased_col_name_to_real_col_name, parse_local_name ) for key, value in expr.args.items() @@ -745,6 +745,12 @@ def to_sql_try_avoid_cast( # otherwise process as normal if isinstance(expr, Literal) and isinstance(expr.datatype, _NumericType): return numeric_to_sql_without_cast(expr.value, expr.datatype) + elif ( + isinstance(expr, Literal) + and isinstance(expr.datatype, BooleanType) + and isinstance(expr.value, bool) + ): + return str(expr.value).upper() else: return self.analyze( expr, df_aliased_col_name_to_real_col_name, parse_local_name diff --git a/tests/integ/test_dataframe.py b/tests/integ/test_dataframe.py index 4cf335678e4..0576198c03c 100644 --- a/tests/integ/test_dataframe.py +++ b/tests/integ/test_dataframe.py @@ -3015,6 +3015,31 @@ def test_create_dynamic_table(session, table_name_1, is_transient): Utils.drop_dynamic_table(session, dt_name) +@pytest.mark.xfail( + "config.getoption('local_testing_mode', default=False)", + reason="Dynamic table is a SQL feature", + run=False, +) +def test_create_dynamic_table_with_explode(session): + dt_name = Utils.random_name_for_temp_object(TempObjectType.DYNAMIC_TABLE) + temp_table = Utils.random_name_for_temp_object(TempObjectType.TABLE) + try: + df = session.create_dataframe( + [[1, [1, 2, 3]], [2, [11, 22]]], schema=["idx", "lists"] + ) + df.write.mode("overwrite").save_as_table(temp_table) + df = session.table(temp_table) + df1 = df.select(df.idx, explode(df.lists)) + df1.create_or_replace_dynamic_table( + dt_name, warehouse=session.get_current_warehouse(), lag="1 min" + ) + session.sql(f"alter dynamic table {dt_name} refresh").collect() + res = session.sql(f"show dynamic tables like '{dt_name}'").collect() + assert len(res) == 1 + finally: + Utils.drop_table(session, temp_table) + + @pytest.mark.xfail( "config.getoption('local_testing_mode', default=False)", reason="Dynamic table is a SQL feature",