Skip to content

Issue inserting and fetching tuple array with certain string format #123

@akira

Description

@akira

There's an issue when inserting and trying to fetch a tuple array with certain string formatting - in this case parens:

[("key1", "value1"), ("key2", "this is an invalid pair(with some parens) and this, let's see if it works")]

When it is fetched, it comes back as:

[('key1', 'value1'), ('key2', "'this is an invalid pair(with some parens) and thi"), ("let's see if it works'",)]

Which is not a valid tuple - this cannot be reinserted to Clickhouse.

See code below, this is the entire result fetched:

[{'a': [('key1', 'value1'), ('key2', "'this is an invalid pair(with some parens) and thi"), ("let's see if it works'",)]}, {'a': [('key3', 'value3'), ('key4', 'value4')]}, {'a': [('key5', 'value5'), ('key6', 'value6')]}, {'a': [('key7', 'value7'), ('key8', 'value8')]}, {'a': [('key11', ''), ('key12', "''")]}, {'a': [('key9', 'value9'), ('key10', 'value10')]}]

If trying to reinsert this record as is, we get the error:

aiochclient.exceptions.ChClientError: Code: 386. DB::Exception: There is no supertype for types Tuple(String, String), Tuple(String, String), String because some of them are Tuple and some of them are not: While processing [('key1', 'value1'), ('key2', '\'this is an invalid pair(with some parens) and thi'), 'let\'s see if it works\'']: While executing ValuesBlockInputFormat. (NO_COMMON_TYPE) (version 24.2.3.70 (official build))

But it works without the line including the parens.

import asyncio

from aiohttp import ClientSession

from aiochclient import ChClient


async def some_query(client: ChClient, a: list[tuple[str,str]]):
    result = await client.execute(
        "INSERT INTO t VALUES", [a]
    )


async def main():
    async with ClientSession() as s:
        client = ChClient(s, url="http://localhost:8123")
        # preparing database        
        await client.execute("DROP TABLE IF EXISTS t")
        await client.execute("CREATE TABLE IF NOT EXISTS t (a  Array(Tuple(String, String))) ENGINE = Memory")        
        # making queries in parallel
        await asyncio.gather(
            some_query(client, [("key1", "value1"), ("key2", "this is an invalid pair(with some parens) and this, let's see if it works")]),
            some_query(client, [("key3", "value3"), ("key4", "value4")]),
            some_query(client, [("key11", ""), ("key12", "''")]),
        )
        print("Fetch results:")
        results = await client.fetch("SELECT * FROM t")
        print([{**r} for r in results])
        for result in results:
            await client.execute("INSERT INTO t VALUES", [result['a']])


if __name__ == "__main__":
    # if >=3.7:
    asyncio.run(main())

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions