clickhouse-driver 0.2.8__cp312-cp312-win32.whl → 0.2.10__cp312-cp312-win32.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.
- clickhouse_driver/__init__.py +1 -1
- clickhouse_driver/bufferedreader.cp312-win32.pyd +0 -0
- clickhouse_driver/bufferedwriter.cp312-win32.pyd +0 -0
- clickhouse_driver/client.py +12 -96
- clickhouse_driver/clientinfo.py +1 -1
- clickhouse_driver/columns/datetimecolumn.py +3 -2
- clickhouse_driver/columns/enumcolumn.py +27 -17
- clickhouse_driver/columns/largeint.cp312-win32.pyd +0 -0
- clickhouse_driver/columns/numpy/datetimecolumn.py +6 -3
- clickhouse_driver/columns/util.py +2 -1
- clickhouse_driver/compression/__init__.py +4 -0
- clickhouse_driver/connection.py +48 -7
- clickhouse_driver/defines.py +4 -1
- clickhouse_driver/numpy/helpers.py +5 -2
- clickhouse_driver/progress.py +7 -1
- clickhouse_driver/protocol.py +19 -3
- clickhouse_driver/streams/native.py +6 -0
- clickhouse_driver/util/escape.py +1 -1
- clickhouse_driver/util/helpers.py +116 -0
- clickhouse_driver/varint.cp312-win32.pyd +0 -0
- {clickhouse_driver-0.2.8.dist-info → clickhouse_driver-0.2.10.dist-info}/METADATA +27 -13
- {clickhouse_driver-0.2.8.dist-info → clickhouse_driver-0.2.10.dist-info}/RECORD +25 -25
- {clickhouse_driver-0.2.8.dist-info → clickhouse_driver-0.2.10.dist-info}/WHEEL +1 -1
- {clickhouse_driver-0.2.8.dist-info → clickhouse_driver-0.2.10.dist-info/licenses}/LICENSE +0 -0
- {clickhouse_driver-0.2.8.dist-info → clickhouse_driver-0.2.10.dist-info}/top_level.txt +0 -0
clickhouse_driver/__init__.py
CHANGED
|
Binary file
|
|
Binary file
|
clickhouse_driver/client.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import re
|
|
2
|
-
import ssl
|
|
3
2
|
from collections import deque
|
|
4
3
|
from contextlib import contextmanager
|
|
5
4
|
from time import time
|
|
6
5
|
import types
|
|
7
|
-
from urllib.parse import urlparse
|
|
6
|
+
from urllib.parse import urlparse
|
|
8
7
|
|
|
9
8
|
from . import errors, defines
|
|
10
9
|
from .block import ColumnOrientedBlock, RowOrientedBlock
|
|
@@ -15,7 +14,7 @@ from .result import (
|
|
|
15
14
|
IterQueryResult, ProgressQueryResult, QueryResult, QueryInfo
|
|
16
15
|
)
|
|
17
16
|
from .util.escape import escape_params
|
|
18
|
-
from .util.helpers import column_chunks, chunks,
|
|
17
|
+
from .util.helpers import column_chunks, chunks, parse_url
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
class Client(object):
|
|
@@ -312,6 +311,7 @@ class Client(object):
|
|
|
312
311
|
def disconnect_on_error(self, query, settings):
|
|
313
312
|
try:
|
|
314
313
|
self.establish_connection(settings)
|
|
314
|
+
self.connection.server_info.session_timezone = None
|
|
315
315
|
|
|
316
316
|
yield
|
|
317
317
|
|
|
@@ -746,9 +746,13 @@ class Client(object):
|
|
|
746
746
|
elif packet.type == ServerPacketTypes.EXCEPTION:
|
|
747
747
|
raise packet.exception
|
|
748
748
|
|
|
749
|
+
elif packet.type == ServerPacketTypes.TIMEZONE_UPDATE:
|
|
750
|
+
pass
|
|
751
|
+
|
|
749
752
|
else:
|
|
750
753
|
message = self.connection.unexpected_packet_message(
|
|
751
|
-
'ProfileEvents, Progress, Log or
|
|
754
|
+
'ProfileEvents, Progress, Log, Exception or '
|
|
755
|
+
'TimezoneUpdate', packet.type
|
|
752
756
|
)
|
|
753
757
|
raise errors.UnexpectedPacketFromServerError(message)
|
|
754
758
|
|
|
@@ -796,101 +800,13 @@ class Client(object):
|
|
|
796
800
|
clickhouses://[user:password]@localhost:9440/default
|
|
797
801
|
|
|
798
802
|
Three URL schemes are supported:
|
|
799
|
-
|
|
800
|
-
|
|
803
|
+
|
|
804
|
+
* clickhouse:// creates a normal TCP socket connection
|
|
805
|
+
* clickhouses:// creates a SSL wrapped TCP socket connection
|
|
801
806
|
|
|
802
807
|
Any additional querystring arguments will be passed along to
|
|
803
808
|
the Connection class's initializer.
|
|
804
809
|
"""
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
settings = {}
|
|
808
|
-
kwargs = {}
|
|
809
|
-
|
|
810
|
-
host = url.hostname
|
|
811
|
-
|
|
812
|
-
if url.port is not None:
|
|
813
|
-
kwargs['port'] = url.port
|
|
814
|
-
|
|
815
|
-
path = url.path.replace('/', '', 1)
|
|
816
|
-
if path:
|
|
817
|
-
kwargs['database'] = path
|
|
818
|
-
|
|
819
|
-
if url.username is not None:
|
|
820
|
-
kwargs['user'] = unquote(url.username)
|
|
821
|
-
|
|
822
|
-
if url.password is not None:
|
|
823
|
-
kwargs['password'] = unquote(url.password)
|
|
824
|
-
|
|
825
|
-
if url.scheme == 'clickhouses':
|
|
826
|
-
kwargs['secure'] = True
|
|
827
|
-
|
|
828
|
-
compression_algs = {'lz4', 'lz4hc', 'zstd'}
|
|
829
|
-
timeouts = {
|
|
830
|
-
'connect_timeout',
|
|
831
|
-
'send_receive_timeout',
|
|
832
|
-
'sync_request_timeout'
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
for name, value in parse_qs(url.query).items():
|
|
836
|
-
if not value or not len(value):
|
|
837
|
-
continue
|
|
838
|
-
|
|
839
|
-
value = value[0]
|
|
840
|
-
|
|
841
|
-
if name == 'compression':
|
|
842
|
-
value = value.lower()
|
|
843
|
-
if value in compression_algs:
|
|
844
|
-
kwargs[name] = value
|
|
845
|
-
else:
|
|
846
|
-
kwargs[name] = asbool(value)
|
|
847
|
-
|
|
848
|
-
elif name == 'secure':
|
|
849
|
-
kwargs[name] = asbool(value)
|
|
850
|
-
|
|
851
|
-
elif name == 'use_numpy':
|
|
852
|
-
settings[name] = asbool(value)
|
|
853
|
-
|
|
854
|
-
elif name == 'round_robin':
|
|
855
|
-
kwargs[name] = asbool(value)
|
|
856
|
-
|
|
857
|
-
elif name == 'client_name':
|
|
858
|
-
kwargs[name] = value
|
|
859
|
-
|
|
860
|
-
elif name in timeouts:
|
|
861
|
-
kwargs[name] = float(value)
|
|
862
|
-
|
|
863
|
-
elif name == 'compress_block_size':
|
|
864
|
-
kwargs[name] = int(value)
|
|
865
|
-
|
|
866
|
-
elif name == 'settings_is_important':
|
|
867
|
-
kwargs[name] = asbool(value)
|
|
868
|
-
|
|
869
|
-
elif name == 'tcp_keepalive':
|
|
870
|
-
try:
|
|
871
|
-
kwargs[name] = asbool(value)
|
|
872
|
-
except ValueError:
|
|
873
|
-
parts = value.split(',')
|
|
874
|
-
kwargs[name] = (
|
|
875
|
-
int(parts[0]), int(parts[1]), int(parts[2])
|
|
876
|
-
)
|
|
877
|
-
elif name == 'client_revision':
|
|
878
|
-
kwargs[name] = int(value)
|
|
879
|
-
|
|
880
|
-
# ssl
|
|
881
|
-
elif name == 'verify':
|
|
882
|
-
kwargs[name] = asbool(value)
|
|
883
|
-
elif name == 'ssl_version':
|
|
884
|
-
kwargs[name] = getattr(ssl, value)
|
|
885
|
-
elif name in ['ca_certs', 'ciphers', 'keyfile', 'certfile',
|
|
886
|
-
'server_hostname']:
|
|
887
|
-
kwargs[name] = value
|
|
888
|
-
elif name == 'alt_hosts':
|
|
889
|
-
kwargs['alt_hosts'] = value
|
|
890
|
-
else:
|
|
891
|
-
settings[name] = value
|
|
892
|
-
|
|
893
|
-
if settings:
|
|
894
|
-
kwargs['settings'] = settings
|
|
810
|
+
host, kwargs = parse_url(url)
|
|
895
811
|
|
|
896
812
|
return cls(host, **kwargs)
|
clickhouse_driver/clientinfo.py
CHANGED
|
@@ -193,8 +193,9 @@ def create_datetime_column(spec, column_options):
|
|
|
193
193
|
else:
|
|
194
194
|
if not context.settings.get('use_client_time_zone', False):
|
|
195
195
|
local_timezone = get_localzone_name_compat()
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
remote_timezone = context.server_info.get_timezone()
|
|
197
|
+
if local_timezone != remote_timezone:
|
|
198
|
+
tz_name = remote_timezone
|
|
198
199
|
|
|
199
200
|
if tz_name:
|
|
200
201
|
timezone = get_timezone(tz_name)
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
+
from collections import OrderedDict
|
|
2
3
|
|
|
3
4
|
from .. import errors
|
|
4
5
|
from .intcolumn import IntColumn
|
|
5
6
|
|
|
7
|
+
invalid_names_for_python_enum = frozenset(['mro', ''])
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
class EnumColumn(IntColumn):
|
|
8
11
|
py_types = (Enum, int, str)
|
|
9
12
|
|
|
10
|
-
def __init__(self,
|
|
11
|
-
self.
|
|
13
|
+
def __init__(self, name_by_value, value_by_name, **kwargs):
|
|
14
|
+
self.name_by_value = name_by_value
|
|
15
|
+
self.value_by_name = value_by_name
|
|
12
16
|
super(EnumColumn, self).__init__(**kwargs)
|
|
13
17
|
|
|
14
18
|
def before_write_items(self, items, nulls_map=None):
|
|
15
19
|
null_value = self.null_value
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
name_by_value = self.name_by_value
|
|
21
|
+
value_by_name = self.value_by_name
|
|
18
22
|
|
|
19
23
|
for i, item in enumerate(items):
|
|
20
24
|
if nulls_map and nulls_map[i]:
|
|
@@ -26,15 +30,15 @@ class EnumColumn(IntColumn):
|
|
|
26
30
|
# Check real enum value
|
|
27
31
|
try:
|
|
28
32
|
if isinstance(source_value, str):
|
|
29
|
-
items[i] =
|
|
33
|
+
items[i] = value_by_name[source_value]
|
|
30
34
|
else:
|
|
31
|
-
items[i] =
|
|
35
|
+
items[i] = value_by_name[name_by_value[source_value]]
|
|
32
36
|
except (ValueError, KeyError):
|
|
33
37
|
choices = ', '.join(
|
|
34
|
-
"'{}' = {}".format(
|
|
35
|
-
for
|
|
38
|
+
"'{}' = {}".format(name.replace("'", r"\'"), value)
|
|
39
|
+
for name, value in value_by_name.items()
|
|
36
40
|
)
|
|
37
|
-
enum_str = '{}({})'.format(
|
|
41
|
+
enum_str = '{}({})'.format(self.ch_type, choices)
|
|
38
42
|
|
|
39
43
|
raise errors.LogicalError(
|
|
40
44
|
"Unknown element '{}' for type {}"
|
|
@@ -42,13 +46,13 @@ class EnumColumn(IntColumn):
|
|
|
42
46
|
)
|
|
43
47
|
|
|
44
48
|
def after_read_items(self, items, nulls_map=None):
|
|
45
|
-
|
|
49
|
+
name_by_value = self.name_by_value
|
|
46
50
|
|
|
47
51
|
if nulls_map is None:
|
|
48
|
-
return tuple(
|
|
52
|
+
return tuple(name_by_value[item] for item in items)
|
|
49
53
|
else:
|
|
50
54
|
return tuple(
|
|
51
|
-
(None if is_null else
|
|
55
|
+
(None if is_null else name_by_value[items[i]])
|
|
52
56
|
for i, is_null in enumerate(nulls_map)
|
|
53
57
|
)
|
|
54
58
|
|
|
@@ -73,11 +77,13 @@ def create_enum_column(spec, column_options):
|
|
|
73
77
|
params = spec[7:-1]
|
|
74
78
|
cls = Enum16Column
|
|
75
79
|
|
|
76
|
-
|
|
80
|
+
name_by_value, value_by_name = _parse_options(params)
|
|
81
|
+
|
|
82
|
+
return cls(name_by_value, value_by_name, **column_options)
|
|
77
83
|
|
|
78
84
|
|
|
79
85
|
def _parse_options(option_string):
|
|
80
|
-
|
|
86
|
+
name_by_value, value_by_name = {}, OrderedDict()
|
|
81
87
|
after_name = False
|
|
82
88
|
escaped = False
|
|
83
89
|
quote_character = None
|
|
@@ -93,7 +99,9 @@ def _parse_options(option_string):
|
|
|
93
99
|
if ch in (' ', '='):
|
|
94
100
|
pass
|
|
95
101
|
elif ch == ',':
|
|
96
|
-
|
|
102
|
+
value = int(value)
|
|
103
|
+
name_by_value[value] = name
|
|
104
|
+
value_by_name[name] = value
|
|
97
105
|
after_name = False
|
|
98
106
|
name = ''
|
|
99
107
|
value = '' # reset before collecting new option
|
|
@@ -114,6 +122,8 @@ def _parse_options(option_string):
|
|
|
114
122
|
quote_character = ch
|
|
115
123
|
|
|
116
124
|
if after_name:
|
|
117
|
-
|
|
125
|
+
value = int(value)
|
|
126
|
+
name_by_value[value] = name
|
|
127
|
+
value_by_name[name] = value
|
|
118
128
|
|
|
119
|
-
return
|
|
129
|
+
return name_by_value, value_by_name
|
|
Binary file
|
|
@@ -33,7 +33,9 @@ class NumpyDateTimeColumnBase(NumpyColumn):
|
|
|
33
33
|
ts = items
|
|
34
34
|
else:
|
|
35
35
|
timezone = self.timezone if self.timezone else self.local_timezone
|
|
36
|
-
ts = pd.to_datetime(items)
|
|
36
|
+
ts = pd.to_datetime(items)
|
|
37
|
+
if not getattr(ts.dtype, 'tz', None):
|
|
38
|
+
ts = ts.tz_localize(timezone)
|
|
37
39
|
|
|
38
40
|
ts = ts.tz_convert('UTC')
|
|
39
41
|
return ts.tz_localize(None).to_numpy(self.datetime_dtype)
|
|
@@ -133,8 +135,9 @@ def create_numpy_datetime_column(spec, column_options):
|
|
|
133
135
|
offset_naive = False
|
|
134
136
|
else:
|
|
135
137
|
if not context.settings.get('use_client_time_zone', False):
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
remote_timezone = context.server_info.get_timezone()
|
|
139
|
+
if local_tz_name != remote_timezone:
|
|
140
|
+
tz_name = remote_timezone
|
|
138
141
|
|
|
139
142
|
timezone = get_timezone(tz_name) if tz_name else None
|
|
140
143
|
local_timezone = get_timezone(local_tz_name) if local_tz_name else None
|
|
@@ -37,12 +37,13 @@ def get_inner_columns(spec):
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def get_inner_columns_with_types(spec):
|
|
40
|
+
spec = spec.strip()
|
|
40
41
|
brackets = 0
|
|
41
42
|
prev_comma = 0
|
|
42
43
|
prev_space = 0
|
|
43
44
|
|
|
44
45
|
columns = []
|
|
45
|
-
for i, x in enumerate(spec + ','):
|
|
46
|
+
for i, x in enumerate(spec.strip() + ','):
|
|
46
47
|
if x == ',':
|
|
47
48
|
if brackets == 0:
|
|
48
49
|
columns.append((
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import importlib
|
|
2
|
+
import logging
|
|
2
3
|
|
|
3
4
|
from .. import errors
|
|
4
5
|
from ..protocol import CompressionMethodByte
|
|
5
6
|
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
def get_compressor_cls(alg):
|
|
8
11
|
try:
|
|
@@ -10,6 +13,7 @@ def get_compressor_cls(alg):
|
|
|
10
13
|
return module.Compressor
|
|
11
14
|
|
|
12
15
|
except ImportError:
|
|
16
|
+
logger.warning('Unable to import module %s', alg, exc_info=True)
|
|
13
17
|
raise errors.UnknownCompressionMethod(
|
|
14
18
|
"Unknown compression method: '{}'".format(alg)
|
|
15
19
|
)
|
clickhouse_driver/connection.py
CHANGED
|
@@ -7,6 +7,11 @@ from sys import platform
|
|
|
7
7
|
from time import time
|
|
8
8
|
from urllib.parse import urlparse
|
|
9
9
|
|
|
10
|
+
try:
|
|
11
|
+
import certifi
|
|
12
|
+
except ImportError:
|
|
13
|
+
certifi = None
|
|
14
|
+
|
|
10
15
|
from . import defines
|
|
11
16
|
from . import errors
|
|
12
17
|
from .block import RowOrientedBlock
|
|
@@ -53,11 +58,15 @@ class ServerInfo(object):
|
|
|
53
58
|
self.version_patch = version_patch
|
|
54
59
|
self.revision = revision
|
|
55
60
|
self.timezone = timezone
|
|
61
|
+
self.session_timezone = None
|
|
56
62
|
self.display_name = display_name
|
|
57
63
|
self.used_revision = used_revision
|
|
58
64
|
|
|
59
65
|
super(ServerInfo, self).__init__()
|
|
60
66
|
|
|
67
|
+
def get_timezone(self):
|
|
68
|
+
return self.session_timezone or self.timezone
|
|
69
|
+
|
|
61
70
|
def version_tuple(self):
|
|
62
71
|
return self.version_major, self.version_minor, self.version_patch
|
|
63
72
|
|
|
@@ -116,7 +125,10 @@ class Connection(object):
|
|
|
116
125
|
:param ca_certs: see :func:`ssl.wrap_socket` docs.
|
|
117
126
|
:param ciphers: see :func:`ssl.wrap_socket` docs.
|
|
118
127
|
:param keyfile: see :func:`ssl.wrap_socket` docs.
|
|
128
|
+
:param keypass: see :func:`ssl.wrap_socket` docs.
|
|
119
129
|
:param certfile: see :func:`ssl.wrap_socket` docs.
|
|
130
|
+
:param check_hostname: see :func:`ssl.wrap_socket` docs.
|
|
131
|
+
Defaults to ``True``.
|
|
120
132
|
:param server_hostname: Hostname to use in SSL Wrapper construction.
|
|
121
133
|
Defaults to `None` which will send the passed
|
|
122
134
|
host param during SSL initialization. This param
|
|
@@ -137,6 +149,10 @@ class Connection(object):
|
|
|
137
149
|
Defaults to ``False``.
|
|
138
150
|
:param client_revision: can be used for client version downgrading.
|
|
139
151
|
Defaults to ``None``.
|
|
152
|
+
:param disable_reconnect: disable automatic reconnect in case of
|
|
153
|
+
failed ``ping``, helpful when every reconnect
|
|
154
|
+
need to be caught in calling code.
|
|
155
|
+
Defaults to ``False``.
|
|
140
156
|
"""
|
|
141
157
|
|
|
142
158
|
def __init__(
|
|
@@ -152,12 +168,13 @@ class Connection(object):
|
|
|
152
168
|
secure=False,
|
|
153
169
|
# Secure socket parameters.
|
|
154
170
|
verify=True, ssl_version=None, ca_certs=None, ciphers=None,
|
|
155
|
-
keyfile=None, certfile=None,
|
|
171
|
+
keyfile=None, keypass=None, certfile=None, check_hostname=True,
|
|
156
172
|
server_hostname=None,
|
|
157
173
|
alt_hosts=None,
|
|
158
174
|
settings_is_important=False,
|
|
159
175
|
tcp_keepalive=False,
|
|
160
|
-
client_revision=None
|
|
176
|
+
client_revision=None,
|
|
177
|
+
disable_reconnect=False,
|
|
161
178
|
):
|
|
162
179
|
if secure:
|
|
163
180
|
default_port = defines.DEFAULT_SECURE_PORT
|
|
@@ -183,10 +200,14 @@ class Connection(object):
|
|
|
183
200
|
self.client_revision = min(
|
|
184
201
|
client_revision or defines.CLIENT_REVISION, defines.CLIENT_REVISION
|
|
185
202
|
)
|
|
203
|
+
self.disable_reconnect = disable_reconnect
|
|
186
204
|
|
|
187
205
|
self.secure_socket = secure
|
|
188
206
|
self.verify_cert = verify
|
|
189
207
|
|
|
208
|
+
if certifi is not None:
|
|
209
|
+
ca_certs = ca_certs or certifi.where()
|
|
210
|
+
|
|
190
211
|
ssl_options = {}
|
|
191
212
|
if ssl_version is not None:
|
|
192
213
|
ssl_options['ssl_version'] = ssl_version
|
|
@@ -196,11 +217,14 @@ class Connection(object):
|
|
|
196
217
|
ssl_options['ciphers'] = ciphers
|
|
197
218
|
if keyfile is not None:
|
|
198
219
|
ssl_options['keyfile'] = keyfile
|
|
220
|
+
if keypass is not None:
|
|
221
|
+
ssl_options['keypass'] = keypass
|
|
199
222
|
if certfile is not None:
|
|
200
223
|
ssl_options['certfile'] = certfile
|
|
201
224
|
|
|
202
225
|
self.ssl_options = ssl_options
|
|
203
226
|
|
|
227
|
+
self.check_hostname = check_hostname if self.verify_cert else False
|
|
204
228
|
self.server_hostname = server_hostname
|
|
205
229
|
|
|
206
230
|
# Use LZ4 compression by default.
|
|
@@ -254,6 +278,11 @@ class Connection(object):
|
|
|
254
278
|
self.connect()
|
|
255
279
|
|
|
256
280
|
elif not self.ping():
|
|
281
|
+
if self.disable_reconnect:
|
|
282
|
+
raise errors.NetworkError(
|
|
283
|
+
"Connection was closed, reconnect is disabled."
|
|
284
|
+
)
|
|
285
|
+
|
|
257
286
|
logger.warning('Connection was closed, reconnecting.')
|
|
258
287
|
self.connect()
|
|
259
288
|
|
|
@@ -301,15 +330,14 @@ class Connection(object):
|
|
|
301
330
|
def _create_ssl_context(self, ssl_options):
|
|
302
331
|
purpose = ssl.Purpose.SERVER_AUTH
|
|
303
332
|
|
|
304
|
-
version = ssl_options.get('ssl_version', ssl.
|
|
333
|
+
version = ssl_options.get('ssl_version', ssl.PROTOCOL_TLS_CLIENT)
|
|
305
334
|
context = ssl.SSLContext(version)
|
|
306
|
-
context.check_hostname = self.
|
|
335
|
+
context.check_hostname = self.check_hostname
|
|
307
336
|
|
|
308
337
|
if 'ca_certs' in ssl_options:
|
|
309
338
|
context.load_verify_locations(ssl_options['ca_certs'])
|
|
310
339
|
elif ssl_options.get('cert_reqs') != ssl.CERT_NONE:
|
|
311
|
-
context.load_default_certs(purpose
|
|
312
|
-
)
|
|
340
|
+
context.load_default_certs(purpose)
|
|
313
341
|
if 'ciphers' in ssl_options:
|
|
314
342
|
context.set_ciphers(ssl_options['ciphers'])
|
|
315
343
|
|
|
@@ -318,7 +346,11 @@ class Connection(object):
|
|
|
318
346
|
|
|
319
347
|
if 'certfile' in ssl_options:
|
|
320
348
|
keyfile = ssl_options.get('keyfile')
|
|
321
|
-
|
|
349
|
+
keypass = ssl_options.get('keypass')
|
|
350
|
+
context.load_cert_chain(
|
|
351
|
+
ssl_options['certfile'],
|
|
352
|
+
keyfile=keyfile, password=keypass
|
|
353
|
+
)
|
|
322
354
|
|
|
323
355
|
return context
|
|
324
356
|
|
|
@@ -539,6 +571,9 @@ class Connection(object):
|
|
|
539
571
|
)
|
|
540
572
|
|
|
541
573
|
def ping(self):
|
|
574
|
+
if not self.socket:
|
|
575
|
+
return None
|
|
576
|
+
|
|
542
577
|
timeout = self.sync_request_timeout
|
|
543
578
|
|
|
544
579
|
with self.timeout_setter(timeout):
|
|
@@ -613,6 +648,12 @@ class Connection(object):
|
|
|
613
648
|
elif packet_type == ServerPacketTypes.PROFILE_EVENTS:
|
|
614
649
|
packet.block = self.receive_data(may_be_compressed=False)
|
|
615
650
|
|
|
651
|
+
elif packet_type == ServerPacketTypes.TIMEZONE_UPDATE:
|
|
652
|
+
timezone = read_binary_str(self.fin)
|
|
653
|
+
if timezone:
|
|
654
|
+
logger.info('Server timezone changed to %s', timezone)
|
|
655
|
+
self.server_info.session_timezone = timezone
|
|
656
|
+
|
|
616
657
|
else:
|
|
617
658
|
message = 'Unknown packet {} from server {}'.format(
|
|
618
659
|
packet_type, self.get_description()
|
clickhouse_driver/defines.py
CHANGED
|
@@ -33,6 +33,9 @@ DBMS_MIN_PROTOCOL_VERSION_WITH_PARAMETERS = 54459
|
|
|
33
33
|
DBMS_MIN_PROTOCOL_VERSION_WITH_SERVER_QUERY_TIME_IN_PROGRESS = 54460
|
|
34
34
|
DBMS_MIN_PROTOCOL_VERSION_WITH_PASSWORD_COMPLEXITY_RULES = 54461
|
|
35
35
|
DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET_V2 = 54462
|
|
36
|
+
DBMS_MIN_PROTOCOL_VERSION_WITH_TOTAL_BYTES_IN_PROGRESS = 54463
|
|
37
|
+
DBMS_MIN_PROTOCOL_VERSION_WITH_TIMEZONE_UPDATES = 54464
|
|
38
|
+
DBMS_MIN_REVISION_WITH_SYSTEM_KEYWORDS_TABLE = 54468
|
|
36
39
|
|
|
37
40
|
# Timeouts
|
|
38
41
|
DBMS_DEFAULT_CONNECT_TIMEOUT_SEC = 10
|
|
@@ -48,7 +51,7 @@ CLIENT_NAME = 'python-driver'
|
|
|
48
51
|
CLIENT_VERSION_MAJOR = 20
|
|
49
52
|
CLIENT_VERSION_MINOR = 10
|
|
50
53
|
CLIENT_VERSION_PATCH = 2
|
|
51
|
-
CLIENT_REVISION =
|
|
54
|
+
CLIENT_REVISION = DBMS_MIN_REVISION_WITH_SYSTEM_KEYWORDS_TABLE
|
|
52
55
|
|
|
53
56
|
BUFFER_SIZE = 1048576
|
|
54
57
|
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import pandas as pd
|
|
3
|
+
from pandas.core.arrays import ExtensionArray
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
def column_chunks(columns, n):
|
|
6
7
|
for column in columns:
|
|
7
|
-
if not isinstance(
|
|
8
|
+
if not isinstance(
|
|
9
|
+
column, (np.ndarray, pd.DatetimeIndex, ExtensionArray)
|
|
10
|
+
):
|
|
8
11
|
raise TypeError(
|
|
9
12
|
'Unsupported column type: {}. '
|
|
10
|
-
'ndarray/DatetimeIndex is expected.'
|
|
13
|
+
'ndarray/DatetimeIndex/ExtensionArray is expected.'
|
|
11
14
|
.format(type(column))
|
|
12
15
|
)
|
|
13
16
|
|
clickhouse_driver/progress.py
CHANGED
|
@@ -6,7 +6,8 @@ class Progress(object):
|
|
|
6
6
|
def __init__(self):
|
|
7
7
|
self.rows = 0
|
|
8
8
|
self.bytes = 0
|
|
9
|
-
self.total_rows = 0
|
|
9
|
+
self.total_rows = 0 # total_rows_to_read
|
|
10
|
+
self.total_bytes = 0 # total_bytes_to_read
|
|
10
11
|
self.written_rows = 0
|
|
11
12
|
self.written_bytes = 0
|
|
12
13
|
self.elapsed_ns = 0
|
|
@@ -21,6 +22,10 @@ class Progress(object):
|
|
|
21
22
|
if revision >= defines.DBMS_MIN_REVISION_WITH_TOTAL_ROWS_IN_PROGRESS:
|
|
22
23
|
self.total_rows = read_varint(fin)
|
|
23
24
|
|
|
25
|
+
if revision >= defines. \
|
|
26
|
+
DBMS_MIN_PROTOCOL_VERSION_WITH_TOTAL_BYTES_IN_PROGRESS:
|
|
27
|
+
self.total_bytes = read_varint(fin)
|
|
28
|
+
|
|
24
29
|
if revision >= defines.DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO:
|
|
25
30
|
self.written_rows = read_varint(fin)
|
|
26
31
|
self.written_bytes = read_varint(fin)
|
|
@@ -33,6 +38,7 @@ class Progress(object):
|
|
|
33
38
|
self.rows += another_progress.rows
|
|
34
39
|
self.bytes += another_progress.bytes
|
|
35
40
|
self.total_rows += another_progress.total_rows
|
|
41
|
+
self.total_bytes += another_progress.total_bytes
|
|
36
42
|
self.written_rows += another_progress.written_rows
|
|
37
43
|
self.written_bytes += another_progress.written_bytes
|
|
38
44
|
self.elapsed_ns += another_progress.elapsed_ns
|
clickhouse_driver/protocol.py
CHANGED
|
@@ -29,7 +29,10 @@ class ClientPacketTypes(object):
|
|
|
29
29
|
|
|
30
30
|
@classmethod
|
|
31
31
|
def to_str(cls, packet):
|
|
32
|
-
|
|
32
|
+
try:
|
|
33
|
+
return cls._types_str[packet]
|
|
34
|
+
except IndexError:
|
|
35
|
+
return 'Unknown packet'
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
class ServerPacketTypes(object):
|
|
@@ -81,15 +84,28 @@ class ServerPacketTypes(object):
|
|
|
81
84
|
# Packet with profile events from server.
|
|
82
85
|
PROFILE_EVENTS = 14
|
|
83
86
|
|
|
87
|
+
MERGE_TREE_ALL_RANGES_ANNOUNCEMENT = 15
|
|
88
|
+
|
|
89
|
+
# Request from a MergeTree replica to a coordinator
|
|
90
|
+
MERGE_TREE_READ_TASK_REQUEST = 16
|
|
91
|
+
|
|
92
|
+
# Receive server's (session-wide) default timezone
|
|
93
|
+
TIMEZONE_UPDATE = 17
|
|
94
|
+
|
|
84
95
|
_types_str = [
|
|
85
96
|
'Hello', 'Data', 'Exception', 'Progress', 'Pong', 'EndOfStream',
|
|
86
97
|
'ProfileInfo', 'Totals', 'Extremes', 'TablesStatusResponse', 'Log',
|
|
87
|
-
'TableColumns', 'PartUUIDs', 'ReadTaskRequest', 'ProfileEvents'
|
|
98
|
+
'TableColumns', 'PartUUIDs', 'ReadTaskRequest', 'ProfileEvents',
|
|
99
|
+
'MergeTreeAllRangesAnnouncement', 'MergeTreeReadTaskRequest',
|
|
100
|
+
'TimezoneUpdate'
|
|
88
101
|
]
|
|
89
102
|
|
|
90
103
|
@classmethod
|
|
91
104
|
def to_str(cls, packet):
|
|
92
|
-
|
|
105
|
+
try:
|
|
106
|
+
return cls._types_str[packet]
|
|
107
|
+
except IndexError:
|
|
108
|
+
return 'Unknown packet'
|
|
93
109
|
|
|
94
110
|
@classmethod
|
|
95
111
|
def strings_in_message(cls, packet):
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
1
3
|
from ..block import ColumnOrientedBlock, BlockInfo
|
|
2
4
|
from ..columns.service import read_column, write_column
|
|
3
5
|
from ..reader import read_binary_str, read_binary_uint8
|
|
@@ -5,6 +7,8 @@ from ..varint import write_varint, read_varint
|
|
|
5
7
|
from ..writer import write_binary_str, write_binary_uint8
|
|
6
8
|
from .. import defines
|
|
7
9
|
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
8
12
|
|
|
9
13
|
class BlockOutputStream(object):
|
|
10
14
|
def __init__(self, fout, context):
|
|
@@ -40,6 +44,7 @@ class BlockOutputStream(object):
|
|
|
40
44
|
# We write always sparse data without custom serialization.
|
|
41
45
|
write_binary_uint8(0, self.fout)
|
|
42
46
|
|
|
47
|
+
logger.debug('Writing column %s', col_name)
|
|
43
48
|
write_column(self.context, col_name, col_type, items,
|
|
44
49
|
self.fout, types_check=block.types_check)
|
|
45
50
|
|
|
@@ -80,6 +85,7 @@ class BlockInputStream(object):
|
|
|
80
85
|
has_custom_serialization = bool(read_binary_uint8(self.fin))
|
|
81
86
|
|
|
82
87
|
if n_rows:
|
|
88
|
+
logger.debug('Reading column %s', column_name)
|
|
83
89
|
column = read_column(
|
|
84
90
|
self.context, column_type, n_rows,
|
|
85
91
|
self.fin, use_numpy=use_numpy,
|
clickhouse_driver/util/escape.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import ssl
|
|
1
2
|
from itertools import islice, tee
|
|
3
|
+
from urllib.parse import urlparse, parse_qs, unquote
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
def chunks(seq, n):
|
|
@@ -55,3 +57,117 @@ def asbool(obj):
|
|
|
55
57
|
else:
|
|
56
58
|
raise ValueError('String is not true/false: %r' % obj)
|
|
57
59
|
return bool(obj)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def parse_url(url):
|
|
63
|
+
"""
|
|
64
|
+
Parses url into host and kwargs suitable for further Client construction.
|
|
65
|
+
Return host and kwargs.
|
|
66
|
+
|
|
67
|
+
For example::
|
|
68
|
+
|
|
69
|
+
clickhouse://[user:password]@localhost:9000/default
|
|
70
|
+
clickhouses://[user:password]@localhost:9440/default
|
|
71
|
+
|
|
72
|
+
Three URL schemes are supported:
|
|
73
|
+
|
|
74
|
+
* clickhouse:// creates a normal TCP socket connection
|
|
75
|
+
* clickhouses:// creates a SSL wrapped TCP socket connection
|
|
76
|
+
|
|
77
|
+
Any additional querystring arguments will be passed along to
|
|
78
|
+
the Connection class's initializer.
|
|
79
|
+
"""
|
|
80
|
+
url = urlparse(url)
|
|
81
|
+
|
|
82
|
+
settings = {}
|
|
83
|
+
kwargs = {}
|
|
84
|
+
|
|
85
|
+
host = url.hostname
|
|
86
|
+
|
|
87
|
+
if url.port is not None:
|
|
88
|
+
kwargs['port'] = url.port
|
|
89
|
+
|
|
90
|
+
path = url.path.replace('/', '', 1)
|
|
91
|
+
if path:
|
|
92
|
+
kwargs['database'] = path
|
|
93
|
+
|
|
94
|
+
if url.username is not None:
|
|
95
|
+
kwargs['user'] = unquote(url.username)
|
|
96
|
+
|
|
97
|
+
if url.password is not None:
|
|
98
|
+
kwargs['password'] = unquote(url.password)
|
|
99
|
+
|
|
100
|
+
if url.scheme == 'clickhouses':
|
|
101
|
+
kwargs['secure'] = True
|
|
102
|
+
|
|
103
|
+
compression_algs = {'lz4', 'lz4hc', 'zstd'}
|
|
104
|
+
timeouts = {
|
|
105
|
+
'connect_timeout',
|
|
106
|
+
'send_receive_timeout',
|
|
107
|
+
'sync_request_timeout'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for name, value in parse_qs(url.query).items():
|
|
111
|
+
if not value or not len(value):
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
value = value[0]
|
|
115
|
+
|
|
116
|
+
if name == 'compression':
|
|
117
|
+
value = value.lower()
|
|
118
|
+
if value in compression_algs:
|
|
119
|
+
kwargs[name] = value
|
|
120
|
+
else:
|
|
121
|
+
kwargs[name] = asbool(value)
|
|
122
|
+
|
|
123
|
+
elif name == 'secure':
|
|
124
|
+
kwargs[name] = asbool(value)
|
|
125
|
+
|
|
126
|
+
elif name == 'use_numpy':
|
|
127
|
+
settings[name] = asbool(value)
|
|
128
|
+
|
|
129
|
+
elif name == 'round_robin':
|
|
130
|
+
kwargs[name] = asbool(value)
|
|
131
|
+
|
|
132
|
+
elif name == 'client_name':
|
|
133
|
+
kwargs[name] = value
|
|
134
|
+
|
|
135
|
+
elif name in timeouts:
|
|
136
|
+
kwargs[name] = float(value)
|
|
137
|
+
|
|
138
|
+
elif name == 'compress_block_size':
|
|
139
|
+
kwargs[name] = int(value)
|
|
140
|
+
|
|
141
|
+
elif name == 'settings_is_important':
|
|
142
|
+
kwargs[name] = asbool(value)
|
|
143
|
+
|
|
144
|
+
elif name == 'tcp_keepalive':
|
|
145
|
+
try:
|
|
146
|
+
kwargs[name] = asbool(value)
|
|
147
|
+
except ValueError:
|
|
148
|
+
parts = value.split(',')
|
|
149
|
+
kwargs[name] = (
|
|
150
|
+
int(parts[0]), int(parts[1]), int(parts[2])
|
|
151
|
+
)
|
|
152
|
+
elif name == 'client_revision':
|
|
153
|
+
kwargs[name] = int(value)
|
|
154
|
+
|
|
155
|
+
# ssl
|
|
156
|
+
elif name == 'verify':
|
|
157
|
+
kwargs[name] = asbool(value)
|
|
158
|
+
elif name == 'check_hostname':
|
|
159
|
+
kwargs[name] = asbool(value)
|
|
160
|
+
elif name == 'ssl_version':
|
|
161
|
+
kwargs[name] = getattr(ssl, value)
|
|
162
|
+
elif name in ['ca_certs', 'ciphers', 'keyfile', 'keypass', 'certfile',
|
|
163
|
+
'server_hostname']:
|
|
164
|
+
kwargs[name] = value
|
|
165
|
+
elif name == 'alt_hosts':
|
|
166
|
+
kwargs['alt_hosts'] = value
|
|
167
|
+
else:
|
|
168
|
+
settings[name] = value
|
|
169
|
+
|
|
170
|
+
if settings:
|
|
171
|
+
kwargs['settings'] = settings
|
|
172
|
+
|
|
173
|
+
return host, kwargs
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: clickhouse-driver
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.10
|
|
4
4
|
Summary: Python driver with native interface for ClickHouse
|
|
5
5
|
Home-page: https://github.com/mymarilyn/clickhouse-driver
|
|
6
6
|
Author: Konstantin Lebedev
|
|
@@ -17,11 +17,12 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
|
18
18
|
Classifier: Programming Language :: SQL
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
24
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
26
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
26
27
|
Classifier: Topic :: Database
|
|
27
28
|
Classifier: Topic :: Software Development
|
|
@@ -29,20 +30,33 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
29
30
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
30
31
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
31
32
|
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
32
|
-
Requires-Python: >=3.
|
|
33
|
+
Requires-Python: >=3.9, <4
|
|
33
34
|
License-File: LICENSE
|
|
34
35
|
Requires-Dist: pytz
|
|
35
36
|
Requires-Dist: tzlocal
|
|
36
37
|
Provides-Extra: lz4
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist: lz4
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Provides-Extra: numpy
|
|
41
|
-
Requires-Dist: numpy >=1.12.0 ; extra == 'numpy'
|
|
42
|
-
Requires-Dist: pandas >=0.24.0 ; extra == 'numpy'
|
|
38
|
+
Requires-Dist: lz4<=3.0.1; implementation_name == "pypy" and extra == "lz4"
|
|
39
|
+
Requires-Dist: lz4; implementation_name != "pypy" and extra == "lz4"
|
|
40
|
+
Requires-Dist: clickhouse-cityhash>=1.0.2.1; extra == "lz4"
|
|
43
41
|
Provides-Extra: zstd
|
|
44
|
-
Requires-Dist: zstd
|
|
45
|
-
Requires-Dist: clickhouse-cityhash
|
|
42
|
+
Requires-Dist: zstd; extra == "zstd"
|
|
43
|
+
Requires-Dist: clickhouse-cityhash>=1.0.2.1; extra == "zstd"
|
|
44
|
+
Provides-Extra: numpy
|
|
45
|
+
Requires-Dist: numpy>=1.12.0; extra == "numpy"
|
|
46
|
+
Requires-Dist: pandas>=0.24.0; extra == "numpy"
|
|
47
|
+
Dynamic: author
|
|
48
|
+
Dynamic: author-email
|
|
49
|
+
Dynamic: classifier
|
|
50
|
+
Dynamic: description
|
|
51
|
+
Dynamic: home-page
|
|
52
|
+
Dynamic: keywords
|
|
53
|
+
Dynamic: license
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
Dynamic: project-url
|
|
56
|
+
Dynamic: provides-extra
|
|
57
|
+
Dynamic: requires-dist
|
|
58
|
+
Dynamic: requires-python
|
|
59
|
+
Dynamic: summary
|
|
46
60
|
|
|
47
61
|
ClickHouse Python Driver
|
|
48
62
|
========================
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
clickhouse_driver/__init__.py,sha256
|
|
1
|
+
clickhouse_driver/__init__.py,sha256=-RHHLH8KESN2fiVtQ1br8WM8Hl6CkqkunzvCOJCNkbM,159
|
|
2
2
|
clickhouse_driver/block.py,sha256=t2zZhtCzwp4aJj0CuDqXlDEgHXgwc6GRsIks2aaIZvI,6311
|
|
3
3
|
clickhouse_driver/blockstreamprofileinfo.py,sha256=nYx9QXWAS8aPiRbtAzwLRT5JIlJ8S103JMkudncwpFg,712
|
|
4
|
-
clickhouse_driver/bufferedreader.cp312-win32.pyd,sha256=
|
|
5
|
-
clickhouse_driver/bufferedwriter.cp312-win32.pyd,sha256=
|
|
6
|
-
clickhouse_driver/client.py,sha256=
|
|
7
|
-
clickhouse_driver/clientinfo.py,sha256=
|
|
8
|
-
clickhouse_driver/connection.py,sha256=
|
|
4
|
+
clickhouse_driver/bufferedreader.cp312-win32.pyd,sha256=JklvZWSinVBCtwZ4II-Cte7d_NfmHsFTxdyy08HoRiY,74240
|
|
5
|
+
clickhouse_driver/bufferedwriter.cp312-win32.pyd,sha256=sJkk4YeZ24in30X_odp4e4HwyFIYVhzB-7UI_neD5J4,74752
|
|
6
|
+
clickhouse_driver/client.py,sha256=iYSz2DLQC-t6RLmtWJvtHoEWBAFtKDIafl874tz2ebs,32251
|
|
7
|
+
clickhouse_driver/clientinfo.py,sha256=cdMA2td6tuYPsN6m4qtGzLzGKY4zQune0s0fZlNRiEA,4271
|
|
8
|
+
clickhouse_driver/connection.py,sha256=1GlehPjkzAPtFaAAzKHlBxyXMAHLyNOtNUKQjG7kjq4,29950
|
|
9
9
|
clickhouse_driver/context.py,sha256=yPkJ_BN4LGODvKCOjNlDGqABwxAMQTQl7w1vIGRPBDg,909
|
|
10
|
-
clickhouse_driver/defines.py,sha256=
|
|
10
|
+
clickhouse_driver/defines.py,sha256=EwrQz7sNNUmGZmZywQFpDpBFc67nB9GAZOBQEvvUJzA,2130
|
|
11
11
|
clickhouse_driver/errors.py,sha256=mffBg-Y2LFOSRzvE9V34RwFcvmfh67yqLeEBhrdjeXE,14343
|
|
12
12
|
clickhouse_driver/log.py,sha256=P9VS_YDY3a4JQsNOeUNNK0L1AAallTC1GF4FG5gCrac,1091
|
|
13
13
|
clickhouse_driver/opentelemetry.py,sha256=GIzHCxdB8LB1ozXtUjIpxsdznmRABAts64G2u2l4C_A,1622
|
|
14
|
-
clickhouse_driver/progress.py,sha256=
|
|
15
|
-
clickhouse_driver/protocol.py,sha256=
|
|
14
|
+
clickhouse_driver/progress.py,sha256=mom2NRLg8dfE_ObOEthKqjSBIliBvDjt7joePvY_Fdw,1574
|
|
15
|
+
clickhouse_driver/protocol.py,sha256=BxCJiZLH0QkFmdNwog1OJm9MEMwdPZ1i5Jv1_NHcLb0,2965
|
|
16
16
|
clickhouse_driver/queryprocessingstage.py,sha256=lbV-bB5jWUp0hqYBTsUcRYkJhCgCTfN2G21AykMoAp0,186
|
|
17
17
|
clickhouse_driver/reader.py,sha256=PWKOKwjszu0sJbG-dd_TyGn8tQAzxg2gCJVbz27G3-8,1322
|
|
18
18
|
clickhouse_driver/readhelpers.py,sha256=tXOmSL9GSeHLdKE2yBlk0epfy-hGJ3bTOLq3Q6sXIkw,717
|
|
19
19
|
clickhouse_driver/result.py,sha256=RpjBUvRQJ70xISye7u6gxgQBJwc2UkNuusLkaZF7SmM,4098
|
|
20
|
-
clickhouse_driver/varint.cp312-win32.pyd,sha256=
|
|
20
|
+
clickhouse_driver/varint.cp312-win32.pyd,sha256=FF4eJeVbjqnrNtCae4bBjDtWRGeX08hqTyyTjcA-KQQ,32768
|
|
21
21
|
clickhouse_driver/writer.py,sha256=yf5f1vTr56YFtL-Swpi_jBsPw5bQS56j53joB0Acdyk,1286
|
|
22
22
|
clickhouse_driver/columns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
clickhouse_driver/columns/arraycolumn.py,sha256=UiA48jw3o4-ert8BnzEbl2h1jVmtDH3jtcP1BTPru2w,5322
|
|
24
24
|
clickhouse_driver/columns/base.py,sha256=jRThD8Ol7gwNy3x0M7vvslkm0RDOsCLJqKGf0arsa0w,6504
|
|
25
25
|
clickhouse_driver/columns/boolcolumn.py,sha256=QgVCqbZWoFD1yvpppc92iiXIzReCVEh692efNSNH4UE,127
|
|
26
26
|
clickhouse_driver/columns/datecolumn.py,sha256=FT6qzmniFGKw5SpjFITiBf-fJGEwaoUIz7PMZMFxe8M,3209
|
|
27
|
-
clickhouse_driver/columns/datetimecolumn.py,sha256=
|
|
27
|
+
clickhouse_driver/columns/datetimecolumn.py,sha256=RWucoNtcc4wUGQ6xPL0cTNmxFy8eQ50ZdHzexXBm3XE,6730
|
|
28
28
|
clickhouse_driver/columns/decimalcolumn.py,sha256=MBczjN6AtI0jgbVTNguwVE7ZdWql0XuMl-QohxV-sN0,3450
|
|
29
|
-
clickhouse_driver/columns/enumcolumn.py,sha256=
|
|
29
|
+
clickhouse_driver/columns/enumcolumn.py,sha256=zqZkSVVXfWsaPUbP59ayy7w8rG4otS9J51UPD29zs2Y,3674
|
|
30
30
|
clickhouse_driver/columns/exceptions.py,sha256=vrZMZ9ORRP7RSSd34azM_xFaeMaaYbwy6h6ZCeFNbIg,163
|
|
31
31
|
clickhouse_driver/columns/floatcolumn.py,sha256=Mci7Fl05dgkpDQRfjGaDP9QraZER5nkYX1lVsTA89Yk,925
|
|
32
32
|
clickhouse_driver/columns/intcolumn.py,sha256=ntpxyMiu44VQYJ0HyHlglwxMgUtnIgf3JE9LUD9Xwwc,3519
|
|
33
33
|
clickhouse_driver/columns/intervalcolumn.py,sha256=oQeybb4qrcp07LeVYfqgeZuHYGH5RaY7KnWVoIsDe1I,600
|
|
34
34
|
clickhouse_driver/columns/ipcolumn.py,sha256=LIt-NiUy70-8u5Amu0v0tlAlrolZ8gXzlFxcJYmjRAk,4095
|
|
35
35
|
clickhouse_driver/columns/jsoncolumn.py,sha256=SeCLSrmRoEg9wlvoehs7-EmrV8XkOL3lknzeOORhbJg,1175
|
|
36
|
-
clickhouse_driver/columns/largeint.cp312-win32.pyd,sha256=
|
|
36
|
+
clickhouse_driver/columns/largeint.cp312-win32.pyd,sha256=cWp3sM8WzTGfr5hRqQtus2X_BIF4ddL67pgAbjm6FBs,55296
|
|
37
37
|
clickhouse_driver/columns/lowcardinalitycolumn.py,sha256=vMlhYYUPNmFhQiUAS77pE25KjI8TrO6ySz6w0ByBdZQ,4920
|
|
38
38
|
clickhouse_driver/columns/mapcolumn.py,sha256=gX7xvwsilfOHDCwmRJu4fW2Y1OrN_1cgZTmbvcyer30,2133
|
|
39
39
|
clickhouse_driver/columns/nestedcolumn.py,sha256=7x3xNYR22kEmgV4_3rPVZea2zCTU364O1tlOewMgw3M,303
|
|
@@ -44,20 +44,20 @@ clickhouse_driver/columns/service.py,sha256=6nIGwvcG-5LErQFn_3a2GRKZI2OnKYsy2oII
|
|
|
44
44
|
clickhouse_driver/columns/simpleaggregatefunctioncolumn.py,sha256=zDWBd_Hc7AktHFZ5JY7SwxIk7G4WBHdJdcPBqihe7q0,235
|
|
45
45
|
clickhouse_driver/columns/stringcolumn.py,sha256=C-l7HaReg9AcJGQvgpSH07aV-CZMBP1jKArPHZi8Q2k,2059
|
|
46
46
|
clickhouse_driver/columns/tuplecolumn.py,sha256=DnwtEwVXzm-YyL5-cPe9MiOLOoTEcDhcYeBY6SuuZZQ,2040
|
|
47
|
-
clickhouse_driver/columns/util.py,sha256=
|
|
47
|
+
clickhouse_driver/columns/util.py,sha256=3q965GjEmKkTmjIva31PhvAEGfuuGulad1amK7kQBEQ,1427
|
|
48
48
|
clickhouse_driver/columns/uuidcolumn.py,sha256=7CLPxsHJtV6Zt9jxILSkE0LAwffloLmrjjbwCZH34mA,1865
|
|
49
49
|
clickhouse_driver/columns/numpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
50
|
clickhouse_driver/columns/numpy/base.py,sha256=Wk1ADpoQGWQv5X8sWi0esA2jmQGEoDakXZxImuYM2eM,1410
|
|
51
51
|
clickhouse_driver/columns/numpy/boolcolumn.py,sha256=0_RwEroY2-ZqMuxKeTNG27ZCWN_y9BxYZzbuFKeqoQg,140
|
|
52
52
|
clickhouse_driver/columns/numpy/datecolumn.py,sha256=xWFsFwiRmszK9A20UWnF4beTE5f8XQDj18x53xtXtSI,482
|
|
53
|
-
clickhouse_driver/columns/numpy/datetimecolumn.py,sha256=
|
|
53
|
+
clickhouse_driver/columns/numpy/datetimecolumn.py,sha256=X6XgslCvWOF3dtVP3ogDQ4WLWhQqAkAdw5qAIuE8f1o,4890
|
|
54
54
|
clickhouse_driver/columns/numpy/floatcolumn.py,sha256=WnnlyR3vabh6ixllXwdyQ_t8y5MSqCddImWityxz6pE,599
|
|
55
55
|
clickhouse_driver/columns/numpy/intcolumn.py,sha256=ZzmjvjpEaZ_kk-mGEPdBAqUCjqCgGT8tUEzbQKwUVVA,792
|
|
56
56
|
clickhouse_driver/columns/numpy/lowcardinalitycolumn.py,sha256=ExYtwBBn6WfSQtWC0f79ZqjdqO3ZJ3IL6KtlQOgMh-k,3368
|
|
57
57
|
clickhouse_driver/columns/numpy/service.py,sha256=ENk26HPfxtbumcO_b2fGTNJdTgaJT0a-l3q_xrRIZZ4,2126
|
|
58
58
|
clickhouse_driver/columns/numpy/stringcolumn.py,sha256=FH87XPQv3ga0ZJnngubqu4DgxmUt8bjW8xJcNfOU7EI,2439
|
|
59
59
|
clickhouse_driver/columns/numpy/tuplecolumn.py,sha256=5RqhCIZ-CrWy_D0yyfTmlWBJgrunT5Yk-bM4OvIKZ1o,1233
|
|
60
|
-
clickhouse_driver/compression/__init__.py,sha256=
|
|
60
|
+
clickhouse_driver/compression/__init__.py,sha256=7D3Wk_-KQsnIdaqp9163YCDsQ98Stbl6GF1h1KAFgAg,840
|
|
61
61
|
clickhouse_driver/compression/base.py,sha256=MCTK2aOGT3Lkso5r3-U-ilj2ln4r-nnfNI_2Ostsu6Q,2434
|
|
62
62
|
clickhouse_driver/compression/lz4.py,sha256=ZTf1zn0uG26O29XHBBZeve26JLPNbbEWWMZe065oa0Y,631
|
|
63
63
|
clickhouse_driver/compression/lz4hc.py,sha256=zGbj9vnM20W298kgzD0dIAgIeV30e5Kx8NSN8t4SDas,195
|
|
@@ -69,7 +69,7 @@ clickhouse_driver/dbapi/errors.py,sha256=yv2SDIK-ZlWmIxBoF5_igfHRyh9zTUJSgAj9g8S
|
|
|
69
69
|
clickhouse_driver/dbapi/extras.py,sha256=je1tjk6gb-QqLMoWu_iXCqhJK159vyyHsCB_8vXkXyw,2129
|
|
70
70
|
clickhouse_driver/numpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
71
|
clickhouse_driver/numpy/block.py,sha256=k8CqQxaVSviZvicS03exPZG_LFwbzB5-NnLB2EuBKgQ,180
|
|
72
|
-
clickhouse_driver/numpy/helpers.py,sha256=
|
|
72
|
+
clickhouse_driver/numpy/helpers.py,sha256=cwRvBX4a-o-QdccYIxFT3p8DPUaXqyXWsVNTSiG8Cdw,803
|
|
73
73
|
clickhouse_driver/numpy/result.py,sha256=D-7IsaIt0u4WJ8iSzXYBB0OiPgPu5ptu-1HiJvTW-No,3563
|
|
74
74
|
clickhouse_driver/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
75
|
clickhouse_driver/settings/available.py,sha256=8b1YUjt-_6gO9Cio02VZSMPdhM70zk-NMhE4f_jwFx8,16613
|
|
@@ -77,13 +77,13 @@ clickhouse_driver/settings/types.py,sha256=u_A3FzREqIjj4OSEdKUwm1Xn8jEnGpp-9Avqb
|
|
|
77
77
|
clickhouse_driver/settings/writer.py,sha256=x0FVdbKZR9lN-hXAT2xxkoqvGo1ojvWWwyP3NaI7ZDA,1099
|
|
78
78
|
clickhouse_driver/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
79
|
clickhouse_driver/streams/compressed.py,sha256=eyFCuq_sLX6oJLQ_h1QX3IB9IgUx56pPqPfhmeiA6ag,2865
|
|
80
|
-
clickhouse_driver/streams/native.py,sha256=
|
|
80
|
+
clickhouse_driver/streams/native.py,sha256=lIJFxLRFrh2zqRAvf8W2JPmXdGtJu3LPDUkfaBrLAfk,3493
|
|
81
81
|
clickhouse_driver/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
82
82
|
clickhouse_driver/util/compat.py,sha256=wIB_6ULSapKx-Fi64lZ0YJ-TtWOQXePHE90wZopIM1I,876
|
|
83
|
-
clickhouse_driver/util/escape.py,sha256=
|
|
84
|
-
clickhouse_driver/util/helpers.py,sha256=
|
|
85
|
-
clickhouse_driver-0.2.
|
|
86
|
-
clickhouse_driver-0.2.
|
|
87
|
-
clickhouse_driver-0.2.
|
|
88
|
-
clickhouse_driver-0.2.
|
|
89
|
-
clickhouse_driver-0.2.
|
|
83
|
+
clickhouse_driver/util/escape.py,sha256=vL8sY6XdHhjFwtHn8yQ3JbeZfocWt6jyvxFf-nEiRtM,2262
|
|
84
|
+
clickhouse_driver/util/helpers.py,sha256=IGmaK3L8_i8C-3NJWPWT2VK5hAtLxfflF0ti2z45SHs,4574
|
|
85
|
+
clickhouse_driver-0.2.10.dist-info/licenses/LICENSE,sha256=b2SjNa4zGQk6XzJwmeE1dQjjtWRvX_zxJIAl_ZbN_S8,1143
|
|
86
|
+
clickhouse_driver-0.2.10.dist-info/METADATA,sha256=L7JSolHa_2zc_NGUpJK-fXouxcU8UNJseMQkSxePWYE,6607
|
|
87
|
+
clickhouse_driver-0.2.10.dist-info/WHEEL,sha256=LwxTQZ0gyDP_uaeNCLm-ZIktY9hv6x0e22Q-hgFd-po,97
|
|
88
|
+
clickhouse_driver-0.2.10.dist-info/top_level.txt,sha256=PrE0Lrs4d-gRQwzABaABfym9Qvr4nN6uTrDy6Q7zQME,18
|
|
89
|
+
clickhouse_driver-0.2.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|