Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions storage/duckdb/convertor/duckdb_select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ static void store_field_temporal_value(Field *field, MYSQL_TIME *ltime)
field->store_time(ltime);
}

/**
Convert a DuckDB value to a string for MariaDB string-like fields.
*/
static duckdb::string duckdb_value_as_string(const duckdb::Value &value)
{
if (value.type().InternalType() == duckdb::PhysicalType::VARCHAR)
return value.GetValueUnsafe<duckdb::string>();
return value.ToString();
}

/**
Store a duckdb value in a field of mysql format.
@param field the field to store value
Expand All @@ -67,7 +77,7 @@ void store_duckdb_field_in_mysql_format(Field *field, duckdb::Value &value,
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_BIT: {
auto str= value.GetValueUnsafe<duckdb::string>();
auto str= duckdb_value_as_string(value);
auto varchar= str.c_str();
auto varchar_len= str.size();
field->store(varchar, varchar_len, &my_charset_bin);
Expand All @@ -78,22 +88,22 @@ void store_duckdb_field_in_mysql_format(Field *field, duckdb::Value &value,
case MYSQL_TYPE_VAR_STRING: {
if (is_uuid_field(field))
{
auto str= value.GetValue<duckdb::string>();
auto str= duckdb_value_as_string(value);
field->store(str.c_str(), str.size(), system_charset_info);
break;
}
if (field->has_charset())
{
DBUG_ASSERT(field->charset() != &my_charset_bin);
auto str= value.GetValue<duckdb::string>();
auto str= duckdb_value_as_string(value);
auto varchar= str.c_str();
auto varchar_len= str.size();
field->store(varchar, varchar_len, field->charset());
break;
}
else
{
auto str= value.GetValueUnsafe<duckdb::string>();
auto str= duckdb_value_as_string(value);
auto varchar= str.c_str();
auto varchar_len= str.size();
field->store(varchar, varchar_len, &my_charset_bin);
Expand All @@ -105,7 +115,7 @@ void store_duckdb_field_in_mysql_format(Field *field, duckdb::Value &value,
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_NEWDECIMAL: {
auto str= value.GetValue<duckdb::string>();
auto str= duckdb_value_as_string(value);
auto varchar= str.c_str();
auto varchar_len= str.size();
field->store(varchar, varchar_len, system_charset_info);
Expand Down Expand Up @@ -157,7 +167,7 @@ void store_duckdb_field_in_mysql_format(Field *field, duckdb::Value &value,
DuckDB date_t stores days since 1970-01-01.
Convert to MYSQL_TIME via val_str and store_time.
*/
auto str= value.GetValue<duckdb::string>();
auto str= duckdb_value_as_string(value);
MYSQL_TIME tm;
MYSQL_TIME_STATUS status;
my_time_status_init(&status);
Expand All @@ -167,7 +177,7 @@ void store_duckdb_field_in_mysql_format(Field *field, duckdb::Value &value,
}
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_DATETIME2: {
auto str= value.GetValue<duckdb::string>();
auto str= duckdb_value_as_string(value);
MYSQL_TIME tm;
MYSQL_TIME_STATUS status;
my_time_status_init(&status);
Expand All @@ -177,7 +187,7 @@ void store_duckdb_field_in_mysql_format(Field *field, duckdb::Value &value,
}
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_TIMESTAMP2: {
auto str= value.GetValue<duckdb::string>();
auto str= duckdb_value_as_string(value);
MYSQL_TIME tm;
MYSQL_TIME_STATUS status;
my_time_status_init(&status);
Expand All @@ -187,7 +197,7 @@ void store_duckdb_field_in_mysql_format(Field *field, duckdb::Value &value,
}
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_TIME2: {
auto str= value.GetValue<duckdb::string>();
auto str= duckdb_value_as_string(value);
MYSQL_TIME tm;
MYSQL_TIME_STATUS status;
my_time_status_init(&status);
Expand Down
31 changes: 31 additions & 0 deletions storage/duckdb/mysql-test/duckdb/r/mdev_41208.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
CREATE TABLE t1 (c1 INT PRIMARY KEY) ENGINE=DuckDB;
INSERT INTO t1 VALUES (1);
SELECT COALESCE(1,'t') FROM t1;
COALESCE(1,'t')
1
SELECT COALESCE(c1,'t') FROM t1;
COALESCE(c1,'t')
1
SELECT IFNULL(1,'t') FROM t1;
IFNULL(1,'t')
1
SET NAMES BINARY;
SELECT COALESCE(1,'t') FROM t1;
COALESCE(1,'t')
1
SELECT COALESCE(c1,'t') FROM t1;
COALESCE(c1,'t')
1
SELECT IFNULL(1,'t') FROM t1;
IFNULL(1,'t')
1
SET NAMES utf8mb4;
CREATE TABLE t2 (c1 VARCHAR(10) CHARACTER SET utf8mb4 PRIMARY KEY) ENGINE=DuckDB;
INSERT INTO t2 VALUES ('ab');
SELECT c1 FROM t2;
c1
ab
SELECT COALESCE(c1, 'z') FROM t2;
COALESCE(c1, 'z')
ab
DROP TABLE t1, t2;
31 changes: 31 additions & 0 deletions storage/duckdb/mysql-test/duckdb/t/mdev_41208.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--source ../include/have_duckdb.inc
--source include/not_msan.inc
--disable_warnings

#
# MDEV-41208 SIGABRT in StringValue::Get after SET NAMES BINARY
#
# MariaDB types mixed numeric/string COALESCE as VARCHAR. DuckDB types it as
# INTEGER because untyped string literals take the other argument's type.
# Fetching that integer with GetValueUnsafe<string>() asserts VARCHAR.
#

CREATE TABLE t1 (c1 INT PRIMARY KEY) ENGINE=DuckDB;
INSERT INTO t1 VALUES (1);

SELECT COALESCE(1,'t') FROM t1;
SELECT COALESCE(c1,'t') FROM t1;
SELECT IFNULL(1,'t') FROM t1;

SET NAMES BINARY;
SELECT COALESCE(1,'t') FROM t1;
SELECT COALESCE(c1,'t') FROM t1;
SELECT IFNULL(1,'t') FROM t1;
SET NAMES utf8mb4;

CREATE TABLE t2 (c1 VARCHAR(10) CHARACTER SET utf8mb4 PRIMARY KEY) ENGINE=DuckDB;
INSERT INTO t2 VALUES ('ab');
SELECT c1 FROM t2;
SELECT COALESCE(c1, 'z') FROM t2;

DROP TABLE t1, t2;