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  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  decompile_column_index_array(val, conForm->conrelid, &buf);
2264 
2265  /* add foreign relation name */
2266  appendStringInfo(&buf, ") REFERENCES %s(",
2267  generate_relation_name(conForm->confrelid,
2268  NIL));
2269 
2270  /* Fetch and build referenced-column list */
2271  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2272  Anum_pg_constraint_confkey);
2273 
2274  decompile_column_index_array(val, conForm->confrelid, &buf);
2275 
2276  appendStringInfoChar(&buf, ')');
2277 
2278  /* Add match type */
2279  switch (conForm->confmatchtype)
2280  {
2281  case FKCONSTR_MATCH_FULL:
2282  string = " MATCH FULL";
2283  break;
2285  string = " MATCH PARTIAL";
2286  break;
2287  case FKCONSTR_MATCH_SIMPLE:
2288  string = "";
2289  break;
2290  default:
2291  elog(ERROR, "unrecognized confmatchtype: %d",
2292  conForm->confmatchtype);
2293  string = ""; /* keep compiler quiet */
2294  break;
2295  }
2296  appendStringInfoString(&buf, string);
2297 
2298  /* Add ON UPDATE and ON DELETE clauses, if needed */
2299  switch (conForm->confupdtype)
2300  {
2302  string = NULL; /* suppress default */
2303  break;
2305  string = "RESTRICT";
2306  break;
2308  string = "CASCADE";
2309  break;
2311  string = "SET NULL";
2312  break;
2314  string = "SET DEFAULT";
2315  break;
2316  default:
2317  elog(ERROR, "unrecognized confupdtype: %d",
2318  conForm->confupdtype);
2319  string = NULL; /* keep compiler quiet */
2320  break;
2321  }
2322  if (string)
2323  appendStringInfo(&buf, " ON UPDATE %s", string);
2324 
2325  switch (conForm->confdeltype)
2326  {
2328  string = NULL; /* suppress default */
2329  break;
2331  string = "RESTRICT";
2332  break;
2334  string = "CASCADE";
2335  break;
2337  string = "SET NULL";
2338  break;
2340  string = "SET DEFAULT";
2341  break;
2342  default:
2343  elog(ERROR, "unrecognized confdeltype: %d",
2344  conForm->confdeltype);
2345  string = NULL; /* keep compiler quiet */
2346  break;
2347  }
2348  if (string)
2349  appendStringInfo(&buf, " ON DELETE %s", string);
2350 
2351  /*
2352  * Add columns specified to SET NULL or SET DEFAULT if
2353  * provided.
2354  */
2355  val = SysCacheGetAttr(CONSTROID, tup,
2356  Anum_pg_constraint_confdelsetcols, &isnull);
2357  if (!isnull)
2358  {
2359  appendStringInfoString(&buf, " (");
2360  decompile_column_index_array(val, conForm->conrelid, &buf);
2361  appendStringInfoChar(&buf, ')');
2362  }
2363 
2364  break;
2365  }
2366  case CONSTRAINT_PRIMARY:
2367  case CONSTRAINT_UNIQUE:
2368  {
2369  Datum val;
2370  Oid indexId;
2371  int keyatts;
2372  HeapTuple indtup;
2373 
2374  /* Start off the constraint definition */
2375  if (conForm->contype == CONSTRAINT_PRIMARY)
2376  appendStringInfoString(&buf, "PRIMARY KEY ");
2377  else
2378  appendStringInfoString(&buf, "UNIQUE ");
2379 
2380  indexId = conForm->conindid;
2381 
2382  indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2383  if (!HeapTupleIsValid(indtup))
2384  elog(ERROR, "cache lookup failed for index %u", indexId);
2385  if (conForm->contype == CONSTRAINT_UNIQUE &&
2386  ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2387  appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2388 
2389  appendStringInfoChar(&buf, '(');
2390 
2391  /* Fetch and build target column list */
2392  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2393  Anum_pg_constraint_conkey);
2394 
2395  keyatts = decompile_column_index_array(val, conForm->conrelid, &buf);
2396 
2397  appendStringInfoChar(&buf, ')');
2398 
2399  /* Build including column list (from pg_index.indkeys) */
2400  val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2401  Anum_pg_index_indnatts);
2402  if (DatumGetInt32(val) > keyatts)
2403  {
2404  Datum cols;
2405  Datum *keys;
2406  int nKeys;
2407  int j;
2408 
2409  appendStringInfoString(&buf, " INCLUDE (");
2410 
2411  cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2412  Anum_pg_index_indkey);
2413 
2415  &keys, NULL, &nKeys);
2416 
2417  for (j = keyatts; j < nKeys; j++)
2418  {
2419  char *colName;
2420 
2421  colName = get_attname(conForm->conrelid,
2422  DatumGetInt16(keys[j]), false);
2423  if (j > keyatts)
2424  appendStringInfoString(&buf, ", ");
2426  }
2427 
2428  appendStringInfoChar(&buf, ')');
2429  }
2430  ReleaseSysCache(indtup);
2431 
2432  /* XXX why do we only print these bits if fullCommand? */
2433  if (fullCommand && OidIsValid(indexId))
2434  {
2435  char *options = flatten_reloptions(indexId);
2436  Oid tblspc;
2437 
2438  if (options)
2439  {
2440  appendStringInfo(&buf, " WITH (%s)", options);
2441  pfree(options);
2442  }
2443 
2444  /*
2445  * Print the tablespace, unless it's the database default.
2446  * This is to help ALTER TABLE usage of this facility,
2447  * which needs this behavior to recreate exact catalog
2448  * state.
2449  */
2450  tblspc = get_rel_tablespace(indexId);
2451  if (OidIsValid(tblspc))
2452  appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2454  }
2455 
2456  break;
2457  }
2458  case CONSTRAINT_CHECK:
2459  {
2460  Datum val;
2461  char *conbin;
2462  char *consrc;
2463  Node *expr;
2464  List *context;
2465 
2466  /* Fetch constraint expression in parsetree form */
2467  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2468  Anum_pg_constraint_conbin);
2469 
2470  conbin = TextDatumGetCString(val);
2471  expr = stringToNode(conbin);
2472 
2473  /* Set up deparsing context for Var nodes in constraint */
2474  if (conForm->conrelid != InvalidOid)
2475  {
2476  /* relation constraint */
2477  context = deparse_context_for(get_relation_name(conForm->conrelid),
2478  conForm->conrelid);
2479  }
2480  else
2481  {
2482  /* domain constraint --- can't have Vars */
2483  context = NIL;
2484  }
2485 
2486  consrc = deparse_expression_pretty(expr, context, false, false,
2487  prettyFlags, 0);
2488 
2489  /*
2490  * Now emit the constraint definition, adding NO INHERIT if
2491  * necessary.
2492  *
2493  * There are cases where the constraint expression will be
2494  * fully parenthesized and we don't need the outer parens ...
2495  * but there are other cases where we do need 'em. Be
2496  * conservative for now.
2497  *
2498  * Note that simply checking for leading '(' and trailing ')'
2499  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2500  */
2501  appendStringInfo(&buf, "CHECK (%s)%s",
2502  consrc,
2503  conForm->connoinherit ? " NO INHERIT" : "");
2504  break;
2505  }
2506  case CONSTRAINT_TRIGGER:
2507 
2508  /*
2509  * There isn't an ALTER TABLE syntax for creating a user-defined
2510  * constraint trigger, but it seems better to print something than
2511  * throw an error; if we throw error then this function couldn't
2512  * safely be applied to all rows of pg_constraint.
2513  */
2514  appendStringInfoString(&buf, "TRIGGER");
2515  break;
2516  case CONSTRAINT_EXCLUSION:
2517  {
2518  Oid indexOid = conForm->conindid;
2519  Datum val;
2520  Datum *elems;
2521  int nElems;
2522  int i;
2523  Oid *operators;
2524 
2525  /* Extract operator OIDs from the pg_constraint tuple */
2526  val = SysCacheGetAttrNotNull(CONSTROID, tup,
2527  Anum_pg_constraint_conexclop);
2528 
2530  &elems, NULL, &nElems);
2531 
2532  operators = (Oid *) palloc(nElems * sizeof(Oid));
2533  for (i = 0; i < nElems; i++)
2534  operators[i] = DatumGetObjectId(elems[i]);
2535 
2536  /* pg_get_indexdef_worker does the rest */
2537  /* suppress tablespace because pg_dump wants it that way */
2539  pg_get_indexdef_worker(indexOid,
2540  0,
2541  operators,
2542  false,
2543  false,
2544  false,
2545  false,
2546  prettyFlags,
2547  false));
2548  break;
2549  }
2550  default:
2551  elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2552  break;
2553  }
2554 
2555  if (conForm->condeferrable)
2556  appendStringInfoString(&buf, " DEFERRABLE");
2557  if (conForm->condeferred)
2558  appendStringInfoString(&buf, " INITIALLY DEFERRED");
2559  if (!conForm->convalidated)
2560  appendStringInfoString(&buf, " NOT VALID");
2561 
2562  /* Cleanup */
2563  systable_endscan(scandesc);
2564  table_close(relation, AccessShareLock);
2565 
2566  return buf.data;
2567 }
2568 
2569 
2570 /*
2571  * Convert an int16[] Datum into a comma-separated list of column names
2572  * for the indicated relation; append the list to buf. Returns the number
2573  * of keys.
2574  */
2575 static int
2576 decompile_column_index_array(Datum column_index_array, Oid relId,
2577  StringInfo buf)
2578 {
2579  Datum *keys;
2580  int nKeys;
2581  int j;
2582 
2583  /* Extract data from array of int16 */
2584  deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2585  &keys, NULL, &nKeys);
2586 
2587  for (j = 0; j < nKeys; j++)
2588  {
2589  char *colName;
2590 
2591  colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2592 
2593  if (j == 0)
2595  else
2596  appendStringInfo(buf, ", %s", quote_identifier(colName));
2597  }
2598 
2599  return nKeys;
2600 }
2601 
2602 
2603 /* ----------
2604  * pg_get_expr - Decompile an expression tree
2605  *
2606  * Input: an expression tree in nodeToString form, and a relation OID
2607  *
2608  * Output: reverse-listed expression
2609  *
2610  * Currently, the expression can only refer to a single relation, namely
2611  * the one specified by the second parameter. This is sufficient for
2612  * partial indexes, column default expressions, etc. We also support
2613  * Var-free expressions, for which the OID can be InvalidOid.
2614  *
2615  * If the OID is nonzero but not actually valid, don't throw an error,
2616  * just return NULL. This is a bit questionable, but it's what we've
2617  * done historically, and it can help avoid unwanted failures when
2618  * examining catalog entries for just-deleted relations.
2619  *
2620  * We expect this function to work, or throw a reasonably clean error,
2621  * for any node tree that can appear in a catalog pg_node_tree column.
2622  * Query trees, such as those appearing in pg_rewrite.ev_action, are
2623  * not supported. Nor are expressions in more than one relation, which
2624  * can appear in places like pg_rewrite.ev_qual.
2625  * ----------
2626  */
2627 Datum
2629 {
2630  text *expr = PG_GETARG_TEXT_PP(0);
2631  Oid relid = PG_GETARG_OID(1);
2632  text *result;
2633  int prettyFlags;
2634 
2635  prettyFlags = PRETTYFLAG_INDENT;
2636 
2637  result = pg_get_expr_worker(expr, relid, prettyFlags);
2638  if (result)
2639  PG_RETURN_TEXT_P(result);
2640  else
2641  PG_RETURN_NULL();
2642 }
2643 
2644 Datum
2646 {
2647  text *expr = PG_GETARG_TEXT_PP(0);
2648  Oid relid = PG_GETARG_OID(1);
2649  bool pretty = PG_GETARG_BOOL(2);
2650  text *result;
2651  int prettyFlags;
2652 
2653  prettyFlags = GET_PRETTY_FLAGS(pretty);
2654 
2655  result = pg_get_expr_worker(expr, relid, prettyFlags);
2656  if (result)
2657  PG_RETURN_TEXT_P(result);
2658  else
2659  PG_RETURN_NULL();
2660 }
2661 
2662 static text *
2663 pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
2664 {
2665  Node *node;
2666  Node *tst;
2667  Relids relids;
2668  List *context;
2669  char *exprstr;
2670  Relation rel = NULL;
2671  char *str;
2672 
2673  /* Convert input pg_node_tree (really TEXT) object to C string */
2674  exprstr = text_to_cstring(expr);
2675 
2676  /* Convert expression to node tree */
2677  node = (Node *) stringToNode(exprstr);
2678 
2679  pfree(exprstr);
2680 
2681  /*
2682  * Throw error if the input is a querytree rather than an expression tree.
2683  * While we could support queries here, there seems no very good reason
2684  * to. In most such catalog columns, we'll see a List of Query nodes, or
2685  * even nested Lists, so drill down to a non-List node before checking.
2686  */
2687  tst = node;
2688  while (tst && IsA(tst, List))
2689  tst = linitial((List *) tst);
2690  if (tst && IsA(tst, Query))
2691  ereport(ERROR,
2692  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2693  errmsg("input is a query, not an expression")));
2694 
2695  /*
2696  * Throw error if the expression contains Vars we won't be able to
2697  * deparse.
2698  */
2699  relids = pull_varnos(NULL, node);
2700  if (OidIsValid(relid))
2701  {
2702  if (!bms_is_subset(relids, bms_make_singleton(1)))
2703  ereport(ERROR,
2704  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2705  errmsg("expression contains variables of more than one relation")));
2706  }
2707  else
2708  {
2709  if (!bms_is_empty(relids))
2710  ereport(ERROR,
2711  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2712  errmsg("expression contains variables")));
2713  }
2714 
2715  /*
2716  * Prepare deparse context if needed. If we are deparsing with a relid,
2717  * we need to transiently open and lock the rel, to make sure it won't go
2718  * away underneath us. (set_relation_column_names would lock it anyway,
2719  * so this isn't really introducing any new behavior.)
2720  */
2721  if (OidIsValid(relid))
2722  {
2723  rel = try_relation_open(relid, AccessShareLock);
2724  if (rel == NULL)
2725  return NULL;
2727  }
2728  else
2729  context = NIL;
2730 
2731  /* Deparse */
2732  str = deparse_expression_pretty(node, context, false, false,
2733  prettyFlags, 0);
2734 
2735  if (rel != NULL)
2737 
2738  return string_to_text(str);
2739 }
2740 
2741 
2742 /* ----------
2743  * pg_get_userbyid - Get a user name by roleid and
2744  * fallback to 'unknown (OID=n)'
2745  * ----------
2746  */
2747 Datum
2749 {
2750  Oid roleid = PG_GETARG_OID(0);
2751  Name result;
2752  HeapTuple roletup;
2753  Form_pg_authid role_rec;
2754 
2755  /*
2756  * Allocate space for the result
2757  */
2758  result = (Name) palloc(NAMEDATALEN);
2759  memset(NameStr(*result), 0, NAMEDATALEN);
2760 
2761  /*
2762  * Get the pg_authid entry and print the result
2763  */
2764  roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2765  if (HeapTupleIsValid(roletup))
2766  {
2767  role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2768  *result = role_rec->rolname;
2769  ReleaseSysCache(roletup);
2770  }
2771  else
2772  sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2773 
2774  PG_RETURN_NAME(result);
2775 }
2776 
2777 
2778 /*
2779  * pg_get_serial_sequence
2780  * Get the name of the sequence used by an identity or serial column,
2781  * formatted suitably for passing to setval, nextval or currval.
2782  * First parameter is not treated as double-quoted, second parameter
2783  * is --- see documentation for reason.
2784  */
2785 Datum
2787 {
2788  text *tablename = PG_GETARG_TEXT_PP(0);
2789  text *columnname = PG_GETARG_TEXT_PP(1);
2790  RangeVar *tablerv;
2791  Oid tableOid;
2792  char *column;
2794  Oid sequenceId = InvalidOid;
2795  Relation depRel;
2796  ScanKeyData key[3];
2797  SysScanDesc scan;
2798  HeapTuple tup;
2799 
2800  /* Look up table name. Can't lock it - we might not have privileges. */
2801  tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2802  tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2803 
2804  /* Get the number of the column */
2805  column = text_to_cstring(columnname);
2806 
2807  attnum = get_attnum(tableOid, column);
2808  if (attnum == InvalidAttrNumber)
2809  ereport(ERROR,
2810  (errcode(ERRCODE_UNDEFINED_COLUMN),
2811  errmsg("column \"%s\" of relation \"%s\" does not exist",
2812  column, tablerv->relname)));
2813 
2814  /* Search the dependency table for the dependent sequence */
2815  depRel = table_open(DependRelationId, AccessShareLock);
2816 
2817  ScanKeyInit(&key[0],
2818  Anum_pg_depend_refclassid,
2819  BTEqualStrategyNumber, F_OIDEQ,
2820  ObjectIdGetDatum(RelationRelationId));
2821  ScanKeyInit(&key[1],
2822  Anum_pg_depend_refobjid,
2823  BTEqualStrategyNumber, F_OIDEQ,
2824  ObjectIdGetDatum(tableOid));
2825  ScanKeyInit(&key[2],
2826  Anum_pg_depend_refobjsubid,
2827  BTEqualStrategyNumber, F_INT4EQ,
2829 
2830  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2831  NULL, 3, key);
2832 
2833  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2834  {
2835  Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2836 
2837  /*
2838  * Look for an auto dependency (serial column) or internal dependency
2839  * (identity column) of a sequence on a column. (We need the relkind
2840  * test because indexes can also have auto dependencies on columns.)
2841  */
2842  if (deprec->classid == RelationRelationId &&
2843  deprec->objsubid == 0 &&
2844  (deprec->deptype == DEPENDENCY_AUTO ||
2845  deprec->deptype == DEPENDENCY_INTERNAL) &&
2846  get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2847  {
2848  sequenceId = deprec->objid;
2849  break;
2850  }
2851  }
2852 
2853  systable_endscan(scan);
2854  table_close(depRel, AccessShareLock);
2855 
2856  if (OidIsValid(sequenceId))
2857  {
2858  char *result;
2859 
2860  result = generate_qualified_relation_name(sequenceId);
2861 
2863  }
2864 
2865  PG_RETURN_NULL();
2866 }
2867 
2868 
2869 /*
2870  * pg_get_functiondef
2871  * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2872  * the specified function.
2873  *
2874  * Note: if you change the output format of this function, be careful not
2875  * to break psql's rules (in \ef and \sf) for identifying the start of the
2876  * function body. To wit: the function body starts on a line that begins with
2877  * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
2878  */
2879 Datum
2881 {
2882  Oid funcid = PG_GETARG_OID(0);
2884  StringInfoData dq;
2885  HeapTuple proctup;
2886  Form_pg_proc proc;
2887  bool isfunction;
2888  Datum tmp;
2889  bool isnull;
2890  const char *prosrc;
2891  const char *name;
2892  const char *nsp;
2893  float4 procost;
2894  int oldlen;
2895 
2896  initStringInfo(&buf);
2897 
2898  /* Look up the function */
2899  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2900  if (!HeapTupleIsValid(proctup))
2901  PG_RETURN_NULL();
2902 
2903  proc = (Form_pg_proc) GETSTRUCT(proctup);
2904  name = NameStr(proc->proname);
2905 
2906  if (proc->prokind == PROKIND_AGGREGATE)
2907  ereport(ERROR,
2908  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2909  errmsg("\"%s\" is an aggregate function", name)));
2910 
2911  isfunction = (proc->prokind != PROKIND_PROCEDURE);
2912 
2913  /*
2914  * We always qualify the function name, to ensure the right function gets
2915  * replaced.
2916  */
2917  nsp = get_namespace_name_or_temp(proc->pronamespace);
2918  appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2919  isfunction ? "FUNCTION" : "PROCEDURE",
2921  (void) print_function_arguments(&buf, proctup, false, true);
2922  appendStringInfoString(&buf, ")\n");
2923  if (isfunction)
2924  {
2925  appendStringInfoString(&buf, " RETURNS ");
2926  print_function_rettype(&buf, proctup);
2927  appendStringInfoChar(&buf, '\n');
2928  }
2929 
2930  print_function_trftypes(&buf, proctup);
2931 
2932  appendStringInfo(&buf, " LANGUAGE %s\n",
2933  quote_identifier(get_language_name(proc->prolang, false)));
2934 
2935  /* Emit some miscellaneous options on one line */
2936  oldlen = buf.len;
2937 
2938  if (proc->prokind == PROKIND_WINDOW)
2939  appendStringInfoString(&buf, " WINDOW");
2940  switch (proc->provolatile)
2941  {
2942  case PROVOLATILE_IMMUTABLE:
2943  appendStringInfoString(&buf, " IMMUTABLE");
2944  break;
2945  case PROVOLATILE_STABLE:
2946  appendStringInfoString(&buf, " STABLE");
2947  break;
2948  case PROVOLATILE_VOLATILE:
2949  break;
2950  }
2951 
2952  switch (proc->proparallel)
2953  {
2954  case PROPARALLEL_SAFE:
2955  appendStringInfoString(&buf, " PARALLEL SAFE");
2956  break;
2957  case PROPARALLEL_RESTRICTED:
2958  appendStringInfoString(&buf, " PARALLEL RESTRICTED");
2959  break;
2960  case PROPARALLEL_UNSAFE:
2961  break;
2962  }
2963 
2964  if (proc->proisstrict)
2965  appendStringInfoString(&buf, " STRICT");
2966  if (proc->prosecdef)
2967  appendStringInfoString(&buf, " SECURITY DEFINER");
2968  if (proc->proleakproof)
2969  appendStringInfoString(&buf, " LEAKPROOF");
2970 
2971  /* This code for the default cost and rows should match functioncmds.c */
2972  if (proc->prolang == INTERNALlanguageId ||
2973  proc->prolang == ClanguageId)
2974  procost = 1;
2975  else
2976  procost = 100;
2977  if (proc->procost != procost)
2978  appendStringInfo(&buf, " COST %g", proc->procost);
2979 
2980  if (proc->prorows > 0 && proc->prorows != 1000)
2981  appendStringInfo(&buf, " ROWS %g", proc->prorows);
2982 
2983  if (proc->prosupport)
2984  {
2985  Oid argtypes[1];
2986 
2987  /*
2988  * We should qualify the support function's name if it wouldn't be
2989  * resolved by lookup in the current search path.
2990  */
2991  argtypes[0] = INTERNALOID;
2992  appendStringInfo(&buf, " SUPPORT %s",
2993  generate_function_name(proc->prosupport, 1,
2994  NIL, argtypes,
2995  false, NULL, EXPR_KIND_NONE));
2996  }
2997 
2998  if (oldlen != buf.len)
2999  appendStringInfoChar(&buf, '\n');
3000 
3001  /* Emit any proconfig options, one per line */
3002  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
3003  if (!isnull)
3004  {
3005  ArrayType *a = DatumGetArrayTypeP(tmp);
3006  int i;
3007 
3008  Assert(ARR_ELEMTYPE(a) == TEXTOID);
3009  Assert(ARR_NDIM(a) == 1);
3010  Assert(ARR_LBOUND(a)[0] == 1);
3011 
3012  for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3013  {
3014  Datum d;
3015 
3016  d = array_ref(a, 1, &i,
3017  -1 /* varlenarray */ ,
3018  -1 /* TEXT's typlen */ ,
3019  false /* TEXT's typbyval */ ,
3020  TYPALIGN_INT /* TEXT's typalign */ ,
3021  &isnull);
3022  if (!isnull)
3023  {
3024  char *configitem = TextDatumGetCString(d);
3025  char *pos;
3026 
3027  pos = strchr(configitem, '=');
3028  if (pos == NULL)
3029  continue;
3030  *pos++ = '\0';
3031 
3032  appendStringInfo(&buf, " SET %s TO ",
3033  quote_identifier(configitem));
3034 
3035  /*
3036  * Variables that are marked GUC_LIST_QUOTE were already fully
3037  * quoted by flatten_set_variable_args() before they were put
3038  * into the proconfig array. However, because the quoting
3039  * rules used there aren't exactly like SQL's, we have to
3040  * break the list value apart and then quote the elements as
3041  * string literals. (The elements may be double-quoted as-is,
3042  * but we can't just feed them to the SQL parser; it would do
3043  * the wrong thing with elements that are zero-length or
3044  * longer than NAMEDATALEN.)
3045  *
3046  * Variables that are not so marked should just be emitted as
3047  * simple string literals. If the variable is not known to
3048  * guc.c, we'll do that; this makes it unsafe to use
3049  * GUC_LIST_QUOTE for extension variables.
3050  */
3051  if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3052  {
3053  List *namelist;
3054  ListCell *lc;
3055 
3056  /* Parse string into list of identifiers */
3057  if (!SplitGUCList(pos, ',', &namelist))
3058  {
3059  /* this shouldn't fail really */
3060  elog(ERROR, "invalid list syntax in proconfig item");
3061  }
3062  foreach(lc, namelist)
3063  {
3064  char *curname = (char *) lfirst(lc);
3065 
3066  simple_quote_literal(&buf, curname);
3067  if (lnext(namelist, lc))
3068  appendStringInfoString(&buf, ", ");
3069  }
3070  }
3071  else
3072  simple_quote_literal(&buf, pos);
3073  appendStringInfoChar(&buf, '\n');
3074  }
3075  }
3076  }
3077 
3078  /* And finally the function definition ... */
3079  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3080  if (proc->prolang == SQLlanguageId && !isnull)
3081  {
3082  print_function_sqlbody(&buf, proctup);
3083  }
3084  else
3085  {
3086  appendStringInfoString(&buf, "AS ");
3087 
3088  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
3089  if (!isnull)
3090  {
3092  appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3093  }
3094 
3095  tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
3096  prosrc = TextDatumGetCString(tmp);
3097 
3098  /*
3099  * We always use dollar quoting. Figure out a suitable delimiter.
3100  *
3101  * Since the user is likely to be editing the function body string, we
3102  * shouldn't use a short delimiter that he might easily create a
3103  * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3104  * if needed.
3105  */
3106  initStringInfo(&dq);
3107  appendStringInfoChar(&dq, '$');
3108  appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3109  while (strstr(prosrc, dq.data) != NULL)
3110  appendStringInfoChar(&dq, 'x');
3111  appendStringInfoChar(&dq, '$');
3112 
3113  appendBinaryStringInfo(&buf, dq.data, dq.len);
3114  appendStringInfoString(&buf, prosrc);
3115  appendBinaryStringInfo(&buf, dq.data, dq.len);
3116  }
3117 
3118  appendStringInfoChar(&buf, '\n');
3119 
3120  ReleaseSysCache(proctup);
3121 
3123 }
3124 
3125 /*
3126  * pg_get_function_arguments
3127  * Get a nicely-formatted list of arguments for a function.
3128  * This is everything that would go between the parentheses in
3129  * CREATE FUNCTION.
3130  */
3131 Datum
3133 {
3134  Oid funcid = PG_GETARG_OID(0);
3136  HeapTuple proctup;
3137 
3138  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3139  if (!HeapTupleIsValid(proctup))
3140  PG_RETURN_NULL();
3141 
3142  initStringInfo(&buf);
3143 
3144  (void) print_function_arguments(&buf, proctup, false, true);
3145 
3146  ReleaseSysCache(proctup);
3147 
3149 }
3150 
3151 /*
3152  * pg_get_function_identity_arguments
3153  * Get a formatted list of arguments for a function.
3154  * This is everything that would go between the parentheses in
3155  * ALTER FUNCTION, etc. In particular, don't print defaults.
3156  */
3157 Datum
3159 {
3160  Oid funcid = PG_GETARG_OID(0);
3162  HeapTuple proctup;
3163 
3164  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3165  if (!HeapTupleIsValid(proctup))
3166  PG_RETURN_NULL();
3167 
3168  initStringInfo(&buf);
3169 
3170  (void) print_function_arguments(&buf, proctup, false, false);
3171 
3172  ReleaseSysCache(proctup);
3173 
3175 }
3176 
3177 /*
3178  * pg_get_function_result
3179  * Get a nicely-formatted version of the result type of a function.
3180  * This is what would appear after RETURNS in CREATE FUNCTION.
3181  */
3182 Datum
3184 {
3185  Oid funcid = PG_GETARG_OID(0);
3187  HeapTuple proctup;
3188 
3189  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3190  if (!HeapTupleIsValid(proctup))
3191  PG_RETURN_NULL();
3192 
3193  if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3194  {
3195  ReleaseSysCache(proctup);
3196  PG_RETURN_NULL();
3197  }
3198 
3199  initStringInfo(&buf);
3200 
3201  print_function_rettype(&buf, proctup);
3202 
3203  ReleaseSysCache(proctup);
3204 
3206 }
3207 
3208 /*
3209  * Guts of pg_get_function_result: append the function's return type
3210  * to the specified buffer.
3211  */
3212 static void
3214 {
3215  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3216  int ntabargs = 0;
3217  StringInfoData rbuf;
3218 
3219  initStringInfo(&rbuf);
3220 
3221  if (proc->proretset)
3222  {
3223  /* It might be a table function; try to print the arguments */
3224  appendStringInfoString(&rbuf, "TABLE(");
3225  ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3226  if (ntabargs > 0)
3227  appendStringInfoChar(&rbuf, ')');
3228  else
3229  resetStringInfo(&rbuf);
3230  }
3231 
3232  if (ntabargs == 0)
3233  {
3234  /* Not a table function, so do the normal thing */
3235  if (proc->proretset)
3236  appendStringInfoString(&rbuf, "SETOF ");
3237  appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3238  }
3239 
3240  appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3241 }
3242 
3243 /*
3244  * Common code for pg_get_function_arguments and pg_get_function_result:
3245  * append the desired subset of arguments to buf. We print only TABLE
3246  * arguments when print_table_args is true, and all the others when it's false.
3247  * We print argument defaults only if print_defaults is true.
3248  * Function return value is the number of arguments printed.
3249  */
3250 static int
3252  bool print_table_args, bool print_defaults)
3253 {
3254  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3255  int numargs;
3256  Oid *argtypes;
3257  char **argnames;
3258  char *argmodes;
3259  int insertorderbyat = -1;
3260  int argsprinted;
3261  int inputargno;
3262  int nlackdefaults;
3263  List *argdefaults = NIL;
3264  ListCell *nextargdefault = NULL;
3265  int i;
3266 
3267  numargs = get_func_arg_info(proctup,
3268  &argtypes, &argnames, &argmodes);
3269 
3270  nlackdefaults = numargs;
3271  if (print_defaults && proc->pronargdefaults > 0)
3272  {
3273  Datum proargdefaults;
3274  bool isnull;
3275 
3276  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3277  Anum_pg_proc_proargdefaults,
3278  &isnull);
3279  if (!isnull)
3280  {
3281  char *str;
3282 
3283  str = TextDatumGetCString(proargdefaults);
3284  argdefaults = castNode(List, stringToNode(str));
3285  pfree(str);
3286  nextargdefault = list_head(argdefaults);
3287  /* nlackdefaults counts only *input* arguments lacking defaults */
3288  nlackdefaults = proc->pronargs - list_length(argdefaults);
3289  }
3290  }
3291 
3292  /* Check for special treatment of ordered-set aggregates */
3293  if (proc->prokind == PROKIND_AGGREGATE)
3294  {
3295  HeapTuple aggtup;
3296  Form_pg_aggregate agg;
3297 
3298  aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(proc->oid));
3299  if (!HeapTupleIsValid(aggtup))
3300  elog(ERROR, "cache lookup failed for aggregate %u",
3301  proc->oid);
3302  agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3303  if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3304  insertorderbyat = agg->aggnumdirectargs;
3305  ReleaseSysCache(aggtup);
3306  }
3307 
3308  argsprinted = 0;
3309  inputargno = 0;
3310  for (i = 0; i < numargs; i++)
3311  {
3312  Oid argtype = argtypes[i];
3313  char *argname = argnames ? argnames[i] : NULL;
3314  char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3315  const char *modename;
3316  bool isinput;
3317 
3318  switch (argmode)
3319  {
3320  case PROARGMODE_IN:
3321 
3322  /*
3323  * For procedures, explicitly mark all argument modes, so as
3324  * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3325  */
3326  if (proc->prokind == PROKIND_PROCEDURE)
3327  modename = "IN ";
3328  else
3329  modename = "";
3330  isinput = true;
3331  break;
3332  case PROARGMODE_INOUT:
3333  modename = "INOUT ";
3334  isinput = true;
3335  break;
3336  case PROARGMODE_OUT:
3337  modename = "OUT ";
3338  isinput = false;
3339  break;
3340  case PROARGMODE_VARIADIC:
3341  modename = "VARIADIC ";
3342  isinput = true;
3343  break;
3344  case PROARGMODE_TABLE:
3345  modename = "";
3346  isinput = false;
3347  break;
3348  default:
3349  elog(ERROR, "invalid parameter mode '%c'", argmode);
3350  modename = NULL; /* keep compiler quiet */
3351  isinput = false;
3352  break;
3353  }
3354  if (isinput)
3355  inputargno++; /* this is a 1-based counter */
3356 
3357  if (print_table_args != (argmode == PROARGMODE_TABLE))
3358  continue;
3359 
3360  if (argsprinted == insertorderbyat)
3361  {
3362  if (argsprinted)
3363  appendStringInfoChar(buf, ' ');
3364  appendStringInfoString(buf, "ORDER BY ");
3365  }
3366  else if (argsprinted)
3367  appendStringInfoString(buf, ", ");
3368 
3369  appendStringInfoString(buf, modename);
3370  if (argname && argname[0])
3371  appendStringInfo(buf, "%s ", quote_identifier(argname));
3373  if (print_defaults && isinput && inputargno > nlackdefaults)
3374  {
3375  Node *expr;
3376 
3377  Assert(nextargdefault != NULL);
3378  expr = (Node *) lfirst(nextargdefault);
3379  nextargdefault = lnext(argdefaults, nextargdefault);
3380 
3381  appendStringInfo(buf, " DEFAULT %s",
3382  deparse_expression(expr, NIL, false, false));
3383  }
3384  argsprinted++;
3385 
3386  /* nasty hack: print the last arg twice for variadic ordered-set agg */
3387  if (argsprinted == insertorderbyat && i == numargs - 1)
3388  {
3389  i--;
3390  /* aggs shouldn't have defaults anyway, but just to be sure ... */
3391  print_defaults = false;
3392  }
3393  }
3394 
3395  return argsprinted;
3396 }
3397 
3398 static bool
3399 is_input_argument(int nth, const char *argmodes)
3400 {
3401  return (!argmodes
3402  || argmodes[nth] == PROARGMODE_IN
3403  || argmodes[nth] == PROARGMODE_INOUT
3404  || argmodes[nth] == PROARGMODE_VARIADIC);
3405 }
3406 
3407 /*
3408  * Append used transformed types to specified buffer
3409  */
3410 static void
3412 {
3413  Oid *trftypes;
3414  int ntypes;
3415 
3416  ntypes = get_func_trftypes(proctup, &trftypes);
3417  if (ntypes > 0)
3418  {
3419  int i;
3420 
3421  appendStringInfoString(buf, " TRANSFORM ");
3422  for (i = 0; i < ntypes; i++)
3423  {
3424  if (i != 0)
3425  appendStringInfoString(buf, ", ");
3426  appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3427  }
3428  appendStringInfoChar(buf, '\n');
3429  }
3430 }
3431 
3432 /*
3433  * Get textual representation of a function argument's default value. The
3434  * second argument of this function is the argument number among all arguments
3435  * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3436  * how information_schema.sql uses it.
3437  */
3438 Datum
3440 {
3441  Oid funcid = PG_GETARG_OID(0);
3442  int32 nth_arg = PG_GETARG_INT32(1);
3443  HeapTuple proctup;
3444  Form_pg_proc proc;
3445  int numargs;
3446  Oid *argtypes;
3447  char **argnames;
3448  char *argmodes;
3449  int i;
3450  List *argdefaults;
3451  Node *node;
3452  char *str;
3453  int nth_inputarg;
3454  Datum proargdefaults;
3455  bool isnull;
3456  int nth_default;
3457 
3458  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3459  if (!HeapTupleIsValid(proctup))
3460  PG_RETURN_NULL();
3461 
3462  numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3463  if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3464  {
3465  ReleaseSysCache(proctup);
3466  PG_RETURN_NULL();
3467  }
3468 
3469  nth_inputarg = 0;
3470  for (i = 0; i < nth_arg; i++)
3471  if (is_input_argument(i, argmodes))
3472  nth_inputarg++;
3473 
3474  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3475  Anum_pg_proc_proargdefaults,
3476  &isnull);
3477  if (isnull)
3478  {
3479  ReleaseSysCache(proctup);
3480  PG_RETURN_NULL();
3481  }
3482 
3483  str = TextDatumGetCString(proargdefaults);
3484  argdefaults = castNode(List, stringToNode(str));
3485  pfree(str);
3486 
3487  proc = (Form_pg_proc) GETSTRUCT(proctup);
3488 
3489  /*
3490  * Calculate index into proargdefaults: proargdefaults corresponds to the
3491  * last N input arguments, where N = pronargdefaults.
3492  */
3493  nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3494 
3495  if (nth_default < 0 || nth_default >= list_length(argdefaults))
3496  {
3497  ReleaseSysCache(proctup);
3498  PG_RETURN_NULL();
3499  }
3500  node = list_nth(argdefaults, nth_default);
3501  str = deparse_expression(node, NIL, false, false);
3502 
3503  ReleaseSysCache(proctup);
3504 
3506 }
3507 
3508 static void
3510 {
3511  int numargs;
3512  Oid *argtypes;
3513  char **argnames;
3514  char *argmodes;
3515  deparse_namespace dpns = {0};
3516  Datum tmp;
3517  Node *n;
3518 
3519  dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3520  numargs = get_func_arg_info(proctup,
3521  &argtypes, &argnames, &argmodes);
3522  dpns.numargs = numargs;
3523  dpns.argnames = argnames;
3524 
3525  tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3527 
3528  if (IsA(n, List))
3529  {
3530  List *stmts;
3531  ListCell *lc;
3532 
3533  stmts = linitial(castNode(List, n));
3534 
3535  appendStringInfoString(buf, "BEGIN ATOMIC\n");
3536 
3537  foreach(lc, stmts)
3538  {
3539  Query *query = lfirst_node(Query, lc);
3540 
3541  /* It seems advisable to get at least AccessShareLock on rels */
3542  AcquireRewriteLocks(query, false, false);
3543  get_query_def(query, buf, list_make1(&dpns), NULL, false,
3545  appendStringInfoChar(buf, ';');
3546  appendStringInfoChar(buf, '\n');
3547  }
3548 
3549  appendStringInfoString(buf, "END");
3550  }
3551  else
3552  {
3553  Query *query = castNode(Query, n);
3554 
3555  /* It seems advisable to get at least AccessShareLock on rels */
3556  AcquireRewriteLocks(query, false, false);
3557  get_query_def(query, buf, list_make1(&dpns), NULL, false,
3558  0, WRAP_COLUMN_DEFAULT, 0);
3559  }
3560 }
3561 
3562 Datum
3564 {
3565  Oid funcid = PG_GETARG_OID(0);
3567  HeapTuple proctup;
3568  bool isnull;
3569 
3570  initStringInfo(&buf);
3571 
3572  /* Look up the function */
3573  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3574  if (!HeapTupleIsValid(proctup))
3575  PG_RETURN_NULL();
3576 
3577  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3578  if (isnull)
3579  {
3580  ReleaseSysCache(proctup);
3581  PG_RETURN_NULL();
3582  }
3583 
3584  print_function_sqlbody(&buf, proctup);
3585 
3586  ReleaseSysCache(proctup);
3587 
3589 }
3590 
3591 
3592 /*
3593  * deparse_expression - General utility for deparsing expressions
3594  *
3595  * calls deparse_expression_pretty with all prettyPrinting disabled
3596  */
3597 char *
3598 deparse_expression(Node *expr, List *dpcontext,
3599  bool forceprefix, bool showimplicit)
3600 {
3601  return deparse_expression_pretty(expr, dpcontext, forceprefix,
3602  showimplicit, 0, 0);
3603 }
3604 
3605 /* ----------
3606  * deparse_expression_pretty - General utility for deparsing expressions
3607  *
3608  * expr is the node tree to be deparsed. It must be a transformed expression
3609  * tree (ie, not the raw output of gram.y).
3610  *
3611  * dpcontext is a list of deparse_namespace nodes representing the context
3612  * for interpreting Vars in the node tree. It can be NIL if no Vars are
3613  * expected.
3614  *
3615  * forceprefix is true to force all Vars to be prefixed with their table names.
3616  *
3617  * showimplicit is true to force all implicit casts to be shown explicitly.
3618  *
3619  * Tries to pretty up the output according to prettyFlags and startIndent.
3620  *
3621  * The result is a palloc'd string.
3622  * ----------
3623  */
3624 static char *
3626  bool forceprefix, bool showimplicit,
3627  int prettyFlags, int startIndent)
3628 {
3631 
3632  initStringInfo(&buf);
3633  context.buf = &buf;
3634  context.namespaces = dpcontext;
3635  context.windowClause = NIL;
3636  context.windowTList = NIL;
3637  context.varprefix = forceprefix;
3638  context.prettyFlags = prettyFlags;
3639  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3640  context.indentLevel = startIndent;
3641  context.special_exprkind = EXPR_KIND_NONE;
3642  context.appendparents = NULL;
3643 
3644  get_rule_expr(expr, &context, showimplicit);
3645 
3646  return buf.data;
3647 }
3648 
3649 /* ----------
3650  * deparse_context_for - Build deparse context for a single relation
3651  *
3652  * Given the reference name (alias) and OID of a relation, build deparsing
3653  * context for an expression referencing only that relation (as varno 1,
3654  * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3655  * ----------
3656  */
3657 List *
3658 deparse_context_for(const char *aliasname, Oid relid)
3659 {
3660  deparse_namespace *dpns;
3661  RangeTblEntry *rte;
3662 
3663  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3664 
3665  /* Build a minimal RTE for the rel */
3666  rte = makeNode(RangeTblEntry);
3667  rte->rtekind = RTE_RELATION;
3668  rte->relid = relid;
3669  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3670  rte->rellockmode = AccessShareLock;
3671  rte->alias = makeAlias(aliasname, NIL);
3672  rte->eref = rte->alias;
3673  rte->lateral = false;
3674  rte->inh = false;
3675  rte->inFromCl = true;
3676 
3677  /* Build one-element rtable */
3678  dpns->rtable = list_make1(rte);
3679  dpns->subplans = NIL;
3680  dpns->ctes = NIL;
3681  dpns->appendrels = NULL;
3682  set_rtable_names(dpns, NIL, NULL);
3684 
3685  /* Return a one-deep namespace stack */
3686  return list_make1(dpns);
3687 }
3688 
3689 /*
3690  * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3691  *
3692  * When deparsing an expression in a Plan tree, we use the plan's rangetable
3693  * to resolve names of simple Vars. The initialization of column names for
3694  * this is rather expensive if the rangetable is large, and it'll be the same
3695  * for every expression in the Plan tree; so we do it just once and re-use
3696  * the result of this function for each expression. (Note that the result
3697  * is not usable until set_deparse_context_plan() is applied to it.)
3698  *
3699  * In addition to the PlannedStmt, pass the per-RTE alias names
3700  * assigned by a previous call to select_rtable_names_for_explain.
3701  */
3702 List *
3704 {
3705  deparse_namespace *dpns;
3706 
3707  dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3708 
3709  /* Initialize fields that stay the same across the whole plan tree */
3710  dpns->rtable = pstmt->rtable;
3711  dpns->rtable_names = rtable_names;
3712  dpns->subplans = pstmt->subplans;
3713  dpns->ctes = NIL;
3714  if (pstmt->appendRelations)
3715  {
3716  /* Set up the array, indexed by child relid */
3717  int ntables = list_length(dpns->rtable);
3718  ListCell *lc;
3719 
3720  dpns->appendrels = (AppendRelInfo **)
3721  palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3722  foreach(lc, pstmt->appendRelations)
3723  {
3724  AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3725  Index crelid = appinfo->child_relid;
3726 
3727  Assert(crelid > 0 && crelid <= ntables);
3728  Assert(dpns->appendrels[crelid] == NULL);
3729  dpns->appendrels[crelid] = appinfo;
3730  }
3731  }
3732  else
3733  dpns->appendrels = NULL; /* don't need it */
3734 
3735  /*
3736  * Set up column name aliases. We will get rather bogus results for join
3737  * RTEs, but that doesn't matter because plan trees don't contain any join
3738  * alias Vars.
3739  */
3741 
3742  /* Return a one-deep namespace stack */
3743  return list_make1(dpns);
3744 }
3745 
3746 /*
3747  * set_deparse_context_plan - Specify Plan node containing expression
3748  *
3749  * When deparsing an expression in a Plan tree, we might have to resolve
3750  * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
3751  * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
3752  * can be resolved by drilling down into the left and right child plans.
3753  * Similarly, INDEX_VAR references can be resolved by reference to the
3754  * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3755  * ForeignScan and CustomScan nodes. (Note that we don't currently support
3756  * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3757  * for those, we can only deparse the indexqualorig fields, which won't
3758  * contain INDEX_VAR Vars.)
3759  *
3760  * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3761  * the most-closely-nested first. This is needed to resolve PARAM_EXEC
3762  * Params. Note we assume that all the Plan nodes share the same rtable.
3763  *
3764  * Once this function has been called, deparse_expression() can be called on
3765  * subsidiary expression(s) of the specified Plan node. To deparse
3766  * expressions of a different Plan node in the same Plan tree, re-call this
3767  * function to identify the new parent Plan node.
3768  *
3769  * The result is the same List passed in; this is a notational convenience.
3770  */
3771 List *
3772 set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3773 {
3774  deparse_namespace *dpns;
3775 
3776  /* Should always have one-entry namespace list for Plan deparsing */
3777  Assert(list_length(dpcontext) == 1);
3778  dpns = (deparse_namespace *) linitial(dpcontext);
3779 
3780  /* Set our attention on the specific plan node passed in */
3781  dpns->ancestors = ancestors;
3782  set_deparse_plan(dpns, plan);
3783 
3784  return dpcontext;
3785 }
3786 
3787 /*
3788  * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3789  *
3790  * Determine the relation aliases we'll use during an EXPLAIN operation.
3791  * This is just a frontend to set_rtable_names. We have to expose the aliases
3792  * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3793  */
3794 List *
3796 {
3797  deparse_namespace dpns;
3798 
3799  memset(&dpns, 0, sizeof(dpns));
3800  dpns.rtable = rtable;
3801  dpns.subplans = NIL;
3802  dpns.ctes = NIL;
3803  dpns.appendrels = NULL;
3804  set_rtable_names(&dpns, NIL, rels_used);
3805  /* We needn't bother computing column aliases yet */
3806 
3807  return dpns.rtable_names;
3808 }
3809 
3810 /*
3811  * set_rtable_names: select RTE aliases to be used in printing a query
3812  *
3813  * We fill in dpns->rtable_names with a list of names that is one-for-one with
3814  * the already-filled dpns->rtable list. Each RTE name is unique among those
3815  * in the new namespace plus any ancestor namespaces listed in
3816  * parent_namespaces.
3817  *
3818  * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3819  *
3820  * Note that this function is only concerned with relation names, not column
3821  * names.
3822  */
3823 static void
3824 set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3825  Bitmapset *rels_used)
3826 {
3827  HASHCTL hash_ctl;
3828  HTAB *names_hash;
3829  NameHashEntry *hentry;
3830  bool found;
3831  int rtindex;
3832  ListCell *lc;
3833 
3834  dpns->rtable_names = NIL;
3835  /* nothing more to do if empty rtable */
3836  if (dpns->rtable == NIL)
3837  return;
3838 
3839  /*
3840  * We use a hash table to hold known names, so that this process is O(N)
3841  * not O(N^2) for N names.
3842  */
3843  hash_ctl.keysize = NAMEDATALEN;
3844  hash_ctl.entrysize = sizeof(NameHashEntry);
3845  hash_ctl.hcxt = CurrentMemoryContext;
3846  names_hash = hash_create("set_rtable_names names",
3847  list_length(dpns->rtable),
3848  &hash_ctl,
3850 
3851  /* Preload the hash table with names appearing in parent_namespaces */
3852  foreach(lc, parent_namespaces)
3853  {
3854  deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3855  ListCell *lc2;
3856 
3857  foreach(lc2, olddpns->rtable_names)
3858  {
3859  char *oldname = (char *) lfirst(lc2);
3860 
3861  if (oldname == NULL)
3862  continue;
3863  hentry = (NameHashEntry *) hash_search(names_hash,
3864  oldname,
3865  HASH_ENTER,
3866  &found);
3867  /* we do not complain about duplicate names in parent namespaces */
3868  hentry->counter = 0;
3869  }
3870  }
3871 
3872  /* Now we can scan the rtable */
3873  rtindex = 1;
3874  foreach(lc, dpns->rtable)
3875  {
3876  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3877  char *refname;
3878 
3879  /* Just in case this takes an unreasonable amount of time ... */
3881 
3882  if (rels_used && !bms_is_member(rtindex, rels_used))
3883  {
3884  /* Ignore unreferenced RTE */
3885  refname = NULL;
3886  }
3887  else if (rte->alias)
3888  {
3889  /* If RTE has a user-defined alias, prefer that */
3890  refname = rte->alias->aliasname;
3891  }
3892  else if (rte->rtekind == RTE_RELATION)
3893  {
3894  /* Use the current actual name of the relation */
3895  refname = get_rel_name(rte->relid);
3896  }
3897  else if (rte->rtekind == RTE_JOIN)
3898  {
3899  /* Unnamed join has no refname */
3900  refname = NULL;
3901  }
3902  else
3903  {
3904  /* Otherwise use whatever the parser assigned */
3905  refname = rte->eref->aliasname;
3906  }
3907 
3908  /*
3909  * If the selected name isn't unique, append digits to make it so, and
3910  * make a new hash entry for it once we've got a unique name. For a
3911  * very long input name, we might have to truncate to stay within
3912  * NAMEDATALEN.
3913  */
3914  if (refname)
3915  {
3916  hentry = (NameHashEntry *) hash_search(names_hash,
3917  refname,
3918  HASH_ENTER,
3919  &found);
3920  if (found)
3921  {
3922  /* Name already in use, must choose a new one */
3923  int refnamelen = strlen(refname);
3924  char *modname = (char *) palloc(refnamelen + 16);
3925  NameHashEntry *hentry2;
3926 
3927  do
3928  {
3929  hentry->counter++;
3930  for (;;)
3931  {
3932  memcpy(modname, refname, refnamelen);
3933  sprintf(modname + refnamelen, "_%d", hentry->counter);
3934  if (strlen(modname) < NAMEDATALEN)
3935  break;
3936  /* drop chars from refname to keep all the digits */
3937  refnamelen = pg_mbcliplen(refname, refnamelen,
3938  refnamelen - 1);
3939  }
3940  hentry2 = (NameHashEntry *) hash_search(names_hash,
3941  modname,
3942  HASH_ENTER,
3943  &found);
3944  } while (found);
3945  hentry2->counter = 0; /* init new hash entry */
3946  refname = modname;
3947  }
3948  else
3949  {
3950  /* Name not previously used, need only initialize hentry */
3951  hentry->counter = 0;
3952  }
3953  }
3954 
3955  dpns->rtable_names = lappend(dpns->rtable_names, refname);
3956  rtindex++;
3957  }
3958 
3959  hash_destroy(names_hash);
3960 }
3961 
3962 /*
3963  * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
3964  *
3965  * For convenience, this is defined to initialize the deparse_namespace struct
3966  * from scratch.
3967  */
3968 static void
3970  List *parent_namespaces)
3971 {
3972  ListCell *lc;
3973  ListCell *lc2;
3974 
3975  /* Initialize *dpns and fill rtable/ctes links */
3976  memset(dpns, 0, sizeof(deparse_namespace));
3977  dpns->rtable = query->rtable;
3978  dpns->subplans = NIL;
3979  dpns->ctes = query->cteList;
3980  dpns->appendrels = NULL;
3981 
3982  /* Assign a unique relation alias to each RTE */
3983  set_rtable_names(dpns, parent_namespaces, NULL);
3984 
3985  /* Initialize dpns->rtable_columns to contain zeroed structs */
3986  dpns->rtable_columns = NIL;
3987  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
3988  dpns->rtable_columns = lappend(dpns->rtable_columns,
3989  palloc0(sizeof(deparse_columns)));
3990 
3991  /* If it's a utility query, it won't have a jointree */
3992  if (query->jointree)
3993  {
3994  /* Detect whether global uniqueness of USING names is needed */
3995  dpns->unique_using =
3996  has_dangerous_join_using(dpns, (Node *) query->jointree);
3997 
3998  /*
3999  * Select names for columns merged by USING, via a recursive pass over
4000  * the query jointree.
4001  */
4002  set_using_names(dpns, (Node *) query->jointree, NIL);
4003  }
4004 
4005  /*
4006  * Now assign remaining column aliases for each RTE. We do this in a
4007  * linear scan of the rtable, so as to process RTEs whether or not they
4008  * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4009  * etc). JOIN RTEs must be processed after their children, but this is
4010  * okay because they appear later in the rtable list than their children
4011  * (cf Asserts in identify_join_columns()).
4012  */
4013  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4014  {
4015  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4016  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4017 
4018  if (rte->rtekind == RTE_JOIN)
4019  set_join_column_names(dpns, rte, colinfo);
4020  else
4021  set_relation_column_names(dpns, rte, colinfo);
4022  }
4023 }
4024 
4025 /*
4026  * set_simple_column_names: fill in column aliases for non-query situations
4027  *
4028  * This handles EXPLAIN and cases where we only have relation RTEs. Without
4029  * a join tree, we can't do anything smart about join RTEs, but we don't
4030  * need to (note that EXPLAIN should never see join alias Vars anyway).
4031  * If we do hit a join RTE we'll just process it like a non-table base RTE.
4032  */
4033 static void
4035 {
4036  ListCell *lc;
4037  ListCell *lc2;
4038 
4039  /* Initialize dpns->rtable_columns to contain zeroed structs */
4040  dpns->rtable_columns = NIL;
4041  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4042  dpns->rtable_columns = lappend(dpns->rtable_columns,
4043  palloc0(sizeof(deparse_columns)));
4044 
4045  /* Assign unique column aliases within each RTE */
4046  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4047  {
4048  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4049  deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4050 
4051  set_relation_column_names(dpns, rte, colinfo);
4052  }
4053 }
4054 
4055 /*
4056  * has_dangerous_join_using: search jointree for unnamed JOIN USING
4057  *
4058  * Merged columns of a JOIN USING may act differently from either of the input
4059  * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4060  * because an implicit coercion of the underlying input column is required.
4061  * In such a case the column must be referenced as a column of the JOIN not as
4062  * a column of either input. And this is problematic if the join is unnamed
4063  * (alias-less): we cannot qualify the column's name with an RTE name, since
4064  * there is none. (Forcibly assigning an alias to the join is not a solution,
4065  * since that will prevent legal references to tables below the join.)
4066  * To ensure that every column in the query is unambiguously referenceable,
4067  * we must assign such merged columns names that are globally unique across
4068  * the whole query, aliasing other columns out of the way as necessary.
4069  *
4070  * Because the ensuing re-aliasing is fairly damaging to the readability of
4071  * the query, we don't do this unless we have to. So, we must pre-scan
4072  * the join tree to see if we have to, before starting set_using_names().
4073  */
4074 static bool
4076 {
4077  if (IsA(jtnode, RangeTblRef))
4078  {
4079  /* nothing to do here */
4080  }
4081  else if (IsA(jtnode, FromExpr))
4082  {
4083  FromExpr *f = (FromExpr *) jtnode;
4084  ListCell *lc;
4085 
4086  foreach(lc, f->fromlist)
4087  {
4088  if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4089  return true;
4090  }
4091  }
4092  else if (IsA(jtnode, JoinExpr))
4093  {
4094  JoinExpr *j = (JoinExpr *) jtnode;
4095 
4096  /* Is it an unnamed JOIN with USING? */
4097  if (j->alias == NULL && j->usingClause)
4098  {
4099  /*
4100  * Yes, so check each join alias var to see if any of them are not
4101  * simple references to underlying columns. If so, we have a
4102  * dangerous situation and must pick unique aliases.
4103  */
4104  RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4105 
4106  /* We need only examine the merged columns */
4107  for (int i = 0; i < jrte->joinmergedcols; i++)
4108  {
4109  Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4110 
4111  if (!IsA(aliasvar, Var))
4112  return true;
4113  }
4114  }
4115 
4116  /* Nope, but inspect children */
4117  if (has_dangerous_join_using(dpns, j->larg))
4118  return true;
4119  if (has_dangerous_join_using(dpns, j->rarg))
4120  return true;
4121  }
4122  else
4123  elog(ERROR, "unrecognized node type: %d",
4124  (int) nodeTag(jtnode));
4125  return false;
4126 }
4127 
4128 /*
4129  * set_using_names: select column aliases to be used for merged USING columns
4130  *
4131  * We do this during a recursive descent of the query jointree.
4132  * dpns->unique_using must already be set to determine the global strategy.
4133  *
4134  * Column alias info is saved in the dpns->rtable_columns list, which is
4135  * assumed to be filled with pre-zeroed deparse_columns structs.
4136  *
4137  * parentUsing is a list of all USING aliases assigned in parent joins of
4138  * the current jointree node. (The passed-in list must not be modified.)
4139  */
4140 static void
4141 set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4142 {
4143  if (IsA(jtnode, RangeTblRef))
4144  {
4145  /* nothing to do now */
4146  }
4147  else if (IsA(jtnode, FromExpr))
4148  {
4149  FromExpr *f = (FromExpr *) jtnode;
4150  ListCell *lc;
4151 
4152  foreach(lc, f->fromlist)
4153  set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4154  }
4155  else if (IsA(jtnode, JoinExpr))
4156  {
4157  JoinExpr *j = (JoinExpr *) jtnode;
4158  RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4159  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4160  int *leftattnos;
4161  int *rightattnos;
4162  deparse_columns *leftcolinfo;
4163  deparse_columns *rightcolinfo;
4164  int i;
4165  ListCell *lc;
4166 
4167  /* Get info about the shape of the join */
4168  identify_join_columns(j, rte, colinfo);
4169  leftattnos = colinfo->leftattnos;
4170  rightattnos = colinfo->rightattnos;
4171 
4172  /* Look up the not-yet-filled-in child deparse_columns structs */
4173  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4174  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4175 
4176  /*
4177  * If this join is unnamed, then we cannot substitute new aliases at
4178  * this level, so any name requirements pushed down to here must be
4179  * pushed down again to the children.
4180  */
4181  if (rte->alias == NULL)
4182  {
4183  for (i = 0; i < colinfo->num_cols; i++)
4184  {
4185  char *colname = colinfo->colnames[i];
4186 
4187  if (colname == NULL)
4188  continue;
4189 
4190  /* Push down to left column, unless it's a system column */
4191  if (leftattnos[i] > 0)
4192  {
4193  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4194  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4195  }
4196 
4197  /* Same on the righthand side */
4198  if (rightattnos[i] > 0)
4199  {
4200  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4201  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4202  }
4203  }
4204  }
4205 
4206  /*
4207  * If there's a USING clause, select the USING column names and push
4208  * those names down to the children. We have two strategies:
4209  *
4210  * If dpns->unique_using is true, we force all USING names to be
4211  * unique across the whole query level. In principle we'd only need
4212  * the names of dangerous USING columns to be globally unique, but to
4213  * safely assign all USING names in a single pass, we have to enforce
4214  * the same uniqueness rule for all of them. However, if a USING
4215  * column's name has been pushed down from the parent, we should use
4216  * it as-is rather than making a uniqueness adjustment. This is
4217  * necessary when we're at an unnamed join, and it creates no risk of
4218  * ambiguity. Also, if there's a user-written output alias for a
4219  * merged column, we prefer to use that rather than the input name;
4220  * this simplifies the logic and seems likely to lead to less aliasing
4221  * overall.
4222  *
4223  * If dpns->unique_using is false, we only need USING names to be
4224  * unique within their own join RTE. We still need to honor
4225  * pushed-down names, though.
4226  *
4227  * Though significantly different in results, these two strategies are
4228  * implemented by the same code, with only the difference of whether
4229  * to put assigned names into dpns->using_names.
4230  */
4231  if (j->usingClause)
4232  {
4233  /* Copy the input parentUsing list so we don't modify it */
4234  parentUsing = list_copy(parentUsing);
4235 
4236  /* USING names must correspond to the first join output columns */
4237  expand_colnames_array_to(colinfo, list_length(j->usingClause));
4238  i = 0;
4239  foreach(lc, j->usingClause)
4240  {
4241  char *colname = strVal(lfirst(lc));
4242 
4243  /* Assert it's a merged column */
4244  Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4245 
4246  /* Adopt passed-down name if any, else select unique name */
4247  if (colinfo->colnames[i] != NULL)
4248  colname = colinfo->colnames[i];
4249  else
4250  {
4251  /* Prefer user-written output alias if any */
4252  if (rte->alias && i < list_length(rte->alias->colnames))
4253  colname = strVal(list_nth(rte->alias->colnames, i));
4254  /* Make it appropriately unique */
4255  colname = make_colname_unique(colname, dpns, colinfo);
4256  if (dpns->unique_using)
4257  dpns->using_names = lappend(dpns->using_names,
4258  colname);
4259  /* Save it as output column name, too */
4260  colinfo->colnames[i] = colname;
4261  }
4262 
4263  /* Remember selected names for use later */
4264  colinfo->usingNames = lappend(colinfo->usingNames, colname);
4265  parentUsing = lappend(parentUsing, colname);
4266 
4267  /* Push down to left column, unless it's a system column */
4268  if (leftattnos[i] > 0)
4269  {
4270  expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4271  leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4272  }
4273 
4274  /* Same on the righthand side */
4275  if (rightattnos[i] > 0)
4276  {
4277  expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4278  rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4279  }
4280 
4281  i++;
4282  }
4283  }
4284 
4285  /* Mark child deparse_columns structs with correct parentUsing info */
4286  leftcolinfo->parentUsing = parentUsing;
4287  rightcolinfo->parentUsing = parentUsing;
4288 
4289  /* Now recursively assign USING column names in children */
4290  set_using_names(dpns, j->larg, parentUsing);
4291  set_using_names(dpns, j->rarg, parentUsing);
4292  }
4293  else
4294  elog(ERROR, "unrecognized node type: %d",
4295  (int) nodeTag(jtnode));
4296 }
4297 
4298 /*
4299  * set_relation_column_names: select column aliases for a non-join RTE
4300  *
4301  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4302  * If any colnames entries are already filled in, those override local
4303  * choices.
4304  */
4305 static void
4307  deparse_columns *colinfo)
4308 {
4309  int ncolumns;
4310  char **real_colnames;
4311  bool changed_any;
4312  int noldcolumns;
4313  int i;
4314  int j;
4315 
4316  /*
4317  * Construct an array of the current "real" column names of the RTE.
4318  * real_colnames[] will be indexed by physical column number, with NULL
4319  * entries for dropped columns.
4320  */
4321  if (rte->rtekind == RTE_RELATION)
4322  {
4323  /* Relation --- look to the system catalogs for up-to-date info */
4324  Relation rel;
4325  TupleDesc tupdesc;
4326 
4327  rel = relation_open(rte->relid, AccessShareLock);
4328  tupdesc = RelationGetDescr(rel);
4329 
4330  ncolumns = tupdesc->natts;
4331  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4332 
4333  for (i = 0; i < ncolumns; i++)
4334  {
4335  Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4336 
4337  if (attr->attisdropped)
4338  real_colnames[i] = NULL;
4339  else
4340  real_colnames[i] = pstrdup(NameStr(attr->attname));
4341  }
4343  }
4344  else
4345  {
4346  /* Otherwise get the column names from eref or expandRTE() */
4347  List *colnames;
4348  ListCell *lc;
4349 
4350  /*
4351  * Functions returning composites have the annoying property that some
4352  * of the composite type's columns might have been dropped since the
4353  * query was parsed. If possible, use expandRTE() to handle that
4354  * case, since it has the tedious logic needed to find out about
4355  * dropped columns. However, if we're explaining a plan, then we
4356  * don't have rte->functions because the planner thinks that won't be
4357  * needed later, and that breaks expandRTE(). So in that case we have
4358  * to rely on rte->eref, which may lead us to report a dropped
4359  * column's old name; that seems close enough for EXPLAIN's purposes.
4360  *
4361  * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4362  * which should be sufficiently up-to-date: no other RTE types can
4363  * have columns get dropped from under them after parsing.
4364  */
4365  if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4366  {
4367  /* Since we're not creating Vars, rtindex etc. don't matter */
4368  expandRTE(rte, 1, 0, -1, true /* include dropped */ ,
4369  &colnames, NULL);
4370  }
4371  else
4372  colnames = rte->eref->colnames;
4373 
4374  ncolumns = list_length(colnames);
4375  real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4376 
4377  i = 0;
4378  foreach(lc, colnames)
4379  {
4380  /*
4381  * If the column name we find here is an empty string, then it's a
4382  * dropped column, so change to NULL.
4383  */
4384  char *cname = strVal(lfirst(lc));
4385 
4386  if (cname[0] == '\0')
4387  cname = NULL;
4388  real_colnames[i] = cname;
4389  i++;
4390  }
4391  }
4392 
4393  /*
4394  * Ensure colinfo->colnames has a slot for each column. (It could be long
4395  * enough already, if we pushed down a name for the last column.) Note:
4396  * it's possible that there are now more columns than there were when the
4397  * query was parsed, ie colnames could be longer than rte->eref->colnames.
4398  * We must assign unique aliases to the new columns too, else there could
4399  * be unresolved conflicts when the view/rule is reloaded.
4400  */
4401  expand_colnames_array_to(colinfo, ncolumns);
4402  Assert(colinfo->num_cols == ncolumns);
4403 
4404  /*
4405  * Make sufficiently large new_colnames and is_new_col arrays, too.
4406  *
4407  * Note: because we leave colinfo->num_new_cols zero until after the loop,
4408  * colname_is_unique will not consult that array, which is fine because it
4409  * would only be duplicate effort.
4410  */
4411  colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4412  colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4413 
4414  /*
4415  * Scan the columns, select a unique alias for each one, and store it in
4416  * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4417  * entries for dropped columns, the latter omits them. Also mark
4418  * new_colnames entries as to whether they are new since parse time; this
4419  * is the case for entries beyond the length of rte->eref->colnames.
4420  */
4421  noldcolumns = list_length(rte->eref->colnames);
4422  changed_any = false;
4423  j = 0;
4424  for (i = 0; i < ncolumns; i++)
4425  {
4426  char *real_colname = real_colnames[i];
4427  char *colname = colinfo->colnames[i];
4428 
4429  /* Skip dropped columns */
4430  if (real_colname == NULL)
4431  {
4432  Assert(colname == NULL); /* colnames[i] is already NULL */
4433  continue;
4434  }
4435 
4436  /* If alias already assigned, that's what to use */
4437  if (colname == NULL)
4438  {
4439  /* If user wrote an alias, prefer that over real column name */
4440  if (rte->alias && i < list_length(rte->alias->colnames))
4441  colname = strVal(list_nth(rte->alias->colnames, i));
4442  else
4443  colname = real_colname;
4444 
4445  /* Unique-ify and insert into colinfo */
4446  colname = make_colname_unique(colname, dpns, colinfo);
4447 
4448  colinfo->colnames[i] = colname;
4449  }
4450 
4451  /* Put names of non-dropped columns in new_colnames[] too */
4452  colinfo->new_colnames[j] = colname;
4453  /* And mark them as new or not */
4454  colinfo->is_new_col[j] = (i >= noldcolumns);
4455  j++;
4456 
4457  /* Remember if any assigned aliases differ from "real" name */
4458  if (!changed_any && strcmp(colname, real_colname) != 0)
4459  changed_any = true;
4460  }
4461 
4462  /*
4463  * Set correct length for new_colnames[] array. (Note: if columns have
4464  * been added, colinfo->num_cols includes them, which is not really quite
4465  * right but is harmless, since any new columns must be at the end where
4466  * they won't affect varattnos of pre-existing columns.)
4467  */
4468  colinfo->num_new_cols = j;
4469 
4470  /*
4471  * For a relation RTE, we need only print the alias column names if any
4472  * are different from the underlying "real" names. For a function RTE,
4473  * always emit a complete column alias list; this is to protect against
4474  * possible instability of the default column names (eg, from altering
4475  * parameter names). For tablefunc RTEs, we never print aliases, because
4476  * the column names are part of the clause itself. For other RTE types,
4477  * print if we changed anything OR if there were user-written column
4478  * aliases (since the latter would be part of the underlying "reality").
4479  */
4480  if (rte->rtekind == RTE_RELATION)
4481  colinfo->printaliases = changed_any;
4482  else if (rte->rtekind == RTE_FUNCTION)
4483  colinfo->printaliases = true;
4484  else if (rte->rtekind == RTE_TABLEFUNC)
4485  colinfo->printaliases = false;
4486  else if (rte->alias && rte->alias->colnames != NIL)
4487  colinfo->printaliases = true;
4488  else
4489  colinfo->printaliases = changed_any;
4490 }
4491 
4492 /*
4493  * set_join_column_names: select column aliases for a join RTE
4494  *
4495  * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4496  * If any colnames entries are already filled in, those override local
4497  * choices. Also, names for USING columns were already chosen by
4498  * set_using_names(). We further expect that column alias selection has been
4499  * completed for both input RTEs.
4500  */
4501 static void
4503  deparse_columns *colinfo)
4504 {
4505  deparse_columns *leftcolinfo;
4506  deparse_columns *rightcolinfo;
4507  bool changed_any;
4508  int noldcolumns;
4509  int nnewcolumns;
4510  Bitmapset *leftmerged = NULL;
4511  Bitmapset *rightmerged = NULL;
4512  int i;
4513  int j;
4514  int ic;
4515  int jc;
4516 
4517  /* Look up the previously-filled-in child deparse_columns structs */
4518  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4519  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4520 
4521  /*
4522  * Ensure colinfo->colnames has a slot for each column. (It could be long
4523  * enough already, if we pushed down a name for the last column.) Note:
4524  * it's possible that one or both inputs now have more columns than there
4525  * were when the query was parsed, but we'll deal with that below. We
4526  * only need entries in colnames for pre-existing columns.
4527  */
4528  noldcolumns = list_length(rte->eref->colnames);
4529  expand_colnames_array_to(colinfo, noldcolumns);
4530  Assert(colinfo->num_cols == noldcolumns);
4531 
4532  /*
4533  * Scan the join output columns, select an alias for each one, and store
4534  * it in colinfo->colnames. If there are USING columns, set_using_names()
4535  * already selected their names, so we can start the loop at the first
4536  * non-merged column.
4537  */
4538  changed_any = false;
4539  for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4540  {
4541  char *colname = colinfo->colnames[i];
4542  char *real_colname;
4543 
4544  /* Join column must refer to at least one input column */
4545  Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4546 
4547  /* Get the child column name */
4548  if (colinfo->leftattnos[i] > 0)
4549  real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4550  else if (colinfo->rightattnos[i] > 0)
4551  real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4552  else
4553  {
4554  /* We're joining system columns --- use eref name */
4555  real_colname = strVal(list_nth(rte->eref->colnames, i));
4556  }
4557 
4558  /* If child col has been dropped, no need to assign a join colname */
4559  if (real_colname == NULL)
4560  {
4561  colinfo->colnames[i] = NULL;
4562  continue;
4563  }
4564 
4565  /* In an unnamed join, just report child column names as-is */
4566  if (rte->alias == NULL)
4567  {
4568  colinfo->colnames[i] = real_colname;
4569  continue;
4570  }
4571 
4572  /* If alias already assigned, that's what to use */
4573  if (colname == NULL)
4574  {
4575  /* If user wrote an alias, prefer that over real column name */
4576  if (rte->alias && i < list_length(rte->alias->colnames))
4577  colname = strVal(list_nth(rte->alias->colnames, i));
4578  else
4579  colname = real_colname;
4580 
4581  /* Unique-ify and insert into colinfo */
4582  colname = make_colname_unique(colname, dpns, colinfo);
4583 
4584  colinfo->colnames[i] = colname;
4585  }
4586 
4587  /* Remember if any assigned aliases differ from "real" name */
4588  if (!changed_any && strcmp(colname, real_colname) != 0)
4589  changed_any = true;
4590  }
4591 
4592  /*
4593  * Calculate number of columns the join would have if it were re-parsed
4594  * now, and create storage for the new_colnames and is_new_col arrays.
4595  *
4596  * Note: colname_is_unique will be consulting new_colnames[] during the
4597  * loops below, so its not-yet-filled entries must be zeroes.
4598  */
4599  nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4600  list_length(colinfo->usingNames);
4601  colinfo->num_new_cols = nnewcolumns;
4602  colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4603  colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4604 
4605  /*
4606  * Generating the new_colnames array is a bit tricky since any new columns
4607  * added since parse time must be inserted in the right places. This code
4608  * must match the parser, which will order a join's columns as merged
4609  * columns first (in USING-clause order), then non-merged columns from the
4610  * left input (in attnum order), then non-merged columns from the right
4611  * input (ditto). If one of the inputs is itself a join, its columns will
4612  * be ordered according to the same rule, which means newly-added columns
4613  * might not be at the end. We can figure out what's what by consulting
4614  * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4615  *
4616  * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4617  * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4618  * meanings for the current child RTE.
4619  */
4620 
4621  /* Handle merged columns; they are first and can't be new */
4622  i = j = 0;
4623  while (i < noldcolumns &&
4624  colinfo->leftattnos[i] != 0 &&
4625  colinfo->rightattnos[i] != 0)
4626  {
4627  /* column name is already determined and known unique */
4628  colinfo->new_colnames[j] = colinfo->colnames[i];
4629  colinfo->is_new_col[j] = false;
4630 
4631  /* build bitmapsets of child attnums of merged columns */
4632  if (colinfo->leftattnos[i] > 0)
4633  leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4634  if (colinfo->rightattnos[i] > 0)
4635  rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4636 
4637  i++, j++;
4638  }
4639 
4640  /* Handle non-merged left-child columns */
4641  ic = 0;
4642  for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4643  {
4644  char *child_colname = leftcolinfo->new_colnames[jc];
4645 
4646  if (!leftcolinfo->is_new_col[jc])
4647  {
4648  /* Advance ic to next non-dropped old column of left child */
4649  while (ic < leftcolinfo->num_cols &&
4650  leftcolinfo->colnames[ic] == NULL)
4651  ic++;
4652  Assert(ic < leftcolinfo->num_cols);
4653  ic++;
4654  /* If it is a merged column, we already processed it */
4655  if (bms_is_member(ic, leftmerged))
4656  continue;
4657  /* Else, advance i to the corresponding existing join column */
4658  while (i < colinfo->num_cols &&
4659  colinfo->colnames[i] == NULL)
4660  i++;
4661  Assert(i < colinfo->num_cols);
4662  Assert(ic == colinfo->leftattnos[i]);
4663  /* Use the already-assigned name of this column */
4664  colinfo->new_colnames[j] = colinfo->colnames[i];
4665  i++;
4666  }
4667  else
4668  {
4669  /*
4670  * Unique-ify the new child column name and assign, unless we're
4671  * in an unnamed join, in which case just copy
4672  */
4673  if (rte->alias != NULL)
4674  {
4675  colinfo->new_colnames[j] =
4676  make_colname_unique(child_colname, dpns, colinfo);
4677  if (!changed_any &&
4678  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4679  changed_any = true;
4680  }
4681  else
4682  colinfo->new_colnames[j] = child_colname;
4683  }
4684 
4685  colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4686  j++;
4687  }
4688 
4689  /* Handle non-merged right-child columns in exactly the same way */
4690  ic = 0;
4691  for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4692  {
4693  char *child_colname = rightcolinfo->new_colnames[jc];
4694 
4695  if (!rightcolinfo->is_new_col[jc])
4696  {
4697  /* Advance ic to next non-dropped old column of right child */
4698  while (ic < rightcolinfo->num_cols &&
4699  rightcolinfo->colnames[ic] == NULL)
4700  ic++;
4701  Assert(ic < rightcolinfo->num_cols);
4702  ic++;
4703  /* If it is a merged column, we already processed it */
4704  if (bms_is_member(ic, rightmerged))
4705  continue;
4706  /* Else, advance i to the corresponding existing join column */
4707  while (i < colinfo->num_cols &&
4708  colinfo->colnames[i] == NULL)
4709  i++;
4710  Assert(i < colinfo->num_cols);
4711  Assert(ic == colinfo->rightattnos[i]);
4712  /* Use the already-assigned name of this column */
4713  colinfo->new_colnames[j] = colinfo->colnames[i];
4714  i++;
4715  }
4716  else
4717  {
4718  /*
4719  * Unique-ify the new child column name and assign, unless we're
4720  * in an unnamed join, in which case just copy
4721  */
4722  if (rte->alias != NULL)
4723  {
4724  colinfo->new_colnames[j] =
4725  make_colname_unique(child_colname, dpns, colinfo);
4726  if (!changed_any &&
4727  strcmp(colinfo->new_colnames[j], child_colname) != 0)
4728  changed_any = true;
4729  }
4730  else
4731  colinfo->new_colnames[j] = child_colname;
4732  }
4733 
4734  colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4735  j++;
4736  }
4737 
4738  /* Assert we processed the right number of columns */
4739 #ifdef USE_ASSERT_CHECKING
4740  while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4741  i++;
4742  Assert(i == colinfo->num_cols);
4743  Assert(j == nnewcolumns);
4744 #endif
4745 
4746  /*
4747  * For a named join, print column aliases if we changed any from the child
4748  * names. Unnamed joins cannot print aliases.
4749  */
4750  if (rte->alias != NULL)
4751  colinfo->printaliases = changed_any;
4752  else
4753  colinfo->printaliases = false;
4754 }
4755 
4756 /*
4757  * colname_is_unique: is colname distinct from already-chosen column names?
4758  *
4759  * dpns is query-wide info, colinfo is for the column's RTE
4760  */
4761 static bool
4762 colname_is_unique(const char *colname, deparse_namespace *dpns,
4763  deparse_columns *colinfo)
4764 {
4765  int i;
4766  ListCell *lc;
4767 
4768  /* Check against already-assigned column aliases within RTE */
4769  for (i = 0; i < colinfo->num_cols; i++)
4770  {
4771  char *oldname = colinfo->colnames[i];
4772 
4773  if (oldname && strcmp(oldname, colname) == 0)
4774  return false;
4775  }
4776 
4777  /*
4778  * If we're building a new_colnames array, check that too (this will be
4779  * partially but not completely redundant with the previous checks)
4780  */
4781  for (i = 0; i < colinfo->num_new_cols; i++)
4782  {
4783  char *oldname = colinfo->new_colnames[i];
4784 
4785  if (oldname && strcmp(oldname, colname) == 0)
4786  return false;
4787  }
4788 
4789  /* Also check against USING-column names that must be globally unique */
4790  foreach(lc, dpns->using_names)
4791  {
4792  char *oldname = (char *) lfirst(lc);
4793 
4794  if (strcmp(oldname, colname) == 0)
4795  return false;
4796  }
4797 
4798  /* Also check against names already assigned for parent-join USING cols */
4799  foreach(lc, colinfo->parentUsing)
4800  {
4801  char *oldname = (char *) lfirst(lc);
4802 
4803  if (strcmp(oldname, colname) == 0)
4804  return false;
4805  }
4806 
4807  return true;
4808 }
4809 
4810 /*
4811  * make_colname_unique: modify colname if necessary to make it unique
4812  *
4813  * dpns is query-wide info, colinfo is for the column's RTE
4814  */
4815 static char *
4817  deparse_columns *colinfo)
4818 {
4819  /*
4820  * If the selected name isn't unique, append digits to make it so. For a
4821  * very long input name, we might have to truncate to stay within
4822  * NAMEDATALEN.
4823  */
4824  if (!colname_is_unique(colname, dpns, colinfo))
4825  {
4826  int colnamelen = strlen(colname);
4827  char *modname = (char *) palloc(colnamelen + 16);
4828  int i = 0;
4829 
4830  do
4831  {
4832  i++;
4833  for (;;)
4834  {
4835  memcpy(modname, colname, colnamelen);
4836  sprintf(modname + colnamelen, "_%d", i);
4837  if (strlen(modname) < NAMEDATALEN)
4838  break;
4839  /* drop chars from colname to keep all the digits */
4840  colnamelen = pg_mbcliplen(colname, colnamelen,
4841  colnamelen - 1);
4842  }
4843  } while (!colname_is_unique(modname, dpns, colinfo));
4844  colname = modname;
4845  }
4846  return colname;
4847 }
4848 
4849 /*
4850  * expand_colnames_array_to: make colinfo->colnames at least n items long
4851  *
4852  * Any added array entries are initialized to zero.
4853  */
4854 static void
4856 {
4857  if (n > colinfo->num_cols)
4858  {
4859  if (colinfo->colnames == NULL)
4860  colinfo->colnames = palloc0_array(char *, n);
4861  else
4862  colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4863  colinfo->num_cols = n;
4864  }
4865 }
4866 
4867 /*
4868  * identify_join_columns: figure out where columns of a join come from
4869  *
4870  * Fills the join-specific fields of the colinfo struct, except for
4871  * usingNames which is filled later.
4872  */
4873 static void
4875  deparse_columns *colinfo)
4876 {
4877  int numjoincols;
4878  int jcolno;
4879  int rcolno;
4880  ListCell *lc;
4881 
4882  /* Extract left/right child RT indexes */
4883  if (IsA(j->larg, RangeTblRef))
4884  colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
4885  else if (IsA(j->larg, JoinExpr))
4886  colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
4887  else
4888  elog(ERROR, "unrecognized node type in jointree: %d",
4889  (int) nodeTag(j->larg));
4890  if (IsA(j->rarg, RangeTblRef))
4891  colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
4892  else if (IsA(j->rarg, JoinExpr))
4893  colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
4894  else
4895  elog(ERROR, "unrecognized node type in jointree: %d",
4896  (int) nodeTag(j->rarg));
4897 
4898  /* Assert children will be processed earlier than join in second pass */
4899  Assert(colinfo->leftrti < j->rtindex);
4900  Assert(colinfo->rightrti < j->rtindex);
4901 
4902  /* Initialize result arrays with zeroes */
4903  numjoincols = list_length(jrte->joinaliasvars);
4904  Assert(numjoincols == list_length(jrte->eref->colnames));
4905  colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
4906  colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
4907 
4908  /*
4909  * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
4910  * Recall that the column(s) merged due to USING are the first column(s)
4911  * of the join output. We need not do anything special while scanning
4912  * joinleftcols, but while scanning joinrightcols we must distinguish
4913  * merged from unmerged columns.
4914  */
4915  jcolno = 0;
4916  foreach(lc, jrte->joinleftcols)
4917  {
4918  int leftattno = lfirst_int(lc);
4919 
4920  colinfo->leftattnos[jcolno++] = leftattno;
4921  }
4922  rcolno = 0;
4923  foreach(lc, jrte->joinrightcols)
4924  {
4925  int rightattno = lfirst_int(lc);
4926 
4927  if (rcolno < jrte->joinmergedcols) /* merged column? */
4928  colinfo->rightattnos[rcolno] = rightattno;
4929  else
4930  colinfo->rightattnos[jcolno++] = rightattno;
4931  rcolno++;
4932  }
4933  Assert(jcolno == numjoincols);
4934 }
4935 
4936 /*
4937  * get_rtable_name: convenience function to get a previously assigned RTE alias
4938  *
4939  * The RTE must belong to the topmost namespace level in "context".
4940  */
4941 static char *
4943 {
4944  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
4945 
4946  Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4947  return (char *) list_nth(dpns->rtable_names, rtindex - 1);
4948 }
4949 
4950 /*
4951  * set_deparse_plan: set up deparse_namespace to parse subexpressions
4952  * of a given Plan node
4953  *
4954  * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
4955  * and index_tlist fields. Caller must already have adjusted the ancestors
4956  * list if necessary. Note that the rtable, subplans, and ctes fields do
4957  * not need to change when shifting attention to different plan nodes in a
4958  * single plan tree.
4959  */
4960 static void
4962 {
4963  dpns->plan = plan;
4964 
4965  /*
4966  * We special-case Append and MergeAppend to pretend that the first child
4967  * plan is the OUTER referent; we have to interpret OUTER Vars in their
4968  * tlists according to one of the children, and the first one is the most
4969  * natural choice.
4970  */
4971  if (IsA(plan, Append))
4972  dpns->outer_plan = linitial(((Append *) plan)->appendplans);
4973  else if (IsA(plan, MergeAppend))
4974  dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
4975  else
4976  dpns->outer_plan = outerPlan(plan);
4977 
4978  if (dpns->outer_plan)
4979  dpns->outer_tlist = dpns->outer_plan->targetlist;
4980  else
4981  dpns->outer_tlist = NIL;
4982 
4983  /*
4984  * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
4985  * use OUTER because that could someday conflict with the normal meaning.)
4986  * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
4987  * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
4988  * that as INNER referent.
4989  *
4990  * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
4991  * INNER referent. This is the join from the target relation to the data
4992  * source, and all INNER_VAR Vars in other parts of the query refer to its
4993  * targetlist.
4994  *
4995  * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
4996  * excluded expression's tlist. (Similar to the SubqueryScan we don't want
4997  * to reuse OUTER, it's used for RETURNING in some modify table cases,
4998  * although not INSERT .. CONFLICT).
4999  */
5000  if (IsA(plan, SubqueryScan))
5001  dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5002  else if (IsA(plan, CteScan))
5003  dpns->inner_plan = list_nth(dpns->subplans,
5004  ((CteScan *) plan)->ctePlanId - 1);
5005  else if (IsA(plan, WorkTableScan))
5006  dpns->inner_plan = find_recursive_union(dpns,
5007  (WorkTableScan *) plan);
5008  else if (IsA(plan, ModifyTable))
5009  {
5010  if (((ModifyTable *) plan)->operation == CMD_MERGE)
5011  dpns->inner_plan = outerPlan(plan);
5012  else
5013  dpns->inner_plan = plan;
5014  }
5015  else
5016  dpns->inner_plan = innerPlan(plan);
5017 
5018  if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5019  dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5020  else if (dpns->inner_plan)
5021  dpns->inner_tlist = dpns->inner_plan->targetlist;
5022  else
5023  dpns->inner_tlist = NIL;
5024 
5025  /* Set up referent for INDEX_VAR Vars, if needed */
5026  if (IsA(plan, IndexOnlyScan))
5027  dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5028  else if (IsA(plan, ForeignScan))
5029  dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5030  else if (IsA(plan, CustomScan))
5031  dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5032  else
5033  dpns->index_tlist = NIL;
5034 }
5035 
5036 /*
5037  * Locate the ancestor plan node that is the RecursiveUnion generating
5038  * the WorkTableScan's work table. We can match on wtParam, since that
5039  * should be unique within the plan tree.
5040  */
5041 static Plan *
5043 {
5044  ListCell *lc;
5045 
5046  foreach(lc, dpns->ancestors)
5047  {
5048  Plan *ancestor = (Plan *) lfirst(lc);
5049 
5050  if (IsA(ancestor, RecursiveUnion) &&
5051  ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5052  return ancestor;
5053  }
5054  elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5055  wtscan->wtParam);
5056  return NULL;
5057 }
5058 
5059 /*
5060  * push_child_plan: temporarily transfer deparsing attention to a child plan
5061  *
5062  * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5063  * deparse context in case the referenced expression itself uses
5064  * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5065  * affecting levelsup issues (although in a Plan tree there really shouldn't
5066  * be any).
5067  *
5068  * Caller must provide a local deparse_namespace variable to save the
5069  * previous state for pop_child_plan.
5070  */
5071 static void
5073  deparse_namespace *save_dpns)
5074 {
5075  /* Save state for restoration later */
5076  *save_dpns = *dpns;
5077 
5078  /* Link current plan node into ancestors list */
5079  dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5080 
5081  /* Set attention on selected child */
5082  set_deparse_plan(dpns, plan);
5083 }
5084 
5085 /*
5086  * pop_child_plan: undo the effects of push_child_plan
5087  */
5088 static void
5090 {
5091  List *ancestors;
5092 
5093  /* Get rid of ancestors list cell added by push_child_plan */
5094  ancestors = list_delete_first(dpns->ancestors);
5095 
5096  /* Restore fields changed by push_child_plan */
5097  *dpns = *save_dpns;
5098 
5099  /* Make sure dpns->ancestors is right (may be unnecessary) */
5100  dpns->ancestors = ancestors;
5101 }
5102 
5103 /*
5104  * push_ancestor_plan: temporarily transfer deparsing attention to an
5105  * ancestor plan
5106  *
5107  * When expanding a Param reference, we must adjust the deparse context
5108  * to match the plan node that contains the expression being printed;
5109  * otherwise we'd fail if that expression itself contains a Param or
5110  * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5111  *
5112  * The target ancestor is conveniently identified by the ListCell holding it
5113  * in dpns->ancestors.
5114  *
5115  * Caller must provide a local deparse_namespace variable to save the
5116  * previous state for pop_ancestor_plan.
5117  */
5118 static void
5120  deparse_namespace *save_dpns)
5121 {
5122  Plan *plan = (Plan *) lfirst(ancestor_cell);
5123 
5124  /* Save state for restoration later */
5125  *save_dpns = *dpns;
5126 
5127  /* Build a new ancestor list with just this node's ancestors */
5128  dpns->ancestors =
5129  list_copy_tail(dpns->ancestors,
5130  list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5131 
5132  /* Set attention on selected ancestor */
5133  set_deparse_plan(dpns, plan);
5134 }
5135 
5136 /*
5137  * pop_ancestor_plan: undo the effects of push_ancestor_plan
5138  */
5139 static void
5141 {
5142  /* Free the ancestor list made in push_ancestor_plan */
5143  list_free(dpns->ancestors);
5144 
5145  /* Restore fields changed by push_ancestor_plan */
5146  *dpns = *save_dpns;
5147 }
5148 
5149 
5150 /* ----------
5151  * make_ruledef - reconstruct the CREATE RULE command
5152  * for a given pg_rewrite tuple
5153  * ----------
5154  */
5155 static void
5157  int prettyFlags)
5158 {
5159  char *rulename;
5160  char ev_type;
5161  Oid ev_class;
5162  bool is_instead;
5163  char *ev_qual;
5164  char *ev_action;
5165  List *actions;
5166  Relation ev_relation;
5167  TupleDesc viewResultDesc = NULL;
5168  int fno;
5169  Datum dat;
5170  bool isnull;
5171 
5172  /*
5173  * Get the attribute values from the rules tuple
5174  */
5175  fno = SPI_fnumber(rulettc, "rulename");
5176  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5177  Assert(!isnull);
5178  rulename = NameStr(*(DatumGetName(dat)));
5179 
5180  fno = SPI_fnumber(rulettc, "ev_type");
5181  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5182  Assert(!isnull);
5183  ev_type = DatumGetChar(dat);
5184 
5185  fno = SPI_fnumber(rulettc, "ev_class");
5186  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5187  Assert(!isnull);
5188  ev_class = DatumGetObjectId(dat);
5189 
5190  fno = SPI_fnumber(rulettc, "is_instead");
5191  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5192  Assert(!isnull);
5193  is_instead = DatumGetBool(dat);
5194 
5195  fno = SPI_fnumber(rulettc, "ev_qual");
5196  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5197  Assert(ev_qual != NULL);
5198 
5199  fno = SPI_fnumber(rulettc, "ev_action");
5200  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5201  Assert(ev_action != NULL);
5202  actions = (List *) stringToNode(ev_action);
5203  if (actions == NIL)
5204  elog(ERROR, "invalid empty ev_action list");
5205 
5206  ev_relation = table_open(ev_class, AccessShareLock);
5207 
5208  /*
5209  * Build the rules definition text
5210  */
5211  appendStringInfo(buf, "CREATE RULE %s AS",
5212  quote_identifier(rulename));
5213 
5214  if (prettyFlags & PRETTYFLAG_INDENT)
5215  appendStringInfoString(buf, "\n ON ");
5216  else
5217  appendStringInfoString(buf, " ON ");
5218 
5219  /* The event the rule is fired for */
5220  switch (ev_type)
5221  {
5222  case '1':
5223  appendStringInfoString(buf, "SELECT");
5224  viewResultDesc = RelationGetDescr(ev_relation);
5225  break;
5226 
5227  case '2':
5228  appendStringInfoString(buf, "UPDATE");
5229  break;
5230 
5231  case '3':
5232  appendStringInfoString(buf, "INSERT");
5233  break;
5234 
5235  case '4':
5236  appendStringInfoString(buf, "DELETE");
5237  break;
5238 
5239  default:
5240  ereport(ERROR,
5241  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5242  errmsg("rule \"%s\" has unsupported event type %d",
5243  rulename, ev_type)));
5244  break;
5245  }
5246 
5247  /* The relation the rule is fired on */
5248  appendStringInfo(buf, " TO %s",
5249  (prettyFlags & PRETTYFLAG_SCHEMA) ?
5250  generate_relation_name(ev_class, NIL) :
5252 
5253  /* If the rule has an event qualification, add it */
5254  if (strcmp(ev_qual, "<>") != 0)
5255  {
5256  Node *qual;
5257  Query *query;
5259  deparse_namespace dpns;
5260 
5261  if (prettyFlags & PRETTYFLAG_INDENT)
5262  appendStringInfoString(buf, "\n ");
5263  appendStringInfoString(buf, " WHERE ");
5264 
5265  qual = stringToNode(ev_qual);
5266 
5267  /*
5268  * We need to make a context for recognizing any Vars in the qual
5269  * (which can only be references to OLD and NEW). Use the rtable of
5270  * the first query in the action list for this purpose.
5271  */
5272  query = (Query *) linitial(actions);
5273 
5274  /*
5275  * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5276  * into the SELECT, and that's what we need to look at. (Ugly kluge
5277  * ... try to fix this when we redesign querytrees.)
5278  */
5279  query = getInsertSelectQuery(query, NULL);
5280 
5281  /* Must acquire locks right away; see notes in get_query_def() */
5282  AcquireRewriteLocks(query, false, false);
5283 
5284  context.buf = buf;
5285  context.namespaces = list_make1(&dpns);
5286  context.windowClause = NIL;
5287  context.windowTList = NIL;
5288  context.varprefix = (list_length(query->rtable) != 1);
5289  context.prettyFlags = prettyFlags;
5290  context.wrapColumn = WRAP_COLUMN_DEFAULT;
5291  context.indentLevel = PRETTYINDENT_STD;
5292  context.special_exprkind = EXPR_KIND_NONE;
5293  context.appendparents = NULL;
5294 
5295  set_deparse_for_query(&dpns, query, NIL);
5296 
5297  get_rule_expr(qual, &context, false);
5298  }
5299 
5300  appendStringInfoString(buf, " DO ");
5301 
5302  /* The INSTEAD keyword (if so) */
5303  if (is_instead)
5304  appendStringInfoString(buf, "INSTEAD ");
5305 
5306  /* Finally the rules actions */
5307  if (list_length(actions) > 1)
5308  {
5309  ListCell *action;
5310  Query *query;
5311 
5312  appendStringInfoChar(buf, '(');
5313  foreach(action, actions)
5314  {
5315  query = (Query *) lfirst(action);
5316  get_query_def(query, buf, NIL, viewResultDesc, true,
5317  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5318  if (prettyFlags)
5319  appendStringInfoString(buf, ";\n");
5320  else
5321  appendStringInfoString(buf, "; ");
5322  }
5323  appendStringInfoString(buf, ");");
5324  }
5325  else
5326  {
5327  Query *query;
5328 
5329  query = (Query *) linitial(actions);
5330  get_query_def(query, buf, NIL, viewResultDesc, true,
5331  prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5332  appendStringInfoChar(buf, ';');
5333  }
5334 
5335  table_close(ev_relation, AccessShareLock);
5336 }
5337 
5338 
5339 /* ----------
5340  * make_viewdef - reconstruct the SELECT part of a
5341  * view rewrite rule
5342  * ----------
5343  */
5344 static void
5346  int prettyFlags, int wrapColumn)
5347 {
5348  Query *query;
5349  char ev_type;
5350  Oid ev_class;
5351  bool is_instead;
5352  char *ev_qual;
5353  char *ev_action;
5354  List *actions;
5355  Relation ev_relation;
5356  int fno;
5357  Datum dat;
5358  bool isnull;
5359 
5360  /*
5361  * Get the attribute values from the rules tuple
5362  */
5363  fno = SPI_fnumber(rulettc, "ev_type");
5364  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5365  Assert(!isnull);
5366  ev_type = DatumGetChar(dat);
5367 
5368  fno = SPI_fnumber(rulettc, "ev_class");
5369  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5370  Assert(!isnull);
5371  ev_class = DatumGetObjectId(dat);
5372 
5373  fno = SPI_fnumber(rulettc, "is_instead");
5374  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5375  Assert(!isnull);
5376  is_instead = DatumGetBool(dat);
5377 
5378  fno = SPI_fnumber(rulettc, "ev_qual");
5379  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5380  Assert(ev_qual != NULL);
5381 
5382  fno = SPI_fnumber(rulettc, "ev_action");
5383  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5384  Assert(ev_action != NULL);
5385  actions = (List *) stringToNode(ev_action);
5386 
5387  if (list_length(actions) != 1)
5388  {
5389  /* keep output buffer empty and leave */
5390  return;
5391  }
5392 
5393  query = (Query *) linitial(actions);
5394 
5395  if (ev_type != '1' || !is_instead ||
5396  strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5397  {
5398  /* keep output buffer empty and leave */
5399  return;
5400  }
5401 
5402  ev_relation = table_open(ev_class, AccessShareLock);
5403 
5404  get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5405  prettyFlags, wrapColumn, 0);
5406  appendStringInfoChar(buf, ';');
5407 
5408  table_close(ev_relation, AccessShareLock);
5409 }
5410 
5411 
5412 /* ----------
5413  * get_query_def - Parse back one query parsetree
5414  *
5415  * query: parsetree to be displayed
5416  * buf: output text is appended to buf
5417  * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5418  * resultDesc: if not NULL, the output tuple descriptor for the view
5419  * represented by a SELECT query. We use the column names from it
5420  * to label SELECT output columns, in preference to names in the query
5421  * colNamesVisible: true if the surrounding context cares about the output
5422  * column names at all (as, for example, an EXISTS() context does not);
5423  * when false, we can suppress dummy column labels such as "?column?"
5424  * prettyFlags: bitmask of PRETTYFLAG_XXX options
5425  * wrapColumn: maximum line length, or -1 to disable wrapping
5426  * startIndent: initial indentation amount
5427  * ----------
5428  */
5429 static void
5430 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5431  TupleDesc resultDesc, bool colNamesVisible,
5432  int prettyFlags, int wrapColumn, int startIndent)
5433 {
5435  deparse_namespace dpns;
5436 
5437  /* Guard against excessively long or deeply-nested queries */
5440 
5441  /*
5442  * Before we begin to examine the query, acquire locks on referenced
5443  * relations, and fix up deleted columns in JOIN RTEs. This ensures
5444  * consistent results. Note we assume it's OK to scribble on the passed
5445  * querytree!
5446  *
5447  * We are only deparsing the query (we are not about to execute it), so we
5448  * only need AccessShareLock on the relations it mentions.
5449  */
5450  AcquireRewriteLocks(query, false, false);
5451 
5452  context.buf = buf;
5453  context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5454  context.windowClause = NIL;
5455  context.windowTList = NIL;
5456  context.varprefix = (parentnamespace != NIL ||
5457  list_length(query->rtable) != 1);
5458  context.prettyFlags = prettyFlags;
5459  context.wrapColumn = wrapColumn;
5460  context.indentLevel = startIndent;
5461  context.special_exprkind = EXPR_KIND_NONE;
5462  context.appendparents = NULL;
5463 
5464  set_deparse_for_query(&dpns, query, parentnamespace);
5465 
5466  switch (query->commandType)
5467  {
5468  case CMD_SELECT:
5469  get_select_query_def(query, &context, resultDesc, colNamesVisible);
5470  break;
5471 
5472  case CMD_UPDATE:
5473  get_update_query_def(query, &context, colNamesVisible);
5474  break;
5475 
5476  case CMD_INSERT:
5477  get_insert_query_def(query, &context, colNamesVisible);
5478  break;
5479 
5480  case CMD_DELETE:
5481  get_delete_query_def(query, &context, colNamesVisible);
5482  break;
5483 
5484  case CMD_MERGE:
5485  get_merge_query_def(query, &context, colNamesVisible);
5486  break;
5487 
5488  case CMD_NOTHING:
5489  appendStringInfoString(buf, "NOTHING");
5490  break;
5491 
5492  case CMD_UTILITY:
5493  get_utility_query_def(query, &context);
5494  break;
5495 
5496  default:
5497  elog(ERROR, "unrecognized query command type: %d",
5498  query->commandType);
5499  break;
5500  }
5501 }
5502 
5503 /* ----------
5504  * get_values_def - Parse back a VALUES list
5505  * ----------
5506  */
5507 static void
5509 {
5510  StringInfo buf = context->buf;
5511  bool first_list = true;
5512  ListCell *vtl;
5513 
5514  appendStringInfoString(buf, "VALUES ");
5515 
5516  foreach(vtl, values_lists)
5517  {
5518  List *sublist = (List *) lfirst(vtl);
5519  bool first_col = true;
5520  ListCell *lc;
5521 
5522  if (first_list)
5523  first_list = false;
5524  else
5525  appendStringInfoString(buf, ", ");
5526 
5527  appendStringInfoChar(buf, '(');
5528  foreach(lc, sublist)
5529  {
5530  Node *col = (Node *) lfirst(lc);
5531 
5532  if (first_col)
5533  first_col = false;
5534  else
5535  appendStringInfoChar(buf, ',');
5536 
5537  /*
5538  * Print the value. Whole-row Vars need special treatment.
5539  */
5540  get_rule_expr_toplevel(col, context, false);
5541  }
5542  appendStringInfoChar(buf, ')');
5543  }
5544 }
5545 
5546 /* ----------
5547  * get_with_clause - Parse back a WITH clause
5548  * ----------
5549  */
5550 static void
5552 {
5553  StringInfo buf = context->buf;
5554  const char *sep;
5555  ListCell *l;
5556 
5557  if (query->cteList == NIL)
5558  return;
5559 
5560  if (PRETTY_INDENT(context))
5561  {
5562  context->indentLevel += PRETTYINDENT_STD;
5563  appendStringInfoChar(buf, ' ');
5564  }
5565 
5566  if (query->hasRecursive)
5567  sep = "WITH RECURSIVE ";
5568  else
5569  sep = "WITH ";
5570  foreach(l, query->cteList)
5571  {
5572  CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5573 
5576  if (cte->aliascolnames)
5577  {
5578  bool first = true;
5579  ListCell *col;
5580 
5581  appendStringInfoChar(buf, '(');
5582  foreach(col, cte->aliascolnames)
5583  {
5584  if (first)
5585  first = false;
5586  else
5587  appendStringInfoString(buf, ", ");
5589  quote_identifier(strVal(lfirst(col))));
5590  }
5591  appendStringInfoChar(buf, ')');
5592  }
5593  appendStringInfoString(buf, " AS ");
5594  switch (cte->ctematerialized)
5595  {
5596  case CTEMaterializeDefault:
5597  break;
5598  case CTEMaterializeAlways:
5599  appendStringInfoString(buf, "MATERIALIZED ");
5600  break;
5601  case CTEMaterializeNever:
5602  appendStringInfoString(buf, "NOT MATERIALIZED ");
5603  break;
5604  }
5605  appendStringInfoChar(buf, '(');
5606  if (PRETTY_INDENT(context))
5607  appendContextKeyword(context, "", 0, 0, 0);
5608  get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5609  true,
5610  context->prettyFlags, context->wrapColumn,
5611  context->indentLevel);
5612  if (PRETTY_INDENT(context))
5613  appendContextKeyword(context, "", 0, 0, 0);
5614  appendStringInfoChar(buf, ')');
5615 
5616  if (cte->search_clause)
5617  {
5618  bool first = true;
5619  ListCell *lc;
5620 
5621  appendStringInfo(buf, " SEARCH %s FIRST BY ",
5622  cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5623 
5624  foreach(lc, cte->search_clause->search_col_list)
5625  {
5626  if (first)
5627  first = false;
5628  else
5629  appendStringInfoString(buf, ", ");
5632  }
5633 
5634  appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5635  }
5636 
5637  if (cte->cycle_clause)
5638  {
5639  bool first = true;
5640  ListCell *lc;
5641 
5642  appendStringInfoString(buf, " CYCLE ");
5643 
5644  foreach(lc, cte->cycle_clause->cycle_col_list)
5645  {
5646  if (first)
5647  first = false;
5648  else
5649  appendStringInfoString(buf, ", ");
5652  }
5653 
5654  appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5655 
5656  {
5657  Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5658  Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5659 
5660  if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5661  cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5662  {
5663  appendStringInfoString(buf, " TO ");
5664  get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5665  appendStringInfoString(buf, " DEFAULT ");
5666  get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5667  }
5668  }
5669 
5670  appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5671  }
5672 
5673  sep = ", ";
5674  }
5675 
5676  if (PRETTY_INDENT(context))
5677  {
5678  context->indentLevel -= PRETTYINDENT_STD;
5679  appendContextKeyword(context, "", 0, 0, 0);
5680  }
5681  else
5682  appendStringInfoChar(buf, ' ');
5683 }
5684 
5685 /* ----------
5686  * get_select_query_def - Parse back a SELECT parsetree
5687  * ----------
5688  */
5689 static void
5691  TupleDesc resultDesc, bool colNamesVisible)
5692 {
5693  StringInfo buf = context->buf;
5694  List *save_windowclause;
5695  List *save_windowtlist;
5696  bool force_colno;
5697  ListCell *l;
5698 
5699  /* Insert the WITH clause if given */
5700  get_with_clause(query, context);
5701 
5702  /* Set up context for possible window functions */
5703  save_windowclause = context->windowClause;
5704  context->windowClause = query->windowClause;
5705  save_windowtlist = context->windowTList;
5706  context->windowTList = query->targetList;
5707 
5708  /*
5709  * If the Query node has a setOperations tree, then it's the top level of
5710  * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5711  * fields are interesting in the top query itself.
5712  */
5713  if (query->setOperations)
5714  {
5715  get_setop_query(query->setOperations, query, context, resultDesc,
5716  colNamesVisible);
5717  /* ORDER BY clauses must be simple in this case */
5718  force_colno = true;
5719  }
5720  else
5721  {
5722  get_basic_select_query(query, context, resultDesc, colNamesVisible);
5723  force_colno = false;
5724  }
5725 
5726  /* Add the ORDER BY clause if given */
5727  if (query->sortClause != NIL)
5728  {
5729  appendContextKeyword(context, " ORDER BY ",
5731  get_rule_orderby(query->sortClause, query->targetList,
5732  force_colno, context);
5733  }
5734 
5735  /*
5736  * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5737  * standard spelling of LIMIT.
5738  */
5739  if (query->limitOffset != NULL)
5740  {
5741  appendContextKeyword(context, " OFFSET ",
5743  get_rule_expr(query->limitOffset, context, false);
5744  }
5745  if (query->limitCount != NULL)
5746  {
5747  if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5748  {
5749  appendContextKeyword(context, " FETCH FIRST ",
5751  get_rule_expr(query->limitCount, context, false);
5752  appendStringInfoString(buf, " ROWS WITH TIES");
5753  }
5754  else
5755  {
5756  appendContextKeyword(context, " LIMIT ",
5758  if (IsA(query->limitCount, Const) &&
5759  ((Const *) query->limitCount)->constisnull)
5760  appendStringInfoString(buf, "ALL");
5761  else
5762  get_rule_expr(query->limitCount, context, false);
5763  }
5764  }
5765 
5766  /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5767  if (query->hasForUpdate)
5768  {
5769  foreach(l, query->rowMarks)
5770  {
5771  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5772 
5773  /* don't print implicit clauses */
5774  if (rc->pushedDown)
5775  continue;
5776 
5777  switch (rc->strength)
5778  {
5779  case LCS_NONE:
5780  /* we intentionally throw an error for LCS_NONE */
5781  elog(ERROR, "unrecognized LockClauseStrength %d",
5782  (int) rc->strength);
5783  break;
5784  case LCS_FORKEYSHARE:
5785  appendContextKeyword(context, " FOR KEY SHARE",
5787  break;
5788  case LCS_FORSHARE:
5789  appendContextKeyword(context, " FOR SHARE",
5791  break;
5792  case LCS_FORNOKEYUPDATE:
5793  appendContextKeyword(context, " FOR NO KEY UPDATE",
5795  break;
5796  case LCS_FORUPDATE:
5797  appendContextKeyword(context, " FOR UPDATE",
5799  break;
5800  }
5801 
5802  appendStringInfo(buf, " OF %s",
5804  context)));
5805  if (rc->waitPolicy == LockWaitError)
5806  appendStringInfoString(buf, " NOWAIT");
5807  else if (rc->waitPolicy == LockWaitSkip)
5808  appendStringInfoString(buf, " SKIP LOCKED");
5809  }
5810  }
5811 
5812  context->windowClause = save_windowclause;
5813  context->windowTList = save_windowtlist;
5814 }
5815 
5816 /*
5817  * Detect whether query looks like SELECT ... FROM VALUES(),
5818  * with no need to rename the output columns of the VALUES RTE.
5819  * If so, return the VALUES RTE. Otherwise return NULL.
5820  */
5821 static RangeTblEntry *
5823 {
5824  RangeTblEntry *result = NULL;
5825  ListCell *lc;
5826 
5827  /*
5828  * We want to detect a match even if the Query also contains OLD or NEW
5829  * rule RTEs. So the idea is to scan the rtable and see if there is only
5830  * one inFromCl RTE that is a VALUES RTE.
5831  */
5832  foreach(lc, query->rtable)
5833  {
5834  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
5835 
5836  if (rte->rtekind == RTE_VALUES && rte->inFromCl)
5837  {
5838  if (result)
5839  return NULL; /* multiple VALUES (probably not possible) */
5840  result = rte;
5841  }
5842  else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
5843  continue; /* ignore rule entries */
5844  else
5845  return NULL; /* something else -> not simple VALUES */
5846  }
5847 
5848  /*
5849  * We don't need to check the targetlist in any great detail, because
5850  * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
5851  * appear inside auto-generated sub-queries with very restricted
5852  * structure. However, DefineView might have modified the tlist by
5853  * injecting new column aliases, or we might have some other column
5854  * aliases forced by a resultDesc. We can only simplify if the RTE's
5855  * column names match the names that get_target_list() would select.
5856  */
5857  if (result)
5858  {
5859  ListCell *lcn;
5860  int colno;
5861 
5862  if (list_length(query->targetList) != list_length(result->eref->colnames))
5863  return NULL; /* this probably cannot happen */
5864  colno = 0;
5865  forboth(lc, query->targetList, lcn, result->eref->colnames)
5866  {
5867  TargetEntry *tle = (TargetEntry *) lfirst(lc);
5868  char *cname = strVal(lfirst(lcn));
5869  char *colname;
5870 
5871  if (tle->resjunk)
5872  return NULL; /* this probably cannot happen */
5873 
5874  /* compute name that get_target_list would use for column */
5875  colno++;
5876  if (resultDesc && colno <= resultDesc->natts)
5877  colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5878  else
5879  colname = tle->resname;
5880 
5881  /* does it match the VALUES RTE? */
5882  if (colname == NULL || strcmp(colname, cname) != 0)
5883  return NULL; /* column name has been changed */
5884  }
5885  }
5886 
5887  return result;
5888 }
5889 
5890 static void
5892  TupleDesc resultDesc, bool colNamesVisible)
5893 {
5894  StringInfo buf = context->buf;
5895  RangeTblEntry *values_rte;
5896  char *sep;
5897  ListCell *l;
5898 
5899  if (PRETTY_INDENT(context))
5900  {
5901  context->indentLevel += PRETTYINDENT_STD;
5902  appendStringInfoChar(buf, ' ');
5903  }
5904 
5905  /*
5906  * If the query looks like SELECT * FROM (VALUES ...), then print just the
5907  * VALUES part. This reverses what transformValuesClause() did at parse
5908  * time.
5909  */
5910  values_rte = get_simple_values_rte(query, resultDesc);
5911  if (values_rte)
5912  {
5913  get_values_def(values_rte->values_lists, context);
5914  return;
5915  }
5916 
5917  /*
5918  * Build up the query string - first we say SELECT
5919  */
5920  if (query->isReturn)
5921  appendStringInfoString(buf, "RETURN");
5922  else
5923  appendStringInfoString(buf, "SELECT");
5924 
5925  /* Add the DISTINCT clause if given */
5926  if (query->distinctClause != NIL)
5927  {
5928  if (query->hasDistinctOn)
5929  {
5930  appendStringInfoString(buf, " DISTINCT ON (");
5931  sep = "";
5932  foreach(l, query->distinctClause)
5933  {
5934  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5935 
5938  false, context);
5939  sep = ", ";
5940  }
5941  appendStringInfoChar(buf, ')');
5942  }
5943  else
5944  appendStringInfoString(buf, " DISTINCT");
5945  }
5946 
5947  /* Then we tell what to select (the targetlist) */
5948  get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5949 
5950  /* Add the FROM clause if needed */
5951  get_from_clause(query, " FROM ", context);
5952 
5953  /* Add the WHERE clause if given */
5954  if (query->jointree->quals != NULL)
5955  {
5956  appendContextKeyword(context, " WHERE ",
5958  get_rule_expr(query->jointree->quals, context, false);
5959  }
5960 
5961  /* Add the GROUP BY clause if given */
5962  if (query->groupClause != NULL || query->groupingSets != NULL)
5963  {
5964  ParseExprKind save_exprkind;
5965 
5966  appendContextKeyword(context, " GROUP BY ",
5968  if (query->groupDistinct)
5969  appendStringInfoString(buf, "DISTINCT ");
5970 
5971  save_exprkind = context->special_exprkind;
5972  context->special_exprkind = EXPR_KIND_GROUP_BY;
5973 
5974  if (query->groupingSets == NIL)
5975  {
5976  sep = "";
5977  foreach(l, query->groupClause)
5978  {
5979  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5980 
5983  false, context);
5984  sep = ", ";
5985  }
5986  }
5987  else
5988  {
5989  sep = "";
5990  foreach(l, query->groupingSets)
5991  {
5992  GroupingSet *grp = lfirst(l);
5993 
5995  get_rule_groupingset(grp, query->targetList, true, context);
5996  sep = ", ";
5997  }
5998  }
5999 
6000  context->special_exprkind = save_exprkind;
6001  }
6002 
6003  /* Add the HAVING clause if given */
6004  if (query->havingQual != NULL)
6005  {
6006  appendContextKeyword(context, " HAVING ",
6008  get_rule_expr(query->havingQual, context, false);
6009  }
6010 
6011  /* Add the WINDOW clause if needed */
6012  if (query->windowClause != NIL)
6014 }
6015 
6016 /* ----------
6017  * get_target_list - Parse back a SELECT target list
6018  *
6019  * This is also used for RETURNING lists in INSERT/UPDATE/DELETE/MERGE.
6020  *
6021  * resultDesc and colNamesVisible are as for get_query_def()
6022  * ----------
6023  */
6024 static void
6026  TupleDesc resultDesc, bool colNamesVisible)
6027 {
6028  StringInfo buf = context->buf;
6029  StringInfoData targetbuf;
6030  bool last_was_multiline = false;
6031  char *sep;
6032  int colno;
6033  ListCell *l;
6034 
6035  /* we use targetbuf to hold each TLE's text temporarily */
6036  initStringInfo(&targetbuf);
6037 
6038  sep = " ";
6039  colno = 0;
6040  foreach(l, targetList)
6041  {
6042  TargetEntry *tle = (TargetEntry *) lfirst(l);
6043  char *colname;
6044  char *attname;
6045 
6046  if (tle->resjunk)
6047  continue; /* ignore junk entries */
6048 
6050  sep = ", ";
6051  colno++;
6052 
6053  /*
6054  * Put the new field text into targetbuf so we can decide after we've
6055  * got it whether or not it needs to go on a new line.
6056  */
6057  resetStringInfo(&targetbuf);
6058  context->buf = &targetbuf;
6059 
6060  /*
6061  * We special-case Var nodes rather than using get_rule_expr. This is
6062  * needed because get_rule_expr will display a whole-row Var as
6063  * "foo.*", which is the preferred notation in most contexts, but at
6064  * the top level of a SELECT list it's not right (the parser will
6065  * expand that notation into multiple columns, yielding behavior
6066  * different from a whole-row Var). We need to call get_variable
6067  * directly so that we can tell it to do the right thing, and so that
6068  * we can get the attribute name which is the default AS label.
6069  */
6070  if (tle->expr && (IsA(tle->expr, Var)))
6071  {
6072  attname = get_variable((Var *) tle->expr, 0, true, context);
6073  }
6074  else
6075  {
6076  get_rule_expr((Node *) tle->expr, context, true);
6077 
6078  /*
6079  * When colNamesVisible is true, we should always show the
6080  * assigned column name explicitly. Otherwise, show it only if
6081  * it's not FigureColname's fallback.
6082  */
6083  attname = colNamesVisible ? NULL : "?column?";
6084  }
6085 
6086  /*
6087  * Figure out what the result column should be called. In the context
6088  * of a view, use the view's tuple descriptor (so as to pick up the
6089  * effects of any column RENAME that's been done on the view).
6090  * Otherwise, just use what we can find in the TLE.
6091  */
6092  if (resultDesc && colno <= resultDesc->natts)
6093  colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6094  else
6095  colname = tle->resname;
6096 
6097  /* Show AS unless the column's name is correct as-is */
6098  if (colname) /* resname could be NULL */
6099  {
6100  if (attname == NULL || strcmp(attname, colname) != 0)
6101  appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6102  }
6103 
6104  /* Restore context's output buffer */
6105  context->buf = buf;
6106 
6107  /* Consider line-wrapping if enabled */
6108  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6109  {
6110  int leading_nl_pos;
6111 
6112  /* Does the new field start with a new line? */
6113  if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6114  leading_nl_pos = 0;
6115  else
6116  leading_nl_pos = -1;
6117 
6118  /* If so, we shouldn't add anything */
6119  if (leading_nl_pos >= 0)
6120  {
6121  /* instead, remove any trailing spaces currently in buf */
6123  }
6124  else
6125  {
6126  char *trailing_nl;
6127 
6128  /* Locate the start of the current line in the output buffer */
6129  trailing_nl = strrchr(buf->data, '\n');
6130  if (trailing_nl == NULL)
6131  trailing_nl = buf->data;
6132  else
6133  trailing_nl++;
6134 
6135  /*
6136  * Add a newline, plus some indentation, if the new field is
6137  * not the first and either the new field would cause an
6138  * overflow or the last field used more than one line.
6139  */
6140  if (colno > 1 &&
6141  ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6142  last_was_multiline))
6145  }
6146 
6147  /* Remember this field's multiline status for next iteration */
6148  last_was_multiline =
6149  (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6150  }
6151 
6152  /* Add the new field */
6153  appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6154  }
6155 
6156  /* clean up */
6157  pfree(targetbuf.data);
6158 }
6159 
6160 static void
6162  TupleDesc resultDesc, bool colNamesVisible)
6163 {
6164  StringInfo buf = context->buf;
6165  bool need_paren;
6166 
6167  /* Guard against excessively long or deeply-nested queries */
6170 
6171  if (IsA(setOp, RangeTblRef))
6172  {
6173  RangeTblRef *rtr = (RangeTblRef *) setOp;
6174  RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6175  Query *subquery = rte->subquery;
6176 
6177  Assert(subquery != NULL);
6178  Assert(subquery->setOperations == NULL);
6179  /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
6180  need_paren = (subquery->cteList ||
6181  subquery->sortClause ||
6182  subquery->rowMarks ||
6183  subquery->limitOffset ||
6184  subquery->limitCount);
6185  if (need_paren)
6186  appendStringInfoChar(buf, '(');
6187  get_query_def(subquery, buf, context->namespaces, resultDesc,
6188  colNamesVisible,
6189  context->prettyFlags, context->wrapColumn,
6190  context->indentLevel);
6191  if (need_paren)
6192  appendStringInfoChar(buf, ')');
6193  }
6194  else if (IsA(setOp, SetOperationStmt))
6195  {
6196  SetOperationStmt *op = (SetOperationStmt *) setOp;
6197  int subindent;
6198 
6199  /*
6200  * We force parens when nesting two SetOperationStmts, except when the
6201  * lefthand input is another setop of the same kind. Syntactically,
6202  * we could omit parens in rather more cases, but it seems best to use
6203  * parens to flag cases where the setop operator changes. If we use
6204  * parens, we also increase the indentation level for the child query.
6205  *
6206  * There are some cases in which parens are needed around a leaf query
6207  * too, but those are more easily handled at the next level down (see
6208  * code above).
6209  */
6210  if (IsA(op->larg, SetOperationStmt))
6211  {
6212  SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6213 
6214  if (op->op == lop->op && op->all == lop->all)
6215  need_paren = false;
6216  else
6217  need_paren = true;
6218  }
6219  else
6220  need_paren = false;
6221 
6222  if (need_paren)
6223  {
6224  appendStringInfoChar(buf, '(');
6225  subindent = PRETTYINDENT_STD;
6226  appendContextKeyword(context, "", subindent, 0, 0);
6227  }
6228  else
6229  subindent = 0;
6230 
6231  get_setop_query(op->larg, query, context, resultDesc, colNamesVisible);
6232 
6233  if (need_paren)
6234  appendContextKeyword(context, ") ", -subindent, 0, 0);
6235  else if (PRETTY_INDENT(context))
6236  appendContextKeyword(context, "", -subindent, 0, 0);
6237  else
6238  appendStringInfoChar(buf, ' ');
6239 
6240  switch (op->op)
6241  {
6242  case SETOP_UNION:
6243  appendStringInfoString(buf, "UNION ");
6244  break;
6245  case SETOP_INTERSECT:
6246  appendStringInfoString(buf, "INTERSECT ");
6247  break;
6248  case SETOP_EXCEPT:
6249  appendStringInfoString(buf, "EXCEPT ");
6250  break;
6251  default:
6252  elog(ERROR, "unrecognized set op: %d",
6253  (int) op->op);
6254  }
6255  if (op->all)
6256  appendStringInfoString(buf, "ALL ");
6257 
6258  /* Always parenthesize if RHS is another setop */
6259  need_paren = IsA(op->rarg, SetOperationStmt);
6260 
6261  /*
6262  * The indentation code here is deliberately a bit different from that
6263  * for the lefthand input, because we want the line breaks in
6264  * different places.
6265  */
6266  if (need_paren)
6267  {
6268  appendStringInfoChar(buf, '(');
6269  subindent = PRETTYINDENT_STD;
6270  }
6271  else
6272  subindent = 0;
6273  appendContextKeyword(context, "", subindent, 0, 0);
6274 
6275  get_setop_query(op->rarg, query, context, resultDesc, false);
6276 
6277  if (PRETTY_INDENT(context))
6278  context->indentLevel -= subindent;
6279  if (need_paren)
6280  appendContextKeyword(context, ")", 0, 0, 0);
6281  }
6282  else
6283  {
6284  elog(ERROR, "unrecognized node type: %d",
6285  (int) nodeTag(setOp));
6286  }
6287 }
6288 
6289 /*
6290  * Display a sort/group clause.
6291  *
6292  * Also returns the expression tree, so caller need not find it again.
6293  */
6294 static Node *
6295 get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
6297 {
6298  StringInfo buf = context->buf;
6299  TargetEntry *tle;
6300  Node *expr;
6301 
6302  tle = get_sortgroupref_tle(ref, tlist);
6303  expr = (Node *) tle->expr;
6304 
6305  /*
6306  * Use column-number form if requested by caller. Otherwise, if
6307  * expression is a constant, force it to be dumped with an explicit cast
6308  * as decoration --- this is because a simple integer constant is
6309  * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
6310  * dump it without any decoration. If it's anything more complex than a
6311  * simple Var, then force extra parens around it, to ensure it can't be
6312  * misinterpreted as a cube() or rollup() construct.
6313  */
6314  if (force_colno)
6315  {
6316  Assert(!tle->resjunk);
6317  appendStringInfo(buf, "%d", tle->resno);
6318  }
6319  else if (expr && IsA(expr, Const))
6320  get_const_expr((Const *) expr, context, 1);
6321  else if (!expr || IsA(expr, Var))
6322  get_rule_expr(expr, context, true);
6323  else
6324  {
6325  /*
6326  * We must force parens for function-like expressions even if
6327  * PRETTY_PAREN is off, since those are the ones in danger of
6328  * misparsing. For other expressions we need to force them only if
6329  * PRETTY_PAREN is on, since otherwise the expression will output them
6330  * itself. (We can't skip the parens.)
6331  */
6332  bool need_paren = (PRETTY_PAREN(context)
6333  || IsA(expr, FuncExpr)
6334  || IsA(expr, Aggref)
6335  || IsA(expr, WindowFunc)
6336  || IsA(expr, JsonConstructorExpr));
6337 
6338  if (need_paren)
6339  appendStringInfoChar(context->buf, '(');
6340  get_rule_expr(expr, context, true);
6341  if (need_paren)
6342  appendStringInfoChar(context->buf, ')');
6343  }
6344 
6345  return expr;
6346 }
6347 
6348 /*
6349  * Display a GroupingSet
6350  */
6351 static void
6353  bool omit_parens, deparse_context *context)
6354 {
6355  ListCell *l;
6356  StringInfo buf = context->buf;
6357  bool omit_child_parens = true;
6358  char *sep = "";
6359 
6360  switch (gset->kind)
6361  {
6362  case GROUPING_SET_EMPTY:
6363  appendStringInfoString(buf, "()");
6364  return;
6365 
6366  case GROUPING_SET_SIMPLE:
6367  {
6368  if (!omit_parens || list_length(gset->content) != 1)
6369  appendStringInfoChar(buf, '(');
6370 
6371  foreach(l, gset->content)
6372  {
6373  Index ref = lfirst_int(l);
6374 
6376  get_rule_sortgroupclause(ref, targetlist,
6377  false, context);
6378  sep = ", ";
6379  }
6380 
6381  if (!omit_parens || list_length(gset->content) != 1)
6382  appendStringInfoChar(buf, ')');
6383  }
6384  return;
6385 
6386  case GROUPING_SET_ROLLUP:
6387  appendStringInfoString(buf, "ROLLUP(");
6388  break;
6389  case GROUPING_SET_CUBE:
6390  appendStringInfoString(buf, "CUBE(");
6391  break;
6392  case GROUPING_SET_SETS:
6393  appendStringInfoString(buf, "GROUPING SETS (");
6394  omit_child_parens = false;
6395  break;
6396  }
6397 
6398  foreach(l, gset->content)
6399  {
6401  get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6402  sep = ", ";
6403  }
6404 
6405  appendStringInfoChar(buf, ')');
6406 }
6407 
6408 /*
6409  * Display an ORDER BY list.
6410  */
6411 static void
6412 get_rule_orderby(List *orderList, List *targetList,
6413  bool force_colno, deparse_context *context)
6414 {
6415  StringInfo buf = context->buf;
6416  const char *sep;
6417  ListCell *l;
6418 
6419  sep = "";
6420  foreach(l, orderList)
6421  {
6422  SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6423  Node *sortexpr;
6424  Oid sortcoltype;
6425  TypeCacheEntry *typentry;
6426 
6428  sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6429  force_colno, context);
6430  sortcoltype = exprType(sortexpr);
6431  /* See whether operator is default < or > for datatype */
6432  typentry = lookup_type_cache(sortcoltype,
6434  if (srt->sortop == typentry->lt_opr)
6435  {
6436  /* ASC is default, so emit nothing for it */
6437  if (srt->nulls_first)
6438  appendStringInfoString(buf, " NULLS FIRST");
6439  }
6440  else if (srt->sortop == typentry->gt_opr)
6441  {
6442  appendStringInfoString(buf, " DESC");
6443  /* DESC defaults to NULLS FIRST */
6444  if (!srt->nulls_first)
6445  appendStringInfoString(buf, " NULLS LAST");
6446  }
6447  else
6448  {
6449  appendStringInfo(buf, " USING %s",
6451  sortcoltype,
6452  sortcoltype));
6453  /* be specific to eliminate ambiguity */
6454  if (srt->nulls_first)
6455  appendStringInfoString(buf, " NULLS FIRST");
6456  else
6457  appendStringInfoString(buf, " NULLS LAST");
6458  }
6459  sep = ", ";
6460  }
6461 }
6462 
6463 /*
6464  * Display a WINDOW clause.
6465  *
6466  * Note that the windowClause list might contain only anonymous window
6467  * specifications, in which case we should print nothing here.
6468  */
6469 static void
6471 {
6472  StringInfo buf = context->buf;
6473  const char *sep;
6474  ListCell *l;
6475 
6476  sep = NULL;
6477  foreach(l, query->windowClause)
6478  {
6479  WindowClause *wc = (WindowClause *) lfirst(l);
6480 
6481  if (wc->name == NULL)
6482  continue; /* ignore anonymous windows */
6483 
6484  if (sep == NULL)
6485  appendContextKeyword(context, " WINDOW ",
6487  else
6489 
6490  appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6491 
6492  get_rule_windowspec(wc, query->targetList, context);
6493 
6494  sep = ", ";
6495  }
6496 }
6497 
6498 /*
6499  * Display a window definition
6500  */
6501 static void
6504 {
6505  StringInfo buf = context->buf;
6506  bool needspace = false;
6507  const char *sep;
6508  ListCell *l;
6509 
6510  appendStringInfoChar(buf, '(');
6511  if (wc->refname)
6512  {
6514  needspace = true;
6515  }
6516  /* partition clauses are always inherited, so only print if no refname */
6517  if (wc->partitionClause && !wc->refname)
6518  {
6519  if (needspace)
6520  appendStringInfoChar(buf, ' ');
6521  appendStringInfoString(buf, "PARTITION BY ");
6522  sep = "";
6523  foreach(l, wc->partitionClause)
6524  {
6525  SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6526 
6528  get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6529  false, context);
6530  sep = ", ";
6531  }
6532  needspace = true;
6533  }
6534  /* print ordering clause only if not inherited */
6535  if (wc->orderClause && !wc->copiedOrder)
6536  {
6537  if (needspace)
6538  appendStringInfoChar(buf, ' ');
6539  appendStringInfoString(buf, "ORDER BY ");
6540  get_rule_orderby(wc->orderClause, targetList, false, context);
6541  needspace = true;
6542  }
6543  /* framing clause is never inherited, so print unless it's default */
6545  {
6546  if (needspace)
6547  appendStringInfoChar(buf, ' ');
6548  if (wc->frameOptions & FRAMEOPTION_RANGE)
6549  appendStringInfoString(buf, "RANGE ");
6550  else if (wc->frameOptions & FRAMEOPTION_ROWS)
6551  appendStringInfoString(buf, "ROWS ");
6552  else if (wc->frameOptions & FRAMEOPTION_GROUPS)
6553  appendStringInfoString(buf, "GROUPS ");
6554  else
6555  Assert(false);
6557  appendStringInfoString(buf, "BETWEEN ");
6559  appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6561  appendStringInfoString(buf, "CURRENT ROW ");
6562  else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
6563  {
6564  get_rule_expr(wc->startOffset, context, false);
6566  appendStringInfoString(buf, " PRECEDING ");
6568  appendStringInfoString(buf, " FOLLOWING ");
6569  else
6570  Assert(false);
6571  }
6572  else
6573  Assert(false);
6575  {
6576  appendStringInfoString(buf, "AND ");
6578  appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6580  appendStringInfoString(buf, "CURRENT ROW ");
6581  else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
6582  {
6583  get_rule_expr(wc->endOffset, context, false);
6585  appendStringInfoString(buf, " PRECEDING ");
6587  appendStringInfoString(buf, " FOLLOWING ");
6588  else
6589  Assert(false);
6590  }
6591  else
6592  Assert(false);
6593  }
6595  appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6596  else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6597  appendStringInfoString(buf, "EXCLUDE GROUP ");
6598  else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6599  appendStringInfoString(buf, "EXCLUDE TIES ");
6600  /* we will now have a trailing space; remove it */
6601  buf->len--;
6602  }
6603  appendStringInfoChar(buf, ')');
6604 }
6605 
6606 /* ----------
6607  * get_insert_query_def - Parse back an INSERT parsetree
6608  * ----------
6609  */
6610 static void
6612  bool colNamesVisible)
6613 {
6614  StringInfo buf = context->buf;
6615  RangeTblEntry *select_rte = NULL;
6616  RangeTblEntry *values_rte = NULL;
6617  RangeTblEntry *rte;
6618  char *sep;
6619  ListCell *l;
6620  List *strippedexprs;
6621 
6622  /* Insert the WITH clause if given */
6623  get_with_clause(query, context);
6624 
6625  /*
6626  * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6627  * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6628  */
6629  foreach(l, query->rtable)
6630  {
6631  rte = (RangeTblEntry *) lfirst(l);
6632 
6633  if (rte->rtekind == RTE_SUBQUERY)
6634  {
6635  if (select_rte)
6636  elog(ERROR, "too many subquery RTEs in INSERT");
6637  select_rte = rte;
6638  }
6639 
6640  if (rte->rtekind == RTE_VALUES)
6641  {
6642  if (values_rte)
6643  elog(ERROR, "too many values RTEs in INSERT");
6644  values_rte = rte;
6645  }
6646  }
6647  if (select_rte && values_rte)
6648  elog(ERROR, "both subquery and values RTEs in INSERT");
6649 
6650  /*
6651  * Start the query with INSERT INTO relname
6652  */
6653  rte = rt_fetch(query->resultRelation, query->rtable);
6654  Assert(rte->rtekind == RTE_RELATION);
6655 
6656  if (PRETTY_INDENT(context))
6657  {
6658  context->indentLevel += PRETTYINDENT_STD;
6659  appendStringInfoChar(buf, ' ');
6660  }
6661  appendStringInfo(buf, "INSERT INTO %s",
6663 
6664  /* Print the relation alias, if needed; INSERT requires explicit AS */
6665  get_rte_alias(rte, query->resultRelation, true, context);
6666 
6667  /* always want a space here */
6668  appendStringInfoChar(buf, ' ');
6669 
6670  /*
6671  * Add the insert-column-names list. Any indirection decoration needed on
6672  * the column names can be inferred from the top targetlist.
6673  */
6674  strippedexprs = NIL;
6675  sep = "";
6676  if (query->targetList)
6677  appendStringInfoChar(buf, '(');
6678  foreach(l, query->targetList)
6679  {
6680  TargetEntry *tle = (TargetEntry *) lfirst(l);
6681 
6682  if (tle->resjunk)
6683  continue; /* ignore junk entries */
6684 
6686  sep = ", ";
6687 
6688  /*
6689  * Put out name of target column; look in the catalogs, not at
6690  * tle->resname, since resname will fail to track RENAME.
6691  */
6694  tle->resno,
6695  false)));
6696 
6697  /*
6698  * Print any indirection needed (subfields or subscripts), and strip
6699  * off the top-level nodes representing the indirection assignments.
6700  * Add the stripped expressions to strippedexprs. (If it's a
6701  * single-VALUES statement, the stripped expressions are the VALUES to
6702  * print below. Otherwise they're just Vars and not really
6703  * interesting.)
6704  */
6705  strippedexprs = lappend(strippedexprs,
6706  processIndirection((Node *) tle->expr,
6707  context));
6708  }
6709  if (query->targetList)
6710  appendStringInfoString(buf, ") ");
6711 
6712  if (query->override)
6713  {
6714  if (query->override == OVERRIDING_SYSTEM_VALUE)
6715  appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
6716  else if (query->override == OVERRIDING_USER_VALUE)
6717  appendStringInfoString(buf, "OVERRIDING USER VALUE ");
6718  }
6719 
6720  if (select_rte)
6721  {
6722  /* Add the SELECT */
6723  get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
6724  false,
6725  context->prettyFlags, context->wrapColumn,
6726  context->indentLevel);
6727  }
6728  else if (values_rte)
6729  {
6730  /* Add the multi-VALUES expression lists */
6731  get_values_def(values_rte->values_lists, context);
6732  }
6733  else if (strippedexprs)
6734  {
6735  /* Add the single-VALUES expression list */
6736  appendContextKeyword(context, "VALUES (",
6738  get_rule_list_toplevel(strippedexprs, context, false);
6739  appendStringInfoChar(buf, ')');
6740  }
6741  else
6742  {
6743  /* No expressions, so it must be DEFAULT VALUES */
6744  appendStringInfoString(buf, "DEFAULT VALUES");
6745  }
6746 
6747  /* Add ON CONFLICT if present */
6748  if (query->onConflict)
6749  {
6750  OnConflictExpr *confl = query->onConflict;
6751 
6752  appendStringInfoString(buf, " ON CONFLICT");
6753 
6754  if (confl->arbiterElems)
6755  {
6756  /* Add the single-VALUES expression list */
6757  appendStringInfoChar(buf, '(');
6758  get_rule_expr((Node *) confl->arbiterElems, context, false);
6759  appendStringInfoChar(buf, ')');
6760 
6761  /* Add a WHERE clause (for partial indexes) if given */
6762  if (confl->arbiterWhere != NULL)
6763  {
6764  bool save_varprefix;
6765 
6766  /*
6767  * Force non-prefixing of Vars, since parser assumes that they
6768  * belong to target relation. WHERE clause does not use
6769  * InferenceElem, so this is separately required.
6770  */
6771  save_varprefix = context->varprefix;
6772  context->varprefix = false;
6773 
6774  appendContextKeyword(context, " WHERE ",
6776  get_rule_expr(confl->arbiterWhere, context, false);
6777 
6778  context->varprefix = save_varprefix;
6779  }
6780  }
6781  else if (OidIsValid(confl->constraint))
6782  {
6783  char *constraint = get_constraint_name(confl->constraint);
6784 
6785  if (!constraint)
6786  elog(ERROR, "cache lookup failed for constraint %u",
6787  confl->constraint);
6788  appendStringInfo(buf, " ON CONSTRAINT %s",
6789  quote_identifier(constraint));
6790  }
6791 
6792  if (confl->action == ONCONFLICT_NOTHING)
6793  {
6794  appendStringInfoString(buf, " DO NOTHING");
6795  }
6796  else
6797  {
6798  appendStringInfoString(buf, " DO UPDATE SET ");
6799  /* Deparse targetlist */
6801  context, rte);
6802 
6803  /* Add a WHERE clause if given */
6804  if (confl->onConflictWhere != NULL)
6805  {
6806  appendContextKeyword(context, " WHERE ",
6808  get_rule_expr(confl->onConflictWhere, context, false);
6809  }
6810  }
6811  }
6812 
6813  /* Add RETURNING if present */
6814  if (query->returningList)
6815  {
6816  appendContextKeyword(context, " RETURNING",
6818  get_target_list(query->returningList, context, NULL, colNamesVisible);
6819  }
6820 }
6821 
6822 
6823 /* ----------
6824  * get_update_query_def - Parse back an UPDATE parsetree
6825  * ----------
6826  */
6827 static void
6829  bool colNamesVisible)
6830 {
6831  StringInfo buf = context->buf;
6832  RangeTblEntry *rte;
6833 
6834  /* Insert the WITH clause if given */
6835  get_with_clause(query, context);
6836 
6837  /*
6838  * Start the query with UPDATE relname SET
6839  */
6840  rte = rt_fetch(query->resultRelation, query->rtable);
6841  Assert(rte->rtekind == RTE_RELATION);
6842  if (PRETTY_INDENT(context))
6843  {
6844  appendStringInfoChar(buf, ' ');
6845  context->indentLevel += PRETTYINDENT_STD;
6846  }
6847  appendStringInfo(buf, "UPDATE %s%s",
6848  only_marker(rte),
6850 
6851  /* Print the relation alias, if needed */
6852  get_rte_alias(rte, query->resultRelation, false, context);
6853 
6854  appendStringInfoString(buf, " SET ");
6855 
6856  /* Deparse targetlist */
6857  get_update_query_targetlist_def(query, query->targetList, context, rte);
6858 
6859  /* Add the FROM clause if needed */
6860  get_from_clause(query, " FROM ", context);
6861 
6862  /* Add a WHERE clause if given */
6863  if (query->jointree->quals != NULL)
6864  {
6865  appendContextKeyword(context, " WHERE ",
6867  get_rule_expr(query->jointree->quals, context, false);
6868  }
6869 
6870  /* Add RETURNING if present */
6871  if (query->returningList)
6872  {
6873  appendContextKeyword(context, " RETURNING",
6875  get_target_list(query->returningList, context, NULL, colNamesVisible);
6876  }
6877 }
6878 
6879 
6880 /* ----------
6881  * get_update_query_targetlist_def - Parse back an UPDATE targetlist
6882  * ----------
6883  */
6884 static void
6887 {
6888  StringInfo buf = context->buf;
6889  ListCell *l;
6890  ListCell *next_ma_cell;
6891  int remaining_ma_columns;
6892  const char *sep;
6893  SubLink *cur_ma_sublink;
6894  List *ma_sublinks;
6895 
6896  /*
6897  * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
6898  * into a list. We expect them to appear, in ID order, in resjunk tlist
6899  * entries.
6900  */
6901  ma_sublinks = NIL;
6902  if (query->hasSubLinks) /* else there can't be any */
6903  {
6904  foreach(l, targetList)
6905  {
6906  TargetEntry *tle = (TargetEntry *) lfirst(l);
6907 
6908  if (tle->resjunk && IsA(tle->expr, SubLink))
6909  {
6910  SubLink *sl = (SubLink *) tle->expr;
6911 
6913  {
6914  ma_sublinks = lappend(ma_sublinks, sl);
6915  Assert(sl->subLinkId == list_length(ma_sublinks));
6916  }
6917  }
6918  }
6919  }
6920  next_ma_cell = list_head(ma_sublinks);
6921  cur_ma_sublink = NULL;
6922  remaining_ma_columns = 0;
6923 
6924  /* Add the comma separated list of 'attname = value' */
6925  sep = "";
6926  foreach(l, targetList)
6927  {
6928  TargetEntry *tle = (TargetEntry *) lfirst(l);
6929  Node *expr;
6930 
6931  if (tle->resjunk)
6932  continue; /* ignore junk entries */
6933 
6934  /* Emit separator (OK whether we're in multiassignment or not) */
6936  sep = ", ";
6937 
6938  /*
6939  * Check to see if we're starting a multiassignment group: if so,
6940  * output a left paren.
6941  */
6942  if (next_ma_cell != NULL && cur_ma_sublink == NULL)
6943  {
6944  /*
6945  * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
6946  * Param. That could be buried under FieldStores and
6947  * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
6948  * and underneath those there could be an implicit type coercion.
6949  * Because we would ignore implicit type coercions anyway, we
6950  * don't need to be as careful as processIndirection() is about
6951  * descending past implicit CoerceToDomains.
6952  */
6953  expr = (Node *) tle->expr;
6954  while (expr)
6955  {
6956  if (IsA(expr, FieldStore))
6957  {
6958  FieldStore *fstore = (FieldStore *) expr;
6959 
6960  expr = (Node *) linitial(fstore->newvals);
6961  }
6962  else if (IsA(expr, SubscriptingRef))
6963  {
6964  SubscriptingRef *sbsref = (SubscriptingRef *) expr;
6965 
6966  if (sbsref->refassgnexpr == NULL)
6967  break;
6968 
6969  expr = (Node *) sbsref->refassgnexpr;
6970  }
6971  else if (IsA(expr, CoerceToDomain))
6972  {
6973  CoerceToDomain *cdomain = (CoerceToDomain *) expr;
6974 
6975  if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
6976  break;
6977  expr = (Node *) cdomain->arg;
6978  }
6979  else
6980  break;
6981  }
6982  expr = strip_implicit_coercions(expr);
6983 
6984  if (expr && IsA(expr, Param) &&
6985  ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
6986  {
6987  cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
6988  next_ma_cell = lnext(ma_sublinks, next_ma_cell);
6989  remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
6990  Assert(((Param *) expr)->paramid ==
6991  ((cur_ma_sublink->subLinkId << 16) | 1));
6992  appendStringInfoChar(buf, '(');
6993  }
6994  }
6995 
6996  /*
6997  * Put out name of target column; look in the catalogs, not at
6998  * tle->resname, since resname will fail to track RENAME.
6999  */
7002  tle->resno,
7003  false)));
7004 
7005  /*
7006  * Print any indirection needed (subfields or subscripts), and strip
7007  * off the top-level nodes representing the indirection assignments.
7008  */
7009  expr = processIndirection((Node *) tle->expr, context);
7010 
7011  /*
7012  * If we're in a multiassignment, skip printing anything more, unless
7013  * this is the last column; in which case, what we print should be the
7014  * sublink, not the Param.
7015  */
7016  if (cur_ma_sublink != NULL)
7017  {
7018  if (--remaining_ma_columns > 0)
7019  continue; /* not the last column of multiassignment */
7020  appendStringInfoChar(buf, ')');
7021  expr = (Node *) cur_ma_sublink;
7022  cur_ma_sublink = NULL;
7023  }
7024 
7025  appendStringInfoString(buf, " = ");
7026 
7027  get_rule_expr(expr, context, false);
7028  }
7029 }
7030 
7031 
7032 /* ----------
7033  * get_delete_query_def - Parse back a DELETE parsetree
7034  * ----------
7035  */
7036 static void
7038  bool colNamesVisible)
7039 {
7040  StringInfo buf = context->buf;
7041  RangeTblEntry *rte;
7042 
7043  /* Insert the WITH clause if given */
7044  get_with_clause(query, context);
7045 
7046  /*
7047  * Start the query with DELETE FROM relname
7048  */
7049  rte = rt_fetch(query->resultRelation, query->rtable);
7050  Assert(rte->rtekind == RTE_RELATION);
7051  if (PRETTY_INDENT(context))
7052  {
7053  appendStringInfoChar(buf, ' ');
7054  context->indentLevel += PRETTYINDENT_STD;
7055  }
7056  appendStringInfo(buf, "DELETE FROM %s%s",
7057  only_marker(rte),
7059 
7060  /* Print the relation alias, if needed */
7061  get_rte_alias(rte, query->resultRelation, false, context);
7062 
7063  /* Add the USING clause if given */
7064  get_from_clause(query, " USING ", context);
7065 
7066  /* Add a WHERE clause if given */
7067  if (query->jointree->quals != NULL)
7068  {
7069  appendContextKeyword(context, " WHERE ",
7071  get_rule_expr(query->jointree->quals, context, false);
7072  }
7073 
7074  /* Add RETURNING if present */
7075  if (query->returningList)
7076  {
7077  appendContextKeyword(context, " RETURNING",
7079  get_target_list(query->returningList, context, NULL, colNamesVisible);
7080  }
7081 }
7082 
7083 
7084 /* ----------
7085  * get_merge_query_def - Parse back a MERGE parsetree
7086  * ----------
7087  */
7088 static void
7090  bool colNamesVisible)
7091 {
7092  StringInfo buf = context->buf;
7093  RangeTblEntry *rte;
7094  ListCell *lc;
7095  bool haveNotMatchedBySource;
7096 
7097  /* Insert the WITH clause if given */
7098  get_with_clause(query, context);
7099 
7100  /*
7101  * Start the query with MERGE INTO relname
7102  */
7103  rte = rt_fetch(query->resultRelation, query->rtable);
7104  Assert(rte->rtekind == RTE_RELATION);
7105  if (PRETTY_INDENT(context))
7106  {
7107  appendStringInfoChar(buf, ' ');
7108  context->indentLevel += PRETTYINDENT_STD;
7109  }
7110  appendStringInfo(buf, "MERGE INTO %s%s",
7111  only_marker(rte),
7113 
7114  /* Print the relation alias, if needed */
7115  get_rte_alias(rte, query->resultRelation, false, context);
7116 
7117  /* Print the source relation and join clause */
7118  get_from_clause(query, " USING ", context);
7119  appendContextKeyword(context, " ON ",
7121  get_rule_expr(query->mergeJoinCondition, context, false);
7122 
7123  /*
7124  * Test for any NOT MATCHED BY SOURCE actions. If there are none, then
7125  * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7126  * SQL standard. Otherwise, we have a non-SQL-standard query, so output
7127  * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7128  * more explicit.
7129  */
7130  haveNotMatchedBySource = false;
7131  foreach(lc, query->mergeActionList)
7132  {
7134 
7135  if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7136  {
7137  haveNotMatchedBySource = true;
7138  break;
7139  }
7140  }
7141 
7142  /* Print each merge action */
7143  foreach(lc, query->mergeActionList)
7144  {
7146 
7147  appendContextKeyword(context, " WHEN ",
7149  switch (action->matchKind)
7150  {
7151  case MERGE_WHEN_MATCHED:
7152  appendStringInfoString(buf, "MATCHED");
7153  break;
7155  appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7156  break;
7158  if (haveNotMatchedBySource)
7159  appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7160  else
7161  appendStringInfoString(buf, "NOT MATCHED");
7162  break;
7163  default:
7164  elog(ERROR, "unrecognized matchKind: %d",
7165  (int) action->matchKind);
7166  }
7167 
7168  if (action->qual)
7169  {
7170  appendContextKeyword(context, " AND ",
7172  get_rule_expr(action->qual, context, false);
7173  }
7174  appendContextKeyword(context, " THEN ",
7176 
7177  if (action->commandType == CMD_INSERT)
7178  {
7179  /* This generally matches get_insert_query_def() */
7180  List *strippedexprs = NIL;
7181  const char *sep = "";
7182  ListCell *lc2;
7183 
7184  appendStringInfoString(buf, "INSERT");
7185 
7186  if (action->targetList)
7187  appendStringInfoString(buf, " (");
7188  foreach(lc2, action->targetList)
7189  {
7190  TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7191 
7192  Assert(!tle->resjunk);
7193 
7195  sep = ", ";
7196 
7199  tle->resno,
7200  false)));
7201  strippedexprs = lappend(strippedexprs,
7202  processIndirection((Node *) tle->expr,
7203  context));
7204  }
7205  if (action->targetList)
7206  appendStringInfoChar(buf, ')');
7207 
7208  if (action->override)
7209  {
7210  if (action->override == OVERRIDING_SYSTEM_VALUE)
7211  appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7212  else if (action->override == OVERRIDING_USER_VALUE)
7213  appendStringInfoString(buf, " OVERRIDING USER VALUE");
7214  }
7215 
7216  if (strippedexprs)
7217  {
7218  appendContextKeyword(context, " VALUES (",
7220  get_rule_list_toplevel(strippedexprs, context, false);
7221  appendStringInfoChar(buf, ')');
7222  }
7223  else
7224  appendStringInfoString(buf, " DEFAULT VALUES");
7225  }
7226  else if (action->commandType == CMD_UPDATE)
7227  {
7228  appendStringInfoString(buf, "UPDATE SET ");
7229  get_update_query_targetlist_def(query, action->targetList,
7230  context, rte);
7231  }
7232  else if (action->commandType == CMD_DELETE)
7233  appendStringInfoString(buf, "DELETE");
7234  else if (action->commandType == CMD_NOTHING)
7235  appendStringInfoString(buf, "DO NOTHING");
7236  }
7237 
7238  /* Add RETURNING if present */
7239  if (query->returningList)
7240  {
7241  appendContextKeyword(context, " RETURNING",
7243  get_target_list(query->returningList, context, NULL, colNamesVisible);
7244  }
7245 }
7246 
7247 
7248 /* ----------
7249  * get_utility_query_def - Parse back a UTILITY parsetree
7250  * ----------
7251  */
7252 static void
7254 {
7255  StringInfo buf = context->buf;
7256 
7257  if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7258  {
7259  NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7260 
7262  0, PRETTYINDENT_STD, 1);
7263  appendStringInfo(buf, "NOTIFY %s",
7264  quote_identifier(stmt->conditionname));
7265  if (stmt->payload)
7266  {
7267  appendStringInfoString(buf, ", ");
7268  simple_quote_literal(buf, stmt->payload);
7269  }
7270  }
7271  else
7272  {
7273  /* Currently only NOTIFY utility commands can appear in rules */
7274  elog(ERROR, "unexpected utility statement type");
7275  }
7276 }
7277 
7278 /*
7279  * Display a Var appropriately.
7280  *
7281  * In some cases (currently only when recursing into an unnamed join)
7282  * the Var's varlevelsup has to be interpreted with respect to a context
7283  * above the current one; levelsup indicates the offset.
7284  *
7285  * If istoplevel is true, the Var is at the top level of a SELECT's
7286  * targetlist, which means we need special treatment of whole-row Vars.
7287  * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
7288  * dirty hack to prevent "tab.*" from being expanded into multiple columns.
7289  * (The parser will strip the useless coercion, so no inefficiency is added in
7290  * dump and reload.) We used to print just "tab" in such cases, but that is
7291  * ambiguous and will yield the wrong result if "tab" is also a plain column
7292  * name in the query.
7293  *
7294  * Returns the attname of the Var, or NULL if the Var has no attname (because
7295  * it is a whole-row Var or a subplan output reference).
7296  */
7297 static char *
7298 get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
7299 {
7300  StringInfo buf = context->buf;
7301  RangeTblEntry *rte;
7303  int netlevelsup;
7304  deparse_namespace *dpns;
7305  int varno;
7306  AttrNumber varattno;
7307  deparse_columns *colinfo;
7308  char *refname;
7309  char *attname;
7310 
7311  /* Find appropriate nesting depth */
7312  netlevelsup = var->varlevelsup + levelsup;
7313  if (netlevelsup >= list_length(context->namespaces))
7314  elog(ERROR, "bogus varlevelsup: %d offset %d",
7315  var->varlevelsup, levelsup);
7316  dpns = (deparse_namespace *) list_nth(context->namespaces,
7317  netlevelsup);
7318 
7319  /*
7320  * If we have a syntactic referent for the Var, and we're working from a
7321  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7322  * on the semantic referent. (Forcing use of the semantic referent when
7323  * printing plan trees is a design choice that's perhaps more motivated by
7324  * backwards compatibility than anything else. But it does have the
7325  * advantage of making plans more explicit.)
7326  */
7327  if (var->varnosyn > 0 && dpns->plan == NULL)
7328  {
7329  varno = var->varnosyn;
7330  varattno = var->varattnosyn;
7331  }
7332  else
7333  {
7334  varno = var->varno;
7335  varattno = var->varattno;
7336  }
7337 
7338  /*
7339  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7340  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7341  * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7342  * find the aliases previously assigned for this RTE.
7343  */
7344  if (varno >= 1 && varno <= list_length(dpns->rtable))
7345  {
7346  /*
7347  * We might have been asked to map child Vars to some parent relation.
7348  */
7349  if (context->appendparents && dpns->appendrels)
7350  {
7351  int pvarno = varno;
7352  AttrNumber pvarattno = varattno;
7353  AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7354  bool found = false;
7355 
7356  /* Only map up to inheritance parents, not UNION ALL appendrels */
7357  while (appinfo &&
7358  rt_fetch(appinfo->parent_relid,
7359  dpns->rtable)->rtekind == RTE_RELATION)
7360  {
7361  found = false;
7362  if (pvarattno > 0) /* system columns stay as-is */
7363  {
7364  if (pvarattno > appinfo->num_child_cols)
7365  break; /* safety check */
7366  pvarattno = appinfo->parent_colnos[pvarattno - 1];
7367  if (pvarattno == 0)
7368  break; /* Var is local to child */
7369  }
7370 
7371  pvarno = appinfo->parent_relid;
7372  found = true;
7373 
7374  /* If the parent is itself a child, continue up. */
7375  Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7376  appinfo = dpns->appendrels[pvarno];
7377  }
7378 
7379  /*
7380  * If we found an ancestral rel, and that rel is included in
7381  * appendparents, print that column not the original one.
7382  */
7383  if (found && bms_is_member(pvarno, context->appendparents))
7384  {
7385  varno = pvarno;
7386  varattno = pvarattno;
7387  }
7388  }
7389 
7390  rte = rt_fetch(varno, dpns->rtable);
7391  refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7392  colinfo = deparse_columns_fetch(varno, dpns);
7393  attnum = varattno;
7394  }
7395  else
7396  {
7398  get_special_variable, NULL);
7399  return NULL;
7400  }
7401 
7402  /*
7403  * The planner will sometimes emit Vars referencing resjunk elements of a
7404  * subquery's target list (this is currently only possible if it chooses
7405  * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7406  * Although we prefer to print subquery-referencing Vars using the
7407  * subquery's alias, that's not possible for resjunk items since they have
7408  * no alias. So in that case, drill down to the subplan and print the
7409  * contents of the referenced tlist item. This works because in a plan
7410  * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7411  * we'll have set dpns->inner_plan to reference the child plan node.
7412  */
7413  if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7414  attnum > list_length(rte->eref->colnames) &&
7415  dpns->inner_plan)
7416  {
7417  TargetEntry *tle;
7418  deparse_namespace save_dpns;
7419 
7420  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7421  if (!tle)
7422  elog(ERROR, "invalid attnum %d for relation \"%s\"",
7423  attnum, rte->eref->aliasname);
7424 
7425  Assert(netlevelsup == 0);
7426  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7427 
7428  /*
7429  * Force parentheses because our caller probably assumed a Var is a
7430  * simple expression.
7431  */
7432  if (!IsA(tle->expr, Var))
7433  appendStringInfoChar(buf, '(');
7434  get_rule_expr((Node *) tle->expr, context, true);
7435  if (!IsA(tle->expr, Var))
7436  appendStringInfoChar(buf, ')');
7437 
7438  pop_child_plan(dpns, &save_dpns);
7439  return NULL;
7440  }
7441 
7442  /*
7443  * If it's an unnamed join, look at the expansion of the alias variable.
7444  * If it's a simple reference to one of the input vars, then recursively
7445  * print the name of that var instead. When it's not a simple reference,
7446  * we have to just print the unqualified join column name. (This can only
7447  * happen with "dangerous" merged columns in a JOIN USING; we took pains
7448  * previously to make the unqualified column name unique in such cases.)
7449  *
7450  * This wouldn't work in decompiling plan trees, because we don't store
7451  * joinaliasvars lists after planning; but a plan tree should never
7452  * contain a join alias variable.
7453  */
7454  if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7455  {
7456  if (rte->joinaliasvars == NIL)
7457  elog(ERROR, "cannot decompile join alias var in plan tree");
7458  if (attnum > 0)
7459  {
7460  Var *aliasvar;
7461 
7462  aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7463  /* we intentionally don't strip implicit coercions here */
7464  if (aliasvar && IsA(aliasvar, Var))
7465  {
7466  return get_variable(aliasvar, var->varlevelsup + levelsup,
7467  istoplevel, context);
7468  }
7469  }
7470 
7471  /*
7472  * Unnamed join has no refname. (Note: since it's unnamed, there is
7473  * no way the user could have referenced it to create a whole-row Var
7474  * for it. So we don't have to cover that case below.)
7475  */
7476  Assert(refname == NULL);
7477  }
7478 
7479  if (attnum == InvalidAttrNumber)
7480  attname = NULL;
7481  else if (attnum > 0)
7482  {
7483  /* Get column name to use from the colinfo struct */
7484  if (attnum > colinfo->num_cols)
7485  elog(ERROR, "invalid attnum %d for relation \"%s\"",
7486  attnum, rte->eref->aliasname);
7487  attname = colinfo->colnames[attnum - 1];
7488 
7489  /*
7490  * If we find a Var referencing a dropped column, it seems better to
7491  * print something (anything) than to fail. In general this should
7492  * not happen, but it used to be possible for some cases involving
7493  * functions returning named composite types, and perhaps there are
7494  * still bugs out there.
7495  */
7496  if (attname == NULL)
7497  attname = "?dropped?column?";
7498  }
7499  else
7500  {
7501  /* System column - name is fixed, get it from the catalog */
7503  }
7504 
7505  if (refname && (context->varprefix || attname == NULL))
7506  {
7508  appendStringInfoChar(buf, '.');
7509  }
7510  if (attname)
7512  else
7513  {
7514  appendStringInfoChar(buf, '*');
7515  if (istoplevel)
7516  appendStringInfo(buf, "::%s",
7517  format_type_with_typemod(var->vartype,
7518  var->vartypmod));
7519  }
7520 
7521  return attname;
7522 }
7523 
7524 /*
7525  * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
7526  * routine is actually a callback for resolve_special_varno, which handles
7527  * finding the correct TargetEntry. We get the expression contained in that
7528  * TargetEntry and just need to deparse it, a job we can throw back on
7529  * get_rule_expr.
7530  */
7531 static void
7532 get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7533 {
7534  StringInfo buf = context->buf;
7535 
7536  /*
7537  * For a non-Var referent, force parentheses because our caller probably
7538  * assumed a Var is a simple expression.
7539  */
7540  if (!IsA(node, Var))
7541  appendStringInfoChar(buf, '(');
7542  get_rule_expr(node, context, true);
7543  if (!IsA(node, Var))
7544  appendStringInfoChar(buf, ')');
7545 }
7546 
7547 /*
7548  * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7549  * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7550  * invoke the callback provided.
7551  */
7552 static void
7554  rsv_callback callback, void *callback_arg)
7555 {
7556  Var *var;
7557  deparse_namespace *dpns;
7558 
7559  /* This function is recursive, so let's be paranoid. */
7561 
7562  /* If it's not a Var, invoke the callback. */
7563  if (!IsA(node, Var))
7564  {
7565  (*callback) (node, context, callback_arg);
7566  return;
7567  }
7568 
7569  /* Find appropriate nesting depth */
7570  var = (Var *) node;
7571  dpns = (deparse_namespace *) list_nth(context->namespaces,
7572  var->varlevelsup);
7573 
7574  /*
7575  * If varno is special, recurse. (Don't worry about varnosyn; if we're
7576  * here, we already decided not to use that.)
7577  */
7578  if (var->varno == OUTER_VAR && dpns->outer_tlist)
7579  {
7580  TargetEntry *tle;
7581  deparse_namespace save_dpns;
7582  Bitmapset *save_appendparents;
7583 
7584  tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7585  if (!tle)
7586  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7587 
7588  /*
7589  * If we're descending to the first child of an Append or MergeAppend,
7590  * update appendparents. This will affect deparsing of all Vars
7591  * appearing within the eventually-resolved subexpression.
7592  */
7593  save_appendparents = context->appendparents;
7594 
7595  if (IsA(dpns->plan, Append))
7596  context->appendparents = bms_union(context->appendparents,
7597  ((Append *) dpns->plan)->apprelids);
7598  else if (IsA(dpns->plan, MergeAppend))
7599  context->appendparents = bms_union(context->appendparents,
7600  ((MergeAppend *) dpns->plan)->apprelids);
7601 
7602  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7604  callback, callback_arg);
7605  pop_child_plan(dpns, &save_dpns);
7606  context->appendparents = save_appendparents;
7607  return;
7608  }
7609  else if (var->varno == INNER_VAR && dpns->inner_tlist)
7610  {
7611  TargetEntry *tle;
7612  deparse_namespace save_dpns;
7613 
7614  tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7615  if (!tle)
7616  elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7617 
7618  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7620  callback, callback_arg);
7621  pop_child_plan(dpns, &save_dpns);
7622  return;
7623  }
7624  else if (var->varno == INDEX_VAR && dpns->index_tlist)
7625  {
7626  TargetEntry *tle;
7627 
7628  tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7629  if (!tle)
7630  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7631 
7633  callback, callback_arg);
7634  return;
7635  }
7636  else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7637  elog(ERROR, "bogus varno: %d", var->varno);
7638 
7639  /* Not special. Just invoke the callback. */
7640  (*callback) (node, context, callback_arg);
7641 }
7642 
7643 /*
7644  * Get the name of a field of an expression of composite type. The
7645  * expression is usually a Var, but we handle other cases too.
7646  *
7647  * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
7648  *
7649  * This is fairly straightforward when the expression has a named composite
7650  * type; we need only look up the type in the catalogs. However, the type
7651  * could also be RECORD. Since no actual table or view column is allowed to
7652  * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
7653  * or to a subquery output. We drill down to find the ultimate defining
7654  * expression and attempt to infer the field name from it. We ereport if we
7655  * can't determine the name.
7656  *
7657  * Similarly, a PARAM of type RECORD has to refer to some expression of
7658  * a determinable composite type.
7659  */
7660 static const char *
7661 get_name_for_var_field(Var *var, int fieldno,
7662  int levelsup, deparse_context *context)
7663 {
7664  RangeTblEntry *rte;
7666  int netlevelsup;
7667  deparse_namespace *dpns;
7668  int varno;
7669  AttrNumber varattno;
7670  TupleDesc tupleDesc;
7671  Node *expr;
7672 
7673  /*
7674  * If it's a RowExpr that was expanded from a whole-row Var, use the
7675  * column names attached to it. (We could let get_expr_result_tupdesc()
7676  * handle this, but it's much cheaper to just pull out the name we need.)
7677  */
7678  if (IsA(var, RowExpr))
7679  {
7680  RowExpr *r = (RowExpr *) var;
7681 
7682  if (fieldno > 0 && fieldno <= list_length(r->colnames))
7683  return strVal(list_nth(r->colnames, fieldno - 1));
7684  }
7685 
7686  /*
7687  * If it's a Param of type RECORD, try to find what the Param refers to.
7688  */
7689  if (IsA(var, Param))
7690  {
7691  Param *param = (Param *) var;
7692  ListCell *ancestor_cell;
7693 
7694  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7695  if (expr)
7696  {
7697  /* Found a match, so recurse to decipher the field name */
7698  deparse_namespace save_dpns;
7699  const char *result;
7700 
7701  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7702  result = get_name_for_var_field((Var *) expr, fieldno,
7703  0, context);
7704  pop_ancestor_plan(dpns, &save_dpns);
7705  return result;
7706  }
7707  }
7708 
7709  /*
7710  * If it's a Var of type RECORD, we have to find what the Var refers to;
7711  * if not, we can use get_expr_result_tupdesc().
7712  */
7713  if (!IsA(var, Var) ||
7714  var->vartype != RECORDOID)
7715  {
7716  tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7717  /* Got the tupdesc, so we can extract the field name */
7718  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7719  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7720  }
7721 
7722  /* Find appropriate nesting depth */
7723  netlevelsup = var->varlevelsup + levelsup;
7724  if (netlevelsup >= list_length(context->namespaces))
7725  elog(ERROR, "bogus varlevelsup: %d offset %d",
7726  var->varlevelsup, levelsup);
7727  dpns = (deparse_namespace *) list_nth(context->namespaces,
7728  netlevelsup);
7729 
7730  /*
7731  * If we have a syntactic referent for the Var, and we're working from a
7732  * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7733  * on the semantic referent. (See comments in get_variable().)
7734  */
7735  if (var->varnosyn > 0 && dpns->plan == NULL)
7736  {
7737  varno = var->varnosyn;
7738  varattno = var->varattnosyn;
7739  }
7740  else
7741  {
7742  varno = var->varno;
7743  varattno = var->varattno;
7744  }
7745 
7746  /*
7747  * Try to find the relevant RTE in this rtable. In a plan tree, it's
7748  * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7749  * down into the subplans, or INDEX_VAR, which is resolved similarly.
7750  *
7751  * Note: unlike get_variable and resolve_special_varno, we need not worry
7752  * about inheritance mapping: a child Var should have the same datatype as
7753  * its parent, and here we're really only interested in the Var's type.
7754  */
7755  if (varno >= 1 && varno <= list_length(dpns->rtable))
7756  {
7757  rte = rt_fetch(varno, dpns->rtable);
7758  attnum = varattno;
7759  }
7760  else if (varno == OUTER_VAR && dpns->outer_tlist)
7761  {
7762  TargetEntry *tle;
7763  deparse_namespace save_dpns;
7764  const char *result;
7765 
7766  tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7767  if (!tle)
7768  elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7769 
7770  Assert(netlevelsup == 0);
7771  push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7772 
7773  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7774  levelsup, context);
7775 
7776  pop_child_plan(dpns, &save_dpns);
7777  return result;
7778  }
7779  else if (varno == INNER_VAR && dpns->inner_tlist)
7780  {
7781  TargetEntry *tle;
7782  deparse_namespace save_dpns;
7783  const char *result;
7784 
7785  tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7786  if (!tle)
7787  elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7788 
7789  Assert(netlevelsup == 0);
7790  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7791 
7792  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7793  levelsup, context);
7794 
7795  pop_child_plan(dpns, &save_dpns);
7796  return result;
7797  }
7798  else if (varno == INDEX_VAR && dpns->index_tlist)
7799  {
7800  TargetEntry *tle;
7801  const char *result;
7802 
7803  tle = get_tle_by_resno(dpns->index_tlist, varattno);
7804  if (!tle)
7805  elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7806 
7807  Assert(netlevelsup == 0);
7808 
7809  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7810  levelsup, context);
7811 
7812  return result;
7813  }
7814  else
7815  {
7816  elog(ERROR, "bogus varno: %d", varno);
7817  return NULL; /* keep compiler quiet */
7818  }
7819 
7820  if (attnum == InvalidAttrNumber)
7821  {
7822  /* Var is whole-row reference to RTE, so select the right field */
7823  return get_rte_attribute_name(rte, fieldno);
7824  }
7825 
7826  /*
7827  * This part has essentially the same logic as the parser's
7828  * expandRecordVariable() function, but we are dealing with a different
7829  * representation of the input context, and we only need one field name
7830  * not a TupleDesc. Also, we need special cases for finding subquery and
7831  * CTE subplans when deparsing Plan trees.
7832  */
7833  expr = (Node *) var; /* default if we can't drill down */
7834 
7835  switch (rte->rtekind)
7836  {
7837  case RTE_RELATION:
7838  case RTE_VALUES:
7839  case RTE_NAMEDTUPLESTORE:
7840  case RTE_RESULT:
7841 
7842  /*
7843  * This case should not occur: a column of a table, values list,
7844  * or ENR shouldn't have type RECORD. Fall through and fail (most
7845  * likely) at the bottom.
7846  */
7847  break;
7848  case RTE_SUBQUERY:
7849  /* Subselect-in-FROM: examine sub-select's output expr */
7850  {
7851  if (rte->subquery)
7852  {
7854  attnum);
7855 
7856  if (ste == NULL || ste->resjunk)
7857  elog(ERROR, "subquery %s does not have attribute %d",
7858  rte->eref->aliasname, attnum);
7859  expr = (Node *) ste->expr;
7860  if (IsA(expr, Var))
7861  {
7862  /*
7863  * Recurse into the sub-select to see what its Var
7864  * refers to. We have to build an additional level of
7865  * namespace to keep in step with varlevelsup in the
7866  * subselect; furthermore, the subquery RTE might be
7867  * from an outer query level, in which case the
7868  * namespace for the subselect must have that outer
7869  * level as parent namespace.
7870  */
7871  List *save_nslist = context->namespaces;
7872  List *parent_namespaces;
7873  deparse_namespace mydpns;
7874  const char *result;
7875 
7876  parent_namespaces = list_copy_tail(context->namespaces,
7877  netlevelsup);
7878 
7879  set_deparse_for_query(&mydpns, rte->subquery,
7880  parent_namespaces);
7881 
7882  context->namespaces = lcons(&mydpns, parent_namespaces);
7883 
7884  result = get_name_for_var_field((Var *) expr, fieldno,
7885  0, context);
7886 
7887  context->namespaces = save_nslist;
7888 
7889  return result;
7890  }
7891  /* else fall through to inspect the expression */
7892  }
7893  else
7894  {
7895  /*
7896  * We're deparsing a Plan tree so we don't have complete
7897  * RTE entries (in particular, rte->subquery is NULL). But
7898  * the only place we'd see a Var directly referencing a
7899  * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7900  * look into the child plan's tlist instead.
7901  */
7902  TargetEntry *tle;
7903  deparse_namespace save_dpns;
7904  const char *result;
7905 
7906  if (!dpns->inner_plan)
7907  elog(ERROR, "failed to find plan for subquery %s",
7908  rte->eref->aliasname);
7909  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7910  if (!tle)
7911  elog(ERROR, "bogus varattno for subquery var: %d",
7912  attnum);
7913  Assert(netlevelsup == 0);
7914  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7915 
7916  result = get_name_for_var_field((Var *) tle->expr, fieldno,
7917  levelsup, context);
7918 
7919  pop_child_plan(dpns, &save_dpns);
7920  return result;
7921  }
7922  }
7923  break;
7924  case RTE_JOIN:
7925  /* Join RTE --- recursively inspect the alias variable */
7926  if (rte->joinaliasvars == NIL)
7927  elog(ERROR, "cannot decompile join alias var in plan tree");
7928  Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7929  expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
7930  Assert(expr != NULL);
7931  /* we intentionally don't strip implicit coercions here */
7932  if (IsA(expr, Var))
7933  return get_name_for_var_field((Var *) expr, fieldno,
7934  var->varlevelsup + levelsup,
7935  context);
7936  /* else fall through to inspect the expression */
7937  break;
7938  case RTE_FUNCTION:
7939  case RTE_TABLEFUNC:
7940 
7941  /*
7942  * We couldn't get here unless a function is declared with one of
7943  * its result columns as RECORD, which is not allowed.
7944  */
7945  break;
7946  case RTE_CTE:
7947  /* CTE reference: examine subquery's output expr */
7948  {
7949  CommonTableExpr *cte = NULL;
7950  Index ctelevelsup;
7951  ListCell *lc;
7952 
7953  /*
7954  * Try to find the referenced CTE using the namespace stack.
7955  */
7956  ctelevelsup = rte->ctelevelsup + netlevelsup;
7957  if (ctelevelsup >= list_length(context->namespaces))
7958  lc = NULL;
7959  else
7960  {
7961  deparse_namespace *ctedpns;
7962 
7963  ctedpns = (deparse_namespace *)
7964  list_nth(context->namespaces, ctelevelsup);
7965  foreach(lc, ctedpns->ctes)
7966  {
7967  cte = (CommonTableExpr *) lfirst(lc);
7968  if (strcmp(cte->ctename, rte->ctename) == 0)
7969  break;
7970  }
7971  }
7972  if (lc != NULL)
7973  {
7974  Query *ctequery = (Query *) cte->ctequery;
7976  attnum);
7977 
7978  if (ste == NULL || ste->resjunk)
7979  elog(ERROR, "CTE %s does not have attribute %d",
7980  rte->eref->aliasname, attnum);
7981  expr = (Node *) ste->expr;
7982  if (IsA(expr, Var))
7983  {
7984  /*
7985  * Recurse into the CTE to see what its Var refers to.
7986  * We have to build an additional level of namespace
7987  * to keep in step with varlevelsup in the CTE;
7988  * furthermore it could be an outer CTE (compare
7989  * SUBQUERY case above).
7990  */
7991  List *save_nslist = context->namespaces;
7992  List *parent_namespaces;
7993  deparse_namespace mydpns;
7994  const char *result;
7995 
7996  parent_namespaces = list_copy_tail(context->namespaces,
7997  ctelevelsup);
7998 
7999  set_deparse_for_query(&mydpns, ctequery,
8000  parent_namespaces);
8001 
8002  context->namespaces = lcons(&mydpns, parent_namespaces);
8003 
8004  result = get_name_for_var_field((Var *) expr, fieldno,
8005  0, context);
8006 
8007  context->namespaces = save_nslist;
8008 
8009  return result;
8010  }
8011  /* else fall through to inspect the expression */
8012  }
8013  else
8014  {
8015  /*
8016  * We're deparsing a Plan tree so we don't have a CTE
8017  * list. But the only places we'd see a Var directly
8018  * referencing a CTE RTE are in CteScan or WorkTableScan
8019  * plan nodes. For those cases, set_deparse_plan arranged
8020  * for dpns->inner_plan to be the plan node that emits the
8021  * CTE or RecursiveUnion result, and we can look at its
8022  * tlist instead.
8023  */
8024  TargetEntry *tle;
8025  deparse_namespace save_dpns;
8026  const char *result;
8027 
8028  if (!dpns->inner_plan)
8029  elog(ERROR, "failed to find plan for CTE %s",
8030  rte->eref->aliasname);
8031  tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8032  if (!tle)
8033  elog(ERROR, "bogus varattno for subquery var: %d",
8034  attnum);
8035  Assert(netlevelsup == 0);
8036  push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8037 
8038  result = get_name_for_var_field((Var *) tle->expr, fieldno,
8039  levelsup, context);
8040 
8041  pop_child_plan(dpns, &save_dpns);
8042  return result;
8043  }
8044  }
8045  break;
8046  }
8047 
8048  /*
8049  * We now have an expression we can't expand any more, so see if
8050  * get_expr_result_tupdesc() can do anything with it.
8051  */
8052  tupleDesc = get_expr_result_tupdesc(expr, false);
8053  /* Got the tupdesc, so we can extract the field name */
8054  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8055  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8056 }
8057 
8058 /*
8059  * Try to find the referenced expression for a PARAM_EXEC Param that might
8060  * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
8061  *
8062  * If successful, return the expression and set *dpns_p and *ancestor_cell_p
8063  * appropriately for calling push_ancestor_plan(). If no referent can be
8064  * found, return NULL.
8065  */
8066 static Node *
8068  deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
8069 {
8070  /* Initialize output parameters to prevent compiler warnings */
8071  *dpns_p = NULL;
8072  *ancestor_cell_p = NULL;
8073 
8074  /*
8075  * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8076  * SubPlan argument. This will necessarily be in some ancestor of the
8077  * current expression's Plan node.
8078  */
8079  if (param->paramkind == PARAM_EXEC)
8080  {
8081  deparse_namespace *dpns;
8082  Plan *child_plan;
8083  ListCell *lc;
8084 
8085  dpns = (deparse_namespace *) linitial(context->namespaces);
8086  child_plan = dpns->plan;
8087 
8088  foreach(lc, dpns->ancestors)
8089  {
8090  Node *ancestor = (Node *) lfirst(lc);
8091  ListCell *lc2;
8092 
8093  /*
8094  * NestLoops transmit params to their inner child only.
8095  */
8096  if (IsA(ancestor, NestLoop) &&
8097  child_plan == innerPlan(ancestor))
8098  {
8099  NestLoop *nl = (NestLoop *) ancestor;
8100 
8101  foreach(lc2, nl->nestParams)
8102  {
8103  NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8104 
8105  if (nlp->paramno == param->paramid)
8106  {
8107  /* Found a match, so return it */
8108  *dpns_p = dpns;
8109  *ancestor_cell_p = lc;
8110  return (Node *) nlp->paramval;
8111  }
8112  }
8113  }
8114 
8115  /*
8116  * If ancestor is a SubPlan, check the arguments it provides.
8117  */
8118  if (IsA(ancestor, SubPlan))
8119  {
8120  SubPlan *subplan = (SubPlan *) ancestor;
8121  ListCell *lc3;
8122  ListCell *lc4;
8123 
8124  forboth(lc3, subplan->parParam, lc4, subplan->args)
8125  {
8126  int paramid = lfirst_int(lc3);
8127  Node *arg = (Node *) lfirst(lc4);
8128 
8129  if (paramid == param->paramid)
8130  {
8131  /*
8132  * Found a match, so return it. But, since Vars in
8133  * the arg are to be evaluated in the surrounding
8134  * context, we have to point to the next ancestor item
8135  * that is *not* a SubPlan.
8136  */
8137  ListCell *rest;
8138 
8139  for_each_cell(rest, dpns->ancestors,
8140  lnext(dpns->ancestors, lc))
8141  {
8142  Node *ancestor2 = (Node *) lfirst(rest);
8143 
8144  if (!IsA(ancestor2, SubPlan))
8145  {
8146  *dpns_p = dpns;
8147  *ancestor_cell_p = rest;
8148  return arg;
8149  }
8150  }
8151  elog(ERROR, "SubPlan cannot be outermost ancestor");
8152  }
8153  }
8154 
8155  /* SubPlan isn't a kind of Plan, so skip the rest */
8156  continue;
8157  }
8158 
8159  /*
8160  * We need not consider the ancestor's initPlan list, since
8161  * initplans never have any parParams.
8162  */
8163 
8164  /* No luck, crawl up to next ancestor */
8165  child_plan = (Plan *) ancestor;
8166  }
8167  }
8168 
8169  /* No referent found */
8170  return NULL;
8171 }
8172 
8173 /*
8174  * Try to find a subplan/initplan that emits the value for a PARAM_EXEC Param.
8175  *
8176  * If successful, return the generating subplan/initplan and set *column_p
8177  * to the subplan's 0-based output column number.
8178  * Otherwise, return NULL.
8179  */
8180 static SubPlan *
8182 {
8183  /* Initialize output parameter to prevent compiler warnings */
8184  *column_p = 0;
8185 
8186  /*
8187  * If it's a PARAM_EXEC parameter, search the current plan node as well as
8188  * ancestor nodes looking for a subplan or initplan that emits the value
8189  * for the Param. It could appear in the setParams of an initplan or
8190  * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
8191  */
8192  if (param->paramkind == PARAM_EXEC)
8193  {
8194  SubPlan *result;
8195  deparse_namespace *dpns;
8196  ListCell *lc;
8197 
8198  dpns = (deparse_namespace *) linitial(context->namespaces);
8199 
8200  /* First check the innermost plan node's initplans */
8201  result = find_param_generator_initplan(param, dpns->plan, column_p);
8202  if (result)
8203  return result;
8204 
8205  /*
8206  * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
8207  * which can be referenced by Params elsewhere in the targetlist.
8208  * (Such Params should always be in the same targetlist, so there's no
8209  * need to do this work at upper plan nodes.)
8210  */
8211  foreach_node(TargetEntry, tle, dpns->plan->targetlist)
8212  {
8213  if (tle->expr && IsA(tle->expr, SubPlan))
8214  {
8215  SubPlan *subplan = (SubPlan *) tle->expr;
8216 
8217  if (subplan->subLinkType == MULTIEXPR_SUBLINK)
8218  {
8219  foreach_int(paramid, subplan->setParam)
8220  {
8221  if (paramid == param->paramid)
8222  {
8223  /* Found a match, so return it. */
8224  *column_p = foreach_current_index(paramid);
8225  return subplan;
8226  }
8227  }
8228  }
8229  }
8230  }
8231 
8232  /* No luck, so check the ancestor nodes */
8233  foreach(lc, dpns->ancestors)
8234  {
8235  Node *ancestor = (Node *) lfirst(lc);
8236 
8237  /*
8238  * If ancestor is a SubPlan, check the paramIds it provides.
8239  */
8240  if (IsA(ancestor, SubPlan))
8241  {
8242  SubPlan *subplan = (SubPlan *) ancestor;
8243 
8244  foreach_int(paramid, subplan->paramIds)
8245  {
8246  if (paramid == param->paramid)
8247  {
8248  /* Found a match, so return it. */
8249  *column_p = foreach_current_index(paramid);
8250  return subplan;
8251  }
8252  }
8253 
8254  /* SubPlan isn't a kind of Plan, so skip the rest */
8255  continue;
8256  }
8257 
8258  /*
8259  * Otherwise, it's some kind of Plan node, so check its initplans.
8260  */
8261  result = find_param_generator_initplan(param, (Plan *) ancestor,
8262  column_p);
8263  if (result)
8264  return result;
8265 
8266  /* No luck, crawl up to next ancestor */
8267  }
8268  }
8269 
8270  /* No generator found */
8271  return NULL;
8272 }
8273 
8274 /*
8275  * Subroutine for find_param_generator: search one Plan node's initplans
8276  */
8277 static SubPlan *
8279 {
8280  foreach_node(SubPlan, subplan, plan->initPlan)
8281  {
8282  foreach_int(paramid, subplan->setParam)
8283  {
8284  if (paramid == param->paramid)
8285  {
8286  /* Found a match, so return it. */
8287  *column_p = foreach_current_index(paramid);
8288  return subplan;
8289  }
8290  }
8291  }
8292  return NULL;
8293 }
8294 
8295 /*
8296  * Display a Param appropriately.
8297  */
8298 static void
8300 {
8301  Node *expr;
8302  deparse_namespace *dpns;
8303  ListCell *ancestor_cell;
8304  SubPlan *subplan;
8305  int column;
8306 
8307  /*
8308  * If it's a PARAM_EXEC parameter, try to locate the expression from which
8309  * the parameter was computed. This stanza handles only cases in which
8310  * the Param represents an input to the subplan we are currently in.
8311  */
8312  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8313  if (expr)
8314  {
8315  /* Found a match, so print it */
8316  deparse_namespace save_dpns;
8317  bool save_varprefix;
8318  bool need_paren;
8319 
8320  /* Switch attention to the ancestor plan node */
8321  push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8322 
8323  /*
8324  * Force prefixing of Vars, since they won't belong to the relation
8325  * being scanned in the original plan node.
8326  */
8327  save_varprefix = context->varprefix;
8328  context->varprefix = true;
8329 
8330  /*
8331  * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8332  * upper-level Param, which wouldn't need extra parentheses.
8333  * Otherwise, insert parens to ensure the expression looks atomic.
8334  */
8335  need_paren = !(IsA(expr, Var) ||
8336  IsA(expr, Aggref) ||
8337  IsA(expr, GroupingFunc) ||
8338  IsA(expr, Param));
8339  if (need_paren)
8340  appendStringInfoChar(context->buf, '(');
8341 
8342  get_rule_expr(expr, context, false);
8343 
8344  if (need_paren)
8345  appendStringInfoChar(context->buf, ')');
8346 
8347  context->varprefix = save_varprefix;
8348 
8349  pop_ancestor_plan(dpns, &save_dpns);
8350 
8351  return;
8352  }
8353 
8354  /*
8355  * Alternatively, maybe it's a subplan output, which we print as a
8356  * reference to the subplan. (We could drill down into the subplan and
8357  * print the relevant targetlist expression, but that has been deemed too
8358  * confusing since it would violate normal SQL scope rules. Also, we're
8359  * relying on this reference to show that the testexpr containing the
8360  * Param has anything to do with that subplan at all.)
8361  */
8362  subplan = find_param_generator(param, context, &column);
8363  if (subplan)
8364  {
8365  appendStringInfo(context->buf, "(%s%s).col%d",
8366  subplan->useHashTable ? "hashed " : "",
8367  subplan->plan_name, column + 1);
8368 
8369  return;
8370  }
8371 
8372  /*
8373  * If it's an external parameter, see if the outermost namespace provides
8374  * function argument names.
8375  */
8376  if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8377  {
8378  dpns = llast(context->namespaces);
8379  if (dpns->argnames &&
8380  param->paramid > 0 &&
8381  param->paramid <= dpns->numargs)
8382  {
8383  char *argname = dpns->argnames[param->paramid - 1];
8384 
8385  if (argname)
8386  {
8387  bool should_qualify = false;
8388  ListCell *lc;
8389 
8390  /*
8391  * Qualify the parameter name if there are any other deparse
8392  * namespaces with range tables. This avoids qualifying in
8393  * trivial cases like "RETURN a + b", but makes it safe in all
8394  * other cases.
8395  */
8396  foreach(lc, context->namespaces)
8397  {
8398  deparse_namespace *depns = lfirst(lc);
8399 
8400  if (depns->rtable_names != NIL)
8401  {
8402  should_qualify = true;
8403  break;
8404  }
8405  }
8406  if (should_qualify)
8407  {
8409  appendStringInfoChar(context->buf, '.');
8410  }
8411 
8413  return;
8414  }
8415  }
8416  }
8417 
8418  /*
8419  * Not PARAM_EXEC, or couldn't find referent: just print $N.
8420  *
8421  * It's a bug if we get here for anything except PARAM_EXTERN Params, but
8422  * in production builds printing $N seems more useful than failing.
8423  */
8424  Assert(param->paramkind == PARAM_EXTERN);
8425 
8426  appendStringInfo(context->buf, "$%d", param->paramid);
8427 }
8428 
8429 /*
8430  * get_simple_binary_op_name
8431  *
8432  * helper function for isSimpleNode
8433  * will return single char binary operator name, or NULL if it's not
8434  */
8435 static const char *
8437 {
8438  List *args = expr->args;
8439 
8440  if (list_length(args) == 2)
8441  {
8442  /* binary operator */
8443  Node *arg1 = (Node *) linitial(args);
8444  Node *arg2 = (Node *) lsecond(args);
8445  const char *op;
8446 
8447  op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8448  if (strlen(op) == 1)
8449  return op;
8450  }
8451  return NULL;
8452 }
8453 
8454 
8455 /*
8456  * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
8457  *
8458  * true : simple in the context of parent node's type
8459  * false : not simple
8460  */
8461 static bool
8462 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
8463 {
8464  if (!node)
8465  return false;
8466 
8467  switch (nodeTag(node))
8468  {
8469  case T_Var:
8470  case T_Const:
8471  case T_Param:
8472  case T_CoerceToDomainValue:
8473  case T_SetToDefault:
8474  case T_CurrentOfExpr:
8475  /* single words: always simple */
8476  return true;
8477 
8478  case T_SubscriptingRef:
8479  case T_ArrayExpr:
8480  case T_RowExpr:
8481  case T_CoalesceExpr:
8482  case T_MinMaxExpr:
8483  case T_SQLValueFunction:
8484  case T_XmlExpr:
8485  case T_NextValueExpr:
8486  case T_NullIfExpr:
8487  case T_Aggref:
8488  case T_GroupingFunc:
8489  case T_WindowFunc:
8490  case T_MergeSupportFunc:
8491  case T_FuncExpr:
8492  case T_JsonConstructorExpr:
8493  case T_JsonExpr:
8494  /* function-like: name(..) or name[..] */
8495  return true;
8496 
8497  /* CASE keywords act as parentheses */
8498  case T_CaseExpr:
8499  return true;
8500 
8501  case T_FieldSelect:
8502 
8503  /*
8504  * appears simple since . has top precedence, unless parent is
8505  * T_FieldSelect itself!
8506  */
8507  return !IsA(parentNode, FieldSelect);
8508 
8509  case T_FieldStore:
8510 
8511  /*
8512  * treat like FieldSelect (probably doesn't matter)
8513  */
8514  return !IsA(parentNode, FieldStore);
8515 
8516  case T_CoerceToDomain:
8517  /* maybe simple, check args */
8518  return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8519  node, prettyFlags);
8520  case T_RelabelType:
8521  return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8522  node, prettyFlags);
8523  case T_CoerceViaIO:
8524  return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8525  node, prettyFlags);
8526  case T_ArrayCoerceExpr:
8527  return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8528  node, prettyFlags);
8529  case T_ConvertRowtypeExpr:
8530  return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8531  node, prettyFlags);
8532 
8533  case T_OpExpr:
8534  {
8535  /* depends on parent node type; needs further checking */
8536  if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8537  {
8538  const char *op;
8539  const char *parentOp;
8540  bool is_lopriop;
8541  bool is_hipriop;
8542  bool is_lopriparent;
8543  bool is_hipriparent;
8544 
8545  op = get_simple_binary_op_name((OpExpr *) node);
8546  if (!op)
8547  return false;
8548 
8549  /* We know only the basic operators + - and * / % */
8550  is_lopriop = (strchr("+-", *op) != NULL);
8551  is_hipriop = (strchr("*/%", *op) != NULL);
8552  if (!(is_lopriop || is_hipriop))
8553  return false;
8554 
8555  parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8556  if (!parentOp)
8557  return false;
8558 
8559  is_lopriparent = (strchr("+-", *parentOp) != NULL);
8560  is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8561  if (!(is_lopriparent || is_hipriparent))
8562  return false;
8563 
8564  if (is_hipriop && is_lopriparent)
8565  return true; /* op binds tighter than parent */
8566 
8567  if (is_lopriop && is_hipriparent)
8568  return false;
8569 
8570  /*
8571  * Operators are same priority --- can skip parens only if
8572  * we have (a - b) - c, not a - (b - c).
8573  */
8574  if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8575  return true;
8576 
8577  return false;
8578  }
8579  /* else do the same stuff as for T_SubLink et al. */
8580  }
8581  /* FALLTHROUGH */
8582 
8583  case T_SubLink:
8584  case T_NullTest:
8585  case T_BooleanTest:
8586  case T_DistinctExpr:
8587  case T_JsonIsPredicate:
8588  switch (nodeTag(parentNode))
8589  {
8590  case T_FuncExpr:
8591  {
8592  /* special handling for casts and COERCE_SQL_SYNTAX */
8593  CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8594 
8595  if (type == COERCE_EXPLICIT_CAST ||
8598  return false;
8599  return true; /* own parentheses */
8600  }
8601  case T_BoolExpr: /* lower precedence */
8602  case T_SubscriptingRef: /* other separators */
8603  case T_ArrayExpr: /* other separators */
8604  case T_RowExpr: /* other separators */
8605  case T_CoalesceExpr: /* own parentheses */
8606  case T_MinMaxExpr: /* own parentheses */
8607  case T_XmlExpr: /* own parentheses */
8608  case T_NullIfExpr: /* other separators */
8609  case T_Aggref: /* own parentheses */
8610  case T_GroupingFunc: /* own parentheses */
8611  case T_WindowFunc: /* own parentheses */
8612  case T_CaseExpr: /* other separators */
8613  return true;
8614  default:
8615  return false;
8616  }
8617 
8618  case T_BoolExpr:
8619  switch (nodeTag(parentNode))
8620  {
8621  case T_BoolExpr:
8622  if (prettyFlags & PRETTYFLAG_PAREN)
8623  {
8625  BoolExprType parentType;
8626 
8627  type = ((BoolExpr *) node)->boolop;
8628  parentType = ((BoolExpr *) parentNode)->boolop;
8629  switch (type)
8630  {
8631  case NOT_EXPR:
8632  case AND_EXPR:
8633  if (parentType == AND_EXPR || parentType == OR_EXPR)
8634  return true;
8635  break;
8636  case OR_EXPR:
8637  if (parentType == OR_EXPR)
8638  return true;
8639  break;
8640  }
8641  }
8642  return false;
8643  case T_FuncExpr:
8644  {
8645  /* special handling for casts and COERCE_SQL_SYNTAX */
8646  CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8647 
8648  if (type == COERCE_EXPLICIT_CAST ||
8651  return false;
8652  return true; /* own parentheses */
8653  }
8654  case T_SubscriptingRef: /* other separators */
8655  case T_ArrayExpr: /* other separators */
8656  case T_RowExpr: /* other separators */
8657  case T_CoalesceExpr: /* own parentheses */
8658  case T_MinMaxExpr: /* own parentheses */
8659  case T_XmlExpr: /* own parentheses */
8660  case T_NullIfExpr: /* other separators */
8661  case T_Aggref: /* own parentheses */
8662  case T_GroupingFunc: /* own parentheses */
8663  case T_WindowFunc: /* own parentheses */
8664  case T_CaseExpr: /* other separators */
8665  case T_JsonExpr: /* own parentheses */
8666  return true;
8667  default:
8668  return false;
8669  }
8670 
8671  case T_JsonValueExpr:
8672  /* maybe simple, check args */
8673  return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
8674  node, prettyFlags);
8675 
8676  default:
8677  break;
8678  }
8679  /* those we don't know: in dubio complexo */
8680  return false;
8681 }
8682 
8683 
8684 /*
8685  * appendContextKeyword - append a keyword to buffer
8686  *
8687  * If prettyPrint is enabled, perform a line break, and adjust indentation.
8688  * Otherwise, just append the keyword.
8689  */
8690 static void
8692  int indentBefore, int indentAfter, int indentPlus)
8693 {
8694  StringInfo buf = context->buf;
8695 
8696  if (PRETTY_INDENT(context))
8697  {
8698  int indentAmount;
8699 
8700  context->indentLevel += indentBefore;
8701 
8702  /* remove any trailing spaces currently in the buffer ... */
8704  /* ... then add a newline and some spaces */
8705  appendStringInfoChar(buf, '\n');
8706 
8707  if (context->indentLevel < PRETTYINDENT_LIMIT)
8708  indentAmount = Max(context->indentLevel, 0) + indentPlus;
8709  else
8710  {
8711  /*
8712  * If we're indented more than PRETTYINDENT_LIMIT characters, try
8713  * to conserve horizontal space by reducing the per-level
8714  * indentation. For best results the scale factor here should
8715  * divide all the indent amounts that get added to indentLevel
8716  * (PRETTYINDENT_STD, etc). It's important that the indentation
8717  * not grow unboundedly, else deeply-nested trees use O(N^2)
8718  * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8719  */
8720  indentAmount = PRETTYINDENT_LIMIT +
8721  (context->indentLevel - PRETTYINDENT_LIMIT) /
8722  (PRETTYINDENT_STD / 2);
8723  indentAmount %= PRETTYINDENT_LIMIT;
8724  /* scale/wrap logic affects indentLevel, but not indentPlus */
8725  indentAmount += indentPlus;
8726  }
8727  appendStringInfoSpaces(buf, indentAmount);
8728 
8730 
8731  context->indentLevel += indentAfter;
8732  if (context->indentLevel < 0)
8733  context->indentLevel = 0;
8734  }
8735  else
8737 }
8738 
8739 /*
8740  * removeStringInfoSpaces - delete trailing spaces from a buffer.
8741  *
8742  * Possibly this should move to stringinfo.c at some point.
8743  */
8744 static void
8746 {
8747  while (str->len > 0 && str->data[str->len - 1] == ' ')
8748  str->data[--(str->len)] = '\0';
8749 }
8750 
8751 
8752 /*
8753  * get_rule_expr_paren - deparse expr using get_rule_expr,
8754  * embracing the string with parentheses if necessary for prettyPrint.
8755  *
8756  * Never embrace if prettyFlags=0, because it's done in the calling node.
8757  *
8758  * Any node that does *not* embrace its argument node by sql syntax (with
8759  * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
8760  * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
8761  * added.
8762  */
8763 static void
8765  bool showimplicit, Node *parentNode)
8766 {
8767  bool need_paren;
8768 
8769  need_paren = PRETTY_PAREN(context) &&
8770  !isSimpleNode(node, parentNode, context->prettyFlags);
8771 
8772  if (need_paren)
8773  appendStringInfoChar(context->buf, '(');
8774 
8775  get_rule_expr(node, context, showimplicit);
8776 
8777  if (need_paren)
8778  appendStringInfoChar(context->buf, ')');
8779 }
8780 
8781 static void
8783  const char *on)
8784 {
8785  /*
8786  * The order of array elements must correspond to the order of
8787  * JsonBehaviorType members.
8788  */
8789  const char *behavior_names[] =
8790  {
8791  " NULL",
8792  " ERROR",
8793  " EMPTY",
8794  " TRUE",
8795  " FALSE",
8796  " UNKNOWN",
8797  " EMPTY ARRAY",
8798  " EMPTY OBJECT",
8799  " DEFAULT "
8800  };
8801 
8802  if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
8803  elog(ERROR, "invalid json behavior type: %d", behavior->btype);
8804 
8805  appendStringInfoString(context->buf, behavior_names[behavior->btype]);
8806 
8807  if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
8808  get_rule_expr(behavior->expr, context, false);
8809 
8810  appendStringInfo(context->buf, " ON %s", on);
8811 }
8812 
8813 /*
8814  * get_json_expr_options
8815  *
8816  * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
8817  * JSON_TABLE columns.
8818  */
8819 static void
8821  JsonBehaviorType default_behavior)
8822 {
8823  if (jsexpr->op == JSON_QUERY_OP)
8824  {
8825  if (jsexpr->wrapper == JSW_CONDITIONAL)
8826  appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
8827  else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
8828  appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
8829  /* The default */
8830  else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
8831  appendStringInfoString(context->buf, " WITHOUT WRAPPER");
8832 
8833  if (jsexpr->omit_quotes)
8834  appendStringInfoString(context->buf, " OMIT QUOTES");
8835  /* The default */
8836  else
8837  appendStringInfoString(context->buf, " KEEP QUOTES");
8838  }
8839 
8840  if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
8841  get_json_behavior(jsexpr->on_empty, context, "EMPTY");
8842 
8843  if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
8844  get_json_behavior(jsexpr->on_error, context, "ERROR");
8845 }
8846 
8847 /* ----------
8848  * get_rule_expr - Parse back an expression
8849  *
8850  * Note: showimplicit determines whether we display any implicit cast that
8851  * is present at the top of the expression tree. It is a passed argument,
8852  * not a field of the context struct, because we change the value as we
8853  * recurse down into the expression. In general we suppress implicit casts
8854  * when the result type is known with certainty (eg, the arguments of an
8855  * OR must be boolean). We display implicit casts for arguments of functions
8856  * and operators, since this is needed to be certain that the same function
8857  * or operator will be chosen when the expression is re-parsed.
8858  * ----------
8859  */
8860 static void
8862  bool showimplicit)
8863 {
8864  StringInfo buf = context->buf;
8865 
8866  if (node == NULL)
8867  return;
8868 
8869  /* Guard against excessively long or deeply-nested queries */
8872 
8873  /*
8874  * Each level of get_rule_expr must emit an indivisible term
8875  * (parenthesized if necessary) to ensure result is reparsed into the same
8876  * expression tree. The only exception is that when the input is a List,
8877  * we emit the component items comma-separated with no surrounding
8878  * decoration; this is convenient for most callers.
8879  */
8880  switch (nodeTag(node))
8881  {
8882  case T_Var:
8883  (void) get_variable((Var *) node, 0, false, context);
8884  break;
8885 
8886  case T_Const:
8887  get_const_expr((Const *) node, context, 0);
8888  break;
8889 
8890  case T_Param:
8891  get_parameter((Param *) node, context);
8892  break;
8893 
8894  case T_Aggref:
8895  get_agg_expr((Aggref *) node, context, (Aggref *) node);
8896  break;
8897 
8898  case T_GroupingFunc:
8899  {
8900  GroupingFunc *gexpr = (GroupingFunc *) node;
8901 
8902  appendStringInfoString(buf, "GROUPING(");
8903  get_rule_expr((Node *) gexpr->args, context, true);
8904  appendStringInfoChar(buf, ')');
8905  }
8906  break;
8907 
8908  case T_WindowFunc:
8910  break;
8911 
8912  case T_MergeSupportFunc:
8913  appendStringInfoString(buf, "MERGE_ACTION()");
8914  break;
8915 
8916  case T_SubscriptingRef:
8917  {
8918  SubscriptingRef *sbsref = (SubscriptingRef *) node;
8919  bool need_parens;
8920 
8921  /*
8922  * If the argument is a CaseTestExpr, we must be inside a
8923  * FieldStore, ie, we are assigning to an element of an array
8924  * within a composite column. Since we already punted on
8925  * displaying the FieldStore's target information, just punt
8926  * here too, and display only the assignment source
8927  * expression.
8928  */
8929  if (IsA(sbsref->refexpr, CaseTestExpr))
8930  {
8931  Assert(sbsref->refassgnexpr);
8932  get_rule_expr((Node *) sbsref->refassgnexpr,
8933  context, showimplicit);
8934  break;
8935  }
8936 
8937  /*
8938  * Parenthesize the argument unless it's a simple Var or a
8939  * FieldSelect. (In particular, if it's another
8940  * SubscriptingRef, we *must* parenthesize to avoid
8941  * confusion.)
8942  */
8943  need_parens = !IsA(sbsref->refexpr, Var) &&
8944  !IsA(sbsref->refexpr, FieldSelect);
8945  if (need_parens)
8946  appendStringInfoChar(buf, '(');
8947  get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
8948  if (need_parens)
8949  appendStringInfoChar(buf, ')');
8950 
8951  /*
8952  * If there's a refassgnexpr, we want to print the node in the
8953  * format "container[subscripts] := refassgnexpr". This is
8954  * not legal SQL, so decompilation of INSERT or UPDATE
8955  * statements should always use processIndirection as part of
8956  * the statement-level syntax. We should only see this when
8957  * EXPLAIN tries to print the targetlist of a plan resulting
8958  * from such a statement.
8959  */
8960  if (sbsref->refassgnexpr)
8961  {
8962  Node *refassgnexpr;
8963 
8964  /*
8965  * Use processIndirection to print this node's subscripts
8966  * as well as any additional field selections or
8967  * subscripting in immediate descendants. It returns the
8968  * RHS expr that is actually being "assigned".
8969  */
8970  refassgnexpr = processIndirection(node, context);
8971  appendStringInfoString(buf, " := ");
8972  get_rule_expr(refassgnexpr, context, showimplicit);
8973  }
8974  else
8975  {
8976  /* Just an ordinary container fetch, so print subscripts */
8977  printSubscripts(sbsref, context);
8978  }
8979  }
8980  break;
8981 
8982  case T_FuncExpr:
8983  get_func_expr((FuncExpr *) node, context, showimplicit);
8984  break;
8985 
8986  case T_NamedArgExpr:
8987  {
8988  NamedArgExpr *na = (NamedArgExpr *) node;
8989 
8990  appendStringInfo(buf, "%s => ", quote_identifier(na->name));
8991  get_rule_expr((Node *) na->arg, context, showimplicit);
8992  }
8993  break;
8994 
8995  case T_OpExpr:
8996  get_oper_expr((OpExpr *) node, context);
8997  break;
8998 
8999  case T_DistinctExpr:
9000  {
9001  DistinctExpr *expr = (DistinctExpr *) node;
9002  List *args = expr->args;
9003  Node *arg1 = (Node *) linitial(args);
9004  Node *arg2 = (Node *) lsecond(args);
9005 
9006  if (!PRETTY_PAREN(context))
9007  appendStringInfoChar(buf, '(');
9008  get_rule_expr_paren(arg1, context, true, node);
9009  appendStringInfoString(buf, " IS DISTINCT FROM ");
9010  get_rule_expr_paren(arg2, context, true, node);
9011  if (!PRETTY_PAREN(context))
9012  appendStringInfoChar(buf, ')');
9013  }
9014  break;
9015 
9016  case T_NullIfExpr:
9017  {
9018  NullIfExpr *nullifexpr = (NullIfExpr *) node;
9019 
9020  appendStringInfoString(buf, "NULLIF(");
9021  get_rule_expr((Node *) nullifexpr->args, context, true);
9022  appendStringInfoChar(buf, ')');
9023  }
9024  break;
9025 
9026  case T_ScalarArrayOpExpr:
9027  {
9028  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) 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  appendStringInfo(buf, " %s %s (",
9038  exprType(arg1),
9040  expr->useOr ? "ANY" : "ALL");
9041  get_rule_expr_paren(arg2, context, true, node);
9042 
9043  /*
9044  * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9045  * a bare sub-SELECT. Since we're here, the sub-SELECT must
9046  * be meant as a scalar sub-SELECT yielding an array value to
9047  * be used in ScalarArrayOpExpr; but the grammar will
9048  * preferentially interpret such a construct as an ANY/ALL
9049  * SubLink. To prevent misparsing the output that way, insert
9050  * a dummy coercion (which will be stripped by parse analysis,
9051  * so no inefficiency is added in dump and reload). This is
9052  * indeed most likely what the user wrote to get the construct
9053  * accepted in the first place.
9054  */
9055  if (IsA(arg2, SubLink) &&
9056  ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
9057  appendStringInfo(buf, "::%s",
9059  exprTypmod(arg2)));
9060  appendStringInfoChar(buf, ')');
9061  if (!PRETTY_PAREN(context))
9062  appendStringInfoChar(buf, ')');
9063  }
9064  break;
9065 
9066  case T_BoolExpr:
9067  {
9068  BoolExpr *expr = (BoolExpr *) node;
9069  Node *first_arg = linitial(expr->args);
9070  ListCell *arg;
9071 
9072  switch (expr->boolop)
9073  {
9074  case AND_EXPR:
9075  if (!PRETTY_PAREN(context))
9076  appendStringInfoChar(buf, '(');
9077  get_rule_expr_paren(first_arg, context,
9078  false, node);
9079  for_each_from(arg, expr->args, 1)
9080  {
9081  appendStringInfoString(buf, " AND ");
9083  false, node);
9084  }
9085  if (!PRETTY_PAREN(context))
9086  appendStringInfoChar(buf, ')');
9087  break;
9088 
9089  case OR_EXPR:
9090  if (!PRETTY_PAREN(context))
9091  appendStringInfoChar(buf, '(');
9092  get_rule_expr_paren(first_arg, context,
9093  false, node);
9094  for_each_from(arg, expr->args, 1)
9095  {
9096  appendStringInfoString(buf, " OR ");
9098  false, node);
9099  }
9100  if (!PRETTY_PAREN(context))
9101  appendStringInfoChar(buf, ')');
9102  break;
9103 
9104  case NOT_EXPR:
9105  if (!PRETTY_PAREN(context))
9106  appendStringInfoChar(buf, '(');
9107  appendStringInfoString(buf, "NOT ");
9108  get_rule_expr_paren(first_arg, context,
9109  false, node);
9110  if (!PRETTY_PAREN(context))
9111  appendStringInfoChar(buf, ')');
9112  break;
9113 
9114  default:
9115  elog(ERROR, "unrecognized boolop: %d",
9116  (int) expr->boolop);
9117  }
9118  }
9119  break;
9120 
9121  case T_SubLink:
9122  get_sublink_expr((SubLink *) node, context);
9123  break;
9124 
9125  case T_SubPlan:
9126  {
9127  SubPlan *subplan = (SubPlan *) node;
9128 
9129  /*
9130  * We cannot see an already-planned subplan in rule deparsing,
9131  * only while EXPLAINing a query plan. We don't try to
9132  * reconstruct the original SQL, just reference the subplan
9133  * that appears elsewhere in EXPLAIN's result. It does seem
9134  * useful to show the subLinkType and testexpr (if any), and
9135  * we also note whether the subplan will be hashed.
9136  */
9137  switch (subplan->subLinkType)
9138  {
9139  case EXISTS_SUBLINK:
9140  appendStringInfoString(buf, "EXISTS(");
9141  Assert(subplan->testexpr == NULL);
9142  break;
9143  case ALL_SUBLINK:
9144  appendStringInfoString(buf, "(ALL ");
9145  Assert(subplan->testexpr != NULL);
9146  break;
9147  case ANY_SUBLINK:
9148  appendStringInfoString(buf, "(ANY ");
9149  Assert(subplan->testexpr != NULL);
9150  break;
9151  case ROWCOMPARE_SUBLINK:
9152  /* Parenthesizing the testexpr seems sufficient */
9153  appendStringInfoChar(buf, '(');
9154  Assert(subplan->testexpr != NULL);
9155  break;
9156  case EXPR_SUBLINK:
9157  /* No need to decorate these subplan references */
9158  appendStringInfoChar(buf, '(');
9159  Assert(subplan->testexpr == NULL);
9160  break;
9161  case MULTIEXPR_SUBLINK:
9162  /* MULTIEXPR isn't executed in the normal way */
9163  appendStringInfoString(buf, "(rescan ");
9164  Assert(subplan->testexpr == NULL);
9165  break;
9166  case ARRAY_SUBLINK:
9167  appendStringInfoString(buf, "ARRAY(");
9168  Assert(subplan->testexpr == NULL);
9169  break;
9170  case CTE_SUBLINK:
9171  /* This case is unreachable within expressions */
9172  appendStringInfoString(buf, "CTE(");
9173  Assert(subplan->testexpr == NULL);
9174  break;
9175  }
9176 
9177  if (subplan->testexpr != NULL)
9178  {
9179  deparse_namespace *dpns;
9180 
9181  /*
9182  * Push SubPlan into ancestors list while deparsing
9183  * testexpr, so that we can handle PARAM_EXEC references
9184  * to the SubPlan's paramIds. (This makes it look like
9185  * the SubPlan is an "ancestor" of the current plan node,
9186  * which is a little weird, but it does no harm.) In this
9187  * path, we don't need to mention the SubPlan explicitly,
9188  * because the referencing Params will show its existence.
9189  */
9190  dpns = (deparse_namespace *) linitial(context->namespaces);
9191  dpns->ancestors = lcons(subplan, dpns->ancestors);
9192 
9193  get_rule_expr(subplan->testexpr, context, showimplicit);
9194  appendStringInfoChar(buf, ')');
9195 
9196  dpns->ancestors = list_delete_first(dpns->ancestors);
9197  }
9198  else
9199  {
9200  /* No referencing Params, so show the SubPlan's name */
9201  if (subplan->useHashTable)
9202  appendStringInfo(buf, "hashed %s)", subplan->plan_name);
9203  else
9204  appendStringInfo(buf, "%s)", subplan->plan_name);
9205  }
9206  }
9207  break;
9208 
9209  case T_AlternativeSubPlan:
9210  {
9211  AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
9212  ListCell *lc;
9213 
9214  /*
9215  * This case cannot be reached in normal usage, since no
9216  * AlternativeSubPlan can appear either in parsetrees or
9217  * finished plan trees. We keep it just in case somebody
9218  * wants to use this code to print planner data structures.
9219  */
9220  appendStringInfoString(buf, "(alternatives: ");
9221  foreach(lc, asplan->subplans)
9222  {
9223  SubPlan *splan = lfirst_node(SubPlan, lc);
9224 
9225  if (splan->useHashTable)
9226  appendStringInfo(buf, "hashed %s", splan->plan_name);
9227  else
9228  appendStringInfoString(buf, splan->plan_name);
9229  if (lnext(asplan->subplans, lc))
9230  appendStringInfoString(buf, " or ");
9231  }
9232  appendStringInfoChar(buf, ')');
9233  }
9234  break;
9235 
9236  case T_FieldSelect:
9237  {
9238  FieldSelect *fselect = (FieldSelect *) node;
9239  Node *arg = (Node *) fselect->arg;
9240  int fno = fselect->fieldnum;
9241  const char *fieldname;
9242  bool need_parens;
9243 
9244  /*
9245  * Parenthesize the argument unless it's an SubscriptingRef or
9246  * another FieldSelect. Note in particular that it would be
9247  * WRONG to not parenthesize a Var argument; simplicity is not
9248  * the issue here, having the right number of names is.
9249  */
9250  need_parens = !IsA(arg, SubscriptingRef) &&
9251  !IsA(arg, FieldSelect);
9252  if (need_parens)
9253  appendStringInfoChar(buf, '(');
9254  get_rule_expr(arg, context, true);
9255  if (need_parens)
9256  appendStringInfoChar(buf, ')');
9257 
9258  /*
9259  * Get and print the field name.
9260  */
9261  fieldname = get_name_for_var_field((Var *) arg, fno,
9262  0, context);
9263  appendStringInfo(buf, ".%s", quote_identifier(fieldname));
9264  }
9265  break;
9266 
9267  case T_FieldStore:
9268  {
9269  FieldStore *fstore = (FieldStore *) node;
9270  bool need_parens;
9271 
9272  /*
9273  * There is no good way to represent a FieldStore as real SQL,
9274  * so decompilation of INSERT or UPDATE statements should
9275  * always use processIndirection as part of the
9276  * statement-level syntax. We should only get here when
9277  * EXPLAIN tries to print the targetlist of a plan resulting
9278  * from such a statement. The plan case is even harder than
9279  * ordinary rules would be, because the planner tries to
9280  * collapse multiple assignments to the same field or subfield
9281  * into one FieldStore; so we can see a list of target fields
9282  * not just one, and the arguments could be FieldStores
9283  * themselves. We don't bother to try to print the target
9284  * field names; we just print the source arguments, with a
9285  * ROW() around them if there's more than one. This isn't
9286  * terribly complete, but it's probably good enough for
9287  * EXPLAIN's purposes; especially since anything more would be
9288  * either hopelessly confusing or an even poorer
9289  * representation of what the plan is actually doing.
9290  */
9291  need_parens = (list_length(fstore->newvals) != 1);
9292  if (need_parens)
9293  appendStringInfoString(buf, "ROW(");
9294  get_rule_expr((Node *) fstore->newvals, context, showimplicit);
9295  if (need_parens)
9296  appendStringInfoChar(buf, ')');
9297  }
9298  break;
9299 
9300  case T_RelabelType:
9301  {
9302  RelabelType *relabel = (RelabelType *) node;
9303  Node *arg = (Node *) relabel->arg;
9304 
9305  if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
9306  !showimplicit)
9307  {
9308  /* don't show the implicit cast */
9309  get_rule_expr_paren(arg, context, false, node);
9310  }
9311  else
9312  {
9314  relabel->resulttype,
9315  relabel->resulttypmod,
9316  node);
9317  }
9318  }
9319  break;
9320 
9321  case T_CoerceViaIO:
9322  {
9323  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
9324  Node *arg = (Node *) iocoerce->arg;
9325 
9326  if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9327  !showimplicit)
9328  {
9329  /* don't show the implicit cast */
9330  get_rule_expr_paren(arg, context, false, node);
9331  }
9332  else
9333  {
9335  iocoerce->resulttype,
9336  -1,
9337  node);
9338  }
9339  }
9340  break;
9341 
9342  case T_ArrayCoerceExpr:
9343  {
9344  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
9345  Node *arg = (Node *) acoerce->arg;
9346 
9347  if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9348  !showimplicit)
9349  {
9350  /* don't show the implicit cast */
9351  get_rule_expr_paren(arg, context, false, node);
9352  }
9353  else
9354  {
9356  acoerce->resulttype,
9357  acoerce->resulttypmod,
9358  node);
9359  }
9360  }
9361  break;
9362 
9363  case T_ConvertRowtypeExpr:
9364  {
9366  Node *arg = (Node *) convert->arg;
9367 
9368  if (convert->convertformat == COERCE_IMPLICIT_CAST &&
9369  !showimplicit)
9370  {
9371  /* don't show the implicit cast */
9372  get_rule_expr_paren(arg, context, false, node);
9373  }
9374  else
9375  {
9377  convert->resulttype, -1,
9378  node);
9379  }
9380  }
9381  break;
9382 
9383  case T_CollateExpr:
9384  {
9385  CollateExpr *collate = (CollateExpr *) node;
9386  Node *arg = (Node *) collate->arg;
9387 
9388  if (!PRETTY_PAREN(context))
9389  appendStringInfoChar(buf, '(');
9390  get_rule_expr_paren(arg, context, showimplicit, node);
9391  appendStringInfo(buf, " COLLATE %s",
9392  generate_collation_name(collate->collOid));
9393  if (!PRETTY_PAREN(context))
9394  appendStringInfoChar(buf, ')');
9395  }
9396  break;
9397 
9398  case T_CaseExpr:
9399  {
9400  CaseExpr *caseexpr = (CaseExpr *) node;
9401  ListCell *temp;
9402 
9403  appendContextKeyword(context, "CASE",
9404  0, PRETTYINDENT_VAR, 0);
9405  if (caseexpr->arg)
9406  {
9407  appendStringInfoChar(buf, ' ');
9408  get_rule_expr((Node *) caseexpr->arg, context, true);
9409  }
9410  foreach(temp, caseexpr->args)
9411  {
9412  CaseWhen *when = (CaseWhen *) lfirst(temp);
9413  Node *w = (Node *) when->expr;
9414 
9415  if (caseexpr->arg)
9416  {
9417  /*
9418  * The parser should have produced WHEN clauses of the
9419  * form "CaseTestExpr = RHS", possibly with an
9420  * implicit coercion inserted above the CaseTestExpr.
9421  * For accurate decompilation of rules it's essential
9422  * that we show just the RHS. However in an
9423  * expression that's been through the optimizer, the
9424  * WHEN clause could be almost anything (since the
9425  * equality operator could have been expanded into an
9426  * inline function). If we don't recognize the form
9427  * of the WHEN clause, just punt and display it as-is.
9428  */
9429  if (IsA(w, OpExpr))
9430  {
9431  List *args = ((OpExpr *) w)->args;
9432 
9433  if (list_length(args) == 2 &&
9435  CaseTestExpr))
9436  w = (Node *) lsecond(args);
9437  }
9438  }
9439 
9440  if (!PRETTY_INDENT(context))
9441  appendStringInfoChar(buf, ' ');
9442  appendContextKeyword(context, "WHEN ",
9443  0, 0, 0);
9444  get_rule_expr(w, context, false);
9445  appendStringInfoString(buf, " THEN ");
9446  get_rule_expr((Node *) when->result, context, true);
9447  }
9448  if (!PRETTY_INDENT(context))
9449  appendStringInfoChar(buf, ' ');
9450  appendContextKeyword(context, "ELSE ",
9451  0, 0, 0);
9452  get_rule_expr((Node *) caseexpr->defresult, context, true);
9453  if (!PRETTY_INDENT(context))
9454  appendStringInfoChar(buf, ' ');
9456  -PRETTYINDENT_VAR, 0, 0);
9457  }
9458  break;
9459 
9460  case T_CaseTestExpr:
9461  {
9462  /*
9463  * Normally we should never get here, since for expressions
9464  * that can contain this node type we attempt to avoid
9465  * recursing to it. But in an optimized expression we might
9466  * be unable to avoid that (see comments for CaseExpr). If we
9467  * do see one, print it as CASE_TEST_EXPR.
9468  */
9469  appendStringInfoString(buf, "CASE_TEST_EXPR");
9470  }
9471  break;
9472 
9473  case T_ArrayExpr:
9474  {
9475  ArrayExpr *arrayexpr = (ArrayExpr *) node;
9476 
9477  appendStringInfoString(buf, "ARRAY[");
9478  get_rule_expr((Node *) arrayexpr->elements, context, true);
9479  appendStringInfoChar(buf, ']');
9480 
9481  /*
9482  * If the array isn't empty, we assume its elements are
9483  * coerced to the desired type. If it's empty, though, we
9484  * need an explicit coercion to the array type.
9485  */
9486  if (arrayexpr->elements == NIL)
9487  appendStringInfo(buf, "::%s",
9488  format_type_with_typemod(arrayexpr->array_typeid, -1));
9489  }
9490  break;
9491 
9492  case T_RowExpr:
9493  {
9494  RowExpr *rowexpr = (RowExpr *) node;
9495  TupleDesc tupdesc = NULL;
9496  ListCell *arg;
9497  int i;
9498  char *sep;
9499 
9500  /*
9501  * If it's a named type and not RECORD, we may have to skip
9502  * dropped columns and/or claim there are NULLs for added
9503  * columns.
9504  */
9505  if (rowexpr->row_typeid != RECORDOID)
9506  {
9507  tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9508  Assert(list_length(rowexpr->args) <= tupdesc->natts);
9509  }
9510 
9511  /*
9512  * SQL99 allows "ROW" to be omitted when there is more than
9513  * one column, but for simplicity we always print it.
9514  */
9515  appendStringInfoString(buf, "ROW(");
9516  sep = "";
9517  i = 0;
9518  foreach(arg, rowexpr->args)
9519  {
9520  Node *e = (Node *) lfirst(arg);
9521 
9522  if (tupdesc == NULL ||
9523  !TupleDescAttr(tupdesc, i)->attisdropped)
9524  {
9526  /* Whole-row Vars need special treatment here */
9528  sep = ", ";
9529  }
9530  i++;
9531  }
9532  if (tupdesc != NULL)
9533  {
9534  while (i < tupdesc->natts)
9535  {
9536  if (!TupleDescAttr(tupdesc, i)->attisdropped)
9537  {
9539  appendStringInfoString(buf, "NULL");
9540  sep = ", ";
9541  }
9542  i++;
9543  }
9544 
9545  ReleaseTupleDesc(tupdesc);
9546  }
9547  appendStringInfoChar(buf, ')');
9548  if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9549  appendStringInfo(buf, "::%s",
9550  format_type_with_typemod(rowexpr->row_typeid, -1));
9551  }
9552  break;
9553 
9554  case T_RowCompareExpr:
9555  {
9556  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9557 
9558  /*
9559  * SQL99 allows "ROW" to be omitted when there is more than
9560  * one column, but for simplicity we always print it. Within
9561  * a ROW expression, whole-row Vars need special treatment, so
9562  * use get_rule_list_toplevel.
9563  */
9564  appendStringInfoString(buf, "(ROW(");
9565  get_rule_list_toplevel(rcexpr->largs, context, true);
9566 
9567  /*
9568  * We assume that the name of the first-column operator will
9569  * do for all the rest too. This is definitely open to
9570  * failure, eg if some but not all operators were renamed
9571  * since the construct was parsed, but there seems no way to
9572  * be perfect.
9573  */
9574  appendStringInfo(buf, ") %s ROW(",
9575  generate_operator_name(linitial_oid(rcexpr->opnos),
9576  exprType(linitial(rcexpr->largs)),
9577  exprType(linitial(rcexpr->rargs))));
9578  get_rule_list_toplevel(rcexpr->rargs, context, true);
9579  appendStringInfoString(buf, "))");
9580  }
9581  break;
9582 
9583  case T_CoalesceExpr:
9584  {
9585  CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
9586 
9587  appendStringInfoString(buf, "COALESCE(");
9588  get_rule_expr((Node *) coalesceexpr->args, context, true);
9589  appendStringInfoChar(buf, ')');
9590  }
9591  break;
9592 
9593  case T_MinMaxExpr:
9594  {
9595  MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9596 
9597  switch (minmaxexpr->op)
9598  {
9599  case IS_GREATEST:
9600  appendStringInfoString(buf, "GREATEST(");
9601  break;
9602  case IS_LEAST:
9603  appendStringInfoString(buf, "LEAST(");
9604  break;
9605  }
9606  get_rule_expr((Node *) minmaxexpr->args, context, true);
9607  appendStringInfoChar(buf, ')');
9608  }
9609  break;
9610 
9611  case T_SQLValueFunction:
9612  {
9613  SQLValueFunction *svf = (SQLValueFunction *) node;
9614 
9615  /*
9616  * Note: this code knows that typmod for time, timestamp, and
9617  * timestamptz just prints as integer.
9618  */
9619  switch (svf->op)
9620  {
9621  case SVFOP_CURRENT_DATE:
9622  appendStringInfoString(buf, "CURRENT_DATE");
9623  break;
9624  case SVFOP_CURRENT_TIME:
9625  appendStringInfoString(buf, "CURRENT_TIME");
9626  break;
9627  case SVFOP_CURRENT_TIME_N:
9628  appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
9629  break;
9631  appendStringInfoString(buf, "CURRENT_TIMESTAMP");
9632  break;
9634  appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
9635  svf->typmod);
9636  break;
9637  case SVFOP_LOCALTIME:
9638  appendStringInfoString(buf, "LOCALTIME");
9639  break;
9640  case SVFOP_LOCALTIME_N:
9641  appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
9642  break;
9643  case SVFOP_LOCALTIMESTAMP:
9644  appendStringInfoString(buf, "LOCALTIMESTAMP");
9645  break;
9647  appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
9648  svf->typmod);
9649  break;
9650  case SVFOP_CURRENT_ROLE:
9651  appendStringInfoString(buf, "CURRENT_ROLE");
9652  break;
9653  case SVFOP_CURRENT_USER:
9654  appendStringInfoString(buf, "CURRENT_USER");
9655  break;
9656  case SVFOP_USER:
9657  appendStringInfoString(buf, "USER");
9658  break;
9659  case SVFOP_SESSION_USER:
9660  appendStringInfoString(buf, "SESSION_USER");
9661  break;
9662  case SVFOP_CURRENT_CATALOG:
9663  appendStringInfoString(buf, "CURRENT_CATALOG");
9664  break;
9665  case SVFOP_CURRENT_SCHEMA:
9666  appendStringInfoString(buf, "CURRENT_SCHEMA");
9667  break;
9668  }
9669  }
9670  break;
9671 
9672  case T_XmlExpr:
9673  {
9674  XmlExpr *xexpr = (XmlExpr *) node;
9675  bool needcomma = false;
9676  ListCell *arg;
9677  ListCell *narg;
9678  Const *con;
9679 
9680  switch (xexpr->op)
9681  {
9682  case IS_XMLCONCAT:
9683  appendStringInfoString(buf, "XMLCONCAT(");
9684  break;
9685  case IS_XMLELEMENT:
9686  appendStringInfoString(buf, "XMLELEMENT(");
9687  break;
9688  case IS_XMLFOREST:
9689  appendStringInfoString(buf, "XMLFOREST(");
9690  break;
9691  case IS_XMLPARSE:
9692  appendStringInfoString(buf, "XMLPARSE(");
9693  break;
9694  case IS_XMLPI:
9695  appendStringInfoString(buf, "XMLPI(");
9696  break;
9697  case IS_XMLROOT:
9698  appendStringInfoString(buf, "XMLROOT(");
9699  break;
9700  case IS_XMLSERIALIZE:
9701  appendStringInfoString(buf, "XMLSERIALIZE(");
9702  break;
9703  case IS_DOCUMENT:
9704  break;
9705  }
9706  if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
9707  {
9708  if (xexpr->xmloption == XMLOPTION_DOCUMENT)
9709  appendStringInfoString(buf, "DOCUMENT ");
9710  else
9711  appendStringInfoString(buf, "CONTENT ");
9712  }
9713  if (xexpr->name)
9714  {
9715  appendStringInfo(buf, "NAME %s",
9717  needcomma = true;
9718  }
9719  if (xexpr->named_args)
9720  {
9721  if (xexpr->op != IS_XMLFOREST)
9722  {
9723  if (needcomma)
9724  appendStringInfoString(buf, ", ");
9725  appendStringInfoString(buf, "XMLATTRIBUTES(");
9726  needcomma = false;
9727  }
9728  forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
9729  {
9730  Node *e = (Node *) lfirst(arg);
9731  char *argname = strVal(lfirst(narg));
9732 
9733  if (needcomma)
9734  appendStringInfoString(buf, ", ");
9735  get_rule_expr((Node *) e, context, true);
9736  appendStringInfo(buf, " AS %s",
9738  needcomma = true;
9739  }
9740  if (xexpr->op != IS_XMLFOREST)
9741  appendStringInfoChar(buf, ')');
9742  }
9743  if (xexpr->args)
9744  {
9745  if (needcomma)
9746  appendStringInfoString(buf, ", ");
9747  switch (xexpr->op)
9748  {
9749  case IS_XMLCONCAT:
9750  case IS_XMLELEMENT:
9751  case IS_XMLFOREST:
9752  case IS_XMLPI:
9753  case IS_XMLSERIALIZE:
9754  /* no extra decoration needed */
9755  get_rule_expr((Node *) xexpr->args, context, true);
9756  break;
9757  case IS_XMLPARSE:
9758  Assert(list_length(xexpr->args) == 2);
9759 
9760  get_rule_expr((Node *) linitial(xexpr->args),
9761  context, true);
9762 
9763  con = lsecond_node(Const, xexpr->args);
9764  Assert(!con->constisnull);
9765  if (DatumGetBool(con->constvalue))
9767  " PRESERVE WHITESPACE");
9768  else
9770  " STRIP WHITESPACE");
9771  break;
9772  case IS_XMLROOT:
9773  Assert(list_length(xexpr->args) == 3);
9774 
9775  get_rule_expr((Node *) linitial(xexpr->args),
9776  context, true);
9777 
9778  appendStringInfoString(buf, ", VERSION ");
9779  con = (Const *) lsecond(xexpr->args);
9780  if (IsA(con, Const) &&
9781  con->constisnull)
9782  appendStringInfoString(buf, "NO VALUE");
9783  else
9784  get_rule_expr((Node *) con, context, false);
9785 
9786  con = lthird_node(Const, xexpr->args);
9787  if (con->constisnull)
9788  /* suppress STANDALONE NO VALUE */ ;
9789  else
9790  {
9791  switch (DatumGetInt32(con->constvalue))
9792  {
9793  case XML_STANDALONE_YES:
9795  ", STANDALONE YES");
9796  break;
9797  case XML_STANDALONE_NO:
9799  ", STANDALONE NO");
9800  break;
9803  ", STANDALONE NO VALUE");
9804  break;
9805  default:
9806  break;
9807  }
9808  }
9809  break;
9810  case IS_DOCUMENT:
9811  get_rule_expr_paren((Node *) xexpr->args, context, false, node);
9812  break;
9813  }
9814  }
9815  if (xexpr->op == IS_XMLSERIALIZE)
9816  appendStringInfo(buf, " AS %s",
9817  format_type_with_typemod(xexpr->type,
9818  xexpr->typmod));
9819  if (xexpr->op == IS_DOCUMENT)
9820  appendStringInfoString(buf, " IS DOCUMENT");
9821  else
9822  appendStringInfoChar(buf, ')');
9823  }
9824  break;
9825 
9826  case T_NullTest:
9827  {
9828  NullTest *ntest = (NullTest *) node;
9829 
9830  if (!PRETTY_PAREN(context))
9831  appendStringInfoChar(buf, '(');
9832  get_rule_expr_paren((Node *) ntest->arg, context, true, node);
9833 
9834  /*
9835  * For scalar inputs, we prefer to print as IS [NOT] NULL,
9836  * which is shorter and traditional. If it's a rowtype input
9837  * but we're applying a scalar test, must print IS [NOT]
9838  * DISTINCT FROM NULL to be semantically correct.
9839  */
9840  if (ntest->argisrow ||
9841  !type_is_rowtype(exprType((Node *) ntest->arg)))
9842  {
9843  switch (ntest->nulltesttype)
9844  {
9845  case IS_NULL:
9846  appendStringInfoString(buf, " IS NULL");
9847  break;
9848  case IS_NOT_NULL:
9849  appendStringInfoString(buf, " IS NOT NULL");
9850  break;
9851  default:
9852  elog(ERROR, "unrecognized nulltesttype: %d",
9853  (int) ntest->nulltesttype);
9854  }
9855  }
9856  else
9857  {
9858  switch (ntest->nulltesttype)
9859  {
9860  case IS_NULL:
9861  appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
9862  break;
9863  case IS_NOT_NULL:
9864  appendStringInfoString(buf, " IS DISTINCT FROM NULL");
9865  break;
9866  default:
9867  elog(ERROR, "unrecognized nulltesttype: %d",
9868  (int) ntest->nulltesttype);
9869  }
9870  }
9871  if (!PRETTY_PAREN(context))
9872  appendStringInfoChar(buf, ')');
9873  }
9874  break;
9875 
9876  case T_BooleanTest:
9877  {
9878  BooleanTest *btest = (BooleanTest *) node;
9879 
9880  if (!PRETTY_PAREN(context))
9881  appendStringInfoChar(buf, '(');
9882  get_rule_expr_paren((Node *) btest->arg, context, false, node);
9883  switch (btest->booltesttype)
9884  {
9885  case IS_TRUE:
9886  appendStringInfoString(buf, " IS TRUE");
9887  break;
9888  case IS_NOT_TRUE:
9889  appendStringInfoString(buf, " IS NOT TRUE");
9890  break;
9891  case IS_FALSE:
9892  appendStringInfoString(buf, " IS FALSE");
9893  break;
9894  case IS_NOT_FALSE:
9895  appendStringInfoString(buf, " IS NOT FALSE");
9896  break;
9897  case IS_UNKNOWN:
9898  appendStringInfoString(buf, " IS UNKNOWN");
9899  break;
9900  case IS_NOT_UNKNOWN:
9901  appendStringInfoString(buf, " IS NOT UNKNOWN");
9902  break;
9903  default:
9904  elog(ERROR, "unrecognized booltesttype: %d",
9905  (int) btest->booltesttype);
9906  }
9907  if (!PRETTY_PAREN(context))
9908  appendStringInfoChar(buf, ')');
9909  }
9910  break;
9911 
9912  case T_CoerceToDomain:
9913  {
9914  CoerceToDomain *ctest = (CoerceToDomain *) node;
9915  Node *arg = (Node *) ctest->arg;
9916 
9917  if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
9918  !showimplicit)
9919  {
9920  /* don't show the implicit cast */
9921  get_rule_expr(arg, context, false);
9922  }
9923  else
9924  {
9926  ctest->resulttype,
9927  ctest->resulttypmod,
9928  node);
9929  }
9930  }
9931  break;
9932 
9933  case T_CoerceToDomainValue:
9934  appendStringInfoString(buf, "VALUE");
9935  break;
9936 
9937  case T_SetToDefault:
9938  appendStringInfoString(buf, "DEFAULT");
9939  break;
9940 
9941  case T_CurrentOfExpr:
9942  {
9943  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
9944 
9945  if (cexpr->cursor_name)
9946  appendStringInfo(buf, "CURRENT OF %s",
9947  quote_identifier(cexpr->cursor_name));
9948  else
9949  appendStringInfo(buf, "CURRENT OF $%d",
9950  cexpr->cursor_param);
9951  }
9952  break;
9953 
9954  case T_NextValueExpr:
9955  {
9956  NextValueExpr *nvexpr = (NextValueExpr *) node;
9957 
9958  /*
9959  * This isn't exactly nextval(), but that seems close enough
9960  * for EXPLAIN's purposes.
9961  */
9962  appendStringInfoString(buf, "nextval(");
9964  generate_relation_name(nvexpr->seqid,
9965  NIL));
9966  appendStringInfoChar(buf, ')');
9967  }
9968  break;
9969 
9970  case T_InferenceElem:
9971  {
9972  InferenceElem *iexpr = (InferenceElem *) node;
9973  bool save_varprefix;
9974  bool need_parens;
9975 
9976  /*
9977  * InferenceElem can only refer to target relation, so a
9978  * prefix is not useful, and indeed would cause parse errors.
9979  */
9980  save_varprefix = context->varprefix;
9981  context->varprefix = false;
9982 
9983  /*
9984  * Parenthesize the element unless it's a simple Var or a bare
9985  * function call. Follows pg_get_indexdef_worker().
9986  */
9987  need_parens = !IsA(iexpr->expr, Var);
9988  if (IsA(iexpr->expr, FuncExpr) &&
9989  ((FuncExpr *) iexpr->expr)->funcformat ==
9991  need_parens = false;
9992 
9993  if (need_parens)
9994  appendStringInfoChar(buf, '(');
9995  get_rule_expr((Node *) iexpr->expr,
9996  context, false);
9997  if (need_parens)
9998  appendStringInfoChar(buf, ')');
9999 
10000  context->varprefix = save_varprefix;
10001 
10002  if (iexpr->infercollid)
10003  appendStringInfo(buf, " COLLATE %s",
10005 
10006  /* Add the operator class name, if not default */
10007  if (iexpr->inferopclass)
10008  {
10009  Oid inferopclass = iexpr->inferopclass;
10010  Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
10011 
10012  get_opclass_name(inferopclass, inferopcinputtype, buf);
10013  }
10014  }
10015  break;
10016 
10017  case T_PartitionBoundSpec:
10018  {
10019  PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
10020  ListCell *cell;
10021  char *sep;
10022 
10023  if (spec->is_default)
10024  {
10025  appendStringInfoString(buf, "DEFAULT");
10026  break;
10027  }
10028 
10029  switch (spec->strategy)
10030  {
10032  Assert(spec->modulus > 0 && spec->remainder >= 0);
10033  Assert(spec->modulus > spec->remainder);
10034 
10035  appendStringInfoString(buf, "FOR VALUES");
10036  appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
10037  spec->modulus, spec->remainder);
10038  break;
10039 
10041  Assert(spec->listdatums != NIL);
10042 
10043  appendStringInfoString(buf, "FOR VALUES IN (");
10044  sep = "";
10045  foreach(cell, spec->listdatums)
10046  {
10047  Const *val = lfirst_node(Const, cell);
10048 
10050  get_const_expr(val, context, -1);
10051  sep = ", ";
10052  }
10053 
10054  appendStringInfoChar(buf, ')');
10055  break;
10056 
10058  Assert(spec->lowerdatums != NIL &&
10059  spec->upperdatums != NIL &&
10060  list_length(spec->lowerdatums) ==
10061  list_length(spec->upperdatums));
10062 
10063  appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
10066  break;
10067 
10068  default:
10069  elog(ERROR, "unrecognized partition strategy: %d",
10070  (int) spec->strategy);
10071  break;
10072  }
10073  }
10074  break;
10075 
10076  case T_JsonValueExpr:
10077  {
10078  JsonValueExpr *jve = (JsonValueExpr *) node;
10079 
10080  get_rule_expr((Node *) jve->raw_expr, context, false);
10081  get_json_format(jve->format, context->buf);
10082  }
10083  break;
10084 
10085  case T_JsonConstructorExpr:
10087  break;
10088 
10089  case T_JsonIsPredicate:
10090  {
10091  JsonIsPredicate *pred = (JsonIsPredicate *) node;
10092 
10093  if (!PRETTY_PAREN(context))
10094  appendStringInfoChar(context->buf, '(');
10095 
10096  get_rule_expr_paren(pred->expr, context, true, node);
10097 
10098  appendStringInfoString(context->buf, " IS JSON");
10099 
10100  /* TODO: handle FORMAT clause */
10101 
10102  switch (pred->item_type)
10103  {
10104  case JS_TYPE_SCALAR:
10105  appendStringInfoString(context->buf, " SCALAR");
10106  break;
10107  case JS_TYPE_ARRAY:
10108  appendStringInfoString(context->buf, " ARRAY");
10109  break;
10110  case JS_TYPE_OBJECT:
10111  appendStringInfoString(context->buf, " OBJECT");
10112  break;
10113  default:
10114  break;
10115  }
10116 
10117  if (pred->unique_keys)
10118  appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
10119 
10120  if (!PRETTY_PAREN(context))
10121  appendStringInfoChar(context->buf, ')');
10122  }
10123  break;
10124 
10125  case T_JsonExpr:
10126  {
10127  JsonExpr *jexpr = (JsonExpr *) node;
10128 
10129  switch (jexpr->op)
10130  {
10131  case JSON_EXISTS_OP:
10132  appendStringInfoString(buf, "JSON_EXISTS(");
10133  break;
10134  case JSON_QUERY_OP:
10135  appendStringInfoString(buf, "JSON_QUERY(");
10136  break;
10137  case JSON_VALUE_OP:
10138  appendStringInfoString(buf, "JSON_VALUE(");
10139  break;
10140  default:
10141  elog(ERROR, "unrecognized JsonExpr op: %d",
10142  (int) jexpr->op);
10143  }
10144 
10145  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
10146 
10147  appendStringInfoString(buf, ", ");
10148 
10149  get_json_path_spec(jexpr->path_spec, context, showimplicit);
10150 
10151  if (jexpr->passing_values)
10152  {
10153  ListCell *lc1,
10154  *lc2;
10155  bool needcomma = false;
10156 
10157  appendStringInfoString(buf, " PASSING ");
10158 
10159  forboth(lc1, jexpr->passing_names,
10160  lc2, jexpr->passing_values)
10161  {
10162  if (needcomma)
10163  appendStringInfoString(buf, ", ");
10164  needcomma = true;
10165 
10166  get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
10167  appendStringInfo(buf, " AS %s",
10168  ((String *) lfirst_node(String, lc1))->sval);
10169  }
10170  }
10171 
10172  if (jexpr->op != JSON_EXISTS_OP ||
10173  jexpr->returning->typid != BOOLOID)
10174  get_json_returning(jexpr->returning, context->buf,
10175  jexpr->op == JSON_QUERY_OP);
10176 
10178  jexpr->op != JSON_EXISTS_OP ?
10181 
10182  appendStringInfoChar(buf, ')');
10183  }
10184  break;
10185 
10186  case T_List:
10187  {
10188  char *sep;
10189  ListCell *l;
10190 
10191  sep = "";
10192  foreach(l, (List *) node)
10193  {
10195  get_rule_expr((Node *) lfirst(l), context, showimplicit);
10196  sep = ", ";
10197  }
10198  }
10199  break;
10200 
10201  case T_TableFunc:
10202  get_tablefunc((TableFunc *) node, context, showimplicit);
10203  break;
10204 
10205  default:
10206  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
10207  break;
10208  }
10209 }
10210 
10211 /*
10212  * get_rule_expr_toplevel - Parse back a toplevel expression
10213  *
10214  * Same as get_rule_expr(), except that if the expr is just a Var, we pass
10215  * istoplevel = true not false to get_variable(). This causes whole-row Vars
10216  * to get printed with decoration that will prevent expansion of "*".
10217  * We need to use this in contexts such as ROW() and VALUES(), where the
10218  * parser would expand "foo.*" appearing at top level. (In principle we'd
10219  * use this in get_target_list() too, but that has additional worries about
10220  * whether to print AS, so it needs to invoke get_variable() directly anyway.)
10221  */
10222 static void
10224  bool showimplicit)
10225 {
10226  if (node && IsA(node, Var))
10227  (void) get_variable((Var *) node, 0, true, context);
10228  else
10229  get_rule_expr(node, context, showimplicit);
10230 }
10231 
10232 /*
10233  * get_rule_list_toplevel - Parse back a list of toplevel expressions
10234  *
10235  * Apply get_rule_expr_toplevel() to each element of a List.
10236  *
10237  * This adds commas between the expressions, but caller is responsible
10238  * for printing surrounding decoration.
10239  */
10240 static void
10242  bool showimplicit)
10243 {
10244  const char *sep;
10245  ListCell *lc;
10246 
10247  sep = "";
10248  foreach(lc, lst)
10249  {
10250  Node *e = (Node *) lfirst(lc);
10251 
10252  appendStringInfoString(context->buf, sep);
10253  get_rule_expr_toplevel(e, context, showimplicit);
10254  sep = ", ";
10255  }
10256 }
10257 
10258 /*
10259  * get_rule_expr_funccall - Parse back a function-call expression
10260  *
10261  * Same as get_rule_expr(), except that we guarantee that the output will
10262  * look like a function call, or like one of the things the grammar treats as
10263  * equivalent to a function call (see the func_expr_windowless production).
10264  * This is needed in places where the grammar uses func_expr_windowless and
10265  * you can't substitute a parenthesized a_expr. If what we have isn't going
10266  * to look like a function call, wrap it in a dummy CAST() expression, which
10267  * will satisfy the grammar --- and, indeed, is likely what the user wrote to
10268  * produce such a thing.
10269  */
10270 static void
10272  bool showimplicit)
10273 {
10274  if (looks_like_function(node))
10275  get_rule_expr(node, context, showimplicit);
10276  else
10277  {
10278  StringInfo buf = context->buf;
10279 
10280  appendStringInfoString(buf, "CAST(");
10281  /* no point in showing any top-level implicit cast */
10282  get_rule_expr(node, context, false);
10283  appendStringInfo(buf, " AS %s)",
10285  exprTypmod(node)));
10286  }
10287 }
10288 
10289 /*
10290  * Helper function to identify node types that satisfy func_expr_windowless.
10291  * If in doubt, "false" is always a safe answer.
10292  */
10293 static bool
10295 {
10296  if (node == NULL)
10297  return false; /* probably shouldn't happen */
10298  switch (nodeTag(node))
10299  {
10300  case T_FuncExpr:
10301  /* OK, unless it's going to deparse as a cast */
10302  return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10303  ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10304  case T_NullIfExpr:
10305  case T_CoalesceExpr:
10306  case T_MinMaxExpr:
10307  case T_SQLValueFunction:
10308  case T_XmlExpr:
10309  case T_JsonExpr:
10310  /* these are all accepted by func_expr_common_subexpr */
10311  return true;
10312  default:
10313  break;
10314  }
10315  return false;
10316 }
10317 
10318 
10319 /*
10320  * get_oper_expr - Parse back an OpExpr node
10321  */
10322 static void
10324 {
10325  StringInfo buf = context->buf;
10326  Oid opno = expr->opno;
10327  List *args = expr->args;
10328 
10329  if (!PRETTY_PAREN(context))
10330  appendStringInfoChar(buf, '(');
10331  if (list_length(args) == 2)
10332  {
10333  /* binary operator */
10334  Node *arg1 = (Node *) linitial(args);
10335  Node *arg2 = (Node *) lsecond(args);
10336 
10337  get_rule_expr_paren(arg1, context, true, (Node *) expr);
10338  appendStringInfo(buf, " %s ",
10340  exprType(arg1),
10341  exprType(arg2)));
10342  get_rule_expr_paren(arg2, context, true, (Node *) expr);
10343  }
10344  else
10345  {
10346  /* prefix operator */
10347  Node *arg = (Node *) linitial(args);
10348 
10349  appendStringInfo(buf, "%s ",
10351  InvalidOid,
10352  exprType(arg)));
10353  get_rule_expr_paren(arg, context, true, (Node *) expr);
10354  }
10355  if (!PRETTY_PAREN(context))
10356  appendStringInfoChar(buf, ')');
10357 }
10358 
10359 /*
10360  * get_func_expr - Parse back a FuncExpr node
10361  */
10362 static void
10364  bool showimplicit)
10365 {
10366  StringInfo buf = context->buf;
10367  Oid funcoid = expr->funcid;
10368  Oid argtypes[FUNC_MAX_ARGS];
10369  int nargs;
10370  List *argnames;
10371  bool use_variadic;
10372  ListCell *l;
10373 
10374  /*
10375  * If the function call came from an implicit coercion, then just show the
10376  * first argument --- unless caller wants to see implicit coercions.
10377  */
10378  if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10379  {
10381  false, (Node *) expr);
10382  return;
10383  }
10384 
10385  /*
10386  * If the function call came from a cast, then show the first argument
10387  * plus an explicit cast operation.
10388  */
10389  if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10390  expr->funcformat == COERCE_IMPLICIT_CAST)
10391  {
10392  Node *arg = linitial(expr->args);
10393  Oid rettype = expr->funcresulttype;
10394  int32 coercedTypmod;
10395 
10396  /* Get the typmod if this is a length-coercion function */
10397  (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10398 
10400  rettype, coercedTypmod,
10401  (Node *) expr);
10402 
10403  return;
10404  }
10405 
10406  /*
10407  * If the function was called using one of the SQL spec's random special
10408  * syntaxes, try to reproduce that. If we don't recognize the function,
10409  * fall through.
10410  */
10411  if (expr->funcformat == COERCE_SQL_SYNTAX)
10412  {
10413  if (get_func_sql_syntax(expr, context))
10414  return;
10415  }
10416 
10417  /*
10418  * Normal function: display as proname(args). First we need to extract
10419  * the argument datatypes.
10420  */
10421  if (list_length(expr->args) > FUNC_MAX_ARGS)
10422  ereport(ERROR,
10423  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10424  errmsg("too many arguments")));
10425  nargs = 0;
10426  argnames = NIL;
10427  foreach(l, expr->args)
10428  {
10429  Node *arg = (Node *) lfirst(l);
10430 
10431  if (IsA(arg, NamedArgExpr))
10432  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10433  argtypes[nargs] = exprType(arg);
10434  nargs++;
10435  }
10436 
10437  appendStringInfo(buf, "%s(",
10438  generate_function_name(funcoid, nargs,
10439  argnames, argtypes,
10440  expr->funcvariadic,
10441  &use_variadic,
10442  context->special_exprkind));
10443  nargs = 0;
10444  foreach(l, expr->args)
10445  {
10446  if (nargs++ > 0)
10447  appendStringInfoString(buf, ", ");
10448  if (use_variadic && lnext(expr->args, l) == NULL)
10449  appendStringInfoString(buf, "VARIADIC ");
10450  get_rule_expr((Node *) lfirst(l), context, true);
10451  }
10452  appendStringInfoChar(buf, ')');
10453 }
10454 
10455 /*
10456  * get_agg_expr - Parse back an Aggref node
10457  */
10458 static void
10460  Aggref *original_aggref)
10461 {
10462  get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10463  false);
10464 }
10465 
10466 /*
10467  * get_agg_expr_helper - subroutine for get_agg_expr and
10468  * get_json_agg_constructor
10469  */
10470 static void
10472  Aggref *original_aggref, const char *funcname,
10473  const char *options, bool is_json_objectagg)
10474 {
10475  StringInfo buf = context->buf;
10476  Oid argtypes[FUNC_MAX_ARGS];
10477  int nargs;
10478  bool use_variadic = false;
10479 
10480  /*
10481  * For a combining aggregate, we look up and deparse the corresponding
10482  * partial aggregate instead. This is necessary because our input
10483  * argument list has been replaced; the new argument list always has just
10484  * one element, which will point to a partial Aggref that supplies us with
10485  * transition states to combine.
10486  */
10487  if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10488  {
10489  TargetEntry *tle;
10490 
10491  Assert(list_length(aggref->args) == 1);
10492  tle = linitial_node(TargetEntry, aggref->args);
10494  get_agg_combine_expr, original_aggref);
10495  return;
10496  }
10497 
10498  /*
10499  * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10500  * to avoid printing this when recursing from the code just above.
10501  */
10502  if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10503  appendStringInfoString(buf, "PARTIAL ");
10504 
10505  /* Extract the argument types as seen by the parser */
10506  nargs = get_aggregate_argtypes(aggref, argtypes);
10507 
10508  if (!funcname)
10509  funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10510  argtypes, aggref->aggvariadic,
10511  &use_variadic,
10512  context->special_exprkind);
10513 
10514  /* Print the aggregate name, schema-qualified if needed */
10515  appendStringInfo(buf, "%s(%s", funcname,
10516  (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10517 
10518  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10519  {
10520  /*
10521  * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10522  * worry about inserting VARIADIC. So we can just dump the direct
10523  * args as-is.
10524  */
10525  Assert(!aggref->aggvariadic);
10526  get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10527  Assert(aggref->aggorder != NIL);
10528  appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10529  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10530  }
10531  else
10532  {
10533  /* aggstar can be set only in zero-argument aggregates */
10534  if (aggref->aggstar)
10535  appendStringInfoChar(buf, '*');
10536  else
10537  {
10538  ListCell *l;
10539  int i;
10540 
10541  i = 0;
10542  foreach(l, aggref->args)
10543  {
10544  TargetEntry *tle = (TargetEntry *) lfirst(l);
10545  Node *arg = (Node *) tle->expr;
10546 
10547  Assert(!IsA(arg, NamedArgExpr));
10548  if (tle->resjunk)
10549  continue;
10550  if (i++ > 0)
10551  {
10552  if (is_json_objectagg)
10553  {
10554  /*
10555  * the ABSENT ON NULL and WITH UNIQUE args are printed
10556  * separately, so ignore them here
10557  */
10558  if (i > 2)
10559  break;
10560 
10561  appendStringInfoString(buf, " : ");
10562  }
10563  else
10564  appendStringInfoString(buf, ", ");
10565  }
10566  if (use_variadic && i == nargs)
10567  appendStringInfoString(buf, "VARIADIC ");
10568  get_rule_expr(arg, context, true);
10569  }
10570  }
10571 
10572  if (aggref->aggorder != NIL)
10573  {
10574  appendStringInfoString(buf, " ORDER BY ");
10575  get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10576  }
10577  }
10578 
10579  if (options)
10581 
10582  if (aggref->aggfilter != NULL)
10583  {
10584  appendStringInfoString(buf, ") FILTER (WHERE ");
10585  get_rule_expr((Node *) aggref->aggfilter, context, false);
10586  }
10587 
10588  appendStringInfoChar(buf, ')');
10589 }
10590 
10591 /*
10592  * This is a helper function for get_agg_expr(). It's used when we deparse
10593  * a combining Aggref; resolve_special_varno locates the corresponding partial
10594  * Aggref and then calls this.
10595  */
10596 static void
10597 get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
10598 {
10599  Aggref *aggref;
10600  Aggref *original_aggref = callback_arg;
10601 
10602  if (!IsA(node, Aggref))
10603  elog(ERROR, "combining Aggref does not point to an Aggref");
10604 
10605  aggref = (Aggref *) node;
10606  get_agg_expr(aggref, context, original_aggref);
10607 }
10608 
10609 /*
10610  * get_windowfunc_expr - Parse back a WindowFunc node
10611  */
10612 static void
10614 {
10615  get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
10616 }
10617 
10618 
10619 /*
10620  * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
10621  * get_json_agg_constructor
10622  */
10623 static void
10625  const char *funcname, const char *options,
10626  bool is_json_objectagg)
10627 {
10628  StringInfo buf = context->buf;
10629  Oid argtypes[FUNC_MAX_ARGS];
10630  int nargs;
10631  List *argnames;
10632  ListCell *l;
10633 
10634  if (list_length(wfunc->args) > FUNC_MAX_ARGS)
10635  ereport(ERROR,
10636  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10637  errmsg("too many arguments")));
10638  nargs = 0;
10639  argnames = NIL;
10640  foreach(l, wfunc->args)
10641  {
10642  Node *arg = (Node *) lfirst(l);
10643 
10644  if (IsA(arg, NamedArgExpr))
10645  argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10646  argtypes[nargs] = exprType(arg);
10647  nargs++;
10648  }
10649 
10650  if (!funcname)
10651  funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
10652  argtypes, false, NULL,
10653  context->special_exprkind);
10654 
10655  appendStringInfo(buf, "%s(", funcname);
10656 
10657  /* winstar can be set only in zero-argument aggregates */
10658  if (wfunc->winstar)
10659  appendStringInfoChar(buf, '*');
10660  else
10661  {
10662  if (is_json_objectagg)
10663  {
10664  get_rule_expr((Node *) linitial(wfunc->args), context, false);
10665  appendStringInfoString(buf, " : ");
10666  get_rule_expr((Node *) lsecond(wfunc->args), context, false);
10667  }
10668  else
10669  get_rule_expr((Node *) wfunc->args, context, true);
10670  }
10671 
10672  if (options)
10674 
10675  if (wfunc->aggfilter != NULL)
10676  {
10677  appendStringInfoString(buf, ") FILTER (WHERE ");
10678  get_rule_expr((Node *) wfunc->aggfilter, context, false);
10679  }
10680 
10681  appendStringInfoString(buf, ") OVER ");
10682 
10683  foreach(l, context->windowClause)
10684  {
10685  WindowClause *wc = (WindowClause *) lfirst(l);
10686 
10687  if (wc->winref == wfunc->winref)
10688  {
10689  if (wc->name)
10691  else
10692  get_rule_windowspec(wc, context->windowTList, context);
10693  break;
10694  }
10695  }
10696  if (l == NULL)
10697  {
10698  if (context->windowClause)
10699  elog(ERROR, "could not find window clause for winref %u",
10700  wfunc->winref);
10701 
10702  /*
10703  * In EXPLAIN, we don't have window context information available, so
10704  * we have to settle for this:
10705  */
10706  appendStringInfoString(buf, "(?)");
10707  }
10708 }
10709 
10710 /*
10711  * get_func_sql_syntax - Parse back a SQL-syntax function call
10712  *
10713  * Returns true if we successfully deparsed, false if we did not
10714  * recognize the function.
10715  */
10716 static bool
10718 {
10719  StringInfo buf = context->buf;
10720  Oid funcoid = expr->funcid;
10721 
10722  switch (funcoid)
10723  {
10724  case F_TIMEZONE_INTERVAL_TIMESTAMP:
10725  case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10726  case F_TIMEZONE_INTERVAL_TIMETZ:
10727  case F_TIMEZONE_TEXT_TIMESTAMP:
10728  case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10729  case F_TIMEZONE_TEXT_TIMETZ:
10730  /* AT TIME ZONE ... note reversed argument order */
10731  appendStringInfoChar(buf, '(');
10732  get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
10733  (Node *) expr);
10734  appendStringInfoString(buf, " AT TIME ZONE ");
10735  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10736  (Node *) expr);
10737  appendStringInfoChar(buf, ')');
10738  return true;
10739 
10740  case F_TIMEZONE_TIMESTAMP:
10741  case F_TIMEZONE_TIMESTAMPTZ:
10742  case F_TIMEZONE_TIMETZ:
10743  /* AT LOCAL */
10744  appendStringInfoChar(buf, '(');
10745  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10746  (Node *) expr);
10747  appendStringInfoString(buf, " AT LOCAL)");
10748  return true;
10749 
10750  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10751  case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10752  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10753  case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10754  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
10755  case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10756  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10757  case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10758  case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10759  case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10760  case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10761  case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10762  case F_OVERLAPS_TIME_TIME_TIME_TIME:
10763  /* (x1, x2) OVERLAPS (y1, y2) */
10764  appendStringInfoString(buf, "((");
10765  get_rule_expr((Node *) linitial(expr->args), context, false);
10766  appendStringInfoString(buf, ", ");
10767  get_rule_expr((Node *) lsecond(expr->args), context, false);
10768  appendStringInfoString(buf, ") OVERLAPS (");
10769  get_rule_expr((Node *) lthird(expr->args), context, false);
10770  appendStringInfoString(buf, ", ");
10771  get_rule_expr((Node *) lfourth(expr->args), context, false);
10772  appendStringInfoString(buf, "))");
10773  return true;
10774 
10775  case F_EXTRACT_TEXT_DATE:
10776  case F_EXTRACT_TEXT_TIME:
10777  case F_EXTRACT_TEXT_TIMETZ:
10778  case F_EXTRACT_TEXT_TIMESTAMP:
10779  case F_EXTRACT_TEXT_TIMESTAMPTZ:
10780  case F_EXTRACT_TEXT_INTERVAL:
10781  /* EXTRACT (x FROM y) */
10782  appendStringInfoString(buf, "EXTRACT(");
10783  {
10784  Const *con = (Const *) linitial(expr->args);
10785 
10786  Assert(IsA(con, Const) &&
10787  con->consttype == TEXTOID &&
10788  !con->constisnull);
10789  appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
10790  }
10791  appendStringInfoString(buf, " FROM ");
10792  get_rule_expr((Node *) lsecond(expr->args), context, false);
10793  appendStringInfoChar(buf, ')');
10794  return true;
10795 
10796  case F_IS_NORMALIZED:
10797  /* IS xxx NORMALIZED */
10798  appendStringInfoChar(buf, '(');
10799  get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10800  (Node *) expr);
10801  appendStringInfoString(buf, " IS");
10802  if (list_length(expr->args) == 2)
10803  {
10804  Const *con = (Const *) lsecond(expr->args);
10805 
10806  Assert(IsA(con, Const) &&
10807  con->consttype == TEXTOID &&
10808  !con->constisnull);
10809  appendStringInfo(buf, " %s",
10810  TextDatumGetCString(con->constvalue));
10811  }
10812  appendStringInfoString(buf, " NORMALIZED)");
10813  return true;
10814 
10815  case F_PG_COLLATION_FOR:
10816  /* COLLATION FOR */
10817  appendStringInfoString(buf, "COLLATION FOR (");
10818  get_rule_expr((Node *) linitial(expr->args), context, false);
10819  appendStringInfoChar(buf, ')');
10820  return true;
10821 
10822  case F_NORMALIZE:
10823  /* NORMALIZE() */
10824  appendStringInfoString(buf, "NORMALIZE(");
10825  get_rule_expr((Node *) linitial(expr->args), context, false);
10826  if (list_length(expr->args) == 2)
10827  {
10828  Const *con = (Const *) lsecond(expr->args);
10829 
10830  Assert(IsA(con, Const) &&
10831  con->consttype == TEXTOID &&
10832  !con->constisnull);
10833  appendStringInfo(buf, ", %s",
10834  TextDatumGetCString(con->constvalue));
10835  }
10836  appendStringInfoChar(buf, ')');
10837  return true;
10838 
10839  case F_OVERLAY_BIT_BIT_INT4:
10840  case F_OVERLAY_BIT_BIT_INT4_INT4:
10841  case F_OVERLAY_BYTEA_BYTEA_INT4:
10842  case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10843  case F_OVERLAY_TEXT_TEXT_INT4:
10844  case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10845  /* OVERLAY() */
10846  appendStringInfoString(buf, "OVERLAY(");
10847  get_rule_expr((Node *) linitial(expr->args), context, false);
10848  appendStringInfoString(buf, " PLACING ");
10849  get_rule_expr((Node *) lsecond(expr->args), context, false);
10850  appendStringInfoString(buf, " FROM ");
10851  get_rule_expr((Node *) lthird(expr->args), context, false);
10852  if (list_length(expr->args) == 4)
10853  {
10854  appendStringInfoString(buf, " FOR ");
10855  get_rule_expr((Node *) lfourth(expr->args), context, false);
10856  }
10857  appendStringInfoChar(buf, ')');
10858  return true;
10859 
10860  case F_POSITION_BIT_BIT:
10861  case F_POSITION_BYTEA_BYTEA:
10862  case F_POSITION_TEXT_TEXT:
10863  /* POSITION() ... extra parens since args are b_expr not a_expr */
10864  appendStringInfoString(buf, "POSITION((");
10865  get_rule_expr((Node *) lsecond(expr->args), context, false);
10866  appendStringInfoString(buf, ") IN (");
10867  get_rule_expr((Node *) linitial(expr->args), context, false);
10868  appendStringInfoString(buf, "))");
10869  return true;
10870 
10871  case F_SUBSTRING_BIT_INT4:
10872  case F_SUBSTRING_BIT_INT4_INT4:
10873  case F_SUBSTRING_BYTEA_INT4:
10874  case F_SUBSTRING_BYTEA_INT4_INT4:
10875  case F_SUBSTRING_TEXT_INT4:
10876  case F_SUBSTRING_TEXT_INT4_INT4:
10877  /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10878  appendStringInfoString(buf, "SUBSTRING(");
10879  get_rule_expr((Node *) linitial(expr->args), context, false);
10880  appendStringInfoString(buf, " FROM ");
10881  get_rule_expr((Node *) lsecond(expr->args), context, false);
10882  if (list_length(expr->args) == 3)
10883  {
10884  appendStringInfoString(buf, " FOR ");
10885  get_rule_expr((Node *) lthird(expr->args), context, false);
10886  }
10887  appendStringInfoChar(buf, ')');
10888  return true;
10889 
10890  case F_SUBSTRING_TEXT_TEXT_TEXT:
10891  /* SUBSTRING SIMILAR/ESCAPE */
10892  appendStringInfoString(buf, "SUBSTRING(");
10893  get_rule_expr((Node *) linitial(expr->args), context, false);
10894  appendStringInfoString(buf, " SIMILAR ");
10895  get_rule_expr((Node *) lsecond(expr->args), context, false);
10896  appendStringInfoString(buf, " ESCAPE ");
10897  get_rule_expr((Node *) lthird(expr->args), context, false);
10898  appendStringInfoChar(buf, ')');
10899  return true;
10900 
10901  case F_BTRIM_BYTEA_BYTEA:
10902  case F_BTRIM_TEXT:
10903  case F_BTRIM_TEXT_TEXT:
10904  /* TRIM() */
10905  appendStringInfoString(buf, "TRIM(BOTH");
10906  if (list_length(expr->args) == 2)
10907  {
10908  appendStringInfoChar(buf, ' ');
10909  get_rule_expr((Node *) lsecond(expr->args), context, false);
10910  }
10911  appendStringInfoString(buf, " FROM ");
10912  get_rule_expr((Node *) linitial(expr->args), context, false);
10913  appendStringInfoChar(buf, ')');
10914  return true;
10915 
10916  case F_LTRIM_BYTEA_BYTEA:
10917  case F_LTRIM_TEXT:
10918  case F_LTRIM_TEXT_TEXT:
10919  /* TRIM() */
10920  appendStringInfoString(buf, "TRIM(LEADING");
10921  if (list_length(expr->args) == 2)
10922  {
10923  appendStringInfoChar(buf, ' ');
10924  get_rule_expr((Node *) lsecond(expr->args), context, false);
10925  }
10926  appendStringInfoString(buf, " FROM ");
10927  get_rule_expr((Node *) linitial(expr->args), context, false);
10928  appendStringInfoChar(buf, ')');
10929  return true;
10930 
10931  case F_RTRIM_BYTEA_BYTEA:
10932  case F_RTRIM_TEXT:
10933  case F_RTRIM_TEXT_TEXT:
10934  /* TRIM() */
10935  appendStringInfoString(buf, "TRIM(TRAILING");
10936  if (list_length(expr->args) == 2)
10937  {
10938  appendStringInfoChar(buf, ' ');
10939  get_rule_expr((Node *) lsecond(expr->args), context, false);
10940  }
10941  appendStringInfoString(buf, " FROM ");
10942  get_rule_expr((Node *) linitial(expr->args), context, false);
10943  appendStringInfoChar(buf, ')');
10944  return true;
10945 
10946  case F_SYSTEM_USER:
10947  appendStringInfoString(buf, "SYSTEM_USER");
10948  return true;
10949 
10950  case F_XMLEXISTS:
10951  /* XMLEXISTS ... extra parens because args are c_expr */
10952  appendStringInfoString(buf, "XMLEXISTS((");
10953  get_rule_expr((Node *) linitial(expr->args), context, false);
10954  appendStringInfoString(buf, ") PASSING (");
10955  get_rule_expr((Node *) lsecond(expr->args), context, false);
10956  appendStringInfoString(buf, "))");
10957  return true;
10958  }
10959  return false;
10960 }
10961 
10962 /* ----------
10963  * get_coercion_expr
10964  *
10965  * Make a string representation of a value coerced to a specific type
10966  * ----------
10967  */
10968 static void
10970  Oid resulttype, int32 resulttypmod,
10971  Node *parentNode)
10972 {
10973  StringInfo buf = context->buf;
10974 
10975  /*
10976  * Since parse_coerce.c doesn't immediately collapse application of
10977  * length-coercion functions to constants, what we'll typically see in
10978  * such cases is a Const with typmod -1 and a length-coercion function
10979  * right above it. Avoid generating redundant output. However, beware of
10980  * suppressing casts when the user actually wrote something like
10981  * 'foo'::text::char(3).
10982  *
10983  * Note: it might seem that we are missing the possibility of needing to
10984  * print a COLLATE clause for such a Const. However, a Const could only
10985  * have nondefault collation in a post-constant-folding tree, in which the
10986  * length coercion would have been folded too. See also the special
10987  * handling of CollateExpr in coerce_to_target_type(): any collation
10988  * marking will be above the coercion node, not below it.
10989  */
10990  if (arg && IsA(arg, Const) &&
10991  ((Const *) arg)->consttype == resulttype &&
10992  ((Const *) arg)->consttypmod == -1)
10993  {
10994  /* Show the constant without normal ::typename decoration */
10995  get_const_expr((Const *) arg, context, -1);
10996  }
10997  else
10998  {
10999  if (!PRETTY_PAREN(context))
11000  appendStringInfoChar(buf, '(');
11001  get_rule_expr_paren(arg, context, false, parentNode);
11002  if (!PRETTY_PAREN(context))
11003  appendStringInfoChar(buf, ')');
11004  }
11005 
11006  /*
11007  * Never emit resulttype(arg) functional notation. A pg_proc entry could
11008  * take precedence, and a resulttype in pg_temp would require schema
11009  * qualification that format_type_with_typemod() would usually omit. We've
11010  * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11011  * would work fine.
11012  */
11013  appendStringInfo(buf, "::%s",
11014  format_type_with_typemod(resulttype, resulttypmod));
11015 }
11016 
11017 /* ----------
11018  * get_const_expr
11019  *
11020  * Make a string representation of a Const
11021  *
11022  * showtype can be -1 to never show "::typename" decoration, or +1 to always
11023  * show it, or 0 to show it only if the constant wouldn't be assumed to be
11024  * the right type by default.
11025  *
11026  * If the Const's collation isn't default for its type, show that too.
11027  * We mustn't do this when showtype is -1 (since that means the caller will
11028  * print "::typename", and we can't put a COLLATE clause in between). It's
11029  * caller's responsibility that collation isn't missed in such cases.
11030  * ----------
11031  */
11032 static void
11033 get_const_expr(Const *constval, deparse_context *context, int showtype)
11034 {
11035  StringInfo buf = context->buf;
11036  Oid typoutput;
11037  bool typIsVarlena;
11038  char *extval;
11039  bool needlabel = false;
11040 
11041  if (constval->constisnull)
11042  {
11043  /*
11044  * Always label the type of a NULL constant to prevent misdecisions
11045  * about type when reparsing.
11046  */
11047  appendStringInfoString(buf, "NULL");
11048  if (showtype >= 0)
11049  {
11050  appendStringInfo(buf, "::%s",
11052  constval->consttypmod));
11053  get_const_collation(constval, context);
11054  }
11055  return;
11056  }
11057 
11058  getTypeOutputInfo(constval->consttype,
11059  &typoutput, &typIsVarlena);
11060 
11061  extval = OidOutputFunctionCall(typoutput, constval->constvalue);
11062 
11063  switch (constval->consttype)
11064  {
11065  case INT4OID:
11066 
11067  /*
11068  * INT4 can be printed without any decoration, unless it is
11069  * negative; in that case print it as '-nnn'::integer to ensure
11070  * that the output will re-parse as a constant, not as a constant
11071  * plus operator. In most cases we could get away with printing
11072  * (-nnn) instead, because of the way that gram.y handles negative
11073  * literals; but that doesn't work for INT_MIN, and it doesn't
11074  * seem that much prettier anyway.
11075  */
11076  if (extval[0] != '-')
11077  appendStringInfoString(buf, extval);
11078  else
11079  {
11080  appendStringInfo(buf, "'%s'", extval);
11081  needlabel = true; /* we must attach a cast */
11082  }
11083  break;
11084 
11085  case NUMERICOID:
11086 
11087  /*
11088  * NUMERIC can be printed without quotes if it looks like a float
11089  * constant (not an integer, and not Infinity or NaN) and doesn't
11090  * have a leading sign (for the same reason as for INT4).
11091  */
11092  if (isdigit((unsigned char) extval[0]) &&
11093  strcspn(extval, "eE.") != strlen(extval))
11094  {
11095  appendStringInfoString(buf, extval);
11096  }
11097  else
11098  {
11099  appendStringInfo(buf, "'%s'", extval);
11100  needlabel = true; /* we must attach a cast */
11101  }
11102  break;
11103 
11104  case BOOLOID:
11105  if (strcmp(extval, "t") == 0)
11106  appendStringInfoString(buf, "true");
11107  else
11108  appendStringInfoString(buf, "false");
11109  break;
11110 
11111  default:
11112  simple_quote_literal(buf, extval);
11113  break;
11114  }
11115 
11116  pfree(extval);
11117 
11118  if (showtype < 0)
11119  return;
11120 
11121  /*
11122  * For showtype == 0, append ::typename unless the constant will be
11123  * implicitly typed as the right type when it is read in.
11124  *
11125  * XXX this code has to be kept in sync with the behavior of the parser,
11126  * especially make_const.
11127  */
11128  switch (constval->consttype)
11129  {
11130  case BOOLOID:
11131  case UNKNOWNOID:
11132  /* These types can be left unlabeled */
11133  needlabel = false;
11134  break;
11135  case INT4OID:
11136  /* We determined above whether a label is needed */
11137  break;
11138  case NUMERICOID:
11139 
11140  /*
11141  * Float-looking constants will be typed as numeric, which we
11142  * checked above; but if there's a nondefault typmod we need to
11143  * show it.
11144  */
11145  needlabel |= (constval->consttypmod >= 0);
11146  break;
11147  default:
11148  needlabel = true;
11149  break;
11150  }
11151  if (needlabel || showtype > 0)
11152  appendStringInfo(buf, "::%s",
11154  constval->consttypmod));
11155 
11156  get_const_collation(constval, context);
11157 }
11158 
11159 /*
11160  * helper for get_const_expr: append COLLATE if needed
11161  */
11162 static void
11164 {
11165  StringInfo buf = context->buf;
11166 
11167  if (OidIsValid(constval->constcollid))
11168  {
11169  Oid typcollation = get_typcollation(constval->consttype);
11170 
11171  if (constval->constcollid != typcollation)
11172  {
11173  appendStringInfo(buf, " COLLATE %s",
11174  generate_collation_name(constval->constcollid));
11175  }
11176  }
11177 }
11178 
11179 /*
11180  * get_json_path_spec - Parse back a JSON path specification
11181  */
11182 static void
11183 get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
11184 {
11185  if (IsA(path_spec, Const))
11186  get_const_expr((Const *) path_spec, context, -1);
11187  else
11188  get_rule_expr(path_spec, context, showimplicit);
11189 }
11190 
11191 /*
11192  * get_json_format - Parse back a JsonFormat node
11193  */
11194 static void
11196 {
11197  if (format->format_type == JS_FORMAT_DEFAULT)
11198  return;
11199 
11201  format->format_type == JS_FORMAT_JSONB ?
11202  " FORMAT JSONB" : " FORMAT JSON");
11203 
11204  if (format->encoding != JS_ENC_DEFAULT)
11205  {
11206  const char *encoding;
11207 
11208  encoding =
11209  format->encoding == JS_ENC_UTF16 ? "UTF16" :
11210  format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11211 
11212  appendStringInfo(buf, " ENCODING %s", encoding);
11213  }
11214 }
11215 
11216 /*
11217  * get_json_returning - Parse back a JsonReturning structure
11218  */
11219 static void
11221  bool json_format_by_default)
11222 {
11223  if (!OidIsValid(returning->typid))
11224  return;
11225 
11226  appendStringInfo(buf, " RETURNING %s",
11227  format_type_with_typemod(returning->typid,
11228  returning->typmod));
11229 
11230  if (!json_format_by_default ||
11231  returning->format->format_type !=
11232  (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11233  get_json_format(returning->format, buf);
11234 }
11235 
11236 /*
11237  * get_json_constructor - Parse back a JsonConstructorExpr node
11238  */
11239 static void
11241  bool showimplicit)
11242 {
11243  StringInfo buf = context->buf;
11244  const char *funcname;
11245  bool is_json_object;
11246  int curridx;
11247  ListCell *lc;
11248 
11249  if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11250  {
11251  get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11252  return;
11253  }
11254  else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11255  {
11256  get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11257  return;
11258  }
11259 
11260  switch (ctor->type)
11261  {
11262  case JSCTOR_JSON_OBJECT:
11263  funcname = "JSON_OBJECT";
11264  break;
11265  case JSCTOR_JSON_ARRAY:
11266  funcname = "JSON_ARRAY";
11267  break;
11268  case JSCTOR_JSON_PARSE:
11269  funcname = "JSON";
11270  break;
11271  case JSCTOR_JSON_SCALAR:
11272  funcname = "JSON_SCALAR";
11273  break;
11274  case JSCTOR_JSON_SERIALIZE:
11275  funcname = "JSON_SERIALIZE";
11276  break;
11277  default:
11278  elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11279  }
11280 
11281  appendStringInfo(buf, "%s(", funcname);
11282 
11283  is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11284  foreach(lc, ctor->args)
11285  {
11286  curridx = foreach_current_index(lc);
11287  if (curridx > 0)
11288  {
11289  const char *sep;
11290 
11291  sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11293  }
11294 
11295  get_rule_expr((Node *) lfirst(lc), context, true);
11296  }
11297 
11299  appendStringInfoChar(buf, ')');
11300 }
11301 
11302 /*
11303  * Append options, if any, to the JSON constructor being deparsed
11304  */
11305 static void
11307 {
11308  if (ctor->absent_on_null)
11309  {
11310  if (ctor->type == JSCTOR_JSON_OBJECT ||
11311  ctor->type == JSCTOR_JSON_OBJECTAGG)
11312  appendStringInfoString(buf, " ABSENT ON NULL");
11313  }
11314  else
11315  {
11316  if (ctor->type == JSCTOR_JSON_ARRAY ||
11317  ctor->type == JSCTOR_JSON_ARRAYAGG)
11318  appendStringInfoString(buf, " NULL ON NULL");
11319  }
11320 
11321  if (ctor->unique)
11322  appendStringInfoString(buf, " WITH UNIQUE KEYS");
11323 
11324  /*
11325  * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11326  * support one.
11327  */
11328  if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11329  get_json_returning(ctor->returning, buf, true);
11330 }
11331 
11332 /*
11333  * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
11334  */
11335 static void
11337  const char *funcname, bool is_json_objectagg)
11338 {
11340 
11343 
11344  if (IsA(ctor->func, Aggref))
11346  (Aggref *) ctor->func,
11347  funcname, options.data, is_json_objectagg);
11348  else if (IsA(ctor->func, WindowFunc))
11350  funcname, options.data,
11351  is_json_objectagg);
11352  else
11353  elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11354  nodeTag(ctor->func));
11355 }
11356 
11357 /*
11358  * simple_quote_literal - Format a string as a SQL literal, append to buf
11359  */
11360 static void
11362 {
11363  const char *valptr;
11364 
11365  /*
11366  * We form the string literal according to the prevailing setting of
11367  * standard_conforming_strings; we never use E''. User is responsible for
11368  * making sure result is used correctly.
11369  */
11370  appendStringInfoChar(buf, '\'');
11371  for (valptr = val; *valptr; valptr++)
11372  {
11373  char ch = *valptr;
11374 
11378  }
11379  appendStringInfoChar(buf, '\'');
11380 }
11381 
11382 
11383 /* ----------
11384  * get_sublink_expr - Parse back a sublink
11385  * ----------
11386  */
11387 static void
11389 {
11390  StringInfo buf = context->buf;
11391  Query *query = (Query *) (sublink->subselect);
11392  char *opname = NULL;
11393  bool need_paren;
11394 
11395  if (sublink->subLinkType == ARRAY_SUBLINK)
11396  appendStringInfoString(buf, "ARRAY(");
11397  else
11398  appendStringInfoChar(buf, '(');
11399 
11400  /*
11401  * Note that we print the name of only the first operator, when there are
11402  * multiple combining operators. This is an approximation that could go
11403  * wrong in various scenarios (operators in different schemas, renamed
11404  * operators, etc) but there is not a whole lot we can do about it, since
11405  * the syntax allows only one operator to be shown.
11406  */
11407  if (sublink->testexpr)
11408  {
11409  if (IsA(sublink->testexpr, OpExpr))
11410  {
11411  /* single combining operator */
11412  OpExpr *opexpr = (OpExpr *) sublink->testexpr;
11413 
11414  get_rule_expr(linitial(opexpr->args), context, true);
11415  opname = generate_operator_name(opexpr->opno,
11416  exprType(linitial(opexpr->args)),
11417  exprType(lsecond(opexpr->args)));
11418  }
11419  else if (IsA(sublink->testexpr, BoolExpr))
11420  {
11421  /* multiple combining operators, = or <> cases */
11422  char *sep;
11423  ListCell *l;
11424 
11425  appendStringInfoChar(buf, '(');
11426  sep = "";
11427  foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11428  {
11429  OpExpr *opexpr = lfirst_node(OpExpr, l);
11430 
11432  get_rule_expr(linitial(opexpr->args), context, true);
11433  if (!opname)
11434  opname = generate_operator_name(opexpr->opno,
11435  exprType(linitial(opexpr->args)),
11436  exprType(lsecond(opexpr->args)));
11437  sep = ", ";
11438  }
11439  appendStringInfoChar(buf, ')');
11440  }
11441  else if (IsA(sublink->testexpr, RowCompareExpr))
11442  {
11443  /* multiple combining operators, < <= > >= cases */
11444  RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11445 
11446  appendStringInfoChar(buf, '(');
11447  get_rule_expr((Node *) rcexpr->largs, context, true);
11448  opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11449  exprType(linitial(rcexpr->largs)),
11450  exprType(linitial(rcexpr->rargs)));
11451  appendStringInfoChar(buf, ')');
11452  }
11453  else
11454  elog(ERROR, "unrecognized testexpr type: %d",
11455  (int) nodeTag(sublink->testexpr));
11456  }
11457 
11458  need_paren = true;
11459 
11460  switch (sublink->subLinkType)
11461  {
11462  case EXISTS_SUBLINK:
11463  appendStringInfoString(buf, "EXISTS ");
11464  break;
11465 
11466  case ANY_SUBLINK:
11467  if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11468  appendStringInfoString(buf, " IN ");
11469  else
11470  appendStringInfo(buf, " %s ANY ", opname);
11471  break;
11472 
11473  case ALL_SUBLINK:
11474  appendStringInfo(buf, " %s ALL ", opname);
11475  break;
11476 
11477  case ROWCOMPARE_SUBLINK:
11478  appendStringInfo(buf, " %s ", opname);
11479  break;
11480 
11481  case EXPR_SUBLINK:
11482  case MULTIEXPR_SUBLINK:
11483  case ARRAY_SUBLINK:
11484  need_paren = false;
11485  break;
11486 
11487  case CTE_SUBLINK: /* shouldn't occur in a SubLink */
11488  default:
11489  elog(ERROR, "unrecognized sublink type: %d",
11490  (int) sublink->subLinkType);
11491  break;
11492  }
11493 
11494  if (need_paren)
11495  appendStringInfoChar(buf, '(');
11496 
11497  get_query_def(query, buf, context->namespaces, NULL, false,
11498  context->prettyFlags, context->wrapColumn,
11499  context->indentLevel);
11500 
11501  if (need_paren)
11502  appendStringInfoString(buf, "))");
11503  else
11504  appendStringInfoChar(buf, ')');
11505 }
11506 
11507 
11508 /* ----------
11509  * get_xmltable - Parse back a XMLTABLE function
11510  * ----------
11511  */
11512 static void
11514 {
11515  StringInfo buf = context->buf;
11516 
11517  appendStringInfoString(buf, "XMLTABLE(");
11518 
11519  if (tf->ns_uris != NIL)
11520  {
11521  ListCell *lc1,
11522  *lc2;
11523  bool first = true;
11524 
11525  appendStringInfoString(buf, "XMLNAMESPACES (");
11526  forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
11527  {
11528  Node *expr = (Node *) lfirst(lc1);
11529  String *ns_node = lfirst_node(String, lc2);
11530 
11531  if (!first)
11532  appendStringInfoString(buf, ", ");
11533  else
11534  first = false;
11535 
11536  if (ns_node != NULL)
11537  {
11538  get_rule_expr(expr, context, showimplicit);
11539  appendStringInfo(buf, " AS %s", strVal(ns_node));
11540  }
11541  else
11542  {
11543  appendStringInfoString(buf, "DEFAULT ");
11544  get_rule_expr(expr, context, showimplicit);
11545  }
11546  }
11547  appendStringInfoString(buf, "), ");
11548  }
11549 
11550  appendStringInfoChar(buf, '(');
11551  get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
11552  appendStringInfoString(buf, ") PASSING (");
11553  get_rule_expr((Node *) tf->docexpr, context, showimplicit);
11554  appendStringInfoChar(buf, ')');
11555 
11556  if (tf->colexprs != NIL)
11557  {
11558  ListCell *l1;
11559  ListCell *l2;
11560  ListCell *l3;
11561  ListCell *l4;
11562  ListCell *l5;
11563  int colnum = 0;
11564 
11565  appendStringInfoString(buf, " COLUMNS ");
11566  forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
11567  l4, tf->colexprs, l5, tf->coldefexprs)
11568  {
11569  char *colname = strVal(lfirst(l1));
11570  Oid typid = lfirst_oid(l2);
11571  int32 typmod = lfirst_int(l3);
11572  Node *colexpr = (Node *) lfirst(l4);
11573  Node *coldefexpr = (Node *) lfirst(l5);
11574  bool ordinality = (tf->ordinalitycol == colnum);
11575  bool notnull = bms_is_member(colnum, tf->notnulls);
11576 
11577  if (colnum > 0)
11578  appendStringInfoString(buf, ", ");
11579  colnum++;
11580 
11581  appendStringInfo(buf, "%s %s", quote_identifier(colname),
11582  ordinality ? "FOR ORDINALITY" :
11583  format_type_with_typemod(typid, typmod));
11584  if (ordinality)
11585  continue;
11586 
11587  if (coldefexpr != NULL)
11588  {
11589  appendStringInfoString(buf, " DEFAULT (");
11590  get_rule_expr((Node *) coldefexpr, context, showimplicit);
11591  appendStringInfoChar(buf, ')');
11592  }
11593  if (colexpr != NULL)
11594  {
11595  appendStringInfoString(buf, " PATH (");
11596  get_rule_expr((Node *) colexpr, context, showimplicit);
11597  appendStringInfoChar(buf, ')');
11598  }
11599  if (notnull)
11600  appendStringInfoString(buf, " NOT NULL");
11601  }
11602  }
11603 
11604  appendStringInfoChar(buf, ')');
11605 }
11606 
11607 /*
11608  * get_json_table_nested_columns - Parse back nested JSON_TABLE columns
11609  */
11610 static void
11612  deparse_context *context, bool showimplicit,
11613  bool needcomma)
11614 {
11615  if (IsA(plan, JsonTablePathScan))
11616  {
11618 
11619  if (needcomma)
11620  appendStringInfoChar(context->buf, ',');
11621 
11622  appendStringInfoChar(context->buf, ' ');
11623  appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
11624  get_const_expr(scan->path->value, context, -1);
11625  appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
11626  get_json_table_columns(tf, scan, context, showimplicit);
11627  }
11628  else if (IsA(plan, JsonTableSiblingJoin))
11629  {
11631 
11632  get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
11633  needcomma);
11634  get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
11635  true);
11636  }
11637 }
11638 
11639 /*
11640  * get_json_table_columns - Parse back JSON_TABLE columns
11641  */
11642 static void
11645  bool showimplicit)
11646 {
11647  StringInfo buf = context->buf;
11648  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11649  ListCell *lc_colname;
11650  ListCell *lc_coltype;
11651  ListCell *lc_coltypmod;
11652  ListCell *lc_colvalexpr;
11653  int colnum = 0;
11654 
11655  appendStringInfoChar(buf, ' ');
11656  appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
11657 
11658  if (PRETTY_INDENT(context))
11659  context->indentLevel += PRETTYINDENT_VAR;
11660 
11661  forfour(lc_colname, tf->colnames,
11662  lc_coltype, tf->coltypes,
11663  lc_coltypmod, tf->coltypmods,
11664  lc_colvalexpr, tf->colvalexprs)
11665  {
11666  char *colname = strVal(lfirst(lc_colname));
11667  JsonExpr *colexpr;
11668  Oid typid;
11669  int32 typmod;
11670  bool ordinality;
11671  JsonBehaviorType default_behavior;
11672 
11673  typid = lfirst_oid(lc_coltype);
11674  typmod = lfirst_int(lc_coltypmod);
11675  colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
11676 
11677  /* Skip columns that don't belong to this scan. */
11678  if (scan->colMin < 0 || colnum < scan->colMin)
11679  {
11680  colnum++;
11681  continue;
11682  }
11683  if (colnum > scan->colMax)
11684  break;
11685 
11686  if (colnum > scan->colMin)
11687  appendStringInfoString(buf, ", ");
11688 
11689  colnum++;
11690 
11691  ordinality = !colexpr;
11692 
11693  appendContextKeyword(context, "", 0, 0, 0);
11694 
11695  appendStringInfo(buf, "%s %s", quote_identifier(colname),
11696  ordinality ? "FOR ORDINALITY" :
11697  format_type_with_typemod(typid, typmod));
11698  if (ordinality)
11699  continue;
11700 
11701  if (colexpr->op == JSON_EXISTS_OP)
11702  {
11703  appendStringInfoString(buf, " EXISTS");
11704  default_behavior = JSON_BEHAVIOR_FALSE;
11705  }
11706  else
11707  {
11708  if (colexpr->op == JSON_QUERY_OP)
11709  {
11710  char typcategory;
11711  bool typispreferred;
11712 
11713  get_type_category_preferred(typid, &typcategory, &typispreferred);
11714 
11715  if (typcategory == TYPCATEGORY_STRING)
11717  colexpr->format->format_type == JS_FORMAT_JSONB ?
11718  " FORMAT JSONB" : " FORMAT JSON");
11719  }
11720 
11721  default_behavior = JSON_BEHAVIOR_NULL;
11722  }
11723 
11724  if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
11725  default_behavior = JSON_BEHAVIOR_ERROR;
11726 
11727  appendStringInfoString(buf, " PATH ");
11728 
11729  get_json_path_spec(colexpr->path_spec, context, showimplicit);
11730 
11731  get_json_expr_options(colexpr, context, default_behavior);
11732  }
11733 
11734  if (scan->child)
11735  get_json_table_nested_columns(tf, scan->child, context, showimplicit,
11736  scan->colMin >= 0);
11737 
11738  if (PRETTY_INDENT(context))
11739  context->indentLevel -= PRETTYINDENT_VAR;
11740 
11741  appendContextKeyword(context, ")", 0, 0, 0);
11742 }
11743 
11744 /* ----------
11745  * get_json_table - Parse back a JSON_TABLE function
11746  * ----------
11747  */
11748 static void
11750 {
11751  StringInfo buf = context->buf;
11752  JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
11754 
11755  appendStringInfoString(buf, "JSON_TABLE(");
11756 
11757  if (PRETTY_INDENT(context))
11758  context->indentLevel += PRETTYINDENT_VAR;
11759 
11760  appendContextKeyword(context, "", 0, 0, 0);
11761 
11762  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
11763 
11764  appendStringInfoString(buf, ", ");
11765 
11766  get_const_expr(root->path->value, context, -1);
11767 
11768  appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
11769 
11770  if (jexpr->passing_values)
11771  {
11772  ListCell *lc1,
11773  *lc2;
11774  bool needcomma = false;
11775 
11776  appendStringInfoChar(buf, ' ');
11777  appendContextKeyword(context, "PASSING ", 0, 0, 0);
11778 
11779  if (PRETTY_INDENT(context))
11780  context->indentLevel += PRETTYINDENT_VAR;
11781 
11782  forboth(lc1, jexpr->passing_names,
11783  lc2, jexpr->passing_values)
11784  {
11785  if (needcomma)
11786  appendStringInfoString(buf, ", ");
11787  needcomma = true;
11788 
11789  appendContextKeyword(context, "", 0, 0, 0);
11790 
11791  get_rule_expr((Node *) lfirst(lc2), context, false);
11792  appendStringInfo(buf, " AS %s",
11793  quote_identifier((lfirst_node(String, lc1))->sval)
11794  );
11795  }
11796 
11797  if (PRETTY_INDENT(context))
11798  context->indentLevel -= PRETTYINDENT_VAR;
11799  }
11800 
11802  showimplicit);
11803 
11804  if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY)
11805  get_json_behavior(jexpr->on_error, context, "ERROR");
11806 
11807  if (PRETTY_INDENT(context))
11808  context->indentLevel -= PRETTYINDENT_VAR;
11809 
11810  appendContextKeyword(context, ")", 0, 0, 0);
11811 }
11812 
11813 /* ----------
11814  * get_tablefunc - Parse back a table function
11815  * ----------
11816  */
11817 static void
11819 {
11820  /* XMLTABLE and JSON_TABLE are the only existing implementations. */
11821 
11822  if (tf->functype == TFT_XMLTABLE)
11823  get_xmltable(tf, context, showimplicit);
11824  else if (tf->functype == TFT_JSON_TABLE)
11825  get_json_table(tf, context, showimplicit);
11826 }
11827 
11828 /* ----------
11829  * get_from_clause - Parse back a FROM clause
11830  *
11831  * "prefix" is the keyword that denotes the start of the list of FROM
11832  * elements. It is FROM when used to parse back SELECT and UPDATE, but
11833  * is USING when parsing back DELETE.
11834  * ----------
11835  */
11836 static void
11837 get_from_clause(Query *query, const char *prefix, deparse_context *context)
11838 {
11839  StringInfo buf = context->buf;
11840  bool first = true;
11841  ListCell *l;
11842 
11843  /*
11844  * We use the query's jointree as a guide to what to print. However, we
11845  * must ignore auto-added RTEs that are marked not inFromCl. (These can
11846  * only appear at the top level of the jointree, so it's sufficient to
11847  * check here.) This check also ensures we ignore the rule pseudo-RTEs
11848  * for NEW and OLD.
11849  */
11850  foreach(l, query->jointree->fromlist)
11851  {
11852  Node *jtnode = (Node *) lfirst(l);
11853 
11854  if (IsA(jtnode, RangeTblRef))
11855  {
11856  int varno = ((RangeTblRef *) jtnode)->rtindex;
11857  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11858 
11859  if (!rte->inFromCl)
11860  continue;
11861  }
11862 
11863  if (first)
11864  {
11865  appendContextKeyword(context, prefix,
11867  first = false;
11868 
11869  get_from_clause_item(jtnode, query, context);
11870  }
11871  else
11872  {
11873  StringInfoData itembuf;
11874 
11875  appendStringInfoString(buf, ", ");
11876 
11877  /*
11878  * Put the new FROM item's text into itembuf so we can decide
11879  * after we've got it whether or not it needs to go on a new line.
11880  */
11881  initStringInfo(&itembuf);
11882  context->buf = &itembuf;
11883 
11884  get_from_clause_item(jtnode, query, context);
11885 
11886  /* Restore context's output buffer */
11887  context->buf = buf;
11888 
11889  /* Consider line-wrapping if enabled */
11890  if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
11891  {
11892  /* Does the new item start with a new line? */
11893  if (itembuf.len > 0 && itembuf.data[0] == '\n')
11894  {
11895  /* If so, we shouldn't add anything */
11896  /* instead, remove any trailing spaces currently in buf */
11898  }
11899  else
11900  {
11901  char *trailing_nl;
11902 
11903  /* Locate the start of the current line in the buffer */
11904  trailing_nl = strrchr(buf->data, '\n');
11905  if (trailing_nl == NULL)
11906  trailing_nl = buf->data;
11907  else
11908  trailing_nl++;
11909 
11910  /*
11911  * Add a newline, plus some indentation, if the new item
11912  * would cause an overflow.
11913  */
11914  if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
11918  }
11919  }
11920 
11921  /* Add the new item */
11922  appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
11923 
11924  /* clean up */
11925  pfree(itembuf.data);
11926  }
11927  }
11928 }
11929 
11930 static void
11932 {
11933  StringInfo buf = context->buf;
11934  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
11935 
11936  if (IsA(jtnode, RangeTblRef))
11937  {
11938  int varno = ((RangeTblRef *) jtnode)->rtindex;
11939  RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11940  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11941  RangeTblFunction *rtfunc1 = NULL;
11942 
11943  if (rte->lateral)
11944  appendStringInfoString(buf, "LATERAL ");
11945 
11946  /* Print the FROM item proper */
11947  switch (rte->rtekind)
11948  {
11949  case RTE_RELATION:
11950  /* Normal relation RTE */
11951  appendStringInfo(buf, "%s%s",
11952  only_marker(rte),
11954  context->namespaces));
11955  break;
11956  case RTE_SUBQUERY:
11957  /* Subquery RTE */
11958  appendStringInfoChar(buf, '(');
11959  get_query_def(rte->subquery, buf, context->namespaces, NULL,
11960  true,
11961  context->prettyFlags, context->wrapColumn,
11962  context->indentLevel);
11963  appendStringInfoChar(buf, ')');
11964  break;
11965  case RTE_FUNCTION:
11966  /* Function RTE */
11967  rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
11968 
11969  /*
11970  * Omit ROWS FROM() syntax for just one function, unless it
11971  * has both a coldeflist and WITH ORDINALITY. If it has both,
11972  * we must use ROWS FROM() syntax to avoid ambiguity about
11973  * whether the coldeflist includes the ordinality column.
11974  */
11975  if (list_length(rte->functions) == 1 &&
11976  (rtfunc1->funccolnames == NIL || !rte->funcordinality))
11977  {
11978  get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
11979  /* we'll print the coldeflist below, if it has one */
11980  }
11981  else
11982  {
11983  bool all_unnest;
11984  ListCell *lc;
11985 
11986  /*
11987  * If all the function calls in the list are to unnest,
11988  * and none need a coldeflist, then collapse the list back
11989  * down to UNNEST(args). (If we had more than one
11990  * built-in unnest function, this would get more
11991  * difficult.)
11992  *
11993  * XXX This is pretty ugly, since it makes not-terribly-
11994  * future-proof assumptions about what the parser would do
11995  * with the output; but the alternative is to emit our
11996  * nonstandard ROWS FROM() notation for what might have
11997  * been a perfectly spec-compliant multi-argument
11998  * UNNEST().
11999  */
12000  all_unnest = true;
12001  foreach(lc, rte->functions)
12002  {
12003  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12004 
12005  if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12006  ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12007  rtfunc->funccolnames != NIL)
12008  {
12009  all_unnest = false;
12010  break;
12011  }
12012  }
12013 
12014  if (all_unnest)
12015  {
12016  List *allargs = NIL;
12017 
12018  foreach(lc, rte->functions)
12019  {
12020  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12021  List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12022 
12023  allargs = list_concat(allargs, args);
12024  }
12025 
12026  appendStringInfoString(buf, "UNNEST(");
12027  get_rule_expr((Node *) allargs, context, true);
12028  appendStringInfoChar(buf, ')');
12029  }
12030  else
12031  {
12032  int funcno = 0;
12033 
12034  appendStringInfoString(buf, "ROWS FROM(");
12035  foreach(lc, rte->functions)
12036  {
12037  RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12038 
12039  if (funcno > 0)
12040  appendStringInfoString(buf, ", ");
12041  get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12042  if (rtfunc->funccolnames != NIL)
12043  {
12044  /* Reconstruct the column definition list */
12045  appendStringInfoString(buf, " AS ");
12047  NULL,
12048  context);
12049  }
12050  funcno++;
12051  }
12052  appendStringInfoChar(buf, ')');
12053  }
12054  /* prevent printing duplicate coldeflist below */
12055  rtfunc1 = NULL;
12056  }
12057  if (rte->funcordinality)
12058  appendStringInfoString(buf, " WITH ORDINALITY");
12059  break;
12060  case RTE_TABLEFUNC:
12061  get_tablefunc(rte->tablefunc, context, true);
12062  break;
12063  case RTE_VALUES:
12064  /* Values list RTE */
12065  appendStringInfoChar(buf, '(');
12067  appendStringInfoChar(buf, ')');
12068  break;
12069  case RTE_CTE:
12071  break;
12072  default:
12073  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12074  break;
12075  }
12076 
12077  /* Print the relation alias, if needed */
12078  get_rte_alias(rte, varno, false, context);
12079 
12080  /* Print the column definitions or aliases, if needed */
12081  if (rtfunc1 && rtfunc1->funccolnames != NIL)
12082  {
12083  /* Reconstruct the columndef list, which is also the aliases */
12084  get_from_clause_coldeflist(rtfunc1, colinfo, context);
12085  }
12086  else
12087  {
12088  /* Else print column aliases as needed */
12089  get_column_alias_list(colinfo, context);
12090  }
12091 
12092  /* Tablesample clause must go after any alias */
12093  if (rte->rtekind == RTE_RELATION && rte->tablesample)
12095  }
12096  else if (IsA(jtnode, JoinExpr))
12097  {
12098  JoinExpr *j = (JoinExpr *) jtnode;
12099  deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12100  bool need_paren_on_right;
12101 
12102  need_paren_on_right = PRETTY_PAREN(context) &&
12103  !IsA(j->rarg, RangeTblRef) &&
12104  !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12105 
12106  if (!PRETTY_PAREN(context) || j->alias != NULL)
12107  appendStringInfoChar(buf, '(');
12108 
12109  get_from_clause_item(j->larg, query, context);
12110 
12111  switch (j->jointype)
12112  {
12113  case JOIN_INNER:
12114  if (j->quals)
12115  appendContextKeyword(context, " JOIN ",
12119  else
12120  appendContextKeyword(context, " CROSS JOIN ",
12124  break;
12125  case JOIN_LEFT:
12126  appendContextKeyword(context, " LEFT JOIN ",
12130  break;
12131  case JOIN_FULL:
12132  appendContextKeyword(context, " FULL JOIN ",
12136  break;
12137  case JOIN_RIGHT:
12138  appendContextKeyword(context, " RIGHT JOIN ",
12142  break;
12143  default:
12144  elog(ERROR, "unrecognized join type: %d",
12145  (int) j->jointype);
12146  }
12147 
12148  if (need_paren_on_right)
12149  appendStringInfoChar(buf, '(');
12150  get_from_clause_item(j->rarg, query, context);
12151  if (need_paren_on_right)
12152  appendStringInfoChar(buf, ')');
12153 
12154  if (j->usingClause)
12155  {
12156  ListCell *lc;
12157  bool first = true;
12158 
12159  appendStringInfoString(buf, " USING (");
12160  /* Use the assigned names, not what's in usingClause */
12161  foreach(lc, colinfo->usingNames)
12162  {
12163  char *colname = (char *) lfirst(lc);
12164 
12165  if (first)
12166  first = false;
12167  else
12168  appendStringInfoString(buf, ", ");
12170  }
12171  appendStringInfoChar(buf, ')');
12172 
12173  if (j->join_using_alias)
12174  appendStringInfo(buf, " AS %s",
12175  quote_identifier(j->join_using_alias->aliasname));
12176  }
12177  else if (j->quals)
12178  {
12179  appendStringInfoString(buf, " ON ");
12180  if (!PRETTY_PAREN(context))
12181  appendStringInfoChar(buf, '(');
12182  get_rule_expr(j->quals, context, false);
12183  if (!PRETTY_PAREN(context))
12184  appendStringInfoChar(buf, ')');
12185  }
12186  else if (j->jointype != JOIN_INNER)
12187  {
12188  /* If we didn't say CROSS JOIN above, we must provide an ON */
12189  appendStringInfoString(buf, " ON TRUE");
12190  }
12191 
12192  if (!PRETTY_PAREN(context) || j->alias != NULL)
12193  appendStringInfoChar(buf, ')');
12194 
12195  /* Yes, it's correct to put alias after the right paren ... */
12196  if (j->alias != NULL)
12197  {
12198  /*
12199  * Note that it's correct to emit an alias clause if and only if
12200  * there was one originally. Otherwise we'd be converting a named
12201  * join to unnamed or vice versa, which creates semantic
12202  * subtleties we don't want. However, we might print a different
12203  * alias name than was there originally.
12204  */
12205  appendStringInfo(buf, " %s",
12207  context)));
12208  get_column_alias_list(colinfo, context);
12209  }
12210  }
12211  else
12212  elog(ERROR, "unrecognized node type: %d",
12213  (int) nodeTag(jtnode));
12214 }
12215 
12216 /*
12217  * get_rte_alias - print the relation's alias, if needed
12218  *
12219  * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
12220  */
12221 static void
12222 get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
12224 {
12225  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12226  char *refname = get_rtable_name(varno, context);
12227  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12228  bool printalias = false;
12229 
12230  if (rte->alias != NULL)
12231  {
12232  /* Always print alias if user provided one */
12233  printalias = true;
12234  }
12235  else if (colinfo->printaliases)
12236  {
12237  /* Always print alias if we need to print column aliases */
12238  printalias = true;
12239  }
12240  else if (rte->rtekind == RTE_RELATION)
12241  {
12242  /*
12243  * No need to print alias if it's same as relation name (this would
12244  * normally be the case, but not if set_rtable_names had to resolve a
12245  * conflict).
12246  */
12247  if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12248  printalias = true;
12249  }
12250  else if (rte->rtekind == RTE_FUNCTION)
12251  {
12252  /*
12253  * For a function RTE, always print alias. This covers possible
12254  * renaming of the function and/or instability of the FigureColname
12255  * rules for things that aren't simple functions. Note we'd need to
12256  * force it anyway for the columndef list case.
12257  */
12258  printalias = true;
12259  }
12260  else if (rte->rtekind == RTE_SUBQUERY ||
12261  rte->rtekind == RTE_VALUES)
12262  {
12263  /*
12264  * For a subquery, always print alias. This makes the output
12265  * SQL-spec-compliant, even though we allow such aliases to be omitted
12266  * on input.
12267  */
12268  printalias = true;
12269  }
12270  else if (rte->rtekind == RTE_CTE)
12271  {
12272  /*
12273  * No need to print alias if it's same as CTE name (this would
12274  * normally be the case, but not if set_rtable_names had to resolve a
12275  * conflict).
12276  */
12277  if (strcmp(refname, rte->ctename) != 0)
12278  printalias = true;
12279  }
12280 
12281  if (printalias)
12282  appendStringInfo(context->buf, "%s%s",
12283  use_as ? " AS " : " ",
12284  quote_identifier(refname));
12285 }
12286 
12287 /*
12288  * get_column_alias_list - print column alias list for an RTE
12289  *
12290  * Caller must already have printed the relation's alias name.
12291  */
12292 static void
12294 {
12295  StringInfo buf = context->buf;
12296  int i;
12297  bool first = true;
12298 
12299  /* Don't print aliases if not needed */
12300  if (!colinfo->printaliases)
12301  return;
12302 
12303  for (i = 0; i < colinfo->num_new_cols; i++)
12304  {
12305  char *colname = colinfo->new_colnames[i];
12306 
12307  if (first)
12308  {
12309  appendStringInfoChar(buf, '(');
12310  first = false;
12311  }
12312  else
12313  appendStringInfoString(buf, ", ");
12315  }
12316  if (!first)
12317  appendStringInfoChar(buf, ')');
12318 }
12319 
12320 /*
12321  * get_from_clause_coldeflist - reproduce FROM clause coldeflist
12322  *
12323  * When printing a top-level coldeflist (which is syntactically also the
12324  * relation's column alias list), use column names from colinfo. But when
12325  * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
12326  * original coldeflist's names, which are available in rtfunc->funccolnames.
12327  * Pass NULL for colinfo to select the latter behavior.
12328  *
12329  * The coldeflist is appended immediately (no space) to buf. Caller is
12330  * responsible for ensuring that an alias or AS is present before it.
12331  */
12332 static void
12334  deparse_columns *colinfo,
12336 {
12337  StringInfo buf = context->buf;
12338  ListCell *l1;
12339  ListCell *l2;
12340  ListCell *l3;
12341  ListCell *l4;
12342  int i;
12343 
12344  appendStringInfoChar(buf, '(');
12345 
12346  i = 0;
12347  forfour(l1, rtfunc->funccoltypes,
12348  l2, rtfunc->funccoltypmods,
12349  l3, rtfunc->funccolcollations,
12350  l4, rtfunc->funccolnames)
12351  {
12352  Oid atttypid = lfirst_oid(l1);
12353  int32 atttypmod = lfirst_int(l2);
12354  Oid attcollation = lfirst_oid(l3);
12355  char *attname;
12356 
12357  if (colinfo)
12358  attname = colinfo->colnames[i];
12359  else
12360  attname = strVal(lfirst(l4));
12361 
12362  Assert(attname); /* shouldn't be any dropped columns here */
12363 
12364  if (i > 0)
12365  appendStringInfoString(buf, ", ");
12366  appendStringInfo(buf, "%s %s",
12368  format_type_with_typemod(atttypid, atttypmod));
12369  if (OidIsValid(attcollation) &&
12370  attcollation != get_typcollation(atttypid))
12371  appendStringInfo(buf, " COLLATE %s",
12372  generate_collation_name(attcollation));
12373 
12374  i++;
12375  }
12376 
12377  appendStringInfoChar(buf, ')');
12378 }
12379 
12380 /*
12381  * get_tablesample_def - print a TableSampleClause
12382  */
12383 static void
12385 {
12386  StringInfo buf = context->buf;
12387  Oid argtypes[1];
12388  int nargs;
12389  ListCell *l;
12390 
12391  /*
12392  * We should qualify the handler's function name if it wouldn't be
12393  * resolved by lookup in the current search path.
12394  */
12395  argtypes[0] = INTERNALOID;
12396  appendStringInfo(buf, " TABLESAMPLE %s (",
12397  generate_function_name(tablesample->tsmhandler, 1,
12398  NIL, argtypes,
12399  false, NULL, EXPR_KIND_NONE));
12400 
12401  nargs = 0;
12402  foreach(l, tablesample->args)
12403  {
12404  if (nargs++ > 0)
12405  appendStringInfoString(buf, ", ");
12406  get_rule_expr((Node *) lfirst(l), context, false);
12407  }
12408  appendStringInfoChar(buf, ')');
12409 
12410  if (tablesample->repeatable != NULL)
12411  {
12412  appendStringInfoString(buf, " REPEATABLE (");
12413  get_rule_expr((Node *) tablesample->repeatable, context, false);
12414  appendStringInfoChar(buf, ')');
12415  }
12416 }
12417 
12418 /*
12419  * get_opclass_name - fetch name of an index operator class
12420  *
12421  * The opclass name is appended (after a space) to buf.
12422  *
12423  * Output is suppressed if the opclass is the default for the given
12424  * actual_datatype. (If you don't want this behavior, just pass
12425  * InvalidOid for actual_datatype.)
12426  */
12427 static void
12428 get_opclass_name(Oid opclass, Oid actual_datatype,
12429  StringInfo buf)
12430 {
12431  HeapTuple ht_opc;
12432  Form_pg_opclass opcrec;
12433  char *opcname;
12434  char *nspname;
12435 
12436  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12437  if (!HeapTupleIsValid(ht_opc))
12438  elog(ERROR, "cache lookup failed for opclass %u", opclass);
12439  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12440 
12441  if (!OidIsValid(actual_datatype) ||
12442  GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12443  {
12444  /* Okay, we need the opclass name. Do we need to qualify it? */
12445  opcname = NameStr(opcrec->opcname);
12446  if (OpclassIsVisible(opclass))
12447  appendStringInfo(buf, " %s", quote_identifier(opcname));
12448  else
12449  {
12450  nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
12451  appendStringInfo(buf, " %s.%s",
12452  quote_identifier(nspname),
12453  quote_identifier(opcname));
12454  }
12455  }
12456  ReleaseSysCache(ht_opc);
12457 }
12458 
12459 /*
12460  * generate_opclass_name
12461  * Compute the name to display for an opclass specified by OID
12462  *
12463  * The result includes all necessary quoting and schema-prefixing.
12464  */
12465 char *
12467 {
12469 
12470  initStringInfo(&buf);
12471  get_opclass_name(opclass, InvalidOid, &buf);
12472 
12473  return &buf.data[1]; /* get_opclass_name() prepends space */
12474 }
12475 
12476 /*
12477  * processIndirection - take care of array and subfield assignment
12478  *
12479  * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
12480  * appear in the input, printing them as decoration for the base column
12481  * name (which we assume the caller just printed). We might also need to
12482  * strip CoerceToDomain nodes, but only ones that appear above assignment
12483  * nodes.
12484  *
12485  * Returns the subexpression that's to be assigned.
12486  */
12487 static Node *
12489 {
12490  StringInfo buf = context->buf;
12491  CoerceToDomain *cdomain = NULL;
12492 
12493  for (;;)
12494  {
12495  if (node == NULL)
12496  break;
12497  if (IsA(node, FieldStore))
12498  {
12499  FieldStore *fstore = (FieldStore *) node;
12500  Oid typrelid;
12501  char *fieldname;
12502 
12503  /* lookup tuple type */
12504  typrelid = get_typ_typrelid(fstore->resulttype);
12505  if (!OidIsValid(typrelid))
12506  elog(ERROR, "argument type %s of FieldStore is not a tuple type",
12507  format_type_be(fstore->resulttype));
12508 
12509  /*
12510  * Print the field name. There should only be one target field in
12511  * stored rules. There could be more than that in executable
12512  * target lists, but this function cannot be used for that case.
12513  */
12514  Assert(list_length(fstore->fieldnums) == 1);
12515  fieldname = get_attname(typrelid,
12516  linitial_int(fstore->fieldnums), false);
12517  appendStringInfo(buf, ".%s", quote_identifier(fieldname));
12518 
12519  /*
12520  * We ignore arg since it should be an uninteresting reference to
12521  * the target column or subcolumn.
12522  */
12523  node = (Node *) linitial(fstore->newvals);
12524  }
12525  else if (IsA(node, SubscriptingRef))
12526  {
12527  SubscriptingRef *sbsref = (SubscriptingRef *) node;
12528 
12529  if (sbsref->refassgnexpr == NULL)
12530  break;
12531 
12532  printSubscripts(sbsref, context);
12533 
12534  /*
12535  * We ignore refexpr since it should be an uninteresting reference
12536  * to the target column or subcolumn.
12537  */
12538  node = (Node *) sbsref->refassgnexpr;
12539  }
12540  else if (IsA(node, CoerceToDomain))
12541  {
12542  cdomain = (CoerceToDomain *) node;
12543  /* If it's an explicit domain coercion, we're done */
12544  if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
12545  break;
12546  /* Tentatively descend past the CoerceToDomain */
12547  node = (Node *) cdomain->arg;
12548  }
12549  else
12550  break;
12551  }
12552 
12553  /*
12554  * If we descended past a CoerceToDomain whose argument turned out not to
12555  * be a FieldStore or array assignment, back up to the CoerceToDomain.
12556  * (This is not enough to be fully correct if there are nested implicit
12557  * CoerceToDomains, but such cases shouldn't ever occur.)
12558  */
12559  if (cdomain && node == (Node *) cdomain->arg)
12560  node = (Node *) cdomain;
12561 
12562  return node;
12563 }
12564 
12565 static void
12567 {
12568  StringInfo buf = context->buf;
12569  ListCell *lowlist_item;
12570  ListCell *uplist_item;
12571 
12572  lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
12573  foreach(uplist_item, sbsref->refupperindexpr)
12574  {
12575  appendStringInfoChar(buf, '[');
12576  if (lowlist_item)
12577  {
12578  /* If subexpression is NULL, get_rule_expr prints nothing */
12579  get_rule_expr((Node *) lfirst(lowlist_item), context, false);
12580  appendStringInfoChar(buf, ':');
12581  lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
12582  }
12583  /* If subexpression is NULL, get_rule_expr prints nothing */
12584  get_rule_expr((Node *) lfirst(uplist_item), context, false);
12585  appendStringInfoChar(buf, ']');
12586  }
12587 }
12588 
12589 /*
12590  * quote_identifier - Quote an identifier only if needed
12591  *
12592  * When quotes are needed, we palloc the required space; slightly
12593  * space-wasteful but well worth it for notational simplicity.
12594  */
12595 const char *
12597 {
12598  /*
12599  * Can avoid quoting if ident starts with a lowercase letter or underscore
12600  * and contains only lowercase letters, digits, and underscores, *and* is
12601  * not any SQL keyword. Otherwise, supply quotes.
12602  */
12603  int nquotes = 0;
12604  bool safe;
12605  const char *ptr;
12606  char *result;
12607  char *optr;
12608 
12609  /*
12610  * would like to use <ctype.h> macros here, but they might yield unwanted
12611  * locale-specific results...
12612  */
12613  safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
12614 
12615  for (ptr = ident; *ptr; ptr++)
12616  {
12617  char ch = *ptr;
12618 
12619  if ((ch >= 'a' && ch <= 'z') ||
12620  (ch >= '0' && ch <= '9') ||
12621  (ch == '_'))
12622  {
12623  /* okay */
12624  }
12625  else
12626  {
12627  safe = false;
12628  if (ch == '"')
12629  nquotes++;
12630  }
12631  }
12632 
12634  safe = false;
12635 
12636  if (safe)
12637  {
12638  /*
12639  * Check for keyword. We quote keywords except for unreserved ones.
12640  * (In some cases we could avoid quoting a col_name or type_func_name
12641  * keyword, but it seems much harder than it's worth to tell that.)
12642  *
12643  * Note: ScanKeywordLookup() does case-insensitive comparison, but
12644  * that's fine, since we already know we have all-lower-case.
12645  */
12646  int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
12647 
12648  if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
12649  safe = false;
12650  }
12651 
12652  if (safe)
12653  return ident; /* no change needed */
12654 
12655  result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
12656 
12657  optr = result;
12658  *optr++ = '"';
12659  for (ptr = ident; *ptr; ptr++)
12660  {
12661  char ch = *ptr;
12662 
12663  if (ch == '"')
12664  *optr++ = '"';
12665  *optr++ = ch;
12666  }
12667  *optr++ = '"';
12668  *optr = '\0';
12669 
12670  return result;
12671 }
12672 
12673 /*
12674  * quote_qualified_identifier - Quote a possibly-qualified identifier
12675  *
12676  * Return a name of the form qualifier.ident, or just ident if qualifier
12677  * is NULL, quoting each component if necessary. The result is palloc'd.
12678  */
12679 char *
12680 quote_qualified_identifier(const char *qualifier,
12681  const char *ident)
12682 {
12684 
12685  initStringInfo(&buf);
12686  if (qualifier)
12687  appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
12689  return buf.data;
12690 }
12691 
12692 /*
12693  * get_relation_name
12694  * Get the unqualified name of a relation specified by OID
12695  *
12696  * This differs from the underlying get_rel_name() function in that it will
12697  * throw error instead of silently returning NULL if the OID is bad.
12698  */
12699 static char *
12701 {
12702  char *relname = get_rel_name(relid);
12703 
12704  if (!relname)
12705  elog(ERROR, "cache lookup failed for relation %u", relid);
12706  return relname;
12707 }
12708 
12709 /*
12710  * generate_relation_name
12711  * Compute the name to display for a relation specified by OID
12712  *
12713  * The result includes all necessary quoting and schema-prefixing.
12714  *
12715  * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
12716  * We will forcibly qualify the relation name if it equals any CTE name
12717  * visible in the namespace list.
12718  */
12719 static char *
12720 generate_relation_name(Oid relid, List *namespaces)
12721 {
12722  HeapTuple tp;
12723  Form_pg_class reltup;
12724  bool need_qual;
12725  ListCell *nslist;
12726  char *relname;
12727  char *nspname;
12728  char *result;
12729 
12730  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12731  if (!HeapTupleIsValid(tp))
12732  elog(ERROR, "cache lookup failed for relation %u", relid);
12733  reltup = (Form_pg_class) GETSTRUCT(tp);
12734  relname = NameStr(reltup->relname);
12735 
12736  /* Check for conflicting CTE name */
12737  need_qual = false;
12738  foreach(nslist, namespaces)
12739  {
12740  deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
12741  ListCell *ctlist;
12742 
12743  foreach(ctlist, dpns->ctes)
12744  {
12745  CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
12746 
12747  if (strcmp(cte->ctename, relname) == 0)
12748  {
12749  need_qual = true;
12750  break;
12751  }
12752  }
12753  if (need_qual)
12754  break;
12755  }
12756 
12757  /* Otherwise, qualify the name if not visible in search path */
12758  if (!need_qual)
12759  need_qual = !RelationIsVisible(relid);
12760 
12761  if (need_qual)
12762  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12763  else
12764  nspname = NULL;
12765 
12766  result = quote_qualified_identifier(nspname, relname);
12767 
12768  ReleaseSysCache(tp);
12769 
12770  return result;
12771 }
12772 
12773 /*
12774  * generate_qualified_relation_name
12775  * Compute the name to display for a relation specified by OID
12776  *
12777  * As above, but unconditionally schema-qualify the name.
12778  */
12779 static char *
12781 {
12782  HeapTuple tp;
12783  Form_pg_class reltup;
12784  char *relname;
12785  char *nspname;
12786  char *result;
12787 
12788  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12789  if (!HeapTupleIsValid(tp))
12790  elog(ERROR, "cache lookup failed for relation %u", relid);
12791  reltup = (Form_pg_class) GETSTRUCT(tp);
12792  relname = NameStr(reltup->relname);
12793 
12794  nspname = get_namespace_name_or_temp(reltup->relnamespace);
12795  if (!nspname)
12796  elog(ERROR, "cache lookup failed for namespace %u",
12797  reltup->relnamespace);
12798 
12799  result = quote_qualified_identifier(nspname, relname);
12800 
12801  ReleaseSysCache(tp);
12802 
12803  return result;
12804 }
12805 
12806 /*
12807  * generate_function_name
12808  * Compute the name to display for a function specified by OID,
12809  * given that it is being called with the specified actual arg names and
12810  * types. (Those matter because of ambiguous-function resolution rules.)
12811  *
12812  * If we're dealing with a potentially variadic function (in practice, this
12813  * means a FuncExpr or Aggref, not some other way of calling a function), then
12814  * has_variadic must specify whether variadic arguments have been merged,
12815  * and *use_variadic_p will be set to indicate whether to print VARIADIC in
12816  * the output. For non-FuncExpr cases, has_variadic should be false and
12817  * use_variadic_p can be NULL.
12818  *
12819  * The result includes all necessary quoting and schema-prefixing.
12820  */
12821 static char *
12822 generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
12823  bool has_variadic, bool *use_variadic_p,
12824  ParseExprKind special_exprkind)
12825 {
12826  char *result;
12827  HeapTuple proctup;
12828  Form_pg_proc procform;
12829  char *proname;
12830  bool use_variadic;
12831  char *nspname;
12832  FuncDetailCode p_result;
12833  Oid p_funcid;
12834  Oid p_rettype;
12835  bool p_retset;
12836  int p_nvargs;
12837  Oid p_vatype;
12838  Oid *p_true_typeids;
12839  bool force_qualify = false;
12840 
12841  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
12842  if (!HeapTupleIsValid(proctup))
12843  elog(ERROR, "cache lookup failed for function %u", funcid);
12844  procform = (Form_pg_proc) GETSTRUCT(proctup);
12845  proname = NameStr(procform->proname);
12846 
12847  /*
12848  * Due to parser hacks to avoid needing to reserve CUBE, we need to force
12849  * qualification in some special cases.
12850  */
12851  if (special_exprkind == EXPR_KIND_GROUP_BY)
12852  {
12853  if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
12854  force_qualify = true;
12855  }
12856 
12857  /*
12858  * Determine whether VARIADIC should be printed. We must do this first
12859  * since it affects the lookup rules in func_get_detail().
12860  *
12861  * We always print VARIADIC if the function has a merged variadic-array
12862  * argument. Note that this is always the case for functions taking a
12863  * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
12864  * and printed the array elements as separate arguments, the call could
12865  * match a newer non-VARIADIC function.
12866  */
12867  if (use_variadic_p)
12868  {
12869  /* Parser should not have set funcvariadic unless fn is variadic */
12870  Assert(!has_variadic || OidIsValid(procform->provariadic));
12871  use_variadic = has_variadic;
12872  *use_variadic_p = use_variadic;
12873  }
12874  else
12875  {
12876  Assert(!has_variadic);
12877  use_variadic = false;
12878  }
12879 
12880  /*
12881  * The idea here is to schema-qualify only if the parser would fail to
12882  * resolve the correct function given the unqualified func name with the
12883  * specified argtypes and VARIADIC flag. But if we already decided to
12884  * force qualification, then we can skip the lookup and pretend we didn't
12885  * find it.
12886  */
12887  if (!force_qualify)
12889  NIL, argnames, nargs, argtypes,
12890  !use_variadic, true, false,
12891  &p_funcid, &p_rettype,
12892  &p_retset, &p_nvargs, &p_vatype,
12893  &p_true_typeids, NULL);
12894  else
12895  {
12896  p_result = FUNCDETAIL_NOTFOUND;
12897  p_funcid = InvalidOid;
12898  }
12899 
12900  if ((p_result == FUNCDETAIL_NORMAL ||
12901  p_result == FUNCDETAIL_AGGREGATE ||
12902  p_result == FUNCDETAIL_WINDOWFUNC) &&
12903  p_funcid == funcid)
12904  nspname = NULL;
12905  else
12906  nspname = get_namespace_name_or_temp(procform->pronamespace);
12907 
12908  result = quote_qualified_identifier(nspname, proname);
12909 
12910  ReleaseSysCache(proctup);
12911 
12912  return result;
12913 }
12914 
12915 /*
12916  * generate_operator_name
12917  * Compute the name to display for an operator specified by OID,
12918  * given that it is being called with the specified actual arg types.
12919  * (Arg types matter because of ambiguous-operator resolution rules.
12920  * Pass InvalidOid for unused arg of a unary operator.)
12921  *
12922  * The result includes all necessary quoting and schema-prefixing,
12923  * plus the OPERATOR() decoration needed to use a qualified operator name
12924  * in an expression.
12925  */
12926 static char *
12927 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
12928 {
12930  HeapTuple opertup;
12931  Form_pg_operator operform;
12932  char *oprname;
12933  char *nspname;
12934  Operator p_result;
12935 
12936  initStringInfo(&buf);
12937 
12938  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
12939  if (!HeapTupleIsValid(opertup))
12940  elog(ERROR, "cache lookup failed for operator %u", operid);
12941  operform = (Form_pg_operator) GETSTRUCT(opertup);
12942  oprname = NameStr(operform->oprname);
12943 
12944  /*
12945  * The idea here is to schema-qualify only if the parser would fail to
12946  * resolve the correct operator given the unqualified op name with the
12947  * specified argtypes.
12948  */
12949  switch (operform->oprkind)
12950  {
12951  case 'b':
12952  p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
12953  true, -1);
12954  break;
12955  case 'l':
12956  p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
12957  true, -1);
12958  break;
12959  default:
12960  elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
12961  p_result = NULL; /* keep compiler quiet */
12962  break;
12963  }
12964 
12965  if (p_result != NULL && oprid(p_result) == operid)
12966  nspname = NULL;
12967  else
12968  {
12969  nspname = get_namespace_name_or_temp(operform->oprnamespace);
12970  appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
12971  }
12972 
12973  appendStringInfoString(&buf, oprname);
12974 
12975  if (nspname)
12976  appendStringInfoChar(&buf, ')');
12977 
12978  if (p_result != NULL)
12979  ReleaseSysCache(p_result);
12980 
12981  ReleaseSysCache(opertup);
12982 
12983  return buf.data;
12984 }
12985 
12986 /*
12987  * generate_operator_clause --- generate a binary-operator WHERE clause
12988  *
12989  * This is used for internally-generated-and-executed SQL queries, where
12990  * precision is essential and readability is secondary. The basic
12991  * requirement is to append "leftop op rightop" to buf, where leftop and
12992  * rightop are given as strings and are assumed to yield types leftoptype
12993  * and rightoptype; the operator is identified by OID. The complexity
12994  * comes from needing to be sure that the parser will select the desired
12995  * operator when the query is parsed. We always name the operator using
12996  * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
12997  * We have to emit casts too, if either input isn't already the input type
12998  * of the operator; else we are at the mercy of the parser's heuristics for
12999  * ambiguous-operator resolution. The caller must ensure that leftop and
13000  * rightop are suitable arguments for a cast operation; it's best to insert
13001  * parentheses if they aren't just variables or parameters.
13002  */
13003 void
13005  const char *leftop, Oid leftoptype,
13006  Oid opoid,
13007  const char *rightop, Oid rightoptype)
13008 {
13009  HeapTuple opertup;
13010  Form_pg_operator operform;
13011  char *oprname;
13012  char *nspname;
13013 
13014  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13015  if (!HeapTupleIsValid(opertup))
13016  elog(ERROR, "cache lookup failed for operator %u", opoid);
13017  operform = (Form_pg_operator) GETSTRUCT(opertup);
13018  Assert(operform->oprkind == 'b');
13019  oprname = NameStr(operform->oprname);
13020 
13021  nspname = get_namespace_name(operform->oprnamespace);
13022 
13023  appendStringInfoString(buf, leftop);
13024  if (leftoptype != operform->oprleft)
13025  add_cast_to(buf, operform->oprleft);
13026  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13027  appendStringInfoString(buf, oprname);
13028  appendStringInfo(buf, ") %s", rightop);
13029  if (rightoptype != operform->oprright)
13030  add_cast_to(buf, operform->oprright);
13031 
13032  ReleaseSysCache(opertup);
13033 }
13034 
13035 /*
13036  * Add a cast specification to buf. We spell out the type name the hard way,
13037  * intentionally not using format_type_be(). This is to avoid corner cases
13038  * for CHARACTER, BIT, and perhaps other types, where specifying the type
13039  * using SQL-standard syntax results in undesirable data truncation. By
13040  * doing it this way we can be certain that the cast will have default (-1)
13041  * target typmod.
13042  */
13043 static void
13045 {
13046  HeapTuple typetup;
13047  Form_pg_type typform;
13048  char *typname;
13049  char *nspname;
13050 
13051  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13052  if (!HeapTupleIsValid(typetup))
13053  elog(ERROR, "cache lookup failed for type %u", typid);
13054  typform = (Form_pg_type) GETSTRUCT(typetup);
13055 
13056  typname = NameStr(typform->typname);
13057  nspname = get_namespace_name_or_temp(typform->typnamespace);
13058 
13059  appendStringInfo(buf, "::%s.%s",
13061 
13062  ReleaseSysCache(typetup);
13063 }
13064 
13065 /*
13066  * generate_qualified_type_name
13067  * Compute the name to display for a type specified by OID
13068  *
13069  * This is different from format_type_be() in that we unconditionally
13070  * schema-qualify the name. That also means no special syntax for
13071  * SQL-standard type names ... although in current usage, this should
13072  * only get used for domains, so such cases wouldn't occur anyway.
13073  */
13074 static char *
13076 {
13077  HeapTuple tp;
13078  Form_pg_type typtup;
13079  char *typname;
13080  char *nspname;
13081  char *result;
13082 
13083  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13084  if (!HeapTupleIsValid(tp))
13085  elog(ERROR, "cache lookup failed for type %u", typid);
13086  typtup = (Form_pg_type) GETSTRUCT(tp);
13087  typname = NameStr(typtup->typname);
13088 
13089  nspname = get_namespace_name_or_temp(typtup->typnamespace);
13090  if (!nspname)
13091  elog(ERROR, "cache lookup failed for namespace %u",
13092  typtup->typnamespace);
13093 
13094  result = quote_qualified_identifier(nspname, typname);
13095 
13096  ReleaseSysCache(tp);
13097 
13098  return result;
13099 }
13100 
13101 /*
13102  * generate_collation_name
13103  * Compute the name to display for a collation specified by OID
13104  *
13105  * The result includes all necessary quoting and schema-prefixing.
13106  */
13107 char *
13109 {
13110  HeapTuple tp;
13111  Form_pg_collation colltup;
13112  char *collname;
13113  char *nspname;
13114  char *result;
13115 
13116  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13117  if (!HeapTupleIsValid(tp))
13118  elog(ERROR, "cache lookup failed for collation %u", collid);
13119  colltup = (Form_pg_collation) GETSTRUCT(tp);
13120  collname = NameStr(colltup->collname);
13121 
13122  if (!CollationIsVisible(collid))
13123  nspname = get_namespace_name_or_temp(colltup->collnamespace);
13124  else
13125  nspname = NULL;
13126 
13127  result = quote_qualified_identifier(nspname, collname);
13128 
13129  ReleaseSysCache(tp);
13130 
13131  return result;
13132 }
13133 
13134 /*
13135  * Given a C string, produce a TEXT datum.
13136  *
13137  * We assume that the input was palloc'd and may be freed.
13138  */
13139 static text *
13141 {
13142  text *result;
13143 
13144  result = cstring_to_text(str);
13145  pfree(str);
13146  return result;
13147 }
13148 
13149 /*
13150  * Generate a C string representing a relation options from text[] datum.
13151  */
13152 static void
13154 {
13155  Datum *options;
13156  int noptions;
13157  int i;
13158 
13159  deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13160  &options, NULL, &noptions);
13161 
13162  for (i = 0; i < noptions; i++)
13163  {
13164  char *option = TextDatumGetCString(options[i]);
13165  char *name;
13166  char *separator;
13167  char *value;
13168 
13169  /*
13170  * Each array element should have the form name=value. If the "=" is
13171  * missing for some reason, treat it like an empty value.
13172  */
13173  name = option;
13174  separator = strchr(option, '=');
13175  if (separator)
13176  {
13177  *separator = '\0';
13178  value = separator + 1;
13179  }
13180  else
13181  value = "";
13182 
13183  if (i > 0)
13184  appendStringInfoString(buf, ", ");
13186 
13187  /*
13188  * In general we need to quote the value; but to avoid unnecessary
13189  * clutter, do not quote if it is an identifier that would not need
13190  * quoting. (We could also allow numbers, but that is a bit trickier
13191  * than it looks --- for example, are leading zeroes significant? We
13192  * don't want to assume very much here about what custom reloptions
13193  * might mean.)
13194  */
13195  if (quote_identifier(value) == value)
13197  else
13199 
13200  pfree(option);
13201  }
13202 }
13203 
13204 /*
13205  * Generate a C string representing a relation's reloptions, or NULL if none.
13206  */
13207 static char *
13209 {
13210  char *result = NULL;
13211  HeapTuple tuple;
13212  Datum reloptions;
13213  bool isnull;
13214 
13215  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13216  if (!HeapTupleIsValid(tuple))
13217  elog(ERROR, "cache lookup failed for relation %u", relid);
13218 
13219  reloptions = SysCacheGetAttr(RELOID, tuple,
13220  Anum_pg_class_reloptions, &isnull);
13221  if (!isnull)
13222  {
13224 
13225  initStringInfo(&buf);
13226  get_reloptions(&buf, reloptions);
13227 
13228  result = buf.data;
13229  }
13230 
13231  ReleaseSysCache(tuple);
13232 
13233  return result;
13234 }
13235 
13236 /*
13237  * get_range_partbound_string
13238  * A C string representation of one range partition bound
13239  */
13240 char *
13242 {
13245  ListCell *cell;
13246  char *sep;
13247 
13248  memset(&context, 0, sizeof(deparse_context));
13249  context.buf = buf;
13250 
13251  appendStringInfoChar(buf, '(');
13252  sep = "";
13253  foreach(cell, bound_datums)
13254  {
13255  PartitionRangeDatum *datum =
13257 
13259  if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
13260  appendStringInfoString(buf, "MINVALUE");
13261  else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13262  appendStringInfoString(buf, "MAXVALUE");
13263  else
13264  {
13265  Const *val = castNode(Const, datum->value);
13266 
13267  get_const_expr(val, &context, -1);
13268  }
13269  sep = ", ";
13270  }
13271  appendStringInfoChar(buf, ')');
13272 
13273  return buf->data;
13274 }
13275 
13276 /*
13277  * get_list_partvalue_string
13278  * A C string representation of one list partition value
13279  */
13280 char *
13282 {
13285 
13286  memset(&context, 0, sizeof(deparse_context));
13287  context.buf = buf;
13288 
13289  get_const_expr(val, &context, -1);
13290 
13291  return buf->data;
13292 }
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:5338
Datum array_ref(ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:3146
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3685
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5408
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:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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:4402
#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:2304
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:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * palloc(Size size)
Definition: mcxt.c:1317
#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:386
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:385
@ ONCONFLICT_NOTHING
Definition: nodes.h:419
@ 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:432
#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:1395
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:2723
@ SETOP_INTERSECT
Definition: parsenodes.h:2115
@ SETOP_UNION
Definition: parsenodes.h:2114
@ SETOP_EXCEPT
Definition: parsenodes.h:2116
#define FRAMEOPTION_END_OFFSET_PRECEDING
Definition: parsenodes.h:593
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:586
#define GetCTETargetList(cte)
Definition: parsenodes.h:1708
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2726
@ 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:2731
@ 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:2730
#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:2724
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:584
#define FRAMEOPTION_BETWEEN
Definition: parsenodes.h:585
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2725
#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:2729
#define FKCONSTR_ACTION_NOACTION
Definition: parsenodes.h:2722
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:583
@ CTEMaterializeNever
Definition: parsenodes.h:1643
@ CTEMaterializeAlways
Definition: parsenodes.h:1642
@ CTEMaterializeDefault
Definition: parsenodes.h:1641
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
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:3530
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:1972
@ IS_NOT_FALSE
Definition: primnodes.h:1972
@ IS_NOT_UNKNOWN
Definition: primnodes.h:1972
@ IS_TRUE
Definition: primnodes.h:1972
@ IS_UNKNOWN
Definition: primnodes.h:1972
@ IS_FALSE
Definition: primnodes.h:1972
@ ARRAY_SUBLINK
Definition: primnodes.h:1003
@ ANY_SUBLINK
Definition: primnodes.h:999
@ MULTIEXPR_SUBLINK
Definition: primnodes.h:1002
@ CTE_SUBLINK
Definition: primnodes.h:1004
@ EXPR_SUBLINK
Definition: primnodes.h:1001
@ ROWCOMPARE_SUBLINK
Definition: primnodes.h:1000
@ ALL_SUBLINK
Definition: primnodes.h:998
@ EXISTS_SUBLINK
Definition: primnodes.h:997
@ JS_FORMAT_JSONB
Definition: primnodes.h:1640
@ JS_FORMAT_DEFAULT
Definition: primnodes.h:1638
@ JS_FORMAT_JSON
Definition: primnodes.h:1639
@ IS_LEAST
Definition: primnodes.h:1503
@ IS_GREATEST
Definition: primnodes.h:1502
@ TFT_XMLTABLE
Definition: primnodes.h:99
@ TFT_JSON_TABLE
Definition: primnodes.h:100
BoolExprType
Definition: primnodes.h:930
@ AND_EXPR
Definition: primnodes.h:931
@ OR_EXPR
Definition: primnodes.h:931
@ NOT_EXPR
Definition: primnodes.h:931
@ JS_ENC_DEFAULT
Definition: primnodes.h:1626
@ JS_ENC_UTF32
Definition: primnodes.h:1629
@ JS_ENC_UTF16
Definition: primnodes.h:1628
@ XMLOPTION_DOCUMENT
Definition: primnodes.h:1592
@ SVFOP_CURRENT_CATALOG
Definition: primnodes.h:1549
@ SVFOP_LOCALTIME_N
Definition: primnodes.h:1542
@ SVFOP_CURRENT_TIMESTAMP
Definition: primnodes.h:1539
@ SVFOP_LOCALTIME
Definition: primnodes.h:1541
@ SVFOP_CURRENT_TIMESTAMP_N
Definition: primnodes.h:1540
@ SVFOP_CURRENT_ROLE
Definition: primnodes.h:1545
@ SVFOP_USER
Definition: primnodes.h:1547
@ SVFOP_CURRENT_SCHEMA
Definition: primnodes.h:1550
@ SVFOP_LOCALTIMESTAMP_N
Definition: primnodes.h:1544
@ SVFOP_CURRENT_DATE
Definition: primnodes.h:1536
@ SVFOP_CURRENT_TIME_N
Definition: primnodes.h:1538
@ SVFOP_CURRENT_TIME
Definition: primnodes.h:1537
@ SVFOP_LOCALTIMESTAMP
Definition: primnodes.h:1543
@ SVFOP_CURRENT_USER
Definition: primnodes.h:1546
@ SVFOP_SESSION_USER
Definition: primnodes.h:1548
@ PARAM_MULTIEXPR
Definition: primnodes.h:370
@ PARAM_EXTERN
Definition: primnodes.h:367
@ PARAM_EXEC
Definition: primnodes.h:368
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1749
@ JSW_CONDITIONAL
Definition: primnodes.h:1748
@ JSW_UNSPEC
Definition: primnodes.h:1746
@ JSW_NONE
Definition: primnodes.h:1747
@ IS_DOCUMENT
Definition: primnodes.h:1587
@ IS_XMLFOREST
Definition: primnodes.h:1582
@ IS_XMLCONCAT
Definition: primnodes.h:1580
@ IS_XMLPI
Definition: primnodes.h:1584
@ IS_XMLPARSE
Definition: primnodes.h:1583
@ IS_XMLSERIALIZE
Definition: primnodes.h:1586
@ IS_XMLROOT
Definition: primnodes.h:1585
@ IS_XMLELEMENT
Definition: primnodes.h:1581
JsonBehaviorType
Definition: primnodes.h:1760
@ JSON_BEHAVIOR_ERROR
Definition: primnodes.h:1762
@ JSON_BEHAVIOR_DEFAULT
Definition: primnodes.h:1769
@ JSON_BEHAVIOR_EMPTY
Definition: primnodes.h:1763
@ JSON_BEHAVIOR_FALSE
Definition: primnodes.h:1765
@ JSON_BEHAVIOR_NULL
Definition: primnodes.h:1761
@ JSON_QUERY_OP
Definition: primnodes.h:1799
@ JSON_EXISTS_OP
Definition: primnodes.h:1798
@ JSON_VALUE_OP
Definition: primnodes.h:1800
CoercionForm
Definition: primnodes.h:733
@ COERCE_SQL_SYNTAX
Definition: primnodes.h:737
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ COERCE_EXPLICIT_CAST
Definition: primnodes.h:735
@ COERCE_EXPLICIT_CALL
Definition: primnodes.h:734
@ OVERRIDING_SYSTEM_VALUE
Definition: primnodes.h:29
@ OVERRIDING_USER_VALUE
Definition: primnodes.h:28
@ IS_NULL
Definition: primnodes.h:1948
@ IS_NOT_NULL
Definition: primnodes.h:1948
@ JS_TYPE_ARRAY
Definition: primnodes.h:1720
@ JS_TYPE_OBJECT
Definition: primnodes.h:1719
@ JS_TYPE_SCALAR
Definition: primnodes.h:1721
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition: primnodes.h:1994
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition: primnodes.h:1993
@ MERGE_WHEN_MATCHED
Definition: primnodes.h:1992
#define OUTER_VAR
Definition: primnodes.h:237
@ JSCTOR_JSON_SERIALIZE
Definition: primnodes.h:1692
@ JSCTOR_JSON_ARRAYAGG
Definition: primnodes.h:1689
@ JSCTOR_JSON_PARSE
Definition: primnodes.h:1690
@ JSCTOR_JSON_OBJECT
Definition: primnodes.h:1686
@ JSCTOR_JSON_SCALAR
Definition: primnodes.h:1691
@ JSCTOR_JSON_ARRAY
Definition: primnodes.h:1687
@ JSCTOR_JSON_OBJECTAGG
Definition: primnodes.h:1688
#define INNER_VAR
Definition: primnodes.h:236
#define INDEX_VAR
Definition: primnodes.h:238
tree context
Definition: radixtree.h:1835
tree ctl root
Definition: radixtree.h:1886
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:5345
static void removeStringInfoSpaces(StringInfo str)
Definition: ruleutils.c:8745
static bool looks_like_function(Node *node)
Definition: ruleutils.c:10294
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:4942
Datum pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
Definition: ruleutils.c:702
static void set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4306
static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus)
Definition: ruleutils.c:8691
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:4141
static Plan * find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
Definition: ruleutils.c:5042
static text * string_to_text(char *str)
Definition: ruleutils.c:13140
static void get_values_def(List *values_lists, deparse_context *context)
Definition: ruleutils.c:5508
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3598
#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:4816
static void get_json_behavior(JsonBehavior *behavior, deparse_context *context, const char *on)
Definition: ruleutils.c:8782
static const char * get_simple_binary_op_name(OpExpr *expr)
Definition: ruleutils.c:8436
static void get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context, const char *funcname, bool is_json_objectagg)
Definition: ruleutils.c:11336
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:3969
static void print_function_trftypes(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3411
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:3399
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, bool colNamesVisible, int prettyFlags, int wrapColumn, int startIndent)
Definition: ruleutils.c:5430
static void get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
Definition: ruleutils.c:12384
Datum pg_get_functiondef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2880
Datum pg_get_function_result(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3183
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12596
Datum pg_get_indexdef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1162
static void get_sublink_expr(SubLink *sublink, deparse_context *context)
Definition: ruleutils.c:11388
static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as, deparse_context *context)
Definition: ruleutils.c:12222
#define only_marker(rte)
Definition: ruleutils.c:535
Datum pg_get_function_arg_default(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3439
char * generate_opclass_name(Oid opclass)
Definition: ruleutils.c:12466
static void get_parameter(Param *param, deparse_context *context)
Definition: ruleutils.c:8299
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:11643
#define PRETTYFLAG_INDENT
Definition: ruleutils.c:90
List * deparse_context_for(const char *aliasname, Oid relid)
Definition: ruleutils.c:3658
static void get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12293
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:11361
static bool colname_is_unique(const char *colname, deparse_namespace *dpns, deparse_columns *colinfo)
Definition: ruleutils.c:4762
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_columns *colinfo, deparse_context *context)
Definition: ruleutils.c:12333
static void get_from_clause(Query *query, const char *prefix, deparse_context *context)
Definition: ruleutils.c:11837
static void get_basic_select_query(Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:5891
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
Definition: ruleutils.c:10717
static void get_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6025
Datum pg_get_partkeydef(PG_FUNCTION_ARGS)
Definition: ruleutils.c:1893
static char * generate_qualified_relation_name(Oid relid)
Definition: ruleutils.c:12780
static void set_simple_column_names(deparse_namespace *dpns)
Definition: ruleutils.c:4034
static void get_json_expr_options(JsonExpr *jsexpr, deparse_context *context, JsonBehaviorType default_behavior)
Definition: ruleutils.c:8820
#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:6352
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:10271
static void expand_colnames_array_to(deparse_columns *colinfo, int n)
Definition: ruleutils.c:4855
static SubPlan * find_param_generator(Param *param, deparse_context *context, int *column_p)
Definition: ruleutils.c:8181
static void add_cast_to(StringInfo buf, Oid typid)
Definition: ruleutils.c:13044
static void get_special_variable(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:7532
static void get_select_query_def(Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:5690
static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context, const char *funcname, const char *options, bool is_json_objectagg)
Definition: ruleutils.c:10624
static void get_rule_list_toplevel(List *lst, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10241
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:11240
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:12822
static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11183
static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
Definition: ruleutils.c:12566
static SubPlan * find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
Definition: ruleutils.c:8278
static void pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5140
char * generate_collation_name(Oid collid)
Definition: ruleutils.c:13108
static void get_rule_expr_paren(Node *node, deparse_context *context, bool showimplicit, Node *parentNode)
Definition: ruleutils.c:8764
bool quote_all_identifiers
Definition: ruleutils.c:323
static void get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
Definition: ruleutils.c:10459
static int decompile_column_index_array(Datum column_index_array, Oid relId, StringInfo buf)
Definition: ruleutils.c:2576
static void get_const_collation(Const *constval, deparse_context *context)
Definition: ruleutils.c:11163
static void get_delete_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7037
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:11611
static char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
Definition: ruleutils.c:3625
Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:563
static void print_function_sqlbody(StringInfo buf, HeapTuple proctup)
Definition: ruleutils.c:3509
static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
Definition: ruleutils.c:4075
static Node * get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6295
List * select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
Definition: ruleutils.c:3795
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:12680
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:5119
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:13208
static text * pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
Definition: ruleutils.c:2663
List * set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
Definition: ruleutils.c:3772
static Node * processIndirection(Node *node, deparse_context *context)
Definition: ruleutils.c:12488
static void get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
Definition: ruleutils.c:10597
#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:3563
Datum pg_get_expr(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2628
static char * generate_qualified_type_name(Oid typid)
Definition: ruleutils.c:13075
static void get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11513
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:7253
static char * get_relation_name(Oid relid)
Definition: ruleutils.c:12700
Datum pg_get_expr_ext(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2645
char * get_list_partvalue_string(Const *val)
Definition: ruleutils.c:13281
static void get_rule_windowclause(Query *query, deparse_context *context)
Definition: ruleutils.c:6470
static void get_rule_windowspec(WindowClause *wc, List *targetList, deparse_context *context)
Definition: ruleutils.c:6502
static void get_json_returning(JsonReturning *returning, StringInfo buf, bool json_format_by_default)
Definition: ruleutils.c:11220
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:8067
static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context)
Definition: ruleutils.c:6412
static void pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
Definition: ruleutils.c:5089
static const char * get_name_for_var_field(Var *var, int fieldno, int levelsup, deparse_context *context)
Definition: ruleutils.c:7661
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte, deparse_columns *colinfo)
Definition: ruleutils.c:4502
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:3824
static void get_update_query_targetlist_def(Query *query, List *targetList, deparse_context *context, RangeTblEntry *rte)
Definition: ruleutils.c:6885
static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:8861
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:10323
char * pg_get_querydef(Query *query, bool pretty)
Definition: ruleutils.c:1572
Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3158
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:13153
static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10363
static void get_const_expr(Const *constval, deparse_context *context, int showtype)
Definition: ruleutils.c:11033
void generate_operator_clause(StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
Definition: ruleutils.c:13004
static void get_setop_query(Node *setOp, Query *query, deparse_context *context, TupleDesc resultDesc, bool colNamesVisible)
Definition: ruleutils.c:6161
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
Definition: ruleutils.c:5156
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:3251
static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte, deparse_columns *colinfo)
Definition: ruleutils.c:4874
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:3213
static RangeTblEntry * get_simple_values_rte(Query *query, TupleDesc resultDesc)
Definition: ruleutils.c:5822
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan)
Definition: ruleutils.c:4961
static void resolve_special_varno(Node *node, deparse_context *context, rsv_callback callback, void *callback_arg)
Definition: ruleutils.c:7553
static void get_merge_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:7089
static void get_json_format(JsonFormat *format, StringInfo buf)
Definition: ruleutils.c:11195
static void get_insert_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6611
static void get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11818
static void get_rule_expr_toplevel(Node *node, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:10223
static void get_coercion_expr(Node *arg, deparse_context *context, Oid resulttype, int32 resulttypmod, Node *parentNode)
Definition: ruleutils.c:10969
static void push_child_plan(deparse_namespace *dpns, Plan *plan, deparse_namespace *save_dpns)
Definition: ruleutils.c:5072
static void get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
Definition: ruleutils.c:11306
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:13241
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
Definition: ruleutils.c:8462
static void get_with_clause(Query *query, deparse_context *context)
Definition: ruleutils.c:5551
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:3703
static void get_update_query_def(Query *query, deparse_context *context, bool colNamesVisible)
Definition: ruleutils.c:6828
static char * generate_relation_name(Oid relid, List *namespaces)
Definition: ruleutils.c:12720
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
Definition: ruleutils.c:10613
static char * get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
Definition: ruleutils.c:7298
Datum pg_get_serial_sequence(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2786
static char * generate_operator_name(Oid operid, Oid arg1, Oid arg2)
Definition: ruleutils.c:12927
static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
Definition: ruleutils.c:11931
Datum pg_get_function_arguments(PG_FUNCTION_ARGS)
Definition: ruleutils.c:3132
static void get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
Definition: ruleutils.c:11749
#define PRETTYFLAG_SCHEMA
Definition: ruleutils.c:91
static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf)
Definition: ruleutils.c:12428
Datum pg_get_viewdef_name(PG_FUNCTION_ARGS)
Definition: ruleutils.c:722
Datum pg_get_userbyid(PG_FUNCTION_ARGS)
Definition: ruleutils.c:2748
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:10471
#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:2970
Index parent_relid
Definition: pathnodes.h:2969
int num_child_cols
Definition: pathnodes.h:3005
List * elements
Definition: primnodes.h:1380
BoolExprType boolop
Definition: primnodes.h:939
List * args
Definition: primnodes.h:940
BoolTestType booltesttype
Definition: primnodes.h:1979
Expr * arg
Definition: primnodes.h:1978
Expr * arg
Definition: primnodes.h:1313
Expr * defresult
Definition: primnodes.h:1315
List * args
Definition: primnodes.h:1314
List * args
Definition: primnodes.h:1492
Expr * arg
Definition: primnodes.h:1207
Oid resulttype
Definition: primnodes.h:1208
Expr * arg
Definition: primnodes.h:1279
CTEMaterialize ctematerialized
Definition: parsenodes.h:1682
Oid consttype
Definition: primnodes.h:312
char * cursor_name
Definition: primnodes.h:2094
AttrNumber fieldnum
Definition: primnodes.h:1129
Expr * arg
Definition: primnodes.h:1128
List * newvals
Definition: primnodes.h:1160
Node * quals
Definition: primnodes.h:2305
List * fromlist
Definition: primnodes.h:2304
Oid funcid
Definition: primnodes.h:750
List * args
Definition: primnodes.h:768
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:224
Node * expr
Definition: primnodes.h:1787
JsonBehaviorType btype
Definition: primnodes.h:1786
JsonReturning * returning
Definition: primnodes.h:1706
JsonConstructorType type
Definition: primnodes.h:1702
Node * formatted_expr
Definition: primnodes.h:1819
List * passing_values
Definition: primnodes.h:1832
JsonBehavior * on_empty
Definition: primnodes.h:1835
JsonFormat * format
Definition: primnodes.h:1822
List * passing_names
Definition: primnodes.h:1831
Node * path_spec
Definition: primnodes.h:1825
JsonReturning * returning
Definition: primnodes.h:1828
JsonWrapper wrapper
Definition: primnodes.h:1846
JsonExprOp op
Definition: primnodes.h:1813
JsonBehavior * on_error
Definition: primnodes.h:1836
bool omit_quotes
Definition: primnodes.h:1849
JsonFormatType format_type
Definition: primnodes.h:1651
JsonValueType item_type
Definition: primnodes.h:1733
JsonFormat * format
Definition: primnodes.h:1663
JsonTablePath * path
Definition: primnodes.h:1894
JsonTablePlan * child
Definition: primnodes.h:1903
Const * value
Definition: primnodes.h:1867
JsonTablePlan * rplan
Definition: primnodes.h:1924
JsonTablePlan * lplan
Definition: primnodes.h:1923
JsonFormat * format
Definition: primnodes.h:1681
Expr * raw_expr
Definition: primnodes.h:1679
Definition: pg_list.h:54
List * args
Definition: primnodes.h:1518
MinMaxOp op
Definition: primnodes.h:1516
Expr * arg
Definition: primnodes.h:791
Var * paramval
Definition: plannodes.h:819
List * nestParams
Definition: plannodes.h:810
Definition: nodes.h:129
NullTestType nulltesttype
Definition: primnodes.h:1955
Expr * arg
Definition: primnodes.h:1954
List * arbiterElems
Definition: primnodes.h:2323
OnConflictAction action
Definition: primnodes.h:2320
List * onConflictSet
Definition: primnodes.h:2329
Node * onConflictWhere
Definition: primnodes.h:2330
Node * arbiterWhere
Definition: primnodes.h:2325
Oid opno
Definition: primnodes.h:818
List * args
Definition: primnodes.h:836
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:1185
Expr * arg
Definition: primnodes.h:1184
TupleDesc rd_att
Definition: rel.h:112
List * args
Definition: primnodes.h:1411
LockClauseStrength strength
Definition: parsenodes.h:1583
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1584
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
SQLValueFunctionOp op
Definition: primnodes.h:1556
SetOperation op
Definition: parsenodes.h:2191
Index tleSortGroupRef
Definition: parsenodes.h:1442
Definition: value.h:64
char * plan_name
Definition: primnodes.h:1072
List * args
Definition: primnodes.h:1091
List * paramIds
Definition: primnodes.h:1068
bool useHashTable
Definition: primnodes.h:1079
Node * testexpr
Definition: primnodes.h:1067
List * parParam
Definition: primnodes.h:1090
List * setParam
Definition: primnodes.h:1088
SubLinkType subLinkType
Definition: primnodes.h:1065
Expr * refassgnexpr
Definition: primnodes.h:703
List * refupperindexpr
Definition: primnodes.h:693
Expr * refexpr
Definition: primnodes.h:701
List * reflowerindexpr
Definition: primnodes.h:699
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:2186
AttrNumber resno
Definition: primnodes.h:2188
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:581
Expr * aggfilter
Definition: primnodes.h:577
Oid winfnoid
Definition: primnodes.h:567
List * args
Definition: primnodes.h:1608
List * named_args
Definition: primnodes.h:1604
XmlExprOp op
Definition: primnodes.h:1600
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:2413
@ 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