Skip to content

Commit f9f0991

Browse files
hovaescoclaude
andauthored
Task LAV-1719: ALTER EXTERNAL ACCESS INTEGRATION remaining SET properties + UNSET (apache#2257)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 31f40e8 commit f9f0991

2 files changed

Lines changed: 132 additions & 11 deletions

File tree

src/ast/mod.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5967,15 +5967,28 @@ pub enum Statement {
59675967
comment: Option<String>,
59685968
},
59695969
/// ```sql
5970-
/// ALTER EXTERNAL ACCESS INTEGRATION [IF EXISTS] <name> SET ENABLED = { TRUE | FALSE }
5970+
/// ALTER EXTERNAL ACCESS INTEGRATION [IF EXISTS] <name> { SET ... | UNSET ... }
59715971
/// ```
59725972
AlterExternalAccessIntegration {
59735973
/// External access integration name.
59745974
name: ObjectName,
59755975
/// `IF EXISTS` flag.
59765976
if_exists: bool,
5977-
/// The `SET ENABLED` value.
5978-
enabled: bool,
5977+
/// `SET ALLOWED_NETWORK_RULES = (<rule> [, ...])`, if given.
5978+
allowed_network_rules: Option<Vec<ObjectName>>,
5979+
/// `SET ALLOWED_API_AUTHENTICATION_INTEGRATIONS = (<i> [, ...]) | NONE`.
5980+
allowed_api_authentication_integrations: Option<ExternalAccessAllowedList>,
5981+
/// `SET ALLOWED_AUTHENTICATION_SECRETS = (<s> [, ...]) | ALL | NONE`.
5982+
allowed_authentication_secrets: Option<ExternalAccessAllowedList>,
5983+
/// `SET ENABLED = { TRUE | FALSE }`, if given.
5984+
enabled: Option<bool>,
5985+
/// `SET COMMENT = '<string>'`, if given.
5986+
comment: Option<String>,
5987+
/// `SET` property names not recognised for this object (routed to the UDF
5988+
/// so it reproduces real Snowflake's `invalid property` reject verbatim).
5989+
set_invalid: Vec<Ident>,
5990+
/// The property names given in an `UNSET` clause.
5991+
unset_options: Vec<Ident>,
59795992
},
59805993
/// ```sql
59815994
/// DROP EXTERNAL ACCESS INTEGRATION [IF EXISTS] <name>
@@ -8943,14 +8956,47 @@ impl fmt::Display for Statement {
89438956
Statement::AlterExternalAccessIntegration {
89448957
name,
89458958
if_exists,
8959+
allowed_network_rules,
8960+
allowed_api_authentication_integrations,
8961+
allowed_authentication_secrets,
89468962
enabled,
8963+
comment,
8964+
set_invalid,
8965+
unset_options,
89478966
} => {
89488967
write!(
89498968
f,
8950-
"ALTER EXTERNAL ACCESS INTEGRATION {if_exists}{name} SET ENABLED = {enabled}",
8969+
"ALTER EXTERNAL ACCESS INTEGRATION {if_exists}{name}",
89518970
if_exists = if *if_exists { "IF EXISTS " } else { "" },
8952-
enabled = if *enabled { "TRUE" } else { "FALSE" },
8953-
)
8971+
)?;
8972+
if !unset_options.is_empty() {
8973+
write!(f, " UNSET {}", display_comma_separated(unset_options))?;
8974+
return Ok(());
8975+
}
8976+
write!(f, " SET")?;
8977+
if let Some(rules) = allowed_network_rules {
8978+
write!(
8979+
f,
8980+
" ALLOWED_NETWORK_RULES = ({})",
8981+
display_comma_separated(rules)
8982+
)?;
8983+
}
8984+
if let Some(list) = allowed_api_authentication_integrations {
8985+
write!(f, " ALLOWED_API_AUTHENTICATION_INTEGRATIONS = {list}")?;
8986+
}
8987+
if let Some(list) = allowed_authentication_secrets {
8988+
write!(f, " ALLOWED_AUTHENTICATION_SECRETS = {list}")?;
8989+
}
8990+
if let Some(enabled) = enabled {
8991+
write!(f, " ENABLED = {}", if *enabled { "TRUE" } else { "FALSE" })?;
8992+
}
8993+
if let Some(comment) = comment {
8994+
write!(f, " COMMENT = '{}'", value::escape_single_quote_string(comment))?;
8995+
}
8996+
for prop in set_invalid {
8997+
write!(f, " {prop} = <invalid>")?;
8998+
}
8999+
Ok(())
89549000
}
89559001
Statement::DropExternalAccessIntegration { name, if_exists } => {
89569002
write!(

src/dialect/snowflake.rs

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4920,21 +4920,96 @@ fn parse_external_access_allowed_list(
49204920
))
49214921
}
49224922

4923-
/// Parse `ALTER EXTERNAL ACCESS INTEGRATION [IF EXISTS] <name> SET ENABLED =
4924-
/// { TRUE | FALSE }`. Only the `SET ENABLED` form is modelled.
4923+
/// Parse `ALTER EXTERNAL ACCESS INTEGRATION [IF EXISTS] <name>
4924+
/// { SET <props> | UNSET <props> }`.
4925+
///
4926+
/// The settable list-valued properties carry the same bare-keyword (`NONE` /
4927+
/// `ALL`) alternatives as `CREATE`, so `SET` is parsed explicitly rather than
4928+
/// through the generic key-value reader. An unrecognised `SET` property is
4929+
/// captured by name (with its value discarded) so the UDF can reproduce real
4930+
/// Snowflake's `invalid property` reject. `UNSET` takes a comma-separated list
4931+
/// of property names.
49254932
fn parse_alter_external_access_integration(
49264933
parser: &mut Parser,
49274934
) -> Result<Statement, ParserError> {
49284935
let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
49294936
let name = parser.parse_object_name(false)?;
4937+
4938+
let mut allowed_network_rules = None;
4939+
let mut allowed_api_authentication_integrations = None;
4940+
let mut allowed_authentication_secrets = None;
4941+
let mut enabled = None;
4942+
let mut comment = None;
4943+
let mut set_invalid = Vec::new();
4944+
4945+
if parser.parse_keyword(Keyword::UNSET) {
4946+
let unset_options = parser.parse_comma_separated(Parser::parse_identifier)?;
4947+
return Ok(Statement::AlterExternalAccessIntegration {
4948+
name,
4949+
if_exists,
4950+
allowed_network_rules,
4951+
allowed_api_authentication_integrations,
4952+
allowed_authentication_secrets,
4953+
enabled,
4954+
comment,
4955+
set_invalid,
4956+
unset_options,
4957+
});
4958+
}
4959+
49304960
parser.expect_keyword(Keyword::SET)?;
4931-
parser.expect_keyword(Keyword::ENABLED)?;
4932-
parser.expect_token(&Token::Eq)?;
4933-
let enabled = parse_bool_literal(parser)?;
4961+
loop {
4962+
let _ = parser.consume_token(&Token::Comma);
4963+
let word = match parser.peek_token().token {
4964+
Token::Word(w) => w,
4965+
_ => break,
4966+
};
4967+
match word.value.to_uppercase().as_str() {
4968+
"ALLOWED_NETWORK_RULES" => {
4969+
parser.next_token();
4970+
parser.expect_token(&Token::Eq)?;
4971+
allowed_network_rules = Some(parse_object_name_paren_list(parser)?);
4972+
}
4973+
"ALLOWED_API_AUTHENTICATION_INTEGRATIONS" => {
4974+
parser.next_token();
4975+
parser.expect_token(&Token::Eq)?;
4976+
allowed_api_authentication_integrations =
4977+
Some(parse_external_access_allowed_list(parser, false)?);
4978+
}
4979+
"ALLOWED_AUTHENTICATION_SECRETS" => {
4980+
parser.next_token();
4981+
parser.expect_token(&Token::Eq)?;
4982+
allowed_authentication_secrets =
4983+
Some(parse_external_access_allowed_list(parser, true)?);
4984+
}
4985+
"ENABLED" => {
4986+
parser.next_token();
4987+
parser.expect_token(&Token::Eq)?;
4988+
enabled = Some(parse_bool_literal(parser)?);
4989+
}
4990+
"COMMENT" => {
4991+
parser.next_token();
4992+
parser.expect_token(&Token::Eq)?;
4993+
comment = Some(parser.parse_literal_string()?);
4994+
}
4995+
_ => {
4996+
set_invalid.push(Ident::new(word.value.clone()));
4997+
parser.next_token();
4998+
let _ = parser.parse_key_value_option(&word, false)?;
4999+
}
5000+
}
5001+
}
5002+
49345003
Ok(Statement::AlterExternalAccessIntegration {
49355004
name,
49365005
if_exists,
5006+
allowed_network_rules,
5007+
allowed_api_authentication_integrations,
5008+
allowed_authentication_secrets,
49375009
enabled,
5010+
comment,
5011+
set_invalid,
5012+
unset_options: vec![],
49385013
})
49395014
}
49405015

0 commit comments

Comments
 (0)