Skip to content

Commit b31d30c

Browse files
committed
Add SETOF support for PostgreSQL function return types
1 parent 15dc6a2 commit b31d30c

File tree

5 files changed

+35
-27
lines changed

5 files changed

+35
-27
lines changed

src/ast/data_type.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ pub enum DataType {
6161
/// Table columns.
6262
columns: Vec<ColumnDef>,
6363
},
64+
/// SETOF type modifier for [PostgreSQL] function return types,
65+
/// e.g. `CREATE FUNCTION ... RETURNS SETOF text`.
66+
///
67+
/// [PostgreSQL]: https://www.postgresql.org/docs/current/sql-createfunction.html
68+
SetOf(Box<DataType>),
6469
/// Fixed-length character type, e.g. CHARACTER(10).
6570
Character(Option<CharacterLength>),
6671
/// Fixed-length char type, e.g. CHAR(10).
@@ -808,6 +813,7 @@ impl fmt::Display for DataType {
808813
DataType::NamedTable { name, columns } => {
809814
write!(f, "{} TABLE ({})", name, display_comma_separated(columns))
810815
}
816+
DataType::SetOf(inner) => write!(f, "SETOF {inner}"),
811817
DataType::GeometricType(kind) => write!(f, "{kind}"),
812818
DataType::TsVector => write!(f, "TSVECTOR"),
813819
DataType::TsQuery => write!(f, "TSQUERY"),

src/ast/spans.rs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -632,33 +632,6 @@ impl Spanned for TableConstraint {
632632
}
633633
}
634634

635-
impl Spanned for PartitionBoundValue {
636-
fn span(&self) -> Span {
637-
match self {
638-
PartitionBoundValue::Expr(expr) => expr.span(),
639-
// MINVALUE and MAXVALUE are keywords without tracked spans
640-
PartitionBoundValue::MinValue => Span::empty(),
641-
PartitionBoundValue::MaxValue => Span::empty(),
642-
}
643-
}
644-
}
645-
646-
impl Spanned for ForValues {
647-
fn span(&self) -> Span {
648-
match self {
649-
ForValues::In(exprs) => union_spans(exprs.iter().map(|e| e.span())),
650-
ForValues::From { from, to } => union_spans(
651-
from.iter()
652-
.map(|v| v.span())
653-
.chain(to.iter().map(|v| v.span())),
654-
),
655-
// WITH (MODULUS n, REMAINDER r) - u64 values have no spans
656-
ForValues::With { .. } => Span::empty(),
657-
ForValues::Default => Span::empty(),
658-
}
659-
}
660-
}
661-
662635
impl Spanned for CreateIndex {
663636
fn span(&self) -> Span {
664637
let CreateIndex {

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,7 @@ define_keywords!(
933933
SESSION_USER,
934934
SET,
935935
SETERROR,
936+
SETOF,
936937
SETS,
937938
SETTINGS,
938939
SHARE,

src/parser/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12064,6 +12064,10 @@ impl<'a> Parser<'a> {
1206412064
let field_defs = self.parse_click_house_tuple_def()?;
1206512065
Ok(DataType::Tuple(field_defs))
1206612066
}
12067+
Keyword::SETOF => {
12068+
let inner = self.parse_data_type()?;
12069+
Ok(DataType::SetOf(Box::new(inner)))
12070+
}
1206712071
Keyword::TRIGGER => Ok(DataType::Trigger),
1206812072
Keyword::ANY if self.peek_keyword(Keyword::TYPE) => {
1206912073
let _ = self.parse_keyword(Keyword::TYPE);

tests/sqlparser_postgres.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4603,6 +4603,30 @@ fn parse_create_function_detailed() {
46034603
);
46044604
}
46054605

4606+
#[test]
4607+
fn parse_create_function_returns_setof() {
4608+
pg_and_generic().verified_stmt(
4609+
"CREATE FUNCTION get_users() RETURNS SETOF TEXT LANGUAGE sql AS 'SELECT name FROM users'",
4610+
);
4611+
pg_and_generic().verified_stmt(
4612+
"CREATE FUNCTION get_ids() RETURNS SETOF INTEGER LANGUAGE sql AS 'SELECT id FROM users'",
4613+
);
4614+
pg_and_generic().verified_stmt(
4615+
r#"CREATE FUNCTION get_all() RETURNS SETOF my_schema."MyType" LANGUAGE sql AS 'SELECT * FROM t'"#,
4616+
);
4617+
pg_and_generic().verified_stmt(
4618+
"CREATE FUNCTION get_rows() RETURNS SETOF RECORD LANGUAGE sql AS 'SELECT * FROM t'",
4619+
);
4620+
4621+
let sql = "CREATE FUNCTION get_names() RETURNS SETOF TEXT LANGUAGE sql AS 'SELECT name FROM t'";
4622+
match pg_and_generic().verified_stmt(sql) {
4623+
Statement::CreateFunction(CreateFunction { return_type, .. }) => {
4624+
assert_eq!(return_type, Some(DataType::SetOf(Box::new(DataType::Text))));
4625+
}
4626+
_ => panic!("Expected CreateFunction"),
4627+
}
4628+
}
4629+
46064630
#[test]
46074631
fn parse_create_function_with_security() {
46084632
let sql =

0 commit comments

Comments
 (0)