Skip to content

Commit d25eb08

Browse files
readyset-data: Inferring padding for char columns
We were previously inferring the wrong default value for char columns. Char columns are padded with spaces to the column length. Instead of returning an empty string, we now return a string of spaces. Closes: REA-5699 Closes: #1503 Release-Note-Core: Fixed issue where char columns were not padded with spaces when using MRBR and being omitted from the insert. Change-Id: Icc0842269fa6d9644783888bbc708b3e7776f666 Reviewed-on: https://gerrit.readyset.name/c/readyset/+/9289 Tested-by: Buildkite CI Reviewed-by: Michael Zink <michael.z@readyset.io>
1 parent 6f5d74f commit d25eb08

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

readyset-data/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,13 @@ impl DfValue {
954954
// TODO: Fix this to return ByteArray(Vec::new().into())
955955
return DfValue::from_str_and_collation("", collation);
956956
} else if dftype.is_any_text() {
957-
return DfValue::from_str_and_collation("", collation);
957+
return match dftype {
958+
// For char columns, we return a space repeated to the length of the column
959+
DfType::Char(len, _) => {
960+
DfValue::from_str_and_collation(&" ".repeat(len.into()), collation)
961+
}
962+
_ => DfValue::from_str_and_collation("", collation),
963+
};
958964
} else if dftype.is_any_int() || dftype.is_bool() {
959965
return DfValue::Int(0);
960966
} else if dftype.is_any_float() {

replicators/tests/tests.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4140,3 +4140,62 @@ async fn mysql_minimal_row_based_collation_and_signedness() {
41404140

41414141
shutdown_tx.shutdown().await;
41424142
}
4143+
4144+
#[tokio::test(flavor = "multi_thread")]
4145+
#[serial(mysql)]
4146+
#[slow]
4147+
async fn mysql_minimal_row_based_char_padding() {
4148+
// REA-5699
4149+
// This test will create a table without PK. The insert will ommit column n, since we are using MRBR it will be deferred to Readyset to fill in the default value.
4150+
// Then we will update the column and ensure that the update is replicated correctly. Because the table has no PK, this will be a full row delete followed by an insert.
4151+
// If we did not chose the right default value, the delete will fail.
4152+
readyset_tracing::init_test_logging();
4153+
let url = mysql_url();
4154+
let mut client = DbConnection::connect(&url).await.unwrap();
4155+
4156+
client
4157+
.query("SET binlog_row_image = minimal;")
4158+
.await
4159+
.unwrap();
4160+
client.query("SET sql_mode = '';").await.unwrap();
4161+
client
4162+
.query("DROP TABLE IF EXISTS mrbr_char_padding;")
4163+
.await
4164+
.unwrap();
4165+
client
4166+
.query("CREATE TABLE `mrbr_char_padding` (ID INT, n CHAR(10) NOT NULL);")
4167+
.await
4168+
.unwrap();
4169+
4170+
let (mut ctx, shutdown_tx) = TestHandle::start_noria(url.to_string(), None)
4171+
.await
4172+
.unwrap();
4173+
4174+
ctx.controller_rx
4175+
.as_mut()
4176+
.unwrap()
4177+
.snapshot_completed()
4178+
.await
4179+
.unwrap();
4180+
4181+
client
4182+
.query("INSERT INTO `mrbr_char_padding` (ID) VALUES (0);")
4183+
.await
4184+
.unwrap();
4185+
client
4186+
.query("UPDATE `mrbr_char_padding` SET n = 'a' WHERE ID = 0;")
4187+
.await
4188+
.unwrap();
4189+
4190+
check_results!(
4191+
ctx,
4192+
"mrbr_char_padding",
4193+
"mrbr_char_padding_insert",
4194+
&[&[
4195+
DfValue::Int(0),
4196+
DfValue::from_str_and_collation("a ", Collation::Citext),
4197+
]]
4198+
);
4199+
4200+
shutdown_tx.shutdown().await;
4201+
}

0 commit comments

Comments
 (0)