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-2024, 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/table.h"
26 #include "catalog/pg_aggregate.h"
27 #include "catalog/pg_am.h"
28 #include "catalog/pg_authid.h"
29 #include "catalog/pg_collation.h"
30 #include "catalog/pg_constraint.h"
31 #include "catalog/pg_depend.h"
32 #include "catalog/pg_language.h"
33 #include "catalog/pg_opclass.h"
34 #include "catalog/pg_operator.h"
36 #include "catalog/pg_proc.h"
38 #include "catalog/pg_trigger.h"
39 #include "catalog/pg_type.h"
40 #include "commands/defrem.h"
41 #include "commands/tablespace.h"
42 #include "common/keywords.h"
43 #include "executor/spi.h"
44 #include "funcapi.h"
45 #include "mb/pg_wchar.h"
46 #include "miscadmin.h"
47 #include "nodes/makefuncs.h"
48 #include "nodes/nodeFuncs.h"
49 #include "nodes/pathnodes.h"
50 #include "optimizer/optimizer.h"
51 #include "parser/parse_agg.h"
52 #include "parser/parse_func.h"
53 #include "parser/parse_node.h"
54 #include "parser/parse_oper.h"
55 #include "parser/parse_relation.h"
56 #include "parser/parser.h"
57 #include "parser/parsetree.h"
58 #include "rewrite/rewriteHandler.h"
59 #include "rewrite/rewriteManip.h"
60 #include "rewrite/rewriteSupport.h"
61 #include "utils/array.h"
62 #include "utils/builtins.h"
63 #include "utils/fmgroids.h"
64 #include "utils/guc.h"
65 #include "utils/hsearch.h"
66 #include "utils/lsyscache.h"
67 #include "utils/partcache.h"
68 #include "utils/rel.h"
69 #include "utils/ruleutils.h"
70 #include "utils/snapmgr.h"
71 #include "utils/syscache.h"
72 #include "utils/typcache.h"
73 #include "utils/varlena.h"
74 #include "utils/xml.h"
75 
76 /* ----------
77  * Pretty formatting constants
78  * ----------
79  */
80 
81 /* Indent counts */
82 #define PRETTYINDENT_STD 8
83 #define PRETTYINDENT_JOIN 4
84 #define PRETTYINDENT_VAR 4
85 
86 #define PRETTYINDENT_LIMIT 40 /* wrap limit */
87 
88 /* Pretty flags */
89 #define PRETTYFLAG_PAREN 0x0001
90 #define PRETTYFLAG_INDENT 0x0002
91 #define PRETTYFLAG_SCHEMA 0x0004
92 
93 /* Standard conversion of a "bool pretty" option to detailed flags */
94 #define GET_PRETTY_FLAGS(pretty) \
95  ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
96  : PRETTYFLAG_INDENT)
97 
98 /* Default line length for pretty-print wrapping: 0 means wrap always */
99 #define WRAP_COLUMN_DEFAULT 0
100 
101 /* macros to test if pretty action needed */
102 #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
103 #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
104 #define PRETTY_SCHEMA(context) ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
105 
106 
107 /* ----------
108  * Local data types
109  * ----------
110  */
111 
112 /* Context info needed for invoking a recursive querytree display routine */
113 typedef struct
114 {
115  StringInfo buf; /* output buffer to append to */
116  List *namespaces; /* List of deparse_namespace nodes */
117  List *windowClause; /* Current query level's WINDOW clause */
118  List *windowTList; /* targetlist for resolving WINDOW clause */
119  int prettyFlags; /* enabling of pretty-print functions */
120  int wrapColumn; /* max line length, or -1 for no limit */
121  int indentLevel; /* current indent level for pretty-print */
122  bool varprefix; /* true to print prefixes on Vars */
123  ParseExprKind special_exprkind; /* set only for exprkinds needing special
124  * handling */
125  Bitmapset *appendparents; /* if not null, map child Vars of these relids
126  * back to the parent rel */
128 
129 /*
130  * Each level of query context around a subtree needs a level of Var namespace.
131  * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
132  * the current context's namespaces list.
133  *
134  * rtable is the list of actual RTEs from the Query or PlannedStmt.
135  * rtable_names holds the alias name to be used for each RTE (either a C
136  * string, or NULL for nameless RTEs such as unnamed joins).
137  * rtable_columns holds the column alias names to be used for each RTE.
138  *
139  * subplans is a list of Plan trees for SubPlans and CTEs (it's only used
140  * in the PlannedStmt case).
141  * ctes is a list of CommonTableExpr nodes (only used in the Query case).
142  * appendrels, if not null (it's only used in the PlannedStmt case), is an
143  * array of AppendRelInfo nodes, indexed by child relid. We use that to map
144  * child-table Vars to their inheritance parents.
145  *
146  * In some cases we need to make names of merged JOIN USING columns unique
147  * across the whole query, not only per-RTE. If so, unique_using is true
148  * and using_names is a list of C strings representing names already assigned
149  * to USING columns.
150  *
151  * When deparsing plan trees, there is always just a single item in the
152  * deparse_namespace list (since a plan tree never contains Vars with
153  * varlevelsup > 0). We store the Plan node that is the immediate
154  * parent of the expression to be deparsed, as well as a list of that
155  * Plan's ancestors. In addition, we store its outer and inner subplan nodes,
156  * as well as their targetlists, and the index tlist if the current plan node
157  * might contain INDEX_VAR Vars. (These fields could be derived on-the-fly
158  * from the current Plan node, but it seems notationally clearer to set them
159  * up as separate fields.)
160  */
161 typedef struct
162 {
163  List *rtable; /* List of RangeTblEntry nodes */
164  List *rtable_names; /* Parallel list of names for RTEs */
165  List *rtable_columns; /* Parallel list of deparse_columns structs */
166  List *subplans; /* List of Plan trees for SubPlans */
167  List *ctes; /* List of CommonTableExpr nodes */
168  AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */
169  /* Workspace for column alias assignment: */
170  bool unique_using; /* Are we making USING names globally unique */
171  List *using_names; /* List of assigned names for USING columns */
172  /* Remaining fields are used only when deparsing a Plan tree: */
173  Plan *plan; /* immediate parent of current expression */
174  List *ancestors; /* ancestors of plan */
175  Plan *outer_plan; /* outer subnode, or NULL if none */
176  Plan *inner_plan; /* inner subnode, or NULL if none */
177  List *outer_tlist; /* referent for OUTER_VAR Vars */
178  List *inner_tlist; /* referent for INNER_VAR Vars */
179  List *index_tlist; /* referent for INDEX_VAR Vars */
180  /* Special namespace representing a function signature: */
181  char *funcname;
182  int numargs;
183  char **argnames;
185 
186 /*
187  * Per-relation data about column alias names.
188  *
189  * Selecting aliases is unreasonably complicated because of the need to dump
190  * rules/views whose underlying tables may have had columns added, deleted, or
191  * renamed since the query was parsed. We must nonetheless print the rule/view
192  * in a form that can be reloaded and will produce the same results as before.
193  *
194  * For each RTE used in the query, we must assign column aliases that are
195  * unique within that RTE. SQL does not require this of the original query,
196  * but due to factors such as *-expansion we need to be able to uniquely
197  * reference every column in a decompiled query. As long as we qualify all
198  * column references, per-RTE uniqueness is sufficient for that.
199  *
200  * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
201  * since they just inherit column names from their input RTEs, and we can't
202  * rename the columns at the join level. Most of the time this isn't an issue
203  * because we don't need to reference the join's output columns as such; we
204  * can reference the input columns instead. That approach can fail for merged
205  * JOIN USING columns, however, so when we have one of those in an unnamed
206  * join, we have to make that column's alias globally unique across the whole
207  * query to ensure it can be referenced unambiguously.
208  *
209  * Another problem is that a JOIN USING clause requires the columns to be
210  * merged to have the same aliases in both input RTEs, and that no other
211  * columns in those RTEs or their children conflict with the USING names.
212  * To handle that, we do USING-column alias assignment in a recursive
213  * traversal of the query's jointree. When descending through a JOIN with
214  * USING, we preassign the USING column names to the child columns, overriding
215  * other rules for column alias assignment. We also mark each RTE with a list
216  * of all USING column names selected for joins containing that RTE, so that
217  * when we assign other columns' aliases later, we can avoid conflicts.
218  *
219  * Another problem is that if a JOIN's input tables have had columns added or
220  * deleted since the query was parsed, we must generate a column alias list
221  * for the join that matches the current set of input columns --- otherwise, a
222  * change in the number of columns in the left input would throw off matching
223  * of aliases to columns of the right input. Thus, positions in the printable
224  * column alias list are not necessarily one-for-one with varattnos of the
225  * JOIN, so we need a separate new_colnames[] array for printing purposes.
226  */
227 typedef struct
228 {
229  /*
230  * colnames is an array containing column aliases to use for columns that
231  * existed when the query was parsed. Dropped columns have NULL entries.
232  * This array can be directly indexed by varattno to get a Var's name.
233  *
234  * Non-NULL entries are guaranteed unique within the RTE, *except* when
235  * this is for an unnamed JOIN RTE. In that case we merely copy up names
236  * from the two input RTEs.
237  *
238  * During the recursive descent in set_using_names(), forcible assignment
239  * of a child RTE's column name is represented by pre-setting that element
240  * of the child's colnames array. So at that stage, NULL entries in this
241  * array just mean that no name has been preassigned, not necessarily that
242  * the column is dropped.
243  */
244  int num_cols; /* length of colnames[] array */
245  char **colnames; /* array of C strings and NULLs */
246 
247  /*
248  * new_colnames is an array containing column aliases to use for columns
249  * that would exist if the query was re-parsed against the current
250  * definitions of its base tables. This is what to print as the column
251  * alias list for the RTE. This array does not include dropped columns,
252  * but it will include columns added since original parsing. Indexes in
253  * it therefore have little to do with current varattno values. As above,
254  * entries are unique unless this is for an unnamed JOIN RTE. (In such an
255  * RTE, we never actually print this array, but we must compute it anyway
256  * for possible use in computing column names of upper joins.) The
257  * parallel array is_new_col marks which of these columns are new since
258  * original parsing. Entries with is_new_col false must match the
259  * non-NULL colnames entries one-for-one.
260  */
261  int num_new_cols; /* length of new_colnames[] array */
262  char **new_colnames; /* array of C strings */
263  bool *is_new_col; /* array of bool flags */
264 
265  /* This flag tells whether we should actually print a column alias list */
267 
268  /* This list has all names used as USING names in joins above this RTE */
269  List *parentUsing; /* names assigned to parent merged columns */
270 
271  /*
272  * If this struct is for a JOIN RTE, we fill these fields during the
273  * set_using_names() pass to describe its relationship to its child RTEs.
274  *
275  * leftattnos and rightattnos are arrays with one entry per existing
276  * output column of the join (hence, indexable by join varattno). For a
277  * simple reference to a column of the left child, leftattnos[i] is the
278  * child RTE's attno and rightattnos[i] is zero; and conversely for a
279  * column of the right child. But for merged columns produced by JOIN
280  * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
281  * Note that a simple reference might be to a child RTE column that's been
282  * dropped; but that's OK since the column could not be used in the query.
283  *
284  * If it's a JOIN USING, usingNames holds the alias names selected for the
285  * merged columns (these might be different from the original USING list,
286  * if we had to modify names to achieve uniqueness).
287  */
288  int leftrti; /* rangetable index of left child */
289  int rightrti; /* rangetable index of right child */
290  int *leftattnos; /* left-child varattnos of join cols, or 0 */
291  int *rightattnos; /* right-child varattnos of join cols, or 0 */
292  List *usingNames; /* names assigned to merged columns */
294 
295 /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
296 #define deparse_columns_fetch(rangetable_index, dpns) \
297  ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
298 
299 /*
300  * Entry in set_rtable_names' hash table
301  */
302 typedef struct
303 {
304  char name[NAMEDATALEN]; /* Hash key --- must be first */
305  int counter; /* Largest addition used so far for name */
306 } NameHashEntry;
307 
308 /* Callback signature for resolve_special_varno() */
309 typedef void (*rsv_callback) (Node *node, deparse_context *context,
310  void *callback_arg);
311 
312 
313 /* ----------
314  * Global data
315  * ----------
316  */
318 static const char *const query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
320 static const char *const query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
321 
322 /* GUC parameters */
324 
325 
326 /* ----------
327  * Local functions
328  *
329  * Most of these functions used to use fixed-size buffers to build their
330  * results. Now, they take an (already initialized) StringInfo object
331  * as a parameter, and append their text output to its contents.
332  * ----------
333  */
334 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
335  bool forceprefix, bool showimplicit,
336  int prettyFlags, int startIndent);
337 static char *pg_get_viewdef_worker(Oid viewoid,
338  int prettyFlags, int wrapColumn);
339 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
340 static int decompile_column_index_array(Datum column_index_array, Oid relId,
341  bool withPeriod, StringInfo buf);
342 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
343 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
344  const Oid *excludeOps,
345  bool attrsOnly, bool keysOnly,
346  bool showTblSpc, bool inherits,
347  int prettyFlags, bool missing_ok);
348 static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
349  bool missing_ok);
350 static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
351  bool attrsOnly, bool missing_ok);
352 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
353  int prettyFlags, bool missing_ok);
354 static text *pg_get_expr_worker(text *expr, Oid relid, int prettyFlags);
356  bool print_table_args, bool print_defaults);
357 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
358 static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
359 static void print_function_sqlbody(StringInfo buf, HeapTuple proctup);
360 static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
361  Bitmapset *rels_used);
362 static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
363  List *parent_namespaces);
364 static void set_simple_column_names(deparse_namespace *dpns);
365 static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
366 static void set_using_names(deparse_namespace *dpns, Node *jtnode,
367  List *parentUsing);
369  RangeTblEntry *rte,
370  deparse_columns *colinfo);
372  deparse_columns *colinfo);
373 static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
374  deparse_columns *colinfo);
375 static char *make_colname_unique(char *colname, deparse_namespace *dpns,
376  deparse_columns *colinfo);
377 static void expand_colnames_array_to(deparse_columns *colinfo, int n);
378 static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
379  deparse_columns *colinfo);
380 static char *get_rtable_name(int rtindex, deparse_context *context);
381 static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
383  WorkTableScan *wtscan);
384 static void push_child_plan(deparse_namespace *dpns, Plan *plan,
385  deparse_namespace *save_dpns);
386 static void pop_child_plan(deparse_namespace *dpns,
387  deparse_namespace *save_dpns);
388 static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
389  deparse_namespace *save_dpns);
390 static void pop_ancestor_plan(deparse_namespace *dpns,
391  deparse_namespace *save_dpns);
392 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
393  int prettyFlags);
394 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
395  int prettyFlags, int wrapColumn);
396 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
397  TupleDesc resultDesc, bool colNamesVisible,
398  int prettyFlags, int wrapColumn, int startIndent);
399 static void get_values_def(List *values_lists, deparse_context *context);
400 static void get_with_clause(Query *query, deparse_context *context);
402  TupleDesc resultDesc, bool colNamesVisible);
404  bool colNamesVisible);
406  bool colNamesVisible);
407 static void get_update_query_targetlist_def(Query *query, List *targetList,
409  RangeTblEntry *rte);
411  bool colNamesVisible);
412 static void get_merge_query_def(Query *query, deparse_context *context,
413  bool colNamesVisible);
414 static void get_utility_query_def(Query *query, deparse_context *context);
416  TupleDesc resultDesc, bool colNamesVisible);
417 static void get_target_list(List *targetList, deparse_context *context,
418  TupleDesc resultDesc, bool colNamesVisible);
419 static void get_setop_query(Node *setOp, Query *query,
421  TupleDesc resultDesc, bool colNamesVisible);
422 static Node *get_rule_sortgroupclause(Index ref, List *tlist,
423  bool force_colno,
425 static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
426  bool omit_parens, deparse_context *context);
427 static void get_rule_orderby(List *orderList, List *targetList,
428  bool force_colno, deparse_context *context);
429 static void get_rule_windowclause(Query *query, deparse_context *context);
430 static void get_rule_windowspec(WindowClause *wc, List *targetList,
432 static char *get_variable(Var *var, int levelsup, bool istoplevel,
435  void *callback_arg);
437  rsv_callback callback, void *callback_arg);
439  deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
441  int *column_p);
443  int *column_p);
444 static void get_parameter(Param *param, deparse_context *context);
445 static const char *get_simple_binary_op_name(OpExpr *expr);
446 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
447 static void appendContextKeyword(deparse_context *context, const char *str,
448  int indentBefore, int indentAfter, int indentPlus);
450 static void get_rule_expr(Node *node, deparse_context *context,
451  bool showimplicit);
453  bool showimplicit);
455  bool showimplicit);
457  bool showimplicit);
458 static bool looks_like_function(Node *node);
459 static void get_oper_expr(OpExpr *expr, deparse_context *context);
460 static void get_func_expr(FuncExpr *expr, deparse_context *context,
461  bool showimplicit);
462 static void get_agg_expr(Aggref *aggref, deparse_context *context,
463  Aggref *original_aggref);
464 static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
465  Aggref *original_aggref, const char *funcname,
466  const char *options, bool is_json_objectagg);
468  void *callback_arg);
471  const char *funcname, const char *options,
472  bool is_json_objectagg);
475  Oid resulttype, int32 resulttypmod,
476  Node *parentNode);
477 static void get_const_expr(Const *constval, deparse_context *context,
478  int showtype);
479 static void get_const_collation(Const *constval, deparse_context *context);
481 static void get_json_returning(JsonReturning *returning, StringInfo buf,
482  bool json_format_by_default);
483 static void get_json_constructor(JsonConstructorExpr *ctor,
484  deparse_context *context, bool showimplicit);
486  StringInfo buf);
489  const char *funcname,
490  bool is_json_objectagg);
491 static void simple_quote_literal(StringInfo buf, const char *val);
492 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
494  bool showimplicit);
495 static void get_from_clause(Query *query, const char *prefix,
497 static void get_from_clause_item(Node *jtnode, Query *query,
499 static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
501 static void get_column_alias_list(deparse_columns *colinfo,
503 static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
504  deparse_columns *colinfo,
506 static void get_tablesample_def(TableSampleClause *tablesample,
508 static void get_opclass_name(Oid opclass, Oid actual_datatype,
509  StringInfo buf);
512 static char *get_relation_name(Oid relid);
513 static char *generate_relation_name(Oid relid, List *namespaces);
514 static char *generate_qualified_relation_name(Oid relid);
515 static char *generate_function_name(Oid funcid, int nargs,
516  List *argnames, Oid *argtypes,
517  bool has_variadic, bool *use_variadic_p,
518  ParseExprKind special_exprkind);
519 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
520 static void add_cast_to(StringInfo buf, Oid typid);
521 static char *generate_qualified_type_name(Oid typid);
522 static text *string_to_text(char *str);
523 static char *flatten_reloptions(Oid relid);
524 static void get_reloptions(StringInfo buf, Datum reloptions);
525 static void get_json_path_spec(Node *path_spec, deparse_context *context,
526  bool showimplicit);
527 static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan,
529  bool showimplicit);
532  bool showimplicit,
533  bool needcomma);
534 
535 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
536 
537 
538 /* ----------
539  * pg_get_ruledef - Do it all and return a text
540  * that could be used as a statement
541  * to recreate the rule
542  * ----------
543  */
544 Datum
546 {
547  Oid ruleoid = PG_GETARG_OID(0);
548  int prettyFlags;
549  char *res;
550 
551  prettyFlags = PRETTYFLAG_INDENT;
552 
553  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
554 
555  if (res == NULL)
556  PG_RETURN_NULL();
557 
559 }
560 
561 
562 Datum
564 {
565  Oid ruleoid = PG_GETARG_OID(0);
566  bool pretty = PG_GETARG_BOOL(1);
567  int prettyFlags;
568  char *res;
569 
570  prettyFlags = GET_PRETTY_FLAGS(pretty);
571 
572  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
573 
574  if (res == NULL)
575  PG_RETURN_NULL();
576 
578 }
579 
580 
581 static char *
582 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
583 {
584  Datum args[1];
585  char nulls[1];
586  int spirc;
587  HeapTuple ruletup;
588  TupleDesc rulettc;
590 
591  /*
592  * Do this first so that string is alloc'd in outer context not SPI's.
593  */
595 
596  /*
597  * Connect to SPI manager
598  */
599  if (SPI_connect() != SPI_OK_CONNECT)
600  elog(ERROR, "SPI_connect failed");
601 
602  /*
603  * On the first call prepare the plan to lookup pg_rewrite. We read
604  * pg_rewrite over the SPI manager instead of using the syscache to be
605  * checked for read access on pg_rewrite.
606  */
607  if (plan_getrulebyoid == NULL)
608  {
609  Oid argtypes[1];
611 
612  argtypes[0] = OIDOID;
613  plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
614  if (plan == NULL)
615  elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
618  }
619 
620  /*
621  * Get the pg_rewrite tuple for this rule
622  */
623  args[0] = ObjectIdGetDatum(ruleoid);
624  nulls[0] = ' ';
625  spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
626  if (spirc != SPI_OK_SELECT)
627  elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
628  if (SPI_processed != 1)
629  {
630  /*
631  * There is no tuple data available here, just keep the output buffer
632  * empty.
633  */
634  }
635  else
636  {
637  /*
638  * Get the rule's definition and put it into executor's memory
639  */
640  ruletup = SPI_tuptable->vals[0];
641  rulettc = SPI_tuptable->tupdesc;
642  make_ruledef(&buf, ruletup, rulettc, prettyFlags);
643  }
644 
645  /*
646  * Disconnect from SPI manager
647  */
648  if (SPI_finish() != SPI_OK_FINISH)
649  elog(ERROR, "SPI_finish failed");
650 
651  if (buf.len == 0)
652  return NULL;
653 
654  return buf.data;
655 }
656 
657 
658 /* ----------
659  * pg_get_viewdef - Mainly the same thing, but we
660  * only return the SELECT part of a view
661  * ----------
662  */
663 Datum
665 {
666  /* By OID */
667  Oid viewoid = PG_GETARG_OID(0);
668  int prettyFlags;
669  char *res;
670 
671  prettyFlags = PRETTYFLAG_INDENT;
672 
673  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
674 
675  if (res == NULL)
676  PG_RETURN_NULL();
677 
679 }
680 
681 
682 Datum
684 {
685  /* By OID */
686  Oid viewoid = PG_GETARG_OID(0);
687  bool pretty = PG_GETARG_BOOL(1);
688  int prettyFlags;
689  char *res;
690 
691  prettyFlags = GET_PRETTY_FLAGS(pretty);
692 
693  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
694 
695  if (res == NULL)
696  PG_RETURN_NULL();
697 
699 }
700 
701 Datum
703 {
704  /* By OID */
705  Oid viewoid = PG_GETARG_OID(0);
706  int wrap = PG_GETARG_INT32(1);
707  int prettyFlags;
708  char *res;
709 
710  /* calling this implies we want pretty printing */
711  prettyFlags = GET_PRETTY_FLAGS(true);
712 
713  res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
714 
715  if (res == NULL)
716  PG_RETURN_NULL();
717 
719 }
720 
721 Datum
723 {
724  /* By qualified name */
725  text *viewname = PG_GETARG_TEXT_PP(0);
726  int prettyFlags;
727  RangeVar *viewrel;
728  Oid viewoid;
729  char *res;
730 
731  prettyFlags = PRETTYFLAG_INDENT;
732 
733  /* Look up view name. Can't lock it - we might not have privileges. */
735  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
736 
737  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
738 
739  if (res == NULL)
740  PG_RETURN_NULL();
741 
743 }
744 
745 
746 Datum
748 {
749  /* By qualified name */
750  text *viewname = PG_GETARG_TEXT_PP(0);
751  bool pretty = PG_GETARG_BOOL(1);
752  int prettyFlags;
753  RangeVar *viewrel;
754  Oid viewoid;
755  char *res;
756 
757  prettyFlags = GET_PRETTY_FLAGS(pretty);
758 
759  /* Look up view name. Can't lock it - we might not have privileges. */
761  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
762 
763  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
764 
765  if (res == NULL)
766  PG_RETURN_NULL();
767 
769 }
770 
771 /*
772  * Common code for by-OID and by-name variants of pg_get_viewdef
773  */
774 static char *
775 pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
776 {
777  Datum args[2];
778  char nulls[2];
779  int spirc;
780  HeapTuple ruletup;
781  TupleDesc rulettc;
783 
784  /*
785  * Do this first so that string is alloc'd in outer context not SPI's.
786  */
788 
789  /*
790  * Connect to SPI manager
791  */
792  if (SPI_connect() != SPI_OK_CONNECT)
793  elog(ERROR, "SPI_connect failed");
794 
795  /*
796  * On the first call prepare the plan to lookup pg_rewrite. We read
797  * pg_rewrite over the SPI manager instead of using the syscache to be
798  * checked for read access on pg_rewrite.
799  */
800  if (plan_getviewrule == NULL)
801  {
802  Oid argtypes[2];
804 
805  argtypes[0] = OIDOID;
806  argtypes[1] = NAMEOID;
807  plan = SPI_prepare(query_getviewrule, 2, argtypes);
808  if (plan == NULL)
809  elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
812  }
813 
814  /*
815  * Get the pg_rewrite tuple for the view's SELECT rule
816  */
817  args[0] = ObjectIdGetDatum(viewoid);
819  nulls[0] = ' ';
820  nulls[1] = ' ';
821  spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
822  if (spirc != SPI_OK_SELECT)
823  elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
824  if (SPI_processed != 1)
825  {
826  /*
827  * There is no tuple data available here, just keep the output buffer
828  * empty.
829  */
830  }
831  else
832  {
833  /*
834  * Get the rule's definition and put it into executor's memory
835  */
836  ruletup = SPI_tuptable->vals[0];
837  rulettc = SPI_tuptable->tupdesc;
838  make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
839  }
840 
841  /*
842  * Disconnect from SPI manager
843  */
844  if (SPI_finish() != SPI_OK_FINISH)
845  elog(ERROR, "SPI_finish failed");
846 
847  if (buf.len == 0)
848  return NULL;
849 
850  return buf.data;
851 }
852 
853 /* ----------
854  * pg_get_triggerdef - Get the definition of a trigger
855  * ----------
856  */
857 Datum
859 {
860  Oid trigid = PG_GETARG_OID(0);
861  char *res;
862 
863  res = pg_get_triggerdef_worker(trigid, false);
864 
865  if (res == NULL)
866  PG_RETURN_NULL();
867 
869 }
870 
871 Datum
873 {
874  Oid trigid = PG_GETARG_OID(0);
875  bool pretty = PG_GETARG_BOOL(1);
876  char *res;
877 
878  res = pg_get_triggerdef_worker(trigid, pretty);
879 
880  if (res == NULL)
881  PG_RETURN_NULL();
882 
884 }
885 
886 static char *
887 pg_get_triggerdef_worker(Oid trigid, bool pretty)
888 {
889  HeapTuple ht_trig;
890  Form_pg_trigger trigrec;
892  Relation tgrel;
893  ScanKeyData skey[1];
894  SysScanDesc tgscan;
895  int findx = 0;
896  char *tgname;
897  char *tgoldtable;
898  char *tgnewtable;
899  Datum value;
900  bool isnull;
901 
902  /*
903  * Fetch the pg_trigger tuple by the Oid of the trigger
904  */
905  tgrel = table_open(TriggerRelationId, AccessShareLock);
906 
907  ScanKeyInit(&skey[0],
908  Anum_pg_trigger_oid,
909  BTEqualStrategyNumber, F_OIDEQ,
910  ObjectIdGetDatum(trigid));
911 
912  tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
913  NULL, 1, skey);
914 
915  ht_trig = systable_getnext(tgscan);
916 
917  if (!HeapTupleIsValid(ht_trig))
918  {
919  systable_endscan(tgscan);
921  return NULL;
922  }
923 
924  trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
925 
926  /*
927  * Start the trigger definition. Note that the trigger's name should never
928  * be schema-qualified, but the trigger rel's name may be.
929  */
931 
932  tgname = NameStr(trigrec->tgname);
933  appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
934  OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
935  quote_identifier(tgname));
936 
937  if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
938  appendStringInfoString(&buf, "BEFORE");
939  else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
940  appendStringInfoString(&buf, "AFTER");
941  else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
942  appendStringInfoString(&buf, "INSTEAD OF");
943  else
944  elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
945 
946  if (TRIGGER_FOR_INSERT(trigrec->tgtype))
947  {
948  appendStringInfoString(&buf, " INSERT");
949  findx++;
950  }
951  if (TRIGGER_FOR_DELETE(trigrec->tgtype))
952  {
953  if (findx > 0)
954  appendStringInfoString(&buf, " OR DELETE");
955  else
956  appendStringInfoString(&buf, " DELETE");
957  findx++;
958  }
959  if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
960  {
961  if (findx > 0)
962  appendStringInfoString(&buf, " OR UPDATE");
963  else
964  appendStringInfoString(&buf, " UPDATE");
965  findx++;
966  /* tgattr is first var-width field, so OK to access directly */
967  if (trigrec->tgattr.dim1 > 0)
968  {
969  int i;
970 
971  appendStringInfoString(&buf, " OF ");
972  for (i = 0; i < trigrec->tgattr.dim1; i++)
973  {
974  char *attname;
975 
976  if (i > 0)
977  appendStringInfoString(&buf, ", ");
978  attname = get_attname(trigrec->tgrelid,
979  trigrec->tgattr.values[i], false);
981  }
982  }
983  }
984  if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
985  {
986  if (findx > 0)
987  appendStringInfoString(&buf, " OR TRUNCATE");
988  else
989  appendStringInfoString(&buf, " TRUNCATE");
990  findx++;
991  }
992 
993  /*
994  * In non-pretty mode, always schema-qualify the target table name for
995  * safety. In pretty mode, schema-qualify only if not visible.
996  */
997  appendStringInfo(&buf, " ON %s ",
998  pretty ?
999  generate_relation_name(trigrec->tgrelid, NIL) :
1000  generate_qualified_relation_name(trigrec->tgrelid));
1001 
1002  if (OidIsValid(trigrec->tgconstraint))
1003  {
1004  if (OidIsValid(trigrec->tgconstrrelid))
1005  appendStringInfo(&buf, "FROM %s ",
1006  generate_relation_name(trigrec->tgconstrrelid, NIL));
1007  if (!trigrec->tgdeferrable)
1008  appendStringInfoString(&buf, "NOT ");
1009  appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
1010  if (trigrec->tginitdeferred)
1011  appendStringInfoString(&buf, "DEFERRED ");
1012  else
1013  appendStringInfoString(&buf, "IMMEDIATE ");
1014  }
1015 
1016  value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
1017  tgrel->rd_att, &isnull);
1018  if (!isnull)
1019  tgoldtable = NameStr(*DatumGetName(value));
1020  else
1021  tgoldtable = NULL;
1022  value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
1023  tgrel->rd_att, &isnull);
1024  if (!isnull)
1025  tgnewtable = NameStr(*DatumGetName(value));
1026  else
1027  tgnewtable = NULL;
1028  if (tgoldtable != NULL || tgnewtable != NULL)
1029  {
1030  appendStringInfoString(&buf, "REFERENCING ");
1031  if (tgoldtable != NULL)
1032  appendStringInfo(&buf, "OLD TABLE AS %s ",
1033  quote_identifier(tgoldtable));
1034  if (tgnewtable != NULL)
1035  appendStringInfo(&buf, "NEW TABLE AS %s ",
1036  quote_identifier(tgnewtable));
1037  }
1038 
1039  if (TRIGGER_FOR_ROW(trigrec->tgtype))
1040  appendStringInfoString(&buf, "FOR EACH ROW ");
1041  else
1042  appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1043 
1044  /* If the trigger has a WHEN qualification, add that */
1045  value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
1046  tgrel->rd_att, &isnull);
1047  if (!isnull)
1048  {
1049  Node *qual;
1050  char relkind;
1052  deparse_namespace dpns;
1053  RangeTblEntry *oldrte;
1054  RangeTblEntry *newrte;
1055 
1056  appendStringInfoString(&buf, "WHEN (");
1057 
1059 
1060  relkind = get_rel_relkind(trigrec->tgrelid);
1061 
1062  /* Build minimal OLD and NEW RTEs for the rel */
1063  oldrte = makeNode(RangeTblEntry);
1064  oldrte->rtekind = RTE_RELATION;
1065  oldrte->relid = trigrec->tgrelid;
1066  oldrte->relkind = relkind;
1067  oldrte->rellockmode = AccessShareLock;
1068  oldrte->alias = makeAlias("old", NIL);
1069  oldrte->eref = oldrte->alias;
1070  oldrte->lateral = false;
1071  oldrte->inh = false;
1072  oldrte->inFromCl = true;
1073 
1074  newrte = makeNode(RangeTblEntry);
1075  newrte->rtekind = RTE_RELATION;
1076  newrte->relid = trigrec->tgrelid;
1077  newrte->relkind = relkind;
1078  newrte->rellockmode = AccessShareLock;
1079  newrte->alias = makeAlias("new", NIL);
1080  newrte->eref = newrte->alias;
1081  newrte->lateral = false;
1082  newrte->inh = false;
1083  newrte->inFromCl = true;
1084 
1085  /* Build two-element rtable */
1086  memset(&dpns, 0, sizeof(dpns));
1087  dpns.rtable = list_make2(oldrte, newrte);
1088  dpns.subplans = NIL;
1089  dpns.ctes = NIL;
1090  dpns.appendrels = NULL;
1091  set_rtable_names(&dpns, NIL, NULL);
1092  set_simple_column_names(&dpns);
1093 
1094  /* Set up context with one-deep namespace stack */
1095  context.buf = &buf;
1096  context.namespaces = list_make1(&dpns);
1097  context.windowClause = NIL;
1098  context.windowTList = NIL;
1099  context.varprefix = true;
1100  context.prettyFlags = GET_PRETTY_FLAGS(pretty);
1101  context.wrapColumn = WRAP_COLUMN_DEFAULT;
1102  context.indentLevel = PRETTYINDENT_STD;
1103  context.special_exprkind = EXPR_KIND_NONE;
1104  context.appendparents = NULL;
1105 
1106  get_rule_expr(qual, &context, false);
1107 
1108  appendStringInfoString(&buf, ") ");
1109  }
1110 
1111  appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1112  generate_function_name(trigrec->tgfoid, 0,
1113  NIL, NULL,
1114  false, NULL, EXPR_KIND_NONE));
1115 
1116  if (trigrec->tgnargs > 0)
1117  {
1118  char *p;
1119  int i;
1120 
1121  value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1122  tgrel->rd_att, &isnull);
1123  if (isnull)
1124  elog(ERROR, "tgargs is null for trigger %u", trigid);
1125  p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1126  for (i = 0; i < trigrec->tgnargs; i++)
1127  {
1128  if (i > 0)
1129  appendStringInfoString(&buf, ", ");
1131  /* advance p to next string embedded in tgargs */
1132  while (*p)
1133  p++;
1134  p++;
1135  }
1136  }
1137 
1138  /* We deliberately do not put semi-colon at end */
1139  appendStringInfoChar(&buf, ')');
1140 
1141  /* Clean up */
1142  systable_endscan(tgscan);
1143 
1144  table_close(tgrel, AccessShareLock);
1145 
1146  return buf.data;
1147 }
1148 
1149 /* ----------
1150  * pg_get_indexdef - Get the definition of an index
1151  *
1152  * In the extended version, there is a colno argument as well as pretty bool.
1153  * if colno == 0, we want a complete index definition.
1154  * if colno > 0, we only want the Nth index key's variable or expression.
1155  *
1156  * Note that the SQL-function versions of this omit any info about the
1157  * index tablespace; this is intentional because pg_dump wants it that way.
1158  * However pg_get_indexdef_string() includes the index tablespace.
1159  * ----------
1160  */
1161 Datum
1163 {
1164  Oid indexrelid = PG_GETARG_OID(0);
1165  int prettyFlags;
1166  char *res;
1167 
1168  prettyFlags = PRETTYFLAG_INDENT;
1169 
1170  res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1171  false, false,
1172  false, false,
1173  prettyFlags, true);
1174 
1175  if (res == NULL)
1176  PG_RETURN_NULL();
1177 
1179 }
1180 
1181 Datum
1183 {
1184  Oid indexrelid = PG_GETARG_OID(0);
1185  int32 colno = PG_GETARG_INT32(1);
1186  bool pretty = PG_GETARG_BOOL(2);
1187  int prettyFlags;
1188  char *res;
1189 
1190  prettyFlags = GET_PRETTY_FLAGS(pretty);
1191 
1192  res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1193  colno != 0, false,
1194  false, false,
1195  prettyFlags, true);
1196 
1197  if (res == NULL)
1198  PG_RETURN_NULL();
1199 
1201 }
1202 
1203 /*
1204  * Internal version for use by ALTER TABLE.
1205  * Includes a tablespace clause in the result.
1206  * Returns a palloc'd C string; no pretty-printing.
1207  */
1208 char *
1210 {
1211  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1212  false, false,
1213  true, true,
1214  0, false);
1215 }
1216 
1217 /* Internal version that just reports the key-column definitions */
1218 char *
1219 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1220 {
1221  int prettyFlags;
1222 
1223  prettyFlags = GET_PRETTY_FLAGS(pretty);
1224 
1225  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1226  true, true,
1227  false, false,
1228  prettyFlags, false);
1229 }
1230 
1231 /* Internal version, extensible with flags to control its behavior */
1232 char *
1234 {
1235  bool pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1236  bool keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1237  int prettyFlags;
1238 
1239  prettyFlags = GET_PRETTY_FLAGS(pretty);
1240 
1241  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1242  true, keys_only,
1243  false, false,
1244  prettyFlags, false);
1245 }
1246 
1247 /*
1248  * Internal workhorse to decompile an index definition.
1249  *
1250  * This is now used for exclusion constraints as well: if excludeOps is not
1251  * NULL then it points to an array of exclusion operator OIDs.
1252  */
1253 static char *
1254 pg_get_indexdef_worker(Oid indexrelid, int colno,
1255  const Oid *excludeOps,
1256  bool attrsOnly, bool keysOnly,
1257  bool showTblSpc, bool inherits,
1258  int prettyFlags, bool missing_ok)
1259 {
1260  /* might want a separate isConstraint parameter later */
1261  bool isConstraint = (excludeOps != NULL);
1262  HeapTuple ht_idx;
1263  HeapTuple ht_idxrel;
1264  HeapTuple ht_am;
1265  Form_pg_index idxrec;
1266  Form_pg_class idxrelrec;
1267  Form_pg_am amrec;
1268  IndexAmRoutine *amroutine;
1269  List *indexprs;
1270  ListCell *indexpr_item;
1271  List *context;
1272  Oid indrelid;
1273  int keyno;
1274  Datum indcollDatum;
1275  Datum indclassDatum;
1276  Datum indoptionDatum;
1277  oidvector *indcollation;
1278  oidvector *indclass;
1279  int2vector *indoption;
1281  char *str;
1282  char *sep;
1283 
1284  /*
1285  * Fetch the pg_index tuple by the Oid of the index
1286  */
1287  ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1288  if (!HeapTupleIsValid(ht_idx))
1289  {
1290  if (missing_ok)
1291  return NULL;
1292  elog(ERROR, "cache lookup failed for index %u", indexrelid);
1293  }
1294  idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1295 
1296  indrelid = idxrec->indrelid;
1297  Assert(indexrelid == idxrec->indexrelid);
1298 
1299  /* Must get indcollation, indclass, and indoption the hard way */
1300  indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1301  Anum_pg_index_indcollation);
1302  indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1303 
1304  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1305  Anum_pg_index_indclass);
1306  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1307 
1308  indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1309  Anum_pg_index_indoption);
1310  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1311 
1312  /*
1313  * Fetch the pg_class tuple of the index relation
1314  */
1315  ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1316  if (!HeapTupleIsValid(ht_idxrel))
1317  elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1318  idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1319 
1320  /*
1321  * Fetch the pg_am tuple of the index' access method
1322  */
1323  ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1324  if (!HeapTupleIsValid(ht_am))
1325  elog(ERROR, "cache lookup failed for access method %u",
1326  idxrelrec->relam);
1327  amrec = (Form_pg_am) GETSTRUCT(ht_am);
1328 
1329  /* Fetch the index AM's API struct */
1330  amroutine = GetIndexAmRoutine(amrec->amhandler);
1331 
1332  /*
1333  * Get the index expressions, if any. (NOTE: we do not use the relcache
1334  * versions of the expressions and predicate, because we want to display
1335  * non-const-folded expressions.)
1336  */
1337  if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
1338  {
1339  Datum exprsDatum;
1340  char *exprsString;
1341 
1342  exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1343  Anum_pg_index_indexprs);
1344  exprsString = TextDatumGetCString(exprsDatum);
1345  indexprs = (List *) stringToNode(exprsString);
1346  pfree(exprsString);
1347  }
1348  else
1349  indexprs = NIL;
1350 
1351  indexpr_item = list_head(indexprs);
1352 
1353  context = deparse_context_for(get_relation_name(indrelid), indrelid);
1354 
1355  /*
1356  * Start the index definition. Note that the index's name should never be
1357  * schema-qualified, but the indexed rel's name may be.
1358  */
1359  initStringInfo(&buf);
1360 
1361  if (!attrsOnly)
1362  {
1363  if (!isConstraint)
1364  appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1365  idxrec->indisunique ? "UNIQUE " : "",
1366  quote_identifier(NameStr(idxrelrec->relname)),
1367  idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1368  && !inherits ? "ONLY " : "",
1369  (prettyFlags & PRETTYFLAG_SCHEMA) ?
1370  generate_relation_name(indrelid, NIL) :
1372  quote_identifier(NameStr(amrec->amname)));
1373  else /* currently, must be EXCLUDE constraint */
1374  appendStringInfo(&buf, "EXCLUDE USING %s (",
1375  quote_identifier(NameStr(amrec->amname)));
1376  }
1377 
1378  /*
1379  * Report the indexed attributes
1380  */
1381  sep = "";
1382  for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1383  {
1384  AttrNumber attnum = idxrec->indkey.values[keyno];
1385  Oid keycoltype;
1386  Oid keycolcollation;
1387 
1388  /*
1389  * Ignore non-key attributes if told to.
1390  */
1391  if (keysOnly && keyno >= idxrec->indnkeyatts)
1392  break;
1393 
1394  /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1395  if (!colno && keyno == idxrec->indnkeyatts)
1396  {
1397  appendStringInfoString(&buf, ") INCLUDE (");
1398  sep = "";
1399  }
1400 
1401  if (!colno)
1402  appendStringInfoString(&buf, sep);
1403  sep = ", ";
1404 
1405  if (attnum != 0)
1406  {
1407  /* Simple index column */
1408  char *attname;
1409  int32 keycoltypmod;
1410 
1411  attname = get_attname(indrelid, attnum, false);
1412  if (!colno || colno == keyno + 1)
1414  get_atttypetypmodcoll(indrelid, attnum,
1415  &keycoltype, &keycoltypmod,
1416  &keycolcollation);
1417  }
1418  else
1419  {
1420  /* expressional index */
1421  Node *indexkey;
1422 
1423  if (indexpr_item == NULL)
1424  elog(ERROR, "too few entries in indexprs list");
1425  indexkey = (Node *) lfirst(indexpr_item);
1426  indexpr_item = lnext(indexprs, indexpr_item);
1427  /* Deparse */
1428  str = deparse_expression_pretty(indexkey, context, false, false,
1429  prettyFlags, 0);
1430  if (!colno || colno == keyno + 1)
1431  {
1432  /* Need parens if it's not a bare function call */
1433  if (looks_like_function(indexkey))
1435  else
1436  appendStringInfo(&buf, "(%s)", str);
1437  }
1438  keycoltype = exprType(indexkey);
1439  keycolcollation = exprCollation(indexkey);
1440  }
1441 
1442  /* Print additional decoration for (selected) key columns */
1443  if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1444  (!colno || colno == keyno + 1))
1445  {
1446  int16 opt = indoption->values[keyno];
1447  Oid indcoll = indcollation->values[keyno];
1448  Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1449  bool has_options = attoptions != (Datum) 0;
1450 
1451  /* Add collation, if not default for column */
1452  if (OidIsValid(indcoll) && indcoll != keycolcollation)
1453  appendStringInfo(&buf, " COLLATE %s",
1454  generate_collation_name((indcoll)));
1455 
1456  /* Add the operator class name, if not default */
1457  get_opclass_name(indclass->values[keyno],
1458  has_options ? InvalidOid : keycoltype, &buf);
1459 
1460  if (has_options)
1461  {
1462  appendStringInfoString(&buf, " (");
1463  get_reloptions(&buf, attoptions);
1464  appendStringInfoChar(&buf, ')');
1465  }
1466 
1467  /* Add options if relevant */
1468  if (amroutine->amcanorder)
1469  {
1470  /* if it supports sort ordering, report DESC and NULLS opts */
1471  if (opt & INDOPTION_DESC)
1472  {
1473  appendStringInfoString(&buf, " DESC");
1474  /* NULLS FIRST is the default in this case */
1475  if (!(opt & INDOPTION_NULLS_FIRST))
1476  appendStringInfoString(&buf, " NULLS LAST");
1477  }
1478  else
1479  {
1480  if (opt & INDOPTION_NULLS_FIRST)
1481  appendStringInfoString(&buf, " NULLS FIRST");
1482  }
1483  }
1484 
1485  /* Add the exclusion operator if relevant */
1486  if (excludeOps != NULL)
1487  appendStringInfo(&buf, " WITH %s",
1488  generate_operator_name(excludeOps[keyno],
1489  keycoltype,
1490  keycoltype));
1491  }
1492  }
1493 
1494  if (!attrsOnly)
1495  {
1496  appendStringInfoChar(&buf, ')');
1497 
1498  if (idxrec->indnullsnotdistinct)
1499  appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1500 
1501  /*
1502  * If it has options, append "WITH (options)"
1503  */
1504  str = flatten_reloptions(indexrelid);
1505  if (str)
1506  {
1507  appendStringInfo(&buf, " WITH (%s)", str);
1508  pfree(str);
1509  }
1510 
1511  /*
1512  * Print tablespace, but only if requested
1513  */
1514  if (showTblSpc)
1515  {
1516  Oid tblspc;
1517 
1518  tblspc = get_rel_tablespace(indexrelid);
1519  if (OidIsValid(tblspc))
1520  {
1521  if (isConstraint)
1522  appendStringInfoString(&buf, " USING INDEX");
1523  appendStringInfo(&buf, " TABLESPACE %s",
1525  }
1526  }
1527 
1528  /*
1529  * If it's a partial index, decompile and append the predicate
1530  */
1531  if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
1532  {
1533  Node *node;
1534  Datum predDatum;
1535  char *predString;
1536 
1537  /* Convert text string to node tree */
1538  predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1539  Anum_pg_index_indpred);
1540  predString = TextDatumGetCString(predDatum);
1541  node = (Node *) stringToNode(predString);
1542  pfree(predString);
1543 
1544  /* Deparse */
1545  str = deparse_expression_pretty(node, context, false, false,
1546  prettyFlags, 0);
1547  if (isConstraint)
1548  appendStringInfo(&buf, " WHERE (%s)", str);
1549  else
1550  appendStringInfo(&buf, " WHERE %s", str);
1551  }
1552  }
1553 
1554  /* Clean up */
1555  ReleaseSysCache(ht_idx);
1556  ReleaseSysCache(ht_idxrel);
1557  ReleaseSysCache(ht_am);
1558 
1559  return buf.data;
1560 }
1561 
1562 /* ----------
1563  * pg_get_querydef
1564  *
1565  * Public entry point to deparse one query parsetree.
1566  * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1567  *
1568  * The result is a palloc'd C string.
1569  * ----------
1570  */
1571 char *
1572 pg_get_querydef(Query *query, bool pretty)
1573 {
1575  int prettyFlags;
1576 
1577  prettyFlags = GET_PRETTY_FLAGS(pretty);
1578 
1579  initStringInfo(&buf);
1580 
1581  get_query_def(query, &buf, NIL, NULL, true,
1582  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1583 
1584  return buf.data;
1585 }
1586 
1587 /*
1588  * pg_get_statisticsobjdef
1589  * Get the definition of an extended statistics object
1590  */
1591 Datum
1593 {
1594  Oid statextid = PG_GETARG_OID(0);
1595  char *res;
1596 
1597  res = pg_get_statisticsobj_worker(statextid, false, true);
1598 
1599  if (res == NULL)
1600  PG_RETURN_NULL();
1601 
1603 }
1604 
1605 /*
1606  * Internal version for use by ALTER TABLE.
1607  * Includes a tablespace clause in the result.
1608  * Returns a palloc'd C string; no pretty-printing.
1609  */
1610 char *
1612 {
1613  return pg_get_statisticsobj_worker(statextid, false, false);
1614 }
1615 
1616 /*
1617  * pg_get_statisticsobjdef_columns
1618  * Get columns and expressions for an extended statistics object
1619  */
1620 Datum
1622 {
1623  Oid statextid = PG_GETARG_OID(0);
1624  char *res;
1625 
1626  res = pg_get_statisticsobj_worker(statextid, true, true);
1627 
1628  if (res == NULL)
1629  PG_RETURN_NULL();
1630 
1632 }
1633 
1634 /*
1635  * Internal workhorse to decompile an extended statistics object.
1636  */
1637 static char *
1638 pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
1639 {
1640  Form_pg_statistic_ext statextrec;
1641  HeapTuple statexttup;
1643  int colno;
1644  char *nsp;
1645  ArrayType *arr;
1646  char *enabled;
1647  Datum datum;
1648  bool ndistinct_enabled;
1649  bool dependencies_enabled;
1650  bool mcv_enabled;
1651  int i;
1652  List *context;
1653  ListCell *lc;
1654  List *exprs = NIL;
1655  bool has_exprs;
1656  int ncolumns;
1657 
1658  statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1659 
1660  if (!HeapTupleIsValid(statexttup))
1661  {
1662  if (missing_ok)
1663  return NULL;
1664  elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1665  }
1666 
1667  /* has the statistics expressions? */
1668  has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1669 
1670  statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1671 
1672  /*
1673  * Get the statistics expressions, if any. (NOTE: we do not use the
1674  * relcache versions of the expressions, because we want to display
1675  * non-const-folded expressions.)
1676  */
1677  if (has_exprs)
1678  {
1679  Datum exprsDatum;
1680  char *exprsString;
1681 
1682  exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1683  Anum_pg_statistic_ext_stxexprs);
1684  exprsString = TextDatumGetCString(exprsDatum);
1685  exprs = (List *) stringToNode(exprsString);
1686  pfree(exprsString);
1687  }
1688  else
1689  exprs = NIL;
1690 
1691  /* count the number of columns (attributes and expressions) */
1692  ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1693 
1694  initStringInfo(&buf);
1695 
1696  if (!columns_only)
1697  {
1698  nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
1699  appendStringInfo(&buf, "CREATE STATISTICS %s",
1701  NameStr(statextrec->stxname)));
1702 
1703  /*
1704  * Decode the stxkind column so that we know which stats types to
1705  * print.
1706  */
1707  datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1708  Anum_pg_statistic_ext_stxkind);
1709  arr = DatumGetArrayTypeP(datum);
1710  if (ARR_NDIM(arr) != 1 ||
1711  ARR_HASNULL(arr) ||
1712  ARR_ELEMTYPE(arr) != CHAROID)
1713  elog(ERROR, "stxkind is not a 1-D char array");
1714  enabled = (char *) ARR_DATA_PTR(arr);
1715 
1716  ndistinct_enabled = false;
1717  dependencies_enabled = false;
1718  mcv_enabled = false;
1719 
1720  for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1721  {
1722  if (enabled[i] == STATS_EXT_NDISTINCT)
1723  ndistinct_enabled = true;
1724  else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1725  dependencies_enabled = true;
1726  else if (enabled[i] == STATS_EXT_MCV)
1727  mcv_enabled = true;
1728 
1729  /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1730  }
1731 
1732  /*
1733  * If any option is disabled, then we'll need to append the types
1734  * clause to show which options are enabled. We omit the types clause
1735  * on purpose when all options are enabled, so a pg_dump/pg_restore
1736  * will create all statistics types on a newer postgres version, if
1737  * the statistics had all options enabled on the original version.
1738  *
1739  * But if the statistics is defined on just a single column, it has to
1740  * be an expression statistics. In that case we don't need to specify
1741  * kinds.
1742  */
1743  if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1744  (ncolumns > 1))
1745  {
1746  bool gotone = false;
1747 
1748  appendStringInfoString(&buf, " (");
1749 
1750  if (ndistinct_enabled)
1751  {
1752  appendStringInfoString(&buf, "ndistinct");
1753  gotone = true;
1754  }
1755 
1756  if (dependencies_enabled)
1757  {
1758  appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
1759  gotone = true;
1760  }
1761 
1762  if (mcv_enabled)
1763  appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1764 
1765  appendStringInfoChar(&buf, ')');
1766  }
1767 
1768  appendStringInfoString(&buf, " ON ");
1769  }
1770 
1771  /* decode simple column references */
1772  for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1773  {
1774  AttrNumber attnum = statextrec->stxkeys.values[colno];
1775  char *attname;
1776 
1777  if (colno > 0)
1778  appendStringInfoString(&buf, ", ");
1779 
1780  attname = get_attname(statextrec->stxrelid, attnum, false);
1781 
1783  }
1784 
1785  context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1786  statextrec->stxrelid);
1787 
1788  foreach(lc, exprs)
1789  {
1790  Node *expr = (Node *) lfirst(lc);
1791  char *str;
1792  int prettyFlags = PRETTYFLAG_PAREN;
1793 
1794  str = deparse_expression_pretty(expr, context, false, false,
1795  prettyFlags, 0);
1796 
1797  if (colno > 0)
1798  appendStringInfoString(&buf, ", ");
1799 
1800  /* Need parens if it's not a bare function call */
1801  if (looks_like_function(expr))
1803  else
1804  appendStringInfo(&buf, "(%s)", str);
1805 
1806  colno++;
1807  }
1808 
1809  if (!columns_only)
1810  appendStringInfo(&buf, " FROM %s",
1811  generate_relation_name(statextrec->stxrelid, NIL));
1812 
1813  ReleaseSysCache(statexttup);
1814 
1815  return buf.data;
1816 }
1817 
1818 /*
1819  * Generate text array of expressions for statistics object.
1820  */
1821 Datum
1823 {
1824  Oid statextid = PG_GETARG_OID(0);
1825  Form_pg_statistic_ext statextrec;
1826  HeapTuple statexttup;
1827  Datum datum;
1828  List *context;
1829  ListCell *lc;
1830  List *exprs = NIL;
1831  bool has_exprs;
1832  char *tmp;
1833  ArrayBuildState *astate = NULL;
1834 
1835  statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1836 
1837  if (!HeapTupleIsValid(statexttup))
1838  PG_RETURN_NULL();
1839 
1840  /* Does the stats object have expressions? */
1841  has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1842 
1843  /* no expressions? we're done */
1844  if (!has_exprs)
1845  {
1846  ReleaseSysCache(statexttup);
1847  PG_RETURN_NULL();
1848  }
1849 
1850  statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1851 
1852  /*
1853  * Get the statistics expressions, and deparse them into text values.
1854  */
1855  datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1856  Anum_pg_statistic_ext_stxexprs);
1857  tmp = TextDatumGetCString(datum);
1858  exprs = (List *) stringToNode(tmp);
1859  pfree(tmp);
1860 
1861  context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1862  statextrec->stxrelid);
1863 
1864  foreach(lc, exprs)
1865  {
1866  Node *expr = (Node *) lfirst(lc);
1867  char *str;
1868  int prettyFlags = PRETTYFLAG_INDENT;
1869 
1870  str = deparse_expression_pretty(expr, context, false, false,
1871  prettyFlags, 0);
1872 
1873  astate = accumArrayResult(astate,
1875  false,
1876  TEXTOID,
1878  }
1879 
1880  ReleaseSysCache(statexttup);
1881 
1883 }
1884 
1885 /*
1886  * pg_get_partkeydef
1887  *
1888  * Returns the partition key specification, ie, the following:
1889  *
1890  * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1891  */
1892 Datum
1894 {
1895  Oid relid = PG_GETARG_OID(0);
1896  char *res;
1897 
1898  res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1899 
1900  if (res == NULL)
1901  PG_RETURN_NULL();
1902 
1904 }
1905 
1906 /* Internal version that just reports the column definitions */
1907 char *
1908 pg_get_partkeydef_columns(Oid relid, bool pretty)
1909 {
1910  int prettyFlags;
1911 
1912  prettyFlags = GET_PRETTY_FLAGS(pretty);
1913 
1914  return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1915 }
1916 
1917 /*
1918  * Internal workhorse to decompile a partition key definition.
1919  */
1920 static char *
1921 pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1922  bool attrsOnly, bool missing_ok)
1923 {
1925  HeapTuple tuple;
1926  oidvector *partclass;
1927  oidvector *partcollation;
1928  List *partexprs;
1929  ListCell *partexpr_item;
1930  List *context;
1931  Datum datum;
1933  int keyno;
1934  char *str;
1935  char *sep;
1936 
1937  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1938  if (!HeapTupleIsValid(tuple))
1939  {
1940  if (missing_ok)
1941  return NULL;
1942  elog(ERROR, "cache lookup failed for partition key of %u", relid);
1943  }
1944 
1945  form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1946 
1947  Assert(form->partrelid == relid);
1948 
1949  /* Must get partclass and partcollation the hard way */
1950  datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1951  Anum_pg_partitioned_table_partclass);
1952  partclass = (oidvector *) DatumGetPointer(datum);
1953 
1954  datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1955  Anum_pg_partitioned_table_partcollation);
1956  partcollation = (oidvector *) DatumGetPointer(datum);
1957 
1958 
1959  /*
1960  * Get the expressions, if any. (NOTE: we do not use the relcache
1961  * versions of the expressions, because we want to display
1962  * non-const-folded expressions.)
1963  */
1964  if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1965  {
1966  Datum exprsDatum;
1967  char *exprsString;
1968 
1969  exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1970  Anum_pg_partitioned_table_partexprs);
1971  exprsString = TextDatumGetCString(exprsDatum);
1972  partexprs = (List *) stringToNode(exprsString);
1973 
1974  if (!IsA(partexprs, List))
1975  elog(ERROR, "unexpected node type found in partexprs: %d",
1976  (int) nodeTag(partexprs));
1977 
1978  pfree(exprsString);
1979  }
1980  else
1981  partexprs = NIL;
1982 
1983  partexpr_item = list_head(partexprs);
1985 
1986  initStringInfo(&buf);
1987 
1988  switch (form->partstrat)
1989  {
1991  if (!attrsOnly)
1992  appendStringInfoString(&buf, "HASH");
1993  break;
1995  if (!attrsOnly)
1996  appendStringInfoString(&buf, "LIST");
1997  break;
1999  if (!attrsOnly)
2000  appendStringInfoString(&buf, "RANGE");
2001  break;
2002  default:
2003  elog(ERROR, "unexpected partition strategy: %d",
2004  (int) form->partstrat);
2005  }
2006 
2007  if (!attrsOnly)
2008  appendStringInfoString(&buf, " (");
2009  sep = "";
2010  for (keyno = 0; keyno < form->partnatts; keyno++)
2011  {
2012  AttrNumber attnum = form->partattrs.values[keyno];
2013  Oid keycoltype;
2014  Oid keycolcollation;
2015  Oid partcoll;
2016 
2017  appendStringInfoString(&buf, sep);
2018  sep = ", ";
2019  if (attnum != 0)
2020  {
2021  /* Simple attribute reference */
2022  char *attname;
2023  int32 keycoltypmod;
2024 
2025  attname = get_attname(relid, attnum, false);
2028  &keycoltype, &keycoltypmod,
2029  &keycolcollation);
2030  }
2031  else
2032  {
2033  /* Expression */
2034  Node *partkey;
2035 
2036  if (partexpr_item == NULL)
2037  elog(ERROR, "too few entries in partexprs list");
2038  partkey = (Node *) lfirst(partexpr_item);
2039  partexpr_item = lnext(partexprs, partexpr_item);
2040 
2041  /* Deparse */
2042  str = deparse_expression_pretty(partkey, context, false, false,
2043  prettyFlags, 0);
2044  /* Need parens if it's not a bare function call */
2045  if (looks_like_function(partkey))
2047  else
2048  appendStringInfo(&buf, "(%s)", str);
2049 
2050  keycoltype = exprType(partkey);
2051  keycolcollation = exprCollation(partkey);
2052  }
2053 
2054  /* Add collation, if not default for column */
2055  partcoll = partcollation->values[keyno];
2056  if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
2057  appendStringInfo(&buf, " COLLATE %s",
2058  generate_collation_name((partcoll)));
2059 
2060  /* Add the operator class name, if not default */
2061  if (!attrsOnly)
2062  get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2063  }
2064 
2065  if (!attrsOnly)
2066  appendStringInfoChar(&buf, ')');
2067 
2068  /* Clean up */
2069  ReleaseSysCache(tuple);
2070 
2071  return buf.data;
2072 }
2073 
2074 /*
2075  * pg_get_partition_constraintdef
2076  *
2077  * Returns partition constraint expression as a string for the input relation
2078  */
2079 Datum
2081 {
2082  Oid relationId = PG_GETARG_OID(0);
2083  Expr *constr_expr;
2084  int prettyFlags;
2085  List *context;
2086  char *consrc;
2087 
2088  constr_expr = get_partition_qual_relid(relationId);
2089 
2090  /* Quick exit if no partition constraint */
2091  if (constr_expr == NULL)
2092  PG_RETURN_NULL();
2093 
2094  /*
2095  * Deparse and return the constraint expression.
2096  */
2097  prettyFlags = PRETTYFLAG_INDENT;
2098  context = deparse_context_for(get_relation_name(relationId), relationId);
2099  consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2100  false, prettyFlags, 0);
2101 
2103 }
2104 
2105 /*
2106  * pg_get_partconstrdef_string
2107  *
2108  * Returns the partition constraint as a C-string for the input relation, with
2109  * the given alias. No pretty-printing.
2110  */
2111 char *
2112 pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
2113 {
2114  Expr *constr_expr;
2115  List *context;
2116 
2117  constr_expr = get_partition_qual_relid(partitionId);
2118  context = deparse_context_for(aliasname, partitionId);
2119 
2120  return deparse_expression((Node *) constr_expr, context, true, false);
2121 }
2122 
2123 /*
2124  * pg_get_constraintdef
2125  *
2126  * Returns the definition for the constraint, ie, everything that needs to
2127  * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2128  */
2129 Datum
2131 {
2132  Oid constraintId = PG_GETARG_OID(0);
2133  int prettyFlags;
2134  char *res;
2135 
2136  prettyFlags = PRETTYFLAG_INDENT;
2137 
2138  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2139 
2140  if (res == NULL)
2141  PG_RETURN_NULL();
2142 
2144 }
2145 
2146 Datum
2148 {
2149  Oid constraintId = PG_GETARG_OID(0);
2150  bool pretty = PG_GETARG_BOOL(1);
2151  int prettyFlags;
2152  char *res;
2153 
2154  prettyFlags = GET_PRETTY_FLAGS(pretty);
2155 
2156  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2157 
2158  if (res == NULL)
2159  PG_RETURN_NULL();
2160 
2162 }
2163 
2164 /*
2165  * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2166  */
2167 char *
2169 {
2170  return pg_get_constraintdef_worker(constraintId, true, 0, false);
2171 }
2172 
2173 /*
2174  * As of 9.4, we now use an MVCC snapshot for this.
2175  */
2176 static char *
2177 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
2178  int prettyFlags, bool missing_ok)
2179 {
2180  HeapTuple tup;
2181  Form_pg_constraint conForm;
2183  SysScanDesc scandesc;
2184  ScanKeyData scankey[1];
2186  Relation relation = table_open(ConstraintRelationId, AccessShareLock);
2187 
2188  ScanKeyInit(&scankey[0],
2189  Anum_pg_constraint_oid,
2190  BTEqualStrategyNumber, F_OIDEQ,
2191  ObjectIdGetDatum(constraintId));
2192 
2193  scandesc = systable_beginscan(relation,
2194  ConstraintOidIndexId,
2195  true,
2196  snapshot,
2197  1,
2198  scankey);
2199 
2200  /*
2201  * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2202  * via SearchSysCache, which works fine.
2203  */
2204  tup = systable_getnext(scandesc);
2205 
2206  UnregisterSnapshot(snapshot);
2207 
2208  if (!HeapTupleIsValid(tup))
2209  {
2210  if (missing_ok)
2211  {
2212  systable_endscan(scandesc);
2213  table_close(relation, AccessShareLock);
2214  return NULL;
2215  }
2216  elog(ERROR, "could not find tuple for constraint %u", constraintId);
2217  }
2218 
2219  conForm = (Form_pg_constraint) GETSTRUCT(tup);
2220 
2221  initStringInfo(&buf);
2222 
2223  if (fullCommand)
2224  {
2225  if (OidIsValid(conForm->conrelid))
2226  {
2227  /*
2228  * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2229  * constraints, and other types of constraints don't inherit
2230  * anyway so it doesn't matter whether we say ONLY or not. Someday
2231  * we might need to let callers specify whether to put ONLY in the
2232  * command.
2233  */
2234  appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2235  generate_qualified_relation_name(conForm->conrelid),
2236  quote_identifier(NameStr(conForm->conname)));
2237  }
2238  else
2239  {
2240  /* Must be a domain constraint */
2241  Assert(OidIsValid(conForm->contypid));
2242  appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2243  generate_qualified_type_name(conForm->contypid),
2244  quote_identifier(NameStr(conForm->conname)));
2245  }
2246  }
2247 
2248  switch (conForm->contype)
2249  {
2250  case CONSTRAINT_FOREIGN:
2251  {
2252  Datum val;
2253  bool isnull;
2254  const char *string;
2255 
2256  /* Start off the constraint definition */
2257  appendStringInfoString(&buf, "FOREIGN KEY (");
2258 
2259  /* Fetch and build referencing-column list */
2260  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2261  Anum_pg_constraint_conkey);
2262 
2263  /* If it is a temporal foreign key then it uses PERIOD. */
2264  decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf);
2265 
2266  /* add foreign relation name */
2267  appendStringInfo(&buf, ") REFERENCES %s(",
2268  generate_relation_name(conForm->confrelid,
2269  NIL));
2270 
2271  /* Fetch and build referenced-column list */
2272  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2273  Anum_pg_constraint_confkey);
2274 
2275  decompile_column_index_array(val, conForm->confrelid, conForm->conperiod, &buf);
2276 
2277  appendStringInfoChar(&buf, ')');
2278 
2279  /* Add match type */
2280  switch (conForm->confmatchtype)
2281  {
2282  case FKCONSTR_MATCH_FULL:
2283  string = " MATCH FULL";
2284  break;
2286  string = " MATCH PARTIAL";
2287  break;
2288  case FKCONSTR_MATCH_SIMPLE:
2289  string = "";
2290  break;
2291  default:
2292  elog(ERROR, "unrecognized confmatchtype: %d",
2293  conForm->confmatchtype);
2294  string = ""; /* keep compiler quiet */
2295  break;
2296  }
2297  appendStringInfoString(&buf, string);
2298 
2299  /* Add ON UPDATE and ON DELETE clauses, if needed */
2300  switch (conForm->confupdtype)
2301  {
2303  string = NULL; /* suppress default */
2304  break;
2306  string = "RESTRICT";
2307  break;
2309  string = "CASCADE";
2310  break;
2312  string = "SET NULL";
2313  break;
2315  string = "SET DEFAULT";
2316  break;
2317  default:
2318  elog(ERROR, "unrecognized confupdtype: %d",
2319  conForm->confupdtype);
2320  string = NULL; /* keep compiler quiet */
2321  break;
2322  }
2323  if (string)
2324  appendStringInfo(&buf, " ON UPDATE %s", string);
2325 
2326  switch (conForm->confdeltype)
2327  {
2329  string = NULL; /* suppress default */
2330  break;
2332  string = "RESTRICT";
2333  break;
2335  string = "CASCADE";
2336  break;
2338  string = "SET NULL";
2339  break;
2341  string = "SET DEFAULT";
2342  break;
2343  default:
2344  elog(ERROR, "unrecognized confdeltype: %d",
2345  conForm->confdeltype);
2346  string = NULL; /* keep compiler quiet */
2347  break;
2348  }
2349  if (string)
2350  appendStringInfo(&buf, " ON DELETE %s", string);
2351 
2352  /*
2353  * Add columns specified to SET NULL or SET DEFAULT if
2354  * provided.
2355  */
2356  val = SysCacheGetAttr(CONSTROID, tup,
2357  Anum_pg_constraint_confdelsetcols, &isnull);
2358  if (!isnull)
2359  {
2360  appendStringInfoString(&buf, " (");
2361  decompile_column_index_array(val, conForm->conrelid, false, &buf);
2362  appendStringInfoChar(&buf, ')');
2363  }
2364 
2365  break;
2366  }
2367  case CONSTRAINT_PRIMARY:
2368  case CONSTRAINT_UNIQUE:
2369  {
2370  Datum val;
2371  Oid indexId;
2372  int keyatts;
2373  HeapTuple indtup;
2374 
2375  /* Start off the constraint definition */
2376  if (conForm->contype == CONSTRAINT_PRIMARY)
2377  appendStringInfoString(&buf, "PRIMARY KEY ");
2378  else
2379  appendStringInfoString(&buf, "UNIQUE ");
2380 
2381  indexId = conForm->conindid;
2382 
2383  indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2384  if (!HeapTupleIsValid(indtup))
2385  elog(ERROR, "cache lookup failed for index %u", indexId);
2386  if (conForm->contype == CONSTRAINT_UNIQUE &&
2387  ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2388  appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2389 
2390  appendStringInfoChar(&buf, '(');
2391 
2392  /* Fetch and build target column list */
2393  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2394  Anum_pg_constraint_conkey);
2395 
2396  keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf);
2397  if (conForm->conperiod)
2398  appendStringInfoString(&buf, " WITHOUT OVERLAPS");
2399 
2400  appendStringInfoChar(&buf, ')');
2401 
2402  /* Build including column list (from pg_index.indkeys) */
2403  val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2404  Anum_pg_index_indnatts);
2405  if (DatumGetInt32(val) > keyatts)
2406  {
2407  Datum cols;
2408  Datum *keys;
2409  int nKeys;
2410  int j;
2411 
2412  appendStringInfoString(&buf, " INCLUDE (");
2413 
2414  cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2415  Anum_pg_index_indkey);
2416 
2418  &keys, NULL, &nKeys);
2419 
2420  for (j = keyatts; j < nKeys; j++)
2421  {
2422  char *colName;
2423 
2424  colName = get_attname(conForm->conrelid,
2425  DatumGetInt16(keys[j]), false);
2426  if (j > keyatts)
2427  appendStringInfoString(&buf, ", ");
2429  }
2430 
2431  appendStringInfoChar(&buf, ')');
2432  }
2433  ReleaseSysCache(indtup);
2434 
2435  /* XXX why do we only print these bits if fullCommand? */
2436  if (fullCommand && OidIsValid(indexId))
2437  {
2438  char *options = flatten_reloptions(indexId);
2439  Oid tblspc;
2440 
2441  if (options)
2442  {
2443  appendStringInfo(&buf, " WITH (%s)", options);
2444  pfree(options);
2445  }
2446 
2447  /*
2448  * Print the tablespace, unless it's the database default.
2449  * This is to help ALTER TABLE usage of this facility,
2450  * which needs this behavior to recreate exact catalog
2451  * state.
2452  */
2453  tblspc = get_rel_tablespace(indexId);
2454  if (OidIsValid(tblspc))
2455  appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2457  }
2458 
2459  break;
2460  }
2461  case CONSTRAINT_CHECK:
2462  {
2463  Datum val;
2464  char *conbin;
2465  char *consrc;
2466  Node *expr;
2467  List *context;
2468 
2469  /* Fetch constraint expression in parsetree form */
2470  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2471  Anum_pg_constraint_conbin);
2472 
2473  conbin = TextDatumGetCString(val);
2474  expr = stringToNode(conbin);
2475 
2476  /* Set up deparsing context for Var nodes in constraint */
2477  if (conForm->conrelid != InvalidOid)
2478  {
2479  /* relation constraint */
2480  context = deparse_context_for(get_relation_name(conForm->conrelid),
2481  conForm->conrelid);
2482  }
2483  else
2484  {
2485  /* domain constraint --- can't have Vars */
2486  context = NIL;
2487  }
2488 
2489  consrc = deparse_expression_pretty(expr, context, false, false,
2490  prettyFlags, 0);
2491 
2492  /*
2493  * Now emit the constraint definition, adding NO INHERIT if
2494  * necessary.
2495  *
2496  * There are cases where the constraint expression will be
2497  * fully parenthesized and we don't need the outer parens ...
2498  * but there are other cases where we do need 'em. Be
2499  * conservative for now.
2500  *
2501  * Note that simply checking for leading '(' and trailing ')'
2502  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2503  */
2504  appendStringInfo(&buf, "CHECK (%s)%s",
2505  consrc,
2506  conForm->connoinherit ? " NO INHERIT" : "");
2507  break;
2508  }
2509  case CONSTRAINT_NOTNULL:
2510  {
2511  if (conForm->conrelid)
2512  {
2514 
2516 
2517  appendStringInfo(&buf, "NOT NULL %s",
2518  quote_identifier(get_attname(conForm->conrelid,
2519  attnum, false)));
2520  if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
2521  appendStringInfoString(&buf, " NO INHERIT");
2522  }
2523  else if (conForm->contypid)
2524  {
2525  /* conkey is null for domain not-null constraints */
2526  appendStringInfoString(&buf, "NOT NULL");
2527  }
2528  break;
2529  }
2530 
2531  case CONSTRAINT_TRIGGER:
2532 
2533  /*
2534  * There isn't an ALTER TABLE syntax for creating a user-defined
2535  * constraint trigger, but it seems better to print something than
2536  * throw an error; if we throw error then this function couldn't
2537  * safely be applied to all rows of pg_constraint.
2538  */
2539  appendStringInfoString(&buf, "TRIGGER");
2540  break;
2541  case CONSTRAINT_EXCLUSION:
2542  {
2543  Oid indexOid = conForm->conindid;
2544  Datum val;
2545  Datum *elems;
2546  int nElems;
2547  int i;
2548  Oid *operators;
2549 
2550  /* Extract operator OIDs from the pg_constraint tuple */
2551  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2552  Anum_pg_constraint_conexclop);
2553 
2555  &elems, NULL, &nElems);
2556 
2557  operators = (Oid *) palloc(nElems * sizeof(Oid));
2558  for (i = 0; i < nElems; i++)
2559  operators[i] = DatumGetObjectId(elems[i]);
2560 
2561  /* pg_get_indexdef_worker does the rest */
2562  /* suppress tablespace because pg_dump wants it that way */
2564  pg_get_indexdef_worker(indexOid,
2565  0,
2566  operators,
2567  false,
2568  false,
2569  false,
2570  false,
2571  prettyFlags,
2572  false));
2573  break;
2574  }
2575  default:
2576  elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2577  break;
2578  }
2579 
2580  if (conForm->condeferrable)
2581  appendStringInfoString(&buf, " DEFERRABLE");
2582  if (conForm->condeferred)
2583  appendStringInfoString(&buf, " INITIALLY DEFERRED");
2584  if (!conForm->convalidated)
2585  appendStringInfoString(&buf, " NOT VALID");
2586 
2587  /* Cleanup */
2588  systable_endscan(scandesc);
2589  table_close(relation, AccessShareLock);
2590 
2591  return buf.data;
2592 }
2593 
2594 
2595 /*
2596  * Convert an int16[] Datum into a comma-separated list of column names
2597  * for the indicated relation; append the list to buf. Returns the number
2598  * of keys.
2599  */
2600 static int
2601 decompile_column_index_array(Datum column_index_array, Oid relId,
2602  bool withPeriod, StringInfo buf)
2603 {
2604  Datum *keys;
2605  int nKeys;
2606  int j;
2607 
2608  /* Extract data from array of int16 */
2609  deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2610  &keys, NULL, &nKeys);
2611 
2612  for (j = 0; j < nKeys; j++)
2613  {
2614  char *colName;
2615 
2616  colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2617 
2618  if (j == 0)
2620  else
2621  appendStringInfo(buf, ", %s%s",
2622  (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
2623  quote_identifier(colName));
2624  }
2625 
2626  return nKeys;
2627 }
2628 
2629 
2630 /* ----------
2631  * pg_get_expr - Decompile an expression tree
2632  *
2633  * Input: an expression tree in nodeToString form, and a relation OID
2634  *
2635  * Output: reverse-listed expression
2636  *
2637  * Currently, the expression can only refer to a single relation, namely
2638  * the one specified by the second parameter. This is sufficient for
2639  * partial indexes, column default expressions, etc. We also support
2640  * Var-free expressions, for which the OID can be InvalidOid.
2641  *
2642  * If the OID is nonzero but not actually valid, don't throw an error,
2643  * just return NULL. This is a bit questionable, but it's what we've
2644  * done historically, and it can help avoid unwanted failures when
2645  * examining catalog entries for just-deleted relations.
2646  *
2647  * We expect this function to work, or throw a reasonably clean error,
2648  * for any node tree that can appear in a catalog pg_node_tree column.
2649  * Query trees, such as those appearing in pg_rewrite.ev_action, are
2650  * not supported. Nor are expressions in more than one relation, which
2651  * can appear in places like pg_rewrite.ev_qual.
2652  * ----------
2653  */
2654 Datum
2656 {
2657  text *expr = PG_GETARG_TEXT_PP(0);
2658  Oid relid = PG_GETARG_OID(1);
2659  text *result;
2660  int prettyFlags;
2661 
2662  prettyFlags = PRETTYFLAG_INDENT;
2663 
2664  result = pg_get_expr_worker(expr, relid, prettyFlags);
2665  if (result)
2666  PG_RETURN_TEXT_P(result);
2667  else
2668  PG_RETURN_NULL();
2669 }
2670 
2671 Datum
2673 {
2674  text *expr = PG_GETARG_TEXT_PP(0);
2675  Oid relid = PG_GETARG_OID(1);
2676  bool pretty = PG_GETARG_BOOL(2);
2677  text *result;
2678  int prettyFlags;
2679 
2680  prettyFlags = GET_PRETTY_FLAGS(pretty);
2681 
2682  result = pg_get_expr_worker(expr, relid, prettyFlags);
2683  if (result)
2684  PG_RETURN_TEXT_P(result);
2685  else
2686  PG_RETURN_NULL();
2687 }
2688 
2689 static text *
2690 pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
2691 {
2692  Node *node;
2693  Node *tst;
2694  Relids relids;
2695  List *context;
2696  char *exprstr;
2697  Relation rel = NULL;
2698  char *str;
2699 
2700  /* Convert input pg_node_tree (really TEXT) object to C string */
2701  exprstr = text_to_cstring(expr);
2702 
2703  /* Convert expression to node tree */
2704  node = (Node *) stringToNode(exprstr);
2705 
2706  pfree(exprstr);
2707 
2708  /*
2709  * Throw error if the input is a querytree rather than an expression tree.
2710  * While we could support queries here, there seems no very good reason
2711  * to. In most such catalog columns, we'll see a List of Query nodes, or
2712  * even nested Lists, so drill down to a non-List node before checking.
2713  */
2714  tst = node;
2715  while (tst && IsA(tst, List))
2716  tst = linitial((List *) tst);
2717  if (tst && IsA(tst, Query))
2718  ereport(ERROR,
2719  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2720  errmsg("input is a query, not an expression")));
2721 
2722  /*
2723  * Throw error if the expression contains Vars we won't be able to
2724  * deparse.
2725  */
2726  relids = pull_varnos(NULL, node);
2727  if (OidIsValid(relid))
2728  {
2729  if (!bms_is_subset(relids, bms_make_singleton(1)))
2730  ereport(ERROR,
2731  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2732  errmsg("expression contains variables of more than one relation")));
2733  }
2734  else
2735  {
2736  if (!bms_is_empty(relids))
2737  ereport(ERROR,
2738  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2739  errmsg("expression contains variables")));
2740  }
2741 
2742  /*
2743  * Prepare deparse context if needed. If we are deparsing with a relid,
2744  * we need to transiently open and lock the rel, to make sure it won't go
2745  * away underneath us. (set_relation_column_names would lock it anyway,
2746  * so this isn't really introducing any new behavior.)
2747  */
2748  if (OidIsValid(relid))
2749  {
2750  rel = try_relation_open(relid, AccessShareLock);
2751  if (rel == NULL)
2752  return NULL;
2754  }
2755  else
2756  context = NIL;
2757 
2758  /* Deparse */
2759  str = deparse_expression_pretty(node, context, false, false,
2760  prettyFlags, 0);
2761 
2762  if (rel != NULL)
2764 
2765  return string_to_text(str);
2766 }
2767 
2768 
2769 /* ----------
2770  * pg_get_userbyid - Get a user name by roleid and
2771  * fallback to 'unknown (OID=n)'
2772  * ----------
2773  */
2774 Datum
2776 {
2777  Oid roleid = PG_GETARG_OID(0);
2778  Name result;
2779  HeapTuple roletup;
2780  Form_pg_authid role_rec;
2781 
2782  /*
2783  * Allocate space for the result
2784  */
2785  result = (Name) palloc(NAMEDATALEN);
2786  memset(NameStr(*result), 0, NAMEDATALEN);
2787 
2788  /*
2789  * Get the pg_authid entry and print the result
2790  */
2791  roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2792  if (HeapTupleIsValid(roletup))
2793  {
2794  role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2795  *result = role_rec->rolname;
2796  ReleaseSysCache(roletup);
2797  }
2798  else
2799  sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2800 
2801  PG_RETURN_NAME(result);
2802 }
2803 
2804 
2805 /*
2806  * pg_get_serial_sequence
2807  * Get the name of the sequence used by an identity or serial column,
2808  * formatted suitably for passing to setval, nextval or currval.
2809  * First parameter is not treated as double-quoted, second parameter
2810  * is --- see documentation for reason.
2811  */
2812 Datum
2814 {
2815  text *tablename = PG_GETARG_TEXT_PP(0);
2816  text *columnname = PG_GETARG_TEXT_PP(1);
2817  RangeVar *tablerv;
2818  Oid tableOid;
2819  char *column;
2821  Oid sequenceId = InvalidOid;
2822  Relation depRel;
2823  ScanKeyData key[3];
2824  SysScanDesc scan;
2825  HeapTuple tup;
2826 
2827  /* Look up table name. Can't lock it - we might not have privileges. */
2828  tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2829  tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2830 
2831  /* Get the number of the column */
2832  column = text_to_cstring(columnname);
2833 
2834  attnum = get_attnum(tableOid, column);
2835  if (attnum == InvalidAttrNumber)
2836  ereport(ERROR,
2837  (errcode(ERRCODE_UNDEFINED_COLUMN),
2838  errmsg("column \"%s\" of relation \"%s\" does not exist",
2839  column, tablerv->relname)));
2840 
2841  /* Search the dependency table for the dependent sequence */
2842  depRel = table_open(DependRelationId, AccessShareLock);
2843 
2844  ScanKeyInit(&key[0],
2845  Anum_pg_depend_refclassid,
2846  BTEqualStrategyNumber, F_OIDEQ,
2847  ObjectIdGetDatum(RelationRelationId));
2848  ScanKeyInit(&key[1],
2849  Anum_pg_depend_refobjid,
2850  BTEqualStrategyNumber, F_OIDEQ,
2851  ObjectIdGetDatum(tableOid));
2852  ScanKeyInit(&key[2],
2853  Anum_pg_depend_refobjsubid,
2854  BTEqualStrategyNumber, F_INT4EQ,
2856 
2857  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2858  NULL, 3, key);
2859 
2860  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2861  {
2862  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2863 
2864  /*
2865  * Look for an auto dependency (serial column) or internal dependency
2866  * (identity column) of a sequence on a column. (We need the relkind
2867  * test because indexes can also have auto dependencies on columns.)
2868  */
2869  if (deprec->classid == RelationRelationId &&
2870  deprec->objsubid == 0 &&
2871  (deprec->deptype == DEPENDENCY_AUTO ||
2872  deprec->deptype == DEPENDENCY_INTERNAL) &&
2873  get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2874  {
2875  sequenceId = deprec->objid;
2876  break;
2877  }
2878  }
2879 
2880  systable_endscan(scan);
2881  table_close(depRel, AccessShareLock);
2882 
2883  if (OidIsValid(sequenceId))
2884  {
2885  char *result;
2886 
2887  result = generate_qualified_relation_name(sequenceId);
2888 
2890  }
2891 
2892  PG_RETURN_NULL();
2893 }
2894 
2895 
2896 /*
2897  * pg_get_functiondef
2898  * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2899  * the specified function.
2900  *
2901  * Note: if you change the output format of this function, be careful not
2902  * to break psql's rules (in \ef and \sf) for identifying the start of the
2903  * function body. To wit: the function body starts on a line that begins with
2904  * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
2905  */
2906 Datum
2908 {
2909  Oid funcid = PG_GETARG_OID(0);
2911  StringInfoData dq;
2912  HeapTuple proctup;
2913  Form_pg_proc proc;
2914  bool isfunction;
2915  Datum tmp;
2916  bool isnull;
2917  const char *prosrc;
2918  const char *name;
2919  const char *nsp;
2920  float4 procost;
2921  int oldlen;
2922 
2923  initStringInfo(&buf);
2924 
2925  /* Look up the function */
2926  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2927  if (!HeapTupleIsValid(proctup))
2928  PG_RETURN_NULL();
2929 
2930  proc = (Form_pg_proc) GETSTRUCT(proctup);
2931  name = NameStr(proc->proname);
2932 
2933  if (proc->prokind == PROKIND_AGGREGATE)
2934  ereport(ERROR,
2935  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2936  errmsg("\"%s\" is an aggregate function", name)));
2937 
2938  isfunction = (proc->prokind != PROKIND_PROCEDURE);
2939 
2940  /*
2941  * We always qualify the function name, to ensure the right function gets
2942  * replaced.
2943  */
2944  nsp = get_namespace_name_or_temp(proc->pronamespace);
2945  appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2946  isfunction ? "FUNCTION" : "PROCEDURE",
2948  (void) print_function_arguments(&buf, proctup, false, true);
2949  appendStringInfoString(&buf, ")\n");
2950  if (isfunction)
2951  {
2952  appendStringInfoString(&buf, " RETURNS ");
2953  print_function_rettype(&buf, proctup);
2954  appendStringInfoChar(&buf, '\n');
2955  }
2956 
2957  print_function_trftypes(&buf, proctup);
2958 
2959  appendStringInfo(&buf, " LANGUAGE %s\n",
2960  quote_identifier(get_language_name(proc->prolang, false)));
2961 
2962  /* Emit some miscellaneous options on one line */
2963  oldlen = buf.len;
2964 
2965  if (proc->prokind == PROKIND_WINDOW)
2966  appendStringInfoString(&buf, " WINDOW");
2967  switch (proc->provolatile)
2968  {
2969  case PROVOLATILE_IMMUTABLE:
2970  appendStringInfoString(&buf, " IMMUTABLE");
2971  break;
2972  case PROVOLATILE_STABLE:
2973  appendStringInfoString(&buf, " STABLE");
2974  break;
2975  case PROVOLATILE_VOLATILE:
2976  break;
2977  }
2978 
2979  switch (proc->proparallel)
2980  {
2981  case PROPARALLEL_SAFE:
2982  appendStringInfoString(&buf, " PARALLEL SAFE");
2983  break;
2984  case PROPARALLEL_RESTRICTED:
2985  appendStringInfoString(&buf, " PARALLEL RESTRICTED");
2986  break;
2987  case PROPARALLEL_UNSAFE:
2988  break;
2989  }
2990 
2991  if (proc->proisstrict)
2992  appendStringInfoString(&buf, " STRICT");
2993  if (proc->prosecdef)
2994  appendStringInfoString(&buf, " SECURITY DEFINER");
2995  if (proc->proleakproof)
2996  appendStringInfoString(&buf, " LEAKPROOF");
2997 
2998  /* This code for the default cost and rows should match functioncmds.c */
2999  if (proc->prolang == INTERNALlanguageId ||
3000  proc->prolang == ClanguageId)
3001  procost = 1;
3002  else
3003  procost = 100;
3004  if (proc->procost != procost)
3005  appendStringInfo(&buf, " COST %g", proc->procost);
3006 
3007  if (proc->prorows > 0 && proc->prorows != 1000)
3008  appendStringInfo(&buf, " ROWS %g", proc->prorows);
3009 
3010  if (proc->prosupport)
3011  {
3012  Oid argtypes[1];
3013 
3014  /*
3015  * We should qualify the support function's name if it wouldn't be
3016  * resolved by lookup in the current search path.
3017  */
3018  argtypes[0] = INTERNALOID;
3019  appendStringInfo(&buf, " SUPPORT %s",
3020  generate_function_name(proc->prosupport, 1,
3021  NIL, argtypes,
3022  false, NULL, EXPR_KIND_NONE));
3023  }
3024 
3025  if (oldlen != buf.len)
3026  appendStringInfoChar(&buf, '\n');
3027 
3028  /* Emit any proconfig options, one per line */
3029  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
3030  if (!isnull)
3031  {
3032  ArrayType *a = DatumGetArrayTypeP(tmp);
3033  int i;
3034 
3035  Assert(ARR_ELEMTYPE(a) == TEXTOID);
3036  Assert(ARR_NDIM(a) == 1);
3037  Assert(ARR_LBOUND(a)[0] == 1);
3038 
3039  for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3040  {
3041  Datum d;
3042 
3043  d = array_ref(a, 1, &i,
3044  -1 /* varlenarray */ ,
3045  -1 /* TEXT's typlen */ ,
3046  false /* TEXT's typbyval */ ,
3047  TYPALIGN_INT /* TEXT's typalign */ ,
3048  &isnull);
3049  if (!isnull)
3050  {
3051  char *configitem = TextDatumGetCString(d);
3052  char *pos;
3053 
3054  pos = strchr(configitem, '=');
3055  if (pos == NULL)
3056  continue;
3057  *pos++ = '\0';
3058 
3059  appendStringInfo(&buf, " SET %s TO ",
3060  quote_identifier(configitem));
3061 
3062  /*
3063  * Variables that are marked GUC_LIST_QUOTE were already fully
3064  * quoted by flatten_set_variable_args() before they were put
3065  * into the proconfig array. However, because the quoting
3066  * rules used there aren't exactly like SQL's, we have to
3067  * break the list value apart and then quote the elements as
3068  * string literals. (The elements may be double-quoted as-is,
3069  * but we can't just feed them to the SQL parser; it would do
3070  * the wrong thing with elements that are zero-length or
3071  * longer than NAMEDATALEN.)
3072  *
3073  * Variables that are not so marked should just be emitted as
3074  * simple string literals. If the variable is not known to
3075  * guc.c, we'll do that; this makes it unsafe to use
3076  * GUC_LIST_QUOTE for extension variables.
3077  */
3078  if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3079  {
3080  List *namelist;
3081  ListCell *lc;
3082 
3083  /* Parse string into list of identifiers */
3084  if (!SplitGUCList(pos, ',', &namelist))
3085  {
3086  /* this shouldn't fail really */
3087  elog(ERROR, "invalid list syntax in proconfig item");
3088  }
3089  foreach(lc, namelist)
3090  {
3091  char *curname = (char *) lfirst(lc);
3092 
3093  simple_quote_literal(&buf, curname);
3094  if (lnext(namelist, lc))
3095  appendStringInfoString(&buf, ", ");
3096  }
3097  }
3098  else
3099  simple_quote_literal(&buf, pos);
3100  appendStringInfoChar(&buf, '\n');
3101  }
3102  }
3103  }
3104 
3105  /* And finally the function definition ... */
3106  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3107  if (proc->prolang == SQLlanguageId && !isnull)
3108  {
3109  print_function_sqlbody(&buf, proctup);
3110  }
3111  else
3112  {
3113  appendStringInfoString(&buf, "AS ");
3114 
3115  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
3116  if (!isnull)
3117  {
3119  appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3120  }
3121 
3122  tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
3123  prosrc = TextDatumGetCString(tmp);
3124 
3125  /*
3126  * We always use dollar quoting. Figure out a suitable delimiter.
3127  *
3128  * Since the user is likely to be editing the function body string, we
3129  * shouldn't use a short delimiter that he might easily create a
3130  * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3131  * if needed.
3132  */
3133  initStringInfo(&dq);
3134  appendStringInfoChar(&dq, '$');
3135  appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3136  while (strstr(prosrc, dq.data) != NULL)
3137  appendStringInfoChar(&dq, 'x');
3138  appendStringInfoChar(&dq, '$');
3139 
3140  appendBinaryStringInfo(&buf, dq.data, dq.len);
3141  appendStringInfoString(&buf, prosrc);
3142  appendBinaryStringInfo(&buf, dq.data, dq.len);
3143  }
3144 
3145  appendStringInfoChar(&buf, '\n');
3146 
3147  ReleaseSysCache(proctup);
3148 
3150 }
3151 
3152 /*
3153  * pg_get_function_arguments
3154  * Get a nicely-formatted list of arguments for a function.
3155  * This is everything that would go between the parentheses in
3156  * CREATE FUNCTION.
3157  */
3158 Datum
3160 {
3161  Oid funcid = PG_GETARG_OID(0);
3163  HeapTuple proctup;
3164 
3165  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3166  if (!HeapTupleIsValid(proctup))
3167  PG_RETURN_NULL();
3168 
3169  initStringInfo(&buf);
3170 
3171  (void) print_function_arguments(&buf, proctup, false, true);
3172 
3173  ReleaseSysCache(proctup);
3174 
3176 }
3177 
3178 /*
3179  * pg_get_function_identity_arguments
3180  * Get a formatted list of arguments for a function.
3181  * This is everything that would go between the parentheses in
3182  * ALTER FUNCTION, etc. In particular, don't print defaults.
3183  */
3184 Datum
3186 {
3187  Oid funcid = PG_GETARG_OID(0);
3189  HeapTuple proctup;
3190 
3191  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3192  if (!HeapTupleIsValid(proctup))
3193  PG_RETURN_NULL();
3194 
3195  initStringInfo(&buf);
3196 
3197  (void) print_function_arguments(&buf, proctup, false, false);
3198 
3199  ReleaseSysCache(proctup);
3200 
3202 }
3203 
3204 /*
3205  * pg_get_function_result
3206  * Get a nicely-formatted version of the result type of a function.
3207  * This is what would appear after RETURNS in CREATE FUNCTION.
3208  */
3209 Datum
3211 {
3212  Oid funcid = PG_GETARG_OID(0);
3214  HeapTuple proctup;
3215 
3216  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3217  if (!HeapTupleIsValid(proctup))
3218  PG_RETURN_NULL();
3219 
3220  if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3221  {
3222  ReleaseSysCache(proctup);
3223  PG_RETURN_NULL();
3224  }
3225 
3226  initStringInfo(&buf);
3227 
3228  print_function_rettype(&buf, proctup);
3229 
3230  ReleaseSysCache(proctup);
3231 
3233 }
3234 
3235 /*
3236  * Guts of pg_get_function_result: append the function's return type
3237  * to the specified buffer.
3238  */
3239 static void
3241 {
3242  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3243  int ntabargs = 0;
3244  StringInfoData rbuf;
3245 
3246  initStringInfo(&rbuf);
3247 
3248  if (proc->proretset)
3249  {
3250  /* It might be a table function; try to print the arguments */
3251  appendStringInfoString(&rbuf, "TABLE(");
3252  ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3253  if (ntabargs > 0)
3254  appendStringInfoChar(&rbuf, ')');
3255  else
3256  resetStringInfo(&rbuf);
3257  }
3258 
3259  if (ntabargs == 0)
3260  {
3261  /* Not a table function, so do the normal thing */
3262  if (proc->proretset)
3263  appendStringInfoString(&rbuf, "SETOF ");
3264  appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3265  }
3266 
3267  appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3268 }
3269 
3270 /*
3271  * Common code for pg_get_function_arguments and pg_get_function_result:
3272  * append the desired subset of arguments to buf. We print only TABLE
3273  * arguments when print_table_args is true, and all the others when it's false.
3274  * We print argument defaults only if print_defaults is true.
3275  * Function return value is the number of arguments printed.
3276  */
3277 static int
3279  bool print_table_args, bool print_defaults)
3280 {
3281  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3282  int numargs;
3283  Oid *argtypes;
3284  char **argnames;
3285  char *argmodes;
3286  int insertorderbyat = -1;
3287  int argsprinted;
3288  int inputargno;
3289  int nlackdefaults;
3290  List *argdefaults = NIL;
3291  ListCell *nextargdefault = NULL;
3292  int i;
3293 
3294  numargs = get_func_arg_info(proctup,
3295  &argtypes, &argnames, &argmodes);
3296 
3297  nlackdefaults = numargs;
3298  if (print_defaults && proc->pronargdefaults > 0)
3299  {
3300  Datum proargdefaults;
3301  bool isnull;
3302 
3303  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3304  Anum_pg_proc_proargdefaults,
3305  &isnull);
3306  if (!isnull)
3307  {
3308  char *str;
3309 
3310  str = TextDatumGetCString(proargdefaults);
3311  argdefaults = castNode(List, stringToNode(str));
3312  pfree(str);
3313  nextargdefault = list_head(argdefaults);
3314  /* nlackdefaults counts only *input* arguments lacking defaults */
3315  nlackdefaults = proc->pronargs - list_length(argdefaults);
3316  }
3317  }
3318 
3319  /* Check for special treatment of ordered-set aggregates */
3320  if (proc->prokind == PROKIND_AGGREGATE)
3321  {
3322  HeapTuple aggtup;
3323  Form_pg_aggregate agg;
3324 
3325  aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(proc->oid));
3326  if (!HeapTupleIsValid(aggtup))
3327  elog(ERROR, "cache lookup failed for aggregate %u",
3328  proc->oid);
3329  agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3330  if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3331  insertorderbyat = agg->aggnumdirectargs;
3332  ReleaseSysCache(aggtup);
3333  }
3334 
3335  argsprinted = 0;
3336  inputargno = 0;
3337  for (i = 0; i < numargs; i++)
3338  {
3339  Oid argtype = argtypes[i];
3340  char *argname = argnames ? argnames[i] : NULL;
3341  char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3342  const char *modename;
3343  bool isinput;
3344 
3345  switch (argmode)
3346  {
3347  case PROARGMODE_IN:
3348 
3349  /*
3350  * For procedures, explicitly mark all argument modes, so as
3351  * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3352  */
3353  if (proc->prokind == PROKIND_PROCEDURE)
3354  modename = "IN ";
3355  else
3356  modename = "";
3357  isinput = true;
3358  break;
3359  case PROARGMODE_INOUT:
3360  modename = "INOUT ";
3361  isinput = true;
3362  break;
3363  case PROARGMODE_OUT:
3364  modename = "OUT ";
3365  isinput = false;
3366  break;
3367  case PROARGMODE_VARIADIC:
3368  modename = "VARIADIC ";
3369  isinput = true;
3370  break;
3371  case PROARGMODE_TABLE:
3372  modename = "";
3373  isinput = false;
3374  break;
3375  default:
3376  elog(ERROR, "invalid parameter mode '%c'", argmode);
3377  modename = NULL; /* keep compiler quiet */
3378  isinput = false;
3379  break;
3380  }
3381  if (isinput)
3382  inputargno++; /* this is a 1-based counter */
3383 
3384  if (print_table_args != (argmode == PROARGMODE_TABLE))
3385  continue;
3386 
3387  if (argsprinted == insertorderbyat)
3388  {
3389  if (argsprinted)
3390  appendStringInfoChar(buf, ' ');
3391  appendStringInfoString(buf, "ORDER BY ");
3392  }
3393  else if (argsprinted)
3394  appendStringInfoString(buf, ", ");
3395 
3396  appendStringInfoString(buf, modename);
3397  if (argname && argname[0])
3398  appendStringInfo(buf, "%s ", quote_identifier(argname));
3400  if (print_defaults && isinput && inputargno > nlackdefaults)
3401  {
3402  Node *expr;
3403 
3404  Assert(nextargdefault != NULL);
3405  expr = (Node *) lfirst(nextargdefault);
3406  nextargdefault = lnext(argdefaults, nextargdefault);
3407 
3408  appendStringInfo(buf, " DEFAULT %s",
3409  deparse_expression(expr, NIL, false, false));
3410  }
3411  argsprinted++;
3412 
3413  /* nasty hack: print the last arg twice for variadic ordered-set agg */
3414  if (argsprinted == insertorderbyat && i == numargs - 1)
3415  {
3416  i--;
3417  /* aggs shouldn't have defaults anyway, but just to be sure ... */
3418  print_defaults = false;
3419  }
3420  }
3421 
3422  return argsprinted;
3423 }
3424 
3425 static bool
3426 is_input_argument(int nth, const char *argmodes)
3427 {
3428  return (!argmodes
3429  || argmodes[nth] == PROARGMODE_IN
3430  || argmodes[nth] == PROARGMODE_INOUT
3431  || argmodes[nth] == PROARGMODE_VARIADIC);
3432 }
3433 
3434 /*
3435  * Append used transformed types to specified buffer
3436  */
3437 static void
3439 {
3440  Oid *trftypes;
3441  int ntypes;
3442 
3443  ntypes = get_func_trftypes(proctup, &trftypes);
3444  if (ntypes > 0)
3445  {
3446  int i;
3447 
3448  appendStringInfoString(buf, " TRANSFORM ");
3449  for (i = 0; i < ntypes; i++)
3450  {
3451  if (i != 0)
3452  appendStringInfoString(buf, ", ");
3453  appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3454  }
3455  appendStringInfoChar(buf, '\n');
3456  }
3457 }
3458 
3459 /*
3460  * Get textual representation of a function argument's default value. The
3461  * second argument of this function is the argument number among all arguments
3462  * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3463  * how information_schema.sql uses it.
3464  */
3465 Datum
3467 {
3468  Oid funcid = PG_GETARG_OID(0);
3469  int32 nth_arg = PG_GETARG_INT32(1);
3470  HeapTuple proctup;
3471  Form_pg_proc proc;
3472  int numargs;
3473  Oid *argtypes;
3474  char **argnames;
3475  char *argmodes;
3476  int i;
3477  List *argdefaults;
3478  Node *node;
3479  char *str;
3480  int nth_inputarg;
3481  Datum proargdefaults;
3482  bool isnull;
3483  int nth_default;
3484 
3485  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3486  if (!HeapTupleIsValid(proctup))
3487  PG_RETURN_NULL();
3488 
3489  numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3490  if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3491  {
3492  ReleaseSysCache(proctup);
3493  PG_RETURN_NULL();
3494  }
3495 
3496  nth_inputarg = 0;
3497  for (i = 0; i < nth_arg; i++)
3498  if (is_input_argument(i, argmodes))
3499  nth_inputarg++;
3500 
3501  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3502  Anum_pg_proc_proargdefaults,
3503  &isnull);
3504  if (isnull)
3505  {
3506  ReleaseSysCache(proctup);
3507  PG_RETURN_NULL();
3508  }
3509 
3510  str = TextDatumGetCString(proargdefaults);
3511  argdefaults = castNode(List, stringToNode(str));
3512  pfree(str);
3513 
3514  proc = (Form_pg_proc) GETSTRUCT(proctup);
3515 
3516  /*
3517  * Calculate index into proargdefaults: proargdefaults corresponds to the
3518  * last N input arguments, where N = pronargdefaults.
3519  */
3520  nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3521 
3522  if (nth_default < 0 || nth_default >= list_length(argdefaults))
3523  {
3524  ReleaseSysCache(proctup);
3525  PG_RETURN_NULL();
3526  }
3527  node = list_nth(argdefaults, nth_default);
3528  str = deparse_expression(node, NIL, false, false);
3529 
3530  ReleaseSysCache(proctup);
3531 
3533 }
3534 
3535 static void
3537 {
3538  int numargs;
3539  Oid *argtypes;
3540  char **argnames;
3541  char *argmodes;
3542  deparse_namespace dpns = {0};
3543  Datum tmp;
3544  Node *n;
3545 
3546  dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3547  numargs = get_func_arg_info(proctup,
3548  &argtypes, &argnames, &argmodes);
3549  dpns.numargs = numargs;
3550  dpns.argnames = argnames;
3551 
3552  tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3554 
3555  if (IsA(n, List))
3556  {
3557  List *stmts;
3558  ListCell *lc;
3559 
3560  stmts = linitial(castNode(List, n));
3561 
3562  appendStringInfoString(buf, "BEGIN ATOMIC\n");
3563 
3564  foreach(lc, stmts)
3565  {
3566  Query *query = lfirst_node(Query, lc);
3567 
3568  /* It seems advisable to get at least AccessShareLock on rels */
3569  AcquireRewriteLocks(query, false, false);
3570  get_query_def(query, buf, list_make1(&dpns), NULL, false,
3572  appendStringInfoChar(buf, ';');
3573  appendStringInfoChar(buf, '\n');
3574  }
3575 
3576  appendStringInfoString(buf, "END");
3577  }
3578  else
3579  {
3580  Query *query = castNode(Query, n);
3581 
3582  /* It seems advisable to get at least AccessShareLock on rels */
3583  AcquireRewriteLocks(query, false, false);
3584  get_query_def(query, buf, list_make1(&dpns), NULL, false,
3585  0, WRAP_COLUMN_DEFAULT, 0);
3586  }
3587 }
3588 
3589 Datum
3591 {
3592  Oid funcid = PG_GETARG_OID(0);
3594  HeapTuple proctup;
3595  bool isnull;
3596 
3597  initStringInfo(&buf);
3598 
3599  /* Look up the function */
3600  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3601  if (!HeapTupleIsValid(proctup))
3602  PG_RETURN_NULL();
3603 
3604  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3605  if (isnull)
3606  {
3607  ReleaseSysCache(proctup);
3608  PG_RETURN_NULL();
3609  }
3610 
3611  print_function_sqlbody(&buf, proctup);
3612 
3613  ReleaseSysCache(proctup);
3614 
3616 }
3617 
3618 
3619 /*
3620  * deparse_expression - General utility for deparsing expressions
3621  *
3622  * calls deparse_expression_pretty with all prettyPrinting disabled
3623  */
3624 char *
3625 deparse_expression(Node *expr, List *dpcontext,
3626  bool forceprefix, bool showimplicit)
3627 {
3628  return deparse_expression_pretty(expr, dpcontext, forceprefix,
3629  showimplicit, 0, 0);
3630 }
3631 
3632 /* ----------
3633  * deparse_expression_pretty - General utility for deparsing expressions
3634  *
3635  * expr is the node tree to be deparsed. It must be a transformed expression
3636  * tree (ie, not the raw output of gram.y).
3637  *
3638  * dpcontext is a list of deparse_namespace nodes representing the context
3639  * for interpreting Vars in the node tree. It can be NIL if no Vars are
3640  * expected.
3641  *
3642  * forceprefix is true to force all Vars to be prefixed with their table names.
3643  *
3644  * showimplicit is true to force all implicit casts to be shown explicitly.
3645  *
3646  * Tries to pretty up the output according to prettyFlags and startIndent.
3647  *
3648  * The result is a palloc'd string.
3649  * ----------
3650  */
3651 static char *
3653  bool forceprefix, bool showimplicit,
3654  int prettyFlags, int startIndent)
3655 {
3658 
3659  initStringInfo(&buf);
3660  context.buf = &buf;
3661  context.namespaces = dpcontext;
3662  context.windowClause = NIL;
3663  context.windowTList = NIL;
3664  context.varprefix = forceprefix;
3665  context.prettyFlags = prettyFlags;
3666  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3667  context.indentLevel = startIndent;
3668  context.special_exprkind = EXPR_KIND_NONE;
3669  context.appendparents = NULL;
3670 
3671  get_rule_expr(expr, &context, showimplicit);
3672 
3673  return buf.data;
3674 }
3675 
3676 /* ----------
3677  * deparse_context_for - Build deparse context for a single relation
3678  *
3679  * Given the reference name (alias) and OID of a relation, build deparsing
3680  * context for an expression referencing only that relation (as varno 1,
3681  * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3682  * ----------
3683  */
3684 List *
3685 deparse_context_for(const char *aliasname, Oid relid)
3686 {
3687  deparse_namespace *dpns;
3688  RangeTblEntry *rte;
3689 
3690  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3691 
3692  /* Build a minimal RTE for the rel */
3693  rte = makeNode(RangeTblEntry);
3694  rte->rtekind = RTE_RELATION;
3695  rte->relid = relid;
3696  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3697  rte->rellockmode = AccessShareLock;
3698  rte->alias = makeAlias(aliasname, NIL);
3699  rte->eref = rte->alias;
3700  rte->lateral = false;
3701  rte->inh = false;
3702  rte->inFromCl = true;
3703 
3704  /* Build one-element rtable */
3705  dpns->rtable = list_make1(rte);
3706  dpns->subplans = NIL;
3707  dpns->ctes = NIL;
3708  dpns->appendrels = NULL;
3709  set_rtable_names(dpns, NIL, NULL);
3711 
3712  /* Return a one-deep namespace stack */
3713  return list_make1(dpns);
3714 }
3715 
3716 /*
3717  * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3718  *
3719  * When deparsing an expression in a Plan tree, we use the plan's rangetable
3720  * to resolve names of simple Vars. The initialization of column names for
3721  * this is rather expensive if the rangetable is large, and it'll be the same
3722  * for every expression in the Plan tree; so we do it just once and re-use
3723  * the result of this function for each expression. (Note that the result
3724  * is not usable until set_deparse_context_plan() is applied to it.)
3725  *
3726  * In addition to the PlannedStmt, pass the per-RTE alias names
3727  * assigned by a previous call to select_rtable_names_for_explain.
3728  */
3729 List *
3731 {
3732  deparse_namespace *dpns;
3733 
3734  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3735 
3736  /* Initialize fields that stay the same across the whole plan tree */
3737  dpns->rtable = pstmt->rtable;
3738  dpns->rtable_names = rtable_names;
3739  dpns->subplans = pstmt->subplans;
3740  dpns->ctes = NIL;
3741  if (pstmt->appendRelations)
3742  {
3743  /* Set up the array, indexed by child relid */
3744  int ntables = list_length(dpns->rtable);
3745  ListCell *lc;
3746 
3747  dpns->appendrels = (AppendRelInfo **)
3748  palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3749  foreach(lc, pstmt->appendRelations)
3750  {
3751  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3752  Index crelid = appinfo->child_relid;
3753 
3754  Assert(crelid > 0 && crelid <= ntables);
3755  Assert(dpns->appendrels[crelid] == NULL);
3756  dpns->appendrels[crelid] = appinfo;
3757  }
3758  }
3759  else
3760  dpns->appendrels = NULL; /* don't need it */
3761 
3762  /*
3763  * Set up column name aliases. We will get rather bogus results for join
3764  * RTEs, but that doesn't matter because plan trees don't contain any join
3765  * alias Vars.
3766  */
3768 
3769  /* Return a one-deep namespace stack */
3770  return list_make1(dpns);
3771 }
3772 
3773 /*
3774  * set_deparse_context_plan - Specify Plan node containing expression
3775  *
3776  * When deparsing an expression in a Plan tree, we might have to resolve
3777  * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
3778  * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
3779  * can be resolved by drilling down into the left and right child plans.
3780  * Similarly, INDEX_VAR references can be resolved by reference to the
3781  * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3782  * ForeignScan and CustomScan nodes. (Note that we don't currently support
3783  * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3784  * for those, we can only deparse the indexqualorig fields, which won't
3785  * contain INDEX_VAR Vars.)
3786  *
3787  * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3788  * the most-closely-nested first. This is needed to resolve PARAM_EXEC
3789  * Params. Note we assume that all the Plan nodes share the same rtable.
3790  *
3791  * Once this function has been called, deparse_expression() can be called on
3792  * subsidiary expression(s) of the specified Plan node. To deparse
3793  * expressions of a different Plan node in the same Plan tree, re-call this
3794  * function to identify the new parent Plan node.
3795  *
3796  * The result is the same List passed in; this is a notational convenience.
3797  */
3798 List *
3799 set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3800 {
3801  deparse_namespace *dpns;
3802 
3803  /* Should always have one-entry namespace list for Plan deparsing */
3804  Assert(list_length(dpcontext) == 1);
3805  dpns = (deparse_namespace *) linitial(dpcontext);
3806 
3807  /* Set our attention on the specific plan node passed in */
3808  dpns->ancestors = ancestors;
3809  set_deparse_plan(dpns, plan);
3810 
3811  return dpcontext;
3812 }
3813 
3814 /*
3815  * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3816  *
3817  * Determine the relation aliases we'll use during an EXPLAIN operation.
3818  * This is just a frontend to set_rtable_names. We have to expose the aliases
3819  * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3820  */
3821 List *
3823 {
3824  deparse_namespace dpns;
3825 
3826  memset(&dpns, 0, sizeof(dpns));
3827  dpns.rtable = rtable;
3828  dpns.subplans = NIL;
3829  dpns.ctes = NIL;
3830  dpns.appendrels = NULL;
3831  set_rtable_names(&dpns, NIL, rels_used);
3832  /* We needn't bother computing column aliases yet */
3833 
3834  return dpns.rtable_names;
3835 }
3836 
3837 /*
3838  * set_rtable_names: select RTE aliases to be used in printing a query
3839  *
3840  * We fill in dpns->rtable_names with a list of names that is one-for-one with
3841  * the already-filled dpns->rtable list. Each RTE name is unique among those
3842  * in the new namespace plus any ancestor namespaces listed in
3843  * parent_namespaces.
3844  *
3845  * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3846  *
3847  * Note that this function is only concerned with relation names, not column
3848  * names.
3849  */
3850 static void
3851 set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3852  Bitmapset *rels_used)
3853 {
3854  HASHCTL hash_ctl;
3855  HTAB *names_hash;
3856  NameHashEntry *hentry;
3857  bool found;
3858  int rtindex;
3859  ListCell *lc;
3860 
3861  dpns->rtable_names = NIL;
3862  /* nothing more to do if empty rtable */
3863  if (dpns->rtable == NIL)
3864  return;
3865 
3866  /*
3867  * We use a hash table to hold known names, so that this process is O(N)
3868  * not O(N^2) for N names.
3869  */
3870  hash_ctl.keysize = NAMEDATALEN;
3871  hash_ctl.entrysize = sizeof(NameHashEntry);
3872  hash_ctl.hcxt = CurrentMemoryContext;
3873  names_hash = hash_create("set_rtable_names names",
3874  list_length(dpns->rtable),
3875  &hash_ctl,
3877 
3878  /* Preload the hash table with names appearing in parent_namespaces */
3879  foreach(lc, parent_namespaces)
3880  {
3881  deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3882  ListCell *lc2;
3883 
3884  foreach(lc2, olddpns->rtable_names)
3885  {
3886  char *oldname = (char *) lfirst(lc2);
3887 
3888  if (oldname == NULL)
3889  continue;
3890  hentry = (NameHashEntry *) hash_search(names_hash,
3891  oldname,
3892  HASH_ENTER,
3893  &found);
3894  /* we do not complain about duplicate names in parent namespaces */
3895  hentry->counter = 0;
3896  }
3897  }
3898 
3899  /* Now we can scan the rtable */
3900  rtindex = 1;
3901  foreach(lc, dpns->rtable)
3902  {
3903  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3904  char *refname;
3905 
3906  /* Just in case this takes an unreasonable amount of time ... */
3908 
3909  if (rels_used && !bms_is_member(rtindex, rels_used))
3910  {
3911  /* Ignore unreferenced RTE */
3912  refname = NULL;
3913  }
3914  else if (rte->alias)
3915  {
3916  /* If RTE has a user-defined alias, prefer that */
3917  refname = rte->alias->aliasname;
3918  }
3919  else if (rte->rtekind == RTE_RELATION)
3920  {
3921  /* Use the current actual name of the relation */
3922  refname = get_rel_name(rte->relid);
3923  }
3924  else if (rte->rtekind == RTE_JOIN)
3925  {
3926  /* Unnamed join has no refname */
3927  refname = NULL;
3928  }
3929  else
3930  {
3931  /* Otherwise use whatever the parser assigned */
3932  refname = rte->eref->aliasname;
3933  }
3934 
3935  /*
3936  * If the selected name isn't unique, append digits to make it so, and
3937  * make a new hash entry for it once we've got a unique name. For a
3938  * very long input name, we might have to truncate to stay within
3939  * NAMEDATALEN.
3940  */
3941  if (refname)
3942  {
3943  hentry = (NameHashEntry *) hash_search(names_hash,
3944  refname,
3945  HASH_ENTER,
3946  &found);
3947  if (found)
3948  {
3949  /* Name already in use, must choose a new one */
3950  int refnamelen = strlen(refname);
3951  char *modname = (char *) palloc(refnamelen + 16);
3952  NameHashEntry *hentry2;
3953 
3954  do
3955  {
3956  hentry->counter++;
3957  for (;;)
3958  {
3959  memcpy(modname, refname, refnamelen);
3960  sprintf(modname + refnamelen, "_%d", hentry->counter);
3961  if (strlen(modname) < NAMEDATALEN)
3962  break;
3963  /* drop chars from refname to keep all the digits */
3964  refnamelen = pg_mbcliplen(refname, refnamelen,
3965  refnamelen - 1);
3966  }
3967  hentry2 = (NameHashEntry *) hash_search(names_hash,
3968  modname,
3969  HASH_ENTER,
3970  &found);
3971  } while (found);
3972  hentry2->counter = 0; /* init new hash entry */
3973  refname = modname;
3974  }
3975  else
3976  {
3977  /* Name not previously used, need only initialize hentry */
3978  hentry->counter = 0;
3979  }
3980  }
3981 
3982  dpns->rtable_names = lappend(dpns->rtable_names, refname);
3983  rtindex++;
3984  }
3985 
3986  hash_destroy(names_hash);
3987 }
3988 
3989 /*
3990  * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
3991  *
3992  * For convenience, this is defined to initialize the deparse_namespace struct
3993  * from scratch.
3994  */
3995 static void
3997  List *parent_namespaces)
3998 {
3999  ListCell *lc;
4000  ListCell *lc2;
4001 
4002  /* Initialize *dpns and fill rtable/ctes links */
4003  memset(dpns, 0, sizeof(deparse_namespace));
4004  dpns->rtable = query->rtable;
4005  dpns->subplans = NIL;
4006  dpns->ctes = query->cteList;
4007  dpns->appendrels = NULL;
4008 
4009  /* Assign a unique relation alias to each RTE */
4010  set_rtable_names(dpns, parent_namespaces, NULL);
4011 
4012  /* Initialize dpns->rtable_columns to contain zeroed structs */
4013  dpns->rtable_columns = NIL;
4014  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4015  dpns->rtable_columns = lappend(dpns->rtable_columns,
4016  palloc0(sizeof(deparse_columns)));
4017 
4018  /* If it's a utility query, it won't have a jointree */
4019  if (query->jointree)
4020  {
4021  /* Detect whether global uniqueness of USING names is needed */
4022  dpns->unique_using =
4023  has_dangerous_join_using(dpns, (Node *) query->jointree);
4024 
4025  /*
4026  * Select names for columns merged by USING, via a recursive pass over
4027  * the query jointree.
4028  */
4029  set_using_names(dpns, (Node *) query->jointree, NIL);
4030  }
4031 
4032  /*
4033  * Now assign remaining column aliases for each RTE. We do this in a
4034  * linear scan of the rtable, so as to process RTEs whether or not they
4035  * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4036  * etc). JOIN RTEs must be processed after their children, but this is
4037  * okay because they appear later in the rtable list than their children
4038  * (cf Asserts in identify_join_columns()).
4039  */
4040  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4041  {
4042  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4043  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4044 
4045  if (rte->rtekind == RTE_JOIN)
4046  set_join_column_names(dpns, rte, colinfo);
4047  else
4048  set_relation_column_names(dpns, rte, colinfo);
4049  }
4050 }
4051 
4052 /*
4053  * set_simple_column_names: fill in column aliases for non-query situations
4054  *
4055  * This handles EXPLAIN and cases where we only have relation RTEs. Without
4056  * a join tree, we can't do anything smart about join RTEs, but we don't
4057  * need to (note that EXPLAIN should never see join alias Vars anyway).
4058  * If we do hit a join RTE we'll just process it like a non-table base RTE.
4059  */
4060 static void
4062 {
4063  ListCell *lc;
4064  ListCell *lc2;
4065 
4066  /* Initialize dpns->rtable_columns to contain zeroed structs */
4067  dpns->rtable_columns = NIL;
4068  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4069  dpns->rtable_columns = lappend(dpns->rtable_columns,
4070  palloc0(sizeof(deparse_columns)));
4071 
4072  /* Assign unique column aliases within each RTE */
4073  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4074  {
4075  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4076  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4077 
4078  set_relation_column_names(dpns, rte, colinfo);
4079  }
4080 }
4081 
4082 /*
4083  * has_dangerous_join_using: search jointree for unnamed JOIN USING
4084  *
4085  * Merged columns of a JOIN USING may act differently from either of the input
4086  * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4087  * because an implicit coercion of the underlying input column is required.
4088  * In such a case the column must be referenced as a column of the JOIN not as
4089  * a column of either input. And this is problematic if the join is unnamed
4090  * (alias-less): we cannot qualify the column's name with an RTE name, since
4091  * there is none. (Forcibly assigning an alias to the join is not a solution,
4092  * since that will prevent legal references to tables below the join.)
4093  * To ensure that every column in the query is unambiguously referenceable,
4094  * we must assign such merged columns names that are globally unique across
4095  * the whole query, aliasing other columns out of the way as necessary.
4096  *
4097  * Because the ensuing re-aliasing is fairly damaging to the readability of
4098  * the query, we don't do this unless we have to. So, we must pre-scan
4099  * the join tree to see if we have to, before starting set_using_names().
4100  */
4101 static bool
4103 {
4104  if (IsA(jtnode, RangeTblRef))
4105  {
4106  /* nothing to do here */
4107  }
4108  else if (IsA(jtnode, FromExpr))
4109  {
4110  FromExpr *f = (FromExpr *) jtnode;
4111  ListCell *lc;
4112 
4113  foreach(lc, f->fromlist)
4114  {
4115  if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4116  return true;
4117  }
4118  }
4119  else if (IsA(jtnode, JoinExpr))
4120  {
4121  JoinExpr *j = (JoinExpr *) jtnode;
4122 
4123  /* Is it an unnamed JOIN with USING? */
4124  if (j->alias == NULL && j->usingClause)
4125  {
4126  /*
4127  * Yes, so check each join alias var to see if any of them are not
4128  * simple references to underlying columns. If so, we have a
4129  * dangerous situation and must pick unique aliases.
4130  */
4131  RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4132 
4133  /* We need only examine the merged columns */
4134  for (int i = 0; i < jrte->joinmergedcols; i++)
4135  {
4136  Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4137 
4138  if (!IsA(aliasvar, Var))
4139  return true;
4140  }
4141  }
4142 
4143  /* Nope, but inspect children */
4144  if (has_dangerous_join_using(dpns, j->larg))
4145  return true;
4146  if (has_dangerous_join_using(dpns, j->rarg))
4147  return true;
4148  }
4149  else
4150  elog(ERROR, "unrecognized node type: %d",
4151  (int) nodeTag(jtnode));
4152  return false;
4153 }
4154 
4155 /*
4156  * set_using_names: select column aliases to be used for merged USING columns
4157  *
4158  * We do this during a recursive descent of the query jointree.
4159  * dpns->unique_using must already be set to determine the global strategy.
4160  *
4161  * Column alias info is saved in the dpns->rtable_columns list, which is
4162  * assumed to be filled with pre-zeroed deparse_columns structs.
4163  *
4164  * parentUsing is a list of all USING aliases assigned in parent joins of
4165  * the current jointree node. (The passed-in list must not be modified.)
4166  */
4167 static void
4168 set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4169 {
4170  if (IsA(jtnode, RangeTblRef))
4171  {
4172  /* nothing to do now */
4173  }
4174  else if (IsA(jtnode, FromExpr))
4175  {
4176  FromExpr *f = (FromExpr *) jtnode;
4177  ListCell *lc;
4178 
4179  foreach(lc, f->fromlist)
4180  set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4181  }
4182  else if (IsA(jtnode, JoinExpr))
4183  {
4184  JoinExpr *j = (JoinExpr *) jtnode;
4185  RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4186  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4187  int *leftattnos;
4188  int *rightattnos;
4189  deparse_columns *leftcolinfo;
4190  deparse_columns *rightcolinfo;
4191  int i;
4192  ListCell *lc;
4193 
4194  /* Get info about the shape of the join */
4195  identify_join_columns(j, rte, colinfo);
4196  leftattnos = colinfo->leftattnos;
4197  rightattnos = colinfo->rightattnos;
4198 
4199  /* Look up the not-yet-filled-in child deparse_columns structs */
4200  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4201  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4202 
4203  /*
4204  * If this join is unnamed, then we cannot substitute new aliases at
4205  * this level, so any name requirements pushed down to here must be
4206  * pushed down again to the children.
4207  */
4208  if (rte->alias == NULL)
4209  {
4210  for (i = 0; i < colinfo->num_cols; i++)
4211  {
4212  char *colname = colinfo->colnames[i];
4213 
4214  if (colname == NULL)
4215  continue;
4216 
4217  /* Push down to left column, unless it's a system column */
4218  if (leftattnos[i] > 0)
4219  {
4220  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4221  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4222  }
4223 
4224  /* Same on the righthand side */
4225  if (rightattnos[i] > 0)
4226  {
4227  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4228  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4229  }
4230  }
4231  }
4232 
4233  /*
4234  * If there's a USING clause, select the USING column names and push
4235  * those names down to the children. We have two strategies:
4236  *
4237  * If dpns->unique_using is true, we force all USING names to be
4238  * unique across the whole query level. In principle we'd only need
4239  * the names of dangerous USING columns to be globally unique, but to
4240  * safely assign all USING names in a single pass, we have to enforce
4241  * the same uniqueness rule for all of them. However, if a USING
4242  * column's name has been pushed down from the parent, we should use
4243  * it as-is rather than making a uniqueness adjustment. This is
4244  * necessary when we're at an unnamed join, and it creates no risk of
4245  * ambiguity. Also, if there's a user-written output alias for a
4246  * merged column, we prefer to use that rather than the input name;
4247  * this simplifies the logic and seems likely to lead to less aliasing
4248  * overall.
4249  *
4250  * If dpns->unique_using is false, we only need USING names to be
4251  * unique within their own join RTE. We still need to honor
4252  * pushed-down names, though.
4253  *
4254  * Though significantly different in results, these two strategies are
4255  * implemented by the same code, with only the difference of whether
4256  * to put assigned names into dpns->using_names.
4257  */
4258  if (j->usingClause)
4259  {
4260  /* Copy the input parentUsing list so we don't modify it */
4261  parentUsing = list_copy(parentUsing);
4262 
4263  /* USING names must correspond to the first join output columns */
4264  expand_colnames_array_to(colinfo, list_length(j->usingClause));
4265  i = 0;
4266  foreach(lc, j->usingClause)
4267  {
4268  char *colname = strVal(lfirst(lc));
4269 
4270  /* Assert it's a merged column */
4271  Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4272 
4273  /* Adopt passed-down name if any, else select unique name */
4274  if (colinfo->colnames[i] != NULL)
4275  colname = colinfo->colnames[i];
4276  else
4277  {
4278  /* Prefer user-written output alias if any */
4279  if (rte->alias && i < list_length(rte->alias->colnames))
4280  colname = strVal(list_nth(rte->alias->colnames, i));
4281  /* Make it appropriately unique */
4282  colname = make_colname_unique(colname, dpns, colinfo);
4283  if (dpns->unique_using)
4284  dpns->using_names = lappend(dpns->using_names,
4285  colname);
4286  /* Save it as output column name, too */
4287  colinfo->colnames[i] = colname;
4288  }
4289 
4290  /* Remember selected names for use later */
4291  colinfo->usingNames = lappend(colinfo->usingNames, colname);
4292  parentUsing = lappend(parentUsing, colname);
4293 
4294  /* Push down to left column, unless it's a system column */
4295  if (leftattnos[i] > 0)
4296  {
4297  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4298  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4299  }
4300 
4301  /* Same on the righthand side */
4302  if (rightattnos[i] > 0)
4303  {
4304  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4305  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4306  }
4307 
4308  i++;
4309  }
4310  }
4311 
4312  /* Mark child deparse_columns structs with correct parentUsing info */
4313  leftcolinfo->parentUsing = parentUsing;
4314  rightcolinfo->parentUsing = parentUsing;
4315 
4316  /* Now recursively assign USING column names in children */
4317  set_using_names(dpns, j->larg, parentUsing);
4318  set_using_names(dpns, j->rarg, parentUsing);
4319  }
4320  else
4321  elog(ERROR, "unrecognized node type: %d",
4322  (int) nodeTag(jtnode));
4323 }
4324 
4325 /*
4326  * set_relation_column_names: select column aliases for a non-join RTE
4327  *
4328  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4329  * If any colnames entries are already filled in, those override local
4330  * choices.
4331  */
4332 static void
4334  deparse_columns *colinfo)
4335 {
4336  int ncolumns;
4337  char **real_colnames;
4338  bool changed_any;
4339  int noldcolumns;
4340  int i;
4341  int j;
4342 
4343  /*
4344  * Construct an array of the current "real" column names of the RTE.
4345  * real_colnames[] will be indexed by physical column number, with NULL
4346  * entries for dropped columns.
4347  */
4348  if (rte->rtekind == RTE_RELATION)
4349  {
4350  /* Relation --- look to the system catalogs for up-to-date info */
4351  Relation rel;
4352  TupleDesc tupdesc;
4353 
4354  rel = relation_open(rte->relid, AccessShareLock);
4355  tupdesc = RelationGetDescr(rel);
4356 
4357  ncolumns = tupdesc->natts;
4358  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4359 
4360  for (i = 0; i < ncolumns; i++)
4361  {
4362  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4363 
4364  if (attr->attisdropped)
4365  real_colnames[i] = NULL;
4366  else
4367  real_colnames[i] = pstrdup(NameStr(attr->attname));
4368  }
4370  }
4371  else
4372  {
4373  /* Otherwise get the column names from eref or expandRTE() */
4374  List *colnames;
4375  ListCell *lc;
4376 
4377  /*
4378  * Functions returning composites have the annoying property that some
4379  * of the composite type's columns might have been dropped since the
4380  * query was parsed. If possible, use expandRTE() to handle that
4381  * case, since it has the tedious logic needed to find out about
4382  * dropped columns. However, if we're explaining a plan, then we
4383  * don't have rte->functions because the planner thinks that won't be
4384  * needed later, and that breaks expandRTE(). So in that case we have
4385  * to rely on rte->eref, which may lead us to report a dropped
4386  * column's old name; that seems close enough for EXPLAIN's purposes.
4387  *
4388  * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4389  * which should be sufficiently up-to-date: no other RTE types can
4390  * have columns get dropped from under them after parsing.
4391  */
4392  if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4393  {
4394  /* Since we're not creating Vars, rtindex etc. don't matter */
4395  expandRTE(rte, 1, 0, -1, true /* include dropped */ ,
4396  &colnames, NULL);
4397  }
4398  else
4399  colnames = rte->eref->colnames;
4400 
4401  ncolumns = list_length(colnames);
4402  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4403 
4404  i = 0;
4405  foreach(lc, colnames)
4406  {
4407  /*
4408  * If the column name we find here is an empty string, then it's a
4409  * dropped column, so change to NULL.
4410  */
4411  char *cname = strVal(lfirst(lc));
4412 
4413  if (cname[0] == '\0')
4414  cname = NULL;
4415  real_colnames[i] = cname;
4416  i++;
4417  }
4418  }
4419 
4420  /*
4421  * Ensure colinfo->colnames has a slot for each column. (It could be long
4422  * enough already, if we pushed down a name for the last column.) Note:
4423  * it's possible that there are now more columns than there were when the
4424  * query was parsed, ie colnames could be longer than rte->eref->colnames.
4425  * We must assign unique aliases to the new columns too, else there could
4426  * be unresolved conflicts when the view/rule is reloaded.
4427  */
4428  expand_colnames_array_to(colinfo, ncolumns);
4429  Assert(colinfo->num_cols == ncolumns);
4430 
4431  /*
4432  * Make sufficiently large new_colnames and is_new_col arrays, too.
4433  *
4434  * Note: because we leave colinfo->num_new_cols zero until after the loop,
4435  * colname_is_unique will not consult that array, which is fine because it
4436  * would only be duplicate effort.
4437  */
4438  colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4439  colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4440 
4441  /*
4442  * Scan the columns, select a unique alias for each one, and store it in
4443  * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4444  * entries for dropped columns, the latter omits them. Also mark
4445  * new_colnames entries as to whether they are new since parse time; this
4446  * is the case for entries beyond the length of rte->eref->colnames.
4447  */
4448  noldcolumns = list_length(rte->eref->colnames);
4449  changed_any = false;
4450  j = 0;
4451  for (i = 0; i < ncolumns; i++)
4452  {
4453  char *real_colname = real_colnames[i];
4454  char *colname = colinfo->colnames[i];
4455 
4456  /* Skip dropped columns */
4457  if (real_colname == NULL)
4458  {
4459  Assert(colname == NULL); /* colnames[i] is already NULL */
4460  continue;
4461  }
4462 
4463  /* If alias already assigned, that's what to use */
4464  if (colname == NULL)
4465  {
4466  /* If user wrote an alias, prefer that over real column name */
4467  if (rte->alias && i < list_length(rte->alias->colnames))
4468  colname = strVal(list_nth(rte->alias->colnames, i));
4469  else
4470  colname = real_colname;
4471 
4472  /* Unique-ify and insert into colinfo */
4473  colname = make_colname_unique(colname, dpns, colinfo);
4474 
4475  colinfo->colnames[i] = colname;
4476  }
4477 
4478  /* Put names of non-dropped columns in new_colnames[] too */
4479  colinfo->new_colnames[j] = colname;
4480  /* And mark them as new or not */
4481  colinfo->is_new_col[j] = (i >= noldcolumns);
4482  j++;
4483 
4484  /* Remember if any assigned aliases differ from "real" name */
4485  if (!changed_any && strcmp(colname, real_colname) != 0)
4486  changed_any = true;
4487  }
4488 
4489  /*
4490  * Set correct length for new_colnames[] array. (Note: if columns have
4491  * been added, colinfo->num_cols includes them, which is not really quite
4492  * right but is harmless, since any new columns must be at the end where
4493  * they won't affect varattnos of pre-existing columns.)
4494  */
4495  colinfo->num_new_cols = j;
4496 
4497  /*
4498  * For a relation RTE, we need only print the alias column names if any
4499  * are different from the underlying "real" names. For a function RTE,
4500  * always emit a complete column alias list; this is to protect against
4501  * possible instability of the default column names (eg, from altering
4502  * parameter names). For tablefunc RTEs, we never print aliases, because
4503  * the column names are part of the clause itself. For other RTE types,
4504  * print if we changed anything OR if there were user-written column
4505  * aliases (since the latter would be part of the underlying "reality").
4506  */
4507  if (rte->rtekind == RTE_RELATION)
4508  colinfo->printaliases = changed_any;
4509  else if (rte->rtekind == RTE_FUNCTION)
4510  colinfo->printaliases = true;
4511  else if (rte->rtekind == RTE_TABLEFUNC)
4512  colinfo->printaliases = false;
4513  else if (rte->alias && rte->alias->colnames != NIL)
4514  colinfo->printaliases = true;
4515  else
4516  colinfo->printaliases = changed_any;
4517 }
4518 
4519 /*
4520  * set_join_column_names: select column aliases for a join RTE
4521  *
4522  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4523  * If any colnames entries are already filled in, those override local
4524  * choices. Also, names for USING columns were already chosen by
4525  * set_using_names(). We further expect that column alias selection has been
4526  * completed for both input RTEs.
4527  */
4528 static void
4530  deparse_columns *colinfo)
4531 {
4532  deparse_columns *leftcolinfo;
4533  deparse_columns *rightcolinfo;
4534  bool changed_any;
4535  int noldcolumns;
4536  int nnewcolumns;
4537  Bitmapset *leftmerged = NULL;
4538  Bitmapset *rightmerged = NULL;
4539  int i;
4540  int j;
4541  int ic;
4542  int jc;
4543 
4544  /* Look up the previously-filled-in child deparse_columns structs */
4545  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4546  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4547 
4548  /*
4549  * Ensure colinfo->colnames has a slot for each column. (It could be long
4550  * enough already, if we pushed down a name for the last column.) Note:
4551  * it's possible that one or both inputs now have more columns than there
4552  * were when the query was parsed, but we'll deal with that below. We
4553  * only need entries in colnames for pre-existing columns.
4554  */
4555  noldcolumns = list_length(rte->eref->colnames);
4556  expand_colnames_array_to(colinfo, noldcolumns);
4557  Assert(colinfo->num_cols == noldcolumns);
4558 
4559  /*
4560  * Scan the join output columns, select an alias for each one, and store
4561  * it in colinfo->colnames. If there are USING columns, set_using_names()
4562  * already selected their names, so we can start the loop at the first
4563  * non-merged column.
4564  */
4565  changed_any = false;
4566  for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4567  {
4568  char *colname = colinfo->colnames[i];
4569  char *real_colname;
4570 
4571  /* Join column must refer to at least one input column */
4572  Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4573 
4574  /* Get the child column name */
4575  if (colinfo->leftattnos[i] > 0)
4576  real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4577  else if (colinfo->rightattnos[i] > 0)
4578  real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4579  else
4580  {
4581  /* We're joining system columns --- use eref name */
4582  real_colname = strVal(list_nth(rte->eref->colnames, i));
4583  }
4584 
4585  /* If child col has been dropped, no need to assign a join colname */
4586  if (real_colname == NULL)
4587  {
4588  colinfo->colnames[i] = NULL;
4589  continue;
4590  }
4591 
4592  /* In an unnamed join, just report child column names as-is */
4593  if (rte->alias == NULL)
4594  {
4595  colinfo->colnames[i] = real_colname;
4596  continue;
4597  }
4598 
4599  /* If alias already assigned, that's what to use */
4600  if (colname == NULL)
4601  {
4602  /* If user wrote an alias, prefer that over real column name */
4603  if (rte->alias && i < list_length(rte->alias->colnames))
4604  colname = strVal(list_nth(rte->alias->colnames, i));
4605  else
4606  colname = real_colname;
4607 
4608  /* Unique-ify and insert into colinfo */
4609  colname = make_colname_unique(colname, dpns, colinfo);
4610 
4611  colinfo->colnames[i] = colname;
4612  }
4613 
4614  /* Remember if any assigned aliases differ from "real" name */
4615  if (!changed_any && strcmp(colname, real_colname) != 0)
4616  changed_any = true;
4617  }
4618 
4619  /*
4620  * Calculate number of columns the join would have if it were re-parsed
4621  * now, and create storage for the new_colnames and is_new_col arrays.
4622  *
4623  * Note: colname_is_unique will be consulting new_colnames[] during the
4624  * loops below, so its not-yet-filled entries must be zeroes.
4625  */
4626  nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4627  list_length(colinfo->usingNames);
4628  colinfo->num_new_cols = nnewcolumns;
4629  colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4630  colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4631 
4632  /*
4633  * Generating the new_colnames array is a bit tricky since any new columns
4634  * added since parse time must be inserted in the right places. This code
4635  * must match the parser, which will order a join's columns as merged
4636  * columns first (in USING-clause order), then non-merged columns from the
4637  * left input (in attnum order), then non-merged columns from the right
4638  * input (ditto). If one of the inputs is itself a join, its columns will
4639  * be ordered according to the same rule, which means newly-added columns
4640  * might not be at the end. We can figure out what's what by consulting
4641  * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4642  *
4643  * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4644  * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4645  * meanings for the current child RTE.
4646  */
4647 
4648  /* Handle merged columns; they are first and can't be new */
4649  i = j = 0;
4650  while (i < noldcolumns &&
4651  colinfo->leftattnos[i] != 0 &&
4652  colinfo->rightattnos[i] != 0)
4653  {
4654  /* column name is already determined and known unique */
4655  colinfo->new_colnames[j] = colinfo->colnames[i];
4656  colinfo->is_new_col[j] = false;
4657 
4658  /* build bitmapsets of child attnums of merged columns */
4659  if (colinfo->leftattnos[i] > 0)
4660  leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4661  if (colinfo->rightattnos[i] > 0)
4662  rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4663 
4664  i++, j++;
4665  }
4666 
4667  /* Handle non-merged left-child columns */
4668  ic = 0;
4669  for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4670  {
4671  char *child_colname = leftcolinfo->new_colnames[jc];
4672 
4673  if (!leftcolinfo->is_new_col[jc])
4674  {
4675  /* Advance ic to next non-dropped old column of left child */
4676  while (ic < leftcolinfo->num_cols &&
4677  leftcolinfo->colnames[ic] == NULL)
4678  ic++;
4679  Assert(ic < leftcolinfo->num_cols);
4680  ic++;
4681  /* If it is a merged column, we already processed it */
4682  if (bms_is_member(ic, leftmerged))
4683  continue;
4684  /* Else, advance i to the corresponding existing join column */
4685  while (i < colinfo->num_cols &&
4686  colinfo->colnames[i] == NULL)
4687  i++;
4688  Assert(i < colinfo->num_cols);
4689  Assert(ic == colinfo->leftattnos[i]);
4690  /* Use the already-assigned name of this column */
4691  colinfo->new_colnames[j] = colinfo->colnames[i];
4692  i++;
4693  }
4694  else
4695  {
4696  /*
4697  * Unique-ify the new child column name and assign, unless we're
4698  * in an unnamed join, in which case just copy
4699  */
4700  if (rte->alias != NULL)
4701  {
4702  colinfo->new_colnames[j] =
4703  make_colname_unique(child_colname, dpns, colinfo);
4704  if (!changed_any &&
4705  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4706  changed_any = true;
4707  }
4708  else
4709  colinfo->new_colnames[j] = child_colname;
4710  }
4711 
4712  colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4713  j++;
4714  }
4715 
4716  /* Handle non-merged right-child columns in exactly the same way */
4717  ic = 0;
4718  for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4719  {
4720  char *child_colname = rightcolinfo->new_colnames[jc];
4721 
4722  if (!rightcolinfo->is_new_col[jc])
4723  {
4724  /* Advance ic to next non-dropped old column of right child */
4725  while (ic < rightcolinfo->num_cols &&
4726  rightcolinfo->colnames[ic] == NULL)
4727  ic++;
4728  Assert(ic < rightcolinfo->num_cols);
4729  ic++;
4730  /* If it is a merged column, we already processed it */
4731  if (bms_is_member(ic, rightmerged))
4732  continue;
4733  /* Else, advance i to the corresponding existing join column */
4734  while (i < colinfo->num_cols &&
4735  colinfo->colnames[i] == NULL)
4736  i++;
4737  Assert(i < colinfo->num_cols);
4738  Assert(ic == colinfo->rightattnos[i]);
4739  /* Use the already-assigned name of this column */
4740  colinfo->new_colnames[j] = colinfo->colnames[i];
4741  i++;
4742  }
4743  else
4744  {
4745  /*
4746  * Unique-ify the new child column name and assign, unless we're
4747  * in an unnamed join, in which case just copy
4748  */
4749  if (rte->alias != NULL)
4750  {
4751  colinfo->new_colnames[j] =
4752  make_colname_unique(child_colname, dpns, colinfo);
4753  if (!changed_any &&
4754  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4755  changed_any = true;
4756  }
4757  else
4758  colinfo->new_colnames[j] = child_colname;
4759  }
4760 
4761  colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4762  j++;
4763  }
4764 
4765  /* Assert we processed the right number of columns */
4766 #ifdef USE_ASSERT_CHECKING
4767  while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4768  i++;
4769  Assert(i == colinfo->num_cols);
4770  Assert(j == nnewcolumns);
4771 #endif
4772 
4773  /*
4774  * For a named join, print column aliases if we changed any from the child
4775  * names. Unnamed joins cannot print aliases.
4776  */
4777  if (rte->alias != NULL)
4778  colinfo->printaliases = changed_any;
4779  else
4780  colinfo->printaliases = false;
4781 }
4782 
4783 /*
4784  * colname_is_unique: is colname distinct from already-chosen column names?
4785  *
4786  * dpns is query-wide info, colinfo is for the column's RTE
4787  */
4788 static bool
4789 colname_is_unique(const char *colname, deparse_namespace *dpns,
4790  deparse_columns *colinfo)
4791 {
4792  int i;
4793  ListCell *lc;
4794 
4795  /* Check against already-assigned column aliases within RTE */
4796  for (i = 0; i < colinfo->num_cols; i++)
4797  {
4798  char *oldname = colinfo->colnames[i];
4799 
4800  if (oldname && strcmp(oldname, colname) == 0)
4801  return false;
4802  }
4803 
4804  /*
4805  * If we're building a new_colnames array, check that too (this will be
4806  * partially but not completely redundant with the previous checks)
4807  */
4808  for (i = 0; i < colinfo->num_new_cols; i++)
4809  {
4810  char *oldname = colinfo->new_colnames[i];
4811 
4812  if (oldname && strcmp(oldname, colname) == 0)
4813  return false;
4814  }
4815 
4816  /* Also check against USING-column names that must be globally unique */
4817  foreach(lc, dpns->using_names)
4818  {
4819  char *oldname = (char *) lfirst(lc);
4820 
4821  if (strcmp(oldname, colname) == 0)
4822  return false;
4823  }
4824 
4825  /* Also check against names already assigned for parent-join USING cols */
4826  foreach(lc, colinfo->parentUsing)
4827  {
4828  char *oldname = (char *) lfirst(lc);
4829 
4830  if (strcmp(oldname, colname) == 0)
4831  return false;
4832  }
4833 
4834  return true;
4835 }
4836 
4837 /*
4838  * make_colname_unique: modify colname if necessary to make it unique
4839  *
4840  * dpns is query-wide info, colinfo is for the column's RTE
4841  */
4842 static char *
4844  deparse_columns *colinfo)
4845 {
4846  /*
4847  * If the selected name isn't unique, append digits to make it so. For a
4848  * very long input name, we might have to truncate to stay within
4849  * NAMEDATALEN.
4850  */
4851  if (!colname_is_unique(colname, dpns, colinfo))
4852  {
4853  int colnamelen = strlen(colname);
4854  char *modname = (char *) palloc(colnamelen + 16);
4855  int i = 0;
4856 
4857  do
4858  {
4859  i++;
4860  for (;;)
4861  {
4862  memcpy(modname, colname, colnamelen);
4863  sprintf(modname + colnamelen, "_%d", i);
4864  if (strlen(modname) < NAMEDATALEN)
4865  break;
4866  /* drop chars from colname to keep all the digits */
4867  colnamelen = pg_mbcliplen(colname, colnamelen,
4868  colnamelen - 1);
4869  }
4870  } while (!colname_is_unique(modname, dpns, colinfo));
4871  colname = modname;
4872  }
4873  return colname;
4874 }
4875 
4876 /*
4877  * expand_colnames_array_to: make colinfo->colnames at least n items long
4878  *
4879  * Any added array entries are initialized to zero.
4880  */
4881 static void
4883 {
4884  if (n > colinfo->num_cols)
4885  {
4886  if (colinfo->colnames == NULL)
4887  colinfo->colnames = palloc0_array(char *, n);
4888  else
4889  colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4890  colinfo->num_cols = n;
4891  }
4892 }
4893 
4894 /*
4895  * identify_join_columns: figure out where columns of a join come from
4896  *
4897  * Fills the join-specific fields of the colinfo struct, except for
4898  * usingNames which is filled later.
4899  */
4900 static void
4902  deparse_columns *colinfo)
4903 {
4904  int numjoincols;
4905  int jcolno;
4906  int rcolno;
4907  ListCell *lc;
4908 
4909  /* Extract left/right child RT indexes */
4910  if (IsA(j->larg, RangeTblRef))
4911  colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
4912  else if (IsA(j->larg, JoinExpr))
4913  colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
4914  else
4915  elog(ERROR, "unrecognized node type in jointree: %d",
4916  (int) nodeTag(j->larg));
4917  if (IsA(j->rarg, RangeTblRef))
4918  colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
4919  else if (IsA(j->rarg, JoinExpr))
4920  colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
4921  else
4922  elog(ERROR, "unrecognized node type in jointree: %d",
4923  (int) nodeTag(j->rarg));
4924 
4925  /* Assert children will be processed earlier than join in second pass */
4926  Assert(colinfo->leftrti < j->rtindex);
4927  Assert(colinfo->rightrti < j->rtindex);
4928 
4929  /* Initialize result arrays with zeroes */
4930  numjoincols = list_length(jrte->joinaliasvars);
4931  Assert(numjoincols == list_length(jrte->eref->colnames));
4932  colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
4933  colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
4934 
4935  /*
4936  * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
4937  * Recall that the column(s) merged due to USING are the first column(s)
4938  * of the join output. We need not do anything special while scanning
4939  * joinleftcols, but while scanning joinrightcols we must distinguish
4940  * merged from unmerged columns.
4941  */
4942  jcolno = 0;
4943  foreach(lc, jrte->joinleftcols)
4944  {
4945  int leftattno = lfirst_int(lc);
4946 
4947  colinfo->leftattnos[jcolno++] = leftattno;
4948  }
4949  rcolno = 0;
4950  foreach(lc, jrte->joinrightcols)
4951  {
4952  int rightattno = lfirst_int(lc);
4953 
4954  if (rcolno < jrte->joinmergedcols) /* merged column? */
4955  colinfo->rightattnos[rcolno] = rightattno;
4956  else
4957  colinfo->rightattnos[jcolno++] = rightattno;
4958  rcolno++;
4959  }
4960  Assert(jcolno == numjoincols);
4961 }
4962 
4963 /*
4964  * get_rtable_name: convenience function to get a previously assigned RTE alias
4965  *
4966  * The RTE must belong to the topmost namespace level in "context".
4967  */
4968 static char *
4970 {
4971  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
4972 
4973  Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4974  return (char *) list_nth(dpns->rtable_names, rtindex - 1);
4975 }
4976 
4977 /*
4978  * set_deparse_plan: set up deparse_namespace to parse subexpressions
4979  * of a given Plan node
4980  *
4981  * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
4982  * and index_tlist fields. Caller must already have adjusted the ancestors
4983  * list if necessary. Note that the rtable, subplans, and ctes fields do
4984  * not need to change when shifting attention to different plan nodes in a
4985  * single plan tree.
4986  */
4987 static void
4989 {
4990  dpns->plan = plan;
4991 
4992  /*
4993  * We special-case Append and MergeAppend to pretend that the first child
4994  * plan is the OUTER referent; we have to interpret OUTER Vars in their
4995  * tlists according to one of the children, and the first one is the most
4996  * natural choice.
4997  */
4998  if (IsA(plan, Append))
4999  dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5000  else if (IsA(plan, MergeAppend))
5001  dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5002  else
5003  dpns->outer_plan = outerPlan(plan);
5004 
5005  if (dpns->outer_plan)
5006  dpns->outer_tlist = dpns->outer_plan->targetlist;
5007  else
5008  dpns->outer_tlist = NIL;
5009 
5010  /*
5011  * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
5012  * use OUTER because that could someday conflict with the normal meaning.)
5013  * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5014  * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5015  * that as INNER referent.
5016  *
5017  * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5018  * INNER referent. This is the join from the target relation to the data
5019  * source, and all INNER_VAR Vars in other parts of the query refer to its
5020  * targetlist.
5021  *
5022  * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
5023  * excluded expression's tlist. (Similar to the SubqueryScan we don't want
5024  * to reuse OUTER, it's used for RETURNING in some modify table cases,
5025  * although not INSERT .. CONFLICT).
5026  */
5027  if (IsA(plan, SubqueryScan))
5028  dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5029  else if (IsA(plan, CteScan))
5030  dpns->inner_plan = list_nth(dpns->subplans,
5031  ((CteScan *) plan)->ctePlanId - 1);
5032  else if (IsA(plan, WorkTableScan))
5033  dpns->inner_plan = find_recursive_union(dpns,
5034  (WorkTableScan *) plan);
5035  else if (IsA(plan, ModifyTable))
5036  {
5037  if (((ModifyTable *) plan)->operation == CMD_MERGE)
5038  dpns->inner_plan = outerPlan(plan);
5039  else
5040  dpns->inner_plan = plan;
5041  }
5042  else
5043  dpns->inner_plan = innerPlan(plan);
5044 
5045  if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5046  dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5047  else if (dpns->inner_plan)
5048  dpns->inner_tlist = dpns->inner_plan->targetlist;
5049  else
5050  dpns->inner_tlist = NIL;
5051 
5052  /* Set up referent for INDEX_VAR Vars, if needed */
5053  if (IsA(plan, IndexOnlyScan))
5054  dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5055  else if (IsA(plan, ForeignScan))
5056  dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5057  else if (IsA(plan, CustomScan))
5058  dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5059  else
5060  dpns->index_tlist = NIL;
5061 }
5062 
5063 /*
5064  * Locate the ancestor plan node that is the RecursiveUnion generating
5065  * the WorkTableScan's work table. We can match on wtParam, since that
5066  * should be unique within the plan tree.
5067  */
5068 static Plan *
5070 {
5071  ListCell *lc;
5072 
5073  foreach(lc, dpns->ancestors)
5074  {
5075  Plan *ancestor = (Plan *) lfirst(lc);
5076 
5077  if (IsA(ancestor, RecursiveUnion) &&
5078  ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5079  return ancestor;
5080  }
5081  elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5082  wtscan->wtParam);
5083  return NULL;
5084 }
5085 
5086 /*
5087  * push_child_plan: temporarily transfer deparsing attention to a child plan
5088  *
5089  * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5090  * deparse context in case the referenced expression itself uses
5091  * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5092  * affecting levelsup issues (although in a Plan tree there really shouldn't
5093  * be any).
5094  *
5095  * Caller must provide a local deparse_namespace variable to save the
5096  * previous state for pop_child_plan.
5097  */
5098 static void
5100  deparse_namespace *save_dpns)
5101 {
5102  /* Save state for restoration later */
5103  *save_dpns = *dpns;
5104 
5105  /* Link current plan node into ancestors list */
5106  dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5107 
5108  /* Set attention on selected child */
5109  set_deparse_plan(dpns, plan);
5110 }
5111 
5112 /*
5113  * pop_child_plan: undo the effects of push_child_plan
5114  */
5115 static void
5117 {
5118  List *ancestors;
5119 
5120  /* Get rid of ancestors list cell added by push_child_plan */
5121  ancestors = list_delete_first(dpns->ancestors);
5122 
5123  /* Restore fields changed by push_child_plan */
5124  *dpns = *save_dpns;
5125 
5126  /* Make sure dpns->ancestors is right (may be unnecessary) */
5127  dpns->ancestors = ancestors;
5128 }
5129 
5130 /*
5131  * push_ancestor_plan: temporarily transfer deparsing attention to an
5132  * ancestor plan
5133  *
5134  * When expanding a Param reference, we must adjust the deparse context
5135  * to match the plan node that contains the expression being printed;
5136  * otherwise we'd fail if that expression itself contains a Param or
5137  * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5138  *
5139  * The target ancestor is conveniently identified by the ListCell holding it
5140  * in dpns->ancestors.
5141  *
5142  * Caller must provide a local deparse_namespace variable to save the
5143  * previous state for pop_ancestor_plan.
5144  */
5145 static void
5147  deparse_namespace *save_dpns)
5148 {
5149  Plan *plan = (Plan *) lfirst(ancestor_cell);
5150 
5151  /* Save state for restoration later */
5152  *save_dpns = *dpns;
5153 
5154  /* Build a new ancestor list with just this node's ancestors */
5155  dpns->ancestors =
5156  list_copy_tail(dpns->ancestors,
5157  list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5158 
5159  /* Set attention on selected ancestor */
5160  set_deparse_plan(dpns, plan);
5161 }
5162 
5163 /*
5164  * pop_ancestor_plan: undo the effects of push_ancestor_plan
5165  */
5166 static void
5168 {
5169  /* Free the ancestor list made in push_ancestor_plan */
5170  list_free(dpns->ancestors);
5171 
5172  /* Restore fields changed by push_ancestor_plan */
5173  *dpns = *save_dpns;
5174 }
5175 
5176 
5177 /* ----------
5178  * make_ruledef - reconstruct the CREATE RULE command
5179  * for a given pg_rewrite tuple
5180  * ----------
5181  */
5182 static void
5184  int prettyFlags)
5185 {
5186  char *rulename;
5187  char ev_type;
5188  Oid ev_class;
5189  bool is_instead;
5190  char *ev_qual;
5191  char *ev_action;
5192  List *actions;
5193  Relation ev_relation;
5194  TupleDesc viewResultDesc = NULL;
5195  int fno;
5196  Datum dat;
5197  bool isnull;
5198 
5199  /*
5200  * Get the attribute values from the rules tuple
5201  */
5202  fno = SPI_fnumber(rulettc, "rulename");
5203  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5204  Assert(!isnull);
5205  rulename = NameStr(*(DatumGetName(dat)));
5206 
5207  fno = SPI_fnumber(rulettc, "ev_type");
5208  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5209  Assert(!isnull);
5210  ev_type = DatumGetChar(dat);
5211 
5212  fno = SPI_fnumber(rulettc, "ev_class");
5213  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5214  Assert(!isnull);
5215  ev_class = DatumGetObjectId(dat);
5216 
5217  fno = SPI_fnumber(rulettc, "is_instead");
5218  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5219  Assert(!isnull);
5220  is_instead = DatumGetBool(dat);
5221 
5222  fno = SPI_fnumber(rulettc, "ev_qual");
5223  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5224  Assert(ev_qual != NULL);
5225 
5226  fno = SPI_fnumber(rulettc, "ev_action");
5227  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5228  Assert(ev_action != NULL);
5229  actions = (List *) stringToNode(ev_action);
5230  if (actions == NIL)
5231  elog(ERROR, "invalid empty ev_action list");
5232 
5233  ev_relation = table_open(ev_class, AccessShareLock);
5234 
5235  /*
5236  * Build the rules definition text
5237  */
5238  appendStringInfo(buf, "CREATE RULE %s AS",
5239  quote_identifier(rulename));
5240 
5241  if (prettyFlags & PRETTYFLAG_INDENT)
5242  appendStringInfoString(buf, "\n ON ");
5243  else
5244  appendStringInfoString(buf, " ON ");
5245 
5246  /* The event the rule is fired for */
5247  switch (ev_type)
5248  {
5249  case '1':
5250  appendStringInfoString(buf, "SELECT");
5251  viewResultDesc = RelationGetDescr(ev_relation);
5252  break;
5253 
5254  case '2':
5255  appendStringInfoString(buf, "UPDATE");
5256  break;
5257 
5258  case '3':
5259  appendStringInfoString(buf, "INSERT");
5260  break;
5261 
5262  case '4':
5263  appendStringInfoString(buf, "DELETE");
5264  break;
5265 
5266  default:
5267  ereport(ERROR,
5268  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5269  errmsg("rule \"%s\" has unsupported event type %d",
5270  rulename, ev_type)));
5271  break;
5272  }
5273 
5274  /* The relation the rule is fired on */
5275  appendStringInfo(buf, " TO %s",
5276  (prettyFlags & PRETTYFLAG_SCHEMA) ?
5277  generate_relation_name(ev_class, NIL) :
5279 
5280  /* If the rule has an event qualification, add it */
5281  if (strcmp(ev_qual, "<>") != 0)
5282  {
5283  Node *qual;
5284  Query *query;
5286  deparse_namespace dpns;
5287 
5288  if (prettyFlags & PRETTYFLAG_INDENT)
5289  appendStringInfoString(buf, "\n ");
5290  appendStringInfoString(buf, " WHERE ");
5291 
5292  qual = stringToNode(ev_qual);
5293 
5294  /*
5295  * We need to make a context for recognizing any Vars in the qual
5296  * (which can only be references to OLD and NEW). Use the rtable of
5297  * the first query in the action list for this purpose.
5298  */
5299  query = (Query *) linitial(actions);
5300 
5301  /*
5302  * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5303  * into the SELECT, and that's what we need to look at. (Ugly kluge
5304  * ... try to fix this when we redesign querytrees.)
5305  */
5306  query = getInsertSelectQuery(query, NULL);
5307 
5308  /* Must acquire locks right away; see notes in get_query_def() */
5309  AcquireRewriteLocks(query, false, false);
5310 
5311  context.buf = buf;
5312  context.namespaces = list_make1(&dpns);
5313  context.windowClause = NIL;
5314  context.windowTList = NIL;
5315  context.varprefix = (list_length(query->rtable) != 1);
5316  context.prettyFlags = prettyFlags;
5317  context.wrapColumn = WRAP_COLUMN_DEFAULT;
5318  context.indentLevel = PRETTYINDENT_STD;
5319  context.special_exprkind = EXPR_KIND_NONE;
5320  context.appendparents = NULL;
5321 
5322  set_deparse_for_query(&dpns, query, NIL);
5323 
5324  get_rule_expr(qual, &context, false);
5325  }
5326 
5327  appendStringInfoString(buf, " DO ");
5328 
5329  /* The INSTEAD keyword (if so) */
5330  if (is_instead)
5331  appendStringInfoString(buf, "INSTEAD ");
5332 
5333  /* Finally the rules actions */
5334  if (list_length(actions) > 1)
5335  {
5336  ListCell *action;
5337  Query *query;
5338 
5339  appendStringInfoChar(buf, '(');
5340  foreach(action, actions)
5341  {
5342  query = (Query *) lfirst(action);
5343  get_query_def(query, buf, NIL, viewResultDesc, true,
5344  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5345  if (prettyFlags)
5346  appendStringInfoString(buf, ";\n");
5347  else
5348  appendStringInfoString(buf, "; ");
5349  }
5350  appendStringInfoString(buf, ");");
5351  }
5352  else
5353  {
5354  Query *query;
5355 
5356  query = (Query *) linitial(actions);
5357  get_query_def(query, buf, NIL, viewResultDesc, true,
5358  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5359  appendStringInfoChar(buf, ';');
5360  }
5361 
5362  table_close(ev_relation, AccessShareLock);
5363 }
5364 
5365 
5366 /* ----------
5367  * make_viewdef - reconstruct the SELECT part of a
5368  * view rewrite rule
5369  * ----------
5370  */
5371 static void
5373  int prettyFlags, int wrapColumn)
5374 {
5375  Query *query;
5376  char ev_type;
5377  Oid ev_class;
5378  bool is_instead;
5379  char *ev_qual;
5380  char *ev_action;
5381  List *actions;
5382  Relation ev_relation;
5383  int fno;
5384  Datum dat;
5385  bool isnull;
5386 
5387  /*
5388  * Get the attribute values from the rules tuple
5389  */
5390  fno = SPI_fnumber(rulettc, "ev_type");
5391  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5392  Assert(!isnull);
5393  ev_type = DatumGetChar(dat);
5394 
5395  fno = SPI_fnumber(rulettc, "ev_class");
5396  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5397  Assert(!isnull);
5398  ev_class = DatumGetObjectId(dat);
5399 
5400  fno = SPI_fnumber(rulettc, "is_instead");
5401  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5402  Assert(!isnull);
5403  is_instead = DatumGetBool(dat);
5404 
5405  fno = SPI_fnumber(rulettc, "ev_qual");
5406  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5407  Assert(ev_qual != NULL);
5408 
5409  fno = SPI_fnumber(rulettc, "ev_action");
5410  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5411  Assert(ev_action != NULL);
5412  actions = (List *) stringToNode(ev_action);
5413 
5414  if (list_length(actions) != 1)
5415  {
5416  /* keep output buffer empty and leave */
5417  return;
5418  }
5419 
5420  query = (Query *) linitial(actions);
5421 
5422  if (ev_type != '1' || !is_instead ||
5423  strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5424  {
5425  /* keep output buffer empty and leave */
5426  return;
5427  }
5428 
5429  ev_relation = table_open(ev_class, AccessShareLock);
5430 
5431  get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5432  prettyFlags, wrapColumn, 0);
5433  appendStringInfoChar(buf, ';');
5434 
5435  table_close(ev_relation, AccessShareLock);
5436 }
5437 
5438 
5439 /* ----------
5440  * get_query_def - Parse back one query parsetree
5441  *
5442  * query: parsetree to be displayed
5443  * buf: output text is appended to buf
5444  * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5445  * resultDesc: if not NULL, the output tuple descriptor for the view
5446  * represented by a SELECT query. We use the column names from it
5447  * to label SELECT output columns, in preference to names in the query
5448  * colNamesVisible: true if the surrounding context cares about the output
5449  * column names at all (as, for example, an EXISTS() context does not);
5450  * when false, we can suppress dummy column labels such as "?column?"
5451  * prettyFlags: bitmask of PRETTYFLAG_XXX options
5452  * wrapColumn: maximum line length, or -1 to disable wrapping
5453  * startIndent: initial indentation amount
5454  * ----------
5455  */
5456 static void
5457 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5458  TupleDesc resultDesc, bool colNamesVisible,
5459  int prettyFlags, int wrapColumn, int startIndent)
5460 {
5462  deparse_namespace dpns;
5463 
5464  /* Guard against excessively long or deeply-nested queries */
5467 
5468  /*
5469  * Before we begin to examine the query, acquire locks on referenced
5470  * relations, and fix up deleted columns in JOIN RTEs. This ensures
5471  * consistent results. Note we assume it's OK to scribble on the passed
5472  * querytree!
5473  *
5474  * We are only deparsing the query (we are not about to execute it), so we
5475  * only need AccessShareLock on the relations it mentions.
5476  */
5477  AcquireRewriteLocks(query, false, false);
5478 
5479  context.buf = buf;
5480  context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5481  context.windowClause = NIL;
5482  context.windowTList = NIL;
5483  context.varprefix = (parentnamespace != NIL ||
5484  list_length(query->rtable) != 1);
5485  context.prettyFlags = prettyFlags;
5486  context.wrapColumn = wrapColumn;
5487  context.indentLevel = startIndent;
5488  context.special_exprkind = EXPR_KIND_NONE;
5489  context.appendparents = NULL;
5490 
5491  set_deparse_for_query(&dpns, query, parentnamespace);
5492 
5493  switch (query->commandType)
5494  {
5495  case CMD_SELECT:
5496  get_select_query_def(query, &context, resultDesc, colNamesVisible);
5497  break;
5498 
5499  case CMD_UPDATE:
5500  get_update_query_def(query, &context, colNamesVisible);
5501  break;
5502 
5503  case CMD_INSERT:
5504  get_insert_query_def(query, &context, colNamesVisible);
5505  break;
5506 
5507  case CMD_DELETE:
5508  get_delete_query_def(query, &context, colNamesVisible);
5509  break;
5510 
5511  case CMD_MERGE:
5512  get_merge_query_def(query, &context, colNamesVisible);
5513  break;
5514 
5515  case CMD_NOTHING:
5516  appendStringInfoString(buf, "NOTHING");
5517  break;
5518 
5519  case CMD_UTILITY:
5520  get_utility_query_def(query, &context);
5521  break;
5522 
5523  default:
5524  elog(ERROR, "unrecognized query command type: %d",
5525  query->commandType);
5526  break;
5527  }
5528 }
5529 
5530 /* ----------
5531  * get_values_def - Parse back a VALUES list
5532  * ----------
5533  */
5534 static void
5536 {
5537  StringInfo buf = context->buf;
5538  bool first_list = true;
5539  ListCell *vtl;
5540 
5541  appendStringInfoString(buf, "VALUES ");
5542 
5543  foreach(vtl, values_lists)
5544  {
5545  List *sublist = (List *) lfirst(vtl);
5546  bool first_col = true;
5547  ListCell *lc;
5548 
5549  if (first_list)
5550  first_list = false;
5551  else
5552  appendStringInfoString(buf, ", ");
5553 
5554  appendStringInfoChar(buf, '(');
5555  foreach(lc, sublist)
5556  {
5557  Node *col = (Node *) lfirst(lc);
5558 
5559  if (first_col)
5560  first_col = false;
5561  else
5562  appendStringInfoChar(buf, ',');
5563 
5564  /*
5565  * Print the value. Whole-row Vars need special treatment.
5566  */
5567  get_rule_expr_toplevel(col, context, false);
5568  }
5569  appendStringInfoChar(buf, ')');
5570  }
5571 }
5572 
5573 /* ----------
5574  * get_with_clause - Parse back a WITH clause
5575  * ----------
5576  */
5577 static void
5579 {
5580  StringInfo buf = context->buf;
5581  const char *sep;
5582  ListCell *l;
5583 
5584  if (query->cteList == NIL)
5585  return;
5586 
5587  if (PRETTY_INDENT(context))
5588  {
5589  context->indentLevel += PRETTYINDENT_STD;
5590  appendStringInfoChar(buf, ' ');
5591  }
5592 
5593  if (query->hasRecursive)
5594  sep = "WITH RECURSIVE ";
5595  else
5596  sep = "WITH ";
5597  foreach(l, query->cteList)
5598  {
5599  CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5600 
5603  if (cte->aliascolnames)
5604  {
5605  bool first = true;
5606  ListCell *col;
5607 
5608  appendStringInfoChar(buf, '(');
5609  foreach(col, cte->aliascolnames)
5610  {
5611  if (first)
5612  first = false;
5613  else
5614  appendStringInfoString(buf, ", ");
5616  quote_identifier(strVal(lfirst(col))));
5617  }
5618  appendStringInfoChar(buf, ')');
5619  }
5620  appendStringInfoString(buf, " AS ");
5621  switch (cte->ctematerialized)
5622  {
5623  case CTEMaterializeDefault:
5624  break;
5625  case CTEMaterializeAlways:
5626  appendStringInfoString(buf, "MATERIALIZED ");
5627  break;
5628  case CTEMaterializeNever:
5629  appendStringInfoString(buf, "NOT MATERIALIZED ");
5630  break;
5631  }
5632  appendStringInfoChar(buf, '(');
5633  if (PRETTY_INDENT(context))
5634  appendContextKeyword(context, "", 0, 0, 0);
5635  get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5636  true,
5637  context->prettyFlags, context->wrapColumn,
5638  context->indentLevel);
5639  if (PRETTY_INDENT(context))
5640  appendContextKeyword(context, "", 0, 0, 0);
5641  appendStringInfoChar(buf, ')');
5642 
5643  if (cte->search_clause)
5644  {
5645  bool first = true;
5646  ListCell *lc;
5647 
5648  appendStringInfo(buf, " SEARCH %s FIRST BY ",
5649  cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5650 
5651  foreach(lc, cte->search_clause->search_col_list)
5652  {
5653  if (first)
5654  first = false;
5655  else
5656  appendStringInfoString(buf, ", ");
5659  }
5660 
5661  appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5662  }
5663 
5664  if (cte->cycle_clause)
5665  {
5666  bool first = true;
5667  ListCell *lc;
5668 
5669  appendStringInfoString(buf, " CYCLE ");
5670 
5671  foreach(lc, cte->cycle_clause->cycle_col_list)
5672  {
5673  if (first)
5674  first = false;
5675  else
5676  appendStringInfoString(buf, ", ");
5679  }
5680 
5681  appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5682 
5683  {
5684  Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5685  Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5686 
5687  if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5688  cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5689  {
5690  appendStringInfoString(buf, " TO ");
5691  get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5692  appendStringInfoString(buf, " DEFAULT ");
5693  get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5694  }
5695  }
5696 
5697  appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5698  }
5699 
5700  sep = ", ";
5701  }
5702 
5703  if (PRETTY_INDENT(context))
5704  {
5705  context->indentLevel -= PRETTYINDENT_STD;
5706  appendContextKeyword(context, "", 0, 0, 0);
5707  }
5708  else
5709  appendStringInfoChar(buf, ' ');
5710 }
5711 
5712 /* ----------
5713  * get_select_query_def - Parse back a SELECT parsetree
5714  * ----------
5715  */
5716 static void
5718  TupleDesc resultDesc, bool colNamesVisible)
5719 {
5720  StringInfo buf = context->buf;
5721  List *save_windowclause;
5722  List *save_windowtlist;
5723  bool force_colno;
5724  ListCell *l;
5725 
5726  /* Insert the WITH clause if given */
5727  get_with_clause(query, context);
5728 
5729  /* Set up context for possible window functions */
5730  save_windowclause = context->windowClause;
5731  context->windowClause = query->windowClause;
5732  save_windowtlist = context->windowTList;
5733  context->windowTList = query->targetList;
5734 
5735  /*
5736  * If the Query node has a setOperations tree, then it's the top level of
5737  * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5738  * fields are interesting in the top query itself.
5739  */
5740  if (query->setOperations)
5741  {
5742  get_setop_query(query->setOperations, query, context, resultDesc,
5743  colNamesVisible);
5744  /* ORDER BY clauses must be simple in this case */
5745  force_colno = true;
5746  }
5747  else
5748  {
5749  get_basic_select_query(query, context, resultDesc, colNamesVisible);
5750  force_colno = false;
5751  }
5752 
5753  /* Add the ORDER BY clause if given */
5754  if (query->sortClause != NIL)
5755  {
5756  appendContextKeyword(context, " ORDER BY ",
5758  get_rule_orderby(query->sortClause, query->targetList,
5759  force_colno, context);
5760  }
5761 
5762  /*
5763  * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5764  * standard spelling of LIMIT.
5765  */
5766  if (query->limitOffset != NULL)
5767  {
5768  appendContextKeyword(context, " OFFSET ",
5770  get_rule_expr(query->limitOffset, context, false);
5771  }
5772  if (query->limitCount != NULL)
5773  {
5774  if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5775  {
5776  appendContextKeyword(context, " FETCH FIRST ",
5778  get_rule_expr(query->limitCount, context, false);
5779  appendStringInfoString(buf, " ROWS WITH TIES");
5780  }
5781  else
5782  {
5783  appendContextKeyword(context, " LIMIT ",
5785  if (IsA(query->limitCount, Const) &&
5786  ((Const *) query->limitCount)->constisnull)
5787  appendStringInfoString(buf, "ALL");
5788  else
5789  get_rule_expr(query->limitCount, context, false);
5790  }
5791  }
5792 
5793  /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5794  if (query->hasForUpdate)
5795  {
5796  foreach(l, query->rowMarks)
5797  {
5798  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5799 
5800  /* don't print implicit clauses */
5801  if (rc->pushedDown)
5802  continue;
5803 
5804  switch (rc->strength)
5805  {
5806  case LCS_NONE:
5807  /* we intentionally throw an error for LCS_NONE */
5808  elog(ERROR, "unrecognized LockClauseStrength %d",
5809  (int) rc->strength);
5810  break;
5811  case LCS_FORKEYSHARE:
5812  appendContextKeyword(context, " FOR KEY SHARE",
5814  break;
5815  case LCS_FORSHARE:
5816  appendContextKeyword(context, " FOR SHARE",
5818  break;
5819  case LCS_FORNOKEYUPDATE:
5820  appendContextKeyword(context, " FOR NO KEY UPDATE",
5822  break;
5823  case LCS_FORUPDATE:
5824  appendContextKeyword(context, " FOR UPDATE",
5826  break;
5827  }
5828 
5829  appendStringInfo(buf, " OF %s",
5831  context)));
5832  if (rc->waitPolicy == LockWaitError)
5833  appendStringInfoString(buf, " NOWAIT");
5834  else if (rc->waitPolicy == LockWaitSkip)
5835  appendStringInfoString(buf, " SKIP LOCKED");
5836  }
5837  }
5838 
5839  context->windowClause = save_windowclause;
5840  context->windowTList = save_windowtlist;
5841 }
5842 
5843 /*
5844  * Detect whether query looks like SELECT ... FROM VALUES(),
5845  * with no need to rename the output columns of the VALUES RTE.
5846  * If so, return the VALUES RTE. Otherwise return NULL.
5847  */
5848 static RangeTblEntry *
5850 {
5851  RangeTblEntry *result = NULL;
5852  ListCell *lc;
5853 
5854  /*
5855  * We want to detect a match even if the Query also contains OLD or NEW
5856  * rule RTEs. So the idea is to scan the rtable and see if there is only
5857  * one inFromCl RTE that is a VALUES RTE.
5858  */
5859  foreach(lc, query->rtable)
5860  {
5861  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
5862 
5863  if (rte->rtekind == RTE_VALUES && rte->inFromCl)
5864  {
5865  if (result)
5866  return NULL; /* multiple VALUES (probably not possible) */
5867  result = rte;
5868  }
5869  else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
5870  continue; /* ignore rule entries */
5871  else
5872  return NULL; /* something else -> not simple VALUES */
5873  }
5874 
5875  /*
5876  * We don't need to check the targetlist in any great detail, because
5877  * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
5878  * appear inside auto-generated sub-queries with very restricted
5879  * structure. However, DefineView might have modified the tlist by
5880  * injecting new column aliases, or we might have some other column
5881  * aliases forced by a resultDesc. We can only simplify if the RTE's
5882  * column names match the names that get_target_list() would select.
5883  */
5884  if (result)
5885  {
5886  ListCell *lcn;
5887  int colno;
5888 
5889  if (list_length(query->targetList) != list_length(result->eref->colnames))
5890  return NULL; /* this probably cannot happen */
5891  colno = 0;
5892  forboth(lc, query->targetList, lcn, result->eref->colnames)
5893  {
5894  TargetEntry *tle = (TargetEntry *) lfirst(lc);
5895  char *cname = strVal(lfirst(lcn));
5896  char *colname;
5897 
5898  if (tle->resjunk)
5899  return NULL; /* this probably cannot happen */
5900 
5901  /* compute name that get_target_list would use for column */
5902  colno++;
5903  if (resultDesc && colno <= resultDesc->natts)
5904  colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5905  else
5906  colname = tle->resname;
5907 
5908  /* does it match the VALUES RTE? */
5909  if (colname == NULL || strcmp(colname, cname) != 0)
5910  return NULL; /* column name has been changed */
5911  }
5912  }
5913 
5914  return result;
5915 }
5916 
5917 static void
5919  TupleDesc resultDesc, bool colNamesVisible)
5920 {
5921  StringInfo buf = context->buf;
5922  RangeTblEntry *values_rte;
5923  char *sep;
5924  ListCell *l;
5925 
5926  if (PRETTY_INDENT(context))
5927  {
5928  context->indentLevel += PRETTYINDENT_STD;
5929  appendStringInfoChar(buf, ' ');
5930  }
5931 
5932  /*
5933  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5934  * VALUES part. This reverses what transformValuesClause() did at parse
5935  * time.
5936  */
5937  values_rte = get_simple_values_rte(query, resultDesc);
5938  if (values_rte)
5939  {
5940  get_values_def(values_rte->values_lists, context);
5941  return;
5942  }
5943 
5944  /*
5945  * Build up the query string - first we say SELECT
5946  */
5947  if (query->isReturn)
5948  appendStringInfoString(buf, "RETURN");
5949  else
5950  appendStringInfoString(buf, "SELECT");
5951 
5952  /* Add the DISTINCT clause if given */
5953  if (query->distinctClause != NIL)
5954  {
5955  if (query->hasDistinctOn)
5956  {
5957  appendStringInfoString(buf, " DISTINCT ON (");
5958  sep = "";
5959  foreach(l, query->distinctClause)
5960  {
5961  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5962 
5965  false, context);
5966  sep = ", ";
5967  }
5968  appendStringInfoChar(buf, ')');
5969  }
5970  else
5971  appendStringInfoString(buf, " DISTINCT");
5972  }
5973 
5974  /* Then we tell what to select (the targetlist) */
5975  get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5976 
5977  /* Add the FROM clause if needed */
5978  get_from_clause(query, " FROM ", context);
5979 
5980  /* Add the WHERE clause if given */
5981  if (query->jointree->quals != NULL)
5982  {
5983  appendContextKeyword(context, " WHERE ",
5985  get_rule_expr(query->jointree->quals, context, false);
5986  }
5987 
5988  /* Add the GROUP BY clause if given */
5989  if (query->groupClause != NULL || query->groupingSets != NULL)
5990  {
5991  ParseExprKind save_exprkind;
5992 
5993  appendContextKeyword(context, " GROUP BY ",
5995  if (query->groupDistinct)
5996  appendStringInfoString(buf, "DISTINCT ");
5997 
5998  save_exprkind = context->special_exprkind;
5999  context->special_exprkind = EXPR_KIND_GROUP_BY;
6000 
6001  if (query->groupingSets == NIL)
6002  {
6003  sep = "";
6004  foreach(l, query->groupClause)
6005  {
6006  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6007 
6010  false, context);
6011  sep = ", ";
6012  }
6013  }
6014  else
6015  {
6016  sep = "";
6017  foreach(l, query->groupingSets)
6018  {
6019  GroupingSet *grp = lfirst(l);
6020 
6022  get_rule_groupingset(grp, query->targetList, true, context);
6023  sep = ", ";
6024  }
6025  }
6026 
6027  context->special_exprkind = save_exprkind;
6028  }
6029 
6030  /* Add the HAVING clause if given */
6031  if (query->havingQual != NULL)
6032  {
6033  appendContextKeyword(context, " HAVING ",
6035  get_rule_expr(query->havingQual, context, false);
6036  }
6037 
6038  /* Add the WINDOW clause if needed */
6039  if (query->windowClause != NIL)
6041 }
6042 
6043 /* ----------
6044  * get_target_list - Parse back a SELECT target list
6045  *
6046  * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
6047  *
6048  * resultDesc and colNamesVisible are as for get_query_def()
6049  * ----------
6050  */
6051 static void
6053  TupleDesc resultDesc, bool colNamesVisible)
6054 {
6055  StringInfo buf = context->buf;
6056  StringInfoData targetbuf;
6057  bool last_was_multiline = false;
6058  char *sep;
6059  int colno;
6060  ListCell *l;
6061 
6062  /* we use targetbuf to hold each TLE's text temporarily */
6063  initStringInfo(&targetbuf);
6064 
6065  sep = " ";
6066  colno = 0;
6067  foreach(l, targetList)
6068  {
6069  TargetEntry *tle = (TargetEntry *) lfirst(l);
6070  char *colname;
6071  char *attname;
6072 
6073  if (tle->resjunk)
6074  continue; /* ignore junk entries */
6075 
6077  sep = ", ";
6078  colno++;
6079 
6080  /*
6081  * Put the new field text into targetbuf so we can decide after we've
6082  * got it whether or not it needs to go on a new line.
6083  */
6084  resetStringInfo(&targetbuf);
6085  context->buf = &targetbuf;
6086 
6087  /*
6088  * We special-case Var nodes rather than using get_rule_expr. This is
6089  * needed because get_rule_expr will display a whole-row Var as
6090  * "foo.*", which is the preferred notation in most contexts, but at
6091  * the top level of a SELECT list it's not right (the parser will
6092  * expand that notation into multiple columns, yielding behavior
6093  * different from a whole-row Var). We need to call get_variable
6094  * directly so that we can tell it to do the right thing, and so that
6095  * we can get the attribute name which is the default AS label.
6096  */
6097  if (tle->expr && (IsA(tle->expr, Var)))
6098  {
6099  attname = get_variable((Var *) tle->expr, 0, true, context);
6100  }
6101  else
6102  {
6103  get_rule_expr((Node *) tle->expr, context, true);
6104 
6105  /*
6106  * When colNamesVisible is true, we should always show the
6107  * assigned column name explicitly. Otherwise, show it only if
6108  * it's not FigureColname's fallback.
6109  */
6110  attname = colNamesVisible ? NULL : "?column?";
6111  }
6112 
6113  /*
6114  * Figure out what the result column should be called. In the context
6115  * of a view, use the view's tuple descriptor (so as to pick up the
6116  * effects of any column RENAME that's been done on the view).
6117  * Otherwise, just use what we can find in the TLE.
6118  */
6119  if (resultDesc && colno <= resultDesc->natts)
6120  colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6121  else
6122  colname = tle->resname;
6123 
6124  /* Show AS unless the column's name is correct as-is */
6125  if (colname) /* resname could be NULL */
6126  {
6127  if (attname == NULL || strcmp(attname, colname) != 0)
6128  appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6129  }
6130 
6131  /* Restore context's output buffer */
6132  context->buf = buf;
6133 
6134  /* Consider line-wrapping if enabled */
6135  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6136  {
6137  int leading_nl_pos;
6138 
6139  /* Does the new field start with a new line? */
6140  if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6141  leading_nl_pos = 0;
6142  else
6143  leading_nl_pos = -1;
6144 
6145  /* If so, we shouldn't add anything */
6146  if (leading_nl_pos >= 0)
6147  {
6148  /* instead, remove any trailing spaces currently in buf */
6150  }
6151  else
6152  {
6153  char *trailing_nl;
6154 
6155  /* Locate the start of the current line in the output buffer */
6156  trailing_nl = strrchr(buf->data, '\n');
6157  if (trailing_nl == NULL)
6158  trailing_nl = buf->data;
6159  else
6160  trailing_nl++;
6161 
6162  /*
6163  * Add a newline, plus some indentation, if the new field is
6164  * not the first and either the new field would cause an
6165  * overflow or the last field used more than one line.
6166  */
6167  if (colno > 1 &&
6168  ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6169  last_was_multiline))
6172  }
6173 
6174  /* Remember this field's multiline status for next iteration */
6175  last_was_multiline =
6176  (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6177  }
6178 
6179  /* Add the new field */
6180  appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6181  }
6182 
6183  /* clean up */
6184  pfree(targetbuf.data);
6185 }
6186 
6187 static void
6189  TupleDesc resultDesc, bool colNamesVisible)
6190 {
6191  StringInfo buf = context->buf;
6192  bool need_paren;
6193 
6194  /* Guard against excessively long or deeply-nested queries */
6197 
6198  if (IsA(setOp, RangeTblRef))
6199  {
6200  RangeTblRef *rtr = (RangeTblRef *) setOp;
6201  RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6202  Query *subquery = rte->subquery;
6203 
6204  Assert(subquery != NULL);
6205  Assert(subquery->setOperations == NULL);
6206  /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
6207  need_paren = (subquery->cteList ||
6208  subquery->sortClause ||
6209  subquery->rowMarks ||
6210  subquery->limitOffset ||
6211  subquery->limitCount);
6212  if (need_paren)
6213  appendStringInfoChar(buf, '(');
6214  get_query_def(subquery, buf, context->namespaces, resultDesc,
6215  colNamesVisible,
6216  context->prettyFlags, context->wrapColumn,
6217  context->indentLevel);
6218  if (need_paren)
6219  appendStringInfoChar(buf, ')');
6220  }
6221  else if (IsA(setOp, SetOperationStmt))
6222  {
6223  SetOperationStmt *op = (SetOperationStmt *) setOp;
6224  int subindent;
6225 
6226  /*
6227  * We force parens when nesting two SetOperationStmts, except when the
6228  * lefthand input is another setop of the same kind. Syntactically,
6229  * we could omit parens in rather more cases, but it seems best to use
6230  * parens to flag cases where the setop operator changes. If we use
6231  * parens, we also increase the indentation level for the child query.
6232  *
6233  * There are some cases in which parens are needed around a leaf query
6234  * too, but those are more easily handled at the next level down (see
6235  * code above).
6236  */
6237  if (IsA(op->larg, SetOperationStmt))
6238  {
6239  SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6240 
6241  if (op->op == lop->op && op->all == lop->all)
6242  need_paren = false;
6243  else
6244  need_paren = true;
6245  }
6246  else
6247  need_paren = false;
6248 
6249  if (need_paren)
6250  {
6251  appendStringInfoChar(buf, '(');
6252  subindent = PRETTYINDENT_STD;
6253  appendContextKeyword(context, "", subindent, 0, 0);
6254  }
6255  else
6256  subindent = 0;
6257 
6258  get_setop_query(op->larg, query, context, resultDesc, colNamesVisible);
6259 
6260  if (need_paren)
6261  appendContextKeyword(context, ") ", -subindent, 0, 0);
6262  else if (PRETTY_INDENT(context))
6263  appendContextKeyword(context, "", -subindent, 0, 0);
6264  else
6265  appendStringInfoChar(buf, ' ');
6266 
6267  switch (op->op)
6268  {
6269  case SETOP_UNION:
6270  appendStringInfoString(buf, "UNION ");
6271  break;
6272  case SETOP_INTERSECT:
6273  appendStringInfoString(buf, "INTERSECT ");
6274  break;
6275  case SETOP_EXCEPT:
6276  appendStringInfoString(buf, "EXCEPT ");
6277  break;
6278  default:
6279  elog(ERROR, "unrecognized set op: %d",
6280  (int) op->op);
6281  }
6282  if (op->all)
6283  appendStringInfoString(buf, "ALL ");
6284 
6285  /* Always parenthesize if RHS is another setop */
6286  need_paren = IsA(op->rarg, SetOperationStmt);
6287 
6288  /*
6289  * The indentation code here is deliberately a bit different from that
6290  * for the lefthand input, because we want the line breaks in
6291  * different places.
6292  */
6293  if (need_paren)
6294  {
6295  appendStringInfoChar(buf, '(');
6296  subindent = PRETTYINDENT_STD;
6297  }
6298  else
6299  subindent = 0;
6300  appendContextKeyword(context, "", subindent, 0, 0);
6301 
6302  get_setop_query(op->rarg, query, context, resultDesc, false);
6303 
6304  if (PRETTY_INDENT(context))
6305  context->indentLevel -= subindent;
6306  if (need_paren)
6307  appendContextKeyword(context, ")", 0, 0, 0);
6308  }
6309  else
6310  {
6311  elog(ERROR, "unrecognized node type: %d",
6312  (int) nodeTag(setOp));
6313  }
6314 }
6315 
6316 /*
6317  * Display a sort/group clause.
6318  *
6319  * Also returns the expression tree, so caller need not find it again.
6320  */
6321 static Node *
6322 get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
6324 {
6325  StringInfo buf = context->buf;
6326  TargetEntry *tle;
6327  Node *expr;
6328 
6329  tle = get_sortgroupref_tle(ref, tlist);
6330  expr = (Node *) tle->expr;
6331 
6332  /*
6333  * Use column-number form if requested by caller. Otherwise, if
6334  * expression is a constant, force it to be dumped with an explicit cast
6335  * as decoration --- this is because a simple integer constant is
6336  * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
6337  * dump it without any decoration. If it's anything more complex than a
6338  * simple Var, then force extra parens around it, to ensure it can't be
6339  * misinterpreted as a cube() or rollup() construct.
6340  */
6341  if (force_colno)
6342  {
6343  Assert(!tle->resjunk);
6344  appendStringInfo(buf, "%d", tle->resno);
6345  }
6346  else if (expr && IsA(expr, Const))
6347  get_const_expr((Const *) expr, context, 1);
6348  else if (!expr || IsA(expr, Var))
6349  get_rule_expr(expr, context, true);
6350  else
6351  {
6352  /*
6353  * We must force parens for function-like expressions even if
6354  * PRETTY_PAREN is off, since those are the ones in danger of
6355  * misparsing. For other expressions we need to force them only if
6356  * PRETTY_PAREN is on, since otherwise the expression will output them
6357  * itself. (We can't skip the parens.)
6358  */
6359  bool need_paren = (PRETTY_PAREN(context)
6360  || IsA(expr, FuncExpr)
6361  || IsA(expr, Aggref)
6362  || IsA(expr, WindowFunc)
6363  || IsA(expr, JsonConstructorExpr));
6364 
6365  if (need_paren)
6366  appendStringInfoChar(context->buf, '(');
6367  get_rule_expr(expr, context, true);
6368  if (need_paren)
6369  appendStringInfoChar(context->buf, ')');
6370  }
6371 
6372  return expr;
6373 }
6374 
6375 /*
6376  * Display a GroupingSet
6377  */
6378 static void
6380  bool omit_parens, deparse_context *context)
6381 {
6382  ListCell *l;
6383  StringInfo buf = context->buf;
6384  bool omit_child_parens = true;
6385  char *sep = "";
6386 
6387  switch (gset->kind)
6388  {
6389  case GROUPING_SET_EMPTY:
6390  appendStringInfoString(buf, "()");
6391  return;
6392 
6393  case GROUPING_SET_SIMPLE:
6394  {
6395  if (!omit_parens || list_length(gset->content) != 1)
6396  appendStringInfoChar(buf, '(');
6397 
6398  foreach(l, gset->content)
6399  {
6400  Index ref = lfirst_int(l);
6401 
6403  get_rule_sortgroupclause(ref, targetlist,
6404  false, context);
6405  sep = ", ";
6406  }
6407 
6408  if (!omit_parens || list_length(gset->content) != 1)
6409  appendStringInfoChar(buf, ')');
6410  }
6411  return;
6412 
6413  case GROUPING_SET_ROLLUP:
6414  appendStringInfoString(buf, "ROLLUP(");
6415  break;
6416  case GROUPING_SET_CUBE:
6417  appendStringInfoString(buf, "CUBE(");
6418  break;
6419  case GROUPING_SET_SETS:
6420  appendStringInfoString(buf, "GROUPING SETS (");
6421  omit_child_parens = false;
6422  break;
6423  }
6424 
6425  foreach(l, gset->content)
6426  {
6428  get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6429  sep = ", ";
6430  }
6431 
6432  appendStringInfoChar(buf, ')');
6433 }
6434 
6435 /*
6436  * Display an ORDER BY list.
6437  */
6438 static void
6439 get_rule_orderby(List *orderList, List *targetList,
6440  bool force_colno, deparse_context *context)
6441 {
6442  StringInfo buf = context->buf;
6443  const char *sep;
6444  ListCell *l;
6445 
6446  sep = "";
6447  foreach(l, orderList)
6448  {
6449  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6450  Node *sortexpr;
6451  Oid sortcoltype;
6452  TypeCacheEntry *typentry;
6453 
6455  sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6456  force_colno, context);
6457  sortcoltype = exprType(sortexpr);
6458  /* See whether operator is default < or > for datatype */
6459  typentry = lookup_type_cache(sortcoltype,
6461  if (srt->sortop == typentry->lt_opr)
6462  {
6463  /* ASC is default, so emit nothing for it */
6464  if (srt->nulls_first)
6465  appendStringInfoString(buf, " NULLS FIRST");
6466  }
6467  else if (srt->sortop == typentry->gt_opr)
6468  {
6469  appendStringInfoString(buf, " DESC");
6470  /* DESC defaults to NULLS FIRST */
6471  if (!srt->nulls_first)
6472  appendStringInfoString(buf, " NULLS LAST");
6473  }
6474  else
6475  {
6476  appendStringInfo(buf, " USING %s",
6478  sortcoltype,
6479  sortcoltype));
6480  /* be specific to eliminate ambiguity */
6481  if (srt->nulls_first)
6482  appendStringInfoString(buf, " NULLS FIRST");
6483  else
6484  appendStringInfoString(buf, " NULLS LAST");
6485  }
6486  sep = ", ";
6487  }
6488 }
6489 
6490 /*
6491  * Display a WINDOW clause.
6492  *
6493  * Note that the windowClause list might contain only anonymous window
6494  * specifications, in which case we should print nothing here.
6495  */
6496 static void
6498 {
6499  StringInfo buf = context->buf;
6500  const char *sep;
6501  ListCell *l;
6502 
6503  sep = NULL;
6504  foreach(l, query->windowClause)
6505  {
6506  WindowClause *wc = (WindowClause *) lfirst(l);
6507 
6508  if (wc->name == NULL)
6509  continue; /* ignore anonymous windows */
6510 
6511  if (sep == NULL)
6512  appendContextKeyword(context, " WINDOW ",
6514  else
6516 
6517  appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6518 
6519  get_rule_windowspec(wc, query->targetList, context);
6520 
6521  sep = ", ";
6522  }
6523 }
6524 
6525 /*
6526  * Display a window definition
6527  */
6528 static void
6531 {
6532  StringInfo buf = context->buf;
6533  bool needspace = false;
6534  const char *sep;
6535  ListCell *l;
6536 
6537  appendStringInfoChar(buf, '(');
6538  if (wc->refname)
6539  {
6541  needspace = true;
6542  }
6543  /* partition clauses are always inherited, so only print if no refname */
6544  if (wc->partitionClause && !wc->refname)
6545  {
6546  if (needspace)
6547  appendStringInfoChar(buf, ' ');
6548  appendStringInfoString(buf, "PARTITION BY ");
6549  sep = "";
6550  foreach(l, wc->partitionClause)
6551  {
6552  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6553 
6555  get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6556  false, context);
6557  sep = ", ";
6558  }
6559  needspace = true;
6560  }
6561  /* print ordering clause only if not inherited */
6562  if (wc->orderClause && !wc->copiedOrder)
6563  {
6564  if (needspace)
6565  appendStringInfoChar(buf, ' ');
6566  appendStringInfoString(buf, "ORDER BY ");
6567  get_rule_orderby(wc->orderClause, targetList, false, context);
6568  needspace = true;
6569  }
6570  /* framing clause is never inherited, so print unless it's default */
6572  {
6573  if (needspace)
6574  appendStringInfoChar(buf, ' ');
6575  if (wc->frameOptions & FRAMEOPTION_RANGE)
6576  appendStringInfoString(buf, "RANGE ");
6577  else if (wc->frameOptions & FRAMEOPTION_ROWS)
6578  appendStringInfoString(buf, "ROWS ");
6579  else if (wc->frameOptions & FRAMEOPTION_GROUPS)
6580  appendStringInfoString(buf, "GROUPS ");
6581  else
6582  Assert(false);
6584  appendStringInfoString(buf, "BETWEEN ");
6586  appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6588  appendStringInfoString(buf, "CURRENT ROW ");
6589  else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
6590  {
6591  get_rule_expr(wc->startOffset, context, false);
6593  appendStringInfoString(buf, " PRECEDING ");
6595  appendStringInfoString(buf, " FOLLOWING ");
6596  else
6597  Assert(false);
6598  }
6599  else
6600  Assert(false);
6602  {
6603  appendStringInfoString(buf, "AND ");
6605  appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6607  appendStringInfoString(buf, "CURRENT ROW ");
6608  else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
6609  {
6610  get_rule_expr(wc->endOffset, context, false);
6612  appendStringInfoString(buf, " PRECEDING ");
6614  appendStringInfoString(buf, " FOLLOWING ");
6615  else
6616  Assert(false);
6617  }
6618  else
6619  Assert(false);
6620  }
6622  appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6623  else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6624  appendStringInfoString(buf, "EXCLUDE GROUP ");
6625  else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6626  appendStringInfoString(buf, "EXCLUDE TIES ");
6627  /* we will now have a trailing space; remove it */
6628  buf->len--;
6629  }
6630  appendStringInfoChar(buf, ')');
6631 }
6632 
6633 /* ----------
6634  * get_insert_query_def - Parse back an INSERT parsetree
6635  * ----------
6636  */
6637 static void
6639  bool colNamesVisible)
6640 {
6641  StringInfo buf = context->buf;
6642  RangeTblEntry *select_rte = NULL;
6643  RangeTblEntry *values_rte = NULL;
6644  RangeTblEntry *rte;
6645  char *sep;
6646  ListCell *l;
6647  List *strippedexprs;
6648 
6649  /* Insert the WITH clause if given */
6650  get_with_clause(query, context);
6651 
6652  /*
6653  * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6654  * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6655  */
6656  foreach(l, query->rtable)
6657  {
6658  rte = (RangeTblEntry *) lfirst(l);
6659 
6660  if (rte->rtekind == RTE_SUBQUERY)
6661  {
6662  if (select_rte)
6663  elog(ERROR, "too many subquery RTEs in INSERT");
6664  select_rte = rte;
6665  }
6666 
6667  if (rte->rtekind == RTE_VALUES)
6668  {
6669  if (values_rte)
6670  elog(ERROR, "too many values RTEs in INSERT");
6671  values_rte = rte;
6672  }
6673  }
6674  if (select_rte && values_rte)
6675  elog(ERROR, "both subquery and values RTEs in INSERT");
6676 
6677  /*
6678  * Start the query with INSERT INTO relname
6679  */
6680  rte = rt_fetch(query->resultRelation, query->rtable);
6681  Assert(rte->rtekind == RTE_RELATION);
6682 
6683  if (PRETTY_INDENT(context))
6684  {
6685  context->indentLevel += PRETTYINDENT_STD;
6686  appendStringInfoChar(buf, ' ');
6687  }
6688  appendStringInfo(buf, "INSERT INTO %s",
6690 
6691  /* Print the relation alias, if needed; INSERT requires explicit AS */
6692  get_rte_alias(rte, query->resultRelation, true, context);
6693 
6694  /* always want a space here */
6695  appendStringInfoChar(buf, ' ');
6696 
6697  /*
6698  * Add the insert-column-names list. Any indirection decoration needed on
6699  * the column names can be inferred from the top targetlist.
6700  */
6701  strippedexprs = NIL;
6702  sep = "";
6703  if (query->targetList)
6704  appendStringInfoChar(buf, '(');
6705  foreach(l, query->targetList)
6706  {
6707  TargetEntry *tle = (TargetEntry *) lfirst(l);
6708 
6709  if (tle->resjunk)
6710  continue; /* ignore junk entries */
6711 
6713  sep = ", ";
6714 
6715  /*
6716  * Put out name of target column; look in the catalogs, not at
6717  * tle->resname, since resname will fail to track RENAME.
6718  */
6721  tle->resno,
6722  false)));
6723 
6724  /*
6725  * Print any indirection needed (subfields or subscripts), and strip
6726  * off the top-level nodes representing the indirection assignments.
6727  * Add the stripped expressions to strippedexprs. (If it's a
6728  * single-VALUES statement, the stripped expressions are the VALUES to
6729  * print below. Otherwise they're just Vars and not really
6730  * interesting.)
6731  */
6732  strippedexprs = lappend(strippedexprs,
6733  processIndirection((Node *) tle->expr,
6734  context));
6735  }
6736  if (query->targetList)
6737  appendStringInfoString(buf, ") ");
6738 
6739  if (query->override)
6740  {
6741  if (query->override == OVERRIDING_SYSTEM_VALUE)
6742  appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
6743  else if (query->override == OVERRIDING_USER_VALUE)
6744  appendStringInfoString(buf, "OVERRIDING USER VALUE ");
6745  }
6746 
6747  if (select_rte)
6748  {
6749  /* Add the SELECT */
6750  get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
6751  false,
6752  context->prettyFlags, context->wrapColumn,
6753  context->indentLevel);
6754  }
6755  else if (values_rte)
6756  {
6757  /* Add the multi-VALUES expression lists */
6758  get_values_def(values_rte->values_lists, context);
6759  }
6760  else if (strippedexprs)
6761  {
6762  /* Add the single-VALUES expression list */
6763  appendContextKeyword(context, "VALUES (",
6765  get_rule_list_toplevel(strippedexprs, context, false);
6766  appendStringInfoChar(buf, ')');
6767  }
6768  else
6769  {
6770  /* No expressions, so it must be DEFAULT VALUES */
6771  appendStringInfoString(buf, "DEFAULT VALUES");
6772  }
6773 
6774  /* Add ON CONFLICT if present */
6775  if (query->onConflict)
6776  {
6777  OnConflictExpr *confl = query->onConflict;
6778 
6779  appendStringInfoString(buf, " ON CONFLICT");
6780 
6781  if (confl->arbiterElems)
6782  {
6783  /* Add the single-VALUES expression list */
6784  appendStringInfoChar(buf, '(');
6785  get_rule_expr((Node *) confl->arbiterElems, context, false);
6786  appendStringInfoChar(buf, ')');
6787 
6788  /* Add a WHERE clause (for partial indexes) if given */
6789  if (confl->arbiterWhere != NULL)
6790  {
6791  bool save_varprefix;
6792 
6793  /*
6794  * Force non-prefixing of Vars, since parser assumes that they
6795  * belong to target relation. WHERE clause does not use
6796  * InferenceElem, so this is separately required.
6797  */
6798  save_varprefix = context->varprefix;
6799  context->varprefix = false;
6800 
6801  appendContextKeyword(context, " WHERE ",
6803  get_rule_expr(confl->arbiterWhere, context, false);
6804 
6805  context->varprefix = save_varprefix;
6806  }
6807  }
6808  else if (OidIsValid(confl->constraint))
6809  {
6810  char *constraint = get_constraint_name(confl->constraint);
6811 
6812  if (!constraint)
6813  elog(ERROR, "cache lookup failed for constraint %u",
6814  confl->constraint);
6815  appendStringInfo(buf, " ON CONSTRAINT %s",
6816  quote_identifier(constraint));
6817  }
6818 
6819  if (confl->action == ONCONFLICT_NOTHING)
6820  {
6821  appendStringInfoString(buf, " DO NOTHING");
6822  }
6823  else
6824  {
6825  appendStringInfoString(buf, " DO UPDATE SET ");
6826  /* Deparse targetlist */
6828  context, rte);
6829 
6830  /* Add a WHERE clause if given */
6831  if (confl->onConflictWhere != NULL)
6832  {
6833  appendContextKeyword(context, " WHERE ",
6835  get_rule_expr(confl->onConflictWhere, context, false);
6836  }
6837  }
6838  }
6839 
6840  /* Add RETURNING if present */
6841  if (query->returningList)
6842  {
6843  appendContextKeyword(context, " RETURNING",
6845  get_target_list(query->returningList, context, NULL, colNamesVisible);
6846  }
6847 }
6848 
6849 
6850 /* ----------
6851  * get_update_query_def - Parse back an UPDATE parsetree
6852  * ----------
6853  */
6854 static void
6856  bool colNamesVisible)
6857 {
6858  StringInfo buf = context->buf;
6859  RangeTblEntry *rte;
6860 
6861  /* Insert the WITH clause if given */
6862  get_with_clause(query, context);
6863 
6864  /*
6865  * Start the query with UPDATE relname SET
6866  */
6867  rte = rt_fetch(query->resultRelation, query->rtable);
6868  Assert(rte->rtekind == RTE_RELATION);
6869  if (PRETTY_INDENT(context))
6870  {
6871  appendStringInfoChar(buf, ' ');
6872  context->indentLevel += PRETTYINDENT_STD;
6873  }
6874  appendStringInfo(buf, "UPDATE %s%s",
6875  only_marker(rte),
6877 
6878  /* Print the relation alias, if needed */
6879  get_rte_alias(rte, query->resultRelation, false, context);
6880 
6881  appendStringInfoString(buf, " SET ");
6882 
6883  /* Deparse targetlist */
6884  get_update_query_targetlist_def(query, query->targetList, context, rte);
6885 
6886  /* Add the FROM clause if needed */
6887  get_from_clause(query, " FROM ", context);
6888 
6889  /* Add a WHERE clause if given */
6890  if (query->jointree->quals != NULL)
6891  {
6892  appendContextKeyword(context, " WHERE ",
6894  get_rule_expr(query->jointree->quals, context, false);
6895  }
6896 
6897  /* Add RETURNING if present */
6898  if (query->returningList)
6899  {
6900  appendContextKeyword(context, " RETURNING",
6902  get_target_list(query->returningList, context, NULL, colNamesVisible);
6903  }
6904 }
6905 
6906 
6907 /* ----------
6908  * get_update_query_targetlist_def - Parse back an UPDATE targetlist
6909  * ----------
6910  */
6911 static void
6914 {
6915  StringInfo buf = context->buf;
6916  ListCell *l;
6917  ListCell *next_ma_cell;
6918  int remaining_ma_columns;
6919  const char *sep;
6920  SubLink *cur_ma_sublink;
6921  List *ma_sublinks;
6922 
6923  /*
6924  * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
6925  * into a list. We expect them to appear, in ID order, in resjunk tlist
6926  * entries.
6927  */
6928  ma_sublinks = NIL;
6929  if (query->hasSubLinks) /* else there can't be any */
6930  {
6931  foreach(l, targetList)
6932  {
6933  TargetEntry *tle = (TargetEntry *) lfirst(l);
6934 
6935  if (tle->resjunk && IsA(tle->expr, SubLink))
6936  {
6937  SubLink *sl = (SubLink *) tle->expr;
6938 
6940  {
6941  ma_sublinks = lappend(ma_sublinks, sl);
6942  Assert(sl->subLinkId == list_length(ma_sublinks));
6943  }
6944  }
6945  }
6946  }
6947  next_ma_cell = list_head(ma_sublinks);
6948  cur_ma_sublink = NULL;
6949  remaining_ma_columns = 0;
6950 
6951  /* Add the comma separated list of 'attname = value' */
6952  sep = "";
6953  foreach(l, targetList)
6954  {
6955  TargetEntry *tle = (TargetEntry *) lfirst(l);
6956  Node *expr;
6957 
6958  if (tle->resjunk)
6959  continue; /* ignore junk entries */
6960 
6961  /* Emit separator (OK whether we're in multiassignment or not) */
6963  sep = ", ";
6964 
6965  /*
6966  * Check to see if we're starting a multiassignment group: if so,
6967  * output a left paren.
6968  */
6969  if (next_ma_cell != NULL && cur_ma_sublink == NULL)
6970  {
6971  /*
6972  * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
6973  * Param. That could be buried under FieldStores and
6974  * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
6975  * and underneath those there could be an implicit type coercion.
6976  * Because we would ignore implicit type coercions anyway, we
6977  * don't need to be as careful as processIndirection() is about
6978  * descending past implicit CoerceToDomains.
6979  */
6980  expr = (Node *) tle->expr;
6981  while (expr)
6982  {
6983  if (IsA(expr, FieldStore))
6984  {
6985  FieldStore *fstore = (FieldStore *) expr;
6986 
6987  expr = (Node *) linitial(fstore->newvals);
6988  }
6989  else if (IsA(expr, SubscriptingRef))
6990  {
6991  SubscriptingRef *sbsref = (SubscriptingRef *) expr;
6992 
6993  if (sbsref->refassgnexpr == NULL)
6994  break;
6995 
6996  expr = (Node *) sbsref->refassgnexpr;
6997  }
6998  else if (IsA(expr, CoerceToDomain))
6999  {
7000  CoerceToDomain *cdomain = (CoerceToDomain *) expr;
7001 
7002  if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
7003  break;
7004  expr = (Node *) cdomain->arg;
7005  }
7006  else
7007  break;
7008  }
7009  expr = strip_implicit_coercions(expr);
7010 
7011  if (expr && IsA(expr, Param) &&
7012  ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
7013  {
7014  cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
7015  next_ma_cell = lnext(ma_sublinks, next_ma_cell);
7016  remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
7017  Assert(((Param *) expr)->paramid ==
7018  ((cur_ma_sublink->subLinkId << 16) | 1));
7019  appendStringInfoChar(buf, '(');
7020  }
7021  }
7022 
7023  /*
7024  * Put out name of target column; look in the catalogs, not at
7025  * tle->resname, since resname will fail to track RENAME.
7026  */
7029  tle->resno,
7030  false)));
7031 
7032  /*
7033  * Print any indirection needed (subfields or subscripts), and strip
7034  * off the top-level nodes representing the indirection assignments.
7035  */
7036  expr = processIndirection((Node *) tle->expr, context);
7037 
7038  /*
7039  * If we're in a multiassignment, skip printing anything more, unless
7040  * this is the last column; in which case, what we print should be the
7041  * sublink, not the Param.
7042  */
7043  if (cur_ma_sublink != NULL)
7044  {
7045  if (--remaining_ma_columns > 0)
7046  continue; /* not the last column of multiassignment */
7047  appendStringInfoChar(buf, ')');
7048  expr = (Node *) cur_ma_sublink;
7049  cur_ma_sublink = NULL;
7050  }
7051 
7052  appendStringInfoString(buf, " = ");
7053 
7054  get_rule_expr(expr, context, false);
7055  }
7056 }
7057 
7058 
7059 /* ----------
7060  * get_delete_query_def - Parse back a DELETE parsetree
7061  * ----------
7062  */
7063 static void
7065  bool colNamesVisible)
7066 {
7067  StringInfo buf = context->buf;
7068  RangeTblEntry *rte;
7069 
7070  /* Insert the WITH clause if given */
7071  get_with_clause(query, context);
7072 
7073  /*
7074  * Start the query with DELETE FROM relname
7075  */
7076  rte = rt_fetch(query->resultRelation, query->rtable);
7077  Assert(rte->rtekind == RTE_RELATION);
7078  if (PRETTY_INDENT(context))
7079  {
7080  appendStringInfoChar(buf, ' ');
7081  context->indentLevel += PRETTYINDENT_STD;
7082  }
7083  appendStringInfo(buf, "DELETE FROM %s%s",
7084  only_marker(rte),
7086 
7087  /* Print the relation alias, if needed */
7088  get_rte_alias(rte, query->resultRelation, false, context);
7089 
7090  /* Add the USING clause if given */
7091  get_from_clause(query, " USING ", context);
7092 
7093  /* Add a WHERE clause if given */
7094  if (query->jointree->quals != NULL)
7095  {
7096  appendContextKeyword(context, " WHERE ",
7098  get_rule_expr(query->jointree->quals, context, false);
7099  }
7100 
7101  /* Add RETURNING if present */
7102  if (query->returningList)
7103  {
7104  appendContextKeyword(context, " RETURNING",
7106  get_target_list(query->returningList, context, NULL, colNamesVisible);
7107  }
7108 }
7109 
7110 
7111 /* ----------
7112  * get_merge_query_def - Parse back a MERGE parsetree
7113  * ----------
7114  */
7115 static void
7117  bool colNamesVisible)
7118 {
7119  StringInfo buf = context->buf;
7120  RangeTblEntry *rte;
7121  ListCell *lc;
7122  bool haveNotMatchedBySource;
7123 
7124  /* Insert the WITH clause if given */
7125  get_with_clause(query, context);
7126 
7127  /*
7128  * Start the query with MERGE INTO relname
7129  */
7130  rte = rt_fetch(query->resultRelation, query->rtable);
7131  Assert(rte->rtekind == RTE_RELATION);
7132  if (PRETTY_INDENT(context))
7133  {
7134  appendStringInfoChar(buf, ' ');
7135  context->indentLevel += PRETTYINDENT_STD;
7136  }
7137  appendStringInfo(buf, "MERGE INTO %s%s",
7138  only_marker(rte),
7140 
7141  /* Print the relation alias, if needed */
7142  get_rte_alias(rte, query->resultRelation, false, context);
7143 
7144  /* Print the source relation and join clause */
7145  get_from_clause(query, " USING ", context);
7146  appendContextKeyword(context, " ON ",
7148  get_rule_expr(query->mergeJoinCondition, context, false);
7149 
7150  /*
7151  * Test for any NOT MATCHED BY SOURCE actions. If there are none, then
7152  * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7153  * SQL standard. Otherwise, we have a non-SQL-standard query, so output
7154  * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7155  * more explicit.
7156  */
7157  haveNotMatchedBySource = false;
7158  foreach(lc, query->mergeActionList)
7159  {
7161 
7162  if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7163  {
7164  haveNotMatchedBySource = true;
7165  break;
7166  }
7167  }
7168 
7169  /* Print each merge action */
7170  foreach(lc, query->mergeActionList)
7171  {
7173 
7174  appendContextKeyword(context, " WHEN ",
7176  switch (action->matchKind)
7177  {
7178  case MERGE_WHEN_MATCHED:
7179  appendStringInfoString(buf, "MATCHED");
7180  break;
7182  appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7183  break;
7185  if (haveNotMatchedBySource)
7186  appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7187  else
7188  appendStringInfoString(buf, "NOT MATCHED");
7189  break;
7190  default:
7191  elog(ERROR, "unrecognized matchKind: %d",
7192  (int) action->matchKind);
7193  }
7194 
7195  if (action->qual)
7196  {
7197  appendContextKeyword(context, " AND ",
7199  get_rule_expr(action->qual, context, false);
7200  }
7201  appendContextKeyword(context, " THEN ",
7203 
7204  if (action->commandType == CMD_INSERT)
7205  {
7206  /* This generally matches get_insert_query_def() */
7207  List *strippedexprs = NIL;
7208  const char *sep = "";
7209  ListCell *lc2;
7210 
7211  appendStringInfoString(buf, "INSERT");
7212 
7213  if (action->targetList)
7214  appendStringInfoString(buf, " (");
7215  foreach(lc2, action->targetList)
7216  {
7217  TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7218 
7219  Assert(!tle->resjunk);
7220 
7222  sep = ", ";
7223 
7226  tle->resno,
7227  false)));
7228  strippedexprs = lappend(strippedexprs,
7229  processIndirection((Node *) tle->expr,
7230  context));
7231  }
7232  if (action->targetList)
7233  appendStringInfoChar(buf, ')');
7234 
7235  if (action->override)
7236  {
7237  if (action->override == OVERRIDING_SYSTEM_VALUE)
7238  appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7239  else if (action->override == OVERRIDING_USER_VALUE)
7240  appendStringInfoString(buf, " OVERRIDING USER VALUE");
7241  }
7242 
7243  if (strippedexprs)
7244  {
7245  appendContextKeyword(context, " VALUES (",
7247  get_rule_list_toplevel(strippedexprs, context, false);
7248  appendStringInfoChar(buf, ')');
7249  }
7250  else
7251  appendStringInfoString(buf, " DEFAULT VALUES");
7252  }
7253  else if (action->commandType == CMD_UPDATE)
7254  {
7255  appendStringInfoString(buf, "UPDATE SET ");
7256  get_update_query_targetlist_def(query, action->targetList,
7257  context, rte);
7258  }
7259  else if (action->commandType == CMD_DELETE)
7260  appendStringInfoString(buf, "DELETE");
7261  else if (action->commandType == CMD_NOTHING)
7262  appendStringInfoString(buf, "DO NOTHING");
7263  }
7264 
7265  /* Add RETURNING if present */
7266  if (query->returningList)
7267  {
7268  appendContextKeyword(context, " RETURNING",
7270  get_target_list(query->returningList, context, NULL, colNamesVisible);
7271  }
7272 }
7273 
7274 
7275 /* ----------
7276  * get_utility_query_def - Parse back a UTILITY parsetree
7277  * ----------
7278  */
7279 static void
7281 {
7282  StringInfo buf = context->buf;
7283 
7284  if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7285  {
7286  NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7287 
7289  0, PRETTYINDENT_STD, 1);
7290  appendStringInfo(buf, "NOTIFY %s",
7291  quote_identifier(stmt->conditionname));
7292  if (stmt->payload)
7293  {
7294  appendStringInfoString(buf, ", ");
7295  simple_quote_literal(buf, stmt->payload);
7296  }
7297  }
7298  else
7299  {
7300  /* Currently only NOTIFY utility commands can appear in rules */
7301  elog(ERROR, "unexpected utility statement type");
7302  }
7303 }
7304 
7305 /*
7306  * Display a Var appropriately.
7307  *
7308  * In some cases (currently only when recursing into an unnamed join)
7309  * the Var's varlevelsup has to be interpreted with respect to a context
7310  * above the current one; levelsup indicates the offset.
7311  *
7312  * If istoplevel is true, the Var is at the top level of a SELECT's
7313  * targetlist, which means we need special treatment of whole-row Vars.
7314  * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
7315  * dirty hack to prevent "tab.*" from being expanded into multiple columns.
7316  * (The parser will strip the useless coercion, so no inefficiency is added in
7317  * dump and reload.) We used to print just "tab" in such cases, but that is
7318  * ambiguous and will yield the wrong result if "tab" is also a plain column
7319  * name in the query.
7320  *
7321  * Returns the attname of the Var, or NULL if the Var has no attname (because
7322  * it is a whole-row Var or a subplan output reference).
7323  */
7324 static char *
7325 get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
7326 {
7327  StringInfo buf = context->buf;
7328  RangeTblEntry *rte;
7330  int netlevelsup;
7331  deparse_namespace *dpns;
7332  int varno;
7333  AttrNumber varattno;
7334  deparse_columns *colinfo;
7335  char *refname;
7336  char *attname;
7337 
7338  /* Find appropriate nesting depth */
7339  netlevelsup = var->varlevelsup + levelsup;
7340  if (netlevelsup >= list_length(context->namespaces))
7341  elog(ERROR, "bogus varlevelsup: %d offset %d",
7342  var->varlevelsup, levelsup);
7343  dpns = (deparse_namespace *) list_nth(context->namespaces,
7344  netlevelsup);
7345 
7346  /*
7347  * If we have a syntactic referent for the Var, and we're working from a
7348  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7349  * on the semantic referent. (Forcing use of the semantic referent when
7350  * printing plan trees is a design choice that's perhaps more motivated by
7351  * backwards compatibility than anything else. But it does have the
7352  * advantage of making plans more explicit.)
7353  */
7354  if (var->varnosyn > 0 && dpns->plan == NULL)
7355  {
7356  varno = var->varnosyn;
7357  varattno = var->varattnosyn;
7358  }
7359  else
7360  {
7361  varno = var->varno;
7362  varattno = var->varattno;
7363  }
7364 
7365  /*
7366  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7367  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7368  * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7369  * find the aliases previously assigned for this RTE.
7370  */
7371  if (varno >= 1 && varno <= list_length(dpns->rtable))
7372  {
7373  /*
7374  * We might have been asked to map child Vars to some parent relation.
7375  */
7376  if (context->appendparents && dpns->appendrels)
7377  {
7378  int pvarno = varno;
7379  AttrNumber pvarattno = varattno;
7380  AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7381  bool found = false;
7382 
7383  /* Only map up to inheritance parents, not UNION ALL appendrels */
7384  while (appinfo &&
7385  rt_fetch(appinfo->parent_relid,
7386  dpns->rtable)->rtekind == RTE_RELATION)
7387  {
7388  found = false;
7389  if (pvarattno > 0) /* system columns stay as-is */
7390  {
7391  if (pvarattno > appinfo->num_child_cols)
7392  break; /* safety check */
7393  pvarattno = appinfo->parent_colnos[pvarattno - 1];
7394  if (pvarattno == 0)
7395  break; /* Var is local to child */
7396  }
7397 
7398  pvarno = appinfo->parent_relid;
7399  found = true;
7400 
7401  /* If the parent is itself a child, continue up. */
7402  Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7403  appinfo = dpns->appendrels[pvarno];
7404  }
7405 
7406  /*
7407  * If we found an ancestral rel, and that rel is included in
7408  * appendparents, print that column not the original one.
7409  */
7410  if (found && bms_is_member(pvarno, context->appendparents))
7411  {
7412  varno = pvarno;
7413  varattno = pvarattno;
7414  }
7415  }
7416 
7417  rte = rt_fetch(varno, dpns->rtable);
7418  refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7419  colinfo = deparse_columns_fetch(varno, dpns);
7420  attnum = varattno;
7421  }
7422  else
7423  {
7425  get_special_variable, NULL);
7426  return NULL;
7427  }
7428 
7429  /*
7430  * The planner will sometimes emit Vars referencing resjunk elements of a
7431  * subquery's target list (this is currently only possible if it chooses
7432  * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7433  * Although we prefer to print subquery-referencing Vars using the
7434  * subquery's alias, that's not possible for resjunk items since they have
7435  * no alias. So in that case, drill down to the subplan and print the
7436  * contents of the referenced tlist item. This works because in a plan
7437  * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7438  * we'll have set dpns->inner_plan to reference the child plan node.
7439  */
7440  if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7441  attnum > list_length(rte->eref->colnames) &&
7442  dpns->inner_plan)
7443  {
7444  TargetEntry *tle;
7445  deparse_namespace save_dpns;
7446 
7447  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7448  if (!tle)
7449  elog(ERROR, "invalid attnum %d for relation \"%s\"",
7450  attnum, rte->eref->aliasname);
7451 
7452  Assert(netlevelsup == 0);
7453  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7454 
7455  /*
7456  * Force parentheses because our caller probably assumed a Var is a
7457  * simple expression.
7458  */
7459  if (!IsA(tle->expr, Var))
7460  appendStringInfoChar(buf, '(');
7461  get_rule_expr((Node *) tle->expr, context, true);
7462  if (!IsA(tle->expr, Var))
7463  appendStringInfoChar(buf, ')');
7464 
7465  pop_child_plan(dpns, &save_dpns);
7466  return NULL;
7467  }
7468 
7469  /*
7470  * If it's an unnamed join, look at the expansion of the alias variable.
7471  * If it's a simple reference to one of the input vars, then recursively
7472  * print the name of that var instead. When it's not a simple reference,
7473  * we have to just print the unqualified join column name. (This can only
7474  * happen with "dangerous" merged columns in a JOIN USING; we took pains
7475  * previously to make the unqualified column name unique in such cases.)
7476  *
7477  * This wouldn't work in decompiling plan trees, because we don't store
7478  * joinaliasvars lists after planning; but a plan tree should never
7479  * contain a join alias variable.
7480  */
7481  if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7482  {
7483  if (rte->joinaliasvars == NIL)
7484  elog(ERROR, "cannot decompile join alias var in plan tree");
7485  if (attnum > 0)
7486  {
7487  Var *aliasvar;
7488 
7489  aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7490  /* we intentionally don't strip implicit coercions here */
7491  if (aliasvar && IsA(aliasvar, Var))
7492  {
7493  return get_variable(aliasvar, var->varlevelsup + levelsup,
7494  istoplevel, context);
7495  }
7496  }
7497 
7498  /*
7499  * Unnamed join has no refname. (Note: since it's unnamed, there is
7500  * no way the user could have referenced it to create a whole-row Var
7501  * for it. So we don't have to cover that case below.)
7502  */
7503  Assert(refname == NULL);
7504  }
7505 
7506  if (attnum == InvalidAttrNumber)
7507  attname = NULL;
7508  else if (attnum > 0)
7509  {
7510  /* Get column name to use from the colinfo struct */
7511  if (attnum > colinfo->num_cols)
7512  elog(ERROR, "invalid attnum %d for relation \"%s\"",
7513  attnum, rte->eref->aliasname);
7514  attname = colinfo->colnames[attnum - 1];
7515 
7516  /*
7517  * If we find a Var referencing a dropped column, it seems better to
7518  * print something (anything) than to fail. In general this should
7519  * not happen, but it used to be possible for some cases involving
7520  * functions returning named composite types, and perhaps there are
7521  * still bugs out there.
7522  */
7523  if (attname == NULL)
7524  attname = "?dropped?column?";
7525  }
7526  else
7527  {
7528  /* System column - name is fixed, get it from the catalog */
7530  }
7531 
7532  if (refname && (context->varprefix || attname == NULL))
7533  {
7535  appendStringInfoChar(buf, '.');
7536  }
7537  if (attname)
7539  else
7540  {
7541  appendStringInfoChar(buf, '*');
7542  if (istoplevel)
7543  appendStringInfo(buf, "::%s",
7544  format_type_with_typemod(var->vartype,
7545  var->vartypmod));
7546  }
7547 
7548  return attname;
7549 }
7550 
7551 /*
7552  * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
7553  * routine is actually a callback for resolve_special_varno, which handles
7554  * finding the correct TargetEntry. We get the expression contained in that
7555  * TargetEntry and just need to deparse it, a job we can throw back on
7556  * get_rule_expr.
7557  */
7558 static void
7559 get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7560 {
7561  StringInfo buf = context->buf;
7562 
7563  /*
7564  * For a non-Var referent, force parentheses because our caller probably
7565  * assumed a Var is a simple expression.
7566  */
7567  if (!IsA(node, Var))
7568  appendStringInfoChar(buf, '(');
7569  get_rule_expr(node, context, true);
7570  if (!IsA(node, Var))
7571  appendStringInfoChar(buf, ')');
7572 }
7573 
7574 /*
7575  * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7576  * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7577  * invoke the callback provided.
7578  */
7579 static void
7581  rsv_callback callback, void *callback_arg)
7582 {
7583  Var *var;
7584  deparse_namespace *dpns;
7585 
7586  /* This function is recursive, so let's be paranoid. */
7588 
7589  /* If it's not a Var, invoke the callback. */
7590  if (!IsA(node, Var))
7591  {
7592  (*callback) (node, context, callback_arg);
7593  return;
7594  }
7595 
7596  /* Find appropriate nesting depth */
7597  var = (Var *) node;
7598  dpns = (deparse_namespace *) list_nth(context->namespaces,
7599  var->varlevelsup);
7600 
7601  /*
7602  * If varno is special, recurse. (Don't worry about varnosyn; if we're
7603  * here, we already decided not to use that.)
7604  */
7605  if (var->varno == OUTER_VAR && dpns->outer_tlist)
7606  {
7607  TargetEntry *tle;
7608  deparse_namespace save_dpns;
7609  Bitmapset *save_appendparents;
7610 
7611  tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7612  if (!tle)
7613  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7614 
7615  /*
7616  * If we're descending to the first child of an Append or MergeAppend,
7617  * update appendparents. This will affect deparsing of all Vars
7618  * appearing within the eventually-resolved subexpression.
7619  */
7620  save_appendparents = context->appendparents;
7621 
7622  if (IsA(dpns->plan, Append))
7623  context->appendparents = bms_union(context->appendparents,
7624  ((Append *) dpns->plan)->apprelids);
7625  else if (IsA(dpns->plan, MergeAppend))
7626  context->appendparents = bms_union(context->appendparents,
7627  ((MergeAppend *) dpns->plan)->apprelids);
7628 
7629  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7631  callback, callback_arg);
7632  pop_child_plan(dpns, &save_dpns);
7633  context->appendparents = save_appendparents;
7634  return;
7635  }
7636  else if (var->varno == INNER_VAR && dpns->inner_tlist)
7637  {
7638  TargetEntry *tle;
7639  deparse_namespace save_dpns;
7640 
7641  tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7642  if (!tle)
7643  elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7644 
7645  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7647  callback, callback_arg);
7648  pop_child_plan(dpns, &save_dpns);
7649  return;
7650  }
7651  else if (var->varno == INDEX_VAR && dpns->index_tlist)
7652  {
7653  TargetEntry *tle;
7654 
7655  tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7656  if (!tle)
7657  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7658 
7660  callback, callback_arg);
7661  return;
7662  }
7663  else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7664  elog(ERROR, "bogus varno: %d", var->varno);
7665 
7666  /* Not special. Just invoke the callback. */
7667  (*callback) (node, context, callback_arg);
7668 }
7669 
7670 /*
7671  * Get the name of a field of an expression of composite type. The
7672  * expression is usually a Var, but we handle other cases too.
7673  *
7674  * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
7675  *
7676  * This is fairly straightforward when the expression has a named composite
7677  * type; we need only look up the type in the catalogs. However, the type
7678  * could also be RECORD. Since no actual table or view column is allowed to
7679  * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
7680  * or to a subquery output. We drill down to find the ultimate defining
7681  * expression and attempt to infer the field name from it. We ereport if we
7682  * can't determine the name.
7683  *
7684  * Similarly, a PARAM of type RECORD has to refer to some expression of
7685  * a determinable composite type.
7686  */
7687 static const char *
7688 get_name_for_var_field(Var *var, int fieldno,
7689  int levelsup, deparse_context *context)
7690 {
7691  RangeTblEntry *rte;
7693  int netlevelsup;
7694  deparse_namespace *dpns;
7695  int varno;
7696  AttrNumber varattno;
7697  TupleDesc tupleDesc;
7698  Node *expr;
7699 
7700  /*
7701  * If it's a RowExpr that was expanded from a whole-row Var, use the
7702  * column names attached to it. (We could let get_expr_result_tupdesc()
7703  * handle this, but it's much cheaper to just pull out the name we need.)
7704  */
7705  if (IsA(var, RowExpr))
7706  {
7707  RowExpr *r = (RowExpr *) var;
7708 
7709  if (fieldno > 0 && fieldno <= list_length(r->colnames))
7710  return strVal(list_nth(r->colnames, fieldno - 1));
7711  }
7712 
7713  /*
7714  * If it's a Param of type RECORD, try to find what the Param refers to.
7715  */
7716  if (IsA(var, Param))
7717  {
7718  Param *param = (Param *) var;
7719  ListCell *ancestor_cell;
7720 
7721  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7722  if (expr)
7723  {
7724  /* Found a match, so recurse to decipher the field name */
7725  deparse_namespace save_dpns;
7726  const char *result;
7727 
7728  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7729  result = get_name_for_var_field((Var *) expr, fieldno,
7730  0, context);
7731  pop_ancestor_plan(dpns, &save_dpns);
7732  return result;
7733  }
7734  }
7735 
7736  /*
7737  * If it's a Var of type RECORD, we have to find what the Var refers to;
7738  * if not, we can use get_expr_result_tupdesc().
7739  */
7740  if (!IsA(var, Var) ||
7741  var->vartype != RECORDOID)
7742  {
7743  tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7744  /* Got the tupdesc, so we can extract the field name */
7745  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7746  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7747  }
7748 
7749  /* Find appropriate nesting depth */
7750  netlevelsup = var->varlevelsup + levelsup;
7751  if (netlevelsup >= list_length(context->namespaces))
7752  elog(ERROR, "bogus varlevelsup: %d offset %d",
7753  var->varlevelsup, levelsup);
7754  dpns = (deparse_namespace *) list_nth(context->namespaces,
7755  netlevelsup);
7756 
7757  /*
7758  * If we have a syntactic referent for the Var, and we're working from a
7759  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7760  * on the semantic referent. (See comments in get_variable().)
7761  */
7762  if (var->varnosyn > 0 && dpns->plan == NULL)
7763  {
7764  varno = var->varnosyn;
7765  varattno = var->varattnosyn;
7766  }
7767  else
7768  {
7769  varno = var->varno;
7770  varattno = var->varattno;
7771  }
7772 
7773  /*
7774  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7775  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7776  * down into the subplans, or INDEX_VAR, which is resolved similarly.
7777  *
7778  * Note: unlike get_variable and resolve_special_varno, we need not worry
7779  * about inheritance mapping: a child Var should have the same datatype as
7780  * its parent, and here we're really only interested in the Var's type.
7781  */
7782  if (varno >= 1 && varno <= list_length(dpns->rtable))
7783  {
7784  rte = rt_fetch(varno, dpns->rtable);
7785  attnum = varattno;
7786  }
7787  else if (varno == OUTER_VAR && dpns->outer_tlist)
7788  {
7789  TargetEntry *tle;
7790  deparse_namespace save_dpns;
7791  const char *result;
7792 
7793  tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7794  if (!tle)
7795  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7796 
7797  Assert(netlevelsup == 0);
7798  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7799 
7800  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7801  levelsup, context);
7802 
7803  pop_child_plan(dpns, &save_dpns);
7804  return result;
7805  }
7806  else if (varno == INNER_VAR && dpns->inner_tlist)
7807  {
7808  TargetEntry *tle;
7809  deparse_namespace save_dpns;
7810  const char *result;
7811 
7812  tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7813  if (!tle)
7814  elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7815 
7816  Assert(netlevelsup == 0);
7817  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7818 
7819  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7820  levelsup, context);
7821 
7822  pop_child_plan(dpns, &save_dpns);
7823  return result;
7824  }
7825  else if (varno == INDEX_VAR && dpns->index_tlist)
7826  {
7827  TargetEntry *tle;
7828  const char *result;
7829 
7830  tle = get_tle_by_resno(dpns->index_tlist, varattno);
7831  if (!tle)
7832  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7833 
7834  Assert(netlevelsup == 0);
7835 
7836  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7837  levelsup, context);
7838 
7839  return result;
7840  }
7841  else
7842  {
7843  elog(ERROR, "bogus varno: %d", varno);
7844  return NULL; /* keep compiler quiet */
7845  }
7846 
7847  if (attnum == InvalidAttrNumber)
7848  {
7849  /* Var is whole-row reference to RTE, so select the right field */
7850  return get_rte_attribute_name(rte, fieldno);
7851  }
7852 
7853  /*
7854  * This part has essentially the same logic as the parser's
7855  * expandRecordVariable() function, but we are dealing with a different
7856  * representation of the input context, and we only need one field name
7857  * not a TupleDesc. Also, we need special cases for finding subquery and
7858  * CTE subplans when deparsing Plan trees.
7859  */
7860  expr = (Node *) var; /* default if we can't drill down */
7861 
7862  switch (rte->rtekind)
7863  {
7864  case RTE_RELATION:
7865  case RTE_VALUES:
7866  case RTE_NAMEDTUPLESTORE:
7867  case RTE_RESULT:
7868 
7869  /*
7870  * This case should not occur: a column of a table, values list,
7871  * or ENR shouldn't have type RECORD. Fall through and fail (most
7872  * likely) at the bottom.
7873  */
7874  break;
7875  case RTE_SUBQUERY:
7876  /* Subselect-in-FROM: examine sub-select's output expr */
7877  {
7878  if (rte->subquery)
7879  {
7881  attnum);
7882 
7883  if (ste == NULL || ste->resjunk)
7884  elog(ERROR, "subquery %s does not have attribute %d",
7885  rte->eref->aliasname, attnum);
7886  expr = (Node *) ste->expr;
7887  if (IsA(expr, Var))
7888  {
7889  /*
7890  * Recurse into the sub-select to see what its Var
7891  * refers to. We have to build an additional level of
7892  * namespace to keep in step with varlevelsup in the
7893  * subselect; furthermore, the subquery RTE might be
7894  * from an outer query level, in which case the
7895  * namespace for the subselect must have that outer
7896  * level as parent namespace.
7897  */
7898  List *save_nslist = context->namespaces;
7899  List *parent_namespaces;
7900  deparse_namespace mydpns;
7901  const char *result;
7902 
7903  parent_namespaces = list_copy_tail(context->namespaces,
7904  netlevelsup);
7905 
7906  set_deparse_for_query(&mydpns, rte->subquery,
7907  parent_namespaces);
7908 
7909  context->namespaces = lcons(&mydpns, parent_namespaces);
7910 
7911  result = get_name_for_var_field((Var *) expr, fieldno,
7912  0, context);
7913 
7914  context->namespaces = save_nslist;
7915 
7916  return result;
7917  }
7918  /* else fall through to inspect the expression */
7919  }
7920  else
7921  {
7922  /*
7923  * We're deparsing a Plan tree so we don't have complete
7924  * RTE entries (in particular, rte->subquery is NULL). But
7925  * the only place we'd see a Var directly referencing a
7926  * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7927  * look into the child plan's tlist instead.
7928  */
7929  TargetEntry *tle;
7930  deparse_namespace save_dpns;
7931  const char *result;
7932 
7933  if (!dpns->inner_plan)
7934  elog(ERROR, "failed to find plan for subquery %s",
7935  rte->eref->aliasname);
7936  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7937  if (!tle)
7938  elog(ERROR, "bogus varattno for subquery var: %d",
7939  attnum);
7940  Assert(netlevelsup == 0);
7941  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7942 
7943  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7944  levelsup, context);
7945 
7946  pop_child_plan(dpns, &save_dpns);
7947  return result;
7948  }
7949  }
7950  break;
7951  case RTE_JOIN:
7952  /* Join RTE --- recursively inspect the alias variable */
7953  if (rte->joinaliasvars == NIL)
7954  elog(ERROR, "cannot decompile join alias var in plan tree");
7955  Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7956  expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
7957  Assert(expr != NULL);
7958  /* we intentionally don't strip implicit coercions here */
7959  if (IsA(expr, Var))
7960  return get_name_for_var_field((Var *) expr, fieldno,
7961  var->varlevelsup + levelsup,
7962  context);
7963  /* else fall through to inspect the expression */
7964  break;
7965  case RTE_FUNCTION:
7966  case RTE_TABLEFUNC:
7967 
7968  /*
7969  * We couldn't get here unless a function is declared with one of
7970  * its result columns as RECORD, which is not allowed.
7971  */
7972  break;
7973  case RTE_CTE:
7974  /* CTE reference: examine subquery's output expr */
7975  {
7976  CommonTableExpr *cte = NULL;
7977  Index ctelevelsup;
7978  ListCell *lc;
7979 
7980  /*
7981  * Try to find the referenced CTE using the namespace stack.
7982  */
7983  ctelevelsup = rte->ctelevelsup + netlevelsup;
7984  if (ctelevelsup >= list_length(context->namespaces))
7985  lc = NULL;
7986  else
7987  {
7988  deparse_namespace *ctedpns;
7989 
7990  ctedpns = (deparse_namespace *)
7991  list_nth(context->namespaces, ctelevelsup);
7992  foreach(lc, ctedpns->ctes)
7993  {
7994  cte = (CommonTableExpr *) lfirst(lc);
7995  if (strcmp(cte->ctename, rte->ctename) == 0)
7996  break;
7997  }
7998  }
7999  if (lc != NULL)
8000  {
8001  Query *ctequery = (Query *) cte->ctequery;
8003  attnum);
8004 
8005  if (ste == NULL || ste->resjunk)
8006  elog(ERROR, "CTE %s does not have attribute %d",
8007  rte->eref->aliasname, attnum);
8008  expr = (Node *) ste->expr;
8009  if (IsA(expr, Var))
8010  {
8011  /*
8012  * Recurse into the CTE to see what its Var refers to.
8013  * We have to build an additional level of namespace
8014  * to keep in step with varlevelsup in the CTE;
8015  * furthermore it could be an outer CTE (compare
8016  * SUBQUERY case above).
8017  */
8018  List *save_nslist = context->namespaces;
8019  List *parent_namespaces;
8020  deparse_namespace mydpns;
8021  const char *result;
8022 
8023  parent_namespaces = list_copy_tail(context->namespaces,
8024  ctelevelsup);
8025 
8026  set_deparse_for_query(&mydpns, ctequery,
8027  parent_namespaces);
8028 
8029  context->namespaces = lcons(&mydpns, parent_namespaces);
8030 
8031  result = get_name_for_var_field((Var *) expr, fieldno,
8032  0, context);
8033 
8034  context->namespaces = save_nslist;
8035 
8036  return result;
8037  }
8038  /* else fall through to inspect the expression */
8039  }
8040  else
8041  {
8042  /*
8043  * We're deparsing a Plan tree so we don't have a CTE
8044  * list. But the only places we'd see a Var directly
8045  * referencing a CTE RTE are in CteScan or WorkTableScan
8046  * plan nodes. For those cases, set_deparse_plan arranged
8047  * for dpns->inner_plan to be the plan node that emits the
8048  * CTE or RecursiveUnion result, and we can look at its
8049  * tlist instead.
8050  */
8051  TargetEntry *tle;
8052  deparse_namespace save_dpns;
8053  const char *result;
8054 
8055  if (!dpns->inner_plan)
8056  elog(ERROR, "failed to find plan for CTE %s",
8057  rte->eref->aliasname);
8058  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8059  if (!tle)
8060  elog(ERROR, "bogus varattno for subquery var: %d",
8061  attnum);
8062  Assert(netlevelsup == 0);
8063  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8064 
8065  result = get_name_for_var_field((Var *) tle->expr, fieldno,
8066  levelsup, context);
8067 
8068  pop_child_plan(dpns, &save_dpns);
8069  return result;
8070  }
8071  }
8072  break;
8073  }
8074 
8075  /*
8076  * We now have an expression we can't expand any more, so see if
8077  * get_expr_result_tupdesc() can do anything with it.
8078  */
8079  tupleDesc = get_expr_result_tupdesc(expr, false);
8080  /* Got the tupdesc, so we can extract the field name */
8081  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8082  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8083 }
8084 
8085 /*
8086  * Try to find the referenced expression for a PARAM_EXEC Param that might
8087  * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
8088  *
8089  * If successful, return the expression and set *dpns_p and *ancestor_cell_p
8090  * appropriately for calling push_ancestor_plan(). If no referent can be
8091  * found, return NULL.
8092  */
8093 static Node *
8095  deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
8096 {
8097  /* Initialize output parameters to prevent compiler warnings */
8098  *dpns_p = NULL;
8099  *ancestor_cell_p = NULL;
8100 
8101  /*
8102  * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8103  * SubPlan argument. This will necessarily be in some ancestor of the
8104  * current expression's Plan node.
8105  */
8106  if (param->paramkind == PARAM_EXEC)
8107  {
8108  deparse_namespace *dpns;
8109  Plan *child_plan;
8110  ListCell *lc;
8111 
8112  dpns = (deparse_namespace *) linitial(context->namespaces);
8113  child_plan = dpns->plan;
8114 
8115  foreach(lc, dpns->ancestors)
8116  {
8117  Node *ancestor = (Node *) lfirst(lc);
8118  ListCell *lc2;
8119 
8120  /*
8121  * NestLoops transmit params to their inner child only.
8122  */
8123  if (IsA(ancestor, NestLoop) &&
8124  child_plan == innerPlan(ancestor))
8125  {
8126  NestLoop *nl = (NestLoop *) ancestor;
8127 
8128  foreach(lc2, nl->nestParams)
8129  {
8130  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8131 
8132  if (nlp->paramno == param->paramid)
8133  {
8134  /* Found a match, so return it */
8135  *dpns_p = dpns;
8136  *ancestor_cell_p = lc;
8137  return (Node *) nlp->paramval;
8138  }
8139  }
8140  }
8141 
8142  /*
8143  * If ancestor is a SubPlan, check the arguments it provides.
8144  */
8145  if (IsA(ancestor, SubPlan))
8146  {
8147  SubPlan *subplan = (SubPlan *) ancestor;
8148  ListCell *lc3;
8149  ListCell *lc4;
8150 
8151  forboth(lc3, subplan->parParam, lc4, subplan->args)
8152  {
8153  int paramid = lfirst_int(lc3);
8154  Node *arg = (Node *) lfirst(lc4);
8155 
8156  if (paramid == param->paramid)
8157  {
8158  /*
8159  * Found a match, so return it. But, since Vars in
8160  * the arg are to be evaluated in the surrounding
8161  * context, we have to point to the next ancestor item
8162  * that is *not* a SubPlan.
8163  */
8164  ListCell *rest;
8165 
8166  for_each_cell(rest, dpns->ancestors,
8167  lnext(dpns->ancestors, lc))
8168  {
8169  Node *ancestor2 = (Node *) lfirst(rest);
8170 
8171  if (!IsA(ancestor2, SubPlan))
8172  {
8173  *dpns_p = dpns;
8174  *ancestor_cell_p = rest;
8175  return arg;
8176  }
8177  }
8178  elog(ERROR, "SubPlan cannot be outermost ancestor");
8179  }
8180  }
8181 
8182  /* SubPlan isn't a kind of Plan, so skip the rest */
8183  continue;
8184  }
8185 
8186  /*
8187  * We need not consider the ancestor's initPlan list, since
8188  * initplans never have any parParams.
8189  */
8190 
8191  /* No luck, crawl up to next ancestor */
8192  child_plan = (Plan *) ancestor;
8193  }
8194  }
8195 
8196  /* No referent found */
8197  return NULL;
8198 }
8199 
8200 /*
8201  * Try to find a subplan/initplan that emits the value for a PARAM_EXEC Param.
8202  *
8203  * If successful, return the generating subplan/initplan and set *column_p
8204  * to the subplan's 0-based output column number.
8205  * Otherwise, return NULL.
8206  */
8207 static SubPlan *
8209 {
8210  /* Initialize output parameter to prevent compiler warnings */
8211  *column_p = 0;
8212 
8213  /*
8214  * If it's a PARAM_EXEC parameter, search the current plan node as well as
8215  * ancestor nodes looking for a subplan or initplan that emits the value
8216  * for the Param. It could appear in the setParams of an initplan or
8217  * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
8218  */
8219  if (param->paramkind == PARAM_EXEC)
8220  {
8221  SubPlan *result;
8222  deparse_namespace *dpns;
8223  ListCell *lc;
8224 
8225  dpns = (deparse_namespace *) linitial(context->namespaces);
8226 
8227  /* First check the innermost plan node's initplans */
8228  result = find_param_generator_initplan(param, dpns->plan, column_p);
8229  if (result)
8230  return result;
8231 
8232  /*
8233  * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
8234  * which can be referenced by Params elsewhere in the targetlist.
8235  * (Such Params should always be in the same targetlist, so there's no
8236  * need to do this work at upper plan nodes.)
8237  */
8238  foreach_node(TargetEntry, tle, dpns->plan->targetlist)
8239  {
8240  if (tle->expr && IsA(tle->expr, SubPlan))
8241  {
8242  SubPlan *subplan = (SubPlan *) tle->expr;
8243 
8244  if (subplan->subLinkType == MULTIEXPR_SUBLINK)
8245  {
8246  foreach_int(paramid, subplan->setParam)
8247  {
8248  if (paramid == param->paramid)
8249  {
8250  /* Found a match, so return it. */
8251  *column_p = foreach_current_index(paramid);
8252  return subplan;
8253  }
8254  }
8255  }
8256  }
8257  }
8258 
8259  /* No luck, so check the ancestor nodes */
8260  foreach(lc, dpns->ancestors)
8261  {
8262  Node *ancestor = (Node *) lfirst(lc);
8263 
8264  /*
8265  * If ancestor is a SubPlan, check the paramIds it provides.
8266  */
8267  if (IsA(ancestor, SubPlan))
8268  {
8269  SubPlan *subplan = (SubPlan *) ancestor;
8270 
8271  foreach_int(paramid, subplan->paramIds)
8272  {
8273  if (paramid == param->paramid)
8274  {
8275  /* Found a match, so return it. */
8276  *column_p = foreach_current_index(paramid);
8277  return subplan;
8278  }
8279  }
8280 
8281  /* SubPlan isn't a kind of Plan, so skip the rest */
8282  continue;
8283  }
8284 
8285  /*
8286  * Otherwise, it's some kind of Plan node, so check its initplans.
8287  */
8288  result = find_param_generator_initplan(param, (Plan *) ancestor,
8289  column_p);
8290  if (result)
8291  return result;
8292 
8293  /* No luck, crawl up to next ancestor */
8294  }
8295  }
8296 
8297  /* No generator found */
8298  return NULL;
8299 }
8300 
8301 /*
8302  * Subroutine for find_param_generator: search one Plan node's initplans
8303  */
8304 static SubPlan *
8306 {
8307  foreach_node(SubPlan, subplan, plan->initPlan)
8308  {
8309  foreach_int(paramid, subplan->setParam)
8310  {
8311  if (paramid == param->paramid)
8312  {
8313  /* Found a match, so return it. */
8314  *column_p = foreach_current_index(paramid);
8315  return subplan;
8316  }
8317  }
8318  }
8319  return NULL;
8320 }
8321 
8322 /*
8323  * Display a Param appropriately.
8324  */
8325 static void
8327 {
8328  Node *expr;
8329  deparse_namespace *dpns;
8330  ListCell *ancestor_cell;
8331  SubPlan *subplan;
8332  int column;
8333 
8334  /*
8335  * If it's a PARAM_EXEC parameter, try to locate the expression from which
8336  * the parameter was computed. This stanza handles only cases in which
8337  * the Param represents an input to the subplan we are currently in.
8338  */
8339  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8340  if (expr)
8341  {
8342  /* Found a match, so print it */
8343  deparse_namespace save_dpns;
8344  bool save_varprefix;
8345  bool need_paren;
8346 
8347  /* Switch attention to the ancestor plan node */
8348  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8349 
8350  /*
8351  * Force prefixing of Vars, since they won't belong to the relation
8352  * being scanned in the original plan node.
8353  */
8354  save_varprefix = context->varprefix;
8355  context->varprefix = true;
8356 
8357  /*
8358  * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8359  * upper-level Param, which wouldn't need extra parentheses.
8360  * Otherwise, insert parens to ensure the expression looks atomic.
8361  */
8362  need_paren = !(IsA(expr, Var) ||
8363  IsA(expr, Aggref) ||
8364  IsA(expr, GroupingFunc) ||
8365  IsA(expr, Param));
8366  if (need_paren)
8367  appendStringInfoChar(context->buf, '(');
8368 
8369  get_rule_expr(expr, context, false);
8370 
8371  if (need_paren)
8372  appendStringInfoChar(context->buf, ')');
8373 
8374  context->varprefix = save_varprefix;
8375 
8376  pop_ancestor_plan(dpns, &save_dpns);
8377 
8378  return;
8379  }
8380 
8381  /*
8382  * Alternatively, maybe it's a subplan output, which we print as a
8383  * reference to the subplan. (We could drill down into the subplan and
8384  * print the relevant targetlist expression, but that has been deemed too
8385  * confusing since it would violate normal SQL scope rules. Also, we're
8386  * relying on this reference to show that the testexpr containing the
8387  * Param has anything to do with that subplan at all.)
8388  */
8389  subplan = find_param_generator(param, context, &column);
8390  if (subplan)
8391  {
8392  appendStringInfo(context->buf, "(%s%s).col%d",
8393  subplan->useHashTable ? "hashed " : "",
8394  subplan->plan_name, column + 1);
8395 
8396  return;
8397  }
8398 
8399  /*
8400  * If it's an external parameter, see if the outermost namespace provides
8401  * function argument names.
8402  */
8403  if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8404  {
8405  dpns = llast(context->namespaces);
8406  if (dpns->argnames &&
8407  param->paramid > 0 &&
8408  param->paramid <= dpns->numargs)
8409  {
8410  char *argname = dpns->argnames[param->paramid - 1];
8411 
8412  if (argname)
8413  {
8414  bool should_qualify = false;
8415  ListCell *lc;
8416 
8417  /*
8418  * Qualify the parameter name if there are any other deparse
8419  * namespaces with range tables. This avoids qualifying in
8420  * trivial cases like "RETURN a + b", but makes it safe in all
8421  * other cases.
8422  */
8423  foreach(lc, context->namespaces)
8424  {
8425  deparse_namespace *depns = lfirst(lc);
8426 
8427  if (depns->rtable_names != NIL)
8428  {
8429  should_qualify = true;
8430  break;
8431  }
8432  }
8433  if (should_qualify)
8434  {
8436  appendStringInfoChar(context->buf, '.');
8437  }
8438 
8440  return;
8441  }
8442  }
8443  }
8444 
8445  /*
8446  * Not PARAM_EXEC, or couldn't find referent: just print $N.
8447  *
8448  * It's a bug if we get here for anything except PARAM_EXTERN Params, but
8449  * in production builds printing $N seems more useful than failing.
8450  */
8451  Assert(param->paramkind == PARAM_EXTERN);
8452 
8453  appendStringInfo(context->buf, "$%d", param->paramid);
8454 }
8455 
8456 /*
8457  * get_simple_binary_op_name
8458  *
8459  * helper function for isSimpleNode
8460  * will return single char binary operator name, or NULL if it's not
8461  */
8462 static const char *
8464 {
8465  List *args = expr->args;
8466 
8467  if (list_length(args) == 2)
8468  {
8469  /* binary operator */
8470  Node *arg1 = (Node *) linitial(args);
8471  Node *arg2 = (Node *) lsecond(args);
8472  const char *op;
8473 
8474  op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8475  if (strlen(op) == 1)
8476  return op;
8477  }
8478  return NULL;
8479 }
8480 
8481 
8482 /*
8483  * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
8484  *
8485  * true : simple in the context of parent node's type
8486  * false : not simple
8487  */
8488 static bool
8489 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
8490 {
8491  if (!node)
8492  return false;
8493 
8494  switch (nodeTag(node))
8495  {
8496  case T_Var:
8497  case T_Const:
8498  case T_Param:
8499  case T_CoerceToDomainValue:
8500  case T_SetToDefault:
8501  case T_CurrentOfExpr:
8502  /* single words: always simple */
8503  return true;
8504 
8505  case T_SubscriptingRef:
8506  case T_ArrayExpr:
8507  case T_RowExpr:
8508  case T_CoalesceExpr:
8509  case T_MinMaxExpr:
8510  case T_SQLValueFunction:
8511  case T_XmlExpr:
8512  case T_NextValueExpr:
8513  case T_NullIfExpr:
8514  case T_Aggref:
8515  case T_GroupingFunc:
8516  case T_WindowFunc:
8517  case T_MergeSupportFunc:
8518  case T_FuncExpr:
8519  case T_JsonConstructorExpr:
8520  case T_JsonExpr:
8521  /* function-like: name(..) or name[..] */
8522  return true;
8523 
8524  /* CASE keywords act as parentheses */
8525  case T_CaseExpr:
8526  return true;
8527 
8528  case T_FieldSelect:
8529 
8530  /*
8531  * appears simple since . has top precedence, unless parent is
8532  * T_FieldSelect itself!
8533  */
8534  return !IsA(parentNode, FieldSelect);
8535 
8536  case T_FieldStore:
8537 
8538  /*
8539  * treat like FieldSelect (probably doesn't matter)
8540  */
8541  return !IsA(parentNode, FieldStore);
8542 
8543  case T_CoerceToDomain:
8544  /* maybe simple, check args */
8545  return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8546  node, prettyFlags);
8547  case T_RelabelType:
8548  return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8549  node, prettyFlags);
8550  case T_CoerceViaIO:
8551  return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8552  node, prettyFlags);
8553  case T_ArrayCoerceExpr:
8554  return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8555  node, prettyFlags);
8556  case T_ConvertRowtypeExpr:
8557  return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8558  node, prettyFlags);
8559 
8560  case T_OpExpr:
8561  {
8562  /* depends on parent node type; needs further checking */
8563  if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8564  {
8565  const char *op;
8566  const char *parentOp;
8567  bool is_lopriop;
8568  bool is_hipriop;
8569  bool is_lopriparent;
8570  bool is_hipriparent;
8571 
8572  op = get_simple_binary_op_name((OpExpr *) node);
8573  if (!op)
8574  return false;
8575 
8576  /* We know only the basic operators + - and * / % */
8577  is_lopriop = (strchr("+-", *op) != NULL);
8578  is_hipriop = (strchr("*/%", *op) != NULL);
8579  if (!(is_lopriop || is_hipriop))
8580  return false;
8581 
8582  parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8583  if (!parentOp)
8584  return false;
8585 
8586  is_lopriparent = (strchr("+-", *parentOp) != NULL);
8587  is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8588  if (!(is_lopriparent || is_hipriparent))
8589  return false;
8590 
8591  if (is_hipriop && is_lopriparent)
8592  return true; /* op binds tighter than parent */
8593 
8594  if (is_lopriop && is_hipriparent)
8595  return false;
8596 
8597  /*
8598  * Operators are same priority --- can skip parens only if
8599  * we have (a - b) - c, not a - (b - c).
8600  */
8601  if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8602  return true;
8603 
8604  return false;
8605  }
8606  /* else do the same stuff as for T_SubLink et al. */
8607  }
8608  /* FALLTHROUGH */
8609 
8610  case T_SubLink:
8611  case T_NullTest:
8612  case T_BooleanTest:
8613  case T_DistinctExpr:
8614  case T_JsonIsPredicate:
8615  switch (nodeTag(parentNode))
8616  {
8617  case T_FuncExpr:
8618  {
8619  /* special handling for casts and COERCE_SQL_SYNTAX */
8620  CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8621 
8622  if (type == COERCE_EXPLICIT_CAST ||
8625  return false;
8626  return true; /* own parentheses */
8627  }
8628  case T_BoolExpr: /* lower precedence */
8629  case T_SubscriptingRef: /* other separators */
8630  case T_ArrayExpr: /* other separators */
8631  case T_RowExpr: /* other separators */
8632  case T_CoalesceExpr: /* own parentheses */
8633  case T_MinMaxExpr: /* own parentheses */
8634  case T_XmlExpr: /* own parentheses */
8635  case T_NullIfExpr: /* other separators */
8636  case T_Aggref: /* own parentheses */
8637  case T_GroupingFunc: /* own parentheses */
8638  case T_WindowFunc: /* own parentheses */
8639  case T_CaseExpr: /* other separators */
8640  return true;
8641  default:
8642  return false;
8643  }
8644 
8645  case T_BoolExpr:
8646  switch (nodeTag(parentNode))
8647  {
8648  case T_BoolExpr:
8649  if (prettyFlags & PRETTYFLAG_PAREN)
8650  {
8652  BoolExprType parentType;
8653 
8654  type = ((BoolExpr *) node)->boolop;
8655  parentType = ((BoolExpr *) parentNode)->boolop;
8656  switch (type)
8657  {
8658  case NOT_EXPR:
8659  case AND_EXPR:
8660  if (parentType == AND_EXPR || parentType == OR_EXPR)
8661  return true;
8662  break;
8663  case OR_EXPR:
8664  if (parentType == OR_EXPR)
8665  return true;
8666  break;
8667  }
8668  }
8669  return false;
8670  case T_FuncExpr:
8671  {
8672  /* special handling for casts and COERCE_SQL_SYNTAX */
8673  CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8674 
8675  if (type == COERCE_EXPLICIT_CAST ||
8678  return false;
8679  return true; /* own parentheses */
8680  }
8681  case T_SubscriptingRef: /* other separators */
8682  case T_ArrayExpr: /* other separators */
8683  case T_RowExpr: /* other separators */
8684  case T_CoalesceExpr: /* own parentheses */
8685  case T_MinMaxExpr: /* own parentheses */
8686  case T_XmlExpr: /* own parentheses */
8687  case T_NullIfExpr: /* other separators */
8688  case T_Aggref: /* own parentheses */
8689  case T_GroupingFunc: /* own parentheses */
8690  case T_WindowFunc: /* own parentheses */
8691  case T_CaseExpr: /* other separators */
8692  case T_JsonExpr: /* own parentheses */
8693  return true;
8694  default:
8695  return false;
8696  }
8697 
8698  case T_JsonValueExpr:
8699  /* maybe simple, check args */
8700  return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
8701  node, prettyFlags);
8702 
8703  default:
8704  break;
8705  }
8706  /* those we don't know: in dubio complexo */
8707  return false;
8708 }
8709 
8710 
8711 /*
8712  * appendContextKeyword - append a keyword to buffer
8713  *
8714  * If prettyPrint is enabled, perform a line break, and adjust indentation.
8715  * Otherwise, just append the keyword.
8716  */
8717 static void
8719  int indentBefore, int indentAfter, int indentPlus)
8720 {
8721  StringInfo buf = context->buf;
8722 
8723  if (PRETTY_INDENT(context))
8724  {
8725  int indentAmount;
8726 
8727  context->indentLevel += indentBefore;
8728 
8729  /* remove any trailing spaces currently in the buffer ... */
8731  /* ... then add a newline and some spaces */
8732  appendStringInfoChar(buf, '\n');
8733 
8734  if (context->indentLevel < PRETTYINDENT_LIMIT)
8735  indentAmount = Max(context->indentLevel, 0) + indentPlus;
8736  else
8737  {
8738  /*
8739  * If we're indented more than PRETTYINDENT_LIMIT characters, try
8740  * to conserve horizontal space by reducing the per-level
8741  * indentation. For best results the scale factor here should
8742  * divide all the indent amounts that get added to indentLevel
8743  * (PRETTYINDENT_STD, etc). It's important that the indentation
8744  * not grow unboundedly, else deeply-nested trees use O(N^2)
8745  * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8746  */
8747  indentAmount = PRETTYINDENT_LIMIT +
8748  (context->indentLevel - PRETTYINDENT_LIMIT) /
8749  (PRETTYINDENT_STD / 2);
8750  indentAmount %= PRETTYINDENT_LIMIT;
8751  /* scale/wrap logic affects indentLevel, but not indentPlus */
8752  indentAmount += indentPlus;
8753  }
8754  appendStringInfoSpaces(buf, indentAmount);
8755 
8757 
8758  context->indentLevel += indentAfter;
8759  if (context->indentLevel < 0)
8760  context->indentLevel = 0;
8761  }
8762  else
8764 }
8765 
8766 /*
8767  * removeStringInfoSpaces - delete trailing spaces from a buffer.
8768  *
8769  * Possibly this should move to stringinfo.c at some point.
8770  */
8771 static void
8773 {
8774  while (str->len > 0 && str->data[str->len - 1] == ' ')
8775  str->data[--(str->len)] = '\0';
8776 }
8777 
8778 
8779 /*
8780  * get_rule_expr_paren - deparse expr using get_rule_expr,
8781  * embracing the string with parentheses if necessary for prettyPrint.
8782  *
8783  * Never embrace if prettyFlags=0, because it's done in the calling node.
8784  *
8785  * Any node that does *not* embrace its argument node by sql syntax (with
8786  * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
8787  * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
8788  * added.
8789  */
8790 static void
8792  bool showimplicit, Node *parentNode)
8793 {
8794  bool need_paren;
8795 
8796  need_paren = PRETTY_PAREN(context) &&
8797  !isSimpleNode(node, parentNode, context->prettyFlags);
8798 
8799  if (need_paren)
8800  appendStringInfoChar(context->buf, '(');
8801 
8802  get_rule_expr(node, context, showimplicit);
8803 
8804  if (need_paren)
8805  appendStringInfoChar(context->buf, ')');
8806 }
8807 
8808 static void
8810  const char *on)
8811 {
8812  /*
8813  * The order of array elements must correspond to the order of
8814  * JsonBehaviorType members.
8815  */
8816  const char *behavior_names[] =
8817  {
8818  " NULL",
8819  " ERROR",
8820  " EMPTY",
8821  " TRUE",
8822  " FALSE",
8823  " UNKNOWN",
8824  " EMPTY ARRAY",
8825  " EMPTY OBJECT",
8826  " DEFAULT "
8827  };
8828 
8829  if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
8830  elog(ERROR, "invalid json behavior type: %d", behavior->btype);
8831 
8832  appendStringInfoString(context->buf, behavior_names[behavior->btype]);
8833 
8834  if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
8835  get_rule_expr(behavior->expr, context, false);
8836 
8837  appendStringInfo(context->buf, " ON %s", on);
8838 }
8839 
8840 /*
8841  * get_json_expr_options
8842  *
8843  * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
8844  * JSON_TABLE columns.
8845  */
8846 static void
8848  JsonBehaviorType default_behavior)
8849 {
8850  if (jsexpr->op == JSON_QUERY_OP)
8851  {
8852  if (jsexpr->wrapper == JSW_CONDITIONAL)
8853  appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
8854  else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
8855  appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
8856  /* The default */
8857  else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
8858  appendStringInfoString(context->buf, " WITHOUT WRAPPER");
8859 
8860  if (jsexpr->omit_quotes)
8861  appendStringInfoString(context->buf, " OMIT QUOTES");
8862  /* The default */
8863  else
8864  appendStringInfoString(context->buf, " KEEP QUOTES");
8865  }
8866 
8867  if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
8868  get_json_behavior(jsexpr->on_empty, context, "EMPTY");
8869 
8870  if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
8871  get_json_behavior(jsexpr->on_error, context, "ERROR");
8872 }
8873 
8874 /* ----------
8875  * get_rule_expr - Parse back an expression
8876  *
8877  * Note: showimplicit determines whether we display any implicit cast that
8878  * is present at the top of the expression tree. It is a passed argument,
8879  * not a field of the context struct, because we change the value as we
8880  * recurse down into the expression. In general we suppress implicit casts
8881  * when the result type is known with certainty (eg, the arguments of an
8882  * OR must be boolean). We display implicit casts for arguments of functions
8883  * and operators, since this is needed to be certain that the same function
8884  * or operator will be chosen when the expression is re-parsed.
8885  * ----------
8886  */
8887 static void
8889  bool showimplicit)
8890 {
8891  StringInfo buf = context->buf;
8892 
8893  if (node == NULL)
8894  return;
8895 
8896  /* Guard against excessively long or deeply-nested queries */
8899 
8900  /*
8901  * Each level of get_rule_expr must emit an indivisible term
8902  * (parenthesized if necessary) to ensure result is reparsed into the same
8903  * expression tree. The only exception is that when the input is a List,
8904  * we emit the component items comma-separated with no surrounding
8905  * decoration; this is convenient for most callers.
8906  */
8907  switch (nodeTag(node))
8908  {
8909  case T_Var:
8910  (void) get_variable((Var *) node, 0, false, context);
8911  break;
8912 
8913  case T_Const:
8914  get_const_expr((Const *) node, context, 0);
8915  break;
8916 
8917  case T_Param:
8918  get_parameter((Param *) node, context);
8919  break;
8920 
8921  case T_Aggref:
8922  get_agg_expr((Aggref *) node, context, (Aggref *) node);
8923  break;
8924 
8925  case T_GroupingFunc:
8926  {
8927  GroupingFunc *gexpr = (GroupingFunc *) node;
8928 
8929  appendStringInfoString(buf, "GROUPING(");
8930  get_rule_expr((Node *) gexpr->args, context, true);
8931  appendStringInfoChar(buf, ')');
8932  }
8933  break;
8934 
8935  case T_WindowFunc:
8937  break;
8938 
8939  case T_MergeSupportFunc:
8940  appendStringInfoString(buf, "MERGE_ACTION()");
8941  break;
8942 
8943  case T_SubscriptingRef:
8944  {
8945  SubscriptingRef *sbsref = (SubscriptingRef *) node;
8946  bool need_parens;
8947 
8948  /*
8949  * If the argument is a CaseTestExpr, we must be inside a
8950  * FieldStore, ie, we are assigning to an element of an array
8951  * within a composite column. Since we already punted on
8952  * displaying the FieldStore's target information, just punt
8953  * here too, and display only the assignment source
8954  * expression.
8955  */
8956  if (IsA(sbsref->refexpr, CaseTestExpr))
8957  {
8958  Assert(sbsref->refassgnexpr);
8959  get_rule_expr((Node *) sbsref->refassgnexpr,
8960  context, showimplicit);
8961  break;
8962  }
8963 
8964  /*
8965  * Parenthesize the argument unless it's a simple Var or a
8966  * FieldSelect. (In particular, if it's another
8967  * SubscriptingRef, we *must* parenthesize to avoid
8968  * confusion.)
8969  */
8970  need_parens = !IsA(sbsref->refexpr, Var) &&
8971  !IsA(sbsref->refexpr, FieldSelect);
8972  if (need_parens)
8973  appendStringInfoChar(buf, '(');
8974  get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
8975  if (need_parens)
8976  appendStringInfoChar(buf, ')');
8977 
8978  /*
8979  * If there's a refassgnexpr, we want to print the node in the
8980  * format "container[subscripts] := refassgnexpr". This is
8981  * not legal SQL, so decompilation of INSERT or UPDATE
8982  * statements should always use processIndirection as part of
8983  * the statement-level syntax. We should only see this when
8984  * EXPLAIN tries to print the targetlist of a plan resulting
8985  * from such a statement.
8986  */
8987  if (sbsref->refassgnexpr)
8988  {
8989  Node *refassgnexpr;
8990 
8991  /*
8992  * Use processIndirection to print this node's subscripts
8993  * as well as any additional field selections or
8994  * subscripting in immediate descendants. It returns the
8995  * RHS expr that is actually being "assigned".
8996  */
8997  refassgnexpr = processIndirection(node, context);
8998  appendStringInfoString(buf, " := ");
8999  get_rule_expr(refassgnexpr, context, showimplicit);
9000  }
9001  else
9002  {
9003  /* Just an ordinary container fetch, so print subscripts */
9004  printSubscripts(sbsref, context);
9005  }
9006  }
9007  break;
9008 
9009  case T_FuncExpr:
9010  get_func_expr((FuncExpr *) node, context, showimplicit);
9011  break;
9012 
9013  case T_NamedArgExpr:
9014  {
9015  NamedArgExpr *na = (NamedArgExpr *) node;
9016 
9017  appendStringInfo(buf, "%s => ", quote_identifier(na->name));
9018  get_rule_expr((Node *) na->arg, context, showimplicit);
9019  }
9020  break;
9021 
9022  case T_OpExpr:
9023  get_oper_expr((OpExpr *) node, context);
9024  break;
9025 
9026  case T_DistinctExpr:
9027  {
9028  DistinctExpr *expr = (DistinctExpr *) node;
9029  List *args = expr->args;
9030  Node *arg1 = (Node *) linitial(args);
9031  Node *arg2 = (Node *) lsecond(args);
9032 
9033  if (!PRETTY_PAREN(context))
9034  appendStringInfoChar(buf, '(');
9035  get_rule_expr_paren(arg1, context, true, node);
9036  appendStringInfoString(buf, " IS DISTINCT FROM ");
9037  get_rule_expr_paren(arg2, context, true, node);
9038  if (!PRETTY_PAREN(context))
9039  appendStringInfoChar(buf, ')');
9040  }
9041  break;
9042 
9043  case T_NullIfExpr:
9044  {
9045  NullIfExpr *nullifexpr = (NullIfExpr *) node;
9046 
9047  appendStringInfoString(buf, "NULLIF(");
9048  get_rule_expr((Node *) nullifexpr->args, context, true);
9049  appendStringInfoChar(buf, ')');
9050  }
9051  break;
9052 
9053  case T_ScalarArrayOpExpr:
9054  {
9055  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
9056  List *args = expr->args;
9057  Node *arg1 = (Node *) linitial(args);
9058  Node *arg2 = (Node *) lsecond(args);
9059 
9060  if (!PRETTY_PAREN(context))
9061  appendStringInfoChar(buf, '(');
9062  get_rule_expr_paren(arg1, context, true, node);
9063  appendStringInfo(buf, " %s %s (",
9065  exprType(arg1),
9067  expr->useOr ? "ANY" : "ALL");
9068  get_rule_expr_paren(arg2, context, true, node);
9069 
9070  /*
9071  * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9072  * a bare sub-SELECT. Since we're here, the sub-SELECT must
9073  * be meant as a scalar sub-SELECT yielding an array value to
9074  * be used in ScalarArrayOpExpr; but the grammar will
9075  * preferentially interpret such a construct as an ANY/ALL
9076  * SubLink. To prevent misparsing the output that way, insert
9077  * a dummy coercion (which will be stripped by parse analysis,
9078  * so no inefficiency is added in dump and reload). This is
9079  * indeed most likely what the user wrote to get the construct
9080  * accepted in the first place.
9081  */
9082  if (IsA(arg2, SubLink) &&
9083  ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
9084  appendStringInfo(buf, "::%s",
9086  exprTypmod(arg2)));
9087  appendStringInfoChar(buf, ')');
9088  if (!PRETTY_PAREN(context))
9089  appendStringInfoChar(buf, ')');
9090  }
9091  break;
9092 
9093  case T_BoolExpr:
9094  {
9095  BoolExpr *expr = (BoolExpr *) node;
9096  Node *first_arg = linitial(expr->args);
9097  ListCell *arg;
9098 
9099  switch (expr->boolop)
9100  {
9101  case AND_EXPR:
9102  if (!PRETTY_PAREN(context))
9103  appendStringInfoChar(buf, '(');
9104  get_rule_expr_paren(first_arg, context,
9105  false, node);
9106  for_each_from(arg, expr->args, 1)
9107  {
9108  appendStringInfoString(buf, " AND ");
9110  false, node);
9111  }
9112  if (!PRETTY_PAREN(context))
9113  appendStringInfoChar(buf, ')');
9114  break;
9115 
9116  case OR_EXPR:
9117  if (!PRETTY_PAREN(context))
9118  appendStringInfoChar(buf, '(');
9119  get_rule_expr_paren(first_arg, context,
9120  false, node);
9121  for_each_from(arg, expr->args, 1)
9122  {
9123  appendStringInfoString(buf, " OR ");
9125  false, node);
9126  }
9127  if (!PRETTY_PAREN(context))
9128  appendStringInfoChar(buf, ')');
9129  break;
9130 
9131  case NOT_EXPR:
9132  if (!PRETTY_PAREN(context))
9133  appendStringInfoChar(buf, '(');
9134  appendStringInfoString(buf, "NOT ");
9135  get_rule_expr_paren(first_arg, context,
9136  false, node);
9137  if (!PRETTY_PAREN(context))
9138  appendStringInfoChar(buf, ')');
9139  break;
9140 
9141  default:
9142  elog(ERROR, "unrecognized boolop: %d",
9143  (int) expr->boolop);
9144  }
9145  }
9146  break;
9147 
9148  case T_SubLink:
9149  get_sublink_expr((SubLink *) node, context);
9150  break;
9151 
9152  case T_SubPlan:
9153  {
9154  SubPlan *subplan = (SubPlan *) node;
9155 
9156  /*
9157  * We cannot see an already-planned subplan in rule deparsing,
9158  * only while EXPLAINing a query plan. We don't try to
9159  * reconstruct the original SQL, just reference the subplan
9160  * that appears elsewhere in EXPLAIN's result. It does seem
9161  * useful to show the subLinkType and testexpr (if any), and
9162  * we also note whether the subplan will be hashed.
9163  */
9164  switch (subplan->subLinkType)
9165  {
9166  case EXISTS_SUBLINK:
9167  appendStringInfoString(buf, "EXISTS(");
9168  Assert(subplan->testexpr == NULL);
9169  break;
9170  case ALL_SUBLINK:
9171  appendStringInfoString(buf, "(ALL ");
9172  Assert(subplan->testexpr != NULL);
9173  break;
9174  case ANY_SUBLINK:
9175  appendStringInfoString(buf, "(ANY ");
9176  Assert(subplan->testexpr != NULL);
9177  break;
9178  case ROWCOMPARE_SUBLINK:
9179  /* Parenthesizing the testexpr seems sufficient */
9180  appendStringInfoChar(buf, '(');
9181  Assert(subplan->testexpr != NULL);
9182  break;
9183  case EXPR_SUBLINK:
9184  /* No need to decorate these subplan references */
9185  appendStringInfoChar(buf, '(');
9186  Assert(subplan->testexpr == NULL);
9187  break;
9188  case MULTIEXPR_SUBLINK:
9189  /* MULTIEXPR isn't executed in the normal way */
9190  appendStringInfoString(buf, "(rescan ");
9191  Assert(subplan->testexpr == NULL);
9192  break;
9193  case ARRAY_SUBLINK:
9194  appendStringInfoString(buf, "ARRAY(");
9195  Assert(subplan->testexpr == NULL);
9196  break;
9197  case CTE_SUBLINK:
9198  /* This case is unreachable within expressions */
9199  appendStringInfoString(buf, "CTE(");
9200  Assert(subplan->testexpr == NULL);
9201  break;
9202  }
9203 
9204  if (subplan->testexpr != NULL)
9205  {
9206  deparse_namespace *dpns;
9207 
9208  /*
9209  * Push SubPlan into ancestors list while deparsing
9210  * testexpr, so that we can handle PARAM_EXEC references
9211  * to the SubPlan's paramIds. (This makes it look like
9212  * the SubPlan is an "ancestor" of the current plan node,
9213  * which is a little weird, but it does no harm.) In this
9214  * path, we don't need to mention the SubPlan explicitly,
9215  * because the referencing Params will show its existence.
9216  */
9217  dpns = (deparse_namespace *) linitial(context->namespaces);
9218  dpns->ancestors = lcons(subplan, dpns->ancestors);
9219 
9220  get_rule_expr(subplan->testexpr, context, showimplicit);
9221  appendStringInfoChar(buf, ')');
9222 
9223  dpns->ancestors = list_delete_first(dpns->ancestors);
9224  }
9225  else
9226  {
9227  /* No referencing Params, so show the SubPlan's name */
9228  if (subplan->useHashTable)
9229  appendStringInfo(buf, "hashed %s)", subplan->plan_name);
9230  else
9231  appendStringInfo(buf, "%s)", subplan->plan_name);
9232  }
9233  }
9234  break;
9235 
9236  case T_AlternativeSubPlan:
9237  {
9238  AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
9239  ListCell *lc;
9240 
9241  /*
9242  * This case cannot be reached in normal usage, since no
9243  * AlternativeSubPlan can appear either in parsetrees or
9244  * finished plan trees. We keep it just in case somebody
9245  * wants to use this code to print planner data structures.
9246  */
9247  appendStringInfoString(buf, "(alternatives: ");
9248  foreach(lc, asplan->subplans)
9249  {
9250  SubPlan *splan = lfirst_node(SubPlan, lc);
9251 
9252  if (splan->useHashTable)
9253  appendStringInfo(buf, "hashed %s", splan->plan_name);
9254  else
9255  appendStringInfoString(buf, splan->plan_name);
9256  if (lnext(asplan->subplans, lc))
9257  appendStringInfoString(buf, " or ");
9258  }
9259  appendStringInfoChar(buf, ')');
9260  }
9261  break;
9262 
9263  case T_FieldSelect:
9264  {
9265  FieldSelect *fselect = (FieldSelect *) node;
9266  Node *arg = (Node *) fselect->arg;
9267  int fno = fselect->fieldnum;
9268  const char *fieldname;
9269  bool need_parens;
9270 
9271  /*
9272  * Parenthesize the argument unless it's an SubscriptingRef or
9273  * another FieldSelect. Note in particular that it would be
9274  * WRONG to not parenthesize a Var argument; simplicity is not
9275  * the issue here, having the right number of names is.
9276  */
9277  need_parens = !IsA(arg, SubscriptingRef) &&
9278  !IsA(arg, FieldSelect);
9279  if (need_parens)
9280  appendStringInfoChar(buf, '(');
9281  get_rule_expr(arg, context, true);
9282  if (need_parens)
9283  appendStringInfoChar(buf, ')');
9284 
9285  /*
9286  * Get and print the field name.
9287  */
9288  fieldname = get_name_for_var_field((Var *) arg, fno,
9289  0, context);
9290  appendStringInfo(buf, ".%s", quote_identifier(fieldname));
9291  }
9292  break;
9293 
9294  case T_FieldStore:
9295  {
9296  FieldStore *fstore = (FieldStore *) node;
9297  bool need_parens;
9298 
9299  /*
9300  * There is no good way to represent a FieldStore as real SQL,
9301  * so decompilation of INSERT or UPDATE statements should
9302  * always use processIndirection as part of the
9303  * statement-level syntax. We should only get here when
9304  * EXPLAIN tries to print the targetlist of a plan resulting
9305  * from such a statement. The plan case is even harder than
9306  * ordinary rules would be, because the planner tries to
9307  * collapse multiple assignments to the same field or subfield
9308  * into one FieldStore; so we can see a list of target fields
9309  * not just one, and the arguments could be FieldStores
9310  * themselves. We don't bother to try to print the target
9311  * field names; we just print the source arguments, with a
9312  * ROW() around them if there's more than one. This isn't
9313  * terribly complete, but it's probably good enough for
9314  * EXPLAIN's purposes; especially since anything more would be
9315  * either hopelessly confusing or an even poorer
9316  * representation of what the plan is actually doing.
9317  */
9318  need_parens = (list_length(fstore->newvals) != 1);
9319  if (need_parens)
9320  appendStringInfoString(buf, "ROW(");
9321  get_rule_expr((Node *) fstore->newvals, context, showimplicit);
9322  if (need_parens)
9323  appendStringInfoChar(buf, ')');
9324  }
9325  break;
9326 
9327  case T_RelabelType:
9328  {
9329  RelabelType *relabel = (RelabelType *) node;
9330  Node *arg = (Node *) relabel->arg;
9331 
9332  if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
9333  !showimplicit)
9334  {
9335  /* don't show the implicit cast */
9336  get_rule_expr_paren(arg, context, false, node);
9337  }
9338  else
9339  {
9341  relabel->resulttype,
9342  relabel->resulttypmod,
9343  node);
9344  }
9345  }
9346  break;
9347 
9348  case T_CoerceViaIO:
9349  {
9350  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
9351  Node *arg = (Node *) iocoerce->arg;
9352 
9353  if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9354  !showimplicit)
9355  {
9356  /* don't show the implicit cast */
9357  get_rule_expr_paren(arg, context, false, node);
9358  }
9359  else
9360  {
9362  iocoerce->resulttype,
9363  -1,
9364  node);
9365  }
9366  }
9367  break;
9368 
9369  case T_ArrayCoerceExpr:
9370  {
9371  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
9372  Node *arg = (Node *) acoerce->arg;
9373 
9374  if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9375  !showimplicit)
9376  {
9377  /* don't show the implicit cast */
9378  get_rule_expr_paren(arg, context, false, node);
9379  }
9380  else
9381  {
9383  acoerce->resulttype,
9384  acoerce->resulttypmod,
9385  node);
9386  }
9387  }
9388  break;
9389 
9390  case T_ConvertRowtypeExpr:
9391  {
9393  Node *arg = (Node *) convert->arg;
9394 
9395  if (convert->convertformat == COERCE_IMPLICIT_CAST &&
9396  !showimplicit)
9397  {
9398  /* don't show the implicit cast */
9399  get_rule_expr_paren(arg, context, false, node);
9400  }
9401  else
9402  {
9404  convert->resulttype, -1,
9405  node);
9406  }
9407  }
9408  break;
9409 
9410  case T_CollateExpr:
9411  {
9412  CollateExpr *collate = (CollateExpr *) node;
9413  Node *arg = (Node *) collate->arg;
9414 
9415  if (!PRETTY_PAREN(context))
9416  appendStringInfoChar(buf, '(');
9417  get_rule_expr_paren(arg, context, showimplicit, node);
9418  appendStringInfo(buf, " COLLATE %s",
9419  generate_collation_name(collate->collOid));
9420  if (!PRETTY_PAREN(context))
9421  appendStringInfoChar(buf, ')');
9422  }
9423  break;
9424 
9425  case T_CaseExpr:
9426  {
9427  CaseExpr *caseexpr = (CaseExpr *) node;
9428  ListCell *temp;
9429 
9430  appendContextKeyword(context, "CASE",
9431  0, PRETTYINDENT_VAR, 0);
9432  if (caseexpr->arg)
9433  {
9434  appendStringInfoChar(buf, ' ');
9435  get_rule_expr((Node *) caseexpr->arg, context, true);
9436  }
9437  foreach(temp, caseexpr->args)
9438  {
9439  CaseWhen *when = (CaseWhen *) lfirst(temp);
9440  Node *w = (Node *) when->expr;
9441 
9442  if (caseexpr->arg)
9443  {
9444  /*
9445  * The parser should have produced WHEN clauses of the
9446  * form "CaseTestExpr = RHS", possibly with an
9447  * implicit coercion inserted above the CaseTestExpr.
9448  * For accurate decompilation of rules it's essential
9449  * that we show just the RHS. However in an
9450  * expression that's been through the optimizer, the
9451  * WHEN clause could be almost anything (since the
9452  * equality operator could have been expanded into an
9453  * inline function). If we don't recognize the form
9454  * of the WHEN clause, just punt and display it as-is.
9455  */
9456  if (IsA(w, OpExpr))
9457  {
9458  List *args = ((OpExpr *) w)->args;
9459 
9460  if (list_length(args) == 2 &&
9462  CaseTestExpr))
9463  w = (Node *) lsecond(args);
9464  }
9465  }
9466 
9467  if (!PRETTY_INDENT(context))
9468  appendStringInfoChar(buf, ' ');
9469  appendContextKeyword(context, "WHEN ",
9470  0, 0, 0);
9471  get_rule_expr(w, context, false);
9472  appendStringInfoString(buf, " THEN ");
9473  get_rule_expr((Node *) when->result, context, true);
9474  }
9475  if (!PRETTY_INDENT(context))
9476  appendStringInfoChar(buf, ' ');
9477  appendContextKeyword(context, "ELSE ",
9478  0, 0, 0);
9479  get_rule_expr((Node *) caseexpr->defresult, context, true);
9480  if (!PRETTY_INDENT(context))
9481  appendStringInfoChar(buf, ' ');
9483  -PRETTYINDENT_VAR, 0, 0);
9484  }
9485  break;
9486 
9487  case T_CaseTestExpr:
9488  {
9489  /*
9490  * Normally we should never get here, since for expressions
9491  * that can contain this node type we attempt to avoid
9492  * recursing to it. But in an optimized expression we might
9493  * be unable to avoid that (see comments for CaseExpr). If we
9494  * do see one, print it as CASE_TEST_EXPR.
9495  */
9496  appendStringInfoString(buf, "CASE_TEST_EXPR");
9497  }
9498  break;
9499 
9500  case T_ArrayExpr:
9501  {
9502  ArrayExpr *arrayexpr = (ArrayExpr *) node;
9503 
9504  appendStringInfoString(buf, "ARRAY[");
9505  get_rule_expr((Node *) arrayexpr->elements, context, true);
9506  appendStringInfoChar(buf, ']');
9507 
9508  /*
9509  * If the array isn't empty, we assume its elements are
9510  * coerced to the desired type. If it's empty, though, we
9511  * need an explicit coercion to the array type.
9512  */
9513  if (arrayexpr->elements == NIL)
9514  appendStringInfo(buf, "::%s",
9515  format_type_with_typemod(arrayexpr->array_typeid, -1));
9516  }
9517  break;
9518 
9519  case T_RowExpr:
9520  {
9521  RowExpr *rowexpr = (RowExpr *) node;
9522  TupleDesc tupdesc = NULL;
9523  ListCell *arg;
9524  int i;
9525  char *sep;
9526 
9527  /*
9528  * If it's a named type and not RECORD, we may have to skip
9529  * dropped columns and/or claim there are NULLs for added
9530  * columns.
9531  */
9532  if (rowexpr->row_typeid != RECORDOID)
9533  {
9534  tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9535  Assert(list_length(rowexpr->args) <= tupdesc->natts);
9536  }
9537 
9538  /*
9539  * SQL99 allows "ROW" to be omitted when there is more than
9540  * one column, but for simplicity we always print it.
9541  */
9542  appendStringInfoString(buf, "ROW(");
9543  sep = "";
9544  i = 0;
9545  foreach(arg, rowexpr->args)
9546  {
9547  Node *e = (Node *) lfirst(arg);
9548 
9549  if (tupdesc == NULL ||
9550  !TupleDescAttr(tupdesc, i)->attisdropped)
9551  {
9553  /* Whole-row Vars need special treatment here */
9555  sep = ", ";
9556  }
9557  i++;
9558  }
9559  if (tupdesc != NULL)
9560  {
9561  while (i < tupdesc->natts)
9562  {
9563  if (!TupleDescAttr(tupdesc, i)->attisdropped)
9564  {
9566  appendStringInfoString(buf, "NULL");
9567  sep = ", ";
9568  }
9569  i++;
9570  }
9571 
9572  ReleaseTupleDesc(tupdesc);
9573  }
9574  appendStringInfoChar(buf, ')');
9575  if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9576  appendStringInfo(buf, "::%s",
9577  format_type_with_typemod(rowexpr->row_typeid, -1));
9578  }
9579  break;
9580 
9581  case T_RowCompareExpr:
9582  {
9583  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9584 
9585  /*
9586  * SQL99 allows "ROW" to be omitted when there is more than
9587  * one column, but for simplicity we always print it. Within
9588  * a ROW expression, whole-row Vars need special treatment, so
9589  * use get_rule_list_toplevel.
9590  */
9591  appendStringInfoString(buf, "(ROW(");
9592  get_rule_list_toplevel(rcexpr->largs, context, true);
9593 
9594  /*
9595  * We assume that the name of the first-column operator will
9596  * do for all the rest too. This is definitely open to
9597  * failure, eg if some but not all operators were renamed
9598  * since the construct was parsed, but there seems no way to
9599  * be perfect.
9600  */
9601  appendStringInfo(buf, ") %s ROW(",
9602  generate_operator_name(linitial_oid(rcexpr->opnos),
9603  exprType(linitial(rcexpr->largs)),
9604  exprType(linitial(rcexpr->rargs))));
9605  get_rule_list_toplevel(rcexpr->rargs, context, true);
9606  appendStringInfoString(buf, "))");
9607  }
9608  break;
9609 
9610  case T_CoalesceExpr:
9611  {
9612  CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
9613 
9614  appendStringInfoString(buf, "COALESCE(");
9615  get_rule_expr((Node *) coalesceexpr->args, context, true);
9616  appendStringInfoChar(buf, ')');
9617  }
9618  break;
9619 
9620  case T_MinMaxExpr:
9621  {
9622  MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9623 
9624  switch (minmaxexpr->op)
9625  {
9626  case IS_GREATEST:
9627  appendStringInfoString(buf, "GREATEST(");
9628  break;
9629  case IS_LEAST:
9630  appendStringInfoString(buf, "LEAST(");
9631  break;
9632  }
9633  get_rule_expr((Node *) minmaxexpr->args, context, true);
9634  appendStringInfoChar(buf, ')');
9635  }
9636  break;
9637 
9638  case T_SQLValueFunction:
9639  {
9640  SQLValueFunction *svf = (SQLValueFunction *) node;
9641 
9642  /*
9643  * Note: this code knows that typmod for time, timestamp, and
9644  * timestamptz just prints as integer.
9645  */
9646  switch (svf->op)
9647  {
9648  case SVFOP_CURRENT_DATE:
9649  appendStringInfoString(buf, "CURRENT_DATE");
9650  break;
9651  case SVFOP_CURRENT_TIME:
9652  appendStringInfoString(buf, "CURRENT_TIME");
9653  break;
9654  case SVFOP_CURRENT_TIME_N:
9655  appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
9656  break;
9658  appendStringInfoString(buf, "CURRENT_TIMESTAMP");
9659  break;
9661  appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
9662  svf->typmod);
9663  break;
9664  case SVFOP_LOCALTIME:
9665  appendStringInfoString(buf, "LOCALTIME");
9666  break;
9667  case SVFOP_LOCALTIME_N:
9668  appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
9669  break;
9670  case SVFOP_LOCALTIMESTAMP:
9671  appendStringInfoString(buf, "LOCALTIMESTAMP");
9672  break;
9674  appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
9675  svf->typmod);
9676  break;
9677  case SVFOP_CURRENT_ROLE:
9678  appendStringInfoString(buf, "CURRENT_ROLE");
9679  break;
9680  case SVFOP_CURRENT_USER:
9681  appendStringInfoString(buf, "CURRENT_USER");
9682  break;
9683  case SVFOP_USER:
9684  appendStringInfoString(buf, "USER");
9685  break;
9686  case SVFOP_SESSION_USER:
9687  appendStringInfoString(buf, "SESSION_USER");
9688  break;
9689  case SVFOP_CURRENT_CATALOG:
9690  appendStringInfoString(buf, "CURRENT_CATALOG");
9691  break;
9692  case SVFOP_CURRENT_SCHEMA:
9693  appendStringInfoString(buf, "CURRENT_SCHEMA");
9694  break;
9695  }
9696  }
9697  break;
9698 
9699  case T_XmlExpr:
9700  {
9701  XmlExpr *xexpr = (XmlExpr *) node;
9702  bool needcomma = false;
9703  ListCell *arg;
9704  ListCell *narg;
9705  Const *con;
9706 
9707  switch (xexpr->op)
9708  {
9709  case IS_XMLCONCAT:
9710  appendStringInfoString(buf, "XMLCONCAT(");
9711  break;
9712  case IS_XMLELEMENT:
9713  appendStringInfoString(buf, "XMLELEMENT(");
9714  break;
9715  case IS_XMLFOREST:
9716  appendStringInfoString(buf, "XMLFOREST(");
9717  break;
9718  case IS_XMLPARSE:
9719  appendStringInfoString(buf, "XMLPARSE(");
9720  break;
9721  case IS_XMLPI:
9722  appendStringInfoString(buf, "XMLPI(");
9723  break;
9724  case IS_XMLROOT:
9725  appendStringInfoString(buf, "XMLROOT(");
9726  break;
9727  case IS_XMLSERIALIZE:
9728  appendStringInfoString(buf, "XMLSERIALIZE(");
9729  break;
9730  case IS_DOCUMENT:
9731  break;
9732  }
9733  if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
9734  {
9735  if (xexpr->xmloption == XMLOPTION_DOCUMENT)
9736  appendStringInfoString(buf, "DOCUMENT ");
9737  else
9738  appendStringInfoString(buf, "CONTENT ");
9739  }
9740  if (xexpr->name)
9741  {
9742  appendStringInfo(buf, "NAME %s",
9744  needcomma = true;
9745  }
9746  if (xexpr->named_args)
9747  {
9748  if (xexpr->op != IS_XMLFOREST)
9749  {
9750  if (needcomma)
9751  appendStringInfoString(buf, ", ");
9752  appendStringInfoString(buf, "XMLATTRIBUTES(");
9753  needcomma = false;
9754  }
9755  forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
9756  {
9757  Node *e = (Node *) lfirst(arg);
9758  char *argname = strVal(lfirst(narg));
9759 
9760  if (needcomma)
9761  appendStringInfoString(buf, ", ");
9762  get_rule_expr((Node *) e, context, true);
9763  appendStringInfo(buf, " AS %s",
9765  needcomma = true;
9766  }
9767  if (xexpr->op != IS_XMLFOREST)
9768  appendStringInfoChar(buf, ')');
9769  }
9770  if (xexpr->args)
9771  {
9772  if (needcomma)
9773  appendStringInfoString(buf, ", ");
9774  switch (xexpr->op)
9775  {
9776  case IS_XMLCONCAT:
9777  case IS_XMLELEMENT:
9778  case IS_XMLFOREST:
9779  case IS_XMLPI:
9780  case IS_XMLSERIALIZE:
9781  /* no extra decoration needed */
9782  get_rule_expr((Node *) xexpr->args, context, true);
9783  break;
9784  case IS_XMLPARSE:
9785  Assert(list_length(xexpr->args) == 2);
9786 
9787  get_rule_expr((Node *) linitial(xexpr->args),
9788  context, true);
9789 
9790  con = lsecond_node(Const, xexpr->args);
9791  Assert(!con->constisnull);
9792  if (DatumGetBool(con->constvalue))
9794  " PRESERVE WHITESPACE");
9795  else
9797  " STRIP WHITESPACE");
9798  break;
9799  case IS_XMLROOT:
9800  Assert(list_length(xexpr->args) == 3);
9801 
9802  get_rule_expr((Node *) linitial(xexpr->args),
9803  context, true);
9804 
9805  appendStringInfoString(buf, ", VERSION ");
9806  con = (Const *) lsecond(xexpr->args);
9807  if (IsA(con, Const) &&
9808  con->constisnull)
9809  appendStringInfoString(buf, "NO VALUE");
9810  else
9811  get_rule_expr((Node *) con, context, false);
9812 
9813  con = lthird_node(Const, xexpr->args);
9814  if (con->constisnull)
9815  /* suppress STANDALONE NO VALUE */ ;
9816  else
9817  {
9818  switch (DatumGetInt32(con->constvalue))
9819  {
9820  case XML_STANDALONE_YES:
9822  ", STANDALONE YES");
9823  break;
9824  case XML_STANDALONE_NO:
9826  ", STANDALONE NO");
9827  break;
9830  ", STANDALONE NO VALUE");
9831  break;
9832  default:
9833  break;
9834  }
9835  }
9836  break;
9837  case IS_DOCUMENT:
9838  get_rule_expr_paren((Node *) xexpr->args, context, false, node);
9839  break;
9840  }
9841  }
9842  if (xexpr->op == IS_XMLSERIALIZE)
9843  appendStringInfo(buf, " AS %s",
9844  format_type_with_typemod(xexpr->type,
9845  xexpr->typmod));
9846  if (xexpr->op == IS_DOCUMENT)
9847  appendStringInfoString(buf, " IS DOCUMENT");
9848  else
9849  appendStringInfoChar(buf, ')');
9850  }
9851  break;
9852 
9853  case T_NullTest:
9854  {
9855  NullTest *ntest = (NullTest *) node;
9856 
9857  if (!PRETTY_PAREN(context))
9858  appendStringInfoChar(buf, '(');
9859  get_rule_expr_paren((Node *) ntest->arg, context, true, node);
9860 
9861  /*
9862  * For scalar inputs, we prefer to print as IS [NOT] NULL,
9863  * which is shorter and traditional. If it's a rowtype input
9864  * but we're applying a scalar test, must print IS [NOT]
9865  * DISTINCT FROM NULL to be semantically correct.
9866  */
9867  if (ntest->argisrow ||
9868  !type_is_rowtype(exprType((Node *) ntest->arg)))
9869  {
9870  switch (ntest->nulltesttype)
9871  {
9872  case IS_NULL:
9873  appendStringInfoString(buf, " IS NULL");
9874  break;
9875  case IS_NOT_NULL:
9876  appendStringInfoString(buf, " IS NOT NULL");
9877  break;
9878  default:
9879  elog(ERROR, "unrecognized nulltesttype: %d",
9880  (int) ntest->nulltesttype);
9881  }
9882  }
9883  else
9884  {
9885  switch (ntest->nulltesttype)
9886  {
9887  case IS_NULL:
9888  appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
9889  break;
9890  case IS_NOT_NULL:
9891  appendStringInfoString(buf, " IS DISTINCT FROM NULL");
9892  break;
9893  default:
9894  elog(ERROR, "unrecognized nulltesttype: %d",
9895  (int) ntest->nulltesttype);
9896  }
9897  }
9898  if (!PRETTY_PAREN(context))
9899  appendStringInfoChar(buf, ')');
9900  }
9901  break;
9902 
9903  case T_BooleanTest:
9904  {
9905  BooleanTest *btest = (BooleanTest *) node;
9906 
9907  if (!PRETTY_PAREN(context))
9908  appendStringInfoChar(buf, '(');
9909  get_rule_expr_paren((Node *) btest->arg, context, false, node);
9910  switch (btest->booltesttype)
9911  {
9912  case IS_TRUE:
9913  appendStringInfoString(buf, " IS TRUE");
9914  break;
9915  case IS_NOT_TRUE:
9916  appendStringInfoString(buf, " IS NOT TRUE");
9917  break;
9918  case IS_FALSE:
9919  appendStringInfoString(buf, " IS FALSE");
9920  break;
9921  case IS_NOT_FALSE:
9922  appendStringInfoString(buf, " IS NOT FALSE");
9923  break;
9924  case IS_UNKNOWN:
9925  appendStringInfoString(buf, " IS UNKNOWN");
9926  break;
9927  case IS_NOT_UNKNOWN:
9928  appendStringInfoString(buf, " IS NOT UNKNOWN");
9929  break;
9930  default:
9931  elog(ERROR, "unrecognized booltesttype: %d",
9932  (int) btest->booltesttype);
9933  }
9934  if (!PRETTY_PAREN(context))
9935  appendStringInfoChar(buf, ')');
9936  }
9937  break;
9938 
9939  case T_CoerceToDomain:
9940  {
9941  CoerceToDomain *ctest = (CoerceToDomain *) node;
9942  Node *arg = (Node *) ctest->arg;
9943 
9944  if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
9945  !showimplicit)
9946  {
9947  /* don't show the implicit cast */
9948  get_rule_expr(arg, context, false);
9949  }
9950  else
9951  {
9953  ctest->resulttype,
9954  ctest->resulttypmod,
9955  node);
9956  }
9957  }
9958  break;
9959 
9960  case T_CoerceToDomainValue:
9961  appendStringInfoString(buf, "VALUE");
9962  break;
9963 
9964  case T_SetToDefault:
9965  appendStringInfoString(buf, "DEFAULT");
9966  break;
9967 
9968  case T_CurrentOfExpr:
9969  {
9970  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
9971 
9972  if (cexpr->cursor_name)
9973  appendStringInfo(buf, "CURRENT OF %s",
9974  quote_identifier(cexpr->cursor_name));
9975  else
9976  appendStringInfo(buf, "CURRENT OF $%d",
9977  cexpr->cursor_param);
9978  }
9979  break;
9980 
9981  case T_NextValueExpr:
9982  {
9983  NextValueExpr *nvexpr = (NextValueExpr *) node;
9984 
9985  /*
9986  * This isn't exactly nextval(), but that seems close enough
9987  * for EXPLAIN's purposes.
9988  */
9989  appendStringInfoString(buf, "nextval(");
9991  generate_relation_name(nvexpr->seqid,
9992  NIL));
9993  appendStringInfoChar(buf, ')');
9994  }
9995  break;
9996 
9997  case T_InferenceElem:
9998  {
9999  InferenceElem *iexpr = (InferenceElem *) node;
10000  bool save_varprefix;
10001  bool need_parens;
10002 
10003  /*
10004  * InferenceElem can only refer to target relation, so a
10005  * prefix is not useful, and indeed would cause parse errors.
10006  */
10007  save_varprefix = context->varprefix;
10008  context->varprefix = false;
10009 
10010  /*
10011  * Parenthesize the element unless it's a simple Var or a bare
10012  * function call. Follows pg_get_indexdef_worker().
10013  */
10014  need_parens = !IsA(iexpr->expr, Var);
10015  if (IsA(iexpr->expr, FuncExpr) &&
10016  ((FuncExpr *) iexpr->expr)->funcformat ==
10018  need_parens = false;
10019 
10020  if (need_parens)
10021  appendStringInfoChar(buf, '(');
10022  get_rule_expr((Node *) iexpr->expr,
10023  context, false);
10024  if (need_parens)
10025  appendStringInfoChar(buf, ')');
10026 
10027  context->varprefix = save_varprefix;
10028 
10029  if (iexpr->infercollid)
10030  appendStringInfo(buf, " COLLATE %s",
10032 
10033  /* Add the operator class name, if not default */
10034  if (iexpr->inferopclass)
10035  {
10036  Oid inferopclass = iexpr->inferopclass;
10037  Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
10038 
10039  get_opclass_name(inferopclass, inferopcinputtype, buf);
10040  }
10041  }
10042  break;
10043 
10044  case T_PartitionBoundSpec:
10045  {
10046  PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
10047  ListCell *cell;
10048  char *sep;
10049 
10050  if (spec->is_default)
10051  {
10052  appendStringInfoString(buf, "DEFAULT");
10053  break;
10054  }
10055 
10056  switch (spec->strategy)
10057  {
10059  Assert(spec->modulus > 0 && spec->remainder >= 0);
10060  Assert(spec->modulus > spec->remainder);
10061 
10062  appendStringInfoString(buf, "FOR VALUES");
10063  appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
10064  spec->modulus, spec->remainder);
10065  break;
10066 
10068  Assert(spec->listdatums != NIL);
10069 
10070  appendStringInfoString(buf, "FOR VALUES IN (");
10071  sep = "";
10072  foreach(cell, spec->listdatums)
10073  {
10074  Const *val = lfirst_node(Const, cell);
10075 
10077  get_const_expr(val, context, -1);
10078  sep = ", ";
10079  }
10080 
10081  appendStringInfoChar(buf, ')');
10082  break;
10083 
10085  Assert(spec->lowerdatums != NIL &&
10086  spec->upperdatums != NIL &&
10087  list_length(spec->lowerdatums) ==
10088  list_length(spec->upperdatums));
10089 
10090  appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
10093  break;
10094 
10095  default:
10096  elog(ERROR, "unrecognized partition strategy: %d",
10097  (int) spec->strategy);
10098  break;
10099  }
10100  }
10101  break;
10102 
10103  case T_JsonValueExpr:
10104  {
10105  JsonValueExpr *jve = (JsonValueExpr *) node;
10106 
10107  get_rule_expr((Node *) jve->raw_expr, context, false);
10108  get_json_format(jve->format, context->buf);
10109  }
10110  break;
10111 
10112  case T_JsonConstructorExpr:
10114  break;
10115 
10116  case T_JsonIsPredicate:
10117  {
10118  JsonIsPredicate *pred = (JsonIsPredicate *) node;
10119 
10120  if (!PRETTY_PAREN(context))
10121  appendStringInfoChar(context->buf, '(');
10122 
10123  get_rule_expr_paren(pred->expr, context, true, node);
10124 
10125  appendStringInfoString(context->buf, " IS JSON");
10126 
10127  /* TODO: handle FORMAT clause */
10128 
10129  switch (pred->item_type)
10130  {
10131  case JS_TYPE_SCALAR:
10132  appendStringInfoString(context->buf, " SCALAR");
10133  break;
10134  case JS_TYPE_ARRAY:
10135  appendStringInfoString(context->buf, " ARRAY");
10136  break;
10137  case JS_TYPE_OBJECT:
10138  appendStringInfoString(context->buf, " OBJECT");
10139  break;
10140  default:
10141  break;
10142  }
10143 
10144  if (pred->unique_keys)
10145  appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
10146 
10147  if (!PRETTY_PAREN(context))
10148  appendStringInfoChar(context->buf, ')');
10149  }
10150  break;
10151 
10152  case T_JsonExpr:
10153  {
10154  JsonExpr *jexpr = (JsonExpr *) node;
10155 
10156  switch (jexpr->op)
10157  {
10158  case JSON_EXISTS_OP:
10159  appendStringInfoString(buf, "JSON_EXISTS(");
10160  break;
10161  case JSON_QUERY_OP:
10162  appendStringInfoString(buf, "JSON_QUERY(");
10163  break;
10164  case JSON_VALUE_OP:
10165  appendStringInfoString(buf, "JSON_VALUE(");
10166  break;
10167  default:
10168  elog(ERROR, "unrecognized JsonExpr op: %d",
10169  (int) jexpr->op);
10170  }
10171 
10172  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
10173 
10174  appendStringInfoString(buf, ", ");
10175 
10176  get_json_path_spec(jexpr->path_spec, context, showimplicit);
10177 
10178  if (jexpr->passing_values)
10179  {
10180  ListCell *lc1,
10181  *lc2;
10182  bool needcomma = false;
10183 
10184  appendStringInfoString(buf, " PASSING ");
10185 
10186  forboth(lc1, jexpr->passing_names,
10187  lc2, jexpr->passing_values)
10188  {
10189  if (needcomma)
10190  appendStringInfoString(buf, ", ");
10191  needcomma = true;
10192 
10193  get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
10194  appendStringInfo(buf, " AS %s",
10195  ((String *) lfirst_node(String, lc1))->sval);
10196  }
10197  }
10198 
10199  if (jexpr->op != JSON_EXISTS_OP ||
10200  jexpr->returning->typid != BOOLOID)
10201  get_json_returning(jexpr->returning, context->buf,
10202  jexpr->op == JSON_QUERY_OP);
10203 
10205  jexpr->op != JSON_EXISTS_OP ?
10208 
10209  appendStringInfoChar(buf, ')');
10210  }
10211  break;
10212 
10213  case T_List:
10214  {
10215  char *sep;
10216  ListCell *l;
10217 
10218  sep = "";
10219  foreach(l, (List *) node)
10220  {
10222  get_rule_expr((Node *) lfirst(l), context, showimplicit);
10223  sep = ", ";
10224  }
10225  }
10226  break;
10227 
10228  case T_TableFunc:
10229  get_tablefunc((TableFunc *) node, context, showimplicit);
10230  break;
10231 
10232  default:
10233  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
10234  break;
10235  }
10236 }
10237 
10238 /*
10239  * get_rule_expr_toplevel - Parse back a toplevel expression
10240  *
10241  * Same as get_rule_expr(), except that if the expr is just a Var, we pass
10242  * istoplevel = true not false to get_variable(). This causes whole-row Vars
10243  * to get printed with decoration that will prevent expansion of "*".
10244  * We need to use this in contexts such as ROW() and VALUES(), where the
10245  * parser would expand "foo.*" appearing at top level. (In principle we'd
10246  * use this in get_target_list() too, but that has additional worries about
10247  * whether to print AS, so it needs to invoke get_variable() directly anyway.)
10248  */
10249 static void
10251  bool showimplicit)
10252 {
10253  if (node && IsA(node, Var))
10254  (void) get_variable((Var *) node, 0, true, context);
10255  else
10256  get_rule_expr(node, context, showimplicit);
10257 }
10258 
10259 /*
10260  * get_rule_list_toplevel - Parse back a list of toplevel expressions
10261  *
10262  * Apply get_rule_expr_toplevel() to each element of a List.
10263  *
10264  * This adds commas between the expressions, but caller is responsible
10265  * for printing surrounding decoration.
10266  */
10267 static void
10269  bool showimplicit)
10270 {
10271  const char *sep;
10272  ListCell *lc;
10273 
10274  sep = "";
10275  foreach(lc, lst)
10276  {
10277  Node *e = (Node *) lfirst(lc);
10278 
10279  appendStringInfoString(context->buf, sep);
10280  get_rule_expr_toplevel(e, context, showimplicit);
10281  sep = ", ";
10282  }
10283 }
10284 
10285 /*
10286  * get_rule_expr_funccall - Parse back a function-call expression
10287  *
10288  * Same as get_rule_expr(), except that we guarantee that the output will
10289  * look like a function call, or like one of the things the grammar treats as
10290  * equivalent to a function call (see the func_expr_windowless production).
10291  * This is needed in places where the grammar uses func_expr_windowless and
10292  * you can't substitute a parenthesized a_expr. If what we have isn't going
10293  * to look like a function call, wrap it in a dummy CAST() expression, which
10294  * will satisfy the grammar --- and, indeed, is likely what the user wrote to
10295  * produce such a thing.
10296  */
10297 static void
10299  bool showimplicit)
10300 {
10301  if (looks_like_function(node))
10302  get_rule_expr(node, context, showimplicit);
10303  else
10304  {
10305  StringInfo buf = context->buf;
10306 
10307  appendStringInfoString(buf, "CAST(");
10308  /* no point in showing any top-level implicit cast */
10309  get_rule_expr(node, context, false);
10310  appendStringInfo(buf, " AS %s)",
10312  exprTypmod(node)));
10313  }
10314 }
10315 
10316 /*
10317  * Helper function to identify node types that satisfy func_expr_windowless.
10318  * If in doubt, "false" is always a safe answer.
10319  */
10320 static bool
10322 {
10323  if (node == NULL)
10324  return false; /* probably shouldn't happen */
10325  switch (nodeTag(node))
10326  {
10327  case T_FuncExpr:
10328  /* OK, unless it's going to deparse as a cast */
10329  return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10330  ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10331  case T_NullIfExpr:
10332  case T_CoalesceExpr:
10333  case T_MinMaxExpr:
10334  case T_SQLValueFunction:
10335  case T_XmlExpr:
10336  case T_JsonExpr:
10337  /* these are all accepted by func_expr_common_subexpr */
10338  return true;
10339  default:
10340  break;
10341  }
10342  return false;
10343 }
10344 
10345 
10346 /*
10347  * get_oper_expr - Parse back an OpExpr node
10348  */
10349 static void
10351 {
10352  StringInfo buf = context->buf;
10353  Oid opno = expr->opno;
10354  List *args = expr->args;
10355 
10356  if (!PRETTY_PAREN(context))
10357  appendStringInfoChar(buf, '(');
10358  if (list_length(args) == 2)
10359  {
10360  /* binary operator */
10361  Node *arg1 = (Node *) linitial(args);
10362  Node *arg2 = (Node *) lsecond(args);
10363 
10364  get_rule_expr_paren(arg1, context, true, (Node *) expr);
10365  appendStringInfo(buf, " %s ",
10367  exprType(arg1),
10368  exprType(arg2)));
10369  get_rule_expr_paren(arg2, context, true, (Node *) expr);
10370  }
10371  else
10372  {
10373  /* prefix operator */
10374  Node *arg = (Node *) linitial(args);
10375 
10376  appendStringInfo(buf, "%s ",
10378  InvalidOid,
10379  exprType(arg)));
10380  get_rule_expr_paren(arg, context, true, (Node *) expr);
10381  }
10382  if (!PRETTY_PAREN(context))
10383  appendStringInfoChar(buf, ')');
10384 }
10385 
10386 /*
10387  * get_func_expr - Parse back a FuncExpr node
10388  */
10389 static void
10391  bool showimplicit)
10392 {
10393  StringInfo buf = context->buf;
10394  Oid funcoid = expr->funcid;
10395  Oid argtypes[FUNC_MAX_ARGS];
10396  int nargs;
10397  List *argnames;
10398  bool use_variadic;
10399  ListCell *l;
10400 
10401  /*
10402  * If the function call came from an implicit coercion, then just show the
10403  * first argument --- unless caller wants to see implicit coercions.
10404  */
10405  if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10406  {
10408  false, (Node *) expr);
10409  return;
10410  }
10411 
10412  /*
10413  * If the function call came from a cast, then show the first argument
10414  * plus an explicit cast operation.
10415  */
10416  if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10417  expr->funcformat == COERCE_IMPLICIT_CAST)
10418  {
10419  Node *arg = linitial(expr->args);
10420  Oid rettype = expr->funcresulttype;
10421  int32 coercedTypmod;
10422 
10423  /* Get the typmod if this is a length-coercion function */
10424  (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10425 
10427  rettype, coercedTypmod,
10428  (Node *) expr);
10429 
10430  return;
10431  }
10432 
10433  /*
10434  * If the function was called using one of the SQL spec's random special
10435  * syntaxes, try to reproduce that. If we don't recognize the function,
10436  * fall through.
10437  */
10438  if (expr->funcformat == COERCE_SQL_SYNTAX)
10439  {
10440  if (get_func_sql_syntax(expr, context))
10441  return;
10442  }
10443 
10444  /*
10445  * Normal function: display as proname(args). First we need to extract
10446  * the argument datatypes.
10447  */
10448  if (list_length(expr->args) > FUNC_MAX_ARGS)
10449  ereport(ERROR,
10450  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10451  errmsg("too many arguments")));
10452  nargs = 0;
10453  argnames = NIL;
10454  foreach(l, expr->args)
10455  {
10456  Node *arg = (Node *) lfirst(l);
10457 
10458  if (IsA(arg, NamedArgExpr))
10459  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10460  argtypes[nargs] = exprType(arg);
10461  nargs++;
10462  }
10463 
10464  appendStringInfo(buf, "%s(",
10465  generate_function_name(funcoid, nargs,
10466  argnames, argtypes,
10467  expr->funcvariadic,
10468  &use_variadic,
10469  context->special_exprkind));
10470  nargs = 0;
10471  foreach(l, expr->args)
10472  {
10473  if (nargs++ > 0)
10474  appendStringInfoString(buf, ", ");
10475  if (use_variadic && lnext(expr->args, l) == NULL)
10476  appendStringInfoString(buf, "VARIADIC ");
10477  get_rule_expr((Node *) lfirst(l), context, true);
10478  }
10479  appendStringInfoChar(buf, ')');
10480 }
10481 
10482 /*
10483  * get_agg_expr - Parse back an Aggref node
10484  */
10485 static void
10487  Aggref *original_aggref)
10488 {
10489  get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10490  false);
10491 }
10492 
10493 /*
10494  * get_agg_expr_helper - subroutine for get_agg_expr and
10495  * get_json_agg_constructor
10496  */
10497 static void
10499  Aggref *original_aggref, const char *funcname,
10500  const char *options, bool is_json_objectagg)
10501 {
10502  StringInfo buf = context->buf;
10503  Oid argtypes[FUNC_MAX_ARGS];
10504  int nargs;
10505  bool use_variadic = false;
10506 
10507  /*
10508  * For a combining aggregate, we look up and deparse the corresponding
10509  * partial aggregate instead. This is necessary because our input
10510  * argument list has been replaced; the new argument list always has just
10511  * one element, which will point to a partial Aggref that supplies us with
10512  * transition states to combine.
10513  */
10514  if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10515  {
10516  TargetEntry *tle;
10517 
10518  Assert(list_length(aggref->args) == 1);
10519  tle = linitial_node(TargetEntry, aggref->args);
10521  get_agg_combine_expr, original_aggref);
10522  return;
10523  }
10524 
10525  /*
10526  * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10527  * to avoid printing this when recursing from the code just above.
10528  */
10529  if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10530  appendStringInfoString(buf, "PARTIAL ");
10531 
10532  /* Extract the argument types as seen by the parser */
10533  nargs = get_aggregate_argtypes(aggref, argtypes);
10534 
10535  if (!funcname)
10536  funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10537  argtypes, aggref->aggvariadic,
10538  &use_variadic,
10539  context->special_exprkind);
10540 
10541  /* Print the aggregate name, schema-qualified if needed */
10542  appendStringInfo(buf, "%s(%s", funcname,
10543  (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10544 
10545  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10546  {
10547  /*
10548  * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10549  * worry about inserting VARIADIC. So we can just dump the direct
10550  * args as-is.
10551  */
10552  Assert(!aggref->aggvariadic);
10553  get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10554  Assert(aggref->aggorder != NIL);
10555  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10556  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10557  }
10558  else
10559  {
10560  /* aggstar can be set only in zero-argument aggregates */
10561  if (aggref->aggstar)
10562  appendStringInfoChar(buf, '*');
10563  else
10564  {
10565  ListCell *l;
10566  int i;
10567 
10568  i = 0;
10569  foreach(l, aggref->args)
10570  {
10571  TargetEntry *tle = (TargetEntry *) lfirst(l);
10572  Node *arg = (Node *) tle->expr;
10573 
10574  Assert(!IsA(arg, NamedArgExpr));
10575  if (tle->resjunk)
10576  continue;
10577  if (i++ > 0)
10578  {
10579  if (is_json_objectagg)
10580  {
10581  /*
10582  * the ABSENT ON NULL and WITH UNIQUE args are printed
10583  * separately, so ignore them here
10584  */
10585  if (i > 2)
10586  break;
10587 
10588  appendStringInfoString(buf, " : ");
10589  }
10590  else
10591  appendStringInfoString(buf, ", ");
10592  }
10593  if (use_variadic && i == nargs)
10594  appendStringInfoString(buf, "VARIADIC ");
10595  get_rule_expr(arg, context, true);
10596  }
10597  }
10598 
10599  if (aggref->aggorder != NIL)
10600  {
10601  appendStringInfoString(buf, " ORDER BY ");
10602  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10603  }
10604  }
10605 
10606  if (options)
10608 
10609  if (aggref->aggfilter != NULL)
10610  {
10611  appendStringInfoString(buf, ") FILTER (WHERE ");
10612  get_rule_expr((Node *) aggref->aggfilter, context, false);
10613  }
10614 
10615  appendStringInfoChar(buf, ')');
10616 }
10617 
10618 /*
10619  * This is a helper function for get_agg_expr(). It's used when we deparse
10620  * a combining Aggref; resolve_special_varno locates the corresponding partial
10621  * Aggref and then calls this.
10622  */
10623 static void
10624 get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
10625 {
10626  Aggref *aggref;
10627  Aggref *original_aggref = callback_arg;
10628 
10629  if (!IsA(node, Aggref))
10630  elog(ERROR, "combining Aggref does not point to an Aggref");
10631 
10632  aggref = (Aggref *) node;
10633  get_agg_expr(aggref, context, original_aggref);
10634 }
10635 
10636 /*
10637  * get_windowfunc_expr - Parse back a WindowFunc node
10638  */
10639 static void
10641 {
10642  get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
10643 }
10644 
10645 
10646 /*
10647  * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
10648  * get_json_agg_constructor
10649  */
10650 static void
10652  const char *funcname, const char *options,
10653  bool is_json_objectagg)
10654 {
10655  StringInfo buf = context->buf;
10656  Oid argtypes[FUNC_MAX_ARGS];
10657  int nargs;
10658  List *argnames;
10659  ListCell *l;
10660 
10661  if (list_length(wfunc->args) > FUNC_MAX_ARGS)
10662  ereport(ERROR,
10663  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10664  errmsg("too many arguments")));
10665  nargs = 0;
10666  argnames = NIL;
10667  foreach(l, wfunc->args)
10668  {
10669  Node *arg = (Node *) lfirst(l);
10670 
10671  if (IsA(arg, NamedArgExpr))
10672  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10673  argtypes[nargs] = exprType(arg);
10674  nargs++;
10675  }
10676 
10677  if (!funcname)
10678  funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
10679  argtypes, false, NULL,
10680  context->special_exprkind);
10681 
10682  appendStringInfo(buf, "%s(", funcname);
10683 
10684  /* winstar can be set only in zero-argument aggregates */
10685  if (wfunc->winstar)
10686  appendStringInfoChar(buf, '*');
10687  else
10688  {
10689  if (is_json_objectagg)
10690  {
10691  get_rule_expr((Node *) linitial(wfunc->args), context, false);
10692  appendStringInfoString(buf, " : ");
10693  get_rule_expr((Node *) lsecond(wfunc->args), context, false);
10694  }
10695  else
10696  get_rule_expr((Node *) wfunc->args, context, true);
10697  }
10698 
10699  if (options)
10701 
10702  if (wfunc->aggfilter != NULL)
10703  {
10704  appendStringInfoString(buf, ") FILTER (WHERE ");
10705  get_rule_expr((Node *) wfunc->aggfilter, context, false);
10706  }
10707 
10708  appendStringInfoString(buf, ") OVER ");
10709 
10710  foreach(l, context->windowClause)
10711  {
10712  WindowClause *wc = (WindowClause *) lfirst(l);
10713 
10714  if (wc->winref == wfunc->winref)
10715  {
10716  if (wc->name)
10718  else
10719  get_rule_windowspec(wc, context->windowTList, context);
10720  break;
10721  }
10722  }
10723  if (l == NULL)
10724  {
10725  if (context->windowClause)
10726  elog(ERROR, "could not find window clause for winref %u",
10727  wfunc->winref);
10728 
10729  /*
10730  * In EXPLAIN, we don't have window context information available, so
10731  * we have to settle for this:
10732  */
10733  appendStringInfoString(buf, "(?)");
10734  }
10735 }
10736 
10737 /*
10738  * get_func_sql_syntax - Parse back a SQL-syntax function call
10739  *
10740  * Returns true if we successfully deparsed, false if we did not
10741  * recognize the function.
10742  */
10743 static bool
10745 {
10746  StringInfo buf = context->buf;
10747  Oid funcoid = expr->funcid;
10748 
10749  switch (funcoid)
10750  {
10751  case F_TIMEZONE_INTERVAL_TIMESTAMP:
10752  case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10753  case F_TIMEZONE_INTERVAL_TIMETZ:
10754  case F_TIMEZONE_TEXT_TIMESTAMP:
10755  case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10756  case F_TIMEZONE_TEXT_TIMETZ:
10757  /* AT TIME ZONE ... note reversed argument order */
10758  appendStringInfoChar(buf, '(');
10759  get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
10760  (Node *) expr);
10761  appendStringInfoString(buf, " AT TIME ZONE ");
10762  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10763  (Node *) expr);
10764  appendStringInfoChar(buf, ')');
10765  return true;
10766 
10767  case F_TIMEZONE_TIMESTAMP:
10768  case F_TIMEZONE_TIMESTAMPTZ:
10769  case F_TIMEZONE_TIMETZ:
10770  /* AT LOCAL */
10771  appendStringInfoChar(buf, '(');
10772  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10773  (Node *) expr);
10774  appendStringInfoString(buf, " AT LOCAL)");
10775  return true;
10776 
10777  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10778  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10779  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10780  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10781  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
10782  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10783  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10784  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10785  case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10786  case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10787  case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10788  case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10789  case F_OVERLAPS_TIME_TIME_TIME_TIME:
10790  /* (x1, x2) OVERLAPS (y1, y2) */
10791  appendStringInfoString(buf, "((");
10792  get_rule_expr((Node *) linitial(expr->args), context, false);
10793  appendStringInfoString(buf, ", ");
10794  get_rule_expr((Node *) lsecond(expr->args), context, false);
10795  appendStringInfoString(buf, ") OVERLAPS (");
10796  get_rule_expr((Node *) lthird(expr->args), context, false);
10797  appendStringInfoString(buf, ", ");
10798  get_rule_expr((Node *) lfourth(expr->args), context, false);
10799  appendStringInfoString(buf, "))");
10800  return true;
10801 
10802  case F_EXTRACT_TEXT_DATE:
10803  case F_EXTRACT_TEXT_TIME:
10804  case F_EXTRACT_TEXT_TIMETZ:
10805  case F_EXTRACT_TEXT_TIMESTAMP:
10806  case F_EXTRACT_TEXT_TIMESTAMPTZ:
10807  case F_EXTRACT_TEXT_INTERVAL:
10808  /* EXTRACT (x FROM y) */
10809  appendStringInfoString(buf, "EXTRACT(");
10810  {
10811  Const *con = (Const *) linitial(expr->args);
10812 
10813  Assert(IsA(con, Const) &&
10814  con->consttype == TEXTOID &&
10815  !con->constisnull);
10816  appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
10817  }
10818  appendStringInfoString(buf, " FROM ");
10819  get_rule_expr((Node *) lsecond(expr->args), context, false);
10820  appendStringInfoChar(buf, ')');
10821  return true;
10822 
10823  case F_IS_NORMALIZED:
10824  /* IS xxx NORMALIZED */
10825  appendStringInfoChar(buf, '(');
10826  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10827  (Node *) expr);
10828  appendStringInfoString(buf, " IS");
10829  if (list_length(expr->args) == 2)
10830  {
10831  Const *con = (Const *) lsecond(expr->args);
10832 
10833  Assert(IsA(con, Const) &&
10834  con->consttype == TEXTOID &&
10835  !con->constisnull);
10836  appendStringInfo(buf, " %s",
10837  TextDatumGetCString(con->constvalue));
10838  }
10839  appendStringInfoString(buf, " NORMALIZED)");
10840  return true;
10841 
10842  case F_PG_COLLATION_FOR:
10843  /* COLLATION FOR */
10844  appendStringInfoString(buf, "COLLATION FOR (");
10845  get_rule_expr((Node *) linitial(expr->args), context, false);
10846  appendStringInfoChar(buf, ')');
10847  return true;
10848 
10849  case F_NORMALIZE:
10850  /* NORMALIZE() */
10851  appendStringInfoString(buf, "NORMALIZE(");
10852  get_rule_expr((Node *) linitial(expr->args), context, false);
10853  if (list_length(expr->args) == 2)
10854  {
10855  Const *con = (Const *) lsecond(expr->args);
10856 
10857  Assert(IsA(con, Const) &&
10858  con->consttype == TEXTOID &&
10859  !con->constisnull);
10860  appendStringInfo(buf, ", %s",
10861  TextDatumGetCString(con->constvalue));
10862  }
10863  appendStringInfoChar(buf, ')');
10864  return true;
10865 
10866  case F_OVERLAY_BIT_BIT_INT4:
10867  case F_OVERLAY_BIT_BIT_INT4_INT4:
10868  case F_OVERLAY_BYTEA_BYTEA_INT4:
10869  case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10870  case F_OVERLAY_TEXT_TEXT_INT4:
10871  case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10872  /* OVERLAY() */
10873  appendStringInfoString(buf, "OVERLAY(");
10874  get_rule_expr((Node *) linitial(expr->args), context, false);
10875  appendStringInfoString(buf, " PLACING ");
10876  get_rule_expr((Node *) lsecond(expr->args), context, false);
10877  appendStringInfoString(buf, " FROM ");
10878  get_rule_expr((Node *) lthird(expr->args), context, false);
10879  if (list_length(expr->args) == 4)
10880  {
10881  appendStringInfoString(buf, " FOR ");
10882  get_rule_expr((Node *) lfourth(expr->args), context, false);
10883  }
10884  appendStringInfoChar(buf, ')');
10885  return true;
10886 
10887  case F_POSITION_BIT_BIT:
10888  case F_POSITION_BYTEA_BYTEA:
10889  case F_POSITION_TEXT_TEXT:
10890  /* POSITION() ... extra parens since args are b_expr not a_expr */
10891  appendStringInfoString(buf, "POSITION((");
10892  get_rule_expr((Node *) lsecond(expr->args), context, false);
10893  appendStringInfoString(buf, ") IN (");
10894  get_rule_expr((Node *) linitial(expr->args), context, false);
10895  appendStringInfoString(buf, "))");
10896  return true;
10897 
10898  case F_SUBSTRING_BIT_INT4:
10899  case F_SUBSTRING_BIT_INT4_INT4:
10900  case F_SUBSTRING_BYTEA_INT4:
10901  case F_SUBSTRING_BYTEA_INT4_INT4:
10902  case F_SUBSTRING_TEXT_INT4:
10903  case F_SUBSTRING_TEXT_INT4_INT4:
10904  /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10905  appendStringInfoString(buf, "SUBSTRING(");
10906  get_rule_expr((Node *) linitial(expr->args), context, false);
10907  appendStringInfoString(buf, " FROM ");
10908  get_rule_expr((Node *) lsecond(expr->args), context, false);
10909  if (list_length(expr->args) == 3)
10910  {
10911  appendStringInfoString(buf, " FOR ");
10912  get_rule_expr((Node *) lthird(expr->args), context, false);
10913  }
10914  appendStringInfoChar(buf, ')');
10915  return true;
10916 
10917  case F_SUBSTRING_TEXT_TEXT_TEXT:
10918  /* SUBSTRING SIMILAR/ESCAPE */
10919  appendStringInfoString(buf, "SUBSTRING(");
10920  get_rule_expr((Node *) linitial(expr->args), context, false);
10921  appendStringInfoString(buf, " SIMILAR ");
10922  get_rule_expr((Node *) lsecond(expr->args), context, false);
10923  appendStringInfoString(buf, " ESCAPE ");
10924  get_rule_expr((Node *) lthird(expr->args), context, false);
10925  appendStringInfoChar(buf, ')');
10926  return true;
10927 
10928  case F_BTRIM_BYTEA_BYTEA:
10929  case F_BTRIM_TEXT:
10930  case F_BTRIM_TEXT_TEXT:
10931  /* TRIM() */
10932  appendStringInfoString(buf, "TRIM(BOTH");
10933  if (list_length(expr->args) == 2)
10934  {
10935  appendStringInfoChar(buf, ' ');
10936  get_rule_expr((Node *) lsecond(expr->args), context, false);
10937  }
10938  appendStringInfoString(buf, " FROM ");
10939  get_rule_expr((Node *) linitial(expr->args), context, false);
10940  appendStringInfoChar(buf, ')');
10941  return true;
10942 
10943  case F_LTRIM_BYTEA_BYTEA:
10944  case F_LTRIM_TEXT:
10945  case F_LTRIM_TEXT_TEXT:
10946  /* TRIM() */
10947  appendStringInfoString(buf, "TRIM(LEADING");
10948  if (list_length(expr->args) == 2)
10949  {
10950  appendStringInfoChar(buf, ' ');
10951  get_rule_expr((Node *) lsecond(expr->args), context, false);
10952  }
10953  appendStringInfoString(buf, " FROM ");
10954  get_rule_expr((Node *) linitial(expr->args), context, false);
10955  appendStringInfoChar(buf, ')');
10956  return true;
10957 
10958  case F_RTRIM_BYTEA_BYTEA:
10959  case F_RTRIM_TEXT:
10960  case F_RTRIM_TEXT_TEXT:
10961  /* TRIM() */
10962  appendStringInfoString(buf, "TRIM(TRAILING");
10963  if (list_length(expr->args) == 2)
10964  {
10965  appendStringInfoChar(buf, ' ');
10966  get_rule_expr((Node *) lsecond(expr->args), context, false);
10967  }
10968  appendStringInfoString(buf, " FROM ");
10969  get_rule_expr((Node *) linitial(expr->args), context, false);
10970  appendStringInfoChar(buf, ')');
10971  return true;
10972 
10973  case F_SYSTEM_USER:
10974  appendStringInfoString(buf, "SYSTEM_USER");
10975  return true;
10976 
10977  case F_XMLEXISTS:
10978  /* XMLEXISTS ... extra parens because args are c_expr */
10979  appendStringInfoString(buf, "XMLEXISTS((");
10980  get_rule_expr((Node *) linitial(expr->args), context, false);
10981  appendStringInfoString(buf, ") PASSING (");
10982  get_rule_expr((Node *) lsecond(expr->args), context, false);
10983  appendStringInfoString(buf, "))");
10984  return true;
10985  }
10986  return false;
10987 }
10988 
10989 /* ----------
10990  * get_coercion_expr
10991  *
10992  * Make a string representation of a value coerced to a specific type
10993  * ----------
10994  */
10995 static void
10997  Oid resulttype, int32 resulttypmod,
10998  Node *parentNode)
10999 {
11000  StringInfo buf = context->buf;
11001 
11002  /*
11003  * Since parse_coerce.c doesn't immediately collapse application of
11004  * length-coercion functions to constants, what we'll typically see in
11005  * such cases is a Const with typmod -1 and a length-coercion function
11006  * right above it. Avoid generating redundant output. However, beware of
11007  * suppressing casts when the user actually wrote something like
11008  * 'foo'::text::char(3).
11009  *
11010  * Note: it might seem that we are missing the possibility of needing to
11011  * print a COLLATE clause for such a Const. However, a Const could only
11012  * have nondefault collation in a post-constant-folding tree, in which the
11013  * length coercion would have been folded too. See also the special
11014  * handling of CollateExpr in coerce_to_target_type(): any collation
11015  * marking will be above the coercion node, not below it.
11016  */
11017  if (arg && IsA(arg, Const) &&
11018  ((Const *) arg)->consttype == resulttype &&
11019  ((Const *) arg)->consttypmod == -1)
11020  {
11021  /* Show the constant without normal ::typename decoration */
11022  get_const_expr((Const *) arg, context, -1);
11023  }
11024  else
11025  {
11026  if (!PRETTY_PAREN(context))
11027  appendStringInfoChar(buf, '(');
11028  get_rule_expr_paren(arg, context, false, parentNode);
11029  if (!PRETTY_PAREN(context))
11030  appendStringInfoChar(buf, ')');
11031  }
11032 
11033  /*
11034  * Never emit resulttype(arg) functional notation. A pg_proc entry could
11035  * take precedence, and a resulttype in pg_temp would require schema
11036  * qualification that format_type_with_typemod() would usually omit. We've
11037  * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11038  * would work fine.
11039  */
11040  appendStringInfo(buf, "::%s",
11041  format_type_with_typemod(resulttype, resulttypmod));
11042 }
11043 
11044 /* ----------
11045  * get_const_expr
11046  *
11047  * Make a string representation of a Const
11048  *
11049  * showtype can be -1 to never show "::typename" decoration, or +1 to always
11050  * show it, or 0 to show it only if the constant wouldn't be assumed to be
11051  * the right type by default.
11052  *
11053  * If the Const's collation isn't default for its type, show that too.
11054  * We mustn't do this when showtype is -1 (since that means the caller will
11055  * print "::typename", and we can't put a COLLATE clause in between). It's
11056  * caller's responsibility that collation isn't missed in such cases.
11057  * ----------
11058  */
11059 static void
11060 get_const_expr(Const *constval, deparse_context *context, int showtype)
11061 {
11062  StringInfo buf = context->buf;
11063  Oid typoutput;
11064  bool typIsVarlena;
11065  char *extval;
11066  bool needlabel = false;
11067 
11068  if (constval->constisnull)
11069  {
11070  /*
11071  * Always label the type of a NULL constant to prevent misdecisions
11072  * about type when reparsing.
11073  */
11074  appendStringInfoString(buf, "NULL");
11075  if (showtype >= 0)
11076  {
11077  appendStringInfo(buf, "::%s",
11079  constval->consttypmod));
11080  get_const_collation(constval, context);
11081  }
11082  return;
11083  }
11084 
11085  getTypeOutputInfo(constval->consttype,
11086  &typoutput, &typIsVarlena);
11087 
11088  extval = OidOutputFunctionCall(typoutput, constval->constvalue);
11089 
11090  switch (constval->consttype)
11091  {
11092  case INT4OID:
11093 
11094  /*
11095  * INT4 can be printed without any decoration, unless it is
11096  * negative; in that case print it as '-nnn'::integer to ensure
11097  * that the output will re-parse as a constant, not as a constant
11098  * plus operator. In most cases we could get away with printing
11099  * (-nnn) instead, because of the way that gram.y handles negative
11100  * literals; but that doesn't work for INT_MIN, and it doesn't
11101  * seem that much prettier anyway.
11102  */
11103  if (extval[0] != '-')
11104  appendStringInfoString(buf, extval);
11105  else
11106  {
11107  appendStringInfo(buf, "'%s'", extval);
11108  needlabel = true; /* we must attach a cast */
11109  }
11110  break;
11111 
11112  case NUMERICOID:
11113 
11114  /*
11115  * NUMERIC can be printed without quotes if it looks like a float
11116  * constant (not an integer, and not Infinity or NaN) and doesn't
11117  * have a leading sign (for the same reason as for INT4).
11118  */
11119  if (isdigit((unsigned char) extval[0]) &&
11120  strcspn(extval, "eE.") != strlen(extval))
11121  {
11122  appendStringInfoString(buf, extval);
11123  }
11124  else
11125  {
11126  appendStringInfo(buf, "'%s'", extval);
11127  needlabel = true; /* we must attach a cast */
11128  }
11129  break;
11130 
11131  case BOOLOID:
11132  if (strcmp(extval, "t") == 0)
11133  appendStringInfoString(buf, "true");
11134  else
11135  appendStringInfoString(buf, "false");
11136  break;
11137 
11138  default:
11139  simple_quote_literal(buf, extval);
11140  break;
11141  }
11142 
11143  pfree(extval);
11144 
11145  if (showtype < 0)
11146  return;
11147 
11148  /*
11149  * For showtype == 0, append ::typename unless the constant will be
11150  * implicitly typed as the right type when it is read in.
11151  *
11152  * XXX this code has to be kept in sync with the behavior of the parser,
11153  * especially make_const.
11154  */
11155  switch (constval->consttype)
11156  {
11157  case BOOLOID:
11158  case UNKNOWNOID:
11159  /* These types can be left unlabeled */
11160  needlabel = false;
11161  break;
11162  case INT4OID:
11163  /* We determined above whether a label is needed */
11164  break;
11165  case NUMERICOID:
11166 
11167  /*
11168  * Float-looking constants will be typed as numeric, which we
11169  * checked above; but if there's a nondefault typmod we need to
11170  * show it.
11171  */
11172  needlabel |= (constval->consttypmod >= 0);
11173  break;
11174  default:
11175  needlabel = true;
11176  break;
11177  }
11178  if (needlabel || showtype > 0)
11179  appendStringInfo(buf, "::%s",
11181  constval->consttypmod));
11182 
11183  get_const_collation(constval, context);
11184 }
11185 
11186 /*
11187  * helper for get_const_expr: append COLLATE if needed
11188  */
11189 static void
11191 {
11192  StringInfo buf = context->buf;
11193 
11194  if (OidIsValid(constval->constcollid))
11195  {
11196  Oid typcollation = get_typcollation(constval->consttype);
11197 
11198  if (constval->constcollid != typcollation)
11199  {
11200  appendStringInfo(buf, " COLLATE %s",
11201  generate_collation_name(constval->constcollid));
11202  }
11203  }
11204 }
11205 
11206 /*
11207  * get_json_path_spec - Parse back a JSON path specification
11208  */
11209 static void
11210 get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
11211 {
11212  if (IsA(path_spec, Const))
11213  get_const_expr((Const *) path_spec, context, -1);
11214  else
11215  get_rule_expr(path_spec, context, showimplicit);
11216 }
11217 
11218 /*
11219  * get_json_format - Parse back a JsonFormat node
11220  */
11221 static void
11223 {
11224  if (format->format_type == JS_FORMAT_DEFAULT)
11225  return;
11226 
11228  format->format_type == JS_FORMAT_JSONB ?
11229  " FORMAT JSONB" : " FORMAT JSON");
11230 
11231  if (format->encoding != JS_ENC_DEFAULT)
11232  {
11233  const char *encoding;
11234 
11235  encoding =
11236  format->encoding == JS_ENC_UTF16 ? "UTF16" :
11237  format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11238 
11239  appendStringInfo(buf, " ENCODING %s", encoding);
11240  }
11241 }
11242 
11243 /*
11244  * get_json_returning - Parse back a JsonReturning structure
11245  */
11246 static void
11248  bool json_format_by_default)
11249 {
11250  if (!OidIsValid(returning->typid))
11251  return;
11252 
11253  appendStringInfo(buf, " RETURNING %s",
11254  format_type_with_typemod(returning->typid,
11255  returning->typmod));
11256 
11257  if (!json_format_by_default ||
11258  returning->format->format_type !=
11259  (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11260  get_json_format(returning->format, buf);
11261 }
11262 
11263 /*
11264  * get_json_constructor - Parse back a JsonConstructorExpr node
11265  */
11266 static void
11268  bool showimplicit)
11269 {
11270  StringInfo buf = context->buf;
11271  const char *funcname;
11272  bool is_json_object;
11273  int curridx;
11274  ListCell *lc;
11275 
11276  if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11277  {
11278  get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11279  return;
11280  }
11281  else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11282  {
11283  get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11284  return;
11285  }
11286 
11287  switch (ctor->type)
11288  {
11289  case JSCTOR_JSON_OBJECT:
11290  funcname = "JSON_OBJECT";
11291  break;
11292  case JSCTOR_JSON_ARRAY:
11293  funcname = "JSON_ARRAY";
11294  break;
11295  case JSCTOR_JSON_PARSE:
11296  funcname = "JSON";
11297  break;
11298  case JSCTOR_JSON_SCALAR:
11299  funcname = "JSON_SCALAR";
11300  break;
11301  case JSCTOR_JSON_SERIALIZE:
11302  funcname = "JSON_SERIALIZE";
11303  break;
11304  default:
11305  elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11306  }
11307 
11308  appendStringInfo(buf, "%s(", funcname);
11309 
11310  is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11311  foreach(lc, ctor->args)
11312  {
11313  curridx = foreach_current_index(lc);
11314  if (curridx > 0)
11315  {
11316  const char *sep;
11317 
11318  sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11320  }
11321 
11322  get_rule_expr((Node *) lfirst(lc), context, true);
11323  }
11324 
11326  appendStringInfoChar(buf, ')');
11327 }
11328 
11329 /*
11330  * Append options, if any, to the JSON constructor being deparsed
11331  */
11332 static void
11334 {
11335  if (ctor->absent_on_null)
11336  {
11337  if (ctor->type == JSCTOR_JSON_OBJECT ||
11338  ctor->type == JSCTOR_JSON_OBJECTAGG)
11339  appendStringInfoString(buf, " ABSENT ON NULL");
11340  }
11341  else
11342  {
11343  if (ctor->type == JSCTOR_JSON_ARRAY ||
11344  ctor->type == JSCTOR_JSON_ARRAYAGG)
11345  appendStringInfoString(buf, " NULL ON NULL");
11346  }
11347 
11348  if (ctor->unique)
11349  appendStringInfoString(buf, " WITH UNIQUE KEYS");
11350 
11351  /*
11352  * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11353  * support one.
11354  */
11355  if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11356  get_json_returning(ctor->returning, buf, true);
11357 }
11358 
11359 /*
11360  * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
11361  */
11362 static void
11364  const char *funcname, bool is_json_objectagg)
11365 {
11367 
11370 
11371  if (IsA(ctor->func, Aggref))
11373  (Aggref *) ctor->func,
11374  funcname, options.data, is_json_objectagg);
11375  else if (IsA(ctor->func, WindowFunc))
11377  funcname, options.data,
11378  is_json_objectagg);
11379  else
11380  elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11381  nodeTag(ctor->func));
11382 }
11383 
11384 /*
11385  * simple_quote_literal - Format a string as a SQL literal, append to buf
11386  */
11387 static void
11389 {
11390  const char *valptr;
11391 
11392  /*
11393  * We form the string literal according to the prevailing setting of
11394  * standard_conforming_strings; we never use E''. User is responsible for
11395  * making sure result is used correctly.
11396  */
11397  appendStringInfoChar(buf, '\'');
11398  for (valptr = val; *valptr; valptr++)
11399  {
11400  char ch = *valptr;
11401 
11405  }
11406  appendStringInfoChar(buf, '\'');
11407 }
11408 
11409 
11410 /* ----------
11411  * get_sublink_expr - Parse back a sublink
11412  * ----------
11413  */
11414 static void
11416 {
11417  StringInfo buf = context->buf;
11418  Query *query = (Query *) (sublink->subselect);
11419  char *opname = NULL;
11420  bool need_paren;
11421 
11422  if (sublink->subLinkType == ARRAY_SUBLINK)
11423  appendStringInfoString(buf, "ARRAY(");
11424  else
11425  appendStringInfoChar(buf, '(');
11426 
11427  /*
11428  * Note that we print the name of only the first operator, when there are
11429  * multiple combining operators. This is an approximation that could go
11430  * wrong in various scenarios (operators in different schemas, renamed
11431  * operators, etc) but there is not a whole lot we can do about it, since
11432  * the syntax allows only one operator to be shown.
11433  */
11434  if (sublink->testexpr)
11435  {
11436  if (IsA(sublink->testexpr, OpExpr))
11437  {
11438  /* single combining operator */
11439  OpExpr *opexpr = (OpExpr *) sublink->testexpr;
11440 
11441  get_rule_expr(linitial(opexpr->args), context, true);
11442  opname = generate_operator_name(opexpr->opno,
11443  exprType(linitial(opexpr->args)),
11444  exprType(lsecond(opexpr->args)));
11445  }
11446  else if (IsA(sublink->testexpr, BoolExpr))
11447  {
11448  /* multiple combining operators, = or <> cases */
11449  char *sep;
11450  ListCell *l;
11451 
11452  appendStringInfoChar(buf, '(');
11453  sep = "";
11454  foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11455  {
11456  OpExpr *opexpr = lfirst_node(OpExpr, l);
11457 
11459  get_rule_expr(linitial(opexpr->args), context, true);
11460  if (!opname)
11461  opname = generate_operator_name(opexpr->opno,
11462  exprType(linitial(opexpr->args)),
11463  exprType(lsecond(opexpr->args)));
11464  sep = ", ";
11465  }
11466  appendStringInfoChar(buf, ')');
11467  }
11468  else if (IsA(sublink->testexpr, RowCompareExpr))
11469  {
11470  /* multiple combining operators, < <= > >= cases */
11471  RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11472 
11473  appendStringInfoChar(buf, '(');
11474  get_rule_expr((Node *) rcexpr->largs, context, true);
11475  opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11476  exprType(linitial(rcexpr->largs)),
11477  exprType(linitial(rcexpr->rargs)));
11478  appendStringInfoChar(buf, ')');
11479  }
11480  else
11481  elog(ERROR, "unrecognized testexpr type: %d",
11482  (int) nodeTag(sublink->testexpr));
11483  }
11484 
11485  need_paren = true;
11486 
11487  switch (sublink->subLinkType)
11488  {
11489  case EXISTS_SUBLINK:
11490  appendStringInfoString(buf, "EXISTS ");
11491  break;
11492 
11493  case ANY_SUBLINK:
11494  if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11495  appendStringInfoString(buf, " IN ");
11496  else
11497  appendStringInfo(buf, " %s ANY ", opname);
11498  break;
11499 
11500  case ALL_SUBLINK:
11501  appendStringInfo(buf, " %s ALL ", opname);
11502  break;
11503 
11504  case ROWCOMPARE_SUBLINK:
11505  appendStringInfo(buf, " %s ", opname);
11506  break;
11507 
11508  case EXPR_SUBLINK:
11509  case MULTIEXPR_SUBLINK:
11510  case ARRAY_SUBLINK:
11511  need_paren = false;
11512  break;
11513 
11514  case CTE_SUBLINK: /* shouldn't occur in a SubLink */
11515  default:
11516  elog(ERROR, "unrecognized sublink type: %d",
11517  (int) sublink->subLinkType);
11518  break;
11519  }
11520 
11521  if (need_paren)
11522  appendStringInfoChar(buf, '(');
11523 
11524  get_query_def(query, buf, context->namespaces, NULL, false,
11525  context->prettyFlags, context->wrapColumn,
11526  context->indentLevel);
11527 
11528  if (need_paren)
11529  appendStringInfoString(buf, "))");
11530  else
11531  appendStringInfoChar(buf, ')');
11532 }
11533 
11534 
11535 /* ----------
11536  * get_xmltable - Parse back a XMLTABLE function
11537  * ----------
11538  */
11539 static void
11541 {
11542  StringInfo buf = context->buf;
11543 
11544  appendStringInfoString(buf, "XMLTABLE(");
11545 
11546  if (tf->ns_uris != NIL)
11547  {
11548  ListCell *lc1,
11549  *lc2;
11550  bool first = true;
11551 
11552  appendStringInfoString(buf, "XMLNAMESPACES (");
11553  forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
11554  {
11555  Node *expr = (Node *) lfirst(lc1);
11556  String *ns_node = lfirst_node(String, lc2);
11557 
11558  if (!first)
11559  appendStringInfoString(buf, ", ");
11560  else
11561  first = false;
11562 
11563  if (ns_node != NULL)
11564  {
11565  get_rule_expr(expr, context, showimplicit);
11566  appendStringInfo(buf, " AS %s", strVal(ns_node));
11567  }
11568  else
11569  {
11570  appendStringInfoString(buf, "DEFAULT ");
11571  get_rule_expr(expr, context, showimplicit);
11572  }
11573  }
11574  appendStringInfoString(buf, "), ");
11575  }
11576 
11577  appendStringInfoChar(buf, '(');
11578  get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
11579  appendStringInfoString(buf, ") PASSING (");
11580  get_rule_expr((Node *) tf->docexpr, context, showimplicit);
11581  appendStringInfoChar(buf, ')');
11582 
11583  if (tf->colexprs != NIL)
11584  {
11585  ListCell *l1;
11586  ListCell *l2;
11587  ListCell *l3;
11588  ListCell *l4;
11589  ListCell *l5;
11590  int colnum = 0;
11591 
11592  appendStringInfoString(buf, " COLUMNS ");
11593  forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
11594  l4, tf->colexprs, l5, tf->coldefexprs)
11595  {
11596  char *colname = strVal(lfirst(l1));
11597  Oid typid = lfirst_oid(l2);
11598  int32 typmod = lfirst_int(l3);
11599  Node *colexpr = (Node *) lfirst(l4);
11600  Node *coldefexpr = (Node *) lfirst(l5);
11601  bool ordinality = (tf->ordinalitycol == colnum);
11602  bool notnull = bms_is_member(colnum, tf->notnulls);
11603 
11604  if (colnum > 0)
11605  appendStringInfoString(buf, ", ");
11606  colnum++;
11607 
11608  appendStringInfo(buf, "%s %s", quote_identifier(colname),
11609  ordinality ? "FOR ORDINALITY" :
11610  format_type_with_typemod(typid, typmod));
11611  if (ordinality)
11612  continue;
11613 
11614  if (coldefexpr != NULL)
11615  {
11616  appendStringInfoString(buf, " DEFAULT (");
11617  get_rule_expr((Node *) coldefexpr, context, showimplicit);
11618  appendStringInfoChar(buf, ')');
11619  }
11620  if (colexpr != NULL)
11621  {
11622  appendStringInfoString(buf, " PATH (");
11623  get_rule_expr((Node *) colexpr, context, showimplicit);
11624  appendStringInfoChar(buf, ')');
11625  }
11626  if (notnull)
11627  appendStringInfoString(buf, " NOT NULL");
11628  }
11629  }
11630 
11631  appendStringInfoChar(buf, ')');
11632 }
11633 
11634 /*
11635  * get_json_nested_columns - Parse back nested JSON_TABLE columns
11636  */
11637 static void
11639  deparse_context *context, bool showimplicit,
11640  bool needcomma)
11641 {
11642  if (IsA(plan, JsonTablePathScan))
11643  {
11645 
11646  if (needcomma)
11647  appendStringInfoChar(context->buf, ',');
11648 
11649  appendStringInfoChar(context->buf, ' ');
11650  appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
11651  get_const_expr(scan->path->value, context, -1);
11652  appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
11653  get_json_table_columns(tf, scan, context, showimplicit);
11654  }
11655  else if (IsA(plan, JsonTableSiblingJoin))
11656  {
11658 
11659  get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
11660  needcomma);
11661  get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
11662  true);
11663  }
11664 }
11665 
11666 /*
11667  * get_json_table_columns - Parse back JSON_TABLE columns
11668  */
11669 static void
11672  bool showimplicit)
11673 {
11674  StringInfo buf = context->buf;
11675  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11676  ListCell *lc_colname;
11677  ListCell *lc_coltype;
11678  ListCell *lc_coltypmod;
11679  ListCell *lc_colvalexpr;
11680  int colnum = 0;
11681 
11682  appendStringInfoChar(buf, ' ');
11683  appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
11684 
11685  if (PRETTY_INDENT(context))
11686  context->indentLevel += PRETTYINDENT_VAR;
11687 
11688  forfour(lc_colname, tf->colnames,
11689  lc_coltype, tf->coltypes,
11690  lc_coltypmod, tf->coltypmods,
11691  lc_colvalexpr, tf->colvalexprs)
11692  {
11693  char *colname = strVal(lfirst(lc_colname));
11694  JsonExpr *colexpr;
11695  Oid typid;
11696  int32 typmod;
11697  bool ordinality;
11698  JsonBehaviorType default_behavior;
11699 
11700  typid = lfirst_oid(lc_coltype);
11701  typmod = lfirst_int(lc_coltypmod);
11702  colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
11703 
11704  /* Skip columns that don't belong to this scan. */
11705  if (scan->colMin < 0 || colnum < scan->colMin)
11706  {
11707  colnum++;
11708  continue;
11709  }
11710  if (colnum > scan->colMax)
11711  break;
11712 
11713  if (colnum > scan->colMin)
11714  appendStringInfoString(buf, ", ");
11715 
11716  colnum++;
11717 
11718  ordinality = !colexpr;
11719 
11720  appendContextKeyword(context, "", 0, 0, 0);
11721 
11722  appendStringInfo(buf, "%s %s", quote_identifier(colname),
11723  ordinality ? "FOR ORDINALITY" :
11724  format_type_with_typemod(typid, typmod));
11725  if (ordinality)
11726  continue;
11727 
11728  if (colexpr->op == JSON_EXISTS_OP)
11729  {
11730  appendStringInfoString(buf, " EXISTS");
11731  default_behavior = JSON_BEHAVIOR_FALSE;
11732  }
11733  else
11734  {
11735  if (colexpr->op == JSON_QUERY_OP)
11736  {
11737  char typcategory;
11738  bool typispreferred;
11739 
11740  get_type_category_preferred(typid, &typcategory, &typispreferred);
11741 
11742  if (typcategory == TYPCATEGORY_STRING)
11744  colexpr->format->format_type == JS_FORMAT_JSONB ?
11745  " FORMAT JSONB" : " FORMAT JSON");
11746  }
11747 
11748  default_behavior = JSON_BEHAVIOR_NULL;
11749  }
11750 
11751  if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
11752  default_behavior = JSON_BEHAVIOR_ERROR;
11753 
11754  appendStringInfoString(buf, " PATH ");
11755 
11756  get_json_path_spec(colexpr->path_spec, context, showimplicit);
11757 
11758  get_json_expr_options(colexpr, context, default_behavior);
11759  }
11760 
11761  if (scan->child)
11762  get_json_table_nested_columns(tf, scan->child, context, showimplicit,
11763  scan->colMin >= 0);
11764 
11765  if (PRETTY_INDENT(context))
11766  context->indentLevel -= PRETTYINDENT_VAR;
11767 
11768  appendContextKeyword(context, ")", 0, 0, 0);
11769 }
11770 
11771 /* ----------
11772  * get_json_table - Parse back a JSON_TABLE function
11773  * ----------
11774  */
11775 static void
11777 {
11778  StringInfo buf = context->buf;
11779  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11781 
11782  appendStringInfoString(buf, "JSON_TABLE(");
11783 
11784  if (PRETTY_INDENT(context))
11785  context->indentLevel += PRETTYINDENT_VAR;
11786 
11787  appendContextKeyword(context, "", 0, 0, 0);
11788 
11789  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
11790 
11791  appendStringInfoString(buf, ", ");
11792 
11793  get_const_expr(root->path->value, context, -1);
11794 
11795  appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
11796 
11797  if (jexpr->passing_values)
11798  {
11799  ListCell *lc1,
11800  *lc2;
11801  bool needcomma = false;
11802 
11803  appendStringInfoChar(buf, ' ');
11804  appendContextKeyword(context, "PASSING ", 0, 0, 0);
11805 
11806  if (PRETTY_INDENT(context))
11807  context->indentLevel += PRETTYINDENT_VAR;
11808 
11809  forboth(lc1, jexpr->passing_names,
11810  lc2, jexpr->passing_values)
11811  {
11812  if (needcomma)
11813  appendStringInfoString(buf, ", ");
11814  needcomma = true;
11815 
11816  appendContextKeyword(context, "", 0, 0, 0);
11817 
11818  get_rule_expr((Node *) lfirst(lc2), context, false);
11819  appendStringInfo(buf, " AS %s",
11820  quote_identifier((lfirst_node(String, lc1))->sval)
11821  );
11822  }
11823 
11824  if (PRETTY_INDENT(context))
11825  context->indentLevel -= PRETTYINDENT_VAR;
11826  }
11827 
11829  showimplicit);
11830 
11831  if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY)
11832  get_json_behavior(jexpr->on_error, context, "ERROR");
11833 
11834  if (PRETTY_INDENT(context))
11835  context->indentLevel -= PRETTYINDENT_VAR;
11836 
11837  appendContextKeyword(context, ")", 0, 0, 0);
11838 }
11839 
11840 /* ----------
11841  * get_tablefunc - Parse back a table function
11842  * ----------
11843  */
11844 static void
11846 {
11847  /* XMLTABLE and JSON_TABLE are the only existing implementations. */
11848 
11849  if (tf->functype == TFT_XMLTABLE)
11850  get_xmltable(tf, context, showimplicit);
11851  else if (tf->functype == TFT_JSON_TABLE)
11852  get_json_table(tf, context, showimplicit);
11853 }
11854 
11855 /* ----------
11856  * get_from_clause - Parse back a FROM clause
11857  *
11858  * "prefix" is the keyword that denotes the start of the list of FROM
11859  * elements. It is FROM when used to parse back SELECT and UPDATE, but
11860  * is USING when parsing back DELETE.
11861  * ----------
11862  */
11863 static void
11864 get_from_clause(Query *query, const char *prefix, deparse_context *context)
11865 {
11866  StringInfo buf = context->buf;
11867  bool first = true;
11868  ListCell *l;
11869 
11870  /*
11871  * We use the query's jointree as a guide to what to print. However, we
11872  * must ignore auto-added RTEs that are marked not inFromCl. (These can
11873  * only appear at the top level of the jointree, so it's sufficient to
11874  * check here.) This check also ensures we ignore the rule pseudo-RTEs
11875  * for NEW and OLD.
11876  */
11877  foreach(l, query->jointree->fromlist)
11878  {
11879  Node *jtnode = (Node *) lfirst(l);
11880 
11881  if (IsA(jtnode, RangeTblRef))
11882  {
11883  int varno = ((RangeTblRef *) jtnode)->rtindex;
11884  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11885 
11886  if (!rte->inFromCl)
11887  continue;
11888  }
11889 
11890  if (first)
11891  {
11892  appendContextKeyword(context, prefix,
11894  first = false;
11895 
11896  get_from_clause_item(jtnode, query, context);
11897  }
11898  else
11899  {
11900  StringInfoData itembuf;
11901 
11902  appendStringInfoString(buf, ", ");
11903 
11904  /*
11905  * Put the new FROM item's text into itembuf so we can decide
11906  * after we've got it whether or not it needs to go on a new line.
11907  */
11908  initStringInfo(&itembuf);
11909  context->buf = &itembuf;
11910 
11911  get_from_clause_item(jtnode, query, context);
11912 
11913  /* Restore context's output buffer */
11914  context->buf = buf;
11915 
11916  /* Consider line-wrapping if enabled */
11917  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
11918  {
11919  /* Does the new item start with a new line? */
11920  if (itembuf.len > 0 && itembuf.data[0] == '\n')
11921  {
11922  /* If so, we shouldn't add anything */
11923  /* instead, remove any trailing spaces currently in buf */
11925  }
11926  else
11927  {
11928  char *trailing_nl;
11929 
11930  /* Locate the start of the current line in the buffer */
11931  trailing_nl = strrchr(buf->data, '\n');
11932  if (trailing_nl == NULL)
11933  trailing_nl = buf->data;
11934  else
11935  trailing_nl++;
11936 
11937  /*
11938  * Add a newline, plus some indentation, if the new item
11939  * would cause an overflow.
11940  */
11941  if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
11945  }
11946  }
11947 
11948  /* Add the new item */
11949  appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
11950 
11951  /* clean up */
11952  pfree(itembuf.data);
11953  }
11954  }
11955 }
11956 
11957 static void
11959 {
11960  StringInfo buf = context->buf;
11961  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
11962 
11963  if (IsA(jtnode, RangeTblRef))
11964  {
11965  int varno = ((RangeTblRef *) jtnode)->rtindex;
11966  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11967  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11968  RangeTblFunction *rtfunc1 = NULL;
11969 
11970  if (rte->lateral)
11971  appendStringInfoString(buf, "LATERAL ");
11972 
11973  /* Print the FROM item proper */
11974  switch (rte->rtekind)
11975  {
11976  case RTE_RELATION:
11977  /* Normal relation RTE */
11978  appendStringInfo(buf, "%s%s",
11979  only_marker(rte),
11981  context->namespaces));
11982  break;
11983  case RTE_SUBQUERY:
11984  /* Subquery RTE */
11985  appendStringInfoChar(buf, '(');
11986  get_query_def(rte->subquery, buf, context->namespaces, NULL,
11987  true,
11988  context->prettyFlags, context->wrapColumn,
11989  context->indentLevel);
11990  appendStringInfoChar(buf, ')');
11991  break;
11992  case RTE_FUNCTION:
11993  /* Function RTE */
11994  rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
11995 
11996  /*
11997  * Omit ROWS FROM() syntax for just one function, unless it
11998  * has both a coldeflist and WITH ORDINALITY. If it has both,
11999  * we must use ROWS FROM() syntax to avoid ambiguity about
12000  * whether the coldeflist includes the ordinality column.
12001  */
12002  if (list_length(rte->functions) == 1 &&
12003  (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12004  {
12005  get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12006  /* we'll print the coldeflist below, if it has one */
12007  }
12008  else
12009  {
12010  bool all_unnest;
12011  ListCell *lc;
12012 
12013  /*
12014  * If all the function calls in the list are to unnest,
12015  * and none need a coldeflist, then collapse the list back
12016  * down to UNNEST(args). (If we had more than one
12017  * built-in unnest function, this would get more
12018  * difficult.)
12019  *
12020  * XXX This is pretty ugly, since it makes not-terribly-
12021  * future-proof assumptions about what the parser would do
12022  * with the output; but the alternative is to emit our
12023  * nonstandard ROWS FROM() notation for what might have
12024  * been a perfectly spec-compliant multi-argument
12025  * UNNEST().
12026  */
12027  all_unnest = true;
12028  foreach(lc, rte->functions)
12029  {
12030  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12031 
12032  if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12033  ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12034  rtfunc->funccolnames != NIL)
12035  {
12036  all_unnest = false;
12037  break;
12038  }
12039  }
12040 
12041  if (all_unnest)
12042  {
12043  List *allargs = NIL;
12044 
12045  foreach(lc, rte->functions)
12046  {
12047  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12048  List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12049 
12050  allargs = list_concat(allargs, args);
12051  }
12052 
12053  appendStringInfoString(buf, "UNNEST(");
12054  get_rule_expr((Node *) allargs, context, true);
12055  appendStringInfoChar(buf, ')');
12056  }
12057  else
12058  {
12059  int funcno = 0;
12060 
12061  appendStringInfoString(buf, "ROWS FROM(");
12062  foreach(lc, rte->functions)
12063  {
12064  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12065 
12066  if (funcno > 0)
12067  appendStringInfoString(buf, ", ");
12068  get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12069  if (rtfunc->funccolnames != NIL)
12070  {
12071  /* Reconstruct the column definition list */
12072  appendStringInfoString(buf, " AS ");
12074  NULL,
12075  context);
12076  }
12077  funcno++;
12078  }
12079  appendStringInfoChar(buf, ')');
12080  }
12081  /* prevent printing duplicate coldeflist below */
12082  rtfunc1 = NULL;
12083  }
12084  if (rte->funcordinality)
12085  appendStringInfoString(buf, " WITH ORDINALITY");
12086  break;
12087  case RTE_TABLEFUNC:
12088  get_tablefunc(rte->tablefunc, context, true);
12089  break;
12090  case RTE_VALUES:
12091  /* Values list RTE */
12092  appendStringInfoChar(buf, '(');
12094  appendStringInfoChar(buf, ')');
12095  break;
12096  case RTE_CTE:
12098  break;
12099  default:
12100  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12101  break;
12102  }
12103 
12104  /* Print the relation alias, if needed */
12105  get_rte_alias(rte, varno, false, context);
12106 
12107  /* Print the column definitions or aliases, if needed */
12108  if (rtfunc1 && rtfunc1->funccolnames != NIL)
12109  {
12110  /* Reconstruct the columndef list, which is also the aliases */
12111  get_from_clause_coldeflist(rtfunc1, colinfo, context);
12112  }
12113  else
12114  {
12115  /* Else print column aliases as needed */
12116  get_column_alias_list(colinfo, context);
12117  }
12118 
12119  /* Tablesample clause must go after any alias */
12120  if (rte->rtekind == RTE_RELATION && rte->tablesample)
12122  }
12123  else if (IsA(jtnode, JoinExpr))
12124  {
12125  JoinExpr *j = (JoinExpr *) jtnode;
12126  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12127  bool need_paren_on_right;
12128 
12129  need_paren_on_right = PRETTY_PAREN(context) &&
12130  !IsA(j->rarg, RangeTblRef) &&
12131  !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12132 
12133  if (!PRETTY_PAREN(context) || j->alias != NULL)
12134  appendStringInfoChar(buf, '(');
12135 
12136  get_from_clause_item(j->larg, query, context);
12137 
12138  switch (j->jointype)
12139  {
12140  case JOIN_INNER:
12141  if (j->quals)
12142  appendContextKeyword(context, " JOIN ",
12146  else
12147  appendContextKeyword(context, " CROSS JOIN ",
12151  break;
12152  case JOIN_LEFT:
12153  appendContextKeyword(context, " LEFT JOIN ",
12157  break;
12158  case JOIN_FULL:
12159  appendContextKeyword(context, " FULL JOIN ",
12163  break;
12164  case JOIN_RIGHT:
12165  appendContextKeyword(context, " RIGHT JOIN ",
12169  break;
12170  default:
12171  elog(ERROR, "unrecognized join type: %d",
12172  (int) j->jointype);
12173  }
12174 
12175  if (need_paren_on_right)
12176  appendStringInfoChar(buf, '(');
12177  get_from_clause_item(j->rarg, query, context);
12178  if (need_paren_on_right)
12179  appendStringInfoChar(buf, ')');
12180 
12181  if (j->usingClause)
12182  {
12183  ListCell *lc;
12184  bool first = true;
12185 
12186  appendStringInfoString(buf, " USING (");
12187  /* Use the assigned names, not what's in usingClause */
12188  foreach(lc, colinfo->usingNames)
12189  {
12190  char *colname = (char *) lfirst(lc);
12191 
12192  if (first)
12193  first = false;
12194  else
12195  appendStringInfoString(buf, ", ");
12197  }
12198  appendStringInfoChar(buf, ')');
12199 
12200  if (j->join_using_alias)
12201  appendStringInfo(buf, " AS %s",
12202  quote_identifier(j->join_using_alias->aliasname));
12203  }
12204  else if (j->quals)
12205  {
12206  appendStringInfoString(buf, " ON ");
12207  if (!PRETTY_PAREN(context))
12208  appendStringInfoChar(buf, '(');
12209  get_rule_expr(j->quals, context, false);
12210  if (!PRETTY_PAREN(context))
12211  appendStringInfoChar(buf, ')');
12212  }
12213  else if (j->jointype != JOIN_INNER)
12214  {
12215  /* If we didn't say CROSS JOIN above, we must provide an ON */
12216  appendStringInfoString(buf, " ON TRUE");
12217  }
12218 
12219  if (!PRETTY_PAREN(context) || j->alias != NULL)
12220  appendStringInfoChar(buf, ')');
12221 
12222  /* Yes, it's correct to put alias after the right paren ... */
12223  if (j->alias != NULL)
12224  {
12225  /*
12226  * Note that it's correct to emit an alias clause if and only if
12227  * there was one originally. Otherwise we'd be converting a named
12228  * join to unnamed or vice versa, which creates semantic
12229  * subtleties we don't want. However, we might print a different
12230  * alias name than was there originally.
12231  */
12232  appendStringInfo(buf, " %s",
12234  context)));
12235  get_column_alias_list(colinfo, context);
12236  }
12237  }
12238  else
12239  elog(ERROR, "unrecognized node type: %d",
12240  (int) nodeTag(jtnode));
12241 }
12242 
12243 /*
12244  * get_rte_alias - print the relation's alias, if needed
12245  *
12246  * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
12247  */
12248 static void
12249 get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
12251 {
12252  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12253  char *refname = get_rtable_name(varno, context);
12254  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12255  bool printalias = false;
12256 
12257  if (rte->alias != NULL)
12258  {
12259  /* Always print alias if user provided one */
12260  printalias = true;
12261  }
12262  else if (colinfo->printaliases)
12263  {
12264  /* Always print alias if we need to print column aliases */
12265  printalias = true;
12266  }
12267  else if (rte->rtekind == RTE_RELATION)
12268  {
12269  /*
12270  * No need to print alias if it's same as relation name (this would
12271  * normally be the case, but not if set_rtable_names had to resolve a
12272  * conflict).
12273  */
12274  if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12275  printalias = true;
12276  }
12277  else if (rte->rtekind == RTE_FUNCTION)
12278  {
12279  /*
12280  * For a function RTE, always print alias. This covers possible
12281  * renaming of the function and/or instability of the FigureColname
12282  * rules for things that aren't simple functions. Note we'd need to
12283  * force it anyway for the columndef list case.
12284  */
12285  printalias = true;
12286  }
12287  else if (rte->rtekind == RTE_SUBQUERY ||
12288  rte->rtekind == RTE_VALUES)
12289  {
12290  /*
12291  * For a subquery, always print alias. This makes the output
12292  * SQL-spec-compliant, even though we allow such aliases to be omitted
12293  * on input.
12294  */
12295  printalias = true;
12296  }
12297  else if (rte->rtekind == RTE_CTE)
12298  {
12299  /*
12300  * No need to print alias if it's same as CTE name (this would
12301  * normally be the case, but not if set_rtable_names had to resolve a
12302  * conflict).
12303  */
12304  if (strcmp(refname, rte->ctename) != 0)
12305  printalias = true;
12306  }
12307 
12308  if (printalias)
12309  appendStringInfo(context->buf, "%s%s",
12310  use_as ? " AS " : " ",
12311  quote_identifier(refname));
12312 }
12313 
12314 /*
12315  * get_column_alias_list - print column alias list for an RTE
12316  *
12317  * Caller must already have printed the relation's alias name.
12318  */
12319 static void
12321 {
12322  StringInfo buf = context->buf;
12323  int i;
12324  bool first = true;
12325 
12326  /* Don't print aliases if not needed */
12327  if (!colinfo->printaliases)
12328  return;
12329 
12330  for (i = 0; i < colinfo->num_new_cols; i++)
12331  {
12332  char *colname = colinfo->new_colnames[i];
12333 
12334  if (first)
12335  {
12336  appendStringInfoChar(buf, '(');
12337  first = false;
12338  }
12339  else
12340  appendStringInfoString(buf, ", ");
12342  }
12343  if (!first)
12344  appendStringInfoChar(buf, ')');
12345 }
12346 
12347 /*
12348  * get_from_clause_coldeflist - reproduce FROM clause coldeflist
12349  *
12350  * When printing a top-level coldeflist (which is syntactically also the
12351  * relation's column alias list), use column names from colinfo. But when
12352  * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
12353  * original coldeflist's names, which are available in rtfunc->funccolnames.
12354  * Pass NULL for colinfo to select the latter behavior.
12355  *
12356  * The coldeflist is appended immediately (no space) to buf. Caller is
12357  * responsible for ensuring that an alias or AS is present before it.
12358  */
12359 static void
12361  deparse_columns *colinfo,
12363 {
12364  StringInfo buf = context->buf;
12365  ListCell *l1;
12366  ListCell *l2;
12367  ListCell *l3;
12368  ListCell *l4;
12369  int i;
12370 
12371  appendStringInfoChar(buf, '(');
12372 
12373  i = 0;
12374  forfour(l1, rtfunc->funccoltypes,
12375  l2, rtfunc->funccoltypmods,
12376  l3, rtfunc->funccolcollations,
12377  l4, rtfunc->funccolnames)
12378  {
12379  Oid atttypid = lfirst_oid(l1);
12380  int32 atttypmod = lfirst_int(l2);
12381  Oid attcollation = lfirst_oid(l3);
12382  char *attname;
12383 
12384  if (colinfo)
12385  attname = colinfo->colnames[i];
12386  else
12387  attname = strVal(lfirst(l4));
12388 
12389  Assert(attname); /* shouldn't be any dropped columns here */
12390 
12391  if (i > 0)
12392  appendStringInfoString(buf, ", ");
12393  appendStringInfo(buf, "%s %s",
12395  format_type_with_typemod(atttypid, atttypmod));
12396  if (OidIsValid(attcollation) &&
12397  attcollation != get_typcollation(atttypid))
12398  appendStringInfo(buf, " COLLATE %s",
12399  generate_collation_name(attcollation));
12400 
12401  i++;
12402  }
12403 
12404  appendStringInfoChar(buf, ')');
12405 }
12406 
12407 /*
12408  * get_tablesample_def - print a TableSampleClause
12409  */
12410 static void
12412 {
12413  StringInfo buf = context->buf;
12414  Oid argtypes[1];
12415  int nargs;
12416  ListCell *l;
12417 
12418  /*
12419  * We should qualify the handler's function name if it wouldn't be
12420  * resolved by lookup in the current search path.
12421  */
12422  argtypes[0] = INTERNALOID;
12423  appendStringInfo(buf, " TABLESAMPLE %s (",
12424  generate_function_name(tablesample->tsmhandler, 1,
12425  NIL, argtypes,
12426  false, NULL, EXPR_KIND_NONE));
12427 
12428  nargs = 0;
12429  foreach(l, tablesample->args)
12430  {
12431  if (nargs++ > 0)
12432  appendStringInfoString(buf, ", ");
12433  get_rule_expr((Node *) lfirst(l), context, false);
12434  }
12435  appendStringInfoChar(buf, ')');
12436 
12437  if (tablesample->repeatable != NULL)
12438  {
12439  appendStringInfoString(buf, " REPEATABLE (");
12440  get_rule_expr((Node *) tablesample->repeatable, context, false);
12441  appendStringInfoChar(buf, ')');
12442  }
12443 }
12444 
12445 /*
12446  * get_opclass_name - fetch name of an index operator class
12447  *
12448  * The opclass name is appended (after a space) to buf.
12449  *
12450  * Output is suppressed if the opclass is the default for the given
12451  * actual_datatype. (If you don't want this behavior, just pass
12452  * InvalidOid for actual_datatype.)
12453  */
12454 static void
12455 get_opclass_name(Oid opclass, Oid actual_datatype,
12456  StringInfo buf)
12457 {
12458  HeapTuple ht_opc;
12459  Form_pg_opclass opcrec;
12460  char *opcname;
12461  char *nspname;
12462 
12463  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12464  if (!HeapTupleIsValid(ht_opc))
12465  elog(ERROR, "cache lookup failed for opclass %u", opclass);
12466  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12467 
12468  if (!OidIsValid(actual_datatype) ||
12469  GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12470  {
12471  /* Okay, we need the opclass name. Do we need to qualify it? */
12472  opcname = NameStr(opcrec->opcname);
12473  if (OpclassIsVisible(opclass))
12474  appendStringInfo(buf, " %s", quote_identifier(opcname));
12475  else
12476  {
12477  nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
12478  appendStringInfo(buf, " %s.%s",
12479  quote_identifier(nspname),
12480  quote_identifier(opcname));
12481  }
12482  }
12483  ReleaseSysCache(ht_opc);
12484 }
12485 
12486 /*
12487  * generate_opclass_name
12488  * Compute the name to display for an opclass specified by OID
12489  *
12490  * The result includes all necessary quoting and schema-prefixing.
12491  */
12492 char *
12494 {
12496 
12497  initStringInfo(&buf);
12498  get_opclass_name(opclass, InvalidOid, &buf);
12499 
12500  return &buf.data[1]; /* get_opclass_name() prepends space */
12501 }
12502 
12503 /*
12504  * processIndirection - take care of array and subfield assignment
12505  *
12506  * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
12507  * appear in the input, printing them as decoration for the base column
12508  * name (which we assume the caller just printed). We might also need to
12509  * strip CoerceToDomain nodes, but only ones that appear above assignment
12510  * nodes.
12511  *
12512  * Returns the subexpression that's to be assigned.
12513  */
12514 static Node *
12516 {
12517  StringInfo buf = context->buf;
12518  CoerceToDomain *cdomain = NULL;
12519 
12520  for (;;)
12521  {
12522  if (node == NULL)
12523  break;
12524  if (IsA(node, FieldStore))
12525  {
12526  FieldStore *fstore = (FieldStore *) node;
12527  Oid typrelid;
12528  char *fieldname;
12529 
12530  /* lookup tuple type */
12531  typrelid = get_typ_typrelid(fstore->resulttype);
12532  if (!OidIsValid(typrelid))
12533  elog(ERROR, "argument type %s of FieldStore is not a tuple type",
12534  format_type_be(fstore->resulttype));
12535 
12536  /*
12537  * Print the field name. There should only be one target field in
12538  * stored rules. There could be more than that in executable
12539  * target lists, but this function cannot be used for that case.
12540  */
12541  Assert(list_length(fstore->fieldnums) == 1);
12542  fieldname = get_attname(typrelid,
12543  linitial_int(fstore->fieldnums), false);
12544  appendStringInfo(buf, ".%s", quote_identifier(fieldname));
12545 
12546  /*
12547  * We ignore arg since it should be an uninteresting reference to
12548  * the target column or subcolumn.
12549  */
12550  node = (Node *) linitial(fstore->newvals);
12551  }
12552  else if (IsA(node, SubscriptingRef))
12553  {
12554  SubscriptingRef *sbsref = (SubscriptingRef *) node;
12555 
12556  if (sbsref->refassgnexpr == NULL)
12557  break;
12558 
12559  printSubscripts(sbsref, context);
12560 
12561  /*
12562  * We ignore refexpr since it should be an uninteresting reference
12563  * to the target column or subcolumn.
12564  */
12565  node = (Node *) sbsref->refassgnexpr;
12566  }
12567  else if (IsA(node, CoerceToDomain))
12568  {
12569  cdomain = (CoerceToDomain *) node;
12570  /* If it's an explicit domain coercion, we're done */
12571  if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
12572  break;
12573  /* Tentatively descend past the CoerceToDomain */
12574  node = (Node *) cdomain->arg;
12575  }
12576  else
12577  break;
12578  }
12579 
12580  /*
12581  * If we descended past a CoerceToDomain whose argument turned out not to
12582  * be a FieldStore or array assignment, back up to the CoerceToDomain.
12583  * (This is not enough to be fully correct if there are nested implicit
12584  * CoerceToDomains, but such cases shouldn't ever occur.)
12585  */
12586  if (cdomain && node == (Node *) cdomain->arg)
12587  node = (Node *) cdomain;
12588 
12589  return node;
12590 }
12591 
12592 static void
12594 {
12595  StringInfo buf = context->buf;
12596  ListCell *lowlist_item;
12597  ListCell *uplist_item;
12598 
12599  lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
12600  foreach(uplist_item, sbsref->refupperindexpr)
12601  {
12602  appendStringInfoChar(buf, '[');
12603  if (lowlist_item)
12604  {
12605  /* If subexpression is NULL, get_rule_expr prints nothing */
12606  get_rule_expr((Node *) lfirst(lowlist_item), context, false);
12607  appendStringInfoChar(buf, ':');
12608  lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
12609  }
12610  /* If subexpression is NULL, get_rule_expr prints nothing */
12611  get_rule_expr((Node *) lfirst(uplist_item), context, false);
12612  appendStringInfoChar(buf, ']');
12613  }
12614 }
12615 
12616 /*
12617  * quote_identifier - Quote an identifier only if needed
12618  *
12619  * When quotes are needed, we palloc the required space; slightly
12620  * space-wasteful but well worth it for notational simplicity.
12621  */
12622 const char *
12624 {
12625  /*
12626  * Can avoid quoting if ident starts with a lowercase letter or underscore
12627  * and contains only lowercase letters, digits, and underscores, *and* is
12628  * not any SQL keyword. Otherwise, supply quotes.
12629  */
12630  int nquotes = 0;
12631  bool safe;
12632  const char *ptr;
12633  char *result;
12634  char *optr;
12635 
12636  /*
12637  * would like to use <ctype.h> macros here, but they might yield unwanted
12638  * locale-specific results...
12639  */
12640  safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
12641 
12642  for (ptr = ident; *ptr; ptr++)
12643  {
12644  char ch = *ptr;
12645 
12646  if ((ch >= 'a' && ch <= 'z') ||
12647  (ch >= '0' && ch <= '9') ||
12648  (ch == '_'))
12649  {
12650  /* okay */
12651  }
12652  else
12653  {
12654  safe = false;
12655  if (ch == '"')
12656  nquotes++;
12657  }
12658  }
12659 
12661  safe = false;
12662 
12663  if (safe)
12664  {
12665  /*
12666  * Check for keyword. We quote keywords except for unreserved ones.
12667  * (In some cases we could avoid quoting a col_name or type_func_name
12668  * keyword, but it seems much harder than it's worth to tell that.)
12669  *
12670  * Note: ScanKeywordLookup() does case-insensitive comparison, but
12671  * that's fine, since we already know we have all-lower-case.
12672  */
12673  int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
12674 
12675  if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
12676  safe = false;
12677  }
12678 
12679  if (safe)
12680  return ident; /* no change needed */
12681 
12682  result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
12683 
12684  optr = result;
12685  *optr++ = '"';
12686  for (ptr = ident; *ptr; ptr++)
12687  {
12688  char ch = *ptr;
12689 
12690  if (ch == '"')
12691  *optr++ = '"';
12692  *optr++ = ch;
12693  }
12694  *optr++ = '"';
12695  *optr = '\0';
12696 
12697  return result;
12698 }
12699 
12700 /*
12701  * quote_qualified_identifier - Quote a possibly-qualified identifier
12702  *
12703  * Return a name of the form qualifier.ident, or just ident if qualifier
12704  * is NULL, quoting each component if necessary. The result is palloc'd.
12705  */
12706 char *
12707 quote_qualified_identifier(const char *qualifier,
12708  const char *ident)
12709 {
12711 
12712  initStringInfo(&buf);
12713  if (qualifier)
12714  appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
12716  return buf.data;
12717 }
12718 
12719 /*
12720  * get_relation_name
12721  * Get the unqualified name of a relation specified by OID
12722  *
12723  * This differs from the underlying get_rel_name() function in that it will
12724  * throw error instead of silently returning NULL if the OID is bad.
12725  */
12726 static char *
12728 {
12729  char *relname = get_rel_name(relid);
12730 
12731  if (!relname)
12732  elog(ERROR, "cache lookup failed for relation %u", relid);
12733  return relname;
12734 }
12735 
12736 /*
12737  * generate_relation_name
12738  * Compute the name to display for a relation specified by OID
12739  *
12740  * The result includes all necessary quoting and schema-prefixing.
12741  *
12742  * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
12743  * We will forcibly qualify the relation name if it equals any CTE name
12744  * visible in the namespace list.
12745  */
12746 static char *
12747 generate_relation_name(Oid relid, List *namespaces)
12748 {
12749  HeapTuple tp;
12750  Form_pg_class reltup;
12751  bool need_qual;
12752  ListCell *nslist;
12753  char *relname;
12754  char *nspname;
12755  char *result;
12756 
12757  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12758  if (!HeapTupleIsValid(tp))
12759  elog(ERROR, "cache lookup failed for relation %u", relid);
12760  reltup = (Form_pg_class) GETSTRUCT(tp);
12761  relname = NameStr(reltup->relname);
12762 
12763  /* Check for conflicting CTE name */
12764  need_qual = false;
12765  foreach(nslist, namespaces)
12766  {
12767  deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
12768  ListCell *ctlist;
12769 
12770  foreach(ctlist, dpns->ctes)
12771  {
12772  CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
12773 
12774  if (strcmp(cte->ctename, relname) == 0)
12775  {
12776  need_qual = true;
12777  break;
12778  }
12779  }
12780  if (need_qual)
12781  break;
12782  }
12783 
12784  /* Otherwise, qualify the name if not visible in search path */
12785  if (!need_qual)
12786  need_qual = !RelationIsVisible(relid);
12787 
12788  if (need_qual)
12789  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12790  else
12791  nspname = NULL;
12792 
12793  result = quote_qualified_identifier(nspname, relname);
12794 
12795  ReleaseSysCache(tp);
12796 
12797  return result;
12798 }
12799 
12800 /*
12801  * generate_qualified_relation_name
12802  * Compute the name to display for a relation specified by OID
12803  *
12804  * As above, but unconditionally schema-qualify the name.
12805  */
12806 static char *
12808 {
12809  HeapTuple tp;
12810  Form_pg_class reltup;
12811  char *relname;
12812  char *nspname;
12813  char *result;
12814 
12815  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12816  if (!HeapTupleIsValid(tp))
12817  elog(ERROR, "cache lookup failed for relation %u", relid);
12818  reltup = (Form_pg_class) GETSTRUCT(tp);
12819  relname = NameStr(reltup->relname);
12820 
12821  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12822  if (!nspname)
12823  elog(ERROR, "cache lookup failed for namespace %u",
12824  reltup->relnamespace);
12825 
12826  result = quote_qualified_identifier(nspname, relname);
12827 
12828  ReleaseSysCache(tp);
12829 
12830  return result;
12831 }
12832 
12833 /*
12834  * generate_function_name
12835  * Compute the name to display for a function specified by OID,
12836  * given that it is being called with the specified actual arg names and
12837  * types. (Those matter because of ambiguous-function resolution rules.)
12838  *
12839  * If we're dealing with a potentially variadic function (in practice, this
12840  * means a FuncExpr or Aggref, not some other way of calling a function), then
12841  * has_variadic must specify whether variadic arguments have been merged,
12842  * and *use_variadic_p will be set to indicate whether to print VARIADIC in
12843  * the output. For non-FuncExpr cases, has_variadic should be false and
12844  * use_variadic_p can be NULL.
12845  *
12846  * The result includes all necessary quoting and schema-prefixing.
12847  */
12848 static char *
12849 generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
12850  bool has_variadic, bool *use_variadic_p,
12851  ParseExprKind special_exprkind)
12852 {
12853  char *result;
12854  HeapTuple proctup;
12855  Form_pg_proc procform;
12856  char *proname;
12857  bool use_variadic;
12858  char *nspname;
12859  FuncDetailCode p_result;
12860  Oid p_funcid;
12861  Oid p_rettype;
12862  bool p_retset;
12863  int p_nvargs;
12864  Oid p_vatype;
12865  Oid *p_true_typeids;
12866  bool force_qualify = false;
12867 
12868  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
12869  if (!HeapTupleIsValid(proctup))
12870  elog(ERROR, "cache lookup failed for function %u", funcid);
12871  procform = (Form_pg_proc) GETSTRUCT(proctup);
12872  proname = NameStr(procform->proname);
12873 
12874  /*
12875  * Due to parser hacks to avoid needing to reserve CUBE, we need to force
12876  * qualification in some special cases.
12877  */
12878  if (special_exprkind == EXPR_KIND_GROUP_BY)
12879  {
12880  if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
12881  force_qualify = true;
12882  }
12883 
12884  /*
12885  * Determine whether VARIADIC should be printed. We must do this first
12886  * since it affects the lookup rules in func_get_detail().
12887  *
12888  * We always print VARIADIC if the function has a merged variadic-array
12889  * argument. Note that this is always the case for functions taking a
12890  * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
12891  * and printed the array elements as separate arguments, the call could
12892  * match a newer non-VARIADIC function.
12893  */
12894  if (use_variadic_p)
12895  {
12896  /* Parser should not have set funcvariadic unless fn is variadic */
12897  Assert(!has_variadic || OidIsValid(procform->provariadic));
12898  use_variadic = has_variadic;
12899  *use_variadic_p = use_variadic;
12900  }
12901  else
12902  {
12903  Assert(!has_variadic);
12904  use_variadic = false;
12905  }
12906 
12907  /*
12908  * The idea here is to schema-qualify only if the parser would fail to
12909  * resolve the correct function given the unqualified func name with the
12910  * specified argtypes and VARIADIC flag. But if we already decided to
12911  * force qualification, then we can skip the lookup and pretend we didn't
12912  * find it.
12913  */
12914  if (!force_qualify)
12916  NIL, argnames, nargs, argtypes,
12917  !use_variadic, true, false,
12918  &p_funcid, &p_rettype,
12919  &p_retset, &p_nvargs, &p_vatype,
12920  &p_true_typeids, NULL);
12921  else
12922  {
12923  p_result = FUNCDETAIL_NOTFOUND;
12924  p_funcid = InvalidOid;
12925  }
12926 
12927  if ((p_result == FUNCDETAIL_NORMAL ||
12928  p_result == FUNCDETAIL_AGGREGATE ||
12929  p_result == FUNCDETAIL_WINDOWFUNC) &&
12930  p_funcid == funcid)
12931  nspname = NULL;
12932  else
12933  nspname = get_namespace_name_or_temp(procform->pronamespace);
12934 
12935  result = quote_qualified_identifier(nspname, proname);
12936 
12937  ReleaseSysCache(proctup);
12938 
12939  return result;
12940 }
12941 
12942 /*
12943  * generate_operator_name
12944  * Compute the name to display for an operator specified by OID,
12945  * given that it is being called with the specified actual arg types.
12946  * (Arg types matter because of ambiguous-operator resolution rules.
12947  * Pass InvalidOid for unused arg of a unary operator.)
12948  *
12949  * The result includes all necessary quoting and schema-prefixing,
12950  * plus the OPERATOR() decoration needed to use a qualified operator name
12951  * in an expression.
12952  */
12953 static char *
12954 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
12955 {
12957  HeapTuple opertup;
12958  Form_pg_operator operform;
12959  char *oprname;
12960  char *nspname;
12961  Operator p_result;
12962 
12963  initStringInfo(&buf);
12964 
12965  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
12966  if (!HeapTupleIsValid(opertup))
12967  elog(ERROR, "cache lookup failed for operator %u", operid);
12968  operform = (Form_pg_operator) GETSTRUCT(opertup);
12969  oprname = NameStr(operform->oprname);
12970 
12971  /*
12972  * The idea here is to schema-qualify only if the parser would fail to
12973  * resolve the correct operator given the unqualified op name with the
12974  * specified argtypes.
12975  */
12976  switch (operform->oprkind)
12977  {
12978  case 'b':
12979  p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
12980  true, -1);
12981  break;
12982  case 'l':
12983  p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
12984  true, -1);
12985  break;
12986  default:
12987  elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
12988  p_result = NULL; /* keep compiler quiet */
12989  break;
12990  }
12991 
12992  if (p_result != NULL && oprid(p_result) == operid)
12993  nspname = NULL;
12994  else
12995  {
12996  nspname = get_namespace_name_or_temp(operform->oprnamespace);
12997  appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
12998  }
12999 
13000  appendStringInfoString(&buf, oprname);
13001 
13002  if (nspname)
13003  appendStringInfoChar(&buf, ')');
13004 
13005  if (p_result != NULL)
13006  ReleaseSysCache(p_result);
13007 
13008  ReleaseSysCache(opertup);
13009 
13010  return buf.data;
13011 }
13012 
13013 /*
13014  * generate_operator_clause --- generate a binary-operator WHERE clause
13015  *
13016  * This is used for internally-generated-and-executed SQL queries, where
13017  * precision is essential and readability is secondary. The basic
13018  * requirement is to append "leftop op rightop" to buf, where leftop and
13019  * rightop are given as strings and are assumed to yield types leftoptype
13020  * and rightoptype; the operator is identified by OID. The complexity
13021  * comes from needing to be sure that the parser will select the desired
13022  * operator when the query is parsed. We always name the operator using
13023  * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
13024  * We have to emit casts too, if either input isn't already the input type
13025  * of the operator; else we are at the mercy of the parser's heuristics for
13026  * ambiguous-operator resolution. The caller must ensure that leftop and
13027  * rightop are suitable arguments for a cast operation; it's best to insert
13028  * parentheses if they aren't just variables or parameters.
13029  */
13030 void
13032  const char *leftop, Oid leftoptype,
13033  Oid opoid,
13034  const char *rightop, Oid rightoptype)
13035 {
13036  HeapTuple opertup;
13037  Form_pg_operator operform;
13038  char *oprname;
13039  char *nspname;
13040 
13041  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13042  if (!HeapTupleIsValid(opertup))
13043  elog(ERROR, "cache lookup failed for operator %u", opoid);
13044  operform = (Form_pg_operator) GETSTRUCT(opertup);
13045  Assert(operform->oprkind == 'b');
13046  oprname = NameStr(operform->oprname);
13047 
13048  nspname = get_namespace_name(operform->oprnamespace);
13049 
13050  appendStringInfoString(buf, leftop);
13051  if (leftoptype != operform->oprleft)
13052  add_cast_to(buf, operform->oprleft);
13053  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13054  appendStringInfoString(buf, oprname);
13055  appendStringInfo(buf, ") %s", rightop);
13056  if (rightoptype != operform->oprright)
13057  add_cast_to(buf, operform->oprright);
13058 
13059  ReleaseSysCache(opertup);
13060 }
13061 
13062 /*
13063  * Add a cast specification to buf. We spell out the type name the hard way,
13064  * intentionally not using format_type_be(). This is to avoid corner cases
13065  * for CHARACTER, BIT, and perhaps other types, where specifying the type
13066  * using SQL-standard syntax results in undesirable data truncation. By
13067  * doing it this way we can be certain that the cast will have default (-1)
13068  * target typmod.
13069  */
13070 static void
13072 {
13073  HeapTuple typetup;
13074  Form_pg_type typform;
13075  char *typname;
13076  char *nspname;
13077 
13078  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13079  if (!HeapTupleIsValid(typetup))
13080  elog(ERROR, "cache lookup failed for type %u", typid);
13081  typform = (Form_pg_type) GETSTRUCT(typetup);
13082 
13083  typname = NameStr(typform->typname);
13084  nspname = get_namespace_name_or_temp(typform->typnamespace);
13085 
13086  appendStringInfo(buf, "::%s.%s",
13088 
13089  ReleaseSysCache(typetup);
13090 }
13091 
13092 /*
13093  * generate_qualified_type_name
13094  * Compute the name to display for a type specified by OID
13095  *
13096  * This is different from format_type_be() in that we unconditionally
13097  * schema-qualify the name. That also means no special syntax for
13098  * SQL-standard type names ... although in current usage, this should
13099  * only get used for domains, so such cases wouldn't occur anyway.
13100  */
13101 static char *
13103 {
13104  HeapTuple tp;
13105  Form_pg_type typtup;
13106  char *typname;
13107  char *nspname;
13108  char *result;
13109 
13110  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13111  if (!HeapTupleIsValid(tp))
13112  elog(ERROR, "cache lookup failed for type %u", typid);
13113  typtup = (Form_pg_type) GETSTRUCT(tp);
13114  typname = NameStr(typtup->typname);
13115 
13116  nspname = get_namespace_name_or_temp(typtup->typnamespace);
13117  if (!nspname)
13118  elog(ERROR, "cache lookup failed for namespace %u",
13119  typtup->typnamespace);
13120 
13121  result = quote_qualified_identifier(nspname, typname);
13122 
13123  ReleaseSysCache(tp);
13124 
13125  return result;
13126 }
13127 
13128 /*
13129  * generate_collation_name
13130  * Compute the name to display for a collation specified by OID
13131  *
13132  * The result includes all necessary quoting and schema-prefixing.
13133  */
13134 char *
13136 {
13137  HeapTuple tp;
13138  Form_pg_collation colltup;
13139  char *collname;
13140  char *nspname;
13141  char *result;
13142 
13143  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13144  if (!HeapTupleIsValid(tp))
13145  elog(ERROR, "cache lookup failed for collation %u", collid);
13146  colltup = (Form_pg_collation) GETSTRUCT(tp);
13147  collname = NameStr(colltup->collname);
13148 
13149  if (!CollationIsVisible(collid))
13150  nspname = get_namespace_name_or_temp(colltup->collnamespace);
13151  else
13152  nspname = NULL;
13153 
13154  result = quote_qualified_identifier(nspname, collname);
13155 
13156  ReleaseSysCache(tp);
13157 
13158  return result;
13159 }
13160 
13161 /*
13162  * Given a C string, produce a TEXT datum.
13163  *
13164  * We assume that the input was palloc'd and may be freed.
13165  */
13166 static text *
13168 {
13169  text *result;
13170 
13171  result = cstring_to_text(str);
13172  pfree(str);
13173  return result;
13174 }
13175 
13176 /*
13177  * Generate a C string representing a relation options from text[] datum.
13178  */
13179 static void
13181 {
13182  Datum *options;
13183  int noptions;
13184  int i;
13185 
13186  deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13187  &options, NULL, &noptions);
13188 
13189  for (i = 0; i < noptions; i++)
13190  {
13191  char *option = TextDatumGetCString(options[i]);
13192  char *name;
13193  char *separator;
13194  char *value;
13195 
13196  /*
13197  * Each array element should have the form name=value. If the "=" is
13198  * missing for some reason, treat it like an empty value.
13199  */
13200  name = option;
13201  separator = strchr(option, '=');
13202  if (separator)
13203  {
13204  *separator = '\0';
13205  value = separator + 1;
13206  }
13207  else
13208  value = "";
13209 
13210  if (i > 0)
13211  appendStringInfoString(buf, ", ");
13213 
13214  /*
13215  * In general we need to quote the value; but to avoid unnecessary
13216  * clutter, do not quote if it is an identifier that would not need
13217  * quoting. (We could also allow numbers, but that is a bit trickier
13218  * than it looks --- for example, are leading zeroes significant? We
13219  * don't want to assume very much here about what custom reloptions
13220  * might mean.)
13221  */
13222  if (quote_identifier(value) == value)
13224  else
13226 
13227  pfree(option);
13228  }
13229 }
13230 
13231 /*
13232  * Generate a C string representing a relation's reloptions, or NULL if none.
13233  */
13234 static char *
13236 {
13237  char *result = NULL;
13238  HeapTuple tuple;
13239  Datum reloptions;
13240  bool isnull;
13241 
13242  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13243  if (!HeapTupleIsValid(tuple))
13244  elog(ERROR, "cache lookup failed for relation %u", relid);
13245 
13246  reloptions = SysCacheGetAttr(RELOID, tuple,
13247  Anum_pg_class_reloptions, &isnull);
13248  if (!isnull)
13249  {
13251 
13252  initStringInfo(&buf);
13253  get_reloptions(&buf, reloptions);
13254 
13255  result = buf.data;
13256  }
13257 
13258  ReleaseSysCache(tuple);
13259 
13260  return result;
13261 }
13262 
13263 /*
13264  * get_range_partbound_string
13265  * A C string representation of one range partition bound
13266  */
13267 char *
13269 {
13272  ListCell *cell;
13273  char *sep;
13274 
13275  memset(&context, 0, sizeof(deparse_context));
13276  context.buf = buf;
13277 
13278  appendStringInfoChar(buf, '(');
13279  sep = "";
13280  foreach(cell, bound_datums)
13281  {
13282  PartitionRangeDatum *datum =
13284 
13286  if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
13287  appendStringInfoString(buf, "MINVALUE");
13288  else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13289  appendStringInfoString(buf, "MAXVALUE");
13290  else
13291  {
13292  Const *val = castNode(Const, datum->value);
13293 
13294  get_const_expr(val, &context, -1);
13295  }
13296  sep = ", ";
13297  }
13298  appendStringInfoChar(buf, ')');
13299 
13300  return buf->data;
13301 }
13302 
13303 /*
13304  * get_list_partvalue_string
13305  * A C string representation of one list partition value
13306  */
13307 char *
13309 {
13312 
13313  memset(&context, 0, sizeof(deparse_context));
13314  context.buf = buf;
13315 
13316  get_const_expr(val, &context, -1);
13317 
13318  return buf->data;
13319 }
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
#define ARR_LBOUND(a)
Definition: array.h:296
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5331
Datum array_ref(ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:3139
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3678
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5401
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
#define bms_is_empty(a)
Definition: bitmapset.h:118
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:746
uint16 bits16
Definition: c.h:514
NameData * Name
Definition: c.h:744
signed short int16
Definition: c.h:493
signed int int32
Definition: c.h:494
#define Max(x, y)
Definition: c.h:998
#define Assert(condition)
Definition: c.h:858
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1163
#define lengthof(array)
Definition: c.h:788
unsigned int Index
Definition: c.h:614
float float4
Definition: c.h:629
#define OidIsValid(objectId)
Definition: c.h:775
Oid collid
const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS]
Definition: keywords.c:29
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_NAME(x)
Definition: fmgr.h:363
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
char * format_type_with_typemod(Oid type_oid, int32 typemod)
Definition: format_type.c:362
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int get_func_trftypes(HeapTuple procTup, Oid **p_trftypes)
Definition: funcapi.c:1475
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
TupleDesc get_expr_result_tupdesc(Node *expr, bool noError)
Definition: funcapi.c:551
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
int GetConfigOptionFlags(const char *name, bool missing_ok)
Definition: guc.c:4395
#define GUC_LIST_QUOTE
Definition: guc.h:211
const char * str
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
#define HASH_STRINGS
Definition: hsearch.h:96
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
#define stmt
Definition: indent_codes.h:59
#define ident
Definition: indent_codes.h:47
#define funcname
Definition: indent_codes.h:69
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2338
long val
Definition: informix.c:670
static struct @155 value
int a
Definition: isn.c:69
int j
Definition: isn.c:74
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
PGDLLIMPORT const ScanKeywordList ScanKeywords
#define UNRESERVED_KEYWORD
Definition: keywords.h:20
int ScanKeywordLookup(const char *str, const ScanKeywordList *keywords)
Definition: kwlookup.c:38
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_copy(const List *oldlist)
Definition: list.c:1573
List * list_delete_first(List *list)
Definition: list.c:943
void list_free(List *list)
Definition: list.c:1546
List * list_copy_tail(const List *oldlist, int nskip)
Definition: list.c:1613
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
List * lcons(void *datum, List *list)
Definition: list.c:495
#define NoLock
Definition: lockdefs.h:34
#define AccessShareLock
Definition: lockdefs.h:36
@ LockWaitSkip
Definition: lockoptions.h:41
@ LockWaitError
Definition: lockoptions.h:43
@ LCS_FORUPDATE
Definition: lockoptions.h:27
@ LCS_NONE
Definition: lockoptions.h:23
@ LCS_FORSHARE
Definition: lockoptions.h:25
@ LCS_FORKEYSHARE
Definition: lockoptions.h:24
@ LCS_FORNOKEYUPDATE
Definition: lockoptions.h:26
char * get_language_name(Oid langoid, bool missing_ok)
Definition: lsyscache.c:1161
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1212
char * get_namespace_name_or_temp(Oid nspid)
Definition: lsyscache.c:3390
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2655
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1081
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2054
Oid get_typ_typrelid(Oid typid)
Definition: lsyscache.c:2731
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2832
void get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
Definition: lsyscache.c:2710
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid)
Definition: lsyscache.c:943
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:389
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083
char * pstrdup(const char *in)
Definition: mcxt.c:1695
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc0(Size size)
Definition: mcxt.c:1346
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * palloc(Size size)
Definition: mcxt.c:1316
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
bool CollationIsVisible(Oid collid)
Definition: namespace.c:2392
bool RelationIsVisible(Oid relid)
Definition: namespace.c:898
bool OpclassIsVisible(Oid opcid)
Definition: namespace.c:2139
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3539
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
Definition: nodeFuncs.c:552
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
Node * strip_implicit_coercions(Node *node)
Definition: nodeFuncs.c:700
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:385
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:384
@ ONCONFLICT_NOTHING
Definition: nodes.h:418
@ CMD_MERGE
Definition: nodes.h:269
@ CMD_UTILITY
Definition: nodes.h:270
@ CMD_INSERT
Definition: nodes.h:267
@ CMD_DELETE
Definition: nodes.h:268
@ CMD_UPDATE
Definition: nodes.h:266
@ CMD_SELECT
Definition: nodes.h:265
@ CMD_NOTHING
Definition: nodes.h:272
@ LIMIT_OPTION_WITH_TIES
Definition: nodes.h:431
#define makeNode(_type_)
Definition: nodes.h:155
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
@ JOIN_FULL
Definition: nodes.h:295
@ JOIN_INNER
Definition: nodes.h:293
@ JOIN_RIGHT
Definition: nodes.h:296
@ JOIN_LEFT
Definition: nodes.h:294
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:109
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1908
FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, bool include_out_arguments, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, Oid **true_typeids, List **argdefaults)
Definition: parse_func.c:1394
FuncDetailCode
Definition: parse_func.h:23
@ FUNCDETAIL_NORMAL
Definition: parse_func.h:26
@ FUNCDETAIL_WINDOWFUNC
Definition: parse_func.h:29
@ FUNCDETAIL_NOTFOUND
Definition: parse_func.h:24
@ FUNCDETAIL_AGGREGATE
Definition: parse_func.h:28
ParseExprKind
Definition: parse_node.h:39
@ EXPR_KIND_NONE
Definition: parse_node.h:40
@ EXPR_KIND_GROUP_BY
Definition: parse_node.h:59
Operator left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
Definition: parse_oper.c:518
Oid oprid(Operator op)
Definition: parse_oper.c:238
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:370
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
char * get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:591
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:602
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW
Definition: parsenodes.h:596
@ GROUPING_SET_CUBE
Definition: parsenodes.h:1505
@ GROUPING_SET_SIMPLE
Definition: parsenodes.h:1503
@ GROUPING_SET_ROLLUP
Definition: parsenodes.h:1504
@ GROUPING_SET_SETS
Definition: parsenodes.h:1506
@ GROUPING_SET_EMPTY
Definition: parsenodes.h:1502
#define FKCONSTR_ACTION_RESTRICT
Definition: parsenodes.h:2726
@ SETOP_INTERSECT
Definition: parsenodes.h:2117
@ SETOP_UNION
Definition: parsenodes.h:2116
@ SETOP_EXCEPT
Definition: parsenodes.h:2118
#define FRAMEOPTION_END_OFFSET_PRECEDING
Definition: parsenodes.h:593
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:586
#define GetCTETargetList(cte)
Definition: parsenodes.h:1710
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2729
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:874
@ PARTITION_STRATEGY_LIST
Definition: parsenodes.h:872
@ PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:873
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:590
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:2734
@ RTE_JOIN
Definition: parsenodes.h:1030
@ RTE_CTE
Definition: parsenodes.h:1034
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1035
@ RTE_VALUES
Definition: parsenodes.h:1033
@ RTE_SUBQUERY
Definition: parsenodes.h:1029
@ RTE_RESULT
Definition: parsenodes.h:1036
@ RTE_FUNCTION
Definition: parsenodes.h:1031
@ RTE_TABLEFUNC
Definition: parsenodes.h:1032
@ RTE_RELATION
Definition: parsenodes.h:1028
#define FRAMEOPTION_START_OFFSET
Definition: parsenodes.h:600
@ PARTITION_RANGE_DATUM_MAXVALUE
Definition: parsenodes.h:926
@ PARTITION_RANGE_DATUM_MINVALUE
Definition: parsenodes.h:924
#define FKCONSTR_MATCH_PARTIAL
Definition: parsenodes.h:2733
#define FRAMEOPTION_END_OFFSET_FOLLOWING
Definition: parsenodes.h:595
#define FRAMEOPTION_EXCLUDE_TIES
Definition: parsenodes.h:598
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:582
#define FRAMEOPTION_EXCLUDE_GROUP
Definition: parsenodes.h:597
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2727
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:584
#define FRAMEOPTION_BETWEEN
Definition: parsenodes.h:585
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2728
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition: parsenodes.h:589
#define FRAMEOPTION_START_OFFSET_PRECEDING
Definition: parsenodes.h:592
#define FRAMEOPTION_START_OFFSET_FOLLOWING
Definition: parsenodes.h:594
#define FRAMEOPTION_NONDEFAULT
Definition: parsenodes.h:581
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:2732
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2725
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:583
@ CTEMaterializeNever
Definition: parsenodes.h:1645
@ CTEMaterializeAlways
Definition: parsenodes.h:1644
@ CTEMaterializeDefault
Definition: parsenodes.h:1643
PGDLLIMPORT bool standard_conforming_strings
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
Expr * get_partition_qual_relid(Oid relid)
Definition: partcache.c:299
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
void * arg
static char format
NameData relname
Definition: pg_class.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
#define NAMEDATALEN
#define FUNC_MAX_ARGS
AttrNumber extractNotNullColumn(HeapTuple constrTup)
FormData_pg_constraint * Form_pg_constraint
while(p+4<=pend)
int32 encoding
Definition: pg_database.h:41
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
#define lfirst(lc)
Definition: pg_list.h:172
#define llast(l)
Definition: pg_list.h:198
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define NIL
Definition: pg_list.h:68
#define lsecond_node(type, l)
Definition: pg_list.h:186
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define lfirst_int(lc)
Definition: pg_list.h:173
#define lthird(l)
Definition: pg_list.h:188
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial_int(l)
Definition: pg_list.h:179
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:438
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
#define for_each_from(cell, lst, N)
Definition: pg_list.h:414
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:575
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define lfourth(l)
Definition: pg_list.h:193
#define linitial_oid(l)
Definition: pg_list.h:180
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition: pg_list.h:588
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define list_make2(x1, x2)
Definition: pg_list.h:214
#define foreach_int(var, lst)
Definition: pg_list.h:470
static int list_cell_number(const List *l, const ListCell *c)
Definition: pg_list.h:333
#define lthird_node(type, l)
Definition: pg_list.h:191
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
FormData_pg_partitioned_table * Form_pg_partitioned_table
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
NameData proname
Definition: pg_proc.h:35
static size_t noptions
static char ** options
#define plan(x)
Definition: pg_regress.c:162
FormData_pg_statistic_ext * Form_pg_statistic_ext
static char * buf
Definition: pg_test_fsync.c:73
FormData_pg_trigger * Form_pg_trigger
Definition: pg_trigger.h:80
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
#define innerPlan(node)
Definition: plannodes.h:181
#define outerPlan(node)
Definition: plannodes.h:182
#define sprintf
Definition: port.h:240
void check_stack_depth(void)
Definition: postgres.c:3531
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Name DatumGetName(Datum X)
Definition: postgres.h:360
uintptr_t Datum
Definition: postgres.h:64
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static char DatumGetChar(Datum X)
Definition: postgres.h:112
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:162
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
e
Definition: preproc-init.c:82
char string[11]
Definition: preproc-type.c:52
@ IS_NOT_TRUE
Definition: primnodes.h:1948
@ IS_NOT_FALSE
Definition: primnodes.h:1948
@ IS_NOT_UNKNOWN
Definition: primnodes.h:1948
@ IS_TRUE
Definition: primnodes.h:1948
@ IS_UNKNOWN
Definition: primnodes.h:1948
@ IS_FALSE
Definition: primnodes.h:1948
@ ARRAY_SUBLINK
Definition: primnodes.h:973
@ ANY_SUBLINK
Definition: primnodes.h:969
@ MULTIEXPR_SUBLINK
Definition: primnodes.h:972
@ CTE_SUBLINK
Definition: primnodes.h:974
@ EXPR_SUBLINK
Definition: primnodes.h:971
@ ROWCOMPARE_SUBLINK
Definition: primnodes.h:970
@ ALL_SUBLINK
Definition: primnodes.h:968
@ EXISTS_SUBLINK
Definition: primnodes.h:967
@ JS_FORMAT_JSONB
Definition: primnodes.h:1610
@ JS_FORMAT_DEFAULT
Definition: primnodes.h:1608
@ JS_FORMAT_JSON
Definition: primnodes.h:1609
@ IS_LEAST
Definition: primnodes.h:1473
@ IS_GREATEST
Definition: primnodes.h:1472
@ TFT_XMLTABLE
Definition: primnodes.h:99
@ TFT_JSON_TABLE
Definition: primnodes.h:100
BoolExprType
Definition: primnodes.h:900
@ AND_EXPR
Definition: primnodes.h:901
@ OR_EXPR
Definition: primnodes.h:901
@ NOT_EXPR
Definition: primnodes.h:901
@ JS_ENC_DEFAULT
Definition: primnodes.h:1596
@ JS_ENC_UTF32
Definition: primnodes.h:1599
@ JS_ENC_UTF16
Definition: primnodes.h:1598
@ XMLOPTION_DOCUMENT
Definition: primnodes.h:1562
@ SVFOP_CURRENT_CATALOG
Definition: primnodes.h:1519
@ SVFOP_LOCALTIME_N
Definition: primnodes.h:1512
@ SVFOP_CURRENT_TIMESTAMP
Definition: primnodes.h:1509
@ SVFOP_LOCALTIME
Definition: primnodes.h:1511
@ SVFOP_CURRENT_TIMESTAMP_N
Definition: primnodes.h:1510
@ SVFOP_CURRENT_ROLE
Definition: primnodes.h:1515
@ SVFOP_USER
Definition: primnodes.h:1517
@ SVFOP_CURRENT_SCHEMA
Definition: primnodes.h:1520
@ SVFOP_LOCALTIMESTAMP_N
Definition: primnodes.h:1514
@ SVFOP_CURRENT_DATE
Definition: primnodes.h:1506
@ SVFOP_CURRENT_TIME_N
Definition: primnodes.h:1508
@ SVFOP_CURRENT_TIME
Definition: primnodes.h:1507
@ SVFOP_LOCALTIMESTAMP
Definition: primnodes.h:1513
@ SVFOP_CURRENT_USER
Definition: primnodes.h:1516
@ SVFOP_SESSION_USER
Definition: primnodes.h:1518
@ PARAM_MULTIEXPR
Definition: primnodes.h:370
@ PARAM_EXTERN
Definition: primnodes.h:367
@ PARAM_EXEC
Definition: primnodes.h:368
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1719
@ JSW_CONDITIONAL
Definition: primnodes.h:1718
@ JSW_UNSPEC
Definition: primnodes.h:1716
@ JSW_NONE
Definition: primnodes.h:1717
@ IS_DOCUMENT
Definition: primnodes.h:1557
@ IS_XMLFOREST
Definition: primnodes.h:1552
@ IS_XMLCONCAT
Definition: primnodes.h:1550
@ IS_XMLPI
Definition: primnodes.h:1554
@ IS_XMLPARSE
Definition: primnodes.h:1553
@ IS_XMLSERIALIZE
Definition: primnodes.h:1556
@ IS_XMLROOT
Definition: primnodes.h:1555
@ IS_XMLELEMENT
Definition: primnodes.h:1551
JsonBehaviorType
Definition: primnodes.h:1730
@ JSON_BEHAVIOR_ERROR
Definition: primnodes.h:1732
@ JSON_BEHAVIOR_DEFAULT
Definition: primnodes.h:1739
@ JSON_BEHAVIOR_EMPTY
Definition: primnodes.h:1733
@ JSON_BEHAVIOR_FALSE
Definition: primnodes.h:1735
@ JSON_BEHAVIOR_NULL
Definition: primnodes.h:1731
@ JSON_QUERY_OP
Definition: primnodes.h:1769
@ JSON_EXISTS_OP
Definition: primnodes.h:1768
@ JSON_VALUE_OP
Definition: primnodes.h:1770
CoercionForm
Definition: primnodes.h:703
@ COERCE_SQL_SYNTAX
Definition: primnodes.h:707
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:706
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:705
@ COERCE_EXPLICIT_CALL
Definition: primnodes.h:704
@ OVERRIDING_SYSTEM_VALUE
Definition: primnodes.h:29
@ OVERRIDING_USER_VALUE
Definition: primnodes.h:28
@ IS_NULL
Definition: primnodes.h:1924
@ IS_NOT_NULL
Definition: primnodes.h:1924
@ JS_TYPE_ARRAY
Definition: primnodes.h:1690
@ JS_TYPE_OBJECT
Definition: primnodes.h:1689
@ JS_TYPE_SCALAR
Definition: primnodes.h:1691
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition: primnodes.h:1970
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition: primnodes.h:1969
@ MERGE_WHEN_MATCHED
Definition: primnodes.h:1968
#define OUTER_VAR
Definition: primnodes.h:237
@ JSCTOR_JSON_SERIALIZE
Definition: primnodes.h:1662
@ JSCTOR_JSON_ARRAYAGG
Definition: primnodes.h:1659
@ JSCTOR_JSON_PARSE
Definition: primnodes.h:1660
@ JSCTOR_JSON_OBJECT
Definition: primnodes.h:1656
@ JSCTOR_JSON_SCALAR
Definition: primnodes.h:1661
@ JSCTOR_JSON_ARRAY
Definition: primnodes.h:1657
@ JSCTOR_JSON_OBJECTAGG
Definition: primnodes.h:1658
#define INNER_VAR
Definition: primnodes.h:236
#define INDEX_VAR
Definition: primnodes.h:238
tree context
Definition: radixtree.h:1829
tree ctl root
Definition: radixtree.h:1880
void * stringToNode(const char *str)
Definition: read.c:90
static SPIPlanPtr splan
Definition: regress.c:269
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
Definition: rewriteManip.c:998
#define ViewSelectRuleName
Datum pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:872
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags, int wrapColumn)
Definition: ruleutils.c:5372
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:8772
static bool looks_like_function(Node *node)
Definition: ruleutils.c:10321
Datum pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2080
static char * get_rtable_name(int rtindex, deparse_context *context)
Definition: ruleutils.c:4969
Datum pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
Definition: ruleutils.c:702
static int decompile_column_index_array(Datum column_index_array, Oid relId, bool withPeriod, StringInfo buf)
Definition: ruleutils.c:2601
static void set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4333
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:8718
Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1182
static void set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
Definition: ruleutils.c:4168
static Plan * find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
Definition: ruleutils.c:5069
static text * string_to_text(char *str)
Definition: ruleutils.c:13167
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5535
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3625
#define PRETTYINDENT_LIMIT
Definition: ruleutils.c:86
Datum pg_get_viewdef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:664
static char * make_colname_unique(char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition: ruleutils.c:4843
static void get_json_behavior(JsonBehavior *behavior, deparse_context *context, const char *on)
Definition: ruleutils.c:8809
static const char * get_simple_binary_op_name(OpExpr *expr)
Definition: ruleutils.c:8463
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Definition: ruleutils.c:11363
Datum pg_get_constraintdef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2130
static void set_deparse_for_query(deparse_namespace *dpns, Query *query, List *parent_namespaces)
Definition: ruleutils.c:3996
static void print_function_trftypes(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3438
void(* rsv_callback)(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:309
#define PRETTYINDENT_STD
Definition: ruleutils.c:82
char * pg_get_constraintdef_command(Oid constraintId)
Definition: ruleutils.c:2168
#define PRETTYINDENT_JOIN
Definition: ruleutils.c:83
static bool is_input_argument(int nth, const char *argmodes)
Definition: ruleutils.c:3426
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition: ruleutils.c:5457
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:12411
Datum pg_get_functiondef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2907
Datum pg_get_function_result(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3210
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12623
Datum pg_get_indexdef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1162
static void get_sublink_expr(SubLink *sublink, deparse_context *context)
Definition: ruleutils.c:11415
static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
Definition: ruleutils.c:12249
#define only_marker(rte)
Definition: ruleutils.c:535
Datum pg_get_function_arg_default(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3466
char * generate_opclass_name(Oid opclass)
Definition: ruleutils.c:12493
static void get_parameter(Param *param, deparse_context *context)
Definition: ruleutils.c:8326
Datum pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1822
Datum pg_get_ruledef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:545
static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11670
#define PRETTYFLAG_INDENT
Definition: ruleutils.c:90
List * deparse_context_for(const char *aliasname, Oid relid)
Definition: ruleutils.c:3685
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12320
Datum pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1621
Datum pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1592
static void simple_quote_literal(StringInfo buf, const char *val)
Definition: ruleutils.c:11388
static bool colname_is_unique(const char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition: ruleutils.c:4789
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12360
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:11864
static void get_basic_select_query(Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:5918
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:10744
static void get_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6052
Datum pg_get_partkeydef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1893
static char * generate_qualified_relation_name(Oid relid)
Definition: ruleutils.c:12807
static void set_simple_column_names(deparse_namespace *dpns)
Definition: ruleutils.c:4061
static void get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
Definition: ruleutils.c:8847
#define PRETTY_INDENT(context)
Definition: ruleutils.c:103
#define PRETTYFLAG_PAREN
Definition: ruleutils.c:89
static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context)
Definition: ruleutils.c:6379
static char * pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool keysOnly, bool showTblSpc, bool inherits, int prettyFlags, bool missing_ok)
Definition: ruleutils.c:1254
static char * pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags, bool missing_ok)
Definition: ruleutils.c:2177
static void get_rule_expr_funccall(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10298
static void expand_colnames_array_to(deparse_columns *colinfo, int n)
Definition: ruleutils.c:4882
static SubPlan * find_param_generator(Param *param, deparse_context *context, int *column_p)
Definition: ruleutils.c:8208
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:13071
static void get_special_variable(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:7559
static void get_select_query_def(Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:5717
static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context, const char *funcname, const char *options, bool is_json_objectagg)
Definition: ruleutils.c:10651
static void get_rule_list_toplevel(List *lst, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10268
char * pg_get_statisticsobjdef_string(Oid statextid)
Definition: ruleutils.c:1611
static char * pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
Definition: ruleutils.c:1638
#define deparse_columns_fetch(rangetable_index, dpns)
Definition: ruleutils.c:296
static void get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11267
static const char *const query_getrulebyoid
Definition: ruleutils.c:318
static char * generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind)
Definition: ruleutils.c:12849
static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11210
static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
Definition: ruleutils.c:12593
static SubPlan * find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
Definition: ruleutils.c:8305
static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5167
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:13135
static void get_rule_expr_paren(Node *node, deparse_context *context, bool showimplicit, Node *parentNode)
Definition: ruleutils.c:8791
bool quote_all_identifiers
Definition: ruleutils.c:323
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:10486
static void get_const_collation(Const *constval, deparse_context *context)
Definition: ruleutils.c:11190
static void get_delete_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7064
static SPIPlanPtr plan_getrulebyoid
Definition: ruleutils.c:317
static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan, deparse_context *context, bool showimplicit, bool needcomma)
Definition: ruleutils.c:11638
static char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
Definition: ruleutils.c:3652
Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:563
static void print_function_sqlbody(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3536
static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
Definition: ruleutils.c:4102
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6322
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3822
char * pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
Definition: ruleutils.c:2112
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:12707
static char * pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
Definition: ruleutils.c:775
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell, deparse_namespace *save_dpns)
Definition: ruleutils.c:5146
static SPIPlanPtr plan_getviewrule
Definition: ruleutils.c:319
char * pg_get_partkeydef_columns(Oid relid, bool pretty)
Definition: ruleutils.c:1908
#define WRAP_COLUMN_DEFAULT
Definition: ruleutils.c:99
static char * flatten_reloptions(Oid relid)
Definition: ruleutils.c:13235
static text * pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
Definition: ruleutils.c:2690
List * set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
Definition: ruleutils.c:3799
static Node * processIndirection(Node *node, deparse_context *context)
Definition: ruleutils.c:12515
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:10624
#define PRETTY_PAREN(context)
Definition: ruleutils.c:102
Datum pg_get_triggerdef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:858
Datum pg_get_function_sqlbody(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3590
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2655
static char * generate_qualified_type_name(Oid typid)
Definition: ruleutils.c:13102
static void get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11540
char * pg_get_indexdef_columns_extended(Oid indexrelid, bits16 flags)
Definition: ruleutils.c:1233
static void get_utility_query_def(Query *query, deparse_context *context)
Definition: ruleutils.c:7280
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:12727
Datum pg_get_expr_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2672
char * get_list_partvalue_string(Const *val)
Definition: ruleutils.c:13308
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6497
static void get_rule_windowspec(WindowClause *wc, List *targetList, deparse_context *context)
Definition: ruleutils.c:6529
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Definition: ruleutils.c:11247
Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:747
static Node * find_param_referent(Param *param, deparse_context *context, deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
Definition: ruleutils.c:8094
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6439
static void pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5116
static const char * get_name_for_var_field(Var *var, int fieldno, int levelsup, deparse_context *context)
Definition: ruleutils.c:7688
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4529
Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2147
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used)
Definition: ruleutils.c:3851
static void get_update_query_targetlist_def(Query *query, List *targetList, deparse_context *context, RangeTblEntry *rte)
Definition: ruleutils.c:6912
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:8888
Datum pg_get_viewdef_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:683
static char * pg_get_partkeydef_worker(Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
Definition: ruleutils.c:1921
static void get_oper_expr(OpExpr *expr, deparse_context *context)
Definition: ruleutils.c:10350
char * pg_get_querydef(Query *query, bool pretty)
Definition: ruleutils.c:1572
Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3185
static char * pg_get_triggerdef_worker(Oid trigid, bool pretty)
Definition: ruleutils.c:887
#define GET_PRETTY_FLAGS(pretty)
Definition: ruleutils.c:94
static void get_reloptions(StringInfo buf, Datum reloptions)
Definition: ruleutils.c:13180
static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10390
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:11060
void generate_operator_clause(StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
Definition: ruleutils.c:13031
static void get_setop_query(Node *setOp, Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6188
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
Definition: ruleutils.c:5183
static const char *const query_getviewrule
Definition: ruleutils.c:320
static char * pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
Definition: ruleutils.c:582
static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults)
Definition: ruleutils.c:3278
static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte, deparse_columns *colinfo)
Definition: ruleutils.c:4901
char * pg_get_indexdef_columns(Oid indexrelid, bool pretty)
Definition: ruleutils.c:1219
static void print_function_rettype(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3240
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:5849
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan)
Definition: ruleutils.c:4988
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7580
static void get_merge_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7116
static void get_json_format(JsonFormat *format, StringInfo buf)
Definition: ruleutils.c:11222
static void get_insert_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6638
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11845
static void get_rule_expr_toplevel(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10250
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:10996
static void push_child_plan(deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
Definition: ruleutils.c:5099
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
Definition: ruleutils.c:11333
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:13268
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
Definition: ruleutils.c:8489
static void get_with_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:5578
char * pg_get_indexdef_string(Oid indexrelid)
Definition: ruleutils.c:1209
#define PRETTYINDENT_VAR
Definition: ruleutils.c:84
List * deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
Definition: ruleutils.c:3730
static void get_update_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6855
static char * generate_relation_name(Oid relid, List *namespaces)
Definition: ruleutils.c:12747
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
Definition: ruleutils.c:10640
static char * get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
Definition: ruleutils.c:7325
Datum pg_get_serial_sequence(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2813
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
Definition: ruleutils.c:12954
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:11958
Datum pg_get_function_arguments(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3159
static void get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11776
#define PRETTYFLAG_SCHEMA
Definition: ruleutils.c:91
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:12455
Datum pg_get_viewdef_name(PG_FUNCTION_ARGS)
Definition: ruleutils.c:722
Datum pg_get_userbyid(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2775
static void get_agg_expr_helper(Aggref *aggref, deparse_context *context, Aggref *original_aggref, const char *funcname, const char *options, bool is_json_objectagg)
Definition: ruleutils.c:10498
#define RULE_INDEXDEF_PRETTY
Definition: ruleutils.h:24
#define RULE_INDEXDEF_KEYS_ONLY
Definition: ruleutils.h:25
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition: spi.c:1172
uint64 SPI_processed
Definition: spi.c:44
SPITupleTable * SPI_tuptable
Definition: spi.c:45
int SPI_connect(void)
Definition: spi.c:94
int SPI_finish(void)
Definition: spi.c:182
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:669
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:857
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:973
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:1217
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1249
#define SPI_OK_CONNECT
Definition: spi.h:82
#define SPI_OK_FINISH
Definition: spi.h:83
#define SPI_OK_SELECT
Definition: spi.h:86
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
#define BTEqualStrategyNumber
Definition: stratnum.h:31
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:78
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:212
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Oid aggfnoid
Definition: primnodes.h:444
List * aggdistinct
Definition: primnodes.h:474
List * aggdirectargs
Definition: primnodes.h:465
List * args
Definition: primnodes.h:468
Expr * aggfilter
Definition: primnodes.h:477
List * aggorder
Definition: primnodes.h:471
Index child_relid
Definition: pathnodes.h:2958
Index parent_relid
Definition: pathnodes.h:2957
int num_child_cols
Definition: pathnodes.h:2993
List * elements
Definition: primnodes.h:1350
BoolExprType boolop
Definition: primnodes.h:909
List * args
Definition: primnodes.h:910
BoolTestType booltesttype
Definition: primnodes.h:1955
Expr * arg
Definition: primnodes.h:1954
Expr * arg
Definition: primnodes.h:1283
Expr * defresult
Definition: primnodes.h:1285
List * args
Definition: primnodes.h:1284
List * args
Definition: primnodes.h:1462
Expr * arg
Definition: primnodes.h:1177
Oid resulttype
Definition: primnodes.h:1178
Expr * arg
Definition: primnodes.h:1249
CTEMaterialize ctematerialized
Definition: parsenodes.h:1684
Oid consttype
Definition: primnodes.h:312
char * cursor_name
Definition: primnodes.h:2068
AttrNumber fieldnum
Definition: primnodes.h:1099
Expr * arg
Definition: primnodes.h:1098
List * newvals
Definition: primnodes.h:1130
Node * quals
Definition: primnodes.h:2279
List * fromlist
Definition: primnodes.h:2278
Oid funcid
Definition: primnodes.h:720
List * args
Definition: primnodes.h:738
List * content
Definition: parsenodes.h:1513
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
bool amcanorder
Definition: amapi.h:223
Node * expr
Definition: primnodes.h:1757
JsonBehaviorType btype
Definition: primnodes.h:1756
JsonReturning * returning
Definition: primnodes.h:1676
JsonConstructorType type
Definition: primnodes.h:1672
Node * formatted_expr
Definition: primnodes.h:1789
List * passing_values
Definition: primnodes.h:1802
JsonBehavior * on_empty
Definition: primnodes.h:1805
JsonFormat * format
Definition: primnodes.h:1792
List * passing_names
Definition: primnodes.h:1801
Node * path_spec
Definition: primnodes.h:1795
JsonReturning * returning
Definition: primnodes.h:1798
JsonWrapper wrapper
Definition: primnodes.h:1822
JsonExprOp op
Definition: primnodes.h:1783
JsonBehavior * on_error
Definition: primnodes.h:1806
bool omit_quotes
Definition: primnodes.h:1825
JsonFormatType format_type
Definition: primnodes.h:1621
JsonValueType item_type
Definition: primnodes.h:1703
JsonFormat * format
Definition: primnodes.h:1633
JsonTablePath * path
Definition: primnodes.h:1870
JsonTablePlan * child
Definition: primnodes.h:1879
Const * value
Definition: primnodes.h:1843
JsonTablePlan * rplan
Definition: primnodes.h:1900
JsonTablePlan * lplan
Definition: primnodes.h:1899
JsonFormat * format
Definition: primnodes.h:1651
Expr * raw_expr
Definition: primnodes.h:1649
Definition: pg_list.h:54
List * args
Definition: primnodes.h:1488
MinMaxOp op
Definition: primnodes.h:1486
Expr * arg
Definition: primnodes.h:761
Var * paramval
Definition: plannodes.h:819
List * nestParams
Definition: plannodes.h:810
Definition: nodes.h:129
NullTestType nulltesttype
Definition: primnodes.h:1931
Expr * arg
Definition: primnodes.h:1930
List * arbiterElems
Definition: primnodes.h:2297
OnConflictAction action
Definition: primnodes.h:2294
List * onConflictSet
Definition: primnodes.h:2303
Node * onConflictWhere
Definition: primnodes.h:2304
Node * arbiterWhere
Definition: primnodes.h:2299
Oid opno
Definition: primnodes.h:788
List * args
Definition: primnodes.h:806
int paramid
Definition: primnodes.h:377
ParamKind paramkind
Definition: primnodes.h:376
PartitionRangeDatumKind kind
Definition: parsenodes.h:933
List * targetlist
Definition: plannodes.h:152
List * appendRelations
Definition: plannodes.h:80
List * subplans
Definition: plannodes.h:82
List * rtable
Definition: plannodes.h:72
List * rowMarks
Definition: parsenodes.h:217
bool groupDistinct
Definition: parsenodes.h:201
Node * mergeJoinCondition
Definition: parsenodes.h:189
Node * limitCount
Definition: parsenodes.h:214
FromExpr * jointree
Definition: parsenodes.h:175
List * returningList
Definition: parsenodes.h:198
Node * setOperations
Definition: parsenodes.h:219
List * cteList
Definition: parsenodes.h:166
OnConflictExpr * onConflict
Definition: parsenodes.h:196
List * groupClause
Definition: parsenodes.h:200
Node * havingQual
Definition: parsenodes.h:205
List * rtable
Definition: parsenodes.h:168
Node * limitOffset
Definition: parsenodes.h:213
CmdType commandType
Definition: parsenodes.h:121
LimitOption limitOption
Definition: parsenodes.h:215
Node * utilityStmt
Definition: parsenodes.h:136
List * mergeActionList
Definition: parsenodes.h:178
List * windowClause
Definition: parsenodes.h:207
List * targetList
Definition: parsenodes.h:191
List * groupingSets
Definition: parsenodes.h:203
List * distinctClause
Definition: parsenodes.h:209
List * sortClause
Definition: parsenodes.h:211
char * ctename
Definition: parsenodes.h:1206
TableFunc * tablefunc
Definition: parsenodes.h:1194
Index ctelevelsup
Definition: parsenodes.h:1208
bool funcordinality
Definition: parsenodes.h:1189
struct TableSampleClause * tablesample
Definition: parsenodes.h:1108
Query * subquery
Definition: parsenodes.h:1114
List * values_lists
Definition: parsenodes.h:1200
List * functions
Definition: parsenodes.h:1187
RTEKind rtekind
Definition: parsenodes.h:1057
char * relname
Definition: primnodes.h:82
Oid resulttype
Definition: primnodes.h:1155
Expr * arg
Definition: primnodes.h:1154
TupleDesc rd_att
Definition: rel.h:112
List * args
Definition: primnodes.h:1381
LockClauseStrength strength
Definition: parsenodes.h:1585
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1586
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
SQLValueFunctionOp op
Definition: primnodes.h:1526
SetOperation op
Definition: parsenodes.h:2193
Index tleSortGroupRef
Definition: parsenodes.h:1442
Definition: value.h:64
char * plan_name
Definition: primnodes.h:1042
List * args
Definition: primnodes.h:1061
List * paramIds
Definition: primnodes.h:1038
bool useHashTable
Definition: primnodes.h:1049
Node * testexpr
Definition: primnodes.h:1037
List * parParam
Definition: primnodes.h:1060
List * setParam
Definition: primnodes.h:1058
SubLinkType subLinkType
Definition: primnodes.h:1035
Expr * refassgnexpr
Definition: primnodes.h:673
List * refupperindexpr
Definition: primnodes.h:663
Expr * refexpr
Definition: primnodes.h:671
List * reflowerindexpr
Definition: primnodes.h:669
Node * docexpr
Definition: primnodes.h:119
Node * rowexpr
Definition: primnodes.h:121
List * colexprs
Definition: primnodes.h:131
TableFuncType functype
Definition: primnodes.h:113
Expr * expr
Definition: primnodes.h:2160
AttrNumber resno
Definition: primnodes.h:2162
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
Node * startOffset
Definition: parsenodes.h:1550
List * partitionClause
Definition: parsenodes.h:1546
Node * endOffset
Definition: parsenodes.h:1551
List * orderClause
Definition: parsenodes.h:1548
List * args
Definition: primnodes.h:575
Index winref
Definition: primnodes.h:579
Expr * aggfilter
Definition: primnodes.h:577
Oid winfnoid
Definition: primnodes.h:567
List * args
Definition: primnodes.h:1578
List * named_args
Definition: primnodes.h:1574
XmlExprOp op
Definition: primnodes.h:1570
List * parentUsing
Definition: ruleutils.c:269
char ** new_colnames
Definition: ruleutils.c:262
char ** colnames
Definition: ruleutils.c:245
int * rightattnos
Definition: ruleutils.c:291
List * usingNames
Definition: ruleutils.c:292
bool * is_new_col
Definition: ruleutils.c:263
int * leftattnos
Definition: ruleutils.c:290
StringInfo buf
Definition: ruleutils.c:115
List * namespaces
Definition: ruleutils.c:116
List * windowClause
Definition: ruleutils.c:117
List * windowTList
Definition: ruleutils.c:118
Bitmapset * appendparents
Definition: ruleutils.c:125
ParseExprKind special_exprkind
Definition: ruleutils.c:123
List * rtable_names
Definition: ruleutils.c:164
List * inner_tlist
Definition: ruleutils.c:178
List * outer_tlist
Definition: ruleutils.c:177
char ** argnames
Definition: ruleutils.c:183
AppendRelInfo ** appendrels
Definition: ruleutils.c:168
List * rtable_columns
Definition: ruleutils.c:165
List * index_tlist
Definition: ruleutils.c:179
List * using_names
Definition: ruleutils.c:171
Definition: c.h:715
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:722
Definition: c.h:741
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733
Definition: c.h:687
Definition: type.h:88
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46
TargetEntry * get_sortgroupref_tle(Index sortref, List *targetList)
Definition: tlist.c:345
int count_nonjunk_tlist_entries(List *tlist)
Definition: tlist.c:186
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1833
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:346
#define TYPECACHE_GT_OPR
Definition: typcache.h:139
#define TYPECACHE_LT_OPR
Definition: typcache.h:138
String * makeString(char *str)
Definition: value.c:63
#define strVal(v)
Definition: value.h:82
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:108
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3399
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3705
char * text_to_cstring(const text *t)
Definition: varlena.c:217
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196
text * cstring_to_text(const char *s)
Definition: varlena.c:184
const char * type
const char * name
char * map_xml_name_to_sql_identifier(const char *name)
Definition: xml.c:2371
@ XML_STANDALONE_NO_VALUE
Definition: xml.h:29
@ XML_STANDALONE_YES
Definition: xml.h:27
@ XML_STANDALONE_NO
Definition: xml.h:28
static void convert(const int32 val, char *const buf)
Definition: zic.c:1992