1use std::collections::HashMap;
6
7use rupg_analyze::{
8 Column, Cte, FRAMEOPTION_END_OFFSET, FRAMEOPTION_END_UNBOUNDED_FOLLOWING,
9 FRAMEOPTION_START_OFFSET, Frame, FromFunction, FromItem, GroupingSet, Join, JoinKind, JoinRow,
10 NullTreatment, Query, Relation, SetKind, SetOp, SetTree, TableSample,
11};
12use rupg_sql::nodes::{
13 FRAMEOPTION_BETWEEN, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_OFFSET_PRECEDING,
14 FRAMEOPTION_EXCLUDE_CURRENT_ROW, FRAMEOPTION_EXCLUDE_GROUP, FRAMEOPTION_EXCLUDE_TIES,
15 FRAMEOPTION_NONDEFAULT, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, FRAMEOPTION_START_CURRENT_ROW,
16 FRAMEOPTION_START_OFFSET_PRECEDING, FRAMEOPTION_START_UNBOUNDED_PRECEDING,
17};
18use rupg_types::qualified_name_list;
19
20use super::{
21 Aggref, Deparser, Error, Expr, ExprKind, Func, FuncForm, INDENT_STD, INDENT_VAR, JoinNames,
22 JsonCtor, Namespace, Result, SortGroup, SubLink, SubLinkKind, Value, WindowClause, WindowFunc,
23 builtin, column_names, json_format, looks_like_function, oid, pretty_arg,
24 qualified_relation_name, quote_identifier, reg, relation_name, sort_operators,
25};
26use crate::{Call, Session, bad_value, not_yet, type_error};
27use rupg_catalog::{
28 TRIGGER_BEFORE, TRIGGER_DELETE, TRIGGER_INSERT, TRIGGER_INSTEAD, TRIGGER_ROW, TRIGGER_TRUNCATE,
29 TRIGGER_UPDATE,
30};
31
32const INDENT_JOIN: i32 = 4;
34const UNNEST: u32 = 2331;
36
37impl Deparser<'_> {
38 pub(super) fn query_def(
40 &mut self,
41 query: &Query,
42 result: Option<&[String]>,
43 names_visible: bool,
44 indent: i32,
45 ) -> Result<()> {
46 let space = self.namespace(query);
47 let joins: usize = query.from.iter().map(join_count).sum();
48 let prefix = !self.namespaces.is_empty()
50 || self.function.is_some()
51 || query.relations.len() + joins != 1;
52 let outputs = query
53 .targets
54 .iter()
55 .filter(|t| !t.junk)
56 .enumerate()
57 .map(|(i, t)| {
58 let name = result.and_then(|r| r.get(i)).unwrap_or(&t.name).clone();
59 let var = match &t.expr.kind {
60 ExprKind::Var(var) => Some(*var),
61 _ => None,
62 };
63 (name, var)
64 })
65 .collect();
66 let saved_indent = std::mem::replace(&mut self.indent, indent);
67 let saved_prefix = std::mem::replace(&mut self.prefix, prefix);
68 let saved_visible = std::mem::replace(&mut self.names_visible, names_visible);
69 let saved_group = std::mem::replace(&mut self.in_group_by, false);
70 let saved_outputs = std::mem::replace(&mut self.outputs, outputs);
71 let saved_windows = std::mem::replace(&mut self.windows, query.windows.clone());
72 let targets = query.targets.iter().map(|t| t.expr.clone()).collect();
73 let saved_targets = std::mem::replace(&mut self.window_targets, targets);
74 self.namespaces.push(space);
75 let done = self.select_query(query, result);
76 self.namespaces.pop();
77 self.windows = saved_windows;
78 self.window_targets = saved_targets;
79 self.indent = saved_indent;
80 self.prefix = saved_prefix;
81 self.names_visible = saved_visible;
82 self.in_group_by = saved_group;
83 self.outputs = saved_outputs;
84 done
85 }
86
87 fn namespace(&self, query: &Query) -> Namespace {
89 let mut used: HashMap<String, u32> = HashMap::new();
90 for space in &self.namespaces {
91 let joins = space.joins.iter().filter_map(|j| j.name.as_ref());
92 for name in space.names.iter().filter(|n| !n.is_empty()).chain(joins) {
93 used.insert(name.clone(), 0);
94 }
95 }
96 self.namespace_in(query, &mut used, false, &[])
97 }
98
99 pub(super) fn base_name(&self, rel: &Relation) -> String {
101 match reg::class_name(rel.oid, self.session) {
102 Some((name, _)) if rel.alias.is_none() && rel.oid != 0 => name.to_string(),
103 _ => rel.name.clone(),
104 }
105 }
106
107 pub(super) fn namespace_in(
109 &self,
110 query: &Query,
111 used: &mut HashMap<String, u32>,
112 explain: bool,
113 hidden: &[usize],
114 ) -> Namespace {
115 let mut joins = Vec::new();
116 let mut order = Vec::new();
117 let tops: Vec<Slot> =
118 query.from.iter().map(|item| walk_from(item, &mut joins, &mut order)).collect();
119 let mut seen = vec![false; query.relations.len()];
120 for slot in &order {
121 if let Slot::Relation(i) = slot
122 && let Some(s) = seen.get_mut(*i)
123 {
124 *s = true;
125 }
126 }
127 order.extend(seen.iter().enumerate().filter(|(_, s)| !**s).map(|(i, _)| Slot::Relation(i)));
128 let mut space =
129 Namespace { names: vec![String::new(); query.relations.len()], ..Default::default() };
130 let mut join_names: Vec<Option<String>> = vec![None; joins.len()];
131 let mut naming = order.clone();
133 if explain {
134 naming.sort_by_key(|slot| match *slot {
135 Slot::Relation(i) => (!seen[i], i),
136 Slot::Join(_) => (true, usize::MAX),
137 });
138 }
139 for slot in &naming {
140 match *slot {
141 Slot::Relation(i) => {
142 let Some(rel) = query.relations.get(i) else { continue };
143 if hidden.contains(&i) {
145 space.names[i] = self.base_name(rel);
146 continue;
147 }
148 space.names[i] = unique_name(self.base_name(rel), used);
149 }
150 Slot::Join(k) => {
151 if let Some(alias) = &joins[k].join.alias
152 && !explain
153 {
154 join_names[k] = Some(unique_name(alias.clone(), used));
155 }
156 }
157 }
158 }
159 let mut state = ColumnNames {
160 relations: query.relations.iter().map(|r| vec![None; r.columns.len()]).collect(),
161 relation_parents: vec![Vec::new(); query.relations.len()],
162 joins: joins.iter().map(|j| vec![None; j.join.columns.len()]).collect(),
163 join_parents: vec![Vec::new(); joins.len()],
164 join_using: vec![Vec::new(); joins.len()],
165 using: Vec::new(),
166 unique_using: joins
167 .iter()
168 .any(|j| j.join.alias.is_none() && !j.join.using.is_empty() && !j.join.plain_using),
169 };
170 for slot in tops {
171 if let Slot::Join(k) = slot {
172 state.using_names(&joins, k, &[]);
173 }
174 }
175 let catalog = self.session.catalog();
177 let real_names: Vec<Vec<String>> = query
178 .relations
179 .iter()
180 .map(|rel| {
181 let now = catalog
182 .and_then(|c| c.relation(rel.oid))
183 .filter(|now| rel.oid != 0 && now.columns.len() >= rel.columns.len());
184 match now {
185 Some(now) => now
186 .columns
187 .iter()
188 .map(|c| if c.dropped { String::new() } else { c.name.clone() })
189 .collect(),
190 None => rel.columns.iter().map(|c| c.name.clone()).collect(),
191 }
192 })
193 .collect();
194 for (names, real) in state.relations.iter_mut().zip(&real_names) {
195 names.resize(real.len().max(names.len()), None);
196 }
197 let mut print_join = vec![false; joins.len()];
198 for slot in &order {
199 match *slot {
200 Slot::Relation(i) => {
201 let Some(rel) = query.relations.get(i) else { continue };
202 let given: &[String] = rel.alias.as_deref().unwrap_or_default();
203 for (c, column) in real_names[i].iter().enumerate() {
204 if state.relations[i][c].is_none() && column.is_empty() {
205 state.relations[i][c] = Some(String::new());
206 } else if state.relations[i][c].is_none() {
207 let wanted = given.get(c).unwrap_or(column);
208 let name = state.unique(wanted, Slot::Relation(i));
209 state.relations[i][c] = Some(name);
210 }
211 }
212 }
213 Slot::Join(k) => print_join[k] = state.join_columns(&joins, k),
214 }
215 }
216 for (i, rel) in query.relations.iter().enumerate() {
217 let given: &[String] = rel.alias.as_deref().unwrap_or_default();
218 let names: Vec<String> =
219 state.relations[i].iter().map(|n| n.clone().unwrap_or_default()).collect();
220 let changed =
222 real_names[i].iter().zip(&names).enumerate().any(|(c, (column, name))| {
223 let real = if rel.oid != 0 { column } else { given.get(c).unwrap_or(column) };
224 name != real
225 });
226 let print = if rel.json_table().is_some() {
228 false
229 } else if rel.oid != 0 {
230 changed
231 } else {
232 rel.function.is_some() || !given.is_empty() || changed
233 };
234 space.columns.push(names);
235 space.print_aliases.push(print);
236 }
237 for (k, info) in joins.iter().enumerate() {
238 space.joins.push(JoinNames {
239 name: join_names[k].clone(),
240 relations: info.relations.clone(),
241 columns: state.joins[k].iter().map(|n| n.clone().unwrap_or_default()).collect(),
242 using: std::mem::take(&mut state.join_using[k]),
243 values: info.join.columns.iter().map(|(_, e)| e.clone()).collect(),
244 print_aliases: print_join[k],
245 });
246 }
247 if !explain {
248 for item in &query.from {
249 merged_columns(item, &mut space.merged);
250 }
251 }
252 space.relations.clone_from(&query.relations);
253 space
254 }
255
256 pub(super) fn join_column(&self, e: &Expr) -> Option<(String, String)> {
258 for (levels, space) in self.namespaces.iter().rev().enumerate() {
259 for (k, join) in space.joins.iter().enumerate() {
260 let Some(name) = &join.name else { continue };
261 if space.inside.contains(&k) {
262 continue;
263 }
264 for (value, column) in join.values.iter().zip(&join.columns) {
265 let found = match (&value.kind, &e.kind) {
266 (ExprKind::Var(v), ExprKind::Var(w)) => {
267 v.relation == w.relation
268 && v.attnum == w.attnum
269 && v.levels_up + levels == w.levels_up
270 }
271 (ExprKind::Var(_), _) | (_, ExprKind::Var(_)) => false,
272 _ if std::mem::discriminant(&value.kind)
273 != std::mem::discriminant(&e.kind) =>
274 {
275 false
276 }
277 _ => {
278 let mut value = value.clone();
279 value.raise(levels);
280 value.same(e)
281 }
282 };
283 if found {
284 return Some((name.clone(), column.clone()));
285 }
286 }
287 }
288 }
289 None
290 }
291
292 pub(super) fn join_row_name(&self, row: &JoinRow) -> String {
294 for (levels, space) in self.namespaces.iter().rev().enumerate() {
295 for join in &space.joins {
296 let Some(name) = &join.name else { continue };
297 let same = join.values.len() == row.fields.len()
298 && join.values.iter().zip(&row.fields).all(|(value, field)| {
299 let mut value = value.clone();
300 value.raise(levels);
301 value.same(field)
302 });
303 if same {
304 return name.clone();
305 }
306 }
307 }
308 row.alias.clone().unwrap_or_default()
309 }
310
311 pub(super) fn merged_name(&self, e: &Expr) -> Option<String> {
313 if let Some((_, column)) = self.join_column(e) {
314 return Some(column);
315 }
316 for (levels, space) in self.namespaces.iter().rev().enumerate() {
317 for (value, name) in &space.merged {
318 let found = if levels == 0 {
319 value.same(e)
320 } else {
321 let mut value = value.clone();
322 value.raise(levels);
323 value.same(e)
324 };
325 if found {
326 return Some(name.clone());
327 }
328 }
329 }
330 None
331 }
332
333 fn select_query(&mut self, query: &Query, result: Option<&[String]>) -> Result<()> {
335 self.with_clause(query)?;
336 let force = match &query.set_op {
337 Some(op) => {
338 self.set_op(op, query, result)?;
339 true
340 }
341 None => {
342 self.basic_select(query, result)?;
343 false
344 }
345 };
346 if !query.sort.is_empty() {
347 self.keyword(" ORDER BY ", -INDENT_STD, INDENT_STD, 1);
348 let exprs: Vec<&Expr> = query.targets.iter().map(|t| &t.expr).collect();
349 self.order_by(&query.sort, &exprs, force)?;
350 }
351 if let Some(offset) = &query.offset {
352 self.keyword(" OFFSET ", -INDENT_STD, INDENT_STD, 0);
353 self.expr(offset, false)?;
354 }
355 if let Some(limit) = &query.limit {
356 if query.with_ties {
357 self.keyword(" FETCH FIRST ", -INDENT_STD, INDENT_STD, 0);
358 self.buf.push('(');
359 self.expr(limit, false)?;
360 self.buf.push_str(") ROWS WITH TIES");
361 } else {
362 self.keyword(" LIMIT ", -INDENT_STD, INDENT_STD, 0);
363 match &limit.kind {
364 ExprKind::Const(value) if value.is_null() => self.buf.push_str("ALL"),
365 _ => self.expr(limit, false)?,
366 }
367 }
368 }
369 Ok(())
370 }
371
372 fn with_clause(&mut self, query: &Query) -> Result<()> {
374 if query.ctes.is_empty() {
375 return Ok(());
376 }
377 self.indent += INDENT_STD;
378 if !self.flat {
379 self.buf.push(' ');
380 }
381 let mut sep = if query.recursive { "WITH RECURSIVE " } else { "WITH " };
382 for cte in &query.ctes {
383 self.buf.push_str(sep);
384 self.buf.push_str("e_identifier(&cte.name));
385 if !cte.aliases.is_empty() {
386 let names: Vec<String> = cte.aliases.iter().map(|n| quote_identifier(n)).collect();
387 self.buf.push_str(&format!("({})", names.join(", ")));
388 }
389 self.buf.push_str(" AS ");
390 match cte.materialized {
391 Some(true) => self.buf.push_str("MATERIALIZED "),
392 Some(false) => self.buf.push_str("NOT MATERIALIZED "),
393 None => {}
394 }
395 self.buf.push('(');
396 self.keyword("", 0, 0, 0);
397 self.query_def(&cte.query, None, true, self.indent)?;
398 self.keyword("", 0, 0, 0);
399 self.buf.push(')');
400 self.search_cycle(cte)?;
401 sep = ", ";
402 }
403 self.indent -= INDENT_STD;
404 self.keyword("", 0, 0, 0);
405 Ok(())
406 }
407
408 fn search_cycle(&mut self, cte: &Cte) -> Result<()> {
410 let names = |list: &[String]| -> String {
411 list.iter().map(|n| quote_identifier(n)).collect::<Vec<_>>().join(", ")
412 };
413 if let Some(s) = &cte.search {
414 let order = if s.breadth { "BREADTH" } else { "DEPTH" };
415 let columns = names(&s.columns);
416 let seq = quote_identifier(&s.seq);
417 self.buf.push_str(&format!(" SEARCH {order} FIRST BY {columns} SET {seq}"));
418 }
419 if let Some(c) = &cte.cycle {
420 let columns = names(&c.columns);
421 let mark = quote_identifier(&c.mark);
422 self.buf.push_str(&format!(" CYCLE {columns} SET {mark}"));
423 let plain = matches!(c.value.kind, ExprKind::Const(Value::Bool(true)))
424 && matches!(c.default.kind, ExprKind::Const(Value::Bool(false)))
425 && c.ty == oid::BOOL;
426 if !plain {
427 self.buf.push_str(" TO ");
428 self.expr(&c.value, false)?;
429 self.buf.push_str(" DEFAULT ");
430 self.expr(&c.default, false)?;
431 }
432 self.buf.push_str(&format!(" USING {}", quote_identifier(&c.path)));
433 }
434 Ok(())
435 }
436
437 fn basic_select(&mut self, query: &Query, result: Option<&[String]>) -> Result<()> {
439 self.indent += INDENT_STD;
440 if !self.flat {
441 self.buf.push(' ');
442 }
443 if let Some(rows) = simple_values(query, result) {
444 return self.values(rows);
445 }
446 self.buf.push_str("SELECT");
447 if !query.distinct.is_empty() {
448 if query.distinct_on {
449 self.buf.push_str(" DISTINCT ON (");
450 for (i, item) in query.distinct.iter().enumerate() {
451 if i > 0 {
452 self.buf.push_str(", ");
453 }
454 let e = target_expr(query, item)?;
455 self.sort_group(e, item.target + 1, false)?;
456 }
457 self.buf.push(')');
458 } else {
459 self.buf.push_str(" DISTINCT");
460 }
461 }
462 self.target_list(query, result)?;
463 self.clause_from(query)?;
464 if let Some(filter) = &query.filter {
465 self.keyword(" WHERE ", -INDENT_STD, INDENT_STD, 1);
466 self.expr(filter, false)?;
467 }
468 if !query.group.is_empty() || !query.grouping_sets.is_empty() {
469 self.keyword(" GROUP BY ", -INDENT_STD, INDENT_STD, 1);
470 if query.group_distinct {
471 self.buf.push_str("DISTINCT ");
472 }
473 let saved = std::mem::replace(&mut self.in_group_by, true);
474 if query.grouping_sets.is_empty() {
475 for (i, item) in query.group.iter().enumerate() {
476 if i > 0 {
477 self.buf.push_str(", ");
478 }
479 let e = target_expr(query, item)?;
480 self.sort_group(e, item.target + 1, false)?;
481 }
482 } else {
483 for (i, set) in query.grouping_sets.iter().enumerate() {
484 if i > 0 {
485 self.buf.push_str(", ");
486 }
487 self.grouping_set(query, set, true)?;
488 }
489 }
490 self.in_group_by = saved;
491 }
492 if let Some(having) = &query.having {
493 self.keyword(" HAVING ", -INDENT_STD, INDENT_STD, 0);
494 self.expr(having, false)?;
495 }
496 let mut first = true;
498 for window in &query.windows {
499 let Some(name) = &window.name else { continue };
500 if first {
501 self.keyword(" WINDOW ", -INDENT_STD, INDENT_STD, 1);
502 } else {
503 self.buf.push_str(", ");
504 }
505 first = false;
506 self.buf.push_str(&format!("{} AS ", quote_identifier(name)));
507 self.window_spec(window)?;
508 }
509 Ok(())
510 }
511
512 fn window_spec(&mut self, window: &WindowClause) -> Result<()> {
514 let targets = std::mem::take(&mut self.window_targets);
515 let exprs: Vec<&Expr> = targets.iter().collect();
516 let done = self.window_parts(window, &exprs);
517 self.window_targets = targets;
518 done
519 }
520
521 fn window_parts(&mut self, window: &WindowClause, exprs: &[&Expr]) -> Result<()> {
523 self.buf.push('(');
524 let mut space = false;
525 if let Some(refname) = &window.refname {
526 self.buf.push_str("e_identifier(refname));
527 space = true;
528 }
529 if !window.partition.is_empty() && window.refname.is_none() {
530 if space {
531 self.buf.push(' ');
532 }
533 self.buf.push_str("PARTITION BY ");
534 for (i, item) in window.partition.iter().enumerate() {
535 if i > 0 {
536 self.buf.push_str(", ");
537 }
538 let e = exprs
539 .get(item.target)
540 .ok_or_else(|| Error::internal("an item of PARTITION BY with no expression"))?;
541 self.sort_group(e, item.target + 1, false)?;
542 }
543 space = true;
544 }
545 if !window.order.is_empty() && !window.copied_order {
546 if space {
547 self.buf.push(' ');
548 }
549 self.buf.push_str("ORDER BY ");
550 self.order_by(&window.order, exprs, false)?;
551 space = true;
552 }
553 if window.frame.options & FRAMEOPTION_NONDEFAULT != 0 {
554 if space {
555 self.buf.push(' ');
556 }
557 self.frame(&window.frame)?;
558 }
559 self.buf.push(')');
560 Ok(())
561 }
562
563 pub(super) fn frame(&mut self, frame: &Frame) -> Result<()> {
565 let options = frame.options;
566 self.buf.push_str(if options & FRAMEOPTION_RANGE != 0 {
567 "RANGE "
568 } else if options & FRAMEOPTION_ROWS != 0 {
569 "ROWS "
570 } else {
571 "GROUPS "
572 });
573 if options & FRAMEOPTION_BETWEEN != 0 {
574 self.buf.push_str("BETWEEN ");
575 }
576 if options & FRAMEOPTION_START_UNBOUNDED_PRECEDING != 0 {
577 self.buf.push_str("UNBOUNDED PRECEDING ");
578 } else if options & FRAMEOPTION_START_CURRENT_ROW != 0 {
579 self.buf.push_str("CURRENT ROW ");
580 } else if options & FRAMEOPTION_START_OFFSET != 0 {
581 let offset = frame
582 .start
583 .as_ref()
584 .ok_or_else(|| Error::internal("a frame start with no offset"))?;
585 self.expr(offset, false)?;
586 self.buf.push_str(if options & FRAMEOPTION_START_OFFSET_PRECEDING != 0 {
587 " PRECEDING "
588 } else {
589 " FOLLOWING "
590 });
591 }
592 if options & FRAMEOPTION_BETWEEN != 0 {
593 self.buf.push_str("AND ");
594 if options & FRAMEOPTION_END_UNBOUNDED_FOLLOWING != 0 {
595 self.buf.push_str("UNBOUNDED FOLLOWING ");
596 } else if options & FRAMEOPTION_END_CURRENT_ROW != 0 {
597 self.buf.push_str("CURRENT ROW ");
598 } else if options & FRAMEOPTION_END_OFFSET != 0 {
599 let offset = frame
600 .end
601 .as_ref()
602 .ok_or_else(|| Error::internal("a frame end with no offset"))?;
603 self.expr(offset, false)?;
604 self.buf.push_str(if options & FRAMEOPTION_END_OFFSET_PRECEDING != 0 {
605 " PRECEDING "
606 } else {
607 " FOLLOWING "
608 });
609 }
610 }
611 if options & FRAMEOPTION_EXCLUDE_CURRENT_ROW != 0 {
612 self.buf.push_str("EXCLUDE CURRENT ROW ");
613 } else if options & FRAMEOPTION_EXCLUDE_GROUP != 0 {
614 self.buf.push_str("EXCLUDE GROUP ");
615 } else if options & FRAMEOPTION_EXCLUDE_TIES != 0 {
616 self.buf.push_str("EXCLUDE TIES ");
617 }
618 self.buf.pop();
620 Ok(())
621 }
622
623 pub(super) fn window_func(&mut self, w: &WindowFunc) -> Result<()> {
625 self.window_func_as(w, None)
626 }
627
628 pub(super) fn window_func_as(
630 &mut self,
631 w: &WindowFunc,
632 json: Option<(&str, &str, bool)>,
633 ) -> Result<()> {
634 match json {
635 Some((name, _, _)) => self.buf.push_str(name),
636 None => {
637 let proc = builtin::proc_by_oid(w.oid).ok_or_else(|| {
638 Error::internal(format!("cache lookup failed for function {}", w.oid))
639 })?;
640 self.buf.push_str("e_identifier(proc.name));
641 }
642 }
643 self.buf.push('(');
644 if w.star {
645 self.buf.push('*');
646 } else if let Some((_, _, true)) = json {
647 let [key, value, ..] = w.args.as_slice() else {
648 return Err(Error::internal("JSON_OBJECTAGG with less than two arguments"));
649 };
650 self.expr(key, false)?;
651 self.buf.push_str(" : ");
652 self.expr(value, false)?;
653 } else {
654 for (i, arg) in w.args.iter().enumerate() {
655 if i > 0 {
656 self.buf.push_str(", ");
657 }
658 self.expr(arg, true)?;
659 }
660 }
661 if let Some((_, options, _)) = json {
662 self.buf.push_str(options);
663 }
664 if let Some(filter) = &w.filter {
665 self.buf.push_str(") FILTER (WHERE ");
666 self.expr(filter, false)?;
667 }
668 self.buf.push_str(") ");
669 if w.nulls == NullTreatment::Ignore {
670 self.buf.push_str("IGNORE NULLS ");
671 }
672 self.buf.push_str("OVER ");
673 if let Some(Some(name)) = w.winref.checked_sub(1).and_then(|i| self.window_names.get(i)) {
674 self.buf.push_str("e_identifier(name));
675 return Ok(());
676 }
677 let window = w.winref.checked_sub(1).and_then(|i| self.windows.get(i)).cloned();
678 let Some(window) = window else {
679 return Err(Error::internal(format!(
680 "could not find window clause for winref {}",
681 w.winref
682 )));
683 };
684 match &window.name {
685 Some(name) => self.buf.push_str("e_identifier(name)),
686 None => self.window_spec(&window)?,
687 }
688 Ok(())
689 }
690
691 fn values(&mut self, rows: &[Vec<Expr>]) -> Result<()> {
693 self.buf.push_str("VALUES ");
694 for (i, row) in rows.iter().enumerate() {
695 if i > 0 {
696 self.buf.push_str(", ");
697 }
698 self.buf.push('(');
699 for (j, value) in row.iter().enumerate() {
700 if j > 0 {
701 self.buf.push(',');
702 }
703 self.expr(value, false)?;
704 }
705 self.buf.push(')');
706 }
707 Ok(())
708 }
709
710 fn target_list(&mut self, query: &Query, result: Option<&[String]>) -> Result<()> {
712 let mut multiline = false;
713 for (i, target) in query.targets.iter().filter(|t| !t.junk).enumerate() {
714 self.buf.push_str(if i == 0 { " " } else { ", " });
715 let outer = std::mem::take(&mut self.buf);
716 let merged = self.merged_name(&target.expr);
717 let attname = match &target.expr.kind {
718 _ if merged.is_some() => {
719 self.expr(&target.expr, true)?;
720 merged
721 }
722 ExprKind::Var(var) if var.attnum == 0 => {
723 self.whole_row(var, &target.expr, true)?;
724 if self.names_visible { None } else { Some("?column?".to_string()) }
725 }
726 ExprKind::JoinRow(row) if row.alias.is_some() => {
728 self.expr(&target.expr, true)?;
729 self.buf.push_str("::record");
730 if self.names_visible { None } else { Some("?column?".to_string()) }
731 }
732 ExprKind::Var(var) => Some(self.variable(var, false)?),
733 _ => {
734 self.expr(&target.expr, true)?;
735 if self.names_visible { None } else { Some("?column?".to_string()) }
736 }
737 };
738 let colname = result.and_then(|r| r.get(i)).unwrap_or(&target.name);
739 if attname.as_deref() != Some(colname.as_str()) {
740 self.buf.push_str(&format!(" AS {}", quote_identifier(colname)));
741 }
742 let item = std::mem::replace(&mut self.buf, outer);
743 if self.wrap >= 0 {
744 let leading = item.starts_with('\n');
745 if leading {
746 self.trim_spaces();
747 } else if i > 0 && (self.too_long(&item) || multiline) {
748 self.keyword("", -INDENT_STD, INDENT_STD, INDENT_VAR);
749 }
750 multiline = item[usize::from(leading)..].contains('\n');
751 }
752 self.buf.push_str(&item);
753 }
754 Ok(())
755 }
756
757 fn trim_spaces(&mut self) {
759 let kept = self.buf.trim_end_matches(' ').len();
760 self.buf.truncate(kept);
761 }
762
763 fn too_long(&self, item: &str) -> bool {
765 let line = self.buf.rsplit('\n').next().map_or(0, str::len);
766 usize::try_from(self.wrap).is_ok_and(|wrap| line + item.len() > wrap)
767 }
768
769 fn clause_from(&mut self, query: &Query) -> Result<()> {
771 for (i, item) in query.from.iter().enumerate() {
772 if i == 0 {
773 self.keyword(" FROM ", -INDENT_STD, INDENT_STD, 2);
774 self.range_item(item, query)?;
775 continue;
776 }
777 self.buf.push_str(", ");
778 let outer = std::mem::take(&mut self.buf);
779 self.range_item(item, query)?;
780 let text = std::mem::replace(&mut self.buf, outer);
781 if self.wrap >= 0 {
782 if text.starts_with('\n') {
783 self.trim_spaces();
784 } else if self.too_long(&text) {
785 self.keyword("", -INDENT_STD, INDENT_STD, INDENT_VAR);
786 }
787 }
788 self.buf.push_str(&text);
789 }
790 Ok(())
791 }
792
793 fn range_item(&mut self, item: &FromItem, query: &Query) -> Result<()> {
795 let index = match item {
796 FromItem::Relation(index) => *index,
797 FromItem::Join(join) => return self.join(join, query),
798 };
799 let rel = query
800 .relations
801 .get(index)
802 .ok_or_else(|| Error::internal(format!("no relation {index} in the query")))?;
803 let lateral = rel.lateral
804 || rel.function.as_ref().is_some_and(|f| f.calls.iter().any(|(c, _)| refers_to(c, 0)));
805 if lateral {
806 self.buf.push_str("LATERAL ");
807 }
808 let mut coldef = false;
809 if let Some(cte) = &rel.cte {
810 self.buf.push_str("e_identifier(&cte.name));
811 } else if rel.oid != 0 {
812 self.buf.push_str(&relation_name(rel.oid, self.session)?);
813 } else if let Some(table) = rel.json_table() {
814 self.json_table(table)?;
815 } else if let Some(function) = &rel.function {
816 coldef = self.function_item(function, &rel.columns)?;
817 } else if let Some(rows) = &rel.values {
818 self.buf.push('(');
819 self.values(rows)?;
820 self.buf.push(')');
821 } else if let Some(sub) = &rel.subquery {
822 self.buf.push('(');
823 self.query_def(sub, None, true, self.indent)?;
824 self.buf.push(')');
825 }
826 let space = self.namespaces.last().ok_or_else(|| Error::internal("no namespace"))?;
827 let refname = space.names.get(index).cloned().unwrap_or_default();
828 let columns = space.columns.get(index).cloned().unwrap_or_default();
829 let print_aliases = space.print_aliases.get(index).copied().unwrap_or(false);
830 let show = rel.alias.is_some()
832 || print_aliases
833 || match &rel.cte {
834 Some(cte) => cte.name != refname,
835 None if rel.json_table().is_some() => false,
836 None if rel.oid == 0 => true,
837 None => {
838 reg::class_name(rel.oid, self.session).is_none_or(|(name, _)| name != refname)
839 }
840 };
841 if show {
842 self.buf.push(' ');
843 self.buf.push_str("e_identifier(&refname));
844 }
845 if coldef {
846 self.coldef(&columns, &rel.columns)?;
847 } else if print_aliases && !columns.is_empty() {
848 let names: Vec<String> =
850 columns.iter().filter(|c| !c.is_empty()).map(|c| quote_identifier(c)).collect();
851 self.buf.push_str(&format!("({})", names.join(", ")));
852 }
853 if let Some(sample) = &rel.tablesample {
855 self.tablesample(sample)?;
856 }
857 Ok(())
858 }
859
860 fn tablesample(&mut self, sample: &TableSample) -> Result<()> {
862 let proc = builtin::proc_by_oid(sample.handler).ok_or_else(|| {
863 Error::internal(format!("cache lookup failed for function {}", sample.handler))
864 })?;
865 let name = if reg::function_visible(proc, self.session) {
866 quote_identifier(proc.name)
867 } else {
868 reg::qualified(reg::namespace_name(proc.namespace, self.session), proc.name)
869 };
870 self.buf.push_str(&format!(" TABLESAMPLE {name} ("));
871 for (i, arg) in sample.args.iter().enumerate() {
872 if i > 0 {
873 self.buf.push_str(", ");
874 }
875 self.expr(arg, false)?;
876 }
877 self.buf.push(')');
878 if let Some(seed) = &sample.repeatable {
879 self.buf.push_str(" REPEATABLE (");
880 self.expr(seed, false)?;
881 self.buf.push(')');
882 }
883 Ok(())
884 }
885
886 fn function_item(&mut self, function: &FromFunction, columns: &[Column]) -> Result<bool> {
888 let has_coldef = |i: usize| function.coldefs.get(i).copied().unwrap_or(false);
889 let mut coldef = false;
890 if let [(call, _)] = function.calls.as_slice()
891 && (!has_coldef(0) || !function.ordinality)
892 {
893 self.funccall(call)?;
894 coldef = has_coldef(0);
895 } else if function.calls.iter().enumerate().all(|(i, (call, _))| {
896 !has_coldef(i) && matches!(&call.kind, ExprKind::Func(f) if f.oid == UNNEST)
897 }) {
898 self.buf.push_str("UNNEST(");
899 let mut first = true;
900 for (call, _) in &function.calls {
901 let ExprKind::Func(f) = &call.kind else { continue };
902 for arg in &f.args {
903 if !first {
904 self.buf.push_str(", ");
905 }
906 first = false;
907 self.expr(arg, true)?;
908 }
909 }
910 self.buf.push(')');
911 } else {
912 self.buf.push_str("ROWS FROM(");
913 let mut at = 0;
914 for (i, (call, count)) in function.calls.iter().enumerate() {
915 if i > 0 {
916 self.buf.push_str(", ");
917 }
918 self.funccall(call)?;
919 let part = columns.get(at..at + count).unwrap_or_default();
920 if has_coldef(i) {
921 self.buf.push_str(" AS ");
922 let names: Vec<String> = part.iter().map(|c| c.name.clone()).collect();
923 self.coldef(&names, part)?;
924 }
925 at += count;
926 }
927 self.buf.push(')');
928 }
929 if function.ordinality {
930 self.buf.push_str(" WITH ORDINALITY");
931 }
932 Ok(coldef)
933 }
934
935 fn funccall(&mut self, e: &Expr) -> Result<()> {
937 if looks_like_function(e) {
938 return self.expr(e, true);
939 }
940 self.buf.push_str("CAST(");
941 self.expr(e, false)?;
942 let ty = reg::type_text(e.ty, Some(e.typmod), self.session)?;
943 self.buf.push_str(&format!(" AS {ty})"));
944 Ok(())
945 }
946
947 fn coldef(&mut self, names: &[String], columns: &[Column]) -> Result<()> {
949 self.buf.push('(');
950 for (i, (name, column)) in names.iter().zip(columns).enumerate() {
951 if i > 0 {
952 self.buf.push_str(", ");
953 }
954 let ty = reg::type_text(column.ty, Some(column.typmod), self.session)?;
955 self.buf.push_str(&format!("{} {ty}", quote_identifier(name)));
956 }
957 self.buf.push(')');
958 Ok(())
959 }
960
961 fn join(&mut self, join: &Join, query: &Query) -> Result<()> {
963 let mut relations = Vec::new();
964 base_relations(&join.left, &mut relations);
965 base_relations(&join.right, &mut relations);
966 let space = self.namespaces.last().ok_or_else(|| Error::internal("no namespace"))?;
967 let k = space
968 .joins
969 .iter()
970 .position(|j| j.relations == relations)
971 .ok_or_else(|| Error::internal("a join with no names"))?;
972 let using = space.joins[k].using.clone();
973 let paren_right = self.paren
974 && !matches!(&join.right, FromItem::Relation(_))
975 && !matches!(&join.right, FromItem::Join(right) if right.alias.is_some());
976 let parens = !self.paren || join.alias.is_some();
977 if parens {
978 self.buf.push('(');
979 }
980 if let Some(space) = self.namespaces.last_mut() {
981 space.inside.push(k);
982 }
983 let done = self.join_body(join, query, paren_right, &using);
984 if let Some(space) = self.namespaces.last_mut() {
985 space.inside.pop();
986 }
987 done?;
988 if parens {
989 self.buf.push(')');
990 }
991 let space = self.namespaces.last().ok_or_else(|| Error::internal("no namespace"))?;
992 let names = &space.joins[k];
993 if let Some(name) = &names.name {
994 let mut text = format!(" {}", quote_identifier(name));
995 if names.print_aliases && !names.columns.is_empty() {
996 let columns: Vec<String> =
997 names.columns.iter().map(|c| quote_identifier(c)).collect();
998 text.push_str(&format!("({})", columns.join(", ")));
999 }
1000 self.buf.push_str(&text);
1001 }
1002 Ok(())
1003 }
1004
1005 fn join_body(
1007 &mut self,
1008 join: &Join,
1009 query: &Query,
1010 paren_right: bool,
1011 using: &[String],
1012 ) -> Result<()> {
1013 self.range_item(&join.left, query)?;
1014 let word = match join.kind {
1015 JoinKind::Inner if join.on.is_some() => " JOIN ",
1016 JoinKind::Inner => " CROSS JOIN ",
1017 JoinKind::Left => " LEFT JOIN ",
1018 JoinKind::Full => " FULL JOIN ",
1019 JoinKind::Right => " RIGHT JOIN ",
1020 JoinKind::Semi | JoinKind::Anti | JoinKind::RightSemi | JoinKind::RightAnti => " JOIN ",
1021 };
1022 self.keyword(word, -INDENT_STD, INDENT_STD, INDENT_JOIN);
1023 if paren_right {
1024 self.buf.push('(');
1025 }
1026 self.range_item(&join.right, query)?;
1027 if paren_right {
1028 self.buf.push(')');
1029 }
1030 if !join.using.is_empty() {
1031 let names: Vec<String> = using.iter().map(|n| quote_identifier(n)).collect();
1032 self.buf.push_str(&format!(" USING ({})", names.join(", ")));
1033 if let Some(alias) = &join.using_alias {
1034 self.buf.push_str(&format!(" AS {}", quote_identifier(alias)));
1035 }
1036 } else if let Some(on) = &join.on {
1037 self.buf.push_str(" ON ");
1038 self.open();
1039 self.expr(on, false)?;
1040 self.close();
1041 } else if join.kind != JoinKind::Inner {
1042 self.buf.push_str(" ON TRUE");
1043 }
1044 Ok(())
1045 }
1046
1047 fn set_op(&mut self, op: &SetOp, query: &Query, result: Option<&[String]>) -> Result<()> {
1049 let paren_left =
1050 matches!(&op.left, SetTree::Op(left) if left.kind != op.kind || left.all != op.all);
1051 let mut sub = 0;
1052 if paren_left {
1053 self.buf.push('(');
1054 sub = INDENT_STD;
1055 self.keyword("", sub, 0, 0);
1056 }
1057 self.set_tree(&op.left, query, result)?;
1058 self.keyword(if paren_left { ") " } else { "" }, -sub, 0, 0);
1059 self.buf.push_str(match op.kind {
1060 SetKind::Union => "UNION ",
1061 SetKind::Intersect => "INTERSECT ",
1062 SetKind::Except => "EXCEPT ",
1063 });
1064 if op.all {
1065 self.buf.push_str("ALL ");
1066 }
1067 let paren_right = matches!(op.right, SetTree::Op(_));
1068 sub = 0;
1069 if paren_right {
1070 self.buf.push('(');
1071 sub = INDENT_STD;
1072 }
1073 self.keyword("", sub, 0, 0);
1074 let saved = std::mem::replace(&mut self.names_visible, false);
1075 self.set_tree(&op.right, query, result)?;
1076 self.names_visible = saved;
1077 self.indent -= sub;
1078 if paren_right {
1079 self.keyword(")", 0, 0, 0);
1080 }
1081 Ok(())
1082 }
1083
1084 fn set_tree(&mut self, tree: &SetTree, query: &Query, result: Option<&[String]>) -> Result<()> {
1086 let index = match tree {
1087 SetTree::Op(op) => return self.set_op(op, query, result),
1088 SetTree::Leaf(index) => *index,
1089 };
1090 let sub = query
1091 .relations
1092 .get(index)
1093 .and_then(|r| r.subquery.as_deref())
1094 .ok_or_else(|| Error::internal("a part of a set operation with no query"))?;
1095 let paren = !sub.sort.is_empty()
1096 || sub.offset.is_some()
1097 || sub.limit.is_some()
1098 || sub.set_op.is_some();
1099 let mut sub = sub.clone();
1101 for target in &mut sub.targets {
1102 target.expr = target.expr.strip_implicit().clone();
1103 }
1104 if paren {
1105 self.buf.push('(');
1106 }
1107 self.query_def(&sub, result, self.names_visible, self.indent)?;
1108 if paren {
1109 self.buf.push(')');
1110 }
1111 Ok(())
1112 }
1113
1114 fn order_by(&mut self, items: &[SortGroup], exprs: &[&Expr], force: bool) -> Result<()> {
1116 for (i, item) in items.iter().enumerate() {
1117 if i > 0 {
1118 self.buf.push_str(", ");
1119 }
1120 let e = exprs
1121 .get(item.target)
1122 .ok_or_else(|| Error::internal("an item of ORDER BY with no expression"))?;
1123 self.sort_group(e, item.target + 1, force)?;
1124 let (lt, gt) = sort_operators(e.ty);
1125 if item.operator == lt {
1126 if item.nulls_first {
1127 self.buf.push_str(" NULLS FIRST");
1128 }
1129 } else if item.operator == gt {
1130 self.buf.push_str(" DESC");
1131 if !item.nulls_first {
1132 self.buf.push_str(" NULLS LAST");
1133 }
1134 } else {
1135 let op = builtin::operator_by_oid(item.operator).ok_or_else(|| {
1136 Error::internal(format!("cache lookup failed for operator {}", item.operator))
1137 })?;
1138 self.buf.push_str(&format!(" USING {}", op.name));
1139 self.buf.push_str(if item.nulls_first { " NULLS FIRST" } else { " NULLS LAST" });
1140 }
1141 }
1142 Ok(())
1143 }
1144
1145 fn sort_group(&mut self, e: &Expr, number: usize, force: bool) -> Result<()> {
1147 if force {
1148 self.buf.push_str(&number.to_string());
1149 return Ok(());
1150 }
1151 if self.merged_name(e).is_some() {
1152 return self.expr(e, true);
1153 }
1154 match &e.kind {
1155 ExprKind::Const(value) => self.constant(e, value, 1),
1156 ExprKind::Var(var) if var.attnum != 0 => self.variable(var, true).map(|_| ()),
1157 _ => {
1158 let paren = self.paren
1159 || matches!(&e.kind, ExprKind::Func(f) if !matches!(f.form, FuncForm::Operator(_)))
1160 || matches!(
1161 e.kind,
1162 ExprKind::Agg(_) | ExprKind::Window(_) | ExprKind::JsonCtor(_)
1163 );
1164 if paren {
1165 self.buf.push('(');
1166 }
1167 self.expr(e, true)?;
1168 if paren {
1169 self.buf.push(')');
1170 }
1171 Ok(())
1172 }
1173 }
1174 }
1175
1176 fn grouping_set(&mut self, query: &Query, set: &GroupingSet, omit_parens: bool) -> Result<()> {
1178 let (open, content, omit_child) = match set {
1179 GroupingSet::Empty => {
1180 self.buf.push_str("()");
1181 return Ok(());
1182 }
1183 GroupingSet::Simple(items) => {
1184 let parens = !omit_parens || items.len() != 1;
1185 if parens {
1186 self.buf.push('(');
1187 }
1188 for (i, &target) in items.iter().enumerate() {
1189 if i > 0 {
1190 self.buf.push_str(", ");
1191 }
1192 let e = query
1193 .targets
1194 .get(target)
1195 .map(|t| &t.expr)
1196 .ok_or_else(|| Error::internal("a grouping set item has no target"))?;
1197 self.sort_group(e, target + 1, false)?;
1198 }
1199 if parens {
1200 self.buf.push(')');
1201 }
1202 return Ok(());
1203 }
1204 GroupingSet::Rollup(content) => ("ROLLUP(", content, true),
1205 GroupingSet::Cube(content) => ("CUBE(", content, true),
1206 GroupingSet::Sets(content) => ("GROUPING SETS (", content, false),
1207 };
1208 self.buf.push_str(open);
1209 for (i, child) in content.iter().enumerate() {
1210 if i > 0 {
1211 self.buf.push_str(", ");
1212 }
1213 self.grouping_set(query, child, omit_child)?;
1214 }
1215 self.buf.push(')');
1216 Ok(())
1217 }
1218
1219 pub(super) fn aggregate(&mut self, agg: &Aggref) -> Result<()> {
1221 self.aggregate_as(agg, None)
1222 }
1223
1224 pub(super) fn aggregate_as(
1226 &mut self,
1227 agg: &Aggref,
1228 json: Option<(&str, &str, bool)>,
1229 ) -> Result<()> {
1230 let proc = builtin::proc_by_oid(agg.oid).ok_or_else(|| {
1231 Error::internal(format!("cache lookup failed for function {}", agg.oid))
1232 })?;
1233 match json {
1234 Some((name, _, _)) => self.buf.push_str(name),
1235 None => self.buf.push_str("e_identifier(proc.name)),
1236 }
1237 self.buf.push('(');
1238 if !agg.distinct.is_empty() {
1239 self.buf.push_str("DISTINCT ");
1240 }
1241 if agg.kind != b'n' {
1242 for (i, arg) in agg.direct.iter().enumerate() {
1244 if i > 0 {
1245 self.buf.push_str(", ");
1246 }
1247 self.expr(arg, true)?;
1248 }
1249 self.buf.push_str(") WITHIN GROUP (ORDER BY ");
1250 let exprs: Vec<&Expr> = agg.args.iter().collect();
1251 self.order_by(&agg.order, &exprs, false)?;
1252 } else if agg.star {
1253 self.buf.push('*');
1254 } else {
1255 let variadic = agg.variadic && proc.variadic != 0;
1256 let object = matches!(json, Some((_, _, true)));
1257 for (i, arg) in agg.args.iter().take(agg.nargs).enumerate() {
1258 if object && i > 1 {
1259 break;
1260 }
1261 if i > 0 {
1262 self.buf.push_str(if object { " : " } else { ", " });
1263 }
1264 if variadic && i + 1 == agg.nargs {
1265 self.buf.push_str("VARIADIC ");
1266 }
1267 self.expr(arg, true)?;
1268 }
1269 }
1270 if agg.kind == b'n' && !agg.order.is_empty() {
1271 self.buf.push_str(" ORDER BY ");
1272 let exprs: Vec<&Expr> = agg.args.iter().collect();
1273 self.order_by(&agg.order, &exprs, false)?;
1274 }
1275 if let Some((_, options, _)) = json {
1276 self.buf.push_str(options);
1277 }
1278 if let Some(filter) = &agg.filter {
1279 self.buf.push_str(") FILTER (WHERE ");
1280 self.expr(filter, false)?;
1281 }
1282 self.buf.push(')');
1283 Ok(())
1284 }
1285
1286 pub(super) fn json_array_query(&mut self, c: &JsonCtor) -> Result<()> {
1288 let wrapper = match c.func.as_ref().map(|f| &f.kind) {
1289 Some(ExprKind::Coalesce(args)) => match args.first().map(|a| &a.kind) {
1290 Some(ExprKind::SubLink(sub)) => Some(&sub.query),
1291 _ => None,
1292 },
1293 _ => None,
1294 };
1295 let Some(wrapper) = wrapper else {
1296 return Err(Error::internal("JSON_ARRAY with a subquery and no COALESCE"));
1297 };
1298 let Some(query) = wrapper.relations.first().and_then(|r| r.subquery.as_deref()) else {
1299 return Err(Error::internal("JSON_ARRAY with no subquery"));
1300 };
1301 self.buf.push_str("JSON_ARRAY(");
1302 let names = vec![String::new(); wrapper.relations.len()];
1304 self.namespaces.push(Namespace { names, ..Default::default() });
1305 let done = self.query_def(query, None, false, self.indent);
1306 self.namespaces.pop();
1307 done?;
1308 json_format(c.format, &mut self.buf);
1309 self.json_ctor_options(c)?;
1310 self.buf.push(')');
1311 Ok(())
1312 }
1313
1314 pub(super) fn sublink(&mut self, sub: &SubLink) -> Result<()> {
1316 self.buf.push_str(if sub.kind == SubLinkKind::Array { "ARRAY(" } else { "(" });
1317 let mut opname = "";
1318 if let Some(test) = &sub.test {
1319 let (ops, row) = match &test.kind {
1321 ExprKind::Bool(_, ops) => (ops.as_slice(), true),
1322 ExprKind::RowCompare(rc) => (rc.ops.as_slice(), true),
1323 _ => (std::slice::from_ref(test), false),
1324 };
1325 if row {
1326 self.buf.push('(');
1327 }
1328 for (i, op) in ops.iter().enumerate() {
1329 let ExprKind::Func(Func { form: FuncForm::Operator(opno), args, .. }) = &op.kind
1330 else {
1331 return Err(not_yet("a deparse of a subquery with this test"));
1332 };
1333 if i > 0 {
1334 self.buf.push_str(", ");
1335 }
1336 let left =
1337 args.first().ok_or_else(|| Error::internal("a test with no left argument"))?;
1338 self.expr(left, true)?;
1339 if i == 0 {
1340 opname =
1341 builtin::operator_by_oid(*opno).map(|op| op.name).ok_or_else(|| {
1342 Error::internal(format!("cache lookup failed for operator {opno}"))
1343 })?;
1344 }
1345 }
1346 if row {
1347 self.buf.push(')');
1348 }
1349 }
1350 let paren = match sub.kind {
1351 SubLinkKind::Exists => {
1352 self.buf.push_str("EXISTS ");
1353 true
1354 }
1355 SubLinkKind::Any if opname == "=" => {
1356 self.buf.push_str(" IN ");
1357 true
1358 }
1359 SubLinkKind::Any => {
1360 self.buf.push_str(&format!(" {opname} ANY "));
1361 true
1362 }
1363 SubLinkKind::All => {
1364 self.buf.push_str(&format!(" {opname} ALL "));
1365 true
1366 }
1367 SubLinkKind::RowCompare => {
1368 self.buf.push_str(&format!(" {opname} "));
1369 true
1370 }
1371 SubLinkKind::Expr | SubLinkKind::Array | SubLinkKind::Multi { .. } => false,
1372 };
1373 if paren {
1374 self.buf.push('(');
1375 }
1376 self.query_def(&sub.query, None, false, self.indent)?;
1377 self.buf.push_str(if paren { "))" } else { ")" });
1378 Ok(())
1379 }
1380
1381 pub(super) fn sql_syntax(&mut self, e: &Expr, f: &Func) -> Result<bool> {
1383 let proc = builtin::proc_by_oid(f.oid).ok_or_else(|| {
1384 Error::internal(format!("cache lookup failed for function {}", f.oid))
1385 })?;
1386 let args = f.args.as_slice();
1387 let text = |at: usize| match args.get(at).map(|a| (&a.kind, a.ty)) {
1388 Some((ExprKind::Const(value), oid::TEXT)) => value.as_str().map(str::to_string),
1389 _ => None,
1390 };
1391 match (proc.name, args) {
1392 ("timezone", [zone, value]) => {
1393 self.buf.push('(');
1394 self.paren(value, false, e)?;
1395 self.buf.push_str(" AT TIME ZONE ");
1396 self.paren(zone, false, e)?;
1397 self.buf.push(')');
1398 }
1399 ("timezone", [value]) => {
1400 self.buf.push('(');
1401 self.paren(value, false, e)?;
1402 self.buf.push_str(" AT LOCAL)");
1403 }
1404 ("overlaps", [a, b, c, d]) => {
1405 self.buf.push_str("((");
1406 self.expr(a, false)?;
1407 self.buf.push_str(", ");
1408 self.expr(b, false)?;
1409 self.buf.push_str(") OVERLAPS (");
1410 self.expr(c, false)?;
1411 self.buf.push_str(", ");
1412 self.expr(d, false)?;
1413 self.buf.push_str("))");
1414 }
1415 ("extract", [_, value]) => {
1416 let Some(field) = text(0) else { return Ok(false) };
1417 self.buf.push_str(&format!("EXTRACT({} FROM ", quote_identifier(&field)));
1418 self.expr(value, false)?;
1419 self.buf.push(')');
1420 }
1421 ("is_normalized", [value, rest @ ..]) if rest.len() <= 1 => {
1422 self.buf.push('(');
1423 self.paren(value, false, e)?;
1424 self.buf.push_str(" IS");
1425 if !rest.is_empty() {
1426 let Some(form) = text(1) else { return Ok(false) };
1427 self.buf.push_str(&format!(" {form}"));
1428 }
1429 self.buf.push_str(" NORMALIZED)");
1430 }
1431 ("pg_collation_for", [value]) => {
1432 self.buf.push_str("COLLATION FOR (");
1433 self.expr(value, false)?;
1434 self.buf.push(')');
1435 }
1436 ("normalize", [value, rest @ ..]) if rest.len() <= 1 => {
1437 self.buf.push_str("NORMALIZE(");
1438 self.expr(value, false)?;
1439 if !rest.is_empty() {
1440 let Some(form) = text(1) else { return Ok(false) };
1441 self.buf.push_str(&format!(", {form}"));
1442 }
1443 self.buf.push(')');
1444 }
1445 ("overlay", [value, placing, from, rest @ ..]) if rest.len() <= 1 => {
1446 self.buf.push_str("OVERLAY(");
1447 self.expr(value, false)?;
1448 self.buf.push_str(" PLACING ");
1449 self.expr(placing, false)?;
1450 self.buf.push_str(" FROM ");
1451 self.expr(from, false)?;
1452 if let [count] = rest {
1453 self.buf.push_str(" FOR ");
1454 self.expr(count, false)?;
1455 }
1456 self.buf.push(')');
1457 }
1458 ("position", [value, part]) => {
1459 self.buf.push_str("POSITION((");
1460 self.expr(part, false)?;
1461 self.buf.push_str(") IN (");
1462 self.expr(value, false)?;
1463 self.buf.push_str("))");
1464 }
1465 ("substring", [value, from, rest @ ..])
1466 if rest.len() <= 1 && proc.argtypes.get(1) == Some(&oid::INT4) =>
1467 {
1468 self.buf.push_str("SUBSTRING(");
1469 self.expr(value, false)?;
1470 self.buf.push_str(" FROM ");
1471 self.expr(from, false)?;
1472 if let [count] = rest {
1473 self.buf.push_str(" FOR ");
1474 self.expr(count, false)?;
1475 }
1476 self.buf.push(')');
1477 }
1478 ("substring", [value, pattern, escape]) => {
1479 self.buf.push_str("SUBSTRING(");
1480 self.expr(value, false)?;
1481 self.buf.push_str(" SIMILAR ");
1482 self.expr(pattern, false)?;
1483 self.buf.push_str(" ESCAPE ");
1484 self.expr(escape, false)?;
1485 self.buf.push(')');
1486 }
1487 ("btrim" | "ltrim" | "rtrim", [value, rest @ ..]) if rest.len() <= 1 => {
1488 self.buf.push_str(match proc.name {
1489 "btrim" => "TRIM(BOTH",
1490 "ltrim" => "TRIM(LEADING",
1491 _ => "TRIM(TRAILING",
1492 });
1493 if let [chars] = rest {
1494 self.buf.push(' ');
1495 self.expr(chars, false)?;
1496 }
1497 self.buf.push_str(" FROM ");
1498 self.expr(value, false)?;
1499 self.buf.push(')');
1500 }
1501 ("system_user", []) => self.buf.push_str("SYSTEM_USER"),
1502 _ => return Ok(false),
1503 }
1504 Ok(true)
1505 }
1506}
1507
1508fn merged_columns(item: &FromItem, out: &mut Vec<(Expr, String)>) {
1510 let FromItem::Join(join) = item else { return };
1511 merged_columns(&join.left, out);
1512 merged_columns(&join.right, out);
1513 if join.alias.is_none() {
1514 for (value, name) in join.merged.iter().zip(&join.using) {
1515 if !matches!(value.kind, ExprKind::Var(_)) {
1516 out.push((value.clone(), name.clone()));
1517 }
1518 }
1519 }
1520}
1521
1522fn join_count(item: &FromItem) -> usize {
1524 match item {
1525 FromItem::Relation(_) => 0,
1526 FromItem::Join(join) => 1 + join_count(&join.left) + join_count(&join.right),
1527 }
1528}
1529
1530fn target_expr<'q>(query: &'q Query, item: &SortGroup) -> Result<&'q Expr> {
1532 query
1533 .targets
1534 .get(item.target)
1535 .map(|t| &t.expr)
1536 .ok_or_else(|| Error::internal("an item of a clause with no target"))
1537}
1538
1539fn base_relations(item: &FromItem, out: &mut Vec<usize>) {
1541 match item {
1542 FromItem::Relation(i) => out.push(*i),
1543 FromItem::Join(join) => {
1544 base_relations(&join.left, out);
1545 base_relations(&join.right, out);
1546 }
1547 }
1548}
1549
1550#[derive(Clone, Copy, Debug)]
1552enum Slot {
1553 Relation(usize),
1554 Join(usize),
1555}
1556
1557#[derive(Debug)]
1559struct JoinInfo<'q> {
1560 join: &'q Join,
1561 left: Slot,
1562 right: Slot,
1563 relations: Vec<usize>,
1564}
1565
1566fn walk_from<'q>(item: &'q FromItem, joins: &mut Vec<JoinInfo<'q>>, order: &mut Vec<Slot>) -> Slot {
1568 let join = match item {
1569 FromItem::Relation(i) => {
1570 order.push(Slot::Relation(*i));
1571 return Slot::Relation(*i);
1572 }
1573 FromItem::Join(join) => join,
1574 };
1575 let k = joins.len();
1576 let (left, right) = (Slot::Relation(0), Slot::Relation(0));
1577 joins.push(JoinInfo { join, left, right, relations: Vec::new() });
1578 let left = walk_from(&join.left, joins, order);
1579 let right = walk_from(&join.right, joins, order);
1580 let mut relations = Vec::new();
1581 for side in [left, right] {
1582 match side {
1583 Slot::Relation(i) => relations.push(i),
1584 Slot::Join(j) => relations.extend_from_slice(&joins[j].relations),
1585 }
1586 }
1587 joins[k] = JoinInfo { join, left, right, relations };
1588 order.push(Slot::Join(k));
1589 Slot::Join(k)
1590}
1591
1592pub(super) fn unique_name(base: String, used: &mut HashMap<String, u32>) -> String {
1594 let Some(mut counter) = used.get(&base).copied() else {
1595 used.insert(base.clone(), 0);
1596 return base;
1597 };
1598 let name = loop {
1599 counter += 1;
1600 let name = format!("{base}_{counter}");
1601 if !used.contains_key(&name) {
1602 break name;
1603 }
1604 };
1605 used.insert(base, counter);
1606 used.insert(name.clone(), 0);
1607 name
1608}
1609
1610#[derive(Debug)]
1612struct ColumnNames {
1613 relations: Vec<Vec<Option<String>>>,
1614 relation_parents: Vec<Vec<String>>,
1615 joins: Vec<Vec<Option<String>>>,
1616 join_parents: Vec<Vec<String>>,
1617 join_using: Vec<Vec<String>>,
1619 using: Vec<String>,
1621 unique_using: bool,
1623}
1624
1625impl ColumnNames {
1626 fn names(&self, slot: Slot) -> Option<&Vec<Option<String>>> {
1627 match slot {
1628 Slot::Relation(i) => self.relations.get(i),
1629 Slot::Join(k) => self.joins.get(k),
1630 }
1631 }
1632
1633 fn push(&mut self, slot: Slot, number: usize, name: &str) {
1635 let names = match slot {
1636 Slot::Relation(i) => self.relations.get_mut(i),
1637 Slot::Join(k) => self.joins.get_mut(k),
1638 };
1639 if let Some(names) = names
1640 && number > 0
1641 {
1642 if names.len() < number {
1643 names.resize(number, None);
1644 }
1645 names[number - 1] = Some(name.to_string());
1646 }
1647 }
1648
1649 fn unique(&self, name: &str, slot: Slot) -> String {
1651 let names = self.names(slot).map(Vec::as_slice).unwrap_or_default();
1652 let parents = match slot {
1653 Slot::Relation(i) => self.relation_parents.get(i),
1654 Slot::Join(k) => self.join_parents.get(k),
1655 };
1656 let parents = parents.map(Vec::as_slice).unwrap_or_default();
1657 let taken = |n: &str| {
1658 names.iter().flatten().any(|t| t == n)
1659 || parents.iter().any(|t| t == n)
1660 || self.using.iter().any(|t| t == n)
1661 };
1662 if !taken(name) {
1663 return name.to_string();
1664 }
1665 (1..).map(|i| format!("{name}_{i}")).find(|n| !taken(n)).unwrap_or_default()
1666 }
1667
1668 fn using_names(&mut self, joins: &[JoinInfo<'_>], k: usize, parent: &[String]) {
1670 let Some(info) = joins.get(k) else { return };
1671 let join = info.join;
1672 if join.alias.is_none() {
1673 let pushed = self.joins.get(k).cloned().unwrap_or_default();
1674 for (i, name) in pushed.iter().enumerate() {
1675 let Some(name) = name else { continue };
1676 let (l, r) = join.sources.get(i).copied().unwrap_or_default();
1677 self.push(info.left, l, name);
1678 self.push(info.right, r, name);
1679 }
1680 }
1681 let mut parent = parent.to_vec();
1682 let mut using = Vec::with_capacity(join.using.len());
1683 for (i, written) in join.using.iter().enumerate() {
1684 let pushed = self.joins.get(k).and_then(|n| n.get(i)).cloned().flatten();
1685 let name = match pushed {
1686 Some(name) => name,
1687 None => {
1688 let wanted = match &join.alias {
1690 Some(_) => join.aliases.get(i).unwrap_or(written),
1691 None => written,
1692 };
1693 let name = self.unique(wanted, Slot::Join(k));
1694 if self.unique_using {
1695 self.using.push(name.clone());
1696 }
1697 self.push(Slot::Join(k), i + 1, &name);
1698 name
1699 }
1700 };
1701 let (l, r) = join.sources.get(i).copied().unwrap_or_default();
1702 self.push(info.left, l, &name);
1703 self.push(info.right, r, &name);
1704 parent.push(name.clone());
1705 using.push(name);
1706 }
1707 if let Some(slot) = self.join_using.get_mut(k) {
1708 *slot = using;
1709 }
1710 for side in [info.left, info.right] {
1711 match side {
1712 Slot::Relation(i) => {
1713 if let Some(slot) = self.relation_parents.get_mut(i) {
1714 slot.clone_from(&parent);
1715 }
1716 }
1717 Slot::Join(j) => {
1718 if let Some(slot) = self.join_parents.get_mut(j) {
1719 slot.clone_from(&parent);
1720 }
1721 self.using_names(joins, j, &parent);
1722 }
1723 }
1724 }
1725 }
1726
1727 fn join_columns(&mut self, joins: &[JoinInfo<'_>], k: usize) -> bool {
1729 let Some(info) = joins.get(k) else { return false };
1730 let join = info.join;
1731 let mut changed = false;
1732 for i in join.using.len()..join.columns.len() {
1733 let (l, r) = join.sources.get(i).copied().unwrap_or_default();
1734 let (side, number) = if l > 0 { (info.left, l) } else { (info.right, r) };
1735 let names = self.names(side).map(Vec::as_slice).unwrap_or_default();
1737 let real = match side {
1738 Slot::Relation(_) => {
1739 names.iter().filter(|n| n.as_deref() != Some("")).nth(number.wrapping_sub(1))
1740 }
1741 Slot::Join(_) => names.get(number.wrapping_sub(1)),
1742 };
1743 let real = real.cloned().flatten();
1744 let Some(real) = real else { continue };
1745 let assigned = self.joins.get(k).and_then(|n| n.get(i)).cloned().flatten();
1746 let name = match (&join.alias, assigned) {
1747 (None, _) => real.clone(),
1748 (Some(_), Some(name)) => name,
1749 (Some(_), None) => {
1750 let wanted = join.aliases.get(i).unwrap_or(&real);
1751 self.unique(wanted, Slot::Join(k))
1752 }
1753 };
1754 changed |= name != real;
1755 self.push(Slot::Join(k), i + 1, &name);
1756 }
1757 join.alias.is_some() && changed
1758 }
1759}
1760
1761fn simple_values<'q>(query: &'q Query, result: Option<&[String]>) -> Option<&'q [Vec<Expr>]> {
1763 let [rel] = query.relations.as_slice() else { return None };
1764 let rows = rel.values.as_deref()?;
1765 if query.targets.len() != rel.columns.len() {
1766 return None;
1767 }
1768 for (i, (target, column)) in query.targets.iter().zip(&rel.columns).enumerate() {
1769 let name = result.and_then(|r| r.get(i)).unwrap_or(&target.name);
1770 if target.junk || *name != column.name {
1771 return None;
1772 }
1773 }
1774 Some(rows)
1775}
1776
1777fn refers_to(e: &Expr, level: usize) -> bool {
1779 match &e.kind {
1780 ExprKind::Var(var) => var.levels_up == level,
1781 ExprKind::SubLink(sub) => {
1782 sub.test.as_ref().is_some_and(|t| refers_to(t, level))
1783 || sub.query.exprs().into_iter().any(|x| refers_to(x, level + 1))
1784 }
1785 _ => e.children().into_iter().any(|c| refers_to(c, level)),
1786 }
1787}
1788
1789fn viewdef(oid: u32, paren: bool, wrap: i32, session: &dyn Session) -> Result<Value> {
1791 let env = reg::SessionEnv(session);
1792 let Some(query) = rupg_analyze::view_query(&env, oid)? else { return Ok(Value::Null) };
1793 let rel = session
1794 .catalog()
1795 .and_then(|c| c.relation(oid))
1796 .ok_or_else(|| Error::internal(format!("cache lookup failed for relation {oid}")))?;
1797 let result: Vec<String> = rel.columns.iter().map(|c| c.name.clone()).collect();
1798 let mut d = Deparser::new(session, paren, wrap);
1799 d.query_def(&query, Some(&result), true, 0)?;
1800 d.buf.push(';');
1801 Ok(Value::text(d.buf))
1802}
1803
1804pub fn view_statement(
1810 query: &Query,
1811 name: &str,
1812 columns: &[String],
1813 session: &dyn Session,
1814) -> Result<String> {
1815 let mut d = Deparser::new(session, false, 0);
1816 d.query_def(query, Some(columns), true, 0)?;
1817 Ok(format!("CREATE VIEW {} AS {}", quote_identifier(name), d.buf))
1818}
1819
1820fn flags(args: &[Value]) -> Result<(bool, i32)> {
1822 match args.get(1) {
1823 None => Ok((false, 0)),
1824 Some(Value::Bool(pretty)) => Ok((*pretty, 0)),
1825 Some(value) => {
1826 let wrap = value.as_i64().ok_or_else(bad_value)?;
1827 Ok((true, i32::try_from(wrap).map_err(|_| bad_value())?))
1828 }
1829 }
1830}
1831
1832pub(super) fn get_viewdef(call: &Call<'_>, args: &[Value]) -> Result<Value> {
1834 let oid = args.first().and_then(Value::as_oid).ok_or_else(bad_value)?;
1835 let (paren, wrap) = flags(args)?;
1836 viewdef(oid, paren, wrap, call.session)
1837}
1838
1839pub(super) fn get_viewdef_name(call: &Call<'_>, args: &[Value]) -> Result<Value> {
1841 let text = args.first().and_then(Value::as_str).ok_or_else(bad_value)?;
1842 let names = qualified_name_list(text).map_err(type_error)?;
1843 let oid = reg::relation_oid(&names, call.session)?;
1844 let (paren, wrap) = flags(args)?;
1845 viewdef(oid, paren, wrap, call.session)
1846}
1847
1848pub(super) fn get_ruledef(call: &Call<'_>, args: &[Value]) -> Result<Value> {
1850 let oid = args.first().and_then(Value::as_oid).ok_or_else(bad_value)?;
1851 let pretty = pretty_arg(args, 1)?;
1852 let Some(catalog) = call.session.catalog() else { return Ok(Value::Null) };
1853 if let Some(rule) = catalog.rule(oid) {
1854 return ruledef(rule, pretty, call.session).map(Value::Text);
1855 }
1856 let view = catalog.relations().find(|r| r.view.as_ref().is_some_and(|v| v.rule == oid));
1857 let Some(view) = view.map(|r| r.oid) else { return Ok(Value::Null) };
1858 let Value::Text(query) = viewdef(view, pretty, 0, call.session)? else {
1859 return Ok(Value::Null);
1860 };
1861 let name = if pretty {
1862 relation_name(view, call.session)?
1863 } else {
1864 qualified_relation_name(view, call.session)?
1865 };
1866 let rule = quote_identifier("_RETURN");
1867 Ok(Value::Text(format!("CREATE RULE {rule} AS\n ON SELECT TO {name} DO INSTEAD {query}")))
1868}
1869
1870fn ruledef(rule: &rupg_catalog::Rule, pretty: bool, session: &dyn Session) -> Result<String> {
1872 let env = reg::SessionEnv(session);
1873 let tree = rupg_analyze::rule_tree(&env, rule.oid)?
1874 .ok_or_else(|| Error::internal(format!("cache lookup failed for rule {}", rule.oid)))?;
1875 if tree.actions.iter().any(|a| a.write.is_some()) {
1876 return Err(not_yet("a deparse of a rule action INSERT, UPDATE or DELETE"));
1877 }
1878 let event = match rule.event {
1879 b'1' => "SELECT",
1880 b'2' => "UPDATE",
1881 b'3' => "INSERT",
1882 _ => "DELETE",
1883 };
1884 let name = if pretty {
1885 relation_name(rule.relation, session)?
1886 } else {
1887 qualified_relation_name(rule.relation, session)?
1888 };
1889 let mut d = Deparser::new(session, pretty, 0);
1890 d.buf = format!("CREATE RULE {} AS\n ON {event} TO {name}", quote_identifier(&rule.name));
1891 if let Some(qual) = &tree.qual {
1892 d.buf.push_str("\n WHERE ");
1893 let context = tree.actions.first().unwrap_or(&tree.base);
1894 let space = d.namespace(context);
1895 d.prefix = context.relations.len() != 1;
1896 d.indent = INDENT_STD;
1897 d.namespaces.push(space);
1898 d.expr(qual, false)?;
1899 d.namespaces.pop();
1900 d.indent = 0;
1901 d.prefix = false;
1902 }
1903 d.buf.push_str(" DO ");
1904 if rule.instead {
1905 d.buf.push_str("INSTEAD ");
1906 }
1907 match tree.actions.as_slice() {
1908 [] => d.buf.push_str("NOTHING;"),
1909 [action] => {
1910 d.query_def(action, None, true, 0)?;
1911 d.buf.push(';');
1912 }
1913 actions => {
1914 d.buf.push('(');
1915 for action in actions {
1916 d.query_def(action, None, true, 0)?;
1917 d.buf.push_str(";\n");
1918 }
1919 d.buf.push_str(");");
1920 }
1921 }
1922 Ok(d.buf)
1923}
1924
1925pub(super) fn get_triggerdef(call: &Call<'_>, args: &[Value]) -> Result<Value> {
1927 let oid = args.first().and_then(Value::as_oid).ok_or_else(bad_value)?;
1928 let pretty = pretty_arg(args, 1)?;
1929 let session = call.session;
1930 let Some(trigger) = session.catalog().and_then(|c| c.trigger(oid)) else {
1931 return Ok(Value::Null);
1932 };
1933 let kind = trigger.kind;
1934 let constraint = if trigger.constraint != 0 { "CONSTRAINT " } else { "" };
1935 let mut d = Deparser::new(session, pretty, 0);
1936 d.buf = format!("CREATE {constraint}TRIGGER {} ", quote_identifier(&trigger.name));
1937 d.buf.push_str(if kind & TRIGGER_BEFORE != 0 {
1938 "BEFORE"
1939 } else if kind & TRIGGER_INSTEAD != 0 {
1940 "INSTEAD OF"
1941 } else {
1942 "AFTER"
1943 });
1944 let mut events = 0;
1945 let mut event = |d: &mut Deparser<'_>, name: &str| {
1946 d.buf.push_str(if events > 0 { " OR " } else { " " });
1947 d.buf.push_str(name);
1948 events += 1;
1949 };
1950 if kind & TRIGGER_INSERT != 0 {
1951 event(&mut d, "INSERT");
1952 }
1953 if kind & TRIGGER_DELETE != 0 {
1954 event(&mut d, "DELETE");
1955 }
1956 if kind & TRIGGER_UPDATE != 0 {
1957 event(&mut d, "UPDATE");
1958 if !trigger.columns.is_empty() {
1959 let names = column_names(trigger.relation, session).unwrap_or_default();
1960 let columns: Vec<String> = trigger
1961 .columns
1962 .iter()
1963 .map(|&n| {
1964 let at = usize::try_from(n - 1).unwrap_or(usize::MAX);
1965 names.get(at).map_or_else(String::new, |n| quote_identifier(n))
1966 })
1967 .collect();
1968 d.buf.push_str(" OF ");
1969 d.buf.push_str(&columns.join(", "));
1970 }
1971 }
1972 if kind & TRIGGER_TRUNCATE != 0 {
1973 event(&mut d, "TRUNCATE");
1974 }
1975 let name = if pretty {
1976 relation_name(trigger.relation, session)?
1977 } else {
1978 qualified_relation_name(trigger.relation, session)?
1979 };
1980 d.buf.push_str(&format!(" ON {name} "));
1981 if trigger.constraint != 0 {
1982 if trigger.constraint_relation != 0 {
1983 let from = relation_name(trigger.constraint_relation, session)?;
1984 d.buf.push_str(&format!("FROM {from} "));
1985 }
1986 if !trigger.deferrable {
1987 d.buf.push_str("NOT ");
1988 }
1989 d.buf.push_str("DEFERRABLE INITIALLY ");
1990 d.buf.push_str(if trigger.deferred { "DEFERRED " } else { "IMMEDIATE " });
1991 }
1992 if trigger.old_table.is_some() || trigger.new_table.is_some() {
1993 d.buf.push_str("REFERENCING ");
1994 if let Some(old) = &trigger.old_table {
1995 d.buf.push_str(&format!("OLD TABLE AS {} ", quote_identifier(old)));
1996 }
1997 if let Some(new) = &trigger.new_table {
1998 d.buf.push_str(&format!("NEW TABLE AS {} ", quote_identifier(new)));
1999 }
2000 }
2001 d.buf.push_str(if kind & TRIGGER_ROW != 0 { "FOR EACH ROW " } else { "FOR EACH STATEMENT " });
2002 let env = reg::SessionEnv(session);
2003 if let Some((base, qual)) = rupg_analyze::trigger_when(&env, oid)? {
2004 d.buf.push_str("WHEN (");
2005 let space = d.namespace(&base);
2006 d.prefix = true;
2007 d.indent = INDENT_STD;
2008 d.namespaces.push(space);
2009 d.expr(&qual, false)?;
2010 d.namespaces.pop();
2011 d.indent = 0;
2012 d.prefix = false;
2013 d.buf.push_str(") ");
2014 }
2015 let proc = builtin::proc_by_oid(trigger.function).ok_or_else(|| {
2016 Error::internal(format!("cache lookup failed for function {}", trigger.function))
2017 })?;
2018 let function = if reg::function_visible(proc, session) {
2019 quote_identifier(proc.name)
2020 } else {
2021 reg::qualified(reg::namespace_name(proc.namespace, session), proc.name)
2022 };
2023 let args: Vec<String> =
2025 trigger.args.iter().map(|a| format!("'{}'", a.replace('\'', "''"))).collect();
2026 d.buf.push_str(&format!("EXECUTE FUNCTION {function}({})", args.join(", ")));
2027 Ok(Value::text(d.buf))
2028}