1 /*-------------------------------------------------------------------------
4 * Functions to convert stored expressions/querytrees back to
7 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/utils/adt/ruleutils.c
14 *-------------------------------------------------------------------------
21 #include "access/sysattr.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/pg_authid.h"
25 #include "catalog/pg_collation.h"
26 #include "catalog/pg_constraint.h"
27 #include "catalog/pg_depend.h"
28 #include "catalog/pg_language.h"
29 #include "catalog/pg_opclass.h"
30 #include "catalog/pg_operator.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_trigger.h"
33 #include "catalog/pg_type.h"
34 #include "commands/defrem.h"
35 #include "commands/tablespace.h"
36 #include "executor/spi.h"
38 #include "nodes/makefuncs.h"
39 #include "nodes/nodeFuncs.h"
40 #include "optimizer/clauses.h"
41 #include "optimizer/tlist.h"
42 #include "parser/keywords.h"
43 #include "parser/parse_func.h"
44 #include "parser/parse_oper.h"
45 #include "parser/parser.h"
46 #include "parser/parsetree.h"
47 #include "rewrite/rewriteHandler.h"
48 #include "rewrite/rewriteManip.h"
49 #include "rewrite/rewriteSupport.h"
50 #include "utils/array.h"
51 #include "utils/builtins.h"
52 #include "utils/fmgroids.h"
53 #include "utils/lsyscache.h"
54 #include "utils/rel.h"
55 #include "utils/syscache.h"
56 #include "utils/tqual.h"
57 #include "utils/typcache.h"
58 #include "utils/xml.h"
62 * Pretty formatting constants
67 #define PRETTYINDENT_STD 8
68 #define PRETTYINDENT_JOIN 13
69 #define PRETTYINDENT_JOIN_ON (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
70 #define PRETTYINDENT_VAR 4
73 #define PRETTYFLAG_PAREN 1
74 #define PRETTYFLAG_INDENT 2
76 #define PRETTY_WRAP_DEFAULT 79
78 /* macro to test if pretty action needed */
79 #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
80 #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
88 /* Context info needed for invoking a recursive querytree display routine */
91 StringInfo buf; /* output buffer to append to */
92 List *namespaces; /* List of deparse_namespace nodes */
93 List *windowClause; /* Current query level's WINDOW clause */
94 List *windowTList; /* targetlist for resolving WINDOW clause */
95 int prettyFlags; /* enabling of pretty-print functions */
96 int indentLevel; /* current indent level for prettyprint */
97 bool varprefix; /* TRUE to print prefixes on Vars */
101 * Each level of query context around a subtree needs a level of Var namespace.
102 * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
103 * the current context's namespaces list.
105 * The rangetable is the list of actual RTEs from the query tree, and the
106 * cte list is the list of actual CTEs.
108 * When deparsing plan trees, there is always just a single item in the
109 * deparse_namespace list (since a plan tree never contains Vars with
110 * varlevelsup > 0). We store the PlanState node that is the immediate
111 * parent of the expression to be deparsed, as well as a list of that
112 * PlanState's ancestors. In addition, we store its outer and inner subplan
113 * state nodes, as well as their plan nodes' targetlists, and the indextlist
114 * if the current PlanState is an IndexOnlyScanState. (These fields could
115 * be derived on-the-fly from the current PlanState, but it seems notationally
116 * clearer to set them up as separate fields.)
120 List *rtable; /* List of RangeTblEntry nodes */
121 List *ctes; /* List of CommonTableExpr nodes */
122 /* Remaining fields are used only when deparsing a Plan tree: */
123 PlanState *planstate; /* immediate parent of current expression */
124 List *ancestors; /* ancestors of planstate */
125 PlanState *outer_planstate; /* outer subplan state, or NULL if none */
126 PlanState *inner_planstate; /* inner subplan state, or NULL if none */
127 List *outer_tlist; /* referent for OUTER_VAR Vars */
128 List *inner_tlist; /* referent for INNER_VAR Vars */
129 List *index_tlist; /* referent for INDEX_VAR Vars */
137 static SPIPlanPtr plan_getrulebyoid = NULL;
138 static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
139 static SPIPlanPtr plan_getviewrule = NULL;
140 static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
141 static int pretty_wrap = PRETTY_WRAP_DEFAULT;
144 bool quote_all_identifiers = false;
150 * Most of these functions used to use fixed-size buffers to build their
151 * results. Now, they take an (already initialized) StringInfo object
152 * as a parameter, and append their text output to its contents.
155 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
156 bool forceprefix, bool showimplicit,
157 int prettyFlags, int startIndent);
158 static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);
159 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
160 static void decompile_column_index_array(Datum column_index_array, Oid relId,
162 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
163 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
164 const Oid *excludeOps,
165 bool attrsOnly, bool showTblSpc,
167 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
169 static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
171 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
172 bool print_table_args, bool print_defaults);
173 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
174 static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps);
175 static void push_child_plan(deparse_namespace *dpns, PlanState *ps,
176 deparse_namespace *save_dpns);
177 static void pop_child_plan(deparse_namespace *dpns,
178 deparse_namespace *save_dpns);
179 static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
180 deparse_namespace *save_dpns);
181 static void pop_ancestor_plan(deparse_namespace *dpns,
182 deparse_namespace *save_dpns);
183 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
185 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
187 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
188 TupleDesc resultDesc, int prettyFlags, int startIndent);
189 static void get_values_def(List *values_lists, deparse_context *context);
190 static void get_with_clause(Query *query, deparse_context *context);
191 static void get_select_query_def(Query *query, deparse_context *context,
192 TupleDesc resultDesc);
193 static void get_insert_query_def(Query *query, deparse_context *context);
194 static void get_update_query_def(Query *query, deparse_context *context);
195 static void get_delete_query_def(Query *query, deparse_context *context);
196 static void get_utility_query_def(Query *query, deparse_context *context);
197 static void get_basic_select_query(Query *query, deparse_context *context,
198 TupleDesc resultDesc);
199 static void get_target_list(List *targetList, deparse_context *context,
200 TupleDesc resultDesc);
201 static void get_setop_query(Node *setOp, Query *query,
202 deparse_context *context,
203 TupleDesc resultDesc);
204 static Node *get_rule_sortgroupclause(SortGroupClause *srt, List *tlist,
206 deparse_context *context);
207 static void get_rule_orderby(List *orderList, List *targetList,
208 bool force_colno, deparse_context *context);
209 static void get_rule_windowclause(Query *query, deparse_context *context);
210 static void get_rule_windowspec(WindowClause *wc, List *targetList,
211 deparse_context *context);
212 static char *get_variable(Var *var, int levelsup, bool istoplevel,
213 deparse_context *context);
214 static RangeTblEntry *find_rte_by_refname(const char *refname,
215 deparse_context *context);
216 static Node *find_param_referent(Param *param, deparse_context *context,
217 deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
218 static void get_parameter(Param *param, deparse_context *context);
219 static const char *get_simple_binary_op_name(OpExpr *expr);
220 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
221 static void appendContextKeyword(deparse_context *context, const char *str,
222 int indentBefore, int indentAfter, int indentPlus);
223 static void get_rule_expr(Node *node, deparse_context *context,
225 static void get_oper_expr(OpExpr *expr, deparse_context *context);
226 static void get_func_expr(FuncExpr *expr, deparse_context *context,
228 static void get_agg_expr(Aggref *aggref, deparse_context *context);
229 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
230 static void get_coercion_expr(Node *arg, deparse_context *context,
231 Oid resulttype, int32 resulttypmod,
233 static void get_const_expr(Const *constval, deparse_context *context,
235 static void get_const_collation(Const *constval, deparse_context *context);
236 static void simple_quote_literal(StringInfo buf, const char *val);
237 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
238 static void get_from_clause(Query *query, const char *prefix,
239 deparse_context *context);
240 static void get_from_clause_item(Node *jtnode, Query *query,
241 deparse_context *context);
242 static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
243 deparse_context *context);
244 static void get_from_clause_coldeflist(List *names,
245 List *types, List *typmods, List *collations,
246 deparse_context *context);
247 static void get_opclass_name(Oid opclass, Oid actual_datatype,
249 static Node *processIndirection(Node *node, deparse_context *context,
251 static void printSubscripts(ArrayRef *aref, deparse_context *context);
252 static char *get_relation_name(Oid relid);
253 static char *generate_relation_name(Oid relid, List *namespaces);
254 static char *generate_function_name(Oid funcid, int nargs, List *argnames,
255 Oid *argtypes, bool *is_variadic);
256 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
257 static text *string_to_text(char *str);
258 static char *flatten_reloptions(Oid relid);
260 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
264 * get_ruledef - Do it all and return a text
265 * that could be used as a statement
266 * to recreate the rule
270 pg_get_ruledef(PG_FUNCTION_ARGS)
272 Oid ruleoid = PG_GETARG_OID(0);
274 PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, 0)));
279 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
281 Oid ruleoid = PG_GETARG_OID(0);
282 bool pretty = PG_GETARG_BOOL(1);
285 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
286 PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));
291 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
301 * Do this first so that string is alloc'd in outer context not SPI's.
303 initStringInfo(&buf);
306 * Connect to SPI manager
308 if (SPI_connect() != SPI_OK_CONNECT)
309 elog(ERROR, "SPI_connect failed");
312 * On the first call prepare the plan to lookup pg_rewrite. We read
313 * pg_rewrite over the SPI manager instead of using the syscache to be
314 * checked for read access on pg_rewrite.
316 if (plan_getrulebyoid == NULL)
321 argtypes[0] = OIDOID;
322 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
324 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
326 plan_getrulebyoid = plan;
330 * Get the pg_rewrite tuple for this rule
332 args[0] = ObjectIdGetDatum(ruleoid);
334 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 1);
335 if (spirc != SPI_OK_SELECT)
336 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
337 if (SPI_processed != 1)
338 appendStringInfo(&buf, "-");
342 * Get the rule's definition and put it into executor's memory
344 ruletup = SPI_tuptable->vals[0];
345 rulettc = SPI_tuptable->tupdesc;
346 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
350 * Disconnect from SPI manager
352 if (SPI_finish() != SPI_OK_FINISH)
353 elog(ERROR, "SPI_finish failed");
360 * get_viewdef - Mainly the same thing, but we
361 * only return the SELECT part of a view
365 pg_get_viewdef(PG_FUNCTION_ARGS)
368 Oid viewoid = PG_GETARG_OID(0);
370 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
375 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
378 Oid viewoid = PG_GETARG_OID(0);
379 bool pretty = PG_GETARG_BOOL(1);
382 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
383 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
387 pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
390 Oid viewoid = PG_GETARG_OID(0);
391 int wrap = PG_GETARG_INT32(1);
395 /* calling this implies we want pretty printing */
396 prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT;
398 result = pg_get_viewdef_worker(viewoid, prettyFlags);
399 pretty_wrap = PRETTY_WRAP_DEFAULT;
400 PG_RETURN_TEXT_P(string_to_text(result));
404 pg_get_viewdef_name(PG_FUNCTION_ARGS)
406 /* By qualified name */
407 text *viewname = PG_GETARG_TEXT_P(0);
411 /* Look up view name. Can't lock it - we might not have privileges. */
412 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
413 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
415 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
420 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
422 /* By qualified name */
423 text *viewname = PG_GETARG_TEXT_P(0);
424 bool pretty = PG_GETARG_BOOL(1);
429 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
431 /* Look up view name. Can't lock it - we might not have privileges. */
432 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
433 viewoid = RangeVarGetRelid(viewrel, NoLock, false);
435 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
439 * Common code for by-OID and by-name variants of pg_get_viewdef
442 pg_get_viewdef_worker(Oid viewoid, int prettyFlags)
452 * Do this first so that string is alloc'd in outer context not SPI's.
454 initStringInfo(&buf);
457 * Connect to SPI manager
459 if (SPI_connect() != SPI_OK_CONNECT)
460 elog(ERROR, "SPI_connect failed");
463 * On the first call prepare the plan to lookup pg_rewrite. We read
464 * pg_rewrite over the SPI manager instead of using the syscache to be
465 * checked for read access on pg_rewrite.
467 if (plan_getviewrule == NULL)
472 argtypes[0] = OIDOID;
473 argtypes[1] = NAMEOID;
474 plan = SPI_prepare(query_getviewrule, 2, argtypes);
476 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
478 plan_getviewrule = plan;
482 * Get the pg_rewrite tuple for the view's SELECT rule
484 args[0] = ObjectIdGetDatum(viewoid);
485 args[1] = PointerGetDatum(ViewSelectRuleName);
488 spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 2);
489 if (spirc != SPI_OK_SELECT)
490 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
491 if (SPI_processed != 1)
492 appendStringInfo(&buf, "Not a view");
496 * Get the rule's definition and put it into executor's memory
498 ruletup = SPI_tuptable->vals[0];
499 rulettc = SPI_tuptable->tupdesc;
500 make_viewdef(&buf, ruletup, rulettc, prettyFlags);
504 * Disconnect from SPI manager
506 if (SPI_finish() != SPI_OK_FINISH)
507 elog(ERROR, "SPI_finish failed");
513 * get_triggerdef - Get the definition of a trigger
517 pg_get_triggerdef(PG_FUNCTION_ARGS)
519 Oid trigid = PG_GETARG_OID(0);
521 PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, false)));
525 pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
527 Oid trigid = PG_GETARG_OID(0);
528 bool pretty = PG_GETARG_BOOL(1);
530 PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, pretty)));
534 pg_get_triggerdef_worker(Oid trigid, bool pretty)
537 Form_pg_trigger trigrec;
548 * Fetch the pg_trigger tuple by the Oid of the trigger
550 tgrel = heap_open(TriggerRelationId, AccessShareLock);
552 ScanKeyInit(&skey[0],
553 ObjectIdAttributeNumber,
554 BTEqualStrategyNumber, F_OIDEQ,
555 ObjectIdGetDatum(trigid));
557 tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
558 SnapshotNow, 1, skey);
560 ht_trig = systable_getnext(tgscan);
562 if (!HeapTupleIsValid(ht_trig))
563 elog(ERROR, "could not find tuple for trigger %u", trigid);
565 trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
568 * Start the trigger definition. Note that the trigger's name should never
569 * be schema-qualified, but the trigger rel's name may be.
571 initStringInfo(&buf);
573 tgname = NameStr(trigrec->tgname);
574 appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
575 OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
576 quote_identifier(tgname));
578 if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
579 appendStringInfo(&buf, "BEFORE");
580 else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
581 appendStringInfo(&buf, "AFTER");
582 else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
583 appendStringInfo(&buf, "INSTEAD OF");
585 elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
587 if (TRIGGER_FOR_INSERT(trigrec->tgtype))
589 appendStringInfo(&buf, " INSERT");
592 if (TRIGGER_FOR_DELETE(trigrec->tgtype))
595 appendStringInfo(&buf, " OR DELETE");
597 appendStringInfo(&buf, " DELETE");
600 if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
603 appendStringInfo(&buf, " OR UPDATE");
605 appendStringInfo(&buf, " UPDATE");
607 /* tgattr is first var-width field, so OK to access directly */
608 if (trigrec->tgattr.dim1 > 0)
612 appendStringInfoString(&buf, " OF ");
613 for (i = 0; i < trigrec->tgattr.dim1; i++)
618 appendStringInfoString(&buf, ", ");
619 attname = get_relid_attribute_name(trigrec->tgrelid,
620 trigrec->tgattr.values[i]);
621 appendStringInfoString(&buf, quote_identifier(attname));
625 if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
628 appendStringInfo(&buf, " OR TRUNCATE");
630 appendStringInfo(&buf, " TRUNCATE");
633 appendStringInfo(&buf, " ON %s ",
634 generate_relation_name(trigrec->tgrelid, NIL));
636 if (OidIsValid(trigrec->tgconstraint))
638 if (OidIsValid(trigrec->tgconstrrelid))
639 appendStringInfo(&buf, "FROM %s ",
640 generate_relation_name(trigrec->tgconstrrelid, NIL));
641 if (!trigrec->tgdeferrable)
642 appendStringInfo(&buf, "NOT ");
643 appendStringInfo(&buf, "DEFERRABLE INITIALLY ");
644 if (trigrec->tginitdeferred)
645 appendStringInfo(&buf, "DEFERRED ");
647 appendStringInfo(&buf, "IMMEDIATE ");
650 if (TRIGGER_FOR_ROW(trigrec->tgtype))
651 appendStringInfo(&buf, "FOR EACH ROW ");
653 appendStringInfo(&buf, "FOR EACH STATEMENT ");
655 /* If the trigger has a WHEN qualification, add that */
656 value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
657 tgrel->rd_att, &isnull);
662 deparse_context context;
663 deparse_namespace dpns;
664 RangeTblEntry *oldrte;
665 RangeTblEntry *newrte;
667 appendStringInfoString(&buf, "WHEN (");
669 qual = stringToNode(TextDatumGetCString(value));
671 relkind = get_rel_relkind(trigrec->tgrelid);
673 /* Build minimal OLD and NEW RTEs for the rel */
674 oldrte = makeNode(RangeTblEntry);
675 oldrte->rtekind = RTE_RELATION;
676 oldrte->relid = trigrec->tgrelid;
677 oldrte->relkind = relkind;
678 oldrte->eref = makeAlias("old", NIL);
679 oldrte->lateral = false;
681 oldrte->inFromCl = true;
683 newrte = makeNode(RangeTblEntry);
684 newrte->rtekind = RTE_RELATION;
685 newrte->relid = trigrec->tgrelid;
686 newrte->relkind = relkind;
687 newrte->eref = makeAlias("new", NIL);
688 newrte->lateral = false;
690 newrte->inFromCl = true;
692 /* Build two-element rtable */
693 memset(&dpns, 0, sizeof(dpns));
694 dpns.rtable = list_make2(oldrte, newrte);
697 /* Set up context with one-deep namespace stack */
699 context.namespaces = list_make1(&dpns);
700 context.windowClause = NIL;
701 context.windowTList = NIL;
702 context.varprefix = true;
703 context.prettyFlags = pretty ? PRETTYFLAG_PAREN : 0;
704 context.indentLevel = PRETTYINDENT_STD;
706 get_rule_expr(qual, &context, false);
708 appendStringInfo(&buf, ") ");
711 appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
712 generate_function_name(trigrec->tgfoid, 0,
715 if (trigrec->tgnargs > 0)
720 value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
721 tgrel->rd_att, &isnull);
723 elog(ERROR, "tgargs is null for trigger %u", trigid);
724 p = (char *) VARDATA(DatumGetByteaP(value));
725 for (i = 0; i < trigrec->tgnargs; i++)
728 appendStringInfo(&buf, ", ");
729 simple_quote_literal(&buf, p);
730 /* advance p to next string embedded in tgargs */
737 /* We deliberately do not put semi-colon at end */
738 appendStringInfo(&buf, ")");
741 systable_endscan(tgscan);
743 heap_close(tgrel, AccessShareLock);
749 * get_indexdef - Get the definition of an index
751 * In the extended version, there is a colno argument as well as pretty bool.
752 * if colno == 0, we want a complete index definition.
753 * if colno > 0, we only want the Nth index key's variable or expression.
755 * Note that the SQL-function versions of this omit any info about the
756 * index tablespace; this is intentional because pg_dump wants it that way.
757 * However pg_get_indexdef_string() includes index tablespace if not default.
761 pg_get_indexdef(PG_FUNCTION_ARGS)
763 Oid indexrelid = PG_GETARG_OID(0);
765 PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0,
771 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
773 Oid indexrelid = PG_GETARG_OID(0);
774 int32 colno = PG_GETARG_INT32(1);
775 bool pretty = PG_GETARG_BOOL(2);
778 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
779 PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno,
786 /* Internal version that returns a palloc'd C string */
788 pg_get_indexdef_string(Oid indexrelid)
790 return pg_get_indexdef_worker(indexrelid, 0, NULL, false, true, 0);
793 /* Internal version that just reports the column definitions */
795 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
799 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
800 return pg_get_indexdef_worker(indexrelid, 0, NULL, true, false, prettyFlags);
804 * Internal workhorse to decompile an index definition.
806 * This is now used for exclusion constraints as well: if excludeOps is not
807 * NULL then it points to an array of exclusion operator OIDs.
810 pg_get_indexdef_worker(Oid indexrelid, int colno,
811 const Oid *excludeOps,
812 bool attrsOnly, bool showTblSpc,
815 /* might want a separate isConstraint parameter later */
816 bool isConstraint = (excludeOps != NULL);
820 Form_pg_index idxrec;
821 Form_pg_class idxrelrec;
824 ListCell *indexpr_item;
830 Datum indoptionDatum;
832 oidvector *indcollation;
834 int2vector *indoption;
840 * Fetch the pg_index tuple by the Oid of the index
842 ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
843 if (!HeapTupleIsValid(ht_idx))
844 elog(ERROR, "cache lookup failed for index %u", indexrelid);
845 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
847 indrelid = idxrec->indrelid;
848 Assert(indexrelid == idxrec->indexrelid);
850 /* Must get indcollation, indclass, and indoption the hard way */
851 indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
852 Anum_pg_index_indcollation, &isnull);
854 indcollation = (oidvector *) DatumGetPointer(indcollDatum);
856 indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
857 Anum_pg_index_indclass, &isnull);
859 indclass = (oidvector *) DatumGetPointer(indclassDatum);
861 indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
862 Anum_pg_index_indoption, &isnull);
864 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
867 * Fetch the pg_class tuple of the index relation
869 ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
870 if (!HeapTupleIsValid(ht_idxrel))
871 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
872 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
875 * Fetch the pg_am tuple of the index' access method
877 ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
878 if (!HeapTupleIsValid(ht_am))
879 elog(ERROR, "cache lookup failed for access method %u",
881 amrec = (Form_pg_am) GETSTRUCT(ht_am);
884 * Get the index expressions, if any. (NOTE: we do not use the relcache
885 * versions of the expressions and predicate, because we want to display
886 * non-const-folded expressions.)
888 if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
894 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
895 Anum_pg_index_indexprs, &isnull);
897 exprsString = TextDatumGetCString(exprsDatum);
898 indexprs = (List *) stringToNode(exprsString);
904 indexpr_item = list_head(indexprs);
906 context = deparse_context_for(get_relation_name(indrelid), indrelid);
909 * Start the index definition. Note that the index's name should never be
910 * schema-qualified, but the indexed rel's name may be.
912 initStringInfo(&buf);
917 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
918 idxrec->indisunique ? "UNIQUE " : "",
919 quote_identifier(NameStr(idxrelrec->relname)),
920 generate_relation_name(indrelid, NIL),
921 quote_identifier(NameStr(amrec->amname)));
922 else /* currently, must be EXCLUDE constraint */
923 appendStringInfo(&buf, "EXCLUDE USING %s (",
924 quote_identifier(NameStr(amrec->amname)));
928 * Report the indexed attributes
931 for (keyno = 0; keyno < idxrec->indnatts; keyno++)
933 AttrNumber attnum = idxrec->indkey.values[keyno];
934 int16 opt = indoption->values[keyno];
939 appendStringInfoString(&buf, sep);
944 /* Simple index column */
948 attname = get_relid_attribute_name(indrelid, attnum);
949 if (!colno || colno == keyno + 1)
950 appendStringInfoString(&buf, quote_identifier(attname));
951 get_atttypetypmodcoll(indrelid, attnum,
952 &keycoltype, &keycoltypmod,
957 /* expressional index */
960 if (indexpr_item == NULL)
961 elog(ERROR, "too few entries in indexprs list");
962 indexkey = (Node *) lfirst(indexpr_item);
963 indexpr_item = lnext(indexpr_item);
965 str = deparse_expression_pretty(indexkey, context, false, false,
967 if (!colno || colno == keyno + 1)
969 /* Need parens if it's not a bare function call */
970 if (indexkey && IsA(indexkey, FuncExpr) &&
971 ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
972 appendStringInfoString(&buf, str);
974 appendStringInfo(&buf, "(%s)", str);
976 keycoltype = exprType(indexkey);
977 keycolcollation = exprCollation(indexkey);
980 if (!attrsOnly && (!colno || colno == keyno + 1))
984 /* Add collation, if not default for column */
985 indcoll = indcollation->values[keyno];
986 if (OidIsValid(indcoll) && indcoll != keycolcollation)
987 appendStringInfo(&buf, " COLLATE %s",
988 generate_collation_name((indcoll)));
990 /* Add the operator class name, if not default */
991 get_opclass_name(indclass->values[keyno], keycoltype, &buf);
993 /* Add options if relevant */
994 if (amrec->amcanorder)
996 /* if it supports sort ordering, report DESC and NULLS opts */
997 if (opt & INDOPTION_DESC)
999 appendStringInfo(&buf, " DESC");
1000 /* NULLS FIRST is the default in this case */
1001 if (!(opt & INDOPTION_NULLS_FIRST))
1002 appendStringInfo(&buf, " NULLS LAST");
1006 if (opt & INDOPTION_NULLS_FIRST)
1007 appendStringInfo(&buf, " NULLS FIRST");
1011 /* Add the exclusion operator if relevant */
1012 if (excludeOps != NULL)
1013 appendStringInfo(&buf, " WITH %s",
1014 generate_operator_name(excludeOps[keyno],
1022 appendStringInfoChar(&buf, ')');
1025 * If it has options, append "WITH (options)"
1027 str = flatten_reloptions(indexrelid);
1030 appendStringInfo(&buf, " WITH (%s)", str);
1035 * If it's in a nondefault tablespace, say so, but only if requested
1041 tblspc = get_rel_tablespace(indexrelid);
1042 if (OidIsValid(tblspc))
1045 appendStringInfoString(&buf, " USING INDEX");
1046 appendStringInfo(&buf, " TABLESPACE %s",
1047 quote_identifier(get_tablespace_name(tblspc)));
1052 * If it's a partial index, decompile and append the predicate
1054 if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
1061 /* Convert text string to node tree */
1062 predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1063 Anum_pg_index_indpred, &isnull);
1065 predString = TextDatumGetCString(predDatum);
1066 node = (Node *) stringToNode(predString);
1070 str = deparse_expression_pretty(node, context, false, false,
1073 appendStringInfo(&buf, " WHERE (%s)", str);
1075 appendStringInfo(&buf, " WHERE %s", str);
1080 ReleaseSysCache(ht_idx);
1081 ReleaseSysCache(ht_idxrel);
1082 ReleaseSysCache(ht_am);
1089 * pg_get_constraintdef
1091 * Returns the definition for the constraint, ie, everything that needs to
1092 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
1095 pg_get_constraintdef(PG_FUNCTION_ARGS)
1097 Oid constraintId = PG_GETARG_OID(0);
1099 PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
1104 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
1106 Oid constraintId = PG_GETARG_OID(0);
1107 bool pretty = PG_GETARG_BOOL(1);
1110 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
1111 PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
1112 false, prettyFlags)));
1115 /* Internal version that returns a palloc'd C string */
1117 pg_get_constraintdef_string(Oid constraintId)
1119 return pg_get_constraintdef_worker(constraintId, true, 0);
1123 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
1127 Form_pg_constraint conForm;
1130 tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintId));
1131 if (!HeapTupleIsValid(tup)) /* should not happen */
1132 elog(ERROR, "cache lookup failed for constraint %u", constraintId);
1133 conForm = (Form_pg_constraint) GETSTRUCT(tup);
1135 initStringInfo(&buf);
1137 if (fullCommand && OidIsValid(conForm->conrelid))
1139 appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
1140 generate_relation_name(conForm->conrelid, NIL),
1141 quote_identifier(NameStr(conForm->conname)));
1144 switch (conForm->contype)
1146 case CONSTRAINT_FOREIGN:
1152 /* Start off the constraint definition */
1153 appendStringInfo(&buf, "FOREIGN KEY (");
1155 /* Fetch and build referencing-column list */
1156 val = SysCacheGetAttr(CONSTROID, tup,
1157 Anum_pg_constraint_conkey, &isnull);
1159 elog(ERROR, "null conkey for constraint %u",
1162 decompile_column_index_array(val, conForm->conrelid, &buf);
1164 /* add foreign relation name */
1165 appendStringInfo(&buf, ") REFERENCES %s(",
1166 generate_relation_name(conForm->confrelid,
1169 /* Fetch and build referenced-column list */
1170 val = SysCacheGetAttr(CONSTROID, tup,
1171 Anum_pg_constraint_confkey, &isnull);
1173 elog(ERROR, "null confkey for constraint %u",
1176 decompile_column_index_array(val, conForm->confrelid, &buf);
1178 appendStringInfo(&buf, ")");
1180 /* Add match type */
1181 switch (conForm->confmatchtype)
1183 case FKCONSTR_MATCH_FULL:
1184 string = " MATCH FULL";
1186 case FKCONSTR_MATCH_PARTIAL:
1187 string = " MATCH PARTIAL";
1189 case FKCONSTR_MATCH_SIMPLE:
1193 elog(ERROR, "unrecognized confmatchtype: %d",
1194 conForm->confmatchtype);
1195 string = ""; /* keep compiler quiet */
1198 appendStringInfoString(&buf, string);
1200 /* Add ON UPDATE and ON DELETE clauses, if needed */
1201 switch (conForm->confupdtype)
1203 case FKCONSTR_ACTION_NOACTION:
1204 string = NULL; /* suppress default */
1206 case FKCONSTR_ACTION_RESTRICT:
1207 string = "RESTRICT";
1209 case FKCONSTR_ACTION_CASCADE:
1212 case FKCONSTR_ACTION_SETNULL:
1213 string = "SET NULL";
1215 case FKCONSTR_ACTION_SETDEFAULT:
1216 string = "SET DEFAULT";
1219 elog(ERROR, "unrecognized confupdtype: %d",
1220 conForm->confupdtype);
1221 string = NULL; /* keep compiler quiet */
1225 appendStringInfo(&buf, " ON UPDATE %s", string);
1227 switch (conForm->confdeltype)
1229 case FKCONSTR_ACTION_NOACTION:
1230 string = NULL; /* suppress default */
1232 case FKCONSTR_ACTION_RESTRICT:
1233 string = "RESTRICT";
1235 case FKCONSTR_ACTION_CASCADE:
1238 case FKCONSTR_ACTION_SETNULL:
1239 string = "SET NULL";
1241 case FKCONSTR_ACTION_SETDEFAULT:
1242 string = "SET DEFAULT";
1245 elog(ERROR, "unrecognized confdeltype: %d",
1246 conForm->confdeltype);
1247 string = NULL; /* keep compiler quiet */
1251 appendStringInfo(&buf, " ON DELETE %s", string);
1255 case CONSTRAINT_PRIMARY:
1256 case CONSTRAINT_UNIQUE:
1262 /* Start off the constraint definition */
1263 if (conForm->contype == CONSTRAINT_PRIMARY)
1264 appendStringInfo(&buf, "PRIMARY KEY (");
1266 appendStringInfo(&buf, "UNIQUE (");
1268 /* Fetch and build target column list */
1269 val = SysCacheGetAttr(CONSTROID, tup,
1270 Anum_pg_constraint_conkey, &isnull);
1272 elog(ERROR, "null conkey for constraint %u",
1275 decompile_column_index_array(val, conForm->conrelid, &buf);
1277 appendStringInfo(&buf, ")");
1279 indexId = get_constraint_index(constraintId);
1281 /* XXX why do we only print these bits if fullCommand? */
1282 if (fullCommand && OidIsValid(indexId))
1284 char *options = flatten_reloptions(indexId);
1289 appendStringInfo(&buf, " WITH (%s)", options);
1293 tblspc = get_rel_tablespace(indexId);
1294 if (OidIsValid(tblspc))
1295 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
1296 quote_identifier(get_tablespace_name(tblspc)));
1301 case CONSTRAINT_CHECK:
1310 /* Fetch constraint expression in parsetree form */
1311 val = SysCacheGetAttr(CONSTROID, tup,
1312 Anum_pg_constraint_conbin, &isnull);
1314 elog(ERROR, "null conbin for constraint %u",
1317 conbin = TextDatumGetCString(val);
1318 expr = stringToNode(conbin);
1320 /* Set up deparsing context for Var nodes in constraint */
1321 if (conForm->conrelid != InvalidOid)
1323 /* relation constraint */
1324 context = deparse_context_for(get_relation_name(conForm->conrelid),
1329 /* domain constraint --- can't have Vars */
1333 consrc = deparse_expression_pretty(expr, context, false, false,
1337 * Now emit the constraint definition, adding NO INHERIT if
1340 * There are cases where the constraint expression will be
1341 * fully parenthesized and we don't need the outer parens ...
1342 * but there are other cases where we do need 'em. Be
1343 * conservative for now.
1345 * Note that simply checking for leading '(' and trailing ')'
1346 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
1348 appendStringInfo(&buf, "CHECK (%s)%s",
1350 conForm->connoinherit ? " NO INHERIT" : "");
1353 case CONSTRAINT_TRIGGER:
1356 * There isn't an ALTER TABLE syntax for creating a user-defined
1357 * constraint trigger, but it seems better to print something than
1358 * throw an error; if we throw error then this function couldn't
1359 * safely be applied to all rows of pg_constraint.
1361 appendStringInfo(&buf, "TRIGGER");
1363 case CONSTRAINT_EXCLUSION:
1365 Oid indexOid = conForm->conindid;
1373 /* Extract operator OIDs from the pg_constraint tuple */
1374 val = SysCacheGetAttr(CONSTROID, tup,
1375 Anum_pg_constraint_conexclop,
1378 elog(ERROR, "null conexclop for constraint %u",
1381 deconstruct_array(DatumGetArrayTypeP(val),
1382 OIDOID, sizeof(Oid), true, 'i',
1383 &elems, NULL, &nElems);
1385 operators = (Oid *) palloc(nElems * sizeof(Oid));
1386 for (i = 0; i < nElems; i++)
1387 operators[i] = DatumGetObjectId(elems[i]);
1389 /* pg_get_indexdef_worker does the rest */
1390 /* suppress tablespace because pg_dump wants it that way */
1391 appendStringInfoString(&buf,
1392 pg_get_indexdef_worker(indexOid,
1401 elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
1405 if (conForm->condeferrable)
1406 appendStringInfo(&buf, " DEFERRABLE");
1407 if (conForm->condeferred)
1408 appendStringInfo(&buf, " INITIALLY DEFERRED");
1409 if (!conForm->convalidated)
1410 appendStringInfoString(&buf, " NOT VALID");
1413 ReleaseSysCache(tup);
1420 * Convert an int16[] Datum into a comma-separated list of column names
1421 * for the indicated relation; append the list to buf.
1424 decompile_column_index_array(Datum column_index_array, Oid relId,
1431 /* Extract data from array of int16 */
1432 deconstruct_array(DatumGetArrayTypeP(column_index_array),
1433 INT2OID, 2, true, 's',
1434 &keys, NULL, &nKeys);
1436 for (j = 0; j < nKeys; j++)
1440 colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
1443 appendStringInfoString(buf, quote_identifier(colName));
1445 appendStringInfo(buf, ", %s", quote_identifier(colName));
1451 * get_expr - Decompile an expression tree
1453 * Input: an expression tree in nodeToString form, and a relation OID
1455 * Output: reverse-listed expression
1457 * Currently, the expression can only refer to a single relation, namely
1458 * the one specified by the second parameter. This is sufficient for
1459 * partial indexes, column default expressions, etc. We also support
1460 * Var-free expressions, for which the OID can be InvalidOid.
1464 pg_get_expr(PG_FUNCTION_ARGS)
1466 text *expr = PG_GETARG_TEXT_P(0);
1467 Oid relid = PG_GETARG_OID(1);
1470 if (OidIsValid(relid))
1472 /* Get the name for the relation */
1473 relname = get_rel_name(relid);
1476 * If the OID isn't actually valid, don't throw an error, just return
1477 * NULL. This is a bit questionable, but it's what we've done
1478 * historically, and it can help avoid unwanted failures when
1479 * examining catalog entries for just-deleted relations.
1481 if (relname == NULL)
1487 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, 0));
1491 pg_get_expr_ext(PG_FUNCTION_ARGS)
1493 text *expr = PG_GETARG_TEXT_P(0);
1494 Oid relid = PG_GETARG_OID(1);
1495 bool pretty = PG_GETARG_BOOL(2);
1499 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
1501 if (OidIsValid(relid))
1503 /* Get the name for the relation */
1504 relname = get_rel_name(relid);
1505 /* See notes above */
1506 if (relname == NULL)
1512 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
1516 pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
1523 /* Convert input TEXT object to C string */
1524 exprstr = text_to_cstring(expr);
1526 /* Convert expression to node tree */
1527 node = (Node *) stringToNode(exprstr);
1531 /* Prepare deparse context if needed */
1532 if (OidIsValid(relid))
1533 context = deparse_context_for(relname, relid);
1538 str = deparse_expression_pretty(node, context, false, false,
1541 return string_to_text(str);
1546 * get_userbyid - Get a user name by roleid and
1547 * fallback to 'unknown (OID=n)'
1551 pg_get_userbyid(PG_FUNCTION_ARGS)
1553 Oid roleid = PG_GETARG_OID(0);
1556 Form_pg_authid role_rec;
1559 * Allocate space for the result
1561 result = (Name) palloc(NAMEDATALEN);
1562 memset(NameStr(*result), 0, NAMEDATALEN);
1565 * Get the pg_authid entry and print the result
1567 roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
1568 if (HeapTupleIsValid(roletup))
1570 role_rec = (Form_pg_authid) GETSTRUCT(roletup);
1571 StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);
1572 ReleaseSysCache(roletup);
1575 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
1577 PG_RETURN_NAME(result);
1582 * pg_get_serial_sequence
1583 * Get the name of the sequence used by a serial column,
1584 * formatted suitably for passing to setval, nextval or currval.
1585 * First parameter is not treated as double-quoted, second parameter
1586 * is --- see documentation for reason.
1589 pg_get_serial_sequence(PG_FUNCTION_ARGS)
1591 text *tablename = PG_GETARG_TEXT_P(0);
1592 text *columnname = PG_GETARG_TEXT_PP(1);
1597 Oid sequenceId = InvalidOid;
1603 /* Look up table name. Can't lock it - we might not have privileges. */
1604 tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1605 tableOid = RangeVarGetRelid(tablerv, NoLock, false);
1607 /* Get the number of the column */
1608 column = text_to_cstring(columnname);
1610 attnum = get_attnum(tableOid, column);
1611 if (attnum == InvalidAttrNumber)
1613 (errcode(ERRCODE_UNDEFINED_COLUMN),
1614 errmsg("column \"%s\" of relation \"%s\" does not exist",
1615 column, tablerv->relname)));
1617 /* Search the dependency table for the dependent sequence */
1618 depRel = heap_open(DependRelationId, AccessShareLock);
1620 ScanKeyInit(&key[0],
1621 Anum_pg_depend_refclassid,
1622 BTEqualStrategyNumber, F_OIDEQ,
1623 ObjectIdGetDatum(RelationRelationId));
1624 ScanKeyInit(&key[1],
1625 Anum_pg_depend_refobjid,
1626 BTEqualStrategyNumber, F_OIDEQ,
1627 ObjectIdGetDatum(tableOid));
1628 ScanKeyInit(&key[2],
1629 Anum_pg_depend_refobjsubid,
1630 BTEqualStrategyNumber, F_INT4EQ,
1631 Int32GetDatum(attnum));
1633 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1634 SnapshotNow, 3, key);
1636 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1638 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1641 * We assume any auto dependency of a sequence on a column must be
1642 * what we are looking for. (We need the relkind test because indexes
1643 * can also have auto dependencies on columns.)
1645 if (deprec->classid == RelationRelationId &&
1646 deprec->objsubid == 0 &&
1647 deprec->deptype == DEPENDENCY_AUTO &&
1648 get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
1650 sequenceId = deprec->objid;
1655 systable_endscan(scan);
1656 heap_close(depRel, AccessShareLock);
1658 if (OidIsValid(sequenceId))
1661 Form_pg_class classtuple;
1665 /* Get the sequence's pg_class entry */
1666 classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(sequenceId));
1667 if (!HeapTupleIsValid(classtup))
1668 elog(ERROR, "cache lookup failed for relation %u", sequenceId);
1669 classtuple = (Form_pg_class) GETSTRUCT(classtup);
1671 /* Get the namespace */
1672 nspname = get_namespace_name(classtuple->relnamespace);
1674 elog(ERROR, "cache lookup failed for namespace %u",
1675 classtuple->relnamespace);
1677 /* And construct the result string */
1678 result = quote_qualified_identifier(nspname,
1679 NameStr(classtuple->relname));
1681 ReleaseSysCache(classtup);
1683 PG_RETURN_TEXT_P(string_to_text(result));
1691 * pg_get_functiondef
1692 * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
1693 * the specified function.
1695 * Note: if you change the output format of this function, be careful not
1696 * to break psql's rules (in \ef and \sf) for identifying the start of the
1697 * function body. To wit: the function body starts on a line that begins
1698 * with "AS ", and no preceding line will look like that.
1701 pg_get_functiondef(PG_FUNCTION_ARGS)
1703 Oid funcid = PG_GETARG_OID(0);
1709 Form_pg_language lang;
1718 initStringInfo(&buf);
1720 /* Look up the function */
1721 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1722 if (!HeapTupleIsValid(proctup))
1723 elog(ERROR, "cache lookup failed for function %u", funcid);
1724 proc = (Form_pg_proc) GETSTRUCT(proctup);
1725 name = NameStr(proc->proname);
1729 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1730 errmsg("\"%s\" is an aggregate function", name)));
1732 /* Need its pg_language tuple for the language name */
1733 langtup = SearchSysCache1(LANGOID, ObjectIdGetDatum(proc->prolang));
1734 if (!HeapTupleIsValid(langtup))
1735 elog(ERROR, "cache lookup failed for language %u", proc->prolang);
1736 lang = (Form_pg_language) GETSTRUCT(langtup);
1739 * We always qualify the function name, to ensure the right function gets
1742 nsp = get_namespace_name(proc->pronamespace);
1743 appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
1744 quote_qualified_identifier(nsp, name));
1745 (void) print_function_arguments(&buf, proctup, false, true);
1746 appendStringInfoString(&buf, ")\n RETURNS ");
1747 print_function_rettype(&buf, proctup);
1748 appendStringInfo(&buf, "\n LANGUAGE %s\n",
1749 quote_identifier(NameStr(lang->lanname)));
1751 /* Emit some miscellaneous options on one line */
1754 if (proc->proiswindow)
1755 appendStringInfoString(&buf, " WINDOW");
1756 switch (proc->provolatile)
1758 case PROVOLATILE_IMMUTABLE:
1759 appendStringInfoString(&buf, " IMMUTABLE");
1761 case PROVOLATILE_STABLE:
1762 appendStringInfoString(&buf, " STABLE");
1764 case PROVOLATILE_VOLATILE:
1767 if (proc->proisstrict)
1768 appendStringInfoString(&buf, " STRICT");
1769 if (proc->prosecdef)
1770 appendStringInfoString(&buf, " SECURITY DEFINER");
1772 /* This code for the default cost and rows should match functioncmds.c */
1773 if (proc->prolang == INTERNALlanguageId ||
1774 proc->prolang == ClanguageId)
1778 if (proc->procost != procost)
1779 appendStringInfo(&buf, " COST %g", proc->procost);
1781 if (proc->prorows > 0 && proc->prorows != 1000)
1782 appendStringInfo(&buf, " ROWS %g", proc->prorows);
1784 if (oldlen != buf.len)
1785 appendStringInfoChar(&buf, '\n');
1787 /* Emit any proconfig options, one per line */
1788 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
1791 ArrayType *a = DatumGetArrayTypeP(tmp);
1794 Assert(ARR_ELEMTYPE(a) == TEXTOID);
1795 Assert(ARR_NDIM(a) == 1);
1796 Assert(ARR_LBOUND(a)[0] == 1);
1798 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
1802 d = array_ref(a, 1, &i,
1803 -1 /* varlenarray */ ,
1804 -1 /* TEXT's typlen */ ,
1805 false /* TEXT's typbyval */ ,
1806 'i' /* TEXT's typalign */ ,
1810 char *configitem = TextDatumGetCString(d);
1813 pos = strchr(configitem, '=');
1818 appendStringInfo(&buf, " SET %s TO ",
1819 quote_identifier(configitem));
1822 * Some GUC variable names are 'LIST' type and hence must not
1825 if (pg_strcasecmp(configitem, "DateStyle") == 0
1826 || pg_strcasecmp(configitem, "search_path") == 0)
1827 appendStringInfoString(&buf, pos);
1829 simple_quote_literal(&buf, pos);
1830 appendStringInfoChar(&buf, '\n');
1835 /* And finally the function definition ... */
1836 appendStringInfoString(&buf, "AS ");
1838 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
1841 simple_quote_literal(&buf, TextDatumGetCString(tmp));
1842 appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
1845 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull);
1847 elog(ERROR, "null prosrc");
1848 prosrc = TextDatumGetCString(tmp);
1851 * We always use dollar quoting. Figure out a suitable delimiter.
1853 * Since the user is likely to be editing the function body string, we
1854 * shouldn't use a short delimiter that he might easily create a conflict
1855 * with. Hence prefer "$function$", but extend if needed.
1857 initStringInfo(&dq);
1858 appendStringInfoString(&dq, "$function");
1859 while (strstr(prosrc, dq.data) != NULL)
1860 appendStringInfoChar(&dq, 'x');
1861 appendStringInfoChar(&dq, '$');
1863 appendStringInfoString(&buf, dq.data);
1864 appendStringInfoString(&buf, prosrc);
1865 appendStringInfoString(&buf, dq.data);
1867 appendStringInfoString(&buf, "\n");
1869 ReleaseSysCache(langtup);
1870 ReleaseSysCache(proctup);
1872 PG_RETURN_TEXT_P(string_to_text(buf.data));
1876 * pg_get_function_arguments
1877 * Get a nicely-formatted list of arguments for a function.
1878 * This is everything that would go between the parentheses in
1882 pg_get_function_arguments(PG_FUNCTION_ARGS)
1884 Oid funcid = PG_GETARG_OID(0);
1888 initStringInfo(&buf);
1890 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1891 if (!HeapTupleIsValid(proctup))
1892 elog(ERROR, "cache lookup failed for function %u", funcid);
1894 (void) print_function_arguments(&buf, proctup, false, true);
1896 ReleaseSysCache(proctup);
1898 PG_RETURN_TEXT_P(string_to_text(buf.data));
1902 * pg_get_function_identity_arguments
1903 * Get a formatted list of arguments for a function.
1904 * This is everything that would go between the parentheses in
1905 * ALTER FUNCTION, etc. In particular, don't print defaults.
1908 pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
1910 Oid funcid = PG_GETARG_OID(0);
1914 initStringInfo(&buf);
1916 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1917 if (!HeapTupleIsValid(proctup))
1918 elog(ERROR, "cache lookup failed for function %u", funcid);
1920 (void) print_function_arguments(&buf, proctup, false, false);
1922 ReleaseSysCache(proctup);
1924 PG_RETURN_TEXT_P(string_to_text(buf.data));
1928 * pg_get_function_result
1929 * Get a nicely-formatted version of the result type of a function.
1930 * This is what would appear after RETURNS in CREATE FUNCTION.
1933 pg_get_function_result(PG_FUNCTION_ARGS)
1935 Oid funcid = PG_GETARG_OID(0);
1939 initStringInfo(&buf);
1941 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1942 if (!HeapTupleIsValid(proctup))
1943 elog(ERROR, "cache lookup failed for function %u", funcid);
1945 print_function_rettype(&buf, proctup);
1947 ReleaseSysCache(proctup);
1949 PG_RETURN_TEXT_P(string_to_text(buf.data));
1953 * Guts of pg_get_function_result: append the function's return type
1954 * to the specified buffer.
1957 print_function_rettype(StringInfo buf, HeapTuple proctup)
1959 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
1961 StringInfoData rbuf;
1963 initStringInfo(&rbuf);
1965 if (proc->proretset)
1967 /* It might be a table function; try to print the arguments */
1968 appendStringInfoString(&rbuf, "TABLE(");
1969 ntabargs = print_function_arguments(&rbuf, proctup, true, false);
1971 appendStringInfoString(&rbuf, ")");
1973 resetStringInfo(&rbuf);
1978 /* Not a table function, so do the normal thing */
1979 if (proc->proretset)
1980 appendStringInfoString(&rbuf, "SETOF ");
1981 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
1984 appendStringInfoString(buf, rbuf.data);
1988 * Common code for pg_get_function_arguments and pg_get_function_result:
1989 * append the desired subset of arguments to buf. We print only TABLE
1990 * arguments when print_table_args is true, and all the others when it's false.
1991 * We print argument defaults only if print_defaults is true.
1992 * Function return value is the number of arguments printed.
1995 print_function_arguments(StringInfo buf, HeapTuple proctup,
1996 bool print_table_args, bool print_defaults)
1998 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
2006 ListCell *nextargdefault = NULL;
2009 numargs = get_func_arg_info(proctup,
2010 &argtypes, &argnames, &argmodes);
2012 nlackdefaults = numargs;
2013 if (print_defaults && proc->pronargdefaults > 0)
2015 Datum proargdefaults;
2018 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
2019 Anum_pg_proc_proargdefaults,
2026 str = TextDatumGetCString(proargdefaults);
2027 argdefaults = (List *) stringToNode(str);
2028 Assert(IsA(argdefaults, List));
2030 nextargdefault = list_head(argdefaults);
2031 /* nlackdefaults counts only *input* arguments lacking defaults */
2032 nlackdefaults = proc->pronargs - list_length(argdefaults);
2038 for (i = 0; i < numargs; i++)
2040 Oid argtype = argtypes[i];
2041 char *argname = argnames ? argnames[i] : NULL;
2042 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
2043 const char *modename;
2052 case PROARGMODE_INOUT:
2053 modename = "INOUT ";
2056 case PROARGMODE_OUT:
2060 case PROARGMODE_VARIADIC:
2061 modename = "VARIADIC ";
2064 case PROARGMODE_TABLE:
2069 elog(ERROR, "invalid parameter mode '%c'", argmode);
2070 modename = NULL; /* keep compiler quiet */
2075 inputargno++; /* this is a 1-based counter */
2077 if (print_table_args != (argmode == PROARGMODE_TABLE))
2081 appendStringInfoString(buf, ", ");
2082 appendStringInfoString(buf, modename);
2083 if (argname && argname[0])
2084 appendStringInfo(buf, "%s ", quote_identifier(argname));
2085 appendStringInfoString(buf, format_type_be(argtype));
2086 if (print_defaults && isinput && inputargno > nlackdefaults)
2090 Assert(nextargdefault != NULL);
2091 expr = (Node *) lfirst(nextargdefault);
2092 nextargdefault = lnext(nextargdefault);
2094 appendStringInfo(buf, " DEFAULT %s",
2095 deparse_expression(expr, NIL, false, false));
2105 * deparse_expression - General utility for deparsing expressions
2107 * calls deparse_expression_pretty with all prettyPrinting disabled
2110 deparse_expression(Node *expr, List *dpcontext,
2111 bool forceprefix, bool showimplicit)
2113 return deparse_expression_pretty(expr, dpcontext, forceprefix,
2114 showimplicit, 0, 0);
2118 * deparse_expression_pretty - General utility for deparsing expressions
2120 * expr is the node tree to be deparsed. It must be a transformed expression
2121 * tree (ie, not the raw output of gram.y).
2123 * dpcontext is a list of deparse_namespace nodes representing the context
2124 * for interpreting Vars in the node tree.
2126 * forceprefix is TRUE to force all Vars to be prefixed with their table names.
2128 * showimplicit is TRUE to force all implicit casts to be shown explicitly.
2130 * tries to pretty up the output according to prettyFlags and startIndent.
2132 * The result is a palloc'd string.
2136 deparse_expression_pretty(Node *expr, List *dpcontext,
2137 bool forceprefix, bool showimplicit,
2138 int prettyFlags, int startIndent)
2141 deparse_context context;
2143 initStringInfo(&buf);
2145 context.namespaces = dpcontext;
2146 context.windowClause = NIL;
2147 context.windowTList = NIL;
2148 context.varprefix = forceprefix;
2149 context.prettyFlags = prettyFlags;
2150 context.indentLevel = startIndent;
2152 get_rule_expr(expr, &context, showimplicit);
2158 * deparse_context_for - Build deparse context for a single relation
2160 * Given the reference name (alias) and OID of a relation, build deparsing
2161 * context for an expression referencing only that relation (as varno 1,
2162 * varlevelsup 0). This is sufficient for many uses of deparse_expression.
2166 deparse_context_for(const char *aliasname, Oid relid)
2168 deparse_namespace *dpns;
2171 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
2173 /* Build a minimal RTE for the rel */
2174 rte = makeNode(RangeTblEntry);
2175 rte->rtekind = RTE_RELATION;
2177 rte->relkind = RELKIND_RELATION; /* no need for exactness here */
2178 rte->eref = makeAlias(aliasname, NIL);
2179 rte->lateral = false;
2181 rte->inFromCl = true;
2183 /* Build one-element rtable */
2184 dpns->rtable = list_make1(rte);
2187 /* Return a one-deep namespace stack */
2188 return list_make1(dpns);
2192 * deparse_context_for_planstate - Build deparse context for a plan
2194 * When deparsing an expression in a Plan tree, we might have to resolve
2195 * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
2196 * provide the parent PlanState node. Then OUTER_VAR and INNER_VAR references
2197 * can be resolved by drilling down into the left and right child plans.
2198 * Similarly, INDEX_VAR references can be resolved by reference to the
2199 * indextlist given in the parent IndexOnlyScan node. (Note that we don't
2200 * currently support deparsing of indexquals in regular IndexScan or
2201 * BitmapIndexScan nodes; for those, we can only deparse the indexqualorig
2202 * fields, which won't contain INDEX_VAR Vars.)
2204 * Note: planstate really ought to be declared as "PlanState *", but we use
2205 * "Node *" to avoid having to include execnodes.h in builtins.h.
2207 * The ancestors list is a list of the PlanState's parent PlanStates, the
2208 * most-closely-nested first. This is needed to resolve PARAM_EXEC Params.
2209 * Note we assume that all the PlanStates share the same rtable.
2211 * The plan's rangetable list must also be passed. We actually prefer to use
2212 * the rangetable to resolve simple Vars, but the plan inputs are necessary
2213 * for Vars with special varnos.
2216 deparse_context_for_planstate(Node *planstate, List *ancestors,
2219 deparse_namespace *dpns;
2221 dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
2223 /* Initialize fields that stay the same across the whole plan tree */
2224 dpns->rtable = rtable;
2227 /* Set our attention on the specific plan node passed in */
2228 set_deparse_planstate(dpns, (PlanState *) planstate);
2229 dpns->ancestors = ancestors;
2231 /* Return a one-deep namespace stack */
2232 return list_make1(dpns);
2236 * set_deparse_planstate: set up deparse_namespace to parse subexpressions
2237 * of a given PlanState node
2239 * This sets the planstate, outer_planstate, inner_planstate, outer_tlist,
2240 * inner_tlist, and index_tlist fields. Caller is responsible for adjusting
2241 * the ancestors list if necessary. Note that the rtable and ctes fields do
2242 * not need to change when shifting attention to different plan nodes in a
2246 set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
2248 dpns->planstate = ps;
2251 * We special-case Append and MergeAppend to pretend that the first child
2252 * plan is the OUTER referent; we have to interpret OUTER Vars in their
2253 * tlists according to one of the children, and the first one is the most
2254 * natural choice. Likewise special-case ModifyTable to pretend that the
2255 * first child plan is the OUTER referent; this is to support RETURNING
2256 * lists containing references to non-target relations.
2258 if (IsA(ps, AppendState))
2259 dpns->outer_planstate = ((AppendState *) ps)->appendplans[0];
2260 else if (IsA(ps, MergeAppendState))
2261 dpns->outer_planstate = ((MergeAppendState *) ps)->mergeplans[0];
2262 else if (IsA(ps, ModifyTableState))
2263 dpns->outer_planstate = ((ModifyTableState *) ps)->mt_plans[0];
2265 dpns->outer_planstate = outerPlanState(ps);
2267 if (dpns->outer_planstate)
2268 dpns->outer_tlist = dpns->outer_planstate->plan->targetlist;
2270 dpns->outer_tlist = NIL;
2273 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
2274 * use OUTER because that could someday conflict with the normal meaning.)
2275 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
2277 if (IsA(ps, SubqueryScanState))
2278 dpns->inner_planstate = ((SubqueryScanState *) ps)->subplan;
2279 else if (IsA(ps, CteScanState))
2280 dpns->inner_planstate = ((CteScanState *) ps)->cteplanstate;
2282 dpns->inner_planstate = innerPlanState(ps);
2284 if (dpns->inner_planstate)
2285 dpns->inner_tlist = dpns->inner_planstate->plan->targetlist;
2287 dpns->inner_tlist = NIL;
2289 /* index_tlist is set only if it's an IndexOnlyScan */
2290 if (IsA(ps->plan, IndexOnlyScan))
2291 dpns->index_tlist = ((IndexOnlyScan *) ps->plan)->indextlist;
2293 dpns->index_tlist = NIL;
2297 * push_child_plan: temporarily transfer deparsing attention to a child plan
2299 * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
2300 * deparse context in case the referenced expression itself uses
2301 * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
2302 * affecting levelsup issues (although in a Plan tree there really shouldn't
2305 * Caller must provide a local deparse_namespace variable to save the
2306 * previous state for pop_child_plan.
2309 push_child_plan(deparse_namespace *dpns, PlanState *ps,
2310 deparse_namespace *save_dpns)
2312 /* Save state for restoration later */
2316 * Currently we don't bother to adjust the ancestors list, because an
2317 * OUTER_VAR or INNER_VAR reference really shouldn't contain any Params
2318 * that would be set by the parent node itself. If we did want to adjust
2319 * the list, lcons'ing dpns->planstate onto dpns->ancestors would be the
2320 * appropriate thing --- and pop_child_plan would need to undo the change
2324 /* Set attention on selected child */
2325 set_deparse_planstate(dpns, ps);
2329 * pop_child_plan: undo the effects of push_child_plan
2332 pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
2334 /* Restore fields changed by push_child_plan */
2339 * push_ancestor_plan: temporarily transfer deparsing attention to an
2342 * When expanding a Param reference, we must adjust the deparse context
2343 * to match the plan node that contains the expression being printed;
2344 * otherwise we'd fail if that expression itself contains a Param or
2345 * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
2347 * The target ancestor is conveniently identified by the ListCell holding it
2348 * in dpns->ancestors.
2350 * Caller must provide a local deparse_namespace variable to save the
2351 * previous state for pop_ancestor_plan.
2354 push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
2355 deparse_namespace *save_dpns)
2357 PlanState *ps = (PlanState *) lfirst(ancestor_cell);
2360 /* Save state for restoration later */
2363 /* Build a new ancestor list with just this node's ancestors */
2365 while ((ancestor_cell = lnext(ancestor_cell)) != NULL)
2366 ancestors = lappend(ancestors, lfirst(ancestor_cell));
2367 dpns->ancestors = ancestors;
2369 /* Set attention on selected ancestor */
2370 set_deparse_planstate(dpns, ps);
2374 * pop_ancestor_plan: undo the effects of push_ancestor_plan
2377 pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
2379 /* Free the ancestor list made in push_ancestor_plan */
2380 list_free(dpns->ancestors);
2382 /* Restore fields changed by push_ancestor_plan */
2388 * make_ruledef - reconstruct the CREATE RULE command
2389 * for a given pg_rewrite tuple
2393 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
2403 List *actions = NIL;
2409 * Get the attribute values from the rules tuple
2411 fno = SPI_fnumber(rulettc, "rulename");
2412 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2414 rulename = NameStr(*(DatumGetName(dat)));
2416 fno = SPI_fnumber(rulettc, "ev_type");
2417 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2419 ev_type = DatumGetChar(dat);
2421 fno = SPI_fnumber(rulettc, "ev_class");
2422 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2424 ev_class = DatumGetObjectId(dat);
2426 fno = SPI_fnumber(rulettc, "ev_attr");
2427 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2429 ev_attr = DatumGetInt16(dat);
2431 fno = SPI_fnumber(rulettc, "is_instead");
2432 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2434 is_instead = DatumGetBool(dat);
2436 /* these could be nulls */
2437 fno = SPI_fnumber(rulettc, "ev_qual");
2438 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2440 fno = SPI_fnumber(rulettc, "ev_action");
2441 ev_action = SPI_getvalue(ruletup, rulettc, fno);
2442 if (ev_action != NULL)
2443 actions = (List *) stringToNode(ev_action);
2446 * Build the rules definition text
2448 appendStringInfo(buf, "CREATE RULE %s AS",
2449 quote_identifier(rulename));
2451 if (prettyFlags & PRETTYFLAG_INDENT)
2452 appendStringInfoString(buf, "\n ON ");
2454 appendStringInfoString(buf, " ON ");
2456 /* The event the rule is fired for */
2460 appendStringInfo(buf, "SELECT");
2464 appendStringInfo(buf, "UPDATE");
2468 appendStringInfo(buf, "INSERT");
2472 appendStringInfo(buf, "DELETE");
2477 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2478 errmsg("rule \"%s\" has unsupported event type %d",
2479 rulename, ev_type)));
2483 /* The relation the rule is fired on */
2484 appendStringInfo(buf, " TO %s", generate_relation_name(ev_class, NIL));
2486 appendStringInfo(buf, ".%s",
2487 quote_identifier(get_relid_attribute_name(ev_class,
2490 /* If the rule has an event qualification, add it */
2491 if (ev_qual == NULL)
2493 if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
2497 deparse_context context;
2498 deparse_namespace dpns;
2500 if (prettyFlags & PRETTYFLAG_INDENT)
2501 appendStringInfoString(buf, "\n ");
2502 appendStringInfo(buf, " WHERE ");
2504 qual = stringToNode(ev_qual);
2507 * We need to make a context for recognizing any Vars in the qual
2508 * (which can only be references to OLD and NEW). Use the rtable of
2509 * the first query in the action list for this purpose.
2511 query = (Query *) linitial(actions);
2514 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
2515 * into the SELECT, and that's what we need to look at. (Ugly kluge
2516 * ... try to fix this when we redesign querytrees.)
2518 query = getInsertSelectQuery(query, NULL);
2520 /* Must acquire locks right away; see notes in get_query_def() */
2521 AcquireRewriteLocks(query, false);
2524 context.namespaces = list_make1(&dpns);
2525 context.windowClause = NIL;
2526 context.windowTList = NIL;
2527 context.varprefix = (list_length(query->rtable) != 1);
2528 context.prettyFlags = prettyFlags;
2529 context.indentLevel = PRETTYINDENT_STD;
2531 memset(&dpns, 0, sizeof(dpns));
2532 dpns.rtable = query->rtable;
2533 dpns.ctes = query->cteList;
2535 get_rule_expr(qual, &context, false);
2538 appendStringInfo(buf, " DO ");
2540 /* The INSTEAD keyword (if so) */
2542 appendStringInfo(buf, "INSTEAD ");
2544 /* Finally the rules actions */
2545 if (list_length(actions) > 1)
2550 appendStringInfo(buf, "(");
2551 foreach(action, actions)
2553 query = (Query *) lfirst(action);
2554 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2556 appendStringInfo(buf, ";\n");
2558 appendStringInfo(buf, "; ");
2560 appendStringInfo(buf, ");");
2562 else if (list_length(actions) == 0)
2564 appendStringInfo(buf, "NOTHING;");
2570 query = (Query *) linitial(actions);
2571 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2572 appendStringInfo(buf, ";");
2578 * make_viewdef - reconstruct the SELECT part of a
2583 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
2593 List *actions = NIL;
2594 Relation ev_relation;
2599 * Get the attribute values from the rules tuple
2601 fno = SPI_fnumber(rulettc, "ev_type");
2602 ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2604 fno = SPI_fnumber(rulettc, "ev_class");
2605 ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2607 fno = SPI_fnumber(rulettc, "ev_attr");
2608 ev_attr = (int16) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2610 fno = SPI_fnumber(rulettc, "is_instead");
2611 is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2613 fno = SPI_fnumber(rulettc, "ev_qual");
2614 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2616 fno = SPI_fnumber(rulettc, "ev_action");
2617 ev_action = SPI_getvalue(ruletup, rulettc, fno);
2618 if (ev_action != NULL)
2619 actions = (List *) stringToNode(ev_action);
2621 if (list_length(actions) != 1)
2623 appendStringInfo(buf, "Not a view");
2627 query = (Query *) linitial(actions);
2629 if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
2630 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
2632 appendStringInfo(buf, "Not a view");
2636 ev_relation = heap_open(ev_class, AccessShareLock);
2638 get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
2640 appendStringInfo(buf, ";");
2642 heap_close(ev_relation, AccessShareLock);
2647 * get_query_def - Parse back one query parsetree
2649 * If resultDesc is not NULL, then it is the output tuple descriptor for
2650 * the view represented by a SELECT query.
2654 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
2655 TupleDesc resultDesc, int prettyFlags, int startIndent)
2657 deparse_context context;
2658 deparse_namespace dpns;
2661 * Before we begin to examine the query, acquire locks on referenced
2662 * relations, and fix up deleted columns in JOIN RTEs. This ensures
2663 * consistent results. Note we assume it's OK to scribble on the passed
2666 AcquireRewriteLocks(query, false);
2669 context.namespaces = lcons(&dpns, list_copy(parentnamespace));
2670 context.windowClause = NIL;
2671 context.windowTList = NIL;
2672 context.varprefix = (parentnamespace != NIL ||
2673 list_length(query->rtable) != 1);
2674 context.prettyFlags = prettyFlags;
2675 context.indentLevel = startIndent;
2677 memset(&dpns, 0, sizeof(dpns));
2678 dpns.rtable = query->rtable;
2679 dpns.ctes = query->cteList;
2681 switch (query->commandType)
2684 get_select_query_def(query, &context, resultDesc);
2688 get_update_query_def(query, &context);
2692 get_insert_query_def(query, &context);
2696 get_delete_query_def(query, &context);
2700 appendStringInfo(buf, "NOTHING");
2704 get_utility_query_def(query, &context);
2708 elog(ERROR, "unrecognized query command type: %d",
2709 query->commandType);
2715 * get_values_def - Parse back a VALUES list
2719 get_values_def(List *values_lists, deparse_context *context)
2721 StringInfo buf = context->buf;
2722 bool first_list = true;
2725 appendStringInfoString(buf, "VALUES ");
2727 foreach(vtl, values_lists)
2729 List *sublist = (List *) lfirst(vtl);
2730 bool first_col = true;
2736 appendStringInfoString(buf, ", ");
2738 appendStringInfoChar(buf, '(');
2739 foreach(lc, sublist)
2741 Node *col = (Node *) lfirst(lc);
2746 appendStringInfoChar(buf, ',');
2749 * Strip any top-level nodes representing indirection assignments,
2750 * then print the result.
2752 get_rule_expr(processIndirection(col, context, false),
2755 appendStringInfoChar(buf, ')');
2760 * get_with_clause - Parse back a WITH clause
2764 get_with_clause(Query *query, deparse_context *context)
2766 StringInfo buf = context->buf;
2770 if (query->cteList == NIL)
2773 if (PRETTY_INDENT(context))
2775 context->indentLevel += PRETTYINDENT_STD;
2776 appendStringInfoChar(buf, ' ');
2779 if (query->hasRecursive)
2780 sep = "WITH RECURSIVE ";
2783 foreach(l, query->cteList)
2785 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
2787 appendStringInfoString(buf, sep);
2788 appendStringInfoString(buf, quote_identifier(cte->ctename));
2789 if (cte->aliascolnames)
2794 appendStringInfoChar(buf, '(');
2795 foreach(col, cte->aliascolnames)
2800 appendStringInfoString(buf, ", ");
2801 appendStringInfoString(buf,
2802 quote_identifier(strVal(lfirst(col))));
2804 appendStringInfoChar(buf, ')');
2806 appendStringInfoString(buf, " AS (");
2807 if (PRETTY_INDENT(context))
2808 appendContextKeyword(context, "", 0, 0, 0);
2809 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
2810 context->prettyFlags, context->indentLevel);
2811 if (PRETTY_INDENT(context))
2812 appendContextKeyword(context, "", 0, 0, 0);
2813 appendStringInfoChar(buf, ')');
2817 if (PRETTY_INDENT(context))
2819 context->indentLevel -= PRETTYINDENT_STD;
2820 appendContextKeyword(context, "", 0, 0, 0);
2823 appendStringInfoChar(buf, ' ');
2827 * get_select_query_def - Parse back a SELECT parsetree
2831 get_select_query_def(Query *query, deparse_context *context,
2832 TupleDesc resultDesc)
2834 StringInfo buf = context->buf;
2835 List *save_windowclause;
2836 List *save_windowtlist;
2840 /* Insert the WITH clause if given */
2841 get_with_clause(query, context);
2843 /* Set up context for possible window functions */
2844 save_windowclause = context->windowClause;
2845 context->windowClause = query->windowClause;
2846 save_windowtlist = context->windowTList;
2847 context->windowTList = query->targetList;
2850 * If the Query node has a setOperations tree, then it's the top level of
2851 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
2852 * fields are interesting in the top query itself.
2854 if (query->setOperations)
2856 get_setop_query(query->setOperations, query, context, resultDesc);
2857 /* ORDER BY clauses must be simple in this case */
2862 get_basic_select_query(query, context, resultDesc);
2863 force_colno = false;
2866 /* Add the ORDER BY clause if given */
2867 if (query->sortClause != NIL)
2869 appendContextKeyword(context, " ORDER BY ",
2870 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2871 get_rule_orderby(query->sortClause, query->targetList,
2872 force_colno, context);
2875 /* Add the LIMIT clause if given */
2876 if (query->limitOffset != NULL)
2878 appendContextKeyword(context, " OFFSET ",
2879 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2880 get_rule_expr(query->limitOffset, context, false);
2882 if (query->limitCount != NULL)
2884 appendContextKeyword(context, " LIMIT ",
2885 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2886 if (IsA(query->limitCount, Const) &&
2887 ((Const *) query->limitCount)->constisnull)
2888 appendStringInfo(buf, "ALL");
2890 get_rule_expr(query->limitCount, context, false);
2893 /* Add FOR UPDATE/SHARE clauses if present */
2894 if (query->hasForUpdate)
2896 foreach(l, query->rowMarks)
2898 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
2899 RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);
2901 /* don't print implicit clauses */
2906 appendContextKeyword(context, " FOR UPDATE",
2907 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2909 appendContextKeyword(context, " FOR SHARE",
2910 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2911 appendStringInfo(buf, " OF %s",
2912 quote_identifier(rte->eref->aliasname));
2914 appendStringInfo(buf, " NOWAIT");
2918 context->windowClause = save_windowclause;
2919 context->windowTList = save_windowtlist;
2923 * Detect whether query looks like SELECT ... FROM VALUES();
2924 * if so, return the VALUES RTE. Otherwise return NULL.
2926 static RangeTblEntry *
2927 get_simple_values_rte(Query *query)
2929 RangeTblEntry *result = NULL;
2933 * We want to return TRUE even if the Query also contains OLD or NEW rule
2934 * RTEs. So the idea is to scan the rtable and see if there is only one
2935 * inFromCl RTE that is a VALUES RTE. We don't look at the targetlist at
2936 * all. This is okay because parser/analyze.c will never generate a
2937 * "bare" VALUES RTE --- they only appear inside auto-generated
2938 * sub-queries with very restricted structure.
2940 foreach(lc, query->rtable)
2942 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
2944 if (rte->rtekind == RTE_VALUES && rte->inFromCl)
2947 return NULL; /* multiple VALUES (probably not possible) */
2950 else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
2951 continue; /* ignore rule entries */
2953 return NULL; /* something else -> not simple VALUES */
2959 get_basic_select_query(Query *query, deparse_context *context,
2960 TupleDesc resultDesc)
2962 StringInfo buf = context->buf;
2963 RangeTblEntry *values_rte;
2967 if (PRETTY_INDENT(context))
2969 context->indentLevel += PRETTYINDENT_STD;
2970 appendStringInfoChar(buf, ' ');
2974 * If the query looks like SELECT * FROM (VALUES ...), then print just the
2975 * VALUES part. This reverses what transformValuesClause() did at parse
2978 values_rte = get_simple_values_rte(query);
2981 get_values_def(values_rte->values_lists, context);
2986 * Build up the query string - first we say SELECT
2988 appendStringInfo(buf, "SELECT");
2990 /* Add the DISTINCT clause if given */
2991 if (query->distinctClause != NIL)
2993 if (query->hasDistinctOn)
2995 appendStringInfo(buf, " DISTINCT ON (");
2997 foreach(l, query->distinctClause)
2999 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
3001 appendStringInfoString(buf, sep);
3002 get_rule_sortgroupclause(srt, query->targetList,
3006 appendStringInfo(buf, ")");
3009 appendStringInfo(buf, " DISTINCT");
3012 /* Then we tell what to select (the targetlist) */
3013 get_target_list(query->targetList, context, resultDesc);
3015 /* Add the FROM clause if needed */
3016 get_from_clause(query, " FROM ", context);
3018 /* Add the WHERE clause if given */
3019 if (query->jointree->quals != NULL)
3021 appendContextKeyword(context, " WHERE ",
3022 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3023 get_rule_expr(query->jointree->quals, context, false);
3026 /* Add the GROUP BY clause if given */
3027 if (query->groupClause != NULL)
3029 appendContextKeyword(context, " GROUP BY ",
3030 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3032 foreach(l, query->groupClause)
3034 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
3036 appendStringInfoString(buf, sep);
3037 get_rule_sortgroupclause(grp, query->targetList,
3043 /* Add the HAVING clause if given */
3044 if (query->havingQual != NULL)
3046 appendContextKeyword(context, " HAVING ",
3047 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3048 get_rule_expr(query->havingQual, context, false);
3051 /* Add the WINDOW clause if needed */
3052 if (query->windowClause != NIL)
3053 get_rule_windowclause(query, context);
3057 * get_target_list - Parse back a SELECT target list
3059 * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
3063 get_target_list(List *targetList, deparse_context *context,
3064 TupleDesc resultDesc)
3066 StringInfo buf = context->buf;
3070 bool last_was_multiline = false;
3074 foreach(l, targetList)
3076 TargetEntry *tle = (TargetEntry *) lfirst(l);
3079 StringInfoData targetbuf;
3080 int leading_nl_pos = -1;
3085 continue; /* ignore junk entries */
3087 appendStringInfoString(buf, sep);
3092 * Put the new field spec into targetbuf so we can decide after we've
3093 * got it whether or not it needs to go on a new line.
3096 initStringInfo(&targetbuf);
3097 context->buf = &targetbuf;
3100 * We special-case Var nodes rather than using get_rule_expr. This is
3101 * needed because get_rule_expr will display a whole-row Var as
3102 * "foo.*", which is the preferred notation in most contexts, but at
3103 * the top level of a SELECT list it's not right (the parser will
3104 * expand that notation into multiple columns, yielding behavior
3105 * different from a whole-row Var). We need to call get_variable
3106 * directly so that we can tell it to do the right thing.
3108 if (tle->expr && IsA(tle->expr, Var))
3110 attname = get_variable((Var *) tle->expr, 0, true, context);
3114 get_rule_expr((Node *) tle->expr, context, true);
3115 /* We'll show the AS name unless it's this: */
3116 attname = "?column?";
3120 * Figure out what the result column should be called. In the context
3121 * of a view, use the view's tuple descriptor (so as to pick up the
3122 * effects of any column RENAME that's been done on the view).
3123 * Otherwise, just use what we can find in the TLE.
3125 if (resultDesc && colno <= resultDesc->natts)
3126 colname = NameStr(resultDesc->attrs[colno - 1]->attname);
3128 colname = tle->resname;
3130 /* Show AS unless the column's name is correct as-is */
3131 if (colname) /* resname could be NULL */
3133 if (attname == NULL || strcmp(attname, colname) != 0)
3134 appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
3137 /* Restore context buffer */
3141 /* Does the new field start with whitespace plus a new line? */
3143 for (pos = 0; pos < targetbuf.len; pos++)
3145 if (targetbuf.data[pos] == '\n')
3147 leading_nl_pos = pos;
3150 if (targetbuf.data[pos] > ' ')
3154 /* Locate the start of the current line in the buffer */
3156 trailing_nl = (strrchr(buf->data, '\n'));
3157 if (trailing_nl == NULL)
3158 trailing_nl = buf->data;
3163 * If the field we're adding is the first in the list, or it already
3164 * has a leading newline, or wrap mode is disabled (pretty_wrap < 0),
3165 * don't add anything. Otherwise, add a newline, plus some
3166 * indentation, if either the new field would cause an overflow or the
3167 * last field used more than one line.
3171 leading_nl_pos == -1 &&
3173 ((strlen(trailing_nl) + strlen(targetbuf.data) > pretty_wrap) ||
3174 last_was_multiline))
3176 appendContextKeyword(context, "", -PRETTYINDENT_STD,
3177 PRETTYINDENT_STD, PRETTYINDENT_VAR);
3180 /* Add the new field */
3182 appendStringInfoString(buf, targetbuf.data);
3185 /* Keep track of this field's status for next iteration */
3187 last_was_multiline =
3188 (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
3192 pfree(targetbuf.data);
3197 get_setop_query(Node *setOp, Query *query, deparse_context *context,
3198 TupleDesc resultDesc)
3200 StringInfo buf = context->buf;
3203 if (IsA(setOp, RangeTblRef))
3205 RangeTblRef *rtr = (RangeTblRef *) setOp;
3206 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
3207 Query *subquery = rte->subquery;
3209 Assert(subquery != NULL);
3210 Assert(subquery->setOperations == NULL);
3211 /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
3212 need_paren = (subquery->cteList ||
3213 subquery->sortClause ||
3214 subquery->rowMarks ||
3215 subquery->limitOffset ||
3216 subquery->limitCount);
3218 appendStringInfoChar(buf, '(');
3219 get_query_def(subquery, buf, context->namespaces, resultDesc,
3220 context->prettyFlags, context->indentLevel);
3222 appendStringInfoChar(buf, ')');
3224 else if (IsA(setOp, SetOperationStmt))
3226 SetOperationStmt *op = (SetOperationStmt *) setOp;
3228 if (PRETTY_INDENT(context))
3230 context->indentLevel += PRETTYINDENT_STD;
3231 appendStringInfoSpaces(buf, PRETTYINDENT_STD);
3235 * We force parens whenever nesting two SetOperationStmts. There are
3236 * some cases in which parens are needed around a leaf query too, but
3237 * those are more easily handled at the next level down (see code
3240 need_paren = !IsA(op->larg, RangeTblRef);
3243 appendStringInfoChar(buf, '(');
3244 get_setop_query(op->larg, query, context, resultDesc);
3246 appendStringInfoChar(buf, ')');
3248 if (!PRETTY_INDENT(context))
3249 appendStringInfoChar(buf, ' ');
3253 appendContextKeyword(context, "UNION ",
3254 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3256 case SETOP_INTERSECT:
3257 appendContextKeyword(context, "INTERSECT ",
3258 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3261 appendContextKeyword(context, "EXCEPT ",
3262 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3265 elog(ERROR, "unrecognized set op: %d",
3269 appendStringInfo(buf, "ALL ");
3271 if (PRETTY_INDENT(context))
3272 appendContextKeyword(context, "", 0, 0, 0);
3274 need_paren = !IsA(op->rarg, RangeTblRef);
3277 appendStringInfoChar(buf, '(');
3278 get_setop_query(op->rarg, query, context, resultDesc);
3280 appendStringInfoChar(buf, ')');
3282 if (PRETTY_INDENT(context))
3283 context->indentLevel -= PRETTYINDENT_STD;
3287 elog(ERROR, "unrecognized node type: %d",
3288 (int) nodeTag(setOp));
3293 * Display a sort/group clause.
3295 * Also returns the expression tree, so caller need not find it again.
3298 get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, bool force_colno,
3299 deparse_context *context)
3301 StringInfo buf = context->buf;
3305 tle = get_sortgroupclause_tle(srt, tlist);
3306 expr = (Node *) tle->expr;
3309 * Use column-number form if requested by caller. Otherwise, if
3310 * expression is a constant, force it to be dumped with an explicit cast
3311 * as decoration --- this is because a simple integer constant is
3312 * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
3313 * dump it without any decoration. Otherwise, just dump the expression
3318 Assert(!tle->resjunk);
3319 appendStringInfo(buf, "%d", tle->resno);
3321 else if (expr && IsA(expr, Const))
3322 get_const_expr((Const *) expr, context, 1);
3324 get_rule_expr(expr, context, true);
3330 * Display an ORDER BY list.
3333 get_rule_orderby(List *orderList, List *targetList,
3334 bool force_colno, deparse_context *context)
3336 StringInfo buf = context->buf;
3341 foreach(l, orderList)
3343 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
3346 TypeCacheEntry *typentry;
3348 appendStringInfoString(buf, sep);
3349 sortexpr = get_rule_sortgroupclause(srt, targetList,
3350 force_colno, context);
3351 sortcoltype = exprType(sortexpr);
3352 /* See whether operator is default < or > for datatype */
3353 typentry = lookup_type_cache(sortcoltype,
3354 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
3355 if (srt->sortop == typentry->lt_opr)
3357 /* ASC is default, so emit nothing for it */
3358 if (srt->nulls_first)
3359 appendStringInfo(buf, " NULLS FIRST");
3361 else if (srt->sortop == typentry->gt_opr)
3363 appendStringInfo(buf, " DESC");
3364 /* DESC defaults to NULLS FIRST */
3365 if (!srt->nulls_first)
3366 appendStringInfo(buf, " NULLS LAST");
3370 appendStringInfo(buf, " USING %s",
3371 generate_operator_name(srt->sortop,
3374 /* be specific to eliminate ambiguity */
3375 if (srt->nulls_first)
3376 appendStringInfo(buf, " NULLS FIRST");
3378 appendStringInfo(buf, " NULLS LAST");
3385 * Display a WINDOW clause.
3387 * Note that the windowClause list might contain only anonymous window
3388 * specifications, in which case we should print nothing here.
3391 get_rule_windowclause(Query *query, deparse_context *context)
3393 StringInfo buf = context->buf;
3398 foreach(l, query->windowClause)
3400 WindowClause *wc = (WindowClause *) lfirst(l);
3402 if (wc->name == NULL)
3403 continue; /* ignore anonymous windows */
3406 appendContextKeyword(context, " WINDOW ",
3407 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3409 appendStringInfoString(buf, sep);
3411 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
3413 get_rule_windowspec(wc, query->targetList, context);
3420 * Display a window definition
3423 get_rule_windowspec(WindowClause *wc, List *targetList,
3424 deparse_context *context)
3426 StringInfo buf = context->buf;
3427 bool needspace = false;
3431 appendStringInfoChar(buf, '(');
3434 appendStringInfoString(buf, quote_identifier(wc->refname));
3437 /* partition clauses are always inherited, so only print if no refname */
3438 if (wc->partitionClause && !wc->refname)
3441 appendStringInfoChar(buf, ' ');
3442 appendStringInfoString(buf, "PARTITION BY ");
3444 foreach(l, wc->partitionClause)
3446 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
3448 appendStringInfoString(buf, sep);
3449 get_rule_sortgroupclause(grp, targetList,
3455 /* print ordering clause only if not inherited */
3456 if (wc->orderClause && !wc->copiedOrder)
3459 appendStringInfoChar(buf, ' ');
3460 appendStringInfoString(buf, "ORDER BY ");
3461 get_rule_orderby(wc->orderClause, targetList, false, context);
3464 /* framing clause is never inherited, so print unless it's default */
3465 if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
3468 appendStringInfoChar(buf, ' ');
3469 if (wc->frameOptions & FRAMEOPTION_RANGE)
3470 appendStringInfoString(buf, "RANGE ");
3471 else if (wc->frameOptions & FRAMEOPTION_ROWS)
3472 appendStringInfoString(buf, "ROWS ");
3475 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
3476 appendStringInfoString(buf, "BETWEEN ");
3477 if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
3478 appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
3479 else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
3480 appendStringInfoString(buf, "CURRENT ROW ");
3481 else if (wc->frameOptions & FRAMEOPTION_START_VALUE)
3483 get_rule_expr(wc->startOffset, context, false);
3484 if (wc->frameOptions & FRAMEOPTION_START_VALUE_PRECEDING)
3485 appendStringInfoString(buf, " PRECEDING ");
3486 else if (wc->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING)
3487 appendStringInfoString(buf, " FOLLOWING ");
3493 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
3495 appendStringInfoString(buf, "AND ");
3496 if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
3497 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
3498 else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
3499 appendStringInfoString(buf, "CURRENT ROW ");
3500 else if (wc->frameOptions & FRAMEOPTION_END_VALUE)
3502 get_rule_expr(wc->endOffset, context, false);
3503 if (wc->frameOptions & FRAMEOPTION_END_VALUE_PRECEDING)
3504 appendStringInfoString(buf, " PRECEDING ");
3505 else if (wc->frameOptions & FRAMEOPTION_END_VALUE_FOLLOWING)
3506 appendStringInfoString(buf, " FOLLOWING ");
3513 /* we will now have a trailing space; remove it */
3516 appendStringInfoChar(buf, ')');
3520 * get_insert_query_def - Parse back an INSERT parsetree
3524 get_insert_query_def(Query *query, deparse_context *context)
3526 StringInfo buf = context->buf;
3527 RangeTblEntry *select_rte = NULL;
3528 RangeTblEntry *values_rte = NULL;
3531 ListCell *values_cell;
3533 List *strippedexprs;
3535 /* Insert the WITH clause if given */
3536 get_with_clause(query, context);
3539 * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will be
3540 * a single RTE for the SELECT or VALUES.
3542 foreach(l, query->rtable)
3544 rte = (RangeTblEntry *) lfirst(l);
3546 if (rte->rtekind == RTE_SUBQUERY)
3549 elog(ERROR, "too many subquery RTEs in INSERT");
3553 if (rte->rtekind == RTE_VALUES)
3556 elog(ERROR, "too many values RTEs in INSERT");
3560 if (select_rte && values_rte)
3561 elog(ERROR, "both subquery and values RTEs in INSERT");
3564 * Start the query with INSERT INTO relname
3566 rte = rt_fetch(query->resultRelation, query->rtable);
3567 Assert(rte->rtekind == RTE_RELATION);
3569 if (PRETTY_INDENT(context))
3571 context->indentLevel += PRETTYINDENT_STD;
3572 appendStringInfoChar(buf, ' ');
3574 appendStringInfo(buf, "INSERT INTO %s (",
3575 generate_relation_name(rte->relid, NIL));
3578 * Add the insert-column-names list. To handle indirection properly, we
3579 * need to look for indirection nodes in the top targetlist (if it's
3580 * INSERT ... SELECT or INSERT ... single VALUES), or in the first
3581 * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We
3582 * assume that all the expression lists will have similar indirection in
3586 values_cell = list_head((List *) linitial(values_rte->values_lists));
3589 strippedexprs = NIL;
3591 foreach(l, query->targetList)
3593 TargetEntry *tle = (TargetEntry *) lfirst(l);
3596 continue; /* ignore junk entries */
3598 appendStringInfoString(buf, sep);
3602 * Put out name of target column; look in the catalogs, not at
3603 * tle->resname, since resname will fail to track RENAME.
3605 appendStringInfoString(buf,
3606 quote_identifier(get_relid_attribute_name(rte->relid,
3610 * Print any indirection needed (subfields or subscripts), and strip
3611 * off the top-level nodes representing the indirection assignments.
3615 /* we discard the stripped expression in this case */
3616 processIndirection((Node *) lfirst(values_cell), context, true);
3617 values_cell = lnext(values_cell);
3621 /* we keep a list of the stripped expressions in this case */
3622 strippedexprs = lappend(strippedexprs,
3623 processIndirection((Node *) tle->expr,
3627 appendStringInfo(buf, ") ");
3631 /* Add the SELECT */
3632 get_query_def(select_rte->subquery, buf, NIL, NULL,
3633 context->prettyFlags, context->indentLevel);
3635 else if (values_rte)
3637 /* Add the multi-VALUES expression lists */
3638 get_values_def(values_rte->values_lists, context);
3642 /* Add the single-VALUES expression list */
3643 appendContextKeyword(context, "VALUES (",
3644 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
3645 get_rule_expr((Node *) strippedexprs, context, false);
3646 appendStringInfoChar(buf, ')');
3649 /* Add RETURNING if present */
3650 if (query->returningList)
3652 appendContextKeyword(context, " RETURNING",
3653 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3654 get_target_list(query->returningList, context, NULL);
3660 * get_update_query_def - Parse back an UPDATE parsetree
3664 get_update_query_def(Query *query, deparse_context *context)
3666 StringInfo buf = context->buf;
3671 /* Insert the WITH clause if given */
3672 get_with_clause(query, context);
3675 * Start the query with UPDATE relname SET
3677 rte = rt_fetch(query->resultRelation, query->rtable);
3678 Assert(rte->rtekind == RTE_RELATION);
3679 if (PRETTY_INDENT(context))
3681 appendStringInfoChar(buf, ' ');
3682 context->indentLevel += PRETTYINDENT_STD;
3684 appendStringInfo(buf, "UPDATE %s%s",
3686 generate_relation_name(rte->relid, NIL));
3687 if (rte->alias != NULL)
3688 appendStringInfo(buf, " %s",
3689 quote_identifier(rte->alias->aliasname));
3690 appendStringInfoString(buf, " SET ");
3692 /* Add the comma separated list of 'attname = value' */
3694 foreach(l, query->targetList)
3696 TargetEntry *tle = (TargetEntry *) lfirst(l);
3700 continue; /* ignore junk entries */
3702 appendStringInfoString(buf, sep);
3706 * Put out name of target column; look in the catalogs, not at
3707 * tle->resname, since resname will fail to track RENAME.
3709 appendStringInfoString(buf,
3710 quote_identifier(get_relid_attribute_name(rte->relid,
3714 * Print any indirection needed (subfields or subscripts), and strip
3715 * off the top-level nodes representing the indirection assignments.
3717 expr = processIndirection((Node *) tle->expr, context, true);
3719 appendStringInfo(buf, " = ");
3721 get_rule_expr(expr, context, false);
3724 /* Add the FROM clause if needed */
3725 get_from_clause(query, " FROM ", context);
3727 /* Add a WHERE clause if given */
3728 if (query->jointree->quals != NULL)
3730 appendContextKeyword(context, " WHERE ",
3731 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3732 get_rule_expr(query->jointree->quals, context, false);
3735 /* Add RETURNING if present */
3736 if (query->returningList)
3738 appendContextKeyword(context, " RETURNING",
3739 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3740 get_target_list(query->returningList, context, NULL);
3746 * get_delete_query_def - Parse back a DELETE parsetree
3750 get_delete_query_def(Query *query, deparse_context *context)
3752 StringInfo buf = context->buf;
3755 /* Insert the WITH clause if given */
3756 get_with_clause(query, context);
3759 * Start the query with DELETE FROM relname
3761 rte = rt_fetch(query->resultRelation, query->rtable);
3762 Assert(rte->rtekind == RTE_RELATION);
3763 if (PRETTY_INDENT(context))
3765 appendStringInfoChar(buf, ' ');
3766 context->indentLevel += PRETTYINDENT_STD;
3768 appendStringInfo(buf, "DELETE FROM %s%s",
3770 generate_relation_name(rte->relid, NIL));
3771 if (rte->alias != NULL)
3772 appendStringInfo(buf, " %s",
3773 quote_identifier(rte->alias->aliasname));
3775 /* Add the USING clause if given */
3776 get_from_clause(query, " USING ", context);
3778 /* Add a WHERE clause if given */
3779 if (query->jointree->quals != NULL)
3781 appendContextKeyword(context, " WHERE ",
3782 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3783 get_rule_expr(query->jointree->quals, context, false);
3786 /* Add RETURNING if present */
3787 if (query->returningList)
3789 appendContextKeyword(context, " RETURNING",
3790 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3791 get_target_list(query->returningList, context, NULL);
3797 * get_utility_query_def - Parse back a UTILITY parsetree
3801 get_utility_query_def(Query *query, deparse_context *context)
3803 StringInfo buf = context->buf;
3805 if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
3807 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
3809 appendContextKeyword(context, "",
3810 0, PRETTYINDENT_STD, 1);
3811 appendStringInfo(buf, "NOTIFY %s",
3812 quote_identifier(stmt->conditionname));
3815 appendStringInfoString(buf, ", ");
3816 simple_quote_literal(buf, stmt->payload);
3821 /* Currently only NOTIFY utility commands can appear in rules */
3822 elog(ERROR, "unexpected utility statement type");
3828 * Display a Var appropriately.
3830 * In some cases (currently only when recursing into an unnamed join)
3831 * the Var's varlevelsup has to be interpreted with respect to a context
3832 * above the current one; levelsup indicates the offset.
3834 * If istoplevel is TRUE, the Var is at the top level of a SELECT's
3835 * targetlist, which means we need special treatment of whole-row Vars.
3836 * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
3837 * dirty hack to prevent "tab.*" from being expanded into multiple columns.
3838 * (The parser will strip the useless coercion, so no inefficiency is added in
3839 * dump and reload.) We used to print just "tab" in such cases, but that is
3840 * ambiguous and will yield the wrong result if "tab" is also a plain column
3841 * name in the query.
3843 * Returns the attname of the Var, or NULL if the Var has no attname (because
3844 * it is a whole-row Var).
3847 get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
3849 StringInfo buf = context->buf;
3853 deparse_namespace *dpns;
3858 /* Find appropriate nesting depth */
3859 netlevelsup = var->varlevelsup + levelsup;
3860 if (netlevelsup >= list_length(context->namespaces))
3861 elog(ERROR, "bogus varlevelsup: %d offset %d",
3862 var->varlevelsup, levelsup);
3863 dpns = (deparse_namespace *) list_nth(context->namespaces,
3867 * Try to find the relevant RTE in this rtable. In a plan tree, it's
3868 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
3869 * down into the subplans, or INDEX_VAR, which is resolved similarly.
3871 if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3873 rte = rt_fetch(var->varno, dpns->rtable);
3874 attnum = var->varattno;
3876 else if (var->varno == OUTER_VAR && dpns->outer_tlist)
3879 deparse_namespace save_dpns;
3881 tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
3883 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
3885 Assert(netlevelsup == 0);
3886 push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
3889 * Force parentheses because our caller probably assumed a Var is a
3890 * simple expression.
3892 if (!IsA(tle->expr, Var))
3893 appendStringInfoChar(buf, '(');
3894 get_rule_expr((Node *) tle->expr, context, true);
3895 if (!IsA(tle->expr, Var))
3896 appendStringInfoChar(buf, ')');
3898 pop_child_plan(dpns, &save_dpns);
3901 else if (var->varno == INNER_VAR && dpns->inner_tlist)
3904 deparse_namespace save_dpns;
3906 tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
3908 elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
3910 Assert(netlevelsup == 0);
3911 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3914 * Force parentheses because our caller probably assumed a Var is a
3915 * simple expression.
3917 if (!IsA(tle->expr, Var))
3918 appendStringInfoChar(buf, '(');
3919 get_rule_expr((Node *) tle->expr, context, true);
3920 if (!IsA(tle->expr, Var))
3921 appendStringInfoChar(buf, ')');
3923 pop_child_plan(dpns, &save_dpns);
3926 else if (var->varno == INDEX_VAR && dpns->index_tlist)
3930 tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
3932 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
3934 Assert(netlevelsup == 0);
3937 * Force parentheses because our caller probably assumed a Var is a
3938 * simple expression.
3940 if (!IsA(tle->expr, Var))
3941 appendStringInfoChar(buf, '(');
3942 get_rule_expr((Node *) tle->expr, context, true);
3943 if (!IsA(tle->expr, Var))
3944 appendStringInfoChar(buf, ')');
3950 elog(ERROR, "bogus varno: %d", var->varno);
3951 return NULL; /* keep compiler quiet */
3955 * The planner will sometimes emit Vars referencing resjunk elements of a
3956 * subquery's target list (this is currently only possible if it chooses
3957 * to generate a "physical tlist" for a SubqueryScan or CteScan node).
3958 * Although we prefer to print subquery-referencing Vars using the
3959 * subquery's alias, that's not possible for resjunk items since they have
3960 * no alias. So in that case, drill down to the subplan and print the
3961 * contents of the referenced tlist item. This works because in a plan
3962 * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
3963 * we'll have set dpns->inner_planstate to reference the child plan node.
3965 if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
3966 attnum > list_length(rte->eref->colnames) &&
3967 dpns->inner_planstate)
3970 deparse_namespace save_dpns;
3972 tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
3974 elog(ERROR, "bogus varattno for subquery var: %d", var->varattno);
3976 Assert(netlevelsup == 0);
3977 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3980 * Force parentheses because our caller probably assumed a Var is a
3981 * simple expression.
3983 if (!IsA(tle->expr, Var))
3984 appendStringInfoChar(buf, '(');
3985 get_rule_expr((Node *) tle->expr, context, true);
3986 if (!IsA(tle->expr, Var))
3987 appendStringInfoChar(buf, ')');
3989 pop_child_plan(dpns, &save_dpns);
3993 /* Identify names to use */
3994 schemaname = NULL; /* default assumptions */
3995 refname = rte->eref->aliasname;
3997 /* Exceptions occur only if the RTE is alias-less */
3998 if (rte->alias == NULL)
4000 if (rte->rtekind == RTE_RELATION)
4003 * It's possible that use of the bare refname would find another
4004 * more-closely-nested RTE, or be ambiguous, in which case we need
4005 * to specify the schemaname to avoid these errors.
4007 if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
4008 schemaname = get_namespace_name(get_rel_namespace(rte->relid));
4010 else if (rte->rtekind == RTE_JOIN)
4013 * If it's an unnamed join, look at the expansion of the alias
4014 * variable. If it's a simple reference to one of the input vars
4015 * then recursively print the name of that var, instead. (This
4016 * allows correct decompiling of cases where there are identically
4017 * named columns on both sides of the join.) When it's not a
4018 * simple reference, we have to just print the unqualified
4019 * variable name (this can only happen with columns that were
4020 * merged by USING or NATURAL clauses).
4022 * This wouldn't work in decompiling plan trees, because we don't
4023 * store joinaliasvars lists after planning; but a plan tree
4024 * should never contain a join alias variable.
4026 if (rte->joinaliasvars == NIL)
4027 elog(ERROR, "cannot decompile join alias var in plan tree");
4032 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
4033 if (IsA(aliasvar, Var))
4035 return get_variable(aliasvar, var->varlevelsup + levelsup,
4036 istoplevel, context);
4041 * Unnamed join has neither schemaname nor refname. (Note: since
4042 * it's unnamed, there is no way the user could have referenced it
4043 * to create a whole-row Var for it. So we don't have to cover
4050 if (attnum == InvalidAttrNumber)
4053 attname = get_rte_attribute_name(rte, attnum);
4055 if (refname && (context->varprefix || attname == NULL))
4058 appendStringInfo(buf, "%s.",
4059 quote_identifier(schemaname));
4060 appendStringInfoString(buf, quote_identifier(refname));
4061 appendStringInfoChar(buf, '.');
4064 appendStringInfoString(buf, quote_identifier(attname));
4067 appendStringInfoChar(buf, '*');
4069 appendStringInfo(buf, "::%s",
4070 format_type_with_typemod(var->vartype,
4079 * Get the name of a field of an expression of composite type. The
4080 * expression is usually a Var, but we handle other cases too.
4082 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
4084 * This is fairly straightforward when the expression has a named composite
4085 * type; we need only look up the type in the catalogs. However, the type
4086 * could also be RECORD. Since no actual table or view column is allowed to
4087 * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
4088 * or to a subquery output. We drill down to find the ultimate defining
4089 * expression and attempt to infer the field name from it. We ereport if we
4090 * can't determine the name.
4092 * Similarly, a PARAM of type RECORD has to refer to some expression of
4093 * a determinable composite type.
4096 get_name_for_var_field(Var *var, int fieldno,
4097 int levelsup, deparse_context *context)
4102 deparse_namespace *dpns;
4103 TupleDesc tupleDesc;
4107 * If it's a RowExpr that was expanded from a whole-row Var, use the
4108 * column names attached to it.
4110 if (IsA(var, RowExpr))
4112 RowExpr *r = (RowExpr *) var;
4114 if (fieldno > 0 && fieldno <= list_length(r->colnames))
4115 return strVal(list_nth(r->colnames, fieldno - 1));
4119 * If it's a Param of type RECORD, try to find what the Param refers to.
4121 if (IsA(var, Param))
4123 Param *param = (Param *) var;
4124 ListCell *ancestor_cell;
4126 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
4129 /* Found a match, so recurse to decipher the field name */
4130 deparse_namespace save_dpns;
4133 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
4134 result = get_name_for_var_field((Var *) expr, fieldno,
4136 pop_ancestor_plan(dpns, &save_dpns);
4142 * If it's a Var of type RECORD, we have to find what the Var refers to;
4143 * if not, we can use get_expr_result_type. If that fails, we try
4144 * lookup_rowtype_tupdesc, which will probably fail too, but will ereport
4145 * an acceptable message.
4147 if (!IsA(var, Var) ||
4148 var->vartype != RECORDOID)
4150 if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
4151 tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var),
4152 exprTypmod((Node *) var));
4154 /* Got the tupdesc, so we can extract the field name */
4155 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
4156 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
4159 /* Find appropriate nesting depth */
4160 netlevelsup = var->varlevelsup + levelsup;
4161 if (netlevelsup >= list_length(context->namespaces))
4162 elog(ERROR, "bogus varlevelsup: %d offset %d",
4163 var->varlevelsup, levelsup);
4164 dpns = (deparse_namespace *) list_nth(context->namespaces,
4168 * Try to find the relevant RTE in this rtable. In a plan tree, it's
4169 * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
4170 * down into the subplans, or INDEX_VAR, which is resolved similarly.
4172 if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
4174 rte = rt_fetch(var->varno, dpns->rtable);
4175 attnum = var->varattno;
4177 else if (var->varno == OUTER_VAR && dpns->outer_tlist)
4180 deparse_namespace save_dpns;
4183 tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
4185 elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
4187 Assert(netlevelsup == 0);
4188 push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
4190 result = get_name_for_var_field((Var *) tle->expr, fieldno,
4193 pop_child_plan(dpns, &save_dpns);
4196 else if (var->varno == INNER_VAR && dpns->inner_tlist)
4199 deparse_namespace save_dpns;
4202 tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
4204 elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
4206 Assert(netlevelsup == 0);
4207 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
4209 result = get_name_for_var_field((Var *) tle->expr, fieldno,
4212 pop_child_plan(dpns, &save_dpns);
4215 else if (var->varno == INDEX_VAR && dpns->index_tlist)
4220 tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
4222 elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
4224 Assert(netlevelsup == 0);
4226 result = get_name_for_var_field((Var *) tle->expr, fieldno,
4233 elog(ERROR, "bogus varno: %d", var->varno);
4234 return NULL; /* keep compiler quiet */
4237 if (attnum == InvalidAttrNumber)
4239 /* Var is whole-row reference to RTE, so select the right field */
4240 return get_rte_attribute_name(rte, fieldno);
4244 * This part has essentially the same logic as the parser's
4245 * expandRecordVariable() function, but we are dealing with a different
4246 * representation of the input context, and we only need one field name
4247 * not a TupleDesc. Also, we need special cases for finding subquery and
4248 * CTE subplans when deparsing Plan trees.
4250 expr = (Node *) var; /* default if we can't drill down */
4252 switch (rte->rtekind)
4258 * This case should not occur: a column of a table or values list
4259 * shouldn't have type RECORD. Fall through and fail (most
4260 * likely) at the bottom.
4264 /* Subselect-in-FROM: examine sub-select's output expr */
4268 TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
4271 if (ste == NULL || ste->resjunk)
4272 elog(ERROR, "subquery %s does not have attribute %d",
4273 rte->eref->aliasname, attnum);
4274 expr = (Node *) ste->expr;
4278 * Recurse into the sub-select to see what its Var
4279 * refers to. We have to build an additional level of
4280 * namespace to keep in step with varlevelsup in the
4283 deparse_namespace mydpns;
4286 memset(&mydpns, 0, sizeof(mydpns));
4287 mydpns.rtable = rte->subquery->rtable;
4288 mydpns.ctes = rte->subquery->cteList;
4290 context->namespaces = lcons(&mydpns,
4291 context->namespaces);
4293 result = get_name_for_var_field((Var *) expr, fieldno,
4296 context->namespaces =
4297 list_delete_first(context->namespaces);
4301 /* else fall through to inspect the expression */
4306 * We're deparsing a Plan tree so we don't have complete
4307 * RTE entries (in particular, rte->subquery is NULL). But
4308 * the only place we'd see a Var directly referencing a
4309 * SUBQUERY RTE is in a SubqueryScan plan node, and we can
4310 * look into the child plan's tlist instead.
4313 deparse_namespace save_dpns;
4316 if (!dpns->inner_planstate)
4317 elog(ERROR, "failed to find plan for subquery %s",
4318 rte->eref->aliasname);
4319 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
4321 elog(ERROR, "bogus varattno for subquery var: %d",
4323 Assert(netlevelsup == 0);
4324 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
4326 result = get_name_for_var_field((Var *) tle->expr, fieldno,
4329 pop_child_plan(dpns, &save_dpns);
4335 /* Join RTE --- recursively inspect the alias variable */
4336 if (rte->joinaliasvars == NIL)
4337 elog(ERROR, "cannot decompile join alias var in plan tree");
4338 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
4339 expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
4341 return get_name_for_var_field((Var *) expr, fieldno,
4342 var->varlevelsup + levelsup,
4344 /* else fall through to inspect the expression */
4349 * We couldn't get here unless a function is declared with one of
4350 * its result columns as RECORD, which is not allowed.
4354 /* CTE reference: examine subquery's output expr */
4356 CommonTableExpr *cte = NULL;
4361 * Try to find the referenced CTE using the namespace stack.
4363 ctelevelsup = rte->ctelevelsup + netlevelsup;
4364 if (ctelevelsup >= list_length(context->namespaces))
4368 deparse_namespace *ctedpns;
4370 ctedpns = (deparse_namespace *)
4371 list_nth(context->namespaces, ctelevelsup);
4372 foreach(lc, ctedpns->ctes)
4374 cte = (CommonTableExpr *) lfirst(lc);
4375 if (strcmp(cte->ctename, rte->ctename) == 0)
4381 Query *ctequery = (Query *) cte->ctequery;
4382 TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
4385 if (ste == NULL || ste->resjunk)
4386 elog(ERROR, "subquery %s does not have attribute %d",
4387 rte->eref->aliasname, attnum);
4388 expr = (Node *) ste->expr;
4392 * Recurse into the CTE to see what its Var refers to.
4393 * We have to build an additional level of namespace
4394 * to keep in step with varlevelsup in the CTE.
4395 * Furthermore it could be an outer CTE, so we may
4396 * have to delete some levels of namespace.
4398 List *save_nslist = context->namespaces;
4400 deparse_namespace mydpns;
4403 memset(&mydpns, 0, sizeof(mydpns));
4404 mydpns.rtable = ctequery->rtable;
4405 mydpns.ctes = ctequery->cteList;
4407 new_nslist = list_copy_tail(context->namespaces,
4409 context->namespaces = lcons(&mydpns, new_nslist);
4411 result = get_name_for_var_field((Var *) expr, fieldno,
4414 context->namespaces = save_nslist;
4418 /* else fall through to inspect the expression */
4423 * We're deparsing a Plan tree so we don't have a CTE
4424 * list. But the only place we'd see a Var directly
4425 * referencing a CTE RTE is in a CteScan plan node, and we
4426 * can look into the subplan's tlist instead.
4429 deparse_namespace save_dpns;
4432 if (!dpns->inner_planstate)
4433 elog(ERROR, "failed to find plan for CTE %s",
4434 rte->eref->aliasname);
4435 tle = get_tle_by_resno(dpns->inner_tlist, attnum);
4437 elog(ERROR, "bogus varattno for subquery var: %d",
4439 Assert(netlevelsup == 0);
4440 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
4442 result = get_name_for_var_field((Var *) tle->expr, fieldno,
4445 pop_child_plan(dpns, &save_dpns);
4453 * We now have an expression we can't expand any more, so see if
4454 * get_expr_result_type() can do anything with it. If not, pass to
4455 * lookup_rowtype_tupdesc() which will probably fail, but will give an
4456 * appropriate error message while failing.
4458 if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
4459 tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
4462 /* Got the tupdesc, so we can extract the field name */
4463 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
4464 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
4469 * find_rte_by_refname - look up an RTE by refname in a deparse context
4471 * Returns NULL if there is no matching RTE or the refname is ambiguous.
4473 * NOTE: this code is not really correct since it does not take account of
4474 * the fact that not all the RTEs in a rangetable may be visible from the
4475 * point where a Var reference appears. For the purposes we need, however,
4476 * the only consequence of a false match is that we might stick a schema
4477 * qualifier on a Var that doesn't really need it. So it seems close
4480 static RangeTblEntry *
4481 find_rte_by_refname(const char *refname, deparse_context *context)
4483 RangeTblEntry *result = NULL;
4486 foreach(nslist, context->namespaces)
4488 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
4491 foreach(rtlist, dpns->rtable)
4493 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
4495 if (strcmp(rte->eref->aliasname, refname) == 0)
4498 return NULL; /* it's ambiguous */
4509 * Try to find the referenced expression for a PARAM_EXEC Param that might
4510 * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
4512 * If successful, return the expression and set *dpns_p and *ancestor_cell_p
4513 * appropriately for calling push_ancestor_plan(). If no referent can be
4514 * found, return NULL.
4517 find_param_referent(Param *param, deparse_context *context,
4518 deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
4520 /* Initialize output parameters to prevent compiler warnings */
4522 *ancestor_cell_p = NULL;
4525 * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
4526 * SubPlan argument. This will necessarily be in some ancestor of the
4527 * current expression's PlanState.
4529 if (param->paramkind == PARAM_EXEC)
4531 deparse_namespace *dpns;
4532 PlanState *child_ps;
4533 bool in_same_plan_level;
4536 dpns = (deparse_namespace *) linitial(context->namespaces);
4537 child_ps = dpns->planstate;
4538 in_same_plan_level = true;
4540 foreach(lc, dpns->ancestors)
4542 PlanState *ps = (PlanState *) lfirst(lc);
4546 * NestLoops transmit params to their inner child only; also, once
4547 * we've crawled up out of a subplan, this couldn't possibly be
4550 if (IsA(ps, NestLoopState) &&
4551 child_ps == innerPlanState(ps) &&
4554 NestLoop *nl = (NestLoop *) ps->plan;
4556 foreach(lc2, nl->nestParams)
4558 NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
4560 if (nlp->paramno == param->paramid)
4562 /* Found a match, so return it */
4564 *ancestor_cell_p = lc;
4565 return (Node *) nlp->paramval;
4571 * Check to see if we're crawling up from a subplan.
4573 foreach(lc2, ps->subPlan)
4575 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
4576 SubPlan *subplan = (SubPlan *) sstate->xprstate.expr;
4580 if (child_ps != sstate->planstate)
4583 /* Matched subplan, so check its arguments */
4584 forboth(lc3, subplan->parParam, lc4, subplan->args)
4586 int paramid = lfirst_int(lc3);
4587 Node *arg = (Node *) lfirst(lc4);
4589 if (paramid == param->paramid)
4591 /* Found a match, so return it */
4593 *ancestor_cell_p = lc;
4598 /* Keep looking, but we are emerging from a subplan. */
4599 in_same_plan_level = false;
4604 * Likewise check to see if we're emerging from an initplan.
4605 * Initplans never have any parParams, so no need to search that
4606 * list, but we need to know if we should reset
4607 * in_same_plan_level.
4609 foreach(lc2, ps->initPlan)
4611 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
4613 if (child_ps != sstate->planstate)
4616 /* No parameters to be had here. */
4617 Assert(((SubPlan *) sstate->xprstate.expr)->parParam == NIL);
4619 /* Keep looking, but we are emerging from an initplan. */
4620 in_same_plan_level = false;
4624 /* No luck, crawl up to next ancestor */
4629 /* No referent found */
4634 * Display a Param appropriately.
4637 get_parameter(Param *param, deparse_context *context)
4640 deparse_namespace *dpns;
4641 ListCell *ancestor_cell;
4644 * If it's a PARAM_EXEC parameter, try to locate the expression from which
4645 * the parameter was computed. Note that failing to find a referent isn't
4646 * an error, since the Param might well be a subplan output rather than an
4649 expr = find_param_referent(param, context, &dpns, &ancestor_cell);
4652 /* Found a match, so print it */
4653 deparse_namespace save_dpns;
4654 bool save_varprefix;
4657 /* Switch attention to the ancestor plan node */
4658 push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
4661 * Force prefixing of Vars, since they won't belong to the relation
4662 * being scanned in the original plan node.
4664 save_varprefix = context->varprefix;
4665 context->varprefix = true;
4668 * A Param's expansion is typically a Var, Aggref, or upper-level
4669 * Param, which wouldn't need extra parentheses. Otherwise, insert
4670 * parens to ensure the expression looks atomic.
4672 need_paren = !(IsA(expr, Var) ||
4673 IsA(expr, Aggref) ||
4676 appendStringInfoChar(context->buf, '(');
4678 get_rule_expr(expr, context, false);
4681 appendStringInfoChar(context->buf, ')');
4683 context->varprefix = save_varprefix;
4685 pop_ancestor_plan(dpns, &save_dpns);
4691 * Not PARAM_EXEC, or couldn't find referent: just print $N.
4693 appendStringInfo(context->buf, "$%d", param->paramid);
4697 * get_simple_binary_op_name
4699 * helper function for isSimpleNode
4700 * will return single char binary operator name, or NULL if it's not
4703 get_simple_binary_op_name(OpExpr *expr)
4705 List *args = expr->args;
4707 if (list_length(args) == 2)
4709 /* binary operator */
4710 Node *arg1 = (Node *) linitial(args);
4711 Node *arg2 = (Node *) lsecond(args);
4714 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
4715 if (strlen(op) == 1)
4723 * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
4725 * true : simple in the context of parent node's type
4726 * false : not simple
4729 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
4734 switch (nodeTag(node))
4739 case T_CoerceToDomainValue:
4740 case T_SetToDefault:
4741 case T_CurrentOfExpr:
4742 /* single words: always simple */
4748 case T_CoalesceExpr:
4755 /* function-like: name(..) or name[..] */
4758 /* CASE keywords act as parentheses */
4765 * appears simple since . has top precedence, unless parent is
4766 * T_FieldSelect itself!
4768 return (IsA(parentNode, FieldSelect) ? false : true);
4773 * treat like FieldSelect (probably doesn't matter)
4775 return (IsA(parentNode, FieldStore) ? false : true);
4777 case T_CoerceToDomain:
4778 /* maybe simple, check args */
4779 return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
4782 return isSimpleNode((Node *) ((RelabelType *) node)->arg,
4785 return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
4787 case T_ArrayCoerceExpr:
4788 return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
4790 case T_ConvertRowtypeExpr:
4791 return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
4796 /* depends on parent node type; needs further checking */
4797 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
4800 const char *parentOp;
4803 bool is_lopriparent;
4804 bool is_hipriparent;
4806 op = get_simple_binary_op_name((OpExpr *) node);
4810 /* We know only the basic operators + - and * / % */
4811 is_lopriop = (strchr("+-", *op) != NULL);
4812 is_hipriop = (strchr("*/%", *op) != NULL);
4813 if (!(is_lopriop || is_hipriop))
4816 parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
4820 is_lopriparent = (strchr("+-", *parentOp) != NULL);
4821 is_hipriparent = (strchr("*/%", *parentOp) != NULL);
4822 if (!(is_lopriparent || is_hipriparent))
4825 if (is_hipriop && is_lopriparent)
4826 return true; /* op binds tighter than parent */
4828 if (is_lopriop && is_hipriparent)
4832 * Operators are same priority --- can skip parens only if
4833 * we have (a - b) - c, not a - (b - c).
4835 if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
4840 /* else do the same stuff as for T_SubLink et al. */
4847 case T_DistinctExpr:
4848 switch (nodeTag(parentNode))
4852 /* special handling for casts */
4853 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4855 if (type == COERCE_EXPLICIT_CAST ||
4856 type == COERCE_IMPLICIT_CAST)
4858 return true; /* own parentheses */
4860 case T_BoolExpr: /* lower precedence */
4861 case T_ArrayRef: /* other separators */
4862 case T_ArrayExpr: /* other separators */
4863 case T_RowExpr: /* other separators */
4864 case T_CoalesceExpr: /* own parentheses */
4865 case T_MinMaxExpr: /* own parentheses */
4866 case T_XmlExpr: /* own parentheses */
4867 case T_NullIfExpr: /* other separators */
4868 case T_Aggref: /* own parentheses */
4869 case T_WindowFunc: /* own parentheses */
4870 case T_CaseExpr: /* other separators */
4877 switch (nodeTag(parentNode))
4880 if (prettyFlags & PRETTYFLAG_PAREN)
4883 BoolExprType parentType;
4885 type = ((BoolExpr *) node)->boolop;
4886 parentType = ((BoolExpr *) parentNode)->boolop;
4891 if (parentType == AND_EXPR || parentType == OR_EXPR)
4895 if (parentType == OR_EXPR)
4903 /* special handling for casts */
4904 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4906 if (type == COERCE_EXPLICIT_CAST ||
4907 type == COERCE_IMPLICIT_CAST)
4909 return true; /* own parentheses */
4911 case T_ArrayRef: /* other separators */
4912 case T_ArrayExpr: /* other separators */
4913 case T_RowExpr: /* other separators */
4914 case T_CoalesceExpr: /* own parentheses */
4915 case T_MinMaxExpr: /* own parentheses */
4916 case T_XmlExpr: /* own parentheses */
4917 case T_NullIfExpr: /* other separators */
4918 case T_Aggref: /* own parentheses */
4919 case T_WindowFunc: /* own parentheses */
4920 case T_CaseExpr: /* other separators */
4929 /* those we don't know: in dubio complexo */
4935 * appendContextKeyword - append a keyword to buffer
4937 * If prettyPrint is enabled, perform a line break, and adjust indentation.
4938 * Otherwise, just append the keyword.
4941 appendContextKeyword(deparse_context *context, const char *str,
4942 int indentBefore, int indentAfter, int indentPlus)
4944 if (PRETTY_INDENT(context))
4946 context->indentLevel += indentBefore;
4948 appendStringInfoChar(context->buf, '\n');
4949 appendStringInfoSpaces(context->buf,
4950 Max(context->indentLevel, 0) + indentPlus);
4951 appendStringInfoString(context->buf, str);
4953 context->indentLevel += indentAfter;
4954 if (context->indentLevel < 0)
4955 context->indentLevel = 0;
4958 appendStringInfoString(context->buf, str);
4962 * get_rule_expr_paren - deparse expr using get_rule_expr,
4963 * embracing the string with parentheses if necessary for prettyPrint.
4965 * Never embrace if prettyFlags=0, because it's done in the calling node.
4967 * Any node that does *not* embrace its argument node by sql syntax (with
4968 * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
4969 * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
4973 get_rule_expr_paren(Node *node, deparse_context *context,
4974 bool showimplicit, Node *parentNode)
4978 need_paren = PRETTY_PAREN(context) &&
4979 !isSimpleNode(node, parentNode, context->prettyFlags);
4982 appendStringInfoChar(context->buf, '(');
4984 get_rule_expr(node, context, showimplicit);
4987 appendStringInfoChar(context->buf, ')');
4992 * get_rule_expr - Parse back an expression
4994 * Note: showimplicit determines whether we display any implicit cast that
4995 * is present at the top of the expression tree. It is a passed argument,
4996 * not a field of the context struct, because we change the value as we
4997 * recurse down into the expression. In general we suppress implicit casts
4998 * when the result type is known with certainty (eg, the arguments of an
4999 * OR must be boolean). We display implicit casts for arguments of functions
5000 * and operators, since this is needed to be certain that the same function
5001 * or operator will be chosen when the expression is re-parsed.
5005 get_rule_expr(Node *node, deparse_context *context,
5008 StringInfo buf = context->buf;
5014 * Each level of get_rule_expr must emit an indivisible term
5015 * (parenthesized if necessary) to ensure result is reparsed into the same
5016 * expression tree. The only exception is that when the input is a List,
5017 * we emit the component items comma-separated with no surrounding
5018 * decoration; this is convenient for most callers.
5020 switch (nodeTag(node))
5023 (void) get_variable((Var *) node, 0, false, context);
5027 get_const_expr((Const *) node, context, 0);
5031 get_parameter((Param *) node, context);
5035 get_agg_expr((Aggref *) node, context);
5039 get_windowfunc_expr((WindowFunc *) node, context);
5044 ArrayRef *aref = (ArrayRef *) node;
5048 * If the argument is a CaseTestExpr, we must be inside a
5049 * FieldStore, ie, we are assigning to an element of an array
5050 * within a composite column. Since we already punted on
5051 * displaying the FieldStore's target information, just punt
5052 * here too, and display only the assignment source
5055 if (IsA(aref->refexpr, CaseTestExpr))
5057 Assert(aref->refassgnexpr);
5058 get_rule_expr((Node *) aref->refassgnexpr,
5059 context, showimplicit);
5064 * Parenthesize the argument unless it's a simple Var or a
5065 * FieldSelect. (In particular, if it's another ArrayRef, we
5066 * *must* parenthesize to avoid confusion.)
5068 need_parens = !IsA(aref->refexpr, Var) &&
5069 !IsA(aref->refexpr, FieldSelect);
5071 appendStringInfoChar(buf, '(');
5072 get_rule_expr((Node *) aref->refexpr, context, showimplicit);
5074 appendStringInfoChar(buf, ')');
5077 * If there's a refassgnexpr, we want to print the node in the
5078 * format "array[subscripts] := refassgnexpr". This is not
5079 * legal SQL, so decompilation of INSERT or UPDATE statements
5080 * should always use processIndirection as part of the
5081 * statement-level syntax. We should only see this when
5082 * EXPLAIN tries to print the targetlist of a plan resulting
5083 * from such a statement.
5085 if (aref->refassgnexpr)
5090 * Use processIndirection to print this node's subscripts
5091 * as well as any additional field selections or
5092 * subscripting in immediate descendants. It returns the
5093 * RHS expr that is actually being "assigned".
5095 refassgnexpr = processIndirection(node, context, true);
5096 appendStringInfoString(buf, " := ");
5097 get_rule_expr(refassgnexpr, context, showimplicit);
5101 /* Just an ordinary array fetch, so print subscripts */
5102 printSubscripts(aref, context);
5108 get_func_expr((FuncExpr *) node, context, showimplicit);
5111 case T_NamedArgExpr:
5113 NamedArgExpr *na = (NamedArgExpr *) node;
5115 appendStringInfo(buf, "%s := ", quote_identifier(na->name));
5116 get_rule_expr((Node *) na->arg, context, showimplicit);
5121 get_oper_expr((OpExpr *) node, context);
5124 case T_DistinctExpr:
5126 DistinctExpr *expr = (DistinctExpr *) node;
5127 List *args = expr->args;
5128 Node *arg1 = (Node *) linitial(args);
5129 Node *arg2 = (Node *) lsecond(args);
5131 if (!PRETTY_PAREN(context))
5132 appendStringInfoChar(buf, '(');
5133 get_rule_expr_paren(arg1, context, true, node);
5134 appendStringInfo(buf, " IS DISTINCT FROM ");
5135 get_rule_expr_paren(arg2, context, true, node);
5136 if (!PRETTY_PAREN(context))
5137 appendStringInfoChar(buf, ')');
5143 NullIfExpr *nullifexpr = (NullIfExpr *) node;
5145 appendStringInfo(buf, "NULLIF(");
5146 get_rule_expr((Node *) nullifexpr->args, context, true);
5147 appendStringInfoChar(buf, ')');
5151 case T_ScalarArrayOpExpr:
5153 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
5154 List *args = expr->args;
5155 Node *arg1 = (Node *) linitial(args);
5156 Node *arg2 = (Node *) lsecond(args);
5158 if (!PRETTY_PAREN(context))
5159 appendStringInfoChar(buf, '(');
5160 get_rule_expr_paren(arg1, context, true, node);
5161 appendStringInfo(buf, " %s %s (",
5162 generate_operator_name(expr->opno,
5164 get_base_element_type(exprType(arg2))),
5165 expr->useOr ? "ANY" : "ALL");
5166 get_rule_expr_paren(arg2, context, true, node);
5167 appendStringInfoChar(buf, ')');
5168 if (!PRETTY_PAREN(context))
5169 appendStringInfoChar(buf, ')');
5175 BoolExpr *expr = (BoolExpr *) node;
5176 Node *first_arg = linitial(expr->args);
5177 ListCell *arg = lnext(list_head(expr->args));
5179 switch (expr->boolop)
5182 if (!PRETTY_PAREN(context))
5183 appendStringInfoChar(buf, '(');
5184 get_rule_expr_paren(first_arg, context,
5188 appendStringInfo(buf, " AND ");
5189 get_rule_expr_paren((Node *) lfirst(arg), context,
5193 if (!PRETTY_PAREN(context))
5194 appendStringInfoChar(buf, ')');
5198 if (!PRETTY_PAREN(context))
5199 appendStringInfoChar(buf, '(');
5200 get_rule_expr_paren(first_arg, context,
5204 appendStringInfo(buf, " OR ");
5205 get_rule_expr_paren((Node *) lfirst(arg), context,
5209 if (!PRETTY_PAREN(context))
5210 appendStringInfoChar(buf, ')');
5214 if (!PRETTY_PAREN(context))
5215 appendStringInfoChar(buf, '(');
5216 appendStringInfo(buf, "NOT ");
5217 get_rule_expr_paren(first_arg, context,
5219 if (!PRETTY_PAREN(context))
5220 appendStringInfoChar(buf, ')');
5224 elog(ERROR, "unrecognized boolop: %d",
5225 (int) expr->boolop);
5231 get_sublink_expr((SubLink *) node, context);
5236 SubPlan *subplan = (SubPlan *) node;
5239 * We cannot see an already-planned subplan in rule deparsing,
5240 * only while EXPLAINing a query plan. We don't try to
5241 * reconstruct the original SQL, just reference the subplan
5242 * that appears elsewhere in EXPLAIN's result.
5244 if (subplan->useHashTable)
5245 appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
5247 appendStringInfo(buf, "(%s)", subplan->plan_name);
5251 case T_AlternativeSubPlan:
5253 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
5256 /* As above, this can only happen during EXPLAIN */
5257 appendStringInfo(buf, "(alternatives: ");
5258 foreach(lc, asplan->subplans)
5260 SubPlan *splan = (SubPlan *) lfirst(lc);
5262 Assert(IsA(splan, SubPlan));
5263 if (splan->useHashTable)
5264 appendStringInfo(buf, "hashed %s", splan->plan_name);
5266 appendStringInfo(buf, "%s", splan->plan_name);
5268 appendStringInfo(buf, " or ");
5270 appendStringInfo(buf, ")");
5276 FieldSelect *fselect = (FieldSelect *) node;
5277 Node *arg = (Node *) fselect->arg;
5278 int fno = fselect->fieldnum;
5279 const char *fieldname;
5283 * Parenthesize the argument unless it's an ArrayRef or
5284 * another FieldSelect. Note in particular that it would be
5285 * WRONG to not parenthesize a Var argument; simplicity is not
5286 * the issue here, having the right number of names is.
5288 need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect);
5290 appendStringInfoChar(buf, '(');
5291 get_rule_expr(arg, context, true);
5293 appendStringInfoChar(buf, ')');
5296 * Get and print the field name.
5298 fieldname = get_name_for_var_field((Var *) arg, fno,
5300 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
5306 FieldStore *fstore = (FieldStore *) node;
5310 * There is no good way to represent a FieldStore as real SQL,
5311 * so decompilation of INSERT or UPDATE statements should
5312 * always use processIndirection as part of the
5313 * statement-level syntax. We should only get here when
5314 * EXPLAIN tries to print the targetlist of a plan resulting
5315 * from such a statement. The plan case is even harder than
5316 * ordinary rules would be, because the planner tries to
5317 * collapse multiple assignments to the same field or subfield
5318 * into one FieldStore; so we can see a list of target fields
5319 * not just one, and the arguments could be FieldStores
5320 * themselves. We don't bother to try to print the target
5321 * field names; we just print the source arguments, with a
5322 * ROW() around them if there's more than one. This isn't
5323 * terribly complete, but it's probably good enough for
5324 * EXPLAIN's purposes; especially since anything more would be
5325 * either hopelessly confusing or an even poorer
5326 * representation of what the plan is actually doing.
5328 need_parens = (list_length(fstore->newvals) != 1);
5330 appendStringInfoString(buf, "ROW(");
5331 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
5333 appendStringInfoChar(buf, ')');
5339 RelabelType *relabel = (RelabelType *) node;
5340 Node *arg = (Node *) relabel->arg;
5342 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
5345 /* don't show the implicit cast */
5346 get_rule_expr_paren(arg, context, false, node);
5350 get_coercion_expr(arg, context,
5351 relabel->resulttype,
5352 relabel->resulttypmod,
5360 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
5361 Node *arg = (Node *) iocoerce->arg;
5363 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
5366 /* don't show the implicit cast */
5367 get_rule_expr_paren(arg, context, false, node);
5371 get_coercion_expr(arg, context,
5372 iocoerce->resulttype,
5379 case T_ArrayCoerceExpr:
5381 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
5382 Node *arg = (Node *) acoerce->arg;
5384 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
5387 /* don't show the implicit cast */
5388 get_rule_expr_paren(arg, context, false, node);
5392 get_coercion_expr(arg, context,
5393 acoerce->resulttype,
5394 acoerce->resulttypmod,
5400 case T_ConvertRowtypeExpr:
5402 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
5403 Node *arg = (Node *) convert->arg;
5405 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
5408 /* don't show the implicit cast */
5409 get_rule_expr_paren(arg, context, false, node);
5413 get_coercion_expr(arg, context,
5414 convert->resulttype, -1,
5422 CollateExpr *collate = (CollateExpr *) node;
5423 Node *arg = (Node *) collate->arg;
5425 if (!PRETTY_PAREN(context))
5426 appendStringInfoChar(buf, '(');
5427 get_rule_expr_paren(arg, context, showimplicit, node);
5428 appendStringInfo(buf, " COLLATE %s",
5429 generate_collation_name(collate->collOid));
5430 if (!PRETTY_PAREN(context))
5431 appendStringInfoChar(buf, ')');
5437 CaseExpr *caseexpr = (CaseExpr *) node;
5440 appendContextKeyword(context, "CASE",
5441 0, PRETTYINDENT_VAR, 0);
5444 appendStringInfoChar(buf, ' ');
5445 get_rule_expr((Node *) caseexpr->arg, context, true);
5447 foreach(temp, caseexpr->args)
5449 CaseWhen *when = (CaseWhen *) lfirst(temp);
5450 Node *w = (Node *) when->expr;
5455 * The parser should have produced WHEN clauses of the
5456 * form "CaseTestExpr = RHS", possibly with an
5457 * implicit coercion inserted above the CaseTestExpr.
5458 * For accurate decompilation of rules it's essential
5459 * that we show just the RHS. However in an
5460 * expression that's been through the optimizer, the
5461 * WHEN clause could be almost anything (since the
5462 * equality operator could have been expanded into an
5463 * inline function). If we don't recognize the form
5464 * of the WHEN clause, just punt and display it as-is.
5468 List *args = ((OpExpr *) w)->args;
5470 if (list_length(args) == 2 &&
5471 IsA(strip_implicit_coercions(linitial(args)),
5473 w = (Node *) lsecond(args);
5477 if (!PRETTY_INDENT(context))
5478 appendStringInfoChar(buf, ' ');
5479 appendContextKeyword(context, "WHEN ",
5481 get_rule_expr(w, context, false);
5482 appendStringInfo(buf, " THEN ");
5483 get_rule_expr((Node *) when->result, context, true);
5485 if (!PRETTY_INDENT(context))
5486 appendStringInfoChar(buf, ' ');
5487 appendContextKeyword(context, "ELSE ",
5489 get_rule_expr((Node *) caseexpr->defresult, context, true);
5490 if (!PRETTY_INDENT(context))
5491 appendStringInfoChar(buf, ' ');
5492 appendContextKeyword(context, "END",
5493 -PRETTYINDENT_VAR, 0, 0);
5497 case T_CaseTestExpr:
5500 * Normally we should never get here, since for expressions
5501 * that can contain this node type we attempt to avoid
5502 * recursing to it. But in an optimized expression we might
5503 * be unable to avoid that (see comments for CaseExpr). If we
5504 * do see one, print it as CASE_TEST_EXPR.
5506 appendStringInfo(buf, "CASE_TEST_EXPR");
5512 ArrayExpr *arrayexpr = (ArrayExpr *) node;
5514 appendStringInfo(buf, "ARRAY[");
5515 get_rule_expr((Node *) arrayexpr->elements, context, true);
5516 appendStringInfoChar(buf, ']');
5519 * If the array isn't empty, we assume its elements are
5520 * coerced to the desired type. If it's empty, though, we
5521 * need an explicit coercion to the array type.
5523 if (arrayexpr->elements == NIL)
5524 appendStringInfo(buf, "::%s",
5525 format_type_with_typemod(arrayexpr->array_typeid, -1));
5531 RowExpr *rowexpr = (RowExpr *) node;
5532 TupleDesc tupdesc = NULL;
5538 * If it's a named type and not RECORD, we may have to skip
5539 * dropped columns and/or claim there are NULLs for added
5542 if (rowexpr->row_typeid != RECORDOID)
5544 tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
5545 Assert(list_length(rowexpr->args) <= tupdesc->natts);
5549 * SQL99 allows "ROW" to be omitted when there is more than
5550 * one column, but for simplicity we always print it.
5552 appendStringInfo(buf, "ROW(");
5555 foreach(arg, rowexpr->args)
5557 Node *e = (Node *) lfirst(arg);
5559 if (tupdesc == NULL ||
5560 !tupdesc->attrs[i]->attisdropped)
5562 appendStringInfoString(buf, sep);
5563 get_rule_expr(e, context, true);
5568 if (tupdesc != NULL)
5570 while (i < tupdesc->natts)
5572 if (!tupdesc->attrs[i]->attisdropped)
5574 appendStringInfoString(buf, sep);
5575 appendStringInfo(buf, "NULL");
5581 ReleaseTupleDesc(tupdesc);
5583 appendStringInfo(buf, ")");
5584 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
5585 appendStringInfo(buf, "::%s",
5586 format_type_with_typemod(rowexpr->row_typeid, -1));
5590 case T_RowCompareExpr:
5592 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
5597 * SQL99 allows "ROW" to be omitted when there is more than
5598 * one column, but for simplicity we always print it.
5600 appendStringInfo(buf, "(ROW(");
5602 foreach(arg, rcexpr->largs)
5604 Node *e = (Node *) lfirst(arg);
5606 appendStringInfoString(buf, sep);
5607 get_rule_expr(e, context, true);
5612 * We assume that the name of the first-column operator will
5613 * do for all the rest too. This is definitely open to
5614 * failure, eg if some but not all operators were renamed
5615 * since the construct was parsed, but there seems no way to
5618 appendStringInfo(buf, ") %s ROW(",
5619 generate_operator_name(linitial_oid(rcexpr->opnos),
5620 exprType(linitial(rcexpr->largs)),
5621 exprType(linitial(rcexpr->rargs))));
5623 foreach(arg, rcexpr->rargs)
5625 Node *e = (Node *) lfirst(arg);
5627 appendStringInfoString(buf, sep);
5628 get_rule_expr(e, context, true);
5631 appendStringInfo(buf, "))");
5635 case T_CoalesceExpr:
5637 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
5639 appendStringInfo(buf, "COALESCE(");
5640 get_rule_expr((Node *) coalesceexpr->args, context, true);
5641 appendStringInfoChar(buf, ')');
5647 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
5649 switch (minmaxexpr->op)
5652 appendStringInfo(buf, "GREATEST(");
5655 appendStringInfo(buf, "LEAST(");
5658 get_rule_expr((Node *) minmaxexpr->args, context, true);
5659 appendStringInfoChar(buf, ')');
5665 XmlExpr *xexpr = (XmlExpr *) node;
5666 bool needcomma = false;
5674 appendStringInfoString(buf, "XMLCONCAT(");
5677 appendStringInfoString(buf, "XMLELEMENT(");
5680 appendStringInfoString(buf, "XMLFOREST(");
5683 appendStringInfoString(buf, "XMLPARSE(");
5686 appendStringInfoString(buf, "XMLPI(");
5689 appendStringInfoString(buf, "XMLROOT(");
5691 case IS_XMLSERIALIZE:
5692 appendStringInfoString(buf, "XMLSERIALIZE(");
5697 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
5699 if (xexpr->xmloption == XMLOPTION_DOCUMENT)
5700 appendStringInfoString(buf, "DOCUMENT ");
5702 appendStringInfoString(buf, "CONTENT ");
5706 appendStringInfo(buf, "NAME %s",
5707 quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
5710 if (xexpr->named_args)
5712 if (xexpr->op != IS_XMLFOREST)
5715 appendStringInfoString(buf, ", ");
5716 appendStringInfoString(buf, "XMLATTRIBUTES(");
5719 forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
5721 Node *e = (Node *) lfirst(arg);
5722 char *argname = strVal(lfirst(narg));
5725 appendStringInfoString(buf, ", ");
5726 get_rule_expr((Node *) e, context, true);
5727 appendStringInfo(buf, " AS %s",
5728 quote_identifier(map_xml_name_to_sql_identifier(argname)));
5731 if (xexpr->op != IS_XMLFOREST)
5732 appendStringInfoChar(buf, ')');
5737 appendStringInfoString(buf, ", ");
5744 case IS_XMLSERIALIZE:
5745 /* no extra decoration needed */
5746 get_rule_expr((Node *) xexpr->args, context, true);
5749 Assert(list_length(xexpr->args) == 2);
5751 get_rule_expr((Node *) linitial(xexpr->args),
5754 con = (Const *) lsecond(xexpr->args);
5755 Assert(IsA(con, Const));
5756 Assert(!con->constisnull);
5757 if (DatumGetBool(con->constvalue))
5758 appendStringInfoString(buf,
5759 " PRESERVE WHITESPACE");
5761 appendStringInfoString(buf,
5762 " STRIP WHITESPACE");
5765 Assert(list_length(xexpr->args) == 3);
5767 get_rule_expr((Node *) linitial(xexpr->args),
5770 appendStringInfoString(buf, ", VERSION ");
5771 con = (Const *) lsecond(xexpr->args);
5772 if (IsA(con, Const) &&
5774 appendStringInfoString(buf, "NO VALUE");
5776 get_rule_expr((Node *) con, context, false);
5778 con = (Const *) lthird(xexpr->args);
5779 Assert(IsA(con, Const));
5780 if (con->constisnull)
5781 /* suppress STANDALONE NO VALUE */ ;
5784 switch (DatumGetInt32(con->constvalue))
5786 case XML_STANDALONE_YES:
5787 appendStringInfoString(buf,
5788 ", STANDALONE YES");
5790 case XML_STANDALONE_NO:
5791 appendStringInfoString(buf,
5794 case XML_STANDALONE_NO_VALUE:
5795 appendStringInfoString(buf,
5796 ", STANDALONE NO VALUE");
5804 get_rule_expr_paren((Node *) xexpr->args, context, false, node);
5809 if (xexpr->op == IS_XMLSERIALIZE)
5810 appendStringInfo(buf, " AS %s",
5811 format_type_with_typemod(xexpr->type,
5813 if (xexpr->op == IS_DOCUMENT)
5814 appendStringInfoString(buf, " IS DOCUMENT");
5816 appendStringInfoChar(buf, ')');
5822 NullTest *ntest = (NullTest *) node;
5824 if (!PRETTY_PAREN(context))
5825 appendStringInfoChar(buf, '(');
5826 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
5827 switch (ntest->nulltesttype)
5830 appendStringInfo(buf, " IS NULL");
5833 appendStringInfo(buf, " IS NOT NULL");
5836 elog(ERROR, "unrecognized nulltesttype: %d",
5837 (int) ntest->nulltesttype);
5839 if (!PRETTY_PAREN(context))
5840 appendStringInfoChar(buf, ')');
5846 BooleanTest *btest = (BooleanTest *) node;
5848 if (!PRETTY_PAREN(context))
5849 appendStringInfoChar(buf, '(');
5850 get_rule_expr_paren((Node *) btest->arg, context, false, node);
5851 switch (btest->booltesttype)
5854 appendStringInfo(buf, " IS TRUE");
5857 appendStringInfo(buf, " IS NOT TRUE");
5860 appendStringInfo(buf, " IS FALSE");
5863 appendStringInfo(buf, " IS NOT FALSE");
5866 appendStringInfo(buf, " IS UNKNOWN");
5868 case IS_NOT_UNKNOWN:
5869 appendStringInfo(buf, " IS NOT UNKNOWN");
5872 elog(ERROR, "unrecognized booltesttype: %d",
5873 (int) btest->booltesttype);
5875 if (!PRETTY_PAREN(context))
5876 appendStringInfoChar(buf, ')');
5880 case T_CoerceToDomain:
5882 CoerceToDomain *ctest = (CoerceToDomain *) node;
5883 Node *arg = (Node *) ctest->arg;
5885 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
5888 /* don't show the implicit cast */
5889 get_rule_expr(arg, context, false);
5893 get_coercion_expr(arg, context,
5895 ctest->resulttypmod,
5901 case T_CoerceToDomainValue:
5902 appendStringInfo(buf, "VALUE");
5905 case T_SetToDefault:
5906 appendStringInfo(buf, "DEFAULT");
5909 case T_CurrentOfExpr:
5911 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
5913 if (cexpr->cursor_name)
5914 appendStringInfo(buf, "CURRENT OF %s",
5915 quote_identifier(cexpr->cursor_name));
5917 appendStringInfo(buf, "CURRENT OF $%d",
5918 cexpr->cursor_param);
5928 foreach(l, (List *) node)
5930 appendStringInfoString(buf, sep);
5931 get_rule_expr((Node *) lfirst(l), context, showimplicit);
5938 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
5945 * get_oper_expr - Parse back an OpExpr node
5948 get_oper_expr(OpExpr *expr, deparse_context *context)
5950 StringInfo buf = context->buf;
5951 Oid opno = expr->opno;
5952 List *args = expr->args;
5954 if (!PRETTY_PAREN(context))
5955 appendStringInfoChar(buf, '(');
5956 if (list_length(args) == 2)
5958 /* binary operator */
5959 Node *arg1 = (Node *) linitial(args);
5960 Node *arg2 = (Node *) lsecond(args);
5962 get_rule_expr_paren(arg1, context, true, (Node *) expr);
5963 appendStringInfo(buf, " %s ",
5964 generate_operator_name(opno,
5967 get_rule_expr_paren(arg2, context, true, (Node *) expr);
5971 /* unary operator --- but which side? */
5972 Node *arg = (Node *) linitial(args);
5974 Form_pg_operator optup;
5976 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
5977 if (!HeapTupleIsValid(tp))
5978 elog(ERROR, "cache lookup failed for operator %u", opno);
5979 optup = (Form_pg_operator) GETSTRUCT(tp);
5980 switch (optup->oprkind)
5983 appendStringInfo(buf, "%s ",
5984 generate_operator_name(opno,
5987 get_rule_expr_paren(arg, context, true, (Node *) expr);
5990 get_rule_expr_paren(arg, context, true, (Node *) expr);
5991 appendStringInfo(buf, " %s",
5992 generate_operator_name(opno,
5997 elog(ERROR, "bogus oprkind: %d", optup->oprkind);
5999 ReleaseSysCache(tp);
6001 if (!PRETTY_PAREN(context))
6002 appendStringInfoChar(buf, ')');
6006 * get_func_expr - Parse back a FuncExpr node
6009 get_func_expr(FuncExpr *expr, deparse_context *context,
6012 StringInfo buf = context->buf;
6013 Oid funcoid = expr->funcid;
6014 Oid argtypes[FUNC_MAX_ARGS];
6021 * If the function call came from an implicit coercion, then just show the
6022 * first argument --- unless caller wants to see implicit coercions.
6024 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
6026 get_rule_expr_paren((Node *) linitial(expr->args), context,
6027 false, (Node *) expr);
6032 * If the function call came from a cast, then show the first argument
6033 * plus an explicit cast operation.
6035 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
6036 expr->funcformat == COERCE_IMPLICIT_CAST)
6038 Node *arg = linitial(expr->args);
6039 Oid rettype = expr->funcresulttype;
6040 int32 coercedTypmod;
6042 /* Get the typmod if this is a length-coercion function */
6043 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
6045 get_coercion_expr(arg, context,
6046 rettype, coercedTypmod,
6053 * Normal function: display as proname(args). First we need to extract
6054 * the argument datatypes.
6056 if (list_length(expr->args) > FUNC_MAX_ARGS)
6058 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
6059 errmsg("too many arguments")));
6062 foreach(l, expr->args)
6064 Node *arg = (Node *) lfirst(l);
6066 if (IsA(arg, NamedArgExpr))
6067 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
6068 argtypes[nargs] = exprType(arg);
6072 appendStringInfo(buf, "%s(",
6073 generate_function_name(funcoid, nargs,
6077 foreach(l, expr->args)
6080 appendStringInfoString(buf, ", ");
6081 if (is_variadic && lnext(l) == NULL)
6082 appendStringInfoString(buf, "VARIADIC ");
6083 get_rule_expr((Node *) lfirst(l), context, true);
6085 appendStringInfoChar(buf, ')');
6089 * get_agg_expr - Parse back an Aggref node
6092 get_agg_expr(Aggref *aggref, deparse_context *context)
6094 StringInfo buf = context->buf;
6095 Oid argtypes[FUNC_MAX_ARGS];
6100 /* Extract the regular arguments, ignoring resjunk stuff for the moment */
6103 foreach(l, aggref->args)
6105 TargetEntry *tle = (TargetEntry *) lfirst(l);
6106 Node *arg = (Node *) tle->expr;
6108 Assert(!IsA(arg, NamedArgExpr));
6111 if (nargs >= FUNC_MAX_ARGS) /* paranoia */
6113 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
6114 errmsg("too many arguments")));
6115 argtypes[nargs] = exprType(arg);
6116 arglist = lappend(arglist, arg);
6120 appendStringInfo(buf, "%s(%s",
6121 generate_function_name(aggref->aggfnoid, nargs,
6122 NIL, argtypes, NULL),
6123 (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
6124 /* aggstar can be set only in zero-argument aggregates */
6125 if (aggref->aggstar)
6126 appendStringInfoChar(buf, '*');
6128 get_rule_expr((Node *) arglist, context, true);
6129 if (aggref->aggorder != NIL)
6131 appendStringInfoString(buf, " ORDER BY ");
6132 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
6134 appendStringInfoChar(buf, ')');
6138 * get_windowfunc_expr - Parse back a WindowFunc node
6141 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
6143 StringInfo buf = context->buf;
6144 Oid argtypes[FUNC_MAX_ARGS];
6148 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
6150 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
6151 errmsg("too many arguments")));
6153 foreach(l, wfunc->args)
6155 Node *arg = (Node *) lfirst(l);
6157 Assert(!IsA(arg, NamedArgExpr));
6158 argtypes[nargs] = exprType(arg);
6162 appendStringInfo(buf, "%s(",
6163 generate_function_name(wfunc->winfnoid, nargs,
6164 NIL, argtypes, NULL));
6165 /* winstar can be set only in zero-argument aggregates */
6167 appendStringInfoChar(buf, '*');
6169 get_rule_expr((Node *) wfunc->args, context, true);
6170 appendStringInfoString(buf, ") OVER ");
6172 foreach(l, context->windowClause)
6174 WindowClause *wc = (WindowClause *) lfirst(l);
6176 if (wc->winref == wfunc->winref)
6179 appendStringInfoString(buf, quote_identifier(wc->name));
6181 get_rule_windowspec(wc, context->windowTList, context);
6187 if (context->windowClause)
6188 elog(ERROR, "could not find window clause for winref %u",
6192 * In EXPLAIN, we don't have window context information available, so
6193 * we have to settle for this:
6195 appendStringInfoString(buf, "(?)");
6202 * Make a string representation of a value coerced to a specific type
6206 get_coercion_expr(Node *arg, deparse_context *context,
6207 Oid resulttype, int32 resulttypmod,
6210 StringInfo buf = context->buf;
6213 * Since parse_coerce.c doesn't immediately collapse application of
6214 * length-coercion functions to constants, what we'll typically see in
6215 * such cases is a Const with typmod -1 and a length-coercion function
6216 * right above it. Avoid generating redundant output. However, beware of
6217 * suppressing casts when the user actually wrote something like
6218 * 'foo'::text::char(3).
6220 if (arg && IsA(arg, Const) &&
6221 ((Const *) arg)->consttype == resulttype &&
6222 ((Const *) arg)->consttypmod == -1)
6224 /* Show the constant without normal ::typename decoration */
6225 get_const_expr((Const *) arg, context, -1);
6229 if (!PRETTY_PAREN(context))
6230 appendStringInfoChar(buf, '(');
6231 get_rule_expr_paren(arg, context, false, parentNode);
6232 if (!PRETTY_PAREN(context))
6233 appendStringInfoChar(buf, ')');
6235 appendStringInfo(buf, "::%s",
6236 format_type_with_typemod(resulttype, resulttypmod));
6242 * Make a string representation of a Const
6244 * showtype can be -1 to never show "::typename" decoration, or +1 to always
6245 * show it, or 0 to show it only if the constant wouldn't be assumed to be
6246 * the right type by default.
6248 * If the Const's collation isn't default for its type, show that too.
6249 * This can only happen in trees that have been through constant-folding.
6250 * We assume we don't need to do this when showtype is -1.
6254 get_const_expr(Const *constval, deparse_context *context, int showtype)
6256 StringInfo buf = context->buf;
6260 bool isfloat = false;
6263 if (constval->constisnull)
6266 * Always label the type of a NULL constant to prevent misdecisions
6267 * about type when reparsing.
6269 appendStringInfo(buf, "NULL");
6272 appendStringInfo(buf, "::%s",
6273 format_type_with_typemod(constval->consttype,
6274 constval->consttypmod));
6275 get_const_collation(constval, context);
6280 getTypeOutputInfo(constval->consttype,
6281 &typoutput, &typIsVarlena);
6283 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
6285 switch (constval->consttype)
6296 * These types are printed without quotes unless they contain
6297 * values that aren't accepted by the scanner unquoted (e.g.,
6298 * 'NaN'). Note that strtod() and friends might accept NaN,
6299 * so we can't use that to test.
6301 * In reality we only need to defend against infinity and NaN,
6302 * so we need not get too crazy about pattern matching here.
6304 * There is a special-case gotcha: if the constant is signed,
6305 * we need to parenthesize it, else the parser might see a
6306 * leading plus/minus as binding less tightly than adjacent
6307 * operators --- particularly, the cast that we might attach
6310 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
6312 if (extval[0] == '+' || extval[0] == '-')
6313 appendStringInfo(buf, "(%s)", extval);
6315 appendStringInfoString(buf, extval);
6316 if (strcspn(extval, "eE.") != strlen(extval))
6317 isfloat = true; /* it looks like a float */
6320 appendStringInfo(buf, "'%s'", extval);
6326 appendStringInfo(buf, "B'%s'", extval);
6330 if (strcmp(extval, "t") == 0)
6331 appendStringInfo(buf, "true");
6333 appendStringInfo(buf, "false");
6337 simple_quote_literal(buf, extval);
6347 * For showtype == 0, append ::typename unless the constant will be
6348 * implicitly typed as the right type when it is read in.
6350 * XXX this code has to be kept in sync with the behavior of the parser,
6351 * especially make_const.
6353 switch (constval->consttype)
6358 /* These types can be left unlabeled */
6364 * Float-looking constants will be typed as numeric, but if
6365 * there's a specific typmod we need to show it.
6367 needlabel = !isfloat || (constval->consttypmod >= 0);
6373 if (needlabel || showtype > 0)
6374 appendStringInfo(buf, "::%s",
6375 format_type_with_typemod(constval->consttype,
6376 constval->consttypmod));
6378 get_const_collation(constval, context);
6382 * helper for get_const_expr: append COLLATE if needed
6385 get_const_collation(Const *constval, deparse_context *context)
6387 StringInfo buf = context->buf;
6389 if (OidIsValid(constval->constcollid))
6391 Oid typcollation = get_typcollation(constval->consttype);
6393 if (constval->constcollid != typcollation)
6395 appendStringInfo(buf, " COLLATE %s",
6396 generate_collation_name(constval->constcollid));
6402 * simple_quote_literal - Format a string as a SQL literal, append to buf
6405 simple_quote_literal(StringInfo buf, const char *val)
6410 * We form the string literal according to the prevailing setting of
6411 * standard_conforming_strings; we never use E''. User is responsible for
6412 * making sure result is used correctly.
6414 appendStringInfoChar(buf, '\'');
6415 for (valptr = val; *valptr; valptr++)
6419 if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
6420 appendStringInfoChar(buf, ch);
6421 appendStringInfoChar(buf, ch);
6423 appendStringInfoChar(buf, '\'');
6428 * get_sublink_expr - Parse back a sublink
6432 get_sublink_expr(SubLink *sublink, deparse_context *context)
6434 StringInfo buf = context->buf;
6435 Query *query = (Query *) (sublink->subselect);
6436 char *opname = NULL;
6439 if (sublink->subLinkType == ARRAY_SUBLINK)
6440 appendStringInfo(buf, "ARRAY(");
6442 appendStringInfoChar(buf, '(');
6445 * Note that we print the name of only the first operator, when there are
6446 * multiple combining operators. This is an approximation that could go
6447 * wrong in various scenarios (operators in different schemas, renamed
6448 * operators, etc) but there is not a whole lot we can do about it, since
6449 * the syntax allows only one operator to be shown.
6451 if (sublink->testexpr)
6453 if (IsA(sublink->testexpr, OpExpr))
6455 /* single combining operator */
6456 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
6458 get_rule_expr(linitial(opexpr->args), context, true);
6459 opname = generate_operator_name(opexpr->opno,
6460 exprType(linitial(opexpr->args)),
6461 exprType(lsecond(opexpr->args)));
6463 else if (IsA(sublink->testexpr, BoolExpr))
6465 /* multiple combining operators, = or <> cases */
6469 appendStringInfoChar(buf, '(');
6471 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
6473 OpExpr *opexpr = (OpExpr *) lfirst(l);
6475 Assert(IsA(opexpr, OpExpr));
6476 appendStringInfoString(buf, sep);
6477 get_rule_expr(linitial(opexpr->args), context, true);
6479 opname = generate_operator_name(opexpr->opno,
6480 exprType(linitial(opexpr->args)),
6481 exprType(lsecond(opexpr->args)));
6484 appendStringInfoChar(buf, ')');
6486 else if (IsA(sublink->testexpr, RowCompareExpr))
6488 /* multiple combining operators, < <= > >= cases */
6489 RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
6491 appendStringInfoChar(buf, '(');
6492 get_rule_expr((Node *) rcexpr->largs, context, true);
6493 opname = generate_operator_name(linitial_oid(rcexpr->opnos),
6494 exprType(linitial(rcexpr->largs)),
6495 exprType(linitial(rcexpr->rargs)));
6496 appendStringInfoChar(buf, ')');
6499 elog(ERROR, "unrecognized testexpr type: %d",
6500 (int) nodeTag(sublink->testexpr));
6505 switch (sublink->subLinkType)
6507 case EXISTS_SUBLINK:
6508 appendStringInfo(buf, "EXISTS ");
6512 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
6513 appendStringInfo(buf, " IN ");
6515 appendStringInfo(buf, " %s ANY ", opname);
6519 appendStringInfo(buf, " %s ALL ", opname);
6522 case ROWCOMPARE_SUBLINK:
6523 appendStringInfo(buf, " %s ", opname);
6531 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
6533 elog(ERROR, "unrecognized sublink type: %d",
6534 (int) sublink->subLinkType);
6539 appendStringInfoChar(buf, '(');
6541 get_query_def(query, buf, context->namespaces, NULL,
6542 context->prettyFlags, context->indentLevel);
6545 appendStringInfo(buf, "))");
6547 appendStringInfoChar(buf, ')');
6552 * get_from_clause - Parse back a FROM clause
6554 * "prefix" is the keyword that denotes the start of the list of FROM
6555 * elements. It is FROM when used to parse back SELECT and UPDATE, but
6556 * is USING when parsing back DELETE.
6560 get_from_clause(Query *query, const char *prefix, deparse_context *context)
6562 StringInfo buf = context->buf;
6567 * We use the query's jointree as a guide to what to print. However, we
6568 * must ignore auto-added RTEs that are marked not inFromCl. (These can
6569 * only appear at the top level of the jointree, so it's sufficient to
6570 * check here.) This check also ensures we ignore the rule pseudo-RTEs
6573 foreach(l, query->jointree->fromlist)
6575 Node *jtnode = (Node *) lfirst(l);
6577 if (IsA(jtnode, RangeTblRef))
6579 int varno = ((RangeTblRef *) jtnode)->rtindex;
6580 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
6588 appendContextKeyword(context, prefix,
6589 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
6592 get_from_clause_item(jtnode, query, context);
6596 StringInfoData targetbuf;
6599 appendStringInfoString(buf, ", ");
6601 initStringInfo(&targetbuf);
6602 context->buf = &targetbuf;
6604 get_from_clause_item(jtnode, query, context);
6608 /* Locate the start of the current line in the buffer */
6610 trailing_nl = (strrchr(buf->data, '\n'));
6611 if (trailing_nl == NULL)
6612 trailing_nl = buf->data;
6617 * Add a newline, plus some indentation, if pretty_wrap is on and
6618 * the new from-clause item would cause an overflow.
6621 if (pretty_wrap >= 0 &&
6622 (strlen(trailing_nl) + strlen(targetbuf.data) > pretty_wrap))
6624 appendContextKeyword(context, "", -PRETTYINDENT_STD,
6625 PRETTYINDENT_STD, PRETTYINDENT_VAR);
6628 /* Add the new item */
6630 appendStringInfoString(buf, targetbuf.data);
6634 pfree(targetbuf.data);
6641 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
6643 StringInfo buf = context->buf;
6645 if (IsA(jtnode, RangeTblRef))
6647 int varno = ((RangeTblRef *) jtnode)->rtindex;
6648 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
6649 bool gavealias = false;
6652 appendStringInfoString(buf, "LATERAL ");
6654 switch (rte->rtekind)
6657 /* Normal relation RTE */
6658 appendStringInfo(buf, "%s%s",
6660 generate_relation_name(rte->relid,
6661 context->namespaces));
6665 appendStringInfoChar(buf, '(');
6666 get_query_def(rte->subquery, buf, context->namespaces, NULL,
6667 context->prettyFlags, context->indentLevel);
6668 appendStringInfoChar(buf, ')');
6672 get_rule_expr(rte->funcexpr, context, true);
6675 /* Values list RTE */
6676 get_values_def(rte->values_lists, context);
6679 appendStringInfoString(buf, quote_identifier(rte->ctename));
6682 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
6686 if (rte->alias != NULL)
6688 appendStringInfo(buf, " %s",
6689 quote_identifier(rte->alias->aliasname));
6692 else if (rte->rtekind == RTE_RELATION &&
6693 strcmp(rte->eref->aliasname, get_relation_name(rte->relid)) != 0)
6696 * Apparently the rel has been renamed since the rule was made.
6697 * Emit a fake alias clause so that variable references will still
6698 * work. This is not a 100% solution but should work in most
6699 * reasonable situations.
6701 appendStringInfo(buf, " %s",
6702 quote_identifier(rte->eref->aliasname));
6705 else if (rte->rtekind == RTE_FUNCTION)
6708 * For a function RTE, always give an alias. This covers possible
6709 * renaming of the function and/or instability of the
6710 * FigureColname rules for things that aren't simple functions.
6712 appendStringInfo(buf, " %s",
6713 quote_identifier(rte->eref->aliasname));
6717 if (rte->rtekind == RTE_FUNCTION)
6719 if (rte->funccoltypes != NIL)
6721 /* Function returning RECORD, reconstruct the columndefs */
6723 appendStringInfo(buf, " AS ");
6724 get_from_clause_coldeflist(rte->eref->colnames,
6726 rte->funccoltypmods,
6727 rte->funccolcollations,
6733 * For a function RTE, always emit a complete column alias
6734 * list; this is to protect against possible instability of
6735 * the default column names (eg, from altering parameter
6738 get_from_clause_alias(rte->eref, rte, context);
6744 * For non-function RTEs, just report whatever the user originally
6745 * gave as column aliases.
6747 get_from_clause_alias(rte->alias, rte, context);
6750 else if (IsA(jtnode, JoinExpr))
6752 JoinExpr *j = (JoinExpr *) jtnode;
6753 bool need_paren_on_right;
6755 need_paren_on_right = PRETTY_PAREN(context) &&
6756 !IsA(j->rarg, RangeTblRef) &&
6757 !(IsA(j->rarg, JoinExpr) &&((JoinExpr *) j->rarg)->alias != NULL);
6759 if (!PRETTY_PAREN(context) || j->alias != NULL)
6760 appendStringInfoChar(buf, '(');
6762 get_from_clause_item(j->larg, query, context);
6766 if (!PRETTY_INDENT(context))
6767 appendStringInfoChar(buf, ' ');
6768 switch (j->jointype)
6771 appendContextKeyword(context, "NATURAL JOIN ",
6773 PRETTYINDENT_JOIN, 0);
6776 appendContextKeyword(context, "NATURAL LEFT JOIN ",
6778 PRETTYINDENT_JOIN, 0);
6781 appendContextKeyword(context, "NATURAL FULL JOIN ",
6783 PRETTYINDENT_JOIN, 0);
6786 appendContextKeyword(context, "NATURAL RIGHT JOIN ",
6788 PRETTYINDENT_JOIN, 0);
6791 elog(ERROR, "unrecognized join type: %d",
6797 switch (j->jointype)
6801 appendContextKeyword(context, " JOIN ",
6803 PRETTYINDENT_JOIN, 2);
6805 appendContextKeyword(context, " CROSS JOIN ",
6807 PRETTYINDENT_JOIN, 1);
6810 appendContextKeyword(context, " LEFT JOIN ",
6812 PRETTYINDENT_JOIN, 2);
6815 appendContextKeyword(context, " FULL JOIN ",
6817 PRETTYINDENT_JOIN, 2);
6820 appendContextKeyword(context, " RIGHT JOIN ",
6822 PRETTYINDENT_JOIN, 2);
6825 elog(ERROR, "unrecognized join type: %d",
6830 if (need_paren_on_right)
6831 appendStringInfoChar(buf, '(');
6832 get_from_clause_item(j->rarg, query, context);
6833 if (need_paren_on_right)
6834 appendStringInfoChar(buf, ')');
6836 context->indentLevel -= PRETTYINDENT_JOIN_ON;
6844 appendStringInfo(buf, " USING (");
6845 foreach(col, j->usingClause)
6847 if (col != list_head(j->usingClause))
6848 appendStringInfo(buf, ", ");
6849 appendStringInfoString(buf,
6850 quote_identifier(strVal(lfirst(col))));
6852 appendStringInfoChar(buf, ')');
6856 appendStringInfo(buf, " ON ");
6857 if (!PRETTY_PAREN(context))
6858 appendStringInfoChar(buf, '(');
6859 get_rule_expr(j->quals, context, false);
6860 if (!PRETTY_PAREN(context))
6861 appendStringInfoChar(buf, ')');
6864 if (!PRETTY_PAREN(context) || j->alias != NULL)
6865 appendStringInfoChar(buf, ')');
6867 /* Yes, it's correct to put alias after the right paren ... */
6868 if (j->alias != NULL)
6870 appendStringInfo(buf, " %s",
6871 quote_identifier(j->alias->aliasname));
6872 get_from_clause_alias(j->alias,
6873 rt_fetch(j->rtindex, query->rtable),
6878 elog(ERROR, "unrecognized node type: %d",
6879 (int) nodeTag(jtnode));
6883 * get_from_clause_alias - reproduce column alias list
6885 * This is tricky because we must ignore dropped columns.
6888 get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
6889 deparse_context *context)
6891 StringInfo buf = context->buf;
6896 if (alias == NULL || alias->colnames == NIL)
6897 return; /* definitely nothing to do */
6900 foreach(col, alias->colnames)
6903 if (get_rte_attribute_is_dropped(rte, attnum))
6907 appendStringInfoChar(buf, '(');
6911 appendStringInfo(buf, ", ");
6912 appendStringInfoString(buf,
6913 quote_identifier(strVal(lfirst(col))));
6916 appendStringInfoChar(buf, ')');
6920 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
6922 * The coldeflist is appended immediately (no space) to buf. Caller is
6923 * responsible for ensuring that an alias or AS is present before it.
6926 get_from_clause_coldeflist(List *names,
6927 List *types, List *typmods, List *collations,
6928 deparse_context *context)
6930 StringInfo buf = context->buf;
6937 appendStringInfoChar(buf, '(');
6939 l2 = list_head(types);
6940 l3 = list_head(typmods);
6941 l4 = list_head(collations);
6944 char *attname = strVal(lfirst(l1));
6949 atttypid = lfirst_oid(l2);
6951 atttypmod = lfirst_int(l3);
6953 attcollation = lfirst_oid(l4);
6957 appendStringInfo(buf, ", ");
6958 appendStringInfo(buf, "%s %s",
6959 quote_identifier(attname),
6960 format_type_with_typemod(atttypid, atttypmod));
6961 if (OidIsValid(attcollation) &&
6962 attcollation != get_typcollation(atttypid))
6963 appendStringInfo(buf, " COLLATE %s",
6964 generate_collation_name(attcollation));
6968 appendStringInfoChar(buf, ')');
6972 * get_opclass_name - fetch name of an index operator class
6974 * The opclass name is appended (after a space) to buf.
6976 * Output is suppressed if the opclass is the default for the given
6977 * actual_datatype. (If you don't want this behavior, just pass
6978 * InvalidOid for actual_datatype.)
6981 get_opclass_name(Oid opclass, Oid actual_datatype,
6985 Form_pg_opclass opcrec;
6989 ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
6990 if (!HeapTupleIsValid(ht_opc))
6991 elog(ERROR, "cache lookup failed for opclass %u", opclass);
6992 opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
6994 if (!OidIsValid(actual_datatype) ||
6995 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
6997 /* Okay, we need the opclass name. Do we need to qualify it? */
6998 opcname = NameStr(opcrec->opcname);
6999 if (OpclassIsVisible(opclass))
7000 appendStringInfo(buf, " %s", quote_identifier(opcname));
7003 nspname = get_namespace_name(opcrec->opcnamespace);
7004 appendStringInfo(buf, " %s.%s",
7005 quote_identifier(nspname),
7006 quote_identifier(opcname));
7009 ReleaseSysCache(ht_opc);
7013 * processIndirection - take care of array and subfield assignment
7015 * We strip any top-level FieldStore or assignment ArrayRef nodes that
7016 * appear in the input, and return the subexpression that's to be assigned.
7017 * If printit is true, we also print out the appropriate decoration for the
7018 * base column name (that the caller just printed).
7021 processIndirection(Node *node, deparse_context *context, bool printit)
7023 StringInfo buf = context->buf;
7029 if (IsA(node, FieldStore))
7031 FieldStore *fstore = (FieldStore *) node;
7035 /* lookup tuple type */
7036 typrelid = get_typ_typrelid(fstore->resulttype);
7037 if (!OidIsValid(typrelid))
7038 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
7039 format_type_be(fstore->resulttype));
7042 * Print the field name. There should only be one target field in
7043 * stored rules. There could be more than that in executable
7044 * target lists, but this function cannot be used for that case.
7046 Assert(list_length(fstore->fieldnums) == 1);
7047 fieldname = get_relid_attribute_name(typrelid,
7048 linitial_int(fstore->fieldnums));
7050 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
7053 * We ignore arg since it should be an uninteresting reference to
7054 * the target column or subcolumn.
7056 node = (Node *) linitial(fstore->newvals);
7058 else if (IsA(node, ArrayRef))
7060 ArrayRef *aref = (ArrayRef *) node;
7062 if (aref->refassgnexpr == NULL)
7065 printSubscripts(aref, context);
7068 * We ignore refexpr since it should be an uninteresting reference
7069 * to the target column or subcolumn.
7071 node = (Node *) aref->refassgnexpr;
7081 printSubscripts(ArrayRef *aref, deparse_context *context)
7083 StringInfo buf = context->buf;
7084 ListCell *lowlist_item;
7085 ListCell *uplist_item;
7087 lowlist_item = list_head(aref->reflowerindexpr); /* could be NULL */
7088 foreach(uplist_item, aref->refupperindexpr)
7090 appendStringInfoChar(buf, '[');
7093 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
7094 appendStringInfoChar(buf, ':');
7095 lowlist_item = lnext(lowlist_item);
7097 get_rule_expr((Node *) lfirst(uplist_item), context, false);
7098 appendStringInfoChar(buf, ']');
7103 * quote_identifier - Quote an identifier only if needed
7105 * When quotes are needed, we palloc the required space; slightly
7106 * space-wasteful but well worth it for notational simplicity.
7109 quote_identifier(const char *ident)
7112 * Can avoid quoting if ident starts with a lowercase letter or underscore
7113 * and contains only lowercase letters, digits, and underscores, *and* is
7114 * not any SQL keyword. Otherwise, supply quotes.
7123 * would like to use <ctype.h> macros here, but they might yield unwanted
7124 * locale-specific results...
7126 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
7128 for (ptr = ident; *ptr; ptr++)
7132 if ((ch >= 'a' && ch <= 'z') ||
7133 (ch >= '0' && ch <= '9') ||
7146 if (quote_all_identifiers)
7152 * Check for keyword. We quote keywords except for unreserved ones.
7153 * (In some cases we could avoid quoting a col_name or type_func_name
7154 * keyword, but it seems much harder than it's worth to tell that.)
7156 * Note: ScanKeywordLookup() does case-insensitive comparison, but
7157 * that's fine, since we already know we have all-lower-case.
7159 const ScanKeyword *keyword = ScanKeywordLookup(ident,
7163 if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
7168 return ident; /* no change needed */
7170 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
7174 for (ptr = ident; *ptr; ptr++)
7189 * quote_qualified_identifier - Quote a possibly-qualified identifier
7191 * Return a name of the form qualifier.ident, or just ident if qualifier
7192 * is NULL, quoting each component if necessary. The result is palloc'd.
7195 quote_qualified_identifier(const char *qualifier,
7200 initStringInfo(&buf);
7202 appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
7203 appendStringInfoString(&buf, quote_identifier(ident));
7209 * Get the unqualified name of a relation specified by OID
7211 * This differs from the underlying get_rel_name() function in that it will
7212 * throw error instead of silently returning NULL if the OID is bad.
7215 get_relation_name(Oid relid)
7217 char *relname = get_rel_name(relid);
7220 elog(ERROR, "cache lookup failed for relation %u", relid);
7225 * generate_relation_name
7226 * Compute the name to display for a relation specified by OID
7228 * The result includes all necessary quoting and schema-prefixing.
7230 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
7231 * We will forcibly qualify the relation name if it equals any CTE name
7232 * visible in the namespace list.
7235 generate_relation_name(Oid relid, List *namespaces)
7238 Form_pg_class reltup;
7245 tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
7246 if (!HeapTupleIsValid(tp))
7247 elog(ERROR, "cache lookup failed for relation %u", relid);
7248 reltup = (Form_pg_class) GETSTRUCT(tp);
7249 relname = NameStr(reltup->relname);
7251 /* Check for conflicting CTE name */
7253 foreach(nslist, namespaces)
7255 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
7258 foreach(ctlist, dpns->ctes)
7260 CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
7262 if (strcmp(cte->ctename, relname) == 0)
7272 /* Otherwise, qualify the name if not visible in search path */
7274 need_qual = !RelationIsVisible(relid);
7277 nspname = get_namespace_name(reltup->relnamespace);
7281 result = quote_qualified_identifier(nspname, relname);
7283 ReleaseSysCache(tp);
7289 * generate_function_name
7290 * Compute the name to display for a function specified by OID,
7291 * given that it is being called with the specified actual arg names and
7292 * types. (Those matter because of ambiguous-function resolution rules.)
7294 * The result includes all necessary quoting and schema-prefixing. We can
7295 * also pass back an indication of whether the function is variadic.
7298 generate_function_name(Oid funcid, int nargs, List *argnames,
7299 Oid *argtypes, bool *is_variadic)
7302 Form_pg_proc procform;
7306 FuncDetailCode p_result;
7311 Oid *p_true_typeids;
7313 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
7314 if (!HeapTupleIsValid(proctup))
7315 elog(ERROR, "cache lookup failed for function %u", funcid);
7316 procform = (Form_pg_proc) GETSTRUCT(proctup);
7317 proname = NameStr(procform->proname);
7320 * The idea here is to schema-qualify only if the parser would fail to
7321 * resolve the correct function given the unqualified func name with the
7322 * specified argtypes. If the function is variadic, we should presume
7323 * that VARIADIC will be included in the call.
7325 p_result = func_get_detail(list_make1(makeString(proname)),
7326 NIL, argnames, nargs, argtypes,
7327 !OidIsValid(procform->provariadic), true,
7328 &p_funcid, &p_rettype,
7329 &p_retset, &p_nvargs, &p_true_typeids, NULL);
7330 if ((p_result == FUNCDETAIL_NORMAL ||
7331 p_result == FUNCDETAIL_AGGREGATE ||
7332 p_result == FUNCDETAIL_WINDOWFUNC) &&
7336 nspname = get_namespace_name(procform->pronamespace);
7338 result = quote_qualified_identifier(nspname, proname);
7340 /* Check variadic-ness if caller cares */
7343 /* "any" variadics are not treated as variadics for listing */
7344 if (OidIsValid(procform->provariadic) &&
7345 procform->provariadic != ANYOID)
7346 *is_variadic = true;
7348 *is_variadic = false;
7351 ReleaseSysCache(proctup);
7357 * generate_operator_name
7358 * Compute the name to display for an operator specified by OID,
7359 * given that it is being called with the specified actual arg types.
7360 * (Arg types matter because of ambiguous-operator resolution rules.
7361 * Pass InvalidOid for unused arg of a unary operator.)
7363 * The result includes all necessary quoting and schema-prefixing,
7364 * plus the OPERATOR() decoration needed to use a qualified operator name
7368 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
7372 Form_pg_operator operform;
7377 initStringInfo(&buf);
7379 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
7380 if (!HeapTupleIsValid(opertup))
7381 elog(ERROR, "cache lookup failed for operator %u", operid);
7382 operform = (Form_pg_operator) GETSTRUCT(opertup);
7383 oprname = NameStr(operform->oprname);
7386 * The idea here is to schema-qualify only if the parser would fail to
7387 * resolve the correct operator given the unqualified op name with the
7388 * specified argtypes.
7390 switch (operform->oprkind)
7393 p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
7397 p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
7401 p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
7405 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
7406 p_result = NULL; /* keep compiler quiet */
7410 if (p_result != NULL && oprid(p_result) == operid)
7414 nspname = get_namespace_name(operform->oprnamespace);
7415 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
7418 appendStringInfoString(&buf, oprname);
7421 appendStringInfoChar(&buf, ')');
7423 if (p_result != NULL)
7424 ReleaseSysCache(p_result);
7426 ReleaseSysCache(opertup);
7432 * generate_collation_name
7433 * Compute the name to display for a collation specified by OID
7435 * The result includes all necessary quoting and schema-prefixing.
7438 generate_collation_name(Oid collid)
7441 Form_pg_collation colltup;
7446 tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
7447 if (!HeapTupleIsValid(tp))
7448 elog(ERROR, "cache lookup failed for collation %u", collid);
7449 colltup = (Form_pg_collation) GETSTRUCT(tp);
7450 collname = NameStr(colltup->collname);
7452 if (!CollationIsVisible(collid))
7453 nspname = get_namespace_name(colltup->collnamespace);
7457 result = quote_qualified_identifier(nspname, collname);
7459 ReleaseSysCache(tp);
7465 * Given a C string, produce a TEXT datum.
7467 * We assume that the input was palloc'd and may be freed.
7470 string_to_text(char *str)
7474 result = cstring_to_text(str);
7480 * Generate a C string representing a relation's reloptions, or NULL if none.
7483 flatten_reloptions(Oid relid)
7485 char *result = NULL;
7490 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
7491 if (!HeapTupleIsValid(tuple))
7492 elog(ERROR, "cache lookup failed for relation %u", relid);
7494 reloptions = SysCacheGetAttr(RELOID, tuple,
7495 Anum_pg_class_reloptions, &isnull);
7502 * We want to use array_to_text(reloptions, ', ') --- but
7503 * DirectFunctionCall2(array_to_text) does not work, because
7504 * array_to_text() relies on flinfo to be valid. So use
7507 sep = CStringGetTextDatum(", ");
7508 txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
7509 result = TextDatumGetCString(txt);
7512 ReleaseSysCache(tuple);