Skip to content

fix: plpglsql cmds #336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions crates/pgt_statement_splitter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ mod tests {
)]);
}

#[test]
fn command_between_not_starting() {
Tester::from("select 1\n \\com test\nselect 2")
.expect_statements(vec!["select 1", "select 2"]);
}

#[test]
fn command_between() {
Tester::from("select 1\n\\com test\nselect 2")
.expect_statements(vec!["select 1", "select 2"]);
}

#[test]
fn command_standalone() {
Tester::from("select 1\n\n\\com test\n\nselect 2")
.expect_statements(vec!["select 1", "select 2"]);
}

#[test]
fn insert_with_select() {
Tester::from("\ninsert into tbl (id) select 1\n\nselect 3")
Expand Down
3 changes: 3 additions & 0 deletions crates/pgt_statement_splitter/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ impl Parser {
}
}

/// Advances the parser to the next relevant token and returns it.
///
/// NOTE: This will skip irrelevant tokens.
fn advance(&mut self) -> &Token {
// can't reuse any `find_next_relevant` logic because of Mr. Borrow Checker
let (pos, token) = self
Expand Down
56 changes: 55 additions & 1 deletion crates/pgt_statement_splitter/src/parser/common.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use pgt_lexer::{SyntaxKind, Token, TokenType};
use pgt_lexer::{SyntaxKind, Token, TokenType, WHITESPACE_TOKENS};

use super::{
Parser,
Expand All @@ -24,6 +24,12 @@ pub fn source(p: &mut Parser) {
} => {
p.advance();
}
Token {
kind: SyntaxKind::Ascii92,
..
} => {
plpgsql_command(p);
}
_ => {
statement(p);
}
Expand Down Expand Up @@ -87,6 +93,24 @@ pub(crate) fn parenthesis(p: &mut Parser) {
}
}

pub(crate) fn plpgsql_command(p: &mut Parser) {
p.expect(SyntaxKind::Ascii92);

loop {
match p.current().kind {
SyntaxKind::Newline => {
p.advance();
break;
}
_ => {
// advance the parser to the next token without ignoring irrelevant tokens
// we would skip a newline with `advance()`
p.current_pos += 1;
}
}
}
}

pub(crate) fn case(p: &mut Parser) {
p.expect(SyntaxKind::Case);

Expand Down Expand Up @@ -125,6 +149,36 @@ pub(crate) fn unknown(p: &mut Parser, exclude: &[SyntaxKind]) {
} => {
case(p);
}
Token {
kind: SyntaxKind::Ascii92,
..
} => {
// pgsql commands e.g.
//
// ```
// \if test
// ```
//
// we wait for "\" and check if the previous token is a newline

// newline is a whitespace, but we do not want to ignore it here
let irrelevant = WHITESPACE_TOKENS
.iter()
.filter(|t| **t != SyntaxKind::Newline)
.collect::<Vec<_>>();

// go back from the current position without ignoring irrelevant tokens
if p.tokens
.iter()
.take(p.current_pos)
.rev()
.find(|t| !irrelevant.contains(&&t.kind))
.is_some_and(|t| t.kind == SyntaxKind::Newline)
{
break;
}
p.advance();
}
Token {
kind: SyntaxKind::Ascii40,
..
Expand Down