clickhouse-driver 0.2.10__cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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 +9 -0
- clickhouse_driver/block.py +227 -0
- clickhouse_driver/blockstreamprofileinfo.py +22 -0
- clickhouse_driver/bufferedreader.cpython-310-aarch64-linux-gnu.so +0 -0
- clickhouse_driver/bufferedwriter.cpython-310-aarch64-linux-gnu.so +0 -0
- clickhouse_driver/client.py +812 -0
- clickhouse_driver/clientinfo.py +119 -0
- clickhouse_driver/columns/__init__.py +0 -0
- clickhouse_driver/columns/arraycolumn.py +161 -0
- clickhouse_driver/columns/base.py +221 -0
- clickhouse_driver/columns/boolcolumn.py +7 -0
- clickhouse_driver/columns/datecolumn.py +108 -0
- clickhouse_driver/columns/datetimecolumn.py +203 -0
- clickhouse_driver/columns/decimalcolumn.py +116 -0
- clickhouse_driver/columns/enumcolumn.py +129 -0
- clickhouse_driver/columns/exceptions.py +12 -0
- clickhouse_driver/columns/floatcolumn.py +34 -0
- clickhouse_driver/columns/intcolumn.py +157 -0
- clickhouse_driver/columns/intervalcolumn.py +33 -0
- clickhouse_driver/columns/ipcolumn.py +118 -0
- clickhouse_driver/columns/jsoncolumn.py +37 -0
- clickhouse_driver/columns/largeint.cpython-310-aarch64-linux-gnu.so +0 -0
- clickhouse_driver/columns/lowcardinalitycolumn.py +142 -0
- clickhouse_driver/columns/mapcolumn.py +73 -0
- clickhouse_driver/columns/nestedcolumn.py +10 -0
- clickhouse_driver/columns/nothingcolumn.py +13 -0
- clickhouse_driver/columns/nullablecolumn.py +7 -0
- clickhouse_driver/columns/nullcolumn.py +15 -0
- clickhouse_driver/columns/numpy/__init__.py +0 -0
- clickhouse_driver/columns/numpy/base.py +47 -0
- clickhouse_driver/columns/numpy/boolcolumn.py +8 -0
- clickhouse_driver/columns/numpy/datecolumn.py +19 -0
- clickhouse_driver/columns/numpy/datetimecolumn.py +146 -0
- clickhouse_driver/columns/numpy/floatcolumn.py +24 -0
- clickhouse_driver/columns/numpy/intcolumn.py +43 -0
- clickhouse_driver/columns/numpy/lowcardinalitycolumn.py +96 -0
- clickhouse_driver/columns/numpy/service.py +58 -0
- clickhouse_driver/columns/numpy/stringcolumn.py +78 -0
- clickhouse_driver/columns/numpy/tuplecolumn.py +37 -0
- clickhouse_driver/columns/service.py +185 -0
- clickhouse_driver/columns/simpleaggregatefunctioncolumn.py +7 -0
- clickhouse_driver/columns/stringcolumn.py +73 -0
- clickhouse_driver/columns/tuplecolumn.py +63 -0
- clickhouse_driver/columns/util.py +61 -0
- clickhouse_driver/columns/uuidcolumn.py +64 -0
- clickhouse_driver/compression/__init__.py +32 -0
- clickhouse_driver/compression/base.py +87 -0
- clickhouse_driver/compression/lz4.py +21 -0
- clickhouse_driver/compression/lz4hc.py +9 -0
- clickhouse_driver/compression/zstd.py +20 -0
- clickhouse_driver/connection.py +825 -0
- clickhouse_driver/context.py +36 -0
- clickhouse_driver/dbapi/__init__.py +62 -0
- clickhouse_driver/dbapi/connection.py +99 -0
- clickhouse_driver/dbapi/cursor.py +370 -0
- clickhouse_driver/dbapi/errors.py +40 -0
- clickhouse_driver/dbapi/extras.py +73 -0
- clickhouse_driver/defines.py +58 -0
- clickhouse_driver/errors.py +453 -0
- clickhouse_driver/log.py +48 -0
- clickhouse_driver/numpy/__init__.py +0 -0
- clickhouse_driver/numpy/block.py +8 -0
- clickhouse_driver/numpy/helpers.py +28 -0
- clickhouse_driver/numpy/result.py +123 -0
- clickhouse_driver/opentelemetry.py +43 -0
- clickhouse_driver/progress.py +44 -0
- clickhouse_driver/protocol.py +130 -0
- clickhouse_driver/queryprocessingstage.py +8 -0
- clickhouse_driver/reader.py +69 -0
- clickhouse_driver/readhelpers.py +26 -0
- clickhouse_driver/result.py +144 -0
- clickhouse_driver/settings/__init__.py +0 -0
- clickhouse_driver/settings/available.py +405 -0
- clickhouse_driver/settings/types.py +50 -0
- clickhouse_driver/settings/writer.py +34 -0
- clickhouse_driver/streams/__init__.py +0 -0
- clickhouse_driver/streams/compressed.py +88 -0
- clickhouse_driver/streams/native.py +108 -0
- clickhouse_driver/util/__init__.py +0 -0
- clickhouse_driver/util/compat.py +39 -0
- clickhouse_driver/util/escape.py +94 -0
- clickhouse_driver/util/helpers.py +173 -0
- clickhouse_driver/varint.cpython-310-aarch64-linux-gnu.so +0 -0
- clickhouse_driver/writer.py +67 -0
- clickhouse_driver-0.2.10.dist-info/METADATA +215 -0
- clickhouse_driver-0.2.10.dist-info/RECORD +89 -0
- clickhouse_driver-0.2.10.dist-info/WHEEL +7 -0
- clickhouse_driver-0.2.10.dist-info/licenses/LICENSE +21 -0
- clickhouse_driver-0.2.10.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from pytz import timezone as get_timezone, utc
|
|
4
|
+
from ..util.compat import get_localzone_name_compat
|
|
5
|
+
from .base import FormatColumn
|
|
6
|
+
|
|
7
|
+
EPOCH = datetime(1970, 1, 1, tzinfo=utc)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DateTimeColumn(FormatColumn):
|
|
11
|
+
ch_type = 'DateTime'
|
|
12
|
+
py_types = (datetime, int)
|
|
13
|
+
format = 'I'
|
|
14
|
+
|
|
15
|
+
def __init__(self, timezone=None, offset_naive=True, **kwargs):
|
|
16
|
+
self.timezone = timezone
|
|
17
|
+
self.offset_naive = offset_naive
|
|
18
|
+
super(DateTimeColumn, self).__init__(**kwargs)
|
|
19
|
+
|
|
20
|
+
def after_read_items(self, items, nulls_map=None):
|
|
21
|
+
tz = self.timezone
|
|
22
|
+
fromts = datetime.fromtimestamp
|
|
23
|
+
|
|
24
|
+
# A bit ugly copy-paste. But it helps save time on items
|
|
25
|
+
# processing by avoiding lambda calls or if in loop.
|
|
26
|
+
if self.offset_naive:
|
|
27
|
+
if tz:
|
|
28
|
+
if nulls_map is None:
|
|
29
|
+
return tuple(
|
|
30
|
+
fromts(item, tz).replace(tzinfo=None)
|
|
31
|
+
for item in items
|
|
32
|
+
)
|
|
33
|
+
else:
|
|
34
|
+
return tuple(
|
|
35
|
+
(None if is_null else
|
|
36
|
+
fromts(items[i], tz).replace(tzinfo=None))
|
|
37
|
+
for i, is_null in enumerate(nulls_map)
|
|
38
|
+
)
|
|
39
|
+
else:
|
|
40
|
+
if nulls_map is None:
|
|
41
|
+
return tuple(fromts(item) for item in items)
|
|
42
|
+
else:
|
|
43
|
+
return tuple(
|
|
44
|
+
(None if is_null else fromts(items[i]))
|
|
45
|
+
for i, is_null in enumerate(nulls_map)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
else:
|
|
49
|
+
if nulls_map is None:
|
|
50
|
+
return tuple(fromts(item, tz) for item in items)
|
|
51
|
+
else:
|
|
52
|
+
return tuple(
|
|
53
|
+
(None if is_null else fromts(items[i], tz))
|
|
54
|
+
for i, is_null in enumerate(nulls_map)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def before_write_items(self, items, nulls_map=None):
|
|
58
|
+
timezone = self.timezone
|
|
59
|
+
null_value = self.null_value
|
|
60
|
+
to_timestamp = datetime.timestamp
|
|
61
|
+
|
|
62
|
+
for i, item in enumerate(items):
|
|
63
|
+
if nulls_map and nulls_map[i]:
|
|
64
|
+
items[i] = null_value
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
if isinstance(item, int):
|
|
68
|
+
# support supplying raw integers to avoid
|
|
69
|
+
# costly timezone conversions when using datetime
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
if timezone:
|
|
73
|
+
# Set server's timezone for offset-naive datetime.
|
|
74
|
+
if item.tzinfo is None:
|
|
75
|
+
item = timezone.localize(item)
|
|
76
|
+
|
|
77
|
+
item = item.astimezone(utc)
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
# If datetime is offset-aware use it's timezone.
|
|
81
|
+
if item.tzinfo is not None:
|
|
82
|
+
item = item.astimezone(utc)
|
|
83
|
+
|
|
84
|
+
items[i] = int(to_timestamp(item))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class DateTime64Column(DateTimeColumn):
|
|
88
|
+
ch_type = 'DateTime64'
|
|
89
|
+
format = 'q'
|
|
90
|
+
|
|
91
|
+
max_scale = 6
|
|
92
|
+
|
|
93
|
+
def __init__(self, scale=0, **kwargs):
|
|
94
|
+
self.scale = scale
|
|
95
|
+
super(DateTime64Column, self).__init__(**kwargs)
|
|
96
|
+
|
|
97
|
+
def after_read_items(self, items, nulls_map=None):
|
|
98
|
+
scale = float(10 ** self.scale)
|
|
99
|
+
|
|
100
|
+
tz = self.timezone
|
|
101
|
+
fromts = datetime.fromtimestamp
|
|
102
|
+
|
|
103
|
+
# A bit ugly copy-paste. But it helps save time on items
|
|
104
|
+
# processing by avoiding lambda calls or if in loop.
|
|
105
|
+
if self.offset_naive:
|
|
106
|
+
if tz:
|
|
107
|
+
if nulls_map is None:
|
|
108
|
+
return tuple(
|
|
109
|
+
fromts(item / scale, tz).replace(tzinfo=None)
|
|
110
|
+
for item in items
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
return tuple(
|
|
114
|
+
(None if is_null else
|
|
115
|
+
fromts(items[i] / scale, tz).replace(tzinfo=None))
|
|
116
|
+
for i, is_null in enumerate(nulls_map)
|
|
117
|
+
)
|
|
118
|
+
else:
|
|
119
|
+
if nulls_map is None:
|
|
120
|
+
return tuple(fromts(item / scale) for item in items)
|
|
121
|
+
else:
|
|
122
|
+
return tuple(
|
|
123
|
+
(None if is_null else fromts(items[i] / scale))
|
|
124
|
+
for i, is_null in enumerate(nulls_map)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
else:
|
|
128
|
+
if nulls_map is None:
|
|
129
|
+
return tuple(fromts(item / scale, tz) for item in items)
|
|
130
|
+
else:
|
|
131
|
+
return tuple(
|
|
132
|
+
(None if is_null else fromts(items[i] / scale, tz))
|
|
133
|
+
for i, is_null in enumerate(nulls_map)
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
def before_write_items(self, items, nulls_map=None):
|
|
137
|
+
scale = 10 ** self.scale
|
|
138
|
+
frac_scale = 10 ** (self.max_scale - self.scale)
|
|
139
|
+
|
|
140
|
+
timezone = self.timezone
|
|
141
|
+
null_value = self.null_value
|
|
142
|
+
to_timestamp = datetime.timestamp
|
|
143
|
+
|
|
144
|
+
for i, item in enumerate(items):
|
|
145
|
+
if nulls_map and nulls_map[i]:
|
|
146
|
+
items[i] = null_value
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
if isinstance(item, int):
|
|
150
|
+
# support supplying raw integers to avoid
|
|
151
|
+
# costly timezone conversions when using datetime
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
if timezone:
|
|
155
|
+
# Set server's timezone for offset-naive datetime.
|
|
156
|
+
if item.tzinfo is None:
|
|
157
|
+
item = timezone.localize(item)
|
|
158
|
+
|
|
159
|
+
item = item.astimezone(utc)
|
|
160
|
+
|
|
161
|
+
else:
|
|
162
|
+
# If datetime is offset-aware use it's timezone.
|
|
163
|
+
if item.tzinfo is not None:
|
|
164
|
+
item = item.astimezone(utc)
|
|
165
|
+
|
|
166
|
+
items[i] = (
|
|
167
|
+
int(to_timestamp(item)) * scale +
|
|
168
|
+
int(item.microsecond / frac_scale)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def create_datetime_column(spec, column_options):
|
|
173
|
+
if spec.startswith('DateTime64'):
|
|
174
|
+
cls = DateTime64Column
|
|
175
|
+
spec = spec[11:-1]
|
|
176
|
+
params = spec.split(',', 1)
|
|
177
|
+
column_options['scale'] = int(params[0])
|
|
178
|
+
if len(params) > 1:
|
|
179
|
+
spec = params[1].strip() + ')'
|
|
180
|
+
else:
|
|
181
|
+
cls = DateTimeColumn
|
|
182
|
+
spec = spec[9:]
|
|
183
|
+
|
|
184
|
+
context = column_options['context']
|
|
185
|
+
|
|
186
|
+
tz_name = timezone = None
|
|
187
|
+
offset_naive = True
|
|
188
|
+
|
|
189
|
+
# Use column's timezone if it's specified.
|
|
190
|
+
if spec and spec[-1] == ')':
|
|
191
|
+
tz_name = spec[1:-2]
|
|
192
|
+
offset_naive = False
|
|
193
|
+
else:
|
|
194
|
+
if not context.settings.get('use_client_time_zone', False):
|
|
195
|
+
local_timezone = get_localzone_name_compat()
|
|
196
|
+
remote_timezone = context.server_info.get_timezone()
|
|
197
|
+
if local_timezone != remote_timezone:
|
|
198
|
+
tz_name = remote_timezone
|
|
199
|
+
|
|
200
|
+
if tz_name:
|
|
201
|
+
timezone = get_timezone(tz_name)
|
|
202
|
+
|
|
203
|
+
return cls(timezone=timezone, offset_naive=offset_naive, **column_options)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from decimal import Decimal, localcontext
|
|
2
|
+
|
|
3
|
+
from .base import FormatColumn
|
|
4
|
+
from .exceptions import ColumnTypeMismatchException
|
|
5
|
+
from .intcolumn import Int128Column, Int256Column
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DecimalColumn(FormatColumn):
|
|
9
|
+
py_types = (Decimal, float, int)
|
|
10
|
+
max_precision = None
|
|
11
|
+
|
|
12
|
+
def __init__(self, precision, scale, types_check=False, **kwargs):
|
|
13
|
+
self.precision = precision
|
|
14
|
+
self.scale = scale
|
|
15
|
+
super(DecimalColumn, self).__init__(**kwargs)
|
|
16
|
+
|
|
17
|
+
if types_check:
|
|
18
|
+
def check_item(value):
|
|
19
|
+
parts = str(value).split('.')
|
|
20
|
+
int_part = parts[0]
|
|
21
|
+
|
|
22
|
+
if len(int_part) > precision:
|
|
23
|
+
raise ColumnTypeMismatchException(value)
|
|
24
|
+
|
|
25
|
+
self.check_item = check_item
|
|
26
|
+
|
|
27
|
+
def after_read_items(self, items, nulls_map=None):
|
|
28
|
+
if self.scale >= 1:
|
|
29
|
+
scale = 10 ** self.scale
|
|
30
|
+
|
|
31
|
+
if nulls_map is None:
|
|
32
|
+
return tuple(Decimal(item) / scale for item in items)
|
|
33
|
+
else:
|
|
34
|
+
return tuple(
|
|
35
|
+
(None if is_null else Decimal(items[i]) / scale)
|
|
36
|
+
for i, is_null in enumerate(nulls_map)
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
if nulls_map is None:
|
|
40
|
+
return tuple(Decimal(item) for item in items)
|
|
41
|
+
else:
|
|
42
|
+
return tuple(
|
|
43
|
+
(None if is_null else Decimal(items[i]))
|
|
44
|
+
for i, is_null in enumerate(nulls_map)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def before_write_items(self, items, nulls_map=None):
|
|
48
|
+
null_value = self.null_value
|
|
49
|
+
|
|
50
|
+
if self.scale >= 1:
|
|
51
|
+
scale = 10 ** self.scale
|
|
52
|
+
|
|
53
|
+
for i, item in enumerate(items):
|
|
54
|
+
if nulls_map and nulls_map[i]:
|
|
55
|
+
items[i] = null_value
|
|
56
|
+
else:
|
|
57
|
+
items[i] = int(Decimal(str(item)) * scale)
|
|
58
|
+
|
|
59
|
+
else:
|
|
60
|
+
for i, item in enumerate(items):
|
|
61
|
+
if nulls_map and nulls_map[i]:
|
|
62
|
+
items[i] = null_value
|
|
63
|
+
else:
|
|
64
|
+
items[i] = int(Decimal(str(item)))
|
|
65
|
+
|
|
66
|
+
# Override default precision to the maximum supported by underlying type.
|
|
67
|
+
def _write_data(self, items, buf):
|
|
68
|
+
with localcontext() as ctx:
|
|
69
|
+
ctx.prec = self.max_precision
|
|
70
|
+
super(DecimalColumn, self)._write_data(items, buf)
|
|
71
|
+
|
|
72
|
+
def _read_data(self, n_items, buf, nulls_map=None):
|
|
73
|
+
with localcontext() as ctx:
|
|
74
|
+
ctx.prec = self.max_precision
|
|
75
|
+
return super(DecimalColumn, self)._read_data(
|
|
76
|
+
n_items, buf, nulls_map=nulls_map
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Decimal32Column(DecimalColumn):
|
|
81
|
+
format = 'i'
|
|
82
|
+
max_precision = 9
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class Decimal64Column(DecimalColumn):
|
|
86
|
+
format = 'q'
|
|
87
|
+
max_precision = 18
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class Decimal128Column(DecimalColumn, Int128Column):
|
|
91
|
+
max_precision = 38
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Decimal256Column(DecimalColumn, Int256Column):
|
|
95
|
+
max_precision = 76
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def create_decimal_column(spec, column_options):
|
|
99
|
+
precision, scale = spec[8:-1].split(',')
|
|
100
|
+
precision, scale = int(precision), int(scale)
|
|
101
|
+
|
|
102
|
+
# Maximum precisions for underlying types are:
|
|
103
|
+
# Int32 10**9
|
|
104
|
+
# Int64 10**18
|
|
105
|
+
# Int128 10**38
|
|
106
|
+
# Int256 10**76
|
|
107
|
+
if precision <= 9:
|
|
108
|
+
cls = Decimal32Column
|
|
109
|
+
elif precision <= 18:
|
|
110
|
+
cls = Decimal64Column
|
|
111
|
+
elif precision <= 38:
|
|
112
|
+
cls = Decimal128Column
|
|
113
|
+
else:
|
|
114
|
+
cls = Decimal256Column
|
|
115
|
+
|
|
116
|
+
return cls(precision, scale, **column_options)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from collections import OrderedDict
|
|
3
|
+
|
|
4
|
+
from .. import errors
|
|
5
|
+
from .intcolumn import IntColumn
|
|
6
|
+
|
|
7
|
+
invalid_names_for_python_enum = frozenset(['mro', ''])
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EnumColumn(IntColumn):
|
|
11
|
+
py_types = (Enum, int, str)
|
|
12
|
+
|
|
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
|
|
16
|
+
super(EnumColumn, self).__init__(**kwargs)
|
|
17
|
+
|
|
18
|
+
def before_write_items(self, items, nulls_map=None):
|
|
19
|
+
null_value = self.null_value
|
|
20
|
+
name_by_value = self.name_by_value
|
|
21
|
+
value_by_name = self.value_by_name
|
|
22
|
+
|
|
23
|
+
for i, item in enumerate(items):
|
|
24
|
+
if nulls_map and nulls_map[i]:
|
|
25
|
+
items[i] = null_value
|
|
26
|
+
continue
|
|
27
|
+
|
|
28
|
+
source_value = item.name if isinstance(item, Enum) else item
|
|
29
|
+
|
|
30
|
+
# Check real enum value
|
|
31
|
+
try:
|
|
32
|
+
if isinstance(source_value, str):
|
|
33
|
+
items[i] = value_by_name[source_value]
|
|
34
|
+
else:
|
|
35
|
+
items[i] = value_by_name[name_by_value[source_value]]
|
|
36
|
+
except (ValueError, KeyError):
|
|
37
|
+
choices = ', '.join(
|
|
38
|
+
"'{}' = {}".format(name.replace("'", r"\'"), value)
|
|
39
|
+
for name, value in value_by_name.items()
|
|
40
|
+
)
|
|
41
|
+
enum_str = '{}({})'.format(self.ch_type, choices)
|
|
42
|
+
|
|
43
|
+
raise errors.LogicalError(
|
|
44
|
+
"Unknown element '{}' for type {}"
|
|
45
|
+
.format(source_value, enum_str)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def after_read_items(self, items, nulls_map=None):
|
|
49
|
+
name_by_value = self.name_by_value
|
|
50
|
+
|
|
51
|
+
if nulls_map is None:
|
|
52
|
+
return tuple(name_by_value[item] for item in items)
|
|
53
|
+
else:
|
|
54
|
+
return tuple(
|
|
55
|
+
(None if is_null else name_by_value[items[i]])
|
|
56
|
+
for i, is_null in enumerate(nulls_map)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Enum8Column(EnumColumn):
|
|
61
|
+
ch_type = 'Enum8'
|
|
62
|
+
format = 'b'
|
|
63
|
+
int_size = 1
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Enum16Column(EnumColumn):
|
|
67
|
+
ch_type = 'Enum16'
|
|
68
|
+
format = 'h'
|
|
69
|
+
int_size = 2
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def create_enum_column(spec, column_options):
|
|
73
|
+
if spec.startswith('Enum8'):
|
|
74
|
+
params = spec[6:-1]
|
|
75
|
+
cls = Enum8Column
|
|
76
|
+
else:
|
|
77
|
+
params = spec[7:-1]
|
|
78
|
+
cls = Enum16Column
|
|
79
|
+
|
|
80
|
+
name_by_value, value_by_name = _parse_options(params)
|
|
81
|
+
|
|
82
|
+
return cls(name_by_value, value_by_name, **column_options)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _parse_options(option_string):
|
|
86
|
+
name_by_value, value_by_name = {}, OrderedDict()
|
|
87
|
+
after_name = False
|
|
88
|
+
escaped = False
|
|
89
|
+
quote_character = None
|
|
90
|
+
name = ''
|
|
91
|
+
value = ''
|
|
92
|
+
|
|
93
|
+
for ch in option_string:
|
|
94
|
+
if escaped:
|
|
95
|
+
name += ch
|
|
96
|
+
escaped = False # accepting escaped character
|
|
97
|
+
|
|
98
|
+
elif after_name:
|
|
99
|
+
if ch in (' ', '='):
|
|
100
|
+
pass
|
|
101
|
+
elif ch == ',':
|
|
102
|
+
value = int(value)
|
|
103
|
+
name_by_value[value] = name
|
|
104
|
+
value_by_name[name] = value
|
|
105
|
+
after_name = False
|
|
106
|
+
name = ''
|
|
107
|
+
value = '' # reset before collecting new option
|
|
108
|
+
else:
|
|
109
|
+
value += ch
|
|
110
|
+
|
|
111
|
+
elif quote_character:
|
|
112
|
+
if ch == '\\':
|
|
113
|
+
escaped = True
|
|
114
|
+
elif ch == quote_character:
|
|
115
|
+
quote_character = None
|
|
116
|
+
after_name = True # start collecting option value
|
|
117
|
+
else:
|
|
118
|
+
name += ch
|
|
119
|
+
|
|
120
|
+
else:
|
|
121
|
+
if ch == "'":
|
|
122
|
+
quote_character = ch
|
|
123
|
+
|
|
124
|
+
if after_name:
|
|
125
|
+
value = int(value)
|
|
126
|
+
name_by_value[value] = name
|
|
127
|
+
value_by_name[name] = value
|
|
128
|
+
|
|
129
|
+
return name_by_value, value_by_name
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from ctypes import c_float
|
|
2
|
+
|
|
3
|
+
from .base import FormatColumn
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FloatColumn(FormatColumn):
|
|
7
|
+
py_types = (float, int)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Float32Column(FloatColumn):
|
|
11
|
+
ch_type = 'Float32'
|
|
12
|
+
format = 'f'
|
|
13
|
+
|
|
14
|
+
def __init__(self, types_check=False, **kwargs):
|
|
15
|
+
super(Float32Column, self).__init__(types_check=types_check, **kwargs)
|
|
16
|
+
|
|
17
|
+
if types_check:
|
|
18
|
+
# Chop only bytes that fit current type.
|
|
19
|
+
# Cast to -nan or nan if overflows.
|
|
20
|
+
def before_write_items(items, nulls_map=None):
|
|
21
|
+
null_value = self.null_value
|
|
22
|
+
|
|
23
|
+
for i, item in enumerate(items):
|
|
24
|
+
if nulls_map and nulls_map[i]:
|
|
25
|
+
items[i] = null_value
|
|
26
|
+
else:
|
|
27
|
+
items[i] = c_float(item).value
|
|
28
|
+
|
|
29
|
+
self.before_write_items = before_write_items
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Float64Column(FloatColumn):
|
|
33
|
+
ch_type = 'Float64'
|
|
34
|
+
format = 'd'
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
|
|
2
|
+
from .exceptions import ColumnTypeMismatchException
|
|
3
|
+
from .base import FormatColumn
|
|
4
|
+
from .largeint import (
|
|
5
|
+
int128_from_quads, int128_to_quads, uint128_from_quads, uint128_to_quads,
|
|
6
|
+
int256_from_quads, int256_to_quads, uint256_from_quads, uint256_to_quads
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class IntColumn(FormatColumn):
|
|
11
|
+
py_types = (int, )
|
|
12
|
+
int_size = None
|
|
13
|
+
|
|
14
|
+
def __init__(self, types_check=False, **kwargs):
|
|
15
|
+
super(IntColumn, self).__init__(types_check=types_check, **kwargs)
|
|
16
|
+
|
|
17
|
+
if types_check:
|
|
18
|
+
self.mask = (1 << 8 * self.int_size) - 1
|
|
19
|
+
|
|
20
|
+
# Chop only bytes that fit current type.
|
|
21
|
+
# ctypes.c_intXX is slower.
|
|
22
|
+
def before_write_items(items, nulls_map=None):
|
|
23
|
+
# TODO: cythonize
|
|
24
|
+
null_value = self.null_value
|
|
25
|
+
|
|
26
|
+
for i, item in enumerate(items):
|
|
27
|
+
if nulls_map and nulls_map[i]:
|
|
28
|
+
items[i] = null_value
|
|
29
|
+
continue
|
|
30
|
+
|
|
31
|
+
if item >= 0:
|
|
32
|
+
sign = 1
|
|
33
|
+
else:
|
|
34
|
+
sign = -1
|
|
35
|
+
item = -item
|
|
36
|
+
|
|
37
|
+
items[i] = sign * (item & self.mask)
|
|
38
|
+
|
|
39
|
+
self.before_write_items = before_write_items
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class UIntColumn(IntColumn):
|
|
43
|
+
def __init__(self, types_check=False, **kwargs):
|
|
44
|
+
super(UIntColumn, self).__init__(types_check=types_check, **kwargs)
|
|
45
|
+
|
|
46
|
+
if types_check:
|
|
47
|
+
def check_item(value):
|
|
48
|
+
if value < 0:
|
|
49
|
+
raise ColumnTypeMismatchException(value)
|
|
50
|
+
|
|
51
|
+
self.check_item = check_item
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class Int8Column(IntColumn):
|
|
55
|
+
ch_type = 'Int8'
|
|
56
|
+
format = 'b'
|
|
57
|
+
int_size = 1
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Int16Column(IntColumn):
|
|
61
|
+
ch_type = 'Int16'
|
|
62
|
+
format = 'h'
|
|
63
|
+
int_size = 2
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Int32Column(IntColumn):
|
|
67
|
+
ch_type = 'Int32'
|
|
68
|
+
format = 'i'
|
|
69
|
+
int_size = 4
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Int64Column(IntColumn):
|
|
73
|
+
ch_type = 'Int64'
|
|
74
|
+
format = 'q'
|
|
75
|
+
int_size = 8
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class UInt8Column(UIntColumn):
|
|
79
|
+
ch_type = 'UInt8'
|
|
80
|
+
format = 'B'
|
|
81
|
+
int_size = 1
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class UInt16Column(UIntColumn):
|
|
85
|
+
ch_type = 'UInt16'
|
|
86
|
+
format = 'H'
|
|
87
|
+
int_size = 2
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class UInt32Column(UIntColumn):
|
|
91
|
+
ch_type = 'UInt32'
|
|
92
|
+
format = 'I'
|
|
93
|
+
int_size = 4
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class UInt64Column(UIntColumn):
|
|
97
|
+
ch_type = 'UInt64'
|
|
98
|
+
format = 'Q'
|
|
99
|
+
int_size = 8
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class LargeIntColumn(IntColumn):
|
|
103
|
+
format = 'Q' # We manually deal with sign in read/write.
|
|
104
|
+
factor = None
|
|
105
|
+
|
|
106
|
+
to_quads = None
|
|
107
|
+
from_quads = None
|
|
108
|
+
|
|
109
|
+
def write_items(self, items, buf):
|
|
110
|
+
n_items = len(items)
|
|
111
|
+
|
|
112
|
+
s = self.make_struct(self.factor * n_items)
|
|
113
|
+
uint_64_pairs = self.to_quads(items, n_items)
|
|
114
|
+
|
|
115
|
+
buf.write(s.pack(*uint_64_pairs))
|
|
116
|
+
|
|
117
|
+
def read_items(self, n_items, buf):
|
|
118
|
+
s = self.make_struct(self.factor * n_items)
|
|
119
|
+
items = s.unpack(buf.read(s.size))
|
|
120
|
+
|
|
121
|
+
return self.from_quads(items, n_items)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class Int128Column(LargeIntColumn):
|
|
125
|
+
ch_type = 'Int128'
|
|
126
|
+
int_size = 16
|
|
127
|
+
factor = 2
|
|
128
|
+
|
|
129
|
+
to_quads = int128_to_quads
|
|
130
|
+
from_quads = int128_from_quads
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class UInt128Column(LargeIntColumn):
|
|
134
|
+
ch_type = 'UInt128'
|
|
135
|
+
int_size = 16
|
|
136
|
+
factor = 2
|
|
137
|
+
|
|
138
|
+
to_quads = uint128_to_quads
|
|
139
|
+
from_quads = uint128_from_quads
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class Int256Column(LargeIntColumn):
|
|
143
|
+
ch_type = 'Int256'
|
|
144
|
+
int_size = 32
|
|
145
|
+
factor = 4
|
|
146
|
+
|
|
147
|
+
to_quads = int256_to_quads
|
|
148
|
+
from_quads = int256_from_quads
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class UInt256Column(LargeIntColumn):
|
|
152
|
+
ch_type = 'UInt256'
|
|
153
|
+
int_size = 32
|
|
154
|
+
factor = 4
|
|
155
|
+
|
|
156
|
+
to_quads = uint256_to_quads
|
|
157
|
+
from_quads = uint256_from_quads
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from .intcolumn import Int64Column
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class IntervalColumn(Int64Column):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class IntervalDayColumn(IntervalColumn):
|
|
9
|
+
ch_type = 'IntervalDay'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class IntervalWeekColumn(IntervalColumn):
|
|
13
|
+
ch_type = 'IntervalWeek'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class IntervalMonthColumn(IntervalColumn):
|
|
17
|
+
ch_type = 'IntervalMonth'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class IntervalYearColumn(IntervalColumn):
|
|
21
|
+
ch_type = 'IntervalYear'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class IntervalHourColumn(IntervalColumn):
|
|
25
|
+
ch_type = 'IntervalHour'
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class IntervalMinuteColumn(IntervalColumn):
|
|
29
|
+
ch_type = 'IntervalMinute'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class IntervalSecondColumn(IntervalColumn):
|
|
33
|
+
ch_type = 'IntervalSecond'
|