Redshift: more copy options (#2072)

This commit is contained in:
Yoav Cohen 2025-10-22 11:11:19 +02:00 committed by GitHub
parent 9cc9f9ab38
commit 6b352eaffd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 95 additions and 2 deletions

View file

@ -8210,6 +8210,8 @@ pub enum CopyLegacyOption {
Bzip2,
/// CLEANPATH
CleanPath,
/// COMPUPDATE [ PRESET | { ON | TRUE } | { OFF | FALSE } ]
CompUpdate { preset: bool, enabled: Option<bool> },
/// CSV ...
Csv(Vec<CopyLegacyCsvOption>),
/// DATEFORMAT \[ AS \] {'dateformat_string' | 'auto' }
@ -8250,8 +8252,12 @@ pub enum CopyLegacyOption {
PartitionBy(UnloadPartitionBy),
/// REGION \[ AS \] 'aws-region' }
Region(String),
/// REMOVEQUOTES
RemoveQuotes,
/// ROWGROUPSIZE \[ AS \] size \[ MB | GB \]
RowGroupSize(FileSize),
/// STATUPDATE [ { ON | TRUE } | { OFF | FALSE } ]
StatUpdate(Option<bool>),
/// TIMEFORMAT \[ AS \] {'timeformat_string' | 'auto' | 'epochsecs' | 'epochmillisecs' }
TimeFormat(Option<String>),
/// TRUNCATECOLUMNS
@ -8278,6 +8284,22 @@ impl fmt::Display for CopyLegacyOption {
BlankAsNull => write!(f, "BLANKSASNULL"),
Bzip2 => write!(f, "BZIP2"),
CleanPath => write!(f, "CLEANPATH"),
CompUpdate { preset, enabled } => {
write!(f, "COMPUPDATE")?;
if *preset {
write!(f, " PRESET")?;
} else if let Some(enabled) = enabled {
write!(
f,
"{}",
match enabled {
true => " TRUE",
false => " FALSE",
}
)?;
}
Ok(())
}
Csv(opts) => {
write!(f, "CSV")?;
if !opts.is_empty() {
@ -8324,7 +8346,19 @@ impl fmt::Display for CopyLegacyOption {
Parquet => write!(f, "PARQUET"),
PartitionBy(p) => write!(f, "{p}"),
Region(region) => write!(f, "REGION '{}'", value::escape_single_quote_string(region)),
RemoveQuotes => write!(f, "REMOVEQUOTES"),
RowGroupSize(file_size) => write!(f, "ROWGROUPSIZE {file_size}"),
StatUpdate(enabled) => {
write!(
f,
"STATUPDATE{}",
match enabled {
Some(true) => " TRUE",
Some(false) => " FALSE",
_ => "",
}
)
}
TimeFormat(fmt) => {
write!(f, "TIMEFORMAT")?;
if let Some(fmt) = fmt {

View file

@ -215,6 +215,7 @@ define_keywords!(
COMMITTED,
COMPATIBLE,
COMPRESSION,
COMPUPDATE,
COMPUTE,
CONCURRENTLY,
CONDITION,
@ -749,6 +750,7 @@ define_keywords!(
PRECISION,
PREPARE,
PRESERVE,
PRESET,
PREWHERE,
PRIMARY,
PRINT,
@ -801,6 +803,7 @@ define_keywords!(
RELEASES,
REMOTE,
REMOVE,
REMOVEQUOTES,
RENAME,
REORG,
REPAIR,
@ -915,6 +918,7 @@ define_keywords!(
STATS_AUTO_RECALC,
STATS_PERSISTENT,
STATS_SAMPLE_PAGES,
STATUPDATE,
STATUS,
STDDEV_POP,
STDDEV_SAMP,

View file

@ -9741,6 +9741,7 @@ impl<'a> Parser<'a> {
Keyword::BLANKSASNULL,
Keyword::BZIP2,
Keyword::CLEANPATH,
Keyword::COMPUPDATE,
Keyword::CSV,
Keyword::DATEFORMAT,
Keyword::DELIMITER,
@ -9761,7 +9762,9 @@ impl<'a> Parser<'a> {
Keyword::PARQUET,
Keyword::PARTITION,
Keyword::REGION,
Keyword::REMOVEQUOTES,
Keyword::ROWGROUPSIZE,
Keyword::STATUPDATE,
Keyword::TIMEFORMAT,
Keyword::TRUNCATECOLUMNS,
Keyword::ZSTD,
@ -9782,6 +9785,20 @@ impl<'a> Parser<'a> {
Some(Keyword::BLANKSASNULL) => CopyLegacyOption::BlankAsNull,
Some(Keyword::BZIP2) => CopyLegacyOption::Bzip2,
Some(Keyword::CLEANPATH) => CopyLegacyOption::CleanPath,
Some(Keyword::COMPUPDATE) => {
let preset = self.parse_keyword(Keyword::PRESET);
let enabled = match self.parse_one_of_keywords(&[
Keyword::TRUE,
Keyword::FALSE,
Keyword::ON,
Keyword::OFF,
]) {
Some(Keyword::TRUE) | Some(Keyword::ON) => Some(true),
Some(Keyword::FALSE) | Some(Keyword::OFF) => Some(false),
_ => None,
};
CopyLegacyOption::CompUpdate { preset, enabled }
}
Some(Keyword::CSV) => CopyLegacyOption::Csv({
let mut opts = vec![];
while let Some(opt) =
@ -9870,11 +9887,25 @@ impl<'a> Parser<'a> {
let region = self.parse_literal_string()?;
CopyLegacyOption::Region(region)
}
Some(Keyword::REMOVEQUOTES) => CopyLegacyOption::RemoveQuotes,
Some(Keyword::ROWGROUPSIZE) => {
let _ = self.parse_keyword(Keyword::AS);
let file_size = self.parse_file_size()?;
CopyLegacyOption::RowGroupSize(file_size)
}
Some(Keyword::STATUPDATE) => {
let enabled = match self.parse_one_of_keywords(&[
Keyword::TRUE,
Keyword::FALSE,
Keyword::ON,
Keyword::OFF,
]) {
Some(Keyword::TRUE) | Some(Keyword::ON) => Some(true),
Some(Keyword::FALSE) | Some(Keyword::OFF) => Some(false),
_ => None,
};
CopyLegacyOption::StatUpdate(enabled)
}
Some(Keyword::TIMEFORMAT) => {
let _ = self.parse_keyword(Keyword::AS);
let fmt = if matches!(self.peek_token().token, Token::SingleQuotedString(_)) {

View file

@ -17126,7 +17126,19 @@ fn parse_copy_options() {
"IAM_ROLE DEFAULT ",
"IGNOREHEADER AS 1 ",
"TIMEFORMAT AS 'auto' ",
"TRUNCATECOLUMNS",
"TRUNCATECOLUMNS ",
"REMOVEQUOTES ",
"COMPUPDATE ",
"COMPUPDATE PRESET ",
"COMPUPDATE ON ",
"COMPUPDATE OFF ",
"COMPUPDATE TRUE ",
"COMPUPDATE FALSE ",
"STATUPDATE ",
"STATUPDATE ON ",
"STATUPDATE OFF ",
"STATUPDATE TRUE ",
"STATUPDATE FALSE",
),
concat!(
"COPY dst (c1, c2, c3) FROM 's3://redshift-downloads/tickit/category_pipe.txt' ",
@ -17139,7 +17151,19 @@ fn parse_copy_options() {
"IAM_ROLE DEFAULT ",
"IGNOREHEADER 1 ",
"TIMEFORMAT 'auto' ",
"TRUNCATECOLUMNS",
"TRUNCATECOLUMNS ",
"REMOVEQUOTES ",
"COMPUPDATE ",
"COMPUPDATE PRESET ",
"COMPUPDATE TRUE ",
"COMPUPDATE FALSE ",
"COMPUPDATE TRUE ",
"COMPUPDATE FALSE ",
"STATUPDATE ",
"STATUPDATE TRUE ",
"STATUPDATE FALSE ",
"STATUPDATE TRUE ",
"STATUPDATE FALSE",
),
);
one_statement_parses_to(