diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2023-11-22 10:17:54 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2023-11-22 11:04:40 +0300 |
commit | c08cc1568cdccb1ee2404517a809c31b8601b5ac (patch) | |
tree | 73d1497b32a99a4574ff416a603fa9189df21509 | |
parent | c0ddd9a7b0bb0ab089b2483361389833efefa60c (diff) | |
download | ydb-c08cc1568cdccb1ee2404517a809c31b8601b5ac.tar.gz |
Update contrib/python/clickhouse-connect to 0.6.19
11 files changed, 73 insertions, 62 deletions
diff --git a/contrib/python/clickhouse-connect/.dist-info/METADATA b/contrib/python/clickhouse-connect/.dist-info/METADATA index b078aa4b26..e7582522da 100644 --- a/contrib/python/clickhouse-connect/.dist-info/METADATA +++ b/contrib/python/clickhouse-connect/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: clickhouse-connect -Version: 0.6.18 +Version: 0.6.19 Summary: ClickHouse Database Core Driver for Python, Pandas, and Superset Home-page: https://github.com/ClickHouse/clickhouse-connect Author: ClickHouse Inc. diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py b/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py index 15ce74c8e3..3b0f77b522 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/__version__.py @@ -1 +1 @@ -version = '0.6.18' +version = '0.6.19' diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py index 5eb1ed0113..6b04c7e2fe 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/cc_sqlalchemy/dialect.py @@ -22,6 +22,7 @@ class ClickHouseDialect(DefaultDialect): default_schema_name = 'default' supports_native_decimal = True supports_native_boolean = True + supports_statement_cache = False returns_unicode_strings = True postfetch_lastrowid = False ddl_compiler = ChDDLCompiler diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py index 0281867b8d..36e4c23780 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/container.py @@ -3,7 +3,7 @@ import logging from typing import Sequence, Collection from clickhouse_connect.driver.insert import InsertContext -from clickhouse_connect.driver.query import QueryContext +from clickhouse_connect.driver.query import QueryContext, quote_identifier from clickhouse_connect.driver.types import ByteSource from clickhouse_connect.json_impl import any_to_json from clickhouse_connect.datatypes.base import ClickHouseType, TypeDef @@ -94,7 +94,7 @@ class Tuple(ClickHouseType): self.element_names = type_def.keys self.element_types = [get_from_name(name) for name in type_def.values] if self.element_names: - self._name_suffix = f"({', '.join(k + ' ' + str(v) for k, v in zip(type_def.keys, type_def.values))})" + self._name_suffix = f"({', '.join(quote_identifier(k) + ' ' + str(v) for k, v in zip(type_def.keys, type_def.values))})" else: self._name_suffix = type_def.arg_str diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py index 7f6b7a5a77..0b5a81cbcb 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/datatypes/string.py @@ -45,9 +45,9 @@ class String(ClickHouseType): # pylint: disable=duplicate-code,too-many-nested-blocks,too-many-branches def _write_column_binary(self, column: Union[Sequence, MutableSequence], dest: bytearray, ctx: InsertContext): encoding = None - if isinstance(self._first_value(column), str): + if not isinstance(self._first_value(column), bytes): encoding = ctx.encoding or self.encoding - data_conv.write_str_col(column, encoding, dest) + data_conv.write_str_col(column, self.nullable, encoding, dest) def _active_null(self, ctx): if ctx.use_none: diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/dataconv.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/dataconv.py index 29c96a9a66..2427272572 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/dataconv.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/dataconv.py @@ -5,6 +5,7 @@ from typing import Sequence, Optional, Any from uuid import UUID, SafeUUID from clickhouse_connect.driver.common import int_size +from clickhouse_connect.driver.exceptions import DataError from clickhouse_connect.driver.types import ByteSource from clickhouse_connect.driver.options import np @@ -110,14 +111,18 @@ def pivot(data: Sequence[Sequence], start_row: int, end_row: int) -> Sequence[Se return tuple(zip(*data[start_row: end_row])) -def write_str_col(column: Sequence, encoding: Optional[str], dest: bytearray): +def write_str_col(column: Sequence, nullable: bool, encoding: Optional[str], dest: bytearray): app = dest.append for x in column: if not x: + if not nullable and x is None: + raise DataError('Invalid None value in non-Nullable column') app(0) else: if encoding: x = x.encode(encoding) + else: + x = b'' sz = len(x) while True: b = sz & 0x7f diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py index a158e7f999..acdf9510e0 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/parser.py @@ -130,13 +130,13 @@ def parse_columns(expr: str): named = False level = 0 label = '' - in_str = False + quote = None while True: char = expr[pos] pos += 1 - if in_str: - if "'" == char: - in_str = False + if quote: + if char == quote: + quote = None elif char == '\\' and expr[pos] == "'" and expr[pos:pos + 4] != "' = " and expr[pos:pos + 2] != "')": label += expr[pos] pos += 1 @@ -156,8 +156,8 @@ def parse_columns(expr: str): elif char == ')': columns.append(label) break - if char == "'" and (not label or 'Enum' in label): - in_str = True + if char in ("'", '`') and (not label or 'Enum' in label): + quote = char elif char == '(': level += 1 elif char == ')': diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py b/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py index 0b5086ae11..c4a48aafe0 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/driver/query.py @@ -341,7 +341,7 @@ class QueryResult(Closable): BS = '\\' -must_escape = (BS, '\'') +must_escape = (BS, '\'', '`') def quote_identifier(identifier: str): @@ -349,7 +349,7 @@ def quote_identifier(identifier: str): if first_char in ('`', '"') and identifier[-1] == first_char: # Identifier is already quoted, assume that it's valid return identifier - return f'`{identifier}`' + return f'`{escape_str(identifier)}`' def finalize_query(query: str, parameters: Optional[Union[Sequence, Dict[str, Any]]], diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/driverc/dataconv.pyx b/contrib/python/clickhouse-connect/clickhouse_connect/driverc/dataconv.pyx index dab9114155..0c9bbc19ae 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/driverc/dataconv.pyx +++ b/contrib/python/clickhouse-connect/clickhouse_connect/driverc/dataconv.pyx @@ -19,6 +19,7 @@ from uuid import UUID, SafeUUID from libc.string cimport memcpy from datetime import tzinfo +from clickhouse_connect.driver.exceptions import DataError @cython.boundscheck(False) @cython.wraparound(False) @@ -254,7 +255,7 @@ cdef inline extend_byte_array(target: bytearray, int start, object source, Py_ss @cython.boundscheck(False) @cython.wraparound(False) -def write_str_col(column: Sequence, encoding: Optional[str], dest: bytearray): +def write_str_col(column: Sequence, nullable: bool, encoding: Optional[str], dest: bytearray): cdef unsigned long long buff_size = len(column) << 5 cdef unsigned long long buff_loc = 0, sz = 0, dsz = 0 cdef unsigned long long array_size = PyByteArray_GET_SIZE(dest) @@ -263,50 +264,54 @@ def write_str_col(column: Sequence, encoding: Optional[str], dest: bytearray): cdef object encoded cdef char b cdef char * data - for x in column: - if not x: - temp_buff[buff_loc] = 0 - buff_loc += 1 - if buff_loc == buff_size: - extend_byte_array(dest, array_size, mv, buff_loc) - array_size += buff_loc - buff_loc = 0 - else: - if not encoding: - data = x - dsz = len(x) - else: - encoded = x.encode(encoding) - dsz = len(encoded) - data = encoded - sz = dsz - while True: - b = sz & 0x7f - sz >>= 7 - if sz != 0: - b |= 0x80 - temp_buff[buff_loc] = b + try: + for x in column: + if not x: + if not nullable and x is None: + raise DataError('Invalid None value in non-Nullable column') + temp_buff[buff_loc] = 0 buff_loc += 1 if buff_loc == buff_size: extend_byte_array(dest, array_size, mv, buff_loc) array_size += buff_loc buff_loc = 0 - if sz == 0: - break - if dsz + buff_loc >= buff_size: - if buff_loc > 0: # Write what we have so far - extend_byte_array(dest, array_size, mv, buff_loc) - array_size += buff_loc - buff_loc = 0 - if (dsz << 4) > buff_size: # resize our buffer for very large strings - PyMem_Free(<void *> temp_buff) - mv.release() - buff_size = dsz << 6 - temp_buff = <char *> PyMem_Malloc(<size_t> buff_size) - mv = PyMemoryView_FromMemory(temp_buff, buff_size, PyBUF_READ) - memcpy(temp_buff + buff_loc, data, dsz) - buff_loc += dsz - if buff_loc > 0: - extend_byte_array(dest, array_size, mv, buff_loc) - mv.release() - PyMem_Free(<void *>temp_buff) + else: + if not encoding: + data = x + dsz = len(x) + else: + encoded = x.encode(encoding) + dsz = len(encoded) + data = encoded + sz = dsz + while True: + b = sz & 0x7f + sz >>= 7 + if sz != 0: + b |= 0x80 + temp_buff[buff_loc] = b + buff_loc += 1 + if buff_loc == buff_size: + extend_byte_array(dest, array_size, mv, buff_loc) + array_size += buff_loc + buff_loc = 0 + if sz == 0: + break + if dsz + buff_loc >= buff_size: + if buff_loc > 0: # Write what we have so far + extend_byte_array(dest, array_size, mv, buff_loc) + array_size += buff_loc + buff_loc = 0 + if (dsz << 4) > buff_size: # resize our buffer for very large strings + PyMem_Free(<void *> temp_buff) + mv.release() + buff_size = dsz << 6 + temp_buff = <char *> PyMem_Malloc(<size_t> buff_size) + mv = PyMemoryView_FromMemory(temp_buff, buff_size, PyBUF_READ) + memcpy(temp_buff + buff_loc, data, dsz) + buff_loc += dsz + if buff_loc > 0: + extend_byte_array(dest, array_size, mv, buff_loc) + finally: + mv.release() + PyMem_Free(<void *>temp_buff) diff --git a/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py b/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py index f30b3f754a..4351709610 100644 --- a/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py +++ b/contrib/python/clickhouse-connect/clickhouse_connect/tools/testing.py @@ -1,7 +1,7 @@ from typing import Sequence, Optional, Union, Dict, Any from clickhouse_connect.driver import Client -from clickhouse_connect.driver.query import format_query_value +from clickhouse_connect.driver.query import format_query_value, quote_identifier class TableContext: @@ -29,14 +29,14 @@ class TableContext: self.column_names = columns self.column_types = column_types self.engine = engine - self.order_by = self.column_names[0] if order_by is None else order_by + self.order_by = quote_identifier(self.column_names[0]) if order_by is None else order_by def __enter__(self): if self.client.min_version('19'): self.client.command(f'DROP TABLE IF EXISTS {self.table}') else: self.client.command(f'DROP TABLE IF EXISTS {self.table} SYNC') - col_defs = ','.join(f'{name} {col_type}' for name, col_type in zip(self.column_names, self.column_types)) + col_defs = ','.join(f'{quote_identifier(name)} {col_type}' for name, col_type in zip(self.column_names, self.column_types)) create_cmd = f'CREATE TABLE {self.table} ({col_defs}) ENGINE {self.engine} ORDER BY {self.order_by}' if self.settings: create_cmd += ' SETTINGS ' diff --git a/contrib/python/clickhouse-connect/ya.make b/contrib/python/clickhouse-connect/ya.make index db1563c6b8..b398d299cf 100644 --- a/contrib/python/clickhouse-connect/ya.make +++ b/contrib/python/clickhouse-connect/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(0.6.18) +VERSION(0.6.19) LICENSE(Apache-2.0) |