mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-27 18:12:02 +00:00
Merge pull request #55427 from slvrtrn/mysql-boolean-format-fix
Fix MySQL interface boolean representation
This commit is contained in:
commit
24fecaeb7d
@ -50,10 +50,7 @@ ResultSetRow::ResultSetRow(const Serializations & serializations_, const DataTyp
|
||||
payload_size += 1;
|
||||
break;
|
||||
case TypeIndex::UInt8:
|
||||
if (data_type->getName() == "Bool")
|
||||
payload_size += 2; // BIT MySQL type is string<lenenc> in binary
|
||||
else
|
||||
payload_size += 1;
|
||||
payload_size += 1;
|
||||
break;
|
||||
case TypeIndex::Int16:
|
||||
case TypeIndex::UInt16:
|
||||
@ -168,8 +165,6 @@ void ResultSetRow::writePayloadImpl(WriteBuffer & buffer) const
|
||||
}
|
||||
case TypeIndex::UInt8: {
|
||||
UInt8 value = assert_cast<const ColumnVector<UInt8> &>(*col).getData()[row_num];
|
||||
if (data_type->getName() == "Bool")
|
||||
buffer.write(static_cast<char>(1));
|
||||
buffer.write(reinterpret_cast<char *>(&value), 1);
|
||||
break;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ namespace ProtocolText
|
||||
ResultSetRow::ResultSetRow(const Serializations & serializations, const Columns & columns_, int row_num_)
|
||||
: columns(columns_), row_num(row_num_)
|
||||
{
|
||||
static FormatSettings format_settings = {.bool_true_representation = "1", .bool_false_representation = "0"};
|
||||
for (size_t i = 0; i < columns.size(); ++i)
|
||||
{
|
||||
if (columns[i]->isNullAt(row_num))
|
||||
@ -30,7 +31,7 @@ ResultSetRow::ResultSetRow(const Serializations & serializations, const Columns
|
||||
else
|
||||
{
|
||||
WriteBufferFromOwnString ostr;
|
||||
serializations[i]->serializeText(*columns[i], row_num, ostr, FormatSettings());
|
||||
serializations[i]->serializeText(*columns[i], row_num, ostr, format_settings);
|
||||
payload_size += getLengthEncodedStringSize(ostr.str());
|
||||
serialized.push_back(std::move(ostr.str()));
|
||||
}
|
||||
@ -45,12 +46,10 @@ size_t ResultSetRow::getPayloadSize() const
|
||||
void ResultSetRow::writePayloadImpl(WriteBuffer & buffer) const
|
||||
{
|
||||
for (size_t i = 0; i < columns.size(); ++i)
|
||||
{
|
||||
if (columns[i]->isNullAt(row_num))
|
||||
buffer.write(serialized[i].data(), 1);
|
||||
else
|
||||
writeLengthEncodedString(serialized[i], buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void ComFieldList::readPayloadImpl(ReadBuffer & payload)
|
||||
@ -142,19 +141,13 @@ ColumnDefinition getColumnDefinition(const String & column_name, const DataTypeP
|
||||
CharacterSet charset = CharacterSet::binary;
|
||||
int flags = 0;
|
||||
uint8_t decimals = 0;
|
||||
TypeIndex type_index = removeLowCardinality(removeNullable(data_type))->getTypeId();
|
||||
DataTypePtr normalized_data_type = removeLowCardinality(removeNullable(data_type));
|
||||
TypeIndex type_index = normalized_data_type->getTypeId();
|
||||
switch (type_index)
|
||||
{
|
||||
case TypeIndex::UInt8:
|
||||
if (data_type->getName() == "Bool")
|
||||
{
|
||||
column_type = ColumnType::MYSQL_TYPE_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
column_type = ColumnType::MYSQL_TYPE_TINY;
|
||||
flags = ColumnDefinitionFlags::BINARY_FLAG | ColumnDefinitionFlags::UNSIGNED_FLAG;
|
||||
}
|
||||
column_type = ColumnType::MYSQL_TYPE_TINY;
|
||||
flags = ColumnDefinitionFlags::BINARY_FLAG | ColumnDefinitionFlags::UNSIGNED_FLAG;
|
||||
break;
|
||||
case TypeIndex::UInt16:
|
||||
column_type = ColumnType::MYSQL_TYPE_SHORT;
|
||||
@ -213,7 +206,7 @@ ColumnDefinition getColumnDefinition(const String & column_name, const DataTypeP
|
||||
// MySQL Decimal has max 65 precision and 30 scale
|
||||
// Decimal256 (min scale is 39) is higher than the MySQL supported range and handled in the default case
|
||||
// See https://dev.mysql.com/doc/refman/8.0/en/precision-math-decimal-characteristics.html
|
||||
const auto & type = assert_cast<const DataTypeDecimal128 &>(*data_type);
|
||||
const auto & type = assert_cast<const DataTypeDecimal128 &>(*normalized_data_type);
|
||||
if (type.getPrecision() > 65 || type.getScale() > 30)
|
||||
{
|
||||
column_type = ColumnType::MYSQL_TYPE_STRING;
|
||||
|
@ -14,7 +14,7 @@ ui128 type is CHAR, value: 15324355
|
||||
ui256 type is CHAR, value: 41345135123432
|
||||
f32 type is FLOAT, value: -0.796896
|
||||
f64 type is DOUBLE, value: -0.113259
|
||||
b type is BIT, value: true
|
||||
b type is TINYINT, value: true
|
||||
Row #2
|
||||
i8 type is TINYINT, value: 127
|
||||
i16 type is SMALLINT, value: 32767
|
||||
@ -30,7 +30,7 @@ ui128 type is CHAR, value: 340282366920938463463374607431768211455
|
||||
ui256 type is CHAR, value: 115792089237316195423570985008687907853269984665640564039457584007913129639935
|
||||
f32 type is FLOAT, value: 1.234000
|
||||
f64 type is DOUBLE, value: 3.352451
|
||||
b type is BIT, value: false
|
||||
b type is TINYINT, value: false
|
||||
|
||||
### testStringTypes
|
||||
Row #1
|
||||
|
@ -577,6 +577,37 @@ def test_mysql_set_variables(started_cluster):
|
||||
assert code == 0
|
||||
|
||||
|
||||
def test_mysql_boolean_format(started_cluster):
|
||||
node.query(
|
||||
"""
|
||||
CREATE OR REPLACE TABLE mysql_boolean_format_test
|
||||
(
|
||||
`a` Bool,
|
||||
`b` Nullable(Bool),
|
||||
`c` LowCardinality(Nullable(Bool))
|
||||
) ENGINE MergeTree ORDER BY a;
|
||||
""",
|
||||
settings={"password": "123", "allow_suspicious_low_cardinality_types": 1},
|
||||
)
|
||||
node.query(
|
||||
"INSERT INTO mysql_boolean_format_test VALUES (false, true, false), (true, false, true);",
|
||||
settings={"password": "123"},
|
||||
)
|
||||
code, (stdout, stderr) = started_cluster.mysql_client_container.exec_run(
|
||||
"""
|
||||
mysql --protocol tcp -h {host} -P {port} default -u user_with_double_sha1 --password=abacaba
|
||||
-e "SELECT * FROM mysql_boolean_format_test;"
|
||||
""".format(
|
||||
host=started_cluster.get_instance_ip("node"), port=server_port
|
||||
),
|
||||
demux=True,
|
||||
)
|
||||
logging.debug(
|
||||
f"test_mysql_boolean_format code:{code} stdout:{stdout}, stderr:{stderr}"
|
||||
)
|
||||
assert stdout.decode() == "a\tb\tc\n" + "0\t1\t0\n" + "1\t0\t1\n"
|
||||
|
||||
|
||||
def test_python_client(started_cluster):
|
||||
client = pymysql.connections.Connection(
|
||||
host=started_cluster.get_instance_ip("node"),
|
||||
|
Loading…
Reference in New Issue
Block a user