Skip to content

Commit 1c00c8a

Browse files
committed
Add SET configuration_parameter parsing for PostgreSQL functions.
1 parent 7ab0755 commit 1c00c8a

File tree

2 files changed

+106
-1
lines changed

2 files changed

+106
-1
lines changed

src/parser/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5260,6 +5260,7 @@ impl<'a> Parser<'a> {
52605260
function_body: Option<CreateFunctionBody>,
52615261
called_on_null: Option<FunctionCalledOnNull>,
52625262
parallel: Option<FunctionParallel>,
5263+
options: Vec<SqlOption>,
52635264
}
52645265
let mut body = Body::default();
52655266
loop {
@@ -5326,6 +5327,18 @@ impl<'a> Parser<'a> {
53265327
} else {
53275328
return self.expected("one of UNSAFE | RESTRICTED | SAFE", self.peek_token());
53285329
}
5330+
} else if self.parse_keyword(Keyword::SET) {
5331+
let name = self.parse_identifier()?;
5332+
self.expect_token(&Token::Eq)?;
5333+
let first_value = self.parse_expr()?;
5334+
let value = if self.consume_token(&Token::Comma) {
5335+
let mut values = vec![first_value];
5336+
values.extend(self.parse_comma_separated(Parser::parse_expr)?);
5337+
Expr::Tuple(values)
5338+
} else {
5339+
first_value
5340+
};
5341+
body.options.push(SqlOption::KeyValue { key: name, value });
53295342
} else if self.parse_keyword(Keyword::RETURN) {
53305343
ensure_not_set(&body.function_body, "RETURN")?;
53315344
body.function_body = Some(CreateFunctionBody::Return(self.parse_expr()?));
@@ -5349,7 +5362,11 @@ impl<'a> Parser<'a> {
53495362
if_not_exists: false,
53505363
using: None,
53515364
determinism_specifier: None,
5352-
options: None,
5365+
options: if body.options.is_empty() {
5366+
None
5367+
} else {
5368+
Some(body.options)
5369+
},
53535370
remote_connection: None,
53545371
}))
53555372
}

tests/sqlparser_postgres.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4586,6 +4586,94 @@ fn parse_create_function_c_with_module_pathname() {
45864586
);
45874587
}
45884588

4589+
#[test]
4590+
fn parse_create_function_with_set_config() {
4591+
let sql = r#"CREATE FUNCTION auth.hook(event jsonb)
4592+
RETURNS jsonb
4593+
LANGUAGE plpgsql
4594+
SET search_path = auth, pg_temp, public
4595+
AS $$ BEGIN RETURN event; END; $$"#;
4596+
4597+
let statements = pg().parse_sql_statements(sql).unwrap();
4598+
assert_eq!(statements.len(), 1);
4599+
match &statements[0] {
4600+
Statement::CreateFunction(CreateFunction { name, options, .. }) => {
4601+
assert_eq!(name.to_string(), "auth.hook");
4602+
let opts = options.as_ref().expect("should have options");
4603+
assert_eq!(opts.len(), 1, "Should have one SET option");
4604+
4605+
// Verify the SET option was captured
4606+
match &opts[0] {
4607+
SqlOption::KeyValue { key, value } => {
4608+
assert_eq!(key.to_string(), "search_path");
4609+
// Value should be a comma-separated list of identifiers
4610+
match value {
4611+
Expr::Tuple(tuple) => {
4612+
assert_eq!(tuple.len(), 3);
4613+
// Verify tuple contains expected identifiers
4614+
for (i, expected) in ["auth", "pg_temp", "public"].iter().enumerate() {
4615+
match &tuple[i] {
4616+
Expr::Identifier(ident) => {
4617+
assert_eq!(ident.to_string(), *expected);
4618+
}
4619+
_ => panic!("Expected identifier in tuple position {}", i),
4620+
}
4621+
}
4622+
}
4623+
_ => panic!("Expected Tuple expression for comma-separated values, got: {:?}", value),
4624+
}
4625+
}
4626+
_ => panic!("Expected KeyValue option"),
4627+
}
4628+
}
4629+
_ => panic!("Expected CreateFunction"),
4630+
}
4631+
4632+
// Test with quoted string value
4633+
let sql2 = r#"CREATE FUNCTION test_func() RETURNS void LANGUAGE plpgsql SET work_mem = '64MB' AS $$ BEGIN END; $$"#;
4634+
let statements2 = pg().parse_sql_statements(sql2).unwrap();
4635+
match &statements2[0] {
4636+
Statement::CreateFunction(CreateFunction { options, .. }) => {
4637+
let opts = options.as_ref().expect("should have options");
4638+
match &opts[0] {
4639+
SqlOption::KeyValue { key, value } => {
4640+
assert_eq!(key.to_string(), "work_mem");
4641+
match value {
4642+
Expr::Value(ValueWithSpan { value: Value::SingleQuotedString(s), .. }) => {
4643+
assert_eq!(s, "64MB");
4644+
}
4645+
_ => panic!("Expected SingleQuotedString, got: {:?}", value),
4646+
}
4647+
}
4648+
_ => panic!("Expected KeyValue option"),
4649+
}
4650+
}
4651+
_ => panic!("Expected CreateFunction"),
4652+
}
4653+
4654+
// Test with boolean value
4655+
let sql3 = r#"CREATE FUNCTION test_func2() RETURNS void LANGUAGE plpgsql SET enable_seqscan = false AS $$ BEGIN END; $$"#;
4656+
let statements3 = pg().parse_sql_statements(sql3).unwrap();
4657+
match &statements3[0] {
4658+
Statement::CreateFunction(CreateFunction { options, .. }) => {
4659+
let opts = options.as_ref().expect("should have options");
4660+
match &opts[0] {
4661+
SqlOption::KeyValue { key, value } => {
4662+
assert_eq!(key.to_string(), "enable_seqscan");
4663+
match value {
4664+
Expr::Value(ValueWithSpan { value: Value::Boolean(b), .. }) => {
4665+
assert_eq!(*b, false);
4666+
}
4667+
_ => panic!("Expected Boolean, got: {:?}", value),
4668+
}
4669+
}
4670+
_ => panic!("Expected KeyValue option"),
4671+
}
4672+
}
4673+
_ => panic!("Expected CreateFunction"),
4674+
}
4675+
}
4676+
45894677
#[test]
45904678
fn parse_drop_function() {
45914679
let sql = "DROP FUNCTION IF EXISTS test_func";

0 commit comments

Comments
 (0)