Description
When using server_side_params=True, the @maybe_enquote_for_server decorator in clickhouse_driver/util/escape.py incorrectly wraps arrays and tuples in quotes, converting them to strings that ClickHouse cannot parse.
Reproduction
from clickhouse_driver import Client
client = Client('localhost')
# This fails with: Cannot parse input: expected ']' at end of stream
client.execute(
"SELECT {arr:Array(String)}",
{'arr': ['a', 'b', 'c']},
settings={'server_side_params': True}
)
Error:
clickhouse_driver.errors.ServerException: Code: 27.
DB::Exception: Cannot parse input: expected ']' at end of stream:
value [ cannot be parsed as Array(String) for query parameter 'arr'
Root Cause
In escape_param(), the function correctly formats arrays as ['a','b','c'], but then the @maybe_enquote_for_server decorator sees it doesn't start with a quote and wraps the entire thing: "['a','b','c']" - turning it into a string instead of an array.
The decorator applies to ALL return values, but arrays/tuples already have their own delimiters ([...] and (...)) and should not be quoted.
Current code in clickhouse_driver/util/escape.py:
def maybe_enquote_for_server(f):
@wraps(f)
def wrapper(*args, **kwargs):
rv = f(*args, **kwargs)
if kwargs.get('for_server'):
is_str = isinstance(rv, str)
if not is_str or (is_str and not rv.startswith("'")):
rv = "'%s'" % rv # <-- This quotes arrays too!
return rv
return wrapper
Proposed Fix
The decorator should only quote scalar types, not collections:
def maybe_enquote_for_server(f):
@wraps(f)
def wrapper(item, *args, **kwargs):
rv = f(item, *args, **kwargs)
# Only quote non-collection types - arrays/tuples have their own delimiters
if kwargs.get('for_server') and not isinstance(item, (list, tuple)):
is_str = isinstance(rv, str)
if not is_str or (is_str and not rv.startswith("'")):
rv = "'%s'" % rv
return rv
return wrapper
Impact
This bug affects any use of server_side_params=True with:
Array(T) parameters
Tuple(...) parameters
Array(Tuple(...)) parameters
These are common patterns in real-world ClickHouse queries.
Environment
- clickhouse-driver: 0.2.10
- Python: 3.12
- ClickHouse server: 24.x
Workaround
We're currently working around this with a monkeypatch that reimplements the decorator logic correctly.
Description
When using
server_side_params=True, the@maybe_enquote_for_serverdecorator inclickhouse_driver/util/escape.pyincorrectly wraps arrays and tuples in quotes, converting them to strings that ClickHouse cannot parse.Reproduction
Error:
Root Cause
In
escape_param(), the function correctly formats arrays as['a','b','c'], but then the@maybe_enquote_for_serverdecorator sees it doesn't start with a quote and wraps the entire thing:"['a','b','c']"- turning it into a string instead of an array.The decorator applies to ALL return values, but arrays/tuples already have their own delimiters (
[...]and(...)) and should not be quoted.Current code in
clickhouse_driver/util/escape.py:Proposed Fix
The decorator should only quote scalar types, not collections:
Impact
This bug affects any use of
server_side_params=Truewith:Array(T)parametersTuple(...)parametersArray(Tuple(...))parametersThese are common patterns in real-world ClickHouse queries.
Environment
Workaround
We're currently working around this with a monkeypatch that reimplements the decorator logic correctly.