@@ -28,7 +28,7 @@ use crate::ast::helpers::stmt_data_loading::{
2828};
2929use crate::ast::{
3030 AlterExternalVolumeOperation, AlterFileFormatOperation, AlterMaskingPolicyOperation,
31- AlterNetworkRuleOperation,
31+ AlterNetworkRuleOperation, AlterSnowflakeSecretOperation,
3232 AlterProcedure, AlterProcedureOperation, AlterStageOperation, AlterTable, AlterTableOperation,
3333 AlterTableType, AlterTagOperation, CatalogRestAuthentication, CatalogRestConfig, CatalogSource,
3434 CatalogSyncNamespaceMode, CatalogTableFormat, ColumnOption, ColumnPolicy, ColumnPolicyProperty,
@@ -437,6 +437,11 @@ impl Dialect for SnowflakeDialect {
437437 return Some(parse_alter_network_rule(parser));
438438 }
439439
440+ if parser.parse_keywords(&[Keyword::ALTER, Keyword::SECRET]) {
441+ // ALTER SECRET
442+ return Some(parse_alter_secret(parser));
443+ }
444+
440445 if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
441446 // ALTER SESSION
442447 let set = match parser.parse_one_of_keywords(&[Keyword::SET, Keyword::UNSET]) {
@@ -497,6 +502,11 @@ impl Dialect for SnowflakeDialect {
497502 return Some(parse_drop_network_rule(parser));
498503 }
499504
505+ if parser.parse_keywords(&[Keyword::DROP, Keyword::SECRET]) {
506+ // DROP SECRET
507+ return Some(parse_drop_secret(parser));
508+ }
509+
500510 if parser
501511 .parse_one_of_keywords(&[Keyword::DESC, Keyword::DESCRIBE])
502512 .is_some()
@@ -529,6 +539,10 @@ impl Dialect for SnowflakeDialect {
529539 // DESC[RIBE] NETWORK RULE
530540 return Some(parse_describe_network_rule(parser));
531541 }
542+ if parser.parse_keyword(Keyword::SECRET) {
543+ // DESC[RIBE] SECRET
544+ return Some(parse_describe_secret(parser));
545+ }
532546 // not handled — put back DESC/DESCRIBE
533547 parser.prev_token();
534548 }
@@ -573,6 +587,11 @@ impl Dialect for SnowflakeDialect {
573587 return Some(parse_create_network_rule(or_replace, parser));
574588 }
575589
590+ // CREATE [OR REPLACE] SECRET
591+ if parser.parse_keyword(Keyword::SECRET) {
592+ return Some(parse_create_secret(or_replace, parser));
593+ }
594+
576595 // LOCAL | GLOBAL
577596 let global = match parser.parse_one_of_keywords(&[Keyword::LOCAL, Keyword::GLOBAL]) {
578597 Some(Keyword::LOCAL) => Some(false),
@@ -741,6 +760,9 @@ impl Dialect for SnowflakeDialect {
741760 if parser.parse_keywords(&[Keyword::NETWORK, Keyword::RULES]) {
742761 return Some(parse_show_network_rules(parser));
743762 }
763+ if parser.parse_keyword(Keyword::SECRETS) {
764+ return Some(parse_show_secrets(parser));
765+ }
744766 if parser.parse_keyword(Keyword::PROCEDURES) {
745767 return Some(parse_show_procedures(parser));
746768 }
@@ -4049,6 +4071,65 @@ fn parse_show_network_rules(parser: &mut Parser) -> Result<Statement, ParserErro
40494071 Ok(Statement::ShowNetworkRules { show_options })
40504072}
40514073
4074+ /// Parse `CREATE [OR REPLACE] SECRET [IF NOT EXISTS] <name> <options>`.
4075+ ///
4076+ /// Options (`TYPE`, `USERNAME`, `SECRET_STRING`, `PASSWORD`,
4077+ /// `API_AUTHENTICATION`, `OAUTH_SCOPES`, `OAUTH_REFRESH_TOKEN`,
4078+ /// `ALGORITHM`, `COMMENT`, …) are captured generically as key-value options,
4079+ /// so the parser stays agnostic to the per-type property set.
4080+ fn parse_create_secret(or_replace: bool, parser: &mut Parser) -> Result<Statement, ParserError> {
4081+ let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
4082+ let name = parser.parse_object_name(false)?;
4083+ let options = parser.parse_key_value_options(false, &[], false)?;
4084+ Ok(Statement::CreateSnowflakeSecret {
4085+ or_replace,
4086+ if_not_exists,
4087+ name,
4088+ options,
4089+ })
4090+ }
4091+
4092+ /// Parse `ALTER SECRET [IF EXISTS] <name> { SET <options> | UNSET COMMENT }`.
4093+ fn parse_alter_secret(parser: &mut Parser) -> Result<Statement, ParserError> {
4094+ let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
4095+ let name = parser.parse_object_name(false)?;
4096+ let operation = if parser.parse_keyword(Keyword::SET) {
4097+ let options = parser.parse_key_value_options(false, &[], false)?;
4098+ if options.options.is_empty() {
4099+ return parser.expected_ref("at least one option to SET", parser.peek_token_ref());
4100+ }
4101+ AlterSnowflakeSecretOperation::Set(options)
4102+ } else if parser.parse_keywords(&[Keyword::UNSET, Keyword::COMMENT]) {
4103+ AlterSnowflakeSecretOperation::UnsetComment
4104+ } else {
4105+ return parser.expected_ref("SET <options> or UNSET COMMENT", parser.peek_token_ref());
4106+ };
4107+ Ok(Statement::AlterSnowflakeSecret {
4108+ if_exists,
4109+ name,
4110+ operation,
4111+ })
4112+ }
4113+
4114+ /// Parse `DROP SECRET [IF EXISTS] <name>`.
4115+ fn parse_drop_secret(parser: &mut Parser) -> Result<Statement, ParserError> {
4116+ let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
4117+ let name = parser.parse_object_name(false)?;
4118+ Ok(Statement::DropSnowflakeSecret { if_exists, name })
4119+ }
4120+
4121+ /// Parse `DESC[RIBE] SECRET <name>`.
4122+ fn parse_describe_secret(parser: &mut Parser) -> Result<Statement, ParserError> {
4123+ let name = parser.parse_object_name(false)?;
4124+ Ok(Statement::DescribeSnowflakeSecret { name })
4125+ }
4126+
4127+ /// Parse `SHOW SECRETS [LIKE '<pattern>'] [IN <scope>] [STARTS WITH ...] [LIMIT ...]`.
4128+ fn parse_show_secrets(parser: &mut Parser) -> Result<Statement, ParserError> {
4129+ let show_options = parser.parse_show_stmt_options()?;
4130+ Ok(Statement::ShowSnowflakeSecrets { show_options })
4131+ }
4132+
40524133/// Parse `SHOW PROCEDURES [LIKE '<pattern>'] [IN <scope>]`
40534134fn parse_show_procedures(parser: &mut Parser) -> Result<Statement, ParserError> {
40544135 let show_options = parser.parse_show_stmt_options()?;
0 commit comments