-
Notifications
You must be signed in to change notification settings - Fork 40
Description
PostgreSQL supports the ONLY keyword in DELETE and UPDATE to prevent scanning child tables in an inheritance hierarchy:
DELETE FROM ONLY archived_employees WHERE archived_at < NOW() - INTERVAL '1 year';
UPDATE ONLY parent_table SET status = 'inactive' WHERE id = 1;
Current behavior:
DELETE FROM ONLY archived_employees parses successfully but treats ONLY as the table name:
Delete.table.name = "ONLY"
Delete.table.only = false
UPDATE ONLY parent_table SET status = 'inactive' fails with:
Parse error: Expected identifier, got "Only"
Expected behavior:
Both should parse with table.name = "archived_employees" / "parent_table" and table.only = true, consistent with how parse_table_expression() handles ONLY in SELECT FROM clauses.
Root cause:
parse_table_expression() (line ~3086 in parser.rs) correctly handles ONLY:
let has_only = self.match_token(TokenType::Only);
// ... parse table ...
if has_only {
if let Expression::Table(ref mut table) = expr {
table.only = true;
}
}
But parse_delete() (line ~10082) calls parse_table_ref() directly after consuming FROM, and parse_update() (line ~9737) calls expect_identifier_with_quoted() directly. Neither consumes the ONLY token first.
Suggested fix:
In parse_delete, after consuming FROM, check for and consume ONLY before calling parse_table_ref(), then set table.only = true on the resulting TableRef.
In parse_update, after consuming UPDATE, check for and consume ONLY before parsing the table identifier, then set table.only = true.
Affected dialects: PostgreSQL (and any dialect using inheritance with ONLY).
Reproduction:
use polyglot_sql::{parse_one, DialectType};
use polyglot_sql::expressions::Expression;
let expr = parse_one(
"DELETE FROM ONLY archived_employees WHERE archived_at < NOW() - INTERVAL '1 year'",
DialectType::PostgreSQL,
).unwrap();
if let Expression::Delete(d) = &expr {
assert_eq!(d.table.name.name, "archived_employees"); // FAILS: actual = "ONLY"
assert!(d.table.only); // FAILS: actual = false
}