snowflake-connector-python 5.0.0b1__cp311-cp311-win_arm64.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 (157) hide show
  1. snowflake/connector/__init__.py +112 -0
  2. snowflake/connector/_common/__init__.py +0 -0
  3. snowflake/connector/_core/sf_core.dll +0 -0
  4. snowflake/connector/_internal/__init__.py +6 -0
  5. snowflake/connector/_internal/_private_key_helper.py +50 -0
  6. snowflake/connector/_internal/api_client/__init__.py +6 -0
  7. snowflake/connector/_internal/api_client/c_api.py +187 -0
  8. snowflake/connector/_internal/api_client/client_api.py +224 -0
  9. snowflake/connector/_internal/arrow_context.py +207 -0
  10. snowflake/connector/_internal/arrow_stream_iterator.cp311-win_arm64.pyd +0 -0
  11. snowflake/connector/_internal/arrow_stream_iterator.pyi +42 -0
  12. snowflake/connector/_internal/arrow_stream_utils.py +114 -0
  13. snowflake/connector/_internal/backward_compatibility.py +223 -0
  14. snowflake/connector/_internal/binding_converters.py +538 -0
  15. snowflake/connector/_internal/config_utils.py +71 -0
  16. snowflake/connector/_internal/decorators.py +72 -0
  17. snowflake/connector/_internal/errorcode.py +32 -0
  18. snowflake/connector/_internal/errorhandler.py +120 -0
  19. snowflake/connector/_internal/extras.py +104 -0
  20. snowflake/connector/_internal/logging.py +113 -0
  21. snowflake/connector/_internal/logout_config_mapping.py +159 -0
  22. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +57 -0
  23. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  24. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.cpp +870 -0
  25. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.hpp +63 -0
  26. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +18 -0
  27. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  28. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  29. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  30. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +118 -0
  31. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +108 -0
  32. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.cpp +323 -0
  33. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.hpp +133 -0
  34. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.cpp +244 -0
  35. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.hpp +163 -0
  36. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.cpp +423 -0
  37. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.hpp +30 -0
  38. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +45 -0
  39. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  40. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +76 -0
  41. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  42. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +87 -0
  43. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +63 -0
  44. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +69 -0
  45. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  46. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +29 -0
  47. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  48. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  49. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  50. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +41 -0
  51. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +65 -0
  52. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +54 -0
  53. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  54. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +72 -0
  55. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  56. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +52 -0
  57. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  58. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  59. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
  60. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +54 -0
  61. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +34 -0
  62. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +33 -0
  63. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  64. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +18 -0
  65. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  66. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +35 -0
  67. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  68. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +326 -0
  69. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +138 -0
  70. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  71. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
  72. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  73. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.cpp +12264 -0
  74. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.pyx +203 -0
  75. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +109 -0
  76. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +125 -0
  77. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  78. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1914 -0
  79. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +208 -0
  80. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +128 -0
  81. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  82. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +58 -0
  83. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +144 -0
  84. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  85. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  86. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  87. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +160 -0
  88. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +98 -0
  89. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +243 -0
  90. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  91. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +207 -0
  92. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +80 -0
  93. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +83 -0
  94. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  95. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  96. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +201 -0
  97. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +108 -0
  98. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  99. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  100. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  101. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  102. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  103. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +164 -0
  104. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +926 -0
  105. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +182 -0
  106. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  107. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  108. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc.c +3052 -0
  109. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3019 -0
  110. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3354 -0
  111. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +344 -0
  112. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +29300 -0
  113. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +381 -0
  114. snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.cpp +99 -0
  115. snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.hpp +44 -0
  116. snowflake/connector/_internal/nanoarrow_cpp/scripts/.clang-format +8 -0
  117. snowflake/connector/_internal/nanoarrow_cpp/scripts/format.sh +8 -0
  118. snowflake/connector/_internal/protobuf_gen/__init__.py +0 -0
  119. snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.py +326 -0
  120. snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.pyi +3403 -0
  121. snowflake/connector/_internal/protobuf_gen/database_driver_v1_services.py +944 -0
  122. snowflake/connector/_internal/protobuf_gen/proto_exception.py +17 -0
  123. snowflake/connector/_internal/snow_logging.py +144 -0
  124. snowflake/connector/_internal/snowflake_restful.py +219 -0
  125. snowflake/connector/_internal/sqlstate.py +11 -0
  126. snowflake/connector/_internal/statement_utils.py +151 -0
  127. snowflake/connector/_internal/status_codes.py +113 -0
  128. snowflake/connector/_internal/telemetry.py +62 -0
  129. snowflake/connector/_internal/text_utils.py +211 -0
  130. snowflake/connector/_internal/type_codes.py +126 -0
  131. snowflake/connector/_internal/write_pandas_operation.py +541 -0
  132. snowflake/connector/auth/__init__.py +0 -0
  133. snowflake/connector/auth/workload_identity.py +5 -0
  134. snowflake/connector/compat.py +22 -0
  135. snowflake/connector/config_manager.py +389 -0
  136. snowflake/connector/connection.py +969 -0
  137. snowflake/connector/constants.py +39 -0
  138. snowflake/connector/cursor/__init__.py +43 -0
  139. snowflake/connector/cursor/_base.py +1304 -0
  140. snowflake/connector/cursor/_dict_cursor.py +55 -0
  141. snowflake/connector/cursor/_query_result.py +186 -0
  142. snowflake/connector/cursor/_query_result_waiter.py +47 -0
  143. snowflake/connector/cursor/_result_metadata.py +85 -0
  144. snowflake/connector/cursor/_snowflake_cursor.py +49 -0
  145. snowflake/connector/description.py +7 -0
  146. snowflake/connector/errors.py +373 -0
  147. snowflake/connector/pandas_tools.py +180 -0
  148. snowflake/connector/py.typed +0 -0
  149. snowflake/connector/result_batch.py +339 -0
  150. snowflake/connector/telemetry.py +19 -0
  151. snowflake/connector/time_util.py +11 -0
  152. snowflake/connector/types.py +134 -0
  153. snowflake/connector/util_text.py +3 -0
  154. snowflake/connector/version.py +23 -0
  155. snowflake_connector_python-5.0.0b1.dist-info/METADATA +175 -0
  156. snowflake_connector_python-5.0.0b1.dist-info/RECORD +157 -0
  157. snowflake_connector_python-5.0.0b1.dist-info/WHEEL +4 -0
@@ -0,0 +1,112 @@
1
+ """
2
+ PEP 249 Database API 2.0 Implementation
3
+
4
+ This module provides an empty implementation of the Python Database API Specification 2.0
5
+ as defined in PEP 249.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from . import util_text # noqa: F401 - backward compatibility re-exports
11
+ from ._internal.api_client.c_api import register_default_logger_callback # noqa: F401
12
+ from ._internal.decorators import pep249
13
+ from .connection import Connection, SnowflakeConnection
14
+ from .constants import QueryStatus, StatementParameterName
15
+ from .cursor import DictCursor, SnowflakeCursor
16
+ from .errors import (
17
+ DatabaseError,
18
+ DataError,
19
+ Error,
20
+ IntegrityError,
21
+ InterfaceError,
22
+ InternalError,
23
+ NotSupportedError,
24
+ OperationalError,
25
+ ProgrammingError,
26
+ Warning,
27
+ )
28
+ from .types import (
29
+ BINARY,
30
+ DATETIME,
31
+ NUMBER,
32
+ ROWID,
33
+ STRING,
34
+ Binary,
35
+ Date,
36
+ DateFromTicks,
37
+ Time,
38
+ TimeFromTicks,
39
+ Timestamp,
40
+ TimestampFromTicks,
41
+ )
42
+ from .version import __version__
43
+
44
+
45
+ # PEP 249 Module Interface Constants
46
+ apilevel = "2.0"
47
+ threadsafety = 2 # Threads may share the module and connections, but not cursors
48
+ paramstyle = "pyformat" # Default: %(name)s and %s placeholders (client-side interpolation)
49
+
50
+
51
+ @pep249
52
+ def connect(**kwargs: Any) -> Connection:
53
+ """
54
+ Create a connection to the database.
55
+
56
+ Args:
57
+ database: Database name
58
+ user: Username
59
+ password: Password
60
+ host: Host name
61
+ port: Port number
62
+ **kwargs: Additional connection parameters
63
+
64
+ Returns:
65
+ Connection: A Connection object
66
+ """
67
+ return Connection(**kwargs)
68
+
69
+
70
+ # Export all public symbols
71
+ __all__ = [
72
+ # Version
73
+ "__version__",
74
+ # Module constants
75
+ "apilevel",
76
+ "threadsafety",
77
+ "paramstyle",
78
+ # Connection function
79
+ "connect",
80
+ # Classes
81
+ "Connection",
82
+ "SnowflakeConnection",
83
+ "QueryStatus",
84
+ "StatementParameterName",
85
+ "DictCursor",
86
+ "SnowflakeCursor",
87
+ # Exceptions
88
+ "Warning",
89
+ "Error",
90
+ "InterfaceError",
91
+ "DatabaseError",
92
+ "DataError",
93
+ "OperationalError",
94
+ "IntegrityError",
95
+ "InternalError",
96
+ "ProgrammingError",
97
+ "NotSupportedError",
98
+ # Type constructors
99
+ "Date",
100
+ "Time",
101
+ "Timestamp",
102
+ "DateFromTicks",
103
+ "TimeFromTicks",
104
+ "TimestampFromTicks",
105
+ "Binary",
106
+ # Type objects
107
+ "STRING",
108
+ "BINARY",
109
+ "NUMBER",
110
+ "DATETIME",
111
+ "ROWID",
112
+ ]
File without changes
Binary file
@@ -0,0 +1,6 @@
1
+ """Internal module for snowflake.ud_connector."""
2
+
3
+ from .decorators import internal_api
4
+
5
+
6
+ __all__ = ["internal_api"]
@@ -0,0 +1,50 @@
1
+ """Helper functions for private key conversion."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from ..errors import ProgrammingError
8
+
9
+
10
+ def normalize_private_key(private_key: Any) -> bytes | str:
11
+ """
12
+ Normalize private_key to a format that can be sent to the Rust core.
13
+
14
+ The Rust core handles:
15
+ - bytes: DER format (sent via connection_set_option_bytes)
16
+ - str: base64-encoded PEM or DER (sent via connection_set_option_string)
17
+
18
+ This function only converts RSAPrivateKey objects to bytes.
19
+ bytes and str are passed through as-is.
20
+
21
+ Args:
22
+ private_key: Private key in one of the supported formats:
23
+ - bytes (DER format)
24
+ - str (base64-encoded PEM or DER)
25
+ - RSAPrivateKey object
26
+
27
+ Returns:
28
+ bytes or str: Private key ready to be sent to Rust core
29
+
30
+ Raises:
31
+ ProgrammingError: If the private_key type is not supported or conversion fails
32
+ """
33
+ if isinstance(private_key, (bytes, str)):
34
+ # Pass through - Rust handles DER bytes and base64-encoded strings (PEM or DER)
35
+ return private_key
36
+
37
+ # Handle RSAPrivateKey object from cryptography library
38
+ from cryptography.hazmat.primitives import serialization
39
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
40
+
41
+ if isinstance(private_key, RSAPrivateKey):
42
+ return private_key.private_bytes(
43
+ encoding=serialization.Encoding.DER,
44
+ format=serialization.PrivateFormat.PKCS8,
45
+ encryption_algorithm=serialization.NoEncryption(),
46
+ )
47
+ raise ProgrammingError(
48
+ f"Unsupported private_key type: {type(private_key)}. "
49
+ "Expected bytes, str (base64-encoded), or RSAPrivateKey object."
50
+ )
@@ -0,0 +1,6 @@
1
+ """Initialize the core API with the default logger callback."""
2
+
3
+ from .c_api import c_logger_callback, sf_core_init
4
+
5
+
6
+ sf_core_init(c_logger_callback)
@@ -0,0 +1,187 @@
1
+ import ctypes
2
+ import functools
3
+ import logging
4
+ import os
5
+ import sys
6
+
7
+ from enum import Enum
8
+ from importlib import resources
9
+ from typing import Any
10
+
11
+ from ..logging import get_sf_core_logger
12
+
13
+
14
+ _CORE_LIB_STEM = "sf_core"
15
+ _CORE_LIB_NAME = f"lib{_CORE_LIB_STEM}"
16
+
17
+
18
+ class CORE_API(Enum):
19
+ DATABASE_DRIVER_API_V1 = 1
20
+
21
+
22
+ class CAPIHandle(ctypes.Structure):
23
+ _fields_ = [("id", ctypes.c_int64), ("magic", ctypes.c_int64)]
24
+
25
+
26
+ def _get_core_path() -> Any:
27
+ # Define the file name for each platform.
28
+ # On Windows, cdylib crates produce "sf_core.dll" (no lib prefix).
29
+ # On Unix, they produce "libsf_core.so" / "libsf_core.dylib".
30
+ if sys.platform.startswith("win"):
31
+ lib_name = f"{_CORE_LIB_STEM}.dll"
32
+ elif sys.platform.startswith("darwin"):
33
+ lib_name = f"{_CORE_LIB_NAME}.dylib"
34
+ else:
35
+ lib_name = f"{_CORE_LIB_NAME}.so"
36
+
37
+ files = resources.files("snowflake.connector")
38
+ return files.joinpath("_core").joinpath(lib_name)
39
+
40
+
41
+ def _load_core() -> ctypes.CDLL:
42
+ path = _get_core_path()
43
+ with resources.as_file(path) as lib_path:
44
+ lib_path_str = str(lib_path)
45
+ if sys.platform.startswith("win"):
46
+ # ctypes.CDLL on Python 3.8+ uses restricted DLL search; register
47
+ # _core/ so the Windows loader finds sf_core.dll's co-located deps.
48
+ os.add_dll_directory(os.fspath(lib_path.parent))
49
+ try:
50
+ return ctypes.CDLL(lib_path_str)
51
+ except OSError as err:
52
+ raise OSError(f"Couldn't load core driver (path={lib_path_str})") from err
53
+
54
+
55
+ try:
56
+ core = _load_core()
57
+ except OSError as err:
58
+ raise RuntimeError("Couldn't load core driver dependency") from err
59
+
60
+ LOGGER_CALLBACK = ctypes.CFUNCTYPE(
61
+ ctypes.c_uint32, ctypes.c_uint32, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint32, ctypes.c_char_p
62
+ )
63
+ core.sf_core_init.argtypes = [LOGGER_CALLBACK]
64
+ core.sf_core_init.restype = ctypes.c_uint32
65
+
66
+ core.sf_core_api_call_proto.restype = ctypes.c_uint32
67
+ core.sf_core_api_call_proto.argtypes = [
68
+ ctypes.c_char_p, # const char* api
69
+ ctypes.c_char_p, # const char* method
70
+ ctypes.POINTER(ctypes.c_ubyte), # const char* request
71
+ ctypes.c_size_t, # size_t request_len
72
+ ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), # char* const* response
73
+ ctypes.POINTER(ctypes.c_size_t), # size_t* response_len
74
+ ]
75
+
76
+ core.sf_core_free_buffer.restype = None
77
+ core.sf_core_free_buffer.argtypes = [
78
+ ctypes.POINTER(ctypes.c_ubyte), # uint8_t* buffer
79
+ ctypes.c_size_t, # size_t len
80
+ ]
81
+
82
+
83
+ # Performance instrumentation FFI bindings (see sf_core/src/c_api.rs).
84
+ # These symbols are always present in libsf_core; when the perf_timing feature
85
+ # is off they return empty/no-op results. Callers use sf_core_perf_enabled() to
86
+ # check whether real data is available.
87
+ core.sf_core_perf_enabled.argtypes = []
88
+ core.sf_core_perf_enabled.restype = ctypes.c_bool
89
+
90
+
91
+ class CoreInstrumentationData(ctypes.Structure):
92
+ """Mirrors #[repr(C)] CoreInstrumentationData from sf_core::perf_timing."""
93
+
94
+ _fields_ = [
95
+ ("core_batch_wait_ns", ctypes.c_uint64),
96
+ ("core_chunk_download_ns", ctypes.c_uint64),
97
+ ("core_arrow_decode_ns", ctypes.c_uint64),
98
+ ]
99
+
100
+
101
+ core.sf_core_get_perf_data.argtypes = []
102
+ core.sf_core_get_perf_data.restype = CoreInstrumentationData
103
+
104
+ core.sf_core_reset_perf_metrics.argtypes = []
105
+ core.sf_core_reset_perf_metrics.restype = None
106
+
107
+
108
+ def sf_core_api_call_proto(
109
+ api: ctypes.c_char_p,
110
+ method: ctypes.c_char_p,
111
+ request: Any,
112
+ request_len: int,
113
+ response: Any,
114
+ response_len: Any,
115
+ ) -> int:
116
+ return core.sf_core_api_call_proto(api, method, request, request_len, response, response_len) # type: ignore
117
+
118
+
119
+ def sf_core_free_buffer(buffer: Any, length: int) -> None:
120
+ core.sf_core_free_buffer(buffer, length)
121
+
122
+
123
+ def sf_core_init(callback: Any) -> None:
124
+ core.sf_core_init(callback)
125
+
126
+
127
+ level_map = {
128
+ # sf_core level -> python logging level
129
+ 0: logging.ERROR,
130
+ 1: logging.WARNING,
131
+ 2: logging.INFO,
132
+ 3: logging.DEBUG,
133
+ }
134
+
135
+
136
+ def logger_callback(level: int, message: bytes, filename: bytes, line: int, function: bytes) -> int:
137
+ py_level = level_map.get(level)
138
+ if py_level is None:
139
+ return 0
140
+
141
+ sf_core_logger = get_sf_core_logger()
142
+ # Respect the logger's configured level - skip if not enabled
143
+ if not sf_core_logger.isEnabledFor(py_level):
144
+ return 0
145
+
146
+ record = sf_core_logger.makeRecord(
147
+ sf_core_logger.name,
148
+ py_level,
149
+ filename.decode("utf-8"),
150
+ line,
151
+ message.decode("utf-8"),
152
+ (),
153
+ None,
154
+ func=function.decode("utf-8"),
155
+ )
156
+ sf_core_logger.handle(record)
157
+ return 0
158
+
159
+
160
+ c_logger_callback = LOGGER_CALLBACK(logger_callback)
161
+
162
+
163
+ def register_default_logger_callback() -> None:
164
+ """
165
+ Register the default logger callback with the core API.
166
+ Call this function explicitly to set up logging.
167
+ """
168
+ sf_core_init(c_logger_callback)
169
+
170
+
171
+ @functools.lru_cache(maxsize=1)
172
+ def sf_core_perf_enabled() -> bool:
173
+ return bool(core.sf_core_perf_enabled())
174
+
175
+
176
+ def sf_core_get_perf_data() -> dict[str, float]:
177
+ """Atomically read-and-reset perf counters, returning seconds."""
178
+ data: CoreInstrumentationData = core.sf_core_get_perf_data()
179
+ return {
180
+ "core_batch_wait_s": data.core_batch_wait_ns / 1e9,
181
+ "core_chunk_download_s": data.core_chunk_download_ns / 1e9,
182
+ "core_arrow_decode_s": data.core_arrow_decode_ns / 1e9,
183
+ }
184
+
185
+
186
+ def sf_core_reset_perf_metrics() -> None:
187
+ core.sf_core_reset_perf_metrics()
@@ -0,0 +1,224 @@
1
+ from __future__ import annotations
2
+
3
+ import ctypes
4
+ import threading
5
+
6
+ from ctypes import c_char_p
7
+ from typing import Any
8
+
9
+ from snowflake.connector._internal.status_codes import (
10
+ STATUS_CODE_LABELS,
11
+ STATUS_TO_ERRNO,
12
+ STATUS_TO_EXCEPTION,
13
+ VENDOR_CODE_TO_EXCEPTION,
14
+ )
15
+ from snowflake.connector.errors import DatabaseError, Error, OperationalError
16
+
17
+ from ..protobuf_gen.database_driver_v1_pb2 import (
18
+ AuthenticationError as ProtoAuthenticationError,
19
+ )
20
+ from ..protobuf_gen.database_driver_v1_pb2 import (
21
+ InvalidParameterValue as ProtoInvalidParameterValue,
22
+ )
23
+ from ..protobuf_gen.database_driver_v1_pb2 import (
24
+ LoginError as ProtoLoginError,
25
+ )
26
+ from ..protobuf_gen.database_driver_v1_pb2 import (
27
+ MissingParameter as ProtoMissingParameter,
28
+ )
29
+ from ..protobuf_gen.database_driver_v1_services import DatabaseDriverClient
30
+ from ..protobuf_gen.proto_exception import (
31
+ ProtoApplicationException,
32
+ ProtoTransportException,
33
+ )
34
+ from .c_api import sf_core_api_call_proto, sf_core_free_buffer
35
+
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # Proto-to-PEP-249 error conversion (kept here, at the transport boundary)
39
+ # ---------------------------------------------------------------------------
40
+
41
+
42
+ def _extract_error_detail(driver_exception: Any) -> str | None:
43
+ error = getattr(driver_exception, "error", None)
44
+ if error is None:
45
+ return None
46
+
47
+ error_type = error.WhichOneof("error_type")
48
+ if error_type is None:
49
+ return None
50
+
51
+ inner = getattr(error, error_type, None)
52
+ if inner is None:
53
+ return None
54
+
55
+ if isinstance(inner, ProtoAuthenticationError):
56
+ return inner.detail or None
57
+ if isinstance(inner, ProtoLoginError):
58
+ if inner.message and inner.code:
59
+ return f"{inner.message} (code={inner.code})"
60
+ return inner.message or None
61
+ if isinstance(inner, ProtoMissingParameter):
62
+ return f"Missing required parameter: {inner.parameter}" if inner.parameter else None
63
+ if isinstance(inner, ProtoInvalidParameterValue):
64
+ parts = [f"Invalid value {inner.value!r} for parameter {inner.parameter!r}"]
65
+ if inner.explanation:
66
+ parts.append(inner.explanation)
67
+ return ". ".join(parts)
68
+ # GenericError, InternalError have no extra fields
69
+ return None
70
+
71
+
72
+ def _append_detail(base: str, detail: str) -> str:
73
+ """Append *detail* to *base* with `. ` separator, avoiding double punctuation."""
74
+ if not base:
75
+ return detail
76
+ base = base.rstrip(".")
77
+ return f"{base}. {detail}"
78
+
79
+
80
+ def _proto_to_public_error(proto_exc: Exception) -> Error:
81
+ """Convert a proto-layer exception into a PEP 249 ``Error`` subclass.
82
+
83
+ This function **returns** the converted exception; it does not raise it.
84
+ The caller (``_raise_error`` in the generated client) is responsible for
85
+ raising the returned value.
86
+ """
87
+ if isinstance(proto_exc, ProtoApplicationException):
88
+ return _convert_application_error(proto_exc)
89
+ if isinstance(proto_exc, ProtoTransportException):
90
+ return OperationalError(f"Driver communication error: {proto_exc}")
91
+ return DatabaseError(str(proto_exc))
92
+
93
+
94
+ def _resolve_exception_class(status_code: int, vendor_code: int | None) -> type[Error]:
95
+ """Pick the PEP 249 exception class for a proto error.
96
+
97
+ Resolution order:
98
+ 1. VENDOR_CODE_TO_EXCEPTION — Snowflake-specific vendor_code overrides (e.g. 100072 → IntegrityError).
99
+ 2. STATUS_TO_EXCEPTION — default mapping from the proto StatusCode.
100
+ 3. DatabaseError — catch-all when the status code is unrecognized.
101
+ """
102
+ if vendor_code is not None:
103
+ cls = VENDOR_CODE_TO_EXCEPTION.get(vendor_code)
104
+ if cls is not None:
105
+ return cls
106
+ return STATUS_TO_EXCEPTION.get(status_code, DatabaseError)
107
+
108
+
109
+ def _convert_application_error(proto_exc: ProtoApplicationException) -> Error:
110
+ driver_exc = getattr(proto_exc, "api_error_pb", None)
111
+ if driver_exc is None:
112
+ return DatabaseError(str(proto_exc))
113
+
114
+ status_code = getattr(driver_exc, "status_code", 0)
115
+ message = getattr(driver_exc, "message", "") or ""
116
+
117
+ # The root_cause field carries the deepest error in the chain from the
118
+ # Rust core, which is typically the most informative for end users.
119
+ root_cause = _get_optional_str(driver_exc, "root_cause")
120
+ if root_cause and root_cause not in message:
121
+ message = _append_detail(message, root_cause)
122
+
123
+ detail = _extract_error_detail(driver_exc)
124
+ if detail and detail not in message:
125
+ message = _append_detail(message, detail)
126
+
127
+ if not message:
128
+ message = STATUS_CODE_LABELS.get(status_code, "Unknown error")
129
+
130
+ # Prefer the Snowflake server vendor_code when the core driver provides it
131
+ # (e.g. 1003 for syntax error, 904 for invalid identifier).
132
+ # Fall back to the old-driver-compatible errno mapping, then to the raw
133
+ # proto status code.
134
+ vendor_code = _get_optional_int(driver_exc, "vendor_code")
135
+
136
+ exc_class = _resolve_exception_class(status_code, vendor_code)
137
+ errno = vendor_code if vendor_code is not None else STATUS_TO_ERRNO.get(status_code, status_code)
138
+
139
+ # Prefer the server-provided sql_state; fall back to a type-derived value.
140
+ sqlstate = _get_optional_str(driver_exc, "sql_state") or _derive_sqlstate(driver_exc)
141
+
142
+ sfqid = _get_optional_str(driver_exc, "query_id")
143
+
144
+ return exc_class(message, errno=errno, sqlstate=sqlstate, sfqid=sfqid)
145
+
146
+
147
+ def _get_optional_int(msg: Any, field: str) -> int | None:
148
+ """Read an optional int32 proto field, returning None if not set."""
149
+ try:
150
+ if msg.HasField(field):
151
+ return int(getattr(msg, field))
152
+ except (ValueError, TypeError, AttributeError):
153
+ # Field missing from the proto schema or cannot be coerced to int; treat as unset.
154
+ pass
155
+ return None
156
+
157
+
158
+ def _get_optional_str(msg: Any, field: str) -> str | None:
159
+ """Read an optional string proto field, returning None if not set."""
160
+ try:
161
+ if msg.HasField(field):
162
+ return str(getattr(msg, field)) or None
163
+ except (ValueError, TypeError, AttributeError):
164
+ # Field missing from the proto schema or cannot be coerced to string; treat as unset.
165
+ pass
166
+ return None
167
+
168
+
169
+ def _derive_sqlstate(driver_exception: Any) -> str | None:
170
+ """Derive sqlstate from the error type when the proto does not carry it.
171
+
172
+ Only login/auth errors have an obvious ANSI SQL state mapping today.
173
+ Other error types (missing_parameter, invalid_parameter_value, etc.)
174
+ will return ``None``; extend this function as mappings become clear.
175
+ """
176
+ error = getattr(driver_exception, "error", None)
177
+ if error is None:
178
+ return None
179
+ error_type = error.WhichOneof("error_type")
180
+ if error_type in ("login_error", "auth_error"):
181
+ return "08001" # SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED
182
+ return None
183
+
184
+
185
+ # ---------------------------------------------------------------------------
186
+ # Transport + singleton
187
+ # ---------------------------------------------------------------------------
188
+
189
+
190
+ class ProtoTransport:
191
+ def handle_message(self, api: str, method: str, message: bytes) -> tuple[int, bytes]:
192
+ response = ctypes.POINTER(ctypes.c_ubyte)()
193
+ response_len = ctypes.c_size_t()
194
+ api_bytes: c_char_p = ctypes.c_char_p(api.encode("utf-8"))
195
+ method_bytes: c_char_p = ctypes.c_char_p(method.encode("utf-8"))
196
+ message_buf = (ctypes.c_ubyte * len(message))()
197
+ message_buf[:] = message # type: ignore
198
+ code = sf_core_api_call_proto(
199
+ api_bytes,
200
+ method_bytes,
201
+ ctypes.cast(message_buf, ctypes.POINTER(ctypes.c_ubyte)),
202
+ len(message),
203
+ ctypes.byref(response),
204
+ ctypes.byref(response_len),
205
+ )
206
+ if code == 0 or code == 1 or code == 2:
207
+ result = bytes(response[: response_len.value])
208
+ sf_core_free_buffer(response, response_len.value)
209
+ return (code, result)
210
+
211
+ raise ProtoTransportException(f"Unknown error code: {code}")
212
+
213
+
214
+ _DATABASE_DRIVER_CLIENT: DatabaseDriverClient | None = None
215
+ _DATABASE_DRIVER_CLIENT_LOCK = threading.Lock()
216
+
217
+
218
+ def database_driver_client() -> DatabaseDriverClient:
219
+ global _DATABASE_DRIVER_CLIENT
220
+ if _DATABASE_DRIVER_CLIENT is None:
221
+ with _DATABASE_DRIVER_CLIENT_LOCK:
222
+ if _DATABASE_DRIVER_CLIENT is None:
223
+ _DATABASE_DRIVER_CLIENT = DatabaseDriverClient(ProtoTransport(), error_handler=_proto_to_public_error)
224
+ return _DATABASE_DRIVER_CLIENT