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.
Files changed (204) hide show
  1. snowflake/connector/__init__.py +148 -0
  2. snowflake/connector/_common/__init__.py +0 -0
  3. snowflake/connector/_common/extras.py +134 -0
  4. snowflake/connector/_common/telemetry.py +221 -0
  5. snowflake/connector/_common/wif_util.py +92 -0
  6. snowflake/connector/_core/sf_core_python.cp315-win_amd64.pyd +0 -0
  7. snowflake/connector/_core/sf_core_python.pyi +79 -0
  8. snowflake/connector/_internal/__init__.py +6 -0
  9. snowflake/connector/_internal/_private_key_helper.py +31 -0
  10. snowflake/connector/_internal/api_client/__init__.py +93 -0
  11. snowflake/connector/_internal/api_client/bridge.py +41 -0
  12. snowflake/connector/_internal/api_client/client_api.py +976 -0
  13. snowflake/connector/_internal/arrow.py +47 -0
  14. snowflake/connector/_internal/arrow_context.py +240 -0
  15. snowflake/connector/_internal/arrow_stream_async.py +266 -0
  16. snowflake/connector/_internal/arrow_stream_iterator.cp311-win_amd64.pyd +0 -0
  17. snowflake/connector/_internal/arrow_stream_iterator.cp312-win_amd64.pyd +0 -0
  18. snowflake/connector/_internal/arrow_stream_iterator.cp313-win_amd64.pyd +0 -0
  19. snowflake/connector/_internal/arrow_stream_iterator.cp314-win_amd64.pyd +0 -0
  20. snowflake/connector/_internal/arrow_stream_iterator.cp314t-win_amd64.pyd +0 -0
  21. snowflake/connector/_internal/arrow_stream_iterator.cp315-win_amd64.pyd +0 -0
  22. snowflake/connector/_internal/arrow_stream_iterator.pyi +42 -0
  23. snowflake/connector/_internal/arrow_stream_utils.py +171 -0
  24. snowflake/connector/_internal/authenticator_type.py +53 -0
  25. snowflake/connector/_internal/backward_compatibility.py +245 -0
  26. snowflake/connector/_internal/binding_converters.py +741 -0
  27. snowflake/connector/_internal/config_utils.py +71 -0
  28. snowflake/connector/_internal/connection/__init__.py +39 -0
  29. snowflake/connector/_internal/connection/connection.py +616 -0
  30. snowflake/connector/_internal/connection/connection_types.py +13 -0
  31. snowflake/connector/_internal/connection/constants.py +25 -0
  32. snowflake/connector/_internal/connection/decorators.py +31 -0
  33. snowflake/connector/_internal/connection/freezable_proxy.py +104 -0
  34. snowflake/connector/_internal/connection/queries.py +10 -0
  35. snowflake/connector/_internal/connection_config_mixin.py +755 -0
  36. snowflake/connector/_internal/cursor/__init__.py +25 -0
  37. snowflake/connector/_internal/cursor/base.py +732 -0
  38. snowflake/connector/_internal/cursor/cursor_types.py +13 -0
  39. snowflake/connector/_internal/cursor/decorators.py +56 -0
  40. snowflake/connector/_internal/cursor/query_result.py +202 -0
  41. snowflake/connector/_internal/cursor/query_result_waiter.py +98 -0
  42. snowflake/connector/_internal/cursor/result_metadata.py +255 -0
  43. snowflake/connector/_internal/cursor/result_set_wrapper.py +66 -0
  44. snowflake/connector/_internal/decorators.py +539 -0
  45. snowflake/connector/_internal/error_kinds.py +111 -0
  46. snowflake/connector/_internal/errorcode.py +35 -0
  47. snowflake/connector/_internal/errorhandler.py +278 -0
  48. snowflake/connector/_internal/fips.py +28 -0
  49. snowflake/connector/_internal/logging/__init__.py +52 -0
  50. snowflake/connector/_internal/logging/config.py +134 -0
  51. snowflake/connector/_internal/logging/core_logger.py +218 -0
  52. snowflake/connector/_internal/logging/native_extension_logger.py +144 -0
  53. snowflake/connector/_internal/logout_config_mapping.py +187 -0
  54. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +57 -0
  55. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  56. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.cpp +943 -0
  57. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.hpp +63 -0
  58. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +18 -0
  59. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  60. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  61. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  62. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +118 -0
  63. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +116 -0
  64. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.cpp +323 -0
  65. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.hpp +133 -0
  66. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.cpp +275 -0
  67. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.hpp +168 -0
  68. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.cpp +439 -0
  69. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.hpp +30 -0
  70. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +48 -0
  71. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  72. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +76 -0
  73. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  74. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +90 -0
  75. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +63 -0
  76. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +62 -0
  77. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  78. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +29 -0
  79. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  80. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  81. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  82. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +41 -0
  83. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +65 -0
  84. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +54 -0
  85. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  86. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +79 -0
  87. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  88. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +52 -0
  89. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  90. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  91. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +117 -0
  92. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +54 -0
  93. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +34 -0
  94. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +33 -0
  95. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  96. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +18 -0
  97. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  98. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +39 -0
  99. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  100. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +326 -0
  101. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +138 -0
  102. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  103. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
  104. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  105. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.cpp +13278 -0
  106. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.pyx +204 -0
  107. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +109 -0
  108. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +125 -0
  109. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  110. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1914 -0
  111. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +208 -0
  112. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +128 -0
  113. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  114. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +58 -0
  115. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +144 -0
  116. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  117. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  118. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  119. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +160 -0
  120. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +98 -0
  121. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +243 -0
  122. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  123. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +207 -0
  124. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +80 -0
  125. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +83 -0
  126. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  127. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  128. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +201 -0
  129. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +108 -0
  130. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  131. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  132. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  133. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  134. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  135. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +164 -0
  136. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +926 -0
  137. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +182 -0
  138. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  139. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  140. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc.c +3052 -0
  141. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3019 -0
  142. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3354 -0
  143. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +344 -0
  144. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +29305 -0
  145. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +381 -0
  146. snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.cpp +108 -0
  147. snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.hpp +47 -0
  148. snowflake/connector/_internal/nanoarrow_cpp/scripts/.clang-format +8 -0
  149. snowflake/connector/_internal/nanoarrow_cpp/scripts/format.sh +8 -0
  150. snowflake/connector/_internal/protobuf_gen/__init__.py +0 -0
  151. snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.py +408 -0
  152. snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.pyi +4487 -0
  153. snowflake/connector/_internal/protobuf_gen/database_driver_v1_services.py +2088 -0
  154. snowflake/connector/_internal/protobuf_gen/proto_exception.py +17 -0
  155. snowflake/connector/_internal/result_batch.py +150 -0
  156. snowflake/connector/_internal/snowflake_restful.py +222 -0
  157. snowflake/connector/_internal/snowpark_backcompat_helpers.py +31 -0
  158. snowflake/connector/_internal/sqlstate.py +11 -0
  159. snowflake/connector/_internal/statement_utils.py +207 -0
  160. snowflake/connector/_internal/text_utils.py +112 -0
  161. snowflake/connector/_internal/type_codes.py +139 -0
  162. snowflake/connector/_internal/utils.py +65 -0
  163. snowflake/connector/_internal/write_pandas_operation.py +657 -0
  164. snowflake/connector/aio/README.md +168 -0
  165. snowflake/connector/aio/__init__.py +37 -0
  166. snowflake/connector/aio/connection/__init__.py +17 -0
  167. snowflake/connector/aio/connection/_connection.py +506 -0
  168. snowflake/connector/aio/cursor/__init__.py +35 -0
  169. snowflake/connector/aio/cursor/_base.py +1034 -0
  170. snowflake/connector/aio/cursor/_dict_cursor.py +78 -0
  171. snowflake/connector/aio/cursor/_result_set_wrapper.py +35 -0
  172. snowflake/connector/aio/cursor/_snowflake_cursor.py +72 -0
  173. snowflake/connector/aio/pandas_tools.py +279 -0
  174. snowflake/connector/aio/result_batch.py +165 -0
  175. snowflake/connector/auth/__init__.py +0 -0
  176. snowflake/connector/auth/workload_identity.py +5 -0
  177. snowflake/connector/compat.py +22 -0
  178. snowflake/connector/config_manager.py +392 -0
  179. snowflake/connector/connection/__init__.py +30 -0
  180. snowflake/connector/connection/_connection.py +641 -0
  181. snowflake/connector/connection_config.py +517 -0
  182. snowflake/connector/constants.py +52 -0
  183. snowflake/connector/cursor/__init__.py +37 -0
  184. snowflake/connector/cursor/_base.py +1169 -0
  185. snowflake/connector/cursor/_chunked_download_reader.py +75 -0
  186. snowflake/connector/cursor/_dict_cursor.py +78 -0
  187. snowflake/connector/cursor/_result_set_wrapper.py +35 -0
  188. snowflake/connector/cursor/_snowflake_cursor.py +72 -0
  189. snowflake/connector/description.py +7 -0
  190. snowflake/connector/errors.py +492 -0
  191. snowflake/connector/network.py +71 -0
  192. snowflake/connector/pandas_tools.py +191 -0
  193. snowflake/connector/py.typed +0 -0
  194. snowflake/connector/result_batch.py +216 -0
  195. snowflake/connector/telemetry.py +40 -0
  196. snowflake/connector/time_util.py +11 -0
  197. snowflake/connector/types.py +134 -0
  198. snowflake/connector/util_text.py +3 -0
  199. snowflake/connector/version.py +23 -0
  200. snowflake_connector_python-5.2.0.dist-info/DELVEWHEEL +2 -0
  201. snowflake_connector_python-5.2.0.dist-info/METADATA +190 -0
  202. snowflake_connector_python-5.2.0.dist-info/RECORD +204 -0
  203. snowflake_connector_python-5.2.0.dist-info/WHEEL +4 -0
  204. snowflake_connector_python.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
@@ -0,0 +1,13 @@
1
+ """Shared type aliases and type variables for sync and async cursors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable, Sequence
6
+ from typing import Any, TypeVar
7
+
8
+
9
+ Row = tuple[Any, ...]
10
+ DictRow = dict[str, Any]
11
+
12
+ F = TypeVar("F", bound=Callable[..., Any])
13
+ Args = TypeVar("Args", bound=Sequence[Any])
@@ -0,0 +1,56 @@
1
+ """Cursor precondition decorators shared by sync and async cursor implementations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from ...errors import InterfaceError
8
+ from ..decorators import wrap_method_with_awaitable_pre, wrap_method_with_sync_pre
9
+ from ..errorcode import ER_CURSOR_IS_CLOSED
10
+ from .cursor_types import F
11
+
12
+
13
+ def _raise_if_cursor_closed(self: Any) -> None:
14
+ if self.is_closed():
15
+ raise InterfaceError(msg="Cursor is closed.", errno=ER_CURSOR_IS_CLOSED)
16
+
17
+
18
+ def _raise_if_cursor_flag_closed(self: Any) -> None:
19
+ if self._closed:
20
+ raise InterfaceError(msg="Cursor is closed.", errno=ER_CURSOR_IS_CLOSED)
21
+
22
+
23
+ def _run_prefetch_hook(self: Any) -> None:
24
+ if self._prefetch_hook is not None:
25
+ self._prefetch_hook()
26
+
27
+
28
+ async def _run_prefetch_hook_async(self: Any) -> None:
29
+ if self._prefetch_hook is not None:
30
+ await self._prefetch_hook()
31
+
32
+
33
+ def requires_open(func: F) -> F:
34
+ """Reject the call when the cursor or its connection is closed."""
35
+ return wrap_method_with_sync_pre(func, pre=_raise_if_cursor_closed)
36
+
37
+
38
+ def requires_open_cursor_not_connection(func: F) -> F:
39
+ """Guard that only checks ``self._closed``, ignoring the connection state.
40
+
41
+ Unlike ``requires_open`` (which delegates to ``is_closed()`` and therefore
42
+ also rejects cursors whose *connection* has been closed), this decorator
43
+ deliberately skips the connection check. This preserves backward
44
+ compatibility with the old driver, where fetch methods on a cursor with
45
+ already-buffered results still worked after ``connection.close()``.
46
+ """
47
+ return wrap_method_with_sync_pre(func, pre=_raise_if_cursor_flag_closed)
48
+
49
+
50
+ def with_prefetch_hook(func: F) -> F:
51
+ """Invoke the cursor's prefetch hook (if set) before entering the wrapped method."""
52
+ return wrap_method_with_awaitable_pre(
53
+ func,
54
+ sync_pre=_run_prefetch_hook,
55
+ async_pre=_run_prefetch_hook_async,
56
+ )
@@ -0,0 +1,202 @@
1
+ from __future__ import annotations
2
+
3
+ from ...errors import ProgrammingError
4
+ from ..arrow_stream_utils import release_arrow_stream
5
+ from ..protobuf_gen.database_driver_v1_pb2 import (
6
+ MultiStatementResult,
7
+ PrepareResult,
8
+ ResultSetResponse,
9
+ )
10
+ from ..statement_utils import (
11
+ extract_rowcount,
12
+ extract_sqlstate,
13
+ get_stream_ptr,
14
+ )
15
+ from .result_metadata import QueryResultStats, ResultMetadata, ResultMetadataV2
16
+
17
+
18
+ class MultiStatementQueryResultState:
19
+ """Cursor-level navigation state for multi-statement query results.
20
+
21
+ Tracks the child query IDs returned by the server, which child
22
+ we're currently positioned on, and the parent query ID that
23
+ groups them together.
24
+
25
+ Also holds the submitting ``execute()``'s ``request_id``, which the per-child
26
+ ``ResultSetResponse`` does not carry: this object is the only state
27
+ ``nextset()`` rescues across ``reset()``, so it is the only place a
28
+ submission-scoped value can survive to be re-applied to each child.
29
+ """
30
+
31
+ __slots__ = ("parent_qid", "child_query_ids", "request_id", "_next_index")
32
+
33
+ def __init__(
34
+ self,
35
+ parent_qid: str | None,
36
+ child_query_ids: list[str],
37
+ request_id: str | None,
38
+ ) -> None:
39
+ self.parent_qid = parent_qid
40
+ self.child_query_ids = child_query_ids
41
+ self.request_id = request_id
42
+ self._next_index = 0
43
+
44
+ def advance(self) -> str | None:
45
+ """Return the next child query ID and advance the index, or None if exhausted."""
46
+ if self._next_index >= len(self.child_query_ids):
47
+ return None
48
+ qid = self.child_query_ids[self._next_index]
49
+ self._next_index += 1
50
+ return qid
51
+
52
+ def current_child_query_id(self) -> str | None:
53
+ """Return the query ID of the currently active child result set."""
54
+ if self._next_index == 0:
55
+ return None
56
+ return self.child_query_ids[self._next_index - 1]
57
+
58
+ @staticmethod
59
+ def from_result(
60
+ multi_result: MultiStatementResult, request_id: str | None
61
+ ) -> MultiStatementQueryResultState | None:
62
+ """Create from a proto MultiStatementResult, or None if there are no children.
63
+
64
+ ``request_id`` is required: every caller has the submission's requestId
65
+ in scope, so a None default can never be correct.
66
+ """
67
+ query_ids = list(multi_result.query_ids)
68
+ if not query_ids:
69
+ return None
70
+ parent = multi_result.parent
71
+ parent_qid = parent.query_id if parent.query_id else None
72
+ return MultiStatementQueryResultState(
73
+ parent_qid=parent_qid,
74
+ child_query_ids=query_ids,
75
+ request_id=request_id,
76
+ )
77
+
78
+
79
+ class QueryResult:
80
+ """Pure metadata about a query execution result."""
81
+
82
+ __slots__ = (
83
+ "description_v2",
84
+ "_description_v1",
85
+ "sqlstate",
86
+ "sfqid",
87
+ "request_id",
88
+ "query",
89
+ "stats",
90
+ "rowcount",
91
+ "is_file_transfer",
92
+ "query_result_format",
93
+ )
94
+
95
+ def __init__(
96
+ self,
97
+ *,
98
+ description_v2: list[ResultMetadataV2] | None = None,
99
+ sqlstate: str | None = None,
100
+ sfqid: str | None = None,
101
+ request_id: str | None = None,
102
+ query: str | None = None,
103
+ stats: QueryResultStats | None = None,
104
+ rowcount: int | None = None,
105
+ is_file_transfer: bool = False,
106
+ query_result_format: str | None = None,
107
+ ) -> None:
108
+ self.description_v2 = description_v2
109
+ self._description_v1: list[ResultMetadata] | None = None
110
+ self.sqlstate = sqlstate
111
+ self.sfqid = sfqid
112
+ # Client-generated requestId of the query submission, populated on
113
+ # both the success and error paths.
114
+ self.request_id = request_id
115
+ self.query = query
116
+ self.stats = stats if stats is not None else QueryResultStats()
117
+ self.rowcount = rowcount
118
+ self.is_file_transfer = is_file_transfer
119
+ self.query_result_format = query_result_format
120
+
121
+ @property
122
+ def description(self) -> list[ResultMetadata] | None:
123
+ """PEP 249 view of the column metadata, downcast from ``description_v2``.
124
+
125
+ ``description_v2`` is the single parse of the proto column list; this
126
+ view is built on first read and cached.
127
+ """
128
+ if self._description_v1 is None and self.description_v2 is not None:
129
+ self._description_v1 = [col._to_result_metadata_v1() for col in self.description_v2]
130
+ return self._description_v1
131
+
132
+ def reset(self, closing: bool = False) -> None:
133
+ """Optionally clear the rowcount.
134
+
135
+ Only rowcount is reset — description, sqlstate, sfqid, request_id, query,
136
+ and stats are left intact for backward compatibility (callers may read them after close/reset).
137
+ They are overwritten wholesale when the cursor's _query_result is replaced on the next execute().
138
+ """
139
+ if not closing:
140
+ self.rowcount = None
141
+
142
+ @staticmethod
143
+ def from_prepare_result(result: PrepareResult | None) -> QueryResult:
144
+ stream_ptr = get_stream_ptr(result)
145
+ release_arrow_stream(stream_ptr)
146
+
147
+ description = ResultMetadataV2.create_description(result)
148
+ return QueryResult(
149
+ description_v2=description,
150
+ sqlstate=extract_sqlstate(result),
151
+ sfqid=(result.query_id if result.query_id else None) if result else None,
152
+ request_id=(result.request_id if result.request_id else None) if result else None,
153
+ query=(result.query if result.query else None) if result else None,
154
+ rowcount=0 if description else None,
155
+ )
156
+
157
+ @staticmethod
158
+ def from_programming_error(exc: ProgrammingError) -> QueryResult:
159
+ return QueryResult(
160
+ sqlstate=exc.sqlstate or None,
161
+ sfqid=exc.sfqid or None,
162
+ request_id=exc.request_id or None,
163
+ query=exc.query or None,
164
+ )
165
+
166
+ @staticmethod
167
+ def from_result_set_response(
168
+ response: ResultSetResponse,
169
+ query: str | None = None,
170
+ request_id: str | None = None,
171
+ ) -> QueryResult:
172
+ """Create QueryResult from a ResultSetResponse (metadata only).
173
+
174
+ Args:
175
+ response: ResultSetResponse containing descriptor metadata.
176
+ query: Optional query text (not available in proto, must be passed separately).
177
+ request_id: Optional submission requestId (not carried on ResultSetResponse,
178
+ must be passed separately by callers that submitted the query).
179
+
180
+ Returns:
181
+ QueryResult instance with metadata populated.
182
+ """
183
+ descriptor = response.result_descriptor
184
+
185
+ return QueryResult(
186
+ description_v2=ResultMetadataV2.create_description(descriptor),
187
+ sqlstate=extract_sqlstate(descriptor),
188
+ sfqid=descriptor.query_id if descriptor.query_id else None,
189
+ request_id=request_id,
190
+ query=query,
191
+ rowcount=extract_rowcount(descriptor),
192
+ is_file_transfer=(
193
+ descriptor.statement_type_id in (0x7101, 0x7102) if descriptor.HasField("statement_type_id") else False
194
+ ),
195
+ stats=(
196
+ QueryResultStats.from_query_stats(descriptor.stats)
197
+ if descriptor.HasField("stats")
198
+ else QueryResultStats()
199
+ ),
200
+ # Legacy reports a format-less response as JSON.
201
+ query_result_format=descriptor.query_result_format or "json",
202
+ )
@@ -0,0 +1,98 @@
1
+ """Waiter that polls query status until a query completes or errors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import time
7
+
8
+ from typing import TYPE_CHECKING
9
+
10
+ from ...constants import QueryStatus
11
+ from ...errors import DatabaseError
12
+
13
+
14
+ if TYPE_CHECKING:
15
+ from ...aio.connection import Connection as AsyncConnection
16
+ from ...connection import Connection
17
+ from ..connection import ConnectionMixin
18
+
19
+ _RETRY_PATTERN = [1, 1, 2, 3, 4, 8, 10]
20
+ _NO_DATA_MAX_RETRY = 24
21
+
22
+
23
+ def _no_data_error(sfqid: str) -> DatabaseError:
24
+ return DatabaseError(
25
+ f"Cannot retrieve data on the status of this query. No information returned from server for query '{sfqid}'"
26
+ )
27
+
28
+
29
+ def _advance_no_data_counter(status: QueryStatus, no_data_counter: int, sfqid: str) -> int:
30
+ if status != QueryStatus.NO_DATA:
31
+ return no_data_counter
32
+ no_data_counter += 1
33
+ if no_data_counter > _NO_DATA_MAX_RETRY:
34
+ raise _no_data_error(sfqid)
35
+ return no_data_counter
36
+
37
+
38
+ def _poll_step(
39
+ connection: ConnectionMixin,
40
+ sfqid: str,
41
+ status: QueryStatus,
42
+ no_data_counter: int,
43
+ retry_idx: int,
44
+ ) -> tuple[float | None, int, int]:
45
+ """Advance one poll iteration.
46
+
47
+ Returns ``(sleep_seconds, no_data_counter, retry_idx)``. ``sleep_seconds``
48
+ is ``None`` when polling should stop.
49
+ """
50
+ if not connection.is_still_running(status):
51
+ return None, no_data_counter, retry_idx
52
+ no_data_counter = _advance_no_data_counter(status, no_data_counter, sfqid)
53
+ delay = 0.5 * _RETRY_PATTERN[retry_idx]
54
+ if retry_idx < len(_RETRY_PATTERN) - 1:
55
+ retry_idx += 1
56
+ return delay, no_data_counter, retry_idx
57
+
58
+
59
+ class QueryResultWaiter:
60
+ """Sync waiter that polls query status with capped exponential backoff."""
61
+
62
+ def __init__(self, connection: Connection, sfqid: str) -> None:
63
+ self._connection = connection
64
+ self._sfqid = sfqid
65
+
66
+ def wait(self) -> None:
67
+ """Block until the query completes. Raise on terminal error status."""
68
+ no_data_counter = 0
69
+ retry_idx = 0
70
+ while True:
71
+ status = self._connection.get_query_status_throw_if_error(self._sfqid)
72
+ delay, no_data_counter, retry_idx = _poll_step(
73
+ self._connection, self._sfqid, status, no_data_counter, retry_idx
74
+ )
75
+ if delay is None:
76
+ return
77
+ time.sleep(delay)
78
+
79
+
80
+ class AsyncQueryResultWaiter:
81
+ """Async waiter that polls query status with capped exponential backoff."""
82
+
83
+ def __init__(self, connection: AsyncConnection, sfqid: str) -> None:
84
+ self._connection = connection
85
+ self._sfqid = sfqid
86
+
87
+ async def wait(self) -> None:
88
+ """Await query completion. Raise on terminal error status."""
89
+ no_data_counter = 0
90
+ retry_idx = 0
91
+ while True:
92
+ status = await self._connection.get_query_status_throw_if_error(self._sfqid)
93
+ delay, no_data_counter, retry_idx = _poll_step(
94
+ self._connection, self._sfqid, status, no_data_counter, retry_idx
95
+ )
96
+ if delay is None:
97
+ return
98
+ await asyncio.sleep(delay)
@@ -0,0 +1,255 @@
1
+ """Result metadata and query statistics types."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, NamedTuple
6
+
7
+ from ..protobuf_gen.database_driver_v1_pb2 import (
8
+ PrepareResult,
9
+ QueryStats,
10
+ ResultSetDescriptor,
11
+ )
12
+ from ..type_codes import get_type_code
13
+
14
+
15
+ _TEXT_TYPES = ("TEXT", "VARCHAR", "CHAR", "STRING")
16
+
17
+
18
+ def _type_code_name(col: Any) -> str:
19
+ ext = getattr(col, "ext_col_type_name", "")
20
+ if isinstance(ext, str) and ext:
21
+ return ext
22
+ return str(col.type)
23
+
24
+
25
+ def _column_display_size(col: Any) -> int | None:
26
+ # Char count, text-only — a new-driver-only enhancement (BD#90); the old driver leaves it unset.
27
+ return col.length if col.HasField("length") and col.type.upper() in _TEXT_TYPES else None
28
+
29
+
30
+ def _column_internal_size(col: Any) -> int | None:
31
+ # Char count (old-driver semantics), ungated — BINARY/VARBINARY need a real value too.
32
+ return col.length if col.HasField("length") else None
33
+
34
+
35
+ class ResultMetadata(NamedTuple):
36
+ """PEP 249 column description entry.
37
+
38
+ Each item in ``Cursor.description`` is a ``ResultMetadata`` instance.
39
+ Being a :class:`~typing.NamedTuple` it is fully tuple-compatible as
40
+ required by the spec, while also providing named attribute access.
41
+ """
42
+
43
+ name: str
44
+ type_code: int
45
+ display_size: int | None
46
+ internal_size: int | None
47
+ precision: int | None
48
+ scale: int | None
49
+ is_nullable: bool | None
50
+
51
+ @classmethod
52
+ def from_column(cls, col: Any) -> ResultMetadata:
53
+ """Create a ``ResultMetadata`` from a protobuf ``ColumnMetadata``."""
54
+ type_code = get_type_code(_type_code_name(col))
55
+
56
+ display_size = _column_display_size(col)
57
+ internal_size = _column_internal_size(col)
58
+ precision = col.precision if col.HasField("precision") else None
59
+ scale = col.scale if col.HasField("scale") else None
60
+
61
+ return cls(
62
+ name=col.name,
63
+ type_code=type_code,
64
+ display_size=display_size,
65
+ internal_size=internal_size,
66
+ precision=precision,
67
+ scale=scale,
68
+ is_nullable=col.nullable,
69
+ )
70
+
71
+
72
+ class ResultMetadataV2:
73
+ """New-format column description carrying ``vector_dimension`` and ``fields``.
74
+
75
+ Matches the legacy ``snowflake-connector-python`` ``ResultMetadataV2``
76
+ interface so Snowpark can read ``.name``, ``.type_code``, ``.is_nullable``,
77
+ ``.vector_dimension``, and ``.fields`` without connector-version guards.
78
+
79
+ ``vector_dimension`` is populated from the proto ``dimension`` field.
80
+ ``fields`` carries nested metadata for structured types: the element type
81
+ for VECTOR and ARRAY, the key and value types for MAP, and one entry per
82
+ attribute for structured OBJECT. It is ``None`` for every other type, and
83
+ also for semi-structured ARRAY/OBJECT/MAP, which the server describes
84
+ without a nested field list.
85
+
86
+ Note: ``_is_nullable`` is exposed both as the ``is_nullable`` public property
87
+ and as the ``_is_nullable`` private attribute, because Snowpark accesses the
88
+ private attribute directly on nested ARRAY/MAP element metadata objects
89
+ (``obj._is_nullable``). Both must exist by their exact names.
90
+ """
91
+
92
+ __slots__ = (
93
+ "_name",
94
+ "_type_code",
95
+ "_is_nullable",
96
+ "_display_size",
97
+ "_internal_size",
98
+ "_precision",
99
+ "_scale",
100
+ "_vector_dimension",
101
+ "_fields",
102
+ )
103
+
104
+ def __init__(
105
+ self,
106
+ name: str | None,
107
+ type_code: int,
108
+ is_nullable: bool,
109
+ display_size: int | None = None,
110
+ internal_size: int | None = None,
111
+ precision: int | None = None,
112
+ scale: int | None = None,
113
+ vector_dimension: int | None = None,
114
+ fields: list[ResultMetadataV2] | None = None,
115
+ ) -> None:
116
+ self._name = name
117
+ self._type_code = type_code
118
+ self._is_nullable = is_nullable
119
+ self._display_size = display_size
120
+ self._internal_size = internal_size
121
+ self._precision = precision
122
+ self._scale = scale
123
+ self._vector_dimension = vector_dimension
124
+ self._fields = fields
125
+
126
+ @property
127
+ def name(self) -> str | None:
128
+ return self._name
129
+
130
+ @property
131
+ def type_code(self) -> int:
132
+ return self._type_code
133
+
134
+ @property
135
+ def is_nullable(self) -> bool:
136
+ return self._is_nullable
137
+
138
+ @property
139
+ def display_size(self) -> int | None:
140
+ return self._display_size
141
+
142
+ @property
143
+ def internal_size(self) -> int | None:
144
+ return self._internal_size
145
+
146
+ @property
147
+ def precision(self) -> int | None:
148
+ return self._precision
149
+
150
+ @property
151
+ def scale(self) -> int | None:
152
+ return self._scale
153
+
154
+ @property
155
+ def vector_dimension(self) -> int | None:
156
+ return self._vector_dimension
157
+
158
+ @property
159
+ def fields(self) -> list[ResultMetadataV2] | None:
160
+ return self._fields
161
+
162
+ def __eq__(self, other: object) -> bool:
163
+ if not isinstance(other, ResultMetadataV2):
164
+ return NotImplemented
165
+ return (
166
+ self._name == other._name
167
+ and self._type_code == other._type_code
168
+ and self._is_nullable == other._is_nullable
169
+ and self._display_size == other._display_size
170
+ and self._internal_size == other._internal_size
171
+ and self._precision == other._precision
172
+ and self._scale == other._scale
173
+ and self._vector_dimension == other._vector_dimension
174
+ and self._fields == other._fields
175
+ )
176
+
177
+ def _to_result_metadata_v1(self) -> ResultMetadata:
178
+ """Downcast to a PEP 249-compatible ``ResultMetadata`` NamedTuple."""
179
+ return ResultMetadata(
180
+ name=self._name, # type: ignore[arg-type] # sub-fields carry name=None (legacy parity)
181
+ type_code=self._type_code,
182
+ display_size=self._display_size,
183
+ internal_size=self._internal_size,
184
+ precision=self._precision,
185
+ scale=self._scale,
186
+ is_nullable=self._is_nullable,
187
+ )
188
+
189
+ def __repr__(self) -> str:
190
+ return (
191
+ f"ResultMetadataV2(name={self._name!r}, type_code={self._type_code!r}, "
192
+ f"is_nullable={self._is_nullable!r}, vector_dimension={self._vector_dimension!r}, "
193
+ f"fields={self._fields!r})"
194
+ )
195
+
196
+ @classmethod
197
+ def from_column(cls, col: Any, *, nested: bool = False) -> ResultMetadataV2:
198
+ """Build from a proto ``ColumnMetadata`` message.
199
+
200
+ ``nested`` marks a sub-field of a structured type. Those carry a name
201
+ only for the attributes of a structured OBJECT; the proto renders an
202
+ absent name as the empty string, which maps back to ``None`` here for
203
+ parity with the old driver.
204
+ """
205
+ type_code = get_type_code(_type_code_name(col))
206
+ display_size = _column_display_size(col)
207
+ internal_size = _column_internal_size(col)
208
+ precision = col.precision if col.HasField("precision") else None
209
+ scale = col.scale if col.HasField("scale") else None
210
+ vector_dimension = col.dimension if col.HasField("dimension") else None
211
+ return cls(
212
+ name=(col.name or None) if nested else col.name,
213
+ type_code=type_code,
214
+ is_nullable=col.nullable,
215
+ display_size=display_size,
216
+ internal_size=internal_size,
217
+ precision=precision,
218
+ scale=scale,
219
+ vector_dimension=vector_dimension,
220
+ # For MAP, `col.fields` carries exactly two entries, key type then value
221
+ # type, in that order. Snowpark's structured-type inference reads them
222
+ # positionally as fields[0]/fields[1] today, so this recursion must
223
+ # preserve wire order rather than resort or drop an entry.
224
+ fields=[cls.from_column(f, nested=True) for f in col.fields] if col.fields else None,
225
+ )
226
+
227
+ @classmethod
228
+ def create_description(cls, result: PrepareResult | ResultSetDescriptor | None) -> list[ResultMetadataV2] | None:
229
+ """Build a V2 description list from a prepare/describe result."""
230
+ if result and result.columns:
231
+ return [cls.from_column(col) for col in result.columns]
232
+ return None
233
+
234
+
235
+ class QueryResultStats(NamedTuple):
236
+ """DML operation statistics returned by Snowflake.
237
+
238
+ Exposes per-operation row counts for INSERT, UPDATE, DELETE,
239
+ and the number of duplicate rows skipped during DML.
240
+ """
241
+
242
+ num_rows_inserted: int | None = None
243
+ num_rows_deleted: int | None = None
244
+ num_rows_updated: int | None = None
245
+ num_dml_duplicates: int | None = None
246
+
247
+ @classmethod
248
+ def from_query_stats(cls, s: QueryStats) -> QueryResultStats:
249
+ """Create a ``QueryResultStats`` from a protobuf ``QueryStats``."""
250
+ return cls(
251
+ num_rows_inserted=s.num_rows_inserted if s.HasField("num_rows_inserted") else None,
252
+ num_rows_deleted=s.num_rows_deleted if s.HasField("num_rows_deleted") else None,
253
+ num_rows_updated=s.num_rows_updated if s.HasField("num_rows_updated") else None,
254
+ num_dml_duplicates=s.num_dml_duplicates if s.HasField("num_dml_duplicates") else None,
255
+ )
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from ...errors import ProgrammingError
4
+ from ..api_client.client_api import core_driver
5
+ from ..errorcode import ER_NO_DATA_FOUND
6
+ from ..logging import get_logger
7
+ from ..protobuf_gen.database_driver_v1_pb2 import ResultSetHandle
8
+
9
+
10
+ logger = get_logger(__name__)
11
+
12
+
13
+ class ResultSetWrapperBase:
14
+ """Owns a ``ResultSetHandle`` and guards against misuse.
15
+
16
+ Lifecycle: ``replace()`` releases the previous handle before adopting a
17
+ new one; ``release()`` frees the current handle. ``__del__`` acts as a
18
+ safety net for handles that were never explicitly released.
19
+
20
+ The core layer supports repeated ``result_set_get_stream`` calls — each
21
+ invocation builds a fresh Arrow stream from the stored ``RowsetData``.
22
+
23
+ Release/replace are always synchronous (pure FFI handle deletion, no network I/O).
24
+ """
25
+
26
+ __slots__ = ("_handle",)
27
+
28
+ def __init__(self, handle: ResultSetHandle | None = None) -> None:
29
+ self._handle: ResultSetHandle | None = handle
30
+
31
+ def __del__(self) -> None:
32
+ self._do_release()
33
+
34
+ def replace(self, new_handle: ResultSetHandle | None) -> None:
35
+ """Release the current handle (if any) and adopt *new_handle*."""
36
+ self._do_release()
37
+ self._handle = new_handle
38
+
39
+ def release(self) -> None:
40
+ """Explicitly release the handle."""
41
+ self._do_release()
42
+
43
+ def _do_release(self) -> None:
44
+ handle = self._take_handle()
45
+ if handle is None:
46
+ return
47
+ try:
48
+ core_driver.result_set_release(result_set_handle=handle)
49
+ except Exception as e:
50
+ logger.warning("Failed to release ResultSet handle: %s", type(e).__name__)
51
+ logger.debug("Failed to release ResultSet handle", exc_info=True)
52
+
53
+ def _take_handle(self) -> ResultSetHandle | None:
54
+ handle = self._handle
55
+ if handle is None:
56
+ return None
57
+ self._handle = None
58
+ return handle
59
+
60
+ def _require_handle(self) -> ResultSetHandle:
61
+ if self._handle is None:
62
+ raise ProgrammingError(
63
+ msg="No results available (not produced by this query)",
64
+ errno=ER_NO_DATA_FOUND,
65
+ )
66
+ return self._handle