feat(operator): allow last_row merge mode with append mode (#8065)

* feat(operator): allow last_row merge_mode when append_mode is enabled

- Update RegionOptions::validate to allow last_row merge_mode with append_mode.
- Update fill_table_options_for_create to automatically set merge_mode to last_row when append_mode is enabled for LastNonNull table type.
- Add unit tests in mito2 and operator to verify options validation and table creation.
- Add integration test for InfluxDB write with append mode hint.

Signed-off-by: Lei, HUANG <mrsatangel@gmail.com>

* fix(operator): simplify append mode options

Group `LastNonNull` auto-create options in a single append-mode branch.

Files:

- `src/operator/src/insert.rs`

Signed-off-by: Lei, HUANG <mrsatangel@gmail.com>

* fix: sqlness

Signed-off-by: Lei, HUANG <mrsatangel@gmail.com>

---------

Signed-off-by: Lei, HUANG <mrsatangel@gmail.com>
This commit is contained in:
Lei, HUANG
2026-05-07 15:21:37 +08:00
committed by GitHub
parent 160b7e720b
commit 796aae3d9f
4 changed files with 114 additions and 4 deletions

View File

@@ -96,9 +96,10 @@ impl RegionOptions {
pub fn validate(&self) -> Result<()> {
if self.append_mode {
ensure!(
self.merge_mode.is_none(),
self.merge_mode
.is_none_or(|mode| mode == MergeMode::LastRow),
InvalidRegionOptionsSnafu {
reason: "merge_mode is not allowed when append_mode is enabled",
reason: "only last_row merge_mode is allowed when append_mode is enabled",
}
);
}
@@ -622,6 +623,18 @@ mod tests {
assert_eq!(StatusCode::InvalidArguments, err.status_code());
}
#[test]
fn test_append_mode_allows_last_row_merge_mode() {
let map = make_map(&[("append_mode", "true"), ("merge_mode", "last_row")]);
let options = RegionOptions::try_from(&map).unwrap();
assert!(options.append_mode);
assert_eq!(MergeMode::LastRow, options.merge_mode());
let map = make_map(&[("append_mode", "true"), ("merge_mode", "last_non_null")]);
let err = RegionOptions::try_from(&map).unwrap_err();
assert_eq!(StatusCode::InvalidArguments, err.status_code());
}
#[test]
fn test_with_all() {
let wal_options = WalOptions::Kafka(KafkaWalOptions {

View File

@@ -1090,7 +1090,15 @@ pub fn fill_table_options_for_create(
table_options.insert(APPEND_MODE_KEY.to_string(), "true".to_string());
}
AutoCreateTableType::LastNonNull => {
table_options.insert(MERGE_MODE_KEY.to_string(), "last_non_null".to_string());
if ctx
.extension(APPEND_MODE_KEY)
.is_some_and(|value| value.eq_ignore_ascii_case("true"))
{
table_options.insert(APPEND_MODE_KEY.to_string(), "true".to_string());
table_options.insert(MERGE_MODE_KEY.to_string(), "last_row".to_string());
} else {
table_options.insert(MERGE_MODE_KEY.to_string(), "last_non_null".to_string());
}
}
AutoCreateTableType::Trace => {
table_options.insert(APPEND_MODE_KEY.to_string(), "true".to_string());
@@ -1334,4 +1342,56 @@ mod tests {
assert_eq!(req_schema[0].column_name, ts_name);
assert_eq!(req_schema[1].column_name, field_name);
}
#[test]
fn test_last_non_null_create_options_preserve_default_without_append_mode() {
let ctx = Arc::new(QueryContext::with(
DEFAULT_CATALOG_NAME,
DEFAULT_SCHEMA_NAME,
));
let mut table_options = Default::default();
fill_table_options_for_create(&mut table_options, &AutoCreateTableType::LastNonNull, &ctx);
assert_eq!(
Some("last_non_null"),
table_options.get(MERGE_MODE_KEY).map(String::as_str)
);
assert!(!table_options.contains_key(APPEND_MODE_KEY));
}
#[test]
fn test_last_non_null_create_options_preserve_default_with_append_mode_false() {
let mut ctx = QueryContext::with(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME);
ctx.set_extension(APPEND_MODE_KEY, "false");
let ctx = Arc::new(ctx);
let mut table_options = Default::default();
fill_table_options_for_create(&mut table_options, &AutoCreateTableType::LastNonNull, &ctx);
assert!(!table_options.contains_key(APPEND_MODE_KEY));
assert_eq!(
Some("last_non_null"),
table_options.get(MERGE_MODE_KEY).map(String::as_str)
);
}
#[test]
fn test_last_non_null_create_options_use_last_row_with_append_mode_true() {
let mut ctx = QueryContext::with(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME);
ctx.set_extension(APPEND_MODE_KEY, "true");
let ctx = Arc::new(ctx);
let mut table_options = Default::default();
fill_table_options_for_create(&mut table_options, &AutoCreateTableType::LastNonNull, &ctx);
assert_eq!(
Some("true"),
table_options.get(APPEND_MODE_KEY).map(String::as_str)
);
assert_eq!(
Some("last_row"),
table_options.get(MERGE_MODE_KEY).map(String::as_str)
);
}
}