Skip to content

Commit 1d127af

Browse files
committed
fix: harden PostgreSQL statement type mapping
1 parent 599ad46 commit 1d127af

3 files changed

Lines changed: 70 additions & 148 deletions

File tree

tests/pg_compat/statement_type_cases.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ void test_result_names() {
5454
for (const auto& test_case : cases) {
5555
assert(std::strcmp(pg_compat::result_name(test_case.result), test_case.name) == 0);
5656
}
57+
58+
assert(std::strcmp(
59+
pg_compat::result_name(static_cast<CompatibilityResult>(999)),
60+
"ERROR") == 0);
5761
}
5862

5963
void test_default_and_simple_mappings() {

tools/pg_compat/result.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ inline const char* result_name(CompatibilityResult result) {
3030
case CompatibilityResult::OracleRejected:
3131
return "ORACLE_REJECTED";
3232
}
33-
return "UNKNOWN";
33+
return "ERROR";
3434
}
3535

3636
} // namespace pg_compat

tools/pg_compat/statement_type_map.cpp

Lines changed: 65 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,60 @@
22

33
namespace pg_compat {
44

5+
#define PG_COMPAT_SIMPLE_STATEMENT_TYPE_MAPPINGS(X) \
6+
X(PG_QUERY__NODE__NODE_SELECT_STMT, Equivalent, SELECT) \
7+
X(PG_QUERY__NODE__NODE_INSERT_STMT, Equivalent, INSERT) \
8+
X(PG_QUERY__NODE__NODE_UPDATE_STMT, Equivalent, UPDATE) \
9+
X(PG_QUERY__NODE__NODE_DELETE_STMT, Equivalent, DELETE_STMT) \
10+
X(PG_QUERY__NODE__NODE_VARIABLE_SET_STMT, Equivalent, SET) \
11+
X(PG_QUERY__NODE__NODE_VARIABLE_SHOW_STMT, Equivalent, SHOW) \
12+
X(PG_QUERY__NODE__NODE_PREPARE_STMT, Equivalent, PREPARE) \
13+
X(PG_QUERY__NODE__NODE_EXECUTE_STMT, Equivalent, EXECUTE) \
14+
X(PG_QUERY__NODE__NODE_DEALLOCATE_STMT, Equivalent, DEALLOCATE) \
15+
X(PG_QUERY__NODE__NODE_EXPLAIN_STMT, Equivalent, EXPLAIN) \
16+
X(PG_QUERY__NODE__NODE_CALL_STMT, Equivalent, CALL) \
17+
X(PG_QUERY__NODE__NODE_DO_STMT, Equivalent, DO_STMT) \
18+
X(PG_QUERY__NODE__NODE_TRUNCATE_STMT, Equivalent, TRUNCATE) \
19+
X(PG_QUERY__NODE__NODE_LOCK_STMT, Equivalent, LOCK) \
20+
X(PG_QUERY__NODE__NODE_CREATE_STMT, Equivalent, CREATE) \
21+
X(PG_QUERY__NODE__NODE_CREATE_SCHEMA_STMT, Equivalent, CREATE) \
22+
X(PG_QUERY__NODE__NODE_CREATE_TABLE_AS_STMT, Equivalent, CREATE) \
23+
X(PG_QUERY__NODE__NODE_INDEX_STMT, Equivalent, CREATE) \
24+
X(PG_QUERY__NODE__NODE_CREATE_FUNCTION_STMT, Equivalent, CREATE) \
25+
X(PG_QUERY__NODE__NODE_CREATE_ROLE_STMT, Equivalent, CREATE) \
26+
X(PG_QUERY__NODE__NODE_CREATE_SEQ_STMT, Equivalent, CREATE) \
27+
X(PG_QUERY__NODE__NODE_CREATE_DOMAIN_STMT, Equivalent, CREATE) \
28+
X(PG_QUERY__NODE__NODE_CREATE_ENUM_STMT, Equivalent, CREATE) \
29+
X(PG_QUERY__NODE__NODE_CREATE_RANGE_STMT, Equivalent, CREATE) \
30+
X(PG_QUERY__NODE__NODE_CREATEDB_STMT, Equivalent, CREATE) \
31+
X(PG_QUERY__NODE__NODE_ALTER_TABLE_STMT, Equivalent, ALTER) \
32+
X(PG_QUERY__NODE__NODE_ALTER_FUNCTION_STMT, Equivalent, ALTER) \
33+
X(PG_QUERY__NODE__NODE_ALTER_ROLE_STMT, Equivalent, ALTER) \
34+
X(PG_QUERY__NODE__NODE_ALTER_SEQ_STMT, Equivalent, ALTER) \
35+
X(PG_QUERY__NODE__NODE_ALTER_DOMAIN_STMT, Equivalent, ALTER) \
36+
X(PG_QUERY__NODE__NODE_ALTER_ENUM_STMT, Equivalent, ALTER) \
37+
X(PG_QUERY__NODE__NODE_ALTER_DATABASE_STMT, Equivalent, ALTER) \
38+
X(PG_QUERY__NODE__NODE_RENAME_STMT, Equivalent, ALTER) \
39+
X(PG_QUERY__NODE__NODE_DROP_STMT, Equivalent, DROP) \
40+
X(PG_QUERY__NODE__NODE_DROPDB_STMT, Equivalent, DROP) \
41+
X(PG_QUERY__NODE__NODE_DROP_ROLE_STMT, Equivalent, DROP) \
42+
X(PG_QUERY__NODE__NODE_DROP_TABLE_SPACE_STMT, Equivalent, DROP) \
43+
X(PG_QUERY__NODE__NODE_COPY_STMT, NoEquivalent, UNKNOWN) \
44+
X(PG_QUERY__NODE__NODE_MERGE_STMT, NoEquivalent, UNKNOWN) \
45+
X(PG_QUERY__NODE__NODE_VACUUM_STMT, NoEquivalent, UNKNOWN) \
46+
X(PG_QUERY__NODE__NODE_NOTIFY_STMT, NoEquivalent, UNKNOWN) \
47+
X(PG_QUERY__NODE__NODE_LISTEN_STMT, NoEquivalent, UNKNOWN) \
48+
X(PG_QUERY__NODE__NODE_UNLISTEN_STMT, NoEquivalent, UNKNOWN)
49+
550
StatementTypeMapping expected_stmt_type(const PgQuery__Node& node) {
651
using sql_parser::StmtType;
752

853
switch (node.node_case) {
9-
case PG_QUERY__NODE__NODE_SELECT_STMT:
10-
return {MappingKind::Equivalent, StmtType::SELECT};
11-
case PG_QUERY__NODE__NODE_INSERT_STMT:
12-
return {MappingKind::Equivalent, StmtType::INSERT};
13-
case PG_QUERY__NODE__NODE_UPDATE_STMT:
14-
return {MappingKind::Equivalent, StmtType::UPDATE};
15-
case PG_QUERY__NODE__NODE_DELETE_STMT:
16-
return {MappingKind::Equivalent, StmtType::DELETE_STMT};
17-
case PG_QUERY__NODE__NODE_VARIABLE_SET_STMT:
18-
return {MappingKind::Equivalent, StmtType::SET};
19-
case PG_QUERY__NODE__NODE_VARIABLE_SHOW_STMT:
20-
return {MappingKind::Equivalent, StmtType::SHOW};
21-
case PG_QUERY__NODE__NODE_PREPARE_STMT:
22-
return {MappingKind::Equivalent, StmtType::PREPARE};
23-
case PG_QUERY__NODE__NODE_EXECUTE_STMT:
24-
return {MappingKind::Equivalent, StmtType::EXECUTE};
25-
case PG_QUERY__NODE__NODE_DEALLOCATE_STMT:
26-
return {MappingKind::Equivalent, StmtType::DEALLOCATE};
27-
case PG_QUERY__NODE__NODE_EXPLAIN_STMT:
28-
return {MappingKind::Equivalent, StmtType::EXPLAIN};
29-
case PG_QUERY__NODE__NODE_CALL_STMT:
30-
return {MappingKind::Equivalent, StmtType::CALL};
31-
case PG_QUERY__NODE__NODE_DO_STMT:
32-
return {MappingKind::Equivalent, StmtType::DO_STMT};
33-
case PG_QUERY__NODE__NODE_TRUNCATE_STMT:
34-
return {MappingKind::Equivalent, StmtType::TRUNCATE};
35-
case PG_QUERY__NODE__NODE_LOCK_STMT:
36-
return {MappingKind::Equivalent, StmtType::LOCK};
54+
#define PG_COMPAT_MAPPING_CASE(node_case, mapping_kind, stmt_type) \
55+
case node_case: \
56+
return {MappingKind::mapping_kind, StmtType::stmt_type};
57+
PG_COMPAT_SIMPLE_STATEMENT_TYPE_MAPPINGS(PG_COMPAT_MAPPING_CASE)
58+
#undef PG_COMPAT_MAPPING_CASE
3759
case PG_QUERY__NODE__NODE_TRANSACTION_STMT:
3860
if (node.transaction_stmt == nullptr) {
3961
return {};
@@ -58,32 +80,6 @@ StatementTypeMapping expected_stmt_type(const PgQuery__Node& node) {
5880
default:
5981
return {};
6082
}
61-
case PG_QUERY__NODE__NODE_CREATE_STMT:
62-
case PG_QUERY__NODE__NODE_CREATE_SCHEMA_STMT:
63-
case PG_QUERY__NODE__NODE_CREATE_TABLE_AS_STMT:
64-
case PG_QUERY__NODE__NODE_INDEX_STMT:
65-
case PG_QUERY__NODE__NODE_CREATE_FUNCTION_STMT:
66-
case PG_QUERY__NODE__NODE_CREATE_ROLE_STMT:
67-
case PG_QUERY__NODE__NODE_CREATE_SEQ_STMT:
68-
case PG_QUERY__NODE__NODE_CREATE_DOMAIN_STMT:
69-
case PG_QUERY__NODE__NODE_CREATE_ENUM_STMT:
70-
case PG_QUERY__NODE__NODE_CREATE_RANGE_STMT:
71-
case PG_QUERY__NODE__NODE_CREATEDB_STMT:
72-
return {MappingKind::Equivalent, StmtType::CREATE};
73-
case PG_QUERY__NODE__NODE_ALTER_TABLE_STMT:
74-
case PG_QUERY__NODE__NODE_ALTER_FUNCTION_STMT:
75-
case PG_QUERY__NODE__NODE_ALTER_ROLE_STMT:
76-
case PG_QUERY__NODE__NODE_ALTER_SEQ_STMT:
77-
case PG_QUERY__NODE__NODE_ALTER_DOMAIN_STMT:
78-
case PG_QUERY__NODE__NODE_ALTER_ENUM_STMT:
79-
case PG_QUERY__NODE__NODE_ALTER_DATABASE_STMT:
80-
case PG_QUERY__NODE__NODE_RENAME_STMT:
81-
return {MappingKind::Equivalent, StmtType::ALTER};
82-
case PG_QUERY__NODE__NODE_DROP_STMT:
83-
case PG_QUERY__NODE__NODE_DROPDB_STMT:
84-
case PG_QUERY__NODE__NODE_DROP_ROLE_STMT:
85-
case PG_QUERY__NODE__NODE_DROP_TABLE_SPACE_STMT:
86-
return {MappingKind::Equivalent, StmtType::DROP};
8783
case PG_QUERY__NODE__NODE_GRANT_STMT:
8884
if (node.grant_stmt == nullptr) {
8985
return {};
@@ -100,112 +96,24 @@ StatementTypeMapping expected_stmt_type(const PgQuery__Node& node) {
10096
MappingKind::Equivalent,
10197
node.grant_role_stmt->is_grant ? StmtType::GRANT : StmtType::REVOKE,
10298
};
103-
case PG_QUERY__NODE__NODE_COPY_STMT:
104-
case PG_QUERY__NODE__NODE_MERGE_STMT:
105-
case PG_QUERY__NODE__NODE_VACUUM_STMT:
106-
case PG_QUERY__NODE__NODE_NOTIFY_STMT:
107-
case PG_QUERY__NODE__NODE_LISTEN_STMT:
108-
case PG_QUERY__NODE__NODE_UNLISTEN_STMT:
109-
return {MappingKind::NoEquivalent, StmtType::UNKNOWN};
11099
default:
111100
return {};
112101
}
113102
}
114103

115104
const char* oracle_node_name(PgQuery__Node__NodeCase node_case) {
116105
switch (node_case) {
117-
case PG_QUERY__NODE__NODE_SELECT_STMT:
118-
return "PG_QUERY__NODE__NODE_SELECT_STMT";
119-
case PG_QUERY__NODE__NODE_INSERT_STMT:
120-
return "PG_QUERY__NODE__NODE_INSERT_STMT";
121-
case PG_QUERY__NODE__NODE_UPDATE_STMT:
122-
return "PG_QUERY__NODE__NODE_UPDATE_STMT";
123-
case PG_QUERY__NODE__NODE_DELETE_STMT:
124-
return "PG_QUERY__NODE__NODE_DELETE_STMT";
125-
case PG_QUERY__NODE__NODE_VARIABLE_SET_STMT:
126-
return "PG_QUERY__NODE__NODE_VARIABLE_SET_STMT";
127-
case PG_QUERY__NODE__NODE_VARIABLE_SHOW_STMT:
128-
return "PG_QUERY__NODE__NODE_VARIABLE_SHOW_STMT";
129-
case PG_QUERY__NODE__NODE_PREPARE_STMT:
130-
return "PG_QUERY__NODE__NODE_PREPARE_STMT";
131-
case PG_QUERY__NODE__NODE_EXECUTE_STMT:
132-
return "PG_QUERY__NODE__NODE_EXECUTE_STMT";
133-
case PG_QUERY__NODE__NODE_DEALLOCATE_STMT:
134-
return "PG_QUERY__NODE__NODE_DEALLOCATE_STMT";
135-
case PG_QUERY__NODE__NODE_EXPLAIN_STMT:
136-
return "PG_QUERY__NODE__NODE_EXPLAIN_STMT";
137-
case PG_QUERY__NODE__NODE_CALL_STMT:
138-
return "PG_QUERY__NODE__NODE_CALL_STMT";
139-
case PG_QUERY__NODE__NODE_DO_STMT:
140-
return "PG_QUERY__NODE__NODE_DO_STMT";
141-
case PG_QUERY__NODE__NODE_TRUNCATE_STMT:
142-
return "PG_QUERY__NODE__NODE_TRUNCATE_STMT";
143-
case PG_QUERY__NODE__NODE_LOCK_STMT:
144-
return "PG_QUERY__NODE__NODE_LOCK_STMT";
106+
#define PG_COMPAT_NODE_NAME_CASE(node_case, mapping_kind, stmt_type) \
107+
case node_case: \
108+
return #node_case;
109+
PG_COMPAT_SIMPLE_STATEMENT_TYPE_MAPPINGS(PG_COMPAT_NODE_NAME_CASE)
110+
#undef PG_COMPAT_NODE_NAME_CASE
145111
case PG_QUERY__NODE__NODE_TRANSACTION_STMT:
146112
return "PG_QUERY__NODE__NODE_TRANSACTION_STMT";
147-
case PG_QUERY__NODE__NODE_CREATE_STMT:
148-
return "PG_QUERY__NODE__NODE_CREATE_STMT";
149-
case PG_QUERY__NODE__NODE_CREATE_SCHEMA_STMT:
150-
return "PG_QUERY__NODE__NODE_CREATE_SCHEMA_STMT";
151-
case PG_QUERY__NODE__NODE_CREATE_TABLE_AS_STMT:
152-
return "PG_QUERY__NODE__NODE_CREATE_TABLE_AS_STMT";
153-
case PG_QUERY__NODE__NODE_INDEX_STMT:
154-
return "PG_QUERY__NODE__NODE_INDEX_STMT";
155-
case PG_QUERY__NODE__NODE_CREATE_FUNCTION_STMT:
156-
return "PG_QUERY__NODE__NODE_CREATE_FUNCTION_STMT";
157-
case PG_QUERY__NODE__NODE_CREATE_ROLE_STMT:
158-
return "PG_QUERY__NODE__NODE_CREATE_ROLE_STMT";
159-
case PG_QUERY__NODE__NODE_CREATE_SEQ_STMT:
160-
return "PG_QUERY__NODE__NODE_CREATE_SEQ_STMT";
161-
case PG_QUERY__NODE__NODE_CREATE_DOMAIN_STMT:
162-
return "PG_QUERY__NODE__NODE_CREATE_DOMAIN_STMT";
163-
case PG_QUERY__NODE__NODE_CREATE_ENUM_STMT:
164-
return "PG_QUERY__NODE__NODE_CREATE_ENUM_STMT";
165-
case PG_QUERY__NODE__NODE_CREATE_RANGE_STMT:
166-
return "PG_QUERY__NODE__NODE_CREATE_RANGE_STMT";
167-
case PG_QUERY__NODE__NODE_CREATEDB_STMT:
168-
return "PG_QUERY__NODE__NODE_CREATEDB_STMT";
169-
case PG_QUERY__NODE__NODE_ALTER_TABLE_STMT:
170-
return "PG_QUERY__NODE__NODE_ALTER_TABLE_STMT";
171-
case PG_QUERY__NODE__NODE_ALTER_FUNCTION_STMT:
172-
return "PG_QUERY__NODE__NODE_ALTER_FUNCTION_STMT";
173-
case PG_QUERY__NODE__NODE_ALTER_ROLE_STMT:
174-
return "PG_QUERY__NODE__NODE_ALTER_ROLE_STMT";
175-
case PG_QUERY__NODE__NODE_ALTER_SEQ_STMT:
176-
return "PG_QUERY__NODE__NODE_ALTER_SEQ_STMT";
177-
case PG_QUERY__NODE__NODE_ALTER_DOMAIN_STMT:
178-
return "PG_QUERY__NODE__NODE_ALTER_DOMAIN_STMT";
179-
case PG_QUERY__NODE__NODE_ALTER_ENUM_STMT:
180-
return "PG_QUERY__NODE__NODE_ALTER_ENUM_STMT";
181-
case PG_QUERY__NODE__NODE_ALTER_DATABASE_STMT:
182-
return "PG_QUERY__NODE__NODE_ALTER_DATABASE_STMT";
183-
case PG_QUERY__NODE__NODE_RENAME_STMT:
184-
return "PG_QUERY__NODE__NODE_RENAME_STMT";
185-
case PG_QUERY__NODE__NODE_DROP_STMT:
186-
return "PG_QUERY__NODE__NODE_DROP_STMT";
187-
case PG_QUERY__NODE__NODE_DROPDB_STMT:
188-
return "PG_QUERY__NODE__NODE_DROPDB_STMT";
189-
case PG_QUERY__NODE__NODE_DROP_ROLE_STMT:
190-
return "PG_QUERY__NODE__NODE_DROP_ROLE_STMT";
191-
case PG_QUERY__NODE__NODE_DROP_TABLE_SPACE_STMT:
192-
return "PG_QUERY__NODE__NODE_DROP_TABLE_SPACE_STMT";
193113
case PG_QUERY__NODE__NODE_GRANT_STMT:
194114
return "PG_QUERY__NODE__NODE_GRANT_STMT";
195115
case PG_QUERY__NODE__NODE_GRANT_ROLE_STMT:
196116
return "PG_QUERY__NODE__NODE_GRANT_ROLE_STMT";
197-
case PG_QUERY__NODE__NODE_COPY_STMT:
198-
return "PG_QUERY__NODE__NODE_COPY_STMT";
199-
case PG_QUERY__NODE__NODE_MERGE_STMT:
200-
return "PG_QUERY__NODE__NODE_MERGE_STMT";
201-
case PG_QUERY__NODE__NODE_VACUUM_STMT:
202-
return "PG_QUERY__NODE__NODE_VACUUM_STMT";
203-
case PG_QUERY__NODE__NODE_NOTIFY_STMT:
204-
return "PG_QUERY__NODE__NODE_NOTIFY_STMT";
205-
case PG_QUERY__NODE__NODE_LISTEN_STMT:
206-
return "PG_QUERY__NODE__NODE_LISTEN_STMT";
207-
case PG_QUERY__NODE__NODE_UNLISTEN_STMT:
208-
return "PG_QUERY__NODE__NODE_UNLISTEN_STMT";
209117
default:
210118
return "UNMAPPED_NODE_CASE";
211119
}
@@ -214,6 +122,11 @@ const char* oracle_node_name(PgQuery__Node__NodeCase node_case) {
214122
const char* stmt_type_name(sql_parser::StmtType type) {
215123
using sql_parser::StmtType;
216124

125+
// Missing enum cases are errors so StmtType additions cannot drift silently.
126+
#if defined(__clang__) || defined(__GNUC__)
127+
#pragma GCC diagnostic push
128+
#pragma GCC diagnostic error "-Wswitch"
129+
#endif
217130
switch (type) {
218131
case StmtType::UNKNOWN:
219132
return "UNKNOWN";
@@ -278,7 +191,12 @@ const char* stmt_type_name(sql_parser::StmtType type) {
278191
case StmtType::DO_STMT:
279192
return "DO";
280193
}
194+
#if defined(__clang__) || defined(__GNUC__)
195+
#pragma GCC diagnostic pop
196+
#endif
281197
return "OTHER";
282198
}
283199

200+
#undef PG_COMPAT_SIMPLE_STATEMENT_TYPE_MAPPINGS
201+
284202
} // namespace pg_compat

0 commit comments

Comments
 (0)