snowflake-snowpark-python 1.49.0__tar.gz → 1.50.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/CHANGELOG.md +22 -0
- {snowflake_snowpark_python-1.49.0/src/snowflake_snowpark_python.egg-info → snowflake_snowpark_python-1.50.0}/PKG-INFO +5 -3
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/setup.py +2 -1
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/datatype_mapper.py +10 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/select_statement.py +317 -30
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/snowflake_plan.py +8 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/cte_utils.py +42 -1
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/plan_compiler.py +7 -2
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/telemetry_constants.py +5 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/datasource_partitioner.py +2 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/base_driver.py +2 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/event_table_telemetry.py +1 -1
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/server_connection.py +129 -4
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/telemetry.py +42 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/type_utils.py +187 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/udf_utils.py +1 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/xml_schema_inference.py +31 -17
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/context.py +118 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe.py +124 -52
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe_reader.py +110 -20
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/functions.py +1 -1
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_select_statement.py +2 -2
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/relational_grouped_dataframe.py +10 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/session.py +64 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/types.py +3 -1
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/version.py +1 -1
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0/src/snowflake_snowpark_python.egg-info}/PKG-INFO +5 -3
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake_snowpark_python.egg-info/requires.txt +4 -2
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/LICENSE.txt +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/MANIFEST.in +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/README.md +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/pyproject.toml +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/setup.cfg +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_functions/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_functions/general_functions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_functions/scalar_functions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/analyzer.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/analyzer_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/binary_expression.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/binary_plan_node.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/expression.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/grouping_set.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/metadata_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/query_plan_analysis_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/schema_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/snowflake_plan_node.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/sort_expression.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/table_function.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/table_merge_expression.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/unary_expression.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/unary_plan_node.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/analyzer/window_expression.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/ast/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/ast/batch.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/ast/builder.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/ast/utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/code_generation.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/large_query_breakdown.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/query_generator.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/repeated_subquery_elimination.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/compiler/utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/datasource_reader.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/datasource_typing.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/base_dialect.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/databricks_dialect.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/mysql_dialect.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/oracledb_dialect.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/postgresql_dialect.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/sqlite3_dialect.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/sqlserver_dialect.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/databricks_driver.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/oracledb_driver.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/psycopg2_driver.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/pymsql_driver.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/pyodbc_driver.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/drivers/sqlite_driver.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/jdbc.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/data_source/utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/debug_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/error_message.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/open_telemetry.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/packaging_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/proto/generated/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/proto/generated/ast_pb2.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/proto/generated/ast_pb2.pyi +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/select_projection_complexity_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/snowpark_profiler.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/temp_table_auto_cleaner.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/xml_reader.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/_internal/xpath_handlers.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/async_job.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/catalog.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/column.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe_ai_functions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe_analytics_functions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe_na_functions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe_profiler.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe_stat_functions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/dataframe_writer.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/exceptions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/file_operation.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/files.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/lineage.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_analyzer.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_connection.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_constants.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_functions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_nop_analyzer.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_nop_connection.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_nop_plan.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_options.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_pandas_util.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_plan.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_plan_builder.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_snowflake_data_type.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_snowflake_to_pandas_converter.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_stage_registry.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_stored_procedure.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_telemetry.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_udaf.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_udf.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_udf_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_udtf.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_util.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/_window_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/mock/exceptions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/config/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/config/__main__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/config/envvars.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/config/pubsub.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/conftest.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/aggregation_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/align_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/apply_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/binary_op_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/concat_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/cumulative_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/cut_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/frame.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/generator_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/get_dummies_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/groupby_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/indexing_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/io_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/isin_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/join_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/ordered_dataframe.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/pivot_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/resample_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/row_count_estimation.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/session.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/snowpark_pandas_types.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/statement_params_constants.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/telemetry.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/timestamp_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/transpose_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/type_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/unpivot_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/where_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_internal/window_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/_typing.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/compiler/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/compiler/doc_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/compiler/ray_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/compiler/snowflake_query_compiler.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/base.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/dataframe.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/datetime_index.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/general.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/groupby.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/index.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/io.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/resample.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/series.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/series_utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/shared_docs.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/timedelta_index.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/docstrings/window.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/base_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/dataframe_extensions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/dataframe_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/dataframe_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/datetime_index.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/general_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/index.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/indexing_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/io_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/pd_extensions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/resample_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/resampler_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/rolling_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/series_extensions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/series_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/series_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/snow_partition_iterator.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/timedelta_index.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/extensions/window_overrides.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/io/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/io/factories.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/io/snow_io.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/utils/__init__.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/utils/error_message.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/utils/exceptions.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/utils/frontend_constants.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/utils/numpy_to_pandas.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/plugin/utils/warning_message.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/modin/utils.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/py.typed +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/query_history.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/row.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/secrets.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/stored_procedure.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/stored_procedure_profiler.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/table.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/table_function.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/testing.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/udaf.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/udf.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/udf_profiler.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/udtf.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake/snowpark/window.py +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake_snowpark_python.egg-info/SOURCES.txt +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake_snowpark_python.egg-info/dependency_links.txt +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake_snowpark_python.egg-info/namespace_packages.txt +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake_snowpark_python.egg-info/not-zip-safe +0 -0
- {snowflake_snowpark_python-1.49.0 → snowflake_snowpark_python-1.50.0}/src/snowflake_snowpark_python.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Release History
|
|
2
2
|
|
|
3
|
+
## 1.50.0 (2026-04-23)
|
|
4
|
+
|
|
5
|
+
### Snowpark Python API Updates
|
|
6
|
+
|
|
7
|
+
#### New Features
|
|
8
|
+
|
|
9
|
+
- Added `artifact_repository` support to `udtf_configs` in `session.read.dbapi()`, enabling users to specify a custom artifact repository (e.g. PyPI) for packages used by the internal UDTF during distributed ingestion.
|
|
10
|
+
|
|
11
|
+
#### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- Fixed a bug where `TRY_CAST` reader option is ignored when calling `DataFrameReader.schema().csv()`.
|
|
14
|
+
- Fixed a bug where `event_table_telemetry` is using incorrect resource attributes.
|
|
15
|
+
- Fixed a bug where `value_contains_null` was not propagated for `MapType` in `_as_nested` function.
|
|
16
|
+
- Fixed a bug where CTE optimization incorrectly deduplicated subtrees containing non-deterministic data generation functions (e.g. `uuid_string()`).
|
|
17
|
+
- Fixed a bug where vectorized UDFs using non-anaconda package repositories did not specify the pandas package by default.
|
|
18
|
+
|
|
19
|
+
### Snowpark pandas API Updates
|
|
20
|
+
|
|
21
|
+
#### Dependency Updates
|
|
22
|
+
|
|
23
|
+
- Updated the supported `pandas` versions to <=2.4 (was previously <=2.3.1).
|
|
24
|
+
|
|
3
25
|
## 1.49.0 (2026-04-13)
|
|
4
26
|
|
|
5
27
|
### Snowpark Python API Updates
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: snowflake-snowpark-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.50.0
|
|
4
4
|
Summary: Snowflake Snowpark for Python
|
|
5
5
|
Home-page: https://www.snowflake.com/
|
|
6
6
|
Author: Snowflake, Inc
|
|
@@ -50,7 +50,7 @@ Requires-Dist: snowflake-connector-python[pandas]<5.0.0,>=3.17.0; extra == "pand
|
|
|
50
50
|
Provides-Extra: modin
|
|
51
51
|
Requires-Dist: snowflake-connector-python[pandas]<5.0.0,>=3.17.0; extra == "modin"
|
|
52
52
|
Requires-Dist: modin<0.38.0,>=0.36.0; extra == "modin"
|
|
53
|
-
Requires-Dist: pandas<=2.
|
|
53
|
+
Requires-Dist: pandas<=2.4; extra == "modin"
|
|
54
54
|
Requires-Dist: tqdm; extra == "modin"
|
|
55
55
|
Requires-Dist: ipywidgets; extra == "modin"
|
|
56
56
|
Provides-Extra: secure-local-storage
|
|
@@ -74,10 +74,11 @@ Requires-Dist: tox; extra == "development"
|
|
|
74
74
|
Requires-Dist: snowflake.core<2,>=1.0.0; extra == "development"
|
|
75
75
|
Requires-Dist: psutil; extra == "development"
|
|
76
76
|
Requires-Dist: lxml; extra == "development"
|
|
77
|
+
Requires-Dist: pyarrow; extra == "development"
|
|
77
78
|
Provides-Extra: modin-development
|
|
78
79
|
Requires-Dist: snowflake-connector-python[pandas]<5.0.0,>=3.17.0; extra == "modin-development"
|
|
79
80
|
Requires-Dist: modin<0.38.0,>=0.36.0; extra == "modin-development"
|
|
80
|
-
Requires-Dist: pandas<=2.
|
|
81
|
+
Requires-Dist: pandas<=2.4; extra == "modin-development"
|
|
81
82
|
Requires-Dist: tqdm; extra == "modin-development"
|
|
82
83
|
Requires-Dist: ipywidgets; extra == "modin-development"
|
|
83
84
|
Requires-Dist: pytest<8.0.0; extra == "modin-development"
|
|
@@ -98,6 +99,7 @@ Requires-Dist: tox; extra == "modin-development"
|
|
|
98
99
|
Requires-Dist: snowflake.core<2,>=1.0.0; extra == "modin-development"
|
|
99
100
|
Requires-Dist: psutil; extra == "modin-development"
|
|
100
101
|
Requires-Dist: lxml; extra == "modin-development"
|
|
102
|
+
Requires-Dist: pyarrow; extra == "modin-development"
|
|
101
103
|
Requires-Dist: scipy<=1.16.3; extra == "modin-development"
|
|
102
104
|
Requires-Dist: statsmodels; extra == "modin-development"
|
|
103
105
|
Requires-Dist: scikit-learn; extra == "modin-development"
|
|
@@ -43,7 +43,7 @@ PANDAS_REQUIREMENTS = [
|
|
|
43
43
|
MODIN_REQUIREMENTS = [
|
|
44
44
|
*PANDAS_REQUIREMENTS,
|
|
45
45
|
f"modin{MODIN_DEPENDENCY_VERSION}",
|
|
46
|
-
"pandas<=2.
|
|
46
|
+
"pandas<=2.4",
|
|
47
47
|
"tqdm", # For progress bars during backend switching
|
|
48
48
|
"ipywidgets", # For enhanced progress bars in Jupyter notebooks
|
|
49
49
|
]
|
|
@@ -66,6 +66,7 @@ DEVELOPMENT_REQUIREMENTS = [
|
|
|
66
66
|
"snowflake.core>=1.0.0, <2", # Catalog
|
|
67
67
|
"psutil", # testing for telemetry
|
|
68
68
|
"lxml", # used in XML reader unit tests
|
|
69
|
+
"pyarrow", # used in dataframe reader tests
|
|
69
70
|
]
|
|
70
71
|
MODIN_DEVELOPMENT_REQUIREMENTS = [
|
|
71
72
|
# Snowpark pandas 3rd party library testing. Cap the scipy version because
|
|
@@ -401,6 +401,16 @@ def to_sql(
|
|
|
401
401
|
else str_to_sql(value)
|
|
402
402
|
)
|
|
403
403
|
|
|
404
|
+
if isinstance(datatype, StringType) and isinstance(
|
|
405
|
+
value, (bool, int, float, Decimal)
|
|
406
|
+
):
|
|
407
|
+
# Coerce common Python scalars to str so that VALUES and bind-param
|
|
408
|
+
# paths produce identical string representations. bool is a subclass
|
|
409
|
+
# of int so it must be checked first. Use lowercase for bools to
|
|
410
|
+
# match Snowflake's BOOLEAN::STRING cast semantics.
|
|
411
|
+
s = str(value).lower() if isinstance(value, bool) else str(value)
|
|
412
|
+
return to_sql(s, datatype, from_values_statement=from_values_statement)
|
|
413
|
+
|
|
404
414
|
if isinstance(datatype, _IntegralType):
|
|
405
415
|
return f"{value} :: INT"
|
|
406
416
|
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
6
|
import uuid
|
|
7
|
+
import re
|
|
7
8
|
from abc import ABC, abstractmethod
|
|
8
9
|
from collections import UserDict, defaultdict
|
|
9
10
|
from copy import copy, deepcopy
|
|
10
11
|
from enum import Enum
|
|
11
|
-
from functools import reduce
|
|
12
|
+
from functools import cached_property, reduce
|
|
12
13
|
from typing import (
|
|
13
14
|
TYPE_CHECKING,
|
|
14
15
|
AbstractSet,
|
|
@@ -20,6 +21,7 @@ from typing import (
|
|
|
20
21
|
Sequence,
|
|
21
22
|
Set,
|
|
22
23
|
Union,
|
|
24
|
+
Literal,
|
|
23
25
|
)
|
|
24
26
|
|
|
25
27
|
import snowflake.snowpark._internal.utils
|
|
@@ -86,6 +88,7 @@ from snowflake.snowpark._internal.utils import (
|
|
|
86
88
|
is_sql_select_statement,
|
|
87
89
|
ExprAliasUpdateDict,
|
|
88
90
|
)
|
|
91
|
+
import snowflake.snowpark.context as context
|
|
89
92
|
|
|
90
93
|
# Python 3.8 needs to use typing.Iterable because collections.abc.Iterable is not subscriptable
|
|
91
94
|
# Python 3.9 can use both
|
|
@@ -109,6 +112,22 @@ SEQUENCE_DEPENDENT_DATA_GENERATION = (
|
|
|
109
112
|
"seq8",
|
|
110
113
|
)
|
|
111
114
|
|
|
115
|
+
# Functions that are non-deterministic when called with zero arguments.
|
|
116
|
+
# Used only by the CTE optimizer to prevent deduplication of subtrees that
|
|
117
|
+
# generate random data. Other data generation functions (normal, zipf,
|
|
118
|
+
# uniform, randstr) always require a generator argument (e.g. random()),
|
|
119
|
+
# which is caught by recursive child inspection. seq* functions produce
|
|
120
|
+
# deterministic row-local counters and are safe to dedup.
|
|
121
|
+
NONDETERMINISTIC_DATA_GENERATION = (
|
|
122
|
+
"uuid_string",
|
|
123
|
+
"random",
|
|
124
|
+
)
|
|
125
|
+
# Matches zero-arg calls to nondeterministic functions in SQL text, e.g. "random()" or "UUID_STRING( )".
|
|
126
|
+
NONDETERMINISTIC_ZERO_ARG_RE = re.compile(
|
|
127
|
+
r"\b(?:" + "|".join(NONDETERMINISTIC_DATA_GENERATION) + r")\s*\(\s*\)",
|
|
128
|
+
re.IGNORECASE,
|
|
129
|
+
)
|
|
130
|
+
|
|
112
131
|
|
|
113
132
|
class ColumnChangeState(Enum):
|
|
114
133
|
"""The change state of a column when building a query from its subquery."""
|
|
@@ -995,6 +1014,21 @@ class SelectStatement(Selectable):
|
|
|
995
1014
|
)
|
|
996
1015
|
return copied
|
|
997
1016
|
|
|
1017
|
+
@cached_property
|
|
1018
|
+
def contains_data_generation(self) -> bool:
|
|
1019
|
+
"""True when this node's projection, where, or order_by clauses
|
|
1020
|
+
contain non-deterministic data-generation expressions (e.g. zero-arg
|
|
1021
|
+
``uuid_string()``, ``random()``, ``uniform(1,100,random())``).
|
|
1022
|
+
limit and offset do not accept data generation expressions in snowflake.
|
|
1023
|
+
"""
|
|
1024
|
+
return (
|
|
1025
|
+
has_nondeterministic_data_generation_exp(self.projection)
|
|
1026
|
+
or has_nondeterministic_data_generation_exp(
|
|
1027
|
+
[self.where] if self.where else None
|
|
1028
|
+
)
|
|
1029
|
+
or has_nondeterministic_data_generation_exp(self.order_by)
|
|
1030
|
+
)
|
|
1031
|
+
|
|
998
1032
|
@property
|
|
999
1033
|
def column_states(self) -> ColumnStateDict:
|
|
1000
1034
|
if self._column_states is None:
|
|
@@ -1386,9 +1420,9 @@ class SelectStatement(Selectable):
|
|
|
1386
1420
|
):
|
|
1387
1421
|
# TODO: Clean up, this entire if case is parameter protection
|
|
1388
1422
|
can_be_flattened = False
|
|
1389
|
-
elif (
|
|
1390
|
-
|
|
1391
|
-
):
|
|
1423
|
+
elif (
|
|
1424
|
+
self.where or self.order_by or self.limit_
|
|
1425
|
+
) and has_data_generator_or_window_function_exp(cols):
|
|
1392
1426
|
can_be_flattened = False
|
|
1393
1427
|
elif self.where and (
|
|
1394
1428
|
(subquery_dependent_columns := derive_dependent_columns(self.where))
|
|
@@ -1399,6 +1433,23 @@ class SelectStatement(Selectable):
|
|
|
1399
1433
|
subquery_dependent_columns & new_column_states.active_columns
|
|
1400
1434
|
)
|
|
1401
1435
|
)
|
|
1436
|
+
or (
|
|
1437
|
+
# unflattenable condition: dropped column is used in subquery WHERE clause and dropped column status is NEW or CHANGED in the subquery
|
|
1438
|
+
# reason: we should not flatten because the dropped column is not available in the new query, leading to WHERE clause error
|
|
1439
|
+
# sample query: 'select "b" from (select "a" as "c", "b" from table where "c" > 1)' can not be flatten to 'select "b" from table where "c" > 1'
|
|
1440
|
+
(
|
|
1441
|
+
context._is_snowpark_connect_compatible_mode
|
|
1442
|
+
and context._snowpark_connect_flatten_select_after_sort
|
|
1443
|
+
)
|
|
1444
|
+
and new_column_states.dropped_columns
|
|
1445
|
+
and any(
|
|
1446
|
+
self.column_states[_col].change_state
|
|
1447
|
+
in (ColumnChangeState.NEW, ColumnChangeState.CHANGED_EXP)
|
|
1448
|
+
for _col in (
|
|
1449
|
+
subquery_dependent_columns & new_column_states.dropped_columns
|
|
1450
|
+
)
|
|
1451
|
+
)
|
|
1452
|
+
)
|
|
1402
1453
|
):
|
|
1403
1454
|
can_be_flattened = False
|
|
1404
1455
|
elif self.order_by and (
|
|
@@ -1411,6 +1462,23 @@ class SelectStatement(Selectable):
|
|
|
1411
1462
|
subquery_dependent_columns & new_column_states.active_columns
|
|
1412
1463
|
)
|
|
1413
1464
|
)
|
|
1465
|
+
or (
|
|
1466
|
+
# unflattenable condition: dropped column is used in subquery ORDER BY clause and dropped column status is NEW or CHANGED in the subquery
|
|
1467
|
+
# reason: we should not flatten because the dropped column is not available in the new query, leading to ORDER BY clause error
|
|
1468
|
+
# sample query: 'select "b" from (select "a" as "c", "b" order by "c")' can not be flatten to 'select "b" from table order by "c"'
|
|
1469
|
+
(
|
|
1470
|
+
context._is_snowpark_connect_compatible_mode
|
|
1471
|
+
and context._snowpark_connect_flatten_select_after_sort
|
|
1472
|
+
)
|
|
1473
|
+
and new_column_states.dropped_columns
|
|
1474
|
+
and any(
|
|
1475
|
+
self.column_states[_col].change_state
|
|
1476
|
+
in (ColumnChangeState.NEW, ColumnChangeState.CHANGED_EXP)
|
|
1477
|
+
for _col in (
|
|
1478
|
+
subquery_dependent_columns & new_column_states.dropped_columns
|
|
1479
|
+
)
|
|
1480
|
+
)
|
|
1481
|
+
)
|
|
1414
1482
|
):
|
|
1415
1483
|
can_be_flattened = False
|
|
1416
1484
|
elif self.distinct_:
|
|
@@ -1456,8 +1524,62 @@ class SelectStatement(Selectable):
|
|
|
1456
1524
|
self.df_ast_ids.copy() if self.df_ast_ids is not None else None
|
|
1457
1525
|
)
|
|
1458
1526
|
else:
|
|
1527
|
+
new_order_by = None
|
|
1528
|
+
new_from = self
|
|
1529
|
+
if (
|
|
1530
|
+
context._is_snowpark_connect_compatible_mode
|
|
1531
|
+
and context._snowpark_connect_flatten_select_after_sort
|
|
1532
|
+
) and self.order_by:
|
|
1533
|
+
order_by_dependent_columns = derive_dependent_columns(*self.order_by)
|
|
1534
|
+
if order_by_dependent_columns in (
|
|
1535
|
+
COLUMN_DEPENDENCY_DOLLAR,
|
|
1536
|
+
COLUMN_DEPENDENCY_ALL,
|
|
1537
|
+
):
|
|
1538
|
+
new_order_by = None
|
|
1539
|
+
elif any(
|
|
1540
|
+
col not in self.from_.column_states
|
|
1541
|
+
and col not in self.column_states
|
|
1542
|
+
for col in order_by_dependent_columns
|
|
1543
|
+
):
|
|
1544
|
+
new_order_by = None
|
|
1545
|
+
elif any(
|
|
1546
|
+
_col not in self.column_states
|
|
1547
|
+
or self.column_states[_col].change_state
|
|
1548
|
+
in (ColumnChangeState.CHANGED_EXP, ColumnChangeState.DROPPED)
|
|
1549
|
+
for _col in order_by_dependent_columns
|
|
1550
|
+
):
|
|
1551
|
+
new_from = copy(self)
|
|
1552
|
+
missing_columns = (
|
|
1553
|
+
order_by_dependent_columns
|
|
1554
|
+
- new_from.column_states.active_columns
|
|
1555
|
+
)
|
|
1556
|
+
base_projection: List[Expression] = (
|
|
1557
|
+
new_from.projection
|
|
1558
|
+
if new_from.projection is not None
|
|
1559
|
+
else list(new_from.column_states.projection)
|
|
1560
|
+
)
|
|
1561
|
+
new_from.projection = base_projection + [
|
|
1562
|
+
Attribute(col, DataType()) for col in missing_columns
|
|
1563
|
+
]
|
|
1564
|
+
new_col_states = derive_column_states_from_subquery(
|
|
1565
|
+
new_from.projection, new_from.from_
|
|
1566
|
+
)
|
|
1567
|
+
if new_col_states is not None:
|
|
1568
|
+
new_from.column_states = new_col_states
|
|
1569
|
+
new_from._projection_in_str = None
|
|
1570
|
+
new_from._commented_sql = None
|
|
1571
|
+
new_from._sql_query = None
|
|
1572
|
+
new_order_by = self.order_by
|
|
1573
|
+
else:
|
|
1574
|
+
new_from = self
|
|
1575
|
+
new_order_by = None
|
|
1576
|
+
else:
|
|
1577
|
+
new_order_by = self.order_by
|
|
1459
1578
|
new = SelectStatement(
|
|
1460
|
-
projection=cols,
|
|
1579
|
+
projection=cols,
|
|
1580
|
+
from_=new_from.to_subqueryable(),
|
|
1581
|
+
order_by=new_order_by,
|
|
1582
|
+
analyzer=self.analyzer,
|
|
1461
1583
|
)
|
|
1462
1584
|
new._merge_projection_complexity_with_subquery = (
|
|
1463
1585
|
can_select_projection_complexity_be_merged(
|
|
@@ -1478,12 +1600,30 @@ class SelectStatement(Selectable):
|
|
|
1478
1600
|
return new
|
|
1479
1601
|
|
|
1480
1602
|
def filter(self, col: Expression) -> "SelectStatement":
|
|
1603
|
+
self._session._retrieve_aggregation_function_list()
|
|
1481
1604
|
can_be_flattened = (
|
|
1482
1605
|
(not self.flatten_disabled)
|
|
1483
1606
|
and can_clause_dependent_columns_flatten(
|
|
1484
|
-
derive_dependent_columns(col),
|
|
1607
|
+
derive_dependent_columns(col),
|
|
1608
|
+
self.column_states,
|
|
1609
|
+
"filter",
|
|
1610
|
+
# In Snowpark Connect compatible mode, the NEW-column branch
|
|
1611
|
+
# below allows flattening through any subquery. Pass
|
|
1612
|
+
# subquery_has_limit so that branch can still reject
|
|
1613
|
+
# flattening across LIMIT/OFFSET, since WHERE cannot cross
|
|
1614
|
+
# LIMIT/OFFSET without changing semantics.
|
|
1615
|
+
subquery_has_limit_or_offset=(
|
|
1616
|
+
self.limit_ is not None or self.offset is not None
|
|
1617
|
+
),
|
|
1485
1618
|
)
|
|
1486
|
-
and not
|
|
1619
|
+
and not has_data_generator_or_window_function_exp(self.projection)
|
|
1620
|
+
and not (
|
|
1621
|
+
(
|
|
1622
|
+
context._is_snowpark_connect_compatible_mode
|
|
1623
|
+
and context._snowpark_connect_flatten_select_after_sort
|
|
1624
|
+
)
|
|
1625
|
+
and has_aggregation_function_exp(self.projection)
|
|
1626
|
+
) # sum(col) as new_col, new_col can not be flattened in where clause
|
|
1487
1627
|
and not (self.order_by and self.limit_ is not None)
|
|
1488
1628
|
)
|
|
1489
1629
|
if can_be_flattened:
|
|
@@ -1509,16 +1649,12 @@ class SelectStatement(Selectable):
|
|
|
1509
1649
|
def sort(self, cols: List[Expression]) -> "SelectStatement":
|
|
1510
1650
|
can_be_flattened = (
|
|
1511
1651
|
(not self.flatten_disabled)
|
|
1512
|
-
#
|
|
1513
|
-
#
|
|
1514
|
-
# number of record is satisfied.
|
|
1515
|
-
# Therefore, disallow sql simplification when the
|
|
1516
|
-
# current SelectStatement has a limit clause to avoid moving
|
|
1517
|
-
# order by in front of limit.
|
|
1652
|
+
# Disallow flattening when the current SelectStatement has a
|
|
1653
|
+
# limit clause to avoid moving order by in front of limit.
|
|
1518
1654
|
and (not self.limit_)
|
|
1519
1655
|
and (not self.offset)
|
|
1520
1656
|
and can_clause_dependent_columns_flatten(
|
|
1521
|
-
derive_dependent_columns(*cols), self.column_states
|
|
1657
|
+
derive_dependent_columns(*cols), self.column_states, "sort"
|
|
1522
1658
|
)
|
|
1523
1659
|
and not has_data_generator_exp(self.projection)
|
|
1524
1660
|
)
|
|
@@ -1557,7 +1693,7 @@ class SelectStatement(Selectable):
|
|
|
1557
1693
|
# .order_by(col1).select(col2).distinct() cannot be flattened because
|
|
1558
1694
|
# SELECT DISTINCT B FROM TABLE ORDER BY A is not valid SQL
|
|
1559
1695
|
and (not (self.order_by and self.has_projection))
|
|
1560
|
-
and not
|
|
1696
|
+
and not has_data_generator_or_window_function_exp(self.projection)
|
|
1561
1697
|
)
|
|
1562
1698
|
if can_be_flattened:
|
|
1563
1699
|
new = copy(self)
|
|
@@ -2048,7 +2184,13 @@ def can_projection_dependent_columns_be_flattened(
|
|
|
2048
2184
|
def can_clause_dependent_columns_flatten(
|
|
2049
2185
|
dependent_columns: Optional[AbstractSet[str]],
|
|
2050
2186
|
subquery_column_states: ColumnStateDict,
|
|
2187
|
+
clause: Literal["filter", "sort"],
|
|
2188
|
+
subquery_has_limit_or_offset: bool = False,
|
|
2051
2189
|
) -> bool:
|
|
2190
|
+
assert clause in (
|
|
2191
|
+
"filter",
|
|
2192
|
+
"sort",
|
|
2193
|
+
), f"Invalid clause called in can_clause_dependent_columns_flatten: {clause}"
|
|
2052
2194
|
if dependent_columns == COLUMN_DEPENDENCY_DOLLAR:
|
|
2053
2195
|
return False
|
|
2054
2196
|
elif (
|
|
@@ -2063,15 +2205,39 @@ def can_clause_dependent_columns_flatten(
|
|
|
2063
2205
|
dc_state = subquery_column_states.get(dc)
|
|
2064
2206
|
if dc_state:
|
|
2065
2207
|
if dc_state.change_state == ColumnChangeState.CHANGED_EXP:
|
|
2066
|
-
|
|
2208
|
+
if clause == "filter":
|
|
2209
|
+
return False
|
|
2210
|
+
# sort + CHANGED_EXP: safe in SCOS mode since ORDER BY
|
|
2211
|
+
# is evaluated after projection. Keep checking remaining
|
|
2212
|
+
# columns though — another column may be unsafe.
|
|
2213
|
+
elif not (
|
|
2214
|
+
context._is_snowpark_connect_compatible_mode
|
|
2215
|
+
and context._snowpark_connect_flatten_select_after_sort
|
|
2216
|
+
):
|
|
2217
|
+
return False
|
|
2067
2218
|
elif dc_state.change_state == ColumnChangeState.NEW:
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2219
|
+
if clause == "sort" and dc_state.dependent_columns in (
|
|
2220
|
+
COLUMN_DEPENDENCY_DOLLAR,
|
|
2221
|
+
COLUMN_DEPENDENCY_ALL,
|
|
2222
|
+
):
|
|
2223
|
+
# Scalar subqueries in sort can trigger Snowflake
|
|
2224
|
+
# internal errors when ORDER BY references them
|
|
2225
|
+
# at the same SELECT level.
|
|
2226
|
+
return False
|
|
2227
|
+
if not (
|
|
2228
|
+
context._is_snowpark_connect_compatible_mode
|
|
2229
|
+
and context._snowpark_connect_flatten_select_after_sort
|
|
2230
|
+
):
|
|
2231
|
+
return False
|
|
2232
|
+
# Compatible-mode safety: even though we loosened the
|
|
2233
|
+
# NEW-column flatten rule above, we must not flatten a
|
|
2234
|
+
# WHERE across LIMIT/OFFSET on a NEW column — that
|
|
2235
|
+
# would push the filter in front of the limit and
|
|
2236
|
+
# change the result set. (Sort has its own
|
|
2237
|
+
# `not self.limit_` guard at the call site.)
|
|
2238
|
+
if clause == "filter" and subquery_has_limit_or_offset:
|
|
2239
|
+
return False
|
|
2240
|
+
|
|
2075
2241
|
return True
|
|
2076
2242
|
|
|
2077
2243
|
|
|
@@ -2295,18 +2461,139 @@ def derive_column_states_from_subquery(
|
|
|
2295
2461
|
return column_states
|
|
2296
2462
|
|
|
2297
2463
|
|
|
2298
|
-
def
|
|
2464
|
+
def _check_expressions_for_types(
|
|
2465
|
+
expressions: Optional[List["Expression"]],
|
|
2466
|
+
check_data_gen: bool = False,
|
|
2467
|
+
check_window: bool = False,
|
|
2468
|
+
check_aggregation: bool = False,
|
|
2469
|
+
) -> bool:
|
|
2470
|
+
"""Efficiently check if expressions contain specific types in a single pass.
|
|
2471
|
+
|
|
2472
|
+
Args:
|
|
2473
|
+
expressions: List of expressions to check
|
|
2474
|
+
check_data_gen: Check for data generator functions
|
|
2475
|
+
check_window: Check for window functions
|
|
2476
|
+
check_aggregation: Check for aggregation functions
|
|
2477
|
+
|
|
2478
|
+
Returns:
|
|
2479
|
+
True if any requested type is found
|
|
2480
|
+
"""
|
|
2299
2481
|
if expressions is None:
|
|
2300
2482
|
return False
|
|
2483
|
+
|
|
2301
2484
|
for exp in expressions:
|
|
2302
|
-
if
|
|
2485
|
+
if exp is None:
|
|
2486
|
+
continue
|
|
2487
|
+
|
|
2488
|
+
# Check window functions
|
|
2489
|
+
if check_window and isinstance(exp, WindowExpression):
|
|
2303
2490
|
return True
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2491
|
+
|
|
2492
|
+
if check_data_gen:
|
|
2493
|
+
if isinstance(exp, FunctionExpression) and (
|
|
2494
|
+
exp.is_data_generator
|
|
2495
|
+
or exp.name.lower() in SEQUENCE_DEPENDENT_DATA_GENERATION
|
|
2496
|
+
):
|
|
2497
|
+
# https://docs.snowflake.com/en/sql-reference/functions-data-generation
|
|
2498
|
+
return True
|
|
2499
|
+
|
|
2500
|
+
# Check aggregation functions
|
|
2501
|
+
if check_aggregation and isinstance(exp, FunctionExpression):
|
|
2502
|
+
if exp.name.lower() in context._aggregation_function_set:
|
|
2503
|
+
return True
|
|
2504
|
+
|
|
2505
|
+
# Recursively check children.
|
|
2506
|
+
# Some expression types (e.g. CaseWhen) store sub-expressions in
|
|
2507
|
+
# _child_expressions rather than children; fall back to that.
|
|
2508
|
+
sub_exps = exp.children
|
|
2509
|
+
if not sub_exps:
|
|
2510
|
+
sub_exps = getattr(exp, "_child_expressions", None)
|
|
2511
|
+
if _check_expressions_for_types(
|
|
2512
|
+
sub_exps, check_data_gen, check_window, check_aggregation
|
|
2513
|
+
):
|
|
2514
|
+
return True
|
|
2515
|
+
|
|
2516
|
+
return False
|
|
2517
|
+
|
|
2518
|
+
|
|
2519
|
+
def has_data_generator_exp(expressions: Optional[List["Expression"]]) -> bool:
|
|
2520
|
+
"""Check if expressions contain data generator functions.
|
|
2521
|
+
|
|
2522
|
+
Note:
|
|
2523
|
+
In non-connect mode, window expressions are also treated as data generators
|
|
2524
|
+
for backward compatibility.
|
|
2525
|
+
"""
|
|
2526
|
+
if not (
|
|
2527
|
+
context._is_snowpark_connect_compatible_mode
|
|
2528
|
+
and context._snowpark_connect_flatten_select_after_sort
|
|
2529
|
+
):
|
|
2530
|
+
return _check_expressions_for_types(
|
|
2531
|
+
expressions, check_data_gen=True, check_window=True
|
|
2532
|
+
)
|
|
2533
|
+
return _check_expressions_for_types(expressions, check_data_gen=True)
|
|
2534
|
+
|
|
2535
|
+
|
|
2536
|
+
def has_data_generator_or_window_function_exp(
|
|
2537
|
+
expressions: Optional[List["Expression"]],
|
|
2538
|
+
) -> bool:
|
|
2539
|
+
"""Check if expressions contain data generators or window functions."""
|
|
2540
|
+
return _check_expressions_for_types(
|
|
2541
|
+
expressions, check_data_gen=True, check_window=True
|
|
2542
|
+
)
|
|
2543
|
+
|
|
2544
|
+
|
|
2545
|
+
def has_aggregation_function_exp(expressions: Optional[List["Expression"]]) -> bool:
|
|
2546
|
+
"""Check if expressions contain aggregation functions."""
|
|
2547
|
+
return _check_expressions_for_types(expressions, check_aggregation=True)
|
|
2548
|
+
|
|
2549
|
+
|
|
2550
|
+
def has_nondeterministic_data_generation_exp(
|
|
2551
|
+
expressions: Optional[List["Expression"]],
|
|
2552
|
+
) -> bool:
|
|
2553
|
+
"""Check if expressions contain non-deterministic data generation that would
|
|
2554
|
+
produce different results when materialized once via a CTE vs evaluated
|
|
2555
|
+
multiple times.
|
|
2556
|
+
|
|
2557
|
+
This is a different check than ``has_data_generator_exp`` (which is used
|
|
2558
|
+
for SQL-flattening decisions). Here we only care about functions whose
|
|
2559
|
+
output *changes across evaluations* — i.e. true randomness or
|
|
2560
|
+
sequence-dependent generators invoked **without arguments** (zero-arg
|
|
2561
|
+
``random()``, ``uuid_string()``, ``randstr()``).
|
|
2562
|
+
|
|
2563
|
+
Generators like ``seq1(sign)``, ``uniform(lo, hi, gen)`` with explicit
|
|
2564
|
+
seed, or ``uuid_string(uuid, name)`` are *not* flagged by this function
|
|
2565
|
+
because CTE deduplication is safe for them. Note that ``seq*`` functions
|
|
2566
|
+
are not fully deterministic — values may have gaps and ordering is not
|
|
2567
|
+
guaranteed (see https://docs.snowflake.com/en/user-guide/querying-sequences),
|
|
2568
|
+
however values within a single query are always distinct. This does not
|
|
2569
|
+
affect CTE safety: the concern here is whether *re-evaluating* a subtree
|
|
2570
|
+
would produce *entirely different* values (as ``random()`` or
|
|
2571
|
+
``uuid_string()`` would), not whether sequences are gap-free or ordered.
|
|
2572
|
+
|
|
2573
|
+
Heuristic: a ``FunctionExpression`` is flagged when:
|
|
2574
|
+
- it has ``is_data_generator=True`` **and** zero arguments, OR
|
|
2575
|
+
- its name is in ``NONDETERMINISTIC_DATA_GENERATION`` **and** zero
|
|
2576
|
+
arguments, OR
|
|
2577
|
+
- any of its *children* satisfy the above recursively (catches patterns
|
|
2578
|
+
like ``uniform(1, 100, random())``).
|
|
2579
|
+
|
|
2580
|
+
The zero-arg gate safely distinguishes non-deterministic calls (e.g.
|
|
2581
|
+
``random()``) from deterministic ones (e.g. ``random(seed)``), because the
|
|
2582
|
+
latter have ``len(children) > 0``.
|
|
2583
|
+
|
|
2584
|
+
Known limitations:
|
|
2585
|
+
- ``session.sql(...)`` has no expression tree, so it cannot be
|
|
2586
|
+
auto-detected.
|
|
2587
|
+
"""
|
|
2588
|
+
if expressions is None:
|
|
2589
|
+
return False
|
|
2590
|
+
for exp in expressions:
|
|
2591
|
+
if (
|
|
2592
|
+
isinstance(exp, FunctionExpression)
|
|
2593
|
+
and len(exp.children) == 0
|
|
2594
|
+
and exp.name.lower() in NONDETERMINISTIC_DATA_GENERATION
|
|
2307
2595
|
):
|
|
2308
|
-
# https://docs.snowflake.com/en/sql-reference/functions-data-generation
|
|
2309
2596
|
return True
|
|
2310
|
-
if exp is not None and
|
|
2597
|
+
if exp is not None and has_nondeterministic_data_generation_exp(exp.children):
|
|
2311
2598
|
return True
|
|
2312
2599
|
return False
|
|
@@ -526,6 +526,14 @@ class SnowflakePlan(LogicalPlan):
|
|
|
526
526
|
compiler = PlanCompiler(self)
|
|
527
527
|
return compiler.compile()
|
|
528
528
|
|
|
529
|
+
def get_execution_queries_without_cte(self) -> Dict["PlanQueryType", List["Query"]]:
|
|
530
|
+
"""Compile execution queries with CTE optimization skipped.
|
|
531
|
+
Used for retry when CTE-optimized SQL fails at the server."""
|
|
532
|
+
from snowflake.snowpark._internal.compiler.plan_compiler import PlanCompiler
|
|
533
|
+
|
|
534
|
+
compiler = PlanCompiler(self)
|
|
535
|
+
return compiler.compile(skip_cte_optimization=True)
|
|
536
|
+
|
|
529
537
|
@property
|
|
530
538
|
def children_plan_nodes(self) -> List[Union["Selectable", "SnowflakePlan"]]:
|
|
531
539
|
"""
|
|
@@ -105,6 +105,45 @@ def find_duplicate_subtrees(
|
|
|
105
105
|
|
|
106
106
|
return False
|
|
107
107
|
|
|
108
|
+
def is_node_with_data_generation_exp(node: "TreeNode") -> bool:
|
|
109
|
+
"""Check if a tree node contains non-deterministic data-generation
|
|
110
|
+
expressions (e.g. zero-arg ``uuid_string()``, ``random()``).
|
|
111
|
+
|
|
112
|
+
CTE deduplication must be skipped for such nodes because Snowflake
|
|
113
|
+
materializes CTEs; re-using a single CTE would repeat the same
|
|
114
|
+
generated values instead of producing fresh ones per branch.
|
|
115
|
+
|
|
116
|
+
When sql_simplifier is enabled the plan tree contains
|
|
117
|
+
SelectStatement nodes whose expression trees we can inspect
|
|
118
|
+
directly. When it is disabled the plan tree uses generic
|
|
119
|
+
LogicalPlan nodes (Union, Project, …) that lack expression
|
|
120
|
+
metadata, so we fall back to a regex check on the resolved SQL.
|
|
121
|
+
"""
|
|
122
|
+
if isinstance(node, SelectStatement) and node.contains_data_generation:
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
if isinstance(node, SnowflakePlan) and isinstance(
|
|
126
|
+
node.source_plan, (SnowflakePlan, Selectable)
|
|
127
|
+
):
|
|
128
|
+
return is_node_with_data_generation_exp(node.source_plan)
|
|
129
|
+
elif (
|
|
130
|
+
isinstance(node, SnowflakePlan)
|
|
131
|
+
and node.source_plan is not None
|
|
132
|
+
and not node.session.sql_simplifier_enabled
|
|
133
|
+
):
|
|
134
|
+
# sql_simplifier disabled path — source_plan is a generic
|
|
135
|
+
# LogicalPlan (e.g. Union, Project) without expression trees
|
|
136
|
+
from snowflake.snowpark._internal.analyzer.select_statement import (
|
|
137
|
+
NONDETERMINISTIC_ZERO_ARG_RE,
|
|
138
|
+
) # prevent circular import
|
|
139
|
+
|
|
140
|
+
return bool(NONDETERMINISTIC_ZERO_ARG_RE.search(node.queries[-1].sql))
|
|
141
|
+
|
|
142
|
+
if isinstance(node, SelectSnowflakePlan):
|
|
143
|
+
return is_node_with_data_generation_exp(node.snowflake_plan)
|
|
144
|
+
|
|
145
|
+
return False
|
|
146
|
+
|
|
108
147
|
def traverse(root: "TreeNode") -> None:
|
|
109
148
|
"""
|
|
110
149
|
This function uses an iterative approach to avoid hitting Python's maximum recursion depth limit.
|
|
@@ -117,7 +156,9 @@ def find_duplicate_subtrees(
|
|
|
117
156
|
for node in current_level:
|
|
118
157
|
id_node_map[node.encoded_node_id_with_query].append(node)
|
|
119
158
|
|
|
120
|
-
if is_select_from_file_node(node)
|
|
159
|
+
if is_select_from_file_node(node) or is_node_with_data_generation_exp(
|
|
160
|
+
node
|
|
161
|
+
):
|
|
121
162
|
invalid_ids_for_deduplication.add(node.encoded_node_id_with_query)
|
|
122
163
|
|
|
123
164
|
for child in node.children_plan_nodes:
|
|
@@ -78,7 +78,9 @@ class PlanCompiler:
|
|
|
78
78
|
)
|
|
79
79
|
)
|
|
80
80
|
|
|
81
|
-
def compile(
|
|
81
|
+
def compile(
|
|
82
|
+
self, *, skip_cte_optimization: bool = False
|
|
83
|
+
) -> Dict[PlanQueryType, List[Query]]:
|
|
82
84
|
# initialize the queries with the original queries without optimization
|
|
83
85
|
final_plan = self._plan
|
|
84
86
|
queries = {
|
|
@@ -107,7 +109,10 @@ class PlanCompiler:
|
|
|
107
109
|
# 3. apply each optimizations if needed
|
|
108
110
|
# CTE optimization
|
|
109
111
|
with measure_time() as cte_time:
|
|
110
|
-
if
|
|
112
|
+
if (
|
|
113
|
+
session.cte_optimization_enabled
|
|
114
|
+
and not skip_cte_optimization
|
|
115
|
+
):
|
|
111
116
|
repeated_subquery_eliminator = RepeatedSubqueryElimination(
|
|
112
117
|
logical_plans, query_generator
|
|
113
118
|
)
|