snowflake-connector-python 3.16.0__cp313-cp313-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 (246) hide show
  1. snowflake/connector/__init__.py +96 -0
  2. snowflake/connector/_query_context_cache.py +276 -0
  3. snowflake/connector/_sql_util.py +48 -0
  4. snowflake/connector/_utils.py +70 -0
  5. snowflake/connector/arrow_context.py +203 -0
  6. snowflake/connector/auth/__init__.py +53 -0
  7. snowflake/connector/auth/_auth.py +586 -0
  8. snowflake/connector/auth/_http_server.py +220 -0
  9. snowflake/connector/auth/_oauth_base.py +400 -0
  10. snowflake/connector/auth/by_plugin.py +219 -0
  11. snowflake/connector/auth/default.py +36 -0
  12. snowflake/connector/auth/idtoken.py +72 -0
  13. snowflake/connector/auth/keypair.py +222 -0
  14. snowflake/connector/auth/no_auth.py +39 -0
  15. snowflake/connector/auth/oauth.py +49 -0
  16. snowflake/connector/auth/oauth_code.py +479 -0
  17. snowflake/connector/auth/oauth_credentials.py +66 -0
  18. snowflake/connector/auth/okta.py +335 -0
  19. snowflake/connector/auth/pat.py +39 -0
  20. snowflake/connector/auth/usrpwdmfa.py +69 -0
  21. snowflake/connector/auth/webbrowser.py +502 -0
  22. snowflake/connector/auth/workload_identity.py +94 -0
  23. snowflake/connector/azure_storage_client.py +276 -0
  24. snowflake/connector/backoff_policies.py +141 -0
  25. snowflake/connector/bind_upload_agent.py +89 -0
  26. snowflake/connector/cache.py +696 -0
  27. snowflake/connector/compat.py +127 -0
  28. snowflake/connector/config_manager.py +496 -0
  29. snowflake/connector/connection.py +2273 -0
  30. snowflake/connector/connection_diagnostic.py +776 -0
  31. snowflake/connector/constants.py +442 -0
  32. snowflake/connector/converter.py +785 -0
  33. snowflake/connector/converter_issue23517.py +87 -0
  34. snowflake/connector/converter_null.py +14 -0
  35. snowflake/connector/converter_snowsql.py +205 -0
  36. snowflake/connector/cursor.py +1951 -0
  37. snowflake/connector/dbapi.py +53 -0
  38. snowflake/connector/description.py +19 -0
  39. snowflake/connector/direct_file_operation_utils.py +88 -0
  40. snowflake/connector/encryption_util.py +220 -0
  41. snowflake/connector/errorcode.py +91 -0
  42. snowflake/connector/errors.py +615 -0
  43. snowflake/connector/externals_utils/__init__.py +0 -0
  44. snowflake/connector/externals_utils/externals_setup.py +27 -0
  45. snowflake/connector/feature.py +4 -0
  46. snowflake/connector/file_compression_type.py +118 -0
  47. snowflake/connector/file_lock.py +72 -0
  48. snowflake/connector/file_transfer_agent.py +1215 -0
  49. snowflake/connector/file_util.py +153 -0
  50. snowflake/connector/gcs_storage_client.py +474 -0
  51. snowflake/connector/gzip_decoder.py +85 -0
  52. snowflake/connector/local_storage_client.py +90 -0
  53. snowflake/connector/log_configuration.py +60 -0
  54. snowflake/connector/logging_utils/__init__.py +0 -0
  55. snowflake/connector/logging_utils/filters.py +72 -0
  56. snowflake/connector/nanoarrow_arrow_iterator.cp313-win_amd64.pyd +0 -0
  57. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
  58. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  59. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
  60. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  61. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  62. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  63. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +557 -0
  64. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
  65. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
  66. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
  67. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1005 -0
  68. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +127 -0
  69. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
  70. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  71. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
  72. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  73. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
  74. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
  75. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
  76. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  77. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
  78. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  79. snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  80. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  81. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
  82. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +71 -0
  83. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +56 -0
  84. snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  85. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
  86. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  87. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
  88. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  89. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  90. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
  91. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
  92. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
  93. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
  94. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  95. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
  96. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  97. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
  98. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  99. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
  100. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
  101. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  102. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
  103. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  104. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
  105. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
  106. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  107. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
  108. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
  109. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
  110. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  111. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
  112. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
  113. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  114. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  115. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  116. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
  117. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
  118. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
  119. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  120. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
  121. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
  122. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
  123. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  124. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  125. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
  126. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
  127. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  128. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  129. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  130. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  131. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  132. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
  133. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
  134. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
  135. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  136. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  137. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
  138. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
  139. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
  140. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
  141. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +256 -0
  142. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
  143. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
  144. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
  145. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
  146. snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
  147. snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
  148. snowflake/connector/network.py +1297 -0
  149. snowflake/connector/ocsp_asn1crypto.py +447 -0
  150. snowflake/connector/ocsp_snowflake.py +1883 -0
  151. snowflake/connector/options.py +131 -0
  152. snowflake/connector/pandas_tools.py +732 -0
  153. snowflake/connector/proxy.py +43 -0
  154. snowflake/connector/py.typed +0 -0
  155. snowflake/connector/result_batch.py +786 -0
  156. snowflake/connector/result_set.py +319 -0
  157. snowflake/connector/s3_storage_client.py +605 -0
  158. snowflake/connector/secret_detector.py +181 -0
  159. snowflake/connector/sf_dirs.py +64 -0
  160. snowflake/connector/sfbinaryformat.py +35 -0
  161. snowflake/connector/sfdatetime.py +345 -0
  162. snowflake/connector/snow_logging.py +144 -0
  163. snowflake/connector/sqlstate.py +9 -0
  164. snowflake/connector/ssd_internal_keys.py +30 -0
  165. snowflake/connector/ssl_wrap_socket.py +134 -0
  166. snowflake/connector/storage_client.py +478 -0
  167. snowflake/connector/telemetry.py +249 -0
  168. snowflake/connector/telemetry_oob.py +543 -0
  169. snowflake/connector/test_util.py +30 -0
  170. snowflake/connector/time_util.py +159 -0
  171. snowflake/connector/token_cache.py +402 -0
  172. snowflake/connector/tool/__init__.py +0 -0
  173. snowflake/connector/tool/dump_certs.py +57 -0
  174. snowflake/connector/tool/dump_ocsp_response.py +139 -0
  175. snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
  176. snowflake/connector/tool/probe_connection.py +69 -0
  177. snowflake/connector/url_util.py +49 -0
  178. snowflake/connector/util_text.py +301 -0
  179. snowflake/connector/vendored/__init__.py +3 -0
  180. snowflake/connector/vendored/requests/LICENSE +175 -0
  181. snowflake/connector/vendored/requests/__init__.py +169 -0
  182. snowflake/connector/vendored/requests/__version__.py +14 -0
  183. snowflake/connector/vendored/requests/_internal_utils.py +50 -0
  184. snowflake/connector/vendored/requests/adapters.py +537 -0
  185. snowflake/connector/vendored/requests/api.py +157 -0
  186. snowflake/connector/vendored/requests/auth.py +315 -0
  187. snowflake/connector/vendored/requests/certs.py +17 -0
  188. snowflake/connector/vendored/requests/compat.py +79 -0
  189. snowflake/connector/vendored/requests/cookies.py +561 -0
  190. snowflake/connector/vendored/requests/exceptions.py +140 -0
  191. snowflake/connector/vendored/requests/help.py +134 -0
  192. snowflake/connector/vendored/requests/hooks.py +33 -0
  193. snowflake/connector/vendored/requests/models.py +1033 -0
  194. snowflake/connector/vendored/requests/sessions.py +833 -0
  195. snowflake/connector/vendored/requests/status_codes.py +128 -0
  196. snowflake/connector/vendored/requests/structures.py +99 -0
  197. snowflake/connector/vendored/requests/utils.py +1093 -0
  198. snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
  199. snowflake/connector/vendored/urllib3/__init__.py +85 -0
  200. snowflake/connector/vendored/urllib3/_collections.py +355 -0
  201. snowflake/connector/vendored/urllib3/_version.py +2 -0
  202. snowflake/connector/vendored/urllib3/connection.py +572 -0
  203. snowflake/connector/vendored/urllib3/connectionpool.py +1137 -0
  204. snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
  205. snowflake/connector/vendored/urllib3/contrib/_appengine_environ.py +36 -0
  206. snowflake/connector/vendored/urllib3/contrib/_securetransport/__init__.py +0 -0
  207. snowflake/connector/vendored/urllib3/contrib/_securetransport/bindings.py +519 -0
  208. snowflake/connector/vendored/urllib3/contrib/_securetransport/low_level.py +397 -0
  209. snowflake/connector/vendored/urllib3/contrib/appengine.py +314 -0
  210. snowflake/connector/vendored/urllib3/contrib/ntlmpool.py +130 -0
  211. snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +509 -0
  212. snowflake/connector/vendored/urllib3/contrib/securetransport.py +920 -0
  213. snowflake/connector/vendored/urllib3/contrib/socks.py +216 -0
  214. snowflake/connector/vendored/urllib3/exceptions.py +323 -0
  215. snowflake/connector/vendored/urllib3/fields.py +274 -0
  216. snowflake/connector/vendored/urllib3/filepost.py +98 -0
  217. snowflake/connector/vendored/urllib3/packages/__init__.py +0 -0
  218. snowflake/connector/vendored/urllib3/packages/backports/__init__.py +0 -0
  219. snowflake/connector/vendored/urllib3/packages/backports/makefile.py +51 -0
  220. snowflake/connector/vendored/urllib3/packages/backports/weakref_finalize.py +155 -0
  221. snowflake/connector/vendored/urllib3/packages/six.py +1076 -0
  222. snowflake/connector/vendored/urllib3/poolmanager.py +540 -0
  223. snowflake/connector/vendored/urllib3/request.py +191 -0
  224. snowflake/connector/vendored/urllib3/response.py +885 -0
  225. snowflake/connector/vendored/urllib3/util/__init__.py +49 -0
  226. snowflake/connector/vendored/urllib3/util/connection.py +156 -0
  227. snowflake/connector/vendored/urllib3/util/proxy.py +57 -0
  228. snowflake/connector/vendored/urllib3/util/queue.py +22 -0
  229. snowflake/connector/vendored/urllib3/util/request.py +146 -0
  230. snowflake/connector/vendored/urllib3/util/response.py +107 -0
  231. snowflake/connector/vendored/urllib3/util/retry.py +620 -0
  232. snowflake/connector/vendored/urllib3/util/ssl_.py +495 -0
  233. snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
  234. snowflake/connector/vendored/urllib3/util/ssltransport.py +221 -0
  235. snowflake/connector/vendored/urllib3/util/timeout.py +271 -0
  236. snowflake/connector/vendored/urllib3/util/url.py +435 -0
  237. snowflake/connector/vendored/urllib3/util/wait.py +152 -0
  238. snowflake/connector/version.py +3 -0
  239. snowflake/connector/wif_util.py +407 -0
  240. snowflake_connector_python-3.16.0.dist-info/METADATA +1475 -0
  241. snowflake_connector_python-3.16.0.dist-info/RECORD +246 -0
  242. snowflake_connector_python-3.16.0.dist-info/WHEEL +5 -0
  243. snowflake_connector_python-3.16.0.dist-info/entry_points.txt +4 -0
  244. snowflake_connector_python-3.16.0.dist-info/licenses/LICENSE.txt +202 -0
  245. snowflake_connector_python-3.16.0.dist-info/licenses/NOTICE +8 -0
  246. snowflake_connector_python-3.16.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,785 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ import binascii
5
+ import decimal
6
+ import json
7
+ import time
8
+ from datetime import date, datetime
9
+ from datetime import time as dt_t
10
+ from datetime import timedelta, timezone, tzinfo
11
+ from functools import partial
12
+ from logging import getLogger
13
+ from math import ceil
14
+ from time import struct_time
15
+ from typing import TYPE_CHECKING, Any, Callable, NoReturn
16
+
17
+ import pytz
18
+ from pytz import UTC
19
+
20
+ from .compat import IS_BINARY, IS_NUMERIC
21
+ from .errorcode import ER_NOT_SUPPORT_DATA_TYPE
22
+ from .errors import ProgrammingError
23
+ from .sfbinaryformat import binary_to_python, binary_to_snowflake
24
+ from .sfdatetime import sfdatetime_total_seconds_from_timedelta
25
+
26
+ if TYPE_CHECKING:
27
+ from numpy import bool_, int64
28
+
29
+ try:
30
+ import numpy
31
+ except ImportError:
32
+ numpy = None
33
+ try:
34
+ import tzlocal
35
+ except ImportError:
36
+ tzlocal = None
37
+
38
+ BITS_FOR_TIMEZONE = 14
39
+ ZERO_TIMEDELTA = timedelta(seconds=0)
40
+ ZERO_EPOCH_DATE = date(1970, 1, 1)
41
+ ZERO_EPOCH = datetime.fromtimestamp(0, timezone.utc).replace(tzinfo=None)
42
+ ZERO_FILL = "000000000"
43
+
44
+ logger = getLogger(__name__)
45
+
46
+ PYTHON_TO_SNOWFLAKE_TYPE = {
47
+ "int": "FIXED",
48
+ "long": "FIXED",
49
+ "decimal": "FIXED",
50
+ "float": "REAL",
51
+ "str": "TEXT",
52
+ "unicode": "TEXT",
53
+ "bytes": "BINARY",
54
+ "bytearray": "BINARY",
55
+ "bool": "BOOLEAN",
56
+ "bool_": "BOOLEAN",
57
+ "nonetype": "ANY",
58
+ "datetime": "TIMESTAMP_NTZ",
59
+ "sfdatetime": "TIMESTAMP_NTZ",
60
+ "date": "DATE",
61
+ "time": "TIME",
62
+ "struct_time": "TIMESTAMP_NTZ",
63
+ "timedelta": "TIME",
64
+ "list": "TEXT",
65
+ "tuple": "TEXT",
66
+ "int8": "FIXED",
67
+ "int16": "FIXED",
68
+ "int32": "FIXED",
69
+ "int64": "FIXED",
70
+ "uint8": "FIXED",
71
+ "uint16": "FIXED",
72
+ "uint32": "FIXED",
73
+ "uint64": "FIXED",
74
+ "float16": "REAL",
75
+ "float32": "REAL",
76
+ "float64": "REAL",
77
+ "datetime64": "TIMESTAMP_NTZ",
78
+ "quoted_name": "TEXT",
79
+ }
80
+
81
+ # Type alias
82
+ SnowflakeConverterType = Callable[[Any], Any]
83
+
84
+
85
+ def convert_datetime_to_epoch(dt: datetime) -> float:
86
+ """Converts datetime to epoch time in seconds.
87
+
88
+ If Python > 3.3, you may use timestamp() method.
89
+ """
90
+ if dt.tzinfo is not None:
91
+ dt0 = dt.astimezone(pytz.UTC).replace(tzinfo=None)
92
+ else:
93
+ dt0 = dt
94
+ return (dt0 - ZERO_EPOCH).total_seconds()
95
+
96
+
97
+ def _convert_datetime_to_epoch_nanoseconds(dt: datetime) -> str:
98
+ return f"{convert_datetime_to_epoch(dt):f}".replace(".", "") + "000"
99
+
100
+
101
+ def _convert_time_to_epoch_nanoseconds(tm: dt_t) -> str:
102
+ return (
103
+ str(tm.hour * 3600 + tm.minute * 60 + tm.second)
104
+ + f"{tm.microsecond:06d}"
105
+ + "000"
106
+ )
107
+
108
+
109
+ def _convert_date_to_epoch_seconds(dt: date) -> str:
110
+ return f"{int((dt - ZERO_EPOCH_DATE).total_seconds())}"
111
+
112
+
113
+ def _convert_date_to_epoch_milliseconds(dt: date) -> str:
114
+ return f"{(dt - ZERO_EPOCH_DATE).total_seconds():.3f}".replace(".", "")
115
+
116
+
117
+ def _convert_date_to_epoch_nanoseconds(dt: date) -> str:
118
+ return f"{(dt - ZERO_EPOCH_DATE).total_seconds():.9f}".replace(".", "")
119
+
120
+
121
+ def _extract_timestamp(value: str, ctx: dict) -> tuple[float, int]:
122
+ """Extracts timestamp from a raw data."""
123
+ scale = ctx["scale"]
124
+ microseconds = float(value[0 : -scale + 6]) if scale > 6 else float(value)
125
+ fraction_of_nanoseconds = _adjust_fraction_of_nanoseconds(
126
+ value, ctx["max_fraction"], scale
127
+ )
128
+
129
+ return microseconds, fraction_of_nanoseconds
130
+
131
+
132
+ def _adjust_fraction_of_nanoseconds(value: str, max_fraction: int, scale: int) -> int:
133
+ if scale == 0:
134
+ return 0
135
+ if value[0] != "-":
136
+ return int(value[-scale:] + ZERO_FILL[: 9 - scale])
137
+
138
+ frac = int(value[-scale:])
139
+ if frac == 0:
140
+ return 0
141
+ else:
142
+ return int(str(max_fraction - frac) + ZERO_FILL[: 9 - scale])
143
+
144
+
145
+ def _generate_tzinfo_from_tzoffset(tzoffset_minutes: int) -> tzinfo:
146
+ """Generates tzinfo object from tzoffset."""
147
+ return pytz.FixedOffset(tzoffset_minutes)
148
+
149
+
150
+ class SnowflakeConverter:
151
+ def __init__(self, **kwargs) -> None:
152
+ self._parameters: dict[str, str | int | bool] = {}
153
+ self._use_numpy = kwargs.get("use_numpy", False) and numpy is not None
154
+
155
+ logger.debug("use_numpy: %s", self._use_numpy)
156
+
157
+ def set_parameters(self, new_parameters: dict) -> None:
158
+ self._parameters = new_parameters
159
+
160
+ def set_parameter(self, param: Any, value: Any) -> None:
161
+ self._parameters[param] = value
162
+
163
+ def get_parameters(self) -> dict[str, str | int | bool]:
164
+ return self._parameters
165
+
166
+ def get_parameter(self, param: str) -> str | int | bool | None:
167
+ return self._parameters.get(param)
168
+
169
+ def to_python_method(self, type_name, column) -> SnowflakeConverterType:
170
+ """FROM Snowflake to Python Objects"""
171
+ ctx = column.copy()
172
+ if ctx.get("scale") is not None:
173
+ ctx["max_fraction"] = int(10 ** ctx["scale"])
174
+ ctx["zero_fill"] = "0" * (9 - ctx["scale"])
175
+ converters = [f"_{type_name}_to_python"]
176
+ if self._use_numpy:
177
+ converters.insert(0, f"_{type_name}_numpy_to_python")
178
+ for conv in converters:
179
+ try:
180
+ return getattr(self, conv)(ctx)
181
+ except AttributeError:
182
+ pass
183
+ logger.warning("No column converter found for type: %s", type_name)
184
+ return None # Skip conversion
185
+
186
+ def _FIXED_to_python(self, ctx: dict[str, Any]) -> Callable:
187
+ return int if ctx["scale"] == 0 else decimal.Decimal
188
+
189
+ def _FIXED_numpy_to_python(self, ctx: dict[str, Any]) -> Callable:
190
+ if ctx["scale"]:
191
+ return numpy.float64
192
+ else:
193
+
194
+ def conv(value: str) -> int64:
195
+ try:
196
+ return numpy.int64(value)
197
+ except OverflowError:
198
+ return int(value)
199
+
200
+ return conv
201
+
202
+ def _DECFLOAT_numpy_to_python(self, ctx: dict[str, Any]) -> Callable:
203
+ return numpy.float64
204
+
205
+ def _DECFLOAT_to_python(self, ctx: dict[str, Any]) -> Callable:
206
+ return decimal.Decimal
207
+
208
+ def _REAL_to_python(self, _: dict[str, str | None] | dict[str, str]) -> Callable:
209
+ return float
210
+
211
+ def _REAL_numpy_to_python(self, _) -> Callable:
212
+ return numpy.float64
213
+
214
+ def _TEXT_to_python(self, _: dict[str, Any]) -> None:
215
+ return None # skip conv
216
+
217
+ def _BINARY_to_python(self, _) -> Callable:
218
+ return binary_to_python
219
+
220
+ def _DATE_to_python(self, _: dict[str, str | None]) -> Callable:
221
+ """Converts DATE to date."""
222
+
223
+ def conv(value: str) -> date:
224
+ try:
225
+ return (
226
+ datetime.fromtimestamp(int(value) * 86400, timezone.utc)
227
+ .replace(tzinfo=None)
228
+ .date()
229
+ )
230
+ except (OSError, ValueError) as e:
231
+ logger.debug("Failed to convert: %s", e)
232
+ ts = ZERO_EPOCH + timedelta(seconds=int(value) * (24 * 60 * 60))
233
+ return date(ts.year, ts.month, ts.day)
234
+
235
+ return conv
236
+
237
+ def _DATE_numpy_to_python(self, _) -> Callable:
238
+ """Converts DATE to datetime.
239
+
240
+ No timezone is attached.
241
+ """
242
+ return lambda x: numpy.datetime64(int(x), "D")
243
+
244
+ def _TIMESTAMP_TZ_to_python(self, ctx: dict[str, Any]) -> Callable:
245
+ """Converts TIMESTAMP TZ to datetime.
246
+
247
+ The timezone offset is piggybacked.
248
+ """
249
+ scale = ctx["scale"]
250
+
251
+ def conv(encoded_value: str) -> datetime:
252
+ value, tz = encoded_value.split()
253
+ tzinfo = _generate_tzinfo_from_tzoffset(int(tz) - 1440)
254
+ return SnowflakeConverter.create_timestamp_from_string(
255
+ value=value, scale=scale, tz=tzinfo
256
+ )
257
+
258
+ return conv
259
+
260
+ def _get_session_tz(self) -> tzinfo | UTC:
261
+ """Gets the session timezone or use the local computer's timezone."""
262
+ try:
263
+ tz = self.get_parameter("TIMEZONE")
264
+ if not tz:
265
+ tz = "UTC"
266
+ return pytz.timezone(tz)
267
+ except pytz.exceptions.UnknownTimeZoneError:
268
+ logger.warning("converting to tzinfo failed")
269
+ if tzlocal is not None:
270
+ return tzlocal.get_localzone()
271
+ else:
272
+ return datetime.timezone.utc
273
+
274
+ def _pre_TIMESTAMP_LTZ_to_python(
275
+ self,
276
+ value,
277
+ ctx,
278
+ ) -> tuple[datetime, int] | tuple[struct_time, int]:
279
+ """Converts TIMESTAMP LTZ to datetime.
280
+
281
+ This takes consideration of the session parameter TIMEZONE if available. If not, tzlocal is used.
282
+ """
283
+ microseconds, fraction_of_nanoseconds = _extract_timestamp(value, ctx)
284
+ tzinfo_value = self._get_session_tz()
285
+
286
+ try:
287
+ t0 = ZERO_EPOCH + timedelta(seconds=microseconds)
288
+ t = pytz.utc.localize(t0, is_dst=False).astimezone(tzinfo_value)
289
+ return t, fraction_of_nanoseconds
290
+ except OverflowError:
291
+ logger.debug(
292
+ "OverflowError in converting from epoch time to "
293
+ "timestamp_ltz: %s(ms). Falling back to use struct_time."
294
+ )
295
+ return time.localtime(microseconds), fraction_of_nanoseconds
296
+
297
+ def _TIMESTAMP_LTZ_to_python(self, ctx: dict[str, Any]) -> Callable:
298
+ tzinfo = self._get_session_tz()
299
+ scale = ctx["scale"]
300
+
301
+ return partial(
302
+ SnowflakeConverter.create_timestamp_from_string, scale=scale, tz=tzinfo
303
+ )
304
+
305
+ _TIMESTAMP_to_python = _TIMESTAMP_LTZ_to_python
306
+
307
+ def _TIMESTAMP_NTZ_to_python(self, ctx: dict[str, Any]) -> Callable:
308
+ """TIMESTAMP NTZ to datetime with no timezone info is attached."""
309
+ scale = ctx["scale"]
310
+
311
+ return partial(SnowflakeConverter.create_timestamp_from_string, scale=scale)
312
+
313
+ def _TIMESTAMP_NTZ_numpy_to_python(self, ctx):
314
+ """TIMESTAMP NTZ to datetime64 with no timezone info is attached."""
315
+
316
+ def conv(value: str) -> numpy.datetime64:
317
+ nanoseconds = int(decimal.Decimal(value).scaleb(9))
318
+ return numpy.datetime64(nanoseconds, "ns")
319
+
320
+ return conv
321
+
322
+ def _TIME_to_python(self, ctx: dict[str, Any]) -> Callable:
323
+ """TIME to formatted string, SnowflakeDateTime, or datetime.time with no timezone attached."""
324
+ scale = ctx["scale"]
325
+
326
+ def conv0(value: str) -> time:
327
+ return (
328
+ datetime.fromtimestamp(float(value), timezone.utc)
329
+ .replace(tzinfo=None)
330
+ .time()
331
+ )
332
+
333
+ def conv(value: str) -> dt_t:
334
+ microseconds = float(value[0 : -scale + 6])
335
+ return (
336
+ datetime.fromtimestamp(microseconds, timezone.utc)
337
+ .replace(tzinfo=None)
338
+ .time()
339
+ )
340
+
341
+ return conv if scale > 6 else conv0
342
+
343
+ def _VARIANT_to_python(self, _: dict[str, Any]) -> Any | None:
344
+ return None # skip conv
345
+
346
+ _OBJECT_to_python = _VARIANT_to_python
347
+
348
+ _ARRAY_to_python = _VARIANT_to_python
349
+
350
+ def _VECTOR_to_python(self, ctx: dict[str, Any]) -> Callable:
351
+ return lambda v: json.loads(v)
352
+
353
+ def _BOOLEAN_to_python(
354
+ self, ctx: dict[str, str | None] | dict[str, str]
355
+ ) -> Callable:
356
+ return lambda value: value in ("1", "TRUE")
357
+
358
+ def snowflake_type(self, value: Any) -> str | None:
359
+ """Returns Snowflake data type for the value. This is used for qmark parameter style."""
360
+ type_name = value.__class__.__name__.lower()
361
+ return PYTHON_TO_SNOWFLAKE_TYPE.get(type_name)
362
+
363
+ def to_snowflake_bindings(self, snowflake_type: str, value: Any) -> str:
364
+ """Converts Python data to snowflake data for qmark and numeric parameter style.
365
+
366
+ The output is bound in a query in the server side.
367
+ """
368
+ type_name = value.__class__.__name__.lower()
369
+ return getattr(self, f"_{type_name}_to_snowflake_bindings")(
370
+ snowflake_type, value
371
+ )
372
+
373
+ def _str_to_snowflake_bindings(self, _, value: str) -> str:
374
+ # NOTE: str type is always taken as a text data and never binary
375
+ return str(value)
376
+
377
+ def _date_to_snowflake_bindings_in_bulk_insertion(self, value: date) -> str:
378
+ # notes: this is for date type bulk insertion, it's different from non-bulk date type insertion flow
379
+ milliseconds = _convert_date_to_epoch_milliseconds(value)
380
+ # according to https://docs.snowflake.com/en/sql-reference/functions/to_date
381
+ # through test, value in seconds will lead to wrong date
382
+ # millisecond and nanoarrow second are good
383
+ # if the milliseconds is beyond the range of 31536000000000, we switch to use nanoseconds
384
+ # otherwise we will hit overflow error in snowflake
385
+ if int(milliseconds) < 31536000000000:
386
+ return milliseconds
387
+ return _convert_date_to_epoch_nanoseconds(value)
388
+
389
+ _int_to_snowflake_bindings = _str_to_snowflake_bindings
390
+ _long_to_snowflake_bindings = _str_to_snowflake_bindings
391
+ _float_to_snowflake_bindings = _str_to_snowflake_bindings
392
+ _unicode_to_snowflake_bindings = _str_to_snowflake_bindings
393
+ _decimal_to_snowflake_bindings = _str_to_snowflake_bindings
394
+
395
+ def _bytes_to_snowflake_bindings(self, _, value: bytes) -> str:
396
+ return binascii.hexlify(value).decode("utf-8")
397
+
398
+ _bytearray_to_snowflake_bindings = _bytes_to_snowflake_bindings
399
+
400
+ def _bool_to_snowflake_bindings(self, _, value: bool) -> str:
401
+ return str(value).lower()
402
+
403
+ def _nonetype_to_snowflake_bindings(self, *_) -> None:
404
+ return None
405
+
406
+ def _date_to_snowflake_bindings(self, _, value: date) -> str:
407
+ # this is for date type non-bulk insertion, it's different from bulk date type insertion flow
408
+ # milliseconds
409
+ return _convert_date_to_epoch_milliseconds(value)
410
+
411
+ def _time_to_snowflake_bindings(self, _, value: dt_t) -> str:
412
+ # nanoseconds
413
+ return _convert_time_to_epoch_nanoseconds(value)
414
+
415
+ def _datetime_to_snowflake_bindings(
416
+ self, snowflake_type: str, value: datetime
417
+ ) -> str:
418
+ snowflake_type = snowflake_type.upper()
419
+ if snowflake_type == "TIMESTAMP_LTZ":
420
+ _, t = self._derive_offset_timestamp(value)
421
+ return _convert_datetime_to_epoch_nanoseconds(t)
422
+ elif snowflake_type == "TIMESTAMP_NTZ":
423
+ # nanoseconds
424
+ return _convert_datetime_to_epoch_nanoseconds(value)
425
+ elif snowflake_type == "TIMESTAMP_TZ":
426
+ offset, t = self._derive_offset_timestamp(value, is_utc=True)
427
+ return _convert_datetime_to_epoch_nanoseconds(t) + " {:04d}".format(
428
+ int(offset)
429
+ )
430
+ else:
431
+ raise ProgrammingError(
432
+ msg="Binding datetime object with Snowflake data type {} is "
433
+ "not supported.".format(snowflake_type),
434
+ errno=ER_NOT_SUPPORT_DATA_TYPE,
435
+ )
436
+
437
+ def _derive_offset_timestamp(
438
+ self, value: datetime, is_utc: bool = False
439
+ ) -> tuple[float, datetime]:
440
+ """Derives TZ offset and timestamp from the datetime objects."""
441
+ tzinfo = value.tzinfo
442
+ if tzinfo is None:
443
+ # If no tzinfo is attached, use local timezone.
444
+ tzinfo = self._get_session_tz() if not is_utc else pytz.UTC
445
+ t = pytz.utc.localize(value, is_dst=False).astimezone(tzinfo)
446
+ else:
447
+ # if tzinfo is attached, just covert to epoch time
448
+ # as the server expects it in UTC anyway
449
+ t = value
450
+ offset = tzinfo.utcoffset(t.replace(tzinfo=None)).total_seconds() / 60 + 1440
451
+ return offset, t
452
+
453
+ def _struct_time_to_snowflake_bindings(
454
+ self, snowflake_type: str, value: time.struct_time
455
+ ) -> str:
456
+ return self._datetime_to_snowflake_bindings(
457
+ snowflake_type, datetime.fromtimestamp(time.mktime(value))
458
+ )
459
+
460
+ def _timedelta_to_snowflake_bindings(
461
+ self, snowflake_type: str, value: timedelta
462
+ ) -> str:
463
+ snowflake_type = snowflake_type.upper()
464
+ if snowflake_type != "TIME":
465
+ raise ProgrammingError(
466
+ msg="Binding timedelta object with Snowflake data type {} is "
467
+ "not supported.".format(snowflake_type),
468
+ errno=ER_NOT_SUPPORT_DATA_TYPE,
469
+ )
470
+ (hours, r) = divmod(value.seconds, 3600)
471
+ (mins, secs) = divmod(r, 60)
472
+ hours += value.days * 24
473
+ return (
474
+ str(hours * 3600 + mins * 60 + secs) + f"{value.microseconds:06d}" + "000"
475
+ )
476
+
477
+ def to_snowflake(self, value: Any) -> Any:
478
+ """Converts Python data to Snowflake data for pyformat/format style.
479
+
480
+ The output is bound in a query in the client side.
481
+ """
482
+ type_name = value.__class__.__name__.lower()
483
+ return getattr(self, f"_{type_name}_to_snowflake")(value)
484
+
485
+ def _int_to_snowflake(self, value: int) -> int:
486
+ return int(value)
487
+
488
+ def _long_to_snowflake(self, value):
489
+ return long(value)
490
+
491
+ def _float_to_snowflake(self, value: float) -> float:
492
+ return float(value)
493
+
494
+ def _str_to_snowflake(self, value: str) -> str:
495
+ return str(value)
496
+
497
+ _unicode_to_snowflake = _str_to_snowflake
498
+
499
+ def _bytes_to_snowflake(self, value: bytes) -> bytes:
500
+ return binary_to_snowflake(value)
501
+
502
+ _bytearray_to_snowflake = _bytes_to_snowflake
503
+
504
+ def _bool_to_snowflake(self, value: bool | bool_) -> bool:
505
+ return bool(value)
506
+
507
+ def _bool__to_snowflake(self, value) -> bool:
508
+ return bool(value)
509
+
510
+ def _nonetype_to_snowflake(self, _: Any | None) -> Any | None:
511
+ return None
512
+
513
+ def _total_seconds_from_timedelta(self, td: timedelta) -> int:
514
+ return sfdatetime_total_seconds_from_timedelta(td)
515
+
516
+ def _datetime_to_snowflake(self, value: datetime) -> str:
517
+ tzinfo_value = value.tzinfo
518
+ if tzinfo_value:
519
+ if pytz.utc != tzinfo_value:
520
+ try:
521
+ td = tzinfo_value.utcoffset(value)
522
+ except pytz.exceptions.AmbiguousTimeError:
523
+ td = tzinfo_value.utcoffset(value, is_dst=False)
524
+ else:
525
+ td = ZERO_TIMEDELTA
526
+ sign = "+" if td >= ZERO_TIMEDELTA else "-"
527
+ td_secs = sfdatetime_total_seconds_from_timedelta(td)
528
+ h, m = divmod(abs(td_secs // 60), 60)
529
+ if value.microsecond:
530
+ return (
531
+ "{year:d}-{month:02d}-{day:02d} "
532
+ "{hour:02d}:{minute:02d}:{second:02d}."
533
+ "{microsecond:06d}{sign}{tzh:02d}:{tzm:02d}"
534
+ ).format(
535
+ year=value.year,
536
+ month=value.month,
537
+ day=value.day,
538
+ hour=value.hour,
539
+ minute=value.minute,
540
+ second=value.second,
541
+ microsecond=value.microsecond,
542
+ sign=sign,
543
+ tzh=h,
544
+ tzm=m,
545
+ )
546
+ return (
547
+ "{year:d}-{month:02d}-{day:02d} "
548
+ "{hour:02d}:{minute:02d}:{second:02d}"
549
+ "{sign}{tzh:02d}:{tzm:02d}"
550
+ ).format(
551
+ year=value.year,
552
+ month=value.month,
553
+ day=value.day,
554
+ hour=value.hour,
555
+ minute=value.minute,
556
+ second=value.second,
557
+ sign=sign,
558
+ tzh=h,
559
+ tzm=m,
560
+ )
561
+ else:
562
+ if value.microsecond:
563
+ return (
564
+ "{year:d}-{month:02d}-{day:02d} "
565
+ "{hour:02d}:{minute:02d}:{second:02d}."
566
+ "{microsecond:06d}"
567
+ ).format(
568
+ year=value.year,
569
+ month=value.month,
570
+ day=value.day,
571
+ hour=value.hour,
572
+ minute=value.minute,
573
+ second=value.second,
574
+ microsecond=value.microsecond,
575
+ )
576
+ return (
577
+ "{year:d}-{month:02d}-{day:02d} " "{hour:02d}:{minute:02d}:{second:02d}"
578
+ ).format(
579
+ year=value.year,
580
+ month=value.month,
581
+ day=value.day,
582
+ hour=value.hour,
583
+ minute=value.minute,
584
+ second=value.second,
585
+ )
586
+
587
+ def _date_to_snowflake(self, value: date) -> str:
588
+ """Converts Date object to Snowflake object."""
589
+ return "{year:d}-{month:02d}-{day:02d}".format(
590
+ year=value.year, month=value.month, day=value.day
591
+ )
592
+
593
+ def _time_to_snowflake(self, value: dt_t) -> str:
594
+ if value.microsecond:
595
+ return value.strftime("%H:%M:%S.%%06d") % value.microsecond
596
+ return value.strftime("%H:%M:%S")
597
+
598
+ def _struct_time_to_snowflake(self, value: time.struct_time) -> str:
599
+ tzinfo_value = _generate_tzinfo_from_tzoffset(time.timezone // 60)
600
+ t = datetime.fromtimestamp(time.mktime(value))
601
+ if pytz.utc != tzinfo_value:
602
+ t += tzinfo_value.utcoffset(t)
603
+ t = t.replace(tzinfo=tzinfo_value)
604
+ return self._datetime_to_snowflake(t)
605
+
606
+ def _timedelta_to_snowflake(self, value: timedelta) -> str:
607
+ (hours, r) = divmod(value.seconds, 3600)
608
+ (mins, secs) = divmod(r, 60)
609
+ hours += value.days * 24
610
+ if value.microseconds:
611
+ return ("{hour:02d}:{minute:02d}:{second:02d}." "{microsecond:06d}").format(
612
+ hour=hours, minute=mins, second=secs, microsecond=value.microseconds
613
+ )
614
+ return "{hour:02d}:{minute:02d}:{second:02d}".format(
615
+ hour=hours, minute=mins, second=secs
616
+ )
617
+
618
+ def _decimal_to_snowflake(self, value: decimal.Decimal) -> str | None:
619
+ if isinstance(value, decimal.Decimal):
620
+ return str(value)
621
+
622
+ return None
623
+
624
+ def _list_to_snowflake(self, value: list) -> list:
625
+ return [
626
+ SnowflakeConverter.quote(v0)
627
+ for v0 in [SnowflakeConverter.escape(v) for v in value]
628
+ ]
629
+
630
+ _tuple_to_snowflake = _list_to_snowflake
631
+
632
+ def __numpy_to_snowflake(self, value):
633
+ return value
634
+
635
+ def _float16_to_snowflake(self, value):
636
+ return float(value)
637
+
638
+ _int8_to_snowflake = __numpy_to_snowflake
639
+ _int16_to_snowflake = __numpy_to_snowflake
640
+ _int32_to_snowflake = __numpy_to_snowflake
641
+ _int64_to_snowflake = __numpy_to_snowflake
642
+ _uint8_to_snowflake = __numpy_to_snowflake
643
+ _uint16_to_snowflake = __numpy_to_snowflake
644
+ _uint32_to_snowflake = __numpy_to_snowflake
645
+ _uint64_to_snowflake = __numpy_to_snowflake
646
+ _float32_to_snowflake = _float16_to_snowflake
647
+ _float64_to_snowflake = _float16_to_snowflake
648
+
649
+ def _datetime64_to_snowflake(self, value) -> str:
650
+ return str(value) + "+00:00"
651
+
652
+ def _quoted_name_to_snowflake(self, value) -> str:
653
+ return str(value)
654
+
655
+ def __getattr__(self, item: str) -> NoReturn:
656
+ if item.endswith("_to_snowflake"):
657
+ raise ProgrammingError(
658
+ msg="Binding data in type ({}) is not supported.".format(
659
+ item[1 : item.find("_to_snowflake")]
660
+ ),
661
+ errno=ER_NOT_SUPPORT_DATA_TYPE,
662
+ )
663
+ elif item.endswith("to_snowflake_bindings"):
664
+ raise ProgrammingError(
665
+ msg="Binding data in type ({}) is not supported.".format(
666
+ item[1 : item.find("_to_snowflake_bindings")]
667
+ ),
668
+ errno=ER_NOT_SUPPORT_DATA_TYPE,
669
+ )
670
+ raise AttributeError(f"No method is available: {item}")
671
+
672
+ def to_csv_bindings(self, value: tuple[str, Any] | Any) -> str | None:
673
+ """Convert value to a string representation in CSV-escaped format to INSERT INTO."""
674
+ if isinstance(value, tuple) and len(value) == 2:
675
+ _type, val = value
676
+ if _type in ["TIMESTAMP_TZ", "TIME"]:
677
+ # unspecified timezone is considered utc
678
+ if getattr(val, "tzinfo", 1) is None:
679
+ val = self.to_snowflake(pytz.utc.localize(val))
680
+ else:
681
+ val = self.to_snowflake(val)
682
+ else:
683
+ val = self.to_snowflake_bindings(_type, val)
684
+ else:
685
+ if isinstance(value, (dt_t, timedelta)):
686
+ val = self.to_snowflake(value)
687
+ elif isinstance(value, date) and not isinstance(value, datetime):
688
+ # FIX SNOW-770678 and SNOW-966444
689
+ # bulk insertion congestion is different from non-bulk insertion
690
+ # to_csv_bindings is only used in bulk insertion logic
691
+ val = self._date_to_snowflake_bindings_in_bulk_insertion(value)
692
+ else:
693
+ _type = self.snowflake_type(value)
694
+ val = self.to_snowflake_bindings(_type, value)
695
+ return self.escape_for_csv(val)
696
+
697
+ @staticmethod
698
+ def escape(value: Any) -> Any:
699
+ if isinstance(value, list):
700
+ return value
701
+ if value is None or IS_NUMERIC(value) or IS_BINARY(value):
702
+ return value
703
+ res = value
704
+ res = res.replace("\\", "\\\\")
705
+ res = res.replace("\n", "\\n")
706
+ res = res.replace("\r", "\\r")
707
+ res = res.replace("\047", "\134\047") # single quotes
708
+ return res
709
+
710
+ @staticmethod
711
+ def quote(value) -> str:
712
+ if isinstance(value, list):
713
+ return ",".join(value)
714
+ if value is None:
715
+ return "NULL"
716
+ elif isinstance(value, bool):
717
+ return "TRUE" if value else "FALSE"
718
+ elif IS_NUMERIC(value):
719
+ return str(repr(value))
720
+ elif IS_BINARY(value):
721
+ # Binary literal syntax
722
+ return "X'{}'".format(value.decode("ascii"))
723
+
724
+ return f"'{value}'"
725
+
726
+ @staticmethod
727
+ def escape_for_csv(value: str) -> str:
728
+ if value is None: # NULL
729
+ return ""
730
+ elif not value: # Empty string
731
+ return '""'
732
+ if (
733
+ value.find('"') >= 0
734
+ or value.find("\n") >= 0
735
+ or value.find(",") >= 0
736
+ or value.find("\\") >= 0
737
+ ):
738
+ # replace single quote with double quotes
739
+ value = value.replace('"', '""')
740
+ return f'"{value}"'
741
+ else:
742
+ return value
743
+
744
+ @staticmethod
745
+ def get_seconds_microseconds(
746
+ value: str,
747
+ scale: int,
748
+ ) -> tuple[int, int]:
749
+ """Calculate the second and microsecond parts og a timestamp given as a string.
750
+
751
+ The trick is that we always want to do floor division, but if the timestamp
752
+ is negative then it is given as its inverse. So -0.000_000_009
753
+ (which is 1969-12-31-23:59:59.999999991) should round down to 6
754
+ fraction figures as Python doesn't support sub-microseconds.
755
+ Ultimately for the aforementioned example we should return two integers 0 and -000_001.
756
+ """
757
+ negative = value[0] == "-"
758
+ lhs, _, rhs = value.partition(".")
759
+ seconds = int(lhs)
760
+ microseconds = int(rhs) if rhs else 0
761
+ if scale < 6:
762
+ microseconds *= 10 ** (6 - scale)
763
+ elif scale > 6:
764
+ if negative:
765
+ microseconds = ceil(microseconds / 10 ** (scale - 6))
766
+ else:
767
+ microseconds = microseconds // 10 ** (scale - 6)
768
+ if negative:
769
+ microseconds = -microseconds
770
+ return seconds, microseconds
771
+
772
+ @staticmethod
773
+ def create_timestamp_from_string(
774
+ value: str,
775
+ scale: int,
776
+ tz: tzinfo | None = None,
777
+ ) -> datetime:
778
+ seconds, fraction = SnowflakeConverter.get_seconds_microseconds(
779
+ value=value, scale=scale
780
+ )
781
+ if not tz:
782
+ return datetime.fromtimestamp(seconds, timezone.utc).replace(
783
+ tzinfo=None
784
+ ) + timedelta(microseconds=fraction)
785
+ return datetime.fromtimestamp(seconds, tz=tz) + timedelta(microseconds=fraction)