PostgreSQL Source Code  git master
ruleutils.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ruleutils.c
4  * Functions to convert stored expressions/querytrees back to
5  * source text
6  *
7  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/backend/utils/adt/ruleutils.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 
18 #include <ctype.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 
22 #include "access/amapi.h"
23 #include "access/htup_details.h"
24 #include "access/sysattr.h"
25 #include "catalog/dependency.h"
26 #include "catalog/indexing.h"
27 #include "catalog/partition.h"
28 #include "catalog/pg_aggregate.h"
29 #include "catalog/pg_am.h"
30 #include "catalog/pg_authid.h"
31 #include "catalog/pg_collation.h"
32 #include "catalog/pg_constraint.h"
33 #include "catalog/pg_depend.h"
34 #include "catalog/pg_language.h"
35 #include "catalog/pg_opclass.h"
36 #include "catalog/pg_operator.h"
38 #include "catalog/pg_proc.h"
40 #include "catalog/pg_trigger.h"
41 #include "catalog/pg_type.h"
42 #include "commands/defrem.h"
43 #include "commands/tablespace.h"
44 #include "common/keywords.h"
45 #include "executor/spi.h"
46 #include "funcapi.h"
47 #include "mb/pg_wchar.h"
48 #include "miscadmin.h"
49 #include "nodes/makefuncs.h"
50 #include "nodes/nodeFuncs.h"
51 #include "optimizer/tlist.h"
52 #include "parser/parse_node.h"
53 #include "parser/parse_agg.h"
54 #include "parser/parse_func.h"
55 #include "parser/parse_oper.h"
56 #include "parser/parser.h"
57 #include "parser/parsetree.h"
58 #include "rewrite/rewriteHandler.h"
59 #include "rewrite/rewriteManip.h"
60 #include "rewrite/rewriteSupport.h"
61 #include "utils/array.h"
62 #include "utils/builtins.h"
63 #include "utils/fmgroids.h"
64 #include "utils/hsearch.h"
65 #include "utils/lsyscache.h"
66 #include "utils/rel.h"
67 #include "utils/ruleutils.h"
68 #include "utils/snapmgr.h"
69 #include "utils/syscache.h"
70 #include "utils/tqual.h"
71 #include "utils/typcache.h"
72 #include "utils/varlena.h"
73 #include "utils/xml.h"
74 
75 
76 /* ----------
77  * Pretty formatting constants
78  * ----------
79  */
80 
81 /* Indent counts */
82 #define PRETTYINDENT_STD 8
83 #define PRETTYINDENT_JOIN 4
84 #define PRETTYINDENT_VAR 4
85 
86 #define PRETTYINDENT_LIMIT 40 /* wrap limit */
87 
88 /* Pretty flags */
89 #define PRETTYFLAG_PAREN 1
90 #define PRETTYFLAG_INDENT 2
91 
92 /* Default line length for pretty-print wrapping: 0 means wrap always */
93 #define WRAP_COLUMN_DEFAULT 0
94 
95 /* macro to test if pretty action needed */
96 #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
97 #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
98 
99 
100 /* ----------
101  * Local data types
102  * ----------
103  */
104 
105 /* Context info needed for invoking a recursive querytree display routine */
106 typedef struct
107 {
108  StringInfo buf; /* output buffer to append to */
109  List *namespaces; /* List of deparse_namespace nodes */
110  List *windowClause; /* Current query level's WINDOW clause */
111  List *windowTList; /* targetlist for resolving WINDOW clause */
112  int prettyFlags; /* enabling of pretty-print functions */
113  int wrapColumn; /* max line length, or -1 for no limit */
114  int indentLevel; /* current indent level for prettyprint */
115  bool varprefix; /* true to print prefixes on Vars */
116  ParseExprKind special_exprkind; /* set only for exprkinds needing special
117  * handling */
119 
120 /*
121  * Each level of query context around a subtree needs a level of Var namespace.
122  * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
123  * the current context's namespaces list.
124  *
125  * The rangetable is the list of actual RTEs from the query tree, and the
126  * cte list is the list of actual CTEs.
127  *
128  * rtable_names holds the alias name to be used for each RTE (either a C
129  * string, or NULL for nameless RTEs such as unnamed joins).
130  * rtable_columns holds the column alias names to be used for each RTE.
131  *
132  * In some cases we need to make names of merged JOIN USING columns unique
133  * across the whole query, not only per-RTE. If so, unique_using is true
134  * and using_names is a list of C strings representing names already assigned
135  * to USING columns.
136  *
137  * When deparsing plan trees, there is always just a single item in the
138  * deparse_namespace list (since a plan tree never contains Vars with
139  * varlevelsup > 0). We store the PlanState node that is the immediate
140  * parent of the expression to be deparsed, as well as a list of that
141  * PlanState's ancestors. In addition, we store its outer and inner subplan
142  * state nodes, as well as their plan nodes' targetlists, and the index tlist
143  * if the current plan node might contain INDEX_VAR Vars. (These fields could
144  * be derived on-the-fly from the current PlanState, but it seems notationally
145  * clearer to set them up as separate fields.)
146  */
147 typedef struct
148 {
149  List *rtable; /* List of RangeTblEntry nodes */
150  List *rtable_names; /* Parallel list of names for RTEs */
151  List *rtable_columns; /* Parallel list of deparse_columns structs */
152  List *ctes; /* List of CommonTableExpr nodes */
153  /* Workspace for column alias assignment: */
154  bool unique_using; /* Are we making USING names globally unique */
155  List *using_names; /* List of assigned names for USING columns */
156  /* Remaining fields are used only when deparsing a Plan tree: */
157  PlanState *planstate; /* immediate parent of current expression */
158  List *ancestors; /* ancestors of planstate */
159  PlanState *outer_planstate; /* outer subplan state, or NULL if none */
160  PlanState *inner_planstate; /* inner subplan state, or NULL if none */
161  List *outer_tlist; /* referent for OUTER_VAR Vars */
162  List *inner_tlist; /* referent for INNER_VAR Vars */
163  List *index_tlist; /* referent for INDEX_VAR Vars */
165 
166 /*
167  * Per-relation data about column alias names.
168  *
169  * Selecting aliases is unreasonably complicated because of the need to dump
170  * rules/views whose underlying tables may have had columns added, deleted, or
171  * renamed since the query was parsed. We must nonetheless print the rule/view
172  * in a form that can be reloaded and will produce the same results as before.
173  *
174  * For each RTE used in the query, we must assign column aliases that are
175  * unique within that RTE. SQL does not require this of the original query,
176  * but due to factors such as *-expansion we need to be able to uniquely
177  * reference every column in a decompiled query. As long as we qualify all
178  * column references, per-RTE uniqueness is sufficient for that.
179  *
180  * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
181  * since they just inherit column names from their input RTEs, and we can't
182  * rename the columns at the join level. Most of the time this isn't an issue
183  * because we don't need to reference the join's output columns as such; we
184  * can reference the input columns instead. That approach can fail for merged
185  * JOIN USING columns, however, so when we have one of those in an unnamed
186  * join, we have to make that column's alias globally unique across the whole
187  * query to ensure it can be referenced unambiguously.
188  *
189  * Another problem is that a JOIN USING clause requires the columns to be
190  * merged to have the same aliases in both input RTEs, and that no other
191  * columns in those RTEs or their children conflict with the USING names.
192  * To handle that, we do USING-column alias assignment in a recursive
193  * traversal of the query's jointree. When descending through a JOIN with
194  * USING, we preassign the USING column names to the child columns, overriding
195  * other rules for column alias assignment. We also mark each RTE with a list
196  * of all USING column names selected for joins containing that RTE, so that
197  * when we assign other columns' aliases later, we can avoid conflicts.
198  *
199  * Another problem is that if a JOIN's input tables have had columns added or
200  * deleted since the query was parsed, we must generate a column alias list
201  * for the join that matches the current set of input columns --- otherwise, a
202  * change in the number of columns in the left input would throw off matching
203  * of aliases to columns of the right input. Thus, positions in the printable
204  * column alias list are not necessarily one-for-one with varattnos of the
205  * JOIN, so we need a separate new_colnames[] array for printing purposes.
206  */
207 typedef struct
208 {
209  /*
210  * colnames is an array containing column aliases to use for columns that
211  * existed when the query was parsed. Dropped columns have NULL entries.
212  * This array can be directly indexed by varattno to get a Var's name.
213  *
214  * Non-NULL entries are guaranteed unique within the RTE, *except* when
215  * this is for an unnamed JOIN RTE. In that case we merely copy up names
216  * from the two input RTEs.
217  *
218  * During the recursive descent in set_using_names(), forcible assignment
219  * of a child RTE's column name is represented by pre-setting that element
220  * of the child's colnames array. So at that stage, NULL entries in this
221  * array just mean that no name has been preassigned, not necessarily that
222  * the column is dropped.
223  */
224  int num_cols; /* length of colnames[] array */
225  char **colnames; /* array of C strings and NULLs */
226 
227  /*
228  * new_colnames is an array containing column aliases to use for columns
229  * that would exist if the query was re-parsed against the current
230  * definitions of its base tables. This is what to print as the column
231  * alias list for the RTE. This array does not include dropped columns,
232  * but it will include columns added since original parsing. Indexes in
233  * it therefore have little to do with current varattno values. As above,
234  * entries are unique unless this is for an unnamed JOIN RTE. (In such an
235  * RTE, we never actually print this array, but we must compute it anyway
236  * for possible use in computing column names of upper joins.) The
237  * parallel array is_new_col marks which of these columns are new since
238  * original parsing. Entries with is_new_col false must match the
239  * non-NULL colnames entries one-for-one.
240  */
241  int num_new_cols; /* length of new_colnames[] array */
242  char **new_colnames; /* array of C strings */
243  bool *is_new_col; /* array of bool flags */
244 
245  /* This flag tells whether we should actually print a column alias list */
247 
248  /* This list has all names used as USING names in joins above this RTE */
249  List *parentUsing; /* names assigned to parent merged columns */
250 
251  /*
252  * If this struct is for a JOIN RTE, we fill these fields during the
253  * set_using_names() pass to describe its relationship to its child RTEs.
254  *
255  * leftattnos and rightattnos are arrays with one entry per existing
256  * output column of the join (hence, indexable by join varattno). For a
257  * simple reference to a column of the left child, leftattnos[i] is the
258  * child RTE's attno and rightattnos[i] is zero; and conversely for a
259  * column of the right child. But for merged columns produced by JOIN
260  * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
261  * Also, if the column has been dropped, both are zero.
262  *
263  * If it's a JOIN USING, usingNames holds the alias names selected for the
264  * merged columns (these might be different from the original USING list,
265  * if we had to modify names to achieve uniqueness).
266  */
267  int leftrti; /* rangetable index of left child */
268  int rightrti; /* rangetable index of right child */
269  int *leftattnos; /* left-child varattnos of join cols, or 0 */
270  int *rightattnos; /* right-child varattnos of join cols, or 0 */
271  List *usingNames; /* names assigned to merged columns */
273 
274 /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
275 #define deparse_columns_fetch(rangetable_index, dpns) \
276  ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
277 
278 /*
279  * Entry in set_rtable_names' hash table
280  */
281 typedef struct
282 {
283  char name[NAMEDATALEN]; /* Hash key --- must be first */
284  int counter; /* Largest addition used so far for name */
285 } NameHashEntry;
286 
287 
288 /* ----------
289  * Global data
290  * ----------
291  */
293 static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
295 static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
296 
297 /* GUC parameters */
299 
300 
301 /* ----------
302  * Local functions
303  *
304  * Most of these functions used to use fixed-size buffers to build their
305  * results. Now, they take an (already initialized) StringInfo object
306  * as a parameter, and append their text output to its contents.
307  * ----------
308  */
309 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
310  bool forceprefix, bool showimplicit,
311  int prettyFlags, int startIndent);
312 static char *pg_get_viewdef_worker(Oid viewoid,
313  int prettyFlags, int wrapColumn);
314 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
315 static void decompile_column_index_array(Datum column_index_array, Oid relId,
316  StringInfo buf);
317 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
318 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
319  const Oid *excludeOps,
320  bool attrsOnly, bool showTblSpc,
321  int prettyFlags, bool missing_ok);
322 static char *pg_get_statisticsobj_worker(Oid statextid, bool missing_ok);
323 static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
324  bool attrsOnly, bool missing_ok);
325 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
326  int prettyFlags, bool missing_ok);
327 static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
328  int prettyFlags);
330  bool print_table_args, bool print_defaults);
331 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
332 static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
333 static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
334  Bitmapset *rels_used);
335 static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
336  List *parent_namespaces);
337 static void set_simple_column_names(deparse_namespace *dpns);
338 static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
339 static void set_using_names(deparse_namespace *dpns, Node *jtnode,
340  List *parentUsing);
342  RangeTblEntry *rte,
343  deparse_columns *colinfo);
345  deparse_columns *colinfo);
346 static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
347  deparse_columns *colinfo);
348 static char *make_colname_unique(char *colname, deparse_namespace *dpns,
349  deparse_columns *colinfo);
350 static void expand_colnames_array_to(deparse_columns *colinfo, int n);
351 static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
352  deparse_columns *colinfo);
353 static void flatten_join_using_qual(Node *qual,
354  List **leftvars, List **rightvars);
355 static char *get_rtable_name(int rtindex, deparse_context *context);
356 static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps);
357 static void push_child_plan(deparse_namespace *dpns, PlanState *ps,
358  deparse_namespace *save_dpns);
359 static void pop_child_plan(deparse_namespace *dpns,
360  deparse_namespace *save_dpns);
361 static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
362  deparse_namespace *save_dpns);
363 static void pop_ancestor_plan(deparse_namespace *dpns,
364  deparse_namespace *save_dpns);
365 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
366  int prettyFlags);
367 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
368  int prettyFlags, int wrapColumn);
369 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
370  TupleDesc resultDesc,
371  int prettyFlags, int wrapColumn, int startIndent);
372 static void get_values_def(List *values_lists, deparse_context *context);
373 static void get_with_clause(Query *query, deparse_context *context);
374 static void get_select_query_def(Query *query, deparse_context *context,
375  TupleDesc resultDesc);
376 static void get_insert_query_def(Query *query, deparse_context *context);
377 static void get_update_query_def(Query *query, deparse_context *context);
378 static void get_update_query_targetlist_def(Query *query, List *targetList,
379  deparse_context *context,
380  RangeTblEntry *rte);
381 static void get_delete_query_def(Query *query, deparse_context *context);
382 static void get_utility_query_def(Query *query, deparse_context *context);
383 static void get_basic_select_query(Query *query, deparse_context *context,
384  TupleDesc resultDesc);
385 static void get_target_list(List *targetList, deparse_context *context,
386  TupleDesc resultDesc);
387 static void get_setop_query(Node *setOp, Query *query,
388  deparse_context *context,
389  TupleDesc resultDesc);
390 static Node *get_rule_sortgroupclause(Index ref, List *tlist,
391  bool force_colno,
392  deparse_context *context);
393 static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
394  bool omit_parens, deparse_context *context);
395 static void get_rule_orderby(List *orderList, List *targetList,
396  bool force_colno, deparse_context *context);
397 static void get_rule_windowclause(Query *query, deparse_context *context);
398 static void get_rule_windowspec(WindowClause *wc, List *targetList,
399  deparse_context *context);
400 static char *get_variable(Var *var, int levelsup, bool istoplevel,
401  deparse_context *context);
402 static void get_special_variable(Node *node, deparse_context *context,
403  void *private);
404 static void resolve_special_varno(Node *node, deparse_context *context,
405  void *private,
406  void (*callback) (Node *, deparse_context *, void *));
407 static Node *find_param_referent(Param *param, deparse_context *context,
408  deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
409 static void get_parameter(Param *param, deparse_context *context);
410 static const char *get_simple_binary_op_name(OpExpr *expr);
411 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
412 static void appendContextKeyword(deparse_context *context, const char *str,
413  int indentBefore, int indentAfter, int indentPlus);
415 static void get_rule_expr(Node *node, deparse_context *context,
416  bool showimplicit);
417 static void get_rule_expr_toplevel(Node *node, deparse_context *context,
418  bool showimplicit);
419 static void get_rule_expr_funccall(Node *node, deparse_context *context,
420  bool showimplicit);
421 static bool looks_like_function(Node *node);
422 static void get_oper_expr(OpExpr *expr, deparse_context *context);
423 static void get_func_expr(FuncExpr *expr, deparse_context *context,
424  bool showimplicit);
425 static void get_agg_expr(Aggref *aggref, deparse_context *context,
426  Aggref *original_aggref);
427 static void get_agg_combine_expr(Node *node, deparse_context *context,
428  void *private);
429 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
430 static void get_coercion_expr(Node *arg, deparse_context *context,
431  Oid resulttype, int32 resulttypmod,
432  Node *parentNode);
433 static void get_const_expr(Const *constval, deparse_context *context,
434  int showtype);
435 static void get_const_collation(Const *constval, deparse_context *context);
436 static void simple_quote_literal(StringInfo buf, const char *val);
437 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
438 static void get_tablefunc(TableFunc *tf, deparse_context *context,
439  bool showimplicit);
440 static void get_from_clause(Query *query, const char *prefix,
441  deparse_context *context);
442 static void get_from_clause_item(Node *jtnode, Query *query,
443  deparse_context *context);
444 static void get_column_alias_list(deparse_columns *colinfo,
445  deparse_context *context);
446 static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
447  deparse_columns *colinfo,
448  deparse_context *context);
449 static void get_tablesample_def(TableSampleClause *tablesample,
450  deparse_context *context);
451 static void get_opclass_name(Oid opclass, Oid actual_datatype,
452  StringInfo buf);
453 static Node *processIndirection(Node *node, deparse_context *context);
454 static void printSubscripts(ArrayRef *aref, deparse_context *context);
455 static char *get_relation_name(Oid relid);
456 static char *generate_relation_name(Oid relid, List *namespaces);
457 static char *generate_qualified_relation_name(Oid relid);
458 static char *generate_function_name(Oid funcid, int nargs,
459  List *argnames, Oid *argtypes,
460  bool has_variadic, bool *use_variadic_p,
461  ParseExprKind special_exprkind);
462 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
463 static char *generate_qualified_type_name(Oid typid);
464 static text *string_to_text(char *str);
465 static char *flatten_reloptions(Oid relid);
466 
467 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
468 
469 
470 /* ----------
471  * get_ruledef - Do it all and return a text
472  * that could be used as a statement
473  * to recreate the rule
474  * ----------
475  */
476 Datum
478 {
479  Oid ruleoid = PG_GETARG_OID(0);
480  int prettyFlags;
481  char *res;
482 
483  prettyFlags = PRETTYFLAG_INDENT;
484 
485  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
486 
487  if (res == NULL)
488  PG_RETURN_NULL();
489 
491 }
492 
493 
494 Datum
496 {
497  Oid ruleoid = PG_GETARG_OID(0);
498  bool pretty = PG_GETARG_BOOL(1);
499  int prettyFlags;
500  char *res;
501 
502  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
503 
504  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
505 
506  if (res == NULL)
507  PG_RETURN_NULL();
508 
510 }
511 
512 
513 static char *
514 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
515 {
516  Datum args[1];
517  char nulls[1];
518  int spirc;
519  HeapTuple ruletup;
520  TupleDesc rulettc;
522 
523  /*
524  * Do this first so that string is alloc'd in outer context not SPI's.
525  */
526  initStringInfo(&buf);
527 
528  /*
529  * Connect to SPI manager
530  */
531  if (SPI_connect() != SPI_OK_CONNECT)
532  elog(ERROR, "SPI_connect failed");
533 
534  /*
535  * On the first call prepare the plan to lookup pg_rewrite. We read
536  * pg_rewrite over the SPI manager instead of using the syscache to be
537  * checked for read access on pg_rewrite.
538  */
539  if (plan_getrulebyoid == NULL)
540  {
541  Oid argtypes[1];
542  SPIPlanPtr plan;
543 
544  argtypes[0] = OIDOID;
545  plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
546  if (plan == NULL)
547  elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
548  SPI_keepplan(plan);
549  plan_getrulebyoid = plan;
550  }
551 
552  /*
553  * Get the pg_rewrite tuple for this rule
554  */
555  args[0] = ObjectIdGetDatum(ruleoid);
556  nulls[0] = ' ';
557  spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
558  if (spirc != SPI_OK_SELECT)
559  elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
560  if (SPI_processed != 1)
561  {
562  /*
563  * There is no tuple data available here, just keep the output buffer
564  * empty.
565  */
566  }
567  else
568  {
569  /*
570  * Get the rule's definition and put it into executor's memory
571  */
572  ruletup = SPI_tuptable->vals[0];
573  rulettc = SPI_tuptable->tupdesc;
574  make_ruledef(&buf, ruletup, rulettc, prettyFlags);
575  }
576 
577  /*
578  * Disconnect from SPI manager
579  */
580  if (SPI_finish() != SPI_OK_FINISH)
581  elog(ERROR, "SPI_finish failed");
582 
583  if (buf.len == 0)
584  return NULL;
585 
586  return buf.data;
587 }
588 
589 
590 /* ----------
591  * get_viewdef - Mainly the same thing, but we
592  * only return the SELECT part of a view
593  * ----------
594  */
595 Datum
597 {
598  /* By OID */
599  Oid viewoid = PG_GETARG_OID(0);
600  int prettyFlags;
601  char *res;
602 
603  prettyFlags = PRETTYFLAG_INDENT;
604 
605  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
606 
607  if (res == NULL)
608  PG_RETURN_NULL();
609 
611 }
612 
613 
614 Datum
616 {
617  /* By OID */
618  Oid viewoid = PG_GETARG_OID(0);
619  bool pretty = PG_GETARG_BOOL(1);
620  int prettyFlags;
621  char *res;
622 
623  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
624 
625  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
626 
627  if (res == NULL)
628  PG_RETURN_NULL();
629 
631 }
632 
633 Datum
635 {
636  /* By OID */
637  Oid viewoid = PG_GETARG_OID(0);
638  int wrap = PG_GETARG_INT32(1);
639  int prettyFlags;
640  char *res;
641 
642  /* calling this implies we want pretty printing */
643  prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT;
644 
645  res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
646 
647  if (res == NULL)
648  PG_RETURN_NULL();
649 
651 }
652 
653 Datum
655 {
656  /* By qualified name */
657  text *viewname = PG_GETARG_TEXT_PP(0);
658  int prettyFlags;
659  RangeVar *viewrel;
660  Oid viewoid;
661  char *res;
662 
663  prettyFlags = PRETTYFLAG_INDENT;
664 
665  /* Look up view name. Can't lock it - we might not have privileges. */
667  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
668 
669  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
670 
671  if (res == NULL)
672  PG_RETURN_NULL();
673 
675 }
676 
677 
678 Datum
680 {
681  /* By qualified name */
682  text *viewname = PG_GETARG_TEXT_PP(0);
683  bool pretty = PG_GETARG_BOOL(1);
684  int prettyFlags;
685  RangeVar *viewrel;
686  Oid viewoid;
687  char *res;
688 
689  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
690 
691  /* Look up view name. Can't lock it - we might not have privileges. */
693  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
694 
695  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
696 
697  if (res == NULL)
698  PG_RETURN_NULL();
699 
701 }
702 
703 /*
704  * Common code for by-OID and by-name variants of pg_get_viewdef
705  */
706 static char *
707 pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
708 {
709  Datum args[2];
710  char nulls[2];
711  int spirc;
712  HeapTuple ruletup;
713  TupleDesc rulettc;
715 
716  /*
717  * Do this first so that string is alloc'd in outer context not SPI's.
718  */
719  initStringInfo(&buf);
720 
721  /*
722  * Connect to SPI manager
723  */
724  if (SPI_connect() != SPI_OK_CONNECT)
725  elog(ERROR, "SPI_connect failed");
726 
727  /*
728  * On the first call prepare the plan to lookup pg_rewrite. We read
729  * pg_rewrite over the SPI manager instead of using the syscache to be
730  * checked for read access on pg_rewrite.
731  */
732  if (plan_getviewrule == NULL)
733  {
734  Oid argtypes[2];
735  SPIPlanPtr plan;
736 
737  argtypes[0] = OIDOID;
738  argtypes[1] = NAMEOID;
739  plan = SPI_prepare(query_getviewrule, 2, argtypes);
740  if (plan == NULL)
741  elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
742  SPI_keepplan(plan);
743  plan_getviewrule = plan;
744  }
745 
746  /*
747  * Get the pg_rewrite tuple for the view's SELECT rule
748  */
749  args[0] = ObjectIdGetDatum(viewoid);
751  nulls[0] = ' ';
752  nulls[1] = ' ';
753  spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
754  if (spirc != SPI_OK_SELECT)
755  elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
756  if (SPI_processed != 1)
757  {
758  /*
759  * There is no tuple data available here, just keep the output buffer
760  * empty.
761  */
762  }
763  else
764  {
765  /*
766  * Get the rule's definition and put it into executor's memory
767  */
768  ruletup = SPI_tuptable->vals[0];
769  rulettc = SPI_tuptable->tupdesc;
770  make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
771  }
772 
773  /*
774  * Disconnect from SPI manager
775  */
776  if (SPI_finish() != SPI_OK_FINISH)
777  elog(ERROR, "SPI_finish failed");
778 
779  if (buf.len == 0)
780  return NULL;
781 
782  return buf.data;
783 }
784 
785 /* ----------
786  * get_triggerdef - Get the definition of a trigger
787  * ----------
788  */
789 Datum
791 {
792  Oid trigid = PG_GETARG_OID(0);
793  char *res;
794 
795  res = pg_get_triggerdef_worker(trigid, false);
796 
797  if (res == NULL)
798  PG_RETURN_NULL();
799 
801 }
802 
803 Datum
805 {
806  Oid trigid = PG_GETARG_OID(0);
807  bool pretty = PG_GETARG_BOOL(1);
808  char *res;
809 
810  res = pg_get_triggerdef_worker(trigid, pretty);
811 
812  if (res == NULL)
813  PG_RETURN_NULL();
814 
816 }
817 
818 static char *
819 pg_get_triggerdef_worker(Oid trigid, bool pretty)
820 {
821  HeapTuple ht_trig;
822  Form_pg_trigger trigrec;
824  Relation tgrel;
825  ScanKeyData skey[1];
826  SysScanDesc tgscan;
827  int findx = 0;
828  char *tgname;
829  char *tgoldtable;
830  char *tgnewtable;
831  Oid argtypes[1]; /* dummy */
832  Datum value;
833  bool isnull;
834 
835  /*
836  * Fetch the pg_trigger tuple by the Oid of the trigger
837  */
839 
840  ScanKeyInit(&skey[0],
842  BTEqualStrategyNumber, F_OIDEQ,
843  ObjectIdGetDatum(trigid));
844 
845  tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
846  NULL, 1, skey);
847 
848  ht_trig = systable_getnext(tgscan);
849 
850  if (!HeapTupleIsValid(ht_trig))
851  {
852  systable_endscan(tgscan);
853  heap_close(tgrel, AccessShareLock);
854  return NULL;
855  }
856 
857  trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
858 
859  /*
860  * Start the trigger definition. Note that the trigger's name should never
861  * be schema-qualified, but the trigger rel's name may be.
862  */
863  initStringInfo(&buf);
864 
865  tgname = NameStr(trigrec->tgname);
866  appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
867  OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
868  quote_identifier(tgname));
869 
870  if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
871  appendStringInfoString(&buf, "BEFORE");
872  else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
873  appendStringInfoString(&buf, "AFTER");
874  else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
875  appendStringInfoString(&buf, "INSTEAD OF");
876  else
877  elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
878 
879  if (TRIGGER_FOR_INSERT(trigrec->tgtype))
880  {
881  appendStringInfoString(&buf, " INSERT");
882  findx++;
883  }
884  if (TRIGGER_FOR_DELETE(trigrec->tgtype))
885  {
886  if (findx > 0)
887  appendStringInfoString(&buf, " OR DELETE");
888  else
889  appendStringInfoString(&buf, " DELETE");
890  findx++;
891  }
892  if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
893  {
894  if (findx > 0)
895  appendStringInfoString(&buf, " OR UPDATE");
896  else
897  appendStringInfoString(&buf, " UPDATE");
898  findx++;
899  /* tgattr is first var-width field, so OK to access directly */
900  if (trigrec->tgattr.dim1 > 0)
901  {
902  int i;
903 
904  appendStringInfoString(&buf, " OF ");
905  for (i = 0; i < trigrec->tgattr.dim1; i++)
906  {
907  char *attname;
908 
909  if (i > 0)
910  appendStringInfoString(&buf, ", ");
911  attname = get_relid_attribute_name(trigrec->tgrelid,
912  trigrec->tgattr.values[i]);
914  }
915  }
916  }
917  if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
918  {
919  if (findx > 0)
920  appendStringInfoString(&buf, " OR TRUNCATE");
921  else
922  appendStringInfoString(&buf, " TRUNCATE");
923  findx++;
924  }
925  appendStringInfo(&buf, " ON %s ",
926  generate_relation_name(trigrec->tgrelid, NIL));
927 
928  if (OidIsValid(trigrec->tgconstraint))
929  {
930  if (OidIsValid(trigrec->tgconstrrelid))
931  appendStringInfo(&buf, "FROM %s ",
932  generate_relation_name(trigrec->tgconstrrelid, NIL));
933  if (!trigrec->tgdeferrable)
934  appendStringInfoString(&buf, "NOT ");
935  appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
936  if (trigrec->tginitdeferred)
937  appendStringInfoString(&buf, "DEFERRED ");
938  else
939  appendStringInfoString(&buf, "IMMEDIATE ");
940  }
941 
942  value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
943  tgrel->rd_att, &isnull);
944  if (!isnull)
945  tgoldtable = NameStr(*((NameData *) DatumGetPointer(value)));
946  else
947  tgoldtable = NULL;
948  value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
949  tgrel->rd_att, &isnull);
950  if (!isnull)
951  tgnewtable = NameStr(*((NameData *) DatumGetPointer(value)));
952  else
953  tgnewtable = NULL;
954  if (tgoldtable != NULL || tgnewtable != NULL)
955  {
956  appendStringInfoString(&buf, "REFERENCING ");
957  if (tgoldtable != NULL)
958  appendStringInfo(&buf, "OLD TABLE AS %s ", tgoldtable);
959  if (tgnewtable != NULL)
960  appendStringInfo(&buf, "NEW TABLE AS %s ", tgnewtable);
961  }
962 
963  if (TRIGGER_FOR_ROW(trigrec->tgtype))
964  appendStringInfoString(&buf, "FOR EACH ROW ");
965  else
966  appendStringInfoString(&buf, "FOR EACH STATEMENT ");
967 
968  /* If the trigger has a WHEN qualification, add that */
969  value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
970  tgrel->rd_att, &isnull);
971  if (!isnull)
972  {
973  Node *qual;
974  char relkind;
975  deparse_context context;
976  deparse_namespace dpns;
977  RangeTblEntry *oldrte;
978  RangeTblEntry *newrte;
979 
980  appendStringInfoString(&buf, "WHEN (");
981 
982  qual = stringToNode(TextDatumGetCString(value));
983 
984  relkind = get_rel_relkind(trigrec->tgrelid);
985 
986  /* Build minimal OLD and NEW RTEs for the rel */
987  oldrte = makeNode(RangeTblEntry);
988  oldrte->rtekind = RTE_RELATION;
989  oldrte->relid = trigrec->tgrelid;
990  oldrte->relkind = relkind;
991  oldrte->alias = makeAlias("old", NIL);
992  oldrte->eref = oldrte->alias;
993  oldrte->lateral = false;
994  oldrte->inh = false;
995  oldrte->inFromCl = true;
996 
997  newrte = makeNode(RangeTblEntry);
998  newrte->rtekind = RTE_RELATION;
999  newrte->relid = trigrec->tgrelid;
1000  newrte->relkind = relkind;
1001  newrte->alias = makeAlias("new", NIL);
1002  newrte->eref = newrte->alias;
1003  newrte->lateral = false;
1004  newrte->inh = false;
1005  newrte->inFromCl = true;
1006 
1007  /* Build two-element rtable */
1008  memset(&dpns, 0, sizeof(dpns));
1009  dpns.rtable = list_make2(oldrte, newrte);
1010  dpns.ctes = NIL;
1011  set_rtable_names(&dpns, NIL, NULL);
1012  set_simple_column_names(&dpns);
1013 
1014  /* Set up context with one-deep namespace stack */
1015  context.buf = &buf;
1016  context.namespaces = list_make1(&dpns);
1017  context.windowClause = NIL;
1018  context.windowTList = NIL;
1019  context.varprefix = true;
1021  context.wrapColumn = WRAP_COLUMN_DEFAULT;
1022  context.indentLevel = PRETTYINDENT_STD;
1023  context.special_exprkind = EXPR_KIND_NONE;
1024 
1025  get_rule_expr(qual, &context, false);
1026 
1027  appendStringInfoString(&buf, ") ");
1028  }
1029 
1030  appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
1031  generate_function_name(trigrec->tgfoid, 0,
1032  NIL, argtypes,
1033  false, NULL, EXPR_KIND_NONE));
1034 
1035  if (trigrec->tgnargs > 0)
1036  {
1037  char *p;
1038  int i;
1039 
1040  value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1041  tgrel->rd_att, &isnull);
1042  if (isnull)
1043  elog(ERROR, "tgargs is null for trigger %u", trigid);
1044  p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1045  for (i = 0; i < trigrec->tgnargs; i++)
1046  {
1047  if (i > 0)
1048  appendStringInfoString(&buf, ", ");
1049  simple_quote_literal(&buf, p);
1050  /* advance p to next string embedded in tgargs */
1051  while (*p)
1052  p++;
1053  p++;
1054  }
1055  }
1056 
1057  /* We deliberately do not put semi-colon at end */
1058  appendStringInfoChar(&buf, ')');
1059 
1060  /* Clean up */
1061  systable_endscan(tgscan);
1062 
1063  heap_close(tgrel, AccessShareLock);
1064 
1065  return buf.data;
1066 }
1067 
1068 /* ----------
1069  * get_indexdef - Get the definition of an index
1070  *
1071  * In the extended version, there is a colno argument as well as pretty bool.
1072  * if colno == 0, we want a complete index definition.
1073  * if colno > 0, we only want the Nth index key's variable or expression.
1074  *
1075  * Note that the SQL-function versions of this omit any info about the
1076  * index tablespace; this is intentional because pg_dump wants it that way.
1077  * However pg_get_indexdef_string() includes the index tablespace.
1078  * ----------
1079  */
1080 Datum
1082 {
1083  Oid indexrelid = PG_GETARG_OID(0);
1084  int prettyFlags;
1085  char *res;
1086 
1087  prettyFlags = PRETTYFLAG_INDENT;
1088 
1089  res = pg_get_indexdef_worker(indexrelid, 0, NULL, false, false,
1090  prettyFlags, true);
1091 
1092  if (res == NULL)
1093  PG_RETURN_NULL();
1094 
1096 }
1097 
1098 Datum
1100 {
1101  Oid indexrelid = PG_GETARG_OID(0);
1102  int32 colno = PG_GETARG_INT32(1);
1103  bool pretty = PG_GETARG_BOOL(2);
1104  int prettyFlags;
1105  char *res;
1106 
1107  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
1108 
1109  res = pg_get_indexdef_worker(indexrelid, colno, NULL, colno != 0, false,
1110  prettyFlags, true);
1111 
1112  if (res == NULL)
1113  PG_RETURN_NULL();
1114 
1116 }
1117 
1118 /*
1119  * Internal version for use by ALTER TABLE.
1120  * Includes a tablespace clause in the result.
1121  * Returns a palloc'd C string; no pretty-printing.
1122  */
1123 char *
1125 {
1126  return pg_get_indexdef_worker(indexrelid, 0, NULL, false, true, 0, false);
1127 }
1128 
1129 /* Internal version that just reports the column definitions */
1130 char *
1131 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1132 {
1133  int prettyFlags;
1134 
1135  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
1136  return pg_get_indexdef_worker(indexrelid, 0, NULL, true, false,
1137  prettyFlags, false);
1138 }
1139 
1140 /*
1141  * Internal workhorse to decompile an index definition.
1142  *
1143  * This is now used for exclusion constraints as well: if excludeOps is not
1144  * NULL then it points to an array of exclusion operator OIDs.
1145  */
1146 static char *
1147 pg_get_indexdef_worker(Oid indexrelid, int colno,
1148  const Oid *excludeOps,
1149  bool attrsOnly, bool showTblSpc,
1150  int prettyFlags, bool missing_ok)
1151 {
1152  /* might want a separate isConstraint parameter later */
1153  bool isConstraint = (excludeOps != NULL);
1154  HeapTuple ht_idx;
1155  HeapTuple ht_idxrel;
1156  HeapTuple ht_am;
1157  Form_pg_index idxrec;
1158  Form_pg_class idxrelrec;
1159  Form_pg_am amrec;
1160  IndexAmRoutine *amroutine;
1161  List *indexprs;
1162  ListCell *indexpr_item;
1163  List *context;
1164  Oid indrelid;
1165  int keyno;
1166  Datum indcollDatum;
1167  Datum indclassDatum;
1168  Datum indoptionDatum;
1169  bool isnull;
1170  oidvector *indcollation;
1171  oidvector *indclass;
1172  int2vector *indoption;
1174  char *str;
1175  char *sep;
1176 
1177  /*
1178  * Fetch the pg_index tuple by the Oid of the index
1179  */
1180  ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1181  if (!HeapTupleIsValid(ht_idx))
1182  {
1183  if (missing_ok)
1184  return NULL;
1185  elog(ERROR, "cache lookup failed for index %u", indexrelid);
1186  }
1187  idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1188 
1189  indrelid = idxrec->indrelid;
1190  Assert(indexrelid == idxrec->indexrelid);
1191 
1192  /* Must get indcollation, indclass, and indoption the hard way */
1193  indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1194  Anum_pg_index_indcollation, &isnull);
1195  Assert(!isnull);
1196  indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1197 
1198  indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1199  Anum_pg_index_indclass, &isnull);
1200  Assert(!isnull);
1201  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1202 
1203  indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1204  Anum_pg_index_indoption, &isnull);
1205  Assert(!isnull);
1206  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1207 
1208  /*
1209  * Fetch the pg_class tuple of the index relation
1210  */
1211  ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1212  if (!HeapTupleIsValid(ht_idxrel))
1213  elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1214  idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1215 
1216  /*
1217  * Fetch the pg_am tuple of the index' access method
1218  */
1219  ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1220  if (!HeapTupleIsValid(ht_am))
1221  elog(ERROR, "cache lookup failed for access method %u",
1222  idxrelrec->relam);
1223  amrec = (Form_pg_am) GETSTRUCT(ht_am);
1224 
1225  /* Fetch the index AM's API struct */
1226  amroutine = GetIndexAmRoutine(amrec->amhandler);
1227 
1228  /*
1229  * Get the index expressions, if any. (NOTE: we do not use the relcache
1230  * versions of the expressions and predicate, because we want to display
1231  * non-const-folded expressions.)
1232  */
1233  if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
1234  {
1235  Datum exprsDatum;
1236  bool isnull;
1237  char *exprsString;
1238 
1239  exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1240  Anum_pg_index_indexprs, &isnull);
1241  Assert(!isnull);
1242  exprsString = TextDatumGetCString(exprsDatum);
1243  indexprs = (List *) stringToNode(exprsString);
1244  pfree(exprsString);
1245  }
1246  else
1247  indexprs = NIL;
1248 
1249  indexpr_item = list_head(indexprs);
1250 
1251  context = deparse_context_for(get_relation_name(indrelid), indrelid);
1252 
1253  /*
1254  * Start the index definition. Note that the index's name should never be
1255  * schema-qualified, but the indexed rel's name may be.
1256  */
1257  initStringInfo(&buf);
1258 
1259  if (!attrsOnly)
1260  {
1261  if (!isConstraint)
1262  appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
1263  idxrec->indisunique ? "UNIQUE " : "",
1264  quote_identifier(NameStr(idxrelrec->relname)),
1265  generate_relation_name(indrelid, NIL),
1266  quote_identifier(NameStr(amrec->amname)));
1267  else /* currently, must be EXCLUDE constraint */
1268  appendStringInfo(&buf, "EXCLUDE USING %s (",
1269  quote_identifier(NameStr(amrec->amname)));
1270  }
1271 
1272  /*
1273  * Report the indexed attributes
1274  */
1275  sep = "";
1276  for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1277  {
1278  AttrNumber attnum = idxrec->indkey.values[keyno];
1279  int16 opt = indoption->values[keyno];
1280  Oid keycoltype;
1281  Oid keycolcollation;
1282 
1283  if (!colno)
1284  appendStringInfoString(&buf, sep);
1285  sep = ", ";
1286 
1287  if (attnum != 0)
1288  {
1289  /* Simple index column */
1290  char *attname;
1291  int32 keycoltypmod;
1292 
1293  attname = get_relid_attribute_name(indrelid, attnum);
1294  if (!colno || colno == keyno + 1)
1295  appendStringInfoString(&buf, quote_identifier(attname));
1296  get_atttypetypmodcoll(indrelid, attnum,
1297  &keycoltype, &keycoltypmod,
1298  &keycolcollation);
1299  }
1300  else
1301  {
1302  /* expressional index */
1303  Node *indexkey;
1304 
1305  if (indexpr_item == NULL)
1306  elog(ERROR, "too few entries in indexprs list");
1307  indexkey = (Node *) lfirst(indexpr_item);
1308  indexpr_item = lnext(indexpr_item);
1309  /* Deparse */
1310  str = deparse_expression_pretty(indexkey, context, false, false,
1311  prettyFlags, 0);
1312  if (!colno || colno == keyno + 1)
1313  {
1314  /* Need parens if it's not a bare function call */
1315  if (looks_like_function(indexkey))
1316  appendStringInfoString(&buf, str);
1317  else
1318  appendStringInfo(&buf, "(%s)", str);
1319  }
1320  keycoltype = exprType(indexkey);
1321  keycolcollation = exprCollation(indexkey);
1322  }
1323 
1324  if (!attrsOnly && (!colno || colno == keyno + 1))
1325  {
1326  Oid indcoll;
1327 
1328  /* Add collation, if not default for column */
1329  indcoll = indcollation->values[keyno];
1330  if (OidIsValid(indcoll) && indcoll != keycolcollation)
1331  appendStringInfo(&buf, " COLLATE %s",
1332  generate_collation_name((indcoll)));
1333 
1334  /* Add the operator class name, if not default */
1335  get_opclass_name(indclass->values[keyno], keycoltype, &buf);
1336 
1337  /* Add options if relevant */
1338  if (amroutine->amcanorder)
1339  {
1340  /* if it supports sort ordering, report DESC and NULLS opts */
1341  if (opt & INDOPTION_DESC)
1342  {
1343  appendStringInfoString(&buf, " DESC");
1344  /* NULLS FIRST is the default in this case */
1345  if (!(opt & INDOPTION_NULLS_FIRST))
1346  appendStringInfoString(&buf, " NULLS LAST");
1347  }
1348  else
1349  {
1350  if (opt & INDOPTION_NULLS_FIRST)
1351  appendStringInfoString(&buf, " NULLS FIRST");
1352  }
1353  }
1354 
1355  /* Add the exclusion operator if relevant */
1356  if (excludeOps != NULL)
1357  appendStringInfo(&buf, " WITH %s",
1358  generate_operator_name(excludeOps[keyno],
1359  keycoltype,
1360  keycoltype));
1361  }
1362  }
1363 
1364  if (!attrsOnly)
1365  {
1366  appendStringInfoChar(&buf, ')');
1367 
1368  /*
1369  * If it has options, append "WITH (options)"
1370  */
1371  str = flatten_reloptions(indexrelid);
1372  if (str)
1373  {
1374  appendStringInfo(&buf, " WITH (%s)", str);
1375  pfree(str);
1376  }
1377 
1378  /*
1379  * Print tablespace, but only if requested
1380  */
1381  if (showTblSpc)
1382  {
1383  Oid tblspc;
1384 
1385  tblspc = get_rel_tablespace(indexrelid);
1386  if (!OidIsValid(tblspc))
1387  tblspc = MyDatabaseTableSpace;
1388  if (isConstraint)
1389  appendStringInfoString(&buf, " USING INDEX");
1390  appendStringInfo(&buf, " TABLESPACE %s",
1392  }
1393 
1394  /*
1395  * If it's a partial index, decompile and append the predicate
1396  */
1397  if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
1398  {
1399  Node *node;
1400  Datum predDatum;
1401  bool isnull;
1402  char *predString;
1403 
1404  /* Convert text string to node tree */
1405  predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1406  Anum_pg_index_indpred, &isnull);
1407  Assert(!isnull);
1408  predString = TextDatumGetCString(predDatum);
1409  node = (Node *) stringToNode(predString);
1410  pfree(predString);
1411 
1412  /* Deparse */
1413  str = deparse_expression_pretty(node, context, false, false,
1414  prettyFlags, 0);
1415  if (isConstraint)
1416  appendStringInfo(&buf, " WHERE (%s)", str);
1417  else
1418  appendStringInfo(&buf, " WHERE %s", str);
1419  }
1420  }
1421 
1422  /* Clean up */
1423  ReleaseSysCache(ht_idx);
1424  ReleaseSysCache(ht_idxrel);
1425  ReleaseSysCache(ht_am);
1426 
1427  return buf.data;
1428 }
1429 
1430 /*
1431  * pg_get_statisticsobjdef
1432  * Get the definition of an extended statistics object
1433  */
1434 Datum
1436 {
1437  Oid statextid = PG_GETARG_OID(0);
1438  char *res;
1439 
1440  res = pg_get_statisticsobj_worker(statextid, true);
1441 
1442  if (res == NULL)
1443  PG_RETURN_NULL();
1444 
1446 }
1447 
1448 /*
1449  * Internal workhorse to decompile an extended statistics object.
1450  */
1451 static char *
1452 pg_get_statisticsobj_worker(Oid statextid, bool missing_ok)
1453 {
1454  Form_pg_statistic_ext statextrec;
1455  HeapTuple statexttup;
1457  int colno;
1458  char *nsp;
1459  ArrayType *arr;
1460  char *enabled;
1461  Datum datum;
1462  bool isnull;
1463  bool ndistinct_enabled;
1464  bool dependencies_enabled;
1465  int i;
1466 
1467  statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1468 
1469  if (!HeapTupleIsValid(statexttup))
1470  {
1471  if (missing_ok)
1472  return NULL;
1473  elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1474  }
1475 
1476  statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1477 
1478  initStringInfo(&buf);
1479 
1480  nsp = get_namespace_name(statextrec->stxnamespace);
1481  appendStringInfo(&buf, "CREATE STATISTICS %s",
1483  NameStr(statextrec->stxname)));
1484 
1485  /*
1486  * Decode the stxkind column so that we know which stats types to print.
1487  */
1488  datum = SysCacheGetAttr(STATEXTOID, statexttup,
1490  Assert(!isnull);
1491  arr = DatumGetArrayTypeP(datum);
1492  if (ARR_NDIM(arr) != 1 ||
1493  ARR_HASNULL(arr) ||
1494  ARR_ELEMTYPE(arr) != CHAROID)
1495  elog(ERROR, "stxkind is not a 1-D char array");
1496  enabled = (char *) ARR_DATA_PTR(arr);
1497 
1498  ndistinct_enabled = false;
1499  dependencies_enabled = false;
1500 
1501  for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1502  {
1503  if (enabled[i] == STATS_EXT_NDISTINCT)
1504  ndistinct_enabled = true;
1505  if (enabled[i] == STATS_EXT_DEPENDENCIES)
1506  dependencies_enabled = true;
1507  }
1508 
1509  /*
1510  * If any option is disabled, then we'll need to append the types clause
1511  * to show which options are enabled. We omit the types clause on purpose
1512  * when all options are enabled, so a pg_dump/pg_restore will create all
1513  * statistics types on a newer postgres version, if the statistics had all
1514  * options enabled on the original version.
1515  */
1516  if (!ndistinct_enabled || !dependencies_enabled)
1517  {
1518  appendStringInfoString(&buf, " (");
1519  if (ndistinct_enabled)
1520  appendStringInfoString(&buf, "ndistinct");
1521  else if (dependencies_enabled)
1522  appendStringInfoString(&buf, "dependencies");
1523  appendStringInfoChar(&buf, ')');
1524  }
1525 
1526  appendStringInfoString(&buf, " ON ");
1527 
1528  for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1529  {
1530  AttrNumber attnum = statextrec->stxkeys.values[colno];
1531  char *attname;
1532 
1533  if (colno > 0)
1534  appendStringInfoString(&buf, ", ");
1535 
1536  attname = get_relid_attribute_name(statextrec->stxrelid, attnum);
1537 
1538  appendStringInfoString(&buf, quote_identifier(attname));
1539  }
1540 
1541  appendStringInfo(&buf, " FROM %s",
1542  generate_relation_name(statextrec->stxrelid, NIL));
1543 
1544  ReleaseSysCache(statexttup);
1545 
1546  return buf.data;
1547 }
1548 
1549 /*
1550  * pg_get_partkeydef
1551  *
1552  * Returns the partition key specification, ie, the following:
1553  *
1554  * PARTITION BY { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1555  */
1556 Datum
1558 {
1559  Oid relid = PG_GETARG_OID(0);
1560  char *res;
1561 
1562  res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1563 
1564  if (res == NULL)
1565  PG_RETURN_NULL();
1566 
1568 }
1569 
1570 /* Internal version that just reports the column definitions */
1571 char *
1572 pg_get_partkeydef_columns(Oid relid, bool pretty)
1573 {
1574  int prettyFlags;
1575 
1576  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
1577  return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1578 }
1579 
1580 /*
1581  * Internal workhorse to decompile a partition key definition.
1582  */
1583 static char *
1584 pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1585  bool attrsOnly, bool missing_ok)
1586 {
1588  HeapTuple tuple;
1589  oidvector *partclass;
1590  oidvector *partcollation;
1591  List *partexprs;
1592  ListCell *partexpr_item;
1593  List *context;
1594  Datum datum;
1595  bool isnull;
1597  int keyno;
1598  char *str;
1599  char *sep;
1600 
1601  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1602  if (!HeapTupleIsValid(tuple))
1603  {
1604  if (missing_ok)
1605  return NULL;
1606  elog(ERROR, "cache lookup failed for partition key of %u", relid);
1607  }
1608 
1609  form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1610 
1611  Assert(form->partrelid == relid);
1612 
1613  /* Must get partclass and partcollation the hard way */
1614  datum = SysCacheGetAttr(PARTRELID, tuple,
1616  Assert(!isnull);
1617  partclass = (oidvector *) DatumGetPointer(datum);
1618 
1619  datum = SysCacheGetAttr(PARTRELID, tuple,
1621  Assert(!isnull);
1622  partcollation = (oidvector *) DatumGetPointer(datum);
1623 
1624 
1625  /*
1626  * Get the expressions, if any. (NOTE: we do not use the relcache
1627  * versions of the expressions, because we want to display
1628  * non-const-folded expressions.)
1629  */
1631  {
1632  Datum exprsDatum;
1633  bool isnull;
1634  char *exprsString;
1635 
1636  exprsDatum = SysCacheGetAttr(PARTRELID, tuple,
1638  Assert(!isnull);
1639  exprsString = TextDatumGetCString(exprsDatum);
1640  partexprs = (List *) stringToNode(exprsString);
1641 
1642  if (!IsA(partexprs, List))
1643  elog(ERROR, "unexpected node type found in partexprs: %d",
1644  (int) nodeTag(partexprs));
1645 
1646  pfree(exprsString);
1647  }
1648  else
1649  partexprs = NIL;
1650 
1651  partexpr_item = list_head(partexprs);
1652  context = deparse_context_for(get_relation_name(relid), relid);
1653 
1654  initStringInfo(&buf);
1655 
1656  switch (form->partstrat)
1657  {
1659  if (!attrsOnly)
1660  appendStringInfo(&buf, "HASH");
1661  break;
1663  if (!attrsOnly)
1664  appendStringInfoString(&buf, "LIST");
1665  break;
1667  if (!attrsOnly)
1668  appendStringInfoString(&buf, "RANGE");
1669  break;
1670  default:
1671  elog(ERROR, "unexpected partition strategy: %d",
1672  (int) form->partstrat);
1673  }
1674 
1675  if (!attrsOnly)
1676  appendStringInfoString(&buf, " (");
1677  sep = "";
1678  for (keyno = 0; keyno < form->partnatts; keyno++)
1679  {
1680  AttrNumber attnum = form->partattrs.values[keyno];
1681  Oid keycoltype;
1682  Oid keycolcollation;
1683  Oid partcoll;
1684 
1685  appendStringInfoString(&buf, sep);
1686  sep = ", ";
1687  if (attnum != 0)
1688  {
1689  /* Simple attribute reference */
1690  char *attname;
1691  int32 keycoltypmod;
1692 
1693  attname = get_relid_attribute_name(relid, attnum);
1694  appendStringInfoString(&buf, quote_identifier(attname));
1695  get_atttypetypmodcoll(relid, attnum,
1696  &keycoltype, &keycoltypmod,
1697  &keycolcollation);
1698  }
1699  else
1700  {
1701  /* Expression */
1702  Node *partkey;
1703 
1704  if (partexpr_item == NULL)
1705  elog(ERROR, "too few entries in partexprs list");
1706  partkey = (Node *) lfirst(partexpr_item);
1707  partexpr_item = lnext(partexpr_item);
1708 
1709  /* Deparse */
1710  str = deparse_expression_pretty(partkey, context, false, false,
1711  prettyFlags, 0);
1712  /* Need parens if it's not a bare function call */
1713  if (looks_like_function(partkey))
1714  appendStringInfoString(&buf, str);
1715  else
1716  appendStringInfo(&buf, "(%s)", str);
1717 
1718  keycoltype = exprType(partkey);
1719  keycolcollation = exprCollation(partkey);
1720  }
1721 
1722  /* Add collation, if not default for column */
1723  partcoll = partcollation->values[keyno];
1724  if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
1725  appendStringInfo(&buf, " COLLATE %s",
1726  generate_collation_name((partcoll)));
1727 
1728  /* Add the operator class name, if not default */
1729  if (!attrsOnly)
1730  get_opclass_name(partclass->values[keyno], keycoltype, &buf);
1731  }
1732 
1733  if (!attrsOnly)
1734  appendStringInfoChar(&buf, ')');
1735 
1736  /* Clean up */
1737  ReleaseSysCache(tuple);
1738 
1739  return buf.data;
1740 }
1741 
1742 /*
1743  * pg_get_partition_constraintdef
1744  *
1745  * Returns partition constraint expression as a string for the input relation
1746  */
1747 Datum
1749 {
1750  Oid relationId = PG_GETARG_OID(0);
1751  Expr *constr_expr;
1752  int prettyFlags;
1753  List *context;
1754  char *consrc;
1755 
1756  constr_expr = get_partition_qual_relid(relationId);
1757 
1758  /* Quick exit if no partition constraint */
1759  if (constr_expr == NULL)
1760  PG_RETURN_NULL();
1761 
1762  /*
1763  * Deparse and return the constraint expression.
1764  */
1765  prettyFlags = PRETTYFLAG_INDENT;
1766  context = deparse_context_for(get_relation_name(relationId), relationId);
1767  consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
1768  false, prettyFlags, 0);
1769 
1771 }
1772 
1773 /*
1774  * pg_get_constraintdef
1775  *
1776  * Returns the definition for the constraint, ie, everything that needs to
1777  * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
1778  */
1779 Datum
1781 {
1782  Oid constraintId = PG_GETARG_OID(0);
1783  int prettyFlags;
1784  char *res;
1785 
1786  prettyFlags = PRETTYFLAG_INDENT;
1787 
1788  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
1789 
1790  if (res == NULL)
1791  PG_RETURN_NULL();
1792 
1794 }
1795 
1796 Datum
1798 {
1799  Oid constraintId = PG_GETARG_OID(0);
1800  bool pretty = PG_GETARG_BOOL(1);
1801  int prettyFlags;
1802  char *res;
1803 
1804  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
1805 
1806  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
1807 
1808  if (res == NULL)
1809  PG_RETURN_NULL();
1810 
1812 }
1813 
1814 /*
1815  * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
1816  */
1817 char *
1819 {
1820  return pg_get_constraintdef_worker(constraintId, true, 0, false);
1821 }
1822 
1823 /*
1824  * As of 9.4, we now use an MVCC snapshot for this.
1825  */
1826 static char *
1827 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
1828  int prettyFlags, bool missing_ok)
1829 {
1830  HeapTuple tup;
1831  Form_pg_constraint conForm;
1833  SysScanDesc scandesc;
1834  ScanKeyData scankey[1];
1837 
1838  ScanKeyInit(&scankey[0],
1840  BTEqualStrategyNumber, F_OIDEQ,
1841  ObjectIdGetDatum(constraintId));
1842 
1843  scandesc = systable_beginscan(relation,
1845  true,
1846  snapshot,
1847  1,
1848  scankey);
1849 
1850  /*
1851  * We later use the tuple with SysCacheGetAttr() as if we had obtained it
1852  * via SearchSysCache, which works fine.
1853  */
1854  tup = systable_getnext(scandesc);
1855 
1856  UnregisterSnapshot(snapshot);
1857 
1858  if (!HeapTupleIsValid(tup))
1859  {
1860  if (missing_ok)
1861  {
1862  systable_endscan(scandesc);
1863  heap_close(relation, AccessShareLock);
1864  return NULL;
1865  }
1866  elog(ERROR, "could not find tuple for constraint %u", constraintId);
1867  }
1868 
1869  conForm = (Form_pg_constraint) GETSTRUCT(tup);
1870 
1871  initStringInfo(&buf);
1872 
1873  if (fullCommand)
1874  {
1875  if (OidIsValid(conForm->conrelid))
1876  {
1877  /*
1878  * Currently, callers want ALTER TABLE (without ONLY) for CHECK
1879  * constraints, and other types of constraints don't inherit
1880  * anyway so it doesn't matter whether we say ONLY or not. Someday
1881  * we might need to let callers specify whether to put ONLY in the
1882  * command.
1883  */
1884  appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
1885  generate_qualified_relation_name(conForm->conrelid),
1886  quote_identifier(NameStr(conForm->conname)));
1887  }
1888  else
1889  {
1890  /* Must be a domain constraint */
1891  Assert(OidIsValid(conForm->contypid));
1892  appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
1893  generate_qualified_type_name(conForm->contypid),
1894  quote_identifier(NameStr(conForm->conname)));
1895  }
1896  }
1897 
1898  switch (conForm->contype)
1899  {
1900  case CONSTRAINT_FOREIGN:
1901  {
1902  Datum val;
1903  bool isnull;
1904  const char *string;
1905 
1906  /* Start off the constraint definition */
1907  appendStringInfoString(&buf, "FOREIGN KEY (");
1908 
1909  /* Fetch and build referencing-column list */
1910  val = SysCacheGetAttr(CONSTROID, tup,
1911  Anum_pg_constraint_conkey, &isnull);
1912  if (isnull)
1913  elog(ERROR, "null conkey for constraint %u",
1914  constraintId);
1915 
1916  decompile_column_index_array(val, conForm->conrelid, &buf);
1917 
1918  /* add foreign relation name */
1919  appendStringInfo(&buf, ") REFERENCES %s(",
1920  generate_relation_name(conForm->confrelid,
1921  NIL));
1922 
1923  /* Fetch and build referenced-column list */
1924  val = SysCacheGetAttr(CONSTROID, tup,
1925  Anum_pg_constraint_confkey, &isnull);
1926  if (isnull)
1927  elog(ERROR, "null confkey for constraint %u",
1928  constraintId);
1929 
1930  decompile_column_index_array(val, conForm->confrelid, &buf);
1931 
1932  appendStringInfoChar(&buf, ')');
1933 
1934  /* Add match type */
1935  switch (conForm->confmatchtype)
1936  {
1937  case FKCONSTR_MATCH_FULL:
1938  string = " MATCH FULL";
1939  break;
1941  string = " MATCH PARTIAL";
1942  break;
1943  case FKCONSTR_MATCH_SIMPLE:
1944  string = "";
1945  break;
1946  default:
1947  elog(ERROR, "unrecognized confmatchtype: %d",
1948  conForm->confmatchtype);
1949  string = ""; /* keep compiler quiet */
1950  break;
1951  }
1952  appendStringInfoString(&buf, string);
1953 
1954  /* Add ON UPDATE and ON DELETE clauses, if needed */
1955  switch (conForm->confupdtype)
1956  {
1958  string = NULL; /* suppress default */
1959  break;
1961  string = "RESTRICT";
1962  break;
1964  string = "CASCADE";
1965  break;
1967  string = "SET NULL";
1968  break;
1970  string = "SET DEFAULT";
1971  break;
1972  default:
1973  elog(ERROR, "unrecognized confupdtype: %d",
1974  conForm->confupdtype);
1975  string = NULL; /* keep compiler quiet */
1976  break;
1977  }
1978  if (string)
1979  appendStringInfo(&buf, " ON UPDATE %s", string);
1980 
1981  switch (conForm->confdeltype)
1982  {
1984  string = NULL; /* suppress default */
1985  break;
1987  string = "RESTRICT";
1988  break;
1990  string = "CASCADE";
1991  break;
1993  string = "SET NULL";
1994  break;
1996  string = "SET DEFAULT";
1997  break;
1998  default:
1999  elog(ERROR, "unrecognized confdeltype: %d",
2000  conForm->confdeltype);
2001  string = NULL; /* keep compiler quiet */
2002  break;
2003  }
2004  if (string)
2005  appendStringInfo(&buf, " ON DELETE %s", string);
2006 
2007  break;
2008  }
2009  case CONSTRAINT_PRIMARY:
2010  case CONSTRAINT_UNIQUE:
2011  {
2012  Datum val;
2013  bool isnull;
2014  Oid indexId;
2015 
2016  /* Start off the constraint definition */
2017  if (conForm->contype == CONSTRAINT_PRIMARY)
2018  appendStringInfoString(&buf, "PRIMARY KEY (");
2019  else
2020  appendStringInfoString(&buf, "UNIQUE (");
2021 
2022  /* Fetch and build target column list */
2023  val = SysCacheGetAttr(CONSTROID, tup,
2024  Anum_pg_constraint_conkey, &isnull);
2025  if (isnull)
2026  elog(ERROR, "null conkey for constraint %u",
2027  constraintId);
2028 
2029  decompile_column_index_array(val, conForm->conrelid, &buf);
2030 
2031  appendStringInfoChar(&buf, ')');
2032 
2033  indexId = get_constraint_index(constraintId);
2034 
2035  /* XXX why do we only print these bits if fullCommand? */
2036  if (fullCommand && OidIsValid(indexId))
2037  {
2038  char *options = flatten_reloptions(indexId);
2039  Oid tblspc;
2040 
2041  if (options)
2042  {
2043  appendStringInfo(&buf, " WITH (%s)", options);
2044  pfree(options);
2045  }
2046 
2047  tblspc = get_rel_tablespace(indexId);
2048  if (OidIsValid(tblspc))
2049  appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2051  }
2052 
2053  break;
2054  }
2055  case CONSTRAINT_CHECK:
2056  {
2057  Datum val;
2058  bool isnull;
2059  char *conbin;
2060  char *consrc;
2061  Node *expr;
2062  List *context;
2063 
2064  /* Fetch constraint expression in parsetree form */
2065  val = SysCacheGetAttr(CONSTROID, tup,
2066  Anum_pg_constraint_conbin, &isnull);
2067  if (isnull)
2068  elog(ERROR, "null conbin for constraint %u",
2069  constraintId);
2070 
2071  conbin = TextDatumGetCString(val);
2072  expr = stringToNode(conbin);
2073 
2074  /* Set up deparsing context for Var nodes in constraint */
2075  if (conForm->conrelid != InvalidOid)
2076  {
2077  /* relation constraint */
2078  context = deparse_context_for(get_relation_name(conForm->conrelid),
2079  conForm->conrelid);
2080  }
2081  else
2082  {
2083  /* domain constraint --- can't have Vars */
2084  context = NIL;
2085  }
2086 
2087  consrc = deparse_expression_pretty(expr, context, false, false,
2088  prettyFlags, 0);
2089 
2090  /*
2091  * Now emit the constraint definition, adding NO INHERIT if
2092  * necessary.
2093  *
2094  * There are cases where the constraint expression will be
2095  * fully parenthesized and we don't need the outer parens ...
2096  * but there are other cases where we do need 'em. Be
2097  * conservative for now.
2098  *
2099  * Note that simply checking for leading '(' and trailing ')'
2100  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2101  */
2102  appendStringInfo(&buf, "CHECK (%s)%s",
2103  consrc,
2104  conForm->connoinherit ? " NO INHERIT" : "");
2105  break;
2106  }
2107  case CONSTRAINT_TRIGGER:
2108 
2109  /*
2110  * There isn't an ALTER TABLE syntax for creating a user-defined
2111  * constraint trigger, but it seems better to print something than
2112  * throw an error; if we throw error then this function couldn't
2113  * safely be applied to all rows of pg_constraint.
2114  */
2115  appendStringInfoString(&buf, "TRIGGER");
2116  break;
2117  case CONSTRAINT_EXCLUSION:
2118  {
2119  Oid indexOid = conForm->conindid;
2120  Datum val;
2121  bool isnull;
2122  Datum *elems;
2123  int nElems;
2124  int i;
2125  Oid *operators;
2126 
2127  /* Extract operator OIDs from the pg_constraint tuple */
2128  val = SysCacheGetAttr(CONSTROID, tup,
2130  &isnull);
2131  if (isnull)
2132  elog(ERROR, "null conexclop for constraint %u",
2133  constraintId);
2134 
2136  OIDOID, sizeof(Oid), true, 'i',
2137  &elems, NULL, &nElems);
2138 
2139  operators = (Oid *) palloc(nElems * sizeof(Oid));
2140  for (i = 0; i < nElems; i++)
2141  operators[i] = DatumGetObjectId(elems[i]);
2142 
2143  /* pg_get_indexdef_worker does the rest */
2144  /* suppress tablespace because pg_dump wants it that way */
2146  pg_get_indexdef_worker(indexOid,
2147  0,
2148  operators,
2149  false,
2150  false,
2151  prettyFlags,
2152  false));
2153  break;
2154  }
2155  default:
2156  elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2157  break;
2158  }
2159 
2160  if (conForm->condeferrable)
2161  appendStringInfoString(&buf, " DEFERRABLE");
2162  if (conForm->condeferred)
2163  appendStringInfoString(&buf, " INITIALLY DEFERRED");
2164  if (!conForm->convalidated)
2165  appendStringInfoString(&buf, " NOT VALID");
2166 
2167  /* Cleanup */
2168  systable_endscan(scandesc);
2169  heap_close(relation, AccessShareLock);
2170 
2171  return buf.data;
2172 }
2173 
2174 
2175 /*
2176  * Convert an int16[] Datum into a comma-separated list of column names
2177  * for the indicated relation; append the list to buf.
2178  */
2179 static void
2180 decompile_column_index_array(Datum column_index_array, Oid relId,
2181  StringInfo buf)
2182 {
2183  Datum *keys;
2184  int nKeys;
2185  int j;
2186 
2187  /* Extract data from array of int16 */
2188  deconstruct_array(DatumGetArrayTypeP(column_index_array),
2189  INT2OID, 2, true, 's',
2190  &keys, NULL, &nKeys);
2191 
2192  for (j = 0; j < nKeys; j++)
2193  {
2194  char *colName;
2195 
2196  colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
2197 
2198  if (j == 0)
2200  else
2201  appendStringInfo(buf, ", %s", quote_identifier(colName));
2202  }
2203 }
2204 
2205 
2206 /* ----------
2207  * get_expr - Decompile an expression tree
2208  *
2209  * Input: an expression tree in nodeToString form, and a relation OID
2210  *
2211  * Output: reverse-listed expression
2212  *
2213  * Currently, the expression can only refer to a single relation, namely
2214  * the one specified by the second parameter. This is sufficient for
2215  * partial indexes, column default expressions, etc. We also support
2216  * Var-free expressions, for which the OID can be InvalidOid.
2217  * ----------
2218  */
2219 Datum
2221 {
2222  text *expr = PG_GETARG_TEXT_PP(0);
2223  Oid relid = PG_GETARG_OID(1);
2224  int prettyFlags;
2225  char *relname;
2226 
2227  prettyFlags = PRETTYFLAG_INDENT;
2228 
2229  if (OidIsValid(relid))
2230  {
2231  /* Get the name for the relation */
2232  relname = get_rel_name(relid);
2233 
2234  /*
2235  * If the OID isn't actually valid, don't throw an error, just return
2236  * NULL. This is a bit questionable, but it's what we've done
2237  * historically, and it can help avoid unwanted failures when
2238  * examining catalog entries for just-deleted relations.
2239  */
2240  if (relname == NULL)
2241  PG_RETURN_NULL();
2242  }
2243  else
2244  relname = NULL;
2245 
2246  PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2247 }
2248 
2249 Datum
2251 {
2252  text *expr = PG_GETARG_TEXT_PP(0);
2253  Oid relid = PG_GETARG_OID(1);
2254  bool pretty = PG_GETARG_BOOL(2);
2255  int prettyFlags;
2256  char *relname;
2257 
2258  prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT;
2259 
2260  if (OidIsValid(relid))
2261  {
2262  /* Get the name for the relation */
2263  relname = get_rel_name(relid);
2264  /* See notes above */
2265  if (relname == NULL)
2266  PG_RETURN_NULL();
2267  }
2268  else
2269  relname = NULL;
2270 
2271  PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2272 }
2273 
2274 static text *
2275 pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
2276 {
2277  Node *node;
2278  List *context;
2279  char *exprstr;
2280  char *str;
2281 
2282  /* Convert input TEXT object to C string */
2283  exprstr = text_to_cstring(expr);
2284 
2285  /* Convert expression to node tree */
2286  node = (Node *) stringToNode(exprstr);
2287 
2288  pfree(exprstr);
2289 
2290  /* Prepare deparse context if needed */
2291  if (OidIsValid(relid))
2292  context = deparse_context_for(relname, relid);
2293  else
2294  context = NIL;
2295 
2296  /* Deparse */
2297  str = deparse_expression_pretty(node, context, false, false,
2298  prettyFlags, 0);
2299 
2300  return string_to_text(str);
2301 }
2302 
2303 
2304 /* ----------
2305  * get_userbyid - Get a user name by roleid and
2306  * fallback to 'unknown (OID=n)'
2307  * ----------
2308  */
2309 Datum
2311 {
2312  Oid roleid = PG_GETARG_OID(0);
2313  Name result;
2314  HeapTuple roletup;
2315  Form_pg_authid role_rec;
2316 
2317  /*
2318  * Allocate space for the result
2319  */
2320  result = (Name) palloc(NAMEDATALEN);
2321  memset(NameStr(*result), 0, NAMEDATALEN);
2322 
2323  /*
2324  * Get the pg_authid entry and print the result
2325  */
2326  roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2327  if (HeapTupleIsValid(roletup))
2328  {
2329  role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2330  StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);
2331  ReleaseSysCache(roletup);
2332  }
2333  else
2334  sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2335 
2336  PG_RETURN_NAME(result);
2337 }
2338 
2339 
2340 /*
2341  * pg_get_serial_sequence
2342  * Get the name of the sequence used by an identity or serial column,
2343  * formatted suitably for passing to setval, nextval or currval.
2344  * First parameter is not treated as double-quoted, second parameter
2345  * is --- see documentation for reason.
2346  */
2347 Datum
2349 {
2350  text *tablename = PG_GETARG_TEXT_PP(0);
2351  text *columnname = PG_GETARG_TEXT_PP(1);
2352  RangeVar *tablerv;
2353  Oid tableOid;
2354  char *column;
2355  AttrNumber attnum;
2356  Oid sequenceId = InvalidOid;
2357  Relation depRel;
2358  ScanKeyData key[3];
2359  SysScanDesc scan;
2360  HeapTuple tup;
2361 
2362  /* Look up table name. Can't lock it - we might not have privileges. */
2363  tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2364  tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2365 
2366  /* Get the number of the column */
2367  column = text_to_cstring(columnname);
2368 
2369  attnum = get_attnum(tableOid, column);
2370  if (attnum == InvalidAttrNumber)
2371  ereport(ERROR,
2372  (errcode(ERRCODE_UNDEFINED_COLUMN),
2373  errmsg("column \"%s\" of relation \"%s\" does not exist",
2374  column, tablerv->relname)));
2375 
2376  /* Search the dependency table for the dependent sequence */
2378 
2379  ScanKeyInit(&key[0],
2381  BTEqualStrategyNumber, F_OIDEQ,
2383  ScanKeyInit(&key[1],
2385  BTEqualStrategyNumber, F_OIDEQ,
2386  ObjectIdGetDatum(tableOid));
2387  ScanKeyInit(&key[2],
2389  BTEqualStrategyNumber, F_INT4EQ,
2390  Int32GetDatum(attnum));
2391 
2392  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2393  NULL, 3, key);
2394 
2395  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2396  {
2397  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2398 
2399  /*
2400  * Look for an auto dependency (serial column) or internal dependency
2401  * (identity column) of a sequence on a column. (We need the relkind
2402  * test because indexes can also have auto dependencies on columns.)
2403  */
2404  if (deprec->classid == RelationRelationId &&
2405  deprec->objsubid == 0 &&
2406  (deprec->deptype == DEPENDENCY_AUTO ||
2407  deprec->deptype == DEPENDENCY_INTERNAL) &&
2408  get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2409  {
2410  sequenceId = deprec->objid;
2411  break;
2412  }
2413  }
2414 
2415  systable_endscan(scan);
2416  heap_close(depRel, AccessShareLock);
2417 
2418  if (OidIsValid(sequenceId))
2419  {
2420  char *result;
2421 
2422  result = generate_qualified_relation_name(sequenceId);
2423 
2425  }
2426 
2427  PG_RETURN_NULL();
2428 }
2429 
2430 
2431 /*
2432  * pg_get_functiondef
2433  * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2434  * the specified function.
2435  *
2436  * Note: if you change the output format of this function, be careful not
2437  * to break psql's rules (in \ef and \sf) for identifying the start of the
2438  * function body. To wit: the function body starts on a line that begins
2439  * with "AS ", and no preceding line will look like that.
2440  */
2441 Datum
2443 {
2444  Oid funcid = PG_GETARG_OID(0);
2446  StringInfoData dq;
2447  HeapTuple proctup;
2448  Form_pg_proc proc;
2449  Datum tmp;
2450  bool isnull;
2451  const char *prosrc;
2452  const char *name;
2453  const char *nsp;
2454  float4 procost;
2455  int oldlen;
2456 
2457  initStringInfo(&buf);
2458 
2459  /* Look up the function */
2460  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2461  if (!HeapTupleIsValid(proctup))
2462  PG_RETURN_NULL();
2463 
2464  proc = (Form_pg_proc) GETSTRUCT(proctup);
2465  name = NameStr(proc->proname);
2466 
2467  if (proc->proisagg)
2468  ereport(ERROR,
2469  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2470  errmsg("\"%s\" is an aggregate function", name)));
2471 
2472  /*
2473  * We always qualify the function name, to ensure the right function gets
2474  * replaced.
2475  */
2476  nsp = get_namespace_name(proc->pronamespace);
2477  appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
2478  quote_qualified_identifier(nsp, name));
2479  (void) print_function_arguments(&buf, proctup, false, true);
2480  appendStringInfoString(&buf, ")\n RETURNS ");
2481  print_function_rettype(&buf, proctup);
2482 
2483  print_function_trftypes(&buf, proctup);
2484 
2485  appendStringInfo(&buf, "\n LANGUAGE %s\n",
2486  quote_identifier(get_language_name(proc->prolang, false)));
2487 
2488  /* Emit some miscellaneous options on one line */
2489  oldlen = buf.len;
2490 
2491  if (proc->proiswindow)
2492  appendStringInfoString(&buf, " WINDOW");
2493  switch (proc->provolatile)
2494  {
2495  case PROVOLATILE_IMMUTABLE:
2496  appendStringInfoString(&buf, " IMMUTABLE");
2497  break;
2498  case PROVOLATILE_STABLE:
2499  appendStringInfoString(&buf, " STABLE");
2500  break;
2501  case PROVOLATILE_VOLATILE:
2502  break;
2503  }
2504 
2505  switch (proc->proparallel)
2506  {
2507  case PROPARALLEL_SAFE:
2508  appendStringInfoString(&buf, " PARALLEL SAFE");
2509  break;
2511  appendStringInfoString(&buf, " PARALLEL RESTRICTED");
2512  break;
2513  case PROPARALLEL_UNSAFE:
2514  break;
2515  }
2516 
2517  if (proc->proisstrict)
2518  appendStringInfoString(&buf, " STRICT");
2519  if (proc->prosecdef)
2520  appendStringInfoString(&buf, " SECURITY DEFINER");
2521  if (proc->proleakproof)
2522  appendStringInfoString(&buf, " LEAKPROOF");
2523 
2524  /* This code for the default cost and rows should match functioncmds.c */
2525  if (proc->prolang == INTERNALlanguageId ||
2526  proc->prolang == ClanguageId)
2527  procost = 1;
2528  else
2529  procost = 100;
2530  if (proc->procost != procost)
2531  appendStringInfo(&buf, " COST %g", proc->procost);
2532 
2533  if (proc->prorows > 0 && proc->prorows != 1000)
2534  appendStringInfo(&buf, " ROWS %g", proc->prorows);
2535 
2536  if (oldlen != buf.len)
2537  appendStringInfoChar(&buf, '\n');
2538 
2539  /* Emit any proconfig options, one per line */
2540  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
2541  if (!isnull)
2542  {
2543  ArrayType *a = DatumGetArrayTypeP(tmp);
2544  int i;
2545 
2546  Assert(ARR_ELEMTYPE(a) == TEXTOID);
2547  Assert(ARR_NDIM(a) == 1);
2548  Assert(ARR_LBOUND(a)[0] == 1);
2549 
2550  for (i = 1; i <= ARR_DIMS(a)[0]; i++)
2551  {
2552  Datum d;
2553 
2554  d = array_ref(a, 1, &i,
2555  -1 /* varlenarray */ ,
2556  -1 /* TEXT's typlen */ ,
2557  false /* TEXT's typbyval */ ,
2558  'i' /* TEXT's typalign */ ,
2559  &isnull);
2560  if (!isnull)
2561  {
2562  char *configitem = TextDatumGetCString(d);
2563  char *pos;
2564 
2565  pos = strchr(configitem, '=');
2566  if (pos == NULL)
2567  continue;
2568  *pos++ = '\0';
2569 
2570  appendStringInfo(&buf, " SET %s TO ",
2571  quote_identifier(configitem));
2572 
2573  /*
2574  * Some GUC variable names are 'LIST' type and hence must not
2575  * be quoted.
2576  */
2577  if (pg_strcasecmp(configitem, "DateStyle") == 0
2578  || pg_strcasecmp(configitem, "search_path") == 0)
2579  appendStringInfoString(&buf, pos);
2580  else
2581  simple_quote_literal(&buf, pos);
2582  appendStringInfoChar(&buf, '\n');
2583  }
2584  }
2585  }
2586 
2587  /* And finally the function definition ... */
2588  appendStringInfoString(&buf, "AS ");
2589 
2590  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
2591  if (!isnull)
2592  {
2594  appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
2595  }
2596 
2597  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull);
2598  if (isnull)
2599  elog(ERROR, "null prosrc");
2600  prosrc = TextDatumGetCString(tmp);
2601 
2602  /*
2603  * We always use dollar quoting. Figure out a suitable delimiter.
2604  *
2605  * Since the user is likely to be editing the function body string, we
2606  * shouldn't use a short delimiter that he might easily create a conflict
2607  * with. Hence prefer "$function$", but extend if needed.
2608  */
2609  initStringInfo(&dq);
2610  appendStringInfoString(&dq, "$function");
2611  while (strstr(prosrc, dq.data) != NULL)
2612  appendStringInfoChar(&dq, 'x');
2613  appendStringInfoChar(&dq, '$');
2614 
2615  appendStringInfoString(&buf, dq.data);
2616  appendStringInfoString(&buf, prosrc);
2617  appendStringInfoString(&buf, dq.data);
2618 
2619  appendStringInfoChar(&buf, '\n');
2620 
2621  ReleaseSysCache(proctup);
2622 
2624 }
2625 
2626 /*
2627  * pg_get_function_arguments
2628  * Get a nicely-formatted list of arguments for a function.
2629  * This is everything that would go between the parentheses in
2630  * CREATE FUNCTION.
2631  */
2632 Datum
2634 {
2635  Oid funcid = PG_GETARG_OID(0);
2637  HeapTuple proctup;
2638 
2639  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2640  if (!HeapTupleIsValid(proctup))
2641  PG_RETURN_NULL();
2642 
2643  initStringInfo(&buf);
2644 
2645  (void) print_function_arguments(&buf, proctup, false, true);
2646 
2647  ReleaseSysCache(proctup);
2648 
2650 }
2651 
2652 /*
2653  * pg_get_function_identity_arguments
2654  * Get a formatted list of arguments for a function.
2655  * This is everything that would go between the parentheses in
2656  * ALTER FUNCTION, etc. In particular, don't print defaults.
2657  */
2658 Datum
2660 {
2661  Oid funcid = PG_GETARG_OID(0);
2663  HeapTuple proctup;
2664 
2665  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2666  if (!HeapTupleIsValid(proctup))
2667  PG_RETURN_NULL();
2668 
2669  initStringInfo(&buf);
2670 
2671  (void) print_function_arguments(&buf, proctup, false, false);
2672 
2673  ReleaseSysCache(proctup);
2674 
2676 }
2677 
2678 /*
2679  * pg_get_function_result
2680  * Get a nicely-formatted version of the result type of a function.
2681  * This is what would appear after RETURNS in CREATE FUNCTION.
2682  */
2683 Datum
2685 {
2686  Oid funcid = PG_GETARG_OID(0);
2688  HeapTuple proctup;
2689 
2690  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2691  if (!HeapTupleIsValid(proctup))
2692  PG_RETURN_NULL();
2693 
2694  initStringInfo(&buf);
2695 
2696  print_function_rettype(&buf, proctup);
2697 
2698  ReleaseSysCache(proctup);
2699 
2701 }
2702 
2703 /*
2704  * Guts of pg_get_function_result: append the function's return type
2705  * to the specified buffer.
2706  */
2707 static void
2709 {
2710  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
2711  int ntabargs = 0;
2712  StringInfoData rbuf;
2713 
2714  initStringInfo(&rbuf);
2715 
2716  if (proc->proretset)
2717  {
2718  /* It might be a table function; try to print the arguments */
2719  appendStringInfoString(&rbuf, "TABLE(");
2720  ntabargs = print_function_arguments(&rbuf, proctup, true, false);
2721  if (ntabargs > 0)
2722  appendStringInfoChar(&rbuf, ')');
2723  else
2724  resetStringInfo(&rbuf);
2725  }
2726 
2727  if (ntabargs == 0)
2728  {
2729  /* Not a table function, so do the normal thing */
2730  if (proc->proretset)
2731  appendStringInfoString(&rbuf, "SETOF ");
2732  appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
2733  }
2734 
2735  appendStringInfoString(buf, rbuf.data);
2736 }
2737 
2738 /*
2739  * Common code for pg_get_function_arguments and pg_get_function_result:
2740  * append the desired subset of arguments to buf. We print only TABLE
2741  * arguments when print_table_args is true, and all the others when it's false.
2742  * We print argument defaults only if print_defaults is true.
2743  * Function return value is the number of arguments printed.
2744  */
2745 static int
2747  bool print_table_args, bool print_defaults)
2748 {
2749  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
2750  int numargs;
2751  Oid *argtypes;
2752  char **argnames;
2753  char *argmodes;
2754  int insertorderbyat = -1;
2755  int argsprinted;
2756  int inputargno;
2757  int nlackdefaults;
2758  ListCell *nextargdefault = NULL;
2759  int i;
2760 
2761  numargs = get_func_arg_info(proctup,
2762  &argtypes, &argnames, &argmodes);
2763 
2764  nlackdefaults = numargs;
2765  if (print_defaults && proc->pronargdefaults > 0)
2766  {
2767  Datum proargdefaults;
2768  bool isnull;
2769 
2770  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
2772  &isnull);
2773  if (!isnull)
2774  {
2775  char *str;
2776  List *argdefaults;
2777 
2778  str = TextDatumGetCString(proargdefaults);
2779  argdefaults = castNode(List, stringToNode(str));
2780  pfree(str);
2781  nextargdefault = list_head(argdefaults);
2782  /* nlackdefaults counts only *input* arguments lacking defaults */
2783  nlackdefaults = proc->pronargs - list_length(argdefaults);
2784  }
2785  }
2786 
2787  /* Check for special treatment of ordered-set aggregates */
2788  if (proc->proisagg)
2789  {
2790  HeapTuple aggtup;
2791  Form_pg_aggregate agg;
2792 
2793  aggtup = SearchSysCache1(AGGFNOID,
2794  ObjectIdGetDatum(HeapTupleGetOid(proctup)));
2795  if (!HeapTupleIsValid(aggtup))
2796  elog(ERROR, "cache lookup failed for aggregate %u",
2797  HeapTupleGetOid(proctup));
2798  agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
2799  if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
2800  insertorderbyat = agg->aggnumdirectargs;
2801  ReleaseSysCache(aggtup);
2802  }
2803 
2804  argsprinted = 0;
2805  inputargno = 0;
2806  for (i = 0; i < numargs; i++)
2807  {
2808  Oid argtype = argtypes[i];
2809  char *argname = argnames ? argnames[i] : NULL;
2810  char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
2811  const char *modename;
2812  bool isinput;
2813 
2814  switch (argmode)
2815  {
2816  case PROARGMODE_IN:
2817  modename = "";
2818  isinput = true;
2819  break;
2820  case PROARGMODE_INOUT:
2821  modename = "INOUT ";
2822  isinput = true;
2823  break;
2824  case PROARGMODE_OUT:
2825  modename = "OUT ";
2826  isinput = false;
2827  break;
2828  case PROARGMODE_VARIADIC:
2829  modename = "VARIADIC ";
2830  isinput = true;
2831  break;
2832  case PROARGMODE_TABLE:
2833  modename = "";
2834  isinput = false;
2835  break;
2836  default:
2837  elog(ERROR, "invalid parameter mode '%c'", argmode);
2838  modename = NULL; /* keep compiler quiet */
2839  isinput = false;
2840  break;
2841  }
2842  if (isinput)
2843  inputargno++; /* this is a 1-based counter */
2844 
2845  if (print_table_args != (argmode == PROARGMODE_TABLE))
2846  continue;
2847 
2848  if (argsprinted == insertorderbyat)
2849  {
2850  if (argsprinted)
2851  appendStringInfoChar(buf, ' ');
2852  appendStringInfoString(buf, "ORDER BY ");
2853  }
2854  else if (argsprinted)
2855  appendStringInfoString(buf, ", ");
2856 
2857  appendStringInfoString(buf, modename);
2858  if (argname && argname[0])
2859  appendStringInfo(buf, "%s ", quote_identifier(argname));
2860  appendStringInfoString(buf, format_type_be(argtype));
2861  if (print_defaults && isinput && inputargno > nlackdefaults)
2862  {
2863  Node *expr;
2864 
2865  Assert(nextargdefault != NULL);
2866  expr = (Node *) lfirst(nextargdefault);
2867  nextargdefault = lnext(nextargdefault);
2868 
2869  appendStringInfo(buf, " DEFAULT %s",
2870  deparse_expression(expr, NIL, false, false));
2871  }
2872  argsprinted++;
2873 
2874  /* nasty hack: print the last arg twice for variadic ordered-set agg */
2875  if (argsprinted == insertorderbyat && i == numargs - 1)
2876  {
2877  i--;
2878  /* aggs shouldn't have defaults anyway, but just to be sure ... */
2879  print_defaults = false;
2880  }
2881  }
2882 
2883  return argsprinted;
2884 }
2885 
2886 static bool
2887 is_input_argument(int nth, const char *argmodes)
2888 {
2889  return (!argmodes
2890  || argmodes[nth] == PROARGMODE_IN
2891  || argmodes[nth] == PROARGMODE_INOUT
2892  || argmodes[nth] == PROARGMODE_VARIADIC);
2893 }
2894 
2895 /*
2896  * Append used transformed types to specified buffer
2897  */
2898 static void
2900 {
2901  Oid *trftypes;
2902  int ntypes;
2903 
2904  ntypes = get_func_trftypes(proctup, &trftypes);
2905  if (ntypes > 0)
2906  {
2907  int i;
2908 
2909  appendStringInfoString(buf, "\n TRANSFORM ");
2910  for (i = 0; i < ntypes; i++)
2911  {
2912  if (i != 0)
2913  appendStringInfoString(buf, ", ");
2914  appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
2915  }
2916  }
2917 }
2918 
2919 /*
2920  * Get textual representation of a function argument's default value. The
2921  * second argument of this function is the argument number among all arguments
2922  * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
2923  * how information_schema.sql uses it.
2924  */
2925 Datum
2927 {
2928  Oid funcid = PG_GETARG_OID(0);
2929  int32 nth_arg = PG_GETARG_INT32(1);
2930  HeapTuple proctup;
2931  Form_pg_proc proc;
2932  int numargs;
2933  Oid *argtypes;
2934  char **argnames;
2935  char *argmodes;
2936  int i;
2937  List *argdefaults;
2938  Node *node;
2939  char *str;
2940  int nth_inputarg;
2941  Datum proargdefaults;
2942  bool isnull;
2943  int nth_default;
2944 
2945  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2946  if (!HeapTupleIsValid(proctup))
2947  PG_RETURN_NULL();
2948 
2949  numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
2950  if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
2951  {
2952  ReleaseSysCache(proctup);
2953  PG_RETURN_NULL();
2954  }
2955 
2956  nth_inputarg = 0;
2957  for (i = 0; i < nth_arg; i++)
2958  if (is_input_argument(i, argmodes))
2959  nth_inputarg++;
2960 
2961  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
2963  &isnull);
2964  if (isnull)
2965  {
2966  ReleaseSysCache(proctup);
2967  PG_RETURN_NULL();
2968  }
2969 
2970  str = TextDatumGetCString(proargdefaults);
2971  argdefaults = castNode(List, stringToNode(str));
2972  pfree(str);
2973 
2974  proc = (Form_pg_proc) GETSTRUCT(proctup);
2975 
2976  /*
2977  * Calculate index into proargdefaults: proargdefaults corresponds to the
2978  * last N input arguments, where N = pronargdefaults.
2979  */
2980  nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
2981 
2982  if (nth_default < 0 || nth_default >= list_length(argdefaults))
2983  {
2984  ReleaseSysCache(proctup);
2985  PG_RETURN_NULL();
2986  }
2987  node = list_nth(argdefaults, nth_default);
2988  str = deparse_expression(node, NIL, false, false);
2989 
2990  ReleaseSysCache(proctup);
2991 
2993 }
2994 
2995 
2996 /*
2997  * deparse_expression - General utility for deparsing expressions
2998  *
2999  * calls deparse_expression_pretty with all prettyPrinting disabled
3000  */
3001 char *
3002 deparse_expression(Node *expr, List *dpcontext,
3003  bool forceprefix, bool showimplicit)
3004 {
3005  return deparse_expression_pretty(expr, dpcontext, forceprefix,
3006  showimplicit, 0, 0);
3007 }
3008 
3009 /* ----------
3010  * deparse_expression_pretty - General utility for deparsing expressions
3011  *
3012  * expr is the node tree to be deparsed. It must be a transformed expression
3013  * tree (ie, not the raw output of gram.y).
3014  *
3015  * dpcontext is a list of deparse_namespace nodes representing the context
3016  * for interpreting Vars in the node tree. It can be NIL if no Vars are
3017  * expected.
3018  *
3019  * forceprefix is true to force all Vars to be prefixed with their table names.
3020  *
3021  * showimplicit is true to force all implicit casts to be shown explicitly.
3022  *
3023  * Tries to pretty up the output according to prettyFlags and startIndent.
3024  *
3025  * The result is a palloc'd string.
3026  * ----------
3027  */
3028 static char *
3030  bool forceprefix, bool showimplicit,
3031  int prettyFlags, int startIndent)
3032 {
3034  deparse_context context;
3035 
3036  initStringInfo(&buf);
3037  context.buf = &buf;
3038  context.namespaces = dpcontext;
3039  context.windowClause = NIL;
3040  context.windowTList = NIL;
3041  context.varprefix = forceprefix;
3042  context.prettyFlags = prettyFlags;
3043  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3044  context.indentLevel = startIndent;
3045  context.special_exprkind = EXPR_KIND_NONE;
3046 
3047  get_rule_expr(expr, &context, showimplicit);
3048 
3049  return buf.data;
3050 }
3051 
3052 /* ----------
3053  * deparse_context_for - Build deparse context for a single relation
3054  *
3055  * Given the reference name (alias) and OID of a relation, build deparsing
3056  * context for an expression referencing only that relation (as varno 1,
3057  * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3058  * ----------
3059  */
3060 List *
3061 deparse_context_for(const char *aliasname, Oid relid)
3062 {
3063  deparse_namespace *dpns;
3064  RangeTblEntry *rte;
3065 
3066  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3067 
3068  /* Build a minimal RTE for the rel */
3069  rte = makeNode(RangeTblEntry);
3070  rte->rtekind = RTE_RELATION;
3071  rte->relid = relid;
3072  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3073  rte->alias = makeAlias(aliasname, NIL);
3074  rte->eref = rte->alias;
3075  rte->lateral = false;
3076  rte->inh = false;
3077  rte->inFromCl = true;
3078 
3079  /* Build one-element rtable */
3080  dpns->rtable = list_make1(rte);
3081  dpns->ctes = NIL;
3082  set_rtable_names(dpns, NIL, NULL);
3084 
3085  /* Return a one-deep namespace stack */
3086  return list_make1(dpns);
3087 }
3088 
3089 /*
3090  * deparse_context_for_plan_rtable - Build deparse context for a plan's rtable
3091  *
3092  * When deparsing an expression in a Plan tree, we use the plan's rangetable
3093  * to resolve names of simple Vars. The initialization of column names for
3094  * this is rather expensive if the rangetable is large, and it'll be the same
3095  * for every expression in the Plan tree; so we do it just once and re-use
3096  * the result of this function for each expression. (Note that the result
3097  * is not usable until set_deparse_context_planstate() is applied to it.)
3098  *
3099  * In addition to the plan's rangetable list, pass the per-RTE alias names
3100  * assigned by a previous call to select_rtable_names_for_explain.
3101  */
3102 List *
3104 {
3105  deparse_namespace *dpns;
3106 
3107  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3108 
3109  /* Initialize fields that stay the same across the whole plan tree */
3110  dpns->rtable = rtable;
3111  dpns->rtable_names = rtable_names;
3112  dpns->ctes = NIL;
3113 
3114  /*
3115  * Set up column name aliases. We will get rather bogus results for join
3116  * RTEs, but that doesn't matter because plan trees don't contain any join
3117  * alias Vars.
3118  */
3120 
3121  /* Return a one-deep namespace stack */
3122  return list_make1(dpns);
3123 }
3124 
3125 /*
3126  * set_deparse_context_planstate - Specify Plan node containing expression
3127  *
3128  * When deparsing an expression in a Plan tree, we might have to resolve
3129  * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
3130  * provide the parent PlanState node. Then OUTER_VAR and INNER_VAR references
3131  * can be resolved by drilling down into the left and right child plans.
3132  * Similarly, INDEX_VAR references can be resolved by reference to the
3133  * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3134  * ForeignScan and CustomScan nodes. (Note that we don't currently support
3135  * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3136  * for those, we can only deparse the indexqualorig fields, which won't
3137  * contain INDEX_VAR Vars.)
3138  *
3139  * Note: planstate really ought to be declared as "PlanState *", but we use
3140  * "Node *" to avoid having to include execnodes.h in ruleutils.h.
3141  *
3142  * The ancestors list is a list of the PlanState's parent PlanStates, the
3143  * most-closely-nested first. This is needed to resolve PARAM_EXEC Params.
3144  * Note we assume that all the PlanStates share the same rtable.
3145  *
3146  * Once this function has been called, deparse_expression() can be called on
3147  * subsidiary expression(s) of the specified PlanState node. To deparse
3148  * expressions of a different Plan node in the same Plan tree, re-call this
3149  * function to identify the new parent Plan node.
3150  *
3151  * The result is the same List passed in; this is a notational convenience.
3152  */
3153 List *
3155  Node *planstate, List *ancestors)
3156 {
3157  deparse_namespace *dpns;
3158 
3159  /* Should always have one-entry namespace list for Plan deparsing */
3160  Assert(list_length(dpcontext) == 1);
3161  dpns = (deparse_namespace *) linitial(dpcontext);
3162 
3163  /* Set our attention on the specific plan node passed in */
3164  set_deparse_planstate(dpns, (PlanState *) planstate);
3165  dpns->ancestors = ancestors;
3166 
3167  return dpcontext;
3168 }
3169 
3170 /*
3171  * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3172  *
3173  * Determine the relation aliases we'll use during an EXPLAIN operation.
3174  * This is just a frontend to set_rtable_names. We have to expose the aliases
3175  * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3176  */
3177 List *
3179 {
3180  deparse_namespace dpns;
3181 
3182  memset(&dpns, 0, sizeof(dpns));
3183  dpns.rtable = rtable;
3184  dpns.ctes = NIL;
3185  set_rtable_names(&dpns, NIL, rels_used);
3186  /* We needn't bother computing column aliases yet */
3187 
3188  return dpns.rtable_names;
3189 }
3190 
3191 /*
3192  * set_rtable_names: select RTE aliases to be used in printing a query
3193  *
3194  * We fill in dpns->rtable_names with a list of names that is one-for-one with
3195  * the already-filled dpns->rtable list. Each RTE name is unique among those
3196  * in the new namespace plus any ancestor namespaces listed in
3197  * parent_namespaces.
3198  *
3199  * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3200  *
3201  * Note that this function is only concerned with relation names, not column
3202  * names.
3203  */
3204 static void
3205 set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3206  Bitmapset *rels_used)
3207 {
3208  HASHCTL hash_ctl;
3209  HTAB *names_hash;
3210  NameHashEntry *hentry;
3211  bool found;
3212  int rtindex;
3213  ListCell *lc;
3214 
3215  dpns->rtable_names = NIL;
3216  /* nothing more to do if empty rtable */
3217  if (dpns->rtable == NIL)
3218  return;
3219 
3220  /*
3221  * We use a hash table to hold known names, so that this process is O(N)
3222  * not O(N^2) for N names.
3223  */
3224  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
3225  hash_ctl.keysize = NAMEDATALEN;
3226  hash_ctl.entrysize = sizeof(NameHashEntry);
3227  hash_ctl.hcxt = CurrentMemoryContext;
3228  names_hash = hash_create("set_rtable_names names",
3229  list_length(dpns->rtable),
3230  &hash_ctl,
3232  /* Preload the hash table with names appearing in parent_namespaces */
3233  foreach(lc, parent_namespaces)
3234  {
3235  deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3236  ListCell *lc2;
3237 
3238  foreach(lc2, olddpns->rtable_names)
3239  {
3240  char *oldname = (char *) lfirst(lc2);
3241 
3242  if (oldname == NULL)
3243  continue;
3244  hentry = (NameHashEntry *) hash_search(names_hash,
3245  oldname,
3246  HASH_ENTER,
3247  &found);
3248  /* we do not complain about duplicate names in parent namespaces */
3249  hentry->counter = 0;
3250  }
3251  }
3252 
3253  /* Now we can scan the rtable */
3254  rtindex = 1;
3255  foreach(lc, dpns->rtable)
3256  {
3257  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3258  char *refname;
3259 
3260  /* Just in case this takes an unreasonable amount of time ... */
3262 
3263  if (rels_used && !bms_is_member(rtindex, rels_used))
3264  {
3265  /* Ignore unreferenced RTE */
3266  refname = NULL;
3267  }
3268  else if (rte->alias)
3269  {
3270  /* If RTE has a user-defined alias, prefer that */
3271  refname = rte->alias->aliasname;
3272  }
3273  else if (rte->rtekind == RTE_RELATION)
3274  {
3275  /* Use the current actual name of the relation */
3276  refname = get_rel_name(rte->relid);
3277  }
3278  else if (rte->rtekind == RTE_JOIN)
3279  {
3280  /* Unnamed join has no refname */
3281  refname = NULL;
3282  }
3283  else
3284  {
3285  /* Otherwise use whatever the parser assigned */
3286  refname = rte->eref->aliasname;
3287  }
3288 
3289  /*
3290  * If the selected name isn't unique, append digits to make it so, and
3291  * make a new hash entry for it once we've got a unique name. For a
3292  * very long input name, we might have to truncate to stay within
3293  * NAMEDATALEN.
3294  */
3295  if (refname)
3296  {
3297  hentry = (NameHashEntry *) hash_search(names_hash,
3298  refname,
3299  HASH_ENTER,
3300  &found);
3301  if (found)
3302  {
3303  /* Name already in use, must choose a new one */
3304  int refnamelen = strlen(refname);
3305  char *modname = (char *) palloc(refnamelen + 16);
3306  NameHashEntry *hentry2;
3307 
3308  do
3309  {
3310  hentry->counter++;
3311  for (;;)
3312  {
3313  /*
3314  * We avoid using %.*s here because it can misbehave
3315  * if the data is not valid in what libc thinks is the
3316  * prevailing encoding.
3317  */
3318  memcpy(modname, refname, refnamelen);
3319  sprintf(modname + refnamelen, "_%d", hentry->counter);
3320  if (strlen(modname) < NAMEDATALEN)
3321  break;
3322  /* drop chars from refname to keep all the digits */
3323  refnamelen = pg_mbcliplen(refname, refnamelen,
3324  refnamelen - 1);
3325  }
3326  hentry2 = (NameHashEntry *) hash_search(names_hash,
3327  modname,
3328  HASH_ENTER,
3329  &found);
3330  } while (found);
3331  hentry2->counter = 0; /* init new hash entry */
3332  refname = modname;
3333  }
3334  else
3335  {
3336  /* Name not previously used, need only initialize hentry */
3337  hentry->counter = 0;
3338  }
3339  }
3340 
3341  dpns->rtable_names = lappend(dpns->rtable_names, refname);
3342  rtindex++;
3343  }
3344 
3345  hash_destroy(names_hash);
3346 }
3347 
3348 /*
3349  * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
3350  *
3351  * For convenience, this is defined to initialize the deparse_namespace struct
3352  * from scratch.
3353  */
3354 static void
3356  List *parent_namespaces)
3357 {
3358  ListCell *lc;
3359  ListCell *lc2;
3360 
3361  /* Initialize *dpns and fill rtable/ctes links */
3362  memset(dpns, 0, sizeof(deparse_namespace));
3363  dpns->rtable = query->rtable;
3364  dpns->ctes = query->cteList;
3365 
3366  /* Assign a unique relation alias to each RTE */
3367  set_rtable_names(dpns, parent_namespaces, NULL);
3368 
3369  /* Initialize dpns->rtable_columns to contain zeroed structs */
3370  dpns->rtable_columns = NIL;
3371  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
3372  dpns->rtable_columns = lappend(dpns->rtable_columns,
3373  palloc0(sizeof(deparse_columns)));
3374 
3375  /* If it's a utility query, it won't have a jointree */
3376  if (query->jointree)
3377  {
3378  /* Detect whether global uniqueness of USING names is needed */
3379  dpns->unique_using =
3380  has_dangerous_join_using(dpns, (Node *) query->jointree);
3381 
3382  /*
3383  * Select names for columns merged by USING, via a recursive pass over
3384  * the query jointree.
3385  */
3386  set_using_names(dpns, (Node *) query->jointree, NIL);
3387  }
3388 
3389  /*
3390  * Now assign remaining column aliases for each RTE. We do this in a
3391  * linear scan of the rtable, so as to process RTEs whether or not they
3392  * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
3393  * etc). JOIN RTEs must be processed after their children, but this is
3394  * okay because they appear later in the rtable list than their children
3395  * (cf Asserts in identify_join_columns()).
3396  */
3397  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
3398  {
3399  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3400  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
3401 
3402  if (rte->rtekind == RTE_JOIN)
3403  set_join_column_names(dpns, rte, colinfo);
3404  else
3405  set_relation_column_names(dpns, rte, colinfo);
3406  }
3407 }
3408 
3409 /*
3410  * set_simple_column_names: fill in column aliases for non-query situations
3411  *
3412  * This handles EXPLAIN and cases where we only have relation RTEs. Without
3413  * a join tree, we can't do anything smart about join RTEs, but we don't
3414  * need to (note that EXPLAIN should never see join alias Vars anyway).
3415  * If we do hit a join RTE we'll just process it like a non-table base RTE.
3416  */
3417 static void
3419 {
3420  ListCell *lc;
3421  ListCell *lc2;
3422 
3423  /* Initialize dpns->rtable_columns to contain zeroed structs */
3424  dpns->rtable_columns = NIL;
3425  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
3426  dpns->rtable_columns = lappend(dpns->rtable_columns,
3427  palloc0(sizeof(deparse_columns)));
3428 
3429  /* Assign unique column aliases within each RTE */
3430  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
3431  {
3432  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3433  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
3434 
3435  set_relation_column_names(dpns, rte, colinfo);
3436  }
3437 }
3438 
3439 /*
3440  * has_dangerous_join_using: search jointree for unnamed JOIN USING
3441  *
3442  * Merged columns of a JOIN USING may act differently from either of the input
3443  * columns, either because they are merged with COALESCE (in a FULL JOIN) or
3444  * because an implicit coercion of the underlying input column is required.
3445  * In such a case the column must be referenced as a column of the JOIN not as
3446  * a column of either input. And this is problematic if the join is unnamed
3447  * (alias-less): we cannot qualify the column's name with an RTE name, since
3448  * there is none. (Forcibly assigning an alias to the join is not a solution,
3449  * since that will prevent legal references to tables below the join.)
3450  * To ensure that every column in the query is unambiguously referenceable,
3451  * we must assign such merged columns names that are globally unique across
3452  * the whole query, aliasing other columns out of the way as necessary.
3453  *
3454  * Because the ensuing re-aliasing is fairly damaging to the readability of
3455  * the query, we don't do this unless we have to. So, we must pre-scan
3456  * the join tree to see if we have to, before starting set_using_names().
3457  */
3458 static bool
3460 {
3461  if (IsA(jtnode, RangeTblRef))
3462  {
3463  /* nothing to do here */
3464  }
3465  else if (IsA(jtnode, FromExpr))
3466  {
3467  FromExpr *f = (FromExpr *) jtnode;
3468  ListCell *lc;
3469 
3470  foreach(lc, f->fromlist)
3471  {
3472  if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
3473  return true;
3474  }
3475  }
3476  else if (IsA(jtnode, JoinExpr))
3477  {
3478  JoinExpr *j = (JoinExpr *) jtnode;
3479 
3480  /* Is it an unnamed JOIN with USING? */
3481  if (j->alias == NULL && j->usingClause)
3482  {
3483  /*
3484  * Yes, so check each join alias var to see if any of them are not
3485  * simple references to underlying columns. If so, we have a
3486  * dangerous situation and must pick unique aliases.
3487  */
3488  RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
3489  ListCell *lc;
3490 
3491  foreach(lc, jrte->joinaliasvars)
3492  {
3493  Var *aliasvar = (Var *) lfirst(lc);
3494 
3495  if (aliasvar != NULL && !IsA(aliasvar, Var))
3496  return true;
3497  }
3498  }
3499 
3500  /* Nope, but inspect children */
3501  if (has_dangerous_join_using(dpns, j->larg))
3502  return true;
3503  if (has_dangerous_join_using(dpns, j->rarg))
3504  return true;
3505  }
3506  else
3507  elog(ERROR, "unrecognized node type: %d",
3508  (int) nodeTag(jtnode));
3509  return false;
3510 }
3511 
3512 /*
3513  * set_using_names: select column aliases to be used for merged USING columns
3514  *
3515  * We do this during a recursive descent of the query jointree.
3516  * dpns->unique_using must already be set to determine the global strategy.
3517  *
3518  * Column alias info is saved in the dpns->rtable_columns list, which is
3519  * assumed to be filled with pre-zeroed deparse_columns structs.
3520  *
3521  * parentUsing is a list of all USING aliases assigned in parent joins of
3522  * the current jointree node. (The passed-in list must not be modified.)
3523  */
3524 static void
3525 set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
3526 {
3527  if (IsA(jtnode, RangeTblRef))
3528  {
3529  /* nothing to do now */
3530  }
3531  else if (IsA(jtnode, FromExpr))
3532  {
3533  FromExpr *f = (FromExpr *) jtnode;
3534  ListCell *lc;
3535 
3536  foreach(lc, f->fromlist)
3537  set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
3538  }
3539  else if (IsA(jtnode, JoinExpr))
3540  {
3541  JoinExpr *j = (JoinExpr *) jtnode;
3542  RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
3543  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
3544  int *leftattnos;
3545  int *rightattnos;
3546  deparse_columns *leftcolinfo;
3547  deparse_columns *rightcolinfo;
3548  int i;
3549  ListCell *lc;
3550 
3551  /* Get info about the shape of the join */
3552  identify_join_columns(j, rte, colinfo);
3553  leftattnos = colinfo->leftattnos;
3554  rightattnos = colinfo->rightattnos;
3555 
3556  /* Look up the not-yet-filled-in child deparse_columns structs */
3557  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
3558  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
3559 
3560  /*
3561  * If this join is unnamed, then we cannot substitute new aliases at
3562  * this level, so any name requirements pushed down to here must be
3563  * pushed down again to the children.
3564  */
3565  if (rte->alias == NULL)
3566  {
3567  for (i = 0; i < colinfo->num_cols; i++)
3568  {
3569  char *colname = colinfo->colnames[i];
3570 
3571  if (colname == NULL)
3572  continue;
3573 
3574  /* Push down to left column, unless it's a system column */
3575  if (leftattnos[i] > 0)
3576  {
3577  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
3578  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
3579  }
3580 
3581  /* Same on the righthand side */
3582  if (rightattnos[i] > 0)
3583  {
3584  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
3585  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
3586  }
3587  }
3588  }
3589 
3590  /*
3591  * If there's a USING clause, select the USING column names and push
3592  * those names down to the children. We have two strategies:
3593  *
3594  * If dpns->unique_using is true, we force all USING names to be
3595  * unique across the whole query level. In principle we'd only need
3596  * the names of dangerous USING columns to be globally unique, but to
3597  * safely assign all USING names in a single pass, we have to enforce
3598  * the same uniqueness rule for all of them. However, if a USING
3599  * column's name has been pushed down from the parent, we should use
3600  * it as-is rather than making a uniqueness adjustment. This is
3601  * necessary when we're at an unnamed join, and it creates no risk of
3602  * ambiguity. Also, if there's a user-written output alias for a
3603  * merged column, we prefer to use that rather than the input name;
3604  * this simplifies the logic and seems likely to lead to less aliasing
3605  * overall.
3606  *
3607  * If dpns->unique_using is false, we only need USING names to be
3608  * unique within their own join RTE. We still need to honor
3609  * pushed-down names, though.
3610  *
3611  * Though significantly different in results, these two strategies are
3612  * implemented by the same code, with only the difference of whether
3613  * to put assigned names into dpns->using_names.
3614  */
3615  if (j->usingClause)
3616  {
3617  /* Copy the input parentUsing list so we don't modify it */
3618  parentUsing = list_copy(parentUsing);
3619 
3620  /* USING names must correspond to the first join output columns */
3622  i = 0;
3623  foreach(lc, j->usingClause)
3624  {
3625  char *colname = strVal(lfirst(lc));
3626 
3627  /* Assert it's a merged column */
3628  Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
3629 
3630  /* Adopt passed-down name if any, else select unique name */
3631  if (colinfo->colnames[i] != NULL)
3632  colname = colinfo->colnames[i];
3633  else
3634  {
3635  /* Prefer user-written output alias if any */
3636  if (rte->alias && i < list_length(rte->alias->colnames))
3637  colname = strVal(list_nth(rte->alias->colnames, i));
3638  /* Make it appropriately unique */
3639  colname = make_colname_unique(colname, dpns, colinfo);
3640  if (dpns->unique_using)
3641  dpns->using_names = lappend(dpns->using_names,
3642  colname);
3643  /* Save it as output column name, too */
3644  colinfo->colnames[i] = colname;
3645  }
3646 
3647  /* Remember selected names for use later */
3648  colinfo->usingNames = lappend(colinfo->usingNames, colname);
3649  parentUsing = lappend(parentUsing, colname);
3650 
3651  /* Push down to left column, unless it's a system column */
3652  if (leftattnos[i] > 0)
3653  {
3654  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
3655  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
3656  }
3657 
3658  /* Same on the righthand side */
3659  if (rightattnos[i] > 0)
3660  {
3661  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
3662  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
3663  }
3664 
3665  i++;
3666  }
3667  }
3668 
3669  /* Mark child deparse_columns structs with correct parentUsing info */
3670  leftcolinfo->parentUsing = parentUsing;
3671  rightcolinfo->parentUsing = parentUsing;
3672 
3673  /* Now recursively assign USING column names in children */
3674  set_using_names(dpns, j->larg, parentUsing);
3675  set_using_names(dpns, j->rarg, parentUsing);
3676  }
3677  else
3678  elog(ERROR, "unrecognized node type: %d",
3679  (int) nodeTag(jtnode));
3680 }
3681 
3682 /*
3683  * set_relation_column_names: select column aliases for a non-join RTE
3684  *
3685  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
3686  * If any colnames entries are already filled in, those override local
3687  * choices.
3688  */
3689 static void
3691  deparse_columns *colinfo)
3692 {
3693  int ncolumns;
3694  char **real_colnames;
3695  bool changed_any;
3696  int noldcolumns;
3697  int i;
3698  int j;
3699 
3700  /*
3701  * Extract the RTE's "real" column names. This is comparable to
3702  * get_rte_attribute_name, except that it's important to disregard dropped
3703  * columns. We put NULL into the array for a dropped column.
3704  */
3705  if (rte->rtekind == RTE_RELATION)
3706  {
3707  /* Relation --- look to the system catalogs for up-to-date info */
3708  Relation rel;
3709  TupleDesc tupdesc;
3710 
3711  rel = relation_open(rte->relid, AccessShareLock);
3712  tupdesc = RelationGetDescr(rel);
3713 
3714  ncolumns = tupdesc->natts;
3715  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
3716 
3717  for (i = 0; i < ncolumns; i++)
3718  {
3719  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
3720 
3721  if (attr->attisdropped)
3722  real_colnames[i] = NULL;
3723  else
3724  real_colnames[i] = pstrdup(NameStr(attr->attname));
3725  }
3727  }
3728  else
3729  {
3730  /* Otherwise use the column names from eref */
3731  ListCell *lc;
3732 
3733  ncolumns = list_length(rte->eref->colnames);
3734  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
3735 
3736  i = 0;
3737  foreach(lc, rte->eref->colnames)
3738  {
3739  /*
3740  * If the column name shown in eref is an empty string, then it's
3741  * a column that was dropped at the time of parsing the query, so
3742  * treat it as dropped.
3743  */
3744  char *cname = strVal(lfirst(lc));
3745 
3746  if (cname[0] == '\0')
3747  cname = NULL;
3748  real_colnames[i] = cname;
3749  i++;
3750  }
3751  }
3752 
3753  /*
3754  * Ensure colinfo->colnames has a slot for each column. (It could be long
3755  * enough already, if we pushed down a name for the last column.) Note:
3756  * it's possible that there are now more columns than there were when the
3757  * query was parsed, ie colnames could be longer than rte->eref->colnames.
3758  * We must assign unique aliases to the new columns too, else there could
3759  * be unresolved conflicts when the view/rule is reloaded.
3760  */
3761  expand_colnames_array_to(colinfo, ncolumns);
3762  Assert(colinfo->num_cols == ncolumns);
3763 
3764  /*
3765  * Make sufficiently large new_colnames and is_new_col arrays, too.
3766  *
3767  * Note: because we leave colinfo->num_new_cols zero until after the loop,
3768  * colname_is_unique will not consult that array, which is fine because it
3769  * would only be duplicate effort.
3770  */
3771  colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
3772  colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
3773 
3774  /*
3775  * Scan the columns, select a unique alias for each one, and store it in
3776  * colinfo->colnames and colinfo->new_colnames. The former array has NULL
3777  * entries for dropped columns, the latter omits them. Also mark
3778  * new_colnames entries as to whether they are new since parse time; this
3779  * is the case for entries beyond the length of rte->eref->colnames.
3780  */
3781  noldcolumns = list_length(rte->eref->colnames);
3782  changed_any = false;
3783  j = 0;
3784  for (i = 0; i < ncolumns; i++)
3785  {
3786  char *real_colname = real_colnames[i];
3787  char *colname = colinfo->colnames[i];
3788 
3789  /* Skip dropped columns */
3790  if (real_colname == NULL)
3791  {
3792  Assert(colname == NULL); /* colnames[i] is already NULL */
3793  continue;
3794  }
3795 
3796  /* If alias already assigned, that's what to use */
3797  if (colname == NULL)
3798  {
3799  /* If user wrote an alias, prefer that over real column name */
3800  if (rte->alias && i < list_length(rte->alias->colnames))
3801  colname = strVal(list_nth(rte->alias->colnames, i));
3802  else
3803  colname = real_colname;
3804 
3805  /* Unique-ify and insert into colinfo */
3806  colname = make_colname_unique(colname, dpns, colinfo);
3807 
3808  colinfo->colnames[i] = colname;
3809  }
3810 
3811  /* Put names of non-dropped columns in new_colnames[] too */
3812  colinfo->new_colnames[j] = colname;
3813  /* And mark them as new or not */
3814  colinfo->is_new_col[j] = (i >= noldcolumns);
3815  j++;
3816 
3817  /* Remember if any assigned aliases differ from "real" name */
3818  if (!changed_any && strcmp(colname, real_colname) != 0)
3819  changed_any = true;
3820  }
3821 
3822  /*
3823  * Set correct length for new_colnames[] array. (Note: if columns have
3824  * been added, colinfo->num_cols includes them, which is not really quite
3825  * right but is harmless, since any new columns must be at the end where
3826  * they won't affect varattnos of pre-existing columns.)
3827  */
3828  colinfo->num_new_cols = j;
3829 
3830  /*
3831  * For a relation RTE, we need only print the alias column names if any
3832  * are different from the underlying "real" names. For a function RTE,
3833  * always emit a complete column alias list; this is to protect against
3834  * possible instability of the default column names (eg, from altering
3835  * parameter names). For tablefunc RTEs, we never print aliases, because
3836  * the column names are part of the clause itself. For other RTE types,
3837  * print if we changed anything OR if there were user-written column
3838  * aliases (since the latter would be part of the underlying "reality").
3839  */
3840  if (rte->rtekind == RTE_RELATION)
3841  colinfo->printaliases = changed_any;
3842  else if (rte->rtekind == RTE_FUNCTION)
3843  colinfo->printaliases = true;
3844  else if (rte->rtekind == RTE_TABLEFUNC)
3845  colinfo->printaliases = false;
3846  else if (rte->alias && rte->alias->colnames != NIL)
3847  colinfo->printaliases = true;
3848  else
3849  colinfo->printaliases = changed_any;
3850 }
3851 
3852 /*
3853  * set_join_column_names: select column aliases for a join RTE
3854  *
3855  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
3856  * If any colnames entries are already filled in, those override local
3857  * choices. Also, names for USING columns were already chosen by
3858  * set_using_names(). We further expect that column alias selection has been
3859  * completed for both input RTEs.
3860  */
3861 static void
3863  deparse_columns *colinfo)
3864 {
3865  deparse_columns *leftcolinfo;
3866  deparse_columns *rightcolinfo;
3867  bool changed_any;
3868  int noldcolumns;
3869  int nnewcolumns;
3870  Bitmapset *leftmerged = NULL;
3871  Bitmapset *rightmerged = NULL;
3872  int i;
3873  int j;
3874  int ic;
3875  int jc;
3876 
3877  /* Look up the previously-filled-in child deparse_columns structs */
3878  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
3879  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
3880 
3881  /*
3882  * Ensure colinfo->colnames has a slot for each column. (It could be long
3883  * enough already, if we pushed down a name for the last column.) Note:
3884  * it's possible that one or both inputs now have more columns than there
3885  * were when the query was parsed, but we'll deal with that below. We
3886  * only need entries in colnames for pre-existing columns.
3887  */
3888  noldcolumns = list_length(rte->eref->colnames);
3889  expand_colnames_array_to(colinfo, noldcolumns);
3890  Assert(colinfo->num_cols == noldcolumns);
3891 
3892  /*
3893  * Scan the join output columns, select an alias for each one, and store
3894  * it in colinfo->colnames. If there are USING columns, set_using_names()
3895  * already selected their names, so we can start the loop at the first
3896  * non-merged column.
3897  */
3898  changed_any = false;
3899  for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
3900  {
3901  char *colname = colinfo->colnames[i];
3902  char *real_colname;
3903 
3904  /* Ignore dropped column (only possible for non-merged column) */
3905  if (colinfo->leftattnos[i] == 0 && colinfo->rightattnos[i] == 0)
3906  {
3907  Assert(colname == NULL);
3908  continue;
3909  }
3910 
3911  /* Get the child column name */
3912  if (colinfo->leftattnos[i] > 0)
3913  real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
3914  else if (colinfo->rightattnos[i] > 0)
3915  real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
3916  else
3917  {
3918  /* We're joining system columns --- use eref name */
3919  real_colname = strVal(list_nth(rte->eref->colnames, i));
3920  }
3921  Assert(real_colname != NULL);
3922 
3923  /* In an unnamed join, just report child column names as-is */
3924  if (rte->alias == NULL)
3925  {
3926  colinfo->colnames[i] = real_colname;
3927  continue;
3928  }
3929 
3930  /* If alias already assigned, that's what to use */
3931  if (colname == NULL)
3932  {
3933  /* If user wrote an alias, prefer that over real column name */
3934  if (rte->alias && i < list_length(rte->alias->colnames))
3935  colname = strVal(list_nth(rte->alias->colnames, i));
3936  else
3937  colname = real_colname;
3938 
3939  /* Unique-ify and insert into colinfo */
3940  colname = make_colname_unique(colname, dpns, colinfo);
3941 
3942  colinfo->colnames[i] = colname;
3943  }
3944 
3945  /* Remember if any assigned aliases differ from "real" name */
3946  if (!changed_any && strcmp(colname, real_colname) != 0)
3947  changed_any = true;
3948  }
3949 
3950  /*
3951  * Calculate number of columns the join would have if it were re-parsed
3952  * now, and create storage for the new_colnames and is_new_col arrays.
3953  *
3954  * Note: colname_is_unique will be consulting new_colnames[] during the
3955  * loops below, so its not-yet-filled entries must be zeroes.
3956  */
3957  nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
3958  list_length(colinfo->usingNames);
3959  colinfo->num_new_cols = nnewcolumns;
3960  colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
3961  colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
3962 
3963  /*
3964  * Generating the new_colnames array is a bit tricky since any new columns
3965  * added since parse time must be inserted in the right places. This code
3966  * must match the parser, which will order a join's columns as merged
3967  * columns first (in USING-clause order), then non-merged columns from the
3968  * left input (in attnum order), then non-merged columns from the right
3969  * input (ditto). If one of the inputs is itself a join, its columns will
3970  * be ordered according to the same rule, which means newly-added columns
3971  * might not be at the end. We can figure out what's what by consulting
3972  * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
3973  *
3974  * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
3975  * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
3976  * meanings for the current child RTE.
3977  */
3978 
3979  /* Handle merged columns; they are first and can't be new */
3980  i = j = 0;
3981  while (i < noldcolumns &&
3982  colinfo->leftattnos[i] != 0 &&
3983  colinfo->rightattnos[i] != 0)
3984  {
3985  /* column name is already determined and known unique */
3986  colinfo->new_colnames[j] = colinfo->colnames[i];
3987  colinfo->is_new_col[j] = false;
3988 
3989  /* build bitmapsets of child attnums of merged columns */
3990  if (colinfo->leftattnos[i] > 0)
3991  leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
3992  if (colinfo->rightattnos[i] > 0)
3993  rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
3994 
3995  i++, j++;
3996  }
3997 
3998  /* Handle non-merged left-child columns */
3999  ic = 0;
4000  for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4001  {
4002  char *child_colname = leftcolinfo->new_colnames[jc];
4003 
4004  if (!leftcolinfo->is_new_col[jc])
4005  {
4006  /* Advance ic to next non-dropped old column of left child */
4007  while (ic < leftcolinfo->num_cols &&
4008  leftcolinfo->colnames[ic] == NULL)
4009  ic++;
4010  Assert(ic < leftcolinfo->num_cols);
4011  ic++;
4012  /* If it is a merged column, we already processed it */
4013  if (bms_is_member(ic, leftmerged))
4014  continue;
4015  /* Else, advance i to the corresponding existing join column */
4016  while (i < colinfo->num_cols &&
4017  colinfo->colnames[i] == NULL)
4018  i++;
4019  Assert(i < colinfo->num_cols);
4020  Assert(ic == colinfo->leftattnos[i]);
4021  /* Use the already-assigned name of this column */
4022  colinfo->new_colnames[j] = colinfo->colnames[i];
4023  i++;
4024  }
4025  else
4026  {
4027  /*
4028  * Unique-ify the new child column name and assign, unless we're
4029  * in an unnamed join, in which case just copy
4030  */
4031  if (rte->alias != NULL)
4032  {
4033  colinfo->new_colnames[j] =
4034  make_colname_unique(child_colname, dpns, colinfo);
4035  if (!changed_any &&
4036  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4037  changed_any = true;
4038  }
4039  else
4040  colinfo->new_colnames[j] = child_colname;
4041  }
4042 
4043  colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4044  j++;
4045  }
4046 
4047  /* Handle non-merged right-child columns in exactly the same way */
4048  ic = 0;
4049  for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4050  {
4051  char *child_colname = rightcolinfo->new_colnames[jc];
4052 
4053  if (!rightcolinfo->is_new_col[jc])
4054  {
4055  /* Advance ic to next non-dropped old column of right child */
4056  while (ic < rightcolinfo->num_cols &&
4057  rightcolinfo->colnames[ic] == NULL)
4058  ic++;
4059  Assert(ic < rightcolinfo->num_cols);
4060  ic++;
4061  /* If it is a merged column, we already processed it */
4062  if (bms_is_member(ic, rightmerged))
4063  continue;
4064  /* Else, advance i to the corresponding existing join column */
4065  while (i < colinfo->num_cols &&
4066  colinfo->colnames[i] == NULL)
4067  i++;
4068  Assert(i < colinfo->num_cols);
4069  Assert(ic == colinfo->rightattnos[i]);
4070  /* Use the already-assigned name of this column */
4071  colinfo->new_colnames[j] = colinfo->colnames[i];
4072  i++;
4073  }
4074  else
4075  {
4076  /*
4077  * Unique-ify the new child column name and assign, unless we're
4078  * in an unnamed join, in which case just copy
4079  */
4080  if (rte->alias != NULL)
4081  {
4082  colinfo->new_colnames[j] =
4083  make_colname_unique(child_colname, dpns, colinfo);
4084  if (!changed_any &&
4085  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4086  changed_any = true;
4087  }
4088  else
4089  colinfo->new_colnames[j] = child_colname;
4090  }
4091 
4092  colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4093  j++;
4094  }
4095 
4096  /* Assert we processed the right number of columns */
4097 #ifdef USE_ASSERT_CHECKING
4098  while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4099  i++;
4100  Assert(i == colinfo->num_cols);
4101  Assert(j == nnewcolumns);
4102 #endif
4103 
4104  /*
4105  * For a named join, print column aliases if we changed any from the child
4106  * names. Unnamed joins cannot print aliases.
4107  */
4108  if (rte->alias != NULL)
4109  colinfo->printaliases = changed_any;
4110  else
4111  colinfo->printaliases = false;
4112 }
4113 
4114 /*
4115  * colname_is_unique: is colname distinct from already-chosen column names?
4116  *
4117  * dpns is query-wide info, colinfo is for the column's RTE
4118  */
4119 static bool
4120 colname_is_unique(const char *colname, deparse_namespace *dpns,
4121  deparse_columns *colinfo)
4122 {
4123  int i;
4124  ListCell *lc;
4125 
4126  /* Check against already-assigned column aliases within RTE */
4127  for (i = 0; i < colinfo->num_cols; i++)
4128  {
4129  char *oldname = colinfo->colnames[i];
4130 
4131  if (oldname && strcmp(oldname, colname) == 0)
4132  return false;
4133  }
4134 
4135  /*
4136  * If we're building a new_colnames array, check that too (this will be
4137  * partially but not completely redundant with the previous checks)
4138  */
4139  for (i = 0; i < colinfo->num_new_cols; i++)
4140  {
4141  char *oldname = colinfo->new_colnames[i];
4142 
4143  if (oldname && strcmp(oldname, colname) == 0)
4144  return false;
4145  }
4146 
4147  /* Also check against USING-column names that must be globally unique */
4148  foreach(lc, dpns->using_names)
4149  {
4150  char *oldname = (char *) lfirst(lc);
4151 
4152  if (strcmp(oldname, colname) == 0)
4153  return false;
4154  }
4155 
4156  /* Also check against names already assigned for parent-join USING cols */
4157  foreach(lc, colinfo->parentUsing)
4158  {
4159  char *oldname = (char *) lfirst(lc);
4160 
4161  if (strcmp(oldname, colname) == 0)
4162  return false;
4163  }
4164 
4165  return true;
4166 }
4167 
4168 /*
4169  * make_colname_unique: modify colname if necessary to make it unique
4170  *
4171  * dpns is query-wide info, colinfo is for the column's RTE
4172  */
4173 static char *
4175  deparse_columns *colinfo)
4176 {
4177  /*
4178  * If the selected name isn't unique, append digits to make it so. For a
4179  * very long input name, we might have to truncate to stay within
4180  * NAMEDATALEN.
4181  */
4182  if (!colname_is_unique(colname, dpns, colinfo))
4183  {
4184  int colnamelen = strlen(colname);
4185  char *modname = (char *) palloc(colnamelen + 16);
4186  int i = 0;
4187 
4188  do
4189  {
4190  i++;
4191  for (;;)
4192  {
4193  /*
4194  * We avoid using %.*s here because it can misbehave if the
4195  * data is not valid in what libc thinks is the prevailing
4196  * encoding.
4197  */
4198  memcpy(modname, colname, colnamelen);
4199  sprintf(modname + colnamelen, "_%d", i);
4200  if (strlen(modname) < NAMEDATALEN)
4201  break;
4202  /* drop chars from colname to keep all the digits */
4203  colnamelen = pg_mbcliplen(colname, colnamelen,
4204  colnamelen - 1);
4205  }
4206  } while (!colname_is_unique(modname, dpns, colinfo));
4207  colname = modname;
4208  }
4209  return colname;
4210 }
4211 
4212 /*
4213  * expand_colnames_array_to: make colinfo->colnames at least n items long
4214  *
4215  * Any added array entries are initialized to zero.
4216  */
4217 static void
4219 {
4220  if (n > colinfo->num_cols)
4221  {
4222  if (colinfo->colnames == NULL)
4223  colinfo->colnames = (char **) palloc0(n * sizeof(char *));
4224  else
4225  {
4226  colinfo->colnames = (char **) repalloc(colinfo->colnames,
4227  n * sizeof(char *));
4228  memset(colinfo->colnames + colinfo->num_cols, 0,
4229  (n - colinfo->num_cols) * sizeof(char *));
4230  }
4231  colinfo->num_cols = n;
4232  }
4233 }
4234 
4235 /*
4236  * identify_join_columns: figure out where columns of a join come from
4237  *
4238  * Fills the join-specific fields of the colinfo struct, except for
4239  * usingNames which is filled later.
4240  */
4241 static void
4243  deparse_columns *colinfo)
4244 {
4245  int numjoincols;
4246  int i;
4247  ListCell *lc;
4248 
4249  /* Extract left/right child RT indexes */
4250  if (IsA(j->larg, RangeTblRef))
4251  colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
4252  else if (IsA(j->larg, JoinExpr))
4253  colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
4254  else
4255  elog(ERROR, "unrecognized node type in jointree: %d",
4256  (int) nodeTag(j->larg));
4257  if (IsA(j->rarg, RangeTblRef))
4258  colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
4259  else if (IsA(j->rarg, JoinExpr))
4260  colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
4261  else
4262  elog(ERROR, "unrecognized node type in jointree: %d",
4263  (int) nodeTag(j->rarg));
4264 
4265  /* Assert children will be processed earlier than join in second pass */
4266  Assert(colinfo->leftrti < j->rtindex);
4267  Assert(colinfo->rightrti < j->rtindex);
4268 
4269  /* Initialize result arrays with zeroes */
4270  numjoincols = list_length(jrte->joinaliasvars);
4271  Assert(numjoincols == list_length(jrte->eref->colnames));
4272  colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
4273  colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
4274 
4275  /* Scan the joinaliasvars list to identify simple column references */
4276  i = 0;
4277  foreach(lc, jrte->joinaliasvars)
4278  {
4279  Var *aliasvar = (Var *) lfirst(lc);
4280 
4281  /* get rid of any implicit coercion above the Var */
4282  aliasvar = (Var *) strip_implicit_coercions((Node *) aliasvar);
4283 
4284  if (aliasvar == NULL)
4285  {
4286  /* It's a dropped column; nothing to do here */
4287  }
4288  else if (IsA(aliasvar, Var))
4289  {
4290  Assert(aliasvar->varlevelsup == 0);
4291  Assert(aliasvar->varattno != 0);
4292  if (aliasvar->varno == colinfo->leftrti)
4293  colinfo->leftattnos[i] = aliasvar->varattno;
4294  else if (aliasvar->varno == colinfo->rightrti)
4295  colinfo->rightattnos[i] = aliasvar->varattno;
4296  else
4297  elog(ERROR, "unexpected varno %d in JOIN RTE",
4298  aliasvar->varno);
4299  }
4300  else if (IsA(aliasvar, CoalesceExpr))
4301  {
4302  /*
4303  * It's a merged column in FULL JOIN USING. Ignore it for now and
4304  * let the code below identify the merged columns.
4305  */
4306  }
4307  else
4308  elog(ERROR, "unrecognized node type in join alias vars: %d",
4309  (int) nodeTag(aliasvar));
4310 
4311  i++;
4312  }
4313 
4314  /*
4315  * If there's a USING clause, deconstruct the join quals to identify the
4316  * merged columns. This is a tad painful but if we cannot rely on the
4317  * column names, there is no other representation of which columns were
4318  * joined by USING. (Unless the join type is FULL, we can't tell from the
4319  * joinaliasvars list which columns are merged.) Note: we assume that the
4320  * merged columns are the first output column(s) of the join.
4321  */
4322  if (j->usingClause)
4323  {
4324  List *leftvars = NIL;
4325  List *rightvars = NIL;
4326  ListCell *lc2;
4327 
4328  /* Extract left- and right-side Vars from the qual expression */
4329  flatten_join_using_qual(j->quals, &leftvars, &rightvars);
4330  Assert(list_length(leftvars) == list_length(j->usingClause));
4331  Assert(list_length(rightvars) == list_length(j->usingClause));
4332 
4333  /* Mark the output columns accordingly */
4334  i = 0;
4335  forboth(lc, leftvars, lc2, rightvars)
4336  {
4337  Var *leftvar = (Var *) lfirst(lc);
4338  Var *rightvar = (Var *) lfirst(lc2);
4339 
4340  Assert(leftvar->varlevelsup == 0);
4341  Assert(leftvar->varattno != 0);
4342  if (leftvar->varno != colinfo->leftrti)
4343  elog(ERROR, "unexpected varno %d in JOIN USING qual",
4344  leftvar->varno);
4345  colinfo->leftattnos[i] = leftvar->varattno;
4346 
4347  Assert(rightvar->varlevelsup == 0);
4348  Assert(rightvar->varattno != 0);
4349  if (rightvar->varno != colinfo->rightrti)
4350  elog(ERROR, "unexpected varno %d in JOIN USING qual",
4351  rightvar->varno);
4352  colinfo->rightattnos[i] = rightvar->varattno;
4353 
4354  i++;
4355  }
4356  }
4357 }
4358 
4359 /*
4360  * flatten_join_using_qual: extract Vars being joined from a JOIN/USING qual
4361  *
4362  * We assume that transformJoinUsingClause won't have produced anything except
4363  * AND nodes, equality operator nodes, and possibly implicit coercions, and
4364  * that the AND node inputs match left-to-right with the original USING list.
4365  *
4366  * Caller must initialize the result lists to NIL.
4367  */
4368 static void
4369 flatten_join_using_qual(Node *qual, List **leftvars, List **rightvars)
4370 {
4371  if (IsA(qual, BoolExpr))
4372  {
4373  /* Handle AND nodes by recursion */
4374  BoolExpr *b = (BoolExpr *) qual;
4375  ListCell *lc;
4376 
4377  Assert(b->boolop == AND_EXPR);
4378  foreach(lc, b->args)
4379  {
4381  leftvars, rightvars);
4382  }
4383  }
4384  else if (IsA(qual, OpExpr))
4385  {
4386  /* Otherwise we should have an equality operator */
4387  OpExpr *op = (OpExpr *) qual;
4388  Var *var;
4389 
4390  if (list_length(op->args) != 2)
4391  elog(ERROR, "unexpected unary operator in JOIN/USING qual");
4392  /* Arguments should be Vars with perhaps implicit coercions */
4393  var = (Var *) strip_implicit_coercions((Node *) linitial(op->args));
4394  if (!IsA(var, Var))
4395  elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
4396  (int) nodeTag(var));
4397  *leftvars = lappend(*leftvars, var);
4398  var = (Var *) strip_implicit_coercions((Node *) lsecond(op->args));
4399  if (!IsA(var, Var))
4400  elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
4401  (int) nodeTag(var));
4402  *rightvars = lappend(*rightvars, var);
4403  }
4404  else
4405  {
4406  /* Perhaps we have an implicit coercion to boolean? */
4407  Node *q = strip_implicit_coercions(qual);
4408 
4409  if (q != qual)
4410  flatten_join_using_qual(q, leftvars, rightvars);
4411  else
4412  elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
4413  (int) nodeTag(qual));
4414  }
4415 }
4416 
4417 /*
4418  * get_rtable_name: convenience function to get a previously assigned RTE alias
4419  *
4420  * The RTE must belong to the topmost namespace level in "context".
4421  */
4422 static char *
4423 get_rtable_name(int rtindex, deparse_context *context)
4424 {
4426 
4427  Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4428  return (char *) list_nth(dpns->rtable_names, rtindex - 1);
4429 }
4430 
4431 /*
4432  * set_deparse_planstate: set up deparse_namespace to parse subexpressions
4433  * of a given PlanState node
4434  *
4435  * This sets the planstate, outer_planstate, inner_planstate, outer_tlist,
4436  * inner_tlist, and index_tlist fields. Caller is responsible for adjusting
4437  * the ancestors list if necessary. Note that the rtable and ctes fields do
4438  * not need to change when shifting attention to different plan nodes in a
4439  * single plan tree.
4440  */
4441 static void
4443 {
4444  dpns->planstate = ps;
4445 
4446  /*
4447  * We special-case Append and MergeAppend to pretend that the first child
4448  * plan is the OUTER referent; we have to interpret OUTER Vars in their
4449  * tlists according to one of the children, and the first one is the most
4450  * natural choice. Likewise special-case ModifyTable to pretend that the
4451  * first child plan is the OUTER referent; this is to support RETURNING
4452  * lists containing references to non-target relations.
4453  */
4454  if (IsA(ps, AppendState))
4455  dpns->outer_planstate = ((AppendState *) ps)->appendplans[0];
4456  else if (IsA(ps, MergeAppendState))
4457  dpns->outer_planstate = ((MergeAppendState *) ps)->mergeplans[0];
4458  else if (IsA(ps, ModifyTableState))
4459  dpns->outer_planstate = ((ModifyTableState *) ps)->mt_plans[0];
4460  else
4461  dpns->outer_planstate = outerPlanState(ps);
4462 
4463  if (dpns->outer_planstate)
4464  dpns->outer_tlist = dpns->outer_planstate->plan->targetlist;
4465  else
4466  dpns->outer_tlist = NIL;
4467 
4468  /*
4469  * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
4470  * use OUTER because that could someday conflict with the normal meaning.)
4471  * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
4472  * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
4473  * excluded expression's tlist. (Similar to the SubqueryScan we don't want
4474  * to reuse OUTER, it's used for RETURNING in some modify table cases,
4475  * although not INSERT .. CONFLICT).
4476  */
4477  if (IsA(ps, SubqueryScanState))
4478  dpns->inner_planstate = ((SubqueryScanState *) ps)->subplan;
4479  else if (IsA(ps, CteScanState))
4480  dpns->inner_planstate = ((CteScanState *) ps)->cteplanstate;
4481  else if (IsA(ps, ModifyTableState))
4482  dpns->inner_planstate = ps;
4483  else
4484  dpns->inner_planstate = innerPlanState(ps);
4485 
4486  if (IsA(ps, ModifyTableState))
4487  dpns->inner_tlist = ((ModifyTableState *) ps)->mt_excludedtlist;
4488  else if (dpns->inner_planstate)
4489  dpns->inner_tlist = dpns->inner_planstate->plan->targetlist;
4490  else
4491  dpns->inner_tlist = NIL;
4492 
4493  /* Set up referent for INDEX_VAR Vars, if needed */
4494  if (IsA(ps->plan, IndexOnlyScan))
4495  dpns->index_tlist = ((IndexOnlyScan *) ps->plan)->indextlist;
4496  else if (IsA(ps->plan, ForeignScan))
4497  dpns->index_tlist = ((ForeignScan *) ps->plan)->fdw_scan_tlist;
4498  else if (IsA(ps->plan, CustomScan))
4499  dpns->index_tlist = ((CustomScan *) ps->plan)->custom_scan_tlist;
4500  else
4501  dpns->index_tlist = NIL;
4502 }
4503 
4504 /*
4505  * push_child_plan: temporarily transfer deparsing attention to a child plan
4506  *
4507  * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
4508  * deparse context in case the referenced expression itself uses
4509  * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
4510  * affecting levelsup issues (although in a Plan tree there really shouldn't
4511  * be any).
4512  *
4513  * Caller must provide a local deparse_namespace variable to save the
4514  * previous state for pop_child_plan.
4515  */
4516 static void
4518  deparse_namespace *save_dpns)
4519 {
4520  /* Save state for restoration later */
4521  *save_dpns = *dpns;
4522 
4523  /* Link current plan node into ancestors list */
4524  dpns->ancestors = lcons(dpns->planstate, dpns->ancestors);
4525 
4526  /* Set attention on selected child */
4527  set_deparse_planstate(dpns, ps);
4528 }
4529 
4530 /*
4531  * pop_child_plan: undo the effects of push_child_plan
4532  */
4533 static void
4535 {
4536  List *ancestors;
4537 
4538  /* Get rid of ancestors list cell added by push_child_plan */
4539  ancestors = list_delete_first(dpns->ancestors);
4540 
4541  /* Restore fields changed by push_child_plan */
4542  *dpns = *save_dpns;
4543 
4544  /* Make sure dpns->ancestors is right (may be unnecessary) */
4545  dpns->ancestors = ancestors;
4546 }
4547 
4548 /*
4549  * push_ancestor_plan: temporarily transfer deparsing attention to an
4550  * ancestor plan
4551  *
4552  * When expanding a Param reference, we must adjust the deparse context
4553  * to match the plan node that contains the expression being printed;
4554  * otherwise we'd fail if that expression itself contains a Param or
4555  * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
4556  *
4557  * The target ancestor is conveniently identified by the ListCell holding it
4558  * in dpns->ancestors.
4559  *
4560  * Caller must provide a local deparse_namespace variable to save the
4561  * previous state for pop_ancestor_plan.
4562  */
4563 static void
4565  deparse_namespace *save_dpns)
4566 {
4567  PlanState *ps = (PlanState *) lfirst(ancestor_cell);
4568  List *ancestors;
4569 
4570  /* Save state for restoration later */
4571  *save_dpns = *dpns;
4572 
4573  /* Build a new ancestor list with just this node's ancestors */
4574  ancestors = NIL;
4575  while ((ancestor_cell = lnext(ancestor_cell)) != NULL)
4576  ancestors = lappend(ancestors, lfirst(ancestor_cell));
4577  dpns->ancestors = ancestors;
4578 
4579  /* Set attention on selected ancestor */
4580  set_deparse_planstate(dpns, ps);
4581 }
4582 
4583 /*
4584  * pop_ancestor_plan: undo the effects of push_ancestor_plan
4585  */
4586 static void
4588 {
4589  /* Free the ancestor list made in push_ancestor_plan */
4590  list_free(dpns->ancestors);
4591 
4592  /* Restore fields changed by push_ancestor_plan */
4593  *dpns = *save_dpns;
4594 }
4595 
4596 
4597 /* ----------
4598  * make_ruledef - reconstruct the CREATE RULE command
4599  * for a given pg_rewrite tuple
4600  * ----------
4601  */
4602 static void
4604  int prettyFlags)
4605 {
4606  char *rulename;
4607  char ev_type;
4608  Oid ev_class;
4609  bool is_instead;
4610  char *ev_qual;
4611  char *ev_action;
4612  List *actions = NIL;
4613  Relation ev_relation;
4614  TupleDesc viewResultDesc = NULL;
4615  int fno;
4616  Datum dat;
4617  bool isnull;
4618 
4619  /*
4620  * Get the attribute values from the rules tuple
4621  */
4622  fno = SPI_fnumber(rulettc, "rulename");
4623  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
4624  Assert(!isnull);
4625  rulename = NameStr(*(DatumGetName(dat)));
4626 
4627  fno = SPI_fnumber(rulettc, "ev_type");
4628  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
4629  Assert(!isnull);
4630  ev_type = DatumGetChar(dat);
4631 
4632  fno = SPI_fnumber(rulettc, "ev_class");
4633  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
4634  Assert(!isnull);
4635  ev_class = DatumGetObjectId(dat);
4636 
4637  fno = SPI_fnumber(rulettc, "is_instead");
4638  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
4639  Assert(!isnull);
4640  is_instead = DatumGetBool(dat);
4641 
4642  /* these could be nulls */
4643  fno = SPI_fnumber(rulettc, "ev_qual");
4644  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
4645 
4646  fno = SPI_fnumber(rulettc, "ev_action");
4647  ev_action = SPI_getvalue(ruletup, rulettc, fno);
4648  if (ev_action != NULL)
4649  actions = (List *) stringToNode(ev_action);
4650 
4651  ev_relation = heap_open(ev_class, AccessShareLock);
4652 
4653  /*
4654  * Build the rules definition text
4655  */
4656  appendStringInfo(buf, "CREATE RULE %s AS",
4657  quote_identifier(rulename));
4658 
4659  if (prettyFlags & PRETTYFLAG_INDENT)
4660  appendStringInfoString(buf, "\n ON ");
4661  else
4662  appendStringInfoString(buf, " ON ");
4663 
4664  /* The event the rule is fired for */
4665  switch (ev_type)
4666  {
4667  case '1':
4668  appendStringInfoString(buf, "SELECT");
4669  viewResultDesc = RelationGetDescr(ev_relation);
4670  break;
4671 
4672  case '2':
4673  appendStringInfoString(buf, "UPDATE");
4674  break;
4675 
4676  case '3':
4677  appendStringInfoString(buf, "INSERT");
4678  break;
4679 
4680  case '4':
4681  appendStringInfoString(buf, "DELETE");
4682  break;
4683 
4684  default:
4685  ereport(ERROR,
4686  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4687  errmsg("rule \"%s\" has unsupported event type %d",
4688  rulename, ev_type)));
4689  break;
4690  }
4691 
4692  /* The relation the rule is fired on */
4693  appendStringInfo(buf, " TO %s", generate_relation_name(ev_class, NIL));
4694 
4695  /* If the rule has an event qualification, add it */
4696  if (ev_qual == NULL)
4697  ev_qual = "";
4698  if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
4699  {
4700  Node *qual;
4701  Query *query;
4702  deparse_context context;
4703  deparse_namespace dpns;
4704 
4705  if (prettyFlags & PRETTYFLAG_INDENT)
4706  appendStringInfoString(buf, "\n ");
4707  appendStringInfoString(buf, " WHERE ");
4708 
4709  qual = stringToNode(ev_qual);
4710 
4711  /*
4712  * We need to make a context for recognizing any Vars in the qual
4713  * (which can only be references to OLD and NEW). Use the rtable of
4714  * the first query in the action list for this purpose.
4715  */
4716  query = (Query *) linitial(actions);
4717 
4718  /*
4719  * If the action is INSERT...SELECT, OLD/NEW have been pushed down
4720  * into the SELECT, and that's what we need to look at. (Ugly kluge
4721  * ... try to fix this when we redesign querytrees.)
4722  */
4723  query = getInsertSelectQuery(query, NULL);
4724 
4725  /* Must acquire locks right away; see notes in get_query_def() */
4726  AcquireRewriteLocks(query, false, false);
4727 
4728  context.buf = buf;
4729  context.namespaces = list_make1(&dpns);
4730  context.windowClause = NIL;
4731  context.windowTList = NIL;
4732  context.varprefix = (list_length(query->rtable) != 1);
4733  context.prettyFlags = prettyFlags;
4734  context.wrapColumn = WRAP_COLUMN_DEFAULT;
4735  context.indentLevel = PRETTYINDENT_STD;
4736  context.special_exprkind = EXPR_KIND_NONE;
4737 
4738  set_deparse_for_query(&dpns, query, NIL);
4739 
4740  get_rule_expr(qual, &context, false);
4741  }
4742 
4743  appendStringInfoString(buf, " DO ");
4744 
4745  /* The INSTEAD keyword (if so) */
4746  if (is_instead)
4747  appendStringInfoString(buf, "INSTEAD ");
4748 
4749  /* Finally the rules actions */
4750  if (list_length(actions) > 1)
4751  {
4752  ListCell *action;
4753  Query *query;
4754 
4755  appendStringInfoChar(buf, '(');
4756  foreach(action, actions)
4757  {
4758  query = (Query *) lfirst(action);
4759  get_query_def(query, buf, NIL, viewResultDesc,
4760  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
4761  if (prettyFlags)
4762  appendStringInfoString(buf, ";\n");
4763  else
4764  appendStringInfoString(buf, "; ");
4765  }
4766  appendStringInfoString(buf, ");");
4767  }
4768  else if (list_length(actions) == 0)
4769  {
4770  appendStringInfoString(buf, "NOTHING;");
4771  }
4772  else
4773  {
4774  Query *query;
4775 
4776  query = (Query *) linitial(actions);
4777  get_query_def(query, buf, NIL, viewResultDesc,
4778  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
4779  appendStringInfoChar(buf, ';');
4780  }
4781 
4782  heap_close(ev_relation, AccessShareLock);
4783 }
4784 
4785 
4786 /* ----------
4787  * make_viewdef - reconstruct the SELECT part of a
4788  * view rewrite rule
4789  * ----------
4790  */
4791 static void
4793  int prettyFlags, int wrapColumn)
4794 {
4795  Query *query;
4796  char ev_type;
4797  Oid ev_class;
4798  bool is_instead;
4799  char *ev_qual;
4800  char *ev_action;
4801  List *actions = NIL;
4802  Relation ev_relation;
4803  int fno;
4804  Datum dat;
4805  bool isnull;
4806 
4807  /*
4808  * Get the attribute values from the rules tuple
4809  */
4810  fno = SPI_fnumber(rulettc, "ev_type");
4811  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
4812  Assert(!isnull);
4813  ev_type = DatumGetChar(dat);
4814 
4815  fno = SPI_fnumber(rulettc, "ev_class");
4816  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
4817  Assert(!isnull);
4818  ev_class = DatumGetObjectId(dat);
4819 
4820  fno = SPI_fnumber(rulettc, "is_instead");
4821  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
4822  Assert(!isnull);
4823  is_instead = DatumGetBool(dat);
4824 
4825  /* these could be nulls */
4826  fno = SPI_fnumber(rulettc, "ev_qual");
4827  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
4828 
4829  fno = SPI_fnumber(rulettc, "ev_action");
4830  ev_action = SPI_getvalue(ruletup, rulettc, fno);
4831  if (ev_action != NULL)
4832  actions = (List *) stringToNode(ev_action);
4833 
4834  if (list_length(actions) != 1)
4835  {
4836  /* keep output buffer empty and leave */
4837  return;
4838  }
4839 
4840  query = (Query *) linitial(actions);
4841 
4842  if (ev_type != '1' || !is_instead ||
4843  strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
4844  {
4845  /* keep output buffer empty and leave */
4846  return;
4847  }
4848 
4849  ev_relation = heap_open(ev_class, AccessShareLock);
4850 
4851  get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
4852  prettyFlags, wrapColumn, 0);
4853  appendStringInfoChar(buf, ';');
4854 
4855  heap_close(ev_relation, AccessShareLock);
4856 }
4857 
4858 
4859 /* ----------
4860  * get_query_def - Parse back one query parsetree
4861  *
4862  * If resultDesc is not NULL, then it is the output tuple descriptor for
4863  * the view represented by a SELECT query.
4864  * ----------
4865  */
4866 static void
4867 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
4868  TupleDesc resultDesc,
4869  int prettyFlags, int wrapColumn, int startIndent)
4870 {
4871  deparse_context context;
4872  deparse_namespace dpns;
4873 
4874  /* Guard against excessively long or deeply-nested queries */
4877 
4878  /*
4879  * Before we begin to examine the query, acquire locks on referenced
4880  * relations, and fix up deleted columns in JOIN RTEs. This ensures
4881  * consistent results. Note we assume it's OK to scribble on the passed
4882  * querytree!
4883  *
4884  * We are only deparsing the query (we are not about to execute it), so we
4885  * only need AccessShareLock on the relations it mentions.
4886  */
4887  AcquireRewriteLocks(query, false, false);
4888 
4889  context.buf = buf;
4890  context.namespaces = lcons(&dpns, list_copy(parentnamespace));
4891  context.windowClause = NIL;
4892  context.windowTList = NIL;
4893  context.varprefix = (parentnamespace != NIL ||
4894  list_length(query->rtable) != 1);
4895  context.prettyFlags = prettyFlags;
4896  context.wrapColumn = wrapColumn;
4897  context.indentLevel = startIndent;
4898  context.special_exprkind = EXPR_KIND_NONE;
4899 
4900  set_deparse_for_query(&dpns, query, parentnamespace);
4901 
4902  switch (query->commandType)
4903  {
4904  case CMD_SELECT:
4905  get_select_query_def(query, &context, resultDesc);
4906  break;
4907 
4908  case CMD_UPDATE:
4909  get_update_query_def(query, &context);
4910  break;
4911 
4912  case CMD_INSERT:
4913  get_insert_query_def(query, &context);
4914  break;
4915 
4916  case CMD_DELETE:
4917  get_delete_query_def(query, &context);
4918  break;
4919 
4920  case CMD_NOTHING:
4921  appendStringInfoString(buf, "NOTHING");
4922  break;
4923 
4924  case CMD_UTILITY:
4925  get_utility_query_def(query, &context);
4926  break;
4927 
4928  default:
4929  elog(ERROR, "unrecognized query command type: %d",
4930  query->commandType);
4931  break;
4932  }
4933 }
4934 
4935 /* ----------
4936  * get_values_def - Parse back a VALUES list
4937  * ----------
4938  */
4939 static void
4940 get_values_def(List *values_lists, deparse_context *context)
4941 {
4942  StringInfo buf = context->buf;
4943  bool first_list = true;
4944  ListCell *vtl;
4945 
4946  appendStringInfoString(buf, "VALUES ");
4947 
4948  foreach(vtl, values_lists)
4949  {
4950  List *sublist = (List *) lfirst(vtl);
4951  bool first_col = true;
4952  ListCell *lc;
4953 
4954  if (first_list)
4955  first_list = false;
4956  else
4957  appendStringInfoString(buf, ", ");
4958 
4959  appendStringInfoChar(buf, '(');
4960  foreach(lc, sublist)
4961  {
4962  Node *col = (Node *) lfirst(lc);
4963 
4964  if (first_col)
4965  first_col = false;
4966  else
4967  appendStringInfoChar(buf, ',');
4968 
4969  /*
4970  * Print the value. Whole-row Vars need special treatment.
4971  */
4972  get_rule_expr_toplevel(col, context, false);
4973  }
4974  appendStringInfoChar(buf, ')');
4975  }
4976 }
4977 
4978 /* ----------
4979  * get_with_clause - Parse back a WITH clause
4980  * ----------
4981  */
4982 static void
4984 {
4985  StringInfo buf = context->buf;
4986  const char *sep;
4987  ListCell *l;
4988 
4989  if (query->cteList == NIL)
4990  return;
4991 
4992  if (PRETTY_INDENT(context))
4993  {
4994  context->indentLevel += PRETTYINDENT_STD;
4995  appendStringInfoChar(buf, ' ');
4996  }
4997 
4998  if (query->hasRecursive)
4999  sep = "WITH RECURSIVE ";
5000  else
5001  sep = "WITH ";
5002  foreach(l, query->cteList)
5003  {
5004  CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5005 
5006  appendStringInfoString(buf, sep);
5008  if (cte->aliascolnames)
5009  {
5010  bool first = true;
5011  ListCell *col;
5012 
5013  appendStringInfoChar(buf, '(');
5014  foreach(col, cte->aliascolnames)
5015  {
5016  if (first)
5017  first = false;
5018  else
5019  appendStringInfoString(buf, ", ");
5021  quote_identifier(strVal(lfirst(col))));
5022  }
5023  appendStringInfoChar(buf, ')');
5024  }
5025  appendStringInfoString(buf, " AS (");
5026  if (PRETTY_INDENT(context))
5027  appendContextKeyword(context, "", 0, 0, 0);
5028  get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5029  context->prettyFlags, context->wrapColumn,
5030  context->indentLevel);
5031  if (PRETTY_INDENT(context))
5032  appendContextKeyword(context, "", 0, 0, 0);
5033  appendStringInfoChar(buf, ')');
5034  sep = ", ";
5035  }
5036 
5037  if (PRETTY_INDENT(context))
5038  {
5039  context->indentLevel -= PRETTYINDENT_STD;
5040  appendContextKeyword(context, "", 0, 0, 0);
5041  }
5042  else
5043  appendStringInfoChar(buf, ' ');
5044 }
5045 
5046 /* ----------
5047  * get_select_query_def - Parse back a SELECT parsetree
5048  * ----------
5049  */
5050 static void
5052  TupleDesc resultDesc)
5053 {
5054  StringInfo buf = context->buf;
5055  List *save_windowclause;
5056  List *save_windowtlist;
5057  bool force_colno;
5058  ListCell *l;
5059 
5060  /* Insert the WITH clause if given */
5061  get_with_clause(query, context);
5062 
5063  /* Set up context for possible window functions */
5064  save_windowclause = context->windowClause;
5065  context->windowClause = query->windowClause;
5066  save_windowtlist = context->windowTList;
5067  context->windowTList = query->targetList;
5068 
5069  /*
5070  * If the Query node has a setOperations tree, then it's the top level of
5071  * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5072  * fields are interesting in the top query itself.
5073  */
5074  if (query->setOperations)
5075  {
5076  get_setop_query(query->setOperations, query, context, resultDesc);
5077  /* ORDER BY clauses must be simple in this case */
5078  force_colno = true;
5079  }
5080  else
5081  {
5082  get_basic_select_query(query, context, resultDesc);
5083  force_colno = false;
5084  }
5085 
5086  /* Add the ORDER BY clause if given */
5087  if (query->sortClause != NIL)
5088  {
5089  appendContextKeyword(context, " ORDER BY ",
5091  get_rule_orderby(query->sortClause, query->targetList,
5092  force_colno, context);
5093  }
5094 
5095  /* Add the LIMIT clause if given */
5096  if (query->limitOffset != NULL)
5097  {
5098  appendContextKeyword(context, " OFFSET ",
5100  get_rule_expr(query->limitOffset, context, false);
5101  }
5102  if (query->limitCount != NULL)
5103  {
5104  appendContextKeyword(context, " LIMIT ",
5106  if (IsA(query->limitCount, Const) &&
5107  ((Const *) query->limitCount)->constisnull)
5108  appendStringInfoString(buf, "ALL");
5109  else
5110  get_rule_expr(query->limitCount, context, false);
5111  }
5112 
5113  /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5114  if (query->hasForUpdate)
5115  {
5116  foreach(l, query->rowMarks)
5117  {
5118  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5119 
5120  /* don't print implicit clauses */
5121  if (rc->pushedDown)
5122  continue;
5123 
5124  switch (rc->strength)
5125  {
5126  case LCS_NONE:
5127  /* we intentionally throw an error for LCS_NONE */
5128  elog(ERROR, "unrecognized LockClauseStrength %d",
5129  (int) rc->strength);
5130  break;
5131  case LCS_FORKEYSHARE:
5132  appendContextKeyword(context, " FOR KEY SHARE",
5134  break;
5135  case LCS_FORSHARE:
5136  appendContextKeyword(context, " FOR SHARE",
5138  break;
5139  case LCS_FORNOKEYUPDATE:
5140  appendContextKeyword(context, " FOR NO KEY UPDATE",
5142  break;
5143  case LCS_FORUPDATE:
5144  appendContextKeyword(context, " FOR UPDATE",
5146  break;
5147  }
5148 
5149  appendStringInfo(buf, " OF %s",
5151  context)));
5152  if (rc->waitPolicy == LockWaitError)
5153  appendStringInfoString(buf, " NOWAIT");
5154  else if (rc->waitPolicy == LockWaitSkip)
5155  appendStringInfoString(buf, " SKIP LOCKED");
5156  }
5157  }
5158 
5159  context->windowClause = save_windowclause;
5160  context->windowTList = save_windowtlist;
5161 }
5162 
5163 /*
5164  * Detect whether query looks like SELECT ... FROM VALUES();
5165  * if so, return the VALUES RTE. Otherwise return NULL.
5166  */
5167 static RangeTblEntry *
5169 {
5170  RangeTblEntry *result = NULL;
5171  ListCell *lc;
5172 
5173  /*
5174  * We want to return true even if the Query also contains OLD or NEW rule
5175  * RTEs. So the idea is to scan the rtable and see if there is only one
5176  * inFromCl RTE that is a VALUES RTE.
5177  */
5178  foreach(lc, query->rtable)
5179  {
5180  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
5181 
5182  if (rte->rtekind == RTE_VALUES && rte->inFromCl)
5183  {
5184  if (result)
5185  return NULL; /* multiple VALUES (probably not possible) */
5186  result = rte;
5187  }
5188  else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
5189  continue; /* ignore rule entries */
5190  else
5191  return NULL; /* something else -> not simple VALUES */
5192  }
5193 
5194  /*
5195  * We don't need to check the targetlist in any great detail, because
5196  * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
5197  * appear inside auto-generated sub-queries with very restricted
5198  * structure. However, DefineView might have modified the tlist by
5199  * injecting new column aliases; so compare tlist resnames against the
5200  * RTE's names to detect that.
5201  */
5202  if (result)
5203  {
5204  ListCell *lcn;
5205 
5206  if (list_length(query->targetList) != list_length(result->eref->colnames))
5207  return NULL; /* this probably cannot happen */
5208  forboth(lc, query->targetList, lcn, result->eref->colnames)
5209  {
5210  TargetEntry *tle = (TargetEntry *) lfirst(lc);
5211  char *cname = strVal(lfirst(lcn));
5212 
5213  if (tle->resjunk)
5214  return NULL; /* this probably cannot happen */
5215  if (tle->resname == NULL || strcmp(tle->resname, cname) != 0)
5216  return NULL; /* column name has been changed */
5217  }
5218  }
5219 
5220  return result;
5221 }
5222 
5223 static void
5225  TupleDesc resultDesc)
5226 {
5227  StringInfo buf = context->buf;
5228  RangeTblEntry *values_rte;
5229  char *sep;
5230  ListCell *l;
5231 
5232  if (PRETTY_INDENT(context))
5233  {
5234  context->indentLevel += PRETTYINDENT_STD;
5235  appendStringInfoChar(buf, ' ');
5236  }
5237 
5238  /*
5239  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5240  * VALUES part. This reverses what transformValuesClause() did at parse
5241  * time.
5242  */
5243  values_rte = get_simple_values_rte(query);
5244  if (values_rte)
5245  {
5246  get_values_def(values_rte->values_lists, context);
5247  return;
5248  }
5249 
5250  /*
5251  * Build up the query string - first we say SELECT
5252  */
5253  appendStringInfoString(buf, "SELECT");
5254 
5255  /* Add the DISTINCT clause if given */
5256  if (query->distinctClause != NIL)
5257  {
5258  if (query->hasDistinctOn)
5259  {
5260  appendStringInfoString(buf, " DISTINCT ON (");
5261  sep = "";
5262  foreach(l, query->distinctClause)
5263  {
5264  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5265 
5266  appendStringInfoString(buf, sep);
5268  false, context);
5269  sep = ", ";
5270  }
5271  appendStringInfoChar(buf, ')');
5272  }
5273  else
5274  appendStringInfoString(buf, " DISTINCT");
5275  }
5276 
5277  /* Then we tell what to select (the targetlist) */
5278  get_target_list(query->targetList, context, resultDesc);
5279 
5280  /* Add the FROM clause if needed */
5281  get_from_clause(query, " FROM ", context);
5282 
5283  /* Add the WHERE clause if given */
5284  if (query->jointree->quals != NULL)
5285  {
5286  appendContextKeyword(context, " WHERE ",
5288  get_rule_expr(query->jointree->quals, context, false);
5289  }
5290 
5291  /* Add the GROUP BY clause if given */
5292  if (query->groupClause != NULL || query->groupingSets != NULL)
5293  {
5294  ParseExprKind save_exprkind;
5295 
5296  appendContextKeyword(context, " GROUP BY ",
5298 
5299  save_exprkind = context->special_exprkind;
5301 
5302  if (query->groupingSets == NIL)
5303  {
5304  sep = "";
5305  foreach(l, query->groupClause)
5306  {
5307  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5308 
5309  appendStringInfoString(buf, sep);
5311  false, context);
5312  sep = ", ";
5313  }
5314  }
5315  else
5316  {
5317  sep = "";
5318  foreach(l, query->groupingSets)
5319  {
5320  GroupingSet *grp = lfirst(l);
5321 
5322  appendStringInfoString(buf, sep);
5323  get_rule_groupingset(grp, query->targetList, true, context);
5324  sep = ", ";
5325  }
5326  }
5327 
5328  context->special_exprkind = save_exprkind;
5329  }
5330 
5331  /* Add the HAVING clause if given */
5332  if (query->havingQual != NULL)
5333  {
5334  appendContextKeyword(context, " HAVING ",
5336  get_rule_expr(query->havingQual, context, false);
5337  }
5338 
5339  /* Add the WINDOW clause if needed */
5340  if (query->windowClause != NIL)
5341  get_rule_windowclause(query, context);
5342 }
5343 
5344 /* ----------
5345  * get_target_list - Parse back a SELECT target list
5346  *
5347  * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
5348  * ----------
5349  */
5350 static void
5351 get_target_list(List *targetList, deparse_context *context,
5352  TupleDesc resultDesc)
5353 {
5354  StringInfo buf = context->buf;
5355  StringInfoData targetbuf;
5356  bool last_was_multiline = false;
5357  char *sep;
5358  int colno;
5359  ListCell *l;
5360 
5361  /* we use targetbuf to hold each TLE's text temporarily */
5362  initStringInfo(&targetbuf);
5363 
5364  sep = " ";
5365  colno = 0;
5366  foreach(l, targetList)
5367  {
5368  TargetEntry *tle = (TargetEntry *) lfirst(l);
5369  char *colname;
5370  char *attname;
5371 
5372  if (tle->resjunk)
5373  continue; /* ignore junk entries */
5374 
5375  appendStringInfoString(buf, sep);
5376  sep = ", ";
5377  colno++;
5378 
5379  /*
5380  * Put the new field text into targetbuf so we can decide after we've
5381  * got it whether or not it needs to go on a new line.
5382  */
5383  resetStringInfo(&targetbuf);
5384  context->buf = &targetbuf;
5385 
5386  /*
5387  * We special-case Var nodes rather than using get_rule_expr. This is
5388  * needed because get_rule_expr will display a whole-row Var as
5389  * "foo.*", which is the preferred notation in most contexts, but at
5390  * the top level of a SELECT list it's not right (the parser will
5391  * expand that notation into multiple columns, yielding behavior
5392  * different from a whole-row Var). We need to call get_variable
5393  * directly so that we can tell it to do the right thing, and so that
5394  * we can get the attribute name which is the default AS label.
5395  */
5396  if (tle->expr && (IsA(tle->expr, Var)))
5397  {
5398  attname = get_variable((Var *) tle->expr, 0, true, context);
5399  }
5400  else
5401  {
5402  get_rule_expr((Node *) tle->expr, context, true);
5403  /* We'll show the AS name unless it's this: */
5404  attname = "?column?";
5405  }
5406 
5407  /*
5408  * Figure out what the result column should be called. In the context
5409  * of a view, use the view's tuple descriptor (so as to pick up the
5410  * effects of any column RENAME that's been done on the view).
5411  * Otherwise, just use what we can find in the TLE.
5412  */
5413  if (resultDesc && colno <= resultDesc->natts)
5414  colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5415  else
5416  colname = tle->resname;
5417 
5418  /* Show AS unless the column's name is correct as-is */
5419  if (colname) /* resname could be NULL */
5420  {
5421  if (attname == NULL || strcmp(attname, colname) != 0)
5422  appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
5423  }
5424 
5425  /* Restore context's output buffer */
5426  context->buf = buf;
5427 
5428  /* Consider line-wrapping if enabled */
5429  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
5430  {
5431  int leading_nl_pos;
5432 
5433  /* Does the new field start with a new line? */
5434  if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
5435  leading_nl_pos = 0;
5436  else
5437  leading_nl_pos = -1;
5438 
5439  /* If so, we shouldn't add anything */
5440  if (leading_nl_pos >= 0)
5441  {
5442  /* instead, remove any trailing spaces currently in buf */
5444  }
5445  else
5446  {
5447  char *trailing_nl;
5448 
5449  /* Locate the start of the current line in the output buffer */
5450  trailing_nl = strrchr(buf->data, '\n');
5451  if (trailing_nl == NULL)
5452  trailing_nl = buf->data;
5453  else
5454  trailing_nl++;
5455 
5456  /*
5457  * Add a newline, plus some indentation, if the new field is
5458  * not the first and either the new field would cause an
5459  * overflow or the last field used more than one line.
5460  */
5461  if (colno > 1 &&
5462  ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
5463  last_was_multiline))
5464  appendContextKeyword(context, "", -PRETTYINDENT_STD,
5466  }
5467 
5468  /* Remember this field's multiline status for next iteration */
5469  last_was_multiline =
5470  (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
5471  }
5472 
5473  /* Add the new field */
5474  appendStringInfoString(buf, targetbuf.data);
5475  }
5476 
5477  /* clean up */
5478  pfree(targetbuf.data);
5479 }
5480 
5481 static void
5482 get_setop_query(Node *setOp, Query *query, deparse_context *context,
5483  TupleDesc resultDesc)
5484 {
5485  StringInfo buf = context->buf;
5486  bool need_paren;
5487 
5488  /* Guard against excessively long or deeply-nested queries */
5491 
5492  if (IsA(setOp, RangeTblRef))
5493  {
5494  RangeTblRef *rtr = (RangeTblRef *) setOp;
5495  RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
5496  Query *subquery = rte->subquery;
5497 
5498  Assert(subquery != NULL);
5499  Assert(subquery->setOperations == NULL);
5500  /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
5501  need_paren = (subquery->cteList ||
5502  subquery->sortClause ||
5503  subquery->rowMarks ||
5504  subquery->limitOffset ||
5505  subquery->limitCount);
5506  if (need_paren)
5507  appendStringInfoChar(buf, '(');
5508  get_query_def(subquery, buf, context->namespaces, resultDesc,
5509  context->prettyFlags, context->wrapColumn,
5510  context->indentLevel);
5511  if (need_paren)
5512  appendStringInfoChar(buf, ')');
5513  }
5514  else if (IsA(setOp, SetOperationStmt))
5515  {
5516  SetOperationStmt *op = (SetOperationStmt *) setOp;
5517  int subindent;
5518 
5519  /*
5520  * We force parens when nesting two SetOperationStmts, except when the
5521  * lefthand input is another setop of the same kind. Syntactically,
5522  * we could omit parens in rather more cases, but it seems best to use
5523  * parens to flag cases where the setop operator changes. If we use
5524  * parens, we also increase the indentation level for the child query.
5525  *
5526  * There are some cases in which parens are needed around a leaf query
5527  * too, but those are more easily handled at the next level down (see
5528  * code above).
5529  */
5530  if (IsA(op->larg, SetOperationStmt))
5531  {
5532  SetOperationStmt *lop = (SetOperationStmt *) op->larg;
5533 
5534  if (op->op == lop->op && op->all == lop->all)
5535  need_paren = false;
5536  else
5537  need_paren = true;
5538  }
5539  else
5540  need_paren = false;
5541 
5542  if (need_paren)
5543  {
5544  appendStringInfoChar(buf, '(');
5545  subindent = PRETTYINDENT_STD;
5546  appendContextKeyword(context, "", subindent, 0, 0);
5547  }
5548  else
5549  subindent = 0;
5550 
5551  get_setop_query(op->larg, query, context, resultDesc);
5552 
5553  if (need_paren)
5554  appendContextKeyword(context, ") ", -subindent, 0, 0);
5555  else if (PRETTY_INDENT(context))
5556  appendContextKeyword(context, "", -subindent, 0, 0);
5557  else
5558  appendStringInfoChar(buf, ' ');
5559 
5560  switch (op->op)
5561  {
5562  case SETOP_UNION:
5563  appendStringInfoString(buf, "UNION ");
5564  break;
5565  case SETOP_INTERSECT:
5566  appendStringInfoString(buf, "INTERSECT ");
5567  break;
5568  case SETOP_EXCEPT:
5569  appendStringInfoString(buf, "EXCEPT ");
5570  break;
5571  default:
5572  elog(ERROR, "unrecognized set op: %d",
5573  (int) op->op);
5574  }
5575  if (op->all)
5576  appendStringInfoString(buf, "ALL ");
5577 
5578  /* Always parenthesize if RHS is another setop */
5579  need_paren = IsA(op->rarg, SetOperationStmt);
5580 
5581  /*
5582  * The indentation code here is deliberately a bit different from that
5583  * for the lefthand input, because we want the line breaks in
5584  * different places.
5585  */
5586  if (need_paren)
5587  {
5588  appendStringInfoChar(buf, '(');
5589  subindent = PRETTYINDENT_STD;
5590  }
5591  else
5592  subindent = 0;
5593  appendContextKeyword(context, "", subindent, 0, 0);
5594 
5595  get_setop_query(op->rarg, query, context, resultDesc);
5596 
5597  if (PRETTY_INDENT(context))
5598  context->indentLevel -= subindent;
5599  if (need_paren)
5600  appendContextKeyword(context, ")", 0, 0, 0);
5601  }
5602  else
5603  {
5604  elog(ERROR, "unrecognized node type: %d",
5605  (int) nodeTag(setOp));
5606  }
5607 }
5608 
5609 /*
5610  * Display a sort/group clause.
5611  *
5612  * Also returns the expression tree, so caller need not find it again.
5613  */
5614 static Node *
5615 get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
5616  deparse_context *context)
5617 {
5618  StringInfo buf = context->buf;
5619  TargetEntry *tle;
5620  Node *expr;
5621 
5622  tle = get_sortgroupref_tle(ref, tlist);
5623  expr = (Node *) tle->expr;
5624 
5625  /*
5626  * Use column-number form if requested by caller. Otherwise, if
5627  * expression is a constant, force it to be dumped with an explicit cast
5628  * as decoration --- this is because a simple integer constant is
5629  * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
5630  * dump it without any decoration. If it's anything more complex than a
5631  * simple Var, then force extra parens around it, to ensure it can't be
5632  * misinterpreted as a cube() or rollup() construct.
5633  */
5634  if (force_colno)
5635  {
5636  Assert(!tle->resjunk);
5637  appendStringInfo(buf, "%d", tle->resno);
5638  }
5639  else if (expr && IsA(expr, Const))
5640  get_const_expr((Const *) expr, context, 1);
5641  else if (!expr || IsA(expr, Var))
5642  get_rule_expr(expr, context, true);
5643  else
5644  {
5645  /*
5646  * We must force parens for function-like expressions even if
5647  * PRETTY_PAREN is off, since those are the ones in danger of
5648  * misparsing. For other expressions we need to force them only if
5649  * PRETTY_PAREN is on, since otherwise the expression will output them
5650  * itself. (We can't skip the parens.)
5651  */
5652  bool need_paren = (PRETTY_PAREN(context)
5653  || IsA(expr, FuncExpr)
5654  ||IsA(expr, Aggref)
5655  ||IsA(expr, WindowFunc));
5656 
5657  if (need_paren)
5658  appendStringInfoChar(context->buf, '(');
5659  get_rule_expr(expr, context, true);
5660  if (need_paren)
5661  appendStringInfoChar(context->buf, ')');
5662  }
5663 
5664  return expr;
5665 }
5666 
5667 /*
5668  * Display a GroupingSet
5669  */
5670 static void
5672  bool omit_parens, deparse_context *context)
5673 {
5674  ListCell *l;
5675  StringInfo buf = context->buf;
5676  bool omit_child_parens = true;
5677  char *sep = "";
5678 
5679  switch (gset->kind)
5680  {
5681  case GROUPING_SET_EMPTY:
5682  appendStringInfoString(buf, "()");
5683  return;
5684 
5685  case GROUPING_SET_SIMPLE:
5686  {
5687  if (!omit_parens || list_length(gset->content) != 1)
5688  appendStringInfoChar(buf, '(');
5689 
5690  foreach(l, gset->content)
5691  {
5692  Index ref = lfirst_int(l);
5693 
5694  appendStringInfoString(buf, sep);
5695  get_rule_sortgroupclause(ref, targetlist,
5696  false, context);
5697  sep = ", ";
5698  }
5699 
5700  if (!omit_parens || list_length(gset->content) != 1)
5701  appendStringInfoChar(buf, ')');
5702  }
5703  return;
5704 
5705  case GROUPING_SET_ROLLUP:
5706  appendStringInfoString(buf, "ROLLUP(");
5707  break;
5708  case GROUPING_SET_CUBE:
5709  appendStringInfoString(buf, "CUBE(");
5710  break;