Coverage Report

Created: 2026-09-28 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/adt/ruleutils.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * ruleutils.c
4
 *    Functions to convert stored expressions/querytrees back to
5
 *    source text
6
 *
7
 * Portions Copyright (c) 1996-2026, 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"
35
#include "catalog/pg_partitioned_table.h"
36
#include "catalog/pg_proc.h"
37
#include "catalog/pg_statistic_ext.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_oper.h"
54
#include "parser/parse_relation.h"
55
#include "parser/parser.h"
56
#include "parser/parsetree.h"
57
#include "rewrite/rewriteHandler.h"
58
#include "rewrite/rewriteManip.h"
59
#include "rewrite/rewriteSupport.h"
60
#include "utils/array.h"
61
#include "utils/builtins.h"
62
#include "utils/fmgroids.h"
63
#include "utils/guc.h"
64
#include "utils/hsearch.h"
65
#include "utils/lsyscache.h"
66
#include "utils/partcache.h"
67
#include "utils/rel.h"
68
#include "utils/ruleutils.h"
69
#include "utils/snapmgr.h"
70
#include "utils/syscache.h"
71
#include "utils/typcache.h"
72
#include "utils/varlena.h"
73
#include "utils/xml.h"
74
75
/* ----------
76
 * Pretty formatting constants
77
 * ----------
78
 */
79
80
/* Indent counts */
81
0
#define PRETTYINDENT_STD    8
82
0
#define PRETTYINDENT_JOIN   4
83
0
#define PRETTYINDENT_VAR    4
84
85
0
#define PRETTYINDENT_LIMIT    40  /* wrap limit */
86
87
/* Pretty flags */
88
0
#define PRETTYFLAG_PAREN    0x0001
89
0
#define PRETTYFLAG_INDENT   0x0002
90
0
#define PRETTYFLAG_SCHEMA   0x0004
91
92
/* Standard conversion of a "bool pretty" option to detailed flags */
93
#define GET_PRETTY_FLAGS(pretty) \
94
0
  ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
95
0
   : PRETTYFLAG_INDENT)
96
97
/* Default line length for pretty-print wrapping: 0 means wrap always */
98
0
#define WRAP_COLUMN_DEFAULT   0
99
100
/* macros to test if pretty action needed */
101
0
#define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
102
0
#define PRETTY_INDENT(context)  ((context)->prettyFlags & PRETTYFLAG_INDENT)
103
#define PRETTY_SCHEMA(context)  ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
104
105
106
/* ----------
107
 * Local data types
108
 * ----------
109
 */
110
111
/* Context info needed for invoking a recursive querytree display routine */
112
typedef struct
113
{
114
  StringInfo  buf;      /* output buffer to append to */
115
  List     *namespaces;   /* List of deparse_namespace nodes */
116
  TupleDesc resultDesc;   /* if top level of a view, the view's tupdesc */
117
  List     *targetList;   /* Current query level's SELECT targetlist */
118
  List     *windowClause; /* Current query level's 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
  bool    colNamesVisible;  /* do we care about output column names? */
124
  bool    inGroupBy;    /* deparsing GROUP BY clause? */
125
  bool    varInOrderBy; /* deparsing simple Var in ORDER BY? */
126
  Bitmapset  *appendparents;  /* if not null, map child Vars of these relids
127
                 * back to the parent rel */
128
} deparse_context;
129
130
/*
131
 * Each level of query context around a subtree needs a level of Var namespace.
132
 * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
133
 * the current context's namespaces list.
134
 *
135
 * rtable is the list of actual RTEs from the Query or PlannedStmt.
136
 * rtable_names holds the alias name to be used for each RTE (either a C
137
 * string, or NULL for nameless RTEs such as unnamed joins).
138
 * rtable_columns holds the column alias names to be used for each RTE.
139
 *
140
 * subplans is a list of Plan trees for SubPlans and CTEs (it's only used
141
 * in the PlannedStmt case).
142
 * ctes is a list of CommonTableExpr nodes (only used in the Query case).
143
 * appendrels, if not null (it's only used in the PlannedStmt case), is an
144
 * array of AppendRelInfo nodes, indexed by child relid.  We use that to map
145
 * child-table Vars to their inheritance parents.
146
 *
147
 * In some cases we need to make names of merged JOIN USING columns unique
148
 * across the whole query, not only per-RTE.  If so, unique_using is true
149
 * and using_names is a list of C strings representing names already assigned
150
 * to USING columns.
151
 *
152
 * When deparsing plan trees, there is always just a single item in the
153
 * deparse_namespace list (since a plan tree never contains Vars with
154
 * varlevelsup > 0).  We store the Plan node that is the immediate
155
 * parent of the expression to be deparsed, as well as a list of that
156
 * Plan's ancestors.  In addition, we store its outer and inner subplan nodes,
157
 * as well as their targetlists, and the index tlist if the current plan node
158
 * might contain INDEX_VAR Vars.  (These fields could be derived on-the-fly
159
 * from the current Plan node, but it seems notationally clearer to set them
160
 * up as separate fields.)
161
 */
162
typedef struct
163
{
164
  List     *rtable;     /* List of RangeTblEntry nodes */
165
  List     *rtable_names; /* Parallel list of names for RTEs */
166
  List     *rtable_columns; /* Parallel list of deparse_columns structs */
167
  List     *subplans;   /* List of Plan trees for SubPlans */
168
  List     *ctes;     /* List of CommonTableExpr nodes */
169
  AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */
170
  char     *ret_old_alias;  /* alias for OLD in RETURNING list */
171
  char     *ret_new_alias;  /* alias for NEW in RETURNING list */
172
  /* Workspace for column alias assignment: */
173
  bool    unique_using; /* Are we making USING names globally unique */
174
  List     *using_names;  /* List of assigned names for USING columns */
175
  /* Remaining fields are used only when deparsing a Plan tree: */
176
  Plan     *plan;     /* immediate parent of current expression */
177
  List     *ancestors;    /* ancestors of plan */
178
  Plan     *outer_plan;   /* outer subnode, or NULL if none */
179
  Plan     *inner_plan;   /* inner subnode, or NULL if none */
180
  List     *outer_tlist;  /* referent for OUTER_VAR Vars */
181
  List     *inner_tlist;  /* referent for INNER_VAR Vars */
182
  List     *index_tlist;  /* referent for INDEX_VAR Vars */
183
  /* Special namespace representing a function signature: */
184
  char     *funcname;
185
  int     numargs;
186
  char    **argnames;
187
} deparse_namespace;
188
189
/*
190
 * Per-relation data about column alias names.
191
 *
192
 * Selecting aliases is unreasonably complicated because of the need to dump
193
 * rules/views whose underlying tables may have had columns added, deleted, or
194
 * renamed since the query was parsed.  We must nonetheless print the rule/view
195
 * in a form that can be reloaded and will produce the same results as before.
196
 *
197
 * For each RTE used in the query, we must assign column aliases that are
198
 * unique within that RTE.  SQL does not require this of the original query,
199
 * but due to factors such as *-expansion we need to be able to uniquely
200
 * reference every column in a decompiled query.  As long as we qualify all
201
 * column references, per-RTE uniqueness is sufficient for that.
202
 *
203
 * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
204
 * since they just inherit column names from their input RTEs, and we can't
205
 * rename the columns at the join level.  Most of the time this isn't an issue
206
 * because we don't need to reference the join's output columns as such; we
207
 * can reference the input columns instead.  That approach can fail for merged
208
 * JOIN USING columns, however, so when we have one of those in an unnamed
209
 * join, we have to make that column's alias globally unique across the whole
210
 * query to ensure it can be referenced unambiguously.
211
 *
212
 * Another problem is that a JOIN USING clause requires the columns to be
213
 * merged to have the same aliases in both input RTEs, and that no other
214
 * columns in those RTEs or their children conflict with the USING names.
215
 * To handle that, we do USING-column alias assignment in a recursive
216
 * traversal of the query's jointree.  When descending through a JOIN with
217
 * USING, we preassign the USING column names to the child columns, overriding
218
 * other rules for column alias assignment.  We also mark each RTE with a list
219
 * of all USING column names selected for joins containing that RTE, so that
220
 * when we assign other columns' aliases later, we can avoid conflicts.
221
 *
222
 * Another problem is that if a JOIN's input tables have had columns added or
223
 * deleted since the query was parsed, we must generate a column alias list
224
 * for the join that matches the current set of input columns --- otherwise, a
225
 * change in the number of columns in the left input would throw off matching
226
 * of aliases to columns of the right input.  Thus, positions in the printable
227
 * column alias list are not necessarily one-for-one with varattnos of the
228
 * JOIN, so we need a separate new_colnames[] array for printing purposes.
229
 *
230
 * Finally, when dealing with wide tables we risk O(N^2) costs in assigning
231
 * non-duplicate column names.  We ameliorate that by using a hash table that
232
 * holds all the strings appearing in colnames, new_colnames, and parentUsing.
233
 */
234
typedef struct
235
{
236
  /*
237
   * colnames is an array containing column aliases to use for columns that
238
   * existed when the query was parsed.  Dropped columns have NULL entries.
239
   * This array can be directly indexed by varattno to get a Var's name.
240
   *
241
   * Non-NULL entries are guaranteed unique within the RTE, *except* when
242
   * this is for an unnamed JOIN RTE.  In that case we merely copy up names
243
   * from the two input RTEs.
244
   *
245
   * During the recursive descent in set_using_names(), forcible assignment
246
   * of a child RTE's column name is represented by pre-setting that element
247
   * of the child's colnames array.  So at that stage, NULL entries in this
248
   * array just mean that no name has been preassigned, not necessarily that
249
   * the column is dropped.
250
   */
251
  int     num_cols;   /* length of colnames[] array */
252
  char    **colnames;   /* array of C strings and NULLs */
253
254
  /*
255
   * new_colnames is an array containing column aliases to use for columns
256
   * that would exist if the query was re-parsed against the current
257
   * definitions of its base tables.  This is what to print as the column
258
   * alias list for the RTE.  This array does not include dropped columns,
259
   * but it will include columns added since original parsing.  Indexes in
260
   * it therefore have little to do with current varattno values.  As above,
261
   * entries are unique unless this is for an unnamed JOIN RTE.  (In such an
262
   * RTE, we never actually print this array, but we must compute it anyway
263
   * for possible use in computing column names of upper joins.) The
264
   * parallel array is_new_col marks which of these columns are new since
265
   * original parsing.  Entries with is_new_col false must match the
266
   * non-NULL colnames entries one-for-one.
267
   */
268
  int     num_new_cols; /* length of new_colnames[] array */
269
  char    **new_colnames; /* array of C strings */
270
  bool     *is_new_col;   /* array of bool flags */
271
272
  /* This flag tells whether we should actually print a column alias list */
273
  bool    printaliases;
274
275
  /* This list has all names used as USING names in joins above this RTE */
276
  List     *parentUsing;  /* names assigned to parent merged columns */
277
278
  /*
279
   * If this struct is for a JOIN RTE, we fill these fields during the
280
   * set_using_names() pass to describe its relationship to its child RTEs.
281
   *
282
   * leftattnos and rightattnos are arrays with one entry per existing
283
   * output column of the join (hence, indexable by join varattno).  For a
284
   * simple reference to a column of the left child, leftattnos[i] is the
285
   * child RTE's attno and rightattnos[i] is zero; and conversely for a
286
   * column of the right child.  But for merged columns produced by JOIN
287
   * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
288
   * Note that a simple reference might be to a child RTE column that's been
289
   * dropped; but that's OK since the column could not be used in the query.
290
   *
291
   * If it's a JOIN USING, usingNames holds the alias names selected for the
292
   * merged columns (these might be different from the original USING list,
293
   * if we had to modify names to achieve uniqueness).
294
   */
295
  int     leftrti;    /* rangetable index of left child */
296
  int     rightrti;   /* rangetable index of right child */
297
  int      *leftattnos;   /* left-child varattnos of join cols, or 0 */
298
  int      *rightattnos;  /* right-child varattnos of join cols, or 0 */
299
  List     *usingNames;   /* names assigned to merged columns */
300
301
  /*
302
   * Hash table holding copies of all the strings appearing in this struct's
303
   * colnames, new_colnames, and parentUsing.  We use a hash table only for
304
   * sufficiently wide relations, and only during the colname-assignment
305
   * functions set_relation_column_names and set_join_column_names;
306
   * otherwise, names_hash is NULL.
307
   */
308
  HTAB     *names_hash;   /* entries are just strings */
309
} deparse_columns;
310
311
/* This macro is analogous to rt_fetch(), but for deparse_columns structs */
312
#define deparse_columns_fetch(rangetable_index, dpns) \
313
0
  ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
314
315
/*
316
 * Entry in set_rtable_names' hash table
317
 */
318
typedef struct
319
{
320
  char    name[NAMEDATALEN];  /* Hash key --- must be first */
321
  int     counter;    /* Largest addition used so far for name */
322
} NameHashEntry;
323
324
/* Callback signature for resolve_special_varno() */
325
typedef void (*rsv_callback) (Node *node, deparse_context *context,
326
                void *callback_arg);
327
328
329
/* ----------
330
 * Global data
331
 * ----------
332
 */
333
static SPIPlanPtr plan_getrulebyoid = NULL;
334
static const char *const query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
335
static SPIPlanPtr plan_getviewrule = NULL;
336
static const char *const query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
337
338
/* GUC parameters */
339
bool    quote_all_identifiers = false;
340
341
342
/* ----------
343
 * Local functions
344
 *
345
 * Most of these functions used to use fixed-size buffers to build their
346
 * results.  Now, they take an (already initialized) StringInfo object
347
 * as a parameter, and append their text output to its contents.
348
 * ----------
349
 */
350
static char *deparse_expression_pretty(Node *expr, List *dpcontext,
351
                     bool forceprefix, bool showimplicit,
352
                     int prettyFlags, int startIndent);
353
static char *pg_get_viewdef_worker(Oid viewoid,
354
                   int prettyFlags, int wrapColumn);
355
static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
356
static int  decompile_column_index_array(Datum column_index_array, Oid relId,
357
                     bool withPeriod, StringInfo buf);
358
static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
359
static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
360
                  const Oid *excludeOps,
361
                  bool attrsOnly, bool keysOnly,
362
                  bool showTblSpc, bool inherits,
363
                  int prettyFlags, bool missing_ok);
364
static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
365
                     bool missing_ok);
366
static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
367
                    bool attrsOnly, bool missing_ok);
368
static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
369
                     int prettyFlags, bool missing_ok);
370
static text *pg_get_expr_worker(text *expr, Oid relid, int prettyFlags);
371
static int  print_function_arguments(StringInfo buf, HeapTuple proctup,
372
                   bool print_table_args, bool print_defaults);
373
static void print_function_rettype(StringInfo buf, HeapTuple proctup);
374
static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
375
static void print_function_sqlbody(StringInfo buf, HeapTuple proctup);
376
static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
377
               Bitmapset *rels_used);
378
static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
379
                  List *parent_namespaces);
380
static void set_simple_column_names(deparse_namespace *dpns);
381
static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
382
static void set_using_names(deparse_namespace *dpns, Node *jtnode,
383
              List *parentUsing);
384
static void set_relation_column_names(deparse_namespace *dpns,
385
                    RangeTblEntry *rte,
386
                    deparse_columns *colinfo);
387
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
388
                  deparse_columns *colinfo);
389
static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
390
                deparse_columns *colinfo);
391
static char *make_colname_unique(char *colname, deparse_namespace *dpns,
392
                 deparse_columns *colinfo);
393
static void expand_colnames_array_to(deparse_columns *colinfo, int n);
394
static void build_colinfo_names_hash(deparse_columns *colinfo);
395
static void add_to_names_hash(deparse_columns *colinfo, const char *name);
396
static void destroy_colinfo_names_hash(deparse_columns *colinfo);
397
static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
398
                  deparse_columns *colinfo);
399
static char *get_rtable_name(int rtindex, deparse_context *context);
400
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
401
static Plan *find_recursive_union(deparse_namespace *dpns,
402
                  WorkTableScan *wtscan);
403
static void push_child_plan(deparse_namespace *dpns, Plan *plan,
404
              deparse_namespace *save_dpns);
405
static void pop_child_plan(deparse_namespace *dpns,
406
               deparse_namespace *save_dpns);
407
static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
408
                 deparse_namespace *save_dpns);
409
static void pop_ancestor_plan(deparse_namespace *dpns,
410
                deparse_namespace *save_dpns);
411
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
412
             int prettyFlags);
413
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
414
             int prettyFlags, int wrapColumn);
415
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
416
              TupleDesc resultDesc, bool colNamesVisible,
417
              int prettyFlags, int wrapColumn, int startIndent);
418
static void get_values_def(List *values_lists, deparse_context *context);
419
static void get_with_clause(Query *query, deparse_context *context);
420
static void get_select_query_def(Query *query, deparse_context *context);
421
static void get_insert_query_def(Query *query, deparse_context *context);
422
static void get_update_query_def(Query *query, deparse_context *context);
423
static void get_update_query_targetlist_def(Query *query, List *targetList,
424
                      deparse_context *context,
425
                      RangeTblEntry *rte);
426
static void get_delete_query_def(Query *query, deparse_context *context);
427
static void get_merge_query_def(Query *query, deparse_context *context);
428
static void get_utility_query_def(Query *query, deparse_context *context);
429
static char *get_lock_clause_strength(LockClauseStrength strength);
430
static void get_basic_select_query(Query *query, deparse_context *context);
431
static void get_target_list(List *targetList, deparse_context *context);
432
static void get_returning_clause(Query *query, deparse_context *context);
433
static void get_setop_query(Node *setOp, Query *query,
434
              deparse_context *context);
435
static Node *get_rule_sortgroupclause(Index ref, List *tlist,
436
                    bool force_colno,
437
                    deparse_context *context);
438
static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
439
                 bool omit_parens, deparse_context *context);
440
static void get_rule_orderby(List *orderList, List *targetList,
441
               bool force_colno, deparse_context *context);
442
static void get_rule_windowclause(Query *query, deparse_context *context);
443
static void get_rule_windowspec(WindowClause *wc, List *targetList,
444
                deparse_context *context);
445
static void get_window_frame_options(int frameOptions,
446
                   Node *startOffset, Node *endOffset,
447
                   deparse_context *context);
448
static char *get_variable(Var *var, int levelsup, bool istoplevel,
449
              deparse_context *context);
450
static void get_special_variable(Node *node, deparse_context *context,
451
                 void *callback_arg);
452
static void resolve_special_varno(Node *node, deparse_context *context,
453
                  rsv_callback callback, void *callback_arg);
454
static Node *find_param_referent(Param *param, deparse_context *context,
455
                 deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
456
static SubPlan *find_param_generator(Param *param, deparse_context *context,
457
                   int *column_p);
458
static SubPlan *find_param_generator_initplan(Param *param, Plan *plan,
459
                        int *column_p);
460
static void get_parameter(Param *param, deparse_context *context);
461
static const char *get_simple_binary_op_name(OpExpr *expr);
462
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
463
static void appendContextKeyword(deparse_context *context, const char *str,
464
                 int indentBefore, int indentAfter, int indentPlus);
465
static void removeStringInfoSpaces(StringInfo str);
466
static void get_rule_expr(Node *node, deparse_context *context,
467
              bool showimplicit);
468
static void get_rule_expr_toplevel(Node *node, deparse_context *context,
469
                   bool showimplicit);
470
static void get_rule_list_toplevel(List *lst, deparse_context *context,
471
                   bool showimplicit);
472
static void get_rule_expr_funccall(Node *node, deparse_context *context,
473
                   bool showimplicit);
474
static bool looks_like_function(Node *node);
475
static void get_oper_expr(OpExpr *expr, deparse_context *context);
476
static void get_func_expr(FuncExpr *expr, deparse_context *context,
477
              bool showimplicit);
478
static void get_agg_expr(Aggref *aggref, deparse_context *context,
479
             Aggref *original_aggref);
480
static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
481
                Aggref *original_aggref, const char *funcname,
482
                const char *options, bool is_json_objectagg);
483
static void get_agg_combine_expr(Node *node, deparse_context *context,
484
                 void *callback_arg);
485
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
486
static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
487
                     const char *funcname, const char *options,
488
                     bool is_json_objectagg);
489
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
490
static void get_coercion_expr(Node *arg, deparse_context *context,
491
                Oid resulttype, int32 resulttypmod,
492
                Node *parentNode);
493
static void get_const_expr(Const *constval, deparse_context *context,
494
               int showtype);
495
static void get_const_collation(Const *constval, deparse_context *context);
496
static void get_json_format(JsonFormat *format, StringInfo buf);
497
static void get_json_returning(JsonReturning *returning, StringInfo buf,
498
                 bool json_format_by_default);
499
static void get_json_constructor(JsonConstructorExpr *ctor,
500
                 deparse_context *context, bool showimplicit);
501
static void get_json_constructor_options(JsonConstructorExpr *ctor,
502
                     StringInfo buf);
503
static void get_json_agg_constructor(JsonConstructorExpr *ctor,
504
                   deparse_context *context,
505
                   const char *funcname,
506
                   bool is_json_objectagg);
507
static void get_json_agg_constructor_expr(Node *node, deparse_context *context,
508
                      void *callback_arg);
509
static void simple_quote_literal(StringInfo buf, const char *val);
510
static void get_sublink_expr(SubLink *sublink, deparse_context *context);
511
static void get_tablefunc(TableFunc *tf, deparse_context *context,
512
              bool showimplicit);
513
static void get_from_clause(Query *query, const char *prefix,
514
              deparse_context *context);
515
static void get_from_clause_item(Node *jtnode, Query *query,
516
                 deparse_context *context);
517
static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
518
              deparse_context *context);
519
static void get_column_alias_list(deparse_columns *colinfo,
520
                  deparse_context *context);
521
static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
522
                     deparse_columns *colinfo,
523
                     deparse_context *context);
524
static void get_tablesample_def(TableSampleClause *tablesample,
525
                deparse_context *context);
526
static void get_opclass_name(Oid opclass, Oid actual_datatype,
527
               StringInfo buf);
528
static Node *processIndirection(Node *node, deparse_context *context);
529
static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
530
static char *get_relation_name(Oid relid);
531
static char *generate_relation_name(Oid relid, List *namespaces);
532
static char *generate_qualified_relation_name(Oid relid);
533
static char *generate_function_name(Oid funcid, int nargs,
534
                  List *argnames, Oid *argtypes,
535
                  bool has_variadic, bool *use_variadic_p,
536
                  bool inGroupBy);
537
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
538
static void add_cast_to(StringInfo buf, Oid typid);
539
static char *generate_qualified_type_name(Oid typid);
540
static text *string_to_text(char *str);
541
static char *flatten_reloptions(Oid relid);
542
void    get_reloptions(StringInfo buf, Datum reloptions);
543
static void get_json_path_spec(Node *path_spec, deparse_context *context,
544
                 bool showimplicit);
545
static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan,
546
                   deparse_context *context,
547
                   bool showimplicit);
548
static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
549
                      deparse_context *context,
550
                      bool showimplicit,
551
                      bool needcomma);
552
553
0
#define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
554
555
556
/* ----------
557
 * pg_get_ruledef   - Do it all and return a text
558
 *          that could be used as a statement
559
 *          to recreate the rule
560
 * ----------
561
 */
562
Datum
563
pg_get_ruledef(PG_FUNCTION_ARGS)
564
0
{
565
0
  Oid     ruleoid = PG_GETARG_OID(0);
566
0
  int     prettyFlags;
567
0
  char     *res;
568
569
0
  prettyFlags = PRETTYFLAG_INDENT;
570
571
0
  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
572
573
0
  if (res == NULL)
574
0
    PG_RETURN_NULL();
575
576
0
  PG_RETURN_TEXT_P(string_to_text(res));
577
0
}
578
579
580
Datum
581
pg_get_ruledef_ext(PG_FUNCTION_ARGS)
582
0
{
583
0
  Oid     ruleoid = PG_GETARG_OID(0);
584
0
  bool    pretty = PG_GETARG_BOOL(1);
585
0
  int     prettyFlags;
586
0
  char     *res;
587
588
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
589
590
0
  res = pg_get_ruledef_worker(ruleoid, prettyFlags);
591
592
0
  if (res == NULL)
593
0
    PG_RETURN_NULL();
594
595
0
  PG_RETURN_TEXT_P(string_to_text(res));
596
0
}
597
598
599
static char *
600
pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
601
0
{
602
0
  Datum   args[1];
603
0
  char    nulls[1];
604
0
  int     spirc;
605
0
  HeapTuple ruletup;
606
0
  TupleDesc rulettc;
607
0
  StringInfoData buf;
608
609
  /*
610
   * Do this first so that string is alloc'd in outer context not SPI's.
611
   */
612
0
  initStringInfo(&buf);
613
614
  /*
615
   * Connect to SPI manager
616
   */
617
0
  SPI_connect();
618
619
  /*
620
   * On the first call prepare the plan to lookup pg_rewrite. We read
621
   * pg_rewrite over the SPI manager instead of using the syscache to be
622
   * checked for read access on pg_rewrite.
623
   */
624
0
  if (plan_getrulebyoid == NULL)
625
0
  {
626
0
    Oid     argtypes[1];
627
0
    SPIPlanPtr  plan;
628
629
0
    argtypes[0] = OIDOID;
630
0
    plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
631
0
    if (plan == NULL)
632
0
      elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
633
0
    SPI_keepplan(plan);
634
0
    plan_getrulebyoid = plan;
635
0
  }
636
637
  /*
638
   * Get the pg_rewrite tuple for this rule
639
   */
640
0
  args[0] = ObjectIdGetDatum(ruleoid);
641
0
  nulls[0] = ' ';
642
0
  spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
643
0
  if (spirc != SPI_OK_SELECT)
644
0
    elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
645
0
  if (SPI_processed != 1)
646
0
  {
647
    /*
648
     * There is no tuple data available here, just keep the output buffer
649
     * empty.
650
     */
651
0
  }
652
0
  else
653
0
  {
654
    /*
655
     * Get the rule's definition and put it into executor's memory
656
     */
657
0
    ruletup = SPI_tuptable->vals[0];
658
0
    rulettc = SPI_tuptable->tupdesc;
659
0
    make_ruledef(&buf, ruletup, rulettc, prettyFlags);
660
0
  }
661
662
  /*
663
   * Disconnect from SPI manager
664
   */
665
0
  if (SPI_finish() != SPI_OK_FINISH)
666
0
    elog(ERROR, "SPI_finish failed");
667
668
0
  if (buf.len == 0)
669
0
    return NULL;
670
671
0
  return buf.data;
672
0
}
673
674
675
/* ----------
676
 * pg_get_viewdef   - Mainly the same thing, but we
677
 *          only return the SELECT part of a view
678
 * ----------
679
 */
680
Datum
681
pg_get_viewdef(PG_FUNCTION_ARGS)
682
0
{
683
  /* By OID */
684
0
  Oid     viewoid = PG_GETARG_OID(0);
685
0
  int     prettyFlags;
686
0
  char     *res;
687
688
0
  prettyFlags = PRETTYFLAG_INDENT;
689
690
0
  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
691
692
0
  if (res == NULL)
693
0
    PG_RETURN_NULL();
694
695
0
  PG_RETURN_TEXT_P(string_to_text(res));
696
0
}
697
698
699
Datum
700
pg_get_viewdef_ext(PG_FUNCTION_ARGS)
701
0
{
702
  /* By OID */
703
0
  Oid     viewoid = PG_GETARG_OID(0);
704
0
  bool    pretty = PG_GETARG_BOOL(1);
705
0
  int     prettyFlags;
706
0
  char     *res;
707
708
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
709
710
0
  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
711
712
0
  if (res == NULL)
713
0
    PG_RETURN_NULL();
714
715
0
  PG_RETURN_TEXT_P(string_to_text(res));
716
0
}
717
718
Datum
719
pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
720
0
{
721
  /* By OID */
722
0
  Oid     viewoid = PG_GETARG_OID(0);
723
0
  int     wrap = PG_GETARG_INT32(1);
724
0
  int     prettyFlags;
725
0
  char     *res;
726
727
  /* calling this implies we want pretty printing */
728
0
  prettyFlags = GET_PRETTY_FLAGS(true);
729
730
0
  res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
731
732
0
  if (res == NULL)
733
0
    PG_RETURN_NULL();
734
735
0
  PG_RETURN_TEXT_P(string_to_text(res));
736
0
}
737
738
Datum
739
pg_get_viewdef_name(PG_FUNCTION_ARGS)
740
0
{
741
  /* By qualified name */
742
0
  text     *viewname = PG_GETARG_TEXT_PP(0);
743
0
  int     prettyFlags;
744
0
  RangeVar   *viewrel;
745
0
  Oid     viewoid;
746
0
  char     *res;
747
748
0
  prettyFlags = PRETTYFLAG_INDENT;
749
750
  /* Look up view name.  Can't lock it - we might not have privileges. */
751
0
  viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
752
0
  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
753
754
0
  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
755
756
0
  if (res == NULL)
757
0
    PG_RETURN_NULL();
758
759
0
  PG_RETURN_TEXT_P(string_to_text(res));
760
0
}
761
762
763
Datum
764
pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
765
0
{
766
  /* By qualified name */
767
0
  text     *viewname = PG_GETARG_TEXT_PP(0);
768
0
  bool    pretty = PG_GETARG_BOOL(1);
769
0
  int     prettyFlags;
770
0
  RangeVar   *viewrel;
771
0
  Oid     viewoid;
772
0
  char     *res;
773
774
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
775
776
  /* Look up view name.  Can't lock it - we might not have privileges. */
777
0
  viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
778
0
  viewoid = RangeVarGetRelid(viewrel, NoLock, false);
779
780
0
  res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
781
782
0
  if (res == NULL)
783
0
    PG_RETURN_NULL();
784
785
0
  PG_RETURN_TEXT_P(string_to_text(res));
786
0
}
787
788
/*
789
 * Common code for by-OID and by-name variants of pg_get_viewdef
790
 */
791
static char *
792
pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
793
0
{
794
0
  Datum   args[2];
795
0
  char    nulls[2];
796
0
  int     spirc;
797
0
  HeapTuple ruletup;
798
0
  TupleDesc rulettc;
799
0
  StringInfoData buf;
800
801
  /*
802
   * Do this first so that string is alloc'd in outer context not SPI's.
803
   */
804
0
  initStringInfo(&buf);
805
806
  /*
807
   * Connect to SPI manager
808
   */
809
0
  SPI_connect();
810
811
  /*
812
   * On the first call prepare the plan to lookup pg_rewrite. We read
813
   * pg_rewrite over the SPI manager instead of using the syscache to be
814
   * checked for read access on pg_rewrite.
815
   */
816
0
  if (plan_getviewrule == NULL)
817
0
  {
818
0
    Oid     argtypes[2];
819
0
    SPIPlanPtr  plan;
820
821
0
    argtypes[0] = OIDOID;
822
0
    argtypes[1] = NAMEOID;
823
0
    plan = SPI_prepare(query_getviewrule, 2, argtypes);
824
0
    if (plan == NULL)
825
0
      elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
826
0
    SPI_keepplan(plan);
827
0
    plan_getviewrule = plan;
828
0
  }
829
830
  /*
831
   * Get the pg_rewrite tuple for the view's SELECT rule
832
   */
833
0
  args[0] = ObjectIdGetDatum(viewoid);
834
0
  args[1] = DirectFunctionCall1(namein, CStringGetDatum(ViewSelectRuleName));
835
0
  nulls[0] = ' ';
836
0
  nulls[1] = ' ';
837
0
  spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
838
0
  if (spirc != SPI_OK_SELECT)
839
0
    elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
840
0
  if (SPI_processed != 1)
841
0
  {
842
    /*
843
     * There is no tuple data available here, just keep the output buffer
844
     * empty.
845
     */
846
0
  }
847
0
  else
848
0
  {
849
    /*
850
     * Get the rule's definition and put it into executor's memory
851
     */
852
0
    ruletup = SPI_tuptable->vals[0];
853
0
    rulettc = SPI_tuptable->tupdesc;
854
0
    make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
855
0
  }
856
857
  /*
858
   * Disconnect from SPI manager
859
   */
860
0
  if (SPI_finish() != SPI_OK_FINISH)
861
0
    elog(ERROR, "SPI_finish failed");
862
863
0
  if (buf.len == 0)
864
0
    return NULL;
865
866
0
  return buf.data;
867
0
}
868
869
/* ----------
870
 * pg_get_triggerdef    - Get the definition of a trigger
871
 * ----------
872
 */
873
Datum
874
pg_get_triggerdef(PG_FUNCTION_ARGS)
875
0
{
876
0
  Oid     trigid = PG_GETARG_OID(0);
877
0
  char     *res;
878
879
0
  res = pg_get_triggerdef_worker(trigid, false);
880
881
0
  if (res == NULL)
882
0
    PG_RETURN_NULL();
883
884
0
  PG_RETURN_TEXT_P(string_to_text(res));
885
0
}
886
887
Datum
888
pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
889
0
{
890
0
  Oid     trigid = PG_GETARG_OID(0);
891
0
  bool    pretty = PG_GETARG_BOOL(1);
892
0
  char     *res;
893
894
0
  res = pg_get_triggerdef_worker(trigid, pretty);
895
896
0
  if (res == NULL)
897
0
    PG_RETURN_NULL();
898
899
0
  PG_RETURN_TEXT_P(string_to_text(res));
900
0
}
901
902
static char *
903
pg_get_triggerdef_worker(Oid trigid, bool pretty)
904
0
{
905
0
  HeapTuple ht_trig;
906
0
  Form_pg_trigger trigrec;
907
0
  StringInfoData buf;
908
0
  Relation  tgrel;
909
0
  ScanKeyData skey[1];
910
0
  SysScanDesc tgscan;
911
0
  int     findx = 0;
912
0
  char     *tgname;
913
0
  char     *tgoldtable;
914
0
  char     *tgnewtable;
915
0
  Datum   value;
916
0
  bool    isnull;
917
918
  /*
919
   * Fetch the pg_trigger tuple by the Oid of the trigger
920
   */
921
0
  tgrel = table_open(TriggerRelationId, AccessShareLock);
922
923
0
  ScanKeyInit(&skey[0],
924
0
        Anum_pg_trigger_oid,
925
0
        BTEqualStrategyNumber, F_OIDEQ,
926
0
        ObjectIdGetDatum(trigid));
927
928
0
  tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
929
0
                NULL, 1, skey);
930
931
0
  ht_trig = systable_getnext(tgscan);
932
933
0
  if (!HeapTupleIsValid(ht_trig))
934
0
  {
935
0
    systable_endscan(tgscan);
936
0
    table_close(tgrel, AccessShareLock);
937
0
    return NULL;
938
0
  }
939
940
0
  trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
941
942
  /*
943
   * Start the trigger definition. Note that the trigger's name should never
944
   * be schema-qualified, but the trigger rel's name may be.
945
   */
946
0
  initStringInfo(&buf);
947
948
0
  tgname = NameStr(trigrec->tgname);
949
0
  appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
950
0
           OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
951
0
           quote_identifier(tgname));
952
953
0
  if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
954
0
    appendStringInfoString(&buf, "BEFORE");
955
0
  else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
956
0
    appendStringInfoString(&buf, "AFTER");
957
0
  else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
958
0
    appendStringInfoString(&buf, "INSTEAD OF");
959
0
  else
960
0
    elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
961
962
0
  if (TRIGGER_FOR_INSERT(trigrec->tgtype))
963
0
  {
964
0
    appendStringInfoString(&buf, " INSERT");
965
0
    findx++;
966
0
  }
967
0
  if (TRIGGER_FOR_DELETE(trigrec->tgtype))
968
0
  {
969
0
    if (findx > 0)
970
0
      appendStringInfoString(&buf, " OR DELETE");
971
0
    else
972
0
      appendStringInfoString(&buf, " DELETE");
973
0
    findx++;
974
0
  }
975
0
  if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
976
0
  {
977
0
    if (findx > 0)
978
0
      appendStringInfoString(&buf, " OR UPDATE");
979
0
    else
980
0
      appendStringInfoString(&buf, " UPDATE");
981
0
    findx++;
982
    /* tgattr is first var-width field, so OK to access directly */
983
0
    if (trigrec->tgattr.dim1 > 0)
984
0
    {
985
0
      int     i;
986
987
0
      appendStringInfoString(&buf, " OF ");
988
0
      for (i = 0; i < trigrec->tgattr.dim1; i++)
989
0
      {
990
0
        char     *attname;
991
992
0
        if (i > 0)
993
0
          appendStringInfoString(&buf, ", ");
994
0
        attname = get_attname(trigrec->tgrelid,
995
0
                    trigrec->tgattr.values[i], false);
996
0
        appendStringInfoString(&buf, quote_identifier(attname));
997
0
      }
998
0
    }
999
0
  }
1000
0
  if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
1001
0
  {
1002
0
    if (findx > 0)
1003
0
      appendStringInfoString(&buf, " OR TRUNCATE");
1004
0
    else
1005
0
      appendStringInfoString(&buf, " TRUNCATE");
1006
0
    findx++;
1007
0
  }
1008
1009
  /*
1010
   * In non-pretty mode, always schema-qualify the target table name for
1011
   * safety.  In pretty mode, schema-qualify only if not visible.
1012
   */
1013
0
  appendStringInfo(&buf, " ON %s ",
1014
0
           pretty ?
1015
0
           generate_relation_name(trigrec->tgrelid, NIL) :
1016
0
           generate_qualified_relation_name(trigrec->tgrelid));
1017
1018
0
  if (OidIsValid(trigrec->tgconstraint))
1019
0
  {
1020
0
    if (OidIsValid(trigrec->tgconstrrelid))
1021
0
      appendStringInfo(&buf, "FROM %s ",
1022
0
               generate_relation_name(trigrec->tgconstrrelid, NIL));
1023
0
    if (!trigrec->tgdeferrable)
1024
0
      appendStringInfoString(&buf, "NOT ");
1025
0
    appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
1026
0
    if (trigrec->tginitdeferred)
1027
0
      appendStringInfoString(&buf, "DEFERRED ");
1028
0
    else
1029
0
      appendStringInfoString(&buf, "IMMEDIATE ");
1030
0
  }
1031
1032
0
  value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
1033
0
            tgrel->rd_att, &isnull);
1034
0
  if (!isnull)
1035
0
    tgoldtable = NameStr(*DatumGetName(value));
1036
0
  else
1037
0
    tgoldtable = NULL;
1038
0
  value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
1039
0
            tgrel->rd_att, &isnull);
1040
0
  if (!isnull)
1041
0
    tgnewtable = NameStr(*DatumGetName(value));
1042
0
  else
1043
0
    tgnewtable = NULL;
1044
0
  if (tgoldtable != NULL || tgnewtable != NULL)
1045
0
  {
1046
0
    appendStringInfoString(&buf, "REFERENCING ");
1047
0
    if (tgoldtable != NULL)
1048
0
      appendStringInfo(&buf, "OLD TABLE AS %s ",
1049
0
               quote_identifier(tgoldtable));
1050
0
    if (tgnewtable != NULL)
1051
0
      appendStringInfo(&buf, "NEW TABLE AS %s ",
1052
0
               quote_identifier(tgnewtable));
1053
0
  }
1054
1055
0
  if (TRIGGER_FOR_ROW(trigrec->tgtype))
1056
0
    appendStringInfoString(&buf, "FOR EACH ROW ");
1057
0
  else
1058
0
    appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1059
1060
  /* If the trigger has a WHEN qualification, add that */
1061
0
  value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
1062
0
            tgrel->rd_att, &isnull);
1063
0
  if (!isnull)
1064
0
  {
1065
0
    Node     *qual;
1066
0
    char    relkind;
1067
0
    deparse_context context;
1068
0
    deparse_namespace dpns;
1069
0
    RangeTblEntry *oldrte;
1070
0
    RangeTblEntry *newrte;
1071
1072
0
    appendStringInfoString(&buf, "WHEN (");
1073
1074
0
    qual = stringToNode(TextDatumGetCString(value));
1075
1076
0
    relkind = get_rel_relkind(trigrec->tgrelid);
1077
1078
    /* Build minimal OLD and NEW RTEs for the rel */
1079
0
    oldrte = makeNode(RangeTblEntry);
1080
0
    oldrte->rtekind = RTE_RELATION;
1081
0
    oldrte->relid = trigrec->tgrelid;
1082
0
    oldrte->relkind = relkind;
1083
0
    oldrte->rellockmode = AccessShareLock;
1084
0
    oldrte->alias = makeAlias("old", NIL);
1085
0
    oldrte->eref = oldrte->alias;
1086
0
    oldrte->lateral = false;
1087
0
    oldrte->inh = false;
1088
0
    oldrte->inFromCl = true;
1089
1090
0
    newrte = makeNode(RangeTblEntry);
1091
0
    newrte->rtekind = RTE_RELATION;
1092
0
    newrte->relid = trigrec->tgrelid;
1093
0
    newrte->relkind = relkind;
1094
0
    newrte->rellockmode = AccessShareLock;
1095
0
    newrte->alias = makeAlias("new", NIL);
1096
0
    newrte->eref = newrte->alias;
1097
0
    newrte->lateral = false;
1098
0
    newrte->inh = false;
1099
0
    newrte->inFromCl = true;
1100
1101
    /* Build two-element rtable */
1102
0
    memset(&dpns, 0, sizeof(dpns));
1103
0
    dpns.rtable = list_make2(oldrte, newrte);
1104
0
    dpns.subplans = NIL;
1105
0
    dpns.ctes = NIL;
1106
0
    dpns.appendrels = NULL;
1107
0
    set_rtable_names(&dpns, NIL, NULL);
1108
0
    set_simple_column_names(&dpns);
1109
1110
    /* Set up context with one-deep namespace stack */
1111
0
    context.buf = &buf;
1112
0
    context.namespaces = list_make1(&dpns);
1113
0
    context.resultDesc = NULL;
1114
0
    context.targetList = NIL;
1115
0
    context.windowClause = NIL;
1116
0
    context.varprefix = true;
1117
0
    context.prettyFlags = GET_PRETTY_FLAGS(pretty);
1118
0
    context.wrapColumn = WRAP_COLUMN_DEFAULT;
1119
0
    context.indentLevel = PRETTYINDENT_STD;
1120
0
    context.colNamesVisible = true;
1121
0
    context.inGroupBy = false;
1122
0
    context.varInOrderBy = false;
1123
0
    context.appendparents = NULL;
1124
1125
0
    get_rule_expr(qual, &context, false);
1126
1127
0
    appendStringInfoString(&buf, ") ");
1128
0
  }
1129
1130
0
  appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1131
0
           generate_function_name(trigrec->tgfoid, 0,
1132
0
                      NIL, NULL,
1133
0
                      false, NULL, false));
1134
1135
0
  if (trigrec->tgnargs > 0)
1136
0
  {
1137
0
    char     *p;
1138
0
    int     i;
1139
1140
0
    value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1141
0
              tgrel->rd_att, &isnull);
1142
0
    if (isnull)
1143
0
      elog(ERROR, "tgargs is null for trigger %u", trigid);
1144
0
    p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1145
0
    for (i = 0; i < trigrec->tgnargs; i++)
1146
0
    {
1147
0
      if (i > 0)
1148
0
        appendStringInfoString(&buf, ", ");
1149
0
      simple_quote_literal(&buf, p);
1150
      /* advance p to next string embedded in tgargs */
1151
0
      while (*p)
1152
0
        p++;
1153
0
      p++;
1154
0
    }
1155
0
  }
1156
1157
  /* We deliberately do not put semi-colon at end */
1158
0
  appendStringInfoChar(&buf, ')');
1159
1160
  /* Clean up */
1161
0
  systable_endscan(tgscan);
1162
1163
0
  table_close(tgrel, AccessShareLock);
1164
1165
0
  return buf.data;
1166
0
}
1167
1168
/* ----------
1169
 * pg_get_indexdef      - Get the definition of an index
1170
 *
1171
 * In the extended version, there is a colno argument as well as pretty bool.
1172
 *  if colno == 0, we want a complete index definition.
1173
 *  if colno > 0, we only want the Nth index key's variable or expression.
1174
 *
1175
 * Note that the SQL-function versions of this omit any info about the
1176
 * index tablespace; this is intentional because pg_dump wants it that way.
1177
 * However pg_get_indexdef_string() includes the index tablespace.
1178
 * ----------
1179
 */
1180
Datum
1181
pg_get_indexdef(PG_FUNCTION_ARGS)
1182
0
{
1183
0
  Oid     indexrelid = PG_GETARG_OID(0);
1184
0
  int     prettyFlags;
1185
0
  char     *res;
1186
1187
0
  prettyFlags = PRETTYFLAG_INDENT;
1188
1189
0
  res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1190
0
                 false, false,
1191
0
                 false, false,
1192
0
                 prettyFlags, true);
1193
1194
0
  if (res == NULL)
1195
0
    PG_RETURN_NULL();
1196
1197
0
  PG_RETURN_TEXT_P(string_to_text(res));
1198
0
}
1199
1200
Datum
1201
pg_get_indexdef_ext(PG_FUNCTION_ARGS)
1202
0
{
1203
0
  Oid     indexrelid = PG_GETARG_OID(0);
1204
0
  int32   colno = PG_GETARG_INT32(1);
1205
0
  bool    pretty = PG_GETARG_BOOL(2);
1206
0
  int     prettyFlags;
1207
0
  char     *res;
1208
1209
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
1210
1211
0
  res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1212
0
                 colno != 0, false,
1213
0
                 false, false,
1214
0
                 prettyFlags, true);
1215
1216
0
  if (res == NULL)
1217
0
    PG_RETURN_NULL();
1218
1219
0
  PG_RETURN_TEXT_P(string_to_text(res));
1220
0
}
1221
1222
/*
1223
 * Internal version for use by ALTER TABLE.
1224
 * Includes a tablespace clause in the result.
1225
 * Returns a palloc'd C string; no pretty-printing.
1226
 */
1227
char *
1228
pg_get_indexdef_string(Oid indexrelid)
1229
0
{
1230
0
  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1231
0
                  false, false,
1232
0
                  true, true,
1233
0
                  0, false);
1234
0
}
1235
1236
/* Internal version that just reports the key-column definitions */
1237
char *
1238
pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1239
0
{
1240
0
  int     prettyFlags;
1241
1242
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
1243
1244
0
  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1245
0
                  true, true,
1246
0
                  false, false,
1247
0
                  prettyFlags, false);
1248
0
}
1249
1250
/* Internal version, extensible with flags to control its behavior */
1251
char *
1252
pg_get_indexdef_columns_extended(Oid indexrelid, uint16 flags)
1253
0
{
1254
0
  bool    pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1255
0
  bool    keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1256
0
  int     prettyFlags;
1257
1258
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
1259
1260
0
  return pg_get_indexdef_worker(indexrelid, 0, NULL,
1261
0
                  true, keys_only,
1262
0
                  false, false,
1263
0
                  prettyFlags, false);
1264
0
}
1265
1266
/*
1267
 * Internal workhorse to decompile an index definition.
1268
 *
1269
 * This is now used for exclusion constraints as well: if excludeOps is not
1270
 * NULL then it points to an array of exclusion operator OIDs.
1271
 */
1272
static char *
1273
pg_get_indexdef_worker(Oid indexrelid, int colno,
1274
             const Oid *excludeOps,
1275
             bool attrsOnly, bool keysOnly,
1276
             bool showTblSpc, bool inherits,
1277
             int prettyFlags, bool missing_ok)
1278
0
{
1279
  /* might want a separate isConstraint parameter later */
1280
0
  bool    isConstraint = (excludeOps != NULL);
1281
0
  HeapTuple ht_idx;
1282
0
  HeapTuple ht_idxrel;
1283
0
  HeapTuple ht_am;
1284
0
  Form_pg_index idxrec;
1285
0
  Form_pg_class idxrelrec;
1286
0
  Form_pg_am  amrec;
1287
0
  const IndexAmRoutine *amroutine;
1288
0
  List     *indexprs;
1289
0
  ListCell   *indexpr_item;
1290
0
  List     *context;
1291
0
  Oid     indrelid;
1292
0
  int     keyno;
1293
0
  Datum   indcollDatum;
1294
0
  Datum   indclassDatum;
1295
0
  Datum   indoptionDatum;
1296
0
  oidvector  *indcollation;
1297
0
  oidvector  *indclass;
1298
0
  int2vector *indoption;
1299
0
  StringInfoData buf;
1300
0
  char     *str;
1301
0
  char     *sep;
1302
1303
  /*
1304
   * Fetch the pg_index tuple by the Oid of the index
1305
   */
1306
0
  ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1307
0
  if (!HeapTupleIsValid(ht_idx))
1308
0
  {
1309
0
    if (missing_ok)
1310
0
      return NULL;
1311
0
    elog(ERROR, "cache lookup failed for index %u", indexrelid);
1312
0
  }
1313
0
  idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1314
1315
0
  indrelid = idxrec->indrelid;
1316
0
  Assert(indexrelid == idxrec->indexrelid);
1317
1318
  /* Must get indcollation, indclass, and indoption the hard way */
1319
0
  indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1320
0
                      Anum_pg_index_indcollation);
1321
0
  indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1322
1323
0
  indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1324
0
                       Anum_pg_index_indclass);
1325
0
  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1326
1327
0
  indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1328
0
                      Anum_pg_index_indoption);
1329
0
  indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1330
1331
  /*
1332
   * Fetch the pg_class tuple of the index relation
1333
   */
1334
0
  ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1335
0
  if (!HeapTupleIsValid(ht_idxrel))
1336
0
    elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1337
0
  idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1338
1339
  /*
1340
   * Fetch the pg_am tuple of the index' access method
1341
   */
1342
0
  ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1343
0
  if (!HeapTupleIsValid(ht_am))
1344
0
    elog(ERROR, "cache lookup failed for access method %u",
1345
0
       idxrelrec->relam);
1346
0
  amrec = (Form_pg_am) GETSTRUCT(ht_am);
1347
1348
  /* Fetch the index AM's API struct */
1349
0
  amroutine = GetIndexAmRoutine(amrec->amhandler);
1350
1351
  /*
1352
   * Get the index expressions, if any.  (NOTE: we do not use the relcache
1353
   * versions of the expressions and predicate, because we want to display
1354
   * non-const-folded expressions.)
1355
   */
1356
0
  if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
1357
0
  {
1358
0
    Datum   exprsDatum;
1359
0
    char     *exprsString;
1360
1361
0
    exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1362
0
                      Anum_pg_index_indexprs);
1363
0
    exprsString = TextDatumGetCString(exprsDatum);
1364
0
    indexprs = (List *) stringToNode(exprsString);
1365
0
    pfree(exprsString);
1366
0
  }
1367
0
  else
1368
0
    indexprs = NIL;
1369
1370
0
  indexpr_item = list_head(indexprs);
1371
1372
0
  context = deparse_context_for(get_relation_name(indrelid), indrelid);
1373
1374
  /*
1375
   * Start the index definition.  Note that the index's name should never be
1376
   * schema-qualified, but the indexed rel's name may be.
1377
   */
1378
0
  initStringInfo(&buf);
1379
1380
0
  if (!attrsOnly)
1381
0
  {
1382
0
    if (!isConstraint)
1383
0
      appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1384
0
               idxrec->indisunique ? "UNIQUE " : "",
1385
0
               quote_identifier(NameStr(idxrelrec->relname)),
1386
0
               idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1387
0
               && !inherits ? "ONLY " : "",
1388
0
               (prettyFlags & PRETTYFLAG_SCHEMA) ?
1389
0
               generate_relation_name(indrelid, NIL) :
1390
0
               generate_qualified_relation_name(indrelid),
1391
0
               quote_identifier(NameStr(amrec->amname)));
1392
0
    else          /* currently, must be EXCLUDE constraint */
1393
0
      appendStringInfo(&buf, "EXCLUDE USING %s (",
1394
0
               quote_identifier(NameStr(amrec->amname)));
1395
0
  }
1396
1397
  /*
1398
   * Report the indexed attributes
1399
   */
1400
0
  sep = "";
1401
0
  for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1402
0
  {
1403
0
    AttrNumber  attnum = idxrec->indkey.values[keyno];
1404
0
    Oid     keycoltype;
1405
0
    Oid     keycolcollation;
1406
1407
    /*
1408
     * Ignore non-key attributes if told to.
1409
     */
1410
0
    if (keysOnly && keyno >= idxrec->indnkeyatts)
1411
0
      break;
1412
1413
    /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1414
0
    if (!colno && keyno == idxrec->indnkeyatts)
1415
0
    {
1416
0
      appendStringInfoString(&buf, ") INCLUDE (");
1417
0
      sep = "";
1418
0
    }
1419
1420
0
    if (!colno)
1421
0
      appendStringInfoString(&buf, sep);
1422
0
    sep = ", ";
1423
1424
0
    if (attnum != 0)
1425
0
    {
1426
      /* Simple index column */
1427
0
      char     *attname;
1428
0
      int32   keycoltypmod;
1429
1430
0
      attname = get_attname(indrelid, attnum, false);
1431
0
      if (!colno || colno == keyno + 1)
1432
0
        appendStringInfoString(&buf, quote_identifier(attname));
1433
0
      get_atttypetypmodcoll(indrelid, attnum,
1434
0
                  &keycoltype, &keycoltypmod,
1435
0
                  &keycolcollation);
1436
0
    }
1437
0
    else
1438
0
    {
1439
      /* expressional index */
1440
0
      Node     *indexkey;
1441
1442
0
      if (indexpr_item == NULL)
1443
0
        elog(ERROR, "too few entries in indexprs list");
1444
0
      indexkey = (Node *) lfirst(indexpr_item);
1445
0
      indexpr_item = lnext(indexprs, indexpr_item);
1446
      /* Deparse */
1447
0
      str = deparse_expression_pretty(indexkey, context, false, false,
1448
0
                      prettyFlags, 0);
1449
0
      if (!colno || colno == keyno + 1)
1450
0
      {
1451
        /* Need parens if it's not a bare function call */
1452
0
        if (looks_like_function(indexkey))
1453
0
          appendStringInfoString(&buf, str);
1454
0
        else
1455
0
          appendStringInfo(&buf, "(%s)", str);
1456
0
      }
1457
0
      keycoltype = exprType(indexkey);
1458
0
      keycolcollation = exprCollation(indexkey);
1459
0
    }
1460
1461
    /* Print additional decoration for (selected) key columns */
1462
0
    if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1463
0
      (!colno || colno == keyno + 1))
1464
0
    {
1465
0
      int16   opt = indoption->values[keyno];
1466
0
      Oid     indcoll = indcollation->values[keyno];
1467
0
      Datum   attoptions = get_attoptions(indexrelid, keyno + 1);
1468
0
      bool    has_options = attoptions != (Datum) 0;
1469
1470
      /* Add collation, if not default for column */
1471
0
      if (OidIsValid(indcoll) && indcoll != keycolcollation)
1472
0
        appendStringInfo(&buf, " COLLATE %s",
1473
0
                 generate_collation_name((indcoll)));
1474
1475
      /* Add the operator class name, if not default */
1476
0
      get_opclass_name(indclass->values[keyno],
1477
0
               has_options ? InvalidOid : keycoltype, &buf);
1478
1479
0
      if (has_options)
1480
0
      {
1481
0
        appendStringInfoString(&buf, " (");
1482
0
        get_reloptions(&buf, attoptions);
1483
0
        appendStringInfoChar(&buf, ')');
1484
0
      }
1485
1486
      /* Add options if relevant */
1487
0
      if (amroutine->amcanorder)
1488
0
      {
1489
        /* if it supports sort ordering, report DESC and NULLS opts */
1490
0
        if (opt & INDOPTION_DESC)
1491
0
        {
1492
0
          appendStringInfoString(&buf, " DESC");
1493
          /* NULLS FIRST is the default in this case */
1494
0
          if (!(opt & INDOPTION_NULLS_FIRST))
1495
0
            appendStringInfoString(&buf, " NULLS LAST");
1496
0
        }
1497
0
        else
1498
0
        {
1499
0
          if (opt & INDOPTION_NULLS_FIRST)
1500
0
            appendStringInfoString(&buf, " NULLS FIRST");
1501
0
        }
1502
0
      }
1503
1504
      /* Add the exclusion operator if relevant */
1505
0
      if (excludeOps != NULL)
1506
0
        appendStringInfo(&buf, " WITH %s",
1507
0
                 generate_operator_name(excludeOps[keyno],
1508
0
                            keycoltype,
1509
0
                            keycoltype));
1510
0
    }
1511
0
  }
1512
1513
0
  if (!attrsOnly)
1514
0
  {
1515
0
    appendStringInfoChar(&buf, ')');
1516
1517
0
    if (idxrec->indnullsnotdistinct)
1518
0
      appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1519
1520
    /*
1521
     * If it has options, append "WITH (options)"
1522
     */
1523
0
    str = flatten_reloptions(indexrelid);
1524
0
    if (str)
1525
0
    {
1526
0
      appendStringInfo(&buf, " WITH (%s)", str);
1527
0
      pfree(str);
1528
0
    }
1529
1530
    /*
1531
     * Print tablespace, but only if requested
1532
     */
1533
0
    if (showTblSpc)
1534
0
    {
1535
0
      Oid     tblspc;
1536
1537
0
      tblspc = get_rel_tablespace(indexrelid);
1538
0
      if (OidIsValid(tblspc))
1539
0
      {
1540
0
        if (isConstraint)
1541
0
          appendStringInfoString(&buf, " USING INDEX");
1542
0
        appendStringInfo(&buf, " TABLESPACE %s",
1543
0
                 quote_identifier(get_tablespace_name(tblspc)));
1544
0
      }
1545
0
    }
1546
1547
    /*
1548
     * If it's a partial index, decompile and append the predicate
1549
     */
1550
0
    if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
1551
0
    {
1552
0
      Node     *node;
1553
0
      Datum   predDatum;
1554
0
      char     *predString;
1555
1556
      /* Convert text string to node tree */
1557
0
      predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1558
0
                         Anum_pg_index_indpred);
1559
0
      predString = TextDatumGetCString(predDatum);
1560
0
      node = (Node *) stringToNode(predString);
1561
0
      pfree(predString);
1562
1563
      /* Deparse */
1564
0
      str = deparse_expression_pretty(node, context, false, false,
1565
0
                      prettyFlags, 0);
1566
0
      if (isConstraint)
1567
0
        appendStringInfo(&buf, " WHERE (%s)", str);
1568
0
      else
1569
0
        appendStringInfo(&buf, " WHERE %s", str);
1570
0
    }
1571
0
  }
1572
1573
  /* Clean up */
1574
0
  ReleaseSysCache(ht_idx);
1575
0
  ReleaseSysCache(ht_idxrel);
1576
0
  ReleaseSysCache(ht_am);
1577
1578
0
  return buf.data;
1579
0
}
1580
1581
/* ----------
1582
 * pg_get_querydef
1583
 *
1584
 * Public entry point to deparse one query parsetree.
1585
 * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1586
 *
1587
 * The result is a palloc'd C string.
1588
 * ----------
1589
 */
1590
char *
1591
pg_get_querydef(Query *query, bool pretty)
1592
0
{
1593
0
  StringInfoData buf;
1594
0
  int     prettyFlags;
1595
1596
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
1597
1598
0
  initStringInfo(&buf);
1599
1600
0
  get_query_def(query, &buf, NIL, NULL, true,
1601
0
          prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1602
1603
0
  return buf.data;
1604
0
}
1605
1606
/*
1607
 * pg_get_statisticsobjdef
1608
 *    Get the definition of an extended statistics object
1609
 */
1610
Datum
1611
pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
1612
0
{
1613
0
  Oid     statextid = PG_GETARG_OID(0);
1614
0
  char     *res;
1615
1616
0
  res = pg_get_statisticsobj_worker(statextid, false, true);
1617
1618
0
  if (res == NULL)
1619
0
    PG_RETURN_NULL();
1620
1621
0
  PG_RETURN_TEXT_P(string_to_text(res));
1622
0
}
1623
1624
/*
1625
 * Internal version for use by ALTER TABLE.
1626
 * Returns a palloc'd C string; no pretty-printing.
1627
 */
1628
char *
1629
pg_get_statisticsobjdef_string(Oid statextid)
1630
0
{
1631
0
  return pg_get_statisticsobj_worker(statextid, false, false);
1632
0
}
1633
1634
/*
1635
 * pg_get_statisticsobjdef_columns
1636
 *    Get columns and expressions for an extended statistics object
1637
 */
1638
Datum
1639
pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
1640
0
{
1641
0
  Oid     statextid = PG_GETARG_OID(0);
1642
0
  char     *res;
1643
1644
0
  res = pg_get_statisticsobj_worker(statextid, true, true);
1645
1646
0
  if (res == NULL)
1647
0
    PG_RETURN_NULL();
1648
1649
0
  PG_RETURN_TEXT_P(string_to_text(res));
1650
0
}
1651
1652
/*
1653
 * Internal workhorse to decompile an extended statistics object.
1654
 */
1655
static char *
1656
pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
1657
0
{
1658
0
  Form_pg_statistic_ext statextrec;
1659
0
  HeapTuple statexttup;
1660
0
  StringInfoData buf;
1661
0
  int     colno;
1662
0
  char     *nsp;
1663
0
  ArrayType  *arr;
1664
0
  char     *enabled;
1665
0
  Datum   datum;
1666
0
  bool    ndistinct_enabled;
1667
0
  bool    dependencies_enabled;
1668
0
  bool    mcv_enabled;
1669
0
  int     i;
1670
0
  List     *context;
1671
0
  ListCell   *lc;
1672
0
  List     *exprs = NIL;
1673
0
  bool    has_exprs;
1674
0
  int     ncolumns;
1675
1676
0
  statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1677
1678
0
  if (!HeapTupleIsValid(statexttup))
1679
0
  {
1680
0
    if (missing_ok)
1681
0
      return NULL;
1682
0
    elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1683
0
  }
1684
1685
  /* has the statistics expressions? */
1686
0
  has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1687
1688
0
  statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1689
1690
  /*
1691
   * Get the statistics expressions, if any.  (NOTE: we do not use the
1692
   * relcache versions of the expressions, because we want to display
1693
   * non-const-folded expressions.)
1694
   */
1695
0
  if (has_exprs)
1696
0
  {
1697
0
    Datum   exprsDatum;
1698
0
    char     *exprsString;
1699
1700
0
    exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1701
0
                      Anum_pg_statistic_ext_stxexprs);
1702
0
    exprsString = TextDatumGetCString(exprsDatum);
1703
0
    exprs = (List *) stringToNode(exprsString);
1704
0
    pfree(exprsString);
1705
0
  }
1706
0
  else
1707
0
    exprs = NIL;
1708
1709
  /* count the number of columns (attributes and expressions) */
1710
0
  ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1711
1712
0
  initStringInfo(&buf);
1713
1714
0
  if (!columns_only)
1715
0
  {
1716
0
    nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
1717
0
    appendStringInfo(&buf, "CREATE STATISTICS %s",
1718
0
             quote_qualified_identifier(nsp,
1719
0
                          NameStr(statextrec->stxname)));
1720
1721
    /*
1722
     * Decode the stxkind column so that we know which stats types to
1723
     * print.
1724
     */
1725
0
    datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1726
0
                     Anum_pg_statistic_ext_stxkind);
1727
0
    arr = DatumGetArrayTypeP(datum);
1728
0
    if (ARR_NDIM(arr) != 1 ||
1729
0
      ARR_HASNULL(arr) ||
1730
0
      ARR_ELEMTYPE(arr) != CHAROID)
1731
0
      elog(ERROR, "stxkind is not a 1-D char array");
1732
0
    enabled = (char *) ARR_DATA_PTR(arr);
1733
1734
0
    ndistinct_enabled = false;
1735
0
    dependencies_enabled = false;
1736
0
    mcv_enabled = false;
1737
1738
0
    for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1739
0
    {
1740
0
      if (enabled[i] == STATS_EXT_NDISTINCT)
1741
0
        ndistinct_enabled = true;
1742
0
      else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1743
0
        dependencies_enabled = true;
1744
0
      else if (enabled[i] == STATS_EXT_MCV)
1745
0
        mcv_enabled = true;
1746
1747
      /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1748
0
    }
1749
1750
    /*
1751
     * If any option is disabled, then we'll need to append the types
1752
     * clause to show which options are enabled.  We omit the types clause
1753
     * on purpose when all options are enabled, so a pg_dump/pg_restore
1754
     * will create all statistics types on a newer postgres version, if
1755
     * the statistics had all options enabled on the original version.
1756
     *
1757
     * But if the statistics is defined on just a single column, it has to
1758
     * be an expression statistics. In that case we don't need to specify
1759
     * kinds.
1760
     */
1761
0
    if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1762
0
      (ncolumns > 1))
1763
0
    {
1764
0
      bool    gotone = false;
1765
1766
0
      appendStringInfoString(&buf, " (");
1767
1768
0
      if (ndistinct_enabled)
1769
0
      {
1770
0
        appendStringInfoString(&buf, "ndistinct");
1771
0
        gotone = true;
1772
0
      }
1773
1774
0
      if (dependencies_enabled)
1775
0
      {
1776
0
        appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
1777
0
        gotone = true;
1778
0
      }
1779
1780
0
      if (mcv_enabled)
1781
0
        appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1782
1783
0
      appendStringInfoChar(&buf, ')');
1784
0
    }
1785
1786
0
    appendStringInfoString(&buf, " ON ");
1787
0
  }
1788
1789
  /* decode simple column references */
1790
0
  for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1791
0
  {
1792
0
    AttrNumber  attnum = statextrec->stxkeys.values[colno];
1793
0
    char     *attname;
1794
1795
0
    if (colno > 0)
1796
0
      appendStringInfoString(&buf, ", ");
1797
1798
0
    attname = get_attname(statextrec->stxrelid, attnum, false);
1799
1800
0
    appendStringInfoString(&buf, quote_identifier(attname));
1801
0
  }
1802
1803
0
  context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1804
0
                  statextrec->stxrelid);
1805
1806
0
  foreach(lc, exprs)
1807
0
  {
1808
0
    Node     *expr = (Node *) lfirst(lc);
1809
0
    char     *str;
1810
0
    int     prettyFlags = PRETTYFLAG_PAREN;
1811
1812
0
    str = deparse_expression_pretty(expr, context, false, false,
1813
0
                    prettyFlags, 0);
1814
1815
0
    if (colno > 0)
1816
0
      appendStringInfoString(&buf, ", ");
1817
1818
    /* Need parens if it's not a bare function call */
1819
0
    if (looks_like_function(expr))
1820
0
      appendStringInfoString(&buf, str);
1821
0
    else
1822
0
      appendStringInfo(&buf, "(%s)", str);
1823
1824
0
    colno++;
1825
0
  }
1826
1827
0
  if (!columns_only)
1828
0
    appendStringInfo(&buf, " FROM %s",
1829
0
             generate_relation_name(statextrec->stxrelid, NIL));
1830
1831
0
  ReleaseSysCache(statexttup);
1832
1833
0
  return buf.data;
1834
0
}
1835
1836
/*
1837
 * Generate text array of expressions for statistics object.
1838
 */
1839
Datum
1840
pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
1841
0
{
1842
0
  Oid     statextid = PG_GETARG_OID(0);
1843
0
  Form_pg_statistic_ext statextrec;
1844
0
  HeapTuple statexttup;
1845
0
  Datum   datum;
1846
0
  List     *context;
1847
0
  ListCell   *lc;
1848
0
  List     *exprs = NIL;
1849
0
  bool    has_exprs;
1850
0
  char     *tmp;
1851
0
  ArrayBuildState *astate = NULL;
1852
1853
0
  statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1854
1855
0
  if (!HeapTupleIsValid(statexttup))
1856
0
    PG_RETURN_NULL();
1857
1858
  /* Does the stats object have expressions? */
1859
0
  has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1860
1861
  /* no expressions? we're done */
1862
0
  if (!has_exprs)
1863
0
  {
1864
0
    ReleaseSysCache(statexttup);
1865
0
    PG_RETURN_NULL();
1866
0
  }
1867
1868
0
  statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1869
1870
  /*
1871
   * Get the statistics expressions, and deparse them into text values.
1872
   */
1873
0
  datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1874
0
                   Anum_pg_statistic_ext_stxexprs);
1875
0
  tmp = TextDatumGetCString(datum);
1876
0
  exprs = (List *) stringToNode(tmp);
1877
0
  pfree(tmp);
1878
1879
0
  context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1880
0
                  statextrec->stxrelid);
1881
1882
0
  foreach(lc, exprs)
1883
0
  {
1884
0
    Node     *expr = (Node *) lfirst(lc);
1885
0
    char     *str;
1886
0
    int     prettyFlags = PRETTYFLAG_INDENT;
1887
1888
0
    str = deparse_expression_pretty(expr, context, false, false,
1889
0
                    prettyFlags, 0);
1890
1891
0
    astate = accumArrayResult(astate,
1892
0
                  PointerGetDatum(cstring_to_text(str)),
1893
0
                  false,
1894
0
                  TEXTOID,
1895
0
                  CurrentMemoryContext);
1896
0
  }
1897
1898
0
  ReleaseSysCache(statexttup);
1899
1900
0
  PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
1901
0
}
1902
1903
/*
1904
 * pg_get_partkeydef
1905
 *
1906
 * Returns the partition key specification, ie, the following:
1907
 *
1908
 * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1909
 */
1910
Datum
1911
pg_get_partkeydef(PG_FUNCTION_ARGS)
1912
0
{
1913
0
  Oid     relid = PG_GETARG_OID(0);
1914
0
  char     *res;
1915
1916
0
  res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1917
1918
0
  if (res == NULL)
1919
0
    PG_RETURN_NULL();
1920
1921
0
  PG_RETURN_TEXT_P(string_to_text(res));
1922
0
}
1923
1924
/* Internal version that just reports the column definitions */
1925
char *
1926
pg_get_partkeydef_columns(Oid relid, bool pretty)
1927
0
{
1928
0
  int     prettyFlags;
1929
1930
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
1931
1932
0
  return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1933
0
}
1934
1935
/*
1936
 * Internal workhorse to decompile a partition key definition.
1937
 */
1938
static char *
1939
pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1940
             bool attrsOnly, bool missing_ok)
1941
0
{
1942
0
  Form_pg_partitioned_table form;
1943
0
  HeapTuple tuple;
1944
0
  oidvector  *partclass;
1945
0
  oidvector  *partcollation;
1946
0
  List     *partexprs;
1947
0
  ListCell   *partexpr_item;
1948
0
  List     *context;
1949
0
  Datum   datum;
1950
0
  StringInfoData buf;
1951
0
  int     keyno;
1952
0
  char     *str;
1953
0
  char     *sep;
1954
1955
0
  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1956
0
  if (!HeapTupleIsValid(tuple))
1957
0
  {
1958
0
    if (missing_ok)
1959
0
      return NULL;
1960
0
    elog(ERROR, "cache lookup failed for partition key of %u", relid);
1961
0
  }
1962
1963
0
  form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1964
1965
0
  Assert(form->partrelid == relid);
1966
1967
  /* Must get partclass and partcollation the hard way */
1968
0
  datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1969
0
                   Anum_pg_partitioned_table_partclass);
1970
0
  partclass = (oidvector *) DatumGetPointer(datum);
1971
1972
0
  datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1973
0
                   Anum_pg_partitioned_table_partcollation);
1974
0
  partcollation = (oidvector *) DatumGetPointer(datum);
1975
1976
1977
  /*
1978
   * Get the expressions, if any.  (NOTE: we do not use the relcache
1979
   * versions of the expressions, because we want to display
1980
   * non-const-folded expressions.)
1981
   */
1982
0
  if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1983
0
  {
1984
0
    Datum   exprsDatum;
1985
0
    char     *exprsString;
1986
1987
0
    exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1988
0
                      Anum_pg_partitioned_table_partexprs);
1989
0
    exprsString = TextDatumGetCString(exprsDatum);
1990
0
    partexprs = (List *) stringToNode(exprsString);
1991
1992
0
    if (!IsA(partexprs, List))
1993
0
      elog(ERROR, "unexpected node type found in partexprs: %d",
1994
0
         (int) nodeTag(partexprs));
1995
1996
0
    pfree(exprsString);
1997
0
  }
1998
0
  else
1999
0
    partexprs = NIL;
2000
2001
0
  partexpr_item = list_head(partexprs);
2002
0
  context = deparse_context_for(get_relation_name(relid), relid);
2003
2004
0
  initStringInfo(&buf);
2005
2006
0
  switch (form->partstrat)
2007
0
  {
2008
0
    case PARTITION_STRATEGY_HASH:
2009
0
      if (!attrsOnly)
2010
0
        appendStringInfoString(&buf, "HASH");
2011
0
      break;
2012
0
    case PARTITION_STRATEGY_LIST:
2013
0
      if (!attrsOnly)
2014
0
        appendStringInfoString(&buf, "LIST");
2015
0
      break;
2016
0
    case PARTITION_STRATEGY_RANGE:
2017
0
      if (!attrsOnly)
2018
0
        appendStringInfoString(&buf, "RANGE");
2019
0
      break;
2020
0
    default:
2021
0
      elog(ERROR, "unexpected partition strategy: %d",
2022
0
         (int) form->partstrat);
2023
0
  }
2024
2025
0
  if (!attrsOnly)
2026
0
    appendStringInfoString(&buf, " (");
2027
0
  sep = "";
2028
0
  for (keyno = 0; keyno < form->partnatts; keyno++)
2029
0
  {
2030
0
    AttrNumber  attnum = form->partattrs.values[keyno];
2031
0
    Oid     keycoltype;
2032
0
    Oid     keycolcollation;
2033
0
    Oid     partcoll;
2034
2035
0
    appendStringInfoString(&buf, sep);
2036
0
    sep = ", ";
2037
0
    if (attnum != 0)
2038
0
    {
2039
      /* Simple attribute reference */
2040
0
      char     *attname;
2041
0
      int32   keycoltypmod;
2042
2043
0
      attname = get_attname(relid, attnum, false);
2044
0
      appendStringInfoString(&buf, quote_identifier(attname));
2045
0
      get_atttypetypmodcoll(relid, attnum,
2046
0
                  &keycoltype, &keycoltypmod,
2047
0
                  &keycolcollation);
2048
0
    }
2049
0
    else
2050
0
    {
2051
      /* Expression */
2052
0
      Node     *partkey;
2053
2054
0
      if (partexpr_item == NULL)
2055
0
        elog(ERROR, "too few entries in partexprs list");
2056
0
      partkey = (Node *) lfirst(partexpr_item);
2057
0
      partexpr_item = lnext(partexprs, partexpr_item);
2058
2059
      /* Deparse */
2060
0
      str = deparse_expression_pretty(partkey, context, false, false,
2061
0
                      prettyFlags, 0);
2062
      /* Need parens if it's not a bare function call */
2063
0
      if (looks_like_function(partkey))
2064
0
        appendStringInfoString(&buf, str);
2065
0
      else
2066
0
        appendStringInfo(&buf, "(%s)", str);
2067
2068
0
      keycoltype = exprType(partkey);
2069
0
      keycolcollation = exprCollation(partkey);
2070
0
    }
2071
2072
    /* Add collation, if not default for column */
2073
0
    partcoll = partcollation->values[keyno];
2074
0
    if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
2075
0
      appendStringInfo(&buf, " COLLATE %s",
2076
0
               generate_collation_name((partcoll)));
2077
2078
    /* Add the operator class name, if not default */
2079
0
    if (!attrsOnly)
2080
0
      get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2081
0
  }
2082
2083
0
  if (!attrsOnly)
2084
0
    appendStringInfoChar(&buf, ')');
2085
2086
  /* Clean up */
2087
0
  ReleaseSysCache(tuple);
2088
2089
0
  return buf.data;
2090
0
}
2091
2092
/*
2093
 * pg_get_partition_constraintdef
2094
 *
2095
 * Returns partition constraint expression as a string for the input relation
2096
 */
2097
Datum
2098
pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
2099
0
{
2100
0
  Oid     relationId = PG_GETARG_OID(0);
2101
0
  Expr     *constr_expr;
2102
0
  int     prettyFlags;
2103
0
  List     *context;
2104
0
  char     *consrc;
2105
2106
0
  constr_expr = get_partition_qual_relid(relationId);
2107
2108
  /* Quick exit if no partition constraint */
2109
0
  if (constr_expr == NULL)
2110
0
    PG_RETURN_NULL();
2111
2112
  /*
2113
   * Deparse and return the constraint expression.
2114
   */
2115
0
  prettyFlags = PRETTYFLAG_INDENT;
2116
0
  context = deparse_context_for(get_relation_name(relationId), relationId);
2117
0
  consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2118
0
                     false, prettyFlags, 0);
2119
2120
0
  PG_RETURN_TEXT_P(string_to_text(consrc));
2121
0
}
2122
2123
/*
2124
 * pg_get_partconstrdef_string
2125
 *
2126
 * Returns the partition constraint as a C-string for the input relation, with
2127
 * the given alias.  No pretty-printing.
2128
 */
2129
char *
2130
pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
2131
0
{
2132
0
  Expr     *constr_expr;
2133
0
  List     *context;
2134
2135
0
  constr_expr = get_partition_qual_relid(partitionId);
2136
0
  context = deparse_context_for(aliasname, partitionId);
2137
2138
0
  return deparse_expression((Node *) constr_expr, context, true, false);
2139
0
}
2140
2141
/*
2142
 * pg_get_constraintdef
2143
 *
2144
 * Returns the definition for the constraint, ie, everything that needs to
2145
 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2146
 */
2147
Datum
2148
pg_get_constraintdef(PG_FUNCTION_ARGS)
2149
0
{
2150
0
  Oid     constraintId = PG_GETARG_OID(0);
2151
0
  int     prettyFlags;
2152
0
  char     *res;
2153
2154
0
  prettyFlags = PRETTYFLAG_INDENT;
2155
2156
0
  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2157
2158
0
  if (res == NULL)
2159
0
    PG_RETURN_NULL();
2160
2161
0
  PG_RETURN_TEXT_P(string_to_text(res));
2162
0
}
2163
2164
Datum
2165
pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
2166
0
{
2167
0
  Oid     constraintId = PG_GETARG_OID(0);
2168
0
  bool    pretty = PG_GETARG_BOOL(1);
2169
0
  int     prettyFlags;
2170
0
  char     *res;
2171
2172
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
2173
2174
0
  res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2175
2176
0
  if (res == NULL)
2177
0
    PG_RETURN_NULL();
2178
2179
0
  PG_RETURN_TEXT_P(string_to_text(res));
2180
0
}
2181
2182
/*
2183
 * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2184
 */
2185
char *
2186
pg_get_constraintdef_command(Oid constraintId)
2187
0
{
2188
0
  return pg_get_constraintdef_worker(constraintId, true, 0, false);
2189
0
}
2190
2191
/*
2192
 * As of 9.4, we now use an MVCC snapshot for this.
2193
 */
2194
static char *
2195
pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
2196
              int prettyFlags, bool missing_ok)
2197
0
{
2198
0
  HeapTuple tup;
2199
0
  Form_pg_constraint conForm;
2200
0
  StringInfoData buf;
2201
0
  SysScanDesc scandesc;
2202
0
  ScanKeyData scankey[1];
2203
0
  Snapshot  snapshot = RegisterSnapshot(GetTransactionSnapshot());
2204
0
  Relation  relation = table_open(ConstraintRelationId, AccessShareLock);
2205
2206
0
  ScanKeyInit(&scankey[0],
2207
0
        Anum_pg_constraint_oid,
2208
0
        BTEqualStrategyNumber, F_OIDEQ,
2209
0
        ObjectIdGetDatum(constraintId));
2210
2211
0
  scandesc = systable_beginscan(relation,
2212
0
                  ConstraintOidIndexId,
2213
0
                  true,
2214
0
                  snapshot,
2215
0
                  1,
2216
0
                  scankey);
2217
2218
  /*
2219
   * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2220
   * via SearchSysCache, which works fine.
2221
   */
2222
0
  tup = systable_getnext(scandesc);
2223
2224
0
  UnregisterSnapshot(snapshot);
2225
2226
0
  if (!HeapTupleIsValid(tup))
2227
0
  {
2228
0
    if (missing_ok)
2229
0
    {
2230
0
      systable_endscan(scandesc);
2231
0
      table_close(relation, AccessShareLock);
2232
0
      return NULL;
2233
0
    }
2234
0
    elog(ERROR, "could not find tuple for constraint %u", constraintId);
2235
0
  }
2236
2237
0
  conForm = (Form_pg_constraint) GETSTRUCT(tup);
2238
2239
0
  initStringInfo(&buf);
2240
2241
0
  if (fullCommand)
2242
0
  {
2243
0
    if (OidIsValid(conForm->conrelid))
2244
0
    {
2245
      /*
2246
       * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2247
       * constraints, and other types of constraints don't inherit
2248
       * anyway so it doesn't matter whether we say ONLY or not. Someday
2249
       * we might need to let callers specify whether to put ONLY in the
2250
       * command.
2251
       */
2252
0
      appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2253
0
               generate_qualified_relation_name(conForm->conrelid),
2254
0
               quote_identifier(NameStr(conForm->conname)));
2255
0
    }
2256
0
    else
2257
0
    {
2258
      /* Must be a domain constraint */
2259
0
      Assert(OidIsValid(conForm->contypid));
2260
0
      appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2261
0
               generate_qualified_type_name(conForm->contypid),
2262
0
               quote_identifier(NameStr(conForm->conname)));
2263
0
    }
2264
0
  }
2265
2266
0
  switch (conForm->contype)
2267
0
  {
2268
0
    case CONSTRAINT_FOREIGN:
2269
0
      {
2270
0
        Datum   val;
2271
0
        bool    isnull;
2272
0
        const char *string;
2273
2274
        /* Start off the constraint definition */
2275
0
        appendStringInfoString(&buf, "FOREIGN KEY (");
2276
2277
        /* Fetch and build referencing-column list */
2278
0
        val = SysCacheGetAttrNotNull(CONSTROID, tup,
2279
0
                       Anum_pg_constraint_conkey);
2280
2281
        /* If it is a temporal foreign key then it uses PERIOD. */
2282
0
        decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf);
2283
2284
        /* add foreign relation name */
2285
0
        appendStringInfo(&buf, ") REFERENCES %s(",
2286
0
                 generate_relation_name(conForm->confrelid,
2287
0
                            NIL));
2288
2289
        /* Fetch and build referenced-column list */
2290
0
        val = SysCacheGetAttrNotNull(CONSTROID, tup,
2291
0
                       Anum_pg_constraint_confkey);
2292
2293
0
        decompile_column_index_array(val, conForm->confrelid, conForm->conperiod, &buf);
2294
2295
0
        appendStringInfoChar(&buf, ')');
2296
2297
        /* Add match type */
2298
0
        switch (conForm->confmatchtype)
2299
0
        {
2300
0
          case FKCONSTR_MATCH_FULL:
2301
0
            string = " MATCH FULL";
2302
0
            break;
2303
0
          case FKCONSTR_MATCH_PARTIAL:
2304
0
            string = " MATCH PARTIAL";
2305
0
            break;
2306
0
          case FKCONSTR_MATCH_SIMPLE:
2307
0
            string = "";
2308
0
            break;
2309
0
          default:
2310
0
            elog(ERROR, "unrecognized confmatchtype: %d",
2311
0
               conForm->confmatchtype);
2312
0
            string = "";  /* keep compiler quiet */
2313
0
            break;
2314
0
        }
2315
0
        appendStringInfoString(&buf, string);
2316
2317
        /* Add ON UPDATE and ON DELETE clauses, if needed */
2318
0
        switch (conForm->confupdtype)
2319
0
        {
2320
0
          case FKCONSTR_ACTION_NOACTION:
2321
0
            string = NULL; /* suppress default */
2322
0
            break;
2323
0
          case FKCONSTR_ACTION_RESTRICT:
2324
0
            string = "RESTRICT";
2325
0
            break;
2326
0
          case FKCONSTR_ACTION_CASCADE:
2327
0
            string = "CASCADE";
2328
0
            break;
2329
0
          case FKCONSTR_ACTION_SETNULL:
2330
0
            string = "SET NULL";
2331
0
            break;
2332
0
          case FKCONSTR_ACTION_SETDEFAULT:
2333
0
            string = "SET DEFAULT";
2334
0
            break;
2335
0
          default:
2336
0
            elog(ERROR, "unrecognized confupdtype: %d",
2337
0
               conForm->confupdtype);
2338
0
            string = NULL; /* keep compiler quiet */
2339
0
            break;
2340
0
        }
2341
0
        if (string)
2342
0
          appendStringInfo(&buf, " ON UPDATE %s", string);
2343
2344
0
        switch (conForm->confdeltype)
2345
0
        {
2346
0
          case FKCONSTR_ACTION_NOACTION:
2347
0
            string = NULL; /* suppress default */
2348
0
            break;
2349
0
          case FKCONSTR_ACTION_RESTRICT:
2350
0
            string = "RESTRICT";
2351
0
            break;
2352
0
          case FKCONSTR_ACTION_CASCADE:
2353
0
            string = "CASCADE";
2354
0
            break;
2355
0
          case FKCONSTR_ACTION_SETNULL:
2356
0
            string = "SET NULL";
2357
0
            break;
2358
0
          case FKCONSTR_ACTION_SETDEFAULT:
2359
0
            string = "SET DEFAULT";
2360
0
            break;
2361
0
          default:
2362
0
            elog(ERROR, "unrecognized confdeltype: %d",
2363
0
               conForm->confdeltype);
2364
0
            string = NULL; /* keep compiler quiet */
2365
0
            break;
2366
0
        }
2367
0
        if (string)
2368
0
          appendStringInfo(&buf, " ON DELETE %s", string);
2369
2370
        /*
2371
         * Add columns specified to SET NULL or SET DEFAULT if
2372
         * provided.
2373
         */
2374
0
        val = SysCacheGetAttr(CONSTROID, tup,
2375
0
                    Anum_pg_constraint_confdelsetcols, &isnull);
2376
0
        if (!isnull)
2377
0
        {
2378
0
          appendStringInfoString(&buf, " (");
2379
0
          decompile_column_index_array(val, conForm->conrelid, false, &buf);
2380
0
          appendStringInfoChar(&buf, ')');
2381
0
        }
2382
2383
0
        break;
2384
0
      }
2385
0
    case CONSTRAINT_PRIMARY:
2386
0
    case CONSTRAINT_UNIQUE:
2387
0
      {
2388
0
        Datum   val;
2389
0
        Oid     indexId;
2390
0
        int     keyatts;
2391
0
        HeapTuple indtup;
2392
2393
        /* Start off the constraint definition */
2394
0
        if (conForm->contype == CONSTRAINT_PRIMARY)
2395
0
          appendStringInfoString(&buf, "PRIMARY KEY ");
2396
0
        else
2397
0
          appendStringInfoString(&buf, "UNIQUE ");
2398
2399
0
        indexId = conForm->conindid;
2400
2401
0
        indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2402
0
        if (!HeapTupleIsValid(indtup))
2403
0
          elog(ERROR, "cache lookup failed for index %u", indexId);
2404
0
        if (conForm->contype == CONSTRAINT_UNIQUE &&
2405
0
          ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2406
0
          appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2407
2408
0
        appendStringInfoChar(&buf, '(');
2409
2410
        /* Fetch and build target column list */
2411
0
        val = SysCacheGetAttrNotNull(CONSTROID, tup,
2412
0
                       Anum_pg_constraint_conkey);
2413
2414
0
        keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf);
2415
0
        if (conForm->conperiod)
2416
0
          appendStringInfoString(&buf, " WITHOUT OVERLAPS");
2417
2418
0
        appendStringInfoChar(&buf, ')');
2419
2420
        /* Build including column list (from pg_index.indkeys) */
2421
0
        val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2422
0
                       Anum_pg_index_indnatts);
2423
0
        if (DatumGetInt32(val) > keyatts)
2424
0
        {
2425
0
          Datum   cols;
2426
0
          Datum    *keys;
2427
0
          int     nKeys;
2428
0
          int     j;
2429
2430
0
          appendStringInfoString(&buf, " INCLUDE (");
2431
2432
0
          cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2433
0
                          Anum_pg_index_indkey);
2434
2435
0
          deconstruct_array_builtin(DatumGetArrayTypeP(cols), INT2OID,
2436
0
                        &keys, NULL, &nKeys);
2437
2438
0
          for (j = keyatts; j < nKeys; j++)
2439
0
          {
2440
0
            char     *colName;
2441
2442
0
            colName = get_attname(conForm->conrelid,
2443
0
                        DatumGetInt16(keys[j]), false);
2444
0
            if (j > keyatts)
2445
0
              appendStringInfoString(&buf, ", ");
2446
0
            appendStringInfoString(&buf, quote_identifier(colName));
2447
0
          }
2448
2449
0
          appendStringInfoChar(&buf, ')');
2450
0
        }
2451
0
        ReleaseSysCache(indtup);
2452
2453
        /* XXX why do we only print these bits if fullCommand? */
2454
0
        if (fullCommand && OidIsValid(indexId))
2455
0
        {
2456
0
          char     *options = flatten_reloptions(indexId);
2457
0
          Oid     tblspc;
2458
2459
0
          if (options)
2460
0
          {
2461
0
            appendStringInfo(&buf, " WITH (%s)", options);
2462
0
            pfree(options);
2463
0
          }
2464
2465
          /*
2466
           * Print the tablespace, unless it's the database default.
2467
           * This is to help ALTER TABLE usage of this facility,
2468
           * which needs this behavior to recreate exact catalog
2469
           * state.
2470
           */
2471
0
          tblspc = get_rel_tablespace(indexId);
2472
0
          if (OidIsValid(tblspc))
2473
0
            appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2474
0
                     quote_identifier(get_tablespace_name(tblspc)));
2475
0
        }
2476
2477
0
        break;
2478
0
      }
2479
0
    case CONSTRAINT_CHECK:
2480
0
      {
2481
0
        Datum   val;
2482
0
        char     *conbin;
2483
0
        char     *consrc;
2484
0
        Node     *expr;
2485
0
        List     *context;
2486
2487
        /* Fetch constraint expression in parsetree form */
2488
0
        val = SysCacheGetAttrNotNull(CONSTROID, tup,
2489
0
                       Anum_pg_constraint_conbin);
2490
2491
0
        conbin = TextDatumGetCString(val);
2492
0
        expr = stringToNode(conbin);
2493
2494
        /* Set up deparsing context for Var nodes in constraint */
2495
0
        if (conForm->conrelid != InvalidOid)
2496
0
        {
2497
          /* relation constraint */
2498
0
          context = deparse_context_for(get_relation_name(conForm->conrelid),
2499
0
                          conForm->conrelid);
2500
0
        }
2501
0
        else
2502
0
        {
2503
          /* domain constraint --- can't have Vars */
2504
0
          context = NIL;
2505
0
        }
2506
2507
0
        consrc = deparse_expression_pretty(expr, context, false, false,
2508
0
                           prettyFlags, 0);
2509
2510
        /*
2511
         * Now emit the constraint definition, adding NO INHERIT if
2512
         * necessary.
2513
         *
2514
         * There are cases where the constraint expression will be
2515
         * fully parenthesized and we don't need the outer parens ...
2516
         * but there are other cases where we do need 'em.  Be
2517
         * conservative for now.
2518
         *
2519
         * Note that simply checking for leading '(' and trailing ')'
2520
         * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2521
         */
2522
0
        appendStringInfo(&buf, "CHECK (%s)%s",
2523
0
                 consrc,
2524
0
                 conForm->connoinherit ? " NO INHERIT" : "");
2525
0
        break;
2526
0
      }
2527
0
    case CONSTRAINT_NOTNULL:
2528
0
      {
2529
0
        if (conForm->conrelid)
2530
0
        {
2531
0
          AttrNumber  attnum;
2532
2533
0
          attnum = extractNotNullColumn(tup);
2534
2535
0
          appendStringInfo(&buf, "NOT NULL %s",
2536
0
                   quote_identifier(get_attname(conForm->conrelid,
2537
0
                                  attnum, false)));
2538
0
          if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
2539
0
            appendStringInfoString(&buf, " NO INHERIT");
2540
0
        }
2541
0
        else if (conForm->contypid)
2542
0
        {
2543
          /* conkey is null for domain not-null constraints */
2544
0
          appendStringInfoString(&buf, "NOT NULL");
2545
0
        }
2546
0
        break;
2547
0
      }
2548
2549
0
    case CONSTRAINT_TRIGGER:
2550
2551
      /*
2552
       * There isn't an ALTER TABLE syntax for creating a user-defined
2553
       * constraint trigger, but it seems better to print something than
2554
       * throw an error; if we throw error then this function couldn't
2555
       * safely be applied to all rows of pg_constraint.
2556
       */
2557
0
      appendStringInfoString(&buf, "TRIGGER");
2558
0
      break;
2559
0
    case CONSTRAINT_EXCLUSION:
2560
0
      {
2561
0
        Oid     indexOid = conForm->conindid;
2562
0
        Datum   val;
2563
0
        Datum    *elems;
2564
0
        int     nElems;
2565
0
        int     i;
2566
0
        Oid      *operators;
2567
2568
        /* Extract operator OIDs from the pg_constraint tuple */
2569
0
        val = SysCacheGetAttrNotNull(CONSTROID, tup,
2570
0
                       Anum_pg_constraint_conexclop);
2571
2572
0
        deconstruct_array_builtin(DatumGetArrayTypeP(val), OIDOID,
2573
0
                      &elems, NULL, &nElems);
2574
2575
0
        operators = palloc_array(Oid, nElems);
2576
0
        for (i = 0; i < nElems; i++)
2577
0
          operators[i] = DatumGetObjectId(elems[i]);
2578
2579
        /* pg_get_indexdef_worker does the rest */
2580
        /* suppress tablespace because pg_dump wants it that way */
2581
0
        appendStringInfoString(&buf,
2582
0
                     pg_get_indexdef_worker(indexOid,
2583
0
                                0,
2584
0
                                operators,
2585
0
                                false,
2586
0
                                false,
2587
0
                                false,
2588
0
                                false,
2589
0
                                prettyFlags,
2590
0
                                false));
2591
0
        break;
2592
0
      }
2593
0
    default:
2594
0
      elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2595
0
      break;
2596
0
  }
2597
2598
0
  if (conForm->condeferrable)
2599
0
    appendStringInfoString(&buf, " DEFERRABLE");
2600
0
  if (conForm->condeferred)
2601
0
    appendStringInfoString(&buf, " INITIALLY DEFERRED");
2602
2603
  /* Validated status is irrelevant when the constraint is NOT ENFORCED. */
2604
0
  if (!conForm->conenforced)
2605
0
    appendStringInfoString(&buf, " NOT ENFORCED");
2606
0
  else if (!conForm->convalidated)
2607
0
    appendStringInfoString(&buf, " NOT VALID");
2608
2609
  /* Cleanup */
2610
0
  systable_endscan(scandesc);
2611
0
  table_close(relation, AccessShareLock);
2612
2613
0
  return buf.data;
2614
0
}
2615
2616
2617
/*
2618
 * Convert an int16[] Datum into a comma-separated list of column names
2619
 * for the indicated relation; append the list to buf.  Returns the number
2620
 * of keys.
2621
 */
2622
static int
2623
decompile_column_index_array(Datum column_index_array, Oid relId,
2624
               bool withPeriod, StringInfo buf)
2625
0
{
2626
0
  Datum    *keys;
2627
0
  int     nKeys;
2628
0
  int     j;
2629
2630
  /* Extract data from array of int16 */
2631
0
  deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2632
0
                &keys, NULL, &nKeys);
2633
2634
0
  for (j = 0; j < nKeys; j++)
2635
0
  {
2636
0
    char     *colName;
2637
2638
0
    colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2639
2640
0
    if (j == 0)
2641
0
      appendStringInfoString(buf, quote_identifier(colName));
2642
0
    else
2643
0
      appendStringInfo(buf, ", %s%s",
2644
0
               (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
2645
0
               quote_identifier(colName));
2646
0
  }
2647
2648
0
  return nKeys;
2649
0
}
2650
2651
2652
/* ----------
2653
 * pg_get_expr      - Decompile an expression tree
2654
 *
2655
 * Input: an expression tree in nodeToString form, and a relation OID
2656
 *
2657
 * Output: reverse-listed expression
2658
 *
2659
 * Currently, the expression can only refer to a single relation, namely
2660
 * the one specified by the second parameter.  This is sufficient for
2661
 * partial indexes, column default expressions, etc.  We also support
2662
 * Var-free expressions, for which the OID can be InvalidOid.
2663
 *
2664
 * If the OID is nonzero but not actually valid, don't throw an error,
2665
 * just return NULL.  This is a bit questionable, but it's what we've
2666
 * done historically, and it can help avoid unwanted failures when
2667
 * examining catalog entries for just-deleted relations.
2668
 *
2669
 * We expect this function to work, or throw a reasonably clean error,
2670
 * for any node tree that can appear in a catalog pg_node_tree column.
2671
 * Query trees, such as those appearing in pg_rewrite.ev_action, are
2672
 * not supported.  Nor are expressions in more than one relation, which
2673
 * can appear in places like pg_rewrite.ev_qual.
2674
 * ----------
2675
 */
2676
Datum
2677
pg_get_expr(PG_FUNCTION_ARGS)
2678
0
{
2679
0
  text     *expr = PG_GETARG_TEXT_PP(0);
2680
0
  Oid     relid = PG_GETARG_OID(1);
2681
0
  text     *result;
2682
0
  int     prettyFlags;
2683
2684
0
  prettyFlags = PRETTYFLAG_INDENT;
2685
2686
0
  result = pg_get_expr_worker(expr, relid, prettyFlags);
2687
0
  if (result)
2688
0
    PG_RETURN_TEXT_P(result);
2689
0
  else
2690
0
    PG_RETURN_NULL();
2691
0
}
2692
2693
Datum
2694
pg_get_expr_ext(PG_FUNCTION_ARGS)
2695
0
{
2696
0
  text     *expr = PG_GETARG_TEXT_PP(0);
2697
0
  Oid     relid = PG_GETARG_OID(1);
2698
0
  bool    pretty = PG_GETARG_BOOL(2);
2699
0
  text     *result;
2700
0
  int     prettyFlags;
2701
2702
0
  prettyFlags = GET_PRETTY_FLAGS(pretty);
2703
2704
0
  result = pg_get_expr_worker(expr, relid, prettyFlags);
2705
0
  if (result)
2706
0
    PG_RETURN_TEXT_P(result);
2707
0
  else
2708
0
    PG_RETURN_NULL();
2709
0
}
2710
2711
static text *
2712
pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
2713
0
{
2714
0
  Node     *node;
2715
0
  Node     *tst;
2716
0
  Relids    relids;
2717
0
  List     *context;
2718
0
  char     *exprstr;
2719
0
  Relation  rel = NULL;
2720
0
  char     *str;
2721
2722
  /* Convert input pg_node_tree (really TEXT) object to C string */
2723
0
  exprstr = text_to_cstring(expr);
2724
2725
  /* Convert expression to node tree */
2726
0
  node = (Node *) stringToNode(exprstr);
2727
2728
0
  pfree(exprstr);
2729
2730
  /*
2731
   * Throw error if the input is a querytree rather than an expression tree.
2732
   * While we could support queries here, there seems no very good reason
2733
   * to.  In most such catalog columns, we'll see a List of Query nodes, or
2734
   * even nested Lists, so drill down to a non-List node before checking.
2735
   */
2736
0
  tst = node;
2737
0
  while (tst && IsA(tst, List))
2738
0
    tst = linitial((List *) tst);
2739
0
  if (tst && IsA(tst, Query))
2740
0
    ereport(ERROR,
2741
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2742
0
         errmsg("input is a query, not an expression")));
2743
2744
  /*
2745
   * Throw error if the expression contains Vars we won't be able to
2746
   * deparse.
2747
   */
2748
0
  relids = pull_varnos(NULL, node);
2749
0
  if (OidIsValid(relid))
2750
0
  {
2751
0
    if (!bms_is_subset(relids, bms_make_singleton(1)))
2752
0
      ereport(ERROR,
2753
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2754
0
           errmsg("expression contains variables of more than one relation")));
2755
0
  }
2756
0
  else
2757
0
  {
2758
0
    if (!bms_is_empty(relids))
2759
0
      ereport(ERROR,
2760
0
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2761
0
           errmsg("expression contains variables")));
2762
0
  }
2763
2764
  /*
2765
   * Prepare deparse context if needed.  If we are deparsing with a relid,
2766
   * we need to transiently open and lock the rel, to make sure it won't go
2767
   * away underneath us.  (set_relation_column_names would lock it anyway,
2768
   * so this isn't really introducing any new behavior.)
2769
   */
2770
0
  if (OidIsValid(relid))
2771
0
  {
2772
0
    rel = try_relation_open(relid, AccessShareLock);
2773
0
    if (rel == NULL)
2774
0
      return NULL;
2775
0
    context = deparse_context_for(RelationGetRelationName(rel), relid);
2776
0
  }
2777
0
  else
2778
0
    context = NIL;
2779
2780
  /* Deparse */
2781
0
  str = deparse_expression_pretty(node, context, false, false,
2782
0
                  prettyFlags, 0);
2783
2784
0
  if (rel != NULL)
2785
0
    relation_close(rel, AccessShareLock);
2786
2787
0
  return string_to_text(str);
2788
0
}
2789
2790
2791
/* ----------
2792
 * pg_get_userbyid    - Get a user name by roleid and
2793
 *          fallback to 'unknown (OID=n)'
2794
 * ----------
2795
 */
2796
Datum
2797
pg_get_userbyid(PG_FUNCTION_ARGS)
2798
0
{
2799
0
  Oid     roleid = PG_GETARG_OID(0);
2800
0
  Name    result;
2801
0
  HeapTuple roletup;
2802
0
  Form_pg_authid role_rec;
2803
2804
  /*
2805
   * Allocate space for the result
2806
   */
2807
0
  result = (Name) palloc(NAMEDATALEN);
2808
0
  memset(NameStr(*result), 0, NAMEDATALEN);
2809
2810
  /*
2811
   * Get the pg_authid entry and print the result
2812
   */
2813
0
  roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2814
0
  if (HeapTupleIsValid(roletup))
2815
0
  {
2816
0
    role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2817
0
    *result = role_rec->rolname;
2818
0
    ReleaseSysCache(roletup);
2819
0
  }
2820
0
  else
2821
0
    sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2822
2823
0
  PG_RETURN_NAME(result);
2824
0
}
2825
2826
2827
/*
2828
 * pg_get_serial_sequence
2829
 *    Get the name of the sequence used by an identity or serial column,
2830
 *    formatted suitably for passing to setval, nextval or currval.
2831
 *    First parameter is not treated as double-quoted, second parameter
2832
 *    is --- see documentation for reason.
2833
 */
2834
Datum
2835
pg_get_serial_sequence(PG_FUNCTION_ARGS)
2836
0
{
2837
0
  text     *tablename = PG_GETARG_TEXT_PP(0);
2838
0
  text     *columnname = PG_GETARG_TEXT_PP(1);
2839
0
  RangeVar   *tablerv;
2840
0
  Oid     tableOid;
2841
0
  char     *column;
2842
0
  AttrNumber  attnum;
2843
0
  Oid     sequenceId = InvalidOid;
2844
0
  Relation  depRel;
2845
0
  ScanKeyData key[3];
2846
0
  SysScanDesc scan;
2847
0
  HeapTuple tup;
2848
2849
  /* Look up table name.  Can't lock it - we might not have privileges. */
2850
0
  tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2851
0
  tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2852
2853
  /* Get the number of the column */
2854
0
  column = text_to_cstring(columnname);
2855
2856
0
  attnum = get_attnum(tableOid, column);
2857
0
  if (attnum == InvalidAttrNumber)
2858
0
    ereport(ERROR,
2859
0
        (errcode(ERRCODE_UNDEFINED_COLUMN),
2860
0
         errmsg("column \"%s\" of relation \"%s\" does not exist",
2861
0
            column, tablerv->relname)));
2862
2863
  /* Search the dependency table for the dependent sequence */
2864
0
  depRel = table_open(DependRelationId, AccessShareLock);
2865
2866
0
  ScanKeyInit(&key[0],
2867
0
        Anum_pg_depend_refclassid,
2868
0
        BTEqualStrategyNumber, F_OIDEQ,
2869
0
        ObjectIdGetDatum(RelationRelationId));
2870
0
  ScanKeyInit(&key[1],
2871
0
        Anum_pg_depend_refobjid,
2872
0
        BTEqualStrategyNumber, F_OIDEQ,
2873
0
        ObjectIdGetDatum(tableOid));
2874
0
  ScanKeyInit(&key[2],
2875
0
        Anum_pg_depend_refobjsubid,
2876
0
        BTEqualStrategyNumber, F_INT4EQ,
2877
0
        Int32GetDatum(attnum));
2878
2879
0
  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2880
0
                NULL, 3, key);
2881
2882
0
  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2883
0
  {
2884
0
    Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2885
2886
    /*
2887
     * Look for an auto dependency (serial column) or internal dependency
2888
     * (identity column) of a sequence on a column.  (We need the relkind
2889
     * test because indexes can also have auto dependencies on columns.)
2890
     */
2891
0
    if (deprec->classid == RelationRelationId &&
2892
0
      deprec->objsubid == 0 &&
2893
0
      (deprec->deptype == DEPENDENCY_AUTO ||
2894
0
       deprec->deptype == DEPENDENCY_INTERNAL) &&
2895
0
      get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2896
0
    {
2897
0
      sequenceId = deprec->objid;
2898
0
      break;
2899
0
    }
2900
0
  }
2901
2902
0
  systable_endscan(scan);
2903
0
  table_close(depRel, AccessShareLock);
2904
2905
0
  if (OidIsValid(sequenceId))
2906
0
  {
2907
0
    char     *result;
2908
2909
0
    result = generate_qualified_relation_name(sequenceId);
2910
2911
0
    PG_RETURN_TEXT_P(string_to_text(result));
2912
0
  }
2913
2914
0
  PG_RETURN_NULL();
2915
0
}
2916
2917
2918
/*
2919
 * pg_get_functiondef
2920
 *    Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2921
 *    the specified function.
2922
 *
2923
 * Note: if you change the output format of this function, be careful not
2924
 * to break psql's rules (in \ef and \sf) for identifying the start of the
2925
 * function body.  To wit: the function body starts on a line that begins with
2926
 * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
2927
 */
2928
Datum
2929
pg_get_functiondef(PG_FUNCTION_ARGS)
2930
0
{
2931
0
  Oid     funcid = PG_GETARG_OID(0);
2932
0
  StringInfoData buf;
2933
0
  StringInfoData dq;
2934
0
  HeapTuple proctup;
2935
0
  Form_pg_proc proc;
2936
0
  bool    isfunction;
2937
0
  Datum   tmp;
2938
0
  bool    isnull;
2939
0
  const char *prosrc;
2940
0
  const char *name;
2941
0
  const char *nsp;
2942
0
  float4    procost;
2943
0
  int     oldlen;
2944
2945
0
  initStringInfo(&buf);
2946
2947
  /* Look up the function */
2948
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2949
0
  if (!HeapTupleIsValid(proctup))
2950
0
    PG_RETURN_NULL();
2951
2952
0
  proc = (Form_pg_proc) GETSTRUCT(proctup);
2953
0
  name = NameStr(proc->proname);
2954
2955
0
  if (proc->prokind == PROKIND_AGGREGATE)
2956
0
    ereport(ERROR,
2957
0
        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2958
0
         errmsg("\"%s\" is an aggregate function", name)));
2959
2960
0
  isfunction = (proc->prokind != PROKIND_PROCEDURE);
2961
2962
  /*
2963
   * We always qualify the function name, to ensure the right function gets
2964
   * replaced.
2965
   */
2966
0
  nsp = get_namespace_name_or_temp(proc->pronamespace);
2967
0
  appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2968
0
           isfunction ? "FUNCTION" : "PROCEDURE",
2969
0
           quote_qualified_identifier(nsp, name));
2970
0
  (void) print_function_arguments(&buf, proctup, false, true);
2971
0
  appendStringInfoString(&buf, ")\n");
2972
0
  if (isfunction)
2973
0
  {
2974
0
    appendStringInfoString(&buf, " RETURNS ");
2975
0
    print_function_rettype(&buf, proctup);
2976
0
    appendStringInfoChar(&buf, '\n');
2977
0
  }
2978
2979
0
  print_function_trftypes(&buf, proctup);
2980
2981
0
  appendStringInfo(&buf, " LANGUAGE %s\n",
2982
0
           quote_identifier(get_language_name(proc->prolang, false)));
2983
2984
  /* Emit some miscellaneous options on one line */
2985
0
  oldlen = buf.len;
2986
2987
0
  if (proc->prokind == PROKIND_WINDOW)
2988
0
    appendStringInfoString(&buf, " WINDOW");
2989
0
  switch (proc->provolatile)
2990
0
  {
2991
0
    case PROVOLATILE_IMMUTABLE:
2992
0
      appendStringInfoString(&buf, " IMMUTABLE");
2993
0
      break;
2994
0
    case PROVOLATILE_STABLE:
2995
0
      appendStringInfoString(&buf, " STABLE");
2996
0
      break;
2997
0
    case PROVOLATILE_VOLATILE:
2998
0
      break;
2999
0
  }
3000
3001
0
  switch (proc->proparallel)
3002
0
  {
3003
0
    case PROPARALLEL_SAFE:
3004
0
      appendStringInfoString(&buf, " PARALLEL SAFE");
3005
0
      break;
3006
0
    case PROPARALLEL_RESTRICTED:
3007
0
      appendStringInfoString(&buf, " PARALLEL RESTRICTED");
3008
0
      break;
3009
0
    case PROPARALLEL_UNSAFE:
3010
0
      break;
3011
0
  }
3012
3013
0
  if (proc->proisstrict)
3014
0
    appendStringInfoString(&buf, " STRICT");
3015
0
  if (proc->prosecdef)
3016
0
    appendStringInfoString(&buf, " SECURITY DEFINER");
3017
0
  if (proc->proleakproof)
3018
0
    appendStringInfoString(&buf, " LEAKPROOF");
3019
3020
  /* This code for the default cost and rows should match functioncmds.c */
3021
0
  if (proc->prolang == INTERNALlanguageId ||
3022
0
    proc->prolang == ClanguageId)
3023
0
    procost = 1;
3024
0
  else
3025
0
    procost = 100;
3026
0
  if (proc->procost != procost)
3027
0
    appendStringInfo(&buf, " COST %g", proc->procost);
3028
3029
0
  if (proc->prorows > 0 && proc->prorows != 1000)
3030
0
    appendStringInfo(&buf, " ROWS %g", proc->prorows);
3031
3032
0
  if (proc->prosupport)
3033
0
  {
3034
0
    Oid     argtypes[1];
3035
3036
    /*
3037
     * We should qualify the support function's name if it wouldn't be
3038
     * resolved by lookup in the current search path.
3039
     */
3040
0
    argtypes[0] = INTERNALOID;
3041
0
    appendStringInfo(&buf, " SUPPORT %s",
3042
0
             generate_function_name(proc->prosupport, 1,
3043
0
                        NIL, argtypes,
3044
0
                        false, NULL, false));
3045
0
  }
3046
3047
0
  if (oldlen != buf.len)
3048
0
    appendStringInfoChar(&buf, '\n');
3049
3050
  /* Emit any proconfig options, one per line */
3051
0
  tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
3052
0
  if (!isnull)
3053
0
  {
3054
0
    ArrayType  *a = DatumGetArrayTypeP(tmp);
3055
0
    int     i;
3056
3057
0
    Assert(ARR_ELEMTYPE(a) == TEXTOID);
3058
0
    Assert(ARR_NDIM(a) == 1);
3059
0
    Assert(ARR_LBOUND(a)[0] == 1);
3060
3061
0
    for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3062
0
    {
3063
0
      Datum   d;
3064
3065
0
      d = array_ref(a, 1, &i,
3066
0
              -1 /* varlenarray */ ,
3067
0
              -1 /* TEXT's typlen */ ,
3068
0
              false /* TEXT's typbyval */ ,
3069
0
              TYPALIGN_INT /* TEXT's typalign */ ,
3070
0
              &isnull);
3071
0
      if (!isnull)
3072
0
      {
3073
0
        char     *configitem = TextDatumGetCString(d);
3074
0
        char     *pos;
3075
3076
0
        pos = strchr(configitem, '=');
3077
0
        if (pos == NULL)
3078
0
          continue;
3079
0
        *pos++ = '\0';
3080
3081
0
        appendStringInfo(&buf, " SET %s TO ",
3082
0
                 quote_identifier(configitem));
3083
3084
        /*
3085
         * Variables that are marked GUC_LIST_QUOTE were already fully
3086
         * quoted by flatten_set_variable_args() before they were put
3087
         * into the proconfig array.  However, because the quoting
3088
         * rules used there aren't exactly like SQL's, we have to
3089
         * break the list value apart and then quote the elements as
3090
         * string literals.  (The elements may be double-quoted as-is,
3091
         * but we can't just feed them to the SQL parser; it would do
3092
         * the wrong thing with elements that are zero-length or
3093
         * longer than NAMEDATALEN.)  Also, we need a special case for
3094
         * empty lists.
3095
         *
3096
         * Variables that are not so marked should just be emitted as
3097
         * simple string literals.  If the variable is not known to
3098
         * guc.c, we'll do that; this makes it unsafe to use
3099
         * GUC_LIST_QUOTE for extension variables.
3100
         */
3101
0
        if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3102
0
        {
3103
0
          List     *namelist;
3104
0
          ListCell   *lc;
3105
3106
          /* Parse string into list of identifiers */
3107
0
          if (!SplitGUCList(pos, ',', &namelist))
3108
0
          {
3109
            /* this shouldn't fail really */
3110
0
            elog(ERROR, "invalid list syntax in proconfig item");
3111
0
          }
3112
          /* Special case: represent an empty list as NULL */
3113
0
          if (namelist == NIL)
3114
0
            appendStringInfoString(&buf, "NULL");
3115
0
          foreach(lc, namelist)
3116
0
          {
3117
0
            char     *curname = (char *) lfirst(lc);
3118
3119
0
            simple_quote_literal(&buf, curname);
3120
0
            if (lnext(namelist, lc))
3121
0
              appendStringInfoString(&buf, ", ");
3122
0
          }
3123
0
        }
3124
0
        else
3125
0
          simple_quote_literal(&buf, pos);
3126
0
        appendStringInfoChar(&buf, '\n');
3127
0
      }
3128
0
    }
3129
0
  }
3130
3131
  /* And finally the function definition ... */
3132
0
  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3133
0
  if (proc->prolang == SQLlanguageId && !isnull)
3134
0
  {
3135
0
    print_function_sqlbody(&buf, proctup);
3136
0
  }
3137
0
  else
3138
0
  {
3139
0
    appendStringInfoString(&buf, "AS ");
3140
3141
0
    tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
3142
0
    if (!isnull)
3143
0
    {
3144
0
      simple_quote_literal(&buf, TextDatumGetCString(tmp));
3145
0
      appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3146
0
    }
3147
3148
0
    tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
3149
0
    prosrc = TextDatumGetCString(tmp);
3150
3151
    /*
3152
     * We always use dollar quoting.  Figure out a suitable delimiter.
3153
     *
3154
     * Since the user is likely to be editing the function body string, we
3155
     * shouldn't use a short delimiter that he might easily create a
3156
     * conflict with.  Hence prefer "$function$"/"$procedure$", but extend
3157
     * if needed.
3158
     */
3159
0
    initStringInfo(&dq);
3160
0
    appendStringInfoChar(&dq, '$');
3161
0
    appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3162
0
    while (strstr(prosrc, dq.data) != NULL)
3163
0
      appendStringInfoChar(&dq, 'x');
3164
0
    appendStringInfoChar(&dq, '$');
3165
3166
0
    appendBinaryStringInfo(&buf, dq.data, dq.len);
3167
0
    appendStringInfoString(&buf, prosrc);
3168
0
    appendBinaryStringInfo(&buf, dq.data, dq.len);
3169
0
  }
3170
3171
0
  appendStringInfoChar(&buf, '\n');
3172
3173
0
  ReleaseSysCache(proctup);
3174
3175
0
  PG_RETURN_TEXT_P(string_to_text(buf.data));
3176
0
}
3177
3178
/*
3179
 * pg_get_function_arguments
3180
 *    Get a nicely-formatted list of arguments for a function.
3181
 *    This is everything that would go between the parentheses in
3182
 *    CREATE FUNCTION.
3183
 */
3184
Datum
3185
pg_get_function_arguments(PG_FUNCTION_ARGS)
3186
0
{
3187
0
  Oid     funcid = PG_GETARG_OID(0);
3188
0
  StringInfoData buf;
3189
0
  HeapTuple proctup;
3190
3191
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3192
0
  if (!HeapTupleIsValid(proctup))
3193
0
    PG_RETURN_NULL();
3194
3195
0
  initStringInfo(&buf);
3196
3197
0
  (void) print_function_arguments(&buf, proctup, false, true);
3198
3199
0
  ReleaseSysCache(proctup);
3200
3201
0
  PG_RETURN_TEXT_P(string_to_text(buf.data));
3202
0
}
3203
3204
/*
3205
 * pg_get_function_identity_arguments
3206
 *    Get a formatted list of arguments for a function.
3207
 *    This is everything that would go between the parentheses in
3208
 *    ALTER FUNCTION, etc.  In particular, don't print defaults.
3209
 */
3210
Datum
3211
pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
3212
0
{
3213
0
  Oid     funcid = PG_GETARG_OID(0);
3214
0
  StringInfoData buf;
3215
0
  HeapTuple proctup;
3216
3217
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3218
0
  if (!HeapTupleIsValid(proctup))
3219
0
    PG_RETURN_NULL();
3220
3221
0
  initStringInfo(&buf);
3222
3223
0
  (void) print_function_arguments(&buf, proctup, false, false);
3224
3225
0
  ReleaseSysCache(proctup);
3226
3227
0
  PG_RETURN_TEXT_P(string_to_text(buf.data));
3228
0
}
3229
3230
/*
3231
 * pg_get_function_result
3232
 *    Get a nicely-formatted version of the result type of a function.
3233
 *    This is what would appear after RETURNS in CREATE FUNCTION.
3234
 */
3235
Datum
3236
pg_get_function_result(PG_FUNCTION_ARGS)
3237
0
{
3238
0
  Oid     funcid = PG_GETARG_OID(0);
3239
0
  StringInfoData buf;
3240
0
  HeapTuple proctup;
3241
3242
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3243
0
  if (!HeapTupleIsValid(proctup))
3244
0
    PG_RETURN_NULL();
3245
3246
0
  if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3247
0
  {
3248
0
    ReleaseSysCache(proctup);
3249
0
    PG_RETURN_NULL();
3250
0
  }
3251
3252
0
  initStringInfo(&buf);
3253
3254
0
  print_function_rettype(&buf, proctup);
3255
3256
0
  ReleaseSysCache(proctup);
3257
3258
0
  PG_RETURN_TEXT_P(string_to_text(buf.data));
3259
0
}
3260
3261
/*
3262
 * Guts of pg_get_function_result: append the function's return type
3263
 * to the specified buffer.
3264
 */
3265
static void
3266
print_function_rettype(StringInfo buf, HeapTuple proctup)
3267
0
{
3268
0
  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3269
0
  int     ntabargs = 0;
3270
0
  StringInfoData rbuf;
3271
3272
0
  initStringInfo(&rbuf);
3273
3274
0
  if (proc->proretset)
3275
0
  {
3276
    /* It might be a table function; try to print the arguments */
3277
0
    appendStringInfoString(&rbuf, "TABLE(");
3278
0
    ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3279
0
    if (ntabargs > 0)
3280
0
      appendStringInfoChar(&rbuf, ')');
3281
0
    else
3282
0
      resetStringInfo(&rbuf);
3283
0
  }
3284
3285
0
  if (ntabargs == 0)
3286
0
  {
3287
    /* Not a table function, so do the normal thing */
3288
0
    if (proc->proretset)
3289
0
      appendStringInfoString(&rbuf, "SETOF ");
3290
0
    appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3291
0
  }
3292
3293
0
  appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3294
0
}
3295
3296
/*
3297
 * Common code for pg_get_function_arguments and pg_get_function_result:
3298
 * append the desired subset of arguments to buf.  We print only TABLE
3299
 * arguments when print_table_args is true, and all the others when it's false.
3300
 * We print argument defaults only if print_defaults is true.
3301
 * Function return value is the number of arguments printed.
3302
 */
3303
static int
3304
print_function_arguments(StringInfo buf, HeapTuple proctup,
3305
             bool print_table_args, bool print_defaults)
3306
0
{
3307
0
  Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3308
0
  int     numargs;
3309
0
  Oid      *argtypes;
3310
0
  char    **argnames;
3311
0
  char     *argmodes;
3312
0
  int     insertorderbyat = -1;
3313
0
  int     argsprinted;
3314
0
  int     inputargno;
3315
0
  int     nlackdefaults;
3316
0
  List     *argdefaults = NIL;
3317
0
  ListCell   *nextargdefault = NULL;
3318
0
  int     i;
3319
3320
0
  numargs = get_func_arg_info(proctup,
3321
0
                &argtypes, &argnames, &argmodes);
3322
3323
0
  nlackdefaults = numargs;
3324
0
  if (print_defaults && proc->pronargdefaults > 0)
3325
0
  {
3326
0
    Datum   proargdefaults;
3327
0
    bool    isnull;
3328
3329
0
    proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3330
0
                     Anum_pg_proc_proargdefaults,
3331
0
                     &isnull);
3332
0
    if (!isnull)
3333
0
    {
3334
0
      char     *str;
3335
3336
0
      str = TextDatumGetCString(proargdefaults);
3337
0
      argdefaults = castNode(List, stringToNode(str));
3338
0
      pfree(str);
3339
0
      nextargdefault = list_head(argdefaults);
3340
      /* nlackdefaults counts only *input* arguments lacking defaults */
3341
0
      nlackdefaults = proc->pronargs - list_length(argdefaults);
3342
0
    }
3343
0
  }
3344
3345
  /* Check for special treatment of ordered-set aggregates */
3346
0
  if (proc->prokind == PROKIND_AGGREGATE)
3347
0
  {
3348
0
    HeapTuple aggtup;
3349
0
    Form_pg_aggregate agg;
3350
3351
0
    aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(proc->oid));
3352
0
    if (!HeapTupleIsValid(aggtup))
3353
0
      elog(ERROR, "cache lookup failed for aggregate %u",
3354
0
         proc->oid);
3355
0
    agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3356
0
    if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3357
0
      insertorderbyat = agg->aggnumdirectargs;
3358
0
    ReleaseSysCache(aggtup);
3359
0
  }
3360
3361
0
  argsprinted = 0;
3362
0
  inputargno = 0;
3363
0
  for (i = 0; i < numargs; i++)
3364
0
  {
3365
0
    Oid     argtype = argtypes[i];
3366
0
    char     *argname = argnames ? argnames[i] : NULL;
3367
0
    char    argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3368
0
    const char *modename;
3369
0
    bool    isinput;
3370
3371
0
    switch (argmode)
3372
0
    {
3373
0
      case PROARGMODE_IN:
3374
3375
        /*
3376
         * For procedures, explicitly mark all argument modes, so as
3377
         * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3378
         */
3379
0
        if (proc->prokind == PROKIND_PROCEDURE)
3380
0
          modename = "IN ";
3381
0
        else
3382
0
          modename = "";
3383
0
        isinput = true;
3384
0
        break;
3385
0
      case PROARGMODE_INOUT:
3386
0
        modename = "INOUT ";
3387
0
        isinput = true;
3388
0
        break;
3389
0
      case PROARGMODE_OUT:
3390
0
        modename = "OUT ";
3391
0
        isinput = false;
3392
0
        break;
3393
0
      case PROARGMODE_VARIADIC:
3394
0
        modename = "VARIADIC ";
3395
0
        isinput = true;
3396
0
        break;
3397
0
      case PROARGMODE_TABLE:
3398
0
        modename = "";
3399
0
        isinput = false;
3400
0
        break;
3401
0
      default:
3402
0
        elog(ERROR, "invalid parameter mode '%c'", argmode);
3403
0
        modename = NULL; /* keep compiler quiet */
3404
0
        isinput = false;
3405
0
        break;
3406
0
    }
3407
0
    if (isinput)
3408
0
      inputargno++;   /* this is a 1-based counter */
3409
3410
0
    if (print_table_args != (argmode == PROARGMODE_TABLE))
3411
0
      continue;
3412
3413
0
    if (argsprinted == insertorderbyat)
3414
0
    {
3415
0
      if (argsprinted)
3416
0
        appendStringInfoChar(buf, ' ');
3417
0
      appendStringInfoString(buf, "ORDER BY ");
3418
0
    }
3419
0
    else if (argsprinted)
3420
0
      appendStringInfoString(buf, ", ");
3421
3422
0
    appendStringInfoString(buf, modename);
3423
0
    if (argname && argname[0])
3424
0
      appendStringInfo(buf, "%s ", quote_identifier(argname));
3425
0
    appendStringInfoString(buf, format_type_be(argtype));
3426
0
    if (print_defaults && isinput && inputargno > nlackdefaults)
3427
0
    {
3428
0
      Node     *expr;
3429
3430
0
      Assert(nextargdefault != NULL);
3431
0
      expr = (Node *) lfirst(nextargdefault);
3432
0
      nextargdefault = lnext(argdefaults, nextargdefault);
3433
3434
0
      appendStringInfo(buf, " DEFAULT %s",
3435
0
               deparse_expression(expr, NIL, false, false));
3436
0
    }
3437
0
    argsprinted++;
3438
3439
    /* nasty hack: print the last arg twice for variadic ordered-set agg */
3440
0
    if (argsprinted == insertorderbyat && i == numargs - 1)
3441
0
    {
3442
0
      i--;
3443
      /* aggs shouldn't have defaults anyway, but just to be sure ... */
3444
0
      print_defaults = false;
3445
0
    }
3446
0
  }
3447
3448
0
  return argsprinted;
3449
0
}
3450
3451
static bool
3452
is_input_argument(int nth, const char *argmodes)
3453
0
{
3454
0
  return (!argmodes
3455
0
      || argmodes[nth] == PROARGMODE_IN
3456
0
      || argmodes[nth] == PROARGMODE_INOUT
3457
0
      || argmodes[nth] == PROARGMODE_VARIADIC);
3458
0
}
3459
3460
/*
3461
 * Append used transformed types to specified buffer
3462
 */
3463
static void
3464
print_function_trftypes(StringInfo buf, HeapTuple proctup)
3465
0
{
3466
0
  Oid      *trftypes;
3467
0
  int     ntypes;
3468
3469
0
  ntypes = get_func_trftypes(proctup, &trftypes);
3470
0
  if (ntypes > 0)
3471
0
  {
3472
0
    int     i;
3473
3474
0
    appendStringInfoString(buf, " TRANSFORM ");
3475
0
    for (i = 0; i < ntypes; i++)
3476
0
    {
3477
0
      if (i != 0)
3478
0
        appendStringInfoString(buf, ", ");
3479
0
      appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3480
0
    }
3481
0
    appendStringInfoChar(buf, '\n');
3482
0
  }
3483
0
}
3484
3485
/*
3486
 * Get textual representation of a function argument's default value.  The
3487
 * second argument of this function is the argument number among all arguments
3488
 * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3489
 * how information_schema.sql uses it.
3490
 */
3491
Datum
3492
pg_get_function_arg_default(PG_FUNCTION_ARGS)
3493
0
{
3494
0
  Oid     funcid = PG_GETARG_OID(0);
3495
0
  int32   nth_arg = PG_GETARG_INT32(1);
3496
0
  HeapTuple proctup;
3497
0
  Form_pg_proc proc;
3498
0
  int     numargs;
3499
0
  Oid      *argtypes;
3500
0
  char    **argnames;
3501
0
  char     *argmodes;
3502
0
  int     i;
3503
0
  List     *argdefaults;
3504
0
  Node     *node;
3505
0
  char     *str;
3506
0
  int     nth_inputarg;
3507
0
  Datum   proargdefaults;
3508
0
  bool    isnull;
3509
0
  int     nth_default;
3510
3511
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3512
0
  if (!HeapTupleIsValid(proctup))
3513
0
    PG_RETURN_NULL();
3514
3515
0
  numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3516
0
  if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3517
0
  {
3518
0
    ReleaseSysCache(proctup);
3519
0
    PG_RETURN_NULL();
3520
0
  }
3521
3522
0
  nth_inputarg = 0;
3523
0
  for (i = 0; i < nth_arg; i++)
3524
0
    if (is_input_argument(i, argmodes))
3525
0
      nth_inputarg++;
3526
3527
0
  proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3528
0
                   Anum_pg_proc_proargdefaults,
3529
0
                   &isnull);
3530
0
  if (isnull)
3531
0
  {
3532
0
    ReleaseSysCache(proctup);
3533
0
    PG_RETURN_NULL();
3534
0
  }
3535
3536
0
  str = TextDatumGetCString(proargdefaults);
3537
0
  argdefaults = castNode(List, stringToNode(str));
3538
0
  pfree(str);
3539
3540
0
  proc = (Form_pg_proc) GETSTRUCT(proctup);
3541
3542
  /*
3543
   * Calculate index into proargdefaults: proargdefaults corresponds to the
3544
   * last N input arguments, where N = pronargdefaults.
3545
   */
3546
0
  nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3547
3548
0
  if (nth_default < 0 || nth_default >= list_length(argdefaults))
3549
0
  {
3550
0
    ReleaseSysCache(proctup);
3551
0
    PG_RETURN_NULL();
3552
0
  }
3553
0
  node = list_nth(argdefaults, nth_default);
3554
0
  str = deparse_expression(node, NIL, false, false);
3555
3556
0
  ReleaseSysCache(proctup);
3557
3558
0
  PG_RETURN_TEXT_P(string_to_text(str));
3559
0
}
3560
3561
static void
3562
print_function_sqlbody(StringInfo buf, HeapTuple proctup)
3563
0
{
3564
0
  int     numargs;
3565
0
  Oid      *argtypes;
3566
0
  char    **argnames;
3567
0
  char     *argmodes;
3568
0
  deparse_namespace dpns = {0};
3569
0
  Datum   tmp;
3570
0
  Node     *n;
3571
3572
0
  dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3573
0
  numargs = get_func_arg_info(proctup,
3574
0
                &argtypes, &argnames, &argmodes);
3575
0
  dpns.numargs = numargs;
3576
0
  dpns.argnames = argnames;
3577
3578
0
  tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3579
0
  n = stringToNode(TextDatumGetCString(tmp));
3580
3581
0
  if (IsA(n, List))
3582
0
  {
3583
0
    List     *stmts;
3584
0
    ListCell   *lc;
3585
3586
0
    stmts = linitial(castNode(List, n));
3587
3588
0
    appendStringInfoString(buf, "BEGIN ATOMIC\n");
3589
3590
0
    foreach(lc, stmts)
3591
0
    {
3592
0
      Query    *query = lfirst_node(Query, lc);
3593
3594
      /* It seems advisable to get at least AccessShareLock on rels */
3595
0
      AcquireRewriteLocks(query, false, false);
3596
0
      get_query_def(query, buf, list_make1(&dpns), NULL, false,
3597
0
              PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
3598
0
      appendStringInfoChar(buf, ';');
3599
0
      appendStringInfoChar(buf, '\n');
3600
0
    }
3601
3602
0
    appendStringInfoString(buf, "END");
3603
0
  }
3604
0
  else
3605
0
  {
3606
0
    Query    *query = castNode(Query, n);
3607
3608
    /* It seems advisable to get at least AccessShareLock on rels */
3609
0
    AcquireRewriteLocks(query, false, false);
3610
0
    get_query_def(query, buf, list_make1(&dpns), NULL, false,
3611
0
            0, WRAP_COLUMN_DEFAULT, 0);
3612
0
  }
3613
0
}
3614
3615
Datum
3616
pg_get_function_sqlbody(PG_FUNCTION_ARGS)
3617
0
{
3618
0
  Oid     funcid = PG_GETARG_OID(0);
3619
0
  StringInfoData buf;
3620
0
  HeapTuple proctup;
3621
0
  bool    isnull;
3622
3623
0
  initStringInfo(&buf);
3624
3625
  /* Look up the function */
3626
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3627
0
  if (!HeapTupleIsValid(proctup))
3628
0
    PG_RETURN_NULL();
3629
3630
0
  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3631
0
  if (isnull)
3632
0
  {
3633
0
    ReleaseSysCache(proctup);
3634
0
    PG_RETURN_NULL();
3635
0
  }
3636
3637
0
  print_function_sqlbody(&buf, proctup);
3638
3639
0
  ReleaseSysCache(proctup);
3640
3641
0
  PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
3642
0
}
3643
3644
3645
/*
3646
 * deparse_expression     - General utility for deparsing expressions
3647
 *
3648
 * calls deparse_expression_pretty with all prettyPrinting disabled
3649
 */
3650
char *
3651
deparse_expression(Node *expr, List *dpcontext,
3652
           bool forceprefix, bool showimplicit)
3653
0
{
3654
0
  return deparse_expression_pretty(expr, dpcontext, forceprefix,
3655
0
                   showimplicit, 0, 0);
3656
0
}
3657
3658
/* ----------
3659
 * deparse_expression_pretty  - General utility for deparsing expressions
3660
 *
3661
 * expr is the node tree to be deparsed.  It must be a transformed expression
3662
 * tree (ie, not the raw output of gram.y).
3663
 *
3664
 * dpcontext is a list of deparse_namespace nodes representing the context
3665
 * for interpreting Vars in the node tree.  It can be NIL if no Vars are
3666
 * expected.
3667
 *
3668
 * forceprefix is true to force all Vars to be prefixed with their table names.
3669
 *
3670
 * showimplicit is true to force all implicit casts to be shown explicitly.
3671
 *
3672
 * Tries to pretty up the output according to prettyFlags and startIndent.
3673
 *
3674
 * The result is a palloc'd string.
3675
 * ----------
3676
 */
3677
static char *
3678
deparse_expression_pretty(Node *expr, List *dpcontext,
3679
              bool forceprefix, bool showimplicit,
3680
              int prettyFlags, int startIndent)
3681
0
{
3682
0
  StringInfoData buf;
3683
0
  deparse_context context;
3684
3685
0
  initStringInfo(&buf);
3686
0
  context.buf = &buf;
3687
0
  context.namespaces = dpcontext;
3688
0
  context.resultDesc = NULL;
3689
0
  context.targetList = NIL;
3690
0
  context.windowClause = NIL;
3691
0
  context.varprefix = forceprefix;
3692
0
  context.prettyFlags = prettyFlags;
3693
0
  context.wrapColumn = WRAP_COLUMN_DEFAULT;
3694
0
  context.indentLevel = startIndent;
3695
0
  context.colNamesVisible = true;
3696
0
  context.inGroupBy = false;
3697
0
  context.varInOrderBy = false;
3698
0
  context.appendparents = NULL;
3699
3700
0
  get_rule_expr(expr, &context, showimplicit);
3701
3702
0
  return buf.data;
3703
0
}
3704
3705
/* ----------
3706
 * deparse_context_for      - Build deparse context for a single relation
3707
 *
3708
 * Given the reference name (alias) and OID of a relation, build deparsing
3709
 * context for an expression referencing only that relation (as varno 1,
3710
 * varlevelsup 0).  This is sufficient for many uses of deparse_expression.
3711
 * ----------
3712
 */
3713
List *
3714
deparse_context_for(const char *aliasname, Oid relid)
3715
0
{
3716
0
  deparse_namespace *dpns;
3717
0
  RangeTblEntry *rte;
3718
3719
0
  dpns = palloc0_object(deparse_namespace);
3720
3721
  /* Build a minimal RTE for the rel */
3722
0
  rte = makeNode(RangeTblEntry);
3723
0
  rte->rtekind = RTE_RELATION;
3724
0
  rte->relid = relid;
3725
0
  rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3726
0
  rte->rellockmode = AccessShareLock;
3727
0
  rte->alias = makeAlias(aliasname, NIL);
3728
0
  rte->eref = rte->alias;
3729
0
  rte->lateral = false;
3730
0
  rte->inh = false;
3731
0
  rte->inFromCl = true;
3732
3733
  /* Build one-element rtable */
3734
0
  dpns->rtable = list_make1(rte);
3735
0
  dpns->subplans = NIL;
3736
0
  dpns->ctes = NIL;
3737
0
  dpns->appendrels = NULL;
3738
0
  set_rtable_names(dpns, NIL, NULL);
3739
0
  set_simple_column_names(dpns);
3740
3741
  /* Return a one-deep namespace stack */
3742
0
  return list_make1(dpns);
3743
0
}
3744
3745
/*
3746
 * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3747
 *
3748
 * When deparsing an expression in a Plan tree, we use the plan's rangetable
3749
 * to resolve names of simple Vars.  The initialization of column names for
3750
 * this is rather expensive if the rangetable is large, and it'll be the same
3751
 * for every expression in the Plan tree; so we do it just once and re-use
3752
 * the result of this function for each expression.  (Note that the result
3753
 * is not usable until set_deparse_context_plan() is applied to it.)
3754
 *
3755
 * In addition to the PlannedStmt, pass the per-RTE alias names
3756
 * assigned by a previous call to select_rtable_names_for_explain.
3757
 */
3758
List *
3759
deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
3760
0
{
3761
0
  deparse_namespace *dpns;
3762
3763
0
  dpns = palloc0_object(deparse_namespace);
3764
3765
  /* Initialize fields that stay the same across the whole plan tree */
3766
0
  dpns->rtable = pstmt->rtable;
3767
0
  dpns->rtable_names = rtable_names;
3768
0
  dpns->subplans = pstmt->subplans;
3769
0
  dpns->ctes = NIL;
3770
0
  if (pstmt->appendRelations)
3771
0
  {
3772
    /* Set up the array, indexed by child relid */
3773
0
    int     ntables = list_length(dpns->rtable);
3774
0
    ListCell   *lc;
3775
3776
0
    dpns->appendrels = palloc0_array(AppendRelInfo *, ntables + 1);
3777
0
    foreach(lc, pstmt->appendRelations)
3778
0
    {
3779
0
      AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3780
0
      Index   crelid = appinfo->child_relid;
3781
3782
0
      Assert(crelid > 0 && crelid <= ntables);
3783
0
      Assert(dpns->appendrels[crelid] == NULL);
3784
0
      dpns->appendrels[crelid] = appinfo;
3785
0
    }
3786
0
  }
3787
0
  else
3788
0
    dpns->appendrels = NULL; /* don't need it */
3789
3790
  /*
3791
   * Set up column name aliases, ignoring any join RTEs; they don't matter
3792
   * because plan trees don't contain any join alias Vars.
3793
   */
3794
0
  set_simple_column_names(dpns);
3795
3796
  /* Return a one-deep namespace stack */
3797
0
  return list_make1(dpns);
3798
0
}
3799
3800
/*
3801
 * set_deparse_context_plan - Specify Plan node containing expression
3802
 *
3803
 * When deparsing an expression in a Plan tree, we might have to resolve
3804
 * OUTER_VAR, INNER_VAR, or INDEX_VAR references.  To do this, the caller must
3805
 * provide the parent Plan node.  Then OUTER_VAR and INNER_VAR references
3806
 * can be resolved by drilling down into the left and right child plans.
3807
 * Similarly, INDEX_VAR references can be resolved by reference to the
3808
 * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3809
 * ForeignScan and CustomScan nodes.  (Note that we don't currently support
3810
 * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3811
 * for those, we can only deparse the indexqualorig fields, which won't
3812
 * contain INDEX_VAR Vars.)
3813
 *
3814
 * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3815
 * the most-closely-nested first.  This is needed to resolve PARAM_EXEC
3816
 * Params.  Note we assume that all the Plan nodes share the same rtable.
3817
 *
3818
 * For a ModifyTable plan, we might also need to resolve references to OLD/NEW
3819
 * variables in the RETURNING list, so we copy the alias names of the OLD and
3820
 * NEW rows from the ModifyTable plan node.
3821
 *
3822
 * Once this function has been called, deparse_expression() can be called on
3823
 * subsidiary expression(s) of the specified Plan node.  To deparse
3824
 * expressions of a different Plan node in the same Plan tree, re-call this
3825
 * function to identify the new parent Plan node.
3826
 *
3827
 * The result is the same List passed in; this is a notational convenience.
3828
 */
3829
List *
3830
set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3831
0
{
3832
0
  deparse_namespace *dpns;
3833
3834
  /* Should always have one-entry namespace list for Plan deparsing */
3835
0
  Assert(list_length(dpcontext) == 1);
3836
0
  dpns = (deparse_namespace *) linitial(dpcontext);
3837
3838
  /* Set our attention on the specific plan node passed in */
3839
0
  dpns->ancestors = ancestors;
3840
0
  set_deparse_plan(dpns, plan);
3841
3842
  /* For ModifyTable, set aliases for OLD and NEW in RETURNING */
3843
0
  if (IsA(plan, ModifyTable))
3844
0
  {
3845
0
    dpns->ret_old_alias = ((ModifyTable *) plan)->returningOldAlias;
3846
0
    dpns->ret_new_alias = ((ModifyTable *) plan)->returningNewAlias;
3847
0
  }
3848
3849
0
  return dpcontext;
3850
0
}
3851
3852
/*
3853
 * select_rtable_names_for_explain  - Select RTE aliases for EXPLAIN
3854
 *
3855
 * Determine the relation aliases we'll use during an EXPLAIN operation.
3856
 * This is just a frontend to set_rtable_names.  We have to expose the aliases
3857
 * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3858
 */
3859
List *
3860
select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
3861
0
{
3862
0
  deparse_namespace dpns;
3863
3864
0
  memset(&dpns, 0, sizeof(dpns));
3865
0
  dpns.rtable = rtable;
3866
0
  dpns.subplans = NIL;
3867
0
  dpns.ctes = NIL;
3868
0
  dpns.appendrels = NULL;
3869
0
  set_rtable_names(&dpns, NIL, rels_used);
3870
  /* We needn't bother computing column aliases yet */
3871
3872
0
  return dpns.rtable_names;
3873
0
}
3874
3875
/*
3876
 * set_rtable_names: select RTE aliases to be used in printing a query
3877
 *
3878
 * We fill in dpns->rtable_names with a list of names that is one-for-one with
3879
 * the already-filled dpns->rtable list.  Each RTE name is unique among those
3880
 * in the new namespace plus any ancestor namespaces listed in
3881
 * parent_namespaces.
3882
 *
3883
 * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3884
 *
3885
 * Note that this function is only concerned with relation names, not column
3886
 * names.
3887
 */
3888
static void
3889
set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3890
         Bitmapset *rels_used)
3891
0
{
3892
0
  HASHCTL   hash_ctl;
3893
0
  HTAB     *names_hash;
3894
0
  NameHashEntry *hentry;
3895
0
  bool    found;
3896
0
  int     rtindex;
3897
0
  ListCell   *lc;
3898
3899
0
  dpns->rtable_names = NIL;
3900
  /* nothing more to do if empty rtable */
3901
0
  if (dpns->rtable == NIL)
3902
0
    return;
3903
3904
  /*
3905
   * We use a hash table to hold known names, so that this process is O(N)
3906
   * not O(N^2) for N names.
3907
   */
3908
0
  hash_ctl.keysize = NAMEDATALEN;
3909
0
  hash_ctl.entrysize = sizeof(NameHashEntry);
3910
0
  hash_ctl.hcxt = CurrentMemoryContext;
3911
0
  names_hash = hash_create("set_rtable_names names",
3912
0
               list_length(dpns->rtable),
3913
0
               &hash_ctl,
3914
0
               HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3915
3916
  /* Preload the hash table with names appearing in parent_namespaces */
3917
0
  foreach(lc, parent_namespaces)
3918
0
  {
3919
0
    deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3920
0
    ListCell   *lc2;
3921
3922
0
    foreach(lc2, olddpns->rtable_names)
3923
0
    {
3924
0
      char     *oldname = (char *) lfirst(lc2);
3925
3926
0
      if (oldname == NULL)
3927
0
        continue;
3928
0
      hentry = (NameHashEntry *) hash_search(names_hash,
3929
0
                           oldname,
3930
0
                           HASH_ENTER,
3931
0
                           &found);
3932
      /* we do not complain about duplicate names in parent namespaces */
3933
0
      hentry->counter = 0;
3934
0
    }
3935
0
  }
3936
3937
  /* Now we can scan the rtable */
3938
0
  rtindex = 1;
3939
0
  foreach(lc, dpns->rtable)
3940
0
  {
3941
0
    RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3942
0
    char     *refname;
3943
3944
    /* Just in case this takes an unreasonable amount of time ... */
3945
0
    CHECK_FOR_INTERRUPTS();
3946
3947
0
    if (rels_used && !bms_is_member(rtindex, rels_used))
3948
0
    {
3949
      /* Ignore unreferenced RTE */
3950
0
      refname = NULL;
3951
0
    }
3952
0
    else if (rte->alias)
3953
0
    {
3954
      /* If RTE has a user-defined alias, prefer that */
3955
0
      refname = rte->alias->aliasname;
3956
0
    }
3957
0
    else if (rte->rtekind == RTE_RELATION)
3958
0
    {
3959
      /* Use the current actual name of the relation */
3960
0
      refname = get_rel_name(rte->relid);
3961
0
    }
3962
0
    else if (rte->rtekind == RTE_JOIN)
3963
0
    {
3964
      /* Unnamed join has no refname */
3965
0
      refname = NULL;
3966
0
    }
3967
0
    else
3968
0
    {
3969
      /* Otherwise use whatever the parser assigned */
3970
0
      refname = rte->eref->aliasname;
3971
0
    }
3972
3973
    /*
3974
     * If the selected name isn't unique, append digits to make it so, and
3975
     * make a new hash entry for it once we've got a unique name.  For a
3976
     * very long input name, we might have to truncate to stay within
3977
     * NAMEDATALEN.
3978
     */
3979
0
    if (refname)
3980
0
    {
3981
0
      hentry = (NameHashEntry *) hash_search(names_hash,
3982
0
                           refname,
3983
0
                           HASH_ENTER,
3984
0
                           &found);
3985
0
      if (found)
3986
0
      {
3987
        /* Name already in use, must choose a new one */
3988
0
        int     refnamelen = strlen(refname);
3989
0
        char     *modname = (char *) palloc(refnamelen + 16);
3990
0
        NameHashEntry *hentry2;
3991
3992
0
        do
3993
0
        {
3994
0
          hentry->counter++;
3995
0
          for (;;)
3996
0
          {
3997
0
            memcpy(modname, refname, refnamelen);
3998
0
            sprintf(modname + refnamelen, "_%d", hentry->counter);
3999
0
            if (strlen(modname) < NAMEDATALEN)
4000
0
              break;
4001
            /* drop chars from refname to keep all the digits */
4002
0
            refnamelen = pg_mbcliplen(refname, refnamelen,
4003
0
                          refnamelen - 1);
4004
0
          }
4005
0
          hentry2 = (NameHashEntry *) hash_search(names_hash,
4006
0
                              modname,
4007
0
                              HASH_ENTER,
4008
0
                              &found);
4009
0
        } while (found);
4010
0
        hentry2->counter = 0; /* init new hash entry */
4011
0
        refname = modname;
4012
0
      }
4013
0
      else
4014
0
      {
4015
        /* Name not previously used, need only initialize hentry */
4016
0
        hentry->counter = 0;
4017
0
      }
4018
0
    }
4019
4020
0
    dpns->rtable_names = lappend(dpns->rtable_names, refname);
4021
0
    rtindex++;
4022
0
  }
4023
4024
0
  hash_destroy(names_hash);
4025
0
}
4026
4027
/*
4028
 * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
4029
 *
4030
 * For convenience, this is defined to initialize the deparse_namespace struct
4031
 * from scratch.
4032
 */
4033
static void
4034
set_deparse_for_query(deparse_namespace *dpns, Query *query,
4035
            List *parent_namespaces)
4036
0
{
4037
0
  ListCell   *lc;
4038
0
  ListCell   *lc2;
4039
4040
  /* Initialize *dpns and fill rtable/ctes links */
4041
0
  memset(dpns, 0, sizeof(deparse_namespace));
4042
0
  dpns->rtable = query->rtable;
4043
0
  dpns->subplans = NIL;
4044
0
  dpns->ctes = query->cteList;
4045
0
  dpns->appendrels = NULL;
4046
0
  dpns->ret_old_alias = query->returningOldAlias;
4047
0
  dpns->ret_new_alias = query->returningNewAlias;
4048
4049
  /* Assign a unique relation alias to each RTE */
4050
0
  set_rtable_names(dpns, parent_namespaces, NULL);
4051
4052
  /* Initialize dpns->rtable_columns to contain zeroed structs */
4053
0
  dpns->rtable_columns = NIL;
4054
0
  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4055
0
    dpns->rtable_columns = lappend(dpns->rtable_columns,
4056
0
                     palloc0_object(deparse_columns));
4057
4058
  /* If it's a utility query, it won't have a jointree */
4059
0
  if (query->jointree)
4060
0
  {
4061
    /* Detect whether global uniqueness of USING names is needed */
4062
0
    dpns->unique_using =
4063
0
      has_dangerous_join_using(dpns, (Node *) query->jointree);
4064
4065
    /*
4066
     * Select names for columns merged by USING, via a recursive pass over
4067
     * the query jointree.
4068
     */
4069
0
    set_using_names(dpns, (Node *) query->jointree, NIL);
4070
0
  }
4071
4072
  /*
4073
   * Now assign remaining column aliases for each RTE.  We do this in a
4074
   * linear scan of the rtable, so as to process RTEs whether or not they
4075
   * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4076
   * etc).  JOIN RTEs must be processed after their children, but this is
4077
   * okay because they appear later in the rtable list than their children
4078
   * (cf Asserts in identify_join_columns()).
4079
   */
4080
0
  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4081
0
  {
4082
0
    RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4083
0
    deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4084
4085
0
    if (rte->rtekind == RTE_JOIN)
4086
0
      set_join_column_names(dpns, rte, colinfo);
4087
0
    else
4088
0
      set_relation_column_names(dpns, rte, colinfo);
4089
0
  }
4090
0
}
4091
4092
/*
4093
 * set_simple_column_names: fill in column aliases for non-query situations
4094
 *
4095
 * This handles EXPLAIN and cases where we only have relation RTEs.  Without
4096
 * a join tree, we can't do anything smart about join RTEs, but we don't
4097
 * need to, because EXPLAIN should never see join alias Vars anyway.
4098
 * If we find a join RTE we'll just skip it, leaving its deparse_columns
4099
 * struct all-zero.  If somehow we try to deparse a join alias Var, we'll
4100
 * error out cleanly because the struct's num_cols will be zero.
4101
 */
4102
static void
4103
set_simple_column_names(deparse_namespace *dpns)
4104
0
{
4105
0
  ListCell   *lc;
4106
0
  ListCell   *lc2;
4107
4108
  /* Initialize dpns->rtable_columns to contain zeroed structs */
4109
0
  dpns->rtable_columns = NIL;
4110
0
  while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4111
0
    dpns->rtable_columns = lappend(dpns->rtable_columns,
4112
0
                     palloc0_object(deparse_columns));
4113
4114
  /* Assign unique column aliases within each non-join RTE */
4115
0
  forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4116
0
  {
4117
0
    RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4118
0
    deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4119
4120
0
    if (rte->rtekind != RTE_JOIN)
4121
0
      set_relation_column_names(dpns, rte, colinfo);
4122
0
  }
4123
0
}
4124
4125
/*
4126
 * has_dangerous_join_using: search jointree for unnamed JOIN USING
4127
 *
4128
 * Merged columns of a JOIN USING may act differently from either of the input
4129
 * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4130
 * because an implicit coercion of the underlying input column is required.
4131
 * In such a case the column must be referenced as a column of the JOIN not as
4132
 * a column of either input.  And this is problematic if the join is unnamed
4133
 * (alias-less): we cannot qualify the column's name with an RTE name, since
4134
 * there is none.  (Forcibly assigning an alias to the join is not a solution,
4135
 * since that will prevent legal references to tables below the join.)
4136
 * To ensure that every column in the query is unambiguously referenceable,
4137
 * we must assign such merged columns names that are globally unique across
4138
 * the whole query, aliasing other columns out of the way as necessary.
4139
 *
4140
 * Because the ensuing re-aliasing is fairly damaging to the readability of
4141
 * the query, we don't do this unless we have to.  So, we must pre-scan
4142
 * the join tree to see if we have to, before starting set_using_names().
4143
 */
4144
static bool
4145
has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
4146
0
{
4147
0
  if (IsA(jtnode, RangeTblRef))
4148
0
  {
4149
    /* nothing to do here */
4150
0
  }
4151
0
  else if (IsA(jtnode, FromExpr))
4152
0
  {
4153
0
    FromExpr   *f = (FromExpr *) jtnode;
4154
0
    ListCell   *lc;
4155
4156
0
    foreach(lc, f->fromlist)
4157
0
    {
4158
0
      if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4159
0
        return true;
4160
0
    }
4161
0
  }
4162
0
  else if (IsA(jtnode, JoinExpr))
4163
0
  {
4164
0
    JoinExpr   *j = (JoinExpr *) jtnode;
4165
4166
    /* Is it an unnamed JOIN with USING? */
4167
0
    if (j->alias == NULL && j->usingClause)
4168
0
    {
4169
      /*
4170
       * Yes, so check each join alias var to see if any of them are not
4171
       * simple references to underlying columns.  If so, we have a
4172
       * dangerous situation and must pick unique aliases.
4173
       */
4174
0
      RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4175
4176
      /* We need only examine the merged columns */
4177
0
      for (int i = 0; i < jrte->joinmergedcols; i++)
4178
0
      {
4179
0
        Node     *aliasvar = list_nth(jrte->joinaliasvars, i);
4180
4181
0
        if (!IsA(aliasvar, Var))
4182
0
          return true;
4183
0
      }
4184
0
    }
4185
4186
    /* Nope, but inspect children */
4187
0
    if (has_dangerous_join_using(dpns, j->larg))
4188
0
      return true;
4189
0
    if (has_dangerous_join_using(dpns, j->rarg))
4190
0
      return true;
4191
0
  }
4192
0
  else
4193
0
    elog(ERROR, "unrecognized node type: %d",
4194
0
       (int) nodeTag(jtnode));
4195
0
  return false;
4196
0
}
4197
4198
/*
4199
 * set_using_names: select column aliases to be used for merged USING columns
4200
 *
4201
 * We do this during a recursive descent of the query jointree.
4202
 * dpns->unique_using must already be set to determine the global strategy.
4203
 *
4204
 * Column alias info is saved in the dpns->rtable_columns list, which is
4205
 * assumed to be filled with pre-zeroed deparse_columns structs.
4206
 *
4207
 * parentUsing is a list of all USING aliases assigned in parent joins of
4208
 * the current jointree node.  (The passed-in list must not be modified.)
4209
 *
4210
 * Note that we do not use per-deparse_columns hash tables in this function.
4211
 * The number of names that need to be assigned should be small enough that
4212
 * we don't need to trouble with that.
4213
 */
4214
static void
4215
set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4216
0
{
4217
0
  if (IsA(jtnode, RangeTblRef))
4218
0
  {
4219
    /* nothing to do now */
4220
0
  }
4221
0
  else if (IsA(jtnode, FromExpr))
4222
0
  {
4223
0
    FromExpr   *f = (FromExpr *) jtnode;
4224
0
    ListCell   *lc;
4225
4226
0
    foreach(lc, f->fromlist)
4227
0
      set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4228
0
  }
4229
0
  else if (IsA(jtnode, JoinExpr))
4230
0
  {
4231
0
    JoinExpr   *j = (JoinExpr *) jtnode;
4232
0
    RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4233
0
    deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4234
0
    int      *leftattnos;
4235
0
    int      *rightattnos;
4236
0
    deparse_columns *leftcolinfo;
4237
0
    deparse_columns *rightcolinfo;
4238
0
    int     i;
4239
0
    ListCell   *lc;
4240
4241
    /* Get info about the shape of the join */
4242
0
    identify_join_columns(j, rte, colinfo);
4243
0
    leftattnos = colinfo->leftattnos;
4244
0
    rightattnos = colinfo->rightattnos;
4245
4246
    /* Look up the not-yet-filled-in child deparse_columns structs */
4247
0
    leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4248
0
    rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4249
4250
    /*
4251
     * If this join is unnamed, then we cannot substitute new aliases at
4252
     * this level, so any name requirements pushed down to here must be
4253
     * pushed down again to the children.
4254
     */
4255
0
    if (rte->alias == NULL)
4256
0
    {
4257
0
      for (i = 0; i < colinfo->num_cols; i++)
4258
0
      {
4259
0
        char     *colname = colinfo->colnames[i];
4260
4261
0
        if (colname == NULL)
4262
0
          continue;
4263
4264
        /* Push down to left column, unless it's a system column */
4265
0
        if (leftattnos[i] > 0)
4266
0
        {
4267
0
          expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4268
0
          leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4269
0
        }
4270
4271
        /* Same on the righthand side */
4272
0
        if (rightattnos[i] > 0)
4273
0
        {
4274
0
          expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4275
0
          rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4276
0
        }
4277
0
      }
4278
0
    }
4279
4280
    /*
4281
     * If there's a USING clause, select the USING column names and push
4282
     * those names down to the children.  We have two strategies:
4283
     *
4284
     * If dpns->unique_using is true, we force all USING names to be
4285
     * unique across the whole query level.  In principle we'd only need
4286
     * the names of dangerous USING columns to be globally unique, but to
4287
     * safely assign all USING names in a single pass, we have to enforce
4288
     * the same uniqueness rule for all of them.  However, if a USING
4289
     * column's name has been pushed down from the parent, we should use
4290
     * it as-is rather than making a uniqueness adjustment.  This is
4291
     * necessary when we're at an unnamed join, and it creates no risk of
4292
     * ambiguity.  Also, if there's a user-written output alias for a
4293
     * merged column, we prefer to use that rather than the input name;
4294
     * this simplifies the logic and seems likely to lead to less aliasing
4295
     * overall.
4296
     *
4297
     * If dpns->unique_using is false, we only need USING names to be
4298
     * unique within their own join RTE.  We still need to honor
4299
     * pushed-down names, though.
4300
     *
4301
     * Though significantly different in results, these two strategies are
4302
     * implemented by the same code, with only the difference of whether
4303
     * to put assigned names into dpns->using_names.
4304
     */
4305
0
    if (j->usingClause)
4306
0
    {
4307
      /* Copy the input parentUsing list so we don't modify it */
4308
0
      parentUsing = list_copy(parentUsing);
4309
4310
      /* USING names must correspond to the first join output columns */
4311
0
      expand_colnames_array_to(colinfo, list_length(j->usingClause));
4312
0
      i = 0;
4313
0
      foreach(lc, j->usingClause)
4314
0
      {
4315
0
        char     *colname = strVal(lfirst(lc));
4316
4317
        /* Assert it's a merged column */
4318
0
        Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4319
4320
        /* Adopt passed-down name if any, else select unique name */
4321
0
        if (colinfo->colnames[i] != NULL)
4322
0
          colname = colinfo->colnames[i];
4323
0
        else
4324
0
        {
4325
          /* Prefer user-written output alias if any */
4326
0
          if (rte->alias && i < list_length(rte->alias->colnames))
4327
0
            colname = strVal(list_nth(rte->alias->colnames, i));
4328
          /* Make it appropriately unique */
4329
0
          colname = make_colname_unique(colname, dpns, colinfo);
4330
0
          if (dpns->unique_using)
4331
0
            dpns->using_names = lappend(dpns->using_names,
4332
0
                          colname);
4333
          /* Save it as output column name, too */
4334
0
          colinfo->colnames[i] = colname;
4335
0
        }
4336
4337
        /* Remember selected names for use later */
4338
0
        colinfo->usingNames = lappend(colinfo->usingNames, colname);
4339
0
        parentUsing = lappend(parentUsing, colname);
4340
4341
        /* Push down to left column, unless it's a system column */
4342
0
        if (leftattnos[i] > 0)
4343
0
        {
4344
0
          expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4345
0
          leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4346
0
        }
4347
4348
        /* Same on the righthand side */
4349
0
        if (rightattnos[i] > 0)
4350
0
        {
4351
0
          expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4352
0
          rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4353
0
        }
4354
4355
0
        i++;
4356
0
      }
4357
0
    }
4358
4359
    /* Mark child deparse_columns structs with correct parentUsing info */
4360
0
    leftcolinfo->parentUsing = parentUsing;
4361
0
    rightcolinfo->parentUsing = parentUsing;
4362
4363
    /* Now recursively assign USING column names in children */
4364
0
    set_using_names(dpns, j->larg, parentUsing);
4365
0
    set_using_names(dpns, j->rarg, parentUsing);
4366
0
  }
4367
0
  else
4368
0
    elog(ERROR, "unrecognized node type: %d",
4369
0
       (int) nodeTag(jtnode));
4370
0
}
4371
4372
/*
4373
 * set_relation_column_names: select column aliases for a non-join RTE
4374
 *
4375
 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4376
 * If any colnames entries are already filled in, those override local
4377
 * choices.
4378
 */
4379
static void
4380
set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4381
              deparse_columns *colinfo)
4382
0
{
4383
0
  int     ncolumns;
4384
0
  char    **real_colnames;
4385
0
  bool    changed_any;
4386
0
  int     noldcolumns;
4387
0
  int     i;
4388
0
  int     j;
4389
4390
  /*
4391
   * Construct an array of the current "real" column names of the RTE.
4392
   * real_colnames[] will be indexed by physical column number, with NULL
4393
   * entries for dropped columns.
4394
   */
4395
0
  if (rte->rtekind == RTE_RELATION)
4396
0
  {
4397
    /* Relation --- look to the system catalogs for up-to-date info */
4398
0
    Relation  rel;
4399
0
    TupleDesc tupdesc;
4400
4401
0
    rel = relation_open(rte->relid, AccessShareLock);
4402
0
    tupdesc = RelationGetDescr(rel);
4403
4404
0
    ncolumns = tupdesc->natts;
4405
0
    real_colnames = palloc_array(char *, ncolumns);
4406
4407
0
    for (i = 0; i < ncolumns; i++)
4408
0
    {
4409
0
      Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4410
4411
0
      if (attr->attisdropped)
4412
0
        real_colnames[i] = NULL;
4413
0
      else
4414
0
        real_colnames[i] = pstrdup(NameStr(attr->attname));
4415
0
    }
4416
0
    relation_close(rel, AccessShareLock);
4417
0
  }
4418
0
  else
4419
0
  {
4420
    /* Otherwise get the column names from eref or expandRTE() */
4421
0
    List     *colnames;
4422
0
    ListCell   *lc;
4423
4424
    /*
4425
     * Functions returning composites have the annoying property that some
4426
     * of the composite type's columns might have been dropped since the
4427
     * query was parsed.  If possible, use expandRTE() to handle that
4428
     * case, since it has the tedious logic needed to find out about
4429
     * dropped columns.  However, if we're explaining a plan, then we
4430
     * don't have rte->functions because the planner thinks that won't be
4431
     * needed later, and that breaks expandRTE().  So in that case we have
4432
     * to rely on rte->eref, which may lead us to report a dropped
4433
     * column's old name; that seems close enough for EXPLAIN's purposes.
4434
     *
4435
     * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4436
     * which should be sufficiently up-to-date: no other RTE types can
4437
     * have columns get dropped from under them after parsing.
4438
     */
4439
0
    if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4440
0
    {
4441
      /* Since we're not creating Vars, rtindex etc. don't matter */
4442
0
      expandRTE(rte, 1, 0, VAR_RETURNING_DEFAULT, -1,
4443
0
            true /* include dropped */ , &colnames, NULL);
4444
0
    }
4445
0
    else
4446
0
      colnames = rte->eref->colnames;
4447
4448
0
    ncolumns = list_length(colnames);
4449
0
    real_colnames = palloc_array(char *, ncolumns);
4450
4451
0
    i = 0;
4452
0
    foreach(lc, colnames)
4453
0
    {
4454
      /*
4455
       * If the column name we find here is an empty string, then it's a
4456
       * dropped column, so change to NULL.
4457
       */
4458
0
      char     *cname = strVal(lfirst(lc));
4459
4460
0
      if (cname[0] == '\0')
4461
0
        cname = NULL;
4462
0
      real_colnames[i] = cname;
4463
0
      i++;
4464
0
    }
4465
0
  }
4466
4467
  /*
4468
   * Ensure colinfo->colnames has a slot for each column.  (It could be long
4469
   * enough already, if we pushed down a name for the last column.)  Note:
4470
   * it's possible that there are now more columns than there were when the
4471
   * query was parsed, ie colnames could be longer than rte->eref->colnames.
4472
   * We must assign unique aliases to the new columns too, else there could
4473
   * be unresolved conflicts when the view/rule is reloaded.
4474
   */
4475
0
  expand_colnames_array_to(colinfo, ncolumns);
4476
0
  Assert(colinfo->num_cols == ncolumns);
4477
4478
  /*
4479
   * Make sufficiently large new_colnames and is_new_col arrays, too.
4480
   *
4481
   * Note: because we leave colinfo->num_new_cols zero until after the loop,
4482
   * colname_is_unique will not consult that array, which is fine because it
4483
   * would only be duplicate effort.
4484
   */
4485
0
  colinfo->new_colnames = palloc_array(char *, ncolumns);
4486
0
  colinfo->is_new_col = palloc_array(bool, ncolumns);
4487
4488
  /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4489
0
  build_colinfo_names_hash(colinfo);
4490
4491
  /*
4492
   * Scan the columns, select a unique alias for each one, and store it in
4493
   * colinfo->colnames and colinfo->new_colnames.  The former array has NULL
4494
   * entries for dropped columns, the latter omits them.  Also mark
4495
   * new_colnames entries as to whether they are new since parse time; this
4496
   * is the case for entries beyond the length of rte->eref->colnames.
4497
   */
4498
0
  noldcolumns = list_length(rte->eref->colnames);
4499
0
  changed_any = false;
4500
0
  j = 0;
4501
0
  for (i = 0; i < ncolumns; i++)
4502
0
  {
4503
0
    char     *real_colname = real_colnames[i];
4504
0
    char     *colname = colinfo->colnames[i];
4505
4506
    /* Skip dropped columns */
4507
0
    if (real_colname == NULL)
4508
0
    {
4509
0
      Assert(colname == NULL);  /* colnames[i] is already NULL */
4510
0
      continue;
4511
0
    }
4512
4513
    /* If alias already assigned, that's what to use */
4514
0
    if (colname == NULL)
4515
0
    {
4516
      /* If user wrote an alias, prefer that over real column name */
4517
0
      if (rte->alias && i < list_length(rte->alias->colnames))
4518
0
        colname = strVal(list_nth(rte->alias->colnames, i));
4519
0
      else
4520
0
        colname = real_colname;
4521
4522
      /* Unique-ify and insert into colinfo */
4523
0
      colname = make_colname_unique(colname, dpns, colinfo);
4524
4525
0
      colinfo->colnames[i] = colname;
4526
0
      add_to_names_hash(colinfo, colname);
4527
0
    }
4528
4529
    /* Put names of non-dropped columns in new_colnames[] too */
4530
0
    colinfo->new_colnames[j] = colname;
4531
    /* And mark them as new or not */
4532
0
    colinfo->is_new_col[j] = (i >= noldcolumns);
4533
0
    j++;
4534
4535
    /* Remember if any assigned aliases differ from "real" name */
4536
0
    if (!changed_any && strcmp(colname, real_colname) != 0)
4537
0
      changed_any = true;
4538
0
  }
4539
4540
  /* We're now done needing the colinfo's names_hash */
4541
0
  destroy_colinfo_names_hash(colinfo);
4542
4543
  /*
4544
   * Set correct length for new_colnames[] array.  (Note: if columns have
4545
   * been added, colinfo->num_cols includes them, which is not really quite
4546
   * right but is harmless, since any new columns must be at the end where
4547
   * they won't affect varattnos of pre-existing columns.)
4548
   */
4549
0
  colinfo->num_new_cols = j;
4550
4551
  /*
4552
   * For a relation RTE, we need only print the alias column names if any
4553
   * are different from the underlying "real" names.  For a function RTE,
4554
   * always emit a complete column alias list; this is to protect against
4555
   * possible instability of the default column names (eg, from altering
4556
   * parameter names).  For tablefunc RTEs, we never print aliases, because
4557
   * the column names are part of the clause itself.  For other RTE types,
4558
   * print if we changed anything OR if there were user-written column
4559
   * aliases (since the latter would be part of the underlying "reality").
4560
   */
4561
0
  if (rte->rtekind == RTE_RELATION)
4562
0
    colinfo->printaliases = changed_any;
4563
0
  else if (rte->rtekind == RTE_FUNCTION)
4564
0
    colinfo->printaliases = true;
4565
0
  else if (rte->rtekind == RTE_TABLEFUNC)
4566
0
    colinfo->printaliases = false;
4567
0
  else if (rte->alias && rte->alias->colnames != NIL)
4568
0
    colinfo->printaliases = true;
4569
0
  else
4570
0
    colinfo->printaliases = changed_any;
4571
0
}
4572
4573
/*
4574
 * set_join_column_names: select column aliases for a join RTE
4575
 *
4576
 * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4577
 * If any colnames entries are already filled in, those override local
4578
 * choices.  Also, names for USING columns were already chosen by
4579
 * set_using_names().  We further expect that column alias selection has been
4580
 * completed for both input RTEs.
4581
 */
4582
static void
4583
set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4584
            deparse_columns *colinfo)
4585
0
{
4586
0
  deparse_columns *leftcolinfo;
4587
0
  deparse_columns *rightcolinfo;
4588
0
  bool    changed_any;
4589
0
  int     noldcolumns;
4590
0
  int     nnewcolumns;
4591
0
  Bitmapset  *leftmerged = NULL;
4592
0
  Bitmapset  *rightmerged = NULL;
4593
0
  int     i;
4594
0
  int     j;
4595
0
  int     ic;
4596
0
  int     jc;
4597
4598
  /* Look up the previously-filled-in child deparse_columns structs */
4599
0
  leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4600
0
  rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4601
4602
  /*
4603
   * Ensure colinfo->colnames has a slot for each column.  (It could be long
4604
   * enough already, if we pushed down a name for the last column.)  Note:
4605
   * it's possible that one or both inputs now have more columns than there
4606
   * were when the query was parsed, but we'll deal with that below.  We
4607
   * only need entries in colnames for pre-existing columns.
4608
   */
4609
0
  noldcolumns = list_length(rte->eref->colnames);
4610
0
  expand_colnames_array_to(colinfo, noldcolumns);
4611
0
  Assert(colinfo->num_cols == noldcolumns);
4612
4613
  /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4614
0
  build_colinfo_names_hash(colinfo);
4615
4616
  /*
4617
   * Scan the join output columns, select an alias for each one, and store
4618
   * it in colinfo->colnames.  If there are USING columns, set_using_names()
4619
   * already selected their names, so we can start the loop at the first
4620
   * non-merged column.
4621
   */
4622
0
  changed_any = false;
4623
0
  for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4624
0
  {
4625
0
    char     *colname = colinfo->colnames[i];
4626
0
    char     *real_colname;
4627
4628
    /* Join column must refer to at least one input column */
4629
0
    Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4630
4631
    /* Get the child column name */
4632
0
    if (colinfo->leftattnos[i] > 0)
4633
0
      real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4634
0
    else if (colinfo->rightattnos[i] > 0)
4635
0
      real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4636
0
    else
4637
0
    {
4638
      /* We're joining system columns --- use eref name */
4639
0
      real_colname = strVal(list_nth(rte->eref->colnames, i));
4640
0
    }
4641
4642
    /* If child col has been dropped, no need to assign a join colname */
4643
0
    if (real_colname == NULL)
4644
0
    {
4645
0
      colinfo->colnames[i] = NULL;
4646
0
      continue;
4647
0
    }
4648
4649
    /* In an unnamed join, just report child column names as-is */
4650
0
    if (rte->alias == NULL)
4651
0
    {
4652
0
      colinfo->colnames[i] = real_colname;
4653
0
      add_to_names_hash(colinfo, real_colname);
4654
0
      continue;
4655
0
    }
4656
4657
    /* If alias already assigned, that's what to use */
4658
0
    if (colname == NULL)
4659
0
    {
4660
      /* If user wrote an alias, prefer that over real column name */
4661
0
      if (rte->alias && i < list_length(rte->alias->colnames))
4662
0
        colname = strVal(list_nth(rte->alias->colnames, i));
4663
0
      else
4664
0
        colname = real_colname;
4665
4666
      /* Unique-ify and insert into colinfo */
4667
0
      colname = make_colname_unique(colname, dpns, colinfo);
4668
4669
0
      colinfo->colnames[i] = colname;
4670
0
      add_to_names_hash(colinfo, colname);
4671
0
    }
4672
4673
    /* Remember if any assigned aliases differ from "real" name */
4674
0
    if (!changed_any && strcmp(colname, real_colname) != 0)
4675
0
      changed_any = true;
4676
0
  }
4677
4678
  /*
4679
   * Calculate number of columns the join would have if it were re-parsed
4680
   * now, and create storage for the new_colnames and is_new_col arrays.
4681
   *
4682
   * Note: colname_is_unique will be consulting new_colnames[] during the
4683
   * loops below, so its not-yet-filled entries must be zeroes.
4684
   */
4685
0
  nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4686
0
    list_length(colinfo->usingNames);
4687
0
  colinfo->num_new_cols = nnewcolumns;
4688
0
  colinfo->new_colnames = palloc0_array(char *, nnewcolumns);
4689
0
  colinfo->is_new_col = palloc0_array(bool, nnewcolumns);
4690
4691
  /*
4692
   * Generating the new_colnames array is a bit tricky since any new columns
4693
   * added since parse time must be inserted in the right places.  This code
4694
   * must match the parser, which will order a join's columns as merged
4695
   * columns first (in USING-clause order), then non-merged columns from the
4696
   * left input (in attnum order), then non-merged columns from the right
4697
   * input (ditto).  If one of the inputs is itself a join, its columns will
4698
   * be ordered according to the same rule, which means newly-added columns
4699
   * might not be at the end.  We can figure out what's what by consulting
4700
   * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4701
   *
4702
   * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4703
   * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4704
   * meanings for the current child RTE.
4705
   */
4706
4707
  /* Handle merged columns; they are first and can't be new */
4708
0
  i = j = 0;
4709
0
  while (i < noldcolumns &&
4710
0
       colinfo->leftattnos[i] != 0 &&
4711
0
       colinfo->rightattnos[i] != 0)
4712
0
  {
4713
    /* column name is already determined and known unique */
4714
0
    colinfo->new_colnames[j] = colinfo->colnames[i];
4715
0
    colinfo->is_new_col[j] = false;
4716
4717
    /* build bitmapsets of child attnums of merged columns */
4718
0
    if (colinfo->leftattnos[i] > 0)
4719
0
      leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4720
0
    if (colinfo->rightattnos[i] > 0)
4721
0
      rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4722
4723
0
    i++, j++;
4724
0
  }
4725
4726
  /* Handle non-merged left-child columns */
4727
0
  ic = 0;
4728
0
  for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4729
0
  {
4730
0
    char     *child_colname = leftcolinfo->new_colnames[jc];
4731
4732
0
    if (!leftcolinfo->is_new_col[jc])
4733
0
    {
4734
      /* Advance ic to next non-dropped old column of left child */
4735
0
      while (ic < leftcolinfo->num_cols &&
4736
0
           leftcolinfo->colnames[ic] == NULL)
4737
0
        ic++;
4738
0
      Assert(ic < leftcolinfo->num_cols);
4739
0
      ic++;
4740
      /* If it is a merged column, we already processed it */
4741
0
      if (bms_is_member(ic, leftmerged))
4742
0
        continue;
4743
      /* Else, advance i to the corresponding existing join column */
4744
0
      while (i < colinfo->num_cols &&
4745
0
           colinfo->colnames[i] == NULL)
4746
0
        i++;
4747
0
      Assert(i < colinfo->num_cols);
4748
0
      Assert(ic == colinfo->leftattnos[i]);
4749
      /* Use the already-assigned name of this column */
4750
0
      colinfo->new_colnames[j] = colinfo->colnames[i];
4751
0
      i++;
4752
0
    }
4753
0
    else
4754
0
    {
4755
      /*
4756
       * Unique-ify the new child column name and assign, unless we're
4757
       * in an unnamed join, in which case just copy
4758
       */
4759
0
      if (rte->alias != NULL)
4760
0
      {
4761
0
        colinfo->new_colnames[j] =
4762
0
          make_colname_unique(child_colname, dpns, colinfo);
4763
0
        if (!changed_any &&
4764
0
          strcmp(colinfo->new_colnames[j], child_colname) != 0)
4765
0
          changed_any = true;
4766
0
      }
4767
0
      else
4768
0
        colinfo->new_colnames[j] = child_colname;
4769
0
      add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4770
0
    }
4771
4772
0
    colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4773
0
    j++;
4774
0
  }
4775
4776
  /* Handle non-merged right-child columns in exactly the same way */
4777
0
  ic = 0;
4778
0
  for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4779
0
  {
4780
0
    char     *child_colname = rightcolinfo->new_colnames[jc];
4781
4782
0
    if (!rightcolinfo->is_new_col[jc])
4783
0
    {
4784
      /* Advance ic to next non-dropped old column of right child */
4785
0
      while (ic < rightcolinfo->num_cols &&
4786
0
           rightcolinfo->colnames[ic] == NULL)
4787
0
        ic++;
4788
0
      Assert(ic < rightcolinfo->num_cols);
4789
0
      ic++;
4790
      /* If it is a merged column, we already processed it */
4791
0
      if (bms_is_member(ic, rightmerged))
4792
0
        continue;
4793
      /* Else, advance i to the corresponding existing join column */
4794
0
      while (i < colinfo->num_cols &&
4795
0
           colinfo->colnames[i] == NULL)
4796
0
        i++;
4797
0
      Assert(i < colinfo->num_cols);
4798
0
      Assert(ic == colinfo->rightattnos[i]);
4799
      /* Use the already-assigned name of this column */
4800
0
      colinfo->new_colnames[j] = colinfo->colnames[i];
4801
0
      i++;
4802
0
    }
4803
0
    else
4804
0
    {
4805
      /*
4806
       * Unique-ify the new child column name and assign, unless we're
4807
       * in an unnamed join, in which case just copy
4808
       */
4809
0
      if (rte->alias != NULL)
4810
0
      {
4811
0
        colinfo->new_colnames[j] =
4812
0
          make_colname_unique(child_colname, dpns, colinfo);
4813
0
        if (!changed_any &&
4814
0
          strcmp(colinfo->new_colnames[j], child_colname) != 0)
4815
0
          changed_any = true;
4816
0
      }
4817
0
      else
4818
0
        colinfo->new_colnames[j] = child_colname;
4819
0
      add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4820
0
    }
4821
4822
0
    colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4823
0
    j++;
4824
0
  }
4825
4826
  /* Assert we processed the right number of columns */
4827
#ifdef USE_ASSERT_CHECKING
4828
  while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4829
    i++;
4830
  Assert(i == colinfo->num_cols);
4831
  Assert(j == nnewcolumns);
4832
#endif
4833
4834
  /* We're now done needing the colinfo's names_hash */
4835
0
  destroy_colinfo_names_hash(colinfo);
4836
4837
  /*
4838
   * For a named join, print column aliases if we changed any from the child
4839
   * names.  Unnamed joins cannot print aliases.
4840
   */
4841
0
  if (rte->alias != NULL)
4842
0
    colinfo->printaliases = changed_any;
4843
0
  else
4844
0
    colinfo->printaliases = false;
4845
0
}
4846
4847
/*
4848
 * colname_is_unique: is colname distinct from already-chosen column names?
4849
 *
4850
 * dpns is query-wide info, colinfo is for the column's RTE
4851
 */
4852
static bool
4853
colname_is_unique(const char *colname, deparse_namespace *dpns,
4854
          deparse_columns *colinfo)
4855
0
{
4856
0
  int     i;
4857
0
  ListCell   *lc;
4858
4859
  /*
4860
   * If we have a hash table, consult that instead of linearly scanning the
4861
   * colinfo's strings.
4862
   */
4863
0
  if (colinfo->names_hash)
4864
0
  {
4865
0
    if (hash_search(colinfo->names_hash,
4866
0
            colname,
4867
0
            HASH_FIND,
4868
0
            NULL) != NULL)
4869
0
      return false;
4870
0
  }
4871
0
  else
4872
0
  {
4873
    /* Check against already-assigned column aliases within RTE */
4874
0
    for (i = 0; i < colinfo->num_cols; i++)
4875
0
    {
4876
0
      char     *oldname = colinfo->colnames[i];
4877
4878
0
      if (oldname && strcmp(oldname, colname) == 0)
4879
0
        return false;
4880
0
    }
4881
4882
    /*
4883
     * If we're building a new_colnames array, check that too (this will
4884
     * be partially but not completely redundant with the previous checks)
4885
     */
4886
0
    for (i = 0; i < colinfo->num_new_cols; i++)
4887
0
    {
4888
0
      char     *oldname = colinfo->new_colnames[i];
4889
4890
0
      if (oldname && strcmp(oldname, colname) == 0)
4891
0
        return false;
4892
0
    }
4893
4894
    /*
4895
     * Also check against names already assigned for parent-join USING
4896
     * cols
4897
     */
4898
0
    foreach(lc, colinfo->parentUsing)
4899
0
    {
4900
0
      char     *oldname = (char *) lfirst(lc);
4901
4902
0
      if (strcmp(oldname, colname) == 0)
4903
0
        return false;
4904
0
    }
4905
0
  }
4906
4907
  /*
4908
   * Also check against USING-column names that must be globally unique.
4909
   * These are not hashed, but there should be few of them.
4910
   */
4911
0
  foreach(lc, dpns->using_names)
4912
0
  {
4913
0
    char     *oldname = (char *) lfirst(lc);
4914
4915
0
    if (strcmp(oldname, colname) == 0)
4916
0
      return false;
4917
0
  }
4918
4919
0
  return true;
4920
0
}
4921
4922
/*
4923
 * make_colname_unique: modify colname if necessary to make it unique
4924
 *
4925
 * dpns is query-wide info, colinfo is for the column's RTE
4926
 */
4927
static char *
4928
make_colname_unique(char *colname, deparse_namespace *dpns,
4929
          deparse_columns *colinfo)
4930
0
{
4931
  /*
4932
   * If the selected name isn't unique, append digits to make it so.  For a
4933
   * very long input name, we might have to truncate to stay within
4934
   * NAMEDATALEN.
4935
   */
4936
0
  if (!colname_is_unique(colname, dpns, colinfo))
4937
0
  {
4938
0
    int     colnamelen = strlen(colname);
4939
0
    char     *modname = (char *) palloc(colnamelen + 16);
4940
0
    int     i = 0;
4941
4942
0
    do
4943
0
    {
4944
0
      i++;
4945
0
      for (;;)
4946
0
      {
4947
0
        memcpy(modname, colname, colnamelen);
4948
0
        sprintf(modname + colnamelen, "_%d", i);
4949
0
        if (strlen(modname) < NAMEDATALEN)
4950
0
          break;
4951
        /* drop chars from colname to keep all the digits */
4952
0
        colnamelen = pg_mbcliplen(colname, colnamelen,
4953
0
                      colnamelen - 1);
4954
0
      }
4955
0
    } while (!colname_is_unique(modname, dpns, colinfo));
4956
0
    colname = modname;
4957
0
  }
4958
0
  return colname;
4959
0
}
4960
4961
/*
4962
 * expand_colnames_array_to: make colinfo->colnames at least n items long
4963
 *
4964
 * Any added array entries are initialized to zero.
4965
 */
4966
static void
4967
expand_colnames_array_to(deparse_columns *colinfo, int n)
4968
0
{
4969
0
  if (n > colinfo->num_cols)
4970
0
  {
4971
0
    if (colinfo->colnames == NULL)
4972
0
      colinfo->colnames = palloc0_array(char *, n);
4973
0
    else
4974
0
      colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4975
0
    colinfo->num_cols = n;
4976
0
  }
4977
0
}
4978
4979
/*
4980
 * build_colinfo_names_hash: optionally construct a hash table for colinfo
4981
 */
4982
static void
4983
build_colinfo_names_hash(deparse_columns *colinfo)
4984
0
{
4985
0
  HASHCTL   hash_ctl;
4986
0
  int     i;
4987
0
  ListCell   *lc;
4988
4989
  /*
4990
   * Use a hash table only for RTEs with at least 32 columns.  (The cutoff
4991
   * is somewhat arbitrary, but let's choose it so that this code does get
4992
   * exercised in the regression tests.)
4993
   */
4994
0
  if (colinfo->num_cols < 32)
4995
0
    return;
4996
4997
  /*
4998
   * Set up the hash table.  The entries are just strings with no other
4999
   * payload.
5000
   */
5001
0
  hash_ctl.keysize = NAMEDATALEN;
5002
0
  hash_ctl.entrysize = NAMEDATALEN;
5003
0
  hash_ctl.hcxt = CurrentMemoryContext;
5004
0
  colinfo->names_hash = hash_create("deparse_columns names",
5005
0
                    colinfo->num_cols + colinfo->num_new_cols,
5006
0
                    &hash_ctl,
5007
0
                    HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
5008
5009
  /*
5010
   * Preload the hash table with any names already present (these would have
5011
   * come from set_using_names).
5012
   */
5013
0
  for (i = 0; i < colinfo->num_cols; i++)
5014
0
  {
5015
0
    char     *oldname = colinfo->colnames[i];
5016
5017
0
    if (oldname)
5018
0
      add_to_names_hash(colinfo, oldname);
5019
0
  }
5020
5021
0
  for (i = 0; i < colinfo->num_new_cols; i++)
5022
0
  {
5023
0
    char     *oldname = colinfo->new_colnames[i];
5024
5025
0
    if (oldname)
5026
0
      add_to_names_hash(colinfo, oldname);
5027
0
  }
5028
5029
0
  foreach(lc, colinfo->parentUsing)
5030
0
  {
5031
0
    char     *oldname = (char *) lfirst(lc);
5032
5033
0
    add_to_names_hash(colinfo, oldname);
5034
0
  }
5035
0
}
5036
5037
/*
5038
 * add_to_names_hash: add a string to the names_hash, if we're using one
5039
 */
5040
static void
5041
add_to_names_hash(deparse_columns *colinfo, const char *name)
5042
0
{
5043
0
  if (colinfo->names_hash)
5044
0
    (void) hash_search(colinfo->names_hash,
5045
0
               name,
5046
0
               HASH_ENTER,
5047
0
               NULL);
5048
0
}
5049
5050
/*
5051
 * destroy_colinfo_names_hash: destroy hash table when done with it
5052
 */
5053
static void
5054
destroy_colinfo_names_hash(deparse_columns *colinfo)
5055
0
{
5056
0
  if (colinfo->names_hash)
5057
0
  {
5058
0
    hash_destroy(colinfo->names_hash);
5059
0
    colinfo->names_hash = NULL;
5060
0
  }
5061
0
}
5062
5063
/*
5064
 * identify_join_columns: figure out where columns of a join come from
5065
 *
5066
 * Fills the join-specific fields of the colinfo struct, except for
5067
 * usingNames which is filled later.
5068
 */
5069
static void
5070
identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
5071
            deparse_columns *colinfo)
5072
0
{
5073
0
  int     numjoincols;
5074
0
  int     jcolno;
5075
0
  int     rcolno;
5076
0
  ListCell   *lc;
5077
5078
  /* Extract left/right child RT indexes */
5079
0
  if (IsA(j->larg, RangeTblRef))
5080
0
    colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
5081
0
  else if (IsA(j->larg, JoinExpr))
5082
0
    colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
5083
0
  else
5084
0
    elog(ERROR, "unrecognized node type in jointree: %d",
5085
0
       (int) nodeTag(j->larg));
5086
0
  if (IsA(j->rarg, RangeTblRef))
5087
0
    colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
5088
0
  else if (IsA(j->rarg, JoinExpr))
5089
0
    colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
5090
0
  else
5091
0
    elog(ERROR, "unrecognized node type in jointree: %d",
5092
0
       (int) nodeTag(j->rarg));
5093
5094
  /* Assert children will be processed earlier than join in second pass */
5095
0
  Assert(colinfo->leftrti < j->rtindex);
5096
0
  Assert(colinfo->rightrti < j->rtindex);
5097
5098
  /* Initialize result arrays with zeroes */
5099
0
  numjoincols = list_length(jrte->joinaliasvars);
5100
0
  Assert(numjoincols == list_length(jrte->eref->colnames));
5101
0
  colinfo->leftattnos = palloc0_array(int, numjoincols);
5102
0
  colinfo->rightattnos = palloc0_array(int, numjoincols);
5103
5104
  /*
5105
   * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
5106
   * Recall that the column(s) merged due to USING are the first column(s)
5107
   * of the join output.  We need not do anything special while scanning
5108
   * joinleftcols, but while scanning joinrightcols we must distinguish
5109
   * merged from unmerged columns.
5110
   */
5111
0
  jcolno = 0;
5112
0
  foreach(lc, jrte->joinleftcols)
5113
0
  {
5114
0
    int     leftattno = lfirst_int(lc);
5115
5116
0
    colinfo->leftattnos[jcolno++] = leftattno;
5117
0
  }
5118
0
  rcolno = 0;
5119
0
  foreach(lc, jrte->joinrightcols)
5120
0
  {
5121
0
    int     rightattno = lfirst_int(lc);
5122
5123
0
    if (rcolno < jrte->joinmergedcols) /* merged column? */
5124
0
      colinfo->rightattnos[rcolno] = rightattno;
5125
0
    else
5126
0
      colinfo->rightattnos[jcolno++] = rightattno;
5127
0
    rcolno++;
5128
0
  }
5129
0
  Assert(jcolno == numjoincols);
5130
0
}
5131
5132
/*
5133
 * get_rtable_name: convenience function to get a previously assigned RTE alias
5134
 *
5135
 * The RTE must belong to the topmost namespace level in "context".
5136
 */
5137
static char *
5138
get_rtable_name(int rtindex, deparse_context *context)
5139
0
{
5140
0
  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
5141
5142
0
  Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
5143
0
  return (char *) list_nth(dpns->rtable_names, rtindex - 1);
5144
0
}
5145
5146
/*
5147
 * set_deparse_plan: set up deparse_namespace to parse subexpressions
5148
 * of a given Plan node
5149
 *
5150
 * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
5151
 * and index_tlist fields.  Caller must already have adjusted the ancestors
5152
 * list if necessary.  Note that the rtable, subplans, and ctes fields do
5153
 * not need to change when shifting attention to different plan nodes in a
5154
 * single plan tree.
5155
 */
5156
static void
5157
set_deparse_plan(deparse_namespace *dpns, Plan *plan)
5158
0
{
5159
0
  dpns->plan = plan;
5160
5161
  /*
5162
   * We special-case Append and MergeAppend to pretend that the first child
5163
   * plan is the OUTER referent; we have to interpret OUTER Vars in their
5164
   * tlists according to one of the children, and the first one is the most
5165
   * natural choice.
5166
   */
5167
0
  if (IsA(plan, Append))
5168
0
    dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5169
0
  else if (IsA(plan, MergeAppend))
5170
0
    dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5171
0
  else
5172
0
    dpns->outer_plan = outerPlan(plan);
5173
5174
0
  if (dpns->outer_plan)
5175
0
    dpns->outer_tlist = dpns->outer_plan->targetlist;
5176
0
  else
5177
0
    dpns->outer_tlist = NIL;
5178
5179
  /*
5180
   * For a SubqueryScan, pretend the subplan is INNER referent.  (We don't
5181
   * use OUTER because that could someday conflict with the normal meaning.)
5182
   * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5183
   * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5184
   * that as INNER referent.
5185
   *
5186
   * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5187
   * INNER referent.  This is the join from the target relation to the data
5188
   * source, and all INNER_VAR Vars in other parts of the query refer to its
5189
   * targetlist.
5190
   *
5191
   * For ON CONFLICT DO SELECT/UPDATE we just need the inner tlist to point
5192
   * to the excluded expression's tlist. (Similar to the SubqueryScan we
5193
   * don't want to reuse OUTER, it's used for RETURNING in some modify table
5194
   * cases, although not INSERT .. CONFLICT).
5195
   */
5196
0
  if (IsA(plan, SubqueryScan))
5197
0
    dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5198
0
  else if (IsA(plan, CteScan))
5199
0
    dpns->inner_plan = list_nth(dpns->subplans,
5200
0
                  ((CteScan *) plan)->ctePlanId - 1);
5201
0
  else if (IsA(plan, WorkTableScan))
5202
0
    dpns->inner_plan = find_recursive_union(dpns,
5203
0
                        (WorkTableScan *) plan);
5204
0
  else if (IsA(plan, ModifyTable))
5205
0
  {
5206
0
    if (((ModifyTable *) plan)->operation == CMD_MERGE)
5207
0
      dpns->inner_plan = outerPlan(plan);
5208
0
    else
5209
0
      dpns->inner_plan = plan;
5210
0
  }
5211
0
  else
5212
0
    dpns->inner_plan = innerPlan(plan);
5213
5214
0
  if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5215
0
    dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5216
0
  else if (dpns->inner_plan)
5217
0
    dpns->inner_tlist = dpns->inner_plan->targetlist;
5218
0
  else
5219
0
    dpns->inner_tlist = NIL;
5220
5221
  /* Set up referent for INDEX_VAR Vars, if needed */
5222
0
  if (IsA(plan, IndexOnlyScan))
5223
0
    dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5224
0
  else if (IsA(plan, ForeignScan))
5225
0
    dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5226
0
  else if (IsA(plan, CustomScan))
5227
0
    dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5228
0
  else
5229
0
    dpns->index_tlist = NIL;
5230
0
}
5231
5232
/*
5233
 * Locate the ancestor plan node that is the RecursiveUnion generating
5234
 * the WorkTableScan's work table.  We can match on wtParam, since that
5235
 * should be unique within the plan tree.
5236
 */
5237
static Plan *
5238
find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
5239
0
{
5240
0
  ListCell   *lc;
5241
5242
0
  foreach(lc, dpns->ancestors)
5243
0
  {
5244
0
    Plan     *ancestor = (Plan *) lfirst(lc);
5245
5246
0
    if (IsA(ancestor, RecursiveUnion) &&
5247
0
      ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5248
0
      return ancestor;
5249
0
  }
5250
0
  elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5251
0
     wtscan->wtParam);
5252
0
  return NULL;
5253
0
}
5254
5255
/*
5256
 * push_child_plan: temporarily transfer deparsing attention to a child plan
5257
 *
5258
 * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5259
 * deparse context in case the referenced expression itself uses
5260
 * OUTER_VAR/INNER_VAR.  We modify the top stack entry in-place to avoid
5261
 * affecting levelsup issues (although in a Plan tree there really shouldn't
5262
 * be any).
5263
 *
5264
 * Caller must provide a local deparse_namespace variable to save the
5265
 * previous state for pop_child_plan.
5266
 */
5267
static void
5268
push_child_plan(deparse_namespace *dpns, Plan *plan,
5269
        deparse_namespace *save_dpns)
5270
0
{
5271
  /* Save state for restoration later */
5272
0
  *save_dpns = *dpns;
5273
5274
  /* Link current plan node into ancestors list */
5275
0
  dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5276
5277
  /* Set attention on selected child */
5278
0
  set_deparse_plan(dpns, plan);
5279
0
}
5280
5281
/*
5282
 * pop_child_plan: undo the effects of push_child_plan
5283
 */
5284
static void
5285
pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5286
0
{
5287
0
  List     *ancestors;
5288
5289
  /* Get rid of ancestors list cell added by push_child_plan */
5290
0
  ancestors = list_delete_first(dpns->ancestors);
5291
5292
  /* Restore fields changed by push_child_plan */
5293
0
  *dpns = *save_dpns;
5294
5295
  /* Make sure dpns->ancestors is right (may be unnecessary) */
5296
0
  dpns->ancestors = ancestors;
5297
0
}
5298
5299
/*
5300
 * push_ancestor_plan: temporarily transfer deparsing attention to an
5301
 * ancestor plan
5302
 *
5303
 * When expanding a Param reference, we must adjust the deparse context
5304
 * to match the plan node that contains the expression being printed;
5305
 * otherwise we'd fail if that expression itself contains a Param or
5306
 * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5307
 *
5308
 * The target ancestor is conveniently identified by the ListCell holding it
5309
 * in dpns->ancestors.
5310
 *
5311
 * Caller must provide a local deparse_namespace variable to save the
5312
 * previous state for pop_ancestor_plan.
5313
 */
5314
static void
5315
push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
5316
           deparse_namespace *save_dpns)
5317
0
{
5318
0
  Plan     *plan = (Plan *) lfirst(ancestor_cell);
5319
5320
  /* Save state for restoration later */
5321
0
  *save_dpns = *dpns;
5322
5323
  /* Build a new ancestor list with just this node's ancestors */
5324
0
  dpns->ancestors =
5325
0
    list_copy_tail(dpns->ancestors,
5326
0
             list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5327
5328
  /* Set attention on selected ancestor */
5329
0
  set_deparse_plan(dpns, plan);
5330
0
}
5331
5332
/*
5333
 * pop_ancestor_plan: undo the effects of push_ancestor_plan
5334
 */
5335
static void
5336
pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5337
0
{
5338
  /* Free the ancestor list made in push_ancestor_plan */
5339
0
  list_free(dpns->ancestors);
5340
5341
  /* Restore fields changed by push_ancestor_plan */
5342
0
  *dpns = *save_dpns;
5343
0
}
5344
5345
5346
/* ----------
5347
 * make_ruledef     - reconstruct the CREATE RULE command
5348
 *          for a given pg_rewrite tuple
5349
 * ----------
5350
 */
5351
static void
5352
make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5353
       int prettyFlags)
5354
0
{
5355
0
  char     *rulename;
5356
0
  char    ev_type;
5357
0
  Oid     ev_class;
5358
0
  bool    is_instead;
5359
0
  char     *ev_qual;
5360
0
  char     *ev_action;
5361
0
  List     *actions;
5362
0
  Relation  ev_relation;
5363
0
  TupleDesc viewResultDesc = NULL;
5364
0
  int     fno;
5365
0
  Datum   dat;
5366
0
  bool    isnull;
5367
5368
  /*
5369
   * Get the attribute values from the rules tuple
5370
   */
5371
0
  fno = SPI_fnumber(rulettc, "rulename");
5372
0
  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5373
0
  Assert(!isnull);
5374
0
  rulename = NameStr(*(DatumGetName(dat)));
5375
5376
0
  fno = SPI_fnumber(rulettc, "ev_type");
5377
0
  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5378
0
  Assert(!isnull);
5379
0
  ev_type = DatumGetChar(dat);
5380
5381
0
  fno = SPI_fnumber(rulettc, "ev_class");
5382
0
  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5383
0
  Assert(!isnull);
5384
0
  ev_class = DatumGetObjectId(dat);
5385
5386
0
  fno = SPI_fnumber(rulettc, "is_instead");
5387
0
  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5388
0
  Assert(!isnull);
5389
0
  is_instead = DatumGetBool(dat);
5390
5391
0
  fno = SPI_fnumber(rulettc, "ev_qual");
5392
0
  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5393
0
  Assert(ev_qual != NULL);
5394
5395
0
  fno = SPI_fnumber(rulettc, "ev_action");
5396
0
  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5397
0
  Assert(ev_action != NULL);
5398
0
  actions = (List *) stringToNode(ev_action);
5399
0
  if (actions == NIL)
5400
0
    elog(ERROR, "invalid empty ev_action list");
5401
5402
0
  ev_relation = table_open(ev_class, AccessShareLock);
5403
5404
  /*
5405
   * Build the rules definition text
5406
   */
5407
0
  appendStringInfo(buf, "CREATE RULE %s AS",
5408
0
           quote_identifier(rulename));
5409
5410
0
  if (prettyFlags & PRETTYFLAG_INDENT)
5411
0
    appendStringInfoString(buf, "\n    ON ");
5412
0
  else
5413
0
    appendStringInfoString(buf, " ON ");
5414
5415
  /* The event the rule is fired for */
5416
0
  switch (ev_type)
5417
0
  {
5418
0
    case '1':
5419
0
      appendStringInfoString(buf, "SELECT");
5420
0
      viewResultDesc = RelationGetDescr(ev_relation);
5421
0
      break;
5422
5423
0
    case '2':
5424
0
      appendStringInfoString(buf, "UPDATE");
5425
0
      break;
5426
5427
0
    case '3':
5428
0
      appendStringInfoString(buf, "INSERT");
5429
0
      break;
5430
5431
0
    case '4':
5432
0
      appendStringInfoString(buf, "DELETE");
5433
0
      break;
5434
5435
0
    default:
5436
0
      ereport(ERROR,
5437
0
          (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5438
0
           errmsg("rule \"%s\" has unsupported event type %d",
5439
0
              rulename, ev_type)));
5440
0
      break;
5441
0
  }
5442
5443
  /* The relation the rule is fired on */
5444
0
  appendStringInfo(buf, " TO %s",
5445
0
           (prettyFlags & PRETTYFLAG_SCHEMA) ?
5446
0
           generate_relation_name(ev_class, NIL) :
5447
0
           generate_qualified_relation_name(ev_class));
5448
5449
  /* If the rule has an event qualification, add it */
5450
0
  if (strcmp(ev_qual, "<>") != 0)
5451
0
  {
5452
0
    Node     *qual;
5453
0
    Query    *query;
5454
0
    deparse_context context;
5455
0
    deparse_namespace dpns;
5456
5457
0
    if (prettyFlags & PRETTYFLAG_INDENT)
5458
0
      appendStringInfoString(buf, "\n  ");
5459
0
    appendStringInfoString(buf, " WHERE ");
5460
5461
0
    qual = stringToNode(ev_qual);
5462
5463
    /*
5464
     * We need to make a context for recognizing any Vars in the qual
5465
     * (which can only be references to OLD and NEW).  Use the rtable of
5466
     * the first query in the action list for this purpose.
5467
     */
5468
0
    query = (Query *) linitial(actions);
5469
5470
    /*
5471
     * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5472
     * into the SELECT, and that's what we need to look at. (Ugly kluge
5473
     * ... try to fix this when we redesign querytrees.)
5474
     */
5475
0
    query = getInsertSelectQuery(query, NULL);
5476
5477
    /* Must acquire locks right away; see notes in get_query_def() */
5478
0
    AcquireRewriteLocks(query, false, false);
5479
5480
0
    context.buf = buf;
5481
0
    context.namespaces = list_make1(&dpns);
5482
0
    context.resultDesc = NULL;
5483
0
    context.targetList = NIL;
5484
0
    context.windowClause = NIL;
5485
0
    context.varprefix = (list_length(query->rtable) != 1);
5486
0
    context.prettyFlags = prettyFlags;
5487
0
    context.wrapColumn = WRAP_COLUMN_DEFAULT;
5488
0
    context.indentLevel = PRETTYINDENT_STD;
5489
0
    context.colNamesVisible = true;
5490
0
    context.inGroupBy = false;
5491
0
    context.varInOrderBy = false;
5492
0
    context.appendparents = NULL;
5493
5494
0
    set_deparse_for_query(&dpns, query, NIL);
5495
5496
0
    get_rule_expr(qual, &context, false);
5497
0
  }
5498
5499
0
  appendStringInfoString(buf, " DO ");
5500
5501
  /* The INSTEAD keyword (if so) */
5502
0
  if (is_instead)
5503
0
    appendStringInfoString(buf, "INSTEAD ");
5504
5505
  /* Finally the rules actions */
5506
0
  if (list_length(actions) > 1)
5507
0
  {
5508
0
    ListCell   *action;
5509
0
    Query    *query;
5510
5511
0
    appendStringInfoChar(buf, '(');
5512
0
    foreach(action, actions)
5513
0
    {
5514
0
      query = (Query *) lfirst(action);
5515
0
      get_query_def(query, buf, NIL, viewResultDesc, true,
5516
0
              prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5517
0
      if (prettyFlags)
5518
0
        appendStringInfoString(buf, ";\n");
5519
0
      else
5520
0
        appendStringInfoString(buf, "; ");
5521
0
    }
5522
0
    appendStringInfoString(buf, ");");
5523
0
  }
5524
0
  else
5525
0
  {
5526
0
    Query    *query;
5527
5528
0
    query = (Query *) linitial(actions);
5529
0
    get_query_def(query, buf, NIL, viewResultDesc, true,
5530
0
            prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5531
0
    appendStringInfoChar(buf, ';');
5532
0
  }
5533
5534
0
  table_close(ev_relation, AccessShareLock);
5535
0
}
5536
5537
5538
/* ----------
5539
 * make_viewdef     - reconstruct the SELECT part of a
5540
 *          view rewrite rule
5541
 * ----------
5542
 */
5543
static void
5544
make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5545
       int prettyFlags, int wrapColumn)
5546
0
{
5547
0
  Query    *query;
5548
0
  char    ev_type;
5549
0
  Oid     ev_class;
5550
0
  bool    is_instead;
5551
0
  char     *ev_qual;
5552
0
  char     *ev_action;
5553
0
  List     *actions;
5554
0
  Relation  ev_relation;
5555
0
  int     fno;
5556
0
  Datum   dat;
5557
0
  bool    isnull;
5558
5559
  /*
5560
   * Get the attribute values from the rules tuple
5561
   */
5562
0
  fno = SPI_fnumber(rulettc, "ev_type");
5563
0
  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5564
0
  Assert(!isnull);
5565
0
  ev_type = DatumGetChar(dat);
5566
5567
0
  fno = SPI_fnumber(rulettc, "ev_class");
5568
0
  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5569
0
  Assert(!isnull);
5570
0
  ev_class = DatumGetObjectId(dat);
5571
5572
0
  fno = SPI_fnumber(rulettc, "is_instead");
5573
0
  dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5574
0
  Assert(!isnull);
5575
0
  is_instead = DatumGetBool(dat);
5576
5577
0
  fno = SPI_fnumber(rulettc, "ev_qual");
5578
0
  ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5579
0
  Assert(ev_qual != NULL);
5580
5581
0
  fno = SPI_fnumber(rulettc, "ev_action");
5582
0
  ev_action = SPI_getvalue(ruletup, rulettc, fno);
5583
0
  Assert(ev_action != NULL);
5584
0
  actions = (List *) stringToNode(ev_action);
5585
5586
0
  if (list_length(actions) != 1)
5587
0
  {
5588
    /* keep output buffer empty and leave */
5589
0
    return;
5590
0
  }
5591
5592
0
  query = (Query *) linitial(actions);
5593
5594
0
  if (ev_type != '1' || !is_instead ||
5595
0
    strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5596
0
  {
5597
    /* keep output buffer empty and leave */
5598
0
    return;
5599
0
  }
5600
5601
0
  ev_relation = table_open(ev_class, AccessShareLock);
5602
5603
0
  get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5604
0
          prettyFlags, wrapColumn, 0);
5605
0
  appendStringInfoChar(buf, ';');
5606
5607
0
  table_close(ev_relation, AccessShareLock);
5608
0
}
5609
5610
5611
/* ----------
5612
 * get_query_def      - Parse back one query parsetree
5613
 *
5614
 * query: parsetree to be displayed
5615
 * buf: output text is appended to buf
5616
 * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5617
 * resultDesc: if not NULL, the output tuple descriptor for the view
5618
 *    represented by a SELECT query.  We use the column names from it
5619
 *    to label SELECT output columns, in preference to names in the query
5620
 * colNamesVisible: true if the surrounding context cares about the output
5621
 *    column names at all (as, for example, an EXISTS() context does not);
5622
 *    when false, we can suppress dummy column labels such as "?column?"
5623
 * prettyFlags: bitmask of PRETTYFLAG_XXX options
5624
 * wrapColumn: maximum line length, or -1 to disable wrapping
5625
 * startIndent: initial indentation amount
5626
 * ----------
5627
 */
5628
static void
5629
get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5630
        TupleDesc resultDesc, bool colNamesVisible,
5631
        int prettyFlags, int wrapColumn, int startIndent)
5632
0
{
5633
0
  deparse_context context;
5634
0
  deparse_namespace dpns;
5635
0
  int     rtable_size;
5636
5637
  /* Guard against excessively long or deeply-nested queries */
5638
0
  CHECK_FOR_INTERRUPTS();
5639
0
  check_stack_depth();
5640
5641
0
  rtable_size = query->hasGroupRTE ?
5642
0
    list_length(query->rtable) - 1 :
5643
0
    list_length(query->rtable);
5644
5645
  /*
5646
   * Replace any Vars in the query's targetlist and havingQual that
5647
   * reference GROUP outputs with the underlying grouping expressions.
5648
   *
5649
   * We can safely pass NULL for the root here.  Preserving varnullingrels
5650
   * makes no difference to the deparsed source text.
5651
   */
5652
0
  if (query->hasGroupRTE)
5653
0
  {
5654
0
    query->targetList = (List *)
5655
0
      flatten_group_exprs(NULL, query, (Node *) query->targetList);
5656
0
    query->havingQual =
5657
0
      flatten_group_exprs(NULL, query, query->havingQual);
5658
0
  }
5659
5660
  /*
5661
   * Before we begin to examine the query, acquire locks on referenced
5662
   * relations, and fix up deleted columns in JOIN RTEs.  This ensures
5663
   * consistent results.  Note we assume it's OK to scribble on the passed
5664
   * querytree!
5665
   *
5666
   * We are only deparsing the query (we are not about to execute it), so we
5667
   * only need AccessShareLock on the relations it mentions.
5668
   */
5669
0
  AcquireRewriteLocks(query, false, false);
5670
5671
0
  context.buf = buf;
5672
0
  context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5673
0
  context.resultDesc = NULL;
5674
0
  context.targetList = NIL;
5675
0
  context.windowClause = NIL;
5676
0
  context.varprefix = (parentnamespace != NIL ||
5677
0
             rtable_size != 1);
5678
0
  context.prettyFlags = prettyFlags;
5679
0
  context.wrapColumn = wrapColumn;
5680
0
  context.indentLevel = startIndent;
5681
0
  context.colNamesVisible = colNamesVisible;
5682
0
  context.inGroupBy = false;
5683
0
  context.varInOrderBy = false;
5684
0
  context.appendparents = NULL;
5685
5686
0
  set_deparse_for_query(&dpns, query, parentnamespace);
5687
5688
0
  switch (query->commandType)
5689
0
  {
5690
0
    case CMD_SELECT:
5691
      /* We set context.resultDesc only if it's a SELECT */
5692
0
      context.resultDesc = resultDesc;
5693
0
      get_select_query_def(query, &context);
5694
0
      break;
5695
5696
0
    case CMD_UPDATE:
5697
0
      get_update_query_def(query, &context);
5698
0
      break;
5699
5700
0
    case CMD_INSERT:
5701
0
      get_insert_query_def(query, &context);
5702
0
      break;
5703
5704
0
    case CMD_DELETE:
5705
0
      get_delete_query_def(query, &context);
5706
0
      break;
5707
5708
0
    case CMD_MERGE:
5709
0
      get_merge_query_def(query, &context);
5710
0
      break;
5711
5712
0
    case CMD_NOTHING:
5713
0
      appendStringInfoString(buf, "NOTHING");
5714
0
      break;
5715
5716
0
    case CMD_UTILITY:
5717
0
      get_utility_query_def(query, &context);
5718
0
      break;
5719
5720
0
    default:
5721
0
      elog(ERROR, "unrecognized query command type: %d",
5722
0
         query->commandType);
5723
0
      break;
5724
0
  }
5725
0
}
5726
5727
/* ----------
5728
 * get_values_def     - Parse back a VALUES list
5729
 * ----------
5730
 */
5731
static void
5732
get_values_def(List *values_lists, deparse_context *context)
5733
0
{
5734
0
  StringInfo  buf = context->buf;
5735
0
  bool    first_list = true;
5736
0
  ListCell   *vtl;
5737
5738
0
  appendStringInfoString(buf, "VALUES ");
5739
5740
0
  foreach(vtl, values_lists)
5741
0
  {
5742
0
    List     *sublist = (List *) lfirst(vtl);
5743
0
    bool    first_col = true;
5744
0
    ListCell   *lc;
5745
5746
0
    if (first_list)
5747
0
      first_list = false;
5748
0
    else
5749
0
      appendStringInfoString(buf, ", ");
5750
5751
0
    appendStringInfoChar(buf, '(');
5752
0
    foreach(lc, sublist)
5753
0
    {
5754
0
      Node     *col = (Node *) lfirst(lc);
5755
5756
0
      if (first_col)
5757
0
        first_col = false;
5758
0
      else
5759
0
        appendStringInfoChar(buf, ',');
5760
5761
      /*
5762
       * Print the value.  Whole-row Vars need special treatment.
5763
       */
5764
0
      get_rule_expr_toplevel(col, context, false);
5765
0
    }
5766
0
    appendStringInfoChar(buf, ')');
5767
0
  }
5768
0
}
5769
5770
/* ----------
5771
 * get_with_clause      - Parse back a WITH clause
5772
 * ----------
5773
 */
5774
static void
5775
get_with_clause(Query *query, deparse_context *context)
5776
0
{
5777
0
  StringInfo  buf = context->buf;
5778
0
  const char *sep;
5779
0
  ListCell   *l;
5780
5781
0
  if (query->cteList == NIL)
5782
0
    return;
5783
5784
0
  if (PRETTY_INDENT(context))
5785
0
  {
5786
0
    context->indentLevel += PRETTYINDENT_STD;
5787
0
    appendStringInfoChar(buf, ' ');
5788
0
  }
5789
5790
0
  if (query->hasRecursive)
5791
0
    sep = "WITH RECURSIVE ";
5792
0
  else
5793
0
    sep = "WITH ";
5794
0
  foreach(l, query->cteList)
5795
0
  {
5796
0
    CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5797
5798
0
    appendStringInfoString(buf, sep);
5799
0
    appendStringInfoString(buf, quote_identifier(cte->ctename));
5800
0
    if (cte->aliascolnames)
5801
0
    {
5802
0
      bool    first = true;
5803
0
      ListCell   *col;
5804
5805
0
      appendStringInfoChar(buf, '(');
5806
0
      foreach(col, cte->aliascolnames)
5807
0
      {
5808
0
        if (first)
5809
0
          first = false;
5810
0
        else
5811
0
          appendStringInfoString(buf, ", ");
5812
0
        appendStringInfoString(buf,
5813
0
                     quote_identifier(strVal(lfirst(col))));
5814
0
      }
5815
0
      appendStringInfoChar(buf, ')');
5816
0
    }
5817
0
    appendStringInfoString(buf, " AS ");
5818
0
    switch (cte->ctematerialized)
5819
0
    {
5820
0
      case CTEMaterializeDefault:
5821
0
        break;
5822
0
      case CTEMaterializeAlways:
5823
0
        appendStringInfoString(buf, "MATERIALIZED ");
5824
0
        break;
5825
0
      case CTEMaterializeNever:
5826
0
        appendStringInfoString(buf, "NOT MATERIALIZED ");
5827
0
        break;
5828
0
    }
5829
0
    appendStringInfoChar(buf, '(');
5830
0
    if (PRETTY_INDENT(context))
5831
0
      appendContextKeyword(context, "", 0, 0, 0);
5832
0
    get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5833
0
            true,
5834
0
            context->prettyFlags, context->wrapColumn,
5835
0
            context->indentLevel);
5836
0
    if (PRETTY_INDENT(context))
5837
0
      appendContextKeyword(context, "", 0, 0, 0);
5838
0
    appendStringInfoChar(buf, ')');
5839
5840
0
    if (cte->search_clause)
5841
0
    {
5842
0
      bool    first = true;
5843
0
      ListCell   *lc;
5844
5845
0
      appendStringInfo(buf, " SEARCH %s FIRST BY ",
5846
0
               cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5847
5848
0
      foreach(lc, cte->search_clause->search_col_list)
5849
0
      {
5850
0
        if (first)
5851
0
          first = false;
5852
0
        else
5853
0
          appendStringInfoString(buf, ", ");
5854
0
        appendStringInfoString(buf,
5855
0
                     quote_identifier(strVal(lfirst(lc))));
5856
0
      }
5857
5858
0
      appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5859
0
    }
5860
5861
0
    if (cte->cycle_clause)
5862
0
    {
5863
0
      bool    first = true;
5864
0
      ListCell   *lc;
5865
5866
0
      appendStringInfoString(buf, " CYCLE ");
5867
5868
0
      foreach(lc, cte->cycle_clause->cycle_col_list)
5869
0
      {
5870
0
        if (first)
5871
0
          first = false;
5872
0
        else
5873
0
          appendStringInfoString(buf, ", ");
5874
0
        appendStringInfoString(buf,
5875
0
                     quote_identifier(strVal(lfirst(lc))));
5876
0
      }
5877
5878
0
      appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5879
5880
0
      {
5881
0
        Const    *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5882
0
        Const    *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5883
5884
0
        if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5885
0
            cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5886
0
        {
5887
0
          appendStringInfoString(buf, " TO ");
5888
0
          get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5889
0
          appendStringInfoString(buf, " DEFAULT ");
5890
0
          get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5891
0
        }
5892
0
      }
5893
5894
0
      appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5895
0
    }
5896
5897
0
    sep = ", ";
5898
0
  }
5899
5900
0
  if (PRETTY_INDENT(context))
5901
0
  {
5902
0
    context->indentLevel -= PRETTYINDENT_STD;
5903
0
    appendContextKeyword(context, "", 0, 0, 0);
5904
0
  }
5905
0
  else
5906
0
    appendStringInfoChar(buf, ' ');
5907
0
}
5908
5909
/* ----------
5910
 * get_select_query_def     - Parse back a SELECT parsetree
5911
 * ----------
5912
 */
5913
static void
5914
get_select_query_def(Query *query, deparse_context *context)
5915
0
{
5916
0
  StringInfo  buf = context->buf;
5917
0
  bool    force_colno;
5918
0
  ListCell   *l;
5919
5920
  /* Insert the WITH clause if given */
5921
0
  get_with_clause(query, context);
5922
5923
  /* Subroutines may need to consult the SELECT targetlist and windowClause */
5924
0
  context->targetList = query->targetList;
5925
0
  context->windowClause = query->windowClause;
5926
5927
  /*
5928
   * If the Query node has a setOperations tree, then it's the top level of
5929
   * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5930
   * fields are interesting in the top query itself.
5931
   */
5932
0
  if (query->setOperations)
5933
0
  {
5934
0
    get_setop_query(query->setOperations, query, context);
5935
    /* ORDER BY clauses must be simple in this case */
5936
0
    force_colno = true;
5937
0
  }
5938
0
  else
5939
0
  {
5940
0
    get_basic_select_query(query, context);
5941
0
    force_colno = false;
5942
0
  }
5943
5944
  /* Add the ORDER BY clause if given */
5945
0
  if (query->sortClause != NIL)
5946
0
  {
5947
0
    appendContextKeyword(context, " ORDER BY ",
5948
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5949
0
    get_rule_orderby(query->sortClause, query->targetList,
5950
0
             force_colno, context);
5951
0
  }
5952
5953
  /*
5954
   * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5955
   * standard spelling of LIMIT.
5956
   */
5957
0
  if (query->limitOffset != NULL)
5958
0
  {
5959
0
    appendContextKeyword(context, " OFFSET ",
5960
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5961
0
    get_rule_expr(query->limitOffset, context, false);
5962
0
  }
5963
0
  if (query->limitCount != NULL)
5964
0
  {
5965
0
    if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5966
0
    {
5967
      /*
5968
       * The limitCount arg is a c_expr, so it needs parens. Simple
5969
       * literals and function expressions would not need parens, but
5970
       * unfortunately it's hard to tell if the expression will be
5971
       * printed as a simple literal like 123 or as a typecast
5972
       * expression, like '-123'::int4. The grammar accepts the former
5973
       * without quoting, but not the latter.
5974
       */
5975
0
      appendContextKeyword(context, " FETCH FIRST ",
5976
0
                 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5977
0
      appendStringInfoChar(buf, '(');
5978
0
      get_rule_expr(query->limitCount, context, false);
5979
0
      appendStringInfoChar(buf, ')');
5980
0
      appendStringInfoString(buf, " ROWS WITH TIES");
5981
0
    }
5982
0
    else
5983
0
    {
5984
0
      appendContextKeyword(context, " LIMIT ",
5985
0
                 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5986
0
      if (IsA(query->limitCount, Const) &&
5987
0
        ((Const *) query->limitCount)->constisnull)
5988
0
        appendStringInfoString(buf, "ALL");
5989
0
      else
5990
0
        get_rule_expr(query->limitCount, context, false);
5991
0
    }
5992
0
  }
5993
5994
  /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5995
0
  if (query->hasForUpdate)
5996
0
  {
5997
0
    foreach(l, query->rowMarks)
5998
0
    {
5999
0
      RowMarkClause *rc = (RowMarkClause *) lfirst(l);
6000
6001
      /* don't print implicit clauses */
6002
0
      if (rc->pushedDown)
6003
0
        continue;
6004
6005
0
      appendContextKeyword(context,
6006
0
                 get_lock_clause_strength(rc->strength),
6007
0
                 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6008
6009
0
      appendStringInfo(buf, " OF %s",
6010
0
               quote_identifier(get_rtable_name(rc->rti,
6011
0
                                context)));
6012
0
      if (rc->waitPolicy == LockWaitError)
6013
0
        appendStringInfoString(buf, " NOWAIT");
6014
0
      else if (rc->waitPolicy == LockWaitSkip)
6015
0
        appendStringInfoString(buf, " SKIP LOCKED");
6016
0
    }
6017
0
  }
6018
0
}
6019
6020
static char *
6021
get_lock_clause_strength(LockClauseStrength strength)
6022
0
{
6023
0
  switch (strength)
6024
0
  {
6025
0
    case LCS_NONE:
6026
      /* we intentionally throw an error for LCS_NONE */
6027
0
      elog(ERROR, "unrecognized LockClauseStrength %d",
6028
0
         (int) strength);
6029
0
      break;
6030
0
    case LCS_FORKEYSHARE:
6031
0
      return " FOR KEY SHARE";
6032
0
    case LCS_FORSHARE:
6033
0
      return " FOR SHARE";
6034
0
    case LCS_FORNOKEYUPDATE:
6035
0
      return " FOR NO KEY UPDATE";
6036
0
    case LCS_FORUPDATE:
6037
0
      return " FOR UPDATE";
6038
0
  }
6039
0
  return NULL;       /* keep compiler quiet */
6040
0
}
6041
6042
/*
6043
 * Detect whether query looks like SELECT ... FROM VALUES(),
6044
 * with no need to rename the output columns of the VALUES RTE.
6045
 * If so, return the VALUES RTE.  Otherwise return NULL.
6046
 */
6047
static RangeTblEntry *
6048
get_simple_values_rte(Query *query, TupleDesc resultDesc)
6049
0
{
6050
0
  RangeTblEntry *result = NULL;
6051
0
  ListCell   *lc;
6052
6053
  /*
6054
   * We want to detect a match even if the Query also contains OLD or NEW
6055
   * rule RTEs.  So the idea is to scan the rtable and see if there is only
6056
   * one inFromCl RTE that is a VALUES RTE.
6057
   */
6058
0
  foreach(lc, query->rtable)
6059
0
  {
6060
0
    RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
6061
6062
0
    if (rte->rtekind == RTE_VALUES && rte->inFromCl)
6063
0
    {
6064
0
      if (result)
6065
0
        return NULL; /* multiple VALUES (probably not possible) */
6066
0
      result = rte;
6067
0
    }
6068
0
    else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
6069
0
      continue;     /* ignore rule entries */
6070
0
    else
6071
0
      return NULL;   /* something else -> not simple VALUES */
6072
0
  }
6073
6074
  /*
6075
   * We don't need to check the targetlist in any great detail, because
6076
   * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
6077
   * appear inside auto-generated sub-queries with very restricted
6078
   * structure.  However, DefineView might have modified the tlist by
6079
   * injecting new column aliases, or we might have some other column
6080
   * aliases forced by a resultDesc.  We can only simplify if the RTE's
6081
   * column names match the names that get_target_list() would select.
6082
   */
6083
0
  if (result)
6084
0
  {
6085
0
    ListCell   *lcn;
6086
0
    int     colno;
6087
6088
0
    if (list_length(query->targetList) != list_length(result->eref->colnames))
6089
0
      return NULL;   /* this probably cannot happen */
6090
0
    colno = 0;
6091
0
    forboth(lc, query->targetList, lcn, result->eref->colnames)
6092
0
    {
6093
0
      TargetEntry *tle = (TargetEntry *) lfirst(lc);
6094
0
      char     *cname = strVal(lfirst(lcn));
6095
0
      char     *colname;
6096
6097
0
      if (tle->resjunk)
6098
0
        return NULL; /* this probably cannot happen */
6099
6100
      /* compute name that get_target_list would use for column */
6101
0
      colno++;
6102
0
      if (resultDesc && colno <= resultDesc->natts)
6103
0
        colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6104
0
      else
6105
0
        colname = tle->resname;
6106
6107
      /* does it match the VALUES RTE? */
6108
0
      if (colname == NULL || strcmp(colname, cname) != 0)
6109
0
        return NULL; /* column name has been changed */
6110
0
    }
6111
0
  }
6112
6113
0
  return result;
6114
0
}
6115
6116
static void
6117
get_basic_select_query(Query *query, deparse_context *context)
6118
0
{
6119
0
  StringInfo  buf = context->buf;
6120
0
  RangeTblEntry *values_rte;
6121
0
  char     *sep;
6122
0
  ListCell   *l;
6123
6124
0
  if (PRETTY_INDENT(context))
6125
0
  {
6126
0
    context->indentLevel += PRETTYINDENT_STD;
6127
0
    appendStringInfoChar(buf, ' ');
6128
0
  }
6129
6130
  /*
6131
   * If the query looks like SELECT * FROM (VALUES ...), then print just the
6132
   * VALUES part.  This reverses what transformValuesClause() did at parse
6133
   * time.
6134
   */
6135
0
  values_rte = get_simple_values_rte(query, context->resultDesc);
6136
0
  if (values_rte)
6137
0
  {
6138
0
    get_values_def(values_rte->values_lists, context);
6139
0
    return;
6140
0
  }
6141
6142
  /*
6143
   * Build up the query string - first we say SELECT
6144
   */
6145
0
  if (query->isReturn)
6146
0
    appendStringInfoString(buf, "RETURN");
6147
0
  else
6148
0
    appendStringInfoString(buf, "SELECT");
6149
6150
  /* Add the DISTINCT clause if given */
6151
0
  if (query->distinctClause != NIL)
6152
0
  {
6153
0
    if (query->hasDistinctOn)
6154
0
    {
6155
0
      appendStringInfoString(buf, " DISTINCT ON (");
6156
0
      sep = "";
6157
0
      foreach(l, query->distinctClause)
6158
0
      {
6159
0
        SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6160
6161
0
        appendStringInfoString(buf, sep);
6162
0
        get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
6163
0
                     false, context);
6164
0
        sep = ", ";
6165
0
      }
6166
0
      appendStringInfoChar(buf, ')');
6167
0
    }
6168
0
    else
6169
0
      appendStringInfoString(buf, " DISTINCT");
6170
0
  }
6171
6172
  /* Then we tell what to select (the targetlist) */
6173
0
  get_target_list(query->targetList, context);
6174
6175
  /* Add the FROM clause if needed */
6176
0
  get_from_clause(query, " FROM ", context);
6177
6178
  /* Add the WHERE clause if given */
6179
0
  if (query->jointree->quals != NULL)
6180
0
  {
6181
0
    appendContextKeyword(context, " WHERE ",
6182
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6183
0
    get_rule_expr(query->jointree->quals, context, false);
6184
0
  }
6185
6186
  /* Add the GROUP BY clause if given */
6187
0
  if (query->groupClause != NULL || query->groupingSets != NULL)
6188
0
  {
6189
0
    bool    save_ingroupby;
6190
6191
0
    appendContextKeyword(context, " GROUP BY ",
6192
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6193
0
    if (query->groupDistinct)
6194
0
      appendStringInfoString(buf, "DISTINCT ");
6195
6196
0
    save_ingroupby = context->inGroupBy;
6197
0
    context->inGroupBy = true;
6198
6199
0
    if (query->groupingSets == NIL)
6200
0
    {
6201
0
      sep = "";
6202
0
      foreach(l, query->groupClause)
6203
0
      {
6204
0
        SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6205
6206
0
        appendStringInfoString(buf, sep);
6207
0
        get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
6208
0
                     false, context);
6209
0
        sep = ", ";
6210
0
      }
6211
0
    }
6212
0
    else
6213
0
    {
6214
0
      sep = "";
6215
0
      foreach(l, query->groupingSets)
6216
0
      {
6217
0
        GroupingSet *grp = lfirst(l);
6218
6219
0
        appendStringInfoString(buf, sep);
6220
0
        get_rule_groupingset(grp, query->targetList, true, context);
6221
0
        sep = ", ";
6222
0
      }
6223
0
    }
6224
6225
0
    context->inGroupBy = save_ingroupby;
6226
0
  }
6227
6228
  /* Add the HAVING clause if given */
6229
0
  if (query->havingQual != NULL)
6230
0
  {
6231
0
    appendContextKeyword(context, " HAVING ",
6232
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6233
0
    get_rule_expr(query->havingQual, context, false);
6234
0
  }
6235
6236
  /* Add the WINDOW clause if needed */
6237
0
  if (query->windowClause != NIL)
6238
0
    get_rule_windowclause(query, context);
6239
0
}
6240
6241
/* ----------
6242
 * get_target_list      - Parse back a SELECT target list
6243
 *
6244
 * This is also used for RETURNING lists in INSERT/UPDATE/DELETE/MERGE.
6245
 * ----------
6246
 */
6247
static void
6248
get_target_list(List *targetList, deparse_context *context)
6249
0
{
6250
0
  StringInfo  buf = context->buf;
6251
0
  StringInfoData targetbuf;
6252
0
  bool    last_was_multiline = false;
6253
0
  char     *sep;
6254
0
  int     colno;
6255
0
  ListCell   *l;
6256
6257
  /* we use targetbuf to hold each TLE's text temporarily */
6258
0
  initStringInfo(&targetbuf);
6259
6260
0
  sep = " ";
6261
0
  colno = 0;
6262
0
  foreach(l, targetList)
6263
0
  {
6264
0
    TargetEntry *tle = (TargetEntry *) lfirst(l);
6265
0
    char     *colname;
6266
0
    char     *attname;
6267
6268
0
    if (tle->resjunk)
6269
0
      continue;     /* ignore junk entries */
6270
6271
0
    appendStringInfoString(buf, sep);
6272
0
    sep = ", ";
6273
0
    colno++;
6274
6275
    /*
6276
     * Put the new field text into targetbuf so we can decide after we've
6277
     * got it whether or not it needs to go on a new line.
6278
     */
6279
0
    resetStringInfo(&targetbuf);
6280
0
    context->buf = &targetbuf;
6281
6282
    /*
6283
     * We special-case Var nodes rather than using get_rule_expr. This is
6284
     * needed because get_rule_expr will display a whole-row Var as
6285
     * "foo.*", which is the preferred notation in most contexts, but at
6286
     * the top level of a SELECT list it's not right (the parser will
6287
     * expand that notation into multiple columns, yielding behavior
6288
     * different from a whole-row Var).  We need to call get_variable
6289
     * directly so that we can tell it to do the right thing, and so that
6290
     * we can get the attribute name which is the default AS label.
6291
     */
6292
0
    if (tle->expr && (IsA(tle->expr, Var)))
6293
0
    {
6294
0
      attname = get_variable((Var *) tle->expr, 0, true, context);
6295
0
    }
6296
0
    else
6297
0
    {
6298
0
      get_rule_expr((Node *) tle->expr, context, true);
6299
6300
      /*
6301
       * When colNamesVisible is true, we should always show the
6302
       * assigned column name explicitly.  Otherwise, show it only if
6303
       * it's not FigureColname's fallback.
6304
       */
6305
0
      attname = context->colNamesVisible ? NULL : "?column?";
6306
0
    }
6307
6308
    /*
6309
     * Figure out what the result column should be called.  In the context
6310
     * of a view, use the view's tuple descriptor (so as to pick up the
6311
     * effects of any column RENAME that's been done on the view).
6312
     * Otherwise, just use what we can find in the TLE.
6313
     */
6314
0
    if (context->resultDesc && colno <= context->resultDesc->natts)
6315
0
      colname = NameStr(TupleDescAttr(context->resultDesc,
6316
0
                      colno - 1)->attname);
6317
0
    else
6318
0
      colname = tle->resname;
6319
6320
    /* Show AS unless the column's name is correct as-is */
6321
0
    if (colname)     /* resname could be NULL */
6322
0
    {
6323
0
      if (attname == NULL || strcmp(attname, colname) != 0)
6324
0
        appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6325
0
    }
6326
6327
    /* Restore context's output buffer */
6328
0
    context->buf = buf;
6329
6330
    /* Consider line-wrapping if enabled */
6331
0
    if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6332
0
    {
6333
0
      int     leading_nl_pos;
6334
6335
      /* Does the new field start with a new line? */
6336
0
      if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6337
0
        leading_nl_pos = 0;
6338
0
      else
6339
0
        leading_nl_pos = -1;
6340
6341
      /* If so, we shouldn't add anything */
6342
0
      if (leading_nl_pos >= 0)
6343
0
      {
6344
        /* instead, remove any trailing spaces currently in buf */
6345
0
        removeStringInfoSpaces(buf);
6346
0
      }
6347
0
      else
6348
0
      {
6349
0
        char     *trailing_nl;
6350
6351
        /* Locate the start of the current line in the output buffer */
6352
0
        trailing_nl = strrchr(buf->data, '\n');
6353
0
        if (trailing_nl == NULL)
6354
0
          trailing_nl = buf->data;
6355
0
        else
6356
0
          trailing_nl++;
6357
6358
        /*
6359
         * Add a newline, plus some indentation, if the new field is
6360
         * not the first and either the new field would cause an
6361
         * overflow or the last field used more than one line.
6362
         */
6363
0
        if (colno > 1 &&
6364
0
          ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6365
0
           last_was_multiline))
6366
0
          appendContextKeyword(context, "", -PRETTYINDENT_STD,
6367
0
                     PRETTYINDENT_STD, PRETTYINDENT_VAR);
6368
0
      }
6369
6370
      /* Remember this field's multiline status for next iteration */
6371
0
      last_was_multiline =
6372
0
        (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6373
0
    }
6374
6375
    /* Add the new field */
6376
0
    appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6377
0
  }
6378
6379
  /* clean up */
6380
0
  pfree(targetbuf.data);
6381
0
}
6382
6383
static void
6384
get_returning_clause(Query *query, deparse_context *context)
6385
0
{
6386
0
  StringInfo  buf = context->buf;
6387
6388
0
  if (query->returningList)
6389
0
  {
6390
0
    bool    have_with = false;
6391
6392
0
    appendContextKeyword(context, " RETURNING",
6393
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6394
6395
    /* Add WITH (OLD/NEW) options, if they're not the defaults */
6396
0
    if (query->returningOldAlias && strcmp(query->returningOldAlias, "old") != 0)
6397
0
    {
6398
0
      appendStringInfo(buf, " WITH (OLD AS %s",
6399
0
               quote_identifier(query->returningOldAlias));
6400
0
      have_with = true;
6401
0
    }
6402
0
    if (query->returningNewAlias && strcmp(query->returningNewAlias, "new") != 0)
6403
0
    {
6404
0
      if (have_with)
6405
0
        appendStringInfo(buf, ", NEW AS %s",
6406
0
                 quote_identifier(query->returningNewAlias));
6407
0
      else
6408
0
      {
6409
0
        appendStringInfo(buf, " WITH (NEW AS %s",
6410
0
                 quote_identifier(query->returningNewAlias));
6411
0
        have_with = true;
6412
0
      }
6413
0
    }
6414
0
    if (have_with)
6415
0
      appendStringInfoChar(buf, ')');
6416
6417
    /* Add the returning expressions themselves */
6418
0
    get_target_list(query->returningList, context);
6419
0
  }
6420
0
}
6421
6422
static void
6423
get_setop_query(Node *setOp, Query *query, deparse_context *context)
6424
0
{
6425
0
  StringInfo  buf = context->buf;
6426
0
  bool    need_paren;
6427
6428
  /* Guard against excessively long or deeply-nested queries */
6429
0
  CHECK_FOR_INTERRUPTS();
6430
0
  check_stack_depth();
6431
6432
0
  if (IsA(setOp, RangeTblRef))
6433
0
  {
6434
0
    RangeTblRef *rtr = (RangeTblRef *) setOp;
6435
0
    RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6436
0
    Query    *subquery = rte->subquery;
6437
6438
0
    Assert(subquery != NULL);
6439
6440
    /*
6441
     * We need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y.
6442
     * Also add parens if the leaf query contains its own set operations.
6443
     * (That shouldn't happen unless one of the other clauses is also
6444
     * present, see transformSetOperationTree; but let's be safe.)
6445
     */
6446
0
    need_paren = (subquery->cteList ||
6447
0
            subquery->sortClause ||
6448
0
            subquery->rowMarks ||
6449
0
            subquery->limitOffset ||
6450
0
            subquery->limitCount ||
6451
0
            subquery->setOperations);
6452
0
    if (need_paren)
6453
0
      appendStringInfoChar(buf, '(');
6454
0
    get_query_def(subquery, buf, context->namespaces,
6455
0
            context->resultDesc, context->colNamesVisible,
6456
0
            context->prettyFlags, context->wrapColumn,
6457
0
            context->indentLevel);
6458
0
    if (need_paren)
6459
0
      appendStringInfoChar(buf, ')');
6460
0
  }
6461
0
  else if (IsA(setOp, SetOperationStmt))
6462
0
  {
6463
0
    SetOperationStmt *op = (SetOperationStmt *) setOp;
6464
0
    int     subindent;
6465
0
    bool    save_colnamesvisible;
6466
6467
    /*
6468
     * We force parens when nesting two SetOperationStmts, except when the
6469
     * lefthand input is another setop of the same kind.  Syntactically,
6470
     * we could omit parens in rather more cases, but it seems best to use
6471
     * parens to flag cases where the setop operator changes.  If we use
6472
     * parens, we also increase the indentation level for the child query.
6473
     *
6474
     * There are some cases in which parens are needed around a leaf query
6475
     * too, but those are more easily handled at the next level down (see
6476
     * code above).
6477
     */
6478
0
    if (IsA(op->larg, SetOperationStmt))
6479
0
    {
6480
0
      SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6481
6482
0
      if (op->op == lop->op && op->all == lop->all)
6483
0
        need_paren = false;
6484
0
      else
6485
0
        need_paren = true;
6486
0
    }
6487
0
    else
6488
0
      need_paren = false;
6489
6490
0
    if (need_paren)
6491
0
    {
6492
0
      appendStringInfoChar(buf, '(');
6493
0
      subindent = PRETTYINDENT_STD;
6494
0
      appendContextKeyword(context, "", subindent, 0, 0);
6495
0
    }
6496
0
    else
6497
0
      subindent = 0;
6498
6499
0
    get_setop_query(op->larg, query, context);
6500
6501
0
    if (need_paren)
6502
0
      appendContextKeyword(context, ") ", -subindent, 0, 0);
6503
0
    else if (PRETTY_INDENT(context))
6504
0
      appendContextKeyword(context, "", -subindent, 0, 0);
6505
0
    else
6506
0
      appendStringInfoChar(buf, ' ');
6507
6508
0
    switch (op->op)
6509
0
    {
6510
0
      case SETOP_UNION:
6511
0
        appendStringInfoString(buf, "UNION ");
6512
0
        break;
6513
0
      case SETOP_INTERSECT:
6514
0
        appendStringInfoString(buf, "INTERSECT ");
6515
0
        break;
6516
0
      case SETOP_EXCEPT:
6517
0
        appendStringInfoString(buf, "EXCEPT ");
6518
0
        break;
6519
0
      default:
6520
0
        elog(ERROR, "unrecognized set op: %d",
6521
0
           (int) op->op);
6522
0
    }
6523
0
    if (op->all)
6524
0
      appendStringInfoString(buf, "ALL ");
6525
6526
    /* Always parenthesize if RHS is another setop */
6527
0
    need_paren = IsA(op->rarg, SetOperationStmt);
6528
6529
    /*
6530
     * The indentation code here is deliberately a bit different from that
6531
     * for the lefthand input, because we want the line breaks in
6532
     * different places.
6533
     */
6534
0
    if (need_paren)
6535
0
    {
6536
0
      appendStringInfoChar(buf, '(');
6537
0
      subindent = PRETTYINDENT_STD;
6538
0
    }
6539
0
    else
6540
0
      subindent = 0;
6541
0
    appendContextKeyword(context, "", subindent, 0, 0);
6542
6543
    /*
6544
     * The output column names of the RHS sub-select don't matter.
6545
     */
6546
0
    save_colnamesvisible = context->colNamesVisible;
6547
0
    context->colNamesVisible = false;
6548
6549
0
    get_setop_query(op->rarg, query, context);
6550
6551
0
    context->colNamesVisible = save_colnamesvisible;
6552
6553
0
    if (PRETTY_INDENT(context))
6554
0
      context->indentLevel -= subindent;
6555
0
    if (need_paren)
6556
0
      appendContextKeyword(context, ")", 0, 0, 0);
6557
0
  }
6558
0
  else
6559
0
  {
6560
0
    elog(ERROR, "unrecognized node type: %d",
6561
0
       (int) nodeTag(setOp));
6562
0
  }
6563
0
}
6564
6565
/*
6566
 * Display a sort/group clause.
6567
 *
6568
 * Also returns the expression tree, so caller need not find it again.
6569
 */
6570
static Node *
6571
get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
6572
             deparse_context *context)
6573
0
{
6574
0
  StringInfo  buf = context->buf;
6575
0
  TargetEntry *tle;
6576
0
  Node     *expr;
6577
6578
0
  tle = get_sortgroupref_tle(ref, tlist);
6579
0
  expr = (Node *) tle->expr;
6580
6581
  /*
6582
   * Use column-number form if requested by caller.  Otherwise, if
6583
   * expression is a constant, force it to be dumped with an explicit cast
6584
   * as decoration --- this is because a simple integer constant is
6585
   * ambiguous (and will be misinterpreted by findTargetlistEntrySQL92()) if
6586
   * we dump it without any decoration.  Similarly, if it's just a Var,
6587
   * there is risk of misinterpretation if the column name is reassigned in
6588
   * the SELECT list, so we may need to force table qualification.  And, if
6589
   * it's anything more complex than a simple Var, then force extra parens
6590
   * around it, to ensure it can't be misinterpreted as a cube() or rollup()
6591
   * construct.
6592
   */
6593
0
  if (force_colno)
6594
0
  {
6595
0
    Assert(!tle->resjunk);
6596
0
    appendStringInfo(buf, "%d", tle->resno);
6597
0
  }
6598
0
  else if (!expr)
6599
0
     /* do nothing, probably can't happen */ ;
6600
0
  else if (IsA(expr, Const))
6601
0
    get_const_expr((Const *) expr, context, 1);
6602
0
  else if (IsA(expr, Var))
6603
0
  {
6604
    /* Tell get_variable to check for name conflict */
6605
0
    bool    save_varinorderby = context->varInOrderBy;
6606
6607
0
    context->varInOrderBy = true;
6608
0
    (void) get_variable((Var *) expr, 0, false, context);
6609
0
    context->varInOrderBy = save_varinorderby;
6610
0
  }
6611
0
  else
6612
0
  {
6613
    /*
6614
     * We must force parens for function-like expressions even if
6615
     * PRETTY_PAREN is off, since those are the ones in danger of
6616
     * misparsing. For other expressions we need to force them only if
6617
     * PRETTY_PAREN is on, since otherwise the expression will output them
6618
     * itself. (We can't skip the parens.)
6619
     */
6620
0
    bool    need_paren = (PRETTY_PAREN(context)
6621
0
                  || IsA(expr, FuncExpr)
6622
0
                  || IsA(expr, Aggref)
6623
0
                  || IsA(expr, WindowFunc)
6624
0
                  || IsA(expr, JsonConstructorExpr));
6625
6626
0
    if (need_paren)
6627
0
      appendStringInfoChar(context->buf, '(');
6628
0
    get_rule_expr(expr, context, true);
6629
0
    if (need_paren)
6630
0
      appendStringInfoChar(context->buf, ')');
6631
0
  }
6632
6633
0
  return expr;
6634
0
}
6635
6636
/*
6637
 * Display a GroupingSet
6638
 */
6639
static void
6640
get_rule_groupingset(GroupingSet *gset, List *targetlist,
6641
           bool omit_parens, deparse_context *context)
6642
0
{
6643
0
  ListCell   *l;
6644
0
  StringInfo  buf = context->buf;
6645
0
  bool    omit_child_parens = true;
6646
0
  char     *sep = "";
6647
6648
0
  switch (gset->kind)
6649
0
  {
6650
0
    case GROUPING_SET_EMPTY:
6651
0
      appendStringInfoString(buf, "()");
6652
0
      return;
6653
6654
0
    case GROUPING_SET_SIMPLE:
6655
0
      {
6656
0
        if (!omit_parens || list_length(gset->content) != 1)
6657
0
          appendStringInfoChar(buf, '(');
6658
6659
0
        foreach(l, gset->content)
6660
0
        {
6661
0
          Index   ref = lfirst_int(l);
6662
6663
0
          appendStringInfoString(buf, sep);
6664
0
          get_rule_sortgroupclause(ref, targetlist,
6665
0
                       false, context);
6666
0
          sep = ", ";
6667
0
        }
6668
6669
0
        if (!omit_parens || list_length(gset->content) != 1)
6670
0
          appendStringInfoChar(buf, ')');
6671
0
      }
6672
0
      return;
6673
6674
0
    case GROUPING_SET_ROLLUP:
6675
0
      appendStringInfoString(buf, "ROLLUP(");
6676
0
      break;
6677
0
    case GROUPING_SET_CUBE:
6678
0
      appendStringInfoString(buf, "CUBE(");
6679
0
      break;
6680
0
    case GROUPING_SET_SETS:
6681
0
      appendStringInfoString(buf, "GROUPING SETS (");
6682
0
      omit_child_parens = false;
6683
0
      break;
6684
0
  }
6685
6686
0
  foreach(l, gset->content)
6687
0
  {
6688
0
    appendStringInfoString(buf, sep);
6689
0
    get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6690
0
    sep = ", ";
6691
0
  }
6692
6693
0
  appendStringInfoChar(buf, ')');
6694
0
}
6695
6696
/*
6697
 * Display an ORDER BY list.
6698
 */
6699
static void
6700
get_rule_orderby(List *orderList, List *targetList,
6701
         bool force_colno, deparse_context *context)
6702
0
{
6703
0
  StringInfo  buf = context->buf;
6704
0
  const char *sep;
6705
0
  ListCell   *l;
6706
6707
0
  sep = "";
6708
0
  foreach(l, orderList)
6709
0
  {
6710
0
    SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6711
0
    Node     *sortexpr;
6712
0
    Oid     sortcoltype;
6713
0
    TypeCacheEntry *typentry;
6714
6715
0
    appendStringInfoString(buf, sep);
6716
0
    sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6717
0
                      force_colno, context);
6718
0
    sortcoltype = exprType(sortexpr);
6719
    /* See whether operator is default < or > for datatype */
6720
0
    typentry = lookup_type_cache(sortcoltype,
6721
0
                   TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
6722
0
    if (srt->sortop == typentry->lt_opr)
6723
0
    {
6724
      /* ASC is default, so emit nothing for it */
6725
0
      if (srt->nulls_first)
6726
0
        appendStringInfoString(buf, " NULLS FIRST");
6727
0
    }
6728
0
    else if (srt->sortop == typentry->gt_opr)
6729
0
    {
6730
0
      appendStringInfoString(buf, " DESC");
6731
      /* DESC defaults to NULLS FIRST */
6732
0
      if (!srt->nulls_first)
6733
0
        appendStringInfoString(buf, " NULLS LAST");
6734
0
    }
6735
0
    else
6736
0
    {
6737
0
      appendStringInfo(buf, " USING %s",
6738
0
               generate_operator_name(srt->sortop,
6739
0
                          sortcoltype,
6740
0
                          sortcoltype));
6741
      /* be specific to eliminate ambiguity */
6742
0
      if (srt->nulls_first)
6743
0
        appendStringInfoString(buf, " NULLS FIRST");
6744
0
      else
6745
0
        appendStringInfoString(buf, " NULLS LAST");
6746
0
    }
6747
0
    sep = ", ";
6748
0
  }
6749
0
}
6750
6751
/*
6752
 * Display a WINDOW clause.
6753
 *
6754
 * Note that the windowClause list might contain only anonymous window
6755
 * specifications, in which case we should print nothing here.
6756
 */
6757
static void
6758
get_rule_windowclause(Query *query, deparse_context *context)
6759
0
{
6760
0
  StringInfo  buf = context->buf;
6761
0
  const char *sep;
6762
0
  ListCell   *l;
6763
6764
0
  sep = NULL;
6765
0
  foreach(l, query->windowClause)
6766
0
  {
6767
0
    WindowClause *wc = (WindowClause *) lfirst(l);
6768
6769
0
    if (wc->name == NULL)
6770
0
      continue;     /* ignore anonymous windows */
6771
6772
0
    if (sep == NULL)
6773
0
      appendContextKeyword(context, " WINDOW ",
6774
0
                 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6775
0
    else
6776
0
      appendStringInfoString(buf, sep);
6777
6778
0
    appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6779
6780
0
    get_rule_windowspec(wc, query->targetList, context);
6781
6782
0
    sep = ", ";
6783
0
  }
6784
0
}
6785
6786
/*
6787
 * Display a window definition
6788
 */
6789
static void
6790
get_rule_windowspec(WindowClause *wc, List *targetList,
6791
          deparse_context *context)
6792
0
{
6793
0
  StringInfo  buf = context->buf;
6794
0
  bool    needspace = false;
6795
0
  const char *sep;
6796
0
  ListCell   *l;
6797
6798
0
  appendStringInfoChar(buf, '(');
6799
0
  if (wc->refname)
6800
0
  {
6801
0
    appendStringInfoString(buf, quote_identifier(wc->refname));
6802
0
    needspace = true;
6803
0
  }
6804
  /* partition clauses are always inherited, so only print if no refname */
6805
0
  if (wc->partitionClause && !wc->refname)
6806
0
  {
6807
0
    if (needspace)
6808
0
      appendStringInfoChar(buf, ' ');
6809
0
    appendStringInfoString(buf, "PARTITION BY ");
6810
0
    sep = "";
6811
0
    foreach(l, wc->partitionClause)
6812
0
    {
6813
0
      SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6814
6815
0
      appendStringInfoString(buf, sep);
6816
0
      get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6817
0
                   false, context);
6818
0
      sep = ", ";
6819
0
    }
6820
0
    needspace = true;
6821
0
  }
6822
  /* print ordering clause only if not inherited */
6823
0
  if (wc->orderClause && !wc->copiedOrder)
6824
0
  {
6825
0
    if (needspace)
6826
0
      appendStringInfoChar(buf, ' ');
6827
0
    appendStringInfoString(buf, "ORDER BY ");
6828
0
    get_rule_orderby(wc->orderClause, targetList, false, context);
6829
0
    needspace = true;
6830
0
  }
6831
  /* framing clause is never inherited, so print unless it's default */
6832
0
  if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
6833
0
  {
6834
0
    if (needspace)
6835
0
      appendStringInfoChar(buf, ' ');
6836
0
    get_window_frame_options(wc->frameOptions,
6837
0
                 wc->startOffset, wc->endOffset,
6838
0
                 context);
6839
0
  }
6840
0
  appendStringInfoChar(buf, ')');
6841
0
}
6842
6843
/*
6844
 * Append the description of a window's framing options to context->buf
6845
 */
6846
static void
6847
get_window_frame_options(int frameOptions,
6848
             Node *startOffset, Node *endOffset,
6849
             deparse_context *context)
6850
0
{
6851
0
  StringInfo  buf = context->buf;
6852
6853
0
  if (frameOptions & FRAMEOPTION_NONDEFAULT)
6854
0
  {
6855
0
    if (frameOptions & FRAMEOPTION_RANGE)
6856
0
      appendStringInfoString(buf, "RANGE ");
6857
0
    else if (frameOptions & FRAMEOPTION_ROWS)
6858
0
      appendStringInfoString(buf, "ROWS ");
6859
0
    else if (frameOptions & FRAMEOPTION_GROUPS)
6860
0
      appendStringInfoString(buf, "GROUPS ");
6861
0
    else
6862
0
      Assert(false);
6863
0
    if (frameOptions & FRAMEOPTION_BETWEEN)
6864
0
      appendStringInfoString(buf, "BETWEEN ");
6865
0
    if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
6866
0
      appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6867
0
    else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW)
6868
0
      appendStringInfoString(buf, "CURRENT ROW ");
6869
0
    else if (frameOptions & FRAMEOPTION_START_OFFSET)
6870
0
    {
6871
0
      get_rule_expr(startOffset, context, false);
6872
0
      if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
6873
0
        appendStringInfoString(buf, " PRECEDING ");
6874
0
      else if (frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
6875
0
        appendStringInfoString(buf, " FOLLOWING ");
6876
0
      else
6877
0
        Assert(false);
6878
0
    }
6879
0
    else
6880
0
      Assert(false);
6881
0
    if (frameOptions & FRAMEOPTION_BETWEEN)
6882
0
    {
6883
0
      appendStringInfoString(buf, "AND ");
6884
0
      if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
6885
0
        appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6886
0
      else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
6887
0
        appendStringInfoString(buf, "CURRENT ROW ");
6888
0
      else if (frameOptions & FRAMEOPTION_END_OFFSET)
6889
0
      {
6890
0
        get_rule_expr(endOffset, context, false);
6891
0
        if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
6892
0
          appendStringInfoString(buf, " PRECEDING ");
6893
0
        else if (frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
6894
0
          appendStringInfoString(buf, " FOLLOWING ");
6895
0
        else
6896
0
          Assert(false);
6897
0
      }
6898
0
      else
6899
0
        Assert(false);
6900
0
    }
6901
0
    if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
6902
0
      appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6903
0
    else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6904
0
      appendStringInfoString(buf, "EXCLUDE GROUP ");
6905
0
    else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6906
0
      appendStringInfoString(buf, "EXCLUDE TIES ");
6907
    /* we will now have a trailing space; remove it */
6908
0
    buf->data[--(buf->len)] = '\0';
6909
0
  }
6910
0
}
6911
6912
/*
6913
 * Return the description of a window's framing options as a palloc'd string
6914
 */
6915
char *
6916
get_window_frame_options_for_explain(int frameOptions,
6917
                   Node *startOffset, Node *endOffset,
6918
                   List *dpcontext, bool forceprefix)
6919
0
{
6920
0
  StringInfoData buf;
6921
0
  deparse_context context;
6922
6923
0
  initStringInfo(&buf);
6924
0
  context.buf = &buf;
6925
0
  context.namespaces = dpcontext;
6926
0
  context.resultDesc = NULL;
6927
0
  context.targetList = NIL;
6928
0
  context.windowClause = NIL;
6929
0
  context.varprefix = forceprefix;
6930
0
  context.prettyFlags = 0;
6931
0
  context.wrapColumn = WRAP_COLUMN_DEFAULT;
6932
0
  context.indentLevel = 0;
6933
0
  context.colNamesVisible = true;
6934
0
  context.inGroupBy = false;
6935
0
  context.varInOrderBy = false;
6936
0
  context.appendparents = NULL;
6937
6938
0
  get_window_frame_options(frameOptions, startOffset, endOffset, &context);
6939
6940
0
  return buf.data;
6941
0
}
6942
6943
/* ----------
6944
 * get_insert_query_def     - Parse back an INSERT parsetree
6945
 * ----------
6946
 */
6947
static void
6948
get_insert_query_def(Query *query, deparse_context *context)
6949
0
{
6950
0
  StringInfo  buf = context->buf;
6951
0
  RangeTblEntry *select_rte = NULL;
6952
0
  RangeTblEntry *values_rte = NULL;
6953
0
  RangeTblEntry *rte;
6954
0
  char     *sep;
6955
0
  ListCell   *l;
6956
0
  List     *strippedexprs;
6957
6958
  /* Insert the WITH clause if given */
6959
0
  get_with_clause(query, context);
6960
6961
  /*
6962
   * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6963
   * single RTE for the SELECT or VALUES.  Plain VALUES has neither.
6964
   */
6965
0
  foreach(l, query->rtable)
6966
0
  {
6967
0
    rte = (RangeTblEntry *) lfirst(l);
6968
6969
0
    if (rte->rtekind == RTE_SUBQUERY)
6970
0
    {
6971
0
      if (select_rte)
6972
0
        elog(ERROR, "too many subquery RTEs in INSERT");
6973
0
      select_rte = rte;
6974
0
    }
6975
6976
0
    if (rte->rtekind == RTE_VALUES)
6977
0
    {
6978
0
      if (values_rte)
6979
0
        elog(ERROR, "too many values RTEs in INSERT");
6980
0
      values_rte = rte;
6981
0
    }
6982
0
  }
6983
0
  if (select_rte && values_rte)
6984
0
    elog(ERROR, "both subquery and values RTEs in INSERT");
6985
6986
  /*
6987
   * Start the query with INSERT INTO relname
6988
   */
6989
0
  rte = rt_fetch(query->resultRelation, query->rtable);
6990
0
  Assert(rte->rtekind == RTE_RELATION);
6991
6992
0
  if (PRETTY_INDENT(context))
6993
0
  {
6994
0
    context->indentLevel += PRETTYINDENT_STD;
6995
0
    appendStringInfoChar(buf, ' ');
6996
0
  }
6997
0
  appendStringInfo(buf, "INSERT INTO %s",
6998
0
           generate_relation_name(rte->relid, NIL));
6999
7000
  /* Print the relation alias, if needed; INSERT requires explicit AS */
7001
0
  get_rte_alias(rte, query->resultRelation, true, context);
7002
7003
  /* always want a space here */
7004
0
  appendStringInfoChar(buf, ' ');
7005
7006
  /*
7007
   * Add the insert-column-names list.  Any indirection decoration needed on
7008
   * the column names can be inferred from the top targetlist.
7009
   */
7010
0
  strippedexprs = NIL;
7011
0
  sep = "";
7012
0
  if (query->targetList)
7013
0
    appendStringInfoChar(buf, '(');
7014
0
  foreach(l, query->targetList)
7015
0
  {
7016
0
    TargetEntry *tle = (TargetEntry *) lfirst(l);
7017
7018
0
    if (tle->resjunk)
7019
0
      continue;     /* ignore junk entries */
7020
7021
0
    appendStringInfoString(buf, sep);
7022
0
    sep = ", ";
7023
7024
    /*
7025
     * Put out name of target column; look in the catalogs, not at
7026
     * tle->resname, since resname will fail to track RENAME.
7027
     */
7028
0
    appendStringInfoString(buf,
7029
0
                 quote_identifier(get_attname(rte->relid,
7030
0
                              tle->resno,
7031
0
                              false)));
7032
7033
    /*
7034
     * Print any indirection needed (subfields or subscripts), and strip
7035
     * off the top-level nodes representing the indirection assignments.
7036
     * Add the stripped expressions to strippedexprs.  (If it's a
7037
     * single-VALUES statement, the stripped expressions are the VALUES to
7038
     * print below.  Otherwise they're just Vars and not really
7039
     * interesting.)
7040
     */
7041
0
    strippedexprs = lappend(strippedexprs,
7042
0
                processIndirection((Node *) tle->expr,
7043
0
                           context));
7044
0
  }
7045
0
  if (query->targetList)
7046
0
    appendStringInfoString(buf, ") ");
7047
7048
0
  if (query->override)
7049
0
  {
7050
0
    if (query->override == OVERRIDING_SYSTEM_VALUE)
7051
0
      appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
7052
0
    else if (query->override == OVERRIDING_USER_VALUE)
7053
0
      appendStringInfoString(buf, "OVERRIDING USER VALUE ");
7054
0
  }
7055
7056
0
  if (select_rte)
7057
0
  {
7058
    /* Add the SELECT */
7059
0
    get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
7060
0
            false,
7061
0
            context->prettyFlags, context->wrapColumn,
7062
0
            context->indentLevel);
7063
0
  }
7064
0
  else if (values_rte)
7065
0
  {
7066
    /* Add the multi-VALUES expression lists */
7067
0
    get_values_def(values_rte->values_lists, context);
7068
0
  }
7069
0
  else if (strippedexprs)
7070
0
  {
7071
    /* Add the single-VALUES expression list */
7072
0
    appendContextKeyword(context, "VALUES (",
7073
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7074
0
    get_rule_list_toplevel(strippedexprs, context, false);
7075
0
    appendStringInfoChar(buf, ')');
7076
0
  }
7077
0
  else
7078
0
  {
7079
    /* No expressions, so it must be DEFAULT VALUES */
7080
0
    appendStringInfoString(buf, "DEFAULT VALUES");
7081
0
  }
7082
7083
  /* Add ON CONFLICT if present */
7084
0
  if (query->onConflict)
7085
0
  {
7086
0
    OnConflictExpr *confl = query->onConflict;
7087
7088
0
    appendStringInfoString(buf, " ON CONFLICT");
7089
7090
0
    if (confl->arbiterElems)
7091
0
    {
7092
      /* Add the single-VALUES expression list */
7093
0
      appendStringInfoChar(buf, '(');
7094
0
      get_rule_expr((Node *) confl->arbiterElems, context, false);
7095
0
      appendStringInfoChar(buf, ')');
7096
7097
      /* Add a WHERE clause (for partial indexes) if given */
7098
0
      if (confl->arbiterWhere != NULL)
7099
0
      {
7100
0
        bool    save_varprefix;
7101
7102
        /*
7103
         * Force non-prefixing of Vars, since parser assumes that they
7104
         * belong to target relation.  WHERE clause does not use
7105
         * InferenceElem, so this is separately required.
7106
         */
7107
0
        save_varprefix = context->varprefix;
7108
0
        context->varprefix = false;
7109
7110
0
        appendContextKeyword(context, " WHERE ",
7111
0
                   -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7112
0
        get_rule_expr(confl->arbiterWhere, context, false);
7113
7114
0
        context->varprefix = save_varprefix;
7115
0
      }
7116
0
    }
7117
0
    else if (OidIsValid(confl->constraint))
7118
0
    {
7119
0
      char     *constraint = get_constraint_name(confl->constraint);
7120
7121
0
      if (!constraint)
7122
0
        elog(ERROR, "cache lookup failed for constraint %u",
7123
0
           confl->constraint);
7124
0
      appendStringInfo(buf, " ON CONSTRAINT %s",
7125
0
               quote_identifier(constraint));
7126
0
    }
7127
7128
0
    if (confl->action == ONCONFLICT_NOTHING)
7129
0
    {
7130
0
      appendStringInfoString(buf, " DO NOTHING");
7131
0
    }
7132
0
    else if (confl->action == ONCONFLICT_UPDATE)
7133
0
    {
7134
0
      appendStringInfoString(buf, " DO UPDATE SET ");
7135
      /* Deparse targetlist */
7136
0
      get_update_query_targetlist_def(query, confl->onConflictSet,
7137
0
                      context, rte);
7138
7139
      /* Add a WHERE clause if given */
7140
0
      if (confl->onConflictWhere != NULL)
7141
0
      {
7142
0
        appendContextKeyword(context, " WHERE ",
7143
0
                   -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7144
0
        get_rule_expr(confl->onConflictWhere, context, false);
7145
0
      }
7146
0
    }
7147
0
    else
7148
0
    {
7149
0
      Assert(confl->action == ONCONFLICT_SELECT);
7150
0
      appendStringInfoString(buf, " DO SELECT");
7151
7152
      /* Add FOR [KEY] UPDATE/SHARE clause if present */
7153
0
      if (confl->lockStrength != LCS_NONE)
7154
0
        appendStringInfoString(buf, get_lock_clause_strength(confl->lockStrength));
7155
7156
      /* Add a WHERE clause if given */
7157
0
      if (confl->onConflictWhere != NULL)
7158
0
      {
7159
0
        appendContextKeyword(context, " WHERE ",
7160
0
                   -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7161
0
        get_rule_expr(confl->onConflictWhere, context, false);
7162
0
      }
7163
0
    }
7164
0
  }
7165
7166
  /* Add RETURNING if present */
7167
0
  if (query->returningList)
7168
0
    get_returning_clause(query, context);
7169
0
}
7170
7171
7172
/* ----------
7173
 * get_update_query_def     - Parse back an UPDATE parsetree
7174
 * ----------
7175
 */
7176
static void
7177
get_update_query_def(Query *query, deparse_context *context)
7178
0
{
7179
0
  StringInfo  buf = context->buf;
7180
0
  RangeTblEntry *rte;
7181
7182
  /* Insert the WITH clause if given */
7183
0
  get_with_clause(query, context);
7184
7185
  /*
7186
   * Start the query with UPDATE relname SET
7187
   */
7188
0
  rte = rt_fetch(query->resultRelation, query->rtable);
7189
0
  Assert(rte->rtekind == RTE_RELATION);
7190
0
  if (PRETTY_INDENT(context))
7191
0
  {
7192
0
    appendStringInfoChar(buf, ' ');
7193
0
    context->indentLevel += PRETTYINDENT_STD;
7194
0
  }
7195
0
  appendStringInfo(buf, "UPDATE %s%s",
7196
0
           only_marker(rte),
7197
0
           generate_relation_name(rte->relid, NIL));
7198
7199
  /* Print the relation alias, if needed */
7200
0
  get_rte_alias(rte, query->resultRelation, false, context);
7201
7202
0
  appendStringInfoString(buf, " SET ");
7203
7204
  /* Deparse targetlist */
7205
0
  get_update_query_targetlist_def(query, query->targetList, context, rte);
7206
7207
  /* Add the FROM clause if needed */
7208
0
  get_from_clause(query, " FROM ", context);
7209
7210
  /* Add a WHERE clause if given */
7211
0
  if (query->jointree->quals != NULL)
7212
0
  {
7213
0
    appendContextKeyword(context, " WHERE ",
7214
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7215
0
    get_rule_expr(query->jointree->quals, context, false);
7216
0
  }
7217
7218
  /* Add RETURNING if present */
7219
0
  if (query->returningList)
7220
0
    get_returning_clause(query, context);
7221
0
}
7222
7223
7224
/* ----------
7225
 * get_update_query_targetlist_def      - Parse back an UPDATE targetlist
7226
 * ----------
7227
 */
7228
static void
7229
get_update_query_targetlist_def(Query *query, List *targetList,
7230
                deparse_context *context, RangeTblEntry *rte)
7231
0
{
7232
0
  StringInfo  buf = context->buf;
7233
0
  ListCell   *l;
7234
0
  ListCell   *next_ma_cell;
7235
0
  int     remaining_ma_columns;
7236
0
  const char *sep;
7237
0
  SubLink    *cur_ma_sublink;
7238
0
  List     *ma_sublinks;
7239
7240
  /*
7241
   * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
7242
   * into a list.  We expect them to appear, in ID order, in resjunk tlist
7243
   * entries.
7244
   */
7245
0
  ma_sublinks = NIL;
7246
0
  if (query->hasSubLinks)   /* else there can't be any */
7247
0
  {
7248
0
    foreach(l, targetList)
7249
0
    {
7250
0
      TargetEntry *tle = (TargetEntry *) lfirst(l);
7251
7252
0
      if (tle->resjunk && IsA(tle->expr, SubLink))
7253
0
      {
7254
0
        SubLink    *sl = (SubLink *) tle->expr;
7255
7256
0
        if (sl->subLinkType == MULTIEXPR_SUBLINK)
7257
0
        {
7258
0
          ma_sublinks = lappend(ma_sublinks, sl);
7259
0
          Assert(sl->subLinkId == list_length(ma_sublinks));
7260
0
        }
7261
0
      }
7262
0
    }
7263
0
  }
7264
0
  next_ma_cell = list_head(ma_sublinks);
7265
0
  cur_ma_sublink = NULL;
7266
0
  remaining_ma_columns = 0;
7267
7268
  /* Add the comma separated list of 'attname = value' */
7269
0
  sep = "";
7270
0
  foreach(l, targetList)
7271
0
  {
7272
0
    TargetEntry *tle = (TargetEntry *) lfirst(l);
7273
0
    Node     *expr;
7274
7275
0
    if (tle->resjunk)
7276
0
      continue;     /* ignore junk entries */
7277
7278
    /* Emit separator (OK whether we're in multiassignment or not) */
7279
0
    appendStringInfoString(buf, sep);
7280
0
    sep = ", ";
7281
7282
    /*
7283
     * Check to see if we're starting a multiassignment group: if so,
7284
     * output a left paren.
7285
     */
7286
0
    if (next_ma_cell != NULL && cur_ma_sublink == NULL)
7287
0
    {
7288
      /*
7289
       * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
7290
       * Param.  That could be buried under FieldStores and
7291
       * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
7292
       * and underneath those there could be an implicit type coercion.
7293
       * Because we would ignore implicit type coercions anyway, we
7294
       * don't need to be as careful as processIndirection() is about
7295
       * descending past implicit CoerceToDomains.
7296
       */
7297
0
      expr = (Node *) tle->expr;
7298
0
      while (expr)
7299
0
      {
7300
0
        if (IsA(expr, FieldStore))
7301
0
        {
7302
0
          FieldStore *fstore = (FieldStore *) expr;
7303
7304
0
          expr = (Node *) linitial(fstore->newvals);
7305
0
        }
7306
0
        else if (IsA(expr, SubscriptingRef))
7307
0
        {
7308
0
          SubscriptingRef *sbsref = (SubscriptingRef *) expr;
7309
7310
0
          if (sbsref->refassgnexpr == NULL)
7311
0
            break;
7312
7313
0
          expr = (Node *) sbsref->refassgnexpr;
7314
0
        }
7315
0
        else if (IsA(expr, CoerceToDomain))
7316
0
        {
7317
0
          CoerceToDomain *cdomain = (CoerceToDomain *) expr;
7318
7319
0
          if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
7320
0
            break;
7321
0
          expr = (Node *) cdomain->arg;
7322
0
        }
7323
0
        else
7324
0
          break;
7325
0
      }
7326
0
      expr = strip_implicit_coercions(expr);
7327
7328
0
      if (expr && IsA(expr, Param) &&
7329
0
        ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
7330
0
      {
7331
0
        cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
7332
0
        next_ma_cell = lnext(ma_sublinks, next_ma_cell);
7333
0
        remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
7334
0
        Assert(((Param *) expr)->paramid ==
7335
0
             ((cur_ma_sublink->subLinkId << 16) | 1));
7336
0
        appendStringInfoChar(buf, '(');
7337
0
      }
7338
0
    }
7339
7340
    /*
7341
     * Put out name of target column; look in the catalogs, not at
7342
     * tle->resname, since resname will fail to track RENAME.
7343
     */
7344
0
    appendStringInfoString(buf,
7345
0
                 quote_identifier(get_attname(rte->relid,
7346
0
                              tle->resno,
7347
0
                              false)));
7348
7349
    /*
7350
     * Print any indirection needed (subfields or subscripts), and strip
7351
     * off the top-level nodes representing the indirection assignments.
7352
     */
7353
0
    expr = processIndirection((Node *) tle->expr, context);
7354
7355
    /*
7356
     * If we're in a multiassignment, skip printing anything more, unless
7357
     * this is the last column; in which case, what we print should be the
7358
     * sublink, not the Param.
7359
     */
7360
0
    if (cur_ma_sublink != NULL)
7361
0
    {
7362
0
      if (--remaining_ma_columns > 0)
7363
0
        continue;   /* not the last column of multiassignment */
7364
0
      appendStringInfoChar(buf, ')');
7365
0
      expr = (Node *) cur_ma_sublink;
7366
0
      cur_ma_sublink = NULL;
7367
0
    }
7368
7369
0
    appendStringInfoString(buf, " = ");
7370
7371
0
    get_rule_expr(expr, context, false);
7372
0
  }
7373
0
}
7374
7375
7376
/* ----------
7377
 * get_delete_query_def     - Parse back a DELETE parsetree
7378
 * ----------
7379
 */
7380
static void
7381
get_delete_query_def(Query *query, deparse_context *context)
7382
0
{
7383
0
  StringInfo  buf = context->buf;
7384
0
  RangeTblEntry *rte;
7385
7386
  /* Insert the WITH clause if given */
7387
0
  get_with_clause(query, context);
7388
7389
  /*
7390
   * Start the query with DELETE FROM relname
7391
   */
7392
0
  rte = rt_fetch(query->resultRelation, query->rtable);
7393
0
  Assert(rte->rtekind == RTE_RELATION);
7394
0
  if (PRETTY_INDENT(context))
7395
0
  {
7396
0
    appendStringInfoChar(buf, ' ');
7397
0
    context->indentLevel += PRETTYINDENT_STD;
7398
0
  }
7399
0
  appendStringInfo(buf, "DELETE FROM %s%s",
7400
0
           only_marker(rte),
7401
0
           generate_relation_name(rte->relid, NIL));
7402
7403
  /* Print the relation alias, if needed */
7404
0
  get_rte_alias(rte, query->resultRelation, false, context);
7405
7406
  /* Add the USING clause if given */
7407
0
  get_from_clause(query, " USING ", context);
7408
7409
  /* Add a WHERE clause if given */
7410
0
  if (query->jointree->quals != NULL)
7411
0
  {
7412
0
    appendContextKeyword(context, " WHERE ",
7413
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7414
0
    get_rule_expr(query->jointree->quals, context, false);
7415
0
  }
7416
7417
  /* Add RETURNING if present */
7418
0
  if (query->returningList)
7419
0
    get_returning_clause(query, context);
7420
0
}
7421
7422
7423
/* ----------
7424
 * get_merge_query_def        - Parse back a MERGE parsetree
7425
 * ----------
7426
 */
7427
static void
7428
get_merge_query_def(Query *query, deparse_context *context)
7429
0
{
7430
0
  StringInfo  buf = context->buf;
7431
0
  RangeTblEntry *rte;
7432
0
  ListCell   *lc;
7433
0
  bool    haveNotMatchedBySource;
7434
7435
  /* Insert the WITH clause if given */
7436
0
  get_with_clause(query, context);
7437
7438
  /*
7439
   * Start the query with MERGE INTO relname
7440
   */
7441
0
  rte = rt_fetch(query->resultRelation, query->rtable);
7442
0
  Assert(rte->rtekind == RTE_RELATION);
7443
0
  if (PRETTY_INDENT(context))
7444
0
  {
7445
0
    appendStringInfoChar(buf, ' ');
7446
0
    context->indentLevel += PRETTYINDENT_STD;
7447
0
  }
7448
0
  appendStringInfo(buf, "MERGE INTO %s%s",
7449
0
           only_marker(rte),
7450
0
           generate_relation_name(rte->relid, NIL));
7451
7452
  /* Print the relation alias, if needed */
7453
0
  get_rte_alias(rte, query->resultRelation, false, context);
7454
7455
  /* Print the source relation and join clause */
7456
0
  get_from_clause(query, " USING ", context);
7457
0
  appendContextKeyword(context, " ON ",
7458
0
             -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7459
0
  get_rule_expr(query->mergeJoinCondition, context, false);
7460
7461
  /*
7462
   * Test for any NOT MATCHED BY SOURCE actions.  If there are none, then
7463
   * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7464
   * SQL standard.  Otherwise, we have a non-SQL-standard query, so output
7465
   * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7466
   * more explicit.
7467
   */
7468
0
  haveNotMatchedBySource = false;
7469
0
  foreach(lc, query->mergeActionList)
7470
0
  {
7471
0
    MergeAction *action = lfirst_node(MergeAction, lc);
7472
7473
0
    if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7474
0
    {
7475
0
      haveNotMatchedBySource = true;
7476
0
      break;
7477
0
    }
7478
0
  }
7479
7480
  /* Print each merge action */
7481
0
  foreach(lc, query->mergeActionList)
7482
0
  {
7483
0
    MergeAction *action = lfirst_node(MergeAction, lc);
7484
7485
0
    appendContextKeyword(context, " WHEN ",
7486
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7487
0
    switch (action->matchKind)
7488
0
    {
7489
0
      case MERGE_WHEN_MATCHED:
7490
0
        appendStringInfoString(buf, "MATCHED");
7491
0
        break;
7492
0
      case MERGE_WHEN_NOT_MATCHED_BY_SOURCE:
7493
0
        appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7494
0
        break;
7495
0
      case MERGE_WHEN_NOT_MATCHED_BY_TARGET:
7496
0
        if (haveNotMatchedBySource)
7497
0
          appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7498
0
        else
7499
0
          appendStringInfoString(buf, "NOT MATCHED");
7500
0
        break;
7501
0
      default:
7502
0
        elog(ERROR, "unrecognized matchKind: %d",
7503
0
           (int) action->matchKind);
7504
0
    }
7505
7506
0
    if (action->qual)
7507
0
    {
7508
0
      appendContextKeyword(context, " AND ",
7509
0
                 -PRETTYINDENT_STD, PRETTYINDENT_STD, 3);
7510
0
      get_rule_expr(action->qual, context, false);
7511
0
    }
7512
0
    appendContextKeyword(context, " THEN ",
7513
0
               -PRETTYINDENT_STD, PRETTYINDENT_STD, 3);
7514
7515
0
    if (action->commandType == CMD_INSERT)
7516
0
    {
7517
      /* This generally matches get_insert_query_def() */
7518
0
      List     *strippedexprs = NIL;
7519
0
      const char *sep = "";
7520
0
      ListCell   *lc2;
7521
7522
0
      appendStringInfoString(buf, "INSERT");
7523
7524
0
      if (action->targetList)
7525
0
        appendStringInfoString(buf, " (");
7526
0
      foreach(lc2, action->targetList)
7527
0
      {
7528
0
        TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7529
7530
0
        Assert(!tle->resjunk);
7531
7532
0
        appendStringInfoString(buf, sep);
7533
0
        sep = ", ";
7534
7535
0
        appendStringInfoString(buf,
7536
0
                     quote_identifier(get_attname(rte->relid,
7537
0
                                  tle->resno,
7538
0
                                  false)));
7539
0
        strippedexprs = lappend(strippedexprs,
7540
0
                    processIndirection((Node *) tle->expr,
7541
0
                               context));
7542
0
      }
7543
0
      if (action->targetList)
7544
0
        appendStringInfoChar(buf, ')');
7545
7546
0
      if (action->override)
7547
0
      {
7548
0
        if (action->override == OVERRIDING_SYSTEM_VALUE)
7549
0
          appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7550
0
        else if (action->override == OVERRIDING_USER_VALUE)
7551
0
          appendStringInfoString(buf, " OVERRIDING USER VALUE");
7552
0
      }
7553
7554
0
      if (strippedexprs)
7555
0
      {
7556
0
        appendContextKeyword(context, " VALUES (",
7557
0
                   -PRETTYINDENT_STD, PRETTYINDENT_STD, 4);
7558
0
        get_rule_list_toplevel(strippedexprs, context, false);
7559
0
        appendStringInfoChar(buf, ')');
7560
0
      }
7561
0
      else
7562
0
        appendStringInfoString(buf, " DEFAULT VALUES");
7563
0
    }
7564
0
    else if (action->commandType == CMD_UPDATE)
7565
0
    {
7566
0
      appendStringInfoString(buf, "UPDATE SET ");
7567
0
      get_update_query_targetlist_def(query, action->targetList,
7568
0
                      context, rte);
7569
0
    }
7570
0
    else if (action->commandType == CMD_DELETE)
7571
0
      appendStringInfoString(buf, "DELETE");
7572
0
    else if (action->commandType == CMD_NOTHING)
7573
0
      appendStringInfoString(buf, "DO NOTHING");
7574
0
  }
7575
7576
  /* Add RETURNING if present */
7577
0
  if (query->returningList)
7578
0
    get_returning_clause(query, context);
7579
0
}
7580
7581
7582
/* ----------
7583
 * get_utility_query_def      - Parse back a UTILITY parsetree
7584
 * ----------
7585
 */
7586
static void
7587
get_utility_query_def(Query *query, deparse_context *context)
7588
0
{
7589
0
  StringInfo  buf = context->buf;
7590
7591
0
  if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7592
0
  {
7593
0
    NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7594
7595
0
    appendContextKeyword(context, "",
7596
0
               0, PRETTYINDENT_STD, 1);
7597
0
    appendStringInfo(buf, "NOTIFY %s",
7598
0
             quote_identifier(stmt->conditionname));
7599
0
    if (stmt->payload)
7600
0
    {
7601
0
      appendStringInfoString(buf, ", ");
7602
0
      simple_quote_literal(buf, stmt->payload);
7603
0
    }
7604
0
  }
7605
0
  else
7606
0
  {
7607
    /* Currently only NOTIFY utility commands can appear in rules */
7608
0
    elog(ERROR, "unexpected utility statement type");
7609
0
  }
7610
0
}
7611
7612
/*
7613
 * Display a Var appropriately.
7614
 *
7615
 * In some cases (currently only when recursing into an unnamed join)
7616
 * the Var's varlevelsup has to be interpreted with respect to a context
7617
 * above the current one; levelsup indicates the offset.
7618
 *
7619
 * If istoplevel is true, the Var is at the top level of a SELECT's
7620
 * targetlist, which means we need special treatment of whole-row Vars.
7621
 * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
7622
 * dirty hack to prevent "tab.*" from being expanded into multiple columns.
7623
 * (The parser will strip the useless coercion, so no inefficiency is added in
7624
 * dump and reload.)  We used to print just "tab" in such cases, but that is
7625
 * ambiguous and will yield the wrong result if "tab" is also a plain column
7626
 * name in the query.
7627
 *
7628
 * Returns the attname of the Var, or NULL if the Var has no attname (because
7629
 * it is a whole-row Var or a subplan output reference).
7630
 */
7631
static char *
7632
get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
7633
0
{
7634
0
  StringInfo  buf = context->buf;
7635
0
  RangeTblEntry *rte;
7636
0
  AttrNumber  attnum;
7637
0
  int     netlevelsup;
7638
0
  deparse_namespace *dpns;
7639
0
  int     varno;
7640
0
  AttrNumber  varattno;
7641
0
  deparse_columns *colinfo;
7642
0
  char     *refname;
7643
0
  char     *attname;
7644
0
  bool    need_prefix;
7645
7646
  /* Find appropriate nesting depth */
7647
0
  netlevelsup = var->varlevelsup + levelsup;
7648
0
  if (netlevelsup >= list_length(context->namespaces))
7649
0
    elog(ERROR, "bogus varlevelsup: %d offset %d",
7650
0
       var->varlevelsup, levelsup);
7651
0
  dpns = (deparse_namespace *) list_nth(context->namespaces,
7652
0
                      netlevelsup);
7653
7654
  /*
7655
   * If we have a syntactic referent for the Var, and we're working from a
7656
   * parse tree, prefer to use the syntactic referent.  Otherwise, fall back
7657
   * on the semantic referent.  (Forcing use of the semantic referent when
7658
   * printing plan trees is a design choice that's perhaps more motivated by
7659
   * backwards compatibility than anything else.  But it does have the
7660
   * advantage of making plans more explicit.)
7661
   */
7662
0
  if (var->varnosyn > 0 && dpns->plan == NULL)
7663
0
  {
7664
0
    varno = var->varnosyn;
7665
0
    varattno = var->varattnosyn;
7666
0
  }
7667
0
  else
7668
0
  {
7669
0
    varno = var->varno;
7670
0
    varattno = var->varattno;
7671
0
  }
7672
7673
  /*
7674
   * Try to find the relevant RTE in this rtable.  In a plan tree, it's
7675
   * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7676
   * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7677
   * find the aliases previously assigned for this RTE.
7678
   */
7679
0
  if (varno >= 1 && varno <= list_length(dpns->rtable))
7680
0
  {
7681
    /*
7682
     * We might have been asked to map child Vars to some parent relation.
7683
     */
7684
0
    if (context->appendparents && dpns->appendrels)
7685
0
    {
7686
0
      int     pvarno = varno;
7687
0
      AttrNumber  pvarattno = varattno;
7688
0
      AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7689
0
      bool    found = false;
7690
7691
      /* Only map up to inheritance parents, not UNION ALL appendrels */
7692
0
      while (appinfo &&
7693
0
           rt_fetch(appinfo->parent_relid,
7694
0
              dpns->rtable)->rtekind == RTE_RELATION)
7695
0
      {
7696
0
        found = false;
7697
0
        if (pvarattno > 0) /* system columns stay as-is */
7698
0
        {
7699
0
          if (pvarattno > appinfo->num_child_cols)
7700
0
            break; /* safety check */
7701
0
          pvarattno = appinfo->parent_colnos[pvarattno - 1];
7702
0
          if (pvarattno == 0)
7703
0
            break; /* Var is local to child */
7704
0
        }
7705
7706
0
        pvarno = appinfo->parent_relid;
7707
0
        found = true;
7708
7709
        /* If the parent is itself a child, continue up. */
7710
0
        Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7711
0
        appinfo = dpns->appendrels[pvarno];
7712
0
      }
7713
7714
      /*
7715
       * If we found an ancestral rel, and that rel is included in
7716
       * appendparents, print that column not the original one.
7717
       */
7718
0
      if (found && bms_is_member(pvarno, context->appendparents))
7719
0
      {
7720
0
        varno = pvarno;
7721
0
        varattno = pvarattno;
7722
0
      }
7723
0
    }
7724
7725
0
    rte = rt_fetch(varno, dpns->rtable);
7726
7727
    /* might be returning old/new column value */
7728
0
    if (var->varreturningtype == VAR_RETURNING_OLD)
7729
0
      refname = dpns->ret_old_alias;
7730
0
    else if (var->varreturningtype == VAR_RETURNING_NEW)
7731
0
      refname = dpns->ret_new_alias;
7732
0
    else
7733
0
      refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7734
7735
0
    colinfo = deparse_columns_fetch(varno, dpns);
7736
0
    attnum = varattno;
7737
0
  }
7738
0
  else
7739
0
  {
7740
0
    resolve_special_varno((Node *) var, context,
7741
0
                get_special_variable, NULL);
7742
0
    return NULL;
7743
0
  }
7744
7745
  /*
7746
   * The planner will sometimes emit Vars referencing resjunk elements of a
7747
   * subquery's target list (this is currently only possible if it chooses
7748
   * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7749
   * Although we prefer to print subquery-referencing Vars using the
7750
   * subquery's alias, that's not possible for resjunk items since they have
7751
   * no alias.  So in that case, drill down to the subplan and print the
7752
   * contents of the referenced tlist item.  This works because in a plan
7753
   * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7754
   * we'll have set dpns->inner_plan to reference the child plan node.
7755
   */
7756
0
  if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7757
0
    attnum > list_length(rte->eref->colnames) &&
7758
0
    dpns->inner_plan)
7759
0
  {
7760
0
    TargetEntry *tle;
7761
0
    deparse_namespace save_dpns;
7762
7763
0
    tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7764
0
    if (!tle)
7765
0
      elog(ERROR, "invalid attnum %d for relation \"%s\"",
7766
0
         attnum, rte->eref->aliasname);
7767
7768
0
    Assert(netlevelsup == 0);
7769
0
    push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7770
7771
    /*
7772
     * Force parentheses because our caller probably assumed a Var is a
7773
     * simple expression.
7774
     */
7775
0
    if (!IsA(tle->expr, Var))
7776
0
      appendStringInfoChar(buf, '(');
7777
0
    get_rule_expr((Node *) tle->expr, context, true);
7778
0
    if (!IsA(tle->expr, Var))
7779
0
      appendStringInfoChar(buf, ')');
7780
7781
0
    pop_child_plan(dpns, &save_dpns);
7782
0
    return NULL;
7783
0
  }
7784
7785
  /*
7786
   * If it's an unnamed join, look at the expansion of the alias variable.
7787
   * If it's a simple reference to one of the input vars, then recursively
7788
   * print the name of that var instead.  When it's not a simple reference,
7789
   * we have to just print the unqualified join column name.  (This can only
7790
   * happen with "dangerous" merged columns in a JOIN USING; we took pains
7791
   * previously to make the unqualified column name unique in such cases.)
7792
   *
7793
   * This wouldn't work in decompiling plan trees, because we don't store
7794
   * joinaliasvars lists after planning; but a plan tree should never
7795
   * contain a join alias variable.
7796
   */
7797
0
  if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7798
0
  {
7799
0
    if (rte->joinaliasvars == NIL)
7800
0
      elog(ERROR, "cannot decompile join alias var in plan tree");
7801
0
    if (attnum > 0)
7802
0
    {
7803
0
      Var      *aliasvar;
7804
7805
0
      aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7806
      /* we intentionally don't strip implicit coercions here */
7807
0
      if (aliasvar && IsA(aliasvar, Var))
7808
0
      {
7809
0
        return get_variable(aliasvar, var->varlevelsup + levelsup,
7810
0
                  istoplevel, context);
7811
0
      }
7812
0
    }
7813
7814
    /*
7815
     * Unnamed join has no refname.  (Note: since it's unnamed, there is
7816
     * no way the user could have referenced it to create a whole-row Var
7817
     * for it.  So we don't have to cover that case below.)
7818
     */
7819
0
    Assert(refname == NULL);
7820
0
  }
7821
7822
0
  if (attnum == InvalidAttrNumber)
7823
0
    attname = NULL;
7824
0
  else if (attnum > 0)
7825
0
  {
7826
    /* Get column name to use from the colinfo struct */
7827
0
    if (attnum > colinfo->num_cols)
7828
0
      elog(ERROR, "invalid attnum %d for relation \"%s\"",
7829
0
         attnum, rte->eref->aliasname);
7830
0
    attname = colinfo->colnames[attnum - 1];
7831
7832
    /*
7833
     * If we find a Var referencing a dropped column, it seems better to
7834
     * print something (anything) than to fail.  In general this should
7835
     * not happen, but it used to be possible for some cases involving
7836
     * functions returning named composite types, and perhaps there are
7837
     * still bugs out there.
7838
     */
7839
0
    if (attname == NULL)
7840
0
      attname = "?dropped?column?";
7841
0
  }
7842
0
  else
7843
0
  {
7844
    /* System column - name is fixed, get it from the catalog */
7845
0
    attname = get_rte_attribute_name(rte, attnum);
7846
0
  }
7847
7848
0
  need_prefix = (context->varprefix || attname == NULL ||
7849
0
           var->varreturningtype != VAR_RETURNING_DEFAULT);
7850
7851
  /*
7852
   * If we're considering a plain Var in an ORDER BY (but not GROUP BY)
7853
   * clause, we may need to add a table-name prefix to prevent
7854
   * findTargetlistEntrySQL92 from misinterpreting the name as an
7855
   * output-column name.  To avoid cluttering the output with unnecessary
7856
   * prefixes, do so only if there is a name match to a SELECT tlist item
7857
   * that is different from the Var.
7858
   */
7859
0
  if (context->varInOrderBy && !context->inGroupBy && !need_prefix)
7860
0
  {
7861
0
    int     colno = 0;
7862
7863
0
    foreach_node(TargetEntry, tle, context->targetList)
7864
0
    {
7865
0
      char     *colname;
7866
7867
0
      if (tle->resjunk)
7868
0
        continue;   /* ignore junk entries */
7869
0
      colno++;
7870
7871
      /* This must match colname-choosing logic in get_target_list() */
7872
0
      if (context->resultDesc && colno <= context->resultDesc->natts)
7873
0
        colname = NameStr(TupleDescAttr(context->resultDesc,
7874
0
                        colno - 1)->attname);
7875
0
      else
7876
0
        colname = tle->resname;
7877
7878
0
      if (colname && strcmp(colname, attname) == 0 &&
7879
0
        !equal(var, tle->expr))
7880
0
      {
7881
0
        need_prefix = true;
7882
0
        break;
7883
0
      }
7884
0
    }
7885
0
  }
7886
7887
0
  if (refname && need_prefix)
7888
0
  {
7889
0
    appendStringInfoString(buf, quote_identifier(refname));
7890
0
    appendStringInfoChar(buf, '.');
7891
0
  }
7892
0
  if (attname)
7893
0
    appendStringInfoString(buf, quote_identifier(attname));
7894
0
  else
7895
0
  {
7896
0
    appendStringInfoChar(buf, '*');
7897
0
    if (istoplevel)
7898
0
      appendStringInfo(buf, "::%s",
7899
0
               format_type_with_typemod(var->vartype,
7900
0
                            var->vartypmod));
7901
0
  }
7902
7903
0
  return attname;
7904
0
}
7905
7906
/*
7907
 * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR.  This
7908
 * routine is actually a callback for resolve_special_varno, which handles
7909
 * finding the correct TargetEntry.  We get the expression contained in that
7910
 * TargetEntry and just need to deparse it, a job we can throw back on
7911
 * get_rule_expr.
7912
 */
7913
static void
7914
get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7915
0
{
7916
0
  StringInfo  buf = context->buf;
7917
7918
  /*
7919
   * For a non-Var referent, force parentheses because our caller probably
7920
   * assumed a Var is a simple expression.
7921
   */
7922
0
  if (!IsA(node, Var))
7923
0
    appendStringInfoChar(buf, '(');
7924
0
  get_rule_expr(node, context, true);
7925
0
  if (!IsA(node, Var))
7926
0
    appendStringInfoChar(buf, ')');
7927
0
}
7928
7929
/*
7930
 * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7931
 * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7932
 * invoke the callback provided.
7933
 */
7934
static void
7935
resolve_special_varno(Node *node, deparse_context *context,
7936
            rsv_callback callback, void *callback_arg)
7937
0
{
7938
0
  Var      *var;
7939
0
  deparse_namespace *dpns;
7940
7941
  /* This function is recursive, so let's be paranoid. */
7942
0
  check_stack_depth();
7943
7944
  /* If it's not a Var, invoke the callback. */
7945
0
  if (!IsA(node, Var))
7946
0
  {
7947
0
    (*callback) (node, context, callback_arg);
7948
0
    return;
7949
0
  }
7950
7951
  /* Find appropriate nesting depth */
7952
0
  var = (Var *) node;
7953
0
  dpns = (deparse_namespace *) list_nth(context->namespaces,
7954
0
                      var->varlevelsup);
7955
7956
  /*
7957
   * If varno is special, recurse.  (Don't worry about varnosyn; if we're
7958
   * here, we already decided not to use that.)
7959
   */
7960
0
  if (var->varno == OUTER_VAR && dpns->outer_tlist)
7961
0
  {
7962
0
    TargetEntry *tle;
7963
0
    deparse_namespace save_dpns;
7964
0
    Bitmapset  *save_appendparents;
7965
7966
0
    tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7967
0
    if (!tle)
7968
0
      elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7969
7970
    /*
7971
     * If we're descending to the first child of an Append or MergeAppend,
7972
     * update appendparents.  This will affect deparsing of all Vars
7973
     * appearing within the eventually-resolved subexpression.
7974
     */
7975
0
    save_appendparents = context->appendparents;
7976
7977
0
    if (IsA(dpns->plan, Append))
7978
0
      context->appendparents = bms_union(context->appendparents,
7979
0
                         ((Append *) dpns->plan)->apprelids);
7980
0
    else if (IsA(dpns->plan, MergeAppend))
7981
0
      context->appendparents = bms_union(context->appendparents,
7982
0
                         ((MergeAppend *) dpns->plan)->apprelids);
7983
7984
0
    push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7985
0
    resolve_special_varno((Node *) tle->expr, context,
7986
0
                callback, callback_arg);
7987
0
    pop_child_plan(dpns, &save_dpns);
7988
0
    context->appendparents = save_appendparents;
7989
0
    return;
7990
0
  }
7991
0
  else if (var->varno == INNER_VAR && dpns->inner_tlist)
7992
0
  {
7993
0
    TargetEntry *tle;
7994
0
    deparse_namespace save_dpns;
7995
7996
0
    tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7997
0
    if (!tle)
7998
0
      elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7999
8000
0
    push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8001
0
    resolve_special_varno((Node *) tle->expr, context,
8002
0
                callback, callback_arg);
8003
0
    pop_child_plan(dpns, &save_dpns);
8004
0
    return;
8005
0
  }
8006
0
  else if (var->varno == INDEX_VAR && dpns->index_tlist)
8007
0
  {
8008
0
    TargetEntry *tle;
8009
8010
0
    tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
8011
0
    if (!tle)
8012
0
      elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
8013
8014
0
    resolve_special_varno((Node *) tle->expr, context,
8015
0
                callback, callback_arg);
8016
0
    return;
8017
0
  }
8018
0
  else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
8019
0
    elog(ERROR, "bogus varno: %d", var->varno);
8020
8021
  /* Not special.  Just invoke the callback. */
8022
0
  (*callback) (node, context, callback_arg);
8023
0
}
8024
8025
/*
8026
 * Get the name of a field of an expression of composite type.  The
8027
 * expression is usually a Var, but we handle other cases too.
8028
 *
8029
 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
8030
 *
8031
 * This is fairly straightforward when the expression has a named composite
8032
 * type; we need only look up the type in the catalogs.  However, the type
8033
 * could also be RECORD.  Since no actual table or view column is allowed to
8034
 * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
8035
 * or to a subquery output.  We drill down to find the ultimate defining
8036
 * expression and attempt to infer the field name from it.  We ereport if we
8037
 * can't determine the name.
8038
 *
8039
 * Similarly, a PARAM of type RECORD has to refer to some expression of
8040
 * a determinable composite type.
8041
 */
8042
static const char *
8043
get_name_for_var_field(Var *var, int fieldno,
8044
             int levelsup, deparse_context *context)
8045
0
{
8046
0
  RangeTblEntry *rte;
8047
0
  AttrNumber  attnum;
8048
0
  int     netlevelsup;
8049
0
  deparse_namespace *dpns;
8050
0
  int     varno;
8051
0
  AttrNumber  varattno;
8052
0
  TupleDesc tupleDesc;
8053
0
  Node     *expr;
8054
8055
  /*
8056
   * If it's a RowExpr that was expanded from a whole-row Var, use the
8057
   * column names attached to it.  (We could let get_expr_result_tupdesc()
8058
   * handle this, but it's much cheaper to just pull out the name we need.)
8059
   */
8060
0
  if (IsA(var, RowExpr))
8061
0
  {
8062
0
    RowExpr    *r = (RowExpr *) var;
8063
8064
0
    if (fieldno > 0 && fieldno <= list_length(r->colnames))
8065
0
      return strVal(list_nth(r->colnames, fieldno - 1));
8066
0
  }
8067
8068
  /*
8069
   * If it's a Param of type RECORD, try to find what the Param refers to.
8070
   */
8071
0
  if (IsA(var, Param))
8072
0
  {
8073
0
    Param    *param = (Param *) var;
8074
0
    ListCell   *ancestor_cell;
8075
8076
0
    expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8077
0
    if (expr)
8078
0
    {
8079
      /* Found a match, so recurse to decipher the field name */
8080
0
      deparse_namespace save_dpns;
8081
0
      const char *result;
8082
8083
0
      push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8084
0
      result = get_name_for_var_field((Var *) expr, fieldno,
8085
0
                      0, context);
8086
0
      pop_ancestor_plan(dpns, &save_dpns);
8087
0
      return result;
8088
0
    }
8089
0
  }
8090
8091
  /*
8092
   * If it's a Var of type RECORD, we have to find what the Var refers to;
8093
   * if not, we can use get_expr_result_tupdesc().
8094
   */
8095
0
  if (!IsA(var, Var) ||
8096
0
    var->vartype != RECORDOID)
8097
0
  {
8098
0
    tupleDesc = get_expr_result_tupdesc((Node *) var, false);
8099
    /* Got the tupdesc, so we can extract the field name */
8100
0
    Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8101
0
    return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8102
0
  }
8103
8104
  /* Find appropriate nesting depth */
8105
0
  netlevelsup = var->varlevelsup + levelsup;
8106
0
  if (netlevelsup >= list_length(context->namespaces))
8107
0
    elog(ERROR, "bogus varlevelsup: %d offset %d",
8108
0
       var->varlevelsup, levelsup);
8109
0
  dpns = (deparse_namespace *) list_nth(context->namespaces,
8110
0
                      netlevelsup);
8111
8112
  /*
8113
   * If we have a syntactic referent for the Var, and we're working from a
8114
   * parse tree, prefer to use the syntactic referent.  Otherwise, fall back
8115
   * on the semantic referent.  (See comments in get_variable().)
8116
   */
8117
0
  if (var->varnosyn > 0 && dpns->plan == NULL)
8118
0
  {
8119
0
    varno = var->varnosyn;
8120
0
    varattno = var->varattnosyn;
8121
0
  }
8122
0
  else
8123
0
  {
8124
0
    varno = var->varno;
8125
0
    varattno = var->varattno;
8126
0
  }
8127
8128
  /*
8129
   * Try to find the relevant RTE in this rtable.  In a plan tree, it's
8130
   * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
8131
   * down into the subplans, or INDEX_VAR, which is resolved similarly.
8132
   *
8133
   * Note: unlike get_variable and resolve_special_varno, we need not worry
8134
   * about inheritance mapping: a child Var should have the same datatype as
8135
   * its parent, and here we're really only interested in the Var's type.
8136
   */
8137
0
  if (varno >= 1 && varno <= list_length(dpns->rtable))
8138
0
  {
8139
0
    rte = rt_fetch(varno, dpns->rtable);
8140
0
    attnum = varattno;
8141
0
  }
8142
0
  else if (varno == OUTER_VAR && dpns->outer_tlist)
8143
0
  {
8144
0
    TargetEntry *tle;
8145
0
    deparse_namespace save_dpns;
8146
0
    const char *result;
8147
8148
0
    tle = get_tle_by_resno(dpns->outer_tlist, varattno);
8149
0
    if (!tle)
8150
0
      elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
8151
8152
0
    Assert(netlevelsup == 0);
8153
0
    push_child_plan(dpns, dpns->outer_plan, &save_dpns);
8154
8155
0
    result = get_name_for_var_field((Var *) tle->expr, fieldno,
8156
0
                    levelsup, context);
8157
8158
0
    pop_child_plan(dpns, &save_dpns);
8159
0
    return result;
8160
0
  }
8161
0
  else if (varno == INNER_VAR && dpns->inner_tlist)
8162
0
  {
8163
0
    TargetEntry *tle;
8164
0
    deparse_namespace save_dpns;
8165
0
    const char *result;
8166
8167
0
    tle = get_tle_by_resno(dpns->inner_tlist, varattno);
8168
0
    if (!tle)
8169
0
      elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
8170
8171
0
    Assert(netlevelsup == 0);
8172
0
    push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8173
8174
0
    result = get_name_for_var_field((Var *) tle->expr, fieldno,
8175
0
                    levelsup, context);
8176
8177
0
    pop_child_plan(dpns, &save_dpns);
8178
0
    return result;
8179
0
  }
8180
0
  else if (varno == INDEX_VAR && dpns->index_tlist)
8181
0
  {
8182
0
    TargetEntry *tle;
8183
0
    const char *result;
8184
8185
0
    tle = get_tle_by_resno(dpns->index_tlist, varattno);
8186
0
    if (!tle)
8187
0
      elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
8188
8189
0
    Assert(netlevelsup == 0);
8190
8191
0
    result = get_name_for_var_field((Var *) tle->expr, fieldno,
8192
0
                    levelsup, context);
8193
8194
0
    return result;
8195
0
  }
8196
0
  else
8197
0
  {
8198
0
    elog(ERROR, "bogus varno: %d", varno);
8199
0
    return NULL;     /* keep compiler quiet */
8200
0
  }
8201
8202
0
  if (attnum == InvalidAttrNumber)
8203
0
  {
8204
    /* Var is whole-row reference to RTE, so select the right field */
8205
0
    return get_rte_attribute_name(rte, fieldno);
8206
0
  }
8207
8208
  /*
8209
   * This part has essentially the same logic as the parser's
8210
   * expandRecordVariable() function, but we are dealing with a different
8211
   * representation of the input context, and we only need one field name
8212
   * not a TupleDesc.  Also, we need special cases for finding subquery and
8213
   * CTE subplans when deparsing Plan trees.
8214
   */
8215
0
  expr = (Node *) var;    /* default if we can't drill down */
8216
8217
0
  switch (rte->rtekind)
8218
0
  {
8219
0
    case RTE_RELATION:
8220
0
    case RTE_VALUES:
8221
0
    case RTE_NAMEDTUPLESTORE:
8222
0
    case RTE_RESULT:
8223
8224
      /*
8225
       * This case should not occur: a column of a table, values list,
8226
       * or ENR shouldn't have type RECORD.  Fall through and fail (most
8227
       * likely) at the bottom.
8228
       */
8229
0
      break;
8230
0
    case RTE_SUBQUERY:
8231
      /* Subselect-in-FROM: examine sub-select's output expr */
8232
0
      {
8233
0
        if (rte->subquery)
8234
0
        {
8235
0
          TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
8236
0
                            attnum);
8237
8238
0
          if (ste == NULL || ste->resjunk)
8239
0
            elog(ERROR, "subquery %s does not have attribute %d",
8240
0
               rte->eref->aliasname, attnum);
8241
0
          expr = (Node *) ste->expr;
8242
0
          if (IsA(expr, Var))
8243
0
          {
8244
            /*
8245
             * Recurse into the sub-select to see what its Var
8246
             * refers to. We have to build an additional level of
8247
             * namespace to keep in step with varlevelsup in the
8248
             * subselect; furthermore, the subquery RTE might be
8249
             * from an outer query level, in which case the
8250
             * namespace for the subselect must have that outer
8251
             * level as parent namespace.
8252
             */
8253
0
            List     *save_nslist = context->namespaces;
8254
0
            List     *parent_namespaces;
8255
0
            deparse_namespace mydpns;
8256
0
            const char *result;
8257
8258
0
            parent_namespaces = list_copy_tail(context->namespaces,
8259
0
                               netlevelsup);
8260
8261
0
            set_deparse_for_query(&mydpns, rte->subquery,
8262
0
                        parent_namespaces);
8263
8264
0
            context->namespaces = lcons(&mydpns, parent_namespaces);
8265
8266
0
            result = get_name_for_var_field((Var *) expr, fieldno,
8267
0
                            0, context);
8268
8269
0
            context->namespaces = save_nslist;
8270
8271
0
            return result;
8272
0
          }
8273
          /* else fall through to inspect the expression */
8274
0
        }
8275
0
        else
8276
0
        {
8277
          /*
8278
           * We're deparsing a Plan tree so we don't have complete
8279
           * RTE entries (in particular, rte->subquery is NULL). But
8280
           * the only place we'd normally see a Var directly
8281
           * referencing a SUBQUERY RTE is in a SubqueryScan plan
8282
           * node, and we can look into the child plan's tlist
8283
           * instead.  An exception occurs if the subquery was
8284
           * proven empty and optimized away: then we'd find such a
8285
           * Var in a childless Result node, and there's nothing in
8286
           * the plan tree that would let us figure out what it had
8287
           * originally referenced.  In that case, fall back on
8288
           * printing "fN", analogously to the default column names
8289
           * for RowExprs.
8290
           */
8291
0
          TargetEntry *tle;
8292
0
          deparse_namespace save_dpns;
8293
0
          const char *result;
8294
8295
0
          if (!dpns->inner_plan)
8296
0
          {
8297
0
            char     *dummy_name = palloc(32);
8298
8299
0
            Assert(dpns->plan && IsA(dpns->plan, Result));
8300
0
            snprintf(dummy_name, 32, "f%d", fieldno);
8301
0
            return dummy_name;
8302
0
          }
8303
0
          Assert(dpns->plan && IsA(dpns->plan, SubqueryScan));
8304
8305
0
          tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8306
0
          if (!tle)
8307
0
            elog(ERROR, "bogus varattno for subquery var: %d",
8308
0
               attnum);
8309
0
          Assert(netlevelsup == 0);
8310
0
          push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8311
8312
0
          result = get_name_for_var_field((Var *) tle->expr, fieldno,
8313
0
                          levelsup, context);
8314
8315
0
          pop_child_plan(dpns, &save_dpns);
8316
0
          return result;
8317
0
        }
8318
0
      }
8319
0
      break;
8320
0
    case RTE_JOIN:
8321
      /* Join RTE --- recursively inspect the alias variable */
8322
0
      if (rte->joinaliasvars == NIL)
8323
0
        elog(ERROR, "cannot decompile join alias var in plan tree");
8324
0
      Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
8325
0
      expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
8326
0
      Assert(expr != NULL);
8327
      /* we intentionally don't strip implicit coercions here */
8328
0
      if (IsA(expr, Var))
8329
0
        return get_name_for_var_field((Var *) expr, fieldno,
8330
0
                        var->varlevelsup + levelsup,
8331
0
                        context);
8332
      /* else fall through to inspect the expression */
8333
0
      break;
8334
0
    case RTE_FUNCTION:
8335
0
    case RTE_TABLEFUNC:
8336
8337
      /*
8338
       * We couldn't get here unless a function is declared with one of
8339
       * its result columns as RECORD, which is not allowed.
8340
       */
8341
0
      break;
8342
0
    case RTE_CTE:
8343
      /* CTE reference: examine subquery's output expr */
8344
0
      {
8345
0
        CommonTableExpr *cte = NULL;
8346
0
        Index   ctelevelsup;
8347
0
        ListCell   *lc;
8348
8349
        /*
8350
         * Try to find the referenced CTE using the namespace stack.
8351
         */
8352
0
        ctelevelsup = rte->ctelevelsup + netlevelsup;
8353
0
        if (ctelevelsup >= list_length(context->namespaces))
8354
0
          lc = NULL;
8355
0
        else
8356
0
        {
8357
0
          deparse_namespace *ctedpns;
8358
8359
0
          ctedpns = (deparse_namespace *)
8360
0
            list_nth(context->namespaces, ctelevelsup);
8361
0
          foreach(lc, ctedpns->ctes)
8362
0
          {
8363
0
            cte = (CommonTableExpr *) lfirst(lc);
8364
0
            if (strcmp(cte->ctename, rte->ctename) == 0)
8365
0
              break;
8366
0
          }
8367
0
        }
8368
0
        if (lc != NULL)
8369
0
        {
8370
0
          Query    *ctequery = (Query *) cte->ctequery;
8371
0
          TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
8372
0
                            attnum);
8373
8374
0
          if (ste == NULL || ste->resjunk)
8375
0
            elog(ERROR, "CTE %s does not have attribute %d",
8376
0
               rte->eref->aliasname, attnum);
8377
0
          expr = (Node *) ste->expr;
8378
0
          if (IsA(expr, Var))
8379
0
          {
8380
            /*
8381
             * Recurse into the CTE to see what its Var refers to.
8382
             * We have to build an additional level of namespace
8383
             * to keep in step with varlevelsup in the CTE;
8384
             * furthermore it could be an outer CTE (compare
8385
             * SUBQUERY case above).
8386
             */
8387
0
            List     *save_nslist = context->namespaces;
8388
0
            List     *parent_namespaces;
8389
0
            deparse_namespace mydpns;
8390
0
            const char *result;
8391
8392
0
            parent_namespaces = list_copy_tail(context->namespaces,
8393
0
                               ctelevelsup);
8394
8395
0
            set_deparse_for_query(&mydpns, ctequery,
8396
0
                        parent_namespaces);
8397
8398
0
            context->namespaces = lcons(&mydpns, parent_namespaces);
8399
8400
0
            result = get_name_for_var_field((Var *) expr, fieldno,
8401
0
                            0, context);
8402
8403
0
            context->namespaces = save_nslist;
8404
8405
0
            return result;
8406
0
          }
8407
          /* else fall through to inspect the expression */
8408
0
        }
8409
0
        else
8410
0
        {
8411
          /*
8412
           * We're deparsing a Plan tree so we don't have a CTE
8413
           * list.  But the only places we'd normally see a Var
8414
           * directly referencing a CTE RTE are in CteScan or
8415
           * WorkTableScan plan nodes.  For those cases,
8416
           * set_deparse_plan arranged for dpns->inner_plan to be
8417
           * the plan node that emits the CTE or RecursiveUnion
8418
           * result, and we can look at its tlist instead.  As
8419
           * above, this can fail if the CTE has been proven empty,
8420
           * in which case fall back to "fN".
8421
           */
8422
0
          TargetEntry *tle;
8423
0
          deparse_namespace save_dpns;
8424
0
          const char *result;
8425
8426
0
          if (!dpns->inner_plan)
8427
0
          {
8428
0
            char     *dummy_name = palloc(32);
8429
8430
0
            Assert(dpns->plan && IsA(dpns->plan, Result));
8431
0
            snprintf(dummy_name, 32, "f%d", fieldno);
8432
0
            return dummy_name;
8433
0
          }
8434
0
          Assert(dpns->plan && (IsA(dpns->plan, CteScan) ||
8435
0
                      IsA(dpns->plan, WorkTableScan)));
8436
8437
0
          tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8438
0
          if (!tle)
8439
0
            elog(ERROR, "bogus varattno for subquery var: %d",
8440
0
               attnum);
8441
0
          Assert(netlevelsup == 0);
8442
0
          push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8443
8444
0
          result = get_name_for_var_field((Var *) tle->expr, fieldno,
8445
0
                          levelsup, context);
8446
8447
0
          pop_child_plan(dpns, &save_dpns);
8448
0
          return result;
8449
0
        }
8450
0
      }
8451
0
      break;
8452
0
    case RTE_GROUP:
8453
8454
      /*
8455
       * We couldn't get here: any Vars that reference the RTE_GROUP RTE
8456
       * should have been replaced with the underlying grouping
8457
       * expressions.
8458
       */
8459
0
      break;
8460
0
  }
8461
8462
  /*
8463
   * We now have an expression we can't expand any more, so see if
8464
   * get_expr_result_tupdesc() can do anything with it.
8465
   */
8466
0
  tupleDesc = get_expr_result_tupdesc(expr, false);
8467
  /* Got the tupdesc, so we can extract the field name */
8468
0
  Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8469
0
  return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8470
0
}
8471
8472
/*
8473
 * Try to find the referenced expression for a PARAM_EXEC Param that might
8474
 * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
8475
 *
8476
 * If successful, return the expression and set *dpns_p and *ancestor_cell_p
8477
 * appropriately for calling push_ancestor_plan().  If no referent can be
8478
 * found, return NULL.
8479
 */
8480
static Node *
8481
find_param_referent(Param *param, deparse_context *context,
8482
          deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
8483
0
{
8484
  /* Initialize output parameters to prevent compiler warnings */
8485
0
  *dpns_p = NULL;
8486
0
  *ancestor_cell_p = NULL;
8487
8488
  /*
8489
   * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8490
   * SubPlan argument.  This will necessarily be in some ancestor of the
8491
   * current expression's Plan node.
8492
   */
8493
0
  if (param->paramkind == PARAM_EXEC)
8494
0
  {
8495
0
    deparse_namespace *dpns;
8496
0
    Plan     *child_plan;
8497
0
    ListCell   *lc;
8498
8499
0
    dpns = (deparse_namespace *) linitial(context->namespaces);
8500
0
    child_plan = dpns->plan;
8501
8502
0
    foreach(lc, dpns->ancestors)
8503
0
    {
8504
0
      Node     *ancestor = (Node *) lfirst(lc);
8505
0
      ListCell   *lc2;
8506
8507
      /*
8508
       * NestLoops transmit params to their inner child only.
8509
       */
8510
0
      if (IsA(ancestor, NestLoop) &&
8511
0
        child_plan == innerPlan(ancestor))
8512
0
      {
8513
0
        NestLoop   *nl = (NestLoop *) ancestor;
8514
8515
0
        foreach(lc2, nl->nestParams)
8516
0
        {
8517
0
          NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8518
8519
0
          if (nlp->paramno == param->paramid)
8520
0
          {
8521
            /* Found a match, so return it */
8522
0
            *dpns_p = dpns;
8523
0
            *ancestor_cell_p = lc;
8524
0
            return (Node *) nlp->paramval;
8525
0
          }
8526
0
        }
8527
0
      }
8528
8529
      /*
8530
       * If ancestor is a SubPlan, check the arguments it provides.
8531
       */
8532
0
      if (IsA(ancestor, SubPlan))
8533
0
      {
8534
0
        SubPlan    *subplan = (SubPlan *) ancestor;
8535
0
        ListCell   *lc3;
8536
0
        ListCell   *lc4;
8537
8538
0
        forboth(lc3, subplan->parParam, lc4, subplan->args)
8539
0
        {
8540
0
          int     paramid = lfirst_int(lc3);
8541
0
          Node     *arg = (Node *) lfirst(lc4);
8542
8543
0
          if (paramid == param->paramid)
8544
0
          {
8545
            /*
8546
             * Found a match, so return it.  But, since Vars in
8547
             * the arg are to be evaluated in the surrounding
8548
             * context, we have to point to the next ancestor item
8549
             * that is *not* a SubPlan.
8550
             */
8551
0
            ListCell   *rest;
8552
8553
0
            for_each_cell(rest, dpns->ancestors,
8554
0
                    lnext(dpns->ancestors, lc))
8555
0
            {
8556
0
              Node     *ancestor2 = (Node *) lfirst(rest);
8557
8558
0
              if (!IsA(ancestor2, SubPlan))
8559
0
              {
8560
0
                *dpns_p = dpns;
8561
0
                *ancestor_cell_p = rest;
8562
0
                return arg;
8563
0
              }
8564
0
            }
8565
0
            elog(ERROR, "SubPlan cannot be outermost ancestor");
8566
0
          }
8567
0
        }
8568
8569
        /* SubPlan isn't a kind of Plan, so skip the rest */
8570
0
        continue;
8571
0
      }
8572
8573
      /*
8574
       * We need not consider the ancestor's initPlan list, since
8575
       * initplans never have any parParams.
8576
       */
8577
8578
      /* No luck, crawl up to next ancestor */
8579
0
      child_plan = (Plan *) ancestor;
8580
0
    }
8581
0
  }
8582
8583
  /* No referent found */
8584
0
  return NULL;
8585
0
}
8586
8587
/*
8588
 * Try to find a subplan/initplan that emits the value for a PARAM_EXEC Param.
8589
 *
8590
 * If successful, return the generating subplan/initplan and set *column_p
8591
 * to the subplan's 0-based output column number.
8592
 * Otherwise, return NULL.
8593
 */
8594
static SubPlan *
8595
find_param_generator(Param *param, deparse_context *context, int *column_p)
8596
0
{
8597
  /* Initialize output parameter to prevent compiler warnings */
8598
0
  *column_p = 0;
8599
8600
  /*
8601
   * If it's a PARAM_EXEC parameter, search the current plan node as well as
8602
   * ancestor nodes looking for a subplan or initplan that emits the value
8603
   * for the Param.  It could appear in the setParams of an initplan or
8604
   * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
8605
   */
8606
0
  if (param->paramkind == PARAM_EXEC)
8607
0
  {
8608
0
    SubPlan    *result;
8609
0
    deparse_namespace *dpns;
8610
0
    ListCell   *lc;
8611
8612
0
    dpns = (deparse_namespace *) linitial(context->namespaces);
8613
8614
    /* First check the innermost plan node's initplans */
8615
0
    result = find_param_generator_initplan(param, dpns->plan, column_p);
8616
0
    if (result)
8617
0
      return result;
8618
8619
    /*
8620
     * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
8621
     * which can be referenced by Params elsewhere in the targetlist.
8622
     * (Such Params should always be in the same targetlist, so there's no
8623
     * need to do this work at upper plan nodes.)
8624
     */
8625
0
    foreach_node(TargetEntry, tle, dpns->plan->targetlist)
8626
0
    {
8627
0
      if (tle->expr && IsA(tle->expr, SubPlan))
8628
0
      {
8629
0
        SubPlan    *subplan = (SubPlan *) tle->expr;
8630
8631
0
        if (subplan->subLinkType == MULTIEXPR_SUBLINK)
8632
0
        {
8633
0
          foreach_int(paramid, subplan->setParam)
8634
0
          {
8635
0
            if (paramid == param->paramid)
8636
0
            {
8637
              /* Found a match, so return it. */
8638
0
              *column_p = foreach_current_index(paramid);
8639
0
              return subplan;
8640
0
            }
8641
0
          }
8642
0
        }
8643
0
      }
8644
0
    }
8645
8646
    /* No luck, so check the ancestor nodes */
8647
0
    foreach(lc, dpns->ancestors)
8648
0
    {
8649
0
      Node     *ancestor = (Node *) lfirst(lc);
8650
8651
      /*
8652
       * If ancestor is a SubPlan, check the paramIds it provides.
8653
       */
8654
0
      if (IsA(ancestor, SubPlan))
8655
0
      {
8656
0
        SubPlan    *subplan = (SubPlan *) ancestor;
8657
8658
0
        foreach_int(paramid, subplan->paramIds)
8659
0
        {
8660
0
          if (paramid == param->paramid)
8661
0
          {
8662
            /* Found a match, so return it. */
8663
0
            *column_p = foreach_current_index(paramid);
8664
0
            return subplan;
8665
0
          }
8666
0
        }
8667
8668
        /* SubPlan isn't a kind of Plan, so skip the rest */
8669
0
        continue;
8670
0
      }
8671
8672
      /*
8673
       * Otherwise, it's some kind of Plan node, so check its initplans.
8674
       */
8675
0
      result = find_param_generator_initplan(param, (Plan *) ancestor,
8676
0
                           column_p);
8677
0
      if (result)
8678
0
        return result;
8679
8680
      /* No luck, crawl up to next ancestor */
8681
0
    }
8682
0
  }
8683
8684
  /* No generator found */
8685
0
  return NULL;
8686
0
}
8687
8688
/*
8689
 * Subroutine for find_param_generator: search one Plan node's initplans
8690
 */
8691
static SubPlan *
8692
find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
8693
0
{
8694
0
  foreach_node(SubPlan, subplan, plan->initPlan)
8695
0
  {
8696
0
    foreach_int(paramid, subplan->setParam)
8697
0
    {
8698
0
      if (paramid == param->paramid)
8699
0
      {
8700
        /* Found a match, so return it. */
8701
0
        *column_p = foreach_current_index(paramid);
8702
0
        return subplan;
8703
0
      }
8704
0
    }
8705
0
  }
8706
0
  return NULL;
8707
0
}
8708
8709
/*
8710
 * Display a Param appropriately.
8711
 */
8712
static void
8713
get_parameter(Param *param, deparse_context *context)
8714
0
{
8715
0
  Node     *expr;
8716
0
  deparse_namespace *dpns;
8717
0
  ListCell   *ancestor_cell;
8718
0
  SubPlan    *subplan;
8719
0
  int     column;
8720
8721
  /*
8722
   * If it's a PARAM_EXEC parameter, try to locate the expression from which
8723
   * the parameter was computed.  This stanza handles only cases in which
8724
   * the Param represents an input to the subplan we are currently in.
8725
   */
8726
0
  expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8727
0
  if (expr)
8728
0
  {
8729
    /* Found a match, so print it */
8730
0
    deparse_namespace save_dpns;
8731
0
    bool    save_varprefix;
8732
0
    bool    need_paren;
8733
8734
    /* Switch attention to the ancestor plan node */
8735
0
    push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8736
8737
    /*
8738
     * Force prefixing of Vars, since they won't belong to the relation
8739
     * being scanned in the original plan node.
8740
     */
8741
0
    save_varprefix = context->varprefix;
8742
0
    context->varprefix = true;
8743
8744
    /*
8745
     * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8746
     * upper-level Param, which wouldn't need extra parentheses.
8747
     * Otherwise, insert parens to ensure the expression looks atomic.
8748
     */
8749
0
    need_paren = !(IsA(expr, Var) ||
8750
0
             IsA(expr, Aggref) ||
8751
0
             IsA(expr, GroupingFunc) ||
8752
0
             IsA(expr, Param));
8753
0
    if (need_paren)
8754
0
      appendStringInfoChar(context->buf, '(');
8755
8756
0
    get_rule_expr(expr, context, false);
8757
8758
0
    if (need_paren)
8759
0
      appendStringInfoChar(context->buf, ')');
8760
8761
0
    context->varprefix = save_varprefix;
8762
8763
0
    pop_ancestor_plan(dpns, &save_dpns);
8764
8765
0
    return;
8766
0
  }
8767
8768
  /*
8769
   * Alternatively, maybe it's a subplan output, which we print as a
8770
   * reference to the subplan.  (We could drill down into the subplan and
8771
   * print the relevant targetlist expression, but that has been deemed too
8772
   * confusing since it would violate normal SQL scope rules.  Also, we're
8773
   * relying on this reference to show that the testexpr containing the
8774
   * Param has anything to do with that subplan at all.)
8775
   */
8776
0
  subplan = find_param_generator(param, context, &column);
8777
0
  if (subplan)
8778
0
  {
8779
0
    const char *nameprefix;
8780
8781
0
    if (subplan->isInitPlan)
8782
0
      nameprefix = "InitPlan ";
8783
0
    else
8784
0
      nameprefix = "SubPlan ";
8785
8786
0
    appendStringInfo(context->buf, "(%s%s%s).col%d",
8787
0
             subplan->useHashTable ? "hashed " : "",
8788
0
             nameprefix,
8789
0
             subplan->plan_name, column + 1);
8790
8791
0
    return;
8792
0
  }
8793
8794
  /*
8795
   * If it's an external parameter, see if the outermost namespace provides
8796
   * function argument names.
8797
   */
8798
0
  if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8799
0
  {
8800
0
    dpns = llast(context->namespaces);
8801
0
    if (dpns->argnames &&
8802
0
      param->paramid > 0 &&
8803
0
      param->paramid <= dpns->numargs)
8804
0
    {
8805
0
      char     *argname = dpns->argnames[param->paramid - 1];
8806
8807
0
      if (argname)
8808
0
      {
8809
0
        bool    should_qualify = false;
8810
0
        ListCell   *lc;
8811
8812
        /*
8813
         * Qualify the parameter name if there are any other deparse
8814
         * namespaces with range tables.  This avoids qualifying in
8815
         * trivial cases like "RETURN a + b", but makes it safe in all
8816
         * other cases.
8817
         */
8818
0
        foreach(lc, context->namespaces)
8819
0
        {
8820
0
          deparse_namespace *depns = lfirst(lc);
8821
8822
0
          if (depns->rtable_names != NIL)
8823
0
          {
8824
0
            should_qualify = true;
8825
0
            break;
8826
0
          }
8827
0
        }
8828
0
        if (should_qualify)
8829
0
        {
8830
0
          appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
8831
0
          appendStringInfoChar(context->buf, '.');
8832
0
        }
8833
8834
0
        appendStringInfoString(context->buf, quote_identifier(argname));
8835
0
        return;
8836
0
      }
8837
0
    }
8838
0
  }
8839
8840
  /*
8841
   * Not PARAM_EXEC, or couldn't find referent: just print $N.
8842
   *
8843
   * It's a bug if we get here for anything except PARAM_EXTERN Params, but
8844
   * in production builds printing $N seems more useful than failing.
8845
   */
8846
0
  Assert(param->paramkind == PARAM_EXTERN);
8847
8848
0
  appendStringInfo(context->buf, "$%d", param->paramid);
8849
0
}
8850
8851
/*
8852
 * get_simple_binary_op_name
8853
 *
8854
 * helper function for isSimpleNode
8855
 * will return single char binary operator name, or NULL if it's not
8856
 */
8857
static const char *
8858
get_simple_binary_op_name(OpExpr *expr)
8859
0
{
8860
0
  List     *args = expr->args;
8861
8862
0
  if (list_length(args) == 2)
8863
0
  {
8864
    /* binary operator */
8865
0
    Node     *arg1 = (Node *) linitial(args);
8866
0
    Node     *arg2 = (Node *) lsecond(args);
8867
0
    const char *op;
8868
8869
0
    op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8870
0
    if (strlen(op) == 1)
8871
0
      return op;
8872
0
  }
8873
0
  return NULL;
8874
0
}
8875
8876
8877
/*
8878
 * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
8879
 *
8880
 *  true   : simple in the context of parent node's type
8881
 *  false  : not simple
8882
 */
8883
static bool
8884
isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
8885
0
{
8886
0
  if (!node)
8887
0
    return false;
8888
8889
0
  switch (nodeTag(node))
8890
0
  {
8891
0
    case T_Var:
8892
0
    case T_Const:
8893
0
    case T_Param:
8894
0
    case T_CoerceToDomainValue:
8895
0
    case T_SetToDefault:
8896
0
    case T_CurrentOfExpr:
8897
      /* single words: always simple */
8898
0
      return true;
8899
8900
0
    case T_SubscriptingRef:
8901
0
    case T_ArrayExpr:
8902
0
    case T_RowExpr:
8903
0
    case T_CoalesceExpr:
8904
0
    case T_MinMaxExpr:
8905
0
    case T_SQLValueFunction:
8906
0
    case T_XmlExpr:
8907
0
    case T_NextValueExpr:
8908
0
    case T_NullIfExpr:
8909
0
    case T_Aggref:
8910
0
    case T_GroupingFunc:
8911
0
    case T_WindowFunc:
8912
0
    case T_MergeSupportFunc:
8913
0
    case T_FuncExpr:
8914
0
    case T_JsonConstructorExpr:
8915
0
    case T_JsonExpr:
8916
      /* function-like: name(..) or name[..] */
8917
0
      return true;
8918
8919
      /* CASE keywords act as parentheses */
8920
0
    case T_CaseExpr:
8921
0
      return true;
8922
8923
0
    case T_FieldSelect:
8924
8925
      /*
8926
       * appears simple since . has top precedence, unless parent is
8927
       * T_FieldSelect itself!
8928
       */
8929
0
      return !IsA(parentNode, FieldSelect);
8930
8931
0
    case T_FieldStore:
8932
8933
      /*
8934
       * treat like FieldSelect (probably doesn't matter)
8935
       */
8936
0
      return !IsA(parentNode, FieldStore);
8937
8938
0
    case T_CoerceToDomain:
8939
      /* maybe simple, check args */
8940
0
      return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8941
0
                node, prettyFlags);
8942
0
    case T_RelabelType:
8943
0
      return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8944
0
                node, prettyFlags);
8945
0
    case T_CoerceViaIO:
8946
0
      return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8947
0
                node, prettyFlags);
8948
0
    case T_ArrayCoerceExpr:
8949
0
      return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8950
0
                node, prettyFlags);
8951
0
    case T_ConvertRowtypeExpr:
8952
0
      return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8953
0
                node, prettyFlags);
8954
0
    case T_ReturningExpr:
8955
0
      return isSimpleNode((Node *) ((ReturningExpr *) node)->retexpr,
8956
0
                node, prettyFlags);
8957
8958
0
    case T_OpExpr:
8959
0
      {
8960
        /* depends on parent node type; needs further checking */
8961
0
        if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8962
0
        {
8963
0
          const char *op;
8964
0
          const char *parentOp;
8965
0
          bool    is_lopriop;
8966
0
          bool    is_hipriop;
8967
0
          bool    is_lopriparent;
8968
0
          bool    is_hipriparent;
8969
8970
0
          op = get_simple_binary_op_name((OpExpr *) node);
8971
0
          if (!op)
8972
0
            return false;
8973
8974
          /* We know only the basic operators + - and * / % */
8975
0
          is_lopriop = (strchr("+-", *op) != NULL);
8976
0
          is_hipriop = (strchr("*/%", *op) != NULL);
8977
0
          if (!(is_lopriop || is_hipriop))
8978
0
            return false;
8979
8980
0
          parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8981
0
          if (!parentOp)
8982
0
            return false;
8983
8984
0
          is_lopriparent = (strchr("+-", *parentOp) != NULL);
8985
0
          is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8986
0
          if (!(is_lopriparent || is_hipriparent))
8987
0
            return false;
8988
8989
0
          if (is_hipriop && is_lopriparent)
8990
0
            return true; /* op binds tighter than parent */
8991
8992
0
          if (is_lopriop && is_hipriparent)
8993
0
            return false;
8994
8995
          /*
8996
           * Operators are same priority --- can skip parens only if
8997
           * we have (a - b) - c, not a - (b - c).
8998
           */
8999
0
          if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
9000
0
            return true;
9001
9002
0
          return false;
9003
0
        }
9004
        /* else do the same stuff as for T_SubLink et al. */
9005
0
      }
9006
0
      pg_fallthrough;
9007
9008
0
    case T_SubLink:
9009
0
    case T_NullTest:
9010
0
    case T_BooleanTest:
9011
0
    case T_DistinctExpr:
9012
0
    case T_JsonIsPredicate:
9013
0
      switch (nodeTag(parentNode))
9014
0
      {
9015
0
        case T_FuncExpr:
9016
0
          {
9017
            /* special handling for casts and COERCE_SQL_SYNTAX */
9018
0
            CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
9019
9020
0
            if (type == COERCE_EXPLICIT_CAST ||
9021
0
              type == COERCE_IMPLICIT_CAST ||
9022
0
              type == COERCE_SQL_SYNTAX)
9023
0
              return false;
9024
0
            return true; /* own parentheses */
9025
0
          }
9026
0
        case T_BoolExpr:  /* lower precedence */
9027
0
        case T_SubscriptingRef: /* other separators */
9028
0
        case T_ArrayExpr: /* other separators */
9029
0
        case T_RowExpr: /* other separators */
9030
0
        case T_CoalesceExpr:  /* own parentheses */
9031
0
        case T_MinMaxExpr:  /* own parentheses */
9032
0
        case T_XmlExpr: /* own parentheses */
9033
0
        case T_NullIfExpr:  /* other separators */
9034
0
        case T_Aggref:  /* own parentheses */
9035
0
        case T_GroupingFunc:  /* own parentheses */
9036
0
        case T_WindowFunc:  /* own parentheses */
9037
0
        case T_CaseExpr:  /* other separators */
9038
0
          return true;
9039
0
        default:
9040
0
          return false;
9041
0
      }
9042
9043
0
    case T_BoolExpr:
9044
0
      switch (nodeTag(parentNode))
9045
0
      {
9046
0
        case T_BoolExpr:
9047
0
          if (prettyFlags & PRETTYFLAG_PAREN)
9048
0
          {
9049
0
            BoolExprType type;
9050
0
            BoolExprType parentType;
9051
9052
0
            type = ((BoolExpr *) node)->boolop;
9053
0
            parentType = ((BoolExpr *) parentNode)->boolop;
9054
0
            switch (type)
9055
0
            {
9056
0
              case NOT_EXPR:
9057
0
              case AND_EXPR:
9058
0
                if (parentType == AND_EXPR || parentType == OR_EXPR)
9059
0
                  return true;
9060
0
                break;
9061
0
              case OR_EXPR:
9062
0
                if (parentType == OR_EXPR)
9063
0
                  return true;
9064
0
                break;
9065
0
            }
9066
0
          }
9067
0
          return false;
9068
0
        case T_FuncExpr:
9069
0
          {
9070
            /* special handling for casts and COERCE_SQL_SYNTAX */
9071
0
            CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
9072
9073
0
            if (type == COERCE_EXPLICIT_CAST ||
9074
0
              type == COERCE_IMPLICIT_CAST ||
9075
0
              type == COERCE_SQL_SYNTAX)
9076
0
              return false;
9077
0
            return true; /* own parentheses */
9078
0
          }
9079
0
        case T_SubscriptingRef: /* other separators */
9080
0
        case T_ArrayExpr: /* other separators */
9081
0
        case T_RowExpr: /* other separators */
9082
0
        case T_CoalesceExpr:  /* own parentheses */
9083
0
        case T_MinMaxExpr:  /* own parentheses */
9084
0
        case T_XmlExpr: /* own parentheses */
9085
0
        case T_NullIfExpr:  /* other separators */
9086
0
        case T_Aggref:  /* own parentheses */
9087
0
        case T_GroupingFunc:  /* own parentheses */
9088
0
        case T_WindowFunc:  /* own parentheses */
9089
0
        case T_CaseExpr:  /* other separators */
9090
0
        case T_JsonExpr:  /* own parentheses */
9091
0
          return true;
9092
0
        default:
9093
0
          return false;
9094
0
      }
9095
9096
0
    case T_JsonValueExpr:
9097
      /* maybe simple, check args */
9098
0
      return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
9099
0
                node, prettyFlags);
9100
9101
0
    default:
9102
0
      break;
9103
0
  }
9104
  /* those we don't know: in dubio complexo */
9105
0
  return false;
9106
0
}
9107
9108
9109
/*
9110
 * appendContextKeyword - append a keyword to buffer
9111
 *
9112
 * If prettyPrint is enabled, perform a line break, and adjust indentation.
9113
 * Otherwise, just append the keyword.
9114
 */
9115
static void
9116
appendContextKeyword(deparse_context *context, const char *str,
9117
           int indentBefore, int indentAfter, int indentPlus)
9118
0
{
9119
0
  StringInfo  buf = context->buf;
9120
9121
0
  if (PRETTY_INDENT(context))
9122
0
  {
9123
0
    int     indentAmount;
9124
9125
0
    context->indentLevel += indentBefore;
9126
9127
    /* remove any trailing spaces currently in the buffer ... */
9128
0
    removeStringInfoSpaces(buf);
9129
    /* ... then add a newline and some spaces */
9130
0
    appendStringInfoChar(buf, '\n');
9131
9132
0
    if (context->indentLevel < PRETTYINDENT_LIMIT)
9133
0
      indentAmount = Max(context->indentLevel, 0) + indentPlus;
9134
0
    else
9135
0
    {
9136
      /*
9137
       * If we're indented more than PRETTYINDENT_LIMIT characters, try
9138
       * to conserve horizontal space by reducing the per-level
9139
       * indentation.  For best results the scale factor here should
9140
       * divide all the indent amounts that get added to indentLevel
9141
       * (PRETTYINDENT_STD, etc).  It's important that the indentation
9142
       * not grow unboundedly, else deeply-nested trees use O(N^2)
9143
       * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
9144
       */
9145
0
      indentAmount = PRETTYINDENT_LIMIT +
9146
0
        (context->indentLevel - PRETTYINDENT_LIMIT) /
9147
0
        (PRETTYINDENT_STD / 2);
9148
0
      indentAmount %= PRETTYINDENT_LIMIT;
9149
      /* scale/wrap logic affects indentLevel, but not indentPlus */
9150
0
      indentAmount += indentPlus;
9151
0
    }
9152
0
    appendStringInfoSpaces(buf, indentAmount);
9153
9154
0
    appendStringInfoString(buf, str);
9155
9156
0
    context->indentLevel += indentAfter;
9157
0
    if (context->indentLevel < 0)
9158
0
      context->indentLevel = 0;
9159
0
  }
9160
0
  else
9161
0
    appendStringInfoString(buf, str);
9162
0
}
9163
9164
/*
9165
 * removeStringInfoSpaces - delete trailing spaces from a buffer.
9166
 *
9167
 * Possibly this should move to stringinfo.c at some point.
9168
 */
9169
static void
9170
removeStringInfoSpaces(StringInfo str)
9171
0
{
9172
0
  while (str->len > 0 && str->data[str->len - 1] == ' ')
9173
0
    str->data[--(str->len)] = '\0';
9174
0
}
9175
9176
9177
/*
9178
 * get_rule_expr_paren  - deparse expr using get_rule_expr,
9179
 * embracing the string with parentheses if necessary for prettyPrint.
9180
 *
9181
 * Never embrace if prettyFlags=0, because it's done in the calling node.
9182
 *
9183
 * Any node that does *not* embrace its argument node by sql syntax (with
9184
 * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
9185
 * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
9186
 * added.
9187
 */
9188
static void
9189
get_rule_expr_paren(Node *node, deparse_context *context,
9190
          bool showimplicit, Node *parentNode)
9191
0
{
9192
0
  bool    need_paren;
9193
9194
0
  need_paren = PRETTY_PAREN(context) &&
9195
0
    !isSimpleNode(node, parentNode, context->prettyFlags);
9196
9197
0
  if (need_paren)
9198
0
    appendStringInfoChar(context->buf, '(');
9199
9200
0
  get_rule_expr(node, context, showimplicit);
9201
9202
0
  if (need_paren)
9203
0
    appendStringInfoChar(context->buf, ')');
9204
0
}
9205
9206
static void
9207
get_json_behavior(JsonBehavior *behavior, deparse_context *context,
9208
          const char *on)
9209
0
{
9210
  /*
9211
   * The order of array elements must correspond to the order of
9212
   * JsonBehaviorType members.
9213
   */
9214
0
  const char *behavior_names[] =
9215
0
  {
9216
0
    " NULL",
9217
0
    " ERROR",
9218
0
    " EMPTY",
9219
0
    " TRUE",
9220
0
    " FALSE",
9221
0
    " UNKNOWN",
9222
0
    " EMPTY ARRAY",
9223
0
    " EMPTY OBJECT",
9224
0
    " DEFAULT "
9225
0
  };
9226
9227
0
  if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
9228
0
    elog(ERROR, "invalid json behavior type: %d", behavior->btype);
9229
9230
0
  appendStringInfoString(context->buf, behavior_names[behavior->btype]);
9231
9232
0
  if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
9233
0
    get_rule_expr(behavior->expr, context, false);
9234
9235
0
  appendStringInfo(context->buf, " ON %s", on);
9236
0
}
9237
9238
/*
9239
 * get_json_expr_options
9240
 *
9241
 * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
9242
 * JSON_TABLE columns.
9243
 */
9244
static void
9245
get_json_expr_options(JsonExpr *jsexpr, deparse_context *context,
9246
            JsonBehaviorType default_behavior)
9247
0
{
9248
0
  if (jsexpr->op == JSON_QUERY_OP)
9249
0
  {
9250
0
    if (jsexpr->wrapper == JSW_CONDITIONAL)
9251
0
      appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
9252
0
    else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
9253
0
      appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
9254
    /* The default */
9255
0
    else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
9256
0
      appendStringInfoString(context->buf, " WITHOUT WRAPPER");
9257
9258
0
    if (jsexpr->omit_quotes)
9259
0
      appendStringInfoString(context->buf, " OMIT QUOTES");
9260
    /* The default */
9261
0
    else
9262
0
      appendStringInfoString(context->buf, " KEEP QUOTES");
9263
0
  }
9264
9265
0
  if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
9266
0
    get_json_behavior(jsexpr->on_empty, context, "EMPTY");
9267
9268
0
  if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
9269
0
    get_json_behavior(jsexpr->on_error, context, "ERROR");
9270
0
}
9271
9272
/* ----------
9273
 * get_rule_expr      - Parse back an expression
9274
 *
9275
 * Note: showimplicit determines whether we display any implicit cast that
9276
 * is present at the top of the expression tree.  It is a passed argument,
9277
 * not a field of the context struct, because we change the value as we
9278
 * recurse down into the expression.  In general we suppress implicit casts
9279
 * when the result type is known with certainty (eg, the arguments of an
9280
 * OR must be boolean).  We display implicit casts for arguments of functions
9281
 * and operators, since this is needed to be certain that the same function
9282
 * or operator will be chosen when the expression is re-parsed.
9283
 * ----------
9284
 */
9285
static void
9286
get_rule_expr(Node *node, deparse_context *context,
9287
        bool showimplicit)
9288
0
{
9289
0
  StringInfo  buf = context->buf;
9290
9291
0
  if (node == NULL)
9292
0
    return;
9293
9294
  /* Guard against excessively long or deeply-nested queries */
9295
0
  CHECK_FOR_INTERRUPTS();
9296
0
  check_stack_depth();
9297
9298
  /*
9299
   * Each level of get_rule_expr must emit an indivisible term
9300
   * (parenthesized if necessary) to ensure result is reparsed into the same
9301
   * expression tree.  The only exception is that when the input is a List,
9302
   * we emit the component items comma-separated with no surrounding
9303
   * decoration; this is convenient for most callers.
9304
   */
9305
0
  switch (nodeTag(node))
9306
0
  {
9307
0
    case T_Var:
9308
0
      (void) get_variable((Var *) node, 0, false, context);
9309
0
      break;
9310
9311
0
    case T_Const:
9312
0
      get_const_expr((Const *) node, context, 0);
9313
0
      break;
9314
9315
0
    case T_Param:
9316
0
      get_parameter((Param *) node, context);
9317
0
      break;
9318
9319
0
    case T_Aggref:
9320
0
      get_agg_expr((Aggref *) node, context, (Aggref *) node);
9321
0
      break;
9322
9323
0
    case T_GroupingFunc:
9324
0
      {
9325
0
        GroupingFunc *gexpr = (GroupingFunc *) node;
9326
9327
0
        appendStringInfoString(buf, "GROUPING(");
9328
0
        get_rule_expr((Node *) gexpr->args, context, true);
9329
0
        appendStringInfoChar(buf, ')');
9330
0
      }
9331
0
      break;
9332
9333
0
    case T_WindowFunc:
9334
0
      get_windowfunc_expr((WindowFunc *) node, context);
9335
0
      break;
9336
9337
0
    case T_MergeSupportFunc:
9338
0
      appendStringInfoString(buf, "MERGE_ACTION()");
9339
0
      break;
9340
9341
0
    case T_SubscriptingRef:
9342
0
      {
9343
0
        SubscriptingRef *sbsref = (SubscriptingRef *) node;
9344
0
        bool    need_parens;
9345
9346
        /*
9347
         * If the argument is a CaseTestExpr, we must be inside a
9348
         * FieldStore, ie, we are assigning to an element of an array
9349
         * within a composite column.  Since we already punted on
9350
         * displaying the FieldStore's target information, just punt
9351
         * here too, and display only the assignment source
9352
         * expression.
9353
         */
9354
0
        if (IsA(sbsref->refexpr, CaseTestExpr))
9355
0
        {
9356
0
          Assert(sbsref->refassgnexpr);
9357
0
          get_rule_expr((Node *) sbsref->refassgnexpr,
9358
0
                  context, showimplicit);
9359
0
          break;
9360
0
        }
9361
9362
        /*
9363
         * Parenthesize the argument unless it's a simple Var or a
9364
         * FieldSelect.  (In particular, if it's another
9365
         * SubscriptingRef, we *must* parenthesize to avoid
9366
         * confusion.)
9367
         */
9368
0
        need_parens = !IsA(sbsref->refexpr, Var) &&
9369
0
          !IsA(sbsref->refexpr, FieldSelect);
9370
0
        if (need_parens)
9371
0
          appendStringInfoChar(buf, '(');
9372
0
        get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
9373
0
        if (need_parens)
9374
0
          appendStringInfoChar(buf, ')');
9375
9376
        /*
9377
         * If there's a refassgnexpr, we want to print the node in the
9378
         * format "container[subscripts] := refassgnexpr".  This is
9379
         * not legal SQL, so decompilation of INSERT or UPDATE
9380
         * statements should always use processIndirection as part of
9381
         * the statement-level syntax.  We should only see this when
9382
         * EXPLAIN tries to print the targetlist of a plan resulting
9383
         * from such a statement.
9384
         */
9385
0
        if (sbsref->refassgnexpr)
9386
0
        {
9387
0
          Node     *refassgnexpr;
9388
9389
          /*
9390
           * Use processIndirection to print this node's subscripts
9391
           * as well as any additional field selections or
9392
           * subscripting in immediate descendants.  It returns the
9393
           * RHS expr that is actually being "assigned".
9394
           */
9395
0
          refassgnexpr = processIndirection(node, context);
9396
0
          appendStringInfoString(buf, " := ");
9397
0
          get_rule_expr(refassgnexpr, context, showimplicit);
9398
0
        }
9399
0
        else
9400
0
        {
9401
          /* Just an ordinary container fetch, so print subscripts */
9402
0
          printSubscripts(sbsref, context);
9403
0
        }
9404
0
      }
9405
0
      break;
9406
9407
0
    case T_FuncExpr:
9408
0
      get_func_expr((FuncExpr *) node, context, showimplicit);
9409
0
      break;
9410
9411
0
    case T_NamedArgExpr:
9412
0
      {
9413
0
        NamedArgExpr *na = (NamedArgExpr *) node;
9414
9415
0
        appendStringInfo(buf, "%s => ", quote_identifier(na->name));
9416
0
        get_rule_expr((Node *) na->arg, context, showimplicit);
9417
0
      }
9418
0
      break;
9419
9420
0
    case T_OpExpr:
9421
0
      get_oper_expr((OpExpr *) node, context);
9422
0
      break;
9423
9424
0
    case T_DistinctExpr:
9425
0
      {
9426
0
        DistinctExpr *expr = (DistinctExpr *) node;
9427
0
        List     *args = expr->args;
9428
0
        Node     *arg1 = (Node *) linitial(args);
9429
0
        Node     *arg2 = (Node *) lsecond(args);
9430
9431
0
        if (!PRETTY_PAREN(context))
9432
0
          appendStringInfoChar(buf, '(');
9433
0
        get_rule_expr_paren(arg1, context, true, node);
9434
0
        appendStringInfoString(buf, " IS DISTINCT FROM ");
9435
0
        get_rule_expr_paren(arg2, context, true, node);
9436
0
        if (!PRETTY_PAREN(context))
9437
0
          appendStringInfoChar(buf, ')');
9438
0
      }
9439
0
      break;
9440
9441
0
    case T_NullIfExpr:
9442
0
      {
9443
0
        NullIfExpr *nullifexpr = (NullIfExpr *) node;
9444
9445
0
        appendStringInfoString(buf, "NULLIF(");
9446
0
        get_rule_expr((Node *) nullifexpr->args, context, true);
9447
0
        appendStringInfoChar(buf, ')');
9448
0
      }
9449
0
      break;
9450
9451
0
    case T_ScalarArrayOpExpr:
9452
0
      {
9453
0
        ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
9454
0
        List     *args = expr->args;
9455
0
        Node     *arg1 = (Node *) linitial(args);
9456
0
        Node     *arg2 = (Node *) lsecond(args);
9457
9458
0
        if (!PRETTY_PAREN(context))
9459
0
          appendStringInfoChar(buf, '(');
9460
0
        get_rule_expr_paren(arg1, context, true, node);
9461
0
        appendStringInfo(buf, " %s %s (",
9462
0
                 generate_operator_name(expr->opno,
9463
0
                            exprType(arg1),
9464
0
                            get_base_element_type(exprType(arg2))),
9465
0
                 expr->useOr ? "ANY" : "ALL");
9466
0
        get_rule_expr_paren(arg2, context, true, node);
9467
9468
        /*
9469
         * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9470
         * a bare sub-SELECT.  Since we're here, the sub-SELECT must
9471
         * be meant as a scalar sub-SELECT yielding an array value to
9472
         * be used in ScalarArrayOpExpr; but the grammar will
9473
         * preferentially interpret such a construct as an ANY/ALL
9474
         * SubLink.  To prevent misparsing the output that way, insert
9475
         * a dummy coercion (which will be stripped by parse analysis,
9476
         * so no inefficiency is added in dump and reload).  This is
9477
         * indeed most likely what the user wrote to get the construct
9478
         * accepted in the first place.
9479
         */
9480
0
        if (IsA(arg2, SubLink) &&
9481
0
          ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
9482
0
          appendStringInfo(buf, "::%s",
9483
0
                   format_type_with_typemod(exprType(arg2),
9484
0
                                exprTypmod(arg2)));
9485
0
        appendStringInfoChar(buf, ')');
9486
0
        if (!PRETTY_PAREN(context))
9487
0
          appendStringInfoChar(buf, ')');
9488
0
      }
9489
0
      break;
9490
9491
0
    case T_BoolExpr:
9492
0
      {
9493
0
        BoolExpr   *expr = (BoolExpr *) node;
9494
0
        Node     *first_arg = linitial(expr->args);
9495
0
        ListCell   *arg;
9496
9497
0
        switch (expr->boolop)
9498
0
        {
9499
0
          case AND_EXPR:
9500
0
            if (!PRETTY_PAREN(context))
9501
0
              appendStringInfoChar(buf, '(');
9502
0
            get_rule_expr_paren(first_arg, context,
9503
0
                      false, node);
9504
0
            for_each_from(arg, expr->args, 1)
9505
0
            {
9506
0
              appendStringInfoString(buf, " AND ");
9507
0
              get_rule_expr_paren((Node *) lfirst(arg), context,
9508
0
                        false, node);
9509
0
            }
9510
0
            if (!PRETTY_PAREN(context))
9511
0
              appendStringInfoChar(buf, ')');
9512
0
            break;
9513
9514
0
          case OR_EXPR:
9515
0
            if (!PRETTY_PAREN(context))
9516
0
              appendStringInfoChar(buf, '(');
9517
0
            get_rule_expr_paren(first_arg, context,
9518
0
                      false, node);
9519
0
            for_each_from(arg, expr->args, 1)
9520
0
            {
9521
0
              appendStringInfoString(buf, " OR ");
9522
0
              get_rule_expr_paren((Node *) lfirst(arg), context,
9523
0
                        false, node);
9524
0
            }
9525
0
            if (!PRETTY_PAREN(context))
9526
0
              appendStringInfoChar(buf, ')');
9527
0
            break;
9528
9529
0
          case NOT_EXPR:
9530
0
            if (!PRETTY_PAREN(context))
9531
0
              appendStringInfoChar(buf, '(');
9532
0
            appendStringInfoString(buf, "NOT ");
9533
0
            get_rule_expr_paren(first_arg, context,
9534
0
                      false, node);
9535
0
            if (!PRETTY_PAREN(context))
9536
0
              appendStringInfoChar(buf, ')');
9537
0
            break;
9538
9539
0
          default:
9540
0
            elog(ERROR, "unrecognized boolop: %d",
9541
0
               (int) expr->boolop);
9542
0
        }
9543
0
      }
9544
0
      break;
9545
9546
0
    case T_SubLink:
9547
0
      get_sublink_expr((SubLink *) node, context);
9548
0
      break;
9549
9550
0
    case T_SubPlan:
9551
0
      {
9552
0
        SubPlan    *subplan = (SubPlan *) node;
9553
9554
        /*
9555
         * We cannot see an already-planned subplan in rule deparsing,
9556
         * only while EXPLAINing a query plan.  We don't try to
9557
         * reconstruct the original SQL, just reference the subplan
9558
         * that appears elsewhere in EXPLAIN's result.  It does seem
9559
         * useful to show the subLinkType and testexpr (if any), and
9560
         * we also note whether the subplan will be hashed.
9561
         */
9562
0
        switch (subplan->subLinkType)
9563
0
        {
9564
0
          case EXISTS_SUBLINK:
9565
0
            appendStringInfoString(buf, "EXISTS(");
9566
0
            Assert(subplan->testexpr == NULL);
9567
0
            break;
9568
0
          case ALL_SUBLINK:
9569
0
            appendStringInfoString(buf, "(ALL ");
9570
0
            Assert(subplan->testexpr != NULL);
9571
0
            break;
9572
0
          case ANY_SUBLINK:
9573
0
            appendStringInfoString(buf, "(ANY ");
9574
0
            Assert(subplan->testexpr != NULL);
9575
0
            break;
9576
0
          case ROWCOMPARE_SUBLINK:
9577
            /* Parenthesizing the testexpr seems sufficient */
9578
0
            appendStringInfoChar(buf, '(');
9579
0
            Assert(subplan->testexpr != NULL);
9580
0
            break;
9581
0
          case EXPR_SUBLINK:
9582
            /* No need to decorate these subplan references */
9583
0
            appendStringInfoChar(buf, '(');
9584
0
            Assert(subplan->testexpr == NULL);
9585
0
            break;
9586
0
          case MULTIEXPR_SUBLINK:
9587
            /* MULTIEXPR isn't executed in the normal way */
9588
0
            appendStringInfoString(buf, "(rescan ");
9589
0
            Assert(subplan->testexpr == NULL);
9590
0
            break;
9591
0
          case ARRAY_SUBLINK:
9592
0
            appendStringInfoString(buf, "ARRAY(");
9593
0
            Assert(subplan->testexpr == NULL);
9594
0
            break;
9595
0
          case CTE_SUBLINK:
9596
            /* This case is unreachable within expressions */
9597
0
            appendStringInfoString(buf, "CTE(");
9598
0
            Assert(subplan->testexpr == NULL);
9599
0
            break;
9600
0
        }
9601
9602
0
        if (subplan->testexpr != NULL)
9603
0
        {
9604
0
          deparse_namespace *dpns;
9605
9606
          /*
9607
           * Push SubPlan into ancestors list while deparsing
9608
           * testexpr, so that we can handle PARAM_EXEC references
9609
           * to the SubPlan's paramIds.  (This makes it look like
9610
           * the SubPlan is an "ancestor" of the current plan node,
9611
           * which is a little weird, but it does no harm.)  In this
9612
           * path, we don't need to mention the SubPlan explicitly,
9613
           * because the referencing Params will show its existence.
9614
           */
9615
0
          dpns = (deparse_namespace *) linitial(context->namespaces);
9616
0
          dpns->ancestors = lcons(subplan, dpns->ancestors);
9617
9618
0
          get_rule_expr(subplan->testexpr, context, showimplicit);
9619
0
          appendStringInfoChar(buf, ')');
9620
9621
0
          dpns->ancestors = list_delete_first(dpns->ancestors);
9622
0
        }
9623
0
        else
9624
0
        {
9625
0
          const char *nameprefix;
9626
9627
          /* No referencing Params, so show the SubPlan's name */
9628
0
          if (subplan->isInitPlan)
9629
0
            nameprefix = "InitPlan ";
9630
0
          else
9631
0
            nameprefix = "SubPlan ";
9632
0
          if (subplan->useHashTable)
9633
0
            appendStringInfo(buf, "hashed %s%s)",
9634
0
                     nameprefix, subplan->plan_name);
9635
0
          else
9636
0
            appendStringInfo(buf, "%s%s)",
9637
0
                     nameprefix, subplan->plan_name);
9638
0
        }
9639
0
      }
9640
0
      break;
9641
9642
0
    case T_AlternativeSubPlan:
9643
0
      {
9644
0
        AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
9645
0
        ListCell   *lc;
9646
9647
        /*
9648
         * This case cannot be reached in normal usage, since no
9649
         * AlternativeSubPlan can appear either in parsetrees or
9650
         * finished plan trees.  We keep it just in case somebody
9651
         * wants to use this code to print planner data structures.
9652
         */
9653
0
        appendStringInfoString(buf, "(alternatives: ");
9654
0
        foreach(lc, asplan->subplans)
9655
0
        {
9656
0
          SubPlan    *splan = lfirst_node(SubPlan, lc);
9657
0
          const char *nameprefix;
9658
9659
0
          if (splan->isInitPlan)
9660
0
            nameprefix = "InitPlan ";
9661
0
          else
9662
0
            nameprefix = "SubPlan ";
9663
0
          if (splan->useHashTable)
9664
0
            appendStringInfo(buf, "hashed %s%s", nameprefix,
9665
0
                     splan->plan_name);
9666
0
          else
9667
0
            appendStringInfo(buf, "%s%s", nameprefix,
9668
0
                     splan->plan_name);
9669
0
          if (lnext(asplan->subplans, lc))
9670
0
            appendStringInfoString(buf, " or ");
9671
0
        }
9672
0
        appendStringInfoChar(buf, ')');
9673
0
      }
9674
0
      break;
9675
9676
0
    case T_FieldSelect:
9677
0
      {
9678
0
        FieldSelect *fselect = (FieldSelect *) node;
9679
0
        Node     *arg = (Node *) fselect->arg;
9680
0
        int     fno = fselect->fieldnum;
9681
0
        const char *fieldname;
9682
0
        bool    need_parens;
9683
9684
        /*
9685
         * Parenthesize the argument unless it's a SubscriptingRef or
9686
         * another FieldSelect.  Note in particular that it would be
9687
         * WRONG to not parenthesize a Var argument; simplicity is not
9688
         * the issue here, having the right number of names is.
9689
         */
9690
0
        need_parens = !IsA(arg, SubscriptingRef) &&
9691
0
          !IsA(arg, FieldSelect);
9692
0
        if (need_parens)
9693
0
          appendStringInfoChar(buf, '(');
9694
0
        get_rule_expr(arg, context, true);
9695
0
        if (need_parens)
9696
0
          appendStringInfoChar(buf, ')');
9697
9698
        /*
9699
         * Get and print the field name.
9700
         */
9701
0
        fieldname = get_name_for_var_field((Var *) arg, fno,
9702
0
                           0, context);
9703
0
        appendStringInfo(buf, ".%s", quote_identifier(fieldname));
9704
0
      }
9705
0
      break;
9706
9707
0
    case T_FieldStore:
9708
0
      {
9709
0
        FieldStore *fstore = (FieldStore *) node;
9710
0
        bool    need_parens;
9711
9712
        /*
9713
         * There is no good way to represent a FieldStore as real SQL,
9714
         * so decompilation of INSERT or UPDATE statements should
9715
         * always use processIndirection as part of the
9716
         * statement-level syntax.  We should only get here when
9717
         * EXPLAIN tries to print the targetlist of a plan resulting
9718
         * from such a statement.  The plan case is even harder than
9719
         * ordinary rules would be, because the planner tries to
9720
         * collapse multiple assignments to the same field or subfield
9721
         * into one FieldStore; so we can see a list of target fields
9722
         * not just one, and the arguments could be FieldStores
9723
         * themselves.  We don't bother to try to print the target
9724
         * field names; we just print the source arguments, with a
9725
         * ROW() around them if there's more than one.  This isn't
9726
         * terribly complete, but it's probably good enough for
9727
         * EXPLAIN's purposes; especially since anything more would be
9728
         * either hopelessly confusing or an even poorer
9729
         * representation of what the plan is actually doing.
9730
         */
9731
0
        need_parens = (list_length(fstore->newvals) != 1);
9732
0
        if (need_parens)
9733
0
          appendStringInfoString(buf, "ROW(");
9734
0
        get_rule_expr((Node *) fstore->newvals, context, showimplicit);
9735
0
        if (need_parens)
9736
0
          appendStringInfoChar(buf, ')');
9737
0
      }
9738
0
      break;
9739
9740
0
    case T_RelabelType:
9741
0
      {
9742
0
        RelabelType *relabel = (RelabelType *) node;
9743
0
        Node     *arg = (Node *) relabel->arg;
9744
9745
0
        if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
9746
0
          !showimplicit)
9747
0
        {
9748
          /* don't show the implicit cast */
9749
0
          get_rule_expr_paren(arg, context, false, node);
9750
0
        }
9751
0
        else
9752
0
        {
9753
0
          get_coercion_expr(arg, context,
9754
0
                    relabel->resulttype,
9755
0
                    relabel->resulttypmod,
9756
0
                    node);
9757
0
        }
9758
0
      }
9759
0
      break;
9760
9761
0
    case T_CoerceViaIO:
9762
0
      {
9763
0
        CoerceViaIO *iocoerce = (CoerceViaIO *) node;
9764
0
        Node     *arg = (Node *) iocoerce->arg;
9765
9766
0
        if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9767
0
          !showimplicit)
9768
0
        {
9769
          /* don't show the implicit cast */
9770
0
          get_rule_expr_paren(arg, context, false, node);
9771
0
        }
9772
0
        else
9773
0
        {
9774
0
          get_coercion_expr(arg, context,
9775
0
                    iocoerce->resulttype,
9776
0
                    -1,
9777
0
                    node);
9778
0
        }
9779
0
      }
9780
0
      break;
9781
9782
0
    case T_ArrayCoerceExpr:
9783
0
      {
9784
0
        ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
9785
0
        Node     *arg = (Node *) acoerce->arg;
9786
9787
0
        if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9788
0
          !showimplicit)
9789
0
        {
9790
          /* don't show the implicit cast */
9791
0
          get_rule_expr_paren(arg, context, false, node);
9792
0
        }
9793
0
        else
9794
0
        {
9795
0
          get_coercion_expr(arg, context,
9796
0
                    acoerce->resulttype,
9797
0
                    acoerce->resulttypmod,
9798
0
                    node);
9799
0
        }
9800
0
      }
9801
0
      break;
9802
9803
0
    case T_ConvertRowtypeExpr:
9804
0
      {
9805
0
        ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
9806
0
        Node     *arg = (Node *) convert->arg;
9807
9808
0
        if (convert->convertformat == COERCE_IMPLICIT_CAST &&
9809
0
          !showimplicit)
9810
0
        {
9811
          /* don't show the implicit cast */
9812
0
          get_rule_expr_paren(arg, context, false, node);
9813
0
        }
9814
0
        else
9815
0
        {
9816
0
          get_coercion_expr(arg, context,
9817
0
                    convert->resulttype, -1,
9818
0
                    node);
9819
0
        }
9820
0
      }
9821
0
      break;
9822
9823
0
    case T_CollateExpr:
9824
0
      {
9825
0
        CollateExpr *collate = (CollateExpr *) node;
9826
0
        Node     *arg = (Node *) collate->arg;
9827
9828
0
        if (!PRETTY_PAREN(context))
9829
0
          appendStringInfoChar(buf, '(');
9830
0
        get_rule_expr_paren(arg, context, showimplicit, node);
9831
0
        appendStringInfo(buf, " COLLATE %s",
9832
0
                 generate_collation_name(collate->collOid));
9833
0
        if (!PRETTY_PAREN(context))
9834
0
          appendStringInfoChar(buf, ')');
9835
0
      }
9836
0
      break;
9837
9838
0
    case T_CaseExpr:
9839
0
      {
9840
0
        CaseExpr   *caseexpr = (CaseExpr *) node;
9841
0
        ListCell   *temp;
9842
9843
0
        appendContextKeyword(context, "CASE",
9844
0
                   0, PRETTYINDENT_VAR, 0);
9845
0
        if (caseexpr->arg)
9846
0
        {
9847
0
          appendStringInfoChar(buf, ' ');
9848
0
          get_rule_expr((Node *) caseexpr->arg, context, true);
9849
0
        }
9850
0
        foreach(temp, caseexpr->args)
9851
0
        {
9852
0
          CaseWhen   *when = (CaseWhen *) lfirst(temp);
9853
0
          Node     *w = (Node *) when->expr;
9854
9855
0
          if (caseexpr->arg)
9856
0
          {
9857
            /*
9858
             * The parser should have produced WHEN clauses of the
9859
             * form "CaseTestExpr = RHS", possibly with an
9860
             * implicit coercion inserted above the CaseTestExpr.
9861
             * For accurate decompilation of rules it's essential
9862
             * that we show just the RHS.  However in an
9863
             * expression that's been through the optimizer, the
9864
             * WHEN clause could be almost anything (since the
9865
             * equality operator could have been expanded into an
9866
             * inline function).  If we don't recognize the form
9867
             * of the WHEN clause, just punt and display it as-is.
9868
             */
9869
0
            if (IsA(w, OpExpr))
9870
0
            {
9871
0
              List     *args = ((OpExpr *) w)->args;
9872
9873
0
              if (list_length(args) == 2 &&
9874
0
                IsA(strip_implicit_coercions(linitial(args)),
9875
0
                  CaseTestExpr))
9876
0
                w = (Node *) lsecond(args);
9877
0
            }
9878
0
          }
9879
9880
0
          if (!PRETTY_INDENT(context))
9881
0
            appendStringInfoChar(buf, ' ');
9882
0
          appendContextKeyword(context, "WHEN ",
9883
0
                     0, 0, 0);
9884
0
          get_rule_expr(w, context, false);
9885
0
          appendStringInfoString(buf, " THEN ");
9886
0
          get_rule_expr((Node *) when->result, context, true);
9887
0
        }
9888
0
        if (!PRETTY_INDENT(context))
9889
0
          appendStringInfoChar(buf, ' ');
9890
0
        appendContextKeyword(context, "ELSE ",
9891
0
                   0, 0, 0);
9892
0
        get_rule_expr((Node *) caseexpr->defresult, context, true);
9893
0
        if (!PRETTY_INDENT(context))
9894
0
          appendStringInfoChar(buf, ' ');
9895
0
        appendContextKeyword(context, "END",
9896
0
                   -PRETTYINDENT_VAR, 0, 0);
9897
0
      }
9898
0
      break;
9899
9900
0
    case T_CaseTestExpr:
9901
0
      {
9902
        /*
9903
         * Normally we should never get here, since for expressions
9904
         * that can contain this node type we attempt to avoid
9905
         * recursing to it.  But in an optimized expression we might
9906
         * be unable to avoid that (see comments for CaseExpr).  If we
9907
         * do see one, print it as CASE_TEST_EXPR.
9908
         */
9909
0
        appendStringInfoString(buf, "CASE_TEST_EXPR");
9910
0
      }
9911
0
      break;
9912
9913
0
    case T_ArrayExpr:
9914
0
      {
9915
0
        ArrayExpr  *arrayexpr = (ArrayExpr *) node;
9916
9917
0
        appendStringInfoString(buf, "ARRAY[");
9918
0
        get_rule_expr((Node *) arrayexpr->elements, context, true);
9919
0
        appendStringInfoChar(buf, ']');
9920
9921
        /*
9922
         * If the array isn't empty, we assume its elements are
9923
         * coerced to the desired type.  If it's empty, though, we
9924
         * need an explicit coercion to the array type.
9925
         */
9926
0
        if (arrayexpr->elements == NIL)
9927
0
          appendStringInfo(buf, "::%s",
9928
0
                   format_type_with_typemod(arrayexpr->array_typeid, -1));
9929
0
      }
9930
0
      break;
9931
9932
0
    case T_RowExpr:
9933
0
      {
9934
0
        RowExpr    *rowexpr = (RowExpr *) node;
9935
0
        TupleDesc tupdesc = NULL;
9936
0
        ListCell   *arg;
9937
0
        int     i;
9938
0
        char     *sep;
9939
9940
        /*
9941
         * If it's a named type and not RECORD, we may have to skip
9942
         * dropped columns and/or claim there are NULLs for added
9943
         * columns.
9944
         */
9945
0
        if (rowexpr->row_typeid != RECORDOID)
9946
0
        {
9947
0
          tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9948
0
          Assert(list_length(rowexpr->args) <= tupdesc->natts);
9949
0
        }
9950
9951
        /*
9952
         * SQL99 allows "ROW" to be omitted when there is more than
9953
         * one column, but for simplicity we always print it.
9954
         */
9955
0
        appendStringInfoString(buf, "ROW(");
9956
0
        sep = "";
9957
0
        i = 0;
9958
0
        foreach(arg, rowexpr->args)
9959
0
        {
9960
0
          Node     *e = (Node *) lfirst(arg);
9961
9962
0
          if (tupdesc == NULL ||
9963
0
            !TupleDescCompactAttr(tupdesc, i)->attisdropped)
9964
0
          {
9965
0
            appendStringInfoString(buf, sep);
9966
            /* Whole-row Vars need special treatment here */
9967
0
            get_rule_expr_toplevel(e, context, true);
9968
0
            sep = ", ";
9969
0
          }
9970
0
          i++;
9971
0
        }
9972
0
        if (tupdesc != NULL)
9973
0
        {
9974
0
          while (i < tupdesc->natts)
9975
0
          {
9976
0
            if (!TupleDescCompactAttr(tupdesc, i)->attisdropped)
9977
0
            {
9978
0
              appendStringInfoString(buf, sep);
9979
0
              appendStringInfoString(buf, "NULL");
9980
0
              sep = ", ";
9981
0
            }
9982
0
            i++;
9983
0
          }
9984
9985
0
          ReleaseTupleDesc(tupdesc);
9986
0
        }
9987
0
        appendStringInfoChar(buf, ')');
9988
0
        if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9989
0
          appendStringInfo(buf, "::%s",
9990
0
                   format_type_with_typemod(rowexpr->row_typeid, -1));
9991
0
      }
9992
0
      break;
9993
9994
0
    case T_RowCompareExpr:
9995
0
      {
9996
0
        RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9997
9998
        /*
9999
         * SQL99 allows "ROW" to be omitted when there is more than
10000
         * one column, but for simplicity we always print it.  Within
10001
         * a ROW expression, whole-row Vars need special treatment, so
10002
         * use get_rule_list_toplevel.
10003
         */
10004
0
        appendStringInfoString(buf, "(ROW(");
10005
0
        get_rule_list_toplevel(rcexpr->largs, context, true);
10006
10007
        /*
10008
         * We assume that the name of the first-column operator will
10009
         * do for all the rest too.  This is definitely open to
10010
         * failure, eg if some but not all operators were renamed
10011
         * since the construct was parsed, but there seems no way to
10012
         * be perfect.
10013
         */
10014
0
        appendStringInfo(buf, ") %s ROW(",
10015
0
                 generate_operator_name(linitial_oid(rcexpr->opnos),
10016
0
                            exprType(linitial(rcexpr->largs)),
10017
0
                            exprType(linitial(rcexpr->rargs))));
10018
0
        get_rule_list_toplevel(rcexpr->rargs, context, true);
10019
0
        appendStringInfoString(buf, "))");
10020
0
      }
10021
0
      break;
10022
10023
0
    case T_CoalesceExpr:
10024
0
      {
10025
0
        CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
10026
10027
0
        appendStringInfoString(buf, "COALESCE(");
10028
0
        get_rule_expr((Node *) coalesceexpr->args, context, true);
10029
0
        appendStringInfoChar(buf, ')');
10030
0
      }
10031
0
      break;
10032
10033
0
    case T_MinMaxExpr:
10034
0
      {
10035
0
        MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
10036
10037
0
        switch (minmaxexpr->op)
10038
0
        {
10039
0
          case IS_GREATEST:
10040
0
            appendStringInfoString(buf, "GREATEST(");
10041
0
            break;
10042
0
          case IS_LEAST:
10043
0
            appendStringInfoString(buf, "LEAST(");
10044
0
            break;
10045
0
        }
10046
0
        get_rule_expr((Node *) minmaxexpr->args, context, true);
10047
0
        appendStringInfoChar(buf, ')');
10048
0
      }
10049
0
      break;
10050
10051
0
    case T_SQLValueFunction:
10052
0
      {
10053
0
        SQLValueFunction *svf = (SQLValueFunction *) node;
10054
10055
        /*
10056
         * Note: this code knows that typmod for time, timestamp, and
10057
         * timestamptz just prints as integer.
10058
         */
10059
0
        switch (svf->op)
10060
0
        {
10061
0
          case SVFOP_CURRENT_DATE:
10062
0
            appendStringInfoString(buf, "CURRENT_DATE");
10063
0
            break;
10064
0
          case SVFOP_CURRENT_TIME:
10065
0
            appendStringInfoString(buf, "CURRENT_TIME");
10066
0
            break;
10067
0
          case SVFOP_CURRENT_TIME_N:
10068
0
            appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
10069
0
            break;
10070
0
          case SVFOP_CURRENT_TIMESTAMP:
10071
0
            appendStringInfoString(buf, "CURRENT_TIMESTAMP");
10072
0
            break;
10073
0
          case SVFOP_CURRENT_TIMESTAMP_N:
10074
0
            appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
10075
0
                     svf->typmod);
10076
0
            break;
10077
0
          case SVFOP_LOCALTIME:
10078
0
            appendStringInfoString(buf, "LOCALTIME");
10079
0
            break;
10080
0
          case SVFOP_LOCALTIME_N:
10081
0
            appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
10082
0
            break;
10083
0
          case SVFOP_LOCALTIMESTAMP:
10084
0
            appendStringInfoString(buf, "LOCALTIMESTAMP");
10085
0
            break;
10086
0
          case SVFOP_LOCALTIMESTAMP_N:
10087
0
            appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
10088
0
                     svf->typmod);
10089
0
            break;
10090
0
          case SVFOP_CURRENT_ROLE:
10091
0
            appendStringInfoString(buf, "CURRENT_ROLE");
10092
0
            break;
10093
0
          case SVFOP_CURRENT_USER:
10094
0
            appendStringInfoString(buf, "CURRENT_USER");
10095
0
            break;
10096
0
          case SVFOP_USER:
10097
0
            appendStringInfoString(buf, "USER");
10098
0
            break;
10099
0
          case SVFOP_SESSION_USER:
10100
0
            appendStringInfoString(buf, "SESSION_USER");
10101
0
            break;
10102
0
          case SVFOP_CURRENT_CATALOG:
10103
0
            appendStringInfoString(buf, "CURRENT_CATALOG");
10104
0
            break;
10105
0
          case SVFOP_CURRENT_SCHEMA:
10106
0
            appendStringInfoString(buf, "CURRENT_SCHEMA");
10107
0
            break;
10108
0
        }
10109
0
      }
10110
0
      break;
10111
10112
0
    case T_XmlExpr:
10113
0
      {
10114
0
        XmlExpr    *xexpr = (XmlExpr *) node;
10115
0
        bool    needcomma = false;
10116
0
        ListCell   *arg;
10117
0
        ListCell   *narg;
10118
0
        Const    *con;
10119
10120
0
        switch (xexpr->op)
10121
0
        {
10122
0
          case IS_XMLCONCAT:
10123
0
            appendStringInfoString(buf, "XMLCONCAT(");
10124
0
            break;
10125
0
          case IS_XMLELEMENT:
10126
0
            appendStringInfoString(buf, "XMLELEMENT(");
10127
0
            break;
10128
0
          case IS_XMLFOREST:
10129
0
            appendStringInfoString(buf, "XMLFOREST(");
10130
0
            break;
10131
0
          case IS_XMLPARSE:
10132
0
            appendStringInfoString(buf, "XMLPARSE(");
10133
0
            break;
10134
0
          case IS_XMLPI:
10135
0
            appendStringInfoString(buf, "XMLPI(");
10136
0
            break;
10137
0
          case IS_XMLROOT:
10138
0
            appendStringInfoString(buf, "XMLROOT(");
10139
0
            break;
10140
0
          case IS_XMLSERIALIZE:
10141
0
            appendStringInfoString(buf, "XMLSERIALIZE(");
10142
0
            break;
10143
0
          case IS_DOCUMENT:
10144
0
            break;
10145
0
        }
10146
0
        if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
10147
0
        {
10148
0
          if (xexpr->xmloption == XMLOPTION_DOCUMENT)
10149
0
            appendStringInfoString(buf, "DOCUMENT ");
10150
0
          else
10151
0
            appendStringInfoString(buf, "CONTENT ");
10152
0
        }
10153
0
        if (xexpr->name)
10154
0
        {
10155
0
          appendStringInfo(buf, "NAME %s",
10156
0
                   quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
10157
0
          needcomma = true;
10158
0
        }
10159
0
        if (xexpr->named_args)
10160
0
        {
10161
0
          if (xexpr->op != IS_XMLFOREST)
10162
0
          {
10163
0
            if (needcomma)
10164
0
              appendStringInfoString(buf, ", ");
10165
0
            appendStringInfoString(buf, "XMLATTRIBUTES(");
10166
0
            needcomma = false;
10167
0
          }
10168
0
          forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
10169
0
          {
10170
0
            Node     *e = (Node *) lfirst(arg);
10171
0
            char     *argname = strVal(lfirst(narg));
10172
10173
0
            if (needcomma)
10174
0
              appendStringInfoString(buf, ", ");
10175
0
            get_rule_expr(e, context, true);
10176
0
            appendStringInfo(buf, " AS %s",
10177
0
                     quote_identifier(map_xml_name_to_sql_identifier(argname)));
10178
0
            needcomma = true;
10179
0
          }
10180
0
          if (xexpr->op != IS_XMLFOREST)
10181
0
            appendStringInfoChar(buf, ')');
10182
0
        }
10183
0
        if (xexpr->args)
10184
0
        {
10185
0
          if (needcomma)
10186
0
            appendStringInfoString(buf, ", ");
10187
0
          switch (xexpr->op)
10188
0
          {
10189
0
            case IS_XMLCONCAT:
10190
0
            case IS_XMLELEMENT:
10191
0
            case IS_XMLFOREST:
10192
0
            case IS_XMLPI:
10193
0
            case IS_XMLSERIALIZE:
10194
              /* no extra decoration needed */
10195
0
              get_rule_expr((Node *) xexpr->args, context, true);
10196
0
              break;
10197
0
            case IS_XMLPARSE:
10198
0
              Assert(list_length(xexpr->args) == 2);
10199
10200
0
              get_rule_expr((Node *) linitial(xexpr->args),
10201
0
                      context, true);
10202
10203
0
              con = lsecond_node(Const, xexpr->args);
10204
0
              Assert(!con->constisnull);
10205
0
              if (DatumGetBool(con->constvalue))
10206
0
                appendStringInfoString(buf,
10207
0
                             " PRESERVE WHITESPACE");
10208
0
              else
10209
0
                appendStringInfoString(buf,
10210
0
                             " STRIP WHITESPACE");
10211
0
              break;
10212
0
            case IS_XMLROOT:
10213
0
              Assert(list_length(xexpr->args) == 3);
10214
10215
0
              get_rule_expr((Node *) linitial(xexpr->args),
10216
0
                      context, true);
10217
10218
0
              appendStringInfoString(buf, ", VERSION ");
10219
0
              con = (Const *) lsecond(xexpr->args);
10220
0
              if (IsA(con, Const) &&
10221
0
                con->constisnull)
10222
0
                appendStringInfoString(buf, "NO VALUE");
10223
0
              else
10224
0
                get_rule_expr((Node *) con, context, false);
10225
10226
0
              con = lthird_node(Const, xexpr->args);
10227
0
              if (con->constisnull)
10228
0
                 /* suppress STANDALONE NO VALUE */ ;
10229
0
              else
10230
0
              {
10231
0
                switch (DatumGetInt32(con->constvalue))
10232
0
                {
10233
0
                  case XML_STANDALONE_YES:
10234
0
                    appendStringInfoString(buf,
10235
0
                                 ", STANDALONE YES");
10236
0
                    break;
10237
0
                  case XML_STANDALONE_NO:
10238
0
                    appendStringInfoString(buf,
10239
0
                                 ", STANDALONE NO");
10240
0
                    break;
10241
0
                  case XML_STANDALONE_NO_VALUE:
10242
0
                    appendStringInfoString(buf,
10243
0
                                 ", STANDALONE NO VALUE");
10244
0
                    break;
10245
0
                  default:
10246
0
                    break;
10247
0
                }
10248
0
              }
10249
0
              break;
10250
0
            case IS_DOCUMENT:
10251
0
              get_rule_expr_paren((Node *) xexpr->args, context, false, node);
10252
0
              break;
10253
0
          }
10254
0
        }
10255
0
        if (xexpr->op == IS_XMLSERIALIZE)
10256
0
        {
10257
0
          appendStringInfo(buf, " AS %s",
10258
0
                   format_type_with_typemod(xexpr->type,
10259
0
                                xexpr->typmod));
10260
0
          if (xexpr->indent)
10261
0
            appendStringInfoString(buf, " INDENT");
10262
0
          else
10263
0
            appendStringInfoString(buf, " NO INDENT");
10264
0
        }
10265
10266
0
        if (xexpr->op == IS_DOCUMENT)
10267
0
          appendStringInfoString(buf, " IS DOCUMENT");
10268
0
        else
10269
0
          appendStringInfoChar(buf, ')');
10270
0
      }
10271
0
      break;
10272
10273
0
    case T_NullTest:
10274
0
      {
10275
0
        NullTest   *ntest = (NullTest *) node;
10276
10277
0
        if (!PRETTY_PAREN(context))
10278
0
          appendStringInfoChar(buf, '(');
10279
0
        get_rule_expr_paren((Node *) ntest->arg, context, true, node);
10280
10281
        /*
10282
         * For scalar inputs, we prefer to print as IS [NOT] NULL,
10283
         * which is shorter and traditional.  If it's a rowtype input
10284
         * but we're applying a scalar test, must print IS [NOT]
10285
         * DISTINCT FROM NULL to be semantically correct.
10286
         */
10287
0
        if (ntest->argisrow ||
10288
0
          !type_is_rowtype(exprType((Node *) ntest->arg)))
10289
0
        {
10290
0
          switch (ntest->nulltesttype)
10291
0
          {
10292
0
            case IS_NULL:
10293
0
              appendStringInfoString(buf, " IS NULL");
10294
0
              break;
10295
0
            case IS_NOT_NULL:
10296
0
              appendStringInfoString(buf, " IS NOT NULL");
10297
0
              break;
10298
0
            default:
10299
0
              elog(ERROR, "unrecognized nulltesttype: %d",
10300
0
                 (int) ntest->nulltesttype);
10301
0
          }
10302
0
        }
10303
0
        else
10304
0
        {
10305
0
          switch (ntest->nulltesttype)
10306
0
          {
10307
0
            case IS_NULL:
10308
0
              appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
10309
0
              break;
10310
0
            case IS_NOT_NULL:
10311
0
              appendStringInfoString(buf, " IS DISTINCT FROM NULL");
10312
0
              break;
10313
0
            default:
10314
0
              elog(ERROR, "unrecognized nulltesttype: %d",
10315
0
                 (int) ntest->nulltesttype);
10316
0
          }
10317
0
        }
10318
0
        if (!PRETTY_PAREN(context))
10319
0
          appendStringInfoChar(buf, ')');
10320
0
      }
10321
0
      break;
10322
10323
0
    case T_BooleanTest:
10324
0
      {
10325
0
        BooleanTest *btest = (BooleanTest *) node;
10326
10327
0
        if (!PRETTY_PAREN(context))
10328
0
          appendStringInfoChar(buf, '(');
10329
0
        get_rule_expr_paren((Node *) btest->arg, context, false, node);
10330
0
        switch (btest->booltesttype)
10331
0
        {
10332
0
          case IS_TRUE:
10333
0
            appendStringInfoString(buf, " IS TRUE");
10334
0
            break;
10335
0
          case IS_NOT_TRUE:
10336
0
            appendStringInfoString(buf, " IS NOT TRUE");
10337
0
            break;
10338
0
          case IS_FALSE:
10339
0
            appendStringInfoString(buf, " IS FALSE");
10340
0
            break;
10341
0
          case IS_NOT_FALSE:
10342
0
            appendStringInfoString(buf, " IS NOT FALSE");
10343
0
            break;
10344
0
          case IS_UNKNOWN:
10345
0
            appendStringInfoString(buf, " IS UNKNOWN");
10346
0
            break;
10347
0
          case IS_NOT_UNKNOWN:
10348
0
            appendStringInfoString(buf, " IS NOT UNKNOWN");
10349
0
            break;
10350
0
          default:
10351
0
            elog(ERROR, "unrecognized booltesttype: %d",
10352
0
               (int) btest->booltesttype);
10353
0
        }
10354
0
        if (!PRETTY_PAREN(context))
10355
0
          appendStringInfoChar(buf, ')');
10356
0
      }
10357
0
      break;
10358
10359
0
    case T_CoerceToDomain:
10360
0
      {
10361
0
        CoerceToDomain *ctest = (CoerceToDomain *) node;
10362
0
        Node     *arg = (Node *) ctest->arg;
10363
10364
0
        if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
10365
0
          !showimplicit)
10366
0
        {
10367
          /* don't show the implicit cast */
10368
0
          get_rule_expr(arg, context, false);
10369
0
        }
10370
0
        else
10371
0
        {
10372
0
          get_coercion_expr(arg, context,
10373
0
                    ctest->resulttype,
10374
0
                    ctest->resulttypmod,
10375
0
                    node);
10376
0
        }
10377
0
      }
10378
0
      break;
10379
10380
0
    case T_CoerceToDomainValue:
10381
0
      appendStringInfoString(buf, "VALUE");
10382
0
      break;
10383
10384
0
    case T_SetToDefault:
10385
0
      appendStringInfoString(buf, "DEFAULT");
10386
0
      break;
10387
10388
0
    case T_CurrentOfExpr:
10389
0
      {
10390
0
        CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
10391
10392
0
        if (cexpr->cursor_name)
10393
0
          appendStringInfo(buf, "CURRENT OF %s",
10394
0
                   quote_identifier(cexpr->cursor_name));
10395
0
        else
10396
0
          appendStringInfo(buf, "CURRENT OF $%d",
10397
0
                   cexpr->cursor_param);
10398
0
      }
10399
0
      break;
10400
10401
0
    case T_NextValueExpr:
10402
0
      {
10403
0
        NextValueExpr *nvexpr = (NextValueExpr *) node;
10404
10405
        /*
10406
         * This isn't exactly nextval(), but that seems close enough
10407
         * for EXPLAIN's purposes.
10408
         */
10409
0
        appendStringInfoString(buf, "nextval(");
10410
0
        simple_quote_literal(buf,
10411
0
                   generate_relation_name(nvexpr->seqid,
10412
0
                              NIL));
10413
0
        appendStringInfoChar(buf, ')');
10414
0
      }
10415
0
      break;
10416
10417
0
    case T_InferenceElem:
10418
0
      {
10419
0
        InferenceElem *iexpr = (InferenceElem *) node;
10420
0
        bool    save_varprefix;
10421
0
        bool    need_parens;
10422
10423
        /*
10424
         * InferenceElem can only refer to target relation, so a
10425
         * prefix is not useful, and indeed would cause parse errors.
10426
         */
10427
0
        save_varprefix = context->varprefix;
10428
0
        context->varprefix = false;
10429
10430
        /*
10431
         * Parenthesize the element unless it's a simple Var or a bare
10432
         * function call.  Follows pg_get_indexdef_worker().
10433
         */
10434
0
        need_parens = !IsA(iexpr->expr, Var);
10435
0
        if (IsA(iexpr->expr, FuncExpr) &&
10436
0
          ((FuncExpr *) iexpr->expr)->funcformat ==
10437
0
          COERCE_EXPLICIT_CALL)
10438
0
          need_parens = false;
10439
10440
0
        if (need_parens)
10441
0
          appendStringInfoChar(buf, '(');
10442
0
        get_rule_expr((Node *) iexpr->expr,
10443
0
                context, false);
10444
0
        if (need_parens)
10445
0
          appendStringInfoChar(buf, ')');
10446
10447
0
        context->varprefix = save_varprefix;
10448
10449
0
        if (iexpr->infercollid)
10450
0
          appendStringInfo(buf, " COLLATE %s",
10451
0
                   generate_collation_name(iexpr->infercollid));
10452
10453
        /* Add the operator class name, if not default */
10454
0
        if (iexpr->inferopclass)
10455
0
        {
10456
0
          Oid     inferopclass = iexpr->inferopclass;
10457
0
          Oid     inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
10458
10459
0
          get_opclass_name(inferopclass, inferopcinputtype, buf);
10460
0
        }
10461
0
      }
10462
0
      break;
10463
10464
0
    case T_ReturningExpr:
10465
0
      {
10466
0
        ReturningExpr *retExpr = (ReturningExpr *) node;
10467
10468
        /*
10469
         * We cannot see a ReturningExpr in rule deparsing, only while
10470
         * EXPLAINing a query plan (ReturningExpr nodes are only ever
10471
         * adding during query rewriting). Just display the expression
10472
         * returned (an expanded view column).
10473
         */
10474
0
        get_rule_expr((Node *) retExpr->retexpr, context, showimplicit);
10475
0
      }
10476
0
      break;
10477
10478
0
    case T_PartitionBoundSpec:
10479
0
      {
10480
0
        PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
10481
0
        ListCell   *cell;
10482
0
        char     *sep;
10483
10484
0
        if (spec->is_default)
10485
0
        {
10486
0
          appendStringInfoString(buf, "DEFAULT");
10487
0
          break;
10488
0
        }
10489
10490
0
        switch (spec->strategy)
10491
0
        {
10492
0
          case PARTITION_STRATEGY_HASH:
10493
0
            Assert(spec->modulus > 0 && spec->remainder >= 0);
10494
0
            Assert(spec->modulus > spec->remainder);
10495
10496
0
            appendStringInfoString(buf, "FOR VALUES");
10497
0
            appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
10498
0
                     spec->modulus, spec->remainder);
10499
0
            break;
10500
10501
0
          case PARTITION_STRATEGY_LIST:
10502
0
            Assert(spec->listdatums != NIL);
10503
10504
0
            appendStringInfoString(buf, "FOR VALUES IN (");
10505
0
            sep = "";
10506
0
            foreach(cell, spec->listdatums)
10507
0
            {
10508
0
              Const    *val = lfirst_node(Const, cell);
10509
10510
0
              appendStringInfoString(buf, sep);
10511
0
              get_const_expr(val, context, -1);
10512
0
              sep = ", ";
10513
0
            }
10514
10515
0
            appendStringInfoChar(buf, ')');
10516
0
            break;
10517
10518
0
          case PARTITION_STRATEGY_RANGE:
10519
0
            Assert(spec->lowerdatums != NIL &&
10520
0
                 spec->upperdatums != NIL &&
10521
0
                 list_length(spec->lowerdatums) ==
10522
0
                 list_length(spec->upperdatums));
10523
10524
0
            appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
10525
0
                     get_range_partbound_string(spec->lowerdatums),
10526
0
                     get_range_partbound_string(spec->upperdatums));
10527
0
            break;
10528
10529
0
          default:
10530
0
            elog(ERROR, "unrecognized partition strategy: %d",
10531
0
               (int) spec->strategy);
10532
0
            break;
10533
0
        }
10534
0
      }
10535
0
      break;
10536
10537
0
    case T_JsonValueExpr:
10538
0
      {
10539
0
        JsonValueExpr *jve = (JsonValueExpr *) node;
10540
10541
0
        get_rule_expr((Node *) jve->raw_expr, context, false);
10542
0
        get_json_format(jve->format, context->buf);
10543
0
      }
10544
0
      break;
10545
10546
0
    case T_JsonConstructorExpr:
10547
0
      get_json_constructor((JsonConstructorExpr *) node, context, false);
10548
0
      break;
10549
10550
0
    case T_JsonIsPredicate:
10551
0
      {
10552
0
        JsonIsPredicate *pred = (JsonIsPredicate *) node;
10553
10554
0
        if (!PRETTY_PAREN(context))
10555
0
          appendStringInfoChar(context->buf, '(');
10556
10557
0
        get_rule_expr_paren(pred->expr, context, true, node);
10558
10559
0
        appendStringInfoString(context->buf, " IS JSON");
10560
10561
        /* TODO: handle FORMAT clause */
10562
10563
0
        switch (pred->item_type)
10564
0
        {
10565
0
          case JS_TYPE_SCALAR:
10566
0
            appendStringInfoString(context->buf, " SCALAR");
10567
0
            break;
10568
0
          case JS_TYPE_ARRAY:
10569
0
            appendStringInfoString(context->buf, " ARRAY");
10570
0
            break;
10571
0
          case JS_TYPE_OBJECT:
10572
0
            appendStringInfoString(context->buf, " OBJECT");
10573
0
            break;
10574
0
          default:
10575
0
            break;
10576
0
        }
10577
10578
0
        if (pred->unique_keys)
10579
0
          appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
10580
10581
0
        if (!PRETTY_PAREN(context))
10582
0
          appendStringInfoChar(context->buf, ')');
10583
0
      }
10584
0
      break;
10585
10586
0
    case T_JsonExpr:
10587
0
      {
10588
0
        JsonExpr   *jexpr = (JsonExpr *) node;
10589
10590
0
        switch (jexpr->op)
10591
0
        {
10592
0
          case JSON_EXISTS_OP:
10593
0
            appendStringInfoString(buf, "JSON_EXISTS(");
10594
0
            break;
10595
0
          case JSON_QUERY_OP:
10596
0
            appendStringInfoString(buf, "JSON_QUERY(");
10597
0
            break;
10598
0
          case JSON_VALUE_OP:
10599
0
            appendStringInfoString(buf, "JSON_VALUE(");
10600
0
            break;
10601
0
          default:
10602
0
            elog(ERROR, "unrecognized JsonExpr op: %d",
10603
0
               (int) jexpr->op);
10604
0
        }
10605
10606
0
        get_rule_expr(jexpr->formatted_expr, context, showimplicit);
10607
10608
0
        appendStringInfoString(buf, ", ");
10609
10610
0
        get_json_path_spec(jexpr->path_spec, context, showimplicit);
10611
10612
0
        if (jexpr->passing_values)
10613
0
        {
10614
0
          ListCell   *lc1,
10615
0
                 *lc2;
10616
0
          bool    needcomma = false;
10617
10618
0
          appendStringInfoString(buf, " PASSING ");
10619
10620
0
          forboth(lc1, jexpr->passing_names,
10621
0
              lc2, jexpr->passing_values)
10622
0
          {
10623
0
            if (needcomma)
10624
0
              appendStringInfoString(buf, ", ");
10625
0
            needcomma = true;
10626
10627
0
            get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
10628
0
            appendStringInfo(buf, " AS %s",
10629
0
                     quote_identifier(lfirst_node(String, lc1)->sval));
10630
0
          }
10631
0
        }
10632
10633
0
        if (jexpr->op != JSON_EXISTS_OP ||
10634
0
          jexpr->returning->typid != BOOLOID)
10635
0
          get_json_returning(jexpr->returning, context->buf,
10636
0
                     jexpr->op == JSON_QUERY_OP);
10637
10638
0
        get_json_expr_options(jexpr, context,
10639
0
                    jexpr->op != JSON_EXISTS_OP ?
10640
0
                    JSON_BEHAVIOR_NULL :
10641
0
                    JSON_BEHAVIOR_FALSE);
10642
10643
0
        appendStringInfoChar(buf, ')');
10644
0
      }
10645
0
      break;
10646
10647
0
    case T_List:
10648
0
      {
10649
0
        char     *sep;
10650
0
        ListCell   *l;
10651
10652
0
        sep = "";
10653
0
        foreach(l, (List *) node)
10654
0
        {
10655
0
          appendStringInfoString(buf, sep);
10656
0
          get_rule_expr((Node *) lfirst(l), context, showimplicit);
10657
0
          sep = ", ";
10658
0
        }
10659
0
      }
10660
0
      break;
10661
10662
0
    case T_TableFunc:
10663
0
      get_tablefunc((TableFunc *) node, context, showimplicit);
10664
0
      break;
10665
10666
0
    default:
10667
0
      elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
10668
0
      break;
10669
0
  }
10670
0
}
10671
10672
/*
10673
 * get_rule_expr_toplevel   - Parse back a toplevel expression
10674
 *
10675
 * Same as get_rule_expr(), except that if the expr is just a Var, we pass
10676
 * istoplevel = true not false to get_variable().  This causes whole-row Vars
10677
 * to get printed with decoration that will prevent expansion of "*".
10678
 * We need to use this in contexts such as ROW() and VALUES(), where the
10679
 * parser would expand "foo.*" appearing at top level.  (In principle we'd
10680
 * use this in get_target_list() too, but that has additional worries about
10681
 * whether to print AS, so it needs to invoke get_variable() directly anyway.)
10682
 */
10683
static void
10684
get_rule_expr_toplevel(Node *node, deparse_context *context,
10685
             bool showimplicit)
10686
0
{
10687
0
  if (node && IsA(node, Var))
10688
0
    (void) get_variable((Var *) node, 0, true, context);
10689
0
  else
10690
0
    get_rule_expr(node, context, showimplicit);
10691
0
}
10692
10693
/*
10694
 * get_rule_list_toplevel   - Parse back a list of toplevel expressions
10695
 *
10696
 * Apply get_rule_expr_toplevel() to each element of a List.
10697
 *
10698
 * This adds commas between the expressions, but caller is responsible
10699
 * for printing surrounding decoration.
10700
 */
10701
static void
10702
get_rule_list_toplevel(List *lst, deparse_context *context,
10703
             bool showimplicit)
10704
0
{
10705
0
  const char *sep;
10706
0
  ListCell   *lc;
10707
10708
0
  sep = "";
10709
0
  foreach(lc, lst)
10710
0
  {
10711
0
    Node     *e = (Node *) lfirst(lc);
10712
10713
0
    appendStringInfoString(context->buf, sep);
10714
0
    get_rule_expr_toplevel(e, context, showimplicit);
10715
0
    sep = ", ";
10716
0
  }
10717
0
}
10718
10719
/*
10720
 * get_rule_expr_funccall   - Parse back a function-call expression
10721
 *
10722
 * Same as get_rule_expr(), except that we guarantee that the output will
10723
 * look like a function call, or like one of the things the grammar treats as
10724
 * equivalent to a function call (see the func_expr_windowless production).
10725
 * This is needed in places where the grammar uses func_expr_windowless and
10726
 * you can't substitute a parenthesized a_expr.  If what we have isn't going
10727
 * to look like a function call, wrap it in a dummy CAST() expression, which
10728
 * will satisfy the grammar --- and, indeed, is likely what the user wrote to
10729
 * produce such a thing.
10730
 */
10731
static void
10732
get_rule_expr_funccall(Node *node, deparse_context *context,
10733
             bool showimplicit)
10734
0
{
10735
0
  if (looks_like_function(node))
10736
0
    get_rule_expr(node, context, showimplicit);
10737
0
  else
10738
0
  {
10739
0
    StringInfo  buf = context->buf;
10740
10741
0
    appendStringInfoString(buf, "CAST(");
10742
    /* no point in showing any top-level implicit cast */
10743
0
    get_rule_expr(node, context, false);
10744
0
    appendStringInfo(buf, " AS %s)",
10745
0
             format_type_with_typemod(exprType(node),
10746
0
                          exprTypmod(node)));
10747
0
  }
10748
0
}
10749
10750
/*
10751
 * Helper function to identify node types that satisfy func_expr_windowless.
10752
 * If in doubt, "false" is always a safe answer.
10753
 */
10754
static bool
10755
looks_like_function(Node *node)
10756
0
{
10757
0
  if (node == NULL)
10758
0
    return false;     /* probably shouldn't happen */
10759
0
  switch (nodeTag(node))
10760
0
  {
10761
0
    case T_FuncExpr:
10762
      /* OK, unless it's going to deparse as a cast */
10763
0
      return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10764
0
          ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10765
0
    case T_NullIfExpr:
10766
0
    case T_CoalesceExpr:
10767
0
    case T_MinMaxExpr:
10768
0
    case T_SQLValueFunction:
10769
0
    case T_XmlExpr:
10770
0
    case T_JsonExpr:
10771
      /* these are all accepted by func_expr_common_subexpr */
10772
0
      return true;
10773
0
    default:
10774
0
      break;
10775
0
  }
10776
0
  return false;
10777
0
}
10778
10779
10780
/*
10781
 * get_oper_expr      - Parse back an OpExpr node
10782
 */
10783
static void
10784
get_oper_expr(OpExpr *expr, deparse_context *context)
10785
0
{
10786
0
  StringInfo  buf = context->buf;
10787
0
  Oid     opno = expr->opno;
10788
0
  List     *args = expr->args;
10789
10790
0
  if (!PRETTY_PAREN(context))
10791
0
    appendStringInfoChar(buf, '(');
10792
0
  if (list_length(args) == 2)
10793
0
  {
10794
    /* binary operator */
10795
0
    Node     *arg1 = (Node *) linitial(args);
10796
0
    Node     *arg2 = (Node *) lsecond(args);
10797
10798
0
    get_rule_expr_paren(arg1, context, true, (Node *) expr);
10799
0
    appendStringInfo(buf, " %s ",
10800
0
             generate_operator_name(opno,
10801
0
                        exprType(arg1),
10802
0
                        exprType(arg2)));
10803
0
    get_rule_expr_paren(arg2, context, true, (Node *) expr);
10804
0
  }
10805
0
  else
10806
0
  {
10807
    /* prefix operator */
10808
0
    Node     *arg = (Node *) linitial(args);
10809
10810
0
    appendStringInfo(buf, "%s ",
10811
0
             generate_operator_name(opno,
10812
0
                        InvalidOid,
10813
0
                        exprType(arg)));
10814
0
    get_rule_expr_paren(arg, context, true, (Node *) expr);
10815
0
  }
10816
0
  if (!PRETTY_PAREN(context))
10817
0
    appendStringInfoChar(buf, ')');
10818
0
}
10819
10820
/*
10821
 * get_func_expr      - Parse back a FuncExpr node
10822
 */
10823
static void
10824
get_func_expr(FuncExpr *expr, deparse_context *context,
10825
        bool showimplicit)
10826
0
{
10827
0
  StringInfo  buf = context->buf;
10828
0
  Oid     funcoid = expr->funcid;
10829
0
  Oid     argtypes[FUNC_MAX_ARGS];
10830
0
  int     nargs;
10831
0
  List     *argnames;
10832
0
  bool    use_variadic;
10833
0
  ListCell   *l;
10834
10835
  /*
10836
   * If the function call came from an implicit coercion, then just show the
10837
   * first argument --- unless caller wants to see implicit coercions.
10838
   */
10839
0
  if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10840
0
  {
10841
0
    get_rule_expr_paren((Node *) linitial(expr->args), context,
10842
0
              false, (Node *) expr);
10843
0
    return;
10844
0
  }
10845
10846
  /*
10847
   * If the function call came from a cast, then show the first argument
10848
   * plus an explicit cast operation.
10849
   */
10850
0
  if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10851
0
    expr->funcformat == COERCE_IMPLICIT_CAST)
10852
0
  {
10853
0
    Node     *arg = linitial(expr->args);
10854
0
    Oid     rettype = expr->funcresulttype;
10855
0
    int32   coercedTypmod;
10856
10857
    /* Get the typmod if this is a length-coercion function */
10858
0
    (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10859
10860
0
    get_coercion_expr(arg, context,
10861
0
              rettype, coercedTypmod,
10862
0
              (Node *) expr);
10863
10864
0
    return;
10865
0
  }
10866
10867
  /*
10868
   * If the function was called using one of the SQL spec's random special
10869
   * syntaxes, try to reproduce that.  If we don't recognize the function,
10870
   * fall through.
10871
   */
10872
0
  if (expr->funcformat == COERCE_SQL_SYNTAX)
10873
0
  {
10874
0
    if (get_func_sql_syntax(expr, context))
10875
0
      return;
10876
0
  }
10877
10878
  /*
10879
   * Normal function: display as proname(args).  First we need to extract
10880
   * the argument datatypes.
10881
   */
10882
0
  if (list_length(expr->args) > FUNC_MAX_ARGS)
10883
0
    ereport(ERROR,
10884
0
        (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10885
0
         errmsg("too many arguments")));
10886
0
  nargs = 0;
10887
0
  argnames = NIL;
10888
0
  foreach(l, expr->args)
10889
0
  {
10890
0
    Node     *arg = (Node *) lfirst(l);
10891
10892
0
    if (IsA(arg, NamedArgExpr))
10893
0
      argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10894
0
    argtypes[nargs] = exprType(arg);
10895
0
    nargs++;
10896
0
  }
10897
10898
0
  appendStringInfo(buf, "%s(",
10899
0
           generate_function_name(funcoid, nargs,
10900
0
                      argnames, argtypes,
10901
0
                      expr->funcvariadic,
10902
0
                      &use_variadic,
10903
0
                      context->inGroupBy));
10904
0
  nargs = 0;
10905
0
  foreach(l, expr->args)
10906
0
  {
10907
0
    if (nargs++ > 0)
10908
0
      appendStringInfoString(buf, ", ");
10909
0
    if (use_variadic && lnext(expr->args, l) == NULL)
10910
0
      appendStringInfoString(buf, "VARIADIC ");
10911
0
    get_rule_expr((Node *) lfirst(l), context, true);
10912
0
  }
10913
0
  appendStringInfoChar(buf, ')');
10914
0
}
10915
10916
/*
10917
 * get_agg_expr     - Parse back an Aggref node
10918
 */
10919
static void
10920
get_agg_expr(Aggref *aggref, deparse_context *context,
10921
       Aggref *original_aggref)
10922
0
{
10923
0
  get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10924
0
            false);
10925
0
}
10926
10927
/*
10928
 * get_agg_expr_helper    - subroutine for get_agg_expr and
10929
 *              get_json_agg_constructor
10930
 */
10931
static void
10932
get_agg_expr_helper(Aggref *aggref, deparse_context *context,
10933
          Aggref *original_aggref, const char *funcname,
10934
          const char *options, bool is_json_objectagg)
10935
0
{
10936
0
  StringInfo  buf = context->buf;
10937
0
  Oid     argtypes[FUNC_MAX_ARGS];
10938
0
  int     nargs;
10939
0
  bool    use_variadic = false;
10940
10941
  /*
10942
   * For a combining aggregate, we look up and deparse the corresponding
10943
   * partial aggregate instead.  This is necessary because our input
10944
   * argument list has been replaced; the new argument list always has just
10945
   * one element, which will point to a partial Aggref that supplies us with
10946
   * transition states to combine.
10947
   */
10948
0
  if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10949
0
  {
10950
0
    TargetEntry *tle;
10951
10952
0
    Assert(list_length(aggref->args) == 1);
10953
0
    tle = linitial_node(TargetEntry, aggref->args);
10954
0
    resolve_special_varno((Node *) tle->expr, context,
10955
0
                get_agg_combine_expr, original_aggref);
10956
0
    return;
10957
0
  }
10958
10959
  /*
10960
   * Mark as PARTIAL, if appropriate.  We look to the original aggref so as
10961
   * to avoid printing this when recursing from the code just above.
10962
   */
10963
0
  if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10964
0
    appendStringInfoString(buf, "PARTIAL ");
10965
10966
  /* Extract the argument types as seen by the parser */
10967
0
  nargs = get_aggregate_argtypes(aggref, argtypes);
10968
10969
0
  if (!funcname)
10970
0
    funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10971
0
                      argtypes, aggref->aggvariadic,
10972
0
                      &use_variadic,
10973
0
                      context->inGroupBy);
10974
10975
  /* Print the aggregate name, schema-qualified if needed */
10976
0
  appendStringInfo(buf, "%s(%s", funcname,
10977
0
           (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10978
10979
0
  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10980
0
  {
10981
    /*
10982
     * Ordered-set aggregates do not use "*" syntax.  Also, we needn't
10983
     * worry about inserting VARIADIC.  So we can just dump the direct
10984
     * args as-is.
10985
     */
10986
0
    Assert(!aggref->aggvariadic);
10987
0
    get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10988
0
    Assert(aggref->aggorder != NIL);
10989
0
    appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10990
0
    get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10991
0
  }
10992
0
  else
10993
0
  {
10994
    /* aggstar can be set only in zero-argument aggregates */
10995
0
    if (aggref->aggstar)
10996
0
      appendStringInfoChar(buf, '*');
10997
0
    else
10998
0
    {
10999
0
      ListCell   *l;
11000
0
      int     i;
11001
11002
0
      i = 0;
11003
0
      foreach(l, aggref->args)
11004
0
      {
11005
0
        TargetEntry *tle = (TargetEntry *) lfirst(l);
11006
0
        Node     *arg = (Node *) tle->expr;
11007
11008
0
        Assert(!IsA(arg, NamedArgExpr));
11009
0
        if (tle->resjunk)
11010
0
          continue;
11011
0
        if (i++ > 0)
11012
0
        {
11013
0
          if (is_json_objectagg)
11014
0
          {
11015
            /*
11016
             * the ABSENT ON NULL and WITH UNIQUE args are printed
11017
             * separately, so ignore them here
11018
             */
11019
0
            if (i > 2)
11020
0
              break;
11021
11022
0
            appendStringInfoString(buf, " : ");
11023
0
          }
11024
0
          else
11025
0
            appendStringInfoString(buf, ", ");
11026
0
        }
11027
0
        if (use_variadic && i == nargs)
11028
0
          appendStringInfoString(buf, "VARIADIC ");
11029
0
        get_rule_expr(arg, context, true);
11030
0
      }
11031
0
    }
11032
11033
0
    if (aggref->aggorder != NIL)
11034
0
    {
11035
0
      appendStringInfoString(buf, " ORDER BY ");
11036
0
      get_rule_orderby(aggref->aggorder, aggref->args, false, context);
11037
0
    }
11038
0
  }
11039
11040
0
  if (options)
11041
0
    appendStringInfoString(buf, options);
11042
11043
0
  if (aggref->aggfilter != NULL)
11044
0
  {
11045
0
    appendStringInfoString(buf, ") FILTER (WHERE ");
11046
0
    get_rule_expr((Node *) aggref->aggfilter, context, false);
11047
0
  }
11048
11049
0
  appendStringInfoChar(buf, ')');
11050
0
}
11051
11052
/*
11053
 * This is a helper function for get_agg_expr().  It's used when we deparse
11054
 * a combining Aggref; resolve_special_varno locates the corresponding partial
11055
 * Aggref and then calls this.
11056
 */
11057
static void
11058
get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
11059
0
{
11060
0
  Aggref     *aggref;
11061
0
  Aggref     *original_aggref = callback_arg;
11062
11063
0
  if (!IsA(node, Aggref))
11064
0
    elog(ERROR, "combining Aggref does not point to an Aggref");
11065
11066
0
  aggref = (Aggref *) node;
11067
0
  get_agg_expr(aggref, context, original_aggref);
11068
0
}
11069
11070
/*
11071
 * get_windowfunc_expr  - Parse back a WindowFunc node
11072
 */
11073
static void
11074
get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
11075
0
{
11076
0
  get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
11077
0
}
11078
11079
11080
/*
11081
 * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
11082
 *                get_json_agg_constructor
11083
 */
11084
static void
11085
get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
11086
               const char *funcname, const char *options,
11087
               bool is_json_objectagg)
11088
0
{
11089
0
  StringInfo  buf = context->buf;
11090
0
  Oid     argtypes[FUNC_MAX_ARGS];
11091
0
  int     nargs;
11092
0
  List     *argnames;
11093
0
  ListCell   *l;
11094
11095
0
  if (list_length(wfunc->args) > FUNC_MAX_ARGS)
11096
0
    ereport(ERROR,
11097
0
        (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
11098
0
         errmsg("too many arguments")));
11099
0
  nargs = 0;
11100
0
  argnames = NIL;
11101
0
  foreach(l, wfunc->args)
11102
0
  {
11103
0
    Node     *arg = (Node *) lfirst(l);
11104
11105
0
    if (IsA(arg, NamedArgExpr))
11106
0
      argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
11107
0
    argtypes[nargs] = exprType(arg);
11108
0
    nargs++;
11109
0
  }
11110
11111
0
  if (!funcname)
11112
0
    funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
11113
0
                      argtypes, false, NULL,
11114
0
                      context->inGroupBy);
11115
11116
0
  appendStringInfo(buf, "%s(", funcname);
11117
11118
  /* winstar can be set only in zero-argument aggregates */
11119
0
  if (wfunc->winstar)
11120
0
    appendStringInfoChar(buf, '*');
11121
0
  else
11122
0
  {
11123
0
    if (is_json_objectagg)
11124
0
    {
11125
0
      get_rule_expr((Node *) linitial(wfunc->args), context, false);
11126
0
      appendStringInfoString(buf, " : ");
11127
0
      get_rule_expr((Node *) lsecond(wfunc->args), context, false);
11128
0
    }
11129
0
    else
11130
0
      get_rule_expr((Node *) wfunc->args, context, true);
11131
0
  }
11132
11133
0
  if (options)
11134
0
    appendStringInfoString(buf, options);
11135
11136
0
  if (wfunc->aggfilter != NULL)
11137
0
  {
11138
0
    appendStringInfoString(buf, ") FILTER (WHERE ");
11139
0
    get_rule_expr((Node *) wfunc->aggfilter, context, false);
11140
0
  }
11141
11142
0
  appendStringInfoString(buf, ") ");
11143
11144
0
  if (wfunc->ignore_nulls == PARSER_IGNORE_NULLS)
11145
0
    appendStringInfoString(buf, "IGNORE NULLS ");
11146
11147
0
  appendStringInfoString(buf, "OVER ");
11148
11149
0
  if (context->windowClause)
11150
0
  {
11151
    /* Query-decompilation case: search the windowClause list */
11152
0
    foreach(l, context->windowClause)
11153
0
    {
11154
0
      WindowClause *wc = (WindowClause *) lfirst(l);
11155
11156
0
      if (wc->winref == wfunc->winref)
11157
0
      {
11158
0
        if (wc->name)
11159
0
          appendStringInfoString(buf, quote_identifier(wc->name));
11160
0
        else
11161
0
          get_rule_windowspec(wc, context->targetList, context);
11162
0
        break;
11163
0
      }
11164
0
    }
11165
0
    if (l == NULL)
11166
0
      elog(ERROR, "could not find window clause for winref %u",
11167
0
         wfunc->winref);
11168
0
  }
11169
0
  else
11170
0
  {
11171
    /*
11172
     * In EXPLAIN, search the namespace stack for a matching WindowAgg
11173
     * node (probably it's always the first entry), and print winname.
11174
     */
11175
0
    foreach(l, context->namespaces)
11176
0
    {
11177
0
      deparse_namespace *dpns = (deparse_namespace *) lfirst(l);
11178
11179
0
      if (dpns->plan && IsA(dpns->plan, WindowAgg))
11180
0
      {
11181
0
        WindowAgg  *wagg = (WindowAgg *) dpns->plan;
11182
11183
0
        if (wagg->winref == wfunc->winref)
11184
0
        {
11185
0
          appendStringInfoString(buf, quote_identifier(wagg->winname));
11186
0
          break;
11187
0
        }
11188
0
      }
11189
0
    }
11190
0
    if (l == NULL)
11191
0
      elog(ERROR, "could not find window clause for winref %u",
11192
0
         wfunc->winref);
11193
0
  }
11194
0
}
11195
11196
/*
11197
 * get_func_sql_syntax    - Parse back a SQL-syntax function call
11198
 *
11199
 * Returns true if we successfully deparsed, false if we did not
11200
 * recognize the function.
11201
 */
11202
static bool
11203
get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
11204
0
{
11205
0
  StringInfo  buf = context->buf;
11206
0
  Oid     funcoid = expr->funcid;
11207
11208
0
  switch (funcoid)
11209
0
  {
11210
0
    case F_TIMEZONE_INTERVAL_TIMESTAMP:
11211
0
    case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
11212
0
    case F_TIMEZONE_INTERVAL_TIMETZ:
11213
0
    case F_TIMEZONE_TEXT_TIMESTAMP:
11214
0
    case F_TIMEZONE_TEXT_TIMESTAMPTZ:
11215
0
    case F_TIMEZONE_TEXT_TIMETZ:
11216
      /* AT TIME ZONE ... note reversed argument order */
11217
0
      appendStringInfoChar(buf, '(');
11218
0
      get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
11219
0
                (Node *) expr);
11220
0
      appendStringInfoString(buf, " AT TIME ZONE ");
11221
0
      get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11222
0
                (Node *) expr);
11223
0
      appendStringInfoChar(buf, ')');
11224
0
      return true;
11225
11226
0
    case F_TIMEZONE_TIMESTAMP:
11227
0
    case F_TIMEZONE_TIMESTAMPTZ:
11228
0
    case F_TIMEZONE_TIMETZ:
11229
      /* AT LOCAL */
11230
0
      appendStringInfoChar(buf, '(');
11231
0
      get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11232
0
                (Node *) expr);
11233
0
      appendStringInfoString(buf, " AT LOCAL)");
11234
0
      return true;
11235
11236
0
    case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
11237
0
    case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
11238
0
    case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
11239
0
    case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
11240
0
    case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
11241
0
    case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
11242
0
    case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
11243
0
    case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
11244
0
    case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
11245
0
    case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
11246
0
    case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
11247
0
    case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
11248
0
    case F_OVERLAPS_TIME_TIME_TIME_TIME:
11249
      /* (x1, x2) OVERLAPS (y1, y2) */
11250
0
      appendStringInfoString(buf, "((");
11251
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11252
0
      appendStringInfoString(buf, ", ");
11253
0
      get_rule_expr((Node *) lsecond(expr->args), context, false);
11254
0
      appendStringInfoString(buf, ") OVERLAPS (");
11255
0
      get_rule_expr((Node *) lthird(expr->args), context, false);
11256
0
      appendStringInfoString(buf, ", ");
11257
0
      get_rule_expr((Node *) lfourth(expr->args), context, false);
11258
0
      appendStringInfoString(buf, "))");
11259
0
      return true;
11260
11261
0
    case F_EXTRACT_TEXT_DATE:
11262
0
    case F_EXTRACT_TEXT_TIME:
11263
0
    case F_EXTRACT_TEXT_TIMETZ:
11264
0
    case F_EXTRACT_TEXT_TIMESTAMP:
11265
0
    case F_EXTRACT_TEXT_TIMESTAMPTZ:
11266
0
    case F_EXTRACT_TEXT_INTERVAL:
11267
      /* EXTRACT (x FROM y) */
11268
0
      appendStringInfoString(buf, "EXTRACT(");
11269
0
      {
11270
0
        Const    *con = (Const *) linitial(expr->args);
11271
11272
0
        Assert(IsA(con, Const) &&
11273
0
             con->consttype == TEXTOID &&
11274
0
             !con->constisnull);
11275
0
        appendStringInfoString(buf, quote_identifier(TextDatumGetCString(con->constvalue)));
11276
0
      }
11277
0
      appendStringInfoString(buf, " FROM ");
11278
0
      get_rule_expr((Node *) lsecond(expr->args), context, false);
11279
0
      appendStringInfoChar(buf, ')');
11280
0
      return true;
11281
11282
0
    case F_IS_NORMALIZED:
11283
      /* IS xxx NORMALIZED */
11284
0
      appendStringInfoChar(buf, '(');
11285
0
      get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11286
0
                (Node *) expr);
11287
0
      appendStringInfoString(buf, " IS");
11288
0
      if (list_length(expr->args) == 2)
11289
0
      {
11290
0
        Const    *con = (Const *) lsecond(expr->args);
11291
11292
0
        Assert(IsA(con, Const) &&
11293
0
             con->consttype == TEXTOID &&
11294
0
             !con->constisnull);
11295
        /* NB: safe because no allowed words need quoted/escaped */
11296
0
        appendStringInfo(buf, " %s",
11297
0
                 TextDatumGetCString(con->constvalue));
11298
0
      }
11299
0
      appendStringInfoString(buf, " NORMALIZED)");
11300
0
      return true;
11301
11302
0
    case F_PG_COLLATION_FOR:
11303
      /* COLLATION FOR */
11304
0
      appendStringInfoString(buf, "COLLATION FOR (");
11305
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11306
0
      appendStringInfoChar(buf, ')');
11307
0
      return true;
11308
11309
0
    case F_NORMALIZE:
11310
      /* NORMALIZE() */
11311
0
      appendStringInfoString(buf, "NORMALIZE(");
11312
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11313
0
      if (list_length(expr->args) == 2)
11314
0
      {
11315
0
        Const    *con = (Const *) lsecond(expr->args);
11316
11317
0
        Assert(IsA(con, Const) &&
11318
0
             con->consttype == TEXTOID &&
11319
0
             !con->constisnull);
11320
0
        appendStringInfo(buf, ", %s",
11321
0
                 TextDatumGetCString(con->constvalue));
11322
0
      }
11323
0
      appendStringInfoChar(buf, ')');
11324
0
      return true;
11325
11326
0
    case F_OVERLAY_BIT_BIT_INT4:
11327
0
    case F_OVERLAY_BIT_BIT_INT4_INT4:
11328
0
    case F_OVERLAY_BYTEA_BYTEA_INT4:
11329
0
    case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
11330
0
    case F_OVERLAY_TEXT_TEXT_INT4:
11331
0
    case F_OVERLAY_TEXT_TEXT_INT4_INT4:
11332
      /* OVERLAY() */
11333
0
      appendStringInfoString(buf, "OVERLAY(");
11334
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11335
0
      appendStringInfoString(buf, " PLACING ");
11336
0
      get_rule_expr((Node *) lsecond(expr->args), context, false);
11337
0
      appendStringInfoString(buf, " FROM ");
11338
0
      get_rule_expr((Node *) lthird(expr->args), context, false);
11339
0
      if (list_length(expr->args) == 4)
11340
0
      {
11341
0
        appendStringInfoString(buf, " FOR ");
11342
0
        get_rule_expr((Node *) lfourth(expr->args), context, false);
11343
0
      }
11344
0
      appendStringInfoChar(buf, ')');
11345
0
      return true;
11346
11347
0
    case F_POSITION_BIT_BIT:
11348
0
    case F_POSITION_BYTEA_BYTEA:
11349
0
    case F_POSITION_TEXT_TEXT:
11350
      /* POSITION() ... extra parens since args are b_expr not a_expr */
11351
0
      appendStringInfoString(buf, "POSITION((");
11352
0
      get_rule_expr((Node *) lsecond(expr->args), context, false);
11353
0
      appendStringInfoString(buf, ") IN (");
11354
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11355
0
      appendStringInfoString(buf, "))");
11356
0
      return true;
11357
11358
0
    case F_SUBSTRING_BIT_INT4:
11359
0
    case F_SUBSTRING_BIT_INT4_INT4:
11360
0
    case F_SUBSTRING_BYTEA_INT4:
11361
0
    case F_SUBSTRING_BYTEA_INT4_INT4:
11362
0
    case F_SUBSTRING_TEXT_INT4:
11363
0
    case F_SUBSTRING_TEXT_INT4_INT4:
11364
      /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
11365
0
      appendStringInfoString(buf, "SUBSTRING(");
11366
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11367
0
      appendStringInfoString(buf, " FROM ");
11368
0
      get_rule_expr((Node *) lsecond(expr->args), context, false);
11369
0
      if (list_length(expr->args) == 3)
11370
0
      {
11371
0
        appendStringInfoString(buf, " FOR ");
11372
0
        get_rule_expr((Node *) lthird(expr->args), context, false);
11373
0
      }
11374
0
      appendStringInfoChar(buf, ')');
11375
0
      return true;
11376
11377
0
    case F_SUBSTRING_TEXT_TEXT_TEXT:
11378
      /* SUBSTRING SIMILAR/ESCAPE */
11379
0
      appendStringInfoString(buf, "SUBSTRING(");
11380
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11381
0
      appendStringInfoString(buf, " SIMILAR ");
11382
0
      get_rule_expr((Node *) lsecond(expr->args), context, false);
11383
0
      appendStringInfoString(buf, " ESCAPE ");
11384
0
      get_rule_expr((Node *) lthird(expr->args), context, false);
11385
0
      appendStringInfoChar(buf, ')');
11386
0
      return true;
11387
11388
0
    case F_BTRIM_BYTEA_BYTEA:
11389
0
    case F_BTRIM_TEXT:
11390
0
    case F_BTRIM_TEXT_TEXT:
11391
      /* TRIM() */
11392
0
      appendStringInfoString(buf, "TRIM(BOTH");
11393
0
      if (list_length(expr->args) == 2)
11394
0
      {
11395
0
        appendStringInfoChar(buf, ' ');
11396
0
        get_rule_expr((Node *) lsecond(expr->args), context, false);
11397
0
      }
11398
0
      appendStringInfoString(buf, " FROM ");
11399
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11400
0
      appendStringInfoChar(buf, ')');
11401
0
      return true;
11402
11403
0
    case F_LTRIM_BYTEA_BYTEA:
11404
0
    case F_LTRIM_TEXT:
11405
0
    case F_LTRIM_TEXT_TEXT:
11406
      /* TRIM() */
11407
0
      appendStringInfoString(buf, "TRIM(LEADING");
11408
0
      if (list_length(expr->args) == 2)
11409
0
      {
11410
0
        appendStringInfoChar(buf, ' ');
11411
0
        get_rule_expr((Node *) lsecond(expr->args), context, false);
11412
0
      }
11413
0
      appendStringInfoString(buf, " FROM ");
11414
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11415
0
      appendStringInfoChar(buf, ')');
11416
0
      return true;
11417
11418
0
    case F_RTRIM_BYTEA_BYTEA:
11419
0
    case F_RTRIM_TEXT:
11420
0
    case F_RTRIM_TEXT_TEXT:
11421
      /* TRIM() */
11422
0
      appendStringInfoString(buf, "TRIM(TRAILING");
11423
0
      if (list_length(expr->args) == 2)
11424
0
      {
11425
0
        appendStringInfoChar(buf, ' ');
11426
0
        get_rule_expr((Node *) lsecond(expr->args), context, false);
11427
0
      }
11428
0
      appendStringInfoString(buf, " FROM ");
11429
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11430
0
      appendStringInfoChar(buf, ')');
11431
0
      return true;
11432
11433
0
    case F_SYSTEM_USER:
11434
0
      appendStringInfoString(buf, "SYSTEM_USER");
11435
0
      return true;
11436
11437
0
    case F_XMLEXISTS:
11438
      /* XMLEXISTS ... extra parens because args are c_expr */
11439
0
      appendStringInfoString(buf, "XMLEXISTS((");
11440
0
      get_rule_expr((Node *) linitial(expr->args), context, false);
11441
0
      appendStringInfoString(buf, ") PASSING (");
11442
0
      get_rule_expr((Node *) lsecond(expr->args), context, false);
11443
0
      appendStringInfoString(buf, "))");
11444
0
      return true;
11445
0
  }
11446
0
  return false;
11447
0
}
11448
11449
/* ----------
11450
 * get_coercion_expr
11451
 *
11452
 *  Make a string representation of a value coerced to a specific type
11453
 * ----------
11454
 */
11455
static void
11456
get_coercion_expr(Node *arg, deparse_context *context,
11457
          Oid resulttype, int32 resulttypmod,
11458
          Node *parentNode)
11459
0
{
11460
0
  StringInfo  buf = context->buf;
11461
11462
  /*
11463
   * Since parse_coerce.c doesn't immediately collapse application of
11464
   * length-coercion functions to constants, what we'll typically see in
11465
   * such cases is a Const with typmod -1 and a length-coercion function
11466
   * right above it.  Avoid generating redundant output. However, beware of
11467
   * suppressing casts when the user actually wrote something like
11468
   * 'foo'::text::char(3).
11469
   *
11470
   * Note: it might seem that we are missing the possibility of needing to
11471
   * print a COLLATE clause for such a Const.  However, a Const could only
11472
   * have nondefault collation in a post-constant-folding tree, in which the
11473
   * length coercion would have been folded too.  See also the special
11474
   * handling of CollateExpr in coerce_to_target_type(): any collation
11475
   * marking will be above the coercion node, not below it.
11476
   */
11477
0
  if (arg && IsA(arg, Const) &&
11478
0
    ((Const *) arg)->consttype == resulttype &&
11479
0
    ((Const *) arg)->consttypmod == -1)
11480
0
  {
11481
    /* Show the constant without normal ::typename decoration */
11482
0
    get_const_expr((Const *) arg, context, -1);
11483
0
  }
11484
0
  else
11485
0
  {
11486
0
    if (!PRETTY_PAREN(context))
11487
0
      appendStringInfoChar(buf, '(');
11488
0
    get_rule_expr_paren(arg, context, false, parentNode);
11489
0
    if (!PRETTY_PAREN(context))
11490
0
      appendStringInfoChar(buf, ')');
11491
0
  }
11492
11493
  /*
11494
   * Never emit resulttype(arg) functional notation. A pg_proc entry could
11495
   * take precedence, and a resulttype in pg_temp would require schema
11496
   * qualification that format_type_with_typemod() would usually omit. We've
11497
   * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11498
   * would work fine.
11499
   */
11500
0
  appendStringInfo(buf, "::%s",
11501
0
           format_type_with_typemod(resulttype, resulttypmod));
11502
0
}
11503
11504
/* ----------
11505
 * get_const_expr
11506
 *
11507
 *  Make a string representation of a Const
11508
 *
11509
 * showtype can be -1 to never show "::typename" decoration, or +1 to always
11510
 * show it, or 0 to show it only if the constant wouldn't be assumed to be
11511
 * the right type by default.
11512
 *
11513
 * If the Const's collation isn't default for its type, show that too.
11514
 * We mustn't do this when showtype is -1 (since that means the caller will
11515
 * print "::typename", and we can't put a COLLATE clause in between).  It's
11516
 * caller's responsibility that collation isn't missed in such cases.
11517
 * ----------
11518
 */
11519
static void
11520
get_const_expr(Const *constval, deparse_context *context, int showtype)
11521
0
{
11522
0
  StringInfo  buf = context->buf;
11523
0
  Oid     typoutput;
11524
0
  bool    typIsVarlena;
11525
0
  char     *extval;
11526
0
  bool    needlabel = false;
11527
11528
0
  if (constval->constisnull)
11529
0
  {
11530
    /*
11531
     * Always label the type of a NULL constant to prevent misdecisions
11532
     * about type when reparsing.
11533
     */
11534
0
    appendStringInfoString(buf, "NULL");
11535
0
    if (showtype >= 0)
11536
0
    {
11537
0
      appendStringInfo(buf, "::%s",
11538
0
               format_type_with_typemod(constval->consttype,
11539
0
                            constval->consttypmod));
11540
0
      get_const_collation(constval, context);
11541
0
    }
11542
0
    return;
11543
0
  }
11544
11545
0
  getTypeOutputInfo(constval->consttype,
11546
0
            &typoutput, &typIsVarlena);
11547
11548
0
  extval = OidOutputFunctionCall(typoutput, constval->constvalue);
11549
11550
0
  switch (constval->consttype)
11551
0
  {
11552
0
    case INT4OID:
11553
11554
      /*
11555
       * INT4 can be printed without any decoration, unless it is
11556
       * negative; in that case print it as '-nnn'::integer to ensure
11557
       * that the output will re-parse as a constant, not as a constant
11558
       * plus operator.  In most cases we could get away with printing
11559
       * (-nnn) instead, because of the way that gram.y handles negative
11560
       * literals; but that doesn't work for INT_MIN, and it doesn't
11561
       * seem that much prettier anyway.
11562
       */
11563
0
      if (extval[0] != '-')
11564
0
        appendStringInfoString(buf, extval);
11565
0
      else
11566
0
      {
11567
0
        appendStringInfo(buf, "'%s'", extval);
11568
0
        needlabel = true; /* we must attach a cast */
11569
0
      }
11570
0
      break;
11571
11572
0
    case NUMERICOID:
11573
11574
      /*
11575
       * NUMERIC can be printed without quotes if it looks like a float
11576
       * constant (not an integer, and not Infinity or NaN) and doesn't
11577
       * have a leading sign (for the same reason as for INT4).
11578
       */
11579
0
      if (isdigit((unsigned char) extval[0]) &&
11580
0
        strcspn(extval, "eE.") != strlen(extval))
11581
0
      {
11582
0
        appendStringInfoString(buf, extval);
11583
0
      }
11584
0
      else
11585
0
      {
11586
0
        appendStringInfo(buf, "'%s'", extval);
11587
0
        needlabel = true; /* we must attach a cast */
11588
0
      }
11589
0
      break;
11590
11591
0
    case BOOLOID:
11592
0
      if (strcmp(extval, "t") == 0)
11593
0
        appendStringInfoString(buf, "true");
11594
0
      else
11595
0
        appendStringInfoString(buf, "false");
11596
0
      break;
11597
11598
0
    default:
11599
0
      simple_quote_literal(buf, extval);
11600
0
      break;
11601
0
  }
11602
11603
0
  pfree(extval);
11604
11605
0
  if (showtype < 0)
11606
0
    return;
11607
11608
  /*
11609
   * For showtype == 0, append ::typename unless the constant will be
11610
   * implicitly typed as the right type when it is read in.
11611
   *
11612
   * XXX this code has to be kept in sync with the behavior of the parser,
11613
   * especially make_const.
11614
   */
11615
0
  switch (constval->consttype)
11616
0
  {
11617
0
    case BOOLOID:
11618
0
    case UNKNOWNOID:
11619
      /* These types can be left unlabeled */
11620
0
      needlabel = false;
11621
0
      break;
11622
0
    case INT4OID:
11623
      /* We determined above whether a label is needed */
11624
0
      break;
11625
0
    case NUMERICOID:
11626
11627
      /*
11628
       * Float-looking constants will be typed as numeric, which we
11629
       * checked above; but if there's a nondefault typmod we need to
11630
       * show it.
11631
       */
11632
0
      needlabel |= (constval->consttypmod >= 0);
11633
0
      break;
11634
0
    default:
11635
0
      needlabel = true;
11636
0
      break;
11637
0
  }
11638
0
  if (needlabel || showtype > 0)
11639
0
    appendStringInfo(buf, "::%s",
11640
0
             format_type_with_typemod(constval->consttype,
11641
0
                          constval->consttypmod));
11642
11643
0
  get_const_collation(constval, context);
11644
0
}
11645
11646
/*
11647
 * helper for get_const_expr: append COLLATE if needed
11648
 */
11649
static void
11650
get_const_collation(Const *constval, deparse_context *context)
11651
0
{
11652
0
  StringInfo  buf = context->buf;
11653
11654
0
  if (OidIsValid(constval->constcollid))
11655
0
  {
11656
0
    Oid     typcollation = get_typcollation(constval->consttype);
11657
11658
0
    if (constval->constcollid != typcollation)
11659
0
    {
11660
0
      appendStringInfo(buf, " COLLATE %s",
11661
0
               generate_collation_name(constval->constcollid));
11662
0
    }
11663
0
  }
11664
0
}
11665
11666
/*
11667
 * get_json_path_spec   - Parse back a JSON path specification
11668
 */
11669
static void
11670
get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
11671
0
{
11672
0
  if (IsA(path_spec, Const))
11673
0
    get_const_expr((Const *) path_spec, context, -1);
11674
0
  else
11675
0
    get_rule_expr(path_spec, context, showimplicit);
11676
0
}
11677
11678
/*
11679
 * get_json_format      - Parse back a JsonFormat node
11680
 */
11681
static void
11682
get_json_format(JsonFormat *format, StringInfo buf)
11683
0
{
11684
0
  if (format->format_type == JS_FORMAT_DEFAULT)
11685
0
    return;
11686
11687
0
  appendStringInfoString(buf,
11688
0
               format->format_type == JS_FORMAT_JSONB ?
11689
0
               " FORMAT JSONB" : " FORMAT JSON");
11690
11691
0
  if (format->encoding != JS_ENC_DEFAULT)
11692
0
  {
11693
0
    const char *encoding;
11694
11695
0
    encoding =
11696
0
      format->encoding == JS_ENC_UTF16 ? "UTF16" :
11697
0
      format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11698
11699
0
    appendStringInfo(buf, " ENCODING %s", encoding);
11700
0
  }
11701
0
}
11702
11703
/*
11704
 * get_json_returning   - Parse back a JsonReturning structure
11705
 */
11706
static void
11707
get_json_returning(JsonReturning *returning, StringInfo buf,
11708
           bool json_format_by_default)
11709
0
{
11710
0
  if (!OidIsValid(returning->typid))
11711
0
    return;
11712
11713
0
  appendStringInfo(buf, " RETURNING %s",
11714
0
           format_type_with_typemod(returning->typid,
11715
0
                        returning->typmod));
11716
11717
0
  if (!json_format_by_default ||
11718
0
    returning->format->format_type !=
11719
0
    (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11720
0
    get_json_format(returning->format, buf);
11721
0
}
11722
11723
/*
11724
 * get_json_constructor   - Parse back a JsonConstructorExpr node
11725
 */
11726
static void
11727
get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
11728
           bool showimplicit)
11729
0
{
11730
0
  StringInfo  buf = context->buf;
11731
0
  const char *funcname;
11732
0
  bool    is_json_object;
11733
0
  int     curridx;
11734
0
  ListCell   *lc;
11735
11736
0
  if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11737
0
  {
11738
0
    get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11739
0
    return;
11740
0
  }
11741
0
  else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11742
0
  {
11743
0
    get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11744
0
    return;
11745
0
  }
11746
0
  else if (ctor->type == JSCTOR_JSON_ARRAY_QUERY)
11747
0
  {
11748
0
    Query    *query = castNode(Query, ctor->orig_query);
11749
11750
0
    appendStringInfo(buf, "JSON_ARRAY(");
11751
11752
0
    get_query_def(query, buf, context->namespaces, NULL, false,
11753
0
            context->prettyFlags, context->wrapColumn,
11754
0
            context->indentLevel);
11755
11756
0
    get_json_format(ctor->format, buf);
11757
0
    get_json_constructor_options(ctor, buf);
11758
0
    appendStringInfoChar(buf, ')');
11759
11760
0
    return;
11761
0
  }
11762
11763
0
  switch (ctor->type)
11764
0
  {
11765
0
    case JSCTOR_JSON_OBJECT:
11766
0
      funcname = "JSON_OBJECT";
11767
0
      break;
11768
0
    case JSCTOR_JSON_ARRAY:
11769
0
      funcname = "JSON_ARRAY";
11770
0
      break;
11771
0
    case JSCTOR_JSON_PARSE:
11772
0
      funcname = "JSON";
11773
0
      break;
11774
0
    case JSCTOR_JSON_SCALAR:
11775
0
      funcname = "JSON_SCALAR";
11776
0
      break;
11777
0
    case JSCTOR_JSON_SERIALIZE:
11778
0
      funcname = "JSON_SERIALIZE";
11779
0
      break;
11780
0
    default:
11781
0
      elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11782
0
  }
11783
11784
0
  appendStringInfo(buf, "%s(", funcname);
11785
11786
0
  is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11787
0
  foreach(lc, ctor->args)
11788
0
  {
11789
0
    curridx = foreach_current_index(lc);
11790
0
    if (curridx > 0)
11791
0
    {
11792
0
      const char *sep;
11793
11794
0
      sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11795
0
      appendStringInfoString(buf, sep);
11796
0
    }
11797
11798
0
    get_rule_expr((Node *) lfirst(lc), context, true);
11799
0
  }
11800
11801
0
  get_json_constructor_options(ctor, buf);
11802
0
  appendStringInfoChar(buf, ')');
11803
0
}
11804
11805
/*
11806
 * Append options, if any, to the JSON constructor being deparsed
11807
 */
11808
static void
11809
get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
11810
0
{
11811
0
  if (ctor->absent_on_null)
11812
0
  {
11813
0
    if (ctor->type == JSCTOR_JSON_OBJECT ||
11814
0
      ctor->type == JSCTOR_JSON_OBJECTAGG)
11815
0
      appendStringInfoString(buf, " ABSENT ON NULL");
11816
0
  }
11817
0
  else
11818
0
  {
11819
0
    if (ctor->type == JSCTOR_JSON_ARRAY ||
11820
0
      ctor->type == JSCTOR_JSON_ARRAYAGG)
11821
0
      appendStringInfoString(buf, " NULL ON NULL");
11822
0
  }
11823
11824
0
  if (ctor->unique)
11825
0
    appendStringInfoString(buf, " WITH UNIQUE KEYS");
11826
11827
  /*
11828
   * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11829
   * support one.
11830
   */
11831
0
  if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11832
0
    get_json_returning(ctor->returning, buf, true);
11833
0
}
11834
11835
/*
11836
 * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
11837
 */
11838
static void
11839
get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
11840
             const char *funcname, bool is_json_objectagg)
11841
0
{
11842
0
  StringInfoData options;
11843
11844
0
  initStringInfo(&options);
11845
0
  get_json_constructor_options(ctor, &options);
11846
11847
0
  if (IsA(ctor->func, Aggref))
11848
0
    get_agg_expr_helper((Aggref *) ctor->func, context,
11849
0
              (Aggref *) ctor->func,
11850
0
              funcname, options.data, is_json_objectagg);
11851
0
  else if (IsA(ctor->func, WindowFunc))
11852
0
    get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
11853
0
                   funcname, options.data,
11854
0
                   is_json_objectagg);
11855
0
  else if (IsA(ctor->func, Var))
11856
0
  {
11857
    /*
11858
     * If the aggregate is computed by a lower plan node, setrefs.c will
11859
     * have replaced the Aggref or WindowFunc with a Var referencing that
11860
     * node's output.  Chase the Var back to it so we can still print the
11861
     * original JSON aggregate syntax.  This only happens in EXPLAIN.
11862
     */
11863
0
    resolve_special_varno((Node *) ctor->func, context,
11864
0
                get_json_agg_constructor_expr, ctor);
11865
0
  }
11866
0
  else
11867
0
    elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11868
0
       nodeTag(ctor->func));
11869
0
}
11870
11871
/*
11872
 * Deparse a JsonConstructorExpr whose aggregate is computed by a lower plan
11873
 * node; resolve_special_varno has located the underlying Aggref/WindowFunc.
11874
 */
11875
static void
11876
get_json_agg_constructor_expr(Node *node, deparse_context *context,
11877
                void *callback_arg)
11878
0
{
11879
0
  JsonConstructorExpr ctor;
11880
11881
0
  if (!IsA(node, Aggref) && !IsA(node, WindowFunc))
11882
0
    elog(ERROR, "JSON aggregate constructor does not point to an Aggref or WindowFunc");
11883
11884
  /* Flat copy suffices; we only replace func. */
11885
0
  ctor = *(JsonConstructorExpr *) callback_arg;
11886
0
  ctor.func = (Expr *) node;
11887
0
  get_json_constructor(&ctor, context, false);
11888
0
}
11889
11890
/*
11891
 * simple_quote_literal - Format a string as a SQL literal, append to buf
11892
 */
11893
static void
11894
simple_quote_literal(StringInfo buf, const char *val)
11895
{
11896
  const char *valptr;
11897
11898
  /*
11899
   * We always form the string literal according to standard SQL rules.
11900
   */
11901
  appendStringInfoChar(buf, '\'');
11902
  for (valptr = val; *valptr; valptr++)
11903
  {
11904
    char    ch = *valptr;
11905
11906
    if (SQL_STR_DOUBLE(ch, false))
11907
      appendStringInfoChar(buf, ch);
11908
    appendStringInfoChar(buf, ch);
11909
  }
11910
  appendStringInfoChar(buf, '\'');
11911
}
11912
11913
11914
/* ----------
11915
 * get_sublink_expr     - Parse back a sublink
11916
 * ----------
11917
 */
11918
static void
11919
get_sublink_expr(SubLink *sublink, deparse_context *context)
11920
0
{
11921
0
  StringInfo  buf = context->buf;
11922
0
  Query    *query = (Query *) (sublink->subselect);
11923
0
  char     *opname = NULL;
11924
0
  bool    need_paren;
11925
11926
0
  if (sublink->subLinkType == ARRAY_SUBLINK)
11927
0
    appendStringInfoString(buf, "ARRAY(");
11928
0
  else
11929
0
    appendStringInfoChar(buf, '(');
11930
11931
  /*
11932
   * Note that we print the name of only the first operator, when there are
11933
   * multiple combining operators.  This is an approximation that could go
11934
   * wrong in various scenarios (operators in different schemas, renamed
11935
   * operators, etc) but there is not a whole lot we can do about it, since
11936
   * the syntax allows only one operator to be shown.
11937
   */
11938
0
  if (sublink->testexpr)
11939
0
  {
11940
0
    if (IsA(sublink->testexpr, OpExpr))
11941
0
    {
11942
      /* single combining operator */
11943
0
      OpExpr     *opexpr = (OpExpr *) sublink->testexpr;
11944
11945
0
      get_rule_expr(linitial(opexpr->args), context, true);
11946
0
      opname = generate_operator_name(opexpr->opno,
11947
0
                      exprType(linitial(opexpr->args)),
11948
0
                      exprType(lsecond(opexpr->args)));
11949
0
    }
11950
0
    else if (IsA(sublink->testexpr, BoolExpr))
11951
0
    {
11952
      /* multiple combining operators, = or <> cases */
11953
0
      char     *sep;
11954
0
      ListCell   *l;
11955
11956
0
      appendStringInfoChar(buf, '(');
11957
0
      sep = "";
11958
0
      foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11959
0
      {
11960
0
        OpExpr     *opexpr = lfirst_node(OpExpr, l);
11961
11962
0
        appendStringInfoString(buf, sep);
11963
0
        get_rule_expr(linitial(opexpr->args), context, true);
11964
0
        if (!opname)
11965
0
          opname = generate_operator_name(opexpr->opno,
11966
0
                          exprType(linitial(opexpr->args)),
11967
0
                          exprType(lsecond(opexpr->args)));
11968
0
        sep = ", ";
11969
0
      }
11970
0
      appendStringInfoChar(buf, ')');
11971
0
    }
11972
0
    else if (IsA(sublink->testexpr, RowCompareExpr))
11973
0
    {
11974
      /* multiple combining operators, < <= > >= cases */
11975
0
      RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11976
11977
0
      appendStringInfoChar(buf, '(');
11978
0
      get_rule_expr((Node *) rcexpr->largs, context, true);
11979
0
      opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11980
0
                      exprType(linitial(rcexpr->largs)),
11981
0
                      exprType(linitial(rcexpr->rargs)));
11982
0
      appendStringInfoChar(buf, ')');
11983
0
    }
11984
0
    else
11985
0
      elog(ERROR, "unrecognized testexpr type: %d",
11986
0
         (int) nodeTag(sublink->testexpr));
11987
0
  }
11988
11989
0
  need_paren = true;
11990
11991
0
  switch (sublink->subLinkType)
11992
0
  {
11993
0
    case EXISTS_SUBLINK:
11994
0
      appendStringInfoString(buf, "EXISTS ");
11995
0
      break;
11996
11997
0
    case ANY_SUBLINK:
11998
0
      if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11999
0
        appendStringInfoString(buf, " IN ");
12000
0
      else
12001
0
        appendStringInfo(buf, " %s ANY ", opname);
12002
0
      break;
12003
12004
0
    case ALL_SUBLINK:
12005
0
      appendStringInfo(buf, " %s ALL ", opname);
12006
0
      break;
12007
12008
0
    case ROWCOMPARE_SUBLINK:
12009
0
      appendStringInfo(buf, " %s ", opname);
12010
0
      break;
12011
12012
0
    case EXPR_SUBLINK:
12013
0
    case MULTIEXPR_SUBLINK:
12014
0
    case ARRAY_SUBLINK:
12015
0
      need_paren = false;
12016
0
      break;
12017
12018
0
    case CTE_SUBLINK:   /* shouldn't occur in a SubLink */
12019
0
    default:
12020
0
      elog(ERROR, "unrecognized sublink type: %d",
12021
0
         (int) sublink->subLinkType);
12022
0
      break;
12023
0
  }
12024
12025
0
  if (need_paren)
12026
0
    appendStringInfoChar(buf, '(');
12027
12028
0
  get_query_def(query, buf, context->namespaces, NULL, false,
12029
0
          context->prettyFlags, context->wrapColumn,
12030
0
          context->indentLevel);
12031
12032
0
  if (need_paren)
12033
0
    appendStringInfoString(buf, "))");
12034
0
  else
12035
0
    appendStringInfoChar(buf, ')');
12036
0
}
12037
12038
12039
/* ----------
12040
 * get_xmltable     - Parse back a XMLTABLE function
12041
 * ----------
12042
 */
12043
static void
12044
get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
12045
0
{
12046
0
  StringInfo  buf = context->buf;
12047
12048
0
  appendStringInfoString(buf, "XMLTABLE(");
12049
12050
0
  if (tf->ns_uris != NIL)
12051
0
  {
12052
0
    ListCell   *lc1,
12053
0
           *lc2;
12054
0
    bool    first = true;
12055
12056
0
    appendStringInfoString(buf, "XMLNAMESPACES (");
12057
0
    forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
12058
0
    {
12059
0
      Node     *expr = (Node *) lfirst(lc1);
12060
0
      String     *ns_node = lfirst_node(String, lc2);
12061
12062
0
      if (!first)
12063
0
        appendStringInfoString(buf, ", ");
12064
0
      else
12065
0
        first = false;
12066
12067
0
      if (ns_node != NULL)
12068
0
      {
12069
0
        get_rule_expr(expr, context, showimplicit);
12070
0
        appendStringInfo(buf, " AS %s",
12071
0
                 quote_identifier(strVal(ns_node)));
12072
0
      }
12073
0
      else
12074
0
      {
12075
0
        appendStringInfoString(buf, "DEFAULT ");
12076
0
        get_rule_expr(expr, context, showimplicit);
12077
0
      }
12078
0
    }
12079
0
    appendStringInfoString(buf, "), ");
12080
0
  }
12081
12082
0
  appendStringInfoChar(buf, '(');
12083
0
  get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
12084
0
  appendStringInfoString(buf, ") PASSING (");
12085
0
  get_rule_expr((Node *) tf->docexpr, context, showimplicit);
12086
0
  appendStringInfoChar(buf, ')');
12087
12088
0
  if (tf->colexprs != NIL)
12089
0
  {
12090
0
    ListCell   *l1;
12091
0
    ListCell   *l2;
12092
0
    ListCell   *l3;
12093
0
    ListCell   *l4;
12094
0
    ListCell   *l5;
12095
0
    int     colnum = 0;
12096
12097
0
    appendStringInfoString(buf, " COLUMNS ");
12098
0
    forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
12099
0
        l4, tf->colexprs, l5, tf->coldefexprs)
12100
0
    {
12101
0
      char     *colname = strVal(lfirst(l1));
12102
0
      Oid     typid = lfirst_oid(l2);
12103
0
      int32   typmod = lfirst_int(l3);
12104
0
      Node     *colexpr = (Node *) lfirst(l4);
12105
0
      Node     *coldefexpr = (Node *) lfirst(l5);
12106
0
      bool    ordinality = (tf->ordinalitycol == colnum);
12107
0
      bool    notnull = bms_is_member(colnum, tf->notnulls);
12108
12109
0
      if (colnum > 0)
12110
0
        appendStringInfoString(buf, ", ");
12111
0
      colnum++;
12112
12113
0
      appendStringInfo(buf, "%s %s", quote_identifier(colname),
12114
0
               ordinality ? "FOR ORDINALITY" :
12115
0
               format_type_with_typemod(typid, typmod));
12116
0
      if (ordinality)
12117
0
        continue;
12118
12119
0
      if (coldefexpr != NULL)
12120
0
      {
12121
0
        appendStringInfoString(buf, " DEFAULT (");
12122
0
        get_rule_expr((Node *) coldefexpr, context, showimplicit);
12123
0
        appendStringInfoChar(buf, ')');
12124
0
      }
12125
0
      if (colexpr != NULL)
12126
0
      {
12127
0
        appendStringInfoString(buf, " PATH (");
12128
0
        get_rule_expr((Node *) colexpr, context, showimplicit);
12129
0
        appendStringInfoChar(buf, ')');
12130
0
      }
12131
0
      if (notnull)
12132
0
        appendStringInfoString(buf, " NOT NULL");
12133
0
    }
12134
0
  }
12135
12136
0
  appendStringInfoChar(buf, ')');
12137
0
}
12138
12139
/*
12140
 * get_json_table_nested_columns - Parse back nested JSON_TABLE columns
12141
 */
12142
static void
12143
get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
12144
                deparse_context *context, bool showimplicit,
12145
                bool needcomma)
12146
0
{
12147
0
  if (IsA(plan, JsonTablePathScan))
12148
0
  {
12149
0
    JsonTablePathScan *scan = castNode(JsonTablePathScan, plan);
12150
12151
0
    if (needcomma)
12152
0
      appendStringInfoChar(context->buf, ',');
12153
12154
0
    appendStringInfoChar(context->buf, ' ');
12155
0
    appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
12156
0
    get_const_expr(scan->path->value, context, -1);
12157
0
    appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
12158
0
    get_json_table_columns(tf, scan, context, showimplicit);
12159
0
  }
12160
0
  else if (IsA(plan, JsonTableSiblingJoin))
12161
0
  {
12162
0
    JsonTableSiblingJoin *join = (JsonTableSiblingJoin *) plan;
12163
12164
0
    get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
12165
0
                    needcomma);
12166
0
    get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
12167
0
                    true);
12168
0
  }
12169
0
}
12170
12171
/*
12172
 * json_table_plan_is_default - does this plan match the implicit default?
12173
 *
12174
 * When no PLAN clause is given, JSON_TABLE builds a default plan that joins
12175
 * every nested path to its parent with OUTER and every set of sibling paths
12176
 * with UNION (see transformJsonTableColumns()).  Such a plan is fully implied
12177
 * by the NESTED COLUMNS structure, so we need not (and, to match the input,
12178
 * should not) print a PLAN clause for it; we only deparse a PLAN clause when
12179
 * the plan deviates from the default, i.e. uses an INNER or CROSS join
12180
 * somewhere.  This follows the usual ruleutils convention of omitting a clause
12181
 * that merely restates the default (cf. get_json_expr_options() for ON
12182
 * EMPTY/ON ERROR, or the NULLS FIRST/LAST handling in get_rule_orderby()).
12183
 */
12184
static bool
12185
json_table_plan_is_default(JsonTablePlan *plan)
12186
0
{
12187
0
  if (IsA(plan, JsonTablePathScan))
12188
0
  {
12189
0
    JsonTablePathScan *scan = castNode(JsonTablePathScan, plan);
12190
12191
0
    if (scan->child)
12192
0
    {
12193
0
      if (!scan->outerJoin)
12194
0
        return false; /* INNER is not the default */
12195
0
      return json_table_plan_is_default(scan->child);
12196
0
    }
12197
12198
0
    return true;
12199
0
  }
12200
0
  else
12201
0
  {
12202
0
    JsonTableSiblingJoin *join = castNode(JsonTableSiblingJoin, plan);
12203
12204
0
    if (join->cross)
12205
0
      return false;   /* CROSS is not the default */
12206
0
    return json_table_plan_is_default(join->lplan) &&
12207
0
      json_table_plan_is_default(join->rplan);
12208
0
  }
12209
0
}
12210
12211
/*
12212
 * get_json_table_plan - Parse back a JSON_TABLE plan
12213
 */
12214
static void
12215
get_json_table_plan(TableFunc *tf, JsonTablePlan *plan, deparse_context *context,
12216
          bool parenthesize)
12217
0
{
12218
0
  if (parenthesize)
12219
0
    appendStringInfoChar(context->buf, '(');
12220
12221
0
  if (IsA(plan, JsonTablePathScan))
12222
0
  {
12223
0
    JsonTablePathScan *s = castNode(JsonTablePathScan, plan);
12224
12225
0
    appendStringInfoString(context->buf, quote_identifier(s->path->name));
12226
12227
0
    if (s->child)
12228
0
    {
12229
0
      appendStringInfoString(context->buf,
12230
0
                   s->outerJoin ? " OUTER " : " INNER ");
12231
0
      get_json_table_plan(tf, s->child, context,
12232
0
                IsA(s->child, JsonTableSiblingJoin) ||
12233
0
                castNode(JsonTablePathScan, s->child)->child);
12234
0
    }
12235
0
  }
12236
0
  else if (IsA(plan, JsonTableSiblingJoin))
12237
0
  {
12238
0
    JsonTableSiblingJoin *j = (JsonTableSiblingJoin *) plan;
12239
12240
0
    get_json_table_plan(tf, j->lplan, context,
12241
0
              IsA(j->lplan, JsonTableSiblingJoin) ||
12242
0
              castNode(JsonTablePathScan, j->lplan)->child);
12243
12244
0
    appendStringInfoString(context->buf, j->cross ? " CROSS " : " UNION ");
12245
12246
0
    get_json_table_plan(tf, j->rplan, context,
12247
0
              IsA(j->rplan, JsonTableSiblingJoin) ||
12248
0
              castNode(JsonTablePathScan, j->rplan)->child);
12249
0
  }
12250
12251
0
  if (parenthesize)
12252
0
    appendStringInfoChar(context->buf, ')');
12253
0
}
12254
12255
/*
12256
 * get_json_table_columns - Parse back JSON_TABLE columns
12257
 */
12258
static void
12259
get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan,
12260
             deparse_context *context,
12261
             bool showimplicit)
12262
0
{
12263
0
  StringInfo  buf = context->buf;
12264
0
  ListCell   *lc_colname;
12265
0
  ListCell   *lc_coltype;
12266
0
  ListCell   *lc_coltypmod;
12267
0
  ListCell   *lc_colvalexpr;
12268
0
  int     colnum = 0;
12269
12270
0
  appendStringInfoChar(buf, ' ');
12271
0
  appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
12272
12273
0
  if (PRETTY_INDENT(context))
12274
0
    context->indentLevel += PRETTYINDENT_VAR;
12275
12276
0
  forfour(lc_colname, tf->colnames,
12277
0
      lc_coltype, tf->coltypes,
12278
0
      lc_coltypmod, tf->coltypmods,
12279
0
      lc_colvalexpr, tf->colvalexprs)
12280
0
  {
12281
0
    char     *colname = strVal(lfirst(lc_colname));
12282
0
    JsonExpr   *colexpr;
12283
0
    Oid     typid;
12284
0
    int32   typmod;
12285
0
    bool    ordinality;
12286
0
    JsonBehaviorType default_behavior;
12287
12288
0
    typid = lfirst_oid(lc_coltype);
12289
0
    typmod = lfirst_int(lc_coltypmod);
12290
0
    colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
12291
12292
    /* Skip columns that don't belong to this scan. */
12293
0
    if (scan->colMin < 0 || colnum < scan->colMin)
12294
0
    {
12295
0
      colnum++;
12296
0
      continue;
12297
0
    }
12298
0
    if (colnum > scan->colMax)
12299
0
      break;
12300
12301
0
    if (colnum > scan->colMin)
12302
0
      appendStringInfoString(buf, ", ");
12303
12304
0
    colnum++;
12305
12306
0
    ordinality = !colexpr;
12307
12308
0
    appendContextKeyword(context, "", 0, 0, 0);
12309
12310
0
    appendStringInfo(buf, "%s %s", quote_identifier(colname),
12311
0
             ordinality ? "FOR ORDINALITY" :
12312
0
             format_type_with_typemod(typid, typmod));
12313
0
    if (ordinality)
12314
0
      continue;
12315
12316
    /*
12317
     * Set default_behavior to guide get_json_expr_options() on whether to
12318
     * emit the ON ERROR / EMPTY clauses.
12319
     */
12320
0
    if (colexpr->op == JSON_EXISTS_OP)
12321
0
    {
12322
0
      appendStringInfoString(buf, " EXISTS");
12323
0
      default_behavior = JSON_BEHAVIOR_FALSE;
12324
0
    }
12325
0
    else
12326
0
    {
12327
0
      if (colexpr->op == JSON_QUERY_OP)
12328
0
      {
12329
0
        char    typcategory;
12330
0
        bool    typispreferred;
12331
12332
0
        get_type_category_preferred(typid, &typcategory, &typispreferred);
12333
12334
0
        if (typcategory == TYPCATEGORY_STRING)
12335
0
          appendStringInfoString(buf,
12336
0
                       colexpr->format->format_type == JS_FORMAT_JSONB ?
12337
0
                       " FORMAT JSONB" : " FORMAT JSON");
12338
0
      }
12339
12340
0
      default_behavior = JSON_BEHAVIOR_NULL;
12341
0
    }
12342
12343
0
    appendStringInfoString(buf, " PATH ");
12344
12345
0
    get_json_path_spec(colexpr->path_spec, context, showimplicit);
12346
12347
0
    get_json_expr_options(colexpr, context, default_behavior);
12348
0
  }
12349
12350
0
  if (scan->child)
12351
0
    get_json_table_nested_columns(tf, scan->child, context, showimplicit,
12352
0
                    scan->colMin >= 0);
12353
12354
0
  if (PRETTY_INDENT(context))
12355
0
    context->indentLevel -= PRETTYINDENT_VAR;
12356
12357
0
  appendContextKeyword(context, ")", 0, 0, 0);
12358
0
}
12359
12360
/* ----------
12361
 * get_json_table     - Parse back a JSON_TABLE function
12362
 * ----------
12363
 */
12364
static void
12365
get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
12366
0
{
12367
0
  StringInfo  buf = context->buf;
12368
0
  JsonExpr   *jexpr = castNode(JsonExpr, tf->docexpr);
12369
0
  JsonTablePathScan *root = castNode(JsonTablePathScan, tf->plan);
12370
12371
0
  appendStringInfoString(buf, "JSON_TABLE(");
12372
12373
0
  if (PRETTY_INDENT(context))
12374
0
    context->indentLevel += PRETTYINDENT_VAR;
12375
12376
0
  appendContextKeyword(context, "", 0, 0, 0);
12377
12378
0
  get_rule_expr(jexpr->formatted_expr, context, showimplicit);
12379
12380
0
  appendStringInfoString(buf, ", ");
12381
12382
0
  get_const_expr(root->path->value, context, -1);
12383
12384
0
  appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
12385
12386
0
  if (jexpr->passing_values)
12387
0
  {
12388
0
    ListCell   *lc1,
12389
0
           *lc2;
12390
0
    bool    needcomma = false;
12391
12392
0
    appendStringInfoChar(buf, ' ');
12393
0
    appendContextKeyword(context, "PASSING ", 0, 0, 0);
12394
12395
0
    if (PRETTY_INDENT(context))
12396
0
      context->indentLevel += PRETTYINDENT_VAR;
12397
12398
0
    forboth(lc1, jexpr->passing_names,
12399
0
        lc2, jexpr->passing_values)
12400
0
    {
12401
0
      if (needcomma)
12402
0
        appendStringInfoString(buf, ", ");
12403
0
      needcomma = true;
12404
12405
0
      appendContextKeyword(context, "", 0, 0, 0);
12406
12407
0
      get_rule_expr((Node *) lfirst(lc2), context, false);
12408
0
      appendStringInfo(buf, " AS %s",
12409
0
               quote_identifier((lfirst_node(String, lc1))->sval)
12410
0
        );
12411
0
    }
12412
12413
0
    if (PRETTY_INDENT(context))
12414
0
      context->indentLevel -= PRETTYINDENT_VAR;
12415
0
  }
12416
12417
0
  get_json_table_columns(tf, castNode(JsonTablePathScan, tf->plan), context,
12418
0
               showimplicit);
12419
12420
  /*
12421
   * Deparse a PLAN clause only for a non-default plan; the default plan is
12422
   * implied by the NESTED COLUMNS structure (see
12423
   * json_table_plan_is_default).
12424
   */
12425
0
  if (root->child && !json_table_plan_is_default((JsonTablePlan *) root))
12426
0
  {
12427
0
    appendStringInfoChar(buf, ' ');
12428
0
    appendContextKeyword(context, "PLAN ", 0, 0, 0);
12429
0
    get_json_table_plan(tf, (JsonTablePlan *) root, context, true);
12430
0
  }
12431
12432
0
  if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY_ARRAY)
12433
0
    get_json_behavior(jexpr->on_error, context, "ERROR");
12434
12435
0
  if (PRETTY_INDENT(context))
12436
0
    context->indentLevel -= PRETTYINDENT_VAR;
12437
12438
0
  appendContextKeyword(context, ")", 0, 0, 0);
12439
0
}
12440
12441
/* ----------
12442
 * get_tablefunc      - Parse back a table function
12443
 * ----------
12444
 */
12445
static void
12446
get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
12447
0
{
12448
  /* XMLTABLE and JSON_TABLE are the only existing implementations.  */
12449
12450
0
  if (tf->functype == TFT_XMLTABLE)
12451
0
    get_xmltable(tf, context, showimplicit);
12452
0
  else if (tf->functype == TFT_JSON_TABLE)
12453
0
    get_json_table(tf, context, showimplicit);
12454
0
}
12455
12456
/* ----------
12457
 * get_from_clause      - Parse back a FROM clause
12458
 *
12459
 * "prefix" is the keyword that denotes the start of the list of FROM
12460
 * elements. It is FROM when used to parse back SELECT and UPDATE, but
12461
 * is USING when parsing back DELETE.
12462
 * ----------
12463
 */
12464
static void
12465
get_from_clause(Query *query, const char *prefix, deparse_context *context)
12466
0
{
12467
0
  StringInfo  buf = context->buf;
12468
0
  bool    first = true;
12469
0
  ListCell   *l;
12470
12471
  /*
12472
   * We use the query's jointree as a guide to what to print.  However, we
12473
   * must ignore auto-added RTEs that are marked not inFromCl. (These can
12474
   * only appear at the top level of the jointree, so it's sufficient to
12475
   * check here.)  This check also ensures we ignore the rule pseudo-RTEs
12476
   * for NEW and OLD.
12477
   */
12478
0
  foreach(l, query->jointree->fromlist)
12479
0
  {
12480
0
    Node     *jtnode = (Node *) lfirst(l);
12481
12482
0
    if (IsA(jtnode, RangeTblRef))
12483
0
    {
12484
0
      int     varno = ((RangeTblRef *) jtnode)->rtindex;
12485
0
      RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12486
12487
0
      if (!rte->inFromCl)
12488
0
        continue;
12489
0
    }
12490
12491
0
    if (first)
12492
0
    {
12493
0
      appendContextKeyword(context, prefix,
12494
0
                 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
12495
0
      first = false;
12496
12497
0
      get_from_clause_item(jtnode, query, context);
12498
0
    }
12499
0
    else
12500
0
    {
12501
0
      StringInfoData itembuf;
12502
12503
0
      appendStringInfoString(buf, ", ");
12504
12505
      /*
12506
       * Put the new FROM item's text into itembuf so we can decide
12507
       * after we've got it whether or not it needs to go on a new line.
12508
       */
12509
0
      initStringInfo(&itembuf);
12510
0
      context->buf = &itembuf;
12511
12512
0
      get_from_clause_item(jtnode, query, context);
12513
12514
      /* Restore context's output buffer */
12515
0
      context->buf = buf;
12516
12517
      /* Consider line-wrapping if enabled */
12518
0
      if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
12519
0
      {
12520
        /* Does the new item start with a new line? */
12521
0
        if (itembuf.len > 0 && itembuf.data[0] == '\n')
12522
0
        {
12523
          /* If so, we shouldn't add anything */
12524
          /* instead, remove any trailing spaces currently in buf */
12525
0
          removeStringInfoSpaces(buf);
12526
0
        }
12527
0
        else
12528
0
        {
12529
0
          char     *trailing_nl;
12530
12531
          /* Locate the start of the current line in the buffer */
12532
0
          trailing_nl = strrchr(buf->data, '\n');
12533
0
          if (trailing_nl == NULL)
12534
0
            trailing_nl = buf->data;
12535
0
          else
12536
0
            trailing_nl++;
12537
12538
          /*
12539
           * Add a newline, plus some indentation, if the new item
12540
           * would cause an overflow.
12541
           */
12542
0
          if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
12543
0
            appendContextKeyword(context, "", -PRETTYINDENT_STD,
12544
0
                       PRETTYINDENT_STD,
12545
0
                       PRETTYINDENT_VAR);
12546
0
        }
12547
0
      }
12548
12549
      /* Add the new item */
12550
0
      appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
12551
12552
      /* clean up */
12553
0
      pfree(itembuf.data);
12554
0
    }
12555
0
  }
12556
0
}
12557
12558
static void
12559
get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
12560
0
{
12561
0
  StringInfo  buf = context->buf;
12562
0
  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12563
12564
0
  if (IsA(jtnode, RangeTblRef))
12565
0
  {
12566
0
    int     varno = ((RangeTblRef *) jtnode)->rtindex;
12567
0
    RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12568
0
    deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12569
0
    RangeTblFunction *rtfunc1 = NULL;
12570
12571
0
    if (rte->lateral)
12572
0
      appendStringInfoString(buf, "LATERAL ");
12573
12574
    /* Print the FROM item proper */
12575
0
    switch (rte->rtekind)
12576
0
    {
12577
0
      case RTE_RELATION:
12578
        /* Normal relation RTE */
12579
0
        appendStringInfo(buf, "%s%s",
12580
0
                 only_marker(rte),
12581
0
                 generate_relation_name(rte->relid,
12582
0
                            context->namespaces));
12583
0
        break;
12584
0
      case RTE_SUBQUERY:
12585
        /* Subquery RTE */
12586
0
        appendStringInfoChar(buf, '(');
12587
0
        get_query_def(rte->subquery, buf, context->namespaces, NULL,
12588
0
                true,
12589
0
                context->prettyFlags, context->wrapColumn,
12590
0
                context->indentLevel);
12591
0
        appendStringInfoChar(buf, ')');
12592
0
        break;
12593
0
      case RTE_FUNCTION:
12594
        /* Function RTE */
12595
0
        rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
12596
12597
        /*
12598
         * Omit ROWS FROM() syntax for just one function, unless it
12599
         * has both a coldeflist and WITH ORDINALITY. If it has both,
12600
         * we must use ROWS FROM() syntax to avoid ambiguity about
12601
         * whether the coldeflist includes the ordinality column.
12602
         */
12603
0
        if (list_length(rte->functions) == 1 &&
12604
0
          (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12605
0
        {
12606
0
          get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12607
          /* we'll print the coldeflist below, if it has one */
12608
0
        }
12609
0
        else
12610
0
        {
12611
0
          bool    all_unnest;
12612
0
          ListCell   *lc;
12613
12614
          /*
12615
           * If all the function calls in the list are to unnest,
12616
           * and none need a coldeflist, then collapse the list back
12617
           * down to UNNEST(args).  (If we had more than one
12618
           * built-in unnest function, this would get more
12619
           * difficult.)
12620
           *
12621
           * XXX This is pretty ugly, since it makes not-terribly-
12622
           * future-proof assumptions about what the parser would do
12623
           * with the output; but the alternative is to emit our
12624
           * nonstandard ROWS FROM() notation for what might have
12625
           * been a perfectly spec-compliant multi-argument
12626
           * UNNEST().
12627
           */
12628
0
          all_unnest = true;
12629
0
          foreach(lc, rte->functions)
12630
0
          {
12631
0
            RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12632
12633
0
            if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12634
0
              ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12635
0
              rtfunc->funccolnames != NIL)
12636
0
            {
12637
0
              all_unnest = false;
12638
0
              break;
12639
0
            }
12640
0
          }
12641
12642
0
          if (all_unnest)
12643
0
          {
12644
0
            List     *allargs = NIL;
12645
12646
0
            foreach(lc, rte->functions)
12647
0
            {
12648
0
              RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12649
0
              List     *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12650
12651
0
              allargs = list_concat(allargs, args);
12652
0
            }
12653
12654
0
            appendStringInfoString(buf, "UNNEST(");
12655
0
            get_rule_expr((Node *) allargs, context, true);
12656
0
            appendStringInfoChar(buf, ')');
12657
0
          }
12658
0
          else
12659
0
          {
12660
0
            int     funcno = 0;
12661
12662
0
            appendStringInfoString(buf, "ROWS FROM(");
12663
0
            foreach(lc, rte->functions)
12664
0
            {
12665
0
              RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12666
12667
0
              if (funcno > 0)
12668
0
                appendStringInfoString(buf, ", ");
12669
0
              get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12670
0
              if (rtfunc->funccolnames != NIL)
12671
0
              {
12672
                /* Reconstruct the column definition list */
12673
0
                appendStringInfoString(buf, " AS ");
12674
0
                get_from_clause_coldeflist(rtfunc,
12675
0
                               NULL,
12676
0
                               context);
12677
0
              }
12678
0
              funcno++;
12679
0
            }
12680
0
            appendStringInfoChar(buf, ')');
12681
0
          }
12682
          /* prevent printing duplicate coldeflist below */
12683
0
          rtfunc1 = NULL;
12684
0
        }
12685
0
        if (rte->funcordinality)
12686
0
          appendStringInfoString(buf, " WITH ORDINALITY");
12687
0
        break;
12688
0
      case RTE_TABLEFUNC:
12689
0
        get_tablefunc(rte->tablefunc, context, true);
12690
0
        break;
12691
0
      case RTE_VALUES:
12692
        /* Values list RTE */
12693
0
        appendStringInfoChar(buf, '(');
12694
0
        get_values_def(rte->values_lists, context);
12695
0
        appendStringInfoChar(buf, ')');
12696
0
        break;
12697
0
      case RTE_CTE:
12698
0
        appendStringInfoString(buf, quote_identifier(rte->ctename));
12699
0
        break;
12700
0
      default:
12701
0
        elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12702
0
        break;
12703
0
    }
12704
12705
    /* Print the relation alias, if needed */
12706
0
    get_rte_alias(rte, varno, false, context);
12707
12708
    /* Print the column definitions or aliases, if needed */
12709
0
    if (rtfunc1 && rtfunc1->funccolnames != NIL)
12710
0
    {
12711
      /* Reconstruct the columndef list, which is also the aliases */
12712
0
      get_from_clause_coldeflist(rtfunc1, colinfo, context);
12713
0
    }
12714
0
    else
12715
0
    {
12716
      /* Else print column aliases as needed */
12717
0
      get_column_alias_list(colinfo, context);
12718
0
    }
12719
12720
    /* Tablesample clause must go after any alias */
12721
0
    if (rte->rtekind == RTE_RELATION && rte->tablesample)
12722
0
      get_tablesample_def(rte->tablesample, context);
12723
0
  }
12724
0
  else if (IsA(jtnode, JoinExpr))
12725
0
  {
12726
0
    JoinExpr   *j = (JoinExpr *) jtnode;
12727
0
    deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12728
0
    bool    need_paren_on_right;
12729
12730
0
    need_paren_on_right = PRETTY_PAREN(context) &&
12731
0
      !IsA(j->rarg, RangeTblRef) &&
12732
0
      !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12733
12734
0
    if (!PRETTY_PAREN(context) || j->alias != NULL)
12735
0
      appendStringInfoChar(buf, '(');
12736
12737
0
    get_from_clause_item(j->larg, query, context);
12738
12739
0
    switch (j->jointype)
12740
0
    {
12741
0
      case JOIN_INNER:
12742
0
        if (j->quals)
12743
0
          appendContextKeyword(context, " JOIN ",
12744
0
                     -PRETTYINDENT_STD,
12745
0
                     PRETTYINDENT_STD,
12746
0
                     PRETTYINDENT_JOIN);
12747
0
        else
12748
0
          appendContextKeyword(context, " CROSS JOIN ",
12749
0
                     -PRETTYINDENT_STD,
12750
0
                     PRETTYINDENT_STD,
12751
0
                     PRETTYINDENT_JOIN);
12752
0
        break;
12753
0
      case JOIN_LEFT:
12754
0
        appendContextKeyword(context, " LEFT JOIN ",
12755
0
                   -PRETTYINDENT_STD,
12756
0
                   PRETTYINDENT_STD,
12757
0
                   PRETTYINDENT_JOIN);
12758
0
        break;
12759
0
      case JOIN_FULL:
12760
0
        appendContextKeyword(context, " FULL JOIN ",
12761
0
                   -PRETTYINDENT_STD,
12762
0
                   PRETTYINDENT_STD,
12763
0
                   PRETTYINDENT_JOIN);
12764
0
        break;
12765
0
      case JOIN_RIGHT:
12766
0
        appendContextKeyword(context, " RIGHT JOIN ",
12767
0
                   -PRETTYINDENT_STD,
12768
0
                   PRETTYINDENT_STD,
12769
0
                   PRETTYINDENT_JOIN);
12770
0
        break;
12771
0
      default:
12772
0
        elog(ERROR, "unrecognized join type: %d",
12773
0
           (int) j->jointype);
12774
0
    }
12775
12776
0
    if (need_paren_on_right)
12777
0
      appendStringInfoChar(buf, '(');
12778
0
    get_from_clause_item(j->rarg, query, context);
12779
0
    if (need_paren_on_right)
12780
0
      appendStringInfoChar(buf, ')');
12781
12782
0
    if (j->usingClause)
12783
0
    {
12784
0
      ListCell   *lc;
12785
0
      bool    first = true;
12786
12787
0
      appendStringInfoString(buf, " USING (");
12788
      /* Use the assigned names, not what's in usingClause */
12789
0
      foreach(lc, colinfo->usingNames)
12790
0
      {
12791
0
        char     *colname = (char *) lfirst(lc);
12792
12793
0
        if (first)
12794
0
          first = false;
12795
0
        else
12796
0
          appendStringInfoString(buf, ", ");
12797
0
        appendStringInfoString(buf, quote_identifier(colname));
12798
0
      }
12799
0
      appendStringInfoChar(buf, ')');
12800
12801
0
      if (j->join_using_alias)
12802
0
        appendStringInfo(buf, " AS %s",
12803
0
                 quote_identifier(j->join_using_alias->aliasname));
12804
0
    }
12805
0
    else if (j->quals)
12806
0
    {
12807
0
      appendStringInfoString(buf, " ON ");
12808
0
      if (!PRETTY_PAREN(context))
12809
0
        appendStringInfoChar(buf, '(');
12810
0
      get_rule_expr(j->quals, context, false);
12811
0
      if (!PRETTY_PAREN(context))
12812
0
        appendStringInfoChar(buf, ')');
12813
0
    }
12814
0
    else if (j->jointype != JOIN_INNER)
12815
0
    {
12816
      /* If we didn't say CROSS JOIN above, we must provide an ON */
12817
0
      appendStringInfoString(buf, " ON TRUE");
12818
0
    }
12819
12820
0
    if (!PRETTY_PAREN(context) || j->alias != NULL)
12821
0
      appendStringInfoChar(buf, ')');
12822
12823
    /* Yes, it's correct to put alias after the right paren ... */
12824
0
    if (j->alias != NULL)
12825
0
    {
12826
      /*
12827
       * Note that it's correct to emit an alias clause if and only if
12828
       * there was one originally.  Otherwise we'd be converting a named
12829
       * join to unnamed or vice versa, which creates semantic
12830
       * subtleties we don't want.  However, we might print a different
12831
       * alias name than was there originally.
12832
       */
12833
0
      appendStringInfo(buf, " %s",
12834
0
               quote_identifier(get_rtable_name(j->rtindex,
12835
0
                                context)));
12836
0
      get_column_alias_list(colinfo, context);
12837
0
    }
12838
0
  }
12839
0
  else
12840
0
    elog(ERROR, "unrecognized node type: %d",
12841
0
       (int) nodeTag(jtnode));
12842
0
}
12843
12844
/*
12845
 * get_rte_alias - print the relation's alias, if needed
12846
 *
12847
 * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
12848
 */
12849
static void
12850
get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
12851
        deparse_context *context)
12852
0
{
12853
0
  deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12854
0
  char     *refname = get_rtable_name(varno, context);
12855
0
  deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12856
0
  bool    printalias = false;
12857
12858
0
  if (rte->alias != NULL)
12859
0
  {
12860
    /* Always print alias if user provided one */
12861
0
    printalias = true;
12862
0
  }
12863
0
  else if (colinfo->printaliases)
12864
0
  {
12865
    /* Always print alias if we need to print column aliases */
12866
0
    printalias = true;
12867
0
  }
12868
0
  else if (rte->rtekind == RTE_RELATION)
12869
0
  {
12870
    /*
12871
     * No need to print alias if it's same as relation name (this would
12872
     * normally be the case, but not if set_rtable_names had to resolve a
12873
     * conflict).
12874
     */
12875
0
    if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12876
0
      printalias = true;
12877
0
  }
12878
0
  else if (rte->rtekind == RTE_FUNCTION)
12879
0
  {
12880
    /*
12881
     * For a function RTE, always print alias.  This covers possible
12882
     * renaming of the function and/or instability of the FigureColname
12883
     * rules for things that aren't simple functions.  Note we'd need to
12884
     * force it anyway for the columndef list case.
12885
     */
12886
0
    printalias = true;
12887
0
  }
12888
0
  else if (rte->rtekind == RTE_SUBQUERY ||
12889
0
       rte->rtekind == RTE_VALUES)
12890
0
  {
12891
    /*
12892
     * For a subquery, always print alias.  This makes the output
12893
     * SQL-spec-compliant, even though we allow such aliases to be omitted
12894
     * on input.
12895
     */
12896
0
    printalias = true;
12897
0
  }
12898
0
  else if (rte->rtekind == RTE_CTE)
12899
0
  {
12900
    /*
12901
     * No need to print alias if it's same as CTE name (this would
12902
     * normally be the case, but not if set_rtable_names had to resolve a
12903
     * conflict).
12904
     */
12905
0
    if (strcmp(refname, rte->ctename) != 0)
12906
0
      printalias = true;
12907
0
  }
12908
12909
0
  if (printalias)
12910
0
    appendStringInfo(context->buf, "%s%s",
12911
0
             use_as ? " AS " : " ",
12912
0
             quote_identifier(refname));
12913
0
}
12914
12915
/*
12916
 * get_column_alias_list - print column alias list for an RTE
12917
 *
12918
 * Caller must already have printed the relation's alias name.
12919
 */
12920
static void
12921
get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
12922
0
{
12923
0
  StringInfo  buf = context->buf;
12924
0
  int     i;
12925
0
  bool    first = true;
12926
12927
  /* Don't print aliases if not needed */
12928
0
  if (!colinfo->printaliases)
12929
0
    return;
12930
12931
0
  for (i = 0; i < colinfo->num_new_cols; i++)
12932
0
  {
12933
0
    char     *colname = colinfo->new_colnames[i];
12934
12935
0
    if (first)
12936
0
    {
12937
0
      appendStringInfoChar(buf, '(');
12938
0
      first = false;
12939
0
    }
12940
0
    else
12941
0
      appendStringInfoString(buf, ", ");
12942
0
    appendStringInfoString(buf, quote_identifier(colname));
12943
0
  }
12944
0
  if (!first)
12945
0
    appendStringInfoChar(buf, ')');
12946
0
}
12947
12948
/*
12949
 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
12950
 *
12951
 * When printing a top-level coldeflist (which is syntactically also the
12952
 * relation's column alias list), use column names from colinfo.  But when
12953
 * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
12954
 * original coldeflist's names, which are available in rtfunc->funccolnames.
12955
 * Pass NULL for colinfo to select the latter behavior.
12956
 *
12957
 * The coldeflist is appended immediately (no space) to buf.  Caller is
12958
 * responsible for ensuring that an alias or AS is present before it.
12959
 */
12960
static void
12961
get_from_clause_coldeflist(RangeTblFunction *rtfunc,
12962
               deparse_columns *colinfo,
12963
               deparse_context *context)
12964
0
{
12965
0
  StringInfo  buf = context->buf;
12966
0
  ListCell   *l1;
12967
0
  ListCell   *l2;
12968
0
  ListCell   *l3;
12969
0
  ListCell   *l4;
12970
0
  int     i;
12971
12972
0
  appendStringInfoChar(buf, '(');
12973
12974
0
  i = 0;
12975
0
  forfour(l1, rtfunc->funccoltypes,
12976
0
      l2, rtfunc->funccoltypmods,
12977
0
      l3, rtfunc->funccolcollations,
12978
0
      l4, rtfunc->funccolnames)
12979
0
  {
12980
0
    Oid     atttypid = lfirst_oid(l1);
12981
0
    int32   atttypmod = lfirst_int(l2);
12982
0
    Oid     attcollation = lfirst_oid(l3);
12983
0
    char     *attname;
12984
12985
0
    if (colinfo)
12986
0
      attname = colinfo->colnames[i];
12987
0
    else
12988
0
      attname = strVal(lfirst(l4));
12989
12990
0
    Assert(attname);    /* shouldn't be any dropped columns here */
12991
12992
0
    if (i > 0)
12993
0
      appendStringInfoString(buf, ", ");
12994
0
    appendStringInfo(buf, "%s %s",
12995
0
             quote_identifier(attname),
12996
0
             format_type_with_typemod(atttypid, atttypmod));
12997
0
    if (OidIsValid(attcollation) &&
12998
0
      attcollation != get_typcollation(atttypid))
12999
0
      appendStringInfo(buf, " COLLATE %s",
13000
0
               generate_collation_name(attcollation));
13001
13002
0
    i++;
13003
0
  }
13004
13005
0
  appendStringInfoChar(buf, ')');
13006
0
}
13007
13008
/*
13009
 * get_tablesample_def      - print a TableSampleClause
13010
 */
13011
static void
13012
get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
13013
0
{
13014
0
  StringInfo  buf = context->buf;
13015
0
  Oid     argtypes[1];
13016
0
  int     nargs;
13017
0
  ListCell   *l;
13018
13019
  /*
13020
   * We should qualify the handler's function name if it wouldn't be
13021
   * resolved by lookup in the current search path.
13022
   */
13023
0
  argtypes[0] = INTERNALOID;
13024
0
  appendStringInfo(buf, " TABLESAMPLE %s (",
13025
0
           generate_function_name(tablesample->tsmhandler, 1,
13026
0
                      NIL, argtypes,
13027
0
                      false, NULL, false));
13028
13029
0
  nargs = 0;
13030
0
  foreach(l, tablesample->args)
13031
0
  {
13032
0
    if (nargs++ > 0)
13033
0
      appendStringInfoString(buf, ", ");
13034
0
    get_rule_expr((Node *) lfirst(l), context, false);
13035
0
  }
13036
0
  appendStringInfoChar(buf, ')');
13037
13038
0
  if (tablesample->repeatable != NULL)
13039
0
  {
13040
0
    appendStringInfoString(buf, " REPEATABLE (");
13041
0
    get_rule_expr((Node *) tablesample->repeatable, context, false);
13042
0
    appendStringInfoChar(buf, ')');
13043
0
  }
13044
0
}
13045
13046
/*
13047
 * get_opclass_name     - fetch name of an index operator class
13048
 *
13049
 * The opclass name is appended (after a space) to buf.
13050
 *
13051
 * Output is suppressed if the opclass is the default for the given
13052
 * actual_datatype.  (If you don't want this behavior, just pass
13053
 * InvalidOid for actual_datatype.)
13054
 */
13055
static void
13056
get_opclass_name(Oid opclass, Oid actual_datatype,
13057
         StringInfo buf)
13058
0
{
13059
0
  HeapTuple ht_opc;
13060
0
  Form_pg_opclass opcrec;
13061
0
  char     *opcname;
13062
0
  char     *nspname;
13063
13064
0
  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
13065
0
  if (!HeapTupleIsValid(ht_opc))
13066
0
    elog(ERROR, "cache lookup failed for opclass %u", opclass);
13067
0
  opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
13068
13069
0
  if (!OidIsValid(actual_datatype) ||
13070
0
    GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
13071
0
  {
13072
    /* Okay, we need the opclass name.  Do we need to qualify it? */
13073
0
    opcname = NameStr(opcrec->opcname);
13074
0
    if (OpclassIsVisible(opclass))
13075
0
      appendStringInfo(buf, " %s", quote_identifier(opcname));
13076
0
    else
13077
0
    {
13078
0
      nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
13079
0
      appendStringInfo(buf, " %s.%s",
13080
0
               quote_identifier(nspname),
13081
0
               quote_identifier(opcname));
13082
0
    }
13083
0
  }
13084
0
  ReleaseSysCache(ht_opc);
13085
0
}
13086
13087
/*
13088
 * generate_opclass_name
13089
 *    Compute the name to display for an opclass specified by OID
13090
 *
13091
 * The result includes all necessary quoting and schema-prefixing.
13092
 */
13093
char *
13094
generate_opclass_name(Oid opclass)
13095
0
{
13096
0
  StringInfoData buf;
13097
13098
0
  initStringInfo(&buf);
13099
0
  get_opclass_name(opclass, InvalidOid, &buf);
13100
13101
0
  return &buf.data[1];    /* get_opclass_name() prepends space */
13102
0
}
13103
13104
/*
13105
 * processIndirection - take care of array and subfield assignment
13106
 *
13107
 * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
13108
 * appear in the input, printing them as decoration for the base column
13109
 * name (which we assume the caller just printed).  We might also need to
13110
 * strip CoerceToDomain nodes, but only ones that appear above assignment
13111
 * nodes.
13112
 *
13113
 * Returns the subexpression that's to be assigned.
13114
 */
13115
static Node *
13116
processIndirection(Node *node, deparse_context *context)
13117
0
{
13118
0
  StringInfo  buf = context->buf;
13119
0
  CoerceToDomain *cdomain = NULL;
13120
13121
0
  for (;;)
13122
0
  {
13123
0
    if (node == NULL)
13124
0
      break;
13125
0
    if (IsA(node, FieldStore))
13126
0
    {
13127
0
      FieldStore *fstore = (FieldStore *) node;
13128
0
      Oid     typrelid;
13129
0
      char     *fieldname;
13130
13131
      /* lookup tuple type */
13132
0
      typrelid = get_typ_typrelid(fstore->resulttype);
13133
0
      if (!OidIsValid(typrelid))
13134
0
        elog(ERROR, "argument type %s of FieldStore is not a tuple type",
13135
0
           format_type_be(fstore->resulttype));
13136
13137
      /*
13138
       * Print the field name.  There should only be one target field in
13139
       * stored rules.  There could be more than that in executable
13140
       * target lists, but this function cannot be used for that case.
13141
       */
13142
0
      Assert(list_length(fstore->fieldnums) == 1);
13143
0
      fieldname = get_attname(typrelid,
13144
0
                  linitial_int(fstore->fieldnums), false);
13145
0
      appendStringInfo(buf, ".%s", quote_identifier(fieldname));
13146
13147
      /*
13148
       * We ignore arg since it should be an uninteresting reference to
13149
       * the target column or subcolumn.
13150
       */
13151
0
      node = (Node *) linitial(fstore->newvals);
13152
0
    }
13153
0
    else if (IsA(node, SubscriptingRef))
13154
0
    {
13155
0
      SubscriptingRef *sbsref = (SubscriptingRef *) node;
13156
13157
0
      if (sbsref->refassgnexpr == NULL)
13158
0
        break;
13159
13160
0
      printSubscripts(sbsref, context);
13161
13162
      /*
13163
       * We ignore refexpr since it should be an uninteresting reference
13164
       * to the target column or subcolumn.
13165
       */
13166
0
      node = (Node *) sbsref->refassgnexpr;
13167
0
    }
13168
0
    else if (IsA(node, CoerceToDomain))
13169
0
    {
13170
0
      cdomain = (CoerceToDomain *) node;
13171
      /* If it's an explicit domain coercion, we're done */
13172
0
      if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
13173
0
        break;
13174
      /* Tentatively descend past the CoerceToDomain */
13175
0
      node = (Node *) cdomain->arg;
13176
0
    }
13177
0
    else
13178
0
      break;
13179
0
  }
13180
13181
  /*
13182
   * If we descended past a CoerceToDomain whose argument turned out not to
13183
   * be a FieldStore or array assignment, back up to the CoerceToDomain.
13184
   * (This is not enough to be fully correct if there are nested implicit
13185
   * CoerceToDomains, but such cases shouldn't ever occur.)
13186
   */
13187
0
  if (cdomain && node == (Node *) cdomain->arg)
13188
0
    node = (Node *) cdomain;
13189
13190
0
  return node;
13191
0
}
13192
13193
static void
13194
printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
13195
0
{
13196
0
  StringInfo  buf = context->buf;
13197
0
  ListCell   *lowlist_item;
13198
0
  ListCell   *uplist_item;
13199
13200
0
  lowlist_item = list_head(sbsref->reflowerindexpr);  /* could be NULL */
13201
0
  foreach(uplist_item, sbsref->refupperindexpr)
13202
0
  {
13203
0
    appendStringInfoChar(buf, '[');
13204
0
    if (lowlist_item)
13205
0
    {
13206
      /* If subexpression is NULL, get_rule_expr prints nothing */
13207
0
      get_rule_expr((Node *) lfirst(lowlist_item), context, false);
13208
0
      appendStringInfoChar(buf, ':');
13209
0
      lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
13210
0
    }
13211
    /* If subexpression is NULL, get_rule_expr prints nothing */
13212
0
    get_rule_expr((Node *) lfirst(uplist_item), context, false);
13213
0
    appendStringInfoChar(buf, ']');
13214
0
  }
13215
0
}
13216
13217
/*
13218
 * quote_identifier     - Quote an identifier only if needed
13219
 *
13220
 * When quotes are needed, we palloc the required space; slightly
13221
 * space-wasteful but well worth it for notational simplicity.
13222
 */
13223
const char *
13224
quote_identifier(const char *ident)
13225
0
{
13226
  /*
13227
   * Can avoid quoting if ident starts with a lowercase letter or underscore
13228
   * and contains only lowercase letters, digits, and underscores, *and* is
13229
   * not any SQL keyword.  Otherwise, supply quotes.
13230
   */
13231
0
  int     nquotes = 0;
13232
0
  bool    safe;
13233
0
  const char *ptr;
13234
0
  char     *result;
13235
0
  char     *optr;
13236
13237
  /*
13238
   * would like to use <ctype.h> macros here, but they might yield unwanted
13239
   * locale-specific results...
13240
   */
13241
0
  safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
13242
13243
0
  for (ptr = ident; *ptr; ptr++)
13244
0
  {
13245
0
    char    ch = *ptr;
13246
13247
0
    if ((ch >= 'a' && ch <= 'z') ||
13248
0
      (ch >= '0' && ch <= '9') ||
13249
0
      (ch == '_'))
13250
0
    {
13251
      /* okay */
13252
0
    }
13253
0
    else
13254
0
    {
13255
0
      safe = false;
13256
0
      if (ch == '"')
13257
0
        nquotes++;
13258
0
    }
13259
0
  }
13260
13261
0
  if (quote_all_identifiers)
13262
0
    safe = false;
13263
13264
0
  if (safe)
13265
0
  {
13266
    /*
13267
     * Check for keyword.  We quote keywords except for unreserved ones.
13268
     * (In some cases we could avoid quoting a col_name or type_func_name
13269
     * keyword, but it seems much harder than it's worth to tell that.)
13270
     *
13271
     * Note: ScanKeywordLookup() does case-insensitive comparison, but
13272
     * that's fine, since we already know we have all-lower-case.
13273
     */
13274
0
    int     kwnum = ScanKeywordLookup(ident, &ScanKeywords);
13275
13276
0
    if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
13277
0
      safe = false;
13278
0
  }
13279
13280
0
  if (safe)
13281
0
    return ident;     /* no change needed */
13282
13283
0
  result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
13284
13285
0
  optr = result;
13286
0
  *optr++ = '"';
13287
0
  for (ptr = ident; *ptr; ptr++)
13288
0
  {
13289
0
    char    ch = *ptr;
13290
13291
0
    if (ch == '"')
13292
0
      *optr++ = '"';
13293
0
    *optr++ = ch;
13294
0
  }
13295
0
  *optr++ = '"';
13296
0
  *optr = '\0';
13297
13298
0
  return result;
13299
0
}
13300
13301
/*
13302
 * quote_qualified_identifier - Quote a possibly-qualified identifier
13303
 *
13304
 * Return a name of the form qualifier.ident, or just ident if qualifier
13305
 * is NULL, quoting each component if necessary.  The result is palloc'd.
13306
 */
13307
char *
13308
quote_qualified_identifier(const char *qualifier,
13309
               const char *ident)
13310
0
{
13311
0
  StringInfoData buf;
13312
13313
0
  initStringInfo(&buf);
13314
0
  if (qualifier)
13315
0
    appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
13316
0
  appendStringInfoString(&buf, quote_identifier(ident));
13317
0
  return buf.data;
13318
0
}
13319
13320
/*
13321
 * get_relation_name
13322
 *    Get the unqualified name of a relation specified by OID
13323
 *
13324
 * This differs from the underlying get_rel_name() function in that it will
13325
 * throw error instead of silently returning NULL if the OID is bad.
13326
 */
13327
static char *
13328
get_relation_name(Oid relid)
13329
0
{
13330
0
  char     *relname = get_rel_name(relid);
13331
13332
0
  if (!relname)
13333
0
    elog(ERROR, "cache lookup failed for relation %u", relid);
13334
0
  return relname;
13335
0
}
13336
13337
/*
13338
 * generate_relation_name
13339
 *    Compute the name to display for a relation specified by OID
13340
 *
13341
 * The result includes all necessary quoting and schema-prefixing.
13342
 *
13343
 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
13344
 * We will forcibly qualify the relation name if it equals any CTE name
13345
 * visible in the namespace list.
13346
 */
13347
static char *
13348
generate_relation_name(Oid relid, List *namespaces)
13349
0
{
13350
0
  HeapTuple tp;
13351
0
  Form_pg_class reltup;
13352
0
  bool    need_qual;
13353
0
  ListCell   *nslist;
13354
0
  char     *relname;
13355
0
  char     *nspname;
13356
0
  char     *result;
13357
13358
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13359
0
  if (!HeapTupleIsValid(tp))
13360
0
    elog(ERROR, "cache lookup failed for relation %u", relid);
13361
0
  reltup = (Form_pg_class) GETSTRUCT(tp);
13362
0
  relname = NameStr(reltup->relname);
13363
13364
  /* Check for conflicting CTE name */
13365
0
  need_qual = false;
13366
0
  foreach(nslist, namespaces)
13367
0
  {
13368
0
    deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
13369
0
    ListCell   *ctlist;
13370
13371
0
    foreach(ctlist, dpns->ctes)
13372
0
    {
13373
0
      CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
13374
13375
0
      if (strcmp(cte->ctename, relname) == 0)
13376
0
      {
13377
0
        need_qual = true;
13378
0
        break;
13379
0
      }
13380
0
    }
13381
0
    if (need_qual)
13382
0
      break;
13383
0
  }
13384
13385
  /* Otherwise, qualify the name if not visible in search path */
13386
0
  if (!need_qual)
13387
0
    need_qual = !RelationIsVisible(relid);
13388
13389
0
  if (need_qual)
13390
0
    nspname = get_namespace_name_or_temp(reltup->relnamespace);
13391
0
  else
13392
0
    nspname = NULL;
13393
13394
0
  result = quote_qualified_identifier(nspname, relname);
13395
13396
0
  ReleaseSysCache(tp);
13397
13398
0
  return result;
13399
0
}
13400
13401
/*
13402
 * generate_qualified_relation_name
13403
 *    Compute the name to display for a relation specified by OID
13404
 *
13405
 * As above, but unconditionally schema-qualify the name.
13406
 */
13407
static char *
13408
generate_qualified_relation_name(Oid relid)
13409
0
{
13410
0
  HeapTuple tp;
13411
0
  Form_pg_class reltup;
13412
0
  char     *result;
13413
13414
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13415
0
  if (!HeapTupleIsValid(tp))
13416
0
    elog(ERROR, "cache lookup failed for relation %u", relid);
13417
0
  reltup = (Form_pg_class) GETSTRUCT(tp);
13418
13419
0
  result = get_qualified_objname(reltup->relnamespace,
13420
0
                   NameStr(reltup->relname));
13421
0
  ReleaseSysCache(tp);
13422
13423
0
  return result;
13424
0
}
13425
13426
/*
13427
 * generate_function_name
13428
 *    Compute the name to display for a function specified by OID,
13429
 *    given that it is being called with the specified actual arg names and
13430
 *    types.  (Those matter because of ambiguous-function resolution rules.)
13431
 *
13432
 * If we're dealing with a potentially variadic function (in practice, this
13433
 * means a FuncExpr or Aggref, not some other way of calling a function), then
13434
 * has_variadic must specify whether variadic arguments have been merged,
13435
 * and *use_variadic_p will be set to indicate whether to print VARIADIC in
13436
 * the output.  For non-FuncExpr cases, has_variadic should be false and
13437
 * use_variadic_p can be NULL.
13438
 *
13439
 * inGroupBy must be true if we're deparsing a GROUP BY clause.
13440
 *
13441
 * The result includes all necessary quoting and schema-prefixing.
13442
 */
13443
static char *
13444
generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
13445
             bool has_variadic, bool *use_variadic_p,
13446
             bool inGroupBy)
13447
0
{
13448
0
  char     *result;
13449
0
  HeapTuple proctup;
13450
0
  Form_pg_proc procform;
13451
0
  char     *proname;
13452
0
  bool    use_variadic;
13453
0
  char     *nspname;
13454
0
  FuncDetailCode p_result;
13455
0
  int     fgc_flags;
13456
0
  Oid     p_funcid;
13457
0
  Oid     p_rettype;
13458
0
  bool    p_retset;
13459
0
  int     p_nvargs;
13460
0
  Oid     p_vatype;
13461
0
  Oid      *p_true_typeids;
13462
0
  bool    force_qualify = false;
13463
13464
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
13465
0
  if (!HeapTupleIsValid(proctup))
13466
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
13467
0
  procform = (Form_pg_proc) GETSTRUCT(proctup);
13468
0
  proname = NameStr(procform->proname);
13469
13470
  /*
13471
   * Due to parser hacks to avoid needing to reserve CUBE, we need to force
13472
   * qualification of some function names within GROUP BY.
13473
   */
13474
0
  if (inGroupBy)
13475
0
  {
13476
0
    if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
13477
0
      force_qualify = true;
13478
0
  }
13479
13480
  /*
13481
   * Determine whether VARIADIC should be printed.  We must do this first
13482
   * since it affects the lookup rules in func_get_detail().
13483
   *
13484
   * We always print VARIADIC if the function has a merged variadic-array
13485
   * argument.  Note that this is always the case for functions taking a
13486
   * VARIADIC argument type other than VARIADIC ANY.  If we omitted VARIADIC
13487
   * and printed the array elements as separate arguments, the call could
13488
   * match a newer non-VARIADIC function.
13489
   */
13490
0
  if (use_variadic_p)
13491
0
  {
13492
    /* Parser should not have set funcvariadic unless fn is variadic */
13493
0
    Assert(!has_variadic || OidIsValid(procform->provariadic));
13494
0
    use_variadic = has_variadic;
13495
0
    *use_variadic_p = use_variadic;
13496
0
  }
13497
0
  else
13498
0
  {
13499
0
    Assert(!has_variadic);
13500
0
    use_variadic = false;
13501
0
  }
13502
13503
  /*
13504
   * The idea here is to schema-qualify only if the parser would fail to
13505
   * resolve the correct function given the unqualified func name with the
13506
   * specified argtypes and VARIADIC flag.  But if we already decided to
13507
   * force qualification, then we can skip the lookup and pretend we didn't
13508
   * find it.
13509
   */
13510
0
  if (!force_qualify)
13511
0
    p_result = func_get_detail(list_make1(makeString(proname)),
13512
0
                   NIL, argnames, nargs, argtypes,
13513
0
                   !use_variadic, true, false,
13514
0
                   &fgc_flags,
13515
0
                   &p_funcid, &p_rettype,
13516
0
                   &p_retset, &p_nvargs, &p_vatype,
13517
0
                   &p_true_typeids, NULL);
13518
0
  else
13519
0
  {
13520
0
    p_result = FUNCDETAIL_NOTFOUND;
13521
0
    p_funcid = InvalidOid;
13522
0
  }
13523
13524
0
  if ((p_result == FUNCDETAIL_NORMAL ||
13525
0
     p_result == FUNCDETAIL_AGGREGATE ||
13526
0
     p_result == FUNCDETAIL_WINDOWFUNC) &&
13527
0
    p_funcid == funcid)
13528
0
    nspname = NULL;
13529
0
  else
13530
0
    nspname = get_namespace_name_or_temp(procform->pronamespace);
13531
13532
0
  result = quote_qualified_identifier(nspname, proname);
13533
13534
0
  ReleaseSysCache(proctup);
13535
13536
0
  return result;
13537
0
}
13538
13539
/*
13540
 * generate_operator_name
13541
 *    Compute the name to display for an operator specified by OID,
13542
 *    given that it is being called with the specified actual arg types.
13543
 *    (Arg types matter because of ambiguous-operator resolution rules.
13544
 *    Pass InvalidOid for unused arg of a unary operator.)
13545
 *
13546
 * The result includes all necessary quoting and schema-prefixing,
13547
 * plus the OPERATOR() decoration needed to use a qualified operator name
13548
 * in an expression.
13549
 */
13550
static char *
13551
generate_operator_name(Oid operid, Oid arg1, Oid arg2)
13552
0
{
13553
0
  StringInfoData buf;
13554
0
  HeapTuple opertup;
13555
0
  Form_pg_operator operform;
13556
0
  char     *oprname;
13557
0
  char     *nspname;
13558
0
  Operator  p_result;
13559
13560
0
  initStringInfo(&buf);
13561
13562
0
  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
13563
0
  if (!HeapTupleIsValid(opertup))
13564
0
    elog(ERROR, "cache lookup failed for operator %u", operid);
13565
0
  operform = (Form_pg_operator) GETSTRUCT(opertup);
13566
0
  oprname = NameStr(operform->oprname);
13567
13568
  /*
13569
   * The idea here is to schema-qualify only if the parser would fail to
13570
   * resolve the correct operator given the unqualified op name with the
13571
   * specified argtypes.
13572
   */
13573
0
  switch (operform->oprkind)
13574
0
  {
13575
0
    case 'b':
13576
0
      p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
13577
0
              true, -1);
13578
0
      break;
13579
0
    case 'l':
13580
0
      p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
13581
0
                 true, -1);
13582
0
      break;
13583
0
    default:
13584
0
      elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
13585
0
      p_result = NULL; /* keep compiler quiet */
13586
0
      break;
13587
0
  }
13588
13589
0
  if (p_result != NULL && oprid(p_result) == operid)
13590
0
    nspname = NULL;
13591
0
  else
13592
0
  {
13593
0
    nspname = get_namespace_name_or_temp(operform->oprnamespace);
13594
0
    appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
13595
0
  }
13596
13597
0
  appendStringInfoString(&buf, oprname);
13598
13599
0
  if (nspname)
13600
0
    appendStringInfoChar(&buf, ')');
13601
13602
0
  if (p_result != NULL)
13603
0
    ReleaseSysCache(p_result);
13604
13605
0
  ReleaseSysCache(opertup);
13606
13607
0
  return buf.data;
13608
0
}
13609
13610
/*
13611
 * generate_operator_clause --- generate a binary-operator WHERE clause
13612
 *
13613
 * This is used for internally-generated-and-executed SQL queries, where
13614
 * precision is essential and readability is secondary.  The basic
13615
 * requirement is to append "leftop op rightop" to buf, where leftop and
13616
 * rightop are given as strings and are assumed to yield types leftoptype
13617
 * and rightoptype; the operator is identified by OID.  The complexity
13618
 * comes from needing to be sure that the parser will select the desired
13619
 * operator when the query is parsed.  We always name the operator using
13620
 * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
13621
 * We have to emit casts too, if either input isn't already the input type
13622
 * of the operator; else we are at the mercy of the parser's heuristics for
13623
 * ambiguous-operator resolution.  The caller must ensure that leftop and
13624
 * rightop are suitable arguments for a cast operation; it's best to insert
13625
 * parentheses if they aren't just variables or parameters.
13626
 */
13627
void
13628
generate_operator_clause(StringInfo buf,
13629
             const char *leftop, Oid leftoptype,
13630
             Oid opoid,
13631
             const char *rightop, Oid rightoptype)
13632
0
{
13633
0
  HeapTuple opertup;
13634
0
  Form_pg_operator operform;
13635
0
  char     *oprname;
13636
0
  char     *nspname;
13637
13638
0
  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13639
0
  if (!HeapTupleIsValid(opertup))
13640
0
    elog(ERROR, "cache lookup failed for operator %u", opoid);
13641
0
  operform = (Form_pg_operator) GETSTRUCT(opertup);
13642
0
  Assert(operform->oprkind == 'b');
13643
0
  oprname = NameStr(operform->oprname);
13644
13645
0
  nspname = get_namespace_name(operform->oprnamespace);
13646
13647
0
  appendStringInfoString(buf, leftop);
13648
0
  if (leftoptype != operform->oprleft)
13649
0
    add_cast_to(buf, operform->oprleft);
13650
0
  appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13651
0
  appendStringInfoString(buf, oprname);
13652
0
  appendStringInfo(buf, ") %s", rightop);
13653
0
  if (rightoptype != operform->oprright)
13654
0
    add_cast_to(buf, operform->oprright);
13655
13656
0
  ReleaseSysCache(opertup);
13657
0
}
13658
13659
/*
13660
 * Add a cast specification to buf.  We spell out the type name the hard way,
13661
 * intentionally not using format_type_be().  This is to avoid corner cases
13662
 * for CHARACTER, BIT, and perhaps other types, where specifying the type
13663
 * using SQL-standard syntax results in undesirable data truncation.  By
13664
 * doing it this way we can be certain that the cast will have default (-1)
13665
 * target typmod.
13666
 */
13667
static void
13668
add_cast_to(StringInfo buf, Oid typid)
13669
0
{
13670
0
  HeapTuple typetup;
13671
0
  Form_pg_type typform;
13672
0
  char     *typname;
13673
0
  char     *nspname;
13674
13675
0
  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13676
0
  if (!HeapTupleIsValid(typetup))
13677
0
    elog(ERROR, "cache lookup failed for type %u", typid);
13678
0
  typform = (Form_pg_type) GETSTRUCT(typetup);
13679
13680
0
  typname = NameStr(typform->typname);
13681
0
  nspname = get_namespace_name_or_temp(typform->typnamespace);
13682
13683
0
  appendStringInfo(buf, "::%s.%s",
13684
0
           quote_identifier(nspname), quote_identifier(typname));
13685
13686
0
  ReleaseSysCache(typetup);
13687
0
}
13688
13689
/*
13690
 * generate_qualified_type_name
13691
 *    Compute the name to display for a type specified by OID
13692
 *
13693
 * This is different from format_type_be() in that we unconditionally
13694
 * schema-qualify the name.  That also means no special syntax for
13695
 * SQL-standard type names ... although in current usage, this should
13696
 * only get used for domains, so such cases wouldn't occur anyway.
13697
 */
13698
static char *
13699
generate_qualified_type_name(Oid typid)
13700
0
{
13701
0
  HeapTuple tp;
13702
0
  Form_pg_type typtup;
13703
0
  char     *typname;
13704
0
  char     *nspname;
13705
0
  char     *result;
13706
13707
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13708
0
  if (!HeapTupleIsValid(tp))
13709
0
    elog(ERROR, "cache lookup failed for type %u", typid);
13710
0
  typtup = (Form_pg_type) GETSTRUCT(tp);
13711
0
  typname = NameStr(typtup->typname);
13712
13713
0
  nspname = get_namespace_name_or_temp(typtup->typnamespace);
13714
0
  if (!nspname)
13715
0
    elog(ERROR, "cache lookup failed for namespace %u",
13716
0
       typtup->typnamespace);
13717
13718
0
  result = quote_qualified_identifier(nspname, typname);
13719
13720
0
  ReleaseSysCache(tp);
13721
13722
0
  return result;
13723
0
}
13724
13725
/*
13726
 * generate_collation_name
13727
 *    Compute the name to display for a collation specified by OID
13728
 *
13729
 * The result includes all necessary quoting and schema-prefixing.
13730
 */
13731
char *
13732
generate_collation_name(Oid collid)
13733
0
{
13734
0
  HeapTuple tp;
13735
0
  Form_pg_collation colltup;
13736
0
  char     *collname;
13737
0
  char     *nspname;
13738
0
  char     *result;
13739
13740
0
  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13741
0
  if (!HeapTupleIsValid(tp))
13742
0
    elog(ERROR, "cache lookup failed for collation %u", collid);
13743
0
  colltup = (Form_pg_collation) GETSTRUCT(tp);
13744
0
  collname = NameStr(colltup->collname);
13745
13746
0
  if (!CollationIsVisible(collid))
13747
0
    nspname = get_namespace_name_or_temp(colltup->collnamespace);
13748
0
  else
13749
0
    nspname = NULL;
13750
13751
0
  result = quote_qualified_identifier(nspname, collname);
13752
13753
0
  ReleaseSysCache(tp);
13754
13755
0
  return result;
13756
0
}
13757
13758
/*
13759
 * Given a C string, produce a TEXT datum.
13760
 *
13761
 * We assume that the input was palloc'd and may be freed.
13762
 */
13763
static text *
13764
string_to_text(char *str)
13765
0
{
13766
0
  text     *result;
13767
13768
0
  result = cstring_to_text(str);
13769
0
  pfree(str);
13770
0
  return result;
13771
0
}
13772
13773
/*
13774
 * Generate a C string representing a relation options from text[] datum.
13775
 */
13776
void
13777
get_reloptions(StringInfo buf, Datum reloptions)
13778
0
{
13779
0
  Datum    *options;
13780
0
  int     noptions;
13781
0
  int     i;
13782
13783
0
  deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13784
0
                &options, NULL, &noptions);
13785
13786
0
  for (i = 0; i < noptions; i++)
13787
0
  {
13788
0
    char     *option = TextDatumGetCString(options[i]);
13789
0
    char     *name;
13790
0
    char     *separator;
13791
0
    char     *value;
13792
13793
    /*
13794
     * Each array element should have the form name=value.  If the "=" is
13795
     * missing for some reason, treat it like an empty value.
13796
     */
13797
0
    name = option;
13798
0
    separator = strchr(option, '=');
13799
0
    if (separator)
13800
0
    {
13801
0
      *separator = '\0';
13802
0
      value = separator + 1;
13803
0
    }
13804
0
    else
13805
0
      value = "";
13806
13807
0
    if (i > 0)
13808
0
      appendStringInfoString(buf, ", ");
13809
0
    appendStringInfo(buf, "%s=", quote_identifier(name));
13810
13811
    /*
13812
     * In general we need to quote the value; but to avoid unnecessary
13813
     * clutter, do not quote if it is an identifier that would not need
13814
     * quoting.  (We could also allow numbers, but that is a bit trickier
13815
     * than it looks --- for example, are leading zeroes significant?  We
13816
     * don't want to assume very much here about what custom reloptions
13817
     * might mean.)
13818
     */
13819
0
    if (quote_identifier(value) == value)
13820
0
      appendStringInfoString(buf, value);
13821
0
    else
13822
0
      simple_quote_literal(buf, value);
13823
13824
0
    pfree(option);
13825
0
  }
13826
0
}
13827
13828
/*
13829
 * Generate a C string representing a relation's reloptions, or NULL if none.
13830
 */
13831
static char *
13832
flatten_reloptions(Oid relid)
13833
0
{
13834
0
  char     *result = NULL;
13835
0
  HeapTuple tuple;
13836
0
  Datum   reloptions;
13837
0
  bool    isnull;
13838
13839
0
  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13840
0
  if (!HeapTupleIsValid(tuple))
13841
0
    elog(ERROR, "cache lookup failed for relation %u", relid);
13842
13843
0
  reloptions = SysCacheGetAttr(RELOID, tuple,
13844
0
                 Anum_pg_class_reloptions, &isnull);
13845
0
  if (!isnull)
13846
0
  {
13847
0
    StringInfoData buf;
13848
13849
0
    initStringInfo(&buf);
13850
0
    get_reloptions(&buf, reloptions);
13851
13852
0
    result = buf.data;
13853
0
  }
13854
13855
0
  ReleaseSysCache(tuple);
13856
13857
0
  return result;
13858
0
}
13859
13860
/*
13861
 * get_range_partbound_string
13862
 *    A C string representation of one range partition bound
13863
 */
13864
char *
13865
get_range_partbound_string(List *bound_datums)
13866
0
{
13867
0
  deparse_context context;
13868
0
  StringInfoData buf;
13869
0
  ListCell   *cell;
13870
0
  char     *sep;
13871
13872
0
  initStringInfo(&buf);
13873
0
  memset(&context, 0, sizeof(deparse_context));
13874
0
  context.buf = &buf;
13875
13876
0
  appendStringInfoChar(&buf, '(');
13877
0
  sep = "";
13878
0
  foreach(cell, bound_datums)
13879
0
  {
13880
0
    PartitionRangeDatum *datum =
13881
0
      lfirst_node(PartitionRangeDatum, cell);
13882
13883
0
    appendStringInfoString(&buf, sep);
13884
0
    if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
13885
0
      appendStringInfoString(&buf, "MINVALUE");
13886
0
    else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13887
0
      appendStringInfoString(&buf, "MAXVALUE");
13888
0
    else
13889
0
    {
13890
0
      Const    *val = castNode(Const, datum->value);
13891
13892
0
      get_const_expr(val, &context, -1);
13893
0
    }
13894
0
    sep = ", ";
13895
0
  }
13896
0
  appendStringInfoChar(&buf, ')');
13897
13898
0
  return buf.data;
13899
0
}