Merge pull request #65738 from RodolpheDuge/fix_odbc_nullable_fields

fix ODBC table with nullable fields
This commit is contained in:
Kseniia Sumarokova 2024-07-03 09:43:47 +00:00 committed by GitHub
commit dd9bf6d792
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 66 additions and 2 deletions

View File

@ -3,6 +3,7 @@
#include <IO/ReadBufferFromString.h>
#include <DataTypes/DataTypeNullable.h>
#include <DataTypes/DataTypeDateTime64.h>
#include <Columns/ColumnNullable.h>
#include <Common/assert_cast.h>
#include <IO/ReadHelpers.h>
@ -47,9 +48,17 @@ Chunk ODBCSource::generate()
for (int idx = 0; idx < result.columns(); ++idx)
{
const auto & sample = description.sample_block.getByPosition(idx);
if (!result.is_null(idx))
insertValue(*columns[idx], removeNullable(sample.type), description.types[idx].first, result, idx);
{
if (columns[idx]->isNullable())
{
ColumnNullable & column_nullable = assert_cast<ColumnNullable &>(*columns[idx]);
insertValue(column_nullable.getNestedColumn(), removeNullable(sample.type), description.types[idx].first, result, idx);
column_nullable.getNullMapData().emplace_back(0);
}
else
insertValue(*columns[idx], removeNullable(sample.type), description.types[idx].first, result, idx);
}
else
insertDefaultValue(*columns[idx], *sample.column);
}

View File

@ -40,6 +40,16 @@ create_table_sql_template = """
PRIMARY KEY (`id`)) ENGINE=InnoDB;
"""
create_table_sql_nullable_template = """
CREATE TABLE `clickhouse`.`{}` (
`id` integer not null,
`col1` integer,
`col2` decimal(15,10),
`col3` varchar(32),
`col4` datetime
)
"""
def skip_test_msan(instance):
if instance.is_built_with_memory_sanitizer():
@ -77,6 +87,11 @@ def create_mysql_db(conn, name):
cursor.execute("CREATE DATABASE {} DEFAULT CHARACTER SET 'utf8'".format(name))
def create_mysql_nullable_table(conn, table_name):
with conn.cursor() as cursor:
cursor.execute(create_table_sql_nullable_template.format(table_name))
def create_mysql_table(conn, table_name):
with conn.cursor() as cursor:
cursor.execute(create_table_sql_template.format(table_name))
@ -192,6 +207,46 @@ def started_cluster():
cluster.shutdown()
def test_mysql_odbc_select_nullable(started_cluster):
skip_test_msan(node1)
mysql_setup = node1.odbc_drivers["MySQL"]
table_name = "test_insert_nullable_select"
conn = get_mysql_conn()
create_mysql_nullable_table(conn, table_name)
with conn.cursor() as cursor:
cursor.execute(
"INSERT INTO clickhouse.{} VALUES(1, 1, 1.23456, 'data1', '2010-01-01 00:00:00');".format(
table_name
)
)
cursor.execute(
"INSERT INTO clickhouse.{} VALUES(2, NULL, NULL, NULL, NULL);".format(
table_name
)
)
conn.commit()
node1.query(
"""
CREATE TABLE {}(id UInt32, col1 Nullable(UInt32), col2 Nullable(Decimal(15, 10)), col3 Nullable(String), col4 Nullable(DateTime)) ENGINE = ODBC('DSN={}', 'clickhouse', '{}');
""".format(
table_name, mysql_setup["DSN"], table_name
)
)
assert (
node1.query(
"SELECT id, col1, col2, col3, col4 from {} order by id asc".format(
table_name
)
)
== "1\t1\t1.23456\tdata1\t2010-01-01 00:00:00\n2\t\\N\t\\N\t\\N\t\\N\n"
)
drop_mysql_table(conn, table_name)
conn.close()
def test_mysql_simple_select_works(started_cluster):
skip_test_msan(node1)