Skip to content

Commit 5f95301

Browse files
authored
fix(parser): handle case where table etl is a constraint (#71)
Previously squawk assumed that a tableEtl could only be a column type. Seems the doc comment in the PG source is incorrect: https://github.com/postgres/postgres/blob/20d3fe9009ddbbbb3da3a2da298f922054b43f8c/src/include/nodes/parsenodes.h#L2075 rel: #70
1 parent 7c6c4a7 commit 5f95301

File tree

5 files changed

+199
-11
lines changed

5 files changed

+199
-11
lines changed

linter/src/rules/ban_char_field.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ pub fn ban_char_type(tree: &[RootStmt]) -> Vec<RuleViolation> {
77
for RootStmt::RawStmt(raw_stmt) in tree {
88
match &raw_stmt.stmt {
99
Stmt::CreateStmt(stmt) => {
10-
for TableElt::ColumnDef(column_def) in &stmt.table_elts {
11-
let ColumnDefTypeName::TypeName(type_name) = &column_def.type_name;
12-
for QualifiedName::String(field_type_name) in &type_name.names {
13-
if field_type_name.str == "bpchar" {
14-
errs.push(RuleViolation::new(
15-
RuleViolationKind::BanCharField,
16-
raw_stmt,
17-
None,
18-
));
10+
for column_def in &stmt.table_elts {
11+
if let TableElt::ColumnDef(column_def) = column_def {
12+
let ColumnDefTypeName::TypeName(type_name) = &column_def.type_name;
13+
for QualifiedName::String(field_type_name) in &type_name.names {
14+
if field_type_name.str == "bpchar" {
15+
errs.push(RuleViolation::new(
16+
RuleViolationKind::BanCharField,
17+
raw_stmt,
18+
None,
19+
));
20+
}
1921
}
2022
}
2123
}

linter/src/rules/prefer_text_field.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ pub fn prefer_text_field(tree: &[RootStmt]) -> Vec<RuleViolation> {
1313
for RootStmt::RawStmt(raw_stmt) in tree {
1414
match &raw_stmt.stmt {
1515
Stmt::CreateStmt(stmt) => {
16-
for TableElt::ColumnDef(column_def) in &stmt.table_elts {
17-
check_column_def(&mut errs, raw_stmt, column_def)
16+
for column_def in &stmt.table_elts {
17+
if let TableElt::ColumnDef(column_def) = column_def {
18+
check_column_def(&mut errs, raw_stmt, column_def)
19+
}
1820
}
1921
}
2022
Stmt::AlterTableStmt(stmt) => {

parser/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ pub struct RenameStmt {
679679
#[derive(Debug, Deserialize, Serialize)]
680680
pub enum TableElt {
681681
ColumnDef(ColumnDef),
682+
Constraint(Constraint),
682683
}
683684

684685
/// What to do at commit time for temporary relations

parser/src/parse.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,20 @@ ALTER SUBSCRIPTION mysub DISABLE;
12041204
fn test_drop_subscription_stmt() {
12051205
let sql = r#"
12061206
DROP SUBSCRIPTION mysub;
1207+
"#;
1208+
let res = parse_sql_query(sql);
1209+
assert_debug_snapshot!(res);
1210+
}
1211+
1212+
#[test]
1213+
fn test_parse_create_table_regression() {
1214+
let sql = r#"
1215+
CREATE TABLE example (
1216+
a integer,
1217+
b integer,
1218+
c integer,
1219+
PRIMARY KEY (a, c)
1220+
);
12071221
"#;
12081222
let res = parse_sql_query(sql);
12091223
assert_debug_snapshot!(res);
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
source: parser/src/parse.rs
3+
expression: res
4+
---
5+
Ok(
6+
[
7+
RawStmt(
8+
RawStmt {
9+
stmt: CreateStmt(
10+
CreateStmt {
11+
relation: RangeVar(
12+
RangeVar {
13+
catalogname: None,
14+
schemaname: None,
15+
relname: "example",
16+
inh: true,
17+
relpersistence: "p",
18+
alias: None,
19+
location: 14,
20+
},
21+
),
22+
table_elts: [
23+
ColumnDef(
24+
ColumnDef {
25+
colname: Some(
26+
"a",
27+
),
28+
type_name: TypeName(
29+
TypeName {
30+
names: [
31+
String(
32+
PGString {
33+
str: "pg_catalog",
34+
},
35+
),
36+
String(
37+
PGString {
38+
str: "int4",
39+
},
40+
),
41+
],
42+
type_oid: None,
43+
setof: false,
44+
pct_type: false,
45+
typmods: [],
46+
typemod: -1,
47+
array_bounds: [],
48+
location: 30,
49+
},
50+
),
51+
constraints: [],
52+
is_local: true,
53+
location: 28,
54+
},
55+
),
56+
ColumnDef(
57+
ColumnDef {
58+
colname: Some(
59+
"b",
60+
),
61+
type_name: TypeName(
62+
TypeName {
63+
names: [
64+
String(
65+
PGString {
66+
str: "pg_catalog",
67+
},
68+
),
69+
String(
70+
PGString {
71+
str: "int4",
72+
},
73+
),
74+
],
75+
type_oid: None,
76+
setof: false,
77+
pct_type: false,
78+
typmods: [],
79+
typemod: -1,
80+
array_bounds: [],
81+
location: 45,
82+
},
83+
),
84+
constraints: [],
85+
is_local: true,
86+
location: 43,
87+
},
88+
),
89+
ColumnDef(
90+
ColumnDef {
91+
colname: Some(
92+
"c",
93+
),
94+
type_name: TypeName(
95+
TypeName {
96+
names: [
97+
String(
98+
PGString {
99+
str: "pg_catalog",
100+
},
101+
),
102+
String(
103+
PGString {
104+
str: "int4",
105+
},
106+
),
107+
],
108+
type_oid: None,
109+
setof: false,
110+
pct_type: false,
111+
typmods: [],
112+
typemod: -1,
113+
array_bounds: [],
114+
location: 60,
115+
},
116+
),
117+
constraints: [],
118+
is_local: true,
119+
location: 58,
120+
},
121+
),
122+
Constraint(
123+
Constraint {
124+
contype: Primary,
125+
location: 73,
126+
raw_expr: None,
127+
keys: Some(
128+
Array([
129+
Object({
130+
"String": Object({
131+
"str": String(
132+
"a",
133+
),
134+
}),
135+
}),
136+
Object({
137+
"String": Object({
138+
"str": String(
139+
"c",
140+
),
141+
}),
142+
}),
143+
]),
144+
),
145+
indexname: None,
146+
skip_validation: false,
147+
initially_valid: false,
148+
},
149+
),
150+
],
151+
inh_relations: [],
152+
partbound: None,
153+
partspec: None,
154+
of_typename: None,
155+
constraints: [],
156+
options: [],
157+
oncommit: Noop,
158+
tablespacename: None,
159+
if_not_exists: false,
160+
},
161+
),
162+
stmt_location: 0,
163+
stmt_len: Some(
164+
93,
165+
),
166+
},
167+
),
168+
],
169+
)

0 commit comments

Comments
 (0)