Skip to content
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
1 change: 1 addition & 0 deletions crates/squawk_parser/src/generated/syntax_kind.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 29 additions & 5 deletions crates/squawk_parser/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9173,7 +9173,7 @@ fn publication_object(p: &mut Parser<'_>) {
}

// CREATE PUBLICATION name
// [ FOR ALL TABLES
// [ FOR ALL TABLES [ EXCEPT TABLE ( relation_name [, ...] ) ]
// | FOR publication_object [, ... ] ]
// [ WITH ( publication_parameter [= value] [, ... ] ) ]
//
Expand All @@ -9192,6 +9192,7 @@ fn create_publication(p: &mut Parser<'_>) -> CompletedMarker {
while !p.at(EOF) && p.eat(COMMA) {
publication_all_object(p);
}
opt_except_table_clause(p);
} else {
publication_object(p);
while !p.at(EOF) && p.eat(COMMA) {
Expand All @@ -9213,6 +9214,26 @@ fn publication_all_object(p: &mut Parser<'_>) {
}
}

fn opt_except_table_clause(p: &mut Parser<'_>) {
if !p.at(EXCEPT_KW) {
return;
}

let m = p.start();
p.bump(EXCEPT_KW);
p.expect(TABLE_KW);
delimited(
p,
L_PAREN,
R_PAREN,
COMMA,
|| "unexpected comma".to_string(),
RELATION_NAME_FIRST,
|p| opt_relation_name(p).is_some(),
);
m.complete(p, EXCEPT_TABLE_CLAUSE);
}

// CREATE ROLE name [ [ WITH ] option [ ... ] ]
// where option can be:
// SUPERUSER | NOSUPERUSER
Expand Down Expand Up @@ -13656,13 +13677,19 @@ const NON_RESERVED_WORD: TokenSet = TokenSet::new(&[IDENT])
.union(COLUMN_NAME_KEYWORDS)
.union(TYPE_FUNC_NAME_KEYWORDS);

const RELATION_NAME_FIRST: TokenSet = TokenSet::new(&[ONLY_KW]).union(PATH_FIRST);

fn relation_name(p: &mut Parser<'_>) {
if opt_relation_name(p).is_none() {
p.error("expected relation name");
}
}

fn opt_relation_name(p: &mut Parser<'_>) -> Option<CompletedMarker> {
if !p.at_ts(RELATION_NAME_FIRST) {
return None;
}

let m = p.start();
if p.eat(ONLY_KW) {
let trailing_paren = p.eat(L_PAREN);
Expand All @@ -13672,10 +13699,7 @@ fn opt_relation_name(p: &mut Parser<'_>) -> Option<CompletedMarker> {
p.expect(R_PAREN);
}
} else {
if opt_path_name_ref(p).is_none() {
m.abandon(p);
return None;
};
path_name_ref(p);
p.eat(STAR);
}
Some(m.complete(p, RELATION_NAME))
Expand Down
49 changes: 49 additions & 0 deletions crates/squawk_syntax/src/ast/generated/nodes.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion crates/squawk_syntax/src/postgresql.ungram
Original file line number Diff line number Diff line change
Expand Up @@ -2300,9 +2300,12 @@ CreateProcedure =

CreatePublication =
'create' 'publication' Name
('for' 'all' 'tables' | 'for' (PublicationObject (',' PublicationObject)*))
('for' 'all' 'tables' ExceptTableClause? | 'for' (PublicationObject (',' PublicationObject)*))
WithParams?

ExceptTableClause =
'except' 'table' '(' (RelationName (',' RelationName)*) ')'

PublicationObject =
'table' 'only'? (Path | '(' Path ')') '*'? ColumnList? WhereConditionClause?
| 'tables' 'in' 'schema' ('current_schema' | NameRef) WhereConditionClause?
Expand Down
6 changes: 3 additions & 3 deletions postgres/kwlist.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// synced from:
// commit: ef3c3cf6d021ff9884c513afd850a9fe85cad736
// committed at: 2026-02-14T06:50:06Z
// file: https://github.com/postgres/postgres/blob/ef3c3cf6d021ff9884c513afd850a9fe85cad736/src/include/parser/kwlist.h
// commit: f95d73ed433207c4323802dc96e52f3e5553a86c
// committed at: 2026-03-05T22:43:09Z
// file: https://github.com/postgres/postgres/blob/f95d73ed433207c4323802dc96e52f3e5553a86c/src/include/parser/kwlist.h
//
// update via:
// cargo xtask sync-kwlist
Expand Down
6 changes: 6 additions & 0 deletions postgres/regression_suite/aggregates.sql
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,12 @@ select f2, count(*) from
t1 x(x0,x1) left join (t1 left join t2 using(f2)) on (x0 = 0)
group by f2;

-- check that we preserve join alias in GROUP BY expressions
create temp view v1 as
select f1::int from t1 left join t2 using (f1) group by f1;
select pg_get_viewdef('v1'::regclass);

drop view v1;
drop table t1, t2;

--
Expand Down
8 changes: 8 additions & 0 deletions postgres/regression_suite/alter_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2331,6 +2331,14 @@ ALTER TABLE test_add_column
-- \d test_add_column
ALTER TABLE test_add_column
ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 10);
ALTER TABLE test_add_column
ADD c6 integer; -- omit COLUMN
ALTER TABLE test_add_column
ADD IF NOT EXISTS c6 integer;
ALTER TABLE test_add_column
DROP c6; -- omit COLUMN
ALTER TABLE test_add_column
DROP IF EXISTS c6;
-- \d test_add_column*
DROP TABLE test_add_column;
-- \d test_add_column*
Expand Down
43 changes: 43 additions & 0 deletions postgres/regression_suite/copy2.sql
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,15 @@ COPY x from stdin (force_null (a), force_null (b));
COPY x from stdin (convert_selectively (a), convert_selectively (b));
COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii');
COPY x from stdin (on_error ignore, on_error ignore);
COPY x from stdin (on_error set_null, on_error set_null);
COPY x from stdin (log_verbosity default, log_verbosity verbose);
--
-- -- incorrect options
COPY x from stdin (format BINARY, delimiter ',');
COPY x from stdin (format BINARY, null 'x');
COPY x from stdin (format BINARY, on_error ignore);
COPY x from stdin (format BINARY, on_error set_null);
COPY x from stdin (on_error set_null, reject_limit 2);
COPY x from stdin (on_error unsupported);
COPY x from stdin (format TEXT, force_quote(a));
COPY x from stdin (format TEXT, force_quote *);
Expand All @@ -87,6 +90,7 @@ COPY x from stdin (format TEXT, force_null *);
-- COPY x to stdout (format CSV, force_null(a));
COPY x to stdout (format CSV, force_null *);
COPY x to stdout (format BINARY, on_error unsupported);
COPY x to stdout (on_error set_null);
COPY x from stdin (log_verbosity unsupported);
COPY x from stdin with (reject_limit 1);
COPY x from stdin with (on_error ignore, reject_limit 0);
Expand Down Expand Up @@ -540,6 +544,42 @@ COPY check_ign_err FROM STDIN WITH (on_error ignore, log_verbosity verbose);
-- 8 {8} 8
-- \.

CREATE DOMAIN d_int_not_null AS integer NOT NULL CHECK (value > 0);
CREATE DOMAIN d_int_positive_maybe_null AS integer CHECK (value > 0);
CREATE TABLE t_on_error_null (a d_int_not_null, b d_int_positive_maybe_null, c integer);

-- \pset null NULL
COPY t_on_error_null FROM STDIN WITH (on_error set_null); -- fail
-- \N 11 13
-- \.

COPY t_on_error_null FROM STDIN WITH (on_error set_null); -- fail
-- ss 11 14
-- \.

COPY t_on_error_null FROM STDIN WITH (on_error set_null); -- fail
-- -1 11 13
-- \.

-- fail, less data.
COPY t_on_error_null FROM STDIN WITH (delimiter ',', on_error set_null);
-- 1,1
-- \.
-- fail, extra data.
COPY t_on_error_null FROM STDIN WITH (delimiter ',', on_error set_null);
-- 1,2,3,4
-- \.

COPY t_on_error_null FROM STDIN WITH (on_error set_null, log_verbosity verbose); -- ok
-- 10 x1 yx
-- 11 zx 12
-- 13 14 ea
-- \.

SELECT * FROM t_on_error_null ORDER BY a;

-- \pset null ''

-- tests for on_error option with log_verbosity and null constraint via domain
CREATE DOMAIN dcheck_ign_err2 varchar(15) NOT NULL;
CREATE TABLE check_ign_err2 (n int, m int[], k int, l dcheck_ign_err2);
Expand Down Expand Up @@ -609,6 +649,9 @@ DROP VIEW instead_of_insert_tbl_view;
DROP VIEW instead_of_insert_tbl_view_2;
DROP FUNCTION fun_instead_of_insert_tbl();
DROP TABLE check_ign_err;
DROP TABLE t_on_error_null;
DROP DOMAIN d_int_not_null;
DROP DOMAIN d_int_positive_maybe_null;
DROP TABLE check_ign_err2;
DROP DOMAIN dcheck_ign_err2;
DROP TABLE hard_err;
Expand Down
4 changes: 4 additions & 0 deletions postgres/regression_suite/create_index.sql
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ CREATE INDEX six ON shighway USING btree (name text_ops);
COMMENT ON INDEX six_wrong IS 'bad index';
COMMENT ON INDEX six IS 'good index';
COMMENT ON INDEX six IS NULL;
SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null;
COMMENT ON INDEX six IS 'add the comment back';
COMMENT ON INDEX six IS ''; -- empty string removes the comment, same as NULL
SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null;

--
-- BTREE partial indices
Expand Down
7 changes: 7 additions & 0 deletions postgres/regression_suite/create_role.sql
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ CREATE ROLE regress_hasprivs CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5;

-- ok, we should be able to modify a role we created
COMMENT ON ROLE regress_hasprivs IS 'some comment';
SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment;
COMMENT ON ROLE regress_hasprivs IS NULL;
SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment;
COMMENT ON ROLE regress_hasprivs IS 'add the comment back';
SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment;
COMMENT ON ROLE regress_hasprivs IS ''; -- empty string removes the comment, same as NULL
SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment;
ALTER ROLE regress_hasprivs RENAME TO regress_tenant;
ALTER ROLE regress_tenant NOINHERIT NOLOGIN CONNECTION LIMIT 7;

Expand Down
7 changes: 7 additions & 0 deletions postgres/regression_suite/create_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ SAVEPOINT q; DROP TABLE remember_node_subid; ROLLBACK TO q;
COMMIT;
DROP TABLE remember_node_subid;

-- generated NOT NULL constraint names must not collide with explicitly named constraints
CREATE TABLE two_not_null_constraints (
col integer NOT NULL,
CONSTRAINT two_not_null_constraints_col_not_null CHECK (col IS NOT NULL)
);
DROP TABLE two_not_null_constraints;

--
-- Partitioned tables
--
Expand Down
21 changes: 20 additions & 1 deletion postgres/regression_suite/encoding.sql
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ SELECT reverse(good) FROM regress_encoding;

-- invalid short mb character = error
SELECT length(truncated) FROM regress_encoding;
SELECT substring(truncated, 1, 1) FROM regress_encoding;
SELECT substring(truncated, 1, 3) FROM regress_encoding;
SELECT substring(truncated, 1, 4) FROM regress_encoding;
SELECT reverse(truncated) FROM regress_encoding;
-- invalid short mb character = silently dropped
SELECT regexp_replace(truncated, '^caf(.)$', '\1') FROM regress_encoding;
Expand Down Expand Up @@ -212,9 +213,27 @@ INSERT INTO encoding_tests VALUES
SELECT COUNT(test_encoding(encoding, description, input)) > 0
FROM encoding_tests;

-- substring fetches a slice of a toasted value; unused tail of that slice is
-- an incomplete char (bug #19406)
CREATE TABLE toast_3b_utf8 (c text);
INSERT INTO toast_3b_utf8 VALUES (repeat(U&'\2026', 4000));
SELECT SUBSTRING(c FROM 1 FOR 1) FROM toast_3b_utf8;
SELECT SUBSTRING(c FROM 4001 FOR 1) FROM toast_3b_utf8;
-- diagnose incomplete char iff within the substring
UPDATE toast_3b_utf8 SET c = c || test_bytea_to_text('\xe280');
SELECT SUBSTRING(c FROM 4000 FOR 1) FROM toast_3b_utf8;
SELECT SUBSTRING(c FROM 4001 FOR 1) FROM toast_3b_utf8;
-- substring needing last byte of its slice_size
ALTER TABLE toast_3b_utf8 RENAME TO toast_4b_utf8;
UPDATE toast_4b_utf8 SET c = repeat(U&'\+01F680', 3000);
SELECT SUBSTRING(c FROM 3000 FOR 1) FROM toast_4b_utf8;

DROP TABLE encoding_tests;
DROP TABLE toast_4b_utf8;
DROP FUNCTION test_encoding;
DROP FUNCTION test_wchars_to_text;
DROP FUNCTION test_text_to_wchars;
DROP FUNCTION test_valid_server_encoding;
DROP FUNCTION test_mblen_func;
DROP FUNCTION test_bytea_to_text;
DROP FUNCTION test_text_to_bytea;
Expand Down
7 changes: 6 additions & 1 deletion postgres/regression_suite/event_trigger.sql
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,12 @@ CREATE SCHEMA evttrig
CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two', col_c SERIAL)
CREATE INDEX one_idx ON one (col_b)
CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42)
CREATE TABLE id (col_d int NOT NULL GENERATED ALWAYS AS IDENTITY);
CREATE TABLE id (col_d int NOT NULL GENERATED ALWAYS AS IDENTITY)
CREATE VIEW one_view AS SELECT * FROM two;

-- View with column additions
CREATE OR REPLACE VIEW evttrig.one_view AS SELECT * FROM evttrig.two, evttrig.id;
DROP VIEW evttrig.one_view;

-- Partitioned tables with a partitioned index
CREATE TABLE evttrig.parted (
Expand Down
Loading
Loading