Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: statement splitter#496

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
juleswritescode merged 4 commits intomainfromfix/false-positives
Sep 5, 2025
Merged
Show file tree
Hide file tree
Changes fromall 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
85 changes: 85 additions & 0 deletionscrates/pgt_statement_splitter/src/lib.rs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -62,6 +62,32 @@ mod tests {
}

impl Tester {
fn assert_single_statement(&self) -> &Self {
assert_eq!(
self.result.ranges.len(),
1,
"Expected a single statement for input {}, got {}: {:?}",
self.input,
self.result.ranges.len(),
self.result
.ranges
.iter()
.map(|r| &self.input[*r])
.collect::<Vec<_>>()
);
self
}

fn assert_no_errors(&self) -> &Self {
assert!(
self.result.errors.is_empty(),
"Expected no errors, got {}: {:?}",
self.result.errors.len(),
self.result.errors
);
self
}

fn expect_statements(&self, expected: Vec<&str>) -> &Self {
assert_eq!(
self.result.ranges.len(),
Expand DownExpand Up@@ -114,6 +140,16 @@ mod tests {
);
}

#[test]
fn test_for_no_key_update() {
Tester::from(
"SELECT 1 FROM assessments AS a WHERE a.id = $assessment_id FOR NO KEY UPDATE;",
)
.expect_statements(vec![
"SELECT 1 FROM assessments AS a WHERE a.id = $assessment_id FOR NO KEY UPDATE;",
]);
}

#[test]
fn test_crash_eof() {
Tester::from("CREATE INDEX \"idx_analytics_read_ratio\" ON \"public\".\"message\" USING \"btree\" (\"inbox_id\", \"timestamp\") INCLUDE (\"status\") WHERE (\"is_inbound\" = false and channel_type not in ('postal'', 'sms'));")
Expand DownExpand Up@@ -256,6 +292,55 @@ mod tests {
]);
}

#[test]
fn with_recursive() {
Tester::from(
"
WITH RECURSIVE
template_questions AS (
-- non-recursive term that finds the ID of the template question (if any) for question_id
SELECT
tq.id,
tq.qid,
tq.course_id,
tq.template_directory
FROM
questions AS q
JOIN questions AS tq ON (
tq.qid = q.template_directory
AND tq.course_id = q.course_id
)
WHERE
q.id = $question_id
AND tq.deleted_at IS NULL
-- required UNION for a recursive WITH statement
UNION
-- recursive term that references template_questions again
SELECT
tq.id,
tq.qid,
tq.course_id,
tq.template_directory
FROM
template_questions AS q
JOIN questions AS tq ON (
tq.qid = q.template_directory
AND tq.course_id = q.course_id
)
WHERE
tq.deleted_at IS NULL
)
SELECT
id
FROM
template_questions
LIMIT
100;",
)
.assert_single_statement()
.assert_no_errors();
}

#[test]
fn with_check() {
Tester::from("create policy employee_insert on journey_execution for insert to authenticated with check ((select private.organisation_id()) = organisation_id);")
Expand Down
9 changes: 9 additions & 0 deletionscrates/pgt_statement_splitter/src/splitter.rs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -102,6 +102,15 @@ impl<'a> Splitter<'a> {
self.lexed.kind(self.current_pos)
}

fn eat(&mut self, kind: SyntaxKind) -> bool {
if self.current() == kind {
self.advance();
true
} else {
false
}
}

fn kind(&self, idx: usize) -> SyntaxKind {
self.lexed.kind(idx)
}
Expand Down
2 changes: 2 additions & 0 deletionscrates/pgt_statement_splitter/src/splitter/common.rs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -224,6 +224,8 @@ pub(crate) fn unknown(p: &mut Splitter, exclude: &[SyntaxKind]) {
SyntaxKind::COMMA,
// Do update in INSERT stmt
SyntaxKind::DO_KW,
// FOR NO KEY UPDATE
SyntaxKind::KEY_KW,
]
.iter()
.all(|x| Some(x) != prev.as_ref())
Expand Down
1 change: 1 addition & 0 deletionscrates/pgt_statement_splitter/src/splitter/dml.rs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@ use super::{

pub(crate) fn cte(p: &mut Splitter) {
p.expect(SyntaxKind::WITH_KW);
p.eat(SyntaxKind::RECURSIVE_KW);

loop {
p.expect(SyntaxKind::IDENT);
Expand Down
47 changes: 47 additions & 0 deletionscrates/pgt_workspace/src/workspace/server.tests.rs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -579,6 +579,53 @@ async fn test_disable_typecheck(test_db: PgPool) {
);
}

#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
async fn test_named_params(_test_db: PgPool) {
let conf = PartialConfiguration::init();

let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace");

let path = PgTPath::new("test.sql");

let content = r#"
SELECT
1
FROM
assessments AS a
WHERE
a.id = $assessment_id
FOR NO KEY UPDATE;
"#;

workspace
.open_file(OpenFileParams {
path: path.clone(),
content: content.into(),
version: 1,
})
.expect("Unable to open test file");

let diagnostics = workspace
.pull_diagnostics(crate::workspace::PullDiagnosticsParams {
path: path.clone(),
categories: RuleCategories::all(),
max_diagnostics: 100,
only: vec![],
skip: vec![],
})
.expect("Unable to pull diagnostics")
.diagnostics;

assert_eq!(
diagnostics
.iter()
.filter(|d| d.category().is_some_and(|c| c.name() == "syntax"))
.count(),
0,
"Expected no syntax diagnostic"
);
}

#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
async fn test_cstyle_comments(test_db: PgPool) {
let mut conf = PartialConfiguration::init();
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp