1 /*-------------------------------------------------------------------------
4 * Functions to convert stored expressions/querytrees back to
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.310 2009/10/14 22:14:23 tgl Exp $
14 *-------------------------------------------------------------------------
21 #include "access/genam.h"
22 #include "access/sysattr.h"
23 #include "catalog/dependency.h"
24 #include "catalog/indexing.h"
25 #include "catalog/pg_authid.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/tqual.h"
55 #include "utils/syscache.h"
56 #include "utils/typcache.h"
57 #include "utils/xml.h"
61 * Pretty formatting constants
66 #define PRETTYINDENT_STD 8
67 #define PRETTYINDENT_JOIN 13
68 #define PRETTYINDENT_JOIN_ON (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
69 #define PRETTYINDENT_VAR 4
72 #define PRETTYFLAG_PAREN 1
73 #define PRETTYFLAG_INDENT 2
75 /* macro to test if pretty action needed */
76 #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
77 #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
85 /* Context info needed for invoking a recursive querytree display routine */
88 StringInfo buf; /* output buffer to append to */
89 List *namespaces; /* List of deparse_namespace nodes */
90 List *windowClause; /* Current query level's WINDOW clause */
91 List *windowTList; /* targetlist for resolving WINDOW clause */
92 int prettyFlags; /* enabling of pretty-print functions */
93 int indentLevel; /* current indent level for prettyprint */
94 bool varprefix; /* TRUE to print prefixes on Vars */
98 * Each level of query context around a subtree needs a level of Var namespace.
99 * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
100 * the current context's namespaces list.
102 * The rangetable is the list of actual RTEs from the query tree, and the
103 * cte list is the list of actual CTEs.
105 * For deparsing plan trees, we provide for outer and inner subplan nodes.
106 * The tlists of these nodes are used to resolve OUTER and INNER varnos.
107 * Also, in the plan-tree case we don't have access to the parse-time CTE
108 * list, so we need a list of subplans instead.
112 List *rtable; /* List of RangeTblEntry nodes */
113 List *ctes; /* List of CommonTableExpr nodes */
114 List *subplans; /* List of subplans, in plan-tree case */
115 Plan *outer_plan; /* OUTER subplan, or NULL if none */
116 Plan *inner_plan; /* INNER subplan, or NULL if none */
124 static SPIPlanPtr plan_getrulebyoid = NULL;
125 static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
126 static SPIPlanPtr plan_getviewrule = NULL;
127 static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
133 * Most of these functions used to use fixed-size buffers to build their
134 * results. Now, they take an (already initialized) StringInfo object
135 * as a parameter, and append their text output to its contents.
138 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
139 bool forceprefix, bool showimplicit,
140 int prettyFlags, int startIndent);
141 static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);
142 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
143 static void decompile_column_index_array(Datum column_index_array, Oid relId,
145 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
146 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
147 bool attrsOnly, bool showTblSpc,
149 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
151 static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
153 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
154 bool print_table_args, bool print_defaults);
155 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
156 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
158 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
160 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
161 TupleDesc resultDesc, int prettyFlags, int startIndent);
162 static void get_values_def(List *values_lists, deparse_context *context);
163 static void get_with_clause(Query *query, deparse_context *context);
164 static void get_select_query_def(Query *query, deparse_context *context,
165 TupleDesc resultDesc);
166 static void get_insert_query_def(Query *query, deparse_context *context);
167 static void get_update_query_def(Query *query, deparse_context *context);
168 static void get_delete_query_def(Query *query, deparse_context *context);
169 static void get_utility_query_def(Query *query, deparse_context *context);
170 static void get_basic_select_query(Query *query, deparse_context *context,
171 TupleDesc resultDesc);
172 static void get_target_list(List *targetList, deparse_context *context,
173 TupleDesc resultDesc);
174 static void get_setop_query(Node *setOp, Query *query,
175 deparse_context *context,
176 TupleDesc resultDesc);
177 static Node *get_rule_sortgroupclause(SortGroupClause *srt, List *tlist,
179 deparse_context *context);
180 static void get_rule_orderby(List *orderList, List *targetList,
181 bool force_colno, deparse_context *context);
182 static void get_rule_windowclause(Query *query, deparse_context *context);
183 static void get_rule_windowspec(WindowClause *wc, List *targetList,
184 deparse_context *context);
185 static void push_plan(deparse_namespace *dpns, Plan *subplan);
186 static char *get_variable(Var *var, int levelsup, bool showstar,
187 deparse_context *context);
188 static RangeTblEntry *find_rte_by_refname(const char *refname,
189 deparse_context *context);
190 static const char *get_simple_binary_op_name(OpExpr *expr);
191 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
192 static void appendContextKeyword(deparse_context *context, const char *str,
193 int indentBefore, int indentAfter, int indentPlus);
194 static void get_rule_expr(Node *node, deparse_context *context,
196 static void get_oper_expr(OpExpr *expr, deparse_context *context);
197 static void get_func_expr(FuncExpr *expr, deparse_context *context,
199 static void get_agg_expr(Aggref *aggref, deparse_context *context);
200 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
201 static void get_coercion_expr(Node *arg, deparse_context *context,
202 Oid resulttype, int32 resulttypmod,
204 static void get_const_expr(Const *constval, deparse_context *context,
206 static void simple_quote_literal(StringInfo buf, const char *val);
207 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
208 static void get_from_clause(Query *query, const char *prefix,
209 deparse_context *context);
210 static void get_from_clause_item(Node *jtnode, Query *query,
211 deparse_context *context);
212 static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
213 deparse_context *context);
214 static void get_from_clause_coldeflist(List *names, List *types, List *typmods,
215 deparse_context *context);
216 static void get_opclass_name(Oid opclass, Oid actual_datatype,
218 static Node *processIndirection(Node *node, deparse_context *context,
220 static void printSubscripts(ArrayRef *aref, deparse_context *context);
221 static char *generate_relation_name(Oid relid, List *namespaces);
222 static char *generate_function_name(Oid funcid, int nargs, List *argnames,
223 Oid *argtypes, bool *is_variadic);
224 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
225 static text *string_to_text(char *str);
226 static char *flatten_reloptions(Oid relid);
228 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
232 * get_ruledef - Do it all and return a text
233 * that could be used as a statement
234 * to recreate the rule
238 pg_get_ruledef(PG_FUNCTION_ARGS)
240 Oid ruleoid = PG_GETARG_OID(0);
242 PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, 0)));
247 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
249 Oid ruleoid = PG_GETARG_OID(0);
250 bool pretty = PG_GETARG_BOOL(1);
253 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
254 PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));
259 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
269 * Do this first so that string is alloc'd in outer context not SPI's.
271 initStringInfo(&buf);
274 * Connect to SPI manager
276 if (SPI_connect() != SPI_OK_CONNECT)
277 elog(ERROR, "SPI_connect failed");
280 * On the first call prepare the plan to lookup pg_rewrite. We read
281 * pg_rewrite over the SPI manager instead of using the syscache to be
282 * checked for read access on pg_rewrite.
284 if (plan_getrulebyoid == NULL)
289 argtypes[0] = OIDOID;
290 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
292 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
293 plan_getrulebyoid = SPI_saveplan(plan);
297 * Get the pg_rewrite tuple for this rule
299 args[0] = ObjectIdGetDatum(ruleoid);
301 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 1);
302 if (spirc != SPI_OK_SELECT)
303 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
304 if (SPI_processed != 1)
305 appendStringInfo(&buf, "-");
309 * Get the rule's definition and put it into executor's memory
311 ruletup = SPI_tuptable->vals[0];
312 rulettc = SPI_tuptable->tupdesc;
313 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
317 * Disconnect from SPI manager
319 if (SPI_finish() != SPI_OK_FINISH)
320 elog(ERROR, "SPI_finish failed");
327 * get_viewdef - Mainly the same thing, but we
328 * only return the SELECT part of a view
332 pg_get_viewdef(PG_FUNCTION_ARGS)
335 Oid viewoid = PG_GETARG_OID(0);
337 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
342 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
345 Oid viewoid = PG_GETARG_OID(0);
346 bool pretty = PG_GETARG_BOOL(1);
349 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
350 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
354 pg_get_viewdef_name(PG_FUNCTION_ARGS)
356 /* By qualified name */
357 text *viewname = PG_GETARG_TEXT_P(0);
361 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
362 viewoid = RangeVarGetRelid(viewrel, false);
364 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
369 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
371 /* By qualified name */
372 text *viewname = PG_GETARG_TEXT_P(0);
373 bool pretty = PG_GETARG_BOOL(1);
378 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
379 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
380 viewoid = RangeVarGetRelid(viewrel, false);
382 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
386 * Common code for by-OID and by-name variants of pg_get_viewdef
389 pg_get_viewdef_worker(Oid viewoid, int prettyFlags)
399 * Do this first so that string is alloc'd in outer context not SPI's.
401 initStringInfo(&buf);
404 * Connect to SPI manager
406 if (SPI_connect() != SPI_OK_CONNECT)
407 elog(ERROR, "SPI_connect failed");
410 * On the first call prepare the plan to lookup pg_rewrite. We read
411 * pg_rewrite over the SPI manager instead of using the syscache to be
412 * checked for read access on pg_rewrite.
414 if (plan_getviewrule == NULL)
419 argtypes[0] = OIDOID;
420 argtypes[1] = NAMEOID;
421 plan = SPI_prepare(query_getviewrule, 2, argtypes);
423 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
424 plan_getviewrule = SPI_saveplan(plan);
428 * Get the pg_rewrite tuple for the view's SELECT rule
430 args[0] = ObjectIdGetDatum(viewoid);
431 args[1] = PointerGetDatum(ViewSelectRuleName);
434 spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 2);
435 if (spirc != SPI_OK_SELECT)
436 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
437 if (SPI_processed != 1)
438 appendStringInfo(&buf, "Not a view");
442 * Get the rule's definition and put it into executor's memory
444 ruletup = SPI_tuptable->vals[0];
445 rulettc = SPI_tuptable->tupdesc;
446 make_viewdef(&buf, ruletup, rulettc, prettyFlags);
450 * Disconnect from SPI manager
452 if (SPI_finish() != SPI_OK_FINISH)
453 elog(ERROR, "SPI_finish failed");
459 * get_triggerdef - Get the definition of a trigger
463 pg_get_triggerdef(PG_FUNCTION_ARGS)
465 Oid trigid = PG_GETARG_OID(0);
467 PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, false)));
471 pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
473 Oid trigid = PG_GETARG_OID(0);
474 bool pretty = PG_GETARG_BOOL(1);
476 PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, pretty)));
480 pg_get_triggerdef_worker(Oid trigid, bool pretty)
483 Form_pg_trigger trigrec;
492 * Fetch the pg_trigger tuple by the Oid of the trigger
494 tgrel = heap_open(TriggerRelationId, AccessShareLock);
496 ScanKeyInit(&skey[0],
497 ObjectIdAttributeNumber,
498 BTEqualStrategyNumber, F_OIDEQ,
499 ObjectIdGetDatum(trigid));
501 tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
502 SnapshotNow, 1, skey);
504 ht_trig = systable_getnext(tgscan);
506 if (!HeapTupleIsValid(ht_trig))
507 elog(ERROR, "could not find tuple for trigger %u", trigid);
509 trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
512 * Start the trigger definition. Note that the trigger's name should never
513 * be schema-qualified, but the trigger rel's name may be.
515 initStringInfo(&buf);
517 tgname = NameStr(trigrec->tgname);
518 appendStringInfo(&buf, "CREATE %sTRIGGER %s",
519 trigrec->tgisconstraint ? "CONSTRAINT " : "",
520 quote_identifier(tgname));
521 appendStringInfoString(&buf, pretty ? "\n " : " ");
523 if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
524 appendStringInfo(&buf, "BEFORE");
526 appendStringInfo(&buf, "AFTER");
527 if (TRIGGER_FOR_INSERT(trigrec->tgtype))
529 appendStringInfo(&buf, " INSERT");
532 if (TRIGGER_FOR_DELETE(trigrec->tgtype))
535 appendStringInfo(&buf, " OR DELETE");
537 appendStringInfo(&buf, " DELETE");
540 if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
543 appendStringInfo(&buf, " OR UPDATE");
545 appendStringInfo(&buf, " UPDATE");
546 /* tgattr is first var-width field, so OK to access directly */
547 if (trigrec->tgattr.dim1 > 0)
551 appendStringInfoString(&buf, " OF ");
552 for (i = 0; i < trigrec->tgattr.dim1; i++)
557 appendStringInfoString(&buf, ", ");
558 attname = get_relid_attribute_name(trigrec->tgrelid,
559 trigrec->tgattr.values[i]);
560 appendStringInfoString(&buf, quote_identifier(attname));
564 if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
567 appendStringInfo(&buf, " OR TRUNCATE");
569 appendStringInfo(&buf, " TRUNCATE");
571 appendStringInfo(&buf, " ON %s",
572 generate_relation_name(trigrec->tgrelid, NIL));
573 appendStringInfoString(&buf, pretty ? "\n " : " ");
575 if (trigrec->tgisconstraint)
577 if (trigrec->tgconstrrelid != InvalidOid)
579 appendStringInfo(&buf, "FROM %s",
580 generate_relation_name(trigrec->tgconstrrelid, NIL));
581 appendStringInfoString(&buf, pretty ? "\n " : " ");
583 if (!trigrec->tgdeferrable)
584 appendStringInfo(&buf, "NOT ");
585 appendStringInfo(&buf, "DEFERRABLE INITIALLY ");
586 if (trigrec->tginitdeferred)
587 appendStringInfo(&buf, "DEFERRED");
589 appendStringInfo(&buf, "IMMEDIATE");
590 appendStringInfoString(&buf, pretty ? "\n " : " ");
593 if (TRIGGER_FOR_ROW(trigrec->tgtype))
594 appendStringInfo(&buf, "FOR EACH ROW");
596 appendStringInfo(&buf, "FOR EACH STATEMENT");
597 appendStringInfoString(&buf, pretty ? "\n " : " ");
599 appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
600 generate_function_name(trigrec->tgfoid, 0,
603 if (trigrec->tgnargs > 0)
610 val = DatumGetByteaP(fastgetattr(ht_trig,
611 Anum_pg_trigger_tgargs,
612 tgrel->rd_att, &isnull));
614 elog(ERROR, "tgargs is null for trigger %u", trigid);
615 p = (char *) VARDATA(val);
616 for (i = 0; i < trigrec->tgnargs; i++)
619 appendStringInfo(&buf, ", ");
620 simple_quote_literal(&buf, p);
621 /* advance p to next string embedded in tgargs */
628 /* We deliberately do not put semi-colon at end */
629 appendStringInfo(&buf, ")");
632 systable_endscan(tgscan);
634 heap_close(tgrel, AccessShareLock);
640 * get_indexdef - Get the definition of an index
642 * In the extended version, there is a colno argument as well as pretty bool.
643 * if colno == 0, we want a complete index definition.
644 * if colno > 0, we only want the Nth index key's variable or expression.
646 * Note that the SQL-function versions of this omit any info about the
647 * index tablespace; this is intentional because pg_dump wants it that way.
648 * However pg_get_indexdef_string() includes index tablespace if not default.
652 pg_get_indexdef(PG_FUNCTION_ARGS)
654 Oid indexrelid = PG_GETARG_OID(0);
656 PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0,
661 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
663 Oid indexrelid = PG_GETARG_OID(0);
664 int32 colno = PG_GETARG_INT32(1);
665 bool pretty = PG_GETARG_BOOL(2);
668 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
669 PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno,
675 /* Internal version that returns a palloc'd C string */
677 pg_get_indexdef_string(Oid indexrelid)
679 return pg_get_indexdef_worker(indexrelid, 0, false, true, 0);
682 /* Internal version that just reports the column definitions */
684 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
688 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
689 return pg_get_indexdef_worker(indexrelid, 0, true, false, prettyFlags);
693 pg_get_indexdef_worker(Oid indexrelid, int colno,
694 bool attrsOnly, bool showTblSpc,
700 Form_pg_index idxrec;
701 Form_pg_class idxrelrec;
704 ListCell *indexpr_item;
710 Datum indoptionDatum;
713 int2vector *indoption;
719 * Fetch the pg_index tuple by the Oid of the index
721 ht_idx = SearchSysCache(INDEXRELID,
722 ObjectIdGetDatum(indexrelid),
724 if (!HeapTupleIsValid(ht_idx))
725 elog(ERROR, "cache lookup failed for index %u", indexrelid);
726 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
728 indrelid = idxrec->indrelid;
729 Assert(indexrelid == idxrec->indexrelid);
731 /* Must get indclass and indoption the hard way */
732 indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
733 Anum_pg_index_indclass, &isnull);
735 indclass = (oidvector *) DatumGetPointer(indclassDatum);
736 indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
737 Anum_pg_index_indoption, &isnull);
739 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
742 * Fetch the pg_class tuple of the index relation
744 ht_idxrel = SearchSysCache(RELOID,
745 ObjectIdGetDatum(indexrelid),
747 if (!HeapTupleIsValid(ht_idxrel))
748 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
749 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
752 * Fetch the pg_am tuple of the index' access method
754 ht_am = SearchSysCache(AMOID,
755 ObjectIdGetDatum(idxrelrec->relam),
757 if (!HeapTupleIsValid(ht_am))
758 elog(ERROR, "cache lookup failed for access method %u",
760 amrec = (Form_pg_am) GETSTRUCT(ht_am);
763 * Get the index expressions, if any. (NOTE: we do not use the relcache
764 * versions of the expressions and predicate, because we want to display
765 * non-const-folded expressions.)
767 if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
773 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
774 Anum_pg_index_indexprs, &isnull);
776 exprsString = TextDatumGetCString(exprsDatum);
777 indexprs = (List *) stringToNode(exprsString);
783 indexpr_item = list_head(indexprs);
785 context = deparse_context_for(get_rel_name(indrelid), indrelid);
788 * Start the index definition. Note that the index's name should never be
789 * schema-qualified, but the indexed rel's name may be.
791 initStringInfo(&buf);
794 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
795 idxrec->indisunique ? "UNIQUE " : "",
796 quote_identifier(NameStr(idxrelrec->relname)),
797 generate_relation_name(indrelid, NIL),
798 quote_identifier(NameStr(amrec->amname)));
801 * Report the indexed attributes
804 for (keyno = 0; keyno < idxrec->indnatts; keyno++)
806 AttrNumber attnum = idxrec->indkey.values[keyno];
807 int16 opt = indoption->values[keyno];
810 appendStringInfoString(&buf, sep);
815 /* Simple index column */
818 attname = get_relid_attribute_name(indrelid, attnum);
819 if (!colno || colno == keyno + 1)
820 appendStringInfoString(&buf, quote_identifier(attname));
821 keycoltype = get_atttype(indrelid, attnum);
825 /* expressional index */
828 if (indexpr_item == NULL)
829 elog(ERROR, "too few entries in indexprs list");
830 indexkey = (Node *) lfirst(indexpr_item);
831 indexpr_item = lnext(indexpr_item);
833 str = deparse_expression_pretty(indexkey, context, false, false,
835 if (!colno || colno == keyno + 1)
837 /* Need parens if it's not a bare function call */
838 if (indexkey && IsA(indexkey, FuncExpr) &&
839 ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
840 appendStringInfoString(&buf, str);
842 appendStringInfo(&buf, "(%s)", str);
844 keycoltype = exprType(indexkey);
847 if (!attrsOnly && (!colno || colno == keyno + 1))
849 /* Add the operator class name, if not default */
850 get_opclass_name(indclass->values[keyno], keycoltype, &buf);
852 /* Add options if relevant */
853 if (amrec->amcanorder)
855 /* if it supports sort ordering, report DESC and NULLS opts */
856 if (opt & INDOPTION_DESC)
858 appendStringInfo(&buf, " DESC");
859 /* NULLS FIRST is the default in this case */
860 if (!(opt & INDOPTION_NULLS_FIRST))
861 appendStringInfo(&buf, " NULLS LAST");
865 if (opt & INDOPTION_NULLS_FIRST)
866 appendStringInfo(&buf, " NULLS FIRST");
874 appendStringInfoChar(&buf, ')');
877 * If it has options, append "WITH (options)"
879 str = flatten_reloptions(indexrelid);
882 appendStringInfo(&buf, " WITH (%s)", str);
887 * If it's in a nondefault tablespace, say so, but only if requested
893 tblspc = get_rel_tablespace(indexrelid);
894 if (OidIsValid(tblspc))
895 appendStringInfo(&buf, " TABLESPACE %s",
896 quote_identifier(get_tablespace_name(tblspc)));
900 * If it's a partial index, decompile and append the predicate
902 if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
909 /* Convert text string to node tree */
910 predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
911 Anum_pg_index_indpred, &isnull);
913 predString = TextDatumGetCString(predDatum);
914 node = (Node *) stringToNode(predString);
918 str = deparse_expression_pretty(node, context, false, false,
920 appendStringInfo(&buf, " WHERE %s", str);
925 ReleaseSysCache(ht_idx);
926 ReleaseSysCache(ht_idxrel);
927 ReleaseSysCache(ht_am);
934 * pg_get_constraintdef
936 * Returns the definition for the constraint, ie, everything that needs to
937 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
940 pg_get_constraintdef(PG_FUNCTION_ARGS)
942 Oid constraintId = PG_GETARG_OID(0);
944 PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
949 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
951 Oid constraintId = PG_GETARG_OID(0);
952 bool pretty = PG_GETARG_BOOL(1);
955 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
956 PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
957 false, prettyFlags)));
960 /* Internal version that returns a palloc'd C string */
962 pg_get_constraintdef_string(Oid constraintId)
964 return pg_get_constraintdef_worker(constraintId, true, 0);
968 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
972 Form_pg_constraint conForm;
975 tup = SearchSysCache(CONSTROID,
976 ObjectIdGetDatum(constraintId),
978 if (!HeapTupleIsValid(tup)) /* should not happen */
979 elog(ERROR, "cache lookup failed for constraint %u", constraintId);
980 conForm = (Form_pg_constraint) GETSTRUCT(tup);
982 initStringInfo(&buf);
984 if (fullCommand && OidIsValid(conForm->conrelid))
986 appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
987 generate_relation_name(conForm->conrelid, NIL),
988 quote_identifier(NameStr(conForm->conname)));
991 switch (conForm->contype)
993 case CONSTRAINT_FOREIGN:
999 /* Start off the constraint definition */
1000 appendStringInfo(&buf, "FOREIGN KEY (");
1002 /* Fetch and build referencing-column list */
1003 val = SysCacheGetAttr(CONSTROID, tup,
1004 Anum_pg_constraint_conkey, &isnull);
1006 elog(ERROR, "null conkey for constraint %u",
1009 decompile_column_index_array(val, conForm->conrelid, &buf);
1011 /* add foreign relation name */
1012 appendStringInfo(&buf, ") REFERENCES %s(",
1013 generate_relation_name(conForm->confrelid,
1016 /* Fetch and build referenced-column list */
1017 val = SysCacheGetAttr(CONSTROID, tup,
1018 Anum_pg_constraint_confkey, &isnull);
1020 elog(ERROR, "null confkey for constraint %u",
1023 decompile_column_index_array(val, conForm->confrelid, &buf);
1025 appendStringInfo(&buf, ")");
1027 /* Add match type */
1028 switch (conForm->confmatchtype)
1030 case FKCONSTR_MATCH_FULL:
1031 string = " MATCH FULL";
1033 case FKCONSTR_MATCH_PARTIAL:
1034 string = " MATCH PARTIAL";
1036 case FKCONSTR_MATCH_UNSPECIFIED:
1040 elog(ERROR, "unrecognized confmatchtype: %d",
1041 conForm->confmatchtype);
1042 string = ""; /* keep compiler quiet */
1045 appendStringInfoString(&buf, string);
1047 /* Add ON UPDATE and ON DELETE clauses, if needed */
1048 switch (conForm->confupdtype)
1050 case FKCONSTR_ACTION_NOACTION:
1051 string = NULL; /* suppress default */
1053 case FKCONSTR_ACTION_RESTRICT:
1054 string = "RESTRICT";
1056 case FKCONSTR_ACTION_CASCADE:
1059 case FKCONSTR_ACTION_SETNULL:
1060 string = "SET NULL";
1062 case FKCONSTR_ACTION_SETDEFAULT:
1063 string = "SET DEFAULT";
1066 elog(ERROR, "unrecognized confupdtype: %d",
1067 conForm->confupdtype);
1068 string = NULL; /* keep compiler quiet */
1072 appendStringInfo(&buf, " ON UPDATE %s", string);
1074 switch (conForm->confdeltype)
1076 case FKCONSTR_ACTION_NOACTION:
1077 string = NULL; /* suppress default */
1079 case FKCONSTR_ACTION_RESTRICT:
1080 string = "RESTRICT";
1082 case FKCONSTR_ACTION_CASCADE:
1085 case FKCONSTR_ACTION_SETNULL:
1086 string = "SET NULL";
1088 case FKCONSTR_ACTION_SETDEFAULT:
1089 string = "SET DEFAULT";
1092 elog(ERROR, "unrecognized confdeltype: %d",
1093 conForm->confdeltype);
1094 string = NULL; /* keep compiler quiet */
1098 appendStringInfo(&buf, " ON DELETE %s", string);
1102 case CONSTRAINT_PRIMARY:
1103 case CONSTRAINT_UNIQUE:
1109 /* Start off the constraint definition */
1110 if (conForm->contype == CONSTRAINT_PRIMARY)
1111 appendStringInfo(&buf, "PRIMARY KEY (");
1113 appendStringInfo(&buf, "UNIQUE (");
1115 /* Fetch and build target column list */
1116 val = SysCacheGetAttr(CONSTROID, tup,
1117 Anum_pg_constraint_conkey, &isnull);
1119 elog(ERROR, "null conkey for constraint %u",
1122 decompile_column_index_array(val, conForm->conrelid, &buf);
1124 appendStringInfo(&buf, ")");
1126 indexId = get_constraint_index(constraintId);
1128 /* XXX why do we only print these bits if fullCommand? */
1129 if (fullCommand && OidIsValid(indexId))
1131 char *options = flatten_reloptions(indexId);
1136 appendStringInfo(&buf, " WITH (%s)", options);
1140 tblspc = get_rel_tablespace(indexId);
1141 if (OidIsValid(tblspc))
1142 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
1143 quote_identifier(get_tablespace_name(tblspc)));
1148 case CONSTRAINT_CHECK:
1157 /* Fetch constraint expression in parsetree form */
1158 val = SysCacheGetAttr(CONSTROID, tup,
1159 Anum_pg_constraint_conbin, &isnull);
1161 elog(ERROR, "null conbin for constraint %u",
1164 conbin = TextDatumGetCString(val);
1165 expr = stringToNode(conbin);
1167 /* Set up deparsing context for Var nodes in constraint */
1168 if (conForm->conrelid != InvalidOid)
1170 /* relation constraint */
1171 context = deparse_context_for(get_rel_name(conForm->conrelid),
1176 /* domain constraint --- can't have Vars */
1180 consrc = deparse_expression_pretty(expr, context, false, false,
1184 * Now emit the constraint definition. There are cases where
1185 * the constraint expression will be fully parenthesized and
1186 * we don't need the outer parens ... but there are other
1187 * cases where we do need 'em. Be conservative for now.
1189 * Note that simply checking for leading '(' and trailing ')'
1190 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
1192 appendStringInfo(&buf, "CHECK (%s)", consrc);
1197 elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
1201 if (conForm->condeferrable)
1202 appendStringInfo(&buf, " DEFERRABLE");
1203 if (conForm->condeferred)
1204 appendStringInfo(&buf, " INITIALLY DEFERRED");
1207 ReleaseSysCache(tup);
1214 * Convert an int16[] Datum into a comma-separated list of column names
1215 * for the indicated relation; append the list to buf.
1218 decompile_column_index_array(Datum column_index_array, Oid relId,
1225 /* Extract data from array of int16 */
1226 deconstruct_array(DatumGetArrayTypeP(column_index_array),
1227 INT2OID, 2, true, 's',
1228 &keys, NULL, &nKeys);
1230 for (j = 0; j < nKeys; j++)
1234 colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
1237 appendStringInfoString(buf, quote_identifier(colName));
1239 appendStringInfo(buf, ", %s", quote_identifier(colName));
1245 * get_expr - Decompile an expression tree
1247 * Input: an expression tree in nodeToString form, and a relation OID
1249 * Output: reverse-listed expression
1251 * Currently, the expression can only refer to a single relation, namely
1252 * the one specified by the second parameter. This is sufficient for
1253 * partial indexes, column default expressions, etc. We also support
1254 * Var-free expressions, for which the OID can be InvalidOid.
1258 pg_get_expr(PG_FUNCTION_ARGS)
1260 text *expr = PG_GETARG_TEXT_P(0);
1261 Oid relid = PG_GETARG_OID(1);
1264 if (OidIsValid(relid))
1266 /* Get the name for the relation */
1267 relname = get_rel_name(relid);
1270 * If the OID isn't actually valid, don't throw an error, just return
1271 * NULL. This is a bit questionable, but it's what we've done
1272 * historically, and it can help avoid unwanted failures when
1273 * examining catalog entries for just-deleted relations.
1275 if (relname == NULL)
1281 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, 0));
1285 pg_get_expr_ext(PG_FUNCTION_ARGS)
1287 text *expr = PG_GETARG_TEXT_P(0);
1288 Oid relid = PG_GETARG_OID(1);
1289 bool pretty = PG_GETARG_BOOL(2);
1293 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
1295 if (OidIsValid(relid))
1297 /* Get the name for the relation */
1298 relname = get_rel_name(relid);
1299 /* See notes above */
1300 if (relname == NULL)
1306 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
1310 pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
1317 /* Convert input TEXT object to C string */
1318 exprstr = text_to_cstring(expr);
1320 /* Convert expression to node tree */
1321 node = (Node *) stringToNode(exprstr);
1325 /* Prepare deparse context if needed */
1326 if (OidIsValid(relid))
1327 context = deparse_context_for(relname, relid);
1332 str = deparse_expression_pretty(node, context, false, false,
1335 return string_to_text(str);
1340 * get_userbyid - Get a user name by roleid and
1341 * fallback to 'unknown (OID=n)'
1345 pg_get_userbyid(PG_FUNCTION_ARGS)
1347 Oid roleid = PG_GETARG_OID(0);
1350 Form_pg_authid role_rec;
1353 * Allocate space for the result
1355 result = (Name) palloc(NAMEDATALEN);
1356 memset(NameStr(*result), 0, NAMEDATALEN);
1359 * Get the pg_authid entry and print the result
1361 roletup = SearchSysCache(AUTHOID,
1362 ObjectIdGetDatum(roleid),
1364 if (HeapTupleIsValid(roletup))
1366 role_rec = (Form_pg_authid) GETSTRUCT(roletup);
1367 StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);
1368 ReleaseSysCache(roletup);
1371 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
1373 PG_RETURN_NAME(result);
1378 * pg_get_serial_sequence
1379 * Get the name of the sequence used by a serial column,
1380 * formatted suitably for passing to setval, nextval or currval.
1381 * First parameter is not treated as double-quoted, second parameter
1382 * is --- see documentation for reason.
1385 pg_get_serial_sequence(PG_FUNCTION_ARGS)
1387 text *tablename = PG_GETARG_TEXT_P(0);
1388 text *columnname = PG_GETARG_TEXT_PP(1);
1393 Oid sequenceId = InvalidOid;
1399 /* Get the OID of the table */
1400 tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1401 tableOid = RangeVarGetRelid(tablerv, false);
1403 /* Get the number of the column */
1404 column = text_to_cstring(columnname);
1406 attnum = get_attnum(tableOid, column);
1407 if (attnum == InvalidAttrNumber)
1409 (errcode(ERRCODE_UNDEFINED_COLUMN),
1410 errmsg("column \"%s\" of relation \"%s\" does not exist",
1411 column, tablerv->relname)));
1413 /* Search the dependency table for the dependent sequence */
1414 depRel = heap_open(DependRelationId, AccessShareLock);
1416 ScanKeyInit(&key[0],
1417 Anum_pg_depend_refclassid,
1418 BTEqualStrategyNumber, F_OIDEQ,
1419 ObjectIdGetDatum(RelationRelationId));
1420 ScanKeyInit(&key[1],
1421 Anum_pg_depend_refobjid,
1422 BTEqualStrategyNumber, F_OIDEQ,
1423 ObjectIdGetDatum(tableOid));
1424 ScanKeyInit(&key[2],
1425 Anum_pg_depend_refobjsubid,
1426 BTEqualStrategyNumber, F_INT4EQ,
1427 Int32GetDatum(attnum));
1429 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1430 SnapshotNow, 3, key);
1432 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1434 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1437 * We assume any auto dependency of a sequence on a column must be
1438 * what we are looking for. (We need the relkind test because indexes
1439 * can also have auto dependencies on columns.)
1441 if (deprec->classid == RelationRelationId &&
1442 deprec->objsubid == 0 &&
1443 deprec->deptype == DEPENDENCY_AUTO &&
1444 get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
1446 sequenceId = deprec->objid;
1451 systable_endscan(scan);
1452 heap_close(depRel, AccessShareLock);
1454 if (OidIsValid(sequenceId))
1457 Form_pg_class classtuple;
1461 /* Get the sequence's pg_class entry */
1462 classtup = SearchSysCache(RELOID,
1463 ObjectIdGetDatum(sequenceId),
1465 if (!HeapTupleIsValid(classtup))
1466 elog(ERROR, "cache lookup failed for relation %u", sequenceId);
1467 classtuple = (Form_pg_class) GETSTRUCT(classtup);
1469 /* Get the namespace */
1470 nspname = get_namespace_name(classtuple->relnamespace);
1472 elog(ERROR, "cache lookup failed for namespace %u",
1473 classtuple->relnamespace);
1475 /* And construct the result string */
1476 result = quote_qualified_identifier(nspname,
1477 NameStr(classtuple->relname));
1479 ReleaseSysCache(classtup);
1481 PG_RETURN_TEXT_P(string_to_text(result));
1489 * pg_get_functiondef
1490 * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
1491 * the specified function.
1494 pg_get_functiondef(PG_FUNCTION_ARGS)
1496 Oid funcid = PG_GETARG_OID(0);
1502 Form_pg_language lang;
1511 initStringInfo(&buf);
1513 /* Look up the function */
1514 proctup = SearchSysCache(PROCOID,
1515 ObjectIdGetDatum(funcid),
1517 if (!HeapTupleIsValid(proctup))
1518 elog(ERROR, "cache lookup failed for function %u", funcid);
1519 proc = (Form_pg_proc) GETSTRUCT(proctup);
1520 name = NameStr(proc->proname);
1524 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1525 errmsg("\"%s\" is an aggregate function", name)));
1527 /* Need its pg_language tuple for the language name */
1528 langtup = SearchSysCache(LANGOID,
1529 ObjectIdGetDatum(proc->prolang),
1531 if (!HeapTupleIsValid(langtup))
1532 elog(ERROR, "cache lookup failed for language %u", proc->prolang);
1533 lang = (Form_pg_language) GETSTRUCT(langtup);
1536 * We always qualify the function name, to ensure the right function gets
1539 nsp = get_namespace_name(proc->pronamespace);
1540 appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
1541 quote_qualified_identifier(nsp, name));
1542 (void) print_function_arguments(&buf, proctup, false, true);
1543 appendStringInfoString(&buf, ")\n RETURNS ");
1544 print_function_rettype(&buf, proctup);
1545 appendStringInfo(&buf, "\n LANGUAGE %s\n",
1546 quote_identifier(NameStr(lang->lanname)));
1548 /* Emit some miscellaneous options on one line */
1551 if (proc->proiswindow)
1552 appendStringInfoString(&buf, " WINDOW");
1553 switch (proc->provolatile)
1555 case PROVOLATILE_IMMUTABLE:
1556 appendStringInfoString(&buf, " IMMUTABLE");
1558 case PROVOLATILE_STABLE:
1559 appendStringInfoString(&buf, " STABLE");
1561 case PROVOLATILE_VOLATILE:
1564 if (proc->proisstrict)
1565 appendStringInfoString(&buf, " STRICT");
1566 if (proc->prosecdef)
1567 appendStringInfoString(&buf, " SECURITY DEFINER");
1569 /* This code for the default cost and rows should match functioncmds.c */
1570 if (proc->prolang == INTERNALlanguageId ||
1571 proc->prolang == ClanguageId)
1575 if (proc->procost != procost)
1576 appendStringInfo(&buf, " COST %g", proc->procost);
1578 if (proc->prorows > 0 && proc->prorows != 1000)
1579 appendStringInfo(&buf, " ROWS %g", proc->prorows);
1581 if (oldlen != buf.len)
1582 appendStringInfoChar(&buf, '\n');
1584 /* Emit any proconfig options, one per line */
1585 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
1588 ArrayType *a = DatumGetArrayTypeP(tmp);
1591 Assert(ARR_ELEMTYPE(a) == TEXTOID);
1592 Assert(ARR_NDIM(a) == 1);
1593 Assert(ARR_LBOUND(a)[0] == 1);
1595 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
1599 d = array_ref(a, 1, &i,
1600 -1 /* varlenarray */ ,
1601 -1 /* TEXT's typlen */ ,
1602 false /* TEXT's typbyval */ ,
1603 'i' /* TEXT's typalign */ ,
1607 char *configitem = TextDatumGetCString(d);
1610 pos = strchr(configitem, '=');
1615 appendStringInfo(&buf, " SET %s TO ",
1616 quote_identifier(configitem));
1619 * Some GUC variable names are 'LIST' type and hence must not
1622 if (pg_strcasecmp(configitem, "DateStyle") == 0
1623 || pg_strcasecmp(configitem, "search_path") == 0)
1624 appendStringInfoString(&buf, pos);
1626 simple_quote_literal(&buf, pos);
1627 appendStringInfoChar(&buf, '\n');
1632 /* And finally the function definition ... */
1633 appendStringInfoString(&buf, "AS ");
1635 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
1638 simple_quote_literal(&buf, TextDatumGetCString(tmp));
1639 appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
1642 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull);
1644 elog(ERROR, "null prosrc");
1645 prosrc = TextDatumGetCString(tmp);
1648 * We always use dollar quoting. Figure out a suitable delimiter.
1650 * Since the user is likely to be editing the function body string, we
1651 * shouldn't use a short delimiter that he might easily create a conflict
1652 * with. Hence prefer "$function$", but extend if needed.
1654 initStringInfo(&dq);
1655 appendStringInfoString(&dq, "$function");
1656 while (strstr(prosrc, dq.data) != NULL)
1657 appendStringInfoChar(&dq, 'x');
1658 appendStringInfoChar(&dq, '$');
1660 appendStringInfoString(&buf, dq.data);
1661 appendStringInfoString(&buf, prosrc);
1662 appendStringInfoString(&buf, dq.data);
1664 appendStringInfoString(&buf, "\n");
1666 ReleaseSysCache(langtup);
1667 ReleaseSysCache(proctup);
1669 PG_RETURN_TEXT_P(string_to_text(buf.data));
1673 * pg_get_function_arguments
1674 * Get a nicely-formatted list of arguments for a function.
1675 * This is everything that would go between the parentheses in
1679 pg_get_function_arguments(PG_FUNCTION_ARGS)
1681 Oid funcid = PG_GETARG_OID(0);
1685 initStringInfo(&buf);
1687 proctup = SearchSysCache(PROCOID,
1688 ObjectIdGetDatum(funcid),
1690 if (!HeapTupleIsValid(proctup))
1691 elog(ERROR, "cache lookup failed for function %u", funcid);
1693 (void) print_function_arguments(&buf, proctup, false, true);
1695 ReleaseSysCache(proctup);
1697 PG_RETURN_TEXT_P(string_to_text(buf.data));
1701 * pg_get_function_identity_arguments
1702 * Get a formatted list of arguments for a function.
1703 * This is everything that would go between the parentheses in
1704 * ALTER FUNCTION, etc. In particular, don't print defaults.
1707 pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
1709 Oid funcid = PG_GETARG_OID(0);
1713 initStringInfo(&buf);
1715 proctup = SearchSysCache(PROCOID,
1716 ObjectIdGetDatum(funcid),
1718 if (!HeapTupleIsValid(proctup))
1719 elog(ERROR, "cache lookup failed for function %u", funcid);
1721 (void) print_function_arguments(&buf, proctup, false, false);
1723 ReleaseSysCache(proctup);
1725 PG_RETURN_TEXT_P(string_to_text(buf.data));
1729 * pg_get_function_result
1730 * Get a nicely-formatted version of the result type of a function.
1731 * This is what would appear after RETURNS in CREATE FUNCTION.
1734 pg_get_function_result(PG_FUNCTION_ARGS)
1736 Oid funcid = PG_GETARG_OID(0);
1740 initStringInfo(&buf);
1742 proctup = SearchSysCache(PROCOID,
1743 ObjectIdGetDatum(funcid),
1745 if (!HeapTupleIsValid(proctup))
1746 elog(ERROR, "cache lookup failed for function %u", funcid);
1748 print_function_rettype(&buf, proctup);
1750 ReleaseSysCache(proctup);
1752 PG_RETURN_TEXT_P(string_to_text(buf.data));
1756 * Guts of pg_get_function_result: append the function's return type
1757 * to the specified buffer.
1760 print_function_rettype(StringInfo buf, HeapTuple proctup)
1762 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
1764 StringInfoData rbuf;
1766 initStringInfo(&rbuf);
1768 if (proc->proretset)
1770 /* It might be a table function; try to print the arguments */
1771 appendStringInfoString(&rbuf, "TABLE(");
1772 ntabargs = print_function_arguments(&rbuf, proctup, true, false);
1774 appendStringInfoString(&rbuf, ")");
1776 resetStringInfo(&rbuf);
1781 /* Not a table function, so do the normal thing */
1782 if (proc->proretset)
1783 appendStringInfoString(&rbuf, "SETOF ");
1784 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
1787 appendStringInfoString(buf, rbuf.data);
1791 * Common code for pg_get_function_arguments and pg_get_function_result:
1792 * append the desired subset of arguments to buf. We print only TABLE
1793 * arguments when print_table_args is true, and all the others when it's false.
1794 * We print argument defaults only if print_defaults is true.
1795 * Function return value is the number of arguments printed.
1798 print_function_arguments(StringInfo buf, HeapTuple proctup,
1799 bool print_table_args, bool print_defaults)
1801 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
1809 ListCell *nextargdefault = NULL;
1812 numargs = get_func_arg_info(proctup,
1813 &argtypes, &argnames, &argmodes);
1815 nlackdefaults = numargs;
1816 if (print_defaults && proc->pronargdefaults > 0)
1818 Datum proargdefaults;
1821 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
1822 Anum_pg_proc_proargdefaults,
1829 str = TextDatumGetCString(proargdefaults);
1830 argdefaults = (List *) stringToNode(str);
1831 Assert(IsA(argdefaults, List));
1833 nextargdefault = list_head(argdefaults);
1834 /* nlackdefaults counts only *input* arguments lacking defaults */
1835 nlackdefaults = proc->pronargs - list_length(argdefaults);
1841 for (i = 0; i < numargs; i++)
1843 Oid argtype = argtypes[i];
1844 char *argname = argnames ? argnames[i] : NULL;
1845 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
1846 const char *modename;
1855 case PROARGMODE_INOUT:
1856 modename = "INOUT ";
1859 case PROARGMODE_OUT:
1863 case PROARGMODE_VARIADIC:
1864 modename = "VARIADIC ";
1867 case PROARGMODE_TABLE:
1872 elog(ERROR, "invalid parameter mode '%c'", argmode);
1873 modename = NULL; /* keep compiler quiet */
1878 inputargno++; /* this is a 1-based counter */
1880 if (print_table_args != (argmode == PROARGMODE_TABLE))
1884 appendStringInfoString(buf, ", ");
1885 appendStringInfoString(buf, modename);
1886 if (argname && argname[0])
1887 appendStringInfo(buf, "%s ", quote_identifier(argname));
1888 appendStringInfoString(buf, format_type_be(argtype));
1889 if (print_defaults && isinput && inputargno > nlackdefaults)
1893 Assert(nextargdefault != NULL);
1894 expr = (Node *) lfirst(nextargdefault);
1895 nextargdefault = lnext(nextargdefault);
1897 appendStringInfo(buf, " DEFAULT %s",
1898 deparse_expression(expr, NIL, false, false));
1908 * deparse_expression - General utility for deparsing expressions
1910 * calls deparse_expression_pretty with all prettyPrinting disabled
1913 deparse_expression(Node *expr, List *dpcontext,
1914 bool forceprefix, bool showimplicit)
1916 return deparse_expression_pretty(expr, dpcontext, forceprefix,
1917 showimplicit, 0, 0);
1921 * deparse_expression_pretty - General utility for deparsing expressions
1923 * expr is the node tree to be deparsed. It must be a transformed expression
1924 * tree (ie, not the raw output of gram.y).
1926 * dpcontext is a list of deparse_namespace nodes representing the context
1927 * for interpreting Vars in the node tree.
1929 * forceprefix is TRUE to force all Vars to be prefixed with their table names.
1931 * showimplicit is TRUE to force all implicit casts to be shown explicitly.
1933 * tries to pretty up the output according to prettyFlags and startIndent.
1935 * The result is a palloc'd string.
1939 deparse_expression_pretty(Node *expr, List *dpcontext,
1940 bool forceprefix, bool showimplicit,
1941 int prettyFlags, int startIndent)
1944 deparse_context context;
1946 initStringInfo(&buf);
1948 context.namespaces = dpcontext;
1949 context.windowClause = NIL;
1950 context.windowTList = NIL;
1951 context.varprefix = forceprefix;
1952 context.prettyFlags = prettyFlags;
1953 context.indentLevel = startIndent;
1955 get_rule_expr(expr, &context, showimplicit);
1961 * deparse_context_for - Build deparse context for a single relation
1963 * Given the reference name (alias) and OID of a relation, build deparsing
1964 * context for an expression referencing only that relation (as varno 1,
1965 * varlevelsup 0). This is sufficient for many uses of deparse_expression.
1969 deparse_context_for(const char *aliasname, Oid relid)
1971 deparse_namespace *dpns;
1974 dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));
1976 /* Build a minimal RTE for the rel */
1977 rte = makeNode(RangeTblEntry);
1978 rte->rtekind = RTE_RELATION;
1980 rte->eref = makeAlias(aliasname, NIL);
1982 rte->inFromCl = true;
1984 /* Build one-element rtable */
1985 dpns->rtable = list_make1(rte);
1987 dpns->subplans = NIL;
1988 dpns->outer_plan = dpns->inner_plan = NULL;
1990 /* Return a one-deep namespace stack */
1991 return list_make1(dpns);
1995 * deparse_context_for_plan - Build deparse context for a plan node
1997 * When deparsing an expression in a Plan tree, we might have to resolve
1998 * OUTER or INNER references. To do this, the caller must provide the
1999 * parent Plan node. In the normal case of a join plan node, OUTER and
2000 * INNER references can be resolved by drilling down into the left and
2001 * right child plans. A special case is that a nestloop inner indexscan
2002 * might have OUTER Vars, but the outer side of the join is not a child
2003 * plan node. To handle such cases the outer plan node must be passed
2004 * separately. (Pass NULL for outer_plan otherwise.)
2006 * Note: plan and outer_plan really ought to be declared as "Plan *", but
2007 * we use "Node *" to avoid having to include plannodes.h in builtins.h.
2009 * The plan's rangetable list must also be passed. We actually prefer to use
2010 * the rangetable to resolve simple Vars, but the plan inputs are necessary
2011 * for Vars that reference expressions computed in subplan target lists.
2013 * We also need the list of subplans associated with the Plan tree; this
2014 * is for resolving references to CTE subplans.
2017 deparse_context_for_plan(Node *plan, Node *outer_plan,
2018 List *rtable, List *subplans)
2020 deparse_namespace *dpns;
2022 dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));
2024 dpns->rtable = rtable;
2026 dpns->subplans = subplans;
2029 * Set up outer_plan and inner_plan from the Plan node (this includes
2030 * various special cases for particular Plan types).
2032 push_plan(dpns, (Plan *) plan);
2035 * If outer_plan is given, that overrides whatever we got from the plan.
2038 dpns->outer_plan = (Plan *) outer_plan;
2040 /* Return a one-deep namespace stack */
2041 return list_make1(dpns);
2045 * make_ruledef - reconstruct the CREATE RULE command
2046 * for a given pg_rewrite tuple
2050 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
2060 List *actions = NIL;
2066 * Get the attribute values from the rules tuple
2068 fno = SPI_fnumber(rulettc, "rulename");
2069 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2071 rulename = NameStr(*(DatumGetName(dat)));
2073 fno = SPI_fnumber(rulettc, "ev_type");
2074 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2076 ev_type = DatumGetChar(dat);
2078 fno = SPI_fnumber(rulettc, "ev_class");
2079 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2081 ev_class = DatumGetObjectId(dat);
2083 fno = SPI_fnumber(rulettc, "ev_attr");
2084 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2086 ev_attr = DatumGetInt16(dat);
2088 fno = SPI_fnumber(rulettc, "is_instead");
2089 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2091 is_instead = DatumGetBool(dat);
2093 /* these could be nulls */
2094 fno = SPI_fnumber(rulettc, "ev_qual");
2095 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2097 fno = SPI_fnumber(rulettc, "ev_action");
2098 ev_action = SPI_getvalue(ruletup, rulettc, fno);
2099 if (ev_action != NULL)
2100 actions = (List *) stringToNode(ev_action);
2103 * Build the rules definition text
2105 appendStringInfo(buf, "CREATE RULE %s AS",
2106 quote_identifier(rulename));
2108 if (prettyFlags & PRETTYFLAG_INDENT)
2109 appendStringInfoString(buf, "\n ON ");
2111 appendStringInfoString(buf, " ON ");
2113 /* The event the rule is fired for */
2117 appendStringInfo(buf, "SELECT");
2121 appendStringInfo(buf, "UPDATE");
2125 appendStringInfo(buf, "INSERT");
2129 appendStringInfo(buf, "DELETE");
2134 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2135 errmsg("rule \"%s\" has unsupported event type %d",
2136 rulename, ev_type)));
2140 /* The relation the rule is fired on */
2141 appendStringInfo(buf, " TO %s", generate_relation_name(ev_class, NIL));
2143 appendStringInfo(buf, ".%s",
2144 quote_identifier(get_relid_attribute_name(ev_class,
2147 /* If the rule has an event qualification, add it */
2148 if (ev_qual == NULL)
2150 if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
2154 deparse_context context;
2155 deparse_namespace dpns;
2157 if (prettyFlags & PRETTYFLAG_INDENT)
2158 appendStringInfoString(buf, "\n ");
2159 appendStringInfo(buf, " WHERE ");
2161 qual = stringToNode(ev_qual);
2164 * We need to make a context for recognizing any Vars in the qual
2165 * (which can only be references to OLD and NEW). Use the rtable of
2166 * the first query in the action list for this purpose.
2168 query = (Query *) linitial(actions);
2171 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
2172 * into the SELECT, and that's what we need to look at. (Ugly kluge
2173 * ... try to fix this when we redesign querytrees.)
2175 query = getInsertSelectQuery(query, NULL);
2177 /* Must acquire locks right away; see notes in get_query_def() */
2178 AcquireRewriteLocks(query);
2181 context.namespaces = list_make1(&dpns);
2182 context.windowClause = NIL;
2183 context.windowTList = NIL;
2184 context.varprefix = (list_length(query->rtable) != 1);
2185 context.prettyFlags = prettyFlags;
2186 context.indentLevel = PRETTYINDENT_STD;
2187 dpns.rtable = query->rtable;
2188 dpns.ctes = query->cteList;
2189 dpns.subplans = NIL;
2190 dpns.outer_plan = dpns.inner_plan = NULL;
2192 get_rule_expr(qual, &context, false);
2195 appendStringInfo(buf, " DO ");
2197 /* The INSTEAD keyword (if so) */
2199 appendStringInfo(buf, "INSTEAD ");
2201 /* Finally the rules actions */
2202 if (list_length(actions) > 1)
2207 appendStringInfo(buf, "(");
2208 foreach(action, actions)
2210 query = (Query *) lfirst(action);
2211 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2213 appendStringInfo(buf, ";\n");
2215 appendStringInfo(buf, "; ");
2217 appendStringInfo(buf, ");");
2219 else if (list_length(actions) == 0)
2221 appendStringInfo(buf, "NOTHING;");
2227 query = (Query *) linitial(actions);
2228 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2229 appendStringInfo(buf, ";");
2235 * make_viewdef - reconstruct the SELECT part of a
2240 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
2250 List *actions = NIL;
2251 Relation ev_relation;
2256 * Get the attribute values from the rules tuple
2258 fno = SPI_fnumber(rulettc, "ev_type");
2259 ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2261 fno = SPI_fnumber(rulettc, "ev_class");
2262 ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2264 fno = SPI_fnumber(rulettc, "ev_attr");
2265 ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2267 fno = SPI_fnumber(rulettc, "is_instead");
2268 is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2270 fno = SPI_fnumber(rulettc, "ev_qual");
2271 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2273 fno = SPI_fnumber(rulettc, "ev_action");
2274 ev_action = SPI_getvalue(ruletup, rulettc, fno);
2275 if (ev_action != NULL)
2276 actions = (List *) stringToNode(ev_action);
2278 if (list_length(actions) != 1)
2280 appendStringInfo(buf, "Not a view");
2284 query = (Query *) linitial(actions);
2286 if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
2287 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
2289 appendStringInfo(buf, "Not a view");
2293 ev_relation = heap_open(ev_class, AccessShareLock);
2295 get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
2297 appendStringInfo(buf, ";");
2299 heap_close(ev_relation, AccessShareLock);
2304 * get_query_def - Parse back one query parsetree
2306 * If resultDesc is not NULL, then it is the output tuple descriptor for
2307 * the view represented by a SELECT query.
2311 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
2312 TupleDesc resultDesc, int prettyFlags, int startIndent)
2314 deparse_context context;
2315 deparse_namespace dpns;
2318 * Before we begin to examine the query, acquire locks on referenced
2319 * relations, and fix up deleted columns in JOIN RTEs. This ensures
2320 * consistent results. Note we assume it's OK to scribble on the passed
2323 AcquireRewriteLocks(query);
2326 context.namespaces = lcons(&dpns, list_copy(parentnamespace));
2327 context.windowClause = NIL;
2328 context.windowTList = NIL;
2329 context.varprefix = (parentnamespace != NIL ||
2330 list_length(query->rtable) != 1);
2331 context.prettyFlags = prettyFlags;
2332 context.indentLevel = startIndent;
2334 dpns.rtable = query->rtable;
2335 dpns.ctes = query->cteList;
2336 dpns.subplans = NIL;
2337 dpns.outer_plan = dpns.inner_plan = NULL;
2339 switch (query->commandType)
2342 get_select_query_def(query, &context, resultDesc);
2346 get_update_query_def(query, &context);
2350 get_insert_query_def(query, &context);
2354 get_delete_query_def(query, &context);
2358 appendStringInfo(buf, "NOTHING");
2362 get_utility_query_def(query, &context);
2366 elog(ERROR, "unrecognized query command type: %d",
2367 query->commandType);
2373 * get_values_def - Parse back a VALUES list
2377 get_values_def(List *values_lists, deparse_context *context)
2379 StringInfo buf = context->buf;
2380 bool first_list = true;
2383 appendStringInfoString(buf, "VALUES ");
2385 foreach(vtl, values_lists)
2387 List *sublist = (List *) lfirst(vtl);
2388 bool first_col = true;
2394 appendStringInfoString(buf, ", ");
2396 appendStringInfoChar(buf, '(');
2397 foreach(lc, sublist)
2399 Node *col = (Node *) lfirst(lc);
2404 appendStringInfoChar(buf, ',');
2407 * Strip any top-level nodes representing indirection assignments,
2408 * then print the result.
2410 get_rule_expr(processIndirection(col, context, false),
2413 appendStringInfoChar(buf, ')');
2418 * get_with_clause - Parse back a WITH clause
2422 get_with_clause(Query *query, deparse_context *context)
2424 StringInfo buf = context->buf;
2428 if (query->cteList == NIL)
2431 if (PRETTY_INDENT(context))
2433 context->indentLevel += PRETTYINDENT_STD;
2434 appendStringInfoChar(buf, ' ');
2437 if (query->hasRecursive)
2438 sep = "WITH RECURSIVE ";
2441 foreach(l, query->cteList)
2443 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
2445 appendStringInfoString(buf, sep);
2446 appendStringInfoString(buf, quote_identifier(cte->ctename));
2447 if (cte->aliascolnames)
2452 appendStringInfoChar(buf, '(');
2453 foreach(col, cte->aliascolnames)
2458 appendStringInfoString(buf, ", ");
2459 appendStringInfoString(buf,
2460 quote_identifier(strVal(lfirst(col))));
2462 appendStringInfoChar(buf, ')');
2464 appendStringInfoString(buf, " AS (");
2465 if (PRETTY_INDENT(context))
2466 appendContextKeyword(context, "", 0, 0, 0);
2467 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
2468 context->prettyFlags, context->indentLevel);
2469 if (PRETTY_INDENT(context))
2470 appendContextKeyword(context, "", 0, 0, 0);
2471 appendStringInfoChar(buf, ')');
2475 if (PRETTY_INDENT(context))
2477 context->indentLevel -= PRETTYINDENT_STD;
2478 appendContextKeyword(context, "", 0, 0, 0);
2481 appendStringInfoChar(buf, ' ');
2485 * get_select_query_def - Parse back a SELECT parsetree
2489 get_select_query_def(Query *query, deparse_context *context,
2490 TupleDesc resultDesc)
2492 StringInfo buf = context->buf;
2493 List *save_windowclause;
2494 List *save_windowtlist;
2498 /* Insert the WITH clause if given */
2499 get_with_clause(query, context);
2501 /* Set up context for possible window functions */
2502 save_windowclause = context->windowClause;
2503 context->windowClause = query->windowClause;
2504 save_windowtlist = context->windowTList;
2505 context->windowTList = query->targetList;
2508 * If the Query node has a setOperations tree, then it's the top level of
2509 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
2510 * fields are interesting in the top query itself.
2512 if (query->setOperations)
2514 get_setop_query(query->setOperations, query, context, resultDesc);
2515 /* ORDER BY clauses must be simple in this case */
2520 get_basic_select_query(query, context, resultDesc);
2521 force_colno = false;
2524 /* Add the ORDER BY clause if given */
2525 if (query->sortClause != NIL)
2527 appendContextKeyword(context, " ORDER BY ",
2528 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2529 get_rule_orderby(query->sortClause, query->targetList,
2530 force_colno, context);
2533 /* Add the LIMIT clause if given */
2534 if (query->limitOffset != NULL)
2536 appendContextKeyword(context, " OFFSET ",
2537 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2538 get_rule_expr(query->limitOffset, context, false);
2540 if (query->limitCount != NULL)
2542 appendContextKeyword(context, " LIMIT ",
2543 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2544 if (IsA(query->limitCount, Const) &&
2545 ((Const *) query->limitCount)->constisnull)
2546 appendStringInfo(buf, "ALL");
2548 get_rule_expr(query->limitCount, context, false);
2551 /* Add FOR UPDATE/SHARE clauses if present */
2552 foreach(l, query->rowMarks)
2554 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
2555 RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);
2558 appendContextKeyword(context, " FOR UPDATE",
2559 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2561 appendContextKeyword(context, " FOR SHARE",
2562 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2563 appendStringInfo(buf, " OF %s",
2564 quote_identifier(rte->eref->aliasname));
2566 appendStringInfo(buf, " NOWAIT");
2569 context->windowClause = save_windowclause;
2570 context->windowTList = save_windowtlist;
2574 get_basic_select_query(Query *query, deparse_context *context,
2575 TupleDesc resultDesc)
2577 StringInfo buf = context->buf;
2581 if (PRETTY_INDENT(context))
2583 context->indentLevel += PRETTYINDENT_STD;
2584 appendStringInfoChar(buf, ' ');
2588 * If the query looks like SELECT * FROM (VALUES ...), then print just the
2589 * VALUES part. This reverses what transformValuesClause() did at parse
2590 * time. If the jointree contains just a single VALUES RTE, we assume
2591 * this case applies (without looking at the targetlist...)
2593 if (list_length(query->jointree->fromlist) == 1)
2595 RangeTblRef *rtr = (RangeTblRef *) linitial(query->jointree->fromlist);
2597 if (IsA(rtr, RangeTblRef))
2599 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
2601 if (rte->rtekind == RTE_VALUES)
2603 get_values_def(rte->values_lists, context);
2610 * Build up the query string - first we say SELECT
2612 appendStringInfo(buf, "SELECT");
2614 /* Add the DISTINCT clause if given */
2615 if (query->distinctClause != NIL)
2617 if (query->hasDistinctOn)
2619 appendStringInfo(buf, " DISTINCT ON (");
2621 foreach(l, query->distinctClause)
2623 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
2625 appendStringInfoString(buf, sep);
2626 get_rule_sortgroupclause(srt, query->targetList,
2630 appendStringInfo(buf, ")");
2633 appendStringInfo(buf, " DISTINCT");
2636 /* Then we tell what to select (the targetlist) */
2637 get_target_list(query->targetList, context, resultDesc);
2639 /* Add the FROM clause if needed */
2640 get_from_clause(query, " FROM ", context);
2642 /* Add the WHERE clause if given */
2643 if (query->jointree->quals != NULL)
2645 appendContextKeyword(context, " WHERE ",
2646 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2647 get_rule_expr(query->jointree->quals, context, false);
2650 /* Add the GROUP BY clause if given */
2651 if (query->groupClause != NULL)
2653 appendContextKeyword(context, " GROUP BY ",
2654 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2656 foreach(l, query->groupClause)
2658 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
2660 appendStringInfoString(buf, sep);
2661 get_rule_sortgroupclause(grp, query->targetList,
2667 /* Add the HAVING clause if given */
2668 if (query->havingQual != NULL)
2670 appendContextKeyword(context, " HAVING ",
2671 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2672 get_rule_expr(query->havingQual, context, false);
2675 /* Add the WINDOW clause if needed */
2676 if (query->windowClause != NIL)
2677 get_rule_windowclause(query, context);
2681 * get_target_list - Parse back a SELECT target list
2683 * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
2687 get_target_list(List *targetList, deparse_context *context,
2688 TupleDesc resultDesc)
2690 StringInfo buf = context->buf;
2697 foreach(l, targetList)
2699 TargetEntry *tle = (TargetEntry *) lfirst(l);
2704 continue; /* ignore junk entries */
2706 appendStringInfoString(buf, sep);
2711 * We special-case Var nodes rather than using get_rule_expr. This is
2712 * needed because get_rule_expr will display a whole-row Var as
2713 * "foo.*", which is the preferred notation in most contexts, but at
2714 * the top level of a SELECT list it's not right (the parser will
2715 * expand that notation into multiple columns, yielding behavior
2716 * different from a whole-row Var). We want just "foo", instead.
2718 if (tle->expr && IsA(tle->expr, Var))
2720 attname = get_variable((Var *) tle->expr, 0, false, context);
2724 get_rule_expr((Node *) tle->expr, context, true);
2725 /* We'll show the AS name unless it's this: */
2726 attname = "?column?";
2730 * Figure out what the result column should be called. In the context
2731 * of a view, use the view's tuple descriptor (so as to pick up the
2732 * effects of any column RENAME that's been done on the view).
2733 * Otherwise, just use what we can find in the TLE.
2735 if (resultDesc && colno <= resultDesc->natts)
2736 colname = NameStr(resultDesc->attrs[colno - 1]->attname);
2738 colname = tle->resname;
2740 /* Show AS unless the column's name is correct as-is */
2741 if (colname) /* resname could be NULL */
2743 if (attname == NULL || strcmp(attname, colname) != 0)
2744 appendStringInfo(buf, " AS %s", quote_identifier(colname));
2750 get_setop_query(Node *setOp, Query *query, deparse_context *context,
2751 TupleDesc resultDesc)
2753 StringInfo buf = context->buf;
2756 if (IsA(setOp, RangeTblRef))
2758 RangeTblRef *rtr = (RangeTblRef *) setOp;
2759 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
2760 Query *subquery = rte->subquery;
2762 Assert(subquery != NULL);
2763 Assert(subquery->setOperations == NULL);
2764 /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
2765 need_paren = (subquery->cteList ||
2766 subquery->sortClause ||
2767 subquery->rowMarks ||
2768 subquery->limitOffset ||
2769 subquery->limitCount);
2771 appendStringInfoChar(buf, '(');
2772 get_query_def(subquery, buf, context->namespaces, resultDesc,
2773 context->prettyFlags, context->indentLevel);
2775 appendStringInfoChar(buf, ')');
2777 else if (IsA(setOp, SetOperationStmt))
2779 SetOperationStmt *op = (SetOperationStmt *) setOp;
2781 if (PRETTY_INDENT(context))
2783 context->indentLevel += PRETTYINDENT_STD;
2784 appendStringInfoSpaces(buf, PRETTYINDENT_STD);
2788 * We force parens whenever nesting two SetOperationStmts. There are
2789 * some cases in which parens are needed around a leaf query too, but
2790 * those are more easily handled at the next level down (see code
2793 need_paren = !IsA(op->larg, RangeTblRef);
2796 appendStringInfoChar(buf, '(');
2797 get_setop_query(op->larg, query, context, resultDesc);
2799 appendStringInfoChar(buf, ')');
2801 if (!PRETTY_INDENT(context))
2802 appendStringInfoChar(buf, ' ');
2806 appendContextKeyword(context, "UNION ",
2807 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2809 case SETOP_INTERSECT:
2810 appendContextKeyword(context, "INTERSECT ",
2811 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2814 appendContextKeyword(context, "EXCEPT ",
2815 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2818 elog(ERROR, "unrecognized set op: %d",
2822 appendStringInfo(buf, "ALL ");
2824 if (PRETTY_INDENT(context))
2825 appendContextKeyword(context, "", 0, 0, 0);
2827 need_paren = !IsA(op->rarg, RangeTblRef);
2830 appendStringInfoChar(buf, '(');
2831 get_setop_query(op->rarg, query, context, resultDesc);
2833 appendStringInfoChar(buf, ')');
2835 if (PRETTY_INDENT(context))
2836 context->indentLevel -= PRETTYINDENT_STD;
2840 elog(ERROR, "unrecognized node type: %d",
2841 (int) nodeTag(setOp));
2846 * Display a sort/group clause.
2848 * Also returns the expression tree, so caller need not find it again.
2851 get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, bool force_colno,
2852 deparse_context *context)
2854 StringInfo buf = context->buf;
2858 tle = get_sortgroupclause_tle(srt, tlist);
2859 expr = (Node *) tle->expr;
2862 * Use column-number form if requested by caller. Otherwise, if
2863 * expression is a constant, force it to be dumped with an explicit cast
2864 * as decoration --- this is because a simple integer constant is
2865 * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
2866 * dump it without any decoration. Otherwise, just dump the expression
2871 Assert(!tle->resjunk);
2872 appendStringInfo(buf, "%d", tle->resno);
2874 else if (expr && IsA(expr, Const))
2875 get_const_expr((Const *) expr, context, 1);
2877 get_rule_expr(expr, context, true);
2883 * Display an ORDER BY list.
2886 get_rule_orderby(List *orderList, List *targetList,
2887 bool force_colno, deparse_context *context)
2889 StringInfo buf = context->buf;
2894 foreach(l, orderList)
2896 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
2899 TypeCacheEntry *typentry;
2901 appendStringInfoString(buf, sep);
2902 sortexpr = get_rule_sortgroupclause(srt, targetList,
2903 force_colno, context);
2904 sortcoltype = exprType(sortexpr);
2905 /* See whether operator is default < or > for datatype */
2906 typentry = lookup_type_cache(sortcoltype,
2907 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
2908 if (srt->sortop == typentry->lt_opr)
2910 /* ASC is default, so emit nothing for it */
2911 if (srt->nulls_first)
2912 appendStringInfo(buf, " NULLS FIRST");
2914 else if (srt->sortop == typentry->gt_opr)
2916 appendStringInfo(buf, " DESC");
2917 /* DESC defaults to NULLS FIRST */
2918 if (!srt->nulls_first)
2919 appendStringInfo(buf, " NULLS LAST");
2923 appendStringInfo(buf, " USING %s",
2924 generate_operator_name(srt->sortop,
2927 /* be specific to eliminate ambiguity */
2928 if (srt->nulls_first)
2929 appendStringInfo(buf, " NULLS FIRST");
2931 appendStringInfo(buf, " NULLS LAST");
2938 * Display a WINDOW clause.
2940 * Note that the windowClause list might contain only anonymous window
2941 * specifications, in which case we should print nothing here.
2944 get_rule_windowclause(Query *query, deparse_context *context)
2946 StringInfo buf = context->buf;
2951 foreach(l, query->windowClause)
2953 WindowClause *wc = (WindowClause *) lfirst(l);
2955 if (wc->name == NULL)
2956 continue; /* ignore anonymous windows */
2959 appendContextKeyword(context, " WINDOW ",
2960 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2962 appendStringInfoString(buf, sep);
2964 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
2966 get_rule_windowspec(wc, query->targetList, context);
2973 * Display a window definition
2976 get_rule_windowspec(WindowClause *wc, List *targetList,
2977 deparse_context *context)
2979 StringInfo buf = context->buf;
2980 bool needspace = false;
2984 appendStringInfoChar(buf, '(');
2987 appendStringInfoString(buf, quote_identifier(wc->refname));
2990 /* partition clauses are always inherited, so only print if no refname */
2991 if (wc->partitionClause && !wc->refname)
2994 appendStringInfoChar(buf, ' ');
2995 appendStringInfoString(buf, "PARTITION BY ");
2997 foreach(l, wc->partitionClause)
2999 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
3001 appendStringInfoString(buf, sep);
3002 get_rule_sortgroupclause(grp, targetList,
3008 /* print ordering clause only if not inherited */
3009 if (wc->orderClause && !wc->copiedOrder)
3012 appendStringInfoChar(buf, ' ');
3013 appendStringInfoString(buf, "ORDER BY ");
3014 get_rule_orderby(wc->orderClause, targetList, false, context);
3017 /* framing clause is never inherited, so print unless it's default */
3018 if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
3021 appendStringInfoChar(buf, ' ');
3022 if (wc->frameOptions & FRAMEOPTION_RANGE)
3023 appendStringInfoString(buf, "RANGE ");
3024 else if (wc->frameOptions & FRAMEOPTION_ROWS)
3025 appendStringInfoString(buf, "ROWS ");
3028 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
3029 appendStringInfoString(buf, "BETWEEN ");
3030 if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
3031 appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
3032 else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
3033 appendStringInfoString(buf, "CURRENT ROW ");
3036 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
3038 appendStringInfoString(buf, "AND ");
3039 if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
3040 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
3041 else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
3042 appendStringInfoString(buf, "CURRENT ROW ");
3046 /* we will now have a trailing space; remove it */
3049 appendStringInfoChar(buf, ')');
3053 * get_insert_query_def - Parse back an INSERT parsetree
3057 get_insert_query_def(Query *query, deparse_context *context)
3059 StringInfo buf = context->buf;
3060 RangeTblEntry *select_rte = NULL;
3061 RangeTblEntry *values_rte = NULL;
3064 ListCell *values_cell;
3066 List *strippedexprs;
3069 * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will be
3070 * a single RTE for the SELECT or VALUES.
3072 foreach(l, query->rtable)
3074 rte = (RangeTblEntry *) lfirst(l);
3076 if (rte->rtekind == RTE_SUBQUERY)
3079 elog(ERROR, "too many subquery RTEs in INSERT");
3083 if (rte->rtekind == RTE_VALUES)
3086 elog(ERROR, "too many values RTEs in INSERT");
3090 if (select_rte && values_rte)
3091 elog(ERROR, "both subquery and values RTEs in INSERT");
3094 * Start the query with INSERT INTO relname
3096 rte = rt_fetch(query->resultRelation, query->rtable);
3097 Assert(rte->rtekind == RTE_RELATION);
3099 if (PRETTY_INDENT(context))
3101 context->indentLevel += PRETTYINDENT_STD;
3102 appendStringInfoChar(buf, ' ');
3104 appendStringInfo(buf, "INSERT INTO %s (",
3105 generate_relation_name(rte->relid, NIL));
3108 * Add the insert-column-names list. To handle indirection properly, we
3109 * need to look for indirection nodes in the top targetlist (if it's
3110 * INSERT ... SELECT or INSERT ... single VALUES), or in the first
3111 * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We
3112 * assume that all the expression lists will have similar indirection in
3116 values_cell = list_head((List *) linitial(values_rte->values_lists));
3119 strippedexprs = NIL;
3121 foreach(l, query->targetList)
3123 TargetEntry *tle = (TargetEntry *) lfirst(l);
3126 continue; /* ignore junk entries */
3128 appendStringInfoString(buf, sep);
3132 * Put out name of target column; look in the catalogs, not at
3133 * tle->resname, since resname will fail to track RENAME.
3135 appendStringInfoString(buf,
3136 quote_identifier(get_relid_attribute_name(rte->relid,
3140 * Print any indirection needed (subfields or subscripts), and strip
3141 * off the top-level nodes representing the indirection assignments.
3145 /* we discard the stripped expression in this case */
3146 processIndirection((Node *) lfirst(values_cell), context, true);
3147 values_cell = lnext(values_cell);
3151 /* we keep a list of the stripped expressions in this case */
3152 strippedexprs = lappend(strippedexprs,
3153 processIndirection((Node *) tle->expr,
3157 appendStringInfo(buf, ") ");
3161 /* Add the SELECT */
3162 get_query_def(select_rte->subquery, buf, NIL, NULL,
3163 context->prettyFlags, context->indentLevel);
3165 else if (values_rte)
3167 /* A WITH clause is possible here */
3168 get_with_clause(query, context);
3169 /* Add the multi-VALUES expression lists */
3170 get_values_def(values_rte->values_lists, context);
3174 /* A WITH clause is possible here */
3175 get_with_clause(query, context);
3176 /* Add the single-VALUES expression list */
3177 appendContextKeyword(context, "VALUES (",
3178 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
3179 get_rule_expr((Node *) strippedexprs, context, false);
3180 appendStringInfoChar(buf, ')');
3183 /* Add RETURNING if present */
3184 if (query->returningList)
3186 appendContextKeyword(context, " RETURNING",
3187 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3188 get_target_list(query->returningList, context, NULL);
3194 * get_update_query_def - Parse back an UPDATE parsetree
3198 get_update_query_def(Query *query, deparse_context *context)
3200 StringInfo buf = context->buf;
3206 * Start the query with UPDATE relname SET
3208 rte = rt_fetch(query->resultRelation, query->rtable);
3209 Assert(rte->rtekind == RTE_RELATION);
3210 if (PRETTY_INDENT(context))
3212 appendStringInfoChar(buf, ' ');
3213 context->indentLevel += PRETTYINDENT_STD;
3215 appendStringInfo(buf, "UPDATE %s%s",
3217 generate_relation_name(rte->relid, NIL));
3218 if (rte->alias != NULL)
3219 appendStringInfo(buf, " %s",
3220 quote_identifier(rte->alias->aliasname));
3221 appendStringInfoString(buf, " SET ");
3223 /* Add the comma separated list of 'attname = value' */
3225 foreach(l, query->targetList)
3227 TargetEntry *tle = (TargetEntry *) lfirst(l);
3231 continue; /* ignore junk entries */
3233 appendStringInfoString(buf, sep);
3237 * Put out name of target column; look in the catalogs, not at
3238 * tle->resname, since resname will fail to track RENAME.
3240 appendStringInfoString(buf,
3241 quote_identifier(get_relid_attribute_name(rte->relid,
3245 * Print any indirection needed (subfields or subscripts), and strip
3246 * off the top-level nodes representing the indirection assignments.
3248 expr = processIndirection((Node *) tle->expr, context, true);
3250 appendStringInfo(buf, " = ");
3252 get_rule_expr(expr, context, false);
3255 /* Add the FROM clause if needed */
3256 get_from_clause(query, " FROM ", context);
3258 /* Add a WHERE clause if given */
3259 if (query->jointree->quals != NULL)
3261 appendContextKeyword(context, " WHERE ",
3262 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3263 get_rule_expr(query->jointree->quals, context, false);
3266 /* Add RETURNING if present */
3267 if (query->returningList)
3269 appendContextKeyword(context, " RETURNING",
3270 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3271 get_target_list(query->returningList, context, NULL);
3277 * get_delete_query_def - Parse back a DELETE parsetree
3281 get_delete_query_def(Query *query, deparse_context *context)
3283 StringInfo buf = context->buf;
3287 * Start the query with DELETE FROM relname
3289 rte = rt_fetch(query->resultRelation, query->rtable);
3290 Assert(rte->rtekind == RTE_RELATION);
3291 if (PRETTY_INDENT(context))
3293 appendStringInfoChar(buf, ' ');
3294 context->indentLevel += PRETTYINDENT_STD;
3296 appendStringInfo(buf, "DELETE FROM %s%s",
3298 generate_relation_name(rte->relid, NIL));
3299 if (rte->alias != NULL)
3300 appendStringInfo(buf, " %s",
3301 quote_identifier(rte->alias->aliasname));
3303 /* Add the USING clause if given */
3304 get_from_clause(query, " USING ", context);
3306 /* Add a WHERE clause if given */
3307 if (query->jointree->quals != NULL)
3309 appendContextKeyword(context, " WHERE ",
3310 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3311 get_rule_expr(query->jointree->quals, context, false);
3314 /* Add RETURNING if present */
3315 if (query->returningList)
3317 appendContextKeyword(context, " RETURNING",
3318 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3319 get_target_list(query->returningList, context, NULL);
3325 * get_utility_query_def - Parse back a UTILITY parsetree
3329 get_utility_query_def(Query *query, deparse_context *context)
3331 StringInfo buf = context->buf;
3333 if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
3335 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
3337 appendContextKeyword(context, "",
3338 0, PRETTYINDENT_STD, 1);
3339 appendStringInfo(buf, "NOTIFY %s",
3340 quote_identifier(stmt->conditionname));
3344 /* Currently only NOTIFY utility commands can appear in rules */
3345 elog(ERROR, "unexpected utility statement type");
3351 * push_plan: set up deparse_namespace to recurse into the tlist of a subplan
3353 * When expanding an OUTER or INNER reference, we must push new outer/inner
3354 * subplans in case the referenced expression itself uses OUTER/INNER. We
3355 * modify the top stack entry in-place to avoid affecting levelsup issues
3356 * (although in a Plan tree there really shouldn't be any).
3358 * Caller must save and restore outer_plan and inner_plan around this.
3360 * We also use this to initialize the fields during deparse_context_for_plan.
3363 push_plan(deparse_namespace *dpns, Plan *subplan)
3366 * We special-case ModifyTable to pretend that the first child plan is the
3367 * OUTER referent; otherwise normal. This is to support RETURNING lists
3368 * containing references to non-target relations.
3370 if (IsA(subplan, ModifyTable))
3371 dpns->outer_plan = (Plan *) linitial(((ModifyTable *) subplan)->plans);
3373 dpns->outer_plan = outerPlan(subplan);
3376 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
3377 * use OUTER because that could someday conflict with the normal meaning.)
3378 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
3380 if (IsA(subplan, SubqueryScan))
3381 dpns->inner_plan = ((SubqueryScan *) subplan)->subplan;
3382 else if (IsA(subplan, CteScan))
3384 int ctePlanId = ((CteScan *) subplan)->ctePlanId;
3386 if (ctePlanId > 0 && ctePlanId <= list_length(dpns->subplans))
3387 dpns->inner_plan = list_nth(dpns->subplans, ctePlanId - 1);
3389 dpns->inner_plan = NULL;
3392 dpns->inner_plan = innerPlan(subplan);
3397 * Display a Var appropriately.
3399 * In some cases (currently only when recursing into an unnamed join)
3400 * the Var's varlevelsup has to be interpreted with respect to a context
3401 * above the current one; levelsup indicates the offset.
3403 * If showstar is TRUE, whole-row Vars are displayed as "foo.*";
3404 * if FALSE, merely as "foo".
3406 * Returns the attname of the Var, or NULL if not determinable.
3409 get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
3411 StringInfo buf = context->buf;
3415 deparse_namespace *dpns;
3420 /* Find appropriate nesting depth */
3421 netlevelsup = var->varlevelsup + levelsup;
3422 if (netlevelsup >= list_length(context->namespaces))
3423 elog(ERROR, "bogus varlevelsup: %d offset %d",
3424 var->varlevelsup, levelsup);
3425 dpns = (deparse_namespace *) list_nth(context->namespaces,
3429 * Try to find the relevant RTE in this rtable. In a plan tree, it's
3430 * likely that varno is OUTER or INNER, in which case we must dig down
3431 * into the subplans.
3433 if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3435 rte = rt_fetch(var->varno, dpns->rtable);
3436 attnum = var->varattno;
3438 else if (var->varno == OUTER && dpns->outer_plan)
3444 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3446 elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3448 Assert(netlevelsup == 0);
3449 save_outer = dpns->outer_plan;
3450 save_inner = dpns->inner_plan;
3451 push_plan(dpns, dpns->outer_plan);
3454 * Force parentheses because our caller probably assumed a Var is a
3455 * simple expression.
3457 if (!IsA(tle->expr, Var))
3458 appendStringInfoChar(buf, '(');
3459 get_rule_expr((Node *) tle->expr, context, true);
3460 if (!IsA(tle->expr, Var))
3461 appendStringInfoChar(buf, ')');
3463 dpns->outer_plan = save_outer;
3464 dpns->inner_plan = save_inner;
3467 else if (var->varno == INNER && dpns->inner_plan)
3473 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3475 elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3477 Assert(netlevelsup == 0);
3478 save_outer = dpns->outer_plan;
3479 save_inner = dpns->inner_plan;
3480 push_plan(dpns, dpns->inner_plan);
3483 * Force parentheses because our caller probably assumed a Var is a
3484 * simple expression.
3486 if (!IsA(tle->expr, Var))
3487 appendStringInfoChar(buf, '(');
3488 get_rule_expr((Node *) tle->expr, context, true);
3489 if (!IsA(tle->expr, Var))
3490 appendStringInfoChar(buf, ')');
3492 dpns->outer_plan = save_outer;
3493 dpns->inner_plan = save_inner;
3498 elog(ERROR, "bogus varno: %d", var->varno);
3499 return NULL; /* keep compiler quiet */
3502 /* Identify names to use */
3503 schemaname = NULL; /* default assumptions */
3504 refname = rte->eref->aliasname;
3506 /* Exceptions occur only if the RTE is alias-less */
3507 if (rte->alias == NULL)
3509 if (rte->rtekind == RTE_RELATION)
3512 * It's possible that use of the bare refname would find another
3513 * more-closely-nested RTE, or be ambiguous, in which case we need
3514 * to specify the schemaname to avoid these errors.
3516 if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
3517 schemaname = get_namespace_name(get_rel_namespace(rte->relid));
3519 else if (rte->rtekind == RTE_JOIN)
3522 * If it's an unnamed join, look at the expansion of the alias
3523 * variable. If it's a simple reference to one of the input vars
3524 * then recursively print the name of that var, instead. (This
3525 * allows correct decompiling of cases where there are identically
3526 * named columns on both sides of the join.) When it's not a
3527 * simple reference, we have to just print the unqualified
3528 * variable name (this can only happen with columns that were
3529 * merged by USING or NATURAL clauses).
3531 * This wouldn't work in decompiling plan trees, because we don't
3532 * store joinaliasvars lists after planning; but a plan tree
3533 * should never contain a join alias variable.
3535 if (rte->joinaliasvars == NIL)
3536 elog(ERROR, "cannot decompile join alias var in plan tree");
3541 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
3542 if (IsA(aliasvar, Var))
3544 return get_variable(aliasvar, var->varlevelsup + levelsup,
3548 /* Unnamed join has neither schemaname nor refname */
3553 if (attnum == InvalidAttrNumber)
3556 attname = get_rte_attribute_name(rte, attnum);
3558 if (refname && (context->varprefix || attname == NULL))
3561 appendStringInfo(buf, "%s.",
3562 quote_identifier(schemaname));
3564 if (strcmp(refname, "*NEW*") == 0)
3565 appendStringInfoString(buf, "new");
3566 else if (strcmp(refname, "*OLD*") == 0)
3567 appendStringInfoString(buf, "old");
3569 appendStringInfoString(buf, quote_identifier(refname));
3571 if (attname || showstar)
3572 appendStringInfoChar(buf, '.');
3575 appendStringInfoString(buf, quote_identifier(attname));
3577 appendStringInfoChar(buf, '*');
3584 * Get the name of a field of an expression of composite type.
3586 * This is fairly straightforward except for the case of a Var of type RECORD.
3587 * Since no actual table or view column is allowed to have type RECORD, such
3588 * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
3589 * drill down to find the ultimate defining expression and attempt to infer
3590 * the field name from it. We ereport if we can't determine the name.
3592 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
3595 get_name_for_var_field(Var *var, int fieldno,
3596 int levelsup, deparse_context *context)
3601 deparse_namespace *dpns;
3602 TupleDesc tupleDesc;
3606 * If it's a RowExpr that was expanded from a whole-row Var, use the
3607 * column names attached to it.
3609 if (IsA(var, RowExpr))
3611 RowExpr *r = (RowExpr *) var;
3613 if (fieldno > 0 && fieldno <= list_length(r->colnames))
3614 return strVal(list_nth(r->colnames, fieldno - 1));
3618 * If it's a Var of type RECORD, we have to find what the Var refers to;
3619 * if not, we can use get_expr_result_type. If that fails, we try
3620 * lookup_rowtype_tupdesc, which will probably fail too, but will ereport
3621 * an acceptable message.
3623 if (!IsA(var, Var) ||
3624 var->vartype != RECORDOID)
3626 if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
3627 tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var),
3628 exprTypmod((Node *) var));
3630 /* Got the tupdesc, so we can extract the field name */
3631 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
3632 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
3635 /* Find appropriate nesting depth */
3636 netlevelsup = var->varlevelsup + levelsup;
3637 if (netlevelsup >= list_length(context->namespaces))
3638 elog(ERROR, "bogus varlevelsup: %d offset %d",
3639 var->varlevelsup, levelsup);
3640 dpns = (deparse_namespace *) list_nth(context->namespaces,
3644 * Try to find the relevant RTE in this rtable. In a plan tree, it's
3645 * likely that varno is OUTER or INNER, in which case we must dig down
3646 * into the subplans.
3648 if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3650 rte = rt_fetch(var->varno, dpns->rtable);
3651 attnum = var->varattno;
3653 else if (var->varno == OUTER && dpns->outer_plan)
3660 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3662 elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3664 Assert(netlevelsup == 0);
3665 save_outer = dpns->outer_plan;
3666 save_inner = dpns->inner_plan;
3667 push_plan(dpns, dpns->outer_plan);
3669 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3672 dpns->outer_plan = save_outer;
3673 dpns->inner_plan = save_inner;
3676 else if (var->varno == INNER && dpns->inner_plan)
3683 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3685 elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3687 Assert(netlevelsup == 0);
3688 save_outer = dpns->outer_plan;
3689 save_inner = dpns->inner_plan;
3690 push_plan(dpns, dpns->inner_plan);
3692 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3695 dpns->outer_plan = save_outer;
3696 dpns->inner_plan = save_inner;
3701 elog(ERROR, "bogus varno: %d", var->varno);
3702 return NULL; /* keep compiler quiet */
3705 if (attnum == InvalidAttrNumber)
3707 /* Var is whole-row reference to RTE, so select the right field */
3708 return get_rte_attribute_name(rte, fieldno);
3712 * This part has essentially the same logic as the parser's
3713 * expandRecordVariable() function, but we are dealing with a different
3714 * representation of the input context, and we only need one field name
3715 * not a TupleDesc. Also, we need special cases for finding subquery and
3716 * CTE subplans when deparsing Plan trees.
3718 expr = (Node *) var; /* default if we can't drill down */
3720 switch (rte->rtekind)
3727 * This case should not occur: a column of a table or values list
3728 * shouldn't have type RECORD. Fall through and fail (most
3729 * likely) at the bottom.
3733 /* Subselect-in-FROM: examine sub-select's output expr */
3737 TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
3740 if (ste == NULL || ste->resjunk)
3741 elog(ERROR, "subquery %s does not have attribute %d",
3742 rte->eref->aliasname, attnum);
3743 expr = (Node *) ste->expr;
3747 * Recurse into the sub-select to see what its Var
3748 * refers to. We have to build an additional level of
3749 * namespace to keep in step with varlevelsup in the
3752 deparse_namespace mydpns;
3755 mydpns.rtable = rte->subquery->rtable;
3756 mydpns.ctes = rte->subquery->cteList;
3757 mydpns.subplans = NIL;
3758 mydpns.outer_plan = mydpns.inner_plan = NULL;
3760 context->namespaces = lcons(&mydpns,
3761 context->namespaces);
3763 result = get_name_for_var_field((Var *) expr, fieldno,
3766 context->namespaces =
3767 list_delete_first(context->namespaces);
3771 /* else fall through to inspect the expression */
3776 * We're deparsing a Plan tree so we don't have complete
3777 * RTE entries (in particular, rte->subquery is NULL). But
3778 * the only place we'd see a Var directly referencing a
3779 * SUBQUERY RTE is in a SubqueryScan plan node, and we can
3780 * look into the child plan's tlist instead.
3787 if (!dpns->inner_plan)
3788 elog(ERROR, "failed to find plan for subquery %s",
3789 rte->eref->aliasname);
3790 tle = get_tle_by_resno(dpns->inner_plan->targetlist,
3793 elog(ERROR, "bogus varattno for subquery var: %d",
3795 Assert(netlevelsup == 0);
3796 save_outer = dpns->outer_plan;
3797 save_inner = dpns->inner_plan;
3798 push_plan(dpns, dpns->inner_plan);
3800 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3803 dpns->outer_plan = save_outer;
3804 dpns->inner_plan = save_inner;
3810 /* Join RTE --- recursively inspect the alias variable */
3811 if (rte->joinaliasvars == NIL)
3812 elog(ERROR, "cannot decompile join alias var in plan tree");
3813 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
3814 expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
3816 return get_name_for_var_field((Var *) expr, fieldno,
3817 var->varlevelsup + levelsup,
3819 /* else fall through to inspect the expression */
3824 * We couldn't get here unless a function is declared with one of
3825 * its result columns as RECORD, which is not allowed.
3829 /* CTE reference: examine subquery's output expr */
3831 CommonTableExpr *cte = NULL;
3836 * Try to find the referenced CTE using the namespace stack.
3838 ctelevelsup = rte->ctelevelsup + netlevelsup;
3839 if (ctelevelsup >= list_length(context->namespaces))
3843 deparse_namespace *ctedpns;
3845 ctedpns = (deparse_namespace *)
3846 list_nth(context->namespaces, ctelevelsup);
3847 foreach(lc, ctedpns->ctes)
3849 cte = (CommonTableExpr *) lfirst(lc);
3850 if (strcmp(cte->ctename, rte->ctename) == 0)
3856 Query *ctequery = (Query *) cte->ctequery;
3857 TargetEntry *ste = get_tle_by_resno(ctequery->targetList,
3860 if (ste == NULL || ste->resjunk)
3861 elog(ERROR, "subquery %s does not have attribute %d",
3862 rte->eref->aliasname, attnum);
3863 expr = (Node *) ste->expr;
3867 * Recurse into the CTE to see what its Var refers to.
3868 * We have to build an additional level of namespace
3869 * to keep in step with varlevelsup in the CTE.
3870 * Furthermore it could be an outer CTE, so we may
3871 * have to delete some levels of namespace.
3873 List *save_nslist = context->namespaces;
3875 deparse_namespace mydpns;
3878 mydpns.rtable = ctequery->rtable;
3879 mydpns.ctes = ctequery->cteList;
3880 mydpns.subplans = NIL;
3881 mydpns.outer_plan = mydpns.inner_plan = NULL;
3883 new_nslist = list_copy_tail(context->namespaces,
3885 context->namespaces = lcons(&mydpns, new_nslist);
3887 result = get_name_for_var_field((Var *) expr, fieldno,
3890 context->namespaces = save_nslist;
3894 /* else fall through to inspect the expression */
3899 * We're deparsing a Plan tree so we don't have a CTE
3900 * list. But the only place we'd see a Var directly
3901 * referencing a CTE RTE is in a CteScan plan node, and we
3902 * can look into the subplan's tlist instead.
3909 if (!dpns->inner_plan)
3910 elog(ERROR, "failed to find plan for CTE %s",
3911 rte->eref->aliasname);
3912 tle = get_tle_by_resno(dpns->inner_plan->targetlist,
3915 elog(ERROR, "bogus varattno for subquery var: %d",
3917 Assert(netlevelsup == 0);
3918 save_outer = dpns->outer_plan;
3919 save_inner = dpns->inner_plan;
3920 push_plan(dpns, dpns->inner_plan);
3922 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3925 dpns->outer_plan = save_outer;
3926 dpns->inner_plan = save_inner;
3934 * We now have an expression we can't expand any more, so see if
3935 * get_expr_result_type() can do anything with it. If not, pass to
3936 * lookup_rowtype_tupdesc() which will probably fail, but will give an
3937 * appropriate error message while failing.
3939 if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
3940 tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
3943 /* Got the tupdesc, so we can extract the field name */
3944 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
3945 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
3950 * find_rte_by_refname - look up an RTE by refname in a deparse context
3952 * Returns NULL if there is no matching RTE or the refname is ambiguous.
3954 * NOTE: this code is not really correct since it does not take account of
3955 * the fact that not all the RTEs in a rangetable may be visible from the
3956 * point where a Var reference appears. For the purposes we need, however,
3957 * the only consequence of a false match is that we might stick a schema
3958 * qualifier on a Var that doesn't really need it. So it seems close
3961 static RangeTblEntry *
3962 find_rte_by_refname(const char *refname, deparse_context *context)
3964 RangeTblEntry *result = NULL;
3967 foreach(nslist, context->namespaces)
3969 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
3972 foreach(rtlist, dpns->rtable)
3974 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
3976 if (strcmp(rte->eref->aliasname, refname) == 0)
3979 return NULL; /* it's ambiguous */
3991 * get_simple_binary_op_name
3993 * helper function for isSimpleNode
3994 * will return single char binary operator name, or NULL if it's not
3997 get_simple_binary_op_name(OpExpr *expr)
3999 List *args = expr->args;
4001 if (list_length(args) == 2)
4003 /* binary operator */
4004 Node *arg1 = (Node *) linitial(args);
4005 Node *arg2 = (Node *) lsecond(args);
4008 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
4009 if (strlen(op) == 1)
4017 * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
4019 * true : simple in the context of parent node's type
4020 * false : not simple
4023 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
4028 switch (nodeTag(node))
4033 case T_CoerceToDomainValue:
4034 case T_SetToDefault:
4035 case T_CurrentOfExpr:
4036 /* single words: always simple */
4042 case T_CoalesceExpr:
4049 /* function-like: name(..) or name[..] */
4052 /* CASE keywords act as parentheses */
4059 * appears simple since . has top precedence, unless parent is
4060 * T_FieldSelect itself!
4062 return (IsA(parentNode, FieldSelect) ? false : true);
4067 * treat like FieldSelect (probably doesn't matter)
4069 return (IsA(parentNode, FieldStore) ? false : true);
4071 case T_CoerceToDomain:
4072 /* maybe simple, check args */
4073 return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
4076 return isSimpleNode((Node *) ((RelabelType *) node)->arg,
4079 return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
4081 case T_ArrayCoerceExpr:
4082 return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
4084 case T_ConvertRowtypeExpr:
4085 return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
4090 /* depends on parent node type; needs further checking */
4091 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
4094 const char *parentOp;
4097 bool is_lopriparent;
4098 bool is_hipriparent;
4100 op = get_simple_binary_op_name((OpExpr *) node);
4104 /* We know only the basic operators + - and * / % */
4105 is_lopriop = (strchr("+-", *op) != NULL);
4106 is_hipriop = (strchr("*/%", *op) != NULL);
4107 if (!(is_lopriop || is_hipriop))
4110 parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
4114 is_lopriparent = (strchr("+-", *parentOp) != NULL);
4115 is_hipriparent = (strchr("*/%", *parentOp) != NULL);
4116 if (!(is_lopriparent || is_hipriparent))
4119 if (is_hipriop && is_lopriparent)
4120 return true; /* op binds tighter than parent */
4122 if (is_lopriop && is_hipriparent)
4126 * Operators are same priority --- can skip parens only if
4127 * we have (a - b) - c, not a - (b - c).
4129 if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
4134 /* else do the same stuff as for T_SubLink et al. */
4141 case T_DistinctExpr:
4142 switch (nodeTag(parentNode))
4146 /* special handling for casts */
4147 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4149 if (type == COERCE_EXPLICIT_CAST ||
4150 type == COERCE_IMPLICIT_CAST)
4152 return true; /* own parentheses */
4154 case T_BoolExpr: /* lower precedence */
4155 case T_ArrayRef: /* other separators */
4156 case T_ArrayExpr: /* other separators */
4157 case T_RowExpr: /* other separators */
4158 case T_CoalesceExpr: /* own parentheses */
4159 case T_MinMaxExpr: /* own parentheses */
4160 case T_XmlExpr: /* own parentheses */
4161 case T_NullIfExpr: /* other separators */
4162 case T_Aggref: /* own parentheses */
4163 case T_WindowFunc: /* own parentheses */
4164 case T_CaseExpr: /* other separators */
4171 switch (nodeTag(parentNode))
4174 if (prettyFlags & PRETTYFLAG_PAREN)
4177 BoolExprType parentType;
4179 type = ((BoolExpr *) node)->boolop;
4180 parentType = ((BoolExpr *) parentNode)->boolop;
4185 if (parentType == AND_EXPR || parentType == OR_EXPR)
4189 if (parentType == OR_EXPR)
4197 /* special handling for casts */
4198 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4200 if (type == COERCE_EXPLICIT_CAST ||
4201 type == COERCE_IMPLICIT_CAST)
4203 return true; /* own parentheses */
4205 case T_ArrayRef: /* other separators */
4206 case T_ArrayExpr: /* other separators */
4207 case T_RowExpr: /* other separators */
4208 case T_CoalesceExpr: /* own parentheses */
4209 case T_MinMaxExpr: /* own parentheses */
4210 case T_XmlExpr: /* own parentheses */
4211 case T_NullIfExpr: /* other separators */
4212 case T_Aggref: /* own parentheses */
4213 case T_WindowFunc: /* own parentheses */
4214 case T_CaseExpr: /* other separators */
4223 /* those we don't know: in dubio complexo */
4229 * appendContextKeyword - append a keyword to buffer
4231 * If prettyPrint is enabled, perform a line break, and adjust indentation.
4232 * Otherwise, just append the keyword.
4235 appendContextKeyword(deparse_context *context, const char *str,
4236 int indentBefore, int indentAfter, int indentPlus)
4238 if (PRETTY_INDENT(context))
4240 context->indentLevel += indentBefore;
4242 appendStringInfoChar(context->buf, '\n');
4243 appendStringInfoSpaces(context->buf,
4244 Max(context->indentLevel, 0) + indentPlus);
4245 appendStringInfoString(context->buf, str);
4247 context->indentLevel += indentAfter;
4248 if (context->indentLevel < 0)
4249 context->indentLevel = 0;
4252 appendStringInfoString(context->buf, str);
4256 * get_rule_expr_paren - deparse expr using get_rule_expr,
4257 * embracing the string with parentheses if necessary for prettyPrint.
4259 * Never embrace if prettyFlags=0, because it's done in the calling node.
4261 * Any node that does *not* embrace its argument node by sql syntax (with
4262 * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
4263 * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
4267 get_rule_expr_paren(Node *node, deparse_context *context,
4268 bool showimplicit, Node *parentNode)
4272 need_paren = PRETTY_PAREN(context) &&
4273 !isSimpleNode(node, parentNode, context->prettyFlags);
4276 appendStringInfoChar(context->buf, '(');
4278 get_rule_expr(node, context, showimplicit);
4281 appendStringInfoChar(context->buf, ')');
4286 * get_rule_expr - Parse back an expression
4288 * Note: showimplicit determines whether we display any implicit cast that
4289 * is present at the top of the expression tree. It is a passed argument,
4290 * not a field of the context struct, because we change the value as we
4291 * recurse down into the expression. In general we suppress implicit casts
4292 * when the result type is known with certainty (eg, the arguments of an
4293 * OR must be boolean). We display implicit casts for arguments of functions
4294 * and operators, since this is needed to be certain that the same function
4295 * or operator will be chosen when the expression is re-parsed.
4299 get_rule_expr(Node *node, deparse_context *context,
4302 StringInfo buf = context->buf;
4308 * Each level of get_rule_expr must emit an indivisible term
4309 * (parenthesized if necessary) to ensure result is reparsed into the same
4310 * expression tree. The only exception is that when the input is a List,
4311 * we emit the component items comma-separated with no surrounding
4312 * decoration; this is convenient for most callers.
4314 switch (nodeTag(node))
4317 (void) get_variable((Var *) node, 0, true, context);
4321 get_const_expr((Const *) node, context, 0);
4325 appendStringInfo(buf, "$%d", ((Param *) node)->paramid);
4329 get_agg_expr((Aggref *) node, context);
4333 get_windowfunc_expr((WindowFunc *) node, context);
4338 ArrayRef *aref = (ArrayRef *) node;
4342 * Parenthesize the argument unless it's a simple Var or a
4343 * FieldSelect. (In particular, if it's another ArrayRef, we
4344 * *must* parenthesize to avoid confusion.)
4346 need_parens = !IsA(aref->refexpr, Var) &&
4347 !IsA(aref->refexpr, FieldSelect);
4349 appendStringInfoChar(buf, '(');
4350 get_rule_expr((Node *) aref->refexpr, context, showimplicit);
4352 appendStringInfoChar(buf, ')');
4353 printSubscripts(aref, context);
4356 * Array assignment nodes should have been handled in
4357 * processIndirection().
4359 if (aref->refassgnexpr)
4360 elog(ERROR, "unexpected refassgnexpr");
4365 get_func_expr((FuncExpr *) node, context, showimplicit);
4368 case T_NamedArgExpr:
4370 NamedArgExpr *na = (NamedArgExpr *) node;
4372 get_rule_expr((Node *) na->arg, context, showimplicit);
4373 appendStringInfo(buf, " AS %s", quote_identifier(na->name));
4378 get_oper_expr((OpExpr *) node, context);
4381 case T_DistinctExpr:
4383 DistinctExpr *expr = (DistinctExpr *) node;
4384 List *args = expr->args;
4385 Node *arg1 = (Node *) linitial(args);
4386 Node *arg2 = (Node *) lsecond(args);
4388 if (!PRETTY_PAREN(context))
4389 appendStringInfoChar(buf, '(');
4390 get_rule_expr_paren(arg1, context, true, node);
4391 appendStringInfo(buf, " IS DISTINCT FROM ");
4392 get_rule_expr_paren(arg2, context, true, node);
4393 if (!PRETTY_PAREN(context))
4394 appendStringInfoChar(buf, ')');
4398 case T_ScalarArrayOpExpr:
4400 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
4401 List *args = expr->args;
4402 Node *arg1 = (Node *) linitial(args);
4403 Node *arg2 = (Node *) lsecond(args);
4405 if (!PRETTY_PAREN(context))
4406 appendStringInfoChar(buf, '(');
4407 get_rule_expr_paren(arg1, context, true, node);
4408 appendStringInfo(buf, " %s %s (",
4409 generate_operator_name(expr->opno,
4411 get_element_type(exprType(arg2))),
4412 expr->useOr ? "ANY" : "ALL");
4413 get_rule_expr_paren(arg2, context, true, node);
4414 appendStringInfoChar(buf, ')');
4415 if (!PRETTY_PAREN(context))
4416 appendStringInfoChar(buf, ')');
4422 BoolExpr *expr = (BoolExpr *) node;
4423 Node *first_arg = linitial(expr->args);
4424 ListCell *arg = lnext(list_head(expr->args));
4426 switch (expr->boolop)
4429 if (!PRETTY_PAREN(context))
4430 appendStringInfoChar(buf, '(');
4431 get_rule_expr_paren(first_arg, context,
4435 appendStringInfo(buf, " AND ");
4436 get_rule_expr_paren((Node *) lfirst(arg), context,
4440 if (!PRETTY_PAREN(context))
4441 appendStringInfoChar(buf, ')');
4445 if (!PRETTY_PAREN(context))
4446 appendStringInfoChar(buf, '(');
4447 get_rule_expr_paren(first_arg, context,
4451 appendStringInfo(buf, " OR ");
4452 get_rule_expr_paren((Node *) lfirst(arg), context,
4456 if (!PRETTY_PAREN(context))
4457 appendStringInfoChar(buf, ')');
4461 if (!PRETTY_PAREN(context))
4462 appendStringInfoChar(buf, '(');
4463 appendStringInfo(buf, "NOT ");
4464 get_rule_expr_paren(first_arg, context,
4466 if (!PRETTY_PAREN(context))
4467 appendStringInfoChar(buf, ')');
4471 elog(ERROR, "unrecognized boolop: %d",
4472 (int) expr->boolop);
4478 get_sublink_expr((SubLink *) node, context);
4483 SubPlan *subplan = (SubPlan *) node;
4486 * We cannot see an already-planned subplan in rule deparsing,
4487 * only while EXPLAINing a query plan. We don't try to
4488 * reconstruct the original SQL, just reference the subplan
4489 * that appears elsewhere in EXPLAIN's result.
4491 if (subplan->useHashTable)
4492 appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
4494 appendStringInfo(buf, "(%s)", subplan->plan_name);
4498 case T_AlternativeSubPlan:
4500 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
4503 /* As above, this can only happen during EXPLAIN */
4504 appendStringInfo(buf, "(alternatives: ");
4505 foreach(lc, asplan->subplans)
4507 SubPlan *splan = (SubPlan *) lfirst(lc);
4509 Assert(IsA(splan, SubPlan));
4510 if (splan->useHashTable)
4511 appendStringInfo(buf, "hashed %s", splan->plan_name);
4513 appendStringInfo(buf, "%s", splan->plan_name);
4515 appendStringInfo(buf, " or ");
4517 appendStringInfo(buf, ")");
4523 FieldSelect *fselect = (FieldSelect *) node;
4524 Node *arg = (Node *) fselect->arg;
4525 int fno = fselect->fieldnum;
4526 const char *fieldname;
4530 * Parenthesize the argument unless it's an ArrayRef or
4531 * another FieldSelect. Note in particular that it would be
4532 * WRONG to not parenthesize a Var argument; simplicity is not
4533 * the issue here, having the right number of names is.
4535 need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect);
4537 appendStringInfoChar(buf, '(');
4538 get_rule_expr(arg, context, true);
4540 appendStringInfoChar(buf, ')');
4543 * Get and print the field name.
4545 fieldname = get_name_for_var_field((Var *) arg, fno,
4547 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
4554 * We shouldn't see FieldStore here; it should have been stripped
4555 * off by processIndirection().
4557 elog(ERROR, "unexpected FieldStore");
4562 RelabelType *relabel = (RelabelType *) node;
4563 Node *arg = (Node *) relabel->arg;
4565 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
4568 /* don't show the implicit cast */
4569 get_rule_expr_paren(arg, context, false, node);
4573 get_coercion_expr(arg, context,
4574 relabel->resulttype,
4575 relabel->resulttypmod,
4583 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
4584 Node *arg = (Node *) iocoerce->arg;
4586 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
4589 /* don't show the implicit cast */
4590 get_rule_expr_paren(arg, context, false, node);
4594 get_coercion_expr(arg, context,
4595 iocoerce->resulttype,
4602 case T_ArrayCoerceExpr:
4604 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
4605 Node *arg = (Node *) acoerce->arg;
4607 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
4610 /* don't show the implicit cast */
4611 get_rule_expr_paren(arg, context, false, node);
4615 get_coercion_expr(arg, context,
4616 acoerce->resulttype,
4617 acoerce->resulttypmod,
4623 case T_ConvertRowtypeExpr:
4625 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
4626 Node *arg = (Node *) convert->arg;
4628 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
4631 /* don't show the implicit cast */
4632 get_rule_expr_paren(arg, context, false, node);
4636 get_coercion_expr(arg, context,
4637 convert->resulttype, -1,
4645 CaseExpr *caseexpr = (CaseExpr *) node;
4648 appendContextKeyword(context, "CASE",
4649 0, PRETTYINDENT_VAR, 0);
4652 appendStringInfoChar(buf, ' ');
4653 get_rule_expr((Node *) caseexpr->arg, context, true);
4655 foreach(temp, caseexpr->args)
4657 CaseWhen *when = (CaseWhen *) lfirst(temp);
4658 Node *w = (Node *) when->expr;
4660 if (!PRETTY_INDENT(context))
4661 appendStringInfoChar(buf, ' ');
4662 appendContextKeyword(context, "WHEN ",
4667 * The parser should have produced WHEN clauses of the
4668 * form "CaseTestExpr = RHS"; we want to show just the
4669 * RHS. If the user wrote something silly like "CASE
4670 * boolexpr WHEN TRUE THEN ...", then the optimizer's
4671 * simplify_boolean_equality() may have reduced this
4672 * to just "CaseTestExpr" or "NOT CaseTestExpr", for
4673 * which we have to show "TRUE" or "FALSE". Also,
4674 * depending on context the original CaseTestExpr
4675 * might have been reduced to a Const (but we won't
4676 * see "WHEN Const"). We have also to consider the
4677 * possibility that an implicit coercion was inserted
4678 * between the CaseTestExpr and the operator.
4682 List *args = ((OpExpr *) w)->args;
4686 Assert(list_length(args) == 2);
4687 lhs = strip_implicit_coercions(linitial(args));
4688 Assert(IsA(lhs, CaseTestExpr) ||
4690 rhs = (Node *) lsecond(args);
4691 get_rule_expr(rhs, context, false);
4693 else if (IsA(strip_implicit_coercions(w),
4695 appendStringInfo(buf, "TRUE");
4696 else if (not_clause(w))
4698 Assert(IsA(strip_implicit_coercions((Node *) get_notclausearg((Expr *) w)),
4700 appendStringInfo(buf, "FALSE");
4703 elog(ERROR, "unexpected CASE WHEN clause: %d",
4707 get_rule_expr(w, context, false);
4708 appendStringInfo(buf, " THEN ");
4709 get_rule_expr((Node *) when->result, context, true);
4711 if (!PRETTY_INDENT(context))
4712 appendStringInfoChar(buf, ' ');
4713 appendContextKeyword(context, "ELSE ",
4715 get_rule_expr((Node *) caseexpr->defresult, context, true);
4716 if (!PRETTY_INDENT(context))
4717 appendStringInfoChar(buf, ' ');
4718 appendContextKeyword(context, "END",
4719 -PRETTYINDENT_VAR, 0, 0);
4725 ArrayExpr *arrayexpr = (ArrayExpr *) node;
4727 appendStringInfo(buf, "ARRAY[");
4728 get_rule_expr((Node *) arrayexpr->elements, context, true);
4729 appendStringInfoChar(buf, ']');
4732 * If the array isn't empty, we assume its elements are
4733 * coerced to the desired type. If it's empty, though, we
4734 * need an explicit coercion to the array type.
4736 if (arrayexpr->elements == NIL)
4737 appendStringInfo(buf, "::%s",
4738 format_type_with_typemod(arrayexpr->array_typeid, -1));
4744 RowExpr *rowexpr = (RowExpr *) node;
4745 TupleDesc tupdesc = NULL;
4751 * If it's a named type and not RECORD, we may have to skip
4752 * dropped columns and/or claim there are NULLs for added
4755 if (rowexpr->row_typeid != RECORDOID)
4757 tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
4758 Assert(list_length(rowexpr->args) <= tupdesc->natts);
4762 * SQL99 allows "ROW" to be omitted when there is more than
4763 * one column, but for simplicity we always print it.
4765 appendStringInfo(buf, "ROW(");
4768 foreach(arg, rowexpr->args)
4770 Node *e = (Node *) lfirst(arg);
4772 if (tupdesc == NULL ||
4773 !tupdesc->attrs[i]->attisdropped)
4775 appendStringInfoString(buf, sep);
4776 get_rule_expr(e, context, true);
4781 if (tupdesc != NULL)
4783 while (i < tupdesc->natts)
4785 if (!tupdesc->attrs[i]->attisdropped)
4787 appendStringInfoString(buf, sep);
4788 appendStringInfo(buf, "NULL");
4794 ReleaseTupleDesc(tupdesc);
4796 appendStringInfo(buf, ")");
4797 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
4798 appendStringInfo(buf, "::%s",
4799 format_type_with_typemod(rowexpr->row_typeid, -1));
4803 case T_RowCompareExpr:
4805 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
4810 * SQL99 allows "ROW" to be omitted when there is more than
4811 * one column, but for simplicity we always print it.
4813 appendStringInfo(buf, "(ROW(");
4815 foreach(arg, rcexpr->largs)
4817 Node *e = (Node *) lfirst(arg);
4819 appendStringInfoString(buf, sep);
4820 get_rule_expr(e, context, true);
4825 * We assume that the name of the first-column operator will
4826 * do for all the rest too. This is definitely open to
4827 * failure, eg if some but not all operators were renamed
4828 * since the construct was parsed, but there seems no way to
4831 appendStringInfo(buf, ") %s ROW(",
4832 generate_operator_name(linitial_oid(rcexpr->opnos),
4833 exprType(linitial(rcexpr->largs)),
4834 exprType(linitial(rcexpr->rargs))));
4836 foreach(arg, rcexpr->rargs)
4838 Node *e = (Node *) lfirst(arg);
4840 appendStringInfoString(buf, sep);
4841 get_rule_expr(e, context, true);
4844 appendStringInfo(buf, "))");
4848 case T_CoalesceExpr:
4850 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
4852 appendStringInfo(buf, "COALESCE(");
4853 get_rule_expr((Node *) coalesceexpr->args, context, true);
4854 appendStringInfoChar(buf, ')');
4860 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
4862 switch (minmaxexpr->op)
4865 appendStringInfo(buf, "GREATEST(");
4868 appendStringInfo(buf, "LEAST(");
4871 get_rule_expr((Node *) minmaxexpr->args, context, true);
4872 appendStringInfoChar(buf, ')');
4878 XmlExpr *xexpr = (XmlExpr *) node;
4879 bool needcomma = false;
4887 appendStringInfoString(buf, "XMLCONCAT(");
4890 appendStringInfoString(buf, "XMLELEMENT(");
4893 appendStringInfoString(buf, "XMLFOREST(");
4896 appendStringInfoString(buf, "XMLPARSE(");
4899 appendStringInfoString(buf, "XMLPI(");
4902 appendStringInfoString(buf, "XMLROOT(");
4904 case IS_XMLSERIALIZE:
4905 appendStringInfoString(buf, "XMLSERIALIZE(");
4910 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
4912 if (xexpr->xmloption == XMLOPTION_DOCUMENT)
4913 appendStringInfoString(buf, "DOCUMENT ");
4915 appendStringInfoString(buf, "CONTENT ");
4919 appendStringInfo(buf, "NAME %s",
4920 quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
4923 if (xexpr->named_args)
4925 if (xexpr->op != IS_XMLFOREST)
4928 appendStringInfoString(buf, ", ");
4929 appendStringInfoString(buf, "XMLATTRIBUTES(");
4932 forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
4934 Node *e = (Node *) lfirst(arg);
4935 char *argname = strVal(lfirst(narg));
4938 appendStringInfoString(buf, ", ");
4939 get_rule_expr((Node *) e, context, true);
4940 appendStringInfo(buf, " AS %s",
4941 quote_identifier(map_xml_name_to_sql_identifier(argname)));
4944 if (xexpr->op != IS_XMLFOREST)
4945 appendStringInfoChar(buf, ')');
4950 appendStringInfoString(buf, ", ");
4957 case IS_XMLSERIALIZE:
4958 /* no extra decoration needed */
4959 get_rule_expr((Node *) xexpr->args, context, true);
4962 Assert(list_length(xexpr->args) == 2);
4964 get_rule_expr((Node *) linitial(xexpr->args),
4967 con = (Const *) lsecond(xexpr->args);
4968 Assert(IsA(con, Const));
4969 Assert(!con->constisnull);
4970 if (DatumGetBool(con->constvalue))
4971 appendStringInfoString(buf,
4972 " PRESERVE WHITESPACE");
4974 appendStringInfoString(buf,
4975 " STRIP WHITESPACE");
4978 Assert(list_length(xexpr->args) == 3);
4980 get_rule_expr((Node *) linitial(xexpr->args),
4983 appendStringInfoString(buf, ", VERSION ");
4984 con = (Const *) lsecond(xexpr->args);
4985 if (IsA(con, Const) &&
4987 appendStringInfoString(buf, "NO VALUE");
4989 get_rule_expr((Node *) con, context, false);
4991 con = (Const *) lthird(xexpr->args);
4992 Assert(IsA(con, Const));
4993 if (con->constisnull)
4994 /* suppress STANDALONE NO VALUE */ ;
4997 switch (DatumGetInt32(con->constvalue))
4999 case XML_STANDALONE_YES:
5000 appendStringInfoString(buf,
5001 ", STANDALONE YES");
5003 case XML_STANDALONE_NO:
5004 appendStringInfoString(buf,
5007 case XML_STANDALONE_NO_VALUE:
5008 appendStringInfoString(buf,
5009 ", STANDALONE NO VALUE");
5017 get_rule_expr_paren((Node *) xexpr->args, context, false, node);
5022 if (xexpr->op == IS_XMLSERIALIZE)
5023 appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type,
5025 if (xexpr->op == IS_DOCUMENT)
5026 appendStringInfoString(buf, " IS DOCUMENT");
5028 appendStringInfoChar(buf, ')');
5034 NullIfExpr *nullifexpr = (NullIfExpr *) node;
5036 appendStringInfo(buf, "NULLIF(");
5037 get_rule_expr((Node *) nullifexpr->args, context, true);
5038 appendStringInfoChar(buf, ')');
5044 NullTest *ntest = (NullTest *) node;
5046 if (!PRETTY_PAREN(context))
5047 appendStringInfoChar(buf, '(');
5048 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
5049 switch (ntest->nulltesttype)
5052 appendStringInfo(buf, " IS NULL");
5055 appendStringInfo(buf, " IS NOT NULL");
5058 elog(ERROR, "unrecognized nulltesttype: %d",
5059 (int) ntest->nulltesttype);
5061 if (!PRETTY_PAREN(context))
5062 appendStringInfoChar(buf, ')');
5068 BooleanTest *btest = (BooleanTest *) node;
5070 if (!PRETTY_PAREN(context))
5071 appendStringInfoChar(buf, '(');
5072 get_rule_expr_paren((Node *) btest->arg, context, false, node);
5073 switch (btest->booltesttype)
5076 appendStringInfo(buf, " IS TRUE");
5079 appendStringInfo(buf, " IS NOT TRUE");
5082 appendStringInfo(buf, " IS FALSE");
5085 appendStringInfo(buf, " IS NOT FALSE");
5088 appendStringInfo(buf, " IS UNKNOWN");
5090 case IS_NOT_UNKNOWN:
5091 appendStringInfo(buf, " IS NOT UNKNOWN");
5094 elog(ERROR, "unrecognized booltesttype: %d",
5095 (int) btest->booltesttype);
5097 if (!PRETTY_PAREN(context))
5098 appendStringInfoChar(buf, ')');
5102 case T_CoerceToDomain:
5104 CoerceToDomain *ctest = (CoerceToDomain *) node;
5105 Node *arg = (Node *) ctest->arg;
5107 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
5110 /* don't show the implicit cast */
5111 get_rule_expr(arg, context, false);
5115 get_coercion_expr(arg, context,
5117 ctest->resulttypmod,
5123 case T_CoerceToDomainValue:
5124 appendStringInfo(buf, "VALUE");
5127 case T_SetToDefault:
5128 appendStringInfo(buf, "DEFAULT");
5131 case T_CurrentOfExpr:
5133 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
5135 if (cexpr->cursor_name)
5136 appendStringInfo(buf, "CURRENT OF %s",
5137 quote_identifier(cexpr->cursor_name));
5139 appendStringInfo(buf, "CURRENT OF $%d",
5140 cexpr->cursor_param);
5150 foreach(l, (List *) node)
5152 appendStringInfoString(buf, sep);
5153 get_rule_expr((Node *) lfirst(l), context, showimplicit);
5160 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
5167 * get_oper_expr - Parse back an OpExpr node
5170 get_oper_expr(OpExpr *expr, deparse_context *context)
5172 StringInfo buf = context->buf;
5173 Oid opno = expr->opno;
5174 List *args = expr->args;
5176 if (!PRETTY_PAREN(context))
5177 appendStringInfoChar(buf, '(');
5178 if (list_length(args) == 2)
5180 /* binary operator */
5181 Node *arg1 = (Node *) linitial(args);
5182 Node *arg2 = (Node *) lsecond(args);
5184 get_rule_expr_paren(arg1, context, true, (Node *) expr);
5185 appendStringInfo(buf, " %s ",
5186 generate_operator_name(opno,
5189 get_rule_expr_paren(arg2, context, true, (Node *) expr);
5193 /* unary operator --- but which side? */
5194 Node *arg = (Node *) linitial(args);
5196 Form_pg_operator optup;
5198 tp = SearchSysCache(OPEROID,
5199 ObjectIdGetDatum(opno),
5201 if (!HeapTupleIsValid(tp))
5202 elog(ERROR, "cache lookup failed for operator %u", opno);
5203 optup = (Form_pg_operator) GETSTRUCT(tp);
5204 switch (optup->oprkind)
5207 appendStringInfo(buf, "%s ",
5208 generate_operator_name(opno,
5211 get_rule_expr_paren(arg, context, true, (Node *) expr);
5214 get_rule_expr_paren(arg, context, true, (Node *) expr);
5215 appendStringInfo(buf, " %s",
5216 generate_operator_name(opno,
5221 elog(ERROR, "bogus oprkind: %d", optup->oprkind);
5223 ReleaseSysCache(tp);
5225 if (!PRETTY_PAREN(context))
5226 appendStringInfoChar(buf, ')');
5230 * get_func_expr - Parse back a FuncExpr node
5233 get_func_expr(FuncExpr *expr, deparse_context *context,
5236 StringInfo buf = context->buf;
5237 Oid funcoid = expr->funcid;
5238 Oid argtypes[FUNC_MAX_ARGS];
5245 * If the function call came from an implicit coercion, then just show the
5246 * first argument --- unless caller wants to see implicit coercions.
5248 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
5250 get_rule_expr_paren((Node *) linitial(expr->args), context,
5251 false, (Node *) expr);
5256 * If the function call came from a cast, then show the first argument
5257 * plus an explicit cast operation.
5259 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
5260 expr->funcformat == COERCE_IMPLICIT_CAST)
5262 Node *arg = linitial(expr->args);
5263 Oid rettype = expr->funcresulttype;
5264 int32 coercedTypmod;
5266 /* Get the typmod if this is a length-coercion function */
5267 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
5269 get_coercion_expr(arg, context,
5270 rettype, coercedTypmod,
5277 * Normal function: display as proname(args). First we need to extract
5278 * the argument datatypes.
5280 if (list_length(expr->args) > FUNC_MAX_ARGS)
5282 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5283 errmsg("too many arguments")));
5286 foreach(l, expr->args)
5288 Node *arg = (Node *) lfirst(l);
5290 if (IsA(arg, NamedArgExpr))
5291 argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
5292 argtypes[nargs] = exprType(arg);
5296 appendStringInfo(buf, "%s(",
5297 generate_function_name(funcoid, nargs,
5301 foreach(l, expr->args)
5304 appendStringInfoString(buf, ", ");
5305 if (is_variadic && lnext(l) == NULL)
5306 appendStringInfoString(buf, "VARIADIC ");
5307 get_rule_expr((Node *) lfirst(l), context, true);
5309 appendStringInfoChar(buf, ')');
5313 * get_agg_expr - Parse back an Aggref node
5316 get_agg_expr(Aggref *aggref, deparse_context *context)
5318 StringInfo buf = context->buf;
5319 Oid argtypes[FUNC_MAX_ARGS];
5323 if (list_length(aggref->args) > FUNC_MAX_ARGS)
5325 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5326 errmsg("too many arguments")));
5328 foreach(l, aggref->args)
5330 Node *arg = (Node *) lfirst(l);
5332 Assert(!IsA(arg, NamedArgExpr));
5333 argtypes[nargs] = exprType(arg);
5337 appendStringInfo(buf, "%s(%s",
5338 generate_function_name(aggref->aggfnoid, nargs,
5339 NIL, argtypes, NULL),
5340 aggref->aggdistinct ? "DISTINCT " : "");
5341 /* aggstar can be set only in zero-argument aggregates */
5342 if (aggref->aggstar)
5343 appendStringInfoChar(buf, '*');
5345 get_rule_expr((Node *) aggref->args, context, true);
5346 appendStringInfoChar(buf, ')');
5350 * get_windowfunc_expr - Parse back a WindowFunc node
5353 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
5355 StringInfo buf = context->buf;
5356 Oid argtypes[FUNC_MAX_ARGS];
5360 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
5362 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5363 errmsg("too many arguments")));
5365 foreach(l, wfunc->args)
5367 Node *arg = (Node *) lfirst(l);
5369 Assert(!IsA(arg, NamedArgExpr));
5370 argtypes[nargs] = exprType(arg);
5374 appendStringInfo(buf, "%s(",
5375 generate_function_name(wfunc->winfnoid, nargs,
5376 NIL, argtypes, NULL));
5377 /* winstar can be set only in zero-argument aggregates */
5379 appendStringInfoChar(buf, '*');
5381 get_rule_expr((Node *) wfunc->args, context, true);
5382 appendStringInfoString(buf, ") OVER ");
5384 foreach(l, context->windowClause)
5386 WindowClause *wc = (WindowClause *) lfirst(l);
5388 if (wc->winref == wfunc->winref)
5391 appendStringInfoString(buf, quote_identifier(wc->name));
5393 get_rule_windowspec(wc, context->windowTList, context);
5399 if (context->windowClause)
5400 elog(ERROR, "could not find window clause for winref %u",
5404 * In EXPLAIN, we don't have window context information available, so
5405 * we have to settle for this:
5407 appendStringInfoString(buf, "(?)");
5414 * Make a string representation of a value coerced to a specific type
5418 get_coercion_expr(Node *arg, deparse_context *context,
5419 Oid resulttype, int32 resulttypmod,
5422 StringInfo buf = context->buf;
5425 * Since parse_coerce.c doesn't immediately collapse application of
5426 * length-coercion functions to constants, what we'll typically see in
5427 * such cases is a Const with typmod -1 and a length-coercion function
5428 * right above it. Avoid generating redundant output. However, beware of
5429 * suppressing casts when the user actually wrote something like
5430 * 'foo'::text::char(3).
5432 if (arg && IsA(arg, Const) &&
5433 ((Const *) arg)->consttype == resulttype &&
5434 ((Const *) arg)->consttypmod == -1)
5436 /* Show the constant without normal ::typename decoration */
5437 get_const_expr((Const *) arg, context, -1);
5441 if (!PRETTY_PAREN(context))
5442 appendStringInfoChar(buf, '(');
5443 get_rule_expr_paren(arg, context, false, parentNode);
5444 if (!PRETTY_PAREN(context))
5445 appendStringInfoChar(buf, ')');
5447 appendStringInfo(buf, "::%s",
5448 format_type_with_typemod(resulttype, resulttypmod));
5454 * Make a string representation of a Const
5456 * showtype can be -1 to never show "::typename" decoration, or +1 to always
5457 * show it, or 0 to show it only if the constant wouldn't be assumed to be
5458 * the right type by default.
5462 get_const_expr(Const *constval, deparse_context *context, int showtype)
5464 StringInfo buf = context->buf;
5468 bool isfloat = false;
5471 if (constval->constisnull)
5474 * Always label the type of a NULL constant to prevent misdecisions
5475 * about type when reparsing.
5477 appendStringInfo(buf, "NULL");
5479 appendStringInfo(buf, "::%s",
5480 format_type_with_typemod(constval->consttype,
5481 constval->consttypmod));
5485 getTypeOutputInfo(constval->consttype,
5486 &typoutput, &typIsVarlena);
5488 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
5490 switch (constval->consttype)
5501 * These types are printed without quotes unless they contain
5502 * values that aren't accepted by the scanner unquoted (e.g.,
5503 * 'NaN'). Note that strtod() and friends might accept NaN,
5504 * so we can't use that to test.
5506 * In reality we only need to defend against infinity and NaN,
5507 * so we need not get too crazy about pattern matching here.
5509 * There is a special-case gotcha: if the constant is signed,
5510 * we need to parenthesize it, else the parser might see a
5511 * leading plus/minus as binding less tightly than adjacent
5512 * operators --- particularly, the cast that we might attach
5515 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
5517 if (extval[0] == '+' || extval[0] == '-')
5518 appendStringInfo(buf, "(%s)", extval);
5520 appendStringInfoString(buf, extval);
5521 if (strcspn(extval, "eE.") != strlen(extval))
5522 isfloat = true; /* it looks like a float */
5525 appendStringInfo(buf, "'%s'", extval);
5531 appendStringInfo(buf, "B'%s'", extval);
5535 if (strcmp(extval, "t") == 0)
5536 appendStringInfo(buf, "true");
5538 appendStringInfo(buf, "false");
5542 simple_quote_literal(buf, extval);
5552 * For showtype == 0, append ::typename unless the constant will be
5553 * implicitly typed as the right type when it is read in.
5555 * XXX this code has to be kept in sync with the behavior of the parser,
5556 * especially make_const.
5558 switch (constval->consttype)
5563 /* These types can be left unlabeled */
5569 * Float-looking constants will be typed as numeric, but if
5570 * there's a specific typmod we need to show it.
5572 needlabel = !isfloat || (constval->consttypmod >= 0);
5578 if (needlabel || showtype > 0)
5579 appendStringInfo(buf, "::%s",
5580 format_type_with_typemod(constval->consttype,
5581 constval->consttypmod));
5585 * simple_quote_literal - Format a string as a SQL literal, append to buf
5588 simple_quote_literal(StringInfo buf, const char *val)
5593 * We form the string literal according to the prevailing setting of
5594 * standard_conforming_strings; we never use E''. User is responsible for
5595 * making sure result is used correctly.
5597 appendStringInfoChar(buf, '\'');
5598 for (valptr = val; *valptr; valptr++)
5602 if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
5603 appendStringInfoChar(buf, ch);
5604 appendStringInfoChar(buf, ch);
5606 appendStringInfoChar(buf, '\'');
5611 * get_sublink_expr - Parse back a sublink
5615 get_sublink_expr(SubLink *sublink, deparse_context *context)
5617 StringInfo buf = context->buf;
5618 Query *query = (Query *) (sublink->subselect);
5619 char *opname = NULL;
5622 if (sublink->subLinkType == ARRAY_SUBLINK)
5623 appendStringInfo(buf, "ARRAY(");
5625 appendStringInfoChar(buf, '(');
5628 * Note that we print the name of only the first operator, when there are
5629 * multiple combining operators. This is an approximation that could go
5630 * wrong in various scenarios (operators in different schemas, renamed
5631 * operators, etc) but there is not a whole lot we can do about it, since
5632 * the syntax allows only one operator to be shown.
5634 if (sublink->testexpr)
5636 if (IsA(sublink->testexpr, OpExpr))
5638 /* single combining operator */
5639 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
5641 get_rule_expr(linitial(opexpr->args), context, true);
5642 opname = generate_operator_name(opexpr->opno,
5643 exprType(linitial(opexpr->args)),
5644 exprType(lsecond(opexpr->args)));
5646 else if (IsA(sublink->testexpr, BoolExpr))
5648 /* multiple combining operators, = or <> cases */
5652 appendStringInfoChar(buf, '(');
5654 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
5656 OpExpr *opexpr = (OpExpr *) lfirst(l);
5658 Assert(IsA(opexpr, OpExpr));
5659 appendStringInfoString(buf, sep);
5660 get_rule_expr(linitial(opexpr->args), context, true);
5662 opname = generate_operator_name(opexpr->opno,
5663 exprType(linitial(opexpr->args)),
5664 exprType(lsecond(opexpr->args)));
5667 appendStringInfoChar(buf, ')');
5669 else if (IsA(sublink->testexpr, RowCompareExpr))
5671 /* multiple combining operators, < <= > >= cases */
5672 RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
5674 appendStringInfoChar(buf, '(');
5675 get_rule_expr((Node *) rcexpr->largs, context, true);
5676 opname = generate_operator_name(linitial_oid(rcexpr->opnos),
5677 exprType(linitial(rcexpr->largs)),
5678 exprType(linitial(rcexpr->rargs)));
5679 appendStringInfoChar(buf, ')');
5682 elog(ERROR, "unrecognized testexpr type: %d",
5683 (int) nodeTag(sublink->testexpr));
5688 switch (sublink->subLinkType)
5690 case EXISTS_SUBLINK:
5691 appendStringInfo(buf, "EXISTS ");
5695 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
5696 appendStringInfo(buf, " IN ");
5698 appendStringInfo(buf, " %s ANY ", opname);
5702 appendStringInfo(buf, " %s ALL ", opname);
5705 case ROWCOMPARE_SUBLINK:
5706 appendStringInfo(buf, " %s ", opname);
5714 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
5716 elog(ERROR, "unrecognized sublink type: %d",
5717 (int) sublink->subLinkType);
5722 appendStringInfoChar(buf, '(');
5724 get_query_def(query, buf, context->namespaces, NULL,
5725 context->prettyFlags, context->indentLevel);
5728 appendStringInfo(buf, "))");
5730 appendStringInfoChar(buf, ')');
5735 * get_from_clause - Parse back a FROM clause
5737 * "prefix" is the keyword that denotes the start of the list of FROM
5738 * elements. It is FROM when used to parse back SELECT and UPDATE, but
5739 * is USING when parsing back DELETE.
5743 get_from_clause(Query *query, const char *prefix, deparse_context *context)
5745 StringInfo buf = context->buf;
5750 * We use the query's jointree as a guide to what to print. However, we
5751 * must ignore auto-added RTEs that are marked not inFromCl. (These can
5752 * only appear at the top level of the jointree, so it's sufficient to
5753 * check here.) This check also ensures we ignore the rule pseudo-RTEs
5756 foreach(l, query->jointree->fromlist)
5758 Node *jtnode = (Node *) lfirst(l);
5760 if (IsA(jtnode, RangeTblRef))
5762 int varno = ((RangeTblRef *) jtnode)->rtindex;
5763 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
5771 appendContextKeyword(context, prefix,
5772 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
5776 appendStringInfoString(buf, ", ");
5778 get_from_clause_item(jtnode, query, context);
5783 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
5785 StringInfo buf = context->buf;
5787 if (IsA(jtnode, RangeTblRef))
5789 int varno = ((RangeTblRef *) jtnode)->rtindex;
5790 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
5791 bool gavealias = false;
5793 switch (rte->rtekind)
5796 /* Normal relation RTE */
5797 appendStringInfo(buf, "%s%s",
5799 generate_relation_name(rte->relid,
5800 context->namespaces));
5804 appendStringInfoChar(buf, '(');
5805 get_query_def(rte->subquery, buf, context->namespaces, NULL,
5806 context->prettyFlags, context->indentLevel);
5807 appendStringInfoChar(buf, ')');
5811 get_rule_expr(rte->funcexpr, context, true);
5814 /* Values list RTE */
5815 get_values_def(rte->values_lists, context);
5818 appendStringInfoString(buf, quote_identifier(rte->ctename));
5821 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
5825 if (rte->alias != NULL)
5827 appendStringInfo(buf, " %s",
5828 quote_identifier(rte->alias->aliasname));
5831 else if (rte->rtekind == RTE_RELATION &&
5832 strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
5835 * Apparently the rel has been renamed since the rule was made.
5836 * Emit a fake alias clause so that variable references will still
5837 * work. This is not a 100% solution but should work in most
5838 * reasonable situations.
5840 appendStringInfo(buf, " %s",
5841 quote_identifier(rte->eref->aliasname));
5844 else if (rte->rtekind == RTE_FUNCTION)
5847 * For a function RTE, always give an alias. This covers possible
5848 * renaming of the function and/or instability of the
5849 * FigureColname rules for things that aren't simple functions.
5851 appendStringInfo(buf, " %s",
5852 quote_identifier(rte->eref->aliasname));
5856 if (rte->rtekind == RTE_FUNCTION)
5858 if (rte->funccoltypes != NIL)
5860 /* Function returning RECORD, reconstruct the columndefs */
5862 appendStringInfo(buf, " AS ");
5863 get_from_clause_coldeflist(rte->eref->colnames,
5865 rte->funccoltypmods,
5871 * For a function RTE, always emit a complete column alias
5872 * list; this is to protect against possible instability of
5873 * the default column names (eg, from altering parameter
5876 get_from_clause_alias(rte->eref, rte, context);
5882 * For non-function RTEs, just report whatever the user originally
5883 * gave as column aliases.
5885 get_from_clause_alias(rte->alias, rte, context);
5888 else if (IsA(jtnode, JoinExpr))
5890 JoinExpr *j = (JoinExpr *) jtnode;
5891 bool need_paren_on_right;
5893 need_paren_on_right = PRETTY_PAREN(context) &&
5894 !IsA(j->rarg, RangeTblRef) &&
5895 !(IsA(j->rarg, JoinExpr) &&((JoinExpr *) j->rarg)->alias != NULL);
5897 if (!PRETTY_PAREN(context) || j->alias != NULL)
5898 appendStringInfoChar(buf, '(');
5900 get_from_clause_item(j->larg, query, context);
5904 if (!PRETTY_INDENT(context))
5905 appendStringInfoChar(buf, ' ');
5906 switch (j->jointype)
5909 appendContextKeyword(context, "NATURAL JOIN ",
5911 PRETTYINDENT_JOIN, 0);
5914 appendContextKeyword(context, "NATURAL LEFT JOIN ",
5916 PRETTYINDENT_JOIN, 0);
5919 appendContextKeyword(context, "NATURAL FULL JOIN ",
5921 PRETTYINDENT_JOIN, 0);
5924 appendContextKeyword(context, "NATURAL RIGHT JOIN ",
5926 PRETTYINDENT_JOIN, 0);
5929 elog(ERROR, "unrecognized join type: %d",
5935 switch (j->jointype)
5939 appendContextKeyword(context, " JOIN ",
5941 PRETTYINDENT_JOIN, 2);
5943 appendContextKeyword(context, " CROSS JOIN ",
5945 PRETTYINDENT_JOIN, 1);
5948 appendContextKeyword(context, " LEFT JOIN ",
5950 PRETTYINDENT_JOIN, 2);
5953 appendContextKeyword(context, " FULL JOIN ",
5955 PRETTYINDENT_JOIN, 2);
5958 appendContextKeyword(context, " RIGHT JOIN ",
5960 PRETTYINDENT_JOIN, 2);
5963 elog(ERROR, "unrecognized join type: %d",
5968 if (need_paren_on_right)
5969 appendStringInfoChar(buf, '(');
5970 get_from_clause_item(j->rarg, query, context);
5971 if (need_paren_on_right)
5972 appendStringInfoChar(buf, ')');
5974 context->indentLevel -= PRETTYINDENT_JOIN_ON;
5982 appendStringInfo(buf, " USING (");
5983 foreach(col, j->usingClause)
5985 if (col != list_head(j->usingClause))
5986 appendStringInfo(buf, ", ");
5987 appendStringInfoString(buf,
5988 quote_identifier(strVal(lfirst(col))));
5990 appendStringInfoChar(buf, ')');
5994 appendStringInfo(buf, " ON ");
5995 if (!PRETTY_PAREN(context))
5996 appendStringInfoChar(buf, '(');
5997 get_rule_expr(j->quals, context, false);
5998 if (!PRETTY_PAREN(context))
5999 appendStringInfoChar(buf, ')');
6002 if (!PRETTY_PAREN(context) || j->alias != NULL)
6003 appendStringInfoChar(buf, ')');
6005 /* Yes, it's correct to put alias after the right paren ... */
6006 if (j->alias != NULL)
6008 appendStringInfo(buf, " %s",
6009 quote_identifier(j->alias->aliasname));
6010 get_from_clause_alias(j->alias,
6011 rt_fetch(j->rtindex, query->rtable),
6016 elog(ERROR, "unrecognized node type: %d",
6017 (int) nodeTag(jtnode));
6021 * get_from_clause_alias - reproduce column alias list
6023 * This is tricky because we must ignore dropped columns.
6026 get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
6027 deparse_context *context)
6029 StringInfo buf = context->buf;
6034 if (alias == NULL || alias->colnames == NIL)
6035 return; /* definitely nothing to do */
6038 foreach(col, alias->colnames)
6041 if (get_rte_attribute_is_dropped(rte, attnum))
6045 appendStringInfoChar(buf, '(');
6049 appendStringInfo(buf, ", ");
6050 appendStringInfoString(buf,
6051 quote_identifier(strVal(lfirst(col))));
6054 appendStringInfoChar(buf, ')');
6058 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
6060 * The coldeflist is appended immediately (no space) to buf. Caller is
6061 * responsible for ensuring that an alias or AS is present before it.
6064 get_from_clause_coldeflist(List *names, List *types, List *typmods,
6065 deparse_context *context)
6067 StringInfo buf = context->buf;
6073 appendStringInfoChar(buf, '(');
6075 l2 = list_head(types);
6076 l3 = list_head(typmods);
6079 char *attname = strVal(lfirst(l1));
6083 atttypid = lfirst_oid(l2);
6085 atttypmod = lfirst_int(l3);
6089 appendStringInfo(buf, ", ");
6090 appendStringInfo(buf, "%s %s",
6091 quote_identifier(attname),
6092 format_type_with_typemod(atttypid, atttypmod));
6096 appendStringInfoChar(buf, ')');
6100 * get_opclass_name - fetch name of an index operator class
6102 * The opclass name is appended (after a space) to buf.
6104 * Output is suppressed if the opclass is the default for the given
6105 * actual_datatype. (If you don't want this behavior, just pass
6106 * InvalidOid for actual_datatype.)
6109 get_opclass_name(Oid opclass, Oid actual_datatype,
6113 Form_pg_opclass opcrec;
6117 ht_opc = SearchSysCache(CLAOID,
6118 ObjectIdGetDatum(opclass),
6120 if (!HeapTupleIsValid(ht_opc))
6121 elog(ERROR, "cache lookup failed for opclass %u", opclass);
6122 opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
6124 if (!OidIsValid(actual_datatype) ||
6125 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
6127 /* Okay, we need the opclass name. Do we need to qualify it? */
6128 opcname = NameStr(opcrec->opcname);
6129 if (OpclassIsVisible(opclass))
6130 appendStringInfo(buf, " %s", quote_identifier(opcname));
6133 nspname = get_namespace_name(opcrec->opcnamespace);
6134 appendStringInfo(buf, " %s.%s",
6135 quote_identifier(nspname),
6136 quote_identifier(opcname));
6139 ReleaseSysCache(ht_opc);
6143 * processIndirection - take care of array and subfield assignment
6145 * We strip any top-level FieldStore or assignment ArrayRef nodes that
6146 * appear in the input, and return the subexpression that's to be assigned.
6147 * If printit is true, we also print out the appropriate decoration for the
6148 * base column name (that the caller just printed).
6151 processIndirection(Node *node, deparse_context *context, bool printit)
6153 StringInfo buf = context->buf;
6159 if (IsA(node, FieldStore))
6161 FieldStore *fstore = (FieldStore *) node;
6165 /* lookup tuple type */
6166 typrelid = get_typ_typrelid(fstore->resulttype);
6167 if (!OidIsValid(typrelid))
6168 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
6169 format_type_be(fstore->resulttype));
6172 * Print the field name. Note we assume here that there's only
6173 * one field being assigned to. This is okay in stored rules but
6174 * could be wrong in executable target lists. Presently no
6175 * problem since explain.c doesn't print plan targetlists, but
6176 * someday may have to think of something ...
6178 fieldname = get_relid_attribute_name(typrelid,
6179 linitial_int(fstore->fieldnums));
6181 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
6184 * We ignore arg since it should be an uninteresting reference to
6185 * the target column or subcolumn.
6187 node = (Node *) linitial(fstore->newvals);
6189 else if (IsA(node, ArrayRef))
6191 ArrayRef *aref = (ArrayRef *) node;
6193 if (aref->refassgnexpr == NULL)
6196 printSubscripts(aref, context);
6199 * We ignore refexpr since it should be an uninteresting reference
6200 * to the target column or subcolumn.
6202 node = (Node *) aref->refassgnexpr;
6212 printSubscripts(ArrayRef *aref, deparse_context *context)
6214 StringInfo buf = context->buf;
6215 ListCell *lowlist_item;
6216 ListCell *uplist_item;
6218 lowlist_item = list_head(aref->reflowerindexpr); /* could be NULL */
6219 foreach(uplist_item, aref->refupperindexpr)
6221 appendStringInfoChar(buf, '[');
6224 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
6225 appendStringInfoChar(buf, ':');
6226 lowlist_item = lnext(lowlist_item);
6228 get_rule_expr((Node *) lfirst(uplist_item), context, false);
6229 appendStringInfoChar(buf, ']');
6234 * quote_identifier - Quote an identifier only if needed
6236 * When quotes are needed, we palloc the required space; slightly
6237 * space-wasteful but well worth it for notational simplicity.
6240 quote_identifier(const char *ident)
6243 * Can avoid quoting if ident starts with a lowercase letter or underscore
6244 * and contains only lowercase letters, digits, and underscores, *and* is
6245 * not any SQL keyword. Otherwise, supply quotes.
6254 * would like to use <ctype.h> macros here, but they might yield unwanted
6255 * locale-specific results...
6257 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
6259 for (ptr = ident; *ptr; ptr++)
6263 if ((ch >= 'a' && ch <= 'z') ||
6264 (ch >= '0' && ch <= '9') ||
6280 * Check for keyword. We quote keywords except for unreserved ones.
6281 * (In some cases we could avoid quoting a col_name or type_func_name
6282 * keyword, but it seems much harder than it's worth to tell that.)
6284 * Note: ScanKeywordLookup() does case-insensitive comparison, but
6285 * that's fine, since we already know we have all-lower-case.
6287 const ScanKeyword *keyword = ScanKeywordLookup(ident,
6291 if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
6296 return ident; /* no change needed */
6298 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
6302 for (ptr = ident; *ptr; ptr++)
6317 * quote_qualified_identifier - Quote a possibly-qualified identifier
6319 * Return a name of the form qualifier.ident, or just ident if qualifier
6320 * is NULL, quoting each component if necessary. The result is palloc'd.
6323 quote_qualified_identifier(const char *qualifier,
6328 initStringInfo(&buf);
6330 appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
6331 appendStringInfoString(&buf, quote_identifier(ident));
6336 * generate_relation_name
6337 * Compute the name to display for a relation specified by OID
6339 * The result includes all necessary quoting and schema-prefixing.
6341 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
6342 * We will forcibly qualify the relation name if it equals any CTE name
6343 * visible in the namespace list.
6346 generate_relation_name(Oid relid, List *namespaces)
6349 Form_pg_class reltup;
6356 tp = SearchSysCache(RELOID,
6357 ObjectIdGetDatum(relid),
6359 if (!HeapTupleIsValid(tp))
6360 elog(ERROR, "cache lookup failed for relation %u", relid);
6361 reltup = (Form_pg_class) GETSTRUCT(tp);
6362 relname = NameStr(reltup->relname);
6364 /* Check for conflicting CTE name */
6366 foreach(nslist, namespaces)
6368 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
6371 foreach(ctlist, dpns->ctes)
6373 CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
6375 if (strcmp(cte->ctename, relname) == 0)
6385 /* Otherwise, qualify the name if not visible in search path */
6387 need_qual = !RelationIsVisible(relid);
6390 nspname = get_namespace_name(reltup->relnamespace);
6394 result = quote_qualified_identifier(nspname, relname);
6396 ReleaseSysCache(tp);
6402 * generate_function_name
6403 * Compute the name to display for a function specified by OID,
6404 * given that it is being called with the specified actual arg names and
6405 * types. (Those matter because of ambiguous-function resolution rules.)
6407 * The result includes all necessary quoting and schema-prefixing. We can
6408 * also pass back an indication of whether the function is variadic.
6411 generate_function_name(Oid funcid, int nargs, List *argnames,
6412 Oid *argtypes, bool *is_variadic)
6415 Form_pg_proc procform;
6419 FuncDetailCode p_result;
6424 Oid *p_true_typeids;
6426 proctup = SearchSysCache(PROCOID,
6427 ObjectIdGetDatum(funcid),
6429 if (!HeapTupleIsValid(proctup))
6430 elog(ERROR, "cache lookup failed for function %u", funcid);
6431 procform = (Form_pg_proc) GETSTRUCT(proctup);
6432 proname = NameStr(procform->proname);
6435 * The idea here is to schema-qualify only if the parser would fail to
6436 * resolve the correct function given the unqualified func name with the
6437 * specified argtypes. If the function is variadic, we should presume
6438 * that VARIADIC will be included in the call.
6440 p_result = func_get_detail(list_make1(makeString(proname)),
6441 NIL, argnames, nargs, argtypes,
6442 !OidIsValid(procform->provariadic), true,
6443 &p_funcid, &p_rettype,
6444 &p_retset, &p_nvargs, &p_true_typeids, NULL);
6445 if ((p_result == FUNCDETAIL_NORMAL ||
6446 p_result == FUNCDETAIL_AGGREGATE ||
6447 p_result == FUNCDETAIL_WINDOWFUNC) &&
6451 nspname = get_namespace_name(procform->pronamespace);
6453 result = quote_qualified_identifier(nspname, proname);
6455 /* Check variadic-ness if caller cares */
6458 /* "any" variadics are not treated as variadics for listing */
6459 if (OidIsValid(procform->provariadic) &&
6460 procform->provariadic != ANYOID)
6461 *is_variadic = true;
6463 *is_variadic = false;
6466 ReleaseSysCache(proctup);
6472 * generate_operator_name
6473 * Compute the name to display for an operator specified by OID,
6474 * given that it is being called with the specified actual arg types.
6475 * (Arg types matter because of ambiguous-operator resolution rules.
6476 * Pass InvalidOid for unused arg of a unary operator.)
6478 * The result includes all necessary quoting and schema-prefixing,
6479 * plus the OPERATOR() decoration needed to use a qualified operator name
6483 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
6487 Form_pg_operator operform;
6492 initStringInfo(&buf);
6494 opertup = SearchSysCache(OPEROID,
6495 ObjectIdGetDatum(operid),
6497 if (!HeapTupleIsValid(opertup))
6498 elog(ERROR, "cache lookup failed for operator %u", operid);
6499 operform = (Form_pg_operator) GETSTRUCT(opertup);
6500 oprname = NameStr(operform->oprname);
6503 * The idea here is to schema-qualify only if the parser would fail to
6504 * resolve the correct operator given the unqualified op name with the
6505 * specified argtypes.
6507 switch (operform->oprkind)
6510 p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
6514 p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
6518 p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
6522 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
6523 p_result = NULL; /* keep compiler quiet */
6527 if (p_result != NULL && oprid(p_result) == operid)
6531 nspname = get_namespace_name(operform->oprnamespace);
6532 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
6535 appendStringInfoString(&buf, oprname);
6538 appendStringInfoChar(&buf, ')');
6540 if (p_result != NULL)
6541 ReleaseSysCache(p_result);
6543 ReleaseSysCache(opertup);
6549 * Given a C string, produce a TEXT datum.
6551 * We assume that the input was palloc'd and may be freed.
6554 string_to_text(char *str)
6558 result = cstring_to_text(str);
6564 * Generate a C string representing a relation's reloptions, or NULL if none.
6567 flatten_reloptions(Oid relid)
6569 char *result = NULL;
6574 tuple = SearchSysCache(RELOID,
6575 ObjectIdGetDatum(relid),
6577 if (!HeapTupleIsValid(tuple))
6578 elog(ERROR, "cache lookup failed for relation %u", relid);
6580 reloptions = SysCacheGetAttr(RELOID, tuple,
6581 Anum_pg_class_reloptions, &isnull);
6588 * We want to use array_to_text(reloptions, ', ') --- but
6589 * DirectFunctionCall2(array_to_text) does not work, because
6590 * array_to_text() relies on flinfo to be valid. So use
6593 sep = CStringGetTextDatum(", ");
6594 txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
6595 result = TextDatumGetCString(txt);
6598 ReleaseSysCache(tuple);