singlestoredb 1.16.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. singlestoredb/__init__.py +75 -0
  2. singlestoredb/ai/__init__.py +2 -0
  3. singlestoredb/ai/chat.py +139 -0
  4. singlestoredb/ai/embeddings.py +128 -0
  5. singlestoredb/alchemy/__init__.py +90 -0
  6. singlestoredb/apps/__init__.py +3 -0
  7. singlestoredb/apps/_cloud_functions.py +90 -0
  8. singlestoredb/apps/_config.py +72 -0
  9. singlestoredb/apps/_connection_info.py +18 -0
  10. singlestoredb/apps/_dashboards.py +47 -0
  11. singlestoredb/apps/_process.py +32 -0
  12. singlestoredb/apps/_python_udfs.py +100 -0
  13. singlestoredb/apps/_stdout_supress.py +30 -0
  14. singlestoredb/apps/_uvicorn_util.py +36 -0
  15. singlestoredb/auth.py +245 -0
  16. singlestoredb/config.py +484 -0
  17. singlestoredb/connection.py +1487 -0
  18. singlestoredb/converters.py +950 -0
  19. singlestoredb/docstring/__init__.py +33 -0
  20. singlestoredb/docstring/attrdoc.py +126 -0
  21. singlestoredb/docstring/common.py +230 -0
  22. singlestoredb/docstring/epydoc.py +267 -0
  23. singlestoredb/docstring/google.py +412 -0
  24. singlestoredb/docstring/numpydoc.py +562 -0
  25. singlestoredb/docstring/parser.py +100 -0
  26. singlestoredb/docstring/py.typed +1 -0
  27. singlestoredb/docstring/rest.py +256 -0
  28. singlestoredb/docstring/tests/__init__.py +1 -0
  29. singlestoredb/docstring/tests/_pydoctor.py +21 -0
  30. singlestoredb/docstring/tests/test_epydoc.py +729 -0
  31. singlestoredb/docstring/tests/test_google.py +1007 -0
  32. singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
  33. singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
  34. singlestoredb/docstring/tests/test_parser.py +248 -0
  35. singlestoredb/docstring/tests/test_rest.py +547 -0
  36. singlestoredb/docstring/tests/test_util.py +70 -0
  37. singlestoredb/docstring/util.py +141 -0
  38. singlestoredb/exceptions.py +120 -0
  39. singlestoredb/functions/__init__.py +16 -0
  40. singlestoredb/functions/decorator.py +201 -0
  41. singlestoredb/functions/dtypes.py +1793 -0
  42. singlestoredb/functions/ext/__init__.py +1 -0
  43. singlestoredb/functions/ext/arrow.py +375 -0
  44. singlestoredb/functions/ext/asgi.py +2133 -0
  45. singlestoredb/functions/ext/json.py +420 -0
  46. singlestoredb/functions/ext/mmap.py +413 -0
  47. singlestoredb/functions/ext/rowdat_1.py +724 -0
  48. singlestoredb/functions/ext/timer.py +89 -0
  49. singlestoredb/functions/ext/utils.py +218 -0
  50. singlestoredb/functions/signature.py +1578 -0
  51. singlestoredb/functions/typing/__init__.py +41 -0
  52. singlestoredb/functions/typing/numpy.py +20 -0
  53. singlestoredb/functions/typing/pandas.py +2 -0
  54. singlestoredb/functions/typing/polars.py +2 -0
  55. singlestoredb/functions/typing/pyarrow.py +2 -0
  56. singlestoredb/functions/utils.py +421 -0
  57. singlestoredb/fusion/__init__.py +11 -0
  58. singlestoredb/fusion/graphql.py +213 -0
  59. singlestoredb/fusion/handler.py +916 -0
  60. singlestoredb/fusion/handlers/__init__.py +0 -0
  61. singlestoredb/fusion/handlers/export.py +525 -0
  62. singlestoredb/fusion/handlers/files.py +690 -0
  63. singlestoredb/fusion/handlers/job.py +660 -0
  64. singlestoredb/fusion/handlers/models.py +250 -0
  65. singlestoredb/fusion/handlers/stage.py +502 -0
  66. singlestoredb/fusion/handlers/utils.py +324 -0
  67. singlestoredb/fusion/handlers/workspace.py +956 -0
  68. singlestoredb/fusion/registry.py +249 -0
  69. singlestoredb/fusion/result.py +399 -0
  70. singlestoredb/http/__init__.py +27 -0
  71. singlestoredb/http/connection.py +1267 -0
  72. singlestoredb/magics/__init__.py +34 -0
  73. singlestoredb/magics/run_personal.py +137 -0
  74. singlestoredb/magics/run_shared.py +134 -0
  75. singlestoredb/management/__init__.py +9 -0
  76. singlestoredb/management/billing_usage.py +148 -0
  77. singlestoredb/management/cluster.py +462 -0
  78. singlestoredb/management/export.py +295 -0
  79. singlestoredb/management/files.py +1102 -0
  80. singlestoredb/management/inference_api.py +105 -0
  81. singlestoredb/management/job.py +887 -0
  82. singlestoredb/management/manager.py +373 -0
  83. singlestoredb/management/organization.py +226 -0
  84. singlestoredb/management/region.py +169 -0
  85. singlestoredb/management/utils.py +423 -0
  86. singlestoredb/management/workspace.py +1927 -0
  87. singlestoredb/mysql/__init__.py +177 -0
  88. singlestoredb/mysql/_auth.py +298 -0
  89. singlestoredb/mysql/charset.py +214 -0
  90. singlestoredb/mysql/connection.py +2032 -0
  91. singlestoredb/mysql/constants/CLIENT.py +38 -0
  92. singlestoredb/mysql/constants/COMMAND.py +32 -0
  93. singlestoredb/mysql/constants/CR.py +78 -0
  94. singlestoredb/mysql/constants/ER.py +474 -0
  95. singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
  96. singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
  97. singlestoredb/mysql/constants/FLAG.py +15 -0
  98. singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
  99. singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
  100. singlestoredb/mysql/constants/__init__.py +0 -0
  101. singlestoredb/mysql/converters.py +271 -0
  102. singlestoredb/mysql/cursors.py +896 -0
  103. singlestoredb/mysql/err.py +92 -0
  104. singlestoredb/mysql/optionfile.py +20 -0
  105. singlestoredb/mysql/protocol.py +450 -0
  106. singlestoredb/mysql/tests/__init__.py +19 -0
  107. singlestoredb/mysql/tests/base.py +126 -0
  108. singlestoredb/mysql/tests/conftest.py +37 -0
  109. singlestoredb/mysql/tests/test_DictCursor.py +132 -0
  110. singlestoredb/mysql/tests/test_SSCursor.py +141 -0
  111. singlestoredb/mysql/tests/test_basic.py +452 -0
  112. singlestoredb/mysql/tests/test_connection.py +851 -0
  113. singlestoredb/mysql/tests/test_converters.py +58 -0
  114. singlestoredb/mysql/tests/test_cursor.py +141 -0
  115. singlestoredb/mysql/tests/test_err.py +16 -0
  116. singlestoredb/mysql/tests/test_issues.py +514 -0
  117. singlestoredb/mysql/tests/test_load_local.py +75 -0
  118. singlestoredb/mysql/tests/test_nextset.py +88 -0
  119. singlestoredb/mysql/tests/test_optionfile.py +27 -0
  120. singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
  121. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  122. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
  123. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
  124. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
  125. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
  126. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
  127. singlestoredb/mysql/times.py +23 -0
  128. singlestoredb/notebook/__init__.py +16 -0
  129. singlestoredb/notebook/_objects.py +213 -0
  130. singlestoredb/notebook/_portal.py +352 -0
  131. singlestoredb/py.typed +0 -0
  132. singlestoredb/pytest.py +352 -0
  133. singlestoredb/server/__init__.py +0 -0
  134. singlestoredb/server/docker.py +452 -0
  135. singlestoredb/server/free_tier.py +267 -0
  136. singlestoredb/tests/__init__.py +0 -0
  137. singlestoredb/tests/alltypes.sql +307 -0
  138. singlestoredb/tests/alltypes_no_nulls.sql +208 -0
  139. singlestoredb/tests/empty.sql +0 -0
  140. singlestoredb/tests/ext_funcs/__init__.py +702 -0
  141. singlestoredb/tests/local_infile.csv +3 -0
  142. singlestoredb/tests/test.ipynb +18 -0
  143. singlestoredb/tests/test.sql +680 -0
  144. singlestoredb/tests/test2.ipynb +18 -0
  145. singlestoredb/tests/test2.sql +1 -0
  146. singlestoredb/tests/test_basics.py +1332 -0
  147. singlestoredb/tests/test_config.py +318 -0
  148. singlestoredb/tests/test_connection.py +3103 -0
  149. singlestoredb/tests/test_dbapi.py +27 -0
  150. singlestoredb/tests/test_exceptions.py +45 -0
  151. singlestoredb/tests/test_ext_func.py +1472 -0
  152. singlestoredb/tests/test_ext_func_data.py +1101 -0
  153. singlestoredb/tests/test_fusion.py +1527 -0
  154. singlestoredb/tests/test_http.py +288 -0
  155. singlestoredb/tests/test_management.py +1599 -0
  156. singlestoredb/tests/test_plugin.py +33 -0
  157. singlestoredb/tests/test_results.py +171 -0
  158. singlestoredb/tests/test_types.py +132 -0
  159. singlestoredb/tests/test_udf.py +737 -0
  160. singlestoredb/tests/test_udf_returns.py +459 -0
  161. singlestoredb/tests/test_vectorstore.py +51 -0
  162. singlestoredb/tests/test_xdict.py +333 -0
  163. singlestoredb/tests/utils.py +141 -0
  164. singlestoredb/types.py +373 -0
  165. singlestoredb/utils/__init__.py +0 -0
  166. singlestoredb/utils/config.py +950 -0
  167. singlestoredb/utils/convert_rows.py +69 -0
  168. singlestoredb/utils/debug.py +13 -0
  169. singlestoredb/utils/dtypes.py +205 -0
  170. singlestoredb/utils/events.py +65 -0
  171. singlestoredb/utils/mogrify.py +151 -0
  172. singlestoredb/utils/results.py +585 -0
  173. singlestoredb/utils/xdict.py +425 -0
  174. singlestoredb/vectorstore.py +192 -0
  175. singlestoredb/warnings.py +5 -0
  176. singlestoredb-1.16.1.dist-info/METADATA +165 -0
  177. singlestoredb-1.16.1.dist-info/RECORD +183 -0
  178. singlestoredb-1.16.1.dist-info/WHEEL +5 -0
  179. singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
  180. singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
  181. singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
  182. sqlx/__init__.py +4 -0
  183. sqlx/magic.py +113 -0
@@ -0,0 +1,177 @@
1
+ """
2
+ PyMySQL: A pure-Python MySQL client library.
3
+
4
+ Copyright (c) 2010-2016 PyMySQL contributors
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+ """
24
+ import sys
25
+ from typing import Any
26
+ from typing import FrozenSet
27
+
28
+ from .constants import FIELD_TYPE
29
+ from .err import DatabaseError
30
+ from .err import DataError
31
+ from .err import Error
32
+ from .err import IntegrityError
33
+ from .err import InterfaceError
34
+ from .err import InternalError
35
+ from .err import MySQLError
36
+ from .err import NotSupportedError
37
+ from .err import OperationalError
38
+ from .err import ProgrammingError
39
+ from .err import Warning
40
+ from .times import Date
41
+ from .times import DateFromTicks
42
+ from .times import Time
43
+ from .times import TimeFromTicks
44
+ from .times import Timestamp
45
+ from .times import TimestampFromTicks
46
+
47
+
48
+ threadsafety = 1
49
+ apilevel = '2.0'
50
+ paramstyle = 'pyformat'
51
+
52
+ from . import connection # noqa: E402
53
+
54
+
55
+ class DBAPISet(FrozenSet[Any]):
56
+
57
+ def __ne__(self, other: Any) -> bool:
58
+ if isinstance(other, set):
59
+ return frozenset.__ne__(self, other)
60
+ else:
61
+ return other not in self
62
+
63
+ def __eq__(self, other: Any) -> bool:
64
+ if isinstance(other, frozenset):
65
+ return frozenset.__eq__(self, other)
66
+ else:
67
+ return other in self
68
+
69
+ def __hash__(self) -> int:
70
+ return frozenset.__hash__(self)
71
+
72
+
73
+ STRING = DBAPISet([FIELD_TYPE.ENUM, FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING])
74
+ BINARY = DBAPISet(
75
+ [
76
+ FIELD_TYPE.BLOB,
77
+ FIELD_TYPE.LONG_BLOB,
78
+ FIELD_TYPE.MEDIUM_BLOB,
79
+ FIELD_TYPE.TINY_BLOB,
80
+ ],
81
+ )
82
+ NUMBER = DBAPISet(
83
+ [
84
+ FIELD_TYPE.DECIMAL,
85
+ FIELD_TYPE.DOUBLE,
86
+ FIELD_TYPE.FLOAT,
87
+ FIELD_TYPE.INT24,
88
+ FIELD_TYPE.LONG,
89
+ FIELD_TYPE.LONGLONG,
90
+ FIELD_TYPE.TINY,
91
+ FIELD_TYPE.YEAR,
92
+ ],
93
+ )
94
+ DATE = DBAPISet([FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE])
95
+ TIME = DBAPISet([FIELD_TYPE.TIME])
96
+ TIMESTAMP = DBAPISet([FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME])
97
+ DATETIME = TIMESTAMP
98
+ ROWID = DBAPISet()
99
+
100
+
101
+ def Binary(x: Any) -> bytes:
102
+ """Return x as a binary type."""
103
+ return bytes(x)
104
+
105
+
106
+ Connect = connect = Connection = connection.Connection # type: ignore
107
+
108
+
109
+ def get_client_info() -> str: # for MySQLdb compatibility
110
+ from .. import __version__
111
+ return __version__
112
+
113
+
114
+ # we include a doctored version_info here for MySQLdb compatibility
115
+ version_info = (1, 4, 0, 'final', 0)
116
+
117
+ NULL = 'NULL'
118
+
119
+ __version__ = get_client_info()
120
+
121
+
122
+ def thread_safe() -> bool:
123
+ return True # match MySQLdb.thread_safe()
124
+
125
+
126
+ def install_as_MySQLdb() -> None:
127
+ """
128
+ After this function is called, any application that imports MySQLdb or
129
+ _mysql will unwittingly actually use pymysql.
130
+ """
131
+ sys.modules['MySQLdb'] = sys.modules['_mysql'] = sys.modules['pymysql']
132
+
133
+
134
+ __all__ = [
135
+ 'BINARY',
136
+ 'Binary',
137
+ 'Connect',
138
+ 'Connection',
139
+ 'DATE',
140
+ 'Date',
141
+ 'Time',
142
+ 'Timestamp',
143
+ 'DateFromTicks',
144
+ 'TimeFromTicks',
145
+ 'TimestampFromTicks',
146
+ 'DataError',
147
+ 'DatabaseError',
148
+ 'Error',
149
+ 'FIELD_TYPE',
150
+ 'IntegrityError',
151
+ 'InterfaceError',
152
+ 'InternalError',
153
+ 'MySQLError',
154
+ 'NULL',
155
+ 'NUMBER',
156
+ 'NotSupportedError',
157
+ 'DBAPISet',
158
+ 'OperationalError',
159
+ 'ProgrammingError',
160
+ 'ROWID',
161
+ 'STRING',
162
+ 'TIME',
163
+ 'TIMESTAMP',
164
+ 'Warning',
165
+ 'apilevel',
166
+ 'connect',
167
+ 'connection',
168
+ 'constants',
169
+ 'converters',
170
+ 'cursors',
171
+ 'get_client_info',
172
+ 'paramstyle',
173
+ 'threadsafety',
174
+ 'version_info',
175
+ 'install_as_MySQLdb',
176
+ '__version__',
177
+ ]
@@ -0,0 +1,298 @@
1
+ # type: ignore
2
+ """
3
+ Implements auth methods
4
+ """
5
+ from .err import OperationalError
6
+
7
+ try:
8
+ from cryptography.hazmat.backends import default_backend
9
+ from cryptography.hazmat.primitives import serialization, hashes
10
+ from cryptography.hazmat.primitives.asymmetric import padding
11
+
12
+ _have_cryptography = True
13
+ except ImportError:
14
+ _have_cryptography = False
15
+
16
+ from functools import partial
17
+ import hashlib
18
+
19
+ from ..config import get_option
20
+
21
+
22
+ DEBUG = get_option('debug.connection')
23
+ SCRAMBLE_LENGTH = 20
24
+ sha1_new = partial(hashlib.new, 'sha1')
25
+
26
+
27
+ # mysql_native_password
28
+ # https://dev.mysql.com/doc/internals/en/secure-password-authentication.html#packet-Authentication::Native41
29
+
30
+
31
+ def scramble_native_password(password, message):
32
+ """Scramble used for mysql_native_password."""
33
+ if not password:
34
+ return b''
35
+
36
+ stage1 = sha1_new(password).digest()
37
+ stage2 = sha1_new(stage1).digest()
38
+ s = sha1_new()
39
+ s.update(message[:SCRAMBLE_LENGTH])
40
+ s.update(stage2)
41
+ result = s.digest()
42
+ return _my_crypt(result, stage1)
43
+
44
+
45
+ def _my_crypt(message1, message2):
46
+ result = bytearray(message1)
47
+
48
+ for i in range(len(result)):
49
+ result[i] ^= message2[i]
50
+
51
+ return bytes(result)
52
+
53
+
54
+ # MariaDB's client_ed25519-plugin
55
+ # https://mariadb.com/kb/en/library/connection/#client_ed25519-plugin
56
+
57
+ _nacl_bindings = False
58
+
59
+
60
+ def _init_nacl():
61
+ global _nacl_bindings
62
+ try:
63
+ from nacl import bindings
64
+
65
+ _nacl_bindings = bindings
66
+ except ImportError:
67
+ raise RuntimeError(
68
+ "'pynacl' package is required for ed25519_password auth method",
69
+ )
70
+
71
+
72
+ def _scalar_clamp(s32):
73
+ ba = bytearray(s32)
74
+ ba0 = bytes(bytearray([ba[0] & 248]))
75
+ ba31 = bytes(bytearray([(ba[31] & 127) | 64]))
76
+ return ba0 + bytes(s32[1:31]) + ba31
77
+
78
+
79
+ def ed25519_password(password, scramble):
80
+ """
81
+ Sign a random scramble with elliptic curve Ed25519.
82
+
83
+ Secret and public key are derived from password.
84
+
85
+ """
86
+ # variable names based on rfc8032 section-5.1.6
87
+ #
88
+ if not _nacl_bindings:
89
+ _init_nacl()
90
+
91
+ # h = SHA512(password)
92
+ h = hashlib.sha512(password).digest()
93
+
94
+ # s = prune(first_half(h))
95
+ s = _scalar_clamp(h[:32])
96
+
97
+ # r = SHA512(second_half(h) || M)
98
+ r = hashlib.sha512(h[32:] + scramble).digest()
99
+
100
+ # R = encoded point [r]B
101
+ r = _nacl_bindings.crypto_core_ed25519_scalar_reduce(r)
102
+ R = _nacl_bindings.crypto_scalarmult_ed25519_base_noclamp(r)
103
+
104
+ # A = encoded point [s]B
105
+ A = _nacl_bindings.crypto_scalarmult_ed25519_base_noclamp(s)
106
+
107
+ # k = SHA512(R || A || M)
108
+ k = hashlib.sha512(R + A + scramble).digest()
109
+
110
+ # S = (k * s + r) mod L
111
+ k = _nacl_bindings.crypto_core_ed25519_scalar_reduce(k)
112
+ ks = _nacl_bindings.crypto_core_ed25519_scalar_mul(k, s)
113
+ S = _nacl_bindings.crypto_core_ed25519_scalar_add(ks, r)
114
+
115
+ # signature = R || S
116
+ return R + S
117
+
118
+
119
+ # sha256_password
120
+
121
+
122
+ def _roundtrip(conn, send_data):
123
+ conn.write_packet(send_data)
124
+ pkt = conn._read_packet()
125
+ pkt.check_error()
126
+ return pkt
127
+
128
+
129
+ def _xor_password(password, salt):
130
+ # Trailing NUL character will be added in Auth Switch Request.
131
+ # See https://github.com/mysql/mysql-server/blob/
132
+ # 7d10c82196c8e45554f27c00681474a9fb86d137/sql/auth/sha2_password.cc#L939-L945
133
+ salt = salt[:SCRAMBLE_LENGTH]
134
+ password_bytes = bytearray(password)
135
+ # salt = bytearray(salt) # for PY2 compat.
136
+ salt_len = len(salt)
137
+ for i in range(len(password_bytes)):
138
+ password_bytes[i] ^= salt[i % salt_len]
139
+ return bytes(password_bytes)
140
+
141
+
142
+ def sha2_rsa_encrypt(password, salt, public_key):
143
+ """
144
+ Encrypt password with salt and public_key.
145
+
146
+ Used for sha256_password and caching_sha2_password.
147
+
148
+ """
149
+ if not _have_cryptography:
150
+ raise RuntimeError(
151
+ "'cryptography' package is required for sha256_password or "
152
+ 'caching_sha2_password auth methods',
153
+ )
154
+ message = _xor_password(password + b'\0', salt)
155
+ rsa_key = serialization.load_pem_public_key(public_key, default_backend())
156
+ return rsa_key.encrypt(
157
+ message,
158
+ padding.OAEP(
159
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
160
+ algorithm=hashes.SHA1(),
161
+ label=None,
162
+ ),
163
+ )
164
+
165
+
166
+ def sha256_password_auth(conn, pkt):
167
+ if conn._secure:
168
+ if DEBUG:
169
+ print('sha256: Sending plain password')
170
+ data = conn.password + b'\0'
171
+ return _roundtrip(conn, data)
172
+
173
+ if pkt.is_auth_switch_request():
174
+ conn.salt = pkt.read_all()
175
+ if not conn.server_public_key and conn.password:
176
+ # Request server public key
177
+ if DEBUG:
178
+ print('sha256: Requesting server public key')
179
+ pkt = _roundtrip(conn, b'\1')
180
+
181
+ if pkt.is_extra_auth_data():
182
+ conn.server_public_key = pkt._data[1:]
183
+ if DEBUG:
184
+ print('Received public key:\n', conn.server_public_key.decode('ascii'))
185
+
186
+ if conn.password:
187
+ if not conn.server_public_key:
188
+ raise OperationalError("Couldn't receive server's public key")
189
+
190
+ data = sha2_rsa_encrypt(conn.password, conn.salt, conn.server_public_key)
191
+ else:
192
+ data = b''
193
+
194
+ return _roundtrip(conn, data)
195
+
196
+
197
+ def scramble_caching_sha2(password, nonce):
198
+ # (bytes, bytes) -> bytes
199
+ """
200
+ Scramble algorithm used in cached_sha2_password fast path.
201
+
202
+ XOR(SHA256(password), SHA256(SHA256(SHA256(password)), nonce))
203
+
204
+ """
205
+ if not password:
206
+ return b''
207
+
208
+ p1 = hashlib.sha256(password).digest()
209
+ p2 = hashlib.sha256(p1).digest()
210
+ p3 = hashlib.sha256(p2 + nonce).digest()
211
+
212
+ res = bytearray(p1)
213
+ for i in range(len(p3)):
214
+ res[i] ^= p3[i]
215
+
216
+ return bytes(res)
217
+
218
+
219
+ def caching_sha2_password_auth(conn, pkt):
220
+ # No password fast path
221
+ if not conn.password:
222
+ return _roundtrip(conn, b'')
223
+
224
+ if pkt.is_auth_switch_request():
225
+ # Try from fast auth
226
+ if DEBUG:
227
+ print('caching sha2: Trying fast path')
228
+ conn.salt = pkt.read_all()
229
+ scrambled = scramble_caching_sha2(conn.password, conn.salt)
230
+ pkt = _roundtrip(conn, scrambled)
231
+ # else: fast auth is tried in initial handshake
232
+
233
+ if not pkt.is_extra_auth_data():
234
+ raise OperationalError(
235
+ 'caching sha2: Unknown packet for fast auth: %s' % pkt._data[:1],
236
+ )
237
+
238
+ # magic numbers:
239
+ # 2 - request public key
240
+ # 3 - fast auth succeeded
241
+ # 4 - need full auth
242
+
243
+ pkt.advance(1)
244
+ n = pkt.read_uint8()
245
+
246
+ if n == 3:
247
+ if DEBUG:
248
+ print('caching sha2: succeeded by fast path.')
249
+ pkt = conn._read_packet()
250
+ pkt.check_error() # pkt must be OK packet
251
+ return pkt
252
+
253
+ if n != 4:
254
+ raise OperationalError('caching sha2: Unknwon result for fast auth: %s' % n)
255
+
256
+ if DEBUG:
257
+ print('caching sha2: Trying full auth...')
258
+
259
+ if conn._secure:
260
+ if DEBUG:
261
+ print('caching sha2: Sending plain password via secure connection')
262
+ return _roundtrip(conn, conn.password + b'\0')
263
+
264
+ if not conn.server_public_key:
265
+ pkt = _roundtrip(conn, b'\x02') # Request public key
266
+ if not pkt.is_extra_auth_data():
267
+ raise OperationalError(
268
+ 'caching sha2: Unknown packet for public key: %s' % pkt._data[:1],
269
+ )
270
+
271
+ conn.server_public_key = pkt._data[1:]
272
+ if DEBUG:
273
+ print(conn.server_public_key.decode('ascii'))
274
+
275
+ data = sha2_rsa_encrypt(conn.password, conn.salt, conn.server_public_key)
276
+ pkt = _roundtrip(conn, data)
277
+
278
+
279
+ def gssapi_auth(data):
280
+ try:
281
+ import gssapi.raw
282
+ except ImportError:
283
+ raise ImportError(
284
+ 'The `gssapi` package must be '
285
+ 'installed for Kerberos authentication',
286
+ )
287
+
288
+ ctx = None
289
+ try:
290
+ ctx = gssapi.raw.init_sec_context(
291
+ gssapi.raw.import_name(data, gssapi.raw.NameType.user),
292
+ flags=[0], lifetime=0,
293
+ )
294
+ return ctx.token
295
+
296
+ finally:
297
+ if ctx is not None:
298
+ gssapi.raw.delete_sec_context(ctx.context)
@@ -0,0 +1,214 @@
1
+ from typing import Dict
2
+ from typing import Optional
3
+
4
+ MBLENGTH = {8: 1, 33: 3, 88: 2, 91: 2}
5
+
6
+
7
+ class Charset:
8
+
9
+ def __init__(self, id: int, name: str, collation: str, is_default: str):
10
+ self.id, self.name, self.collation = id, name, collation
11
+ self.is_default = is_default == 'Yes'
12
+
13
+ def __repr__(self) -> str:
14
+ return 'Charset(id=%s, name=%r, collation=%r)' % (
15
+ self.id,
16
+ self.name,
17
+ self.collation,
18
+ )
19
+
20
+ @property
21
+ def encoding(self) -> str:
22
+ name = self.name
23
+ if name in ('utf8mb4', 'utf8mb3'):
24
+ return 'utf8'
25
+ if name == 'latin1':
26
+ return 'cp1252'
27
+ if name == 'koi8r':
28
+ return 'koi8_r'
29
+ if name == 'koi8u':
30
+ return 'koi8_u'
31
+ return name
32
+
33
+ @property
34
+ def is_binary(self) -> bool:
35
+ return self.id == 63
36
+
37
+
38
+ class Charsets:
39
+
40
+ def __init__(self) -> None:
41
+ self._by_id: Dict[int, Charset] = {}
42
+ self._by_name: Dict[str, Charset] = {}
43
+
44
+ def add(self, c: Charset) -> None:
45
+ self._by_id[c.id] = c
46
+ if c.is_default:
47
+ self._by_name[c.name] = c
48
+
49
+ def by_id(self, id: int) -> Charset:
50
+ return self._by_id[id]
51
+
52
+ def by_name(self, name: str) -> Optional[Charset]:
53
+ return self._by_name.get(name.lower())
54
+
55
+
56
+ _charsets = Charsets()
57
+
58
+ # Generated with:
59
+ #
60
+ # mysql -N -s -e "select id, character_set_name, collation_name, is_default
61
+ # from information_schema.collations order by id;" | python -c "import sys
62
+ # for l in sys.stdin.readlines():
63
+ # id, name, collation, is_default = l.split(chr(9))
64
+ # print '_charsets.add(Charset(%s, \'%s\', \'%s\', \'%s\'))' \
65
+ # % (id, name, collation, is_default.strip())
66
+ # "
67
+ #
68
+ #
69
+ _charsets.add(Charset(1, 'big5', 'big5_chinese_ci', 'Yes'))
70
+ _charsets.add(Charset(2, 'latin2', 'latin2_czech_cs', ''))
71
+ _charsets.add(Charset(3, 'dec8', 'dec8_swedish_ci', 'Yes'))
72
+ _charsets.add(Charset(4, 'cp850', 'cp850_general_ci', 'Yes'))
73
+ _charsets.add(Charset(5, 'latin1', 'latin1_german1_ci', ''))
74
+ _charsets.add(Charset(6, 'hp8', 'hp8_english_ci', 'Yes'))
75
+ _charsets.add(Charset(7, 'koi8r', 'koi8r_general_ci', 'Yes'))
76
+ _charsets.add(Charset(8, 'latin1', 'latin1_swedish_ci', 'Yes'))
77
+ _charsets.add(Charset(9, 'latin2', 'latin2_general_ci', 'Yes'))
78
+ _charsets.add(Charset(10, 'swe7', 'swe7_swedish_ci', 'Yes'))
79
+ _charsets.add(Charset(11, 'ascii', 'ascii_general_ci', 'Yes'))
80
+ _charsets.add(Charset(12, 'ujis', 'ujis_japanese_ci', 'Yes'))
81
+ _charsets.add(Charset(13, 'sjis', 'sjis_japanese_ci', 'Yes'))
82
+ _charsets.add(Charset(14, 'cp1251', 'cp1251_bulgarian_ci', ''))
83
+ _charsets.add(Charset(15, 'latin1', 'latin1_danish_ci', ''))
84
+ _charsets.add(Charset(16, 'hebrew', 'hebrew_general_ci', 'Yes'))
85
+ _charsets.add(Charset(18, 'tis620', 'tis620_thai_ci', 'Yes'))
86
+ _charsets.add(Charset(19, 'euckr', 'euckr_korean_ci', 'Yes'))
87
+ _charsets.add(Charset(20, 'latin7', 'latin7_estonian_cs', ''))
88
+ _charsets.add(Charset(21, 'latin2', 'latin2_hungarian_ci', ''))
89
+ _charsets.add(Charset(22, 'koi8u', 'koi8u_general_ci', 'Yes'))
90
+ _charsets.add(Charset(23, 'cp1251', 'cp1251_ukrainian_ci', ''))
91
+ _charsets.add(Charset(24, 'gb2312', 'gb2312_chinese_ci', 'Yes'))
92
+ _charsets.add(Charset(25, 'greek', 'greek_general_ci', 'Yes'))
93
+ _charsets.add(Charset(26, 'cp1250', 'cp1250_general_ci', 'Yes'))
94
+ _charsets.add(Charset(27, 'latin2', 'latin2_croatian_ci', ''))
95
+ _charsets.add(Charset(28, 'gbk', 'gbk_chinese_ci', 'Yes'))
96
+ _charsets.add(Charset(29, 'cp1257', 'cp1257_lithuanian_ci', ''))
97
+ _charsets.add(Charset(30, 'latin5', 'latin5_turkish_ci', 'Yes'))
98
+ _charsets.add(Charset(31, 'latin1', 'latin1_german2_ci', ''))
99
+ _charsets.add(Charset(32, 'armscii8', 'armscii8_general_ci', 'Yes'))
100
+ _charsets.add(Charset(33, 'utf8', 'utf8_general_ci', 'Yes'))
101
+ _charsets.add(Charset(34, 'cp1250', 'cp1250_czech_cs', ''))
102
+ _charsets.add(Charset(36, 'cp866', 'cp866_general_ci', 'Yes'))
103
+ _charsets.add(Charset(37, 'keybcs2', 'keybcs2_general_ci', 'Yes'))
104
+ _charsets.add(Charset(38, 'macce', 'macce_general_ci', 'Yes'))
105
+ _charsets.add(Charset(39, 'macroman', 'macroman_general_ci', 'Yes'))
106
+ _charsets.add(Charset(40, 'cp852', 'cp852_general_ci', 'Yes'))
107
+ _charsets.add(Charset(41, 'latin7', 'latin7_general_ci', 'Yes'))
108
+ _charsets.add(Charset(42, 'latin7', 'latin7_general_cs', ''))
109
+ _charsets.add(Charset(43, 'macce', 'macce_bin', ''))
110
+ _charsets.add(Charset(44, 'cp1250', 'cp1250_croatian_ci', ''))
111
+ _charsets.add(Charset(45, 'utf8mb4', 'utf8mb4_general_ci', 'Yes'))
112
+ _charsets.add(Charset(46, 'utf8mb4', 'utf8mb4_bin', ''))
113
+ _charsets.add(Charset(47, 'latin1', 'latin1_bin', ''))
114
+ _charsets.add(Charset(48, 'latin1', 'latin1_general_ci', ''))
115
+ _charsets.add(Charset(49, 'latin1', 'latin1_general_cs', ''))
116
+ _charsets.add(Charset(50, 'cp1251', 'cp1251_bin', ''))
117
+ _charsets.add(Charset(51, 'cp1251', 'cp1251_general_ci', 'Yes'))
118
+ _charsets.add(Charset(52, 'cp1251', 'cp1251_general_cs', ''))
119
+ _charsets.add(Charset(53, 'macroman', 'macroman_bin', ''))
120
+ _charsets.add(Charset(57, 'cp1256', 'cp1256_general_ci', 'Yes'))
121
+ _charsets.add(Charset(58, 'cp1257', 'cp1257_bin', ''))
122
+ _charsets.add(Charset(59, 'cp1257', 'cp1257_general_ci', 'Yes'))
123
+ _charsets.add(Charset(63, 'binary', 'binary', 'Yes'))
124
+ _charsets.add(Charset(64, 'armscii8', 'armscii8_bin', ''))
125
+ _charsets.add(Charset(65, 'ascii', 'ascii_bin', ''))
126
+ _charsets.add(Charset(66, 'cp1250', 'cp1250_bin', ''))
127
+ _charsets.add(Charset(67, 'cp1256', 'cp1256_bin', ''))
128
+ _charsets.add(Charset(68, 'cp866', 'cp866_bin', ''))
129
+ _charsets.add(Charset(69, 'dec8', 'dec8_bin', ''))
130
+ _charsets.add(Charset(70, 'greek', 'greek_bin', ''))
131
+ _charsets.add(Charset(71, 'hebrew', 'hebrew_bin', ''))
132
+ _charsets.add(Charset(72, 'hp8', 'hp8_bin', ''))
133
+ _charsets.add(Charset(73, 'keybcs2', 'keybcs2_bin', ''))
134
+ _charsets.add(Charset(74, 'koi8r', 'koi8r_bin', ''))
135
+ _charsets.add(Charset(75, 'koi8u', 'koi8u_bin', ''))
136
+ _charsets.add(Charset(76, 'utf8', 'utf8_tolower_ci', ''))
137
+ _charsets.add(Charset(77, 'latin2', 'latin2_bin', ''))
138
+ _charsets.add(Charset(78, 'latin5', 'latin5_bin', ''))
139
+ _charsets.add(Charset(79, 'latin7', 'latin7_bin', ''))
140
+ _charsets.add(Charset(80, 'cp850', 'cp850_bin', ''))
141
+ _charsets.add(Charset(81, 'cp852', 'cp852_bin', ''))
142
+ _charsets.add(Charset(82, 'swe7', 'swe7_bin', ''))
143
+ _charsets.add(Charset(83, 'utf8', 'utf8_bin', ''))
144
+ _charsets.add(Charset(84, 'big5', 'big5_bin', ''))
145
+ _charsets.add(Charset(85, 'euckr', 'euckr_bin', ''))
146
+ _charsets.add(Charset(86, 'gb2312', 'gb2312_bin', ''))
147
+ _charsets.add(Charset(87, 'gbk', 'gbk_bin', ''))
148
+ _charsets.add(Charset(88, 'sjis', 'sjis_bin', ''))
149
+ _charsets.add(Charset(89, 'tis620', 'tis620_bin', ''))
150
+ _charsets.add(Charset(91, 'ujis', 'ujis_bin', ''))
151
+ _charsets.add(Charset(92, 'geostd8', 'geostd8_general_ci', 'Yes'))
152
+ _charsets.add(Charset(93, 'geostd8', 'geostd8_bin', ''))
153
+ _charsets.add(Charset(94, 'latin1', 'latin1_spanish_ci', ''))
154
+ _charsets.add(Charset(95, 'cp932', 'cp932_japanese_ci', 'Yes'))
155
+ _charsets.add(Charset(96, 'cp932', 'cp932_bin', ''))
156
+ _charsets.add(Charset(97, 'eucjpms', 'eucjpms_japanese_ci', 'Yes'))
157
+ _charsets.add(Charset(98, 'eucjpms', 'eucjpms_bin', ''))
158
+ _charsets.add(Charset(99, 'cp1250', 'cp1250_polish_ci', ''))
159
+ _charsets.add(Charset(192, 'utf8', 'utf8_unicode_ci', ''))
160
+ _charsets.add(Charset(193, 'utf8', 'utf8_icelandic_ci', ''))
161
+ _charsets.add(Charset(194, 'utf8', 'utf8_latvian_ci', ''))
162
+ _charsets.add(Charset(195, 'utf8', 'utf8_romanian_ci', ''))
163
+ _charsets.add(Charset(196, 'utf8', 'utf8_slovenian_ci', ''))
164
+ _charsets.add(Charset(197, 'utf8', 'utf8_polish_ci', ''))
165
+ _charsets.add(Charset(198, 'utf8', 'utf8_estonian_ci', ''))
166
+ _charsets.add(Charset(199, 'utf8', 'utf8_spanish_ci', ''))
167
+ _charsets.add(Charset(200, 'utf8', 'utf8_swedish_ci', ''))
168
+ _charsets.add(Charset(201, 'utf8', 'utf8_turkish_ci', ''))
169
+ _charsets.add(Charset(202, 'utf8', 'utf8_czech_ci', ''))
170
+ _charsets.add(Charset(203, 'utf8', 'utf8_danish_ci', ''))
171
+ _charsets.add(Charset(204, 'utf8', 'utf8_lithuanian_ci', ''))
172
+ _charsets.add(Charset(205, 'utf8', 'utf8_slovak_ci', ''))
173
+ _charsets.add(Charset(206, 'utf8', 'utf8_spanish2_ci', ''))
174
+ _charsets.add(Charset(207, 'utf8', 'utf8_roman_ci', ''))
175
+ _charsets.add(Charset(208, 'utf8', 'utf8_persian_ci', ''))
176
+ _charsets.add(Charset(209, 'utf8', 'utf8_esperanto_ci', ''))
177
+ _charsets.add(Charset(210, 'utf8', 'utf8_hungarian_ci', ''))
178
+ _charsets.add(Charset(211, 'utf8', 'utf8_sinhala_ci', ''))
179
+ _charsets.add(Charset(212, 'utf8', 'utf8_german2_ci', ''))
180
+ _charsets.add(Charset(213, 'utf8', 'utf8_croatian_ci', ''))
181
+ _charsets.add(Charset(214, 'utf8', 'utf8_unicode_520_ci', ''))
182
+ _charsets.add(Charset(215, 'utf8', 'utf8_vietnamese_ci', ''))
183
+ _charsets.add(Charset(223, 'utf8', 'utf8_general_mysql500_ci', ''))
184
+ _charsets.add(Charset(224, 'utf8mb4', 'utf8mb4_unicode_ci', ''))
185
+ _charsets.add(Charset(225, 'utf8mb4', 'utf8mb4_icelandic_ci', ''))
186
+ _charsets.add(Charset(226, 'utf8mb4', 'utf8mb4_latvian_ci', ''))
187
+ _charsets.add(Charset(227, 'utf8mb4', 'utf8mb4_romanian_ci', ''))
188
+ _charsets.add(Charset(228, 'utf8mb4', 'utf8mb4_slovenian_ci', ''))
189
+ _charsets.add(Charset(229, 'utf8mb4', 'utf8mb4_polish_ci', ''))
190
+ _charsets.add(Charset(230, 'utf8mb4', 'utf8mb4_estonian_ci', ''))
191
+ _charsets.add(Charset(231, 'utf8mb4', 'utf8mb4_spanish_ci', ''))
192
+ _charsets.add(Charset(232, 'utf8mb4', 'utf8mb4_swedish_ci', ''))
193
+ _charsets.add(Charset(233, 'utf8mb4', 'utf8mb4_turkish_ci', ''))
194
+ _charsets.add(Charset(234, 'utf8mb4', 'utf8mb4_czech_ci', ''))
195
+ _charsets.add(Charset(235, 'utf8mb4', 'utf8mb4_danish_ci', ''))
196
+ _charsets.add(Charset(236, 'utf8mb4', 'utf8mb4_lithuanian_ci', ''))
197
+ _charsets.add(Charset(237, 'utf8mb4', 'utf8mb4_slovak_ci', ''))
198
+ _charsets.add(Charset(238, 'utf8mb4', 'utf8mb4_spanish2_ci', ''))
199
+ _charsets.add(Charset(239, 'utf8mb4', 'utf8mb4_roman_ci', ''))
200
+ _charsets.add(Charset(240, 'utf8mb4', 'utf8mb4_persian_ci', ''))
201
+ _charsets.add(Charset(241, 'utf8mb4', 'utf8mb4_esperanto_ci', ''))
202
+ _charsets.add(Charset(242, 'utf8mb4', 'utf8mb4_hungarian_ci', ''))
203
+ _charsets.add(Charset(243, 'utf8mb4', 'utf8mb4_sinhala_ci', ''))
204
+ _charsets.add(Charset(244, 'utf8mb4', 'utf8mb4_german2_ci', ''))
205
+ _charsets.add(Charset(245, 'utf8mb4', 'utf8mb4_croatian_ci', ''))
206
+ _charsets.add(Charset(246, 'utf8mb4', 'utf8mb4_unicode_520_ci', ''))
207
+ _charsets.add(Charset(247, 'utf8mb4', 'utf8mb4_vietnamese_ci', ''))
208
+ _charsets.add(Charset(248, 'gb18030', 'gb18030_chinese_ci', 'Yes'))
209
+ _charsets.add(Charset(249, 'gb18030', 'gb18030_bin', ''))
210
+ _charsets.add(Charset(250, 'gb18030', 'gb18030_unicode_520_ci', ''))
211
+ _charsets.add(Charset(255, 'utf8mb4', 'utf8mb4_0900_ai_ci', ''))
212
+
213
+ charset_by_name = _charsets.by_name
214
+ charset_by_id = _charsets.by_id