snowflake-snowpark-python 1.52.0__tar.gz → 1.53.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.52.0 → snowflake_snowpark_python-1.53.0}/CHANGELOG.md +25 -0
- {snowflake_snowpark_python-1.52.0/src/snowflake_snowpark_python.egg-info → snowflake_snowpark_python-1.53.0}/PKG-INFO +6 -2
- snowflake_snowpark_python-1.53.0/pyproject.toml +13 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/setup.py +7 -1
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/analyzer_utils.py +158 -29
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/select_statement.py +30 -4
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/snowflake_plan.py +15 -3
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/snowflake_plan_node.py +3 -1
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/base_dialect.py +8 -4
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/databricks_dialect.py +8 -8
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/mysql_dialect.py +8 -8
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/oracledb_dialect.py +8 -8
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/postgresql_dialect.py +16 -11
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/sqlserver_dialect.py +4 -4
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/type_utils.py +120 -3
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/utils.py +204 -10
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe_reader.py +143 -10
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/functions.py +129 -18
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/lineage.py +9 -2
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/session.py +11 -4
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/table.py +37 -4
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/version.py +1 -1
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0/src/snowflake_snowpark_python.egg-info}/PKG-INFO +6 -2
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake_snowpark_python.egg-info/requires.txt +9 -1
- snowflake_snowpark_python-1.52.0/pyproject.toml +0 -7
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/LICENSE.txt +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/MANIFEST.in +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/README.md +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/setup.cfg +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_functions/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_functions/general_functions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_functions/scalar_functions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/analyzer.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/binary_expression.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/binary_plan_node.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/datatype_mapper.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/expression.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/grouping_set.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/metadata_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/query_plan_analysis_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/schema_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/sort_expression.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/table_function.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/table_merge_expression.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/unary_expression.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/unary_plan_node.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/analyzer/window_expression.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/ast/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/ast/batch.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/ast/builder.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/ast/utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/code_generation.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/cte_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/large_query_breakdown.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/plan_compiler.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/query_generator.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/repeated_subquery_elimination.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/telemetry_constants.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/compiler/utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/datasource_partitioner.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/datasource_reader.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/datasource_typing.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/dbms_dialects/sqlite3_dialect.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/base_driver.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/databricks_driver.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/oracledb_driver.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/psycopg2_driver.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/pymsql_driver.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/pyodbc_driver.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/drivers/sqlite_driver.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/jdbc.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/data_source/utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/debug_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/error_message.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/event_table_telemetry.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/open_telemetry.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/packaging_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/proto/generated/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/proto/generated/ast_pb2.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/proto/generated/ast_pb2.pyi +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/select_projection_complexity_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/server_connection.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/snowpark_profiler.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/telemetry.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/temp_table_auto_cleaner.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/udf_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/xml_reader.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/xml_schema_inference.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/_internal/xpath_handlers.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/async_job.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/catalog.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/column.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/context.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe_ai_functions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe_analytics_functions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe_na_functions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe_profiler.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe_stat_functions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/dataframe_writer.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/exceptions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/file_operation.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/files.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_analyzer.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_connection.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_constants.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_functions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_nop_analyzer.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_nop_connection.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_nop_plan.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_options.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_pandas_util.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_plan.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_plan_builder.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_select_statement.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_snowflake_data_type.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_snowflake_to_pandas_converter.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_stage_registry.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_stored_procedure.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_telemetry.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_udaf.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_udf.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_udf_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_udtf.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_util.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/_window_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/mock/exceptions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/config/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/config/__main__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/config/envvars.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/config/pubsub.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/conftest.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/aggregation_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/align_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/apply_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/binary_op_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/concat_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/cumulative_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/cut_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/frame.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/generator_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/get_dummies_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/groupby_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/indexing_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/io_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/isin_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/join_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/ordered_dataframe.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/pivot_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/resample_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/row_count_estimation.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/session.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/snowpark_pandas_types.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/statement_params_constants.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/telemetry.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/timestamp_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/transpose_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/type_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/unpivot_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/where_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_internal/window_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/_typing.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/compiler/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/compiler/doc_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/compiler/ray_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/compiler/snowflake_query_compiler.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/base.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/dataframe.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/datetime_index.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/general.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/groupby.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/index.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/io.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/resample.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/series.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/series_utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/shared_docs.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/timedelta_index.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/docstrings/window.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/base_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/dataframe_extensions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/dataframe_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/dataframe_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/datetime_index.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/general_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/index.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/indexing_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/io_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/pd_extensions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/resample_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/resampler_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/rolling_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/series_extensions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/series_groupby_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/series_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/snow_partition_iterator.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/timedelta_index.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/extensions/window_overrides.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/io/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/io/factories.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/io/snow_io.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/utils/__init__.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/utils/error_message.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/utils/exceptions.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/utils/frontend_constants.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/utils/numpy_to_pandas.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/plugin/utils/warning_message.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/modin/utils.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/py.typed +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/query_history.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/relational_grouped_dataframe.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/row.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/secrets.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/stored_procedure.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/stored_procedure_profiler.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/table_function.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/testing.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/types.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/udaf.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/udf.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/udf_profiler.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/udtf.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake/snowpark/window.py +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake_snowpark_python.egg-info/SOURCES.txt +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake_snowpark_python.egg-info/dependency_links.txt +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake_snowpark_python.egg-info/namespace_packages.txt +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake_snowpark_python.egg-info/not-zip-safe +0 -0
- {snowflake_snowpark_python-1.52.0 → snowflake_snowpark_python-1.53.0}/src/snowflake_snowpark_python.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Release History
|
|
2
2
|
|
|
3
|
+
## 1.53.0 (2026-07-09)
|
|
4
|
+
|
|
5
|
+
### Snowpark Python API Updates
|
|
6
|
+
|
|
7
|
+
#### New Features
|
|
8
|
+
|
|
9
|
+
- Added the `udf_init_once` decorator in `snowflake.snowpark.functions` for marking functions to be executed once during pre-fork initialization on Snowflake workers, matching the server-side `_snowflake.udf_init_once` API.
|
|
10
|
+
|
|
11
|
+
#### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- Fixed a bug where stage paths and file format names that contain single quotes were not consistently escaped when generating SQL, which could produce malformed statements. This affects `INFER_SCHEMA` (used by `DataFrameReader.csv`/`json`/`parquet`/`orc`/`avro`) and `COPY FILES` (used by `FileOperation.copy_files`).
|
|
14
|
+
- Fixed a bug where single quotes and backslashes in stage/file paths were not correctly escaped when generating `COPY INTO` / `PUT` / `GET` SQL, which could produce malformed statements. This affects `DataFrame.write.csv`/`copy_into_location` and the Snowpark-pandas `DataFrame.to_csv` stage path.
|
|
15
|
+
- Fixed a bug where column names containing quote characters returned by an external database were not correctly escaped when generating the `SELECT` query for `DataFrameReader.dbapi`, which could produce malformed SQL. Embedded quote characters in identifiers are now doubled (backticks for Databricks/MySQL, double quotes for Oracle/PostgreSQL/SQL Server).
|
|
16
|
+
- Fixed a bug where the destination passed to `DataFrameWriter.copy_into_location` (and `csv`/`json`/`parquet`/`save`) was embedded into the generated `COPY INTO` statement without quoting, which could produce malformed SQL for locations containing single quotes. The location is now consistently quoted and escaped, and a string that merely starts and ends with a single quote but contains unescaped interior quotes is no longer treated as an already-quoted literal; it is fully escaped so it stays a single SQL string literal.
|
|
17
|
+
- Fixed a bug where UDF default argument values reconstructed from a source file in `register_from_file` were evaluated with `eval()`; they are now evaluated only against the documented set of supported default-value types, and unsupported expressions are ignored.
|
|
18
|
+
- Fixed a bug where `object_name`, `object_domain`, or `object_version` values containing single quotes or backslashes in `session.lineage.trace()` caused incorrect SQL generation. These values are now properly escaped before being embedded in the `SYSTEM$DGQL` call.
|
|
19
|
+
- Fixed a bug where single quotes and backslashes in `comment` (`create_or_replace_view` / dynamic table / `save_as_table`), collation specs (`Column.collate`), VARIANT/OBJECT subfield keys (`Column[...]`), and `DataFrame`/`Session.flatten` paths were not correctly escaped when generating SQL, which could produce malformed statements. Backslash sequences (e.g. `\t`, `\n`) in these values are now applied literally rather than interpreted.
|
|
20
|
+
- Fixed a bug where string values in the AI functions (`ai_extract`, `ai_classify`, `ai_similarity`, `ai_parse_document`, `ai_transcribe`, `ai_complete`) configuration and `response_format` were not correctly escaped when generating the SQL object literal, which could produce malformed statements when a value contained single quotes or backslashes (for example, an apostrophe in a natural-language question).
|
|
21
|
+
|
|
22
|
+
#### Dependency Updates
|
|
23
|
+
|
|
24
|
+
- Lifted `protobuf` restriction for Python 3.14 from `==5.29.3` to `>=5.29.3,<6.34`.
|
|
25
|
+
- Capped `pandas` to `<3.0.0` for the `[pandas]` install extra, as Snowpark Python pandas-related features may not be fully compatible with pandas 3.0 or later.
|
|
26
|
+
|
|
3
27
|
## 1.52.0 (2026-06-10)
|
|
4
28
|
|
|
5
29
|
### Snowpark Python API Updates
|
|
@@ -17,6 +41,7 @@
|
|
|
17
41
|
#### Improvements
|
|
18
42
|
|
|
19
43
|
- Improved CTE optimization to deduplicate identical subtrees in self-joins, which were previously emitted as repeated subqueries.
|
|
44
|
+
- Reduced the size of generated query text for repeated join operations.
|
|
20
45
|
|
|
21
46
|
#### Deprecations
|
|
22
47
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: snowflake-snowpark-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.53.0
|
|
4
4
|
Summary: Snowflake Snowpark for Python
|
|
5
5
|
Home-page: https://www.snowflake.com/
|
|
6
6
|
Author: Snowflake, Inc
|
|
@@ -41,13 +41,16 @@ Requires-Dist: snowflake-connector-python<5.0.0,>=3.17.0
|
|
|
41
41
|
Requires-Dist: typing-extensions<5.0.0,>=4.1.0
|
|
42
42
|
Requires-Dist: pyyaml
|
|
43
43
|
Requires-Dist: cloudpickle!=2.1.0,!=2.2.0,<=3.1.1,>=1.6.0
|
|
44
|
-
Requires-Dist: protobuf<6.34,>=3.20
|
|
44
|
+
Requires-Dist: protobuf<6.34,>=3.20; python_version < "3.14"
|
|
45
|
+
Requires-Dist: protobuf<6.34,>=5.29.0; python_version >= "3.14"
|
|
45
46
|
Requires-Dist: python-dateutil
|
|
46
47
|
Requires-Dist: tzlocal
|
|
47
48
|
Provides-Extra: pandas
|
|
48
49
|
Requires-Dist: snowflake-connector-python[pandas]<5.0.0,>=3.17.0; extra == "pandas"
|
|
50
|
+
Requires-Dist: pandas<3.0.0; extra == "pandas"
|
|
49
51
|
Provides-Extra: modin
|
|
50
52
|
Requires-Dist: snowflake-connector-python[pandas]<5.0.0,>=3.17.0; extra == "modin"
|
|
53
|
+
Requires-Dist: pandas<3.0.0; extra == "modin"
|
|
51
54
|
Requires-Dist: modin<0.38.0,>=0.36.0; extra == "modin"
|
|
52
55
|
Requires-Dist: pandas<=2.4; extra == "modin"
|
|
53
56
|
Requires-Dist: tqdm; extra == "modin"
|
|
@@ -76,6 +79,7 @@ Requires-Dist: lxml; extra == "development"
|
|
|
76
79
|
Requires-Dist: pyarrow; extra == "development"
|
|
77
80
|
Provides-Extra: modin-development
|
|
78
81
|
Requires-Dist: snowflake-connector-python[pandas]<5.0.0,>=3.17.0; extra == "modin-development"
|
|
82
|
+
Requires-Dist: pandas<3.0.0; extra == "modin-development"
|
|
79
83
|
Requires-Dist: modin<0.38.0,>=0.36.0; extra == "modin-development"
|
|
80
84
|
Requires-Dist: pandas<=2.4; extra == "modin-development"
|
|
81
85
|
Requires-Dist: tqdm; extra == "modin-development"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [
|
|
3
|
+
"setuptools",
|
|
4
|
+
# py>=3.14: protoc-wheel-0 has no cp314 wheel on PyPI, so it cannot be installed
|
|
5
|
+
# in pip's build isolation venv. setup.py falls back to shutil.which("protoc").
|
|
6
|
+
"protoc-wheel-0==21.1; python_version < '3.14'", # Protocol buffer compiler for Snowpark IR
|
|
7
|
+
# py>=3.14: pin <=3.6.0 so the build isolation venv does not install mypy-protobuf 5.x,
|
|
8
|
+
# whose extensions_pb2.py was generated with protobuf 6.x gencode and fails at import
|
|
9
|
+
# time when the isolated venv resolves protobuf 5.x (Snowflake internal channel).
|
|
10
|
+
"mypy-protobuf<=3.6.0; python_version >= '3.14'",
|
|
11
|
+
"mypy-protobuf; python_version < '3.14'", # used in generating typed Python code from protobuf for Snowpark IR
|
|
12
|
+
]
|
|
13
|
+
build-backend = "setuptools.build_meta"
|
|
@@ -28,7 +28,12 @@ INSTALL_REQ_LIST = [
|
|
|
28
28
|
"pyyaml",
|
|
29
29
|
"cloudpickle>=1.6.0,<=3.1.1,!=2.1.0,!=2.2.0",
|
|
30
30
|
# `protoc` < 3.20 is not able to generate protobuf code compatible with protobuf >= 3.20.
|
|
31
|
-
"protobuf>=3.20, <6.34", # Snowpark IR
|
|
31
|
+
"protobuf>=3.20, <6.34; python_version < '3.14'", # Snowpark IR
|
|
32
|
+
# py314: protoc-wheel-0 has no cp314 wheel; setup.py uses libprotobuf's protoc from PATH.
|
|
33
|
+
# The pre-generated ast_pb2.py in the tarball has no ValidateProtobufRuntimeVersion call
|
|
34
|
+
# (built with protoc 3.21), so 5.29.0+ is sufficient. Conda recipes may regenerate with
|
|
35
|
+
# a different protoc version and override this constraint via their run deps.
|
|
36
|
+
"protobuf>=5.29.0,<6.34; python_version >= '3.14'", # Snowpark IR
|
|
32
37
|
"python-dateutil", # Snowpark IR
|
|
33
38
|
"tzlocal", # Snowpark IR
|
|
34
39
|
]
|
|
@@ -39,6 +44,7 @@ if os.getenv("SNOWFLAKE_IS_PYTHON_RUNTIME_TEST", False):
|
|
|
39
44
|
|
|
40
45
|
PANDAS_REQUIREMENTS = [
|
|
41
46
|
f"snowflake-connector-python[pandas]{CONNECTOR_DEPENDENCY_VERSION}",
|
|
47
|
+
"pandas<3.0.0",
|
|
42
48
|
]
|
|
43
49
|
MODIN_REQUIREMENTS = [
|
|
44
50
|
*PANDAS_REQUIREMENTS,
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import json
|
|
7
7
|
import math
|
|
8
8
|
import os
|
|
9
|
+
import re
|
|
9
10
|
import tempfile
|
|
10
11
|
from typing import Any, Dict, List, Optional, Tuple, Union, Literal, Sequence
|
|
11
12
|
|
|
@@ -40,7 +41,8 @@ from snowflake.snowpark._internal.utils import (
|
|
|
40
41
|
EMPTY_STRING,
|
|
41
42
|
TempObjectType,
|
|
42
43
|
escape_quotes,
|
|
43
|
-
|
|
44
|
+
escape_quotes_and_backslashes,
|
|
45
|
+
escape_subfield_key,
|
|
44
46
|
get_temp_type_for_object,
|
|
45
47
|
is_single_quoted,
|
|
46
48
|
is_sql_select_statement,
|
|
@@ -402,7 +404,26 @@ def regexp_expression(expr: str, pattern: str, parameters: Optional[str] = None)
|
|
|
402
404
|
|
|
403
405
|
|
|
404
406
|
def collate_expression(expr: str, collation_spec: str) -> str:
|
|
405
|
-
|
|
407
|
+
# Escape the collation spec so a value containing single quotes or
|
|
408
|
+
# backslashes does not terminate the single-quoted literal early and produce
|
|
409
|
+
# invalid SQL.
|
|
410
|
+
#
|
|
411
|
+
# Preserve the historical behavior of single_quote(): a spec that is already
|
|
412
|
+
# wrapped in single quotes (e.g. "'en_US'") is treated as pre-quoted, so we
|
|
413
|
+
# strip the outer quotes, escape the interior, and re-wrap. An unquoted spec
|
|
414
|
+
# is escaped and wrapped. Specs (quoted or unquoted) with no interior quotes
|
|
415
|
+
# or backslashes therefore produce identical SQL to before.
|
|
416
|
+
if is_single_quoted(collation_spec):
|
|
417
|
+
inner = collation_spec[1:-1]
|
|
418
|
+
else:
|
|
419
|
+
inner = collation_spec
|
|
420
|
+
return (
|
|
421
|
+
expr
|
|
422
|
+
+ COLLATE
|
|
423
|
+
+ SINGLE_QUOTE
|
|
424
|
+
+ escape_quotes_and_backslashes(inner)
|
|
425
|
+
+ SINGLE_QUOTE
|
|
426
|
+
)
|
|
406
427
|
|
|
407
428
|
|
|
408
429
|
def subfield_expression(expr: str, field: Union[str, int]) -> str:
|
|
@@ -410,7 +431,12 @@ def subfield_expression(expr: str, field: Union[str, int]) -> str:
|
|
|
410
431
|
expr
|
|
411
432
|
+ LEFT_BRACKET
|
|
412
433
|
+ (
|
|
413
|
-
|
|
434
|
+
# Escape the field so a VARIANT/OBJECT key containing single quotes
|
|
435
|
+
# or backslashes does not terminate the literal early. A key whose
|
|
436
|
+
# single quotes are already doubled is preserved unchanged (minus
|
|
437
|
+
# backslash normalization) to keep the historical "double your own
|
|
438
|
+
# quotes" contract non-breaking.
|
|
439
|
+
SINGLE_QUOTE + escape_subfield_key(field) + SINGLE_QUOTE
|
|
414
440
|
if isinstance(field, str)
|
|
415
441
|
else str(field)
|
|
416
442
|
)
|
|
@@ -431,7 +457,10 @@ def flatten_expression(
|
|
|
431
457
|
+ PATH
|
|
432
458
|
+ RIGHT_ARROW
|
|
433
459
|
+ SINGLE_QUOTE
|
|
434
|
-
|
|
460
|
+
# Escape the JSON path so a value containing single quotes or
|
|
461
|
+
# backslashes does not terminate the literal early and produce invalid
|
|
462
|
+
# SQL in the FLATTEN argument list.
|
|
463
|
+
+ (escape_quotes_and_backslashes(path) if path else EMPTY_STRING)
|
|
435
464
|
+ SINGLE_QUOTE
|
|
436
465
|
+ COMMA
|
|
437
466
|
+ OUTER
|
|
@@ -961,6 +990,33 @@ def lateral_join_statement(
|
|
|
961
990
|
)
|
|
962
991
|
|
|
963
992
|
|
|
993
|
+
_SELECT_STAR_FROM_PREFIX = SELECT + STAR + NEW_LINE + FROM + LEFT_PARENTHESIS + NEW_LINE
|
|
994
|
+
_SELECT_STAR_FROM_SUFFIX = NEW_LINE + RIGHT_PARENTHESIS
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
def _unwrap_select_star_from(sql: str) -> Optional[str]:
|
|
998
|
+
"""If sql is a join-produced `SELECT * FROM (\n<join_source>\n)` (the
|
|
999
|
+
output of project_statement([], join_source)), return <join_source>.
|
|
1000
|
+
Only unwraps when the inner content starts with '(' (possibly preceded
|
|
1001
|
+
by UUID trace comments) which indicates a parenthesized join operand
|
|
1002
|
+
rather than a wrapped SELECT statement."""
|
|
1003
|
+
if sql.startswith(_SELECT_STAR_FROM_PREFIX) and sql.endswith(
|
|
1004
|
+
_SELECT_STAR_FROM_SUFFIX
|
|
1005
|
+
):
|
|
1006
|
+
inner = sql[len(_SELECT_STAR_FROM_PREFIX) : -len(_SELECT_STAR_FROM_SUFFIX)]
|
|
1007
|
+
# In trace-SQL mode, UUID comments (\n-- <uuid>\n) may precede the
|
|
1008
|
+
# opening parenthesis. Strip them before checking.
|
|
1009
|
+
check = inner.lstrip("\n")
|
|
1010
|
+
if check.startswith("--"):
|
|
1011
|
+
# Skip the comment line and any trailing newline
|
|
1012
|
+
newline_pos = check.find("\n")
|
|
1013
|
+
if newline_pos != -1:
|
|
1014
|
+
check = check[newline_pos + 1 :]
|
|
1015
|
+
if check.startswith(LEFT_PARENTHESIS) or inner.startswith(LEFT_PARENTHESIS):
|
|
1016
|
+
return inner
|
|
1017
|
+
return None
|
|
1018
|
+
|
|
1019
|
+
|
|
964
1020
|
def snowflake_supported_join_statement(
|
|
965
1021
|
left: str,
|
|
966
1022
|
right: str,
|
|
@@ -971,17 +1027,30 @@ def snowflake_supported_join_statement(
|
|
|
971
1027
|
left_uuid: Optional[str] = None,
|
|
972
1028
|
right_uuid: Optional[str] = None,
|
|
973
1029
|
directed: bool = False,
|
|
1030
|
+
left_is_join: bool = False,
|
|
974
1031
|
) -> str:
|
|
975
1032
|
LEFT_UUID = format_uuid(left_uuid)
|
|
976
1033
|
RIGHT_UUID = format_uuid(right_uuid)
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1034
|
+
|
|
1035
|
+
# If left is the output of a previous join, flatten into a multi-way join
|
|
1036
|
+
# by unwrapping the SELECT * FROM (...) envelope and appending the new
|
|
1037
|
+
# right operand directly to the existing join source. This avoids nested
|
|
1038
|
+
# SELECT * layers that inflate query text without changing semantics.
|
|
1039
|
+
#
|
|
1040
|
+
# Though it is technically less efficient than constructing the join sub-queries
|
|
1041
|
+
# without the SELECT in the first place, the structure of our SQL processing code
|
|
1042
|
+
# needs top-level projections to be wrapped by a select to be well-formed, so we
|
|
1043
|
+
# must strip it here instead.
|
|
1044
|
+
#
|
|
1045
|
+
# We only unwrap the left side because it is simpler to deal with than unwrapping
|
|
1046
|
+
# both left and right, and left-deep chains are more common, as they're produced
|
|
1047
|
+
# by calls like df1.join(df2).join(df3) etc.
|
|
1048
|
+
unwrapped_left = _unwrap_select_star_from(left) if left_is_join else None
|
|
982
1049
|
right_alias = (
|
|
983
1050
|
"SNOWPARK_RIGHT"
|
|
984
|
-
if use_constant_subquery_alias
|
|
1051
|
+
if use_constant_subquery_alias and unwrapped_left is None
|
|
1052
|
+
# Multi-way join: right alias must be unique to avoid collisions
|
|
1053
|
+
# with aliases already present in the flattened join source.
|
|
985
1054
|
else random_name_for_temp_object(TempObjectType.TABLE)
|
|
986
1055
|
)
|
|
987
1056
|
|
|
@@ -1017,18 +1086,31 @@ def snowflake_supported_join_statement(
|
|
|
1017
1086
|
|
|
1018
1087
|
maybe_directed_sql = DIRECTED_JOIN if directed else JOIN
|
|
1019
1088
|
|
|
1089
|
+
if unwrapped_left is not None:
|
|
1090
|
+
# No need for additional parentheses around the left expression here, since it
|
|
1091
|
+
# should already be parenthesized
|
|
1092
|
+
left_expr = LEFT_UUID + unwrapped_left + NEW_LINE + LEFT_UUID
|
|
1093
|
+
else:
|
|
1094
|
+
left_alias = (
|
|
1095
|
+
"SNOWPARK_LEFT"
|
|
1096
|
+
if use_constant_subquery_alias
|
|
1097
|
+
else random_name_for_temp_object(TempObjectType.TABLE)
|
|
1098
|
+
)
|
|
1099
|
+
left_expr = (
|
|
1100
|
+
LEFT_PARENTHESIS
|
|
1101
|
+
+ NEW_LINE
|
|
1102
|
+
+ LEFT_UUID
|
|
1103
|
+
+ left
|
|
1104
|
+
+ NEW_LINE
|
|
1105
|
+
+ LEFT_UUID
|
|
1106
|
+
+ RIGHT_PARENTHESIS
|
|
1107
|
+
+ AS
|
|
1108
|
+
+ left_alias
|
|
1109
|
+
+ SPACE
|
|
1110
|
+
+ NEW_LINE
|
|
1111
|
+
)
|
|
1020
1112
|
source = (
|
|
1021
|
-
|
|
1022
|
-
+ NEW_LINE
|
|
1023
|
-
+ LEFT_UUID
|
|
1024
|
-
+ left
|
|
1025
|
-
+ NEW_LINE
|
|
1026
|
-
+ LEFT_UUID
|
|
1027
|
-
+ RIGHT_PARENTHESIS
|
|
1028
|
-
+ AS
|
|
1029
|
-
+ left_alias
|
|
1030
|
-
+ SPACE
|
|
1031
|
-
+ NEW_LINE
|
|
1113
|
+
left_expr
|
|
1032
1114
|
+ join_sql
|
|
1033
1115
|
+ maybe_directed_sql
|
|
1034
1116
|
+ NEW_LINE
|
|
@@ -1060,6 +1142,7 @@ def join_statement(
|
|
|
1060
1142
|
left_uuid: Optional[str] = None,
|
|
1061
1143
|
right_uuid: Optional[str] = None,
|
|
1062
1144
|
directed: bool = False,
|
|
1145
|
+
left_is_join: bool = False,
|
|
1063
1146
|
) -> str:
|
|
1064
1147
|
if isinstance(join_type, (LeftSemi, LeftAnti)):
|
|
1065
1148
|
return left_semi_or_anti_join_statement(
|
|
@@ -1087,12 +1170,18 @@ def join_statement(
|
|
|
1087
1170
|
left_uuid=left_uuid,
|
|
1088
1171
|
right_uuid=right_uuid,
|
|
1089
1172
|
directed=directed,
|
|
1173
|
+
left_is_join=left_is_join,
|
|
1090
1174
|
)
|
|
1091
1175
|
|
|
1092
1176
|
|
|
1093
1177
|
def get_comment_sql(comment: Optional[str]) -> str:
|
|
1094
1178
|
return (
|
|
1095
|
-
COMMENT + EQUALS + SINGLE_QUOTE
|
|
1179
|
+
COMMENT + EQUALS + SINGLE_QUOTE
|
|
1180
|
+
# Escape backslashes and single quotes so a comment containing those
|
|
1181
|
+
# characters does not terminate the single-quoted literal early and
|
|
1182
|
+
# produce invalid SQL. A comment with no backslash/quote is emitted
|
|
1183
|
+
# unchanged.
|
|
1184
|
+
+ escape_quotes_and_backslashes(comment) + SINGLE_QUOTE
|
|
1096
1185
|
if comment
|
|
1097
1186
|
else EMPTY_STRING
|
|
1098
1187
|
)
|
|
@@ -1316,13 +1405,11 @@ def infer_schema_statement(
|
|
|
1316
1405
|
+ LEFT_PARENTHESIS
|
|
1317
1406
|
+ LOCATION
|
|
1318
1407
|
+ RIGHT_ARROW
|
|
1319
|
-
+ (path
|
|
1408
|
+
+ single_quote(path)
|
|
1320
1409
|
+ COMMA
|
|
1321
1410
|
+ FILE_FORMAT
|
|
1322
1411
|
+ RIGHT_ARROW
|
|
1323
|
-
+
|
|
1324
|
-
+ file_format_name
|
|
1325
|
-
+ SINGLE_QUOTE
|
|
1412
|
+
+ single_quote(file_format_name)
|
|
1326
1413
|
+ (
|
|
1327
1414
|
", "
|
|
1328
1415
|
+ ", ".join(
|
|
@@ -1351,7 +1438,14 @@ def file_operation_statement(
|
|
|
1351
1438
|
return f"{REMOVE}{stage_location}{get_options_statement(options)}"
|
|
1352
1439
|
if command.lower() == "copy_files":
|
|
1353
1440
|
# For COPY FILES, file_name stores the value of the source stage location or subquery (from a DataFrame)
|
|
1354
|
-
|
|
1441
|
+
# Quote stage_location; file_name may be a subquery that must not be quoted
|
|
1442
|
+
quoted_target = single_quote(stage_location)
|
|
1443
|
+
# If file_name is a subquery (starts with '('), don't quote it
|
|
1444
|
+
if file_name.strip().startswith("("):
|
|
1445
|
+
source = file_name
|
|
1446
|
+
else:
|
|
1447
|
+
source = single_quote(file_name)
|
|
1448
|
+
return f"{COPY_FILES}{INTO}{quoted_target}{FROM}{source}{get_options_statement(options)}"
|
|
1355
1449
|
raise ValueError(f"Unsupported file operation type {command}")
|
|
1356
1450
|
|
|
1357
1451
|
|
|
@@ -1871,7 +1965,7 @@ def copy_into_location(
|
|
|
1871
1965
|
return (
|
|
1872
1966
|
COPY
|
|
1873
1967
|
+ INTO
|
|
1874
|
-
+ stage_location
|
|
1968
|
+
+ escape_location_literal(stage_location)
|
|
1875
1969
|
+ FROM
|
|
1876
1970
|
+ LEFT_PARENTHESIS
|
|
1877
1971
|
+ query
|
|
@@ -2079,12 +2173,47 @@ def table(content: str) -> str:
|
|
|
2079
2173
|
|
|
2080
2174
|
|
|
2081
2175
|
def single_quote(value: str) -> str:
|
|
2082
|
-
if
|
|
2176
|
+
if is_single_quoted(value):
|
|
2083
2177
|
return value
|
|
2084
2178
|
else:
|
|
2179
|
+
# Double any embedded single quotes so the value stays a single literal
|
|
2180
|
+
value = value.replace("'", "''")
|
|
2085
2181
|
return SINGLE_QUOTE + value + SINGLE_QUOTE
|
|
2086
2182
|
|
|
2087
2183
|
|
|
2184
|
+
# Matches a complete, well-formed single-quoted SQL literal. The three body
|
|
2185
|
+
# alternatives each start with a different character (non-quote/non-backslash,
|
|
2186
|
+
# ', \), so every input character fits exactly one branch -- the engine never
|
|
2187
|
+
# backtracks, giving linear-time matching even on adversarial input.
|
|
2188
|
+
# Matches: "'@stage/o''clock/'" (interior quote is doubled -> one literal)
|
|
2189
|
+
# No match: "'@x' UNION SELECT --'" (bare interior quote ends the literal early)
|
|
2190
|
+
_WELL_FORMED_SINGLE_QUOTED_LITERAL = re.compile(
|
|
2191
|
+
r"""
|
|
2192
|
+
' # opening single quote
|
|
2193
|
+
( # body: zero or more of...
|
|
2194
|
+
[^'\\] # any char that is neither a quote nor a backslash
|
|
2195
|
+
| '' # or a doubled (escaped) quote
|
|
2196
|
+
| \\. # or a backslash followed by any char (backslash escape)
|
|
2197
|
+
)*
|
|
2198
|
+
' # closing single quote
|
|
2199
|
+
""",
|
|
2200
|
+
re.VERBOSE | re.DOTALL,
|
|
2201
|
+
)
|
|
2202
|
+
|
|
2203
|
+
|
|
2204
|
+
def escape_location_literal(value: str) -> str:
|
|
2205
|
+
"""Return ``value`` as a single, well-formed single-quoted SQL literal.
|
|
2206
|
+
|
|
2207
|
+
Unlike :func:`single_quote`, a value that merely starts and ends with a
|
|
2208
|
+
single quote but contains unescaped interior quotes is treated as unquoted
|
|
2209
|
+
and fully escaped. This prevents a caller-controlled location from breaking
|
|
2210
|
+
out of the string literal in the generated ``COPY INTO`` statement.
|
|
2211
|
+
"""
|
|
2212
|
+
if _WELL_FORMED_SINGLE_QUOTED_LITERAL.fullmatch(value):
|
|
2213
|
+
return value
|
|
2214
|
+
return SINGLE_QUOTE + value.replace("'", "''") + SINGLE_QUOTE
|
|
2215
|
+
|
|
2216
|
+
|
|
2088
2217
|
def quote_name_without_upper_casing(name: str) -> str:
|
|
2089
2218
|
return DOUBLE_QUOTE + escape_quotes(name) + DOUBLE_QUOTE
|
|
2090
2219
|
|
|
@@ -269,6 +269,7 @@ class Selectable(LogicalPlan, ABC):
|
|
|
269
269
|
self.pre_actions: Optional[List["Query"]] = None
|
|
270
270
|
self.post_actions: Optional[List["Query"]] = None
|
|
271
271
|
self.flatten_disabled: bool = False
|
|
272
|
+
self.protect_dropped_new_columns: bool = False
|
|
272
273
|
self._column_states: Optional[ColumnStateDict] = None
|
|
273
274
|
self._snowflake_plan: Optional[SnowflakePlan] = None
|
|
274
275
|
self.expr_to_alias = (
|
|
@@ -444,6 +445,19 @@ class Selectable(LogicalPlan, ABC):
|
|
|
444
445
|
# Add the last df ast id to the snowflake plan as the most recent
|
|
445
446
|
# dataframe operation to create this plan.
|
|
446
447
|
self._snowflake_plan.df_ast_ids = self.df_ast_ids
|
|
448
|
+
# Propagate join output flag through passthrough SelectStatements
|
|
449
|
+
# so chained joins can flatten into multi-way joins.
|
|
450
|
+
# Only SelectStatement has has_clause/has_projection; other
|
|
451
|
+
# Selectable subclasses (SelectSQL, SetStatement, etc.) skip this.
|
|
452
|
+
if (
|
|
453
|
+
isinstance(self, SelectStatement)
|
|
454
|
+
and not self.has_clause
|
|
455
|
+
and not self.has_projection
|
|
456
|
+
and isinstance(self.from_, SelectSnowflakePlan)
|
|
457
|
+
):
|
|
458
|
+
self._snowflake_plan._is_join_output = (
|
|
459
|
+
self.from_._snowflake_plan._is_join_output
|
|
460
|
+
)
|
|
447
461
|
return self._snowflake_plan
|
|
448
462
|
|
|
449
463
|
@property
|
|
@@ -590,7 +604,11 @@ class SelectableEntity(Selectable):
|
|
|
590
604
|
# Metadata/Attributes for the plan
|
|
591
605
|
self._attributes: Optional[List[Attribute]] = None
|
|
592
606
|
self.table_reference = self.entity.name
|
|
593
|
-
if self.entity.
|
|
607
|
+
if self.entity.iceberg_changes_config is not None:
|
|
608
|
+
self.table_reference += (
|
|
609
|
+
self.entity.iceberg_changes_config.generate_sql_clause()
|
|
610
|
+
)
|
|
611
|
+
elif self.entity.time_travel_config is not None:
|
|
594
612
|
self.table_reference += self.entity.time_travel_config.generate_sql_clause()
|
|
595
613
|
|
|
596
614
|
def __deepcopy__(self, memodict={}) -> "SelectableEntity": # noqa: B006
|
|
@@ -1486,7 +1504,7 @@ class SelectStatement(Selectable):
|
|
|
1486
1504
|
can_be_flattened = False
|
|
1487
1505
|
else:
|
|
1488
1506
|
can_be_flattened = can_select_statement_be_flattened(
|
|
1489
|
-
self.column_states, new_column_states
|
|
1507
|
+
self.column_states, new_column_states, self.protect_dropped_new_columns
|
|
1490
1508
|
)
|
|
1491
1509
|
|
|
1492
1510
|
if can_be_flattened:
|
|
@@ -2183,7 +2201,9 @@ def parse_column_name(
|
|
|
2183
2201
|
|
|
2184
2202
|
|
|
2185
2203
|
def can_select_statement_be_flattened(
|
|
2186
|
-
subquery_column_states: ColumnStateDict,
|
|
2204
|
+
subquery_column_states: ColumnStateDict,
|
|
2205
|
+
new_column_states: ColumnStateDict,
|
|
2206
|
+
protect_dropped_new_columns: bool = False,
|
|
2187
2207
|
) -> bool:
|
|
2188
2208
|
for col, state in new_column_states.items():
|
|
2189
2209
|
dependent_columns = state.dependent_columns
|
|
@@ -2206,7 +2226,13 @@ def can_select_statement_be_flattened(
|
|
|
2206
2226
|
state.change_state == ColumnChangeState.DROPPED
|
|
2207
2227
|
and (subquery_state := subquery_column_states.get(col))
|
|
2208
2228
|
and subquery_state.change_state == ColumnChangeState.NEW
|
|
2209
|
-
and
|
|
2229
|
+
and (
|
|
2230
|
+
subquery_state.is_referenced_by_same_level_column
|
|
2231
|
+
# If the subquery was explicitly marked (e.g. by the SCOS withColumn
|
|
2232
|
+
# path), preserve it so that future filter/sort clauses can still
|
|
2233
|
+
# reference the dropped NEW column.
|
|
2234
|
+
or protect_dropped_new_columns
|
|
2235
|
+
)
|
|
2210
2236
|
):
|
|
2211
2237
|
return False
|
|
2212
2238
|
return True
|
|
@@ -458,6 +458,7 @@ class SnowflakePlan(LogicalPlan):
|
|
|
458
458
|
self.session = session
|
|
459
459
|
self.source_plan = source_plan
|
|
460
460
|
self.is_ddl_on_temp_object = is_ddl_on_temp_object
|
|
461
|
+
self._is_join_output = False
|
|
461
462
|
# We need to copy this list since we don't want to change it for the
|
|
462
463
|
# previous SnowflakePlan objects
|
|
463
464
|
self.api_calls = api_calls.copy() if api_calls else []
|
|
@@ -769,6 +770,7 @@ class SnowflakePlan(LogicalPlan):
|
|
|
769
770
|
referenced_ctes=self.referenced_ctes,
|
|
770
771
|
)
|
|
771
772
|
plan.df_ast_ids = self.df_ast_ids
|
|
773
|
+
plan._is_join_output = self._is_join_output
|
|
772
774
|
return plan
|
|
773
775
|
|
|
774
776
|
def __deepcopy__(self, memodict={}) -> "SnowflakePlan": # noqa: B006
|
|
@@ -808,6 +810,7 @@ class SnowflakePlan(LogicalPlan):
|
|
|
808
810
|
if copied_source_plan:
|
|
809
811
|
copied_source_plan._is_valid_for_replacement = True
|
|
810
812
|
copied_plan.df_ast_ids = self.df_ast_ids
|
|
813
|
+
copied_plan._is_join_output = self._is_join_output
|
|
811
814
|
|
|
812
815
|
return copied_plan
|
|
813
816
|
|
|
@@ -1065,8 +1068,13 @@ class SnowflakePlanBuilder:
|
|
|
1065
1068
|
|
|
1066
1069
|
def table(self, table_name: str, source_plan: LogicalPlan) -> SnowflakePlan:
|
|
1067
1070
|
table_reference = table_name
|
|
1068
|
-
if isinstance(source_plan, SnowflakeTable)
|
|
1069
|
-
|
|
1071
|
+
if isinstance(source_plan, SnowflakeTable):
|
|
1072
|
+
if source_plan.iceberg_changes_config:
|
|
1073
|
+
table_reference += (
|
|
1074
|
+
source_plan.iceberg_changes_config.generate_sql_clause()
|
|
1075
|
+
)
|
|
1076
|
+
elif source_plan.time_travel_config:
|
|
1077
|
+
table_reference += source_plan.time_travel_config.generate_sql_clause()
|
|
1070
1078
|
|
|
1071
1079
|
return self.query(project_statement([], table_reference), source_plan)
|
|
1072
1080
|
|
|
@@ -1231,7 +1239,8 @@ class SnowflakePlanBuilder:
|
|
|
1231
1239
|
use_constant_subquery_alias: bool,
|
|
1232
1240
|
directed: bool = False,
|
|
1233
1241
|
):
|
|
1234
|
-
|
|
1242
|
+
left_is_join = left._is_join_output
|
|
1243
|
+
result = self.build_binary(
|
|
1235
1244
|
lambda x, y: join_statement(
|
|
1236
1245
|
x,
|
|
1237
1246
|
y,
|
|
@@ -1248,11 +1257,14 @@ class SnowflakePlanBuilder:
|
|
|
1248
1257
|
else None
|
|
1249
1258
|
),
|
|
1250
1259
|
directed=directed,
|
|
1260
|
+
left_is_join=left_is_join,
|
|
1251
1261
|
),
|
|
1252
1262
|
left,
|
|
1253
1263
|
right,
|
|
1254
1264
|
source_plan,
|
|
1255
1265
|
)
|
|
1266
|
+
result._is_join_output = True
|
|
1267
|
+
return result
|
|
1256
1268
|
|
|
1257
1269
|
def save_as_table(
|
|
1258
1270
|
self,
|
|
@@ -7,7 +7,7 @@ from collections.abc import Iterable
|
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
|
|
9
9
|
|
|
10
|
-
from snowflake.snowpark._internal.utils import TimeTravelConfig
|
|
10
|
+
from snowflake.snowpark._internal.utils import IcebergChangesConfig, TimeTravelConfig
|
|
11
11
|
|
|
12
12
|
from snowflake.snowpark._internal.analyzer.expression import Attribute, Expression
|
|
13
13
|
from snowflake.snowpark._internal.analyzer.query_plan_analysis_utils import (
|
|
@@ -97,10 +97,12 @@ class SnowflakeTable(LeafNode):
|
|
|
97
97
|
session: "Session",
|
|
98
98
|
is_temp_table_for_cleanup: bool = False,
|
|
99
99
|
time_travel_config: Optional[TimeTravelConfig] = None,
|
|
100
|
+
iceberg_changes_config: Optional[IcebergChangesConfig] = None,
|
|
100
101
|
) -> None:
|
|
101
102
|
super().__init__()
|
|
102
103
|
self.name = name
|
|
103
104
|
self.time_travel_config = time_travel_config
|
|
105
|
+
self.iceberg_changes_config = iceberg_changes_config
|
|
104
106
|
# When `is_temp_table_for_cleanup` is True, it's a temp table
|
|
105
107
|
# generated by Snowpark (currently only df.cache_result) under the hood
|
|
106
108
|
# and users are not aware of it.
|
|
@@ -10,6 +10,11 @@ QUERY_TEMPLATE = "SELECT {cols} FROM {table_or_query} {query_input_alias}"
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class BaseDialect:
|
|
13
|
+
@staticmethod
|
|
14
|
+
def _quote_backtick(name: str) -> str:
|
|
15
|
+
"""Escape a backtick-quoted identifier: double any embedded backticks."""
|
|
16
|
+
return "`" + name.replace("`", "``") + "`"
|
|
17
|
+
|
|
13
18
|
@staticmethod
|
|
14
19
|
def generate_select_query(
|
|
15
20
|
table_or_query: str,
|
|
@@ -20,12 +25,11 @@ class BaseDialect:
|
|
|
20
25
|
) -> str:
|
|
21
26
|
cols = []
|
|
22
27
|
for raw_field in raw_schema:
|
|
28
|
+
quoted_name = BaseDialect._quote_backtick(raw_field[0])
|
|
23
29
|
if is_query:
|
|
24
|
-
cols.append(
|
|
25
|
-
f"""{query_input_alias}.`{raw_field[0]}` AS {raw_field[0]}"""
|
|
26
|
-
)
|
|
30
|
+
cols.append(f"""{query_input_alias}.{quoted_name} AS {quoted_name}""")
|
|
27
31
|
else:
|
|
28
|
-
cols.append(
|
|
32
|
+
cols.append(quoted_name)
|
|
29
33
|
|
|
30
34
|
return QUERY_TEMPLATE.format(
|
|
31
35
|
cols=", ".join(cols),
|
|
@@ -21,21 +21,21 @@ class DatabricksDialect(BaseDialect):
|
|
|
21
21
|
) -> str:
|
|
22
22
|
cols = []
|
|
23
23
|
for field, raw_field in zip(schema.fields, raw_schema):
|
|
24
|
+
quoted_name = self._quote_backtick(raw_field[0])
|
|
24
25
|
field_name = (
|
|
25
|
-
f"{query_input_alias}
|
|
26
|
-
if is_query
|
|
27
|
-
else f"`{raw_field[0]}`"
|
|
26
|
+
f"{query_input_alias}.{quoted_name}" if is_query else quoted_name
|
|
28
27
|
)
|
|
28
|
+
alias = quoted_name
|
|
29
29
|
# databricks-sql-connector returns list of tuples for MapType
|
|
30
30
|
# here we push down to-dict conversion to Databricks
|
|
31
31
|
if isinstance(field.datatype, MapType):
|
|
32
|
-
cols.append(f"""TO_JSON({field_name}) AS {
|
|
32
|
+
cols.append(f"""TO_JSON({field_name}) AS {alias}""")
|
|
33
33
|
elif isinstance(field.datatype, BinaryType):
|
|
34
|
-
cols.append(f"""HEX({field_name}) AS {
|
|
34
|
+
cols.append(f"""HEX({field_name}) AS {alias}""")
|
|
35
35
|
else:
|
|
36
|
-
cols.append(
|
|
37
|
-
|
|
38
|
-
)
|
|
36
|
+
cols.append(f"{field_name} AS {alias}") if is_query else cols.append(
|
|
37
|
+
field_name
|
|
38
|
+
)
|
|
39
39
|
return QUERY_TEMPLATE.format(
|
|
40
40
|
cols=", ".join(cols),
|
|
41
41
|
table_or_query=f"({table_or_query})" if is_query else table_or_query,
|
|
@@ -24,22 +24,22 @@ class MysqlDialect(BaseDialect):
|
|
|
24
24
|
) -> str:
|
|
25
25
|
cols = []
|
|
26
26
|
for field, raw_field in zip(schema.fields, raw_schema):
|
|
27
|
+
quoted_name = self._quote_backtick(raw_field[0])
|
|
27
28
|
field_name = (
|
|
28
|
-
f"{query_input_alias}
|
|
29
|
-
if is_query
|
|
30
|
-
else f"`{raw_field[0]}`"
|
|
29
|
+
f"{query_input_alias}.{quoted_name}" if is_query else quoted_name
|
|
31
30
|
)
|
|
31
|
+
alias = quoted_name
|
|
32
32
|
if isinstance(field.datatype, TimeType):
|
|
33
|
-
cols.append(f"""CAST({field_name} AS CHAR) AS {
|
|
33
|
+
cols.append(f"""CAST({field_name} AS CHAR) AS {alias}""")
|
|
34
34
|
elif (
|
|
35
35
|
isinstance(field.datatype, BinaryType)
|
|
36
36
|
or raw_field[1] == PymysqlTypeCode.BIT
|
|
37
37
|
):
|
|
38
|
-
cols.append(f"""HEX({field_name}) AS {
|
|
38
|
+
cols.append(f"""HEX({field_name}) AS {alias}""")
|
|
39
39
|
else:
|
|
40
|
-
cols.append(
|
|
41
|
-
|
|
42
|
-
)
|
|
40
|
+
cols.append(f"{field_name} AS {alias}") if is_query else cols.append(
|
|
41
|
+
field_name
|
|
42
|
+
)
|
|
43
43
|
|
|
44
44
|
return QUERY_TEMPLATE.format(
|
|
45
45
|
cols=", ".join(cols),
|