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