Skip to content

Commit 241da85

Browse files
alambJichaoS
andauthored
Support CREATE/DROP SECRET for duckdb dialect (apache#1208)
Co-authored-by: Jichao Sun <4977515+JichaoS@users.noreply.github.com>
1 parent 8f67d1a commit 241da85

4 files changed

Lines changed: 486 additions & 2 deletions

File tree

src/ast/mod.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,19 @@ pub enum Statement {
20402040
authorization_owner: Option<ObjectName>,
20412041
},
20422042
/// ```sql
2043+
/// CREATE SECRET
2044+
/// ```
2045+
/// See [duckdb](https://duckdb.org/docs/sql/statements/create_secret.html)
2046+
CreateSecret {
2047+
or_replace: bool,
2048+
temporary: Option<bool>,
2049+
if_not_exists: bool,
2050+
name: Option<Ident>,
2051+
storage_specifier: Option<Ident>,
2052+
secret_type: Ident,
2053+
options: Vec<SecretOption>,
2054+
},
2055+
/// ```sql
20432056
/// ALTER TABLE
20442057
/// ```
20452058
AlterTable {
@@ -2088,6 +2101,31 @@ pub enum Statement {
20882101
/// true if the syntax is 'ATTACH DATABASE', false if it's just 'ATTACH'
20892102
database: bool,
20902103
},
2104+
/// (DuckDB-specific)
2105+
/// ```sql
2106+
/// ATTACH 'sqlite_file.db' AS sqlite_db (READ_ONLY, TYPE SQLITE);
2107+
/// ```
2108+
/// See <https://duckdb.org/docs/sql/statements/attach.html>
2109+
AttachDuckDBDatabase {
2110+
if_not_exists: bool,
2111+
/// true if the syntax is 'ATTACH DATABASE', false if it's just 'ATTACH'
2112+
database: bool,
2113+
/// An expression that indicates the path to the database file
2114+
database_path: Ident,
2115+
database_alias: Option<Ident>,
2116+
attach_options: Vec<AttachDuckDBDatabaseOption>,
2117+
},
2118+
/// (DuckDB-specific)
2119+
/// ```sql
2120+
/// DETACH db_alias;
2121+
/// ```
2122+
/// See <https://duckdb.org/docs/sql/statements/attach.html>
2123+
DetachDuckDBDatabase {
2124+
if_exists: bool,
2125+
/// true if the syntax is 'DETACH DATABASE', false if it's just 'DETACH'
2126+
database: bool,
2127+
database_alias: Ident,
2128+
},
20912129
/// ```sql
20922130
/// DROP [TABLE, VIEW, ...]
20932131
/// ```
@@ -2121,6 +2159,15 @@ pub enum Statement {
21212159
option: Option<ReferentialAction>,
21222160
},
21232161
/// ```sql
2162+
/// DROP SECRET
2163+
/// ```
2164+
DropSecret {
2165+
if_exists: bool,
2166+
temporary: Option<bool>,
2167+
name: Ident,
2168+
storage_specifier: Option<Ident>,
2169+
},
2170+
/// ```sql
21242171
/// DECLARE
21252172
/// ```
21262173
/// Declare Cursor Variables
@@ -2772,6 +2819,40 @@ impl fmt::Display for Statement {
27722819
let keyword = if *database { "DATABASE " } else { "" };
27732820
write!(f, "ATTACH {keyword}{database_file_name} AS {schema_name}")
27742821
}
2822+
Statement::AttachDuckDBDatabase {
2823+
if_not_exists,
2824+
database,
2825+
database_path,
2826+
database_alias,
2827+
attach_options,
2828+
} => {
2829+
write!(
2830+
f,
2831+
"ATTACH{database}{if_not_exists} {database_path}",
2832+
database = if *database { " DATABASE" } else { "" },
2833+
if_not_exists = if *if_not_exists { " IF NOT EXISTS" } else { "" },
2834+
)?;
2835+
if let Some(alias) = database_alias {
2836+
write!(f, " AS {alias}")?;
2837+
}
2838+
if !attach_options.is_empty() {
2839+
write!(f, " ({})", display_comma_separated(attach_options))?;
2840+
}
2841+
Ok(())
2842+
}
2843+
Statement::DetachDuckDBDatabase {
2844+
if_exists,
2845+
database,
2846+
database_alias,
2847+
} => {
2848+
write!(
2849+
f,
2850+
"DETACH{database}{if_exists} {database_alias}",
2851+
database = if *database { " DATABASE" } else { "" },
2852+
if_exists = if *if_exists { " IF EXISTS" } else { "" },
2853+
)?;
2854+
Ok(())
2855+
}
27752856
Statement::Analyze {
27762857
table_name,
27772858
partitions,
@@ -3556,6 +3637,41 @@ impl fmt::Display for Statement {
35563637
}
35573638
Ok(())
35583639
}
3640+
Statement::CreateSecret {
3641+
or_replace,
3642+
temporary,
3643+
if_not_exists,
3644+
name,
3645+
storage_specifier,
3646+
secret_type,
3647+
options,
3648+
} => {
3649+
write!(
3650+
f,
3651+
"CREATE {or_replace}",
3652+
or_replace = if *or_replace { "OR REPLACE " } else { "" },
3653+
)?;
3654+
if let Some(t) = temporary {
3655+
write!(f, "{}", if *t { "TEMPORARY " } else { "PERSISTENT " })?;
3656+
}
3657+
write!(
3658+
f,
3659+
"SECRET {if_not_exists}",
3660+
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
3661+
)?;
3662+
if let Some(n) = name {
3663+
write!(f, "{n} ")?;
3664+
};
3665+
if let Some(s) = storage_specifier {
3666+
write!(f, "IN {s} ")?;
3667+
}
3668+
write!(f, "( TYPE {secret_type}",)?;
3669+
if !options.is_empty() {
3670+
write!(f, ", {o}", o = display_comma_separated(options))?;
3671+
}
3672+
write!(f, " )")?;
3673+
Ok(())
3674+
}
35593675
Statement::AlterTable {
35603676
name,
35613677
if_exists,
@@ -3636,6 +3752,26 @@ impl fmt::Display for Statement {
36363752
}
36373753
Ok(())
36383754
}
3755+
Statement::DropSecret {
3756+
if_exists,
3757+
temporary,
3758+
name,
3759+
storage_specifier,
3760+
} => {
3761+
write!(f, "DROP ")?;
3762+
if let Some(t) = temporary {
3763+
write!(f, "{}", if *t { "TEMPORARY " } else { "PERSISTENT " })?;
3764+
}
3765+
write!(
3766+
f,
3767+
"SECRET {if_exists}{name}",
3768+
if_exists = if *if_exists { "IF EXISTS " } else { "" },
3769+
)?;
3770+
if let Some(s) = storage_specifier {
3771+
write!(f, " FROM {s}")?;
3772+
}
3773+
Ok(())
3774+
}
36393775
Statement::Discard { object_type } => {
36403776
write!(f, "DISCARD {object_type}")?;
36413777
Ok(())
@@ -5070,6 +5206,39 @@ impl fmt::Display for SqlOption {
50705206
}
50715207
}
50725208

5209+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5210+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5211+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5212+
pub struct SecretOption {
5213+
pub key: Ident,
5214+
pub value: Ident,
5215+
}
5216+
5217+
impl fmt::Display for SecretOption {
5218+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5219+
write!(f, "{} {}", self.key, self.value)
5220+
}
5221+
}
5222+
5223+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
5224+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5225+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
5226+
pub enum AttachDuckDBDatabaseOption {
5227+
ReadOnly(Option<bool>),
5228+
Type(Ident),
5229+
}
5230+
5231+
impl fmt::Display for AttachDuckDBDatabaseOption {
5232+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5233+
match self {
5234+
AttachDuckDBDatabaseOption::ReadOnly(Some(true)) => write!(f, "READ_ONLY true"),
5235+
AttachDuckDBDatabaseOption::ReadOnly(Some(false)) => write!(f, "READ_ONLY false"),
5236+
AttachDuckDBDatabaseOption::ReadOnly(None) => write!(f, "READ_ONLY"),
5237+
AttachDuckDBDatabaseOption::Type(t) => write!(f, "TYPE {}", t),
5238+
}
5239+
}
5240+
}
5241+
50735242
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
50745243
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50755244
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]

src/keywords.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ define_keywords!(
224224
DEREF,
225225
DESC,
226226
DESCRIBE,
227+
DETACH,
227228
DETAIL,
228229
DETERMINISTIC,
229230
DIRECTORY,
@@ -514,6 +515,7 @@ define_keywords!(
514515
PERCENTILE_DISC,
515516
PERCENT_RANK,
516517
PERIOD,
518+
PERSISTENT,
517519
PIVOT,
518520
PLACING,
519521
PLANS,
@@ -543,6 +545,7 @@ define_keywords!(
543545
RCFILE,
544546
READ,
545547
READS,
548+
READ_ONLY,
546549
REAL,
547550
RECURSIVE,
548551
REF,
@@ -601,6 +604,7 @@ define_keywords!(
601604
SCROLL,
602605
SEARCH,
603606
SECOND,
607+
SECRET,
604608
SECURITY,
605609
SELECT,
606610
SEMI,

0 commit comments

Comments
 (0)