snowpark-connect 0.27.0__py3-none-any.whl → 1.7.0__py3-none-any.whl
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_connect/__init__.py +1 -0
- snowflake/snowpark_connect/analyze_plan/map_tree_string.py +8 -4
- snowflake/snowpark_connect/client/__init__.py +15 -0
- snowflake/snowpark_connect/client/error_utils.py +30 -0
- snowflake/snowpark_connect/client/exceptions.py +36 -0
- snowflake/snowpark_connect/client/query_results.py +90 -0
- snowflake/snowpark_connect/client/server.py +717 -0
- snowflake/snowpark_connect/client/utils/__init__.py +10 -0
- snowflake/snowpark_connect/client/utils/session.py +85 -0
- snowflake/snowpark_connect/column_name_handler.py +404 -243
- snowflake/snowpark_connect/column_qualifier.py +43 -0
- snowflake/snowpark_connect/config.py +309 -26
- snowflake/snowpark_connect/constants.py +2 -0
- snowflake/snowpark_connect/dataframe_container.py +102 -8
- snowflake/snowpark_connect/date_time_format_mapping.py +71 -13
- snowflake/snowpark_connect/error/error_codes.py +50 -0
- snowflake/snowpark_connect/error/error_utils.py +172 -23
- snowflake/snowpark_connect/error/exceptions.py +13 -4
- snowflake/snowpark_connect/execute_plan/map_execution_command.py +15 -160
- snowflake/snowpark_connect/execute_plan/map_execution_root.py +26 -20
- snowflake/snowpark_connect/execute_plan/utils.py +5 -1
- snowflake/snowpark_connect/expression/error_utils.py +28 -0
- snowflake/snowpark_connect/expression/function_defaults.py +9 -2
- snowflake/snowpark_connect/expression/hybrid_column_map.py +53 -5
- snowflake/snowpark_connect/expression/integral_types_support.py +219 -0
- snowflake/snowpark_connect/expression/literal.py +37 -13
- snowflake/snowpark_connect/expression/map_cast.py +224 -15
- snowflake/snowpark_connect/expression/map_expression.py +80 -27
- snowflake/snowpark_connect/expression/map_extension.py +322 -12
- snowflake/snowpark_connect/expression/map_sql_expression.py +316 -81
- snowflake/snowpark_connect/expression/map_udf.py +86 -20
- snowflake/snowpark_connect/expression/map_unresolved_attribute.py +451 -173
- snowflake/snowpark_connect/expression/map_unresolved_function.py +2964 -829
- snowflake/snowpark_connect/expression/map_unresolved_star.py +87 -23
- snowflake/snowpark_connect/expression/map_update_fields.py +70 -18
- snowflake/snowpark_connect/expression/map_window_function.py +18 -3
- snowflake/snowpark_connect/includes/jars/json4s-ast_2.13-3.7.0-M11.jar +0 -0
- snowflake/snowpark_connect/includes/jars/{scala-library-2.12.18.jar → sas-scala-udf_2.12-0.2.0.jar} +0 -0
- snowflake/snowpark_connect/includes/jars/sas-scala-udf_2.13-0.2.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/scala-reflect-2.13.16.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-common-utils_2.13-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/{spark-connect-client-jvm_2.12-3.5.6.jar → spark-connect-client-jvm_2.13-3.5.6.jar} +0 -0
- snowflake/snowpark_connect/includes/jars/{spark-sql_2.12-3.5.6.jar → spark-sql_2.13-3.5.6.jar} +0 -0
- snowflake/snowpark_connect/includes/python/pyspark/sql/connect/streaming/worker/foreach_batch_worker.py +1 -1
- snowflake/snowpark_connect/includes/python/pyspark/sql/connect/streaming/worker/listener_worker.py +1 -1
- snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.py +12 -10
- snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.pyi +14 -2
- snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2.py +10 -8
- snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2.pyi +13 -6
- snowflake/snowpark_connect/relation/catalogs/abstract_spark_catalog.py +65 -17
- snowflake/snowpark_connect/relation/catalogs/snowflake_catalog.py +297 -49
- snowflake/snowpark_connect/relation/catalogs/utils.py +12 -4
- snowflake/snowpark_connect/relation/io_utils.py +110 -10
- snowflake/snowpark_connect/relation/map_aggregate.py +239 -256
- snowflake/snowpark_connect/relation/map_catalog.py +5 -1
- snowflake/snowpark_connect/relation/map_column_ops.py +264 -96
- snowflake/snowpark_connect/relation/map_extension.py +263 -29
- snowflake/snowpark_connect/relation/map_join.py +683 -442
- snowflake/snowpark_connect/relation/map_local_relation.py +28 -1
- snowflake/snowpark_connect/relation/map_map_partitions.py +83 -8
- snowflake/snowpark_connect/relation/map_relation.py +48 -19
- snowflake/snowpark_connect/relation/map_row_ops.py +310 -91
- snowflake/snowpark_connect/relation/map_show_string.py +13 -6
- snowflake/snowpark_connect/relation/map_sql.py +1233 -222
- snowflake/snowpark_connect/relation/map_stats.py +48 -9
- snowflake/snowpark_connect/relation/map_subquery_alias.py +11 -2
- snowflake/snowpark_connect/relation/map_udtf.py +14 -4
- snowflake/snowpark_connect/relation/read/jdbc_read_dbapi.py +53 -14
- snowflake/snowpark_connect/relation/read/map_read.py +134 -43
- snowflake/snowpark_connect/relation/read/map_read_csv.py +326 -47
- snowflake/snowpark_connect/relation/read/map_read_jdbc.py +21 -6
- snowflake/snowpark_connect/relation/read/map_read_json.py +324 -86
- snowflake/snowpark_connect/relation/read/map_read_parquet.py +146 -28
- snowflake/snowpark_connect/relation/read/map_read_partitioned_parquet.py +142 -0
- snowflake/snowpark_connect/relation/read/map_read_socket.py +15 -3
- snowflake/snowpark_connect/relation/read/map_read_table.py +86 -6
- snowflake/snowpark_connect/relation/read/map_read_text.py +22 -4
- snowflake/snowpark_connect/relation/read/metadata_utils.py +170 -0
- snowflake/snowpark_connect/relation/read/reader_config.py +42 -3
- snowflake/snowpark_connect/relation/read/utils.py +50 -5
- snowflake/snowpark_connect/relation/stage_locator.py +91 -55
- snowflake/snowpark_connect/relation/utils.py +128 -5
- snowflake/snowpark_connect/relation/write/jdbc_write_dbapi.py +19 -3
- snowflake/snowpark_connect/relation/write/map_write.py +929 -319
- snowflake/snowpark_connect/relation/write/map_write_jdbc.py +8 -2
- snowflake/snowpark_connect/resources/java_udfs-1.0-SNAPSHOT.jar +0 -0
- snowflake/snowpark_connect/resources_initializer.py +171 -48
- snowflake/snowpark_connect/server.py +528 -473
- snowflake/snowpark_connect/server_common/__init__.py +503 -0
- snowflake/snowpark_connect/snowflake_session.py +65 -0
- snowflake/snowpark_connect/start_server.py +53 -5
- snowflake/snowpark_connect/type_mapping.py +349 -27
- snowflake/snowpark_connect/type_support.py +130 -0
- snowflake/snowpark_connect/typed_column.py +9 -7
- snowflake/snowpark_connect/utils/artifacts.py +9 -8
- snowflake/snowpark_connect/utils/cache.py +49 -27
- snowflake/snowpark_connect/utils/concurrent.py +36 -1
- snowflake/snowpark_connect/utils/context.py +195 -37
- snowflake/snowpark_connect/utils/describe_query_cache.py +68 -53
- snowflake/snowpark_connect/utils/env_utils.py +5 -1
- snowflake/snowpark_connect/utils/expression_transformer.py +172 -0
- snowflake/snowpark_connect/utils/identifiers.py +137 -3
- snowflake/snowpark_connect/utils/io_utils.py +57 -1
- snowflake/snowpark_connect/utils/java_stored_procedure.py +151 -0
- snowflake/snowpark_connect/utils/java_udaf_utils.py +321 -0
- snowflake/snowpark_connect/utils/java_udtf_utils.py +239 -0
- snowflake/snowpark_connect/utils/jvm_udf_utils.py +281 -0
- snowflake/snowpark_connect/utils/open_telemetry.py +516 -0
- snowflake/snowpark_connect/utils/pandas_udtf_utils.py +8 -4
- snowflake/snowpark_connect/utils/patch_spark_line_number.py +181 -0
- snowflake/snowpark_connect/utils/profiling.py +25 -8
- snowflake/snowpark_connect/utils/scala_udf_utils.py +185 -340
- snowflake/snowpark_connect/utils/sequence.py +21 -0
- snowflake/snowpark_connect/utils/session.py +64 -28
- snowflake/snowpark_connect/utils/snowpark_connect_logging.py +51 -9
- snowflake/snowpark_connect/utils/spcs_logger.py +290 -0
- snowflake/snowpark_connect/utils/telemetry.py +192 -40
- snowflake/snowpark_connect/utils/temporary_view_cache.py +67 -0
- snowflake/snowpark_connect/utils/temporary_view_helper.py +334 -0
- snowflake/snowpark_connect/utils/udf_cache.py +117 -41
- snowflake/snowpark_connect/utils/udf_helper.py +39 -37
- snowflake/snowpark_connect/utils/udf_utils.py +133 -14
- snowflake/snowpark_connect/utils/udtf_helper.py +8 -1
- snowflake/snowpark_connect/utils/udtf_utils.py +46 -31
- snowflake/snowpark_connect/utils/udxf_import_utils.py +9 -2
- snowflake/snowpark_connect/utils/upload_java_jar.py +57 -0
- snowflake/snowpark_connect/version.py +1 -1
- snowflake/snowpark_decoder/dp_session.py +6 -2
- snowflake/snowpark_decoder/spark_decoder.py +12 -0
- {snowpark_connect-0.27.0.data → snowpark_connect-1.7.0.data}/scripts/snowpark-submit +14 -4
- {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/METADATA +16 -7
- {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/RECORD +139 -168
- snowflake/snowpark_connect/hidden_column.py +0 -39
- snowflake/snowpark_connect/includes/jars/antlr4-runtime-4.9.3.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-cli-1.5.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-codec-1.16.1.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-collections-3.2.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-collections4-4.4.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-compiler-3.1.9.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-compress-1.26.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-crypto-1.1.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-dbcp-1.4.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-io-2.16.1.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-lang-2.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-lang3-3.12.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-logging-1.1.3.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-math3-3.6.1.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-pool-1.5.4.jar +0 -0
- snowflake/snowpark_connect/includes/jars/commons-text-1.10.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/hadoop-client-api-trimmed-3.3.4.jar +0 -0
- snowflake/snowpark_connect/includes/jars/jackson-annotations-2.15.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/jackson-core-2.15.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/jackson-core-asl-1.9.13.jar +0 -0
- snowflake/snowpark_connect/includes/jars/jackson-databind-2.15.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/jackson-dataformat-yaml-2.15.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/jackson-datatype-jsr310-2.15.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/jackson-module-scala_2.12-2.15.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/json4s-ast_2.12-3.7.0-M11.jar +0 -0
- snowflake/snowpark_connect/includes/jars/json4s-core_2.12-3.7.0-M11.jar +0 -0
- snowflake/snowpark_connect/includes/jars/json4s-jackson_2.12-3.7.0-M11.jar +0 -0
- snowflake/snowpark_connect/includes/jars/json4s-native_2.12-3.7.0-M11.jar +0 -0
- snowflake/snowpark_connect/includes/jars/json4s-scalap_2.12-3.7.0-M11.jar +0 -0
- snowflake/snowpark_connect/includes/jars/kryo-shaded-4.0.2.jar +0 -0
- snowflake/snowpark_connect/includes/jars/log4j-1.2-api-2.20.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/log4j-api-2.20.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/log4j-core-2.20.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/log4j-slf4j2-impl-2.20.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/paranamer-2.8.3.jar +0 -0
- snowflake/snowpark_connect/includes/jars/paranamer-2.8.jar +0 -0
- snowflake/snowpark_connect/includes/jars/sas-scala-udf_2.12-0.1.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/scala-collection-compat_2.12-2.7.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/scala-parser-combinators_2.12-2.3.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/scala-reflect-2.12.18.jar +0 -0
- snowflake/snowpark_connect/includes/jars/scala-xml_2.12-2.1.0.jar +0 -0
- snowflake/snowpark_connect/includes/jars/slf4j-api-2.0.7.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-catalyst_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-common-utils_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-core_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-graphx_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-hive-thriftserver_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-hive_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-kvstore_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-launcher_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-mesos_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-mllib-local_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-network-common_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-network-shuffle_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-repl_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-sketch_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-sql-api_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-tags_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-unsafe_2.12-3.5.6.jar +0 -0
- snowflake/snowpark_connect/includes/jars/spark-yarn_2.12-3.5.6.jar +0 -0
- {snowpark_connect-0.27.0.data → snowpark_connect-1.7.0.data}/scripts/snowpark-connect +0 -0
- {snowpark_connect-0.27.0.data → snowpark_connect-1.7.0.data}/scripts/snowpark-session +0 -0
- {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/WHEEL +0 -0
- {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/licenses/LICENSE-binary +0 -0
- {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
- {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/licenses/NOTICE-binary +0 -0
- {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/top_level.txt +0 -0
|
@@ -10,6 +10,7 @@ sys.path.append(str(pathlib.Path(__file__).parent / "includes/python"))
|
|
|
10
10
|
|
|
11
11
|
from .server import get_session # noqa: E402, F401
|
|
12
12
|
from .server import start_session # noqa: E402, F401
|
|
13
|
+
from .utils.session import skip_session_configuration # noqa: E402, F401
|
|
13
14
|
|
|
14
15
|
# Turn off catalog warning for Snowpark
|
|
15
16
|
sp_logger = logging.getLogger("snowflake.snowpark")
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
import pyspark.sql.connect.proto.base_pb2 as proto_base
|
|
6
6
|
|
|
7
7
|
from snowflake.snowpark_connect.relation.map_relation import map_relation
|
|
8
|
+
from snowflake.snowpark_connect.relation.read.metadata_utils import (
|
|
9
|
+
without_internal_columns,
|
|
10
|
+
)
|
|
8
11
|
from snowflake.snowpark_connect.type_mapping import (
|
|
9
12
|
SNOWPARK_TYPE_NAME_TO_PYSPARK_TYPE_NAME,
|
|
10
13
|
)
|
|
@@ -16,12 +19,13 @@ def map_tree_string(
|
|
|
16
19
|
# TODO: tracking the difference with pyspark in SNOW-1853347
|
|
17
20
|
tree_string = request.tree_string
|
|
18
21
|
snowpark_df_container = map_relation(tree_string.plan.root)
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
filtered_container = without_internal_columns(snowpark_df_container)
|
|
23
|
+
display_df = filtered_container.dataframe
|
|
24
|
+
filtered_column_mapping = filtered_container.column_map.snowpark_to_spark_map()
|
|
21
25
|
|
|
22
|
-
snowpark_tree_string =
|
|
26
|
+
snowpark_tree_string = display_df._format_schema(
|
|
23
27
|
level=tree_string.level if tree_string.HasField("level") else None,
|
|
24
|
-
translate_columns=
|
|
28
|
+
translate_columns=filtered_column_mapping,
|
|
25
29
|
translate_types=SNOWPARK_TYPE_NAME_TO_PYSPARK_TYPE_NAME,
|
|
26
30
|
)
|
|
27
31
|
# workaround for the capitalization of nullable boolean value.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Lightweight Snowpark Connect client.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from snowflake.snowpark_connect.client.server import ( # noqa: F401
|
|
10
|
+
get_session,
|
|
11
|
+
init_spark_session,
|
|
12
|
+
start_session,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = ["get_session", "init_spark_session", "start_session"]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Lightweight error utilities for the Snowpark Connect client.
|
|
7
|
+
|
|
8
|
+
This is a minimal version of snowflake.snowpark_connect.error.error_utils
|
|
9
|
+
that avoids heavy dependencies like jpype that are only needed server-side.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import threading
|
|
13
|
+
|
|
14
|
+
# Thread-local storage for custom error codes when we can't attach them directly to exceptions
|
|
15
|
+
_thread_local = threading.local()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def attach_custom_error_code(exception: Exception, custom_error_code: int) -> Exception:
|
|
19
|
+
"""
|
|
20
|
+
Attach a custom error code to any exception instance.
|
|
21
|
+
This allows us to add custom error codes to existing PySpark exceptions.
|
|
22
|
+
"""
|
|
23
|
+
if not hasattr(exception, "custom_error_code"):
|
|
24
|
+
try:
|
|
25
|
+
exception.custom_error_code = custom_error_code
|
|
26
|
+
except (AttributeError, TypeError):
|
|
27
|
+
# Some exception types don't allow setting custom attributes
|
|
28
|
+
# Store the error code in thread-local storage for later retrieval
|
|
29
|
+
_thread_local.pending_error_code = custom_error_code
|
|
30
|
+
return exception
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
from google.rpc import status_pb2
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SparkConnectServerException(Exception):
|
|
9
|
+
def __init__(self, message) -> None:
|
|
10
|
+
super().__init__(message)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class InvalidHostException(SparkConnectServerException):
|
|
14
|
+
def __init__(self, message) -> None:
|
|
15
|
+
super().__init__(message)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MissingAuthException(SparkConnectServerException):
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
super().__init__("Missing authorization information")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class UnexpectedResponseException(SparkConnectServerException):
|
|
24
|
+
def __init__(self, message) -> None:
|
|
25
|
+
super().__init__(message)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class QueryTimeoutException(SparkConnectServerException):
|
|
29
|
+
def __init__(self, message) -> None:
|
|
30
|
+
super().__init__(message)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class GrpcErrorStatusException(SparkConnectServerException):
|
|
34
|
+
def __init__(self, status: status_pb2.Status) -> None:
|
|
35
|
+
super().__init__(f"Error code: {status.code}, message: {status.message}")
|
|
36
|
+
self.status = status
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
"""Query result fetching utilities for remote client."""
|
|
6
|
+
|
|
7
|
+
import base64
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Iterator, Tuple
|
|
10
|
+
|
|
11
|
+
import pyarrow as pa
|
|
12
|
+
from google.protobuf.message import DecodeError
|
|
13
|
+
from google.rpc import code_pb2, status_pb2
|
|
14
|
+
|
|
15
|
+
from snowflake.snowpark import Session
|
|
16
|
+
from spark.connect import envelope_pb2
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def fetch_query_result_as_arrow_batches(
|
|
22
|
+
session: Session, query_id: str, arrow_schema: pa.Schema
|
|
23
|
+
) -> Iterator[Tuple[int, bytes]]:
|
|
24
|
+
"""
|
|
25
|
+
Fetch query results as Arrow batches.
|
|
26
|
+
Used for large result sets that are fetched asynchronously.
|
|
27
|
+
|
|
28
|
+
Yields:
|
|
29
|
+
Tuples of (row_count, arrow_batch_bytes)
|
|
30
|
+
"""
|
|
31
|
+
conn = session.connection
|
|
32
|
+
cursor = conn.cursor()
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
cursor.get_results_from_sfqid(query_id)
|
|
36
|
+
|
|
37
|
+
for arrow_table in cursor.fetch_arrow_batches():
|
|
38
|
+
arrow_table = arrow_table.rename_columns(
|
|
39
|
+
[str(i) for i in range(arrow_table.num_columns)]
|
|
40
|
+
)
|
|
41
|
+
# Cast to expected schema
|
|
42
|
+
arrow_table = arrow_table.cast(arrow_schema, safe=False)
|
|
43
|
+
|
|
44
|
+
# Convert table to batches and serialize
|
|
45
|
+
record_batches = arrow_table.to_batches()
|
|
46
|
+
for batch in record_batches:
|
|
47
|
+
sink = pa.BufferOutputStream()
|
|
48
|
+
with pa.ipc.new_stream(sink, batch.schema) as writer:
|
|
49
|
+
writer.write_batch(batch)
|
|
50
|
+
arrow_batch_bytes = sink.getvalue().to_pybytes()
|
|
51
|
+
yield batch.num_rows, arrow_batch_bytes
|
|
52
|
+
finally:
|
|
53
|
+
cursor.close()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def fetch_query_result_as_protobuf(
|
|
57
|
+
session: Session, query_id: str
|
|
58
|
+
) -> envelope_pb2.ResponseEnvelope:
|
|
59
|
+
"""
|
|
60
|
+
Fetch query results as a ResponseEnvelope protobuf.
|
|
61
|
+
Polls for async query completion and decodes the result envelope.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
ResponseEnvelope containing the results
|
|
65
|
+
"""
|
|
66
|
+
conn = session.connection
|
|
67
|
+
cursor = conn.cursor()
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
cursor.get_results_from_sfqid(query_id)
|
|
71
|
+
# Python connector does not know how to handle new "RAW" result type, so for now we must use
|
|
72
|
+
# internal, private methods directly to work around this limitation
|
|
73
|
+
# TODO: Add proper RAW result handling in Python connector
|
|
74
|
+
cursor._prefetch_hook() # block while polling till query is complete
|
|
75
|
+
data = cursor._result_set.batches[0]._data
|
|
76
|
+
resp_bytes = base64.b64decode(data)
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
response_envelope = envelope_pb2.ResponseEnvelope()
|
|
80
|
+
response_envelope.ParseFromString(resp_bytes)
|
|
81
|
+
return response_envelope
|
|
82
|
+
except DecodeError:
|
|
83
|
+
logger.error(f"Failed to decode ResponseEnvelope for query_id: {query_id}")
|
|
84
|
+
return envelope_pb2.ResponseEnvelope(
|
|
85
|
+
status=status_pb2.Status(
|
|
86
|
+
code=code_pb2.INTERNAL, message="Invalid operation or SQL"
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
finally:
|
|
90
|
+
cursor.close()
|