snowflake-connector-python 5.2.0__cp315-cp315-win_amd64.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/connector/__init__.py +148 -0
- snowflake/connector/_common/__init__.py +0 -0
- snowflake/connector/_common/extras.py +134 -0
- snowflake/connector/_common/telemetry.py +221 -0
- snowflake/connector/_common/wif_util.py +92 -0
- snowflake/connector/_core/sf_core_python.cp315-win_amd64.pyd +0 -0
- snowflake/connector/_core/sf_core_python.pyi +79 -0
- snowflake/connector/_internal/__init__.py +6 -0
- snowflake/connector/_internal/_private_key_helper.py +31 -0
- snowflake/connector/_internal/api_client/__init__.py +93 -0
- snowflake/connector/_internal/api_client/bridge.py +41 -0
- snowflake/connector/_internal/api_client/client_api.py +976 -0
- snowflake/connector/_internal/arrow.py +47 -0
- snowflake/connector/_internal/arrow_context.py +240 -0
- snowflake/connector/_internal/arrow_stream_async.py +266 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp311-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp312-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp313-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp314-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp314t-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp315-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.pyi +42 -0
- snowflake/connector/_internal/arrow_stream_utils.py +171 -0
- snowflake/connector/_internal/authenticator_type.py +53 -0
- snowflake/connector/_internal/backward_compatibility.py +245 -0
- snowflake/connector/_internal/binding_converters.py +741 -0
- snowflake/connector/_internal/config_utils.py +71 -0
- snowflake/connector/_internal/connection/__init__.py +39 -0
- snowflake/connector/_internal/connection/connection.py +616 -0
- snowflake/connector/_internal/connection/connection_types.py +13 -0
- snowflake/connector/_internal/connection/constants.py +25 -0
- snowflake/connector/_internal/connection/decorators.py +31 -0
- snowflake/connector/_internal/connection/freezable_proxy.py +104 -0
- snowflake/connector/_internal/connection/queries.py +10 -0
- snowflake/connector/_internal/connection_config_mixin.py +755 -0
- snowflake/connector/_internal/cursor/__init__.py +25 -0
- snowflake/connector/_internal/cursor/base.py +732 -0
- snowflake/connector/_internal/cursor/cursor_types.py +13 -0
- snowflake/connector/_internal/cursor/decorators.py +56 -0
- snowflake/connector/_internal/cursor/query_result.py +202 -0
- snowflake/connector/_internal/cursor/query_result_waiter.py +98 -0
- snowflake/connector/_internal/cursor/result_metadata.py +255 -0
- snowflake/connector/_internal/cursor/result_set_wrapper.py +66 -0
- snowflake/connector/_internal/decorators.py +539 -0
- snowflake/connector/_internal/error_kinds.py +111 -0
- snowflake/connector/_internal/errorcode.py +35 -0
- snowflake/connector/_internal/errorhandler.py +278 -0
- snowflake/connector/_internal/fips.py +28 -0
- snowflake/connector/_internal/logging/__init__.py +52 -0
- snowflake/connector/_internal/logging/config.py +134 -0
- snowflake/connector/_internal/logging/core_logger.py +218 -0
- snowflake/connector/_internal/logging/native_extension_logger.py +144 -0
- snowflake/connector/_internal/logout_config_mapping.py +187 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +57 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.cpp +943 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.hpp +63 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +18 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +118 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +116 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.cpp +323 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.hpp +133 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.cpp +275 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.hpp +168 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.cpp +439 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.hpp +30 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +48 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +76 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +90 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +63 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +62 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +29 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +41 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +65 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +54 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +79 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +52 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +117 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +54 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +34 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +33 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +18 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +39 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +326 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +138 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.cpp +13278 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.pyx +204 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +109 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +125 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1914 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +208 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +128 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +58 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +144 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +160 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +98 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +243 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +207 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +80 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +83 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +201 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +108 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +164 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +926 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +182 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc.c +3052 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3019 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3354 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +344 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +29305 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +381 -0
- snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.cpp +108 -0
- snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.hpp +47 -0
- snowflake/connector/_internal/nanoarrow_cpp/scripts/.clang-format +8 -0
- snowflake/connector/_internal/nanoarrow_cpp/scripts/format.sh +8 -0
- snowflake/connector/_internal/protobuf_gen/__init__.py +0 -0
- snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.py +408 -0
- snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.pyi +4487 -0
- snowflake/connector/_internal/protobuf_gen/database_driver_v1_services.py +2088 -0
- snowflake/connector/_internal/protobuf_gen/proto_exception.py +17 -0
- snowflake/connector/_internal/result_batch.py +150 -0
- snowflake/connector/_internal/snowflake_restful.py +222 -0
- snowflake/connector/_internal/snowpark_backcompat_helpers.py +31 -0
- snowflake/connector/_internal/sqlstate.py +11 -0
- snowflake/connector/_internal/statement_utils.py +207 -0
- snowflake/connector/_internal/text_utils.py +112 -0
- snowflake/connector/_internal/type_codes.py +139 -0
- snowflake/connector/_internal/utils.py +65 -0
- snowflake/connector/_internal/write_pandas_operation.py +657 -0
- snowflake/connector/aio/README.md +168 -0
- snowflake/connector/aio/__init__.py +37 -0
- snowflake/connector/aio/connection/__init__.py +17 -0
- snowflake/connector/aio/connection/_connection.py +506 -0
- snowflake/connector/aio/cursor/__init__.py +35 -0
- snowflake/connector/aio/cursor/_base.py +1034 -0
- snowflake/connector/aio/cursor/_dict_cursor.py +78 -0
- snowflake/connector/aio/cursor/_result_set_wrapper.py +35 -0
- snowflake/connector/aio/cursor/_snowflake_cursor.py +72 -0
- snowflake/connector/aio/pandas_tools.py +279 -0
- snowflake/connector/aio/result_batch.py +165 -0
- snowflake/connector/auth/__init__.py +0 -0
- snowflake/connector/auth/workload_identity.py +5 -0
- snowflake/connector/compat.py +22 -0
- snowflake/connector/config_manager.py +392 -0
- snowflake/connector/connection/__init__.py +30 -0
- snowflake/connector/connection/_connection.py +641 -0
- snowflake/connector/connection_config.py +517 -0
- snowflake/connector/constants.py +52 -0
- snowflake/connector/cursor/__init__.py +37 -0
- snowflake/connector/cursor/_base.py +1169 -0
- snowflake/connector/cursor/_chunked_download_reader.py +75 -0
- snowflake/connector/cursor/_dict_cursor.py +78 -0
- snowflake/connector/cursor/_result_set_wrapper.py +35 -0
- snowflake/connector/cursor/_snowflake_cursor.py +72 -0
- snowflake/connector/description.py +7 -0
- snowflake/connector/errors.py +492 -0
- snowflake/connector/network.py +71 -0
- snowflake/connector/pandas_tools.py +191 -0
- snowflake/connector/py.typed +0 -0
- snowflake/connector/result_batch.py +216 -0
- snowflake/connector/telemetry.py +40 -0
- snowflake/connector/time_util.py +11 -0
- snowflake/connector/types.py +134 -0
- snowflake/connector/util_text.py +3 -0
- snowflake/connector/version.py +23 -0
- snowflake_connector_python-5.2.0.dist-info/DELVEWHEEL +2 -0
- snowflake_connector_python-5.2.0.dist-info/METADATA +190 -0
- snowflake_connector_python-5.2.0.dist-info/RECORD +204 -0
- snowflake_connector_python-5.2.0.dist-info/WHEEL +4 -0
- snowflake_connector_python.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
"""Shared connection mixin for sync and async connection implementations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import uuid
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING, Any, ClassVar, cast
|
|
9
|
+
|
|
10
|
+
from ..._common.extras import check_dependency
|
|
11
|
+
from ..._common.extras import numpy as np
|
|
12
|
+
from ...connection_config import ConnectionConfig
|
|
13
|
+
from ...constants import QueryStatus, SessionParameterName
|
|
14
|
+
from ...errors import Error, ErrorDetails, InterfaceError, ProgrammingError, StructuredErrorHandler
|
|
15
|
+
from ..api_client.client_api import core_driver
|
|
16
|
+
from ..binding_converters import ParamStyle
|
|
17
|
+
from ..decorators import api_telemetry, backward_compatibility, internal_api, pep249
|
|
18
|
+
from ..errorhandler import ErrorHandlerMixin
|
|
19
|
+
from ..logging import get_logger
|
|
20
|
+
from .constants import LOG_MAX_QUERY_LENGTH
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from ...aio.cursor import CursorType as AsyncCursorType
|
|
25
|
+
from ...cursor import CursorType as SyncCursorType
|
|
26
|
+
from ..protobuf_gen.database_driver_v1_pb2 import ConnectionHandle, DatabaseHandle
|
|
27
|
+
from ..protobuf_gen.database_driver_v1_services import ConnectionGetInfoResponse
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
logger = get_logger(__name__)
|
|
31
|
+
|
|
32
|
+
# Matches the legacy connector's `MAX_CLIENT_PREFETCH_THREADS` /
|
|
33
|
+
# `_validate_client_prefetch_threads` bounds (`connection.py`).
|
|
34
|
+
MIN_CLIENT_PREFETCH_THREADS = 1
|
|
35
|
+
MAX_CLIENT_PREFETCH_THREADS = 10
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def clamp_client_prefetch_threads(value: int) -> int:
|
|
39
|
+
"""Clamp to ``[1, 10]``, matching the legacy connector's validation."""
|
|
40
|
+
value = int(value)
|
|
41
|
+
if value <= 0:
|
|
42
|
+
return MIN_CLIENT_PREFETCH_THREADS
|
|
43
|
+
if value > MAX_CLIENT_PREFETCH_THREADS:
|
|
44
|
+
return MAX_CLIENT_PREFETCH_THREADS
|
|
45
|
+
return value
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def validate_query_id(sf_qid: str) -> None:
|
|
49
|
+
"""Raise ValueError if ``sf_qid`` is not a valid UUID, matching the legacy connector's validation."""
|
|
50
|
+
try:
|
|
51
|
+
uuid.UUID(sf_qid)
|
|
52
|
+
except ValueError as err:
|
|
53
|
+
raise ValueError(f"Invalid UUID: '{sf_qid}'") from err
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _session_param_is_true(value: bool | str | None) -> bool:
|
|
57
|
+
"""Return True for a native ``True`` or the string ``"true"`` (case-insensitive).
|
|
58
|
+
|
|
59
|
+
A session-parameter value is a native bool once read through
|
|
60
|
+
``SessionParametersProxy``, or a plain string when supplied via a
|
|
61
|
+
caller-side override; both spellings of ``"true"``/``"false"`` are
|
|
62
|
+
accepted case-insensitively.
|
|
63
|
+
"""
|
|
64
|
+
if isinstance(value, bool):
|
|
65
|
+
return value
|
|
66
|
+
if isinstance(value, str):
|
|
67
|
+
return value.lower() == "true"
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class ConnectionMixin(ErrorHandlerMixin):
|
|
72
|
+
"""Connection members shared by sync and async connection classes.
|
|
73
|
+
|
|
74
|
+
Subclasses set handle/proxy fields (``conn_handle``, ``_session_parameters``,
|
|
75
|
+
``_connection_info``, etc.) and call :meth:`__init__` before performing any
|
|
76
|
+
I/O to establish the session.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
_messages: list[tuple[type[Error], ErrorDetails]]
|
|
80
|
+
_errorhandler: StructuredErrorHandler
|
|
81
|
+
config: ConnectionConfig
|
|
82
|
+
__paramstyle: ParamStyle
|
|
83
|
+
_interpolate_empty_sequences: bool
|
|
84
|
+
_reuse_results: bool
|
|
85
|
+
_session_parameters: Any
|
|
86
|
+
_connection_info: Any
|
|
87
|
+
_client_param_telemetry_enabled: bool
|
|
88
|
+
conn_handle: ConnectionHandle | None
|
|
89
|
+
|
|
90
|
+
# Concrete subclasses set the default cursor class returned by ``cursor()``
|
|
91
|
+
# (the sync vs. async ``SnowflakeCursor``); kept off the shared mixin so
|
|
92
|
+
# ``_internal`` never imports the public cursor packages at runtime.
|
|
93
|
+
_default_cursor_class: ClassVar[SyncCursorType | AsyncCursorType]
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
*,
|
|
98
|
+
connection_name: str | None = None,
|
|
99
|
+
connections_file_path: str | os.PathLike[str] | None = None,
|
|
100
|
+
config: ConnectionConfig | None = None,
|
|
101
|
+
**kwargs: Any,
|
|
102
|
+
) -> None:
|
|
103
|
+
self._messages = []
|
|
104
|
+
self._errorhandler = Error.default_errorhandler
|
|
105
|
+
self._client_param_telemetry_enabled = True
|
|
106
|
+
|
|
107
|
+
if config is not None:
|
|
108
|
+
if kwargs:
|
|
109
|
+
raise ProgrammingError(
|
|
110
|
+
"Cannot pass both a ConnectionConfig object and keyword arguments. Use one or the other."
|
|
111
|
+
)
|
|
112
|
+
config = config._clone()
|
|
113
|
+
if connection_name is not None:
|
|
114
|
+
config.connection_name = connection_name
|
|
115
|
+
if connections_file_path is not None:
|
|
116
|
+
config.connections_file_path = os.fspath(connections_file_path)
|
|
117
|
+
self.config = ConnectionConfig._finalize(config)
|
|
118
|
+
else:
|
|
119
|
+
self.config = ConnectionConfig.from_connection_args(
|
|
120
|
+
connection_name=connection_name,
|
|
121
|
+
connections_file_path=connections_file_path,
|
|
122
|
+
**kwargs,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if self.config.client_prefetch_threads is not None:
|
|
126
|
+
self.config.client_prefetch_threads = clamp_client_prefetch_threads(self.config.client_prefetch_threads)
|
|
127
|
+
|
|
128
|
+
from snowflake.connector import paramstyle as default_paramstyle
|
|
129
|
+
|
|
130
|
+
self.paramstyle = self.config.paramstyle or default_paramstyle
|
|
131
|
+
|
|
132
|
+
if self.config.numpy:
|
|
133
|
+
check_dependency(np)
|
|
134
|
+
|
|
135
|
+
self._interpolate_empty_sequences = bool(self.config.interpolate_empty_sequences)
|
|
136
|
+
self._reuse_results = self.config.reuse_results is True
|
|
137
|
+
|
|
138
|
+
# ------------------------------------------------------------------
|
|
139
|
+
# Cursors
|
|
140
|
+
# ------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
def _instantiate_cursor(self, cursor_class: type[Any] | None) -> Any:
|
|
143
|
+
# The class is chosen by the caller, so this cannot name its constructor.
|
|
144
|
+
factory: Any = cursor_class or self._default_cursor_class
|
|
145
|
+
return factory(self)
|
|
146
|
+
|
|
147
|
+
# ------------------------------------------------------------------
|
|
148
|
+
# Handle release
|
|
149
|
+
# ------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
def _close_telemetry_client(self) -> None:
|
|
152
|
+
client = getattr(self, "_telemetry_client", None)
|
|
153
|
+
if client is not None:
|
|
154
|
+
client.close()
|
|
155
|
+
|
|
156
|
+
def _release_connection_handle(self, conn_handle: ConnectionHandle) -> None:
|
|
157
|
+
"""Release the Rust-side connection handle."""
|
|
158
|
+
try:
|
|
159
|
+
core_driver.connection_release(conn_handle=conn_handle)
|
|
160
|
+
except Exception:
|
|
161
|
+
logger.warning("Failed to release connection handle", exc_info=True)
|
|
162
|
+
|
|
163
|
+
def _release_database_handle(self, db_handle: DatabaseHandle) -> None:
|
|
164
|
+
"""Release the Rust-side database handle."""
|
|
165
|
+
try:
|
|
166
|
+
core_driver.database_release(db_handle=db_handle)
|
|
167
|
+
except Exception:
|
|
168
|
+
logger.warning("Failed to release database handle", exc_info=True)
|
|
169
|
+
|
|
170
|
+
# ------------------------------------------------------------------
|
|
171
|
+
# PEP 249 attributes
|
|
172
|
+
# ------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
@pep249
|
|
176
|
+
@api_telemetry
|
|
177
|
+
def messages(self) -> list[tuple[type[Error], ErrorDetails]]:
|
|
178
|
+
"""List of (exception class, exception value) tuples received from the database."""
|
|
179
|
+
return self._messages
|
|
180
|
+
|
|
181
|
+
@messages.setter
|
|
182
|
+
@api_telemetry
|
|
183
|
+
def messages(self, value: list[tuple[type[Error], ErrorDetails]]) -> None:
|
|
184
|
+
self._messages = value
|
|
185
|
+
|
|
186
|
+
# ------------------------------------------------------------------
|
|
187
|
+
# Paramstyle
|
|
188
|
+
# ------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
@api_telemetry
|
|
192
|
+
def paramstyle(self) -> ParamStyle:
|
|
193
|
+
"""Get the paramstyle for this connection."""
|
|
194
|
+
return self.__paramstyle
|
|
195
|
+
|
|
196
|
+
@paramstyle.setter
|
|
197
|
+
@api_telemetry
|
|
198
|
+
def paramstyle(self, value: str | ParamStyle) -> None:
|
|
199
|
+
"""Set binding style from a :class:`ParamStyle` or PEP 249 string (e.g. ``"pyformat"``)."""
|
|
200
|
+
if isinstance(value, ParamStyle):
|
|
201
|
+
self.__paramstyle = value
|
|
202
|
+
elif isinstance(value, str):
|
|
203
|
+
self.__paramstyle = ParamStyle.from_string(value)
|
|
204
|
+
else:
|
|
205
|
+
raise ProgrammingError(msg=f"paramstyle must be str or ParamStyle, got {type(value).__name__}")
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
@backward_compatibility
|
|
209
|
+
def _paramstyle(self) -> ParamStyle:
|
|
210
|
+
"""Internal binding-style storage (legacy callers assign to ``_paramstyle``)."""
|
|
211
|
+
return self.__paramstyle
|
|
212
|
+
|
|
213
|
+
@_paramstyle.setter
|
|
214
|
+
@backward_compatibility
|
|
215
|
+
def _paramstyle(self, value: str | ParamStyle) -> None:
|
|
216
|
+
"""Normalize assignments to ``_paramstyle`` (e.g. SnowPy ``temporary_paramstyle``)."""
|
|
217
|
+
self.paramstyle = value
|
|
218
|
+
|
|
219
|
+
# ------------------------------------------------------------------
|
|
220
|
+
# Session info
|
|
221
|
+
# ------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
@api_telemetry
|
|
225
|
+
def role(self) -> str | None:
|
|
226
|
+
"""The current role in use for the session."""
|
|
227
|
+
return cast("str | None", self._connection_info["role"])
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
@api_telemetry
|
|
231
|
+
def database(self) -> str | None:
|
|
232
|
+
"""The current database in use for the session."""
|
|
233
|
+
return cast("str | None", self._connection_info["database"])
|
|
234
|
+
|
|
235
|
+
@property
|
|
236
|
+
@api_telemetry
|
|
237
|
+
def schema(self) -> str | None:
|
|
238
|
+
"""The current schema in use for the session."""
|
|
239
|
+
return cast("str | None", self._connection_info["schema"])
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
@api_telemetry
|
|
243
|
+
def account(self) -> str | None:
|
|
244
|
+
"""The Snowflake account name used by this connection."""
|
|
245
|
+
return cast("str | None", self._connection_info["account"])
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
@api_telemetry
|
|
249
|
+
def warehouse(self) -> str | None:
|
|
250
|
+
"""The current warehouse in use for the session."""
|
|
251
|
+
return cast("str | None", self._connection_info["warehouse"])
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
@api_telemetry
|
|
255
|
+
def user(self) -> str | None:
|
|
256
|
+
"""The user name used for authentication."""
|
|
257
|
+
return cast("str | None", self._connection_info["user"])
|
|
258
|
+
|
|
259
|
+
@property
|
|
260
|
+
@api_telemetry
|
|
261
|
+
def host(self) -> str | None:
|
|
262
|
+
"""The host name of the Snowflake instance."""
|
|
263
|
+
return cast("str | None", self._connection_info["host"])
|
|
264
|
+
|
|
265
|
+
@property
|
|
266
|
+
@api_telemetry
|
|
267
|
+
def port(self) -> int | None:
|
|
268
|
+
"""The port number of the Snowflake instance."""
|
|
269
|
+
return cast("int | None", self._connection_info["port"])
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
@api_telemetry
|
|
273
|
+
def session_id(self) -> int:
|
|
274
|
+
"""The Snowflake session ID for this connection."""
|
|
275
|
+
value = cast("int | None", self._connection_info["session_id"])
|
|
276
|
+
if value is None:
|
|
277
|
+
raise InterfaceError(msg="Session ID is not available; connection may not be initialized")
|
|
278
|
+
return value
|
|
279
|
+
|
|
280
|
+
# ------------------------------------------------------------------
|
|
281
|
+
# Proxy info
|
|
282
|
+
# ------------------------------------------------------------------
|
|
283
|
+
|
|
284
|
+
@property
|
|
285
|
+
@api_telemetry
|
|
286
|
+
def proxy_host(self) -> str | None:
|
|
287
|
+
"""The configured HTTP proxy hostname, or ``None`` when no proxy is set."""
|
|
288
|
+
return cast("str | None", self._connection_info["proxy_host"])
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
@api_telemetry
|
|
292
|
+
def proxy_port(self) -> int | None:
|
|
293
|
+
"""The configured HTTP proxy port, or ``None`` when no proxy is set."""
|
|
294
|
+
return cast("int | None", self._connection_info["proxy_port"])
|
|
295
|
+
|
|
296
|
+
@property
|
|
297
|
+
@api_telemetry
|
|
298
|
+
def proxy_user(self) -> str | None:
|
|
299
|
+
"""The configured HTTP proxy username for Basic auth, or ``None`` when unset."""
|
|
300
|
+
return cast("str | None", self._connection_info["proxy_user"])
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
@api_telemetry
|
|
304
|
+
def proxy_password(self) -> str | None:
|
|
305
|
+
"""The configured HTTP proxy password for Basic auth, or ``None`` when unset."""
|
|
306
|
+
return cast("str | None", self._connection_info["proxy_password"])
|
|
307
|
+
|
|
308
|
+
@property
|
|
309
|
+
@api_telemetry
|
|
310
|
+
def no_proxy(self) -> str | None:
|
|
311
|
+
"""Comma-separated list of hosts that bypass the proxy, or ``None`` when unset."""
|
|
312
|
+
return cast("str | None", self._connection_info["no_proxy"])
|
|
313
|
+
|
|
314
|
+
# ------------------------------------------------------------------
|
|
315
|
+
# Connection properties
|
|
316
|
+
# ------------------------------------------------------------------
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
@api_telemetry
|
|
320
|
+
def login_timeout(self) -> int | None:
|
|
321
|
+
"""The login timeout in seconds."""
|
|
322
|
+
return self.config.login_timeout
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
@api_telemetry
|
|
326
|
+
def network_timeout(self) -> int | None:
|
|
327
|
+
"""The network timeout in seconds for all other operations."""
|
|
328
|
+
return self.config.request_timeout
|
|
329
|
+
|
|
330
|
+
@property
|
|
331
|
+
@api_telemetry
|
|
332
|
+
def socket_timeout(self) -> int | None:
|
|
333
|
+
"""The socket timeout in seconds."""
|
|
334
|
+
return self.config.retry_timeout
|
|
335
|
+
|
|
336
|
+
@property
|
|
337
|
+
@api_telemetry
|
|
338
|
+
def platform_detection_timeout_seconds(self) -> float | None:
|
|
339
|
+
"""The configured value, which the driver ignores; each platform check is limited to 2 seconds."""
|
|
340
|
+
return self.config.platform_detection_timeout_seconds
|
|
341
|
+
|
|
342
|
+
@property
|
|
343
|
+
@api_telemetry
|
|
344
|
+
def client_session_keep_alive(self) -> bool | None:
|
|
345
|
+
"""Whether to keep the session active with periodic heartbeat requests."""
|
|
346
|
+
return self.config.client_session_keep_alive
|
|
347
|
+
|
|
348
|
+
@property
|
|
349
|
+
@api_telemetry
|
|
350
|
+
def client_session_keep_alive_heartbeat_frequency(self) -> int | None:
|
|
351
|
+
"""The frequency in seconds of heartbeat requests when session keep-alive is enabled."""
|
|
352
|
+
return self.config.client_session_keep_alive_heartbeat_frequency
|
|
353
|
+
|
|
354
|
+
@property
|
|
355
|
+
@api_telemetry
|
|
356
|
+
def client_prefetch_threads(self) -> int | None:
|
|
357
|
+
"""The number of threads used to prefetch query result data."""
|
|
358
|
+
return self.config.client_prefetch_threads
|
|
359
|
+
|
|
360
|
+
@client_prefetch_threads.setter
|
|
361
|
+
@api_telemetry
|
|
362
|
+
def client_prefetch_threads(self, value: int) -> None:
|
|
363
|
+
"""Update local state only; this is the base (zero-I/O) implementation.
|
|
364
|
+
|
|
365
|
+
The core's chunk-prefetch pool size is read from the server-echoed
|
|
366
|
+
session-parameter cache, not from this config value, so on its own
|
|
367
|
+
this setter has no effect on an already-open connection. The
|
|
368
|
+
synchronous ``Connection`` class overrides this property to also run
|
|
369
|
+
``ALTER SESSION SET CLIENT_PREFETCH_THREADS`` so the change actually
|
|
370
|
+
takes effect on subsequent fetches, matching the old connector's
|
|
371
|
+
immediate, locally-effective setter. Async connections cannot do the
|
|
372
|
+
same through a synchronous property setter (it can't ``await``); use
|
|
373
|
+
``await conn.set_client_prefetch_threads(value)`` there instead.
|
|
374
|
+
"""
|
|
375
|
+
self.config.client_prefetch_threads = clamp_client_prefetch_threads(value)
|
|
376
|
+
|
|
377
|
+
@property
|
|
378
|
+
@api_telemetry
|
|
379
|
+
def application(self) -> str:
|
|
380
|
+
"""The name of the client application connecting to Snowflake."""
|
|
381
|
+
return self.config.application # type: ignore[return-value]
|
|
382
|
+
|
|
383
|
+
# ------------------------------------------------------------------
|
|
384
|
+
# Error handling
|
|
385
|
+
# ------------------------------------------------------------------
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
@pep249
|
|
389
|
+
@api_telemetry
|
|
390
|
+
def errorhandler(self) -> StructuredErrorHandler:
|
|
391
|
+
"""PEP 249 error handler called for connection and cursor errors."""
|
|
392
|
+
return self._errorhandler
|
|
393
|
+
|
|
394
|
+
@errorhandler.setter
|
|
395
|
+
@api_telemetry
|
|
396
|
+
def errorhandler(self, value: StructuredErrorHandler | None) -> None:
|
|
397
|
+
if value is None:
|
|
398
|
+
raise ProgrammingError("Invalid errorhandler is specified")
|
|
399
|
+
self._errorhandler = value
|
|
400
|
+
|
|
401
|
+
@property
|
|
402
|
+
@api_telemetry
|
|
403
|
+
def is_pyformat(self) -> bool:
|
|
404
|
+
"""Whether the connection uses pyformat or format paramstyle (client-side binding)."""
|
|
405
|
+
return self._paramstyle in (ParamStyle.PYFORMAT, ParamStyle.FORMAT)
|
|
406
|
+
|
|
407
|
+
# ------------------------------------------------------------------
|
|
408
|
+
# Logging & options
|
|
409
|
+
# ------------------------------------------------------------------
|
|
410
|
+
|
|
411
|
+
def _server_param_telemetry_enabled(self) -> bool:
|
|
412
|
+
try:
|
|
413
|
+
value = self._session_parameters[SessionParameterName.CLIENT_TELEMETRY_ENABLED]
|
|
414
|
+
except Exception:
|
|
415
|
+
logger.debug("Failed to read CLIENT_TELEMETRY_ENABLED session parameter")
|
|
416
|
+
return False
|
|
417
|
+
return _session_param_is_true(value)
|
|
418
|
+
|
|
419
|
+
@property
|
|
420
|
+
@api_telemetry
|
|
421
|
+
def telemetry_enabled(self) -> bool:
|
|
422
|
+
"""Whether client-side telemetry collection is enabled.
|
|
423
|
+
|
|
424
|
+
True only when both halves agree: the client has not disabled it via
|
|
425
|
+
this property, AND the server has confirmed ``CLIENT_TELEMETRY_ENABLED``
|
|
426
|
+
for the session. Unlike ``sf_core``'s own (unrelated) OTEL-export gate,
|
|
427
|
+
an unconfirmed server parameter is treated as disabled, not enabled,
|
|
428
|
+
matching the old driver version. Reading this property issues an RPC.
|
|
429
|
+
"""
|
|
430
|
+
return self._client_param_telemetry_enabled and self._server_param_telemetry_enabled()
|
|
431
|
+
|
|
432
|
+
@telemetry_enabled.setter
|
|
433
|
+
@api_telemetry
|
|
434
|
+
def telemetry_enabled(self, value: bool) -> None:
|
|
435
|
+
"""Set the client-side telemetry flag.
|
|
436
|
+
|
|
437
|
+
This can only narrow, never widen, server policy: it never issues an
|
|
438
|
+
RPC or ``ALTER SESSION``.
|
|
439
|
+
"""
|
|
440
|
+
self._client_param_telemetry_enabled = bool(value)
|
|
441
|
+
if self._client_param_telemetry_enabled and not self._server_param_telemetry_enabled():
|
|
442
|
+
logger.info(
|
|
443
|
+
"Telemetry has been disabled by the session parameter CLIENT_TELEMETRY_ENABLED."
|
|
444
|
+
" Set session parameter CLIENT_TELEMETRY_ENABLED to true to enable telemetry."
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
@property
|
|
448
|
+
@api_telemetry
|
|
449
|
+
def service_name(self) -> str | None:
|
|
450
|
+
"""The Snowflake service name for the connection, used for service discovery."""
|
|
451
|
+
return cast("str | None", self._session_parameters._get_string("SERVICE_NAME"))
|
|
452
|
+
|
|
453
|
+
@service_name.setter
|
|
454
|
+
@api_telemetry
|
|
455
|
+
def service_name(self, value: str | None) -> None:
|
|
456
|
+
if self.conn_handle is None:
|
|
457
|
+
return
|
|
458
|
+
if value is None:
|
|
459
|
+
value = ""
|
|
460
|
+
core_driver.connection_set_session_parameters(conn_handle=self.conn_handle, parameters={"SERVICE_NAME": value})
|
|
461
|
+
|
|
462
|
+
@property
|
|
463
|
+
@api_telemetry
|
|
464
|
+
def log_max_query_length(self) -> int:
|
|
465
|
+
"""Maximum number of characters of a query string to log."""
|
|
466
|
+
return (
|
|
467
|
+
self.config.log_max_query_length if self.config.log_max_query_length is not None else LOG_MAX_QUERY_LENGTH
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
def _format_query_for_log(self, query: str) -> str:
|
|
471
|
+
"""Collapse whitespace and truncate a query string for gated INFO query logging."""
|
|
472
|
+
ret = " ".join(line.strip() for line in query.split("\n"))
|
|
473
|
+
if len(ret) < self.log_max_query_length:
|
|
474
|
+
return ret
|
|
475
|
+
return ret[: self.log_max_query_length] + "..."
|
|
476
|
+
|
|
477
|
+
@property
|
|
478
|
+
@api_telemetry
|
|
479
|
+
def use_openssl_only(self) -> bool:
|
|
480
|
+
"""Deprecated. Whether to restrict TLS to OpenSSL only (always ``True``)."""
|
|
481
|
+
raise NotImplementedError("use_openssl_only is not yet implemented")
|
|
482
|
+
|
|
483
|
+
@property
|
|
484
|
+
@api_telemetry
|
|
485
|
+
def arrow_number_to_decimal(self) -> bool:
|
|
486
|
+
"""Whether to convert Arrow numeric types to Python ``Decimal`` instead of ``float``."""
|
|
487
|
+
return bool(self.config.arrow_number_to_decimal)
|
|
488
|
+
|
|
489
|
+
@arrow_number_to_decimal.setter
|
|
490
|
+
@api_telemetry
|
|
491
|
+
def arrow_number_to_decimal(self, value: bool) -> None:
|
|
492
|
+
self.config.arrow_number_to_decimal = bool(value)
|
|
493
|
+
|
|
494
|
+
@arrow_number_to_decimal.setter # type: ignore[attr-defined, untyped-decorator]
|
|
495
|
+
@backward_compatibility
|
|
496
|
+
def arrow_number_to_decimal_setter(self, value: bool) -> None:
|
|
497
|
+
"""Set arrow_number_to_decimal field. Deprecated."""
|
|
498
|
+
self.arrow_number_to_decimal = value
|
|
499
|
+
|
|
500
|
+
@property
|
|
501
|
+
@api_telemetry
|
|
502
|
+
def force_microsecond_precision(self) -> bool:
|
|
503
|
+
"""Whether ``fetch_arrow_*`` and ``fetch_pandas_*`` truncate timestamps to microseconds.
|
|
504
|
+
|
|
505
|
+
Those methods use this value when the call omits ``force_microsecond_precision``.
|
|
506
|
+
A per-call argument overrides it.
|
|
507
|
+
"""
|
|
508
|
+
return bool(self.config.force_microsecond_precision)
|
|
509
|
+
|
|
510
|
+
@force_microsecond_precision.setter
|
|
511
|
+
@api_telemetry
|
|
512
|
+
def force_microsecond_precision(self, value: bool) -> None:
|
|
513
|
+
self.config.force_microsecond_precision = bool(value)
|
|
514
|
+
|
|
515
|
+
@property
|
|
516
|
+
@api_telemetry
|
|
517
|
+
def validate_default_parameters(self) -> bool:
|
|
518
|
+
"""Whether to validate default connection parameters at connect time."""
|
|
519
|
+
return bool(self.config.validate_default_parameters)
|
|
520
|
+
|
|
521
|
+
@property
|
|
522
|
+
@api_telemetry
|
|
523
|
+
def insecure_mode(self) -> bool:
|
|
524
|
+
"""Whether OCSP certificate revocation checking is disabled."""
|
|
525
|
+
raise NotImplementedError("insecure_mode is not yet implemented")
|
|
526
|
+
|
|
527
|
+
@property
|
|
528
|
+
@api_telemetry
|
|
529
|
+
def consent_cache_id_token(self) -> bool:
|
|
530
|
+
"""Whether to cache the IdP token for browser-based SSO authentication."""
|
|
531
|
+
raise NotImplementedError("consent_cache_id_token is not yet implemented")
|
|
532
|
+
|
|
533
|
+
# ------------------------------------------------------------------
|
|
534
|
+
# connection state (sync core_driver reads)
|
|
535
|
+
# ------------------------------------------------------------------
|
|
536
|
+
|
|
537
|
+
def _autocommit_enabled(self) -> bool:
|
|
538
|
+
value = self._session_parameters["AUTOCOMMIT"]
|
|
539
|
+
return _session_param_is_true(value)
|
|
540
|
+
|
|
541
|
+
@property
|
|
542
|
+
def _autocommit(self) -> bool:
|
|
543
|
+
"""Whether autocommit is enabled (legacy internal name used by sync tests)."""
|
|
544
|
+
return self._autocommit_enabled()
|
|
545
|
+
|
|
546
|
+
@api_telemetry
|
|
547
|
+
def get_autocommit(self) -> bool:
|
|
548
|
+
"""Return the current autocommit mode."""
|
|
549
|
+
return self._autocommit_enabled()
|
|
550
|
+
|
|
551
|
+
@api_telemetry
|
|
552
|
+
def get_client_prefetch_threads(self) -> int:
|
|
553
|
+
"""Return the configured number of chunk-prefetch threads."""
|
|
554
|
+
return cast(int, self.config.client_prefetch_threads)
|
|
555
|
+
|
|
556
|
+
@api_telemetry
|
|
557
|
+
def is_expired(self) -> bool:
|
|
558
|
+
"""Return True if the connection's master token has expired.
|
|
559
|
+
|
|
560
|
+
Once True, the session can no longer be renewed and the connection
|
|
561
|
+
must be replaced; full re-authentication is required.
|
|
562
|
+
|
|
563
|
+
Matches the legacy ``SnowflakeConnection.expired`` flag — intended as a
|
|
564
|
+
read-only signal for external pool / application code. Fails closed on
|
|
565
|
+
RPC errors so pools evict uncertain connections.
|
|
566
|
+
"""
|
|
567
|
+
if self.conn_handle is None:
|
|
568
|
+
return False
|
|
569
|
+
try:
|
|
570
|
+
response = core_driver.connection_is_expired(conn_handle=self.conn_handle)
|
|
571
|
+
return bool(response.is_expired)
|
|
572
|
+
except Exception:
|
|
573
|
+
return True
|
|
574
|
+
|
|
575
|
+
@property
|
|
576
|
+
@api_telemetry
|
|
577
|
+
def expired(self) -> bool:
|
|
578
|
+
"""Whether the master token has expired (sync legacy property name)."""
|
|
579
|
+
return self.is_expired()
|
|
580
|
+
|
|
581
|
+
@internal_api
|
|
582
|
+
def _get_connection_info(self, include_master_token: bool = False) -> ConnectionGetInfoResponse:
|
|
583
|
+
"""Return connection details from Core."""
|
|
584
|
+
if self.conn_handle is None:
|
|
585
|
+
raise InterfaceError(msg="Connection handle is not available")
|
|
586
|
+
return core_driver.connection_get_info(
|
|
587
|
+
conn_handle=self.conn_handle,
|
|
588
|
+
include_master_token=include_master_token,
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
# ------------------------------------------------------------------
|
|
592
|
+
# Query status helpers
|
|
593
|
+
# ------------------------------------------------------------------
|
|
594
|
+
|
|
595
|
+
@staticmethod
|
|
596
|
+
def is_still_running(status: QueryStatus) -> bool:
|
|
597
|
+
"""Check whether given status is currently running."""
|
|
598
|
+
return status in (
|
|
599
|
+
QueryStatus.RUNNING,
|
|
600
|
+
QueryStatus.QUEUED,
|
|
601
|
+
QueryStatus.RESUMING_WAREHOUSE,
|
|
602
|
+
QueryStatus.QUEUED_REPARING_WAREHOUSE,
|
|
603
|
+
QueryStatus.BLOCKED,
|
|
604
|
+
QueryStatus.NO_DATA,
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
@staticmethod
|
|
608
|
+
def is_an_error(status: QueryStatus) -> bool:
|
|
609
|
+
"""Check whether given status means that there has been an error."""
|
|
610
|
+
return status in (
|
|
611
|
+
QueryStatus.ABORTING,
|
|
612
|
+
QueryStatus.FAILED_WITH_ERROR,
|
|
613
|
+
QueryStatus.ABORTED,
|
|
614
|
+
QueryStatus.FAILED_WITH_INCIDENT,
|
|
615
|
+
QueryStatus.DISCONNECTED,
|
|
616
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Connection type aliases shared by sync and async connection implementations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import Any, TypeVar
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
SessionParameters = dict[str, Any]
|
|
10
|
+
ConnectionParamValue = int | str | float | bytes | bool | SessionParameters
|
|
11
|
+
ConnectionParameters = dict[str, ConnectionParamValue]
|
|
12
|
+
|
|
13
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Connection constants shared by sync and async connection implementations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# backward compatibility constant
|
|
9
|
+
# snowflake-sqlalchemy imports this symbol and calls .get(name) in
|
|
10
|
+
# parse_query_param_type to cast URL query-string values to the types the
|
|
11
|
+
# connector expects. The universal core validates parameters internally, so
|
|
12
|
+
# an empty dict is correct: every .get() returns None and values pass through
|
|
13
|
+
# uncast.
|
|
14
|
+
DEFAULT_CONFIGURATION: dict[str, tuple[Any, tuple[type, ...]]] = {}
|
|
15
|
+
|
|
16
|
+
APPLICATION_NAME = "PythonConnector"
|
|
17
|
+
# Kept as a public alias for backward compatibility — external packages
|
|
18
|
+
# (e.g. snowflake-sqlalchemy) may import this symbol.
|
|
19
|
+
CLIENT_NAME = APPLICATION_NAME
|
|
20
|
+
|
|
21
|
+
# Default upper bound for query strings included in log messages. Mirrors
|
|
22
|
+
# the ``log_max_query_length`` default emitted by the generated
|
|
23
|
+
# :class:`ConnectionConfig` (sourced from ``PARAM_DEFS``); kept here as a
|
|
24
|
+
# named constant so the property fallback isn't a magic number.
|
|
25
|
+
LOG_MAX_QUERY_LENGTH = 80
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Connection precondition decorators shared by sync and async connection implementations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from ...errors import DatabaseError
|
|
8
|
+
from ..decorators import wrap_method_with_sync_pre
|
|
9
|
+
from ..errorcode import ER_CONNECTION_IS_CLOSED
|
|
10
|
+
from ..sqlstate import SQLSTATE_CONNECTION_NOT_EXISTS
|
|
11
|
+
from .connection_types import F
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from ...aio.connection import Connection as AsyncConnection
|
|
16
|
+
from ...connection import Connection
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _raise_if_connection_closed(self: Connection | AsyncConnection) -> None:
|
|
20
|
+
# TODO: it should rather raise InterfaceError, consider to align with the cursor
|
|
21
|
+
if self.conn_handle is None or self.is_closed():
|
|
22
|
+
raise DatabaseError(
|
|
23
|
+
msg="Connection is closed.",
|
|
24
|
+
errno=ER_CONNECTION_IS_CLOSED,
|
|
25
|
+
sqlstate=SQLSTATE_CONNECTION_NOT_EXISTS,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def requires_open(func: F) -> F:
|
|
30
|
+
"""Raise ``DatabaseError`` if the connection is closed."""
|
|
31
|
+
return wrap_method_with_sync_pre(func, pre=_raise_if_connection_closed)
|