ClickHouse / clickhouse-odbc

ODBC driver for ClickHouse
https://clickhouse.tech
Apache License 2.0
239 stars 84 forks source link

segmentation fault (core dumped) when exception happend in SQLExecute #427

Open tianbeierlu opened 11 months ago

tianbeierlu commented 11 months ago

replay method

table struct:

CREATE TABLE t1
    (
        `id` Int64,
        `It8` Nullable(Decimal32(8)),
        `It32` Nullable(Decimal64(10)),
        `c1` Nullable(Int64),
        `c2` Nullable(Int64),
    )
ENGINE = MergeTree
ORDER BY id
SETTINGS index_granularity = 8192;

3 rows to been inserted:

insert into t1
values
    (
        3,
        -8.8888888,
        -0.983748393,
        30000,
        10000
);
insert into t1
values
    (
        2,
        1.93098888,
        10.98374,
        100,
        200
);
insert into t1
values
    (
        4,
        1,
        0,
        1,
        0
);

using isql to execute the sql: select c1%c2 from t1; than isql will hang and than crush:

➜  luban isql clickhouse_mysqltest default -v
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| echo [string]                         |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> select c1%c2 from t1;
+---------------------+
| modulo(c1, c2)      |
+---------------------+
[S1000]Incomplete input stream, expected at least 1701080899 more bytes
+---------------------+
SQLRowCount returns 0
[1]    38008 segmentation fault (core dumped)  isql clickhouse_mysqltest default -v

The reason for analyzing the problem

this is because, in sqlprepare, clickhouse server use the first row to check this sql, the first row have no exception, so it can been executed, but when it execute to row with id=4, 1%0 raise the zero divide exception, then server append the exception message to the previous rows's meta-data, and odbc SQLFetch the result as normal, not the exception, so the protocol between odbc and server is not Matched.

The letter corresponding to the number 1701080899 is ‘C’, ‘o’, ‘d’, and ‘e’., it is the prefix of exception message:

Code: 407. DB::Exception: Decimal math overflow: while executing 'FUNCTION multiply(It8 :: 0, It32 :: 1) -> multiply(It8, It32) Nullable(Decimal(18, 18)) : 2'. (DECIMAL_OVERFLOW) (version 23.7.5.1)

because protocol is not matched, so odbc read 4 bytes for protocol head, it read the "Code", Therefore, ODBC believes that it still needs 1701080899 bytes of data.

modify suggestion:

AmortizedIStreamReader::read,it should process the situation of message package is exception, but not the normal length.