feat: support CSV copy skip bad records (#8198)

* feat: support CSV copy headers and skip bad records

Signed-off-by: QuakeWang <wangfuzheng0814@foxmail.com>

* refactor: reuse CSV skippable error helper

Signed-off-by: QuakeWang <wangfuzheng0814@foxmail.com>

* fix: address CSV skip bad records review

Signed-off-by: QuakeWang <wangfuzheng0814@foxmail.com>

* docs: clarify CSV skip bad records performance tradeoff

Signed-off-by: QuakeWang <wangfuzheng0814@foxmail.com>

---------

Signed-off-by: QuakeWang <wangfuzheng0814@foxmail.com>
This commit is contained in:
QuakeWang
2026-06-03 20:11:02 +08:00
committed by GitHub
parent 31cdd864d2
commit ca07a53deb
7 changed files with 457 additions and 21 deletions

View File

@@ -401,6 +401,28 @@ mod tests {
}
}
#[test]
fn test_parse_copy_table_from_csv_options() {
let sql =
"COPY my_table FROM '/tmp/test.csv' WITH (FORMAT = 'CSV', SKIP_BAD_RECORDS = 'false')";
let mut result =
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
.unwrap();
assert_eq!(1, result.len());
let statement = result.remove(0);
assert_matches!(statement, Statement::Copy { .. });
match statement {
Statement::Copy(crate::statements::copy::Copy::CopyTable(CopyTable::From(
copy_table,
))) => {
assert_eq!(copy_table.with.get("format"), Some("CSV"));
assert_eq!(copy_table.with.get("skip_bad_records"), Some("false"));
}
_ => unreachable!(),
}
}
#[test]
fn test_parse_copy_table_to() {
struct Test<'a> {