clickhouse-driver icon indicating copy to clipboard operation
clickhouse-driver copied to clipboard

bug with array query params

Open zerlok opened this issue 1 year ago • 0 comments

Describe the bug

can't pass array parameters to clickhouse driver ordinary statements

To Reproduce

Setup

# setup client, connect to CH
client = Client(...)

# create  users table
client.execute("""
CREATE TABLE IF NOT EXISTS users (
    `id` Int32,
    `name` String
) ENGINE = MergeTree()
	PRIMARY KEY (id)
""")

# insert users test data
client.execute(
   query="""INSERT INTO users (`id`, `name`) VALUES""",
   params=[
      {'id': 0, 'name': 'user-name-000'},
      {'id': 1, 'name': 'user-name-001'},
      {'id': 2, 'name': 'user-name-002'},
      {'id': 3, 'name': 'user-name-003'},
   ],
)

Then execute a valid CH SQL with parameters:

SELECT * FROM users WHERE id IN {ids:Array(Int32)} ORDER BY id
print(client.execute(
   query="""SELECT * FROM users WHERE id IN {ids:Array(Int32)} ORDER BY id""",
   params={"ids": [2, 3]},
))

Throws the exception:

DB::ParsingException: Cannot parse input: expected ']' at end of stream.: value [ cannot be parsed as Array(Int32) for query parameter 'ids'

Traceback (without private files):

.venv/lib/python3.9/site-packages/clickhouse_driver/client.py:373: in execute
    rv = self.process_ordinary_query(
.venv/lib/python3.9/site-packages/clickhouse_driver/client.py:571: in process_ordinary_query
    return self.receive_result(with_column_types=with_column_types,
.venv/lib/python3.9/site-packages/clickhouse_driver/client.py:204: in receive_result
    return result.get_result()
.venv/lib/python3.9/site-packages/clickhouse_driver/result.py:50: in get_result
    for packet in self.packet_generator:
.venv/lib/python3.9/site-packages/clickhouse_driver/client.py:220: in packet_generator
    packet = self.receive_packet()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <clickhouse_driver.client.Client object at 0x7f3511d1b970>

    def receive_packet(self):
        packet = self.connection.receive_packet()
    
        if packet.type == ServerPacketTypes.EXCEPTION:
>           raise packet.exception
E           clickhouse_driver.errors.ServerException: Code: 27.
E           DB::ParsingException. DB::ParsingException: Cannot parse input: expected ']' at end of stream.: value [ cannot be parsed as Array(Int32) for query parameter 'ids'. Stack trace:
E           
E           0. DB::Exception::Exception(DB::Exception::MessageMasked&&, int, bool) @ 0xe3b7135 in /usr/bin/clickhouse
E           1. ? @ 0xe416ae4 in /usr/bin/clickhouse
E           2. DB::throwAtAssertionFailed(char const*, DB::ReadBuffer&) @ 0xe4169e1 in /usr/bin/clickhouse
E           3. DB::SerializationArray::deserializeText(DB::IColumn&, DB::ReadBuffer&, DB::FormatSettings const&, bool) const @ 0x12dee6b8 in /usr/bin/clickhouse
E           4. DB::ReplaceQueryParameterVisitor::visitQueryParameter(std::shared_ptr<DB::IAST>&) @ 0x13eea1db in /usr/bin/clickhouse
E           5. DB::ReplaceQueryParameterVisitor::visitChildren(std::shared_ptr<DB::IAST>&) @ 0x13eed8f8 in /usr/bin/clickhouse
E           6. DB::ReplaceQueryParameterVisitor::visitChildren(std::shared_ptr<DB::IAST>&) @ 0x13eed8f8 in /usr/bin/clickhouse
E           7. DB::ReplaceQueryParameterVisitor::visitChildren(std::shared_ptr<DB::IAST>&) @ 0x13eed8f8 in /usr/bin/clickhouse
E           8. DB::ReplaceQueryParameterVisitor::visitChildren(std::shared_ptr<DB::IAST>&) @ 0x13eed8f8 in /usr/bin/clickhouse
E           9. DB::ReplaceQueryParameterVisitor::visitChildren(std::shared_ptr<DB::IAST>&) @ 0x13eed8f8 in /usr/bin/clickhouse
E           10. ? @ 0x13efc3e6 in /usr/bin/clickhouse
E           11. DB::executeQuery(String const&, std::shared_ptr<DB::Context>, bool, DB::QueryProcessingStage::Enum) @ 0x13efbc4d in /usr/bin/clickhouse
E           12. DB::TCPHandler::runImpl() @ 0x14cd2771 in /usr/bin/clickhouse
E           13. DB::TCPHandler::run() @ 0x14ce8279 in /usr/bin/clickhouse
E           14. Poco::Net::TCPServerConnection::start() @ 0x17c5ac34 in /usr/bin/clickhouse
E           15. Poco::Net::TCPServerDispatcher::run() @ 0x17c5be5b in /usr/bin/clickhouse
E           16. Poco::PooledThread::run() @ 0x17dd9207 in /usr/bin/clickhouse
E           17. Poco::ThreadImpl::runnableEntry(void*) @ 0x17dd6c3d in /usr/bin/clickhouse
E           18. ? @ 0x7f0cde78a609 in ?
E           19. __clone @ 0x7f0cde6af133 in ?

.venv/lib/python3.9/site-packages/clickhouse_driver/client.py:237: ServerException

Expected behavior

According to clickhouse doc, passed ids value should be casted to Array(Int32) on server side and query should be executed successfully with the following console output:

[(2, "user-name-002"), (3, "user-name-003")]

Versions

  • python: 3.9
  • clickhouse-driver version: 0.2.6
  • clickhouse server version (docker image): clickhouse/clickhouse-server:23.4.3.48-alpine

Notes

Simple int param works perfectly:

SELECT * FROM users WHERE id = {id:Int32}
print(client.execute("""SELECT * FROM users WHERE id = {id:Int32}""", params={'id': 7}"""))

Returns

[(7, "user-name-007")]

UPD: just found that clickhouse driver connection class performs parameter escaping and results in the following (added print statement between 708 and 709 lines this module

params={'ids': [2, 3]}; escaped={'ids': "'['2', '3']'"}

I guess the valid escaped value should be

params={'ids': [2, 3]}; escaped={'ids': "[2, 3]"}

zerlok avatar Feb 26 '24 18:02 zerlok