Skip to content

Commit f58b626

Browse files
committed
PostgreSQL: Make DO statement a named struct
1 parent 0198d07 commit f58b626

4 files changed

Lines changed: 67 additions & 24 deletions

File tree

‎src/ast/mod.rs‎

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4934,12 +4934,7 @@ pub enum Statement {
49344934
/// ```
49354935
///
49364936
/// See Postgres <https://www.postgresql.org/docs/current/sql-do.html>
4937-
Do {
4938-
/// Optional procedural language name.
4939-
language: Option<Ident>,
4940-
/// The anonymous code block, a string literal.
4941-
code: ValueWithSpan,
4942-
},
4937+
Do(DoStatement),
49434938
/// ```sql
49444939
/// NOTIFY channel [ , payload ]
49454940
/// ```
@@ -6517,13 +6512,7 @@ impl fmt::Display for Statement {
65176512
write!(f, "UNLISTEN {channel}")?;
65186513
Ok(())
65196514
}
6520-
Statement::Do { language, code } => {
6521-
write!(f, "DO ")?;
6522-
if let Some(language) = language {
6523-
write!(f, "LANGUAGE {language} ")?;
6524-
}
6525-
write!(f, "{code}")
6526-
}
6515+
Statement::Do(s) => write!(f, "{s}"),
65276516
Statement::NOTIFY { channel, payload } => {
65286517
write!(f, "NOTIFY {channel}")?;
65296518
if let Some(payload) = payload {
@@ -11599,6 +11588,33 @@ impl fmt::Display for WaitForStatement {
1159911588
}
1160011589
}
1160111590

11591+
/// PostgreSQL `DO` statement, executing an anonymous code block.
11592+
///
11593+
/// ```sql
11594+
/// DO [ LANGUAGE lang_name ] code
11595+
/// ```
11596+
///
11597+
/// See <https://www.postgresql.org/docs/current/sql-do.html>
11598+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
11599+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11600+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
11601+
pub struct DoStatement {
11602+
/// Optional procedural language name.
11603+
pub language: Option<Ident>,
11604+
/// The anonymous code block, a string literal.
11605+
pub code: ValueWithSpan,
11606+
}
11607+
11608+
impl fmt::Display for DoStatement {
11609+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
11610+
write!(f, "DO ")?;
11611+
if let Some(language) = &self.language {
11612+
write!(f, "LANGUAGE {language} ")?;
11613+
}
11614+
write!(f, "{}", self.code)
11615+
}
11616+
}
11617+
1160211618
/// Represents a `Return` statement.
1160311619
///
1160411620
/// [MsSql triggers](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql)
@@ -12451,6 +12467,12 @@ impl From<ThrowStatement> for Statement {
1245112467
}
1245212468
}
1245312469

12470+
impl From<DoStatement> for Statement {
12471+
fn from(d: DoStatement) -> Self {
12472+
Self::Do(d)
12473+
}
12474+
}
12475+
1245412476
impl From<Function> for Statement {
1245512477
fn from(f: Function) -> Self {
1245612478
Self::Call(f)

‎src/ast/spans.rs‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ use super::{
3333
AttachedToken, BeginEndStatements, CaseStatement, CloseCursor, ClusteredIndex, ColumnDef,
3434
ColumnOption, ColumnOptionDef, ConditionalStatementBlock, ConditionalStatements,
3535
ConflictTarget, ConnectByKind, ConstraintCharacteristics, CopySource, CreateIndex, CreateTable,
36-
CreateTableOptions, Cte, Delete, DoUpdate, ExceptSelectItem, ExcludeConstraintElement,
37-
ExcludeSelectItem, Expr, ExprWithAlias, Fetch, ForValues, FromTable, Function, FunctionArg,
38-
FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList, FunctionArguments, GroupByExpr,
39-
HavingBound, IfStatement, IlikeSelectItem, IndexColumn, Insert, Interpolate, InterpolateExpr,
40-
Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView, LimitClause,
41-
MatchRecognizePattern, Measure, Merge, MergeAction, MergeClause, MergeInsertExpr,
42-
MergeInsertKind, MergeUpdateExpr, MergeUpdateKind, NamedParenthesizedList,
36+
CreateTableOptions, Cte, Delete, DoStatement, DoUpdate, ExceptSelectItem,
37+
ExcludeConstraintElement, ExcludeSelectItem, Expr, ExprWithAlias, Fetch, ForValues, FromTable,
38+
Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList,
39+
FunctionArguments, GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, IndexColumn, Insert,
40+
Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem,
41+
LateralView, LimitClause, MatchRecognizePattern, Measure, Merge, MergeAction, MergeClause,
42+
MergeInsertExpr, MergeInsertKind, MergeUpdateExpr, MergeUpdateKind, NamedParenthesizedList,
4343
NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
4444
OnInsert, OpenStatement, OrderBy, OrderByExpr, OrderByKind, OutputClause, Parens, Partition,
4545
PartitionBoundValue, PivotValueSource, ProjectionSelect, Query, RaiseStatement,
@@ -498,7 +498,7 @@ impl Spanned for Statement {
498498
Statement::ShowObjects { .. } => Span::empty(),
499499
Statement::ShowViews { .. } => Span::empty(),
500500
Statement::LISTEN { .. } => Span::empty(),
501-
Statement::Do { .. } => Span::empty(),
501+
Statement::Do(s) => s.span(),
502502
Statement::NOTIFY { .. } => Span::empty(),
503503
Statement::LoadData { .. } => Span::empty(),
504504
Statement::UNLISTEN { .. } => Span::empty(),
@@ -2633,6 +2633,18 @@ impl Spanned for comments::CommentWithSpan {
26332633
}
26342634
}
26352635

2636+
impl Spanned for DoStatement {
2637+
fn span(&self) -> Span {
2638+
let DoStatement { language, code } = self;
2639+
union_spans(
2640+
language
2641+
.iter()
2642+
.map(|l| l.span)
2643+
.chain(core::iter::once(code.span)),
2644+
)
2645+
}
2646+
}
2647+
26362648
#[cfg(test)]
26372649
pub mod tests {
26382650
use crate::ast::Value;
@@ -3197,4 +3209,13 @@ WHERE id = 1
31973209
stmt => panic!("expected ALTER TABLE; got {stmt:?}"),
31983210
}
31993211
}
3212+
3213+
#[test]
3214+
fn test_do_statement_span() {
3215+
let dialect = &crate::dialect::PostgreSqlDialect {};
3216+
let sql = "DO LANGUAGE plpgsql $$BEGIN NULL; END$$";
3217+
let test = SpanTest::new(dialect, sql);
3218+
let r = Parser::parse_sql(dialect, sql).unwrap();
3219+
assert_eq!(test.get_source(r[0].span()), "plpgsql $$BEGIN NULL; END$$");
3220+
}
32003221
}

‎src/parser/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,7 @@ impl<'a> Parser<'a> {
15201520
if language.is_none() {
15211521
language = self.parse_do_language()?;
15221522
}
1523-
Ok(Statement::Do { language, code })
1523+
Ok(Statement::Do(DoStatement { language, code }))
15241524
}
15251525

15261526
fn parse_do_language(&mut self) -> Result<Option<Ident>, ParserError> {

‎tests/sqlparser_common.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20439,7 +20439,7 @@ fn parse_do_statement() {
2043920439
let dialects = all_dialects_where(|d| d.supports_do_statement());
2044020440

2044120441
match dialects.verified_stmt("DO $$BEGIN RAISE NOTICE 'hi'; END$$") {
20442-
Statement::Do { language, code } => {
20442+
Statement::Do(DoStatement { language, code }) => {
2044320443
assert_eq!(language, None);
2044420444
assert_eq!(
2044520445
code.value,
@@ -20453,7 +20453,7 @@ fn parse_do_statement() {
2045320453
}
2045420454

2045520455
match dialects.verified_stmt("DO LANGUAGE plpgsql $body$BEGIN NULL; END$body$") {
20456-
Statement::Do { language, .. } => {
20456+
Statement::Do(DoStatement { language, .. }) => {
2045720457
assert_eq!(language, Some(Ident::new("plpgsql")));
2045820458
}
2045920459
_ => unreachable!(),

0 commit comments

Comments
 (0)