Skip to content

Commit 893caa0

Browse files
committed
Redshift: Add support for IAM_ROLE and IGNOREHEADER COPY options
1 parent 4921846 commit 893caa0

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

src/ast/mod.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8570,6 +8570,10 @@ pub enum CopyLegacyOption {
85708570
Null(String),
85718571
/// CSV ...
85728572
Csv(Vec<CopyLegacyCsvOption>),
8573+
/// IAM_ROLE { default | 'arn:aws:iam::<AWS account-id>:role/<role-name>' }
8574+
IamRole(Option<String>),
8575+
/// IGNOREHEADER [ AS ] number_rows
8576+
IgnoreHeader(u64),
85738577
}
85748578

85758579
impl fmt::Display for CopyLegacyOption {
@@ -8579,7 +8583,21 @@ impl fmt::Display for CopyLegacyOption {
85798583
Binary => write!(f, "BINARY"),
85808584
Delimiter(char) => write!(f, "DELIMITER '{char}'"),
85818585
Null(string) => write!(f, "NULL '{}'", value::escape_single_quote_string(string)),
8582-
Csv(opts) => write!(f, "CSV {}", display_separated(opts, " ")),
8586+
Csv(opts) => {
8587+
write!(f, "CSV")?;
8588+
if !opts.is_empty() {
8589+
write!(f, " {}", display_separated(opts, " "))?;
8590+
}
8591+
Ok(())
8592+
}
8593+
IamRole(role) => {
8594+
write!(f, "IAM_ROLE")?;
8595+
match role {
8596+
Some(role) => write!(f, " '{role}'"),
8597+
None => write!(f, " default"),
8598+
}
8599+
}
8600+
IgnoreHeader(num_rows) => write!(f, "IGNOREHEADER {num_rows}"),
85838601
}
85848602
}
85858603
}

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,12 +423,14 @@ define_keywords!(
423423
HOUR,
424424
HOURS,
425425
HUGEINT,
426+
IAM_ROLE,
426427
ICEBERG,
427428
ID,
428429
IDENTITY,
429430
IDENTITY_INSERT,
430431
IF,
431432
IGNORE,
433+
IGNOREHEADER,
432434
ILIKE,
433435
IMMEDIATE,
434436
IMMUTABLE,

src/parser/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9358,6 +9358,8 @@ impl<'a> Parser<'a> {
93589358
Keyword::DELIMITER,
93599359
Keyword::NULL,
93609360
Keyword::CSV,
9361+
Keyword::IAM_ROLE,
9362+
Keyword::IGNOREHEADER,
93619363
]) {
93629364
Some(Keyword::BINARY) => CopyLegacyOption::Binary,
93639365
Some(Keyword::DELIMITER) => {
@@ -9377,6 +9379,19 @@ impl<'a> Parser<'a> {
93779379
}
93789380
opts
93799381
}),
9382+
Some(Keyword::IAM_ROLE) => {
9383+
if self.parse_keyword(Keyword::DEFAULT) {
9384+
CopyLegacyOption::IamRole(None)
9385+
} else {
9386+
let role = self.parse_literal_string()?;
9387+
CopyLegacyOption::IamRole(Some(role))
9388+
}
9389+
}
9390+
Some(Keyword::IGNOREHEADER) => {
9391+
let _ = self.parse_keyword(Keyword::AS);
9392+
let num_rows = self.parse_literal_uint()?;
9393+
CopyLegacyOption::IgnoreHeader(num_rows)
9394+
}
93809395
_ => self.expected("option", self.peek_token())?,
93819396
};
93829397
Ok(ret)

tests/sqlparser_common.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16256,3 +16256,25 @@ fn parse_notnull() {
1625616256
// for unsupported dialects, parsing should stop at `NOT NULL`
1625716257
notnull_unsupported_dialects.expr_parses_to("NOT NULL NOTNULL", "NOT NULL");
1625816258
}
16259+
16260+
#[test]
16261+
fn pares_copy_options() {
16262+
let copy = verified_stmt(
16263+
r#"COPY dst (c1, c2, c3) FROM 's3://redshift-downloads/tickit/category_pipe.txt' IAM_ROLE 'arn:aws:iam::123456789:role/role1' CSV IGNOREHEADER 1"#,
16264+
);
16265+
match copy {
16266+
Statement::Copy { legacy_options, .. } => {
16267+
assert_eq!(
16268+
legacy_options,
16269+
vec![
16270+
CopyLegacyOption::IamRole(Some(
16271+
"arn:aws:iam::123456789:role/role1".to_string()
16272+
)),
16273+
CopyLegacyOption::Csv(vec![]),
16274+
CopyLegacyOption::IgnoreHeader(1),
16275+
]
16276+
);
16277+
}
16278+
_ => unreachable!(),
16279+
}
16280+
}

0 commit comments

Comments
 (0)