1use crate::analysis::facts::StatementFact;
2use crate::analysis::mutations::{Mutation, OpaqueMutation};
3use crate::analysis::state::AnalysisState;
4use crate::ast::identifiers::{ObjectId, QualifiedName};
5
6mod relation;
7mod relation_aux;
8mod replication;
9mod routine;
10mod schema;
11mod security;
12mod sequence;
13mod session;
14mod types;
15
16pub struct Resolver;
17
18impl Resolver {
19 fn resolve_creation_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
20 let schema = name
21 .schema
22 .as_ref()
23 .map(|i| i.resolve())
24 .unwrap_or_else(|| {
25 state
26 .local
27 .search_path
28 .first()
29 .map(|s| s.as_str())
30 .unwrap_or("public")
31 .to_string()
32 });
33
34 ObjectId::new(schema, name.name.resolve())
35 }
36
37 fn resolve_in_namespace(
38 name: &QualifiedName,
39 object_name: String,
40 state: &AnalysisState,
41 present: impl Fn(&AnalysisState, &ObjectId) -> bool,
42 ) -> ObjectId {
43 if let Some(schema_ident) = &name.schema {
44 return ObjectId::new(schema_ident.resolve(), object_name);
45 }
46
47 for schema in &state.local.search_path {
48 let mut candidate = ObjectId::new(schema.clone(), object_name.clone());
49 if present(state, &candidate) {
50 candidate.inferred_schema = true;
51 return candidate;
52 }
53 }
54
55 let schema = state
56 .local
57 .search_path
58 .first()
59 .cloned()
60 .unwrap_or_else(|| "public".to_string());
61 let mut id = ObjectId::new(schema, object_name);
62 id.inferred_schema = true;
63 id
64 }
65
66 fn resolve_relation_lookup_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
67 Self::resolve_in_namespace(
68 name,
69 name.name.resolve(),
70 state,
71 AnalysisState::relation_namespace_object_is_present,
72 )
73 }
74
75 fn resolve_type_lookup_name(name: &QualifiedName, state: &AnalysisState) -> ObjectId {
76 Self::resolve_in_namespace(
77 name,
78 name.name.resolve(),
79 state,
80 AnalysisState::type_is_present,
81 )
82 }
83
84 fn resolve_routine_lookup_name(
85 name: &QualifiedName,
86 params: &[String],
87 state: &AnalysisState,
88 ) -> ObjectId {
89 let signature = params
90 .iter()
91 .map(|param| Self::normalize_function_arg_type(param))
92 .collect::<Vec<_>>()
93 .join(",");
94 let object_name = format!("{}({signature})", name.name.resolve());
95 Self::resolve_in_namespace(name, object_name, state, AnalysisState::routine_is_present)
96 }
97
98 fn resolve_constraint_index_name(name: &QualifiedName, table: &ObjectId) -> ObjectId {
99 let schema = name
100 .schema
101 .as_ref()
102 .map(|schema| schema.resolve())
103 .unwrap_or_else(|| table.schema.clone());
104 ObjectId::new(schema, name.name.resolve())
105 }
106
107 fn resolve_function_id(
108 name: &QualifiedName,
109 params: &[crate::analysis::facts::ParamFact],
110 state: &AnalysisState,
111 ) -> ObjectId {
112 let base_id = Self::resolve_creation_name(name, state);
113 let sig = params
114 .iter()
115 .filter(|p| !matches!(&p.mode, crate::analysis::facts::ParamModeFact::Out))
116 .map(|p| p.ty.clone())
117 .collect::<Vec<_>>()
118 .join(",");
119 Self::resolve_function_id_by_sig(&base_id, &sig)
120 }
121
122 fn resolve_function_id_by_sig(base_id: &ObjectId, sig: &str) -> ObjectId {
123 let normalized_sig = sig
125 .split(',')
126 .map(Self::normalize_function_arg_type)
127 .collect::<Vec<_>>()
128 .join(",");
129
130 let mut id = ObjectId::new(
131 base_id.schema.clone(),
132 format!("{}({})", base_id.name, normalized_sig),
133 );
134 id.inferred_schema = base_id.inferred_schema;
135 id
136 }
137
138 pub(crate) fn normalize_function_arg_type(raw: &str) -> String {
139 let normalized = Self::fold_unquoted_identifier_case(raw.trim());
140 if let Some(element_type) = normalized.strip_suffix("[]") {
141 return format!("{}[]", Self::normalize_function_arg_type(element_type));
142 }
143 match normalized.as_str() {
144 "int" | "int4" => "integer".to_string(),
145 "int8" => "bigint".to_string(),
146 "int2" => "smallint".to_string(),
147 "float8" => "double precision".to_string(),
148 "float4" => "real".to_string(),
149 "bool" => "boolean".to_string(),
150 "varchar" => "character varying".to_string(),
151 "char" => "character".to_string(),
152 "time" => "time without time zone".to_string(),
153 "timestamp" => "timestamp without time zone".to_string(),
154 "timestamptz" => "timestamp with time zone".to_string(),
155 "decimal" => "numeric".to_string(),
156 _ => normalized,
157 }
158 }
159
160 fn fold_unquoted_identifier_case(raw: &str) -> String {
161 let mut folded = String::with_capacity(raw.len());
162 let mut quoted = false;
163 let mut chars = raw.chars().peekable();
164 while let Some(character) = chars.next() {
165 match character {
166 '"' if quoted && chars.peek() == Some(&'"') => {
167 folded.push('"');
168 folded.push('"');
169 chars.next();
170 }
171 '"' => {
172 quoted = !quoted;
173 folded.push(character);
174 }
175 character if quoted => folded.push(character),
176 character => folded.extend(character.to_lowercase()),
177 }
178 }
179 folded
180 }
181
182 pub fn resolve(fact: &StatementFact, state: &AnalysisState) -> Vec<Mutation> {
183 let mut mutations = Vec::new();
184 match fact {
185 StatementFact::CreateSchema {
186 name,
187 if_not_exists,
188 authorization,
189 } => {
190 mutations.push(Self::resolve_create_schema(
191 name,
192 *if_not_exists,
193 authorization,
194 ));
195 }
196 StatementFact::SchemaNeutralNoop => {}
197 StatementFact::AlterSchema { name, action } => {
198 mutations.push(Self::resolve_alter_schema(name, action));
199 }
200 StatementFact::DropSchema {
201 names,
202 if_exists,
203 cascade,
204 } => {
205 mutations.push(Self::resolve_drop_schema(names, *if_exists, *cascade));
206 }
207 StatementFact::CreateTable {
208 name,
209 if_not_exists,
210 as_select,
211 persistence,
212 columns,
213 foreign_keys,
214 table_constraints,
215 partition_by,
216 partition_of,
217 partition_type,
218 } => {
219 mutations.push(Self::resolve_create_table(
220 name,
221 *if_not_exists,
222 *as_select,
223 persistence,
224 columns,
225 foreign_keys,
226 table_constraints,
227 partition_by,
228 partition_of,
229 partition_type,
230 state,
231 ));
232 }
233 StatementFact::CreateView {
234 name,
235 or_replace,
236 depends_on,
237 } => {
238 mutations.push(Self::resolve_create_view(
239 name,
240 *or_replace,
241 depends_on,
242 state,
243 ));
244 }
245 StatementFact::AlterView { name, action } => {
246 if let Some(mutation) = Self::resolve_alter_view(name, action, state) {
247 mutations.push(mutation);
248 }
249 }
250 StatementFact::CreateMaterializedView { name, depends_on } => {
251 mutations.push(Self::resolve_create_materialized_view(
252 name, depends_on, state,
253 ));
254 }
255 StatementFact::AlterMaterializedView { name, new_name } => {
256 if let Some(mutation) =
257 Self::resolve_alter_materialized_view(name, new_name.as_ref(), state)
258 {
259 mutations.push(mutation);
260 }
261 }
262 StatementFact::RefreshMaterializedView { name, concurrently } => {
263 mutations.push(Self::resolve_refresh_materialized_view(
264 name,
265 *concurrently,
266 state,
267 ));
268 }
269 StatementFact::CreateIndex {
270 name,
271 relation,
272 if_not_exists,
273 concurrently,
274 using_method,
275 has_predicate,
276 unique,
277 } => {
278 mutations.push(Self::resolve_create_index(
279 name,
280 relation,
281 *if_not_exists,
282 *concurrently,
283 using_method,
284 *has_predicate,
285 *unique,
286 state,
287 ));
288 }
289 StatementFact::CreatePolicy {
290 name,
291 table,
292 permissive,
293 command,
294 semantics_complete,
295 } => {
296 mutations.push(Self::resolve_create_policy(
297 name,
298 table,
299 *permissive,
300 command,
301 *semantics_complete,
302 state,
303 ));
304 }
305 StatementFact::DropPolicy {
306 name,
307 table,
308 if_exists,
309 } => {
310 mutations.push(Self::resolve_drop_policy(name, table, *if_exists, state));
311 }
312 StatementFact::CreateTrigger {
313 name,
314 table,
315 function,
316 } => {
317 mutations.push(Self::resolve_create_trigger(name, table, function, state));
318 }
319 StatementFact::DropTrigger {
320 name,
321 table,
322 if_exists,
323 } => {
324 mutations.push(Self::resolve_drop_trigger(name, table, *if_exists, state));
325 }
326 StatementFact::AlterTrigger {
327 name,
328 table,
329 new_name,
330 } => mutations.push(Self::resolve_alter_trigger(name, table, new_name, state)),
331 StatementFact::AlterIndex { name, actions } => {
332 mutations.extend(Self::resolve_alter_index(name, actions, state));
333 }
334 StatementFact::CreateType(create_type) => {
335 mutations.push(Self::resolve_create_type(create_type, state));
336 }
337 StatementFact::AlterType(alter_type) => {
338 mutations.extend(Self::resolve_alter_type(alter_type, state));
339 }
340 StatementFact::CreateDomain { name, base_type } => {
341 mutations.push(Self::resolve_create_domain(name, base_type, state));
342 }
343 StatementFact::AlterDomain { name, action } => {
344 mutations.push(Self::resolve_alter_domain(name, action, state));
345 }
346 StatementFact::DropDomain {
347 names,
348 if_exists,
349 cascade,
350 } => {
351 mutations.push(Self::resolve_drop_domain(
352 names, *if_exists, *cascade, state,
353 ));
354 }
355 StatementFact::DropType {
356 names,
357 if_exists,
358 cascade,
359 } => {
360 mutations.push(Self::resolve_drop_type(names, *if_exists, *cascade, state));
361 }
362 StatementFact::CreateSequence {
363 name,
364 if_not_exists,
365 owned_by,
366 } => {
367 mutations.push(Self::resolve_create_sequence(
368 name,
369 *if_not_exists,
370 owned_by,
371 state,
372 ));
373 }
374 StatementFact::AlterSequence {
375 name,
376 if_exists,
377 action,
378 } => {
379 mutations.push(Self::resolve_alter_sequence(
380 name, *if_exists, action, state,
381 ));
382 }
383 StatementFact::DropSequence {
384 names,
385 if_exists,
386 cascade,
387 } => {
388 mutations.push(Self::resolve_drop_sequence(
389 names, *if_exists, *cascade, state,
390 ));
391 }
392 StatementFact::AlterTable { name, actions } => {
393 mutations.extend(Self::resolve_alter_table(name, actions, state));
394 }
395 StatementFact::DropTable {
396 names,
397 if_exists,
398 cascade,
399 } => {
400 mutations.push(Self::resolve_drop_table(names, *if_exists, *cascade, state));
401 }
402 StatementFact::DropView {
403 names,
404 if_exists,
405 cascade,
406 } => {
407 mutations.push(Self::resolve_drop_view(names, *if_exists, *cascade, state));
408 }
409 StatementFact::DropMaterializedView {
410 names,
411 if_exists,
412 cascade,
413 } => {
414 mutations.push(Self::resolve_drop_materialized_view(
415 names, *if_exists, *cascade, state,
416 ));
417 }
418 StatementFact::DropIndex {
419 names,
420 if_exists,
421 concurrently,
422 cascade,
423 } => {
424 mutations.push(Self::resolve_drop_indexes(
425 names,
426 *if_exists,
427 *concurrently,
428 *cascade,
429 state,
430 ));
431 }
432 StatementFact::SetSearchPath { target, local } => {
433 mutations.push(Self::resolve_search_path(target, *local))
434 }
435 StatementFact::SetTimeout {
436 setting,
437 value,
438 local,
439 } => mutations.push(Self::resolve_timeout(*setting, value, *local)),
440 StatementFact::ResetSettings { target } => {
441 mutations.push(Mutation::ResetSettings(*target))
442 }
443 StatementFact::BeginTransaction => mutations.push(Mutation::BeginTransaction),
444 StatementFact::CommitTransaction => mutations.push(Mutation::CommitTransaction),
445 StatementFact::CommitAndChain => mutations.push(Mutation::CommitAndChain),
446 StatementFact::RollbackTransaction => mutations.push(Mutation::RollbackTransaction),
447 StatementFact::RollbackAndChain => mutations.push(Mutation::RollbackAndChain),
448 StatementFact::RollbackToSavepoint { name } => {
449 mutations.push(Self::resolve_rollback_to_savepoint(name))
450 }
451 StatementFact::Savepoint { name } => mutations.push(Self::resolve_savepoint(name)),
452 StatementFact::ReleaseSavepoint { name } => {
453 mutations.push(Self::resolve_release_savepoint(name))
454 }
455 StatementFact::PrepareTransaction { .. } => {
456 mutations.push(Mutation::Opaque(OpaqueMutation::PrepareTransaction))
457 }
458 StatementFact::SetTransaction => {
459 mutations.push(Mutation::Opaque(OpaqueMutation::SetTransaction))
460 }
461 StatementFact::SetConstraints => {
462 mutations.push(Mutation::Opaque(OpaqueMutation::SetConstraints))
463 }
464 StatementFact::OpaqueBlock => mutations.push(Mutation::Opaque(OpaqueMutation::DoBlock)),
465 StatementFact::Execute => mutations.push(Mutation::Opaque(OpaqueMutation::Execute)),
466 StatementFact::Vacuum { relation, is_full } => {
467 mutations.push(Self::resolve_vacuum(relation.as_ref(), *is_full, state))
468 }
469 StatementFact::CreateFunction(f) => {
470 mutations.push(Self::resolve_create_function(f, state));
471 }
472 StatementFact::AlterFunction(f) => {
473 mutations.push(Self::resolve_alter_function(f, state));
474 }
475 StatementFact::DropFunction(f) => {
476 mutations.push(Self::resolve_drop_function(f));
477 }
478 StatementFact::CreateProcedure(p) => {
479 mutations.push(Self::resolve_create_procedure(p, state));
480 }
481 StatementFact::AlterProcedure(p) => {
482 mutations.push(Self::resolve_alter_procedure(p, state));
483 }
484 StatementFact::DropProcedure(p) => {
485 mutations.push(Self::resolve_drop_procedure(p));
486 }
487 StatementFact::CreateAggregate(a) => {
488 mutations.push(Self::resolve_create_aggregate(a, state));
489 }
490 StatementFact::AlterAggregate(a) => {
491 mutations.push(Self::resolve_alter_aggregate(a, state));
492 }
493 StatementFact::DropAggregate(a) => {
494 mutations.push(Self::resolve_drop_aggregate(a));
495 }
496 StatementFact::CreatePublication(p) => {
497 mutations.push(Self::resolve_create_publication(p, state));
498 }
499 StatementFact::AlterPublication(p) => {
500 mutations.push(Self::resolve_alter_publication(p, state));
501 }
502 StatementFact::DropPublication(p) => {
503 mutations.push(Self::resolve_drop_publication(p));
504 }
505 StatementFact::CreateSubscription(s) => {
506 mutations.push(Self::resolve_create_subscription(s));
507 }
508 StatementFact::AlterSubscription(s) => {
509 mutations.push(Self::resolve_alter_subscription(s));
510 }
511 StatementFact::DropSubscription(s) => {
512 mutations.push(Self::resolve_drop_subscription(s));
513 }
514 StatementFact::CreateRole(r) => {
515 mutations.push(Self::resolve_create_role(r));
516 }
517 StatementFact::AlterRole(r) => {
518 mutations.push(Self::resolve_alter_role(r));
519 }
520 StatementFact::DropRole(r) => {
521 mutations.push(Self::resolve_drop_role(r));
522 }
523 StatementFact::Grant(g) => {
524 mutations.push(Self::resolve_grant(g, state));
525 }
526 StatementFact::Revoke(r) => {
527 mutations.push(Self::resolve_revoke(r, state));
528 }
529 StatementFact::CreateDatabase(d) => {
530 mutations.push(Self::resolve_create_database(d));
531 }
532 StatementFact::AlterDatabase(d) => {
533 mutations.push(Self::resolve_alter_database(d));
534 }
535 StatementFact::DropDatabase(d) => {
536 mutations.push(Self::resolve_drop_database(d));
537 }
538 StatementFact::SetRole {
539 role,
540 local,
541 is_session_auth,
542 } => {
543 mutations.push(Self::resolve_set_role(role, *local, *is_session_auth));
544 }
545 }
546 mutations
547 }
548}