Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * ruleutils.c
4 : * Functions to convert stored expressions/querytrees back to
5 : * source text
6 : *
7 : * Portions Copyright (c) 1996-2025, 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 : #define PRETTYINDENT_STD 8
82 : #define PRETTYINDENT_JOIN 4
83 : #define PRETTYINDENT_VAR 4
84 :
85 : #define PRETTYINDENT_LIMIT 40 /* wrap limit */
86 :
87 : /* Pretty flags */
88 : #define PRETTYFLAG_PAREN 0x0001
89 : #define PRETTYFLAG_INDENT 0x0002
90 : #define PRETTYFLAG_SCHEMA 0x0004
91 :
92 : /* Standard conversion of a "bool pretty" option to detailed flags */
93 : #define GET_PRETTY_FLAGS(pretty) \
94 : ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
95 : : PRETTYFLAG_INDENT)
96 :
97 : /* Default line length for pretty-print wrapping: 0 means wrap always */
98 : #define WRAP_COLUMN_DEFAULT 0
99 :
100 : /* macros to test if pretty action needed */
101 : #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
102 : #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 : ((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 void get_basic_select_query(Query *query, deparse_context *context);
430 : static void get_target_list(List *targetList, deparse_context *context);
431 : static void get_returning_clause(Query *query, deparse_context *context);
432 : static void get_setop_query(Node *setOp, Query *query,
433 : deparse_context *context);
434 : static Node *get_rule_sortgroupclause(Index ref, List *tlist,
435 : bool force_colno,
436 : deparse_context *context);
437 : static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
438 : bool omit_parens, deparse_context *context);
439 : static void get_rule_orderby(List *orderList, List *targetList,
440 : bool force_colno, deparse_context *context);
441 : static void get_rule_windowclause(Query *query, deparse_context *context);
442 : static void get_rule_windowspec(WindowClause *wc, List *targetList,
443 : deparse_context *context);
444 : static void get_window_frame_options(int frameOptions,
445 : Node *startOffset, Node *endOffset,
446 : deparse_context *context);
447 : static char *get_variable(Var *var, int levelsup, bool istoplevel,
448 : deparse_context *context);
449 : static void get_special_variable(Node *node, deparse_context *context,
450 : void *callback_arg);
451 : static void resolve_special_varno(Node *node, deparse_context *context,
452 : rsv_callback callback, void *callback_arg);
453 : static Node *find_param_referent(Param *param, deparse_context *context,
454 : deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
455 : static SubPlan *find_param_generator(Param *param, deparse_context *context,
456 : int *column_p);
457 : static SubPlan *find_param_generator_initplan(Param *param, Plan *plan,
458 : int *column_p);
459 : static void get_parameter(Param *param, deparse_context *context);
460 : static const char *get_simple_binary_op_name(OpExpr *expr);
461 : static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
462 : static void appendContextKeyword(deparse_context *context, const char *str,
463 : int indentBefore, int indentAfter, int indentPlus);
464 : static void removeStringInfoSpaces(StringInfo str);
465 : static void get_rule_expr(Node *node, deparse_context *context,
466 : bool showimplicit);
467 : static void get_rule_expr_toplevel(Node *node, deparse_context *context,
468 : bool showimplicit);
469 : static void get_rule_list_toplevel(List *lst, deparse_context *context,
470 : bool showimplicit);
471 : static void get_rule_expr_funccall(Node *node, deparse_context *context,
472 : bool showimplicit);
473 : static bool looks_like_function(Node *node);
474 : static void get_oper_expr(OpExpr *expr, deparse_context *context);
475 : static void get_func_expr(FuncExpr *expr, deparse_context *context,
476 : bool showimplicit);
477 : static void get_agg_expr(Aggref *aggref, deparse_context *context,
478 : Aggref *original_aggref);
479 : static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
480 : Aggref *original_aggref, const char *funcname,
481 : const char *options, bool is_json_objectagg);
482 : static void get_agg_combine_expr(Node *node, deparse_context *context,
483 : void *callback_arg);
484 : static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
485 : static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
486 : const char *funcname, const char *options,
487 : bool is_json_objectagg);
488 : static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
489 : static void get_coercion_expr(Node *arg, deparse_context *context,
490 : Oid resulttype, int32 resulttypmod,
491 : Node *parentNode);
492 : static void get_const_expr(Const *constval, deparse_context *context,
493 : int showtype);
494 : static void get_const_collation(Const *constval, deparse_context *context);
495 : static void get_json_format(JsonFormat *format, StringInfo buf);
496 : static void get_json_returning(JsonReturning *returning, StringInfo buf,
497 : bool json_format_by_default);
498 : static void get_json_constructor(JsonConstructorExpr *ctor,
499 : deparse_context *context, bool showimplicit);
500 : static void get_json_constructor_options(JsonConstructorExpr *ctor,
501 : StringInfo buf);
502 : static void get_json_agg_constructor(JsonConstructorExpr *ctor,
503 : deparse_context *context,
504 : const char *funcname,
505 : bool is_json_objectagg);
506 : static void simple_quote_literal(StringInfo buf, const char *val);
507 : static void get_sublink_expr(SubLink *sublink, deparse_context *context);
508 : static void get_tablefunc(TableFunc *tf, deparse_context *context,
509 : bool showimplicit);
510 : static void get_from_clause(Query *query, const char *prefix,
511 : deparse_context *context);
512 : static void get_from_clause_item(Node *jtnode, Query *query,
513 : deparse_context *context);
514 : static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
515 : deparse_context *context);
516 : static void get_column_alias_list(deparse_columns *colinfo,
517 : deparse_context *context);
518 : static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
519 : deparse_columns *colinfo,
520 : deparse_context *context);
521 : static void get_tablesample_def(TableSampleClause *tablesample,
522 : deparse_context *context);
523 : static void get_opclass_name(Oid opclass, Oid actual_datatype,
524 : StringInfo buf);
525 : static Node *processIndirection(Node *node, deparse_context *context);
526 : static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
527 : static char *get_relation_name(Oid relid);
528 : static char *generate_relation_name(Oid relid, List *namespaces);
529 : static char *generate_qualified_relation_name(Oid relid);
530 : static char *generate_function_name(Oid funcid, int nargs,
531 : List *argnames, Oid *argtypes,
532 : bool has_variadic, bool *use_variadic_p,
533 : bool inGroupBy);
534 : static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
535 : static void add_cast_to(StringInfo buf, Oid typid);
536 : static char *generate_qualified_type_name(Oid typid);
537 : static text *string_to_text(char *str);
538 : static char *flatten_reloptions(Oid relid);
539 : static void get_reloptions(StringInfo buf, Datum reloptions);
540 : static void get_json_path_spec(Node *path_spec, deparse_context *context,
541 : bool showimplicit);
542 : static void get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan,
543 : deparse_context *context,
544 : bool showimplicit);
545 : static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
546 : deparse_context *context,
547 : bool showimplicit,
548 : bool needcomma);
549 :
550 : #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
551 :
552 :
553 : /* ----------
554 : * pg_get_ruledef - Do it all and return a text
555 : * that could be used as a statement
556 : * to recreate the rule
557 : * ----------
558 : */
559 : Datum
560 450 : pg_get_ruledef(PG_FUNCTION_ARGS)
561 : {
562 450 : Oid ruleoid = PG_GETARG_OID(0);
563 : int prettyFlags;
564 : char *res;
565 :
566 450 : prettyFlags = PRETTYFLAG_INDENT;
567 :
568 450 : res = pg_get_ruledef_worker(ruleoid, prettyFlags);
569 :
570 450 : if (res == NULL)
571 6 : PG_RETURN_NULL();
572 :
573 444 : PG_RETURN_TEXT_P(string_to_text(res));
574 : }
575 :
576 :
577 : Datum
578 114 : pg_get_ruledef_ext(PG_FUNCTION_ARGS)
579 : {
580 114 : Oid ruleoid = PG_GETARG_OID(0);
581 114 : bool pretty = PG_GETARG_BOOL(1);
582 : int prettyFlags;
583 : char *res;
584 :
585 114 : prettyFlags = GET_PRETTY_FLAGS(pretty);
586 :
587 114 : res = pg_get_ruledef_worker(ruleoid, prettyFlags);
588 :
589 114 : if (res == NULL)
590 0 : PG_RETURN_NULL();
591 :
592 114 : PG_RETURN_TEXT_P(string_to_text(res));
593 : }
594 :
595 :
596 : static char *
597 564 : pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
598 : {
599 : Datum args[1];
600 : char nulls[1];
601 : int spirc;
602 : HeapTuple ruletup;
603 : TupleDesc rulettc;
604 : StringInfoData buf;
605 :
606 : /*
607 : * Do this first so that string is alloc'd in outer context not SPI's.
608 : */
609 564 : initStringInfo(&buf);
610 :
611 : /*
612 : * Connect to SPI manager
613 : */
614 564 : SPI_connect();
615 :
616 : /*
617 : * On the first call prepare the plan to lookup pg_rewrite. We read
618 : * pg_rewrite over the SPI manager instead of using the syscache to be
619 : * checked for read access on pg_rewrite.
620 : */
621 564 : if (plan_getrulebyoid == NULL)
622 : {
623 : Oid argtypes[1];
624 : SPIPlanPtr plan;
625 :
626 40 : argtypes[0] = OIDOID;
627 40 : plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
628 40 : if (plan == NULL)
629 0 : elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
630 40 : SPI_keepplan(plan);
631 40 : plan_getrulebyoid = plan;
632 : }
633 :
634 : /*
635 : * Get the pg_rewrite tuple for this rule
636 : */
637 564 : args[0] = ObjectIdGetDatum(ruleoid);
638 564 : nulls[0] = ' ';
639 564 : spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
640 564 : if (spirc != SPI_OK_SELECT)
641 0 : elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
642 564 : if (SPI_processed != 1)
643 : {
644 : /*
645 : * There is no tuple data available here, just keep the output buffer
646 : * empty.
647 : */
648 : }
649 : else
650 : {
651 : /*
652 : * Get the rule's definition and put it into executor's memory
653 : */
654 558 : ruletup = SPI_tuptable->vals[0];
655 558 : rulettc = SPI_tuptable->tupdesc;
656 558 : make_ruledef(&buf, ruletup, rulettc, prettyFlags);
657 : }
658 :
659 : /*
660 : * Disconnect from SPI manager
661 : */
662 564 : if (SPI_finish() != SPI_OK_FINISH)
663 0 : elog(ERROR, "SPI_finish failed");
664 :
665 564 : if (buf.len == 0)
666 6 : return NULL;
667 :
668 558 : return buf.data;
669 : }
670 :
671 :
672 : /* ----------
673 : * pg_get_viewdef - Mainly the same thing, but we
674 : * only return the SELECT part of a view
675 : * ----------
676 : */
677 : Datum
678 2638 : pg_get_viewdef(PG_FUNCTION_ARGS)
679 : {
680 : /* By OID */
681 2638 : Oid viewoid = PG_GETARG_OID(0);
682 : int prettyFlags;
683 : char *res;
684 :
685 2638 : prettyFlags = PRETTYFLAG_INDENT;
686 :
687 2638 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
688 :
689 2638 : if (res == NULL)
690 6 : PG_RETURN_NULL();
691 :
692 2632 : PG_RETURN_TEXT_P(string_to_text(res));
693 : }
694 :
695 :
696 : Datum
697 562 : pg_get_viewdef_ext(PG_FUNCTION_ARGS)
698 : {
699 : /* By OID */
700 562 : Oid viewoid = PG_GETARG_OID(0);
701 562 : bool pretty = PG_GETARG_BOOL(1);
702 : int prettyFlags;
703 : char *res;
704 :
705 562 : prettyFlags = GET_PRETTY_FLAGS(pretty);
706 :
707 562 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
708 :
709 562 : if (res == NULL)
710 0 : PG_RETURN_NULL();
711 :
712 562 : PG_RETURN_TEXT_P(string_to_text(res));
713 : }
714 :
715 : Datum
716 6 : pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
717 : {
718 : /* By OID */
719 6 : Oid viewoid = PG_GETARG_OID(0);
720 6 : int wrap = PG_GETARG_INT32(1);
721 : int prettyFlags;
722 : char *res;
723 :
724 : /* calling this implies we want pretty printing */
725 6 : prettyFlags = GET_PRETTY_FLAGS(true);
726 :
727 6 : res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
728 :
729 6 : if (res == NULL)
730 0 : PG_RETURN_NULL();
731 :
732 6 : PG_RETURN_TEXT_P(string_to_text(res));
733 : }
734 :
735 : Datum
736 72 : pg_get_viewdef_name(PG_FUNCTION_ARGS)
737 : {
738 : /* By qualified name */
739 72 : text *viewname = PG_GETARG_TEXT_PP(0);
740 : int prettyFlags;
741 : RangeVar *viewrel;
742 : Oid viewoid;
743 : char *res;
744 :
745 72 : prettyFlags = PRETTYFLAG_INDENT;
746 :
747 : /* Look up view name. Can't lock it - we might not have privileges. */
748 72 : viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
749 72 : viewoid = RangeVarGetRelid(viewrel, NoLock, false);
750 :
751 72 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
752 :
753 72 : if (res == NULL)
754 0 : PG_RETURN_NULL();
755 :
756 72 : PG_RETURN_TEXT_P(string_to_text(res));
757 : }
758 :
759 :
760 : Datum
761 402 : pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
762 : {
763 : /* By qualified name */
764 402 : text *viewname = PG_GETARG_TEXT_PP(0);
765 402 : bool pretty = PG_GETARG_BOOL(1);
766 : int prettyFlags;
767 : RangeVar *viewrel;
768 : Oid viewoid;
769 : char *res;
770 :
771 402 : prettyFlags = GET_PRETTY_FLAGS(pretty);
772 :
773 : /* Look up view name. Can't lock it - we might not have privileges. */
774 402 : viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
775 402 : viewoid = RangeVarGetRelid(viewrel, NoLock, false);
776 :
777 402 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
778 :
779 402 : if (res == NULL)
780 0 : PG_RETURN_NULL();
781 :
782 402 : PG_RETURN_TEXT_P(string_to_text(res));
783 : }
784 :
785 : /*
786 : * Common code for by-OID and by-name variants of pg_get_viewdef
787 : */
788 : static char *
789 3680 : pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
790 : {
791 : Datum args[2];
792 : char nulls[2];
793 : int spirc;
794 : HeapTuple ruletup;
795 : TupleDesc rulettc;
796 : StringInfoData buf;
797 :
798 : /*
799 : * Do this first so that string is alloc'd in outer context not SPI's.
800 : */
801 3680 : initStringInfo(&buf);
802 :
803 : /*
804 : * Connect to SPI manager
805 : */
806 3680 : SPI_connect();
807 :
808 : /*
809 : * On the first call prepare the plan to lookup pg_rewrite. We read
810 : * pg_rewrite over the SPI manager instead of using the syscache to be
811 : * checked for read access on pg_rewrite.
812 : */
813 3680 : if (plan_getviewrule == NULL)
814 : {
815 : Oid argtypes[2];
816 : SPIPlanPtr plan;
817 :
818 244 : argtypes[0] = OIDOID;
819 244 : argtypes[1] = NAMEOID;
820 244 : plan = SPI_prepare(query_getviewrule, 2, argtypes);
821 244 : if (plan == NULL)
822 0 : elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
823 244 : SPI_keepplan(plan);
824 244 : plan_getviewrule = plan;
825 : }
826 :
827 : /*
828 : * Get the pg_rewrite tuple for the view's SELECT rule
829 : */
830 3680 : args[0] = ObjectIdGetDatum(viewoid);
831 3680 : args[1] = DirectFunctionCall1(namein, CStringGetDatum(ViewSelectRuleName));
832 3680 : nulls[0] = ' ';
833 3680 : nulls[1] = ' ';
834 3680 : spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
835 3680 : if (spirc != SPI_OK_SELECT)
836 0 : elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
837 3680 : if (SPI_processed != 1)
838 : {
839 : /*
840 : * There is no tuple data available here, just keep the output buffer
841 : * empty.
842 : */
843 : }
844 : else
845 : {
846 : /*
847 : * Get the rule's definition and put it into executor's memory
848 : */
849 3674 : ruletup = SPI_tuptable->vals[0];
850 3674 : rulettc = SPI_tuptable->tupdesc;
851 3674 : make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
852 : }
853 :
854 : /*
855 : * Disconnect from SPI manager
856 : */
857 3680 : if (SPI_finish() != SPI_OK_FINISH)
858 0 : elog(ERROR, "SPI_finish failed");
859 :
860 3680 : if (buf.len == 0)
861 6 : return NULL;
862 :
863 3674 : return buf.data;
864 : }
865 :
866 : /* ----------
867 : * pg_get_triggerdef - Get the definition of a trigger
868 : * ----------
869 : */
870 : Datum
871 164 : pg_get_triggerdef(PG_FUNCTION_ARGS)
872 : {
873 164 : Oid trigid = PG_GETARG_OID(0);
874 : char *res;
875 :
876 164 : res = pg_get_triggerdef_worker(trigid, false);
877 :
878 164 : if (res == NULL)
879 6 : PG_RETURN_NULL();
880 :
881 158 : PG_RETURN_TEXT_P(string_to_text(res));
882 : }
883 :
884 : Datum
885 1250 : pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
886 : {
887 1250 : Oid trigid = PG_GETARG_OID(0);
888 1250 : bool pretty = PG_GETARG_BOOL(1);
889 : char *res;
890 :
891 1250 : res = pg_get_triggerdef_worker(trigid, pretty);
892 :
893 1250 : if (res == NULL)
894 0 : PG_RETURN_NULL();
895 :
896 1250 : PG_RETURN_TEXT_P(string_to_text(res));
897 : }
898 :
899 : static char *
900 1414 : pg_get_triggerdef_worker(Oid trigid, bool pretty)
901 : {
902 : HeapTuple ht_trig;
903 : Form_pg_trigger trigrec;
904 : StringInfoData buf;
905 : Relation tgrel;
906 : ScanKeyData skey[1];
907 : SysScanDesc tgscan;
908 1414 : int findx = 0;
909 : char *tgname;
910 : char *tgoldtable;
911 : char *tgnewtable;
912 : Datum value;
913 : bool isnull;
914 :
915 : /*
916 : * Fetch the pg_trigger tuple by the Oid of the trigger
917 : */
918 1414 : tgrel = table_open(TriggerRelationId, AccessShareLock);
919 :
920 1414 : ScanKeyInit(&skey[0],
921 : Anum_pg_trigger_oid,
922 : BTEqualStrategyNumber, F_OIDEQ,
923 : ObjectIdGetDatum(trigid));
924 :
925 1414 : tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
926 : NULL, 1, skey);
927 :
928 1414 : ht_trig = systable_getnext(tgscan);
929 :
930 1414 : if (!HeapTupleIsValid(ht_trig))
931 : {
932 6 : systable_endscan(tgscan);
933 6 : table_close(tgrel, AccessShareLock);
934 6 : return NULL;
935 : }
936 :
937 1408 : trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
938 :
939 : /*
940 : * Start the trigger definition. Note that the trigger's name should never
941 : * be schema-qualified, but the trigger rel's name may be.
942 : */
943 1408 : initStringInfo(&buf);
944 :
945 1408 : tgname = NameStr(trigrec->tgname);
946 2816 : appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
947 1408 : OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
948 : quote_identifier(tgname));
949 :
950 1408 : if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
951 506 : appendStringInfoString(&buf, "BEFORE");
952 902 : else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
953 878 : appendStringInfoString(&buf, "AFTER");
954 24 : else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
955 24 : appendStringInfoString(&buf, "INSTEAD OF");
956 : else
957 0 : elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
958 :
959 1408 : if (TRIGGER_FOR_INSERT(trigrec->tgtype))
960 : {
961 990 : appendStringInfoString(&buf, " INSERT");
962 990 : findx++;
963 : }
964 1408 : if (TRIGGER_FOR_DELETE(trigrec->tgtype))
965 : {
966 210 : if (findx > 0)
967 90 : appendStringInfoString(&buf, " OR DELETE");
968 : else
969 120 : appendStringInfoString(&buf, " DELETE");
970 210 : findx++;
971 : }
972 1408 : if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
973 : {
974 648 : if (findx > 0)
975 350 : appendStringInfoString(&buf, " OR UPDATE");
976 : else
977 298 : appendStringInfoString(&buf, " UPDATE");
978 648 : findx++;
979 : /* tgattr is first var-width field, so OK to access directly */
980 648 : if (trigrec->tgattr.dim1 > 0)
981 : {
982 : int i;
983 :
984 76 : appendStringInfoString(&buf, " OF ");
985 168 : for (i = 0; i < trigrec->tgattr.dim1; i++)
986 : {
987 : char *attname;
988 :
989 92 : if (i > 0)
990 16 : appendStringInfoString(&buf, ", ");
991 92 : attname = get_attname(trigrec->tgrelid,
992 92 : trigrec->tgattr.values[i], false);
993 92 : appendStringInfoString(&buf, quote_identifier(attname));
994 : }
995 : }
996 : }
997 1408 : if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
998 : {
999 0 : if (findx > 0)
1000 0 : appendStringInfoString(&buf, " OR TRUNCATE");
1001 : else
1002 0 : appendStringInfoString(&buf, " TRUNCATE");
1003 0 : findx++;
1004 : }
1005 :
1006 : /*
1007 : * In non-pretty mode, always schema-qualify the target table name for
1008 : * safety. In pretty mode, schema-qualify only if not visible.
1009 : */
1010 2816 : appendStringInfo(&buf, " ON %s ",
1011 : pretty ?
1012 138 : generate_relation_name(trigrec->tgrelid, NIL) :
1013 1270 : generate_qualified_relation_name(trigrec->tgrelid));
1014 :
1015 1408 : if (OidIsValid(trigrec->tgconstraint))
1016 : {
1017 0 : if (OidIsValid(trigrec->tgconstrrelid))
1018 0 : appendStringInfo(&buf, "FROM %s ",
1019 : generate_relation_name(trigrec->tgconstrrelid, NIL));
1020 0 : if (!trigrec->tgdeferrable)
1021 0 : appendStringInfoString(&buf, "NOT ");
1022 0 : appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
1023 0 : if (trigrec->tginitdeferred)
1024 0 : appendStringInfoString(&buf, "DEFERRED ");
1025 : else
1026 0 : appendStringInfoString(&buf, "IMMEDIATE ");
1027 : }
1028 :
1029 1408 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
1030 : tgrel->rd_att, &isnull);
1031 1408 : if (!isnull)
1032 98 : tgoldtable = NameStr(*DatumGetName(value));
1033 : else
1034 1310 : tgoldtable = NULL;
1035 1408 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
1036 : tgrel->rd_att, &isnull);
1037 1408 : if (!isnull)
1038 108 : tgnewtable = NameStr(*DatumGetName(value));
1039 : else
1040 1300 : tgnewtable = NULL;
1041 1408 : if (tgoldtable != NULL || tgnewtable != NULL)
1042 : {
1043 152 : appendStringInfoString(&buf, "REFERENCING ");
1044 152 : if (tgoldtable != NULL)
1045 98 : appendStringInfo(&buf, "OLD TABLE AS %s ",
1046 : quote_identifier(tgoldtable));
1047 152 : if (tgnewtable != NULL)
1048 108 : appendStringInfo(&buf, "NEW TABLE AS %s ",
1049 : quote_identifier(tgnewtable));
1050 : }
1051 :
1052 1408 : if (TRIGGER_FOR_ROW(trigrec->tgtype))
1053 1090 : appendStringInfoString(&buf, "FOR EACH ROW ");
1054 : else
1055 318 : appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1056 :
1057 : /* If the trigger has a WHEN qualification, add that */
1058 1408 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
1059 : tgrel->rd_att, &isnull);
1060 1408 : if (!isnull)
1061 : {
1062 : Node *qual;
1063 : char relkind;
1064 : deparse_context context;
1065 : deparse_namespace dpns;
1066 : RangeTblEntry *oldrte;
1067 : RangeTblEntry *newrte;
1068 :
1069 164 : appendStringInfoString(&buf, "WHEN (");
1070 :
1071 164 : qual = stringToNode(TextDatumGetCString(value));
1072 :
1073 164 : relkind = get_rel_relkind(trigrec->tgrelid);
1074 :
1075 : /* Build minimal OLD and NEW RTEs for the rel */
1076 164 : oldrte = makeNode(RangeTblEntry);
1077 164 : oldrte->rtekind = RTE_RELATION;
1078 164 : oldrte->relid = trigrec->tgrelid;
1079 164 : oldrte->relkind = relkind;
1080 164 : oldrte->rellockmode = AccessShareLock;
1081 164 : oldrte->alias = makeAlias("old", NIL);
1082 164 : oldrte->eref = oldrte->alias;
1083 164 : oldrte->lateral = false;
1084 164 : oldrte->inh = false;
1085 164 : oldrte->inFromCl = true;
1086 :
1087 164 : newrte = makeNode(RangeTblEntry);
1088 164 : newrte->rtekind = RTE_RELATION;
1089 164 : newrte->relid = trigrec->tgrelid;
1090 164 : newrte->relkind = relkind;
1091 164 : newrte->rellockmode = AccessShareLock;
1092 164 : newrte->alias = makeAlias("new", NIL);
1093 164 : newrte->eref = newrte->alias;
1094 164 : newrte->lateral = false;
1095 164 : newrte->inh = false;
1096 164 : newrte->inFromCl = true;
1097 :
1098 : /* Build two-element rtable */
1099 164 : memset(&dpns, 0, sizeof(dpns));
1100 164 : dpns.rtable = list_make2(oldrte, newrte);
1101 164 : dpns.subplans = NIL;
1102 164 : dpns.ctes = NIL;
1103 164 : dpns.appendrels = NULL;
1104 164 : set_rtable_names(&dpns, NIL, NULL);
1105 164 : set_simple_column_names(&dpns);
1106 :
1107 : /* Set up context with one-deep namespace stack */
1108 164 : context.buf = &buf;
1109 164 : context.namespaces = list_make1(&dpns);
1110 164 : context.resultDesc = NULL;
1111 164 : context.targetList = NIL;
1112 164 : context.windowClause = NIL;
1113 164 : context.varprefix = true;
1114 164 : context.prettyFlags = GET_PRETTY_FLAGS(pretty);
1115 164 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
1116 164 : context.indentLevel = PRETTYINDENT_STD;
1117 164 : context.colNamesVisible = true;
1118 164 : context.inGroupBy = false;
1119 164 : context.varInOrderBy = false;
1120 164 : context.appendparents = NULL;
1121 :
1122 164 : get_rule_expr(qual, &context, false);
1123 :
1124 164 : appendStringInfoString(&buf, ") ");
1125 : }
1126 :
1127 1408 : appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1128 : generate_function_name(trigrec->tgfoid, 0,
1129 : NIL, NULL,
1130 : false, NULL, false));
1131 :
1132 1408 : if (trigrec->tgnargs > 0)
1133 : {
1134 : char *p;
1135 : int i;
1136 :
1137 410 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1138 : tgrel->rd_att, &isnull);
1139 410 : if (isnull)
1140 0 : elog(ERROR, "tgargs is null for trigger %u", trigid);
1141 410 : p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1142 932 : for (i = 0; i < trigrec->tgnargs; i++)
1143 : {
1144 522 : if (i > 0)
1145 112 : appendStringInfoString(&buf, ", ");
1146 522 : simple_quote_literal(&buf, p);
1147 : /* advance p to next string embedded in tgargs */
1148 5372 : while (*p)
1149 4850 : p++;
1150 522 : p++;
1151 : }
1152 : }
1153 :
1154 : /* We deliberately do not put semi-colon at end */
1155 1408 : appendStringInfoChar(&buf, ')');
1156 :
1157 : /* Clean up */
1158 1408 : systable_endscan(tgscan);
1159 :
1160 1408 : table_close(tgrel, AccessShareLock);
1161 :
1162 1408 : return buf.data;
1163 : }
1164 :
1165 : /* ----------
1166 : * pg_get_indexdef - Get the definition of an index
1167 : *
1168 : * In the extended version, there is a colno argument as well as pretty bool.
1169 : * if colno == 0, we want a complete index definition.
1170 : * if colno > 0, we only want the Nth index key's variable or expression.
1171 : *
1172 : * Note that the SQL-function versions of this omit any info about the
1173 : * index tablespace; this is intentional because pg_dump wants it that way.
1174 : * However pg_get_indexdef_string() includes the index tablespace.
1175 : * ----------
1176 : */
1177 : Datum
1178 5850 : pg_get_indexdef(PG_FUNCTION_ARGS)
1179 : {
1180 5850 : Oid indexrelid = PG_GETARG_OID(0);
1181 : int prettyFlags;
1182 : char *res;
1183 :
1184 5850 : prettyFlags = PRETTYFLAG_INDENT;
1185 :
1186 5850 : res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1187 : false, false,
1188 : false, false,
1189 : prettyFlags, true);
1190 :
1191 5850 : if (res == NULL)
1192 6 : PG_RETURN_NULL();
1193 :
1194 5844 : PG_RETURN_TEXT_P(string_to_text(res));
1195 : }
1196 :
1197 : Datum
1198 1994 : pg_get_indexdef_ext(PG_FUNCTION_ARGS)
1199 : {
1200 1994 : Oid indexrelid = PG_GETARG_OID(0);
1201 1994 : int32 colno = PG_GETARG_INT32(1);
1202 1994 : bool pretty = PG_GETARG_BOOL(2);
1203 : int prettyFlags;
1204 : char *res;
1205 :
1206 1994 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1207 :
1208 1994 : res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1209 : colno != 0, false,
1210 : false, false,
1211 : prettyFlags, true);
1212 :
1213 1994 : if (res == NULL)
1214 0 : PG_RETURN_NULL();
1215 :
1216 1994 : PG_RETURN_TEXT_P(string_to_text(res));
1217 : }
1218 :
1219 : /*
1220 : * Internal version for use by ALTER TABLE.
1221 : * Includes a tablespace clause in the result.
1222 : * Returns a palloc'd C string; no pretty-printing.
1223 : */
1224 : char *
1225 228 : pg_get_indexdef_string(Oid indexrelid)
1226 : {
1227 228 : return pg_get_indexdef_worker(indexrelid, 0, NULL,
1228 : false, false,
1229 : true, true,
1230 : 0, false);
1231 : }
1232 :
1233 : /* Internal version that just reports the key-column definitions */
1234 : char *
1235 1044 : pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1236 : {
1237 : int prettyFlags;
1238 :
1239 1044 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1240 :
1241 1044 : return pg_get_indexdef_worker(indexrelid, 0, NULL,
1242 : true, true,
1243 : false, false,
1244 : prettyFlags, false);
1245 : }
1246 :
1247 : /* Internal version, extensible with flags to control its behavior */
1248 : char *
1249 8 : pg_get_indexdef_columns_extended(Oid indexrelid, bits16 flags)
1250 : {
1251 8 : bool pretty = ((flags & RULE_INDEXDEF_PRETTY) != 0);
1252 8 : bool keys_only = ((flags & RULE_INDEXDEF_KEYS_ONLY) != 0);
1253 : int prettyFlags;
1254 :
1255 8 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1256 :
1257 8 : return pg_get_indexdef_worker(indexrelid, 0, NULL,
1258 : true, keys_only,
1259 : false, false,
1260 : prettyFlags, false);
1261 : }
1262 :
1263 : /*
1264 : * Internal workhorse to decompile an index definition.
1265 : *
1266 : * This is now used for exclusion constraints as well: if excludeOps is not
1267 : * NULL then it points to an array of exclusion operator OIDs.
1268 : */
1269 : static char *
1270 9228 : pg_get_indexdef_worker(Oid indexrelid, int colno,
1271 : const Oid *excludeOps,
1272 : bool attrsOnly, bool keysOnly,
1273 : bool showTblSpc, bool inherits,
1274 : int prettyFlags, bool missing_ok)
1275 : {
1276 : /* might want a separate isConstraint parameter later */
1277 9228 : bool isConstraint = (excludeOps != NULL);
1278 : HeapTuple ht_idx;
1279 : HeapTuple ht_idxrel;
1280 : HeapTuple ht_am;
1281 : Form_pg_index idxrec;
1282 : Form_pg_class idxrelrec;
1283 : Form_pg_am amrec;
1284 : IndexAmRoutine *amroutine;
1285 : List *indexprs;
1286 : ListCell *indexpr_item;
1287 : List *context;
1288 : Oid indrelid;
1289 : int keyno;
1290 : Datum indcollDatum;
1291 : Datum indclassDatum;
1292 : Datum indoptionDatum;
1293 : oidvector *indcollation;
1294 : oidvector *indclass;
1295 : int2vector *indoption;
1296 : StringInfoData buf;
1297 : char *str;
1298 : char *sep;
1299 :
1300 : /*
1301 : * Fetch the pg_index tuple by the Oid of the index
1302 : */
1303 9228 : ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1304 9228 : if (!HeapTupleIsValid(ht_idx))
1305 : {
1306 6 : if (missing_ok)
1307 6 : return NULL;
1308 0 : elog(ERROR, "cache lookup failed for index %u", indexrelid);
1309 : }
1310 9222 : idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1311 :
1312 9222 : indrelid = idxrec->indrelid;
1313 : Assert(indexrelid == idxrec->indexrelid);
1314 :
1315 : /* Must get indcollation, indclass, and indoption the hard way */
1316 9222 : indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1317 : Anum_pg_index_indcollation);
1318 9222 : indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1319 :
1320 9222 : indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1321 : Anum_pg_index_indclass);
1322 9222 : indclass = (oidvector *) DatumGetPointer(indclassDatum);
1323 :
1324 9222 : indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1325 : Anum_pg_index_indoption);
1326 9222 : indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1327 :
1328 : /*
1329 : * Fetch the pg_class tuple of the index relation
1330 : */
1331 9222 : ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1332 9222 : if (!HeapTupleIsValid(ht_idxrel))
1333 0 : elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1334 9222 : idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1335 :
1336 : /*
1337 : * Fetch the pg_am tuple of the index' access method
1338 : */
1339 9222 : ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1340 9222 : if (!HeapTupleIsValid(ht_am))
1341 0 : elog(ERROR, "cache lookup failed for access method %u",
1342 : idxrelrec->relam);
1343 9222 : amrec = (Form_pg_am) GETSTRUCT(ht_am);
1344 :
1345 : /* Fetch the index AM's API struct */
1346 9222 : amroutine = GetIndexAmRoutine(amrec->amhandler);
1347 :
1348 : /*
1349 : * Get the index expressions, if any. (NOTE: we do not use the relcache
1350 : * versions of the expressions and predicate, because we want to display
1351 : * non-const-folded expressions.)
1352 : */
1353 9222 : if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
1354 : {
1355 : Datum exprsDatum;
1356 : char *exprsString;
1357 :
1358 676 : exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1359 : Anum_pg_index_indexprs);
1360 676 : exprsString = TextDatumGetCString(exprsDatum);
1361 676 : indexprs = (List *) stringToNode(exprsString);
1362 676 : pfree(exprsString);
1363 : }
1364 : else
1365 8546 : indexprs = NIL;
1366 :
1367 9222 : indexpr_item = list_head(indexprs);
1368 :
1369 9222 : context = deparse_context_for(get_relation_name(indrelid), indrelid);
1370 :
1371 : /*
1372 : * Start the index definition. Note that the index's name should never be
1373 : * schema-qualified, but the indexed rel's name may be.
1374 : */
1375 9222 : initStringInfo(&buf);
1376 :
1377 9222 : if (!attrsOnly)
1378 : {
1379 7708 : if (!isConstraint)
1380 15208 : appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1381 7604 : idxrec->indisunique ? "UNIQUE " : "",
1382 7604 : quote_identifier(NameStr(idxrelrec->relname)),
1383 7604 : idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1384 694 : && !inherits ? "ONLY " : "",
1385 7604 : (prettyFlags & PRETTYFLAG_SCHEMA) ?
1386 1532 : generate_relation_name(indrelid, NIL) :
1387 6072 : generate_qualified_relation_name(indrelid),
1388 7604 : quote_identifier(NameStr(amrec->amname)));
1389 : else /* currently, must be EXCLUDE constraint */
1390 104 : appendStringInfo(&buf, "EXCLUDE USING %s (",
1391 104 : quote_identifier(NameStr(amrec->amname)));
1392 : }
1393 :
1394 : /*
1395 : * Report the indexed attributes
1396 : */
1397 9222 : sep = "";
1398 23240 : for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1399 : {
1400 14116 : AttrNumber attnum = idxrec->indkey.values[keyno];
1401 : Oid keycoltype;
1402 : Oid keycolcollation;
1403 :
1404 : /*
1405 : * Ignore non-key attributes if told to.
1406 : */
1407 14116 : if (keysOnly && keyno >= idxrec->indnkeyatts)
1408 98 : break;
1409 :
1410 : /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1411 14018 : if (!colno && keyno == idxrec->indnkeyatts)
1412 : {
1413 250 : appendStringInfoString(&buf, ") INCLUDE (");
1414 250 : sep = "";
1415 : }
1416 :
1417 14018 : if (!colno)
1418 13376 : appendStringInfoString(&buf, sep);
1419 14018 : sep = ", ";
1420 :
1421 14018 : if (attnum != 0)
1422 : {
1423 : /* Simple index column */
1424 : char *attname;
1425 : int32 keycoltypmod;
1426 :
1427 13164 : attname = get_attname(indrelid, attnum, false);
1428 13164 : if (!colno || colno == keyno + 1)
1429 12996 : appendStringInfoString(&buf, quote_identifier(attname));
1430 13164 : get_atttypetypmodcoll(indrelid, attnum,
1431 : &keycoltype, &keycoltypmod,
1432 : &keycolcollation);
1433 : }
1434 : else
1435 : {
1436 : /* expressional index */
1437 : Node *indexkey;
1438 :
1439 854 : if (indexpr_item == NULL)
1440 0 : elog(ERROR, "too few entries in indexprs list");
1441 854 : indexkey = (Node *) lfirst(indexpr_item);
1442 854 : indexpr_item = lnext(indexprs, indexpr_item);
1443 : /* Deparse */
1444 854 : str = deparse_expression_pretty(indexkey, context, false, false,
1445 : prettyFlags, 0);
1446 854 : if (!colno || colno == keyno + 1)
1447 : {
1448 : /* Need parens if it's not a bare function call */
1449 842 : if (looks_like_function(indexkey))
1450 52 : appendStringInfoString(&buf, str);
1451 : else
1452 790 : appendStringInfo(&buf, "(%s)", str);
1453 : }
1454 854 : keycoltype = exprType(indexkey);
1455 854 : keycolcollation = exprCollation(indexkey);
1456 : }
1457 :
1458 : /* Print additional decoration for (selected) key columns */
1459 14018 : if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1460 0 : (!colno || colno == keyno + 1))
1461 : {
1462 11500 : int16 opt = indoption->values[keyno];
1463 11500 : Oid indcoll = indcollation->values[keyno];
1464 11500 : Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1465 11500 : bool has_options = attoptions != (Datum) 0;
1466 :
1467 : /* Add collation, if not default for column */
1468 11500 : if (OidIsValid(indcoll) && indcoll != keycolcollation)
1469 94 : appendStringInfo(&buf, " COLLATE %s",
1470 : generate_collation_name((indcoll)));
1471 :
1472 : /* Add the operator class name, if not default */
1473 11500 : get_opclass_name(indclass->values[keyno],
1474 : has_options ? InvalidOid : keycoltype, &buf);
1475 :
1476 11500 : if (has_options)
1477 : {
1478 34 : appendStringInfoString(&buf, " (");
1479 34 : get_reloptions(&buf, attoptions);
1480 34 : appendStringInfoChar(&buf, ')');
1481 : }
1482 :
1483 : /* Add options if relevant */
1484 11500 : if (amroutine->amcanorder)
1485 : {
1486 : /* if it supports sort ordering, report DESC and NULLS opts */
1487 9356 : if (opt & INDOPTION_DESC)
1488 : {
1489 0 : appendStringInfoString(&buf, " DESC");
1490 : /* NULLS FIRST is the default in this case */
1491 0 : if (!(opt & INDOPTION_NULLS_FIRST))
1492 0 : appendStringInfoString(&buf, " NULLS LAST");
1493 : }
1494 : else
1495 : {
1496 9356 : if (opt & INDOPTION_NULLS_FIRST)
1497 0 : appendStringInfoString(&buf, " NULLS FIRST");
1498 : }
1499 : }
1500 :
1501 : /* Add the exclusion operator if relevant */
1502 11500 : if (excludeOps != NULL)
1503 124 : appendStringInfo(&buf, " WITH %s",
1504 124 : generate_operator_name(excludeOps[keyno],
1505 : keycoltype,
1506 : keycoltype));
1507 : }
1508 : }
1509 :
1510 9222 : if (!attrsOnly)
1511 : {
1512 7708 : appendStringInfoChar(&buf, ')');
1513 :
1514 7708 : if (idxrec->indnullsnotdistinct)
1515 12 : appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1516 :
1517 : /*
1518 : * If it has options, append "WITH (options)"
1519 : */
1520 7708 : str = flatten_reloptions(indexrelid);
1521 7708 : if (str)
1522 : {
1523 210 : appendStringInfo(&buf, " WITH (%s)", str);
1524 210 : pfree(str);
1525 : }
1526 :
1527 : /*
1528 : * Print tablespace, but only if requested
1529 : */
1530 7708 : if (showTblSpc)
1531 : {
1532 : Oid tblspc;
1533 :
1534 228 : tblspc = get_rel_tablespace(indexrelid);
1535 228 : if (OidIsValid(tblspc))
1536 : {
1537 54 : if (isConstraint)
1538 0 : appendStringInfoString(&buf, " USING INDEX");
1539 54 : appendStringInfo(&buf, " TABLESPACE %s",
1540 54 : quote_identifier(get_tablespace_name(tblspc)));
1541 : }
1542 : }
1543 :
1544 : /*
1545 : * If it's a partial index, decompile and append the predicate
1546 : */
1547 7708 : if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
1548 : {
1549 : Node *node;
1550 : Datum predDatum;
1551 : char *predString;
1552 :
1553 : /* Convert text string to node tree */
1554 314 : predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1555 : Anum_pg_index_indpred);
1556 314 : predString = TextDatumGetCString(predDatum);
1557 314 : node = (Node *) stringToNode(predString);
1558 314 : pfree(predString);
1559 :
1560 : /* Deparse */
1561 314 : str = deparse_expression_pretty(node, context, false, false,
1562 : prettyFlags, 0);
1563 314 : if (isConstraint)
1564 42 : appendStringInfo(&buf, " WHERE (%s)", str);
1565 : else
1566 272 : appendStringInfo(&buf, " WHERE %s", str);
1567 : }
1568 : }
1569 :
1570 : /* Clean up */
1571 9222 : ReleaseSysCache(ht_idx);
1572 9222 : ReleaseSysCache(ht_idxrel);
1573 9222 : ReleaseSysCache(ht_am);
1574 :
1575 9222 : return buf.data;
1576 : }
1577 :
1578 : /* ----------
1579 : * pg_get_querydef
1580 : *
1581 : * Public entry point to deparse one query parsetree.
1582 : * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1583 : *
1584 : * The result is a palloc'd C string.
1585 : * ----------
1586 : */
1587 : char *
1588 0 : pg_get_querydef(Query *query, bool pretty)
1589 : {
1590 : StringInfoData buf;
1591 : int prettyFlags;
1592 :
1593 0 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1594 :
1595 0 : initStringInfo(&buf);
1596 :
1597 0 : get_query_def(query, &buf, NIL, NULL, true,
1598 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1599 :
1600 0 : return buf.data;
1601 : }
1602 :
1603 : /*
1604 : * pg_get_statisticsobjdef
1605 : * Get the definition of an extended statistics object
1606 : */
1607 : Datum
1608 278 : pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
1609 : {
1610 278 : Oid statextid = PG_GETARG_OID(0);
1611 : char *res;
1612 :
1613 278 : res = pg_get_statisticsobj_worker(statextid, false, true);
1614 :
1615 278 : if (res == NULL)
1616 6 : PG_RETURN_NULL();
1617 :
1618 272 : PG_RETURN_TEXT_P(string_to_text(res));
1619 : }
1620 :
1621 : /*
1622 : * Internal version for use by ALTER TABLE.
1623 : * Returns a palloc'd C string; no pretty-printing.
1624 : */
1625 : char *
1626 26 : pg_get_statisticsobjdef_string(Oid statextid)
1627 : {
1628 26 : return pg_get_statisticsobj_worker(statextid, false, false);
1629 : }
1630 :
1631 : /*
1632 : * pg_get_statisticsobjdef_columns
1633 : * Get columns and expressions for an extended statistics object
1634 : */
1635 : Datum
1636 414 : pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
1637 : {
1638 414 : Oid statextid = PG_GETARG_OID(0);
1639 : char *res;
1640 :
1641 414 : res = pg_get_statisticsobj_worker(statextid, true, true);
1642 :
1643 414 : if (res == NULL)
1644 0 : PG_RETURN_NULL();
1645 :
1646 414 : PG_RETURN_TEXT_P(string_to_text(res));
1647 : }
1648 :
1649 : /*
1650 : * Internal workhorse to decompile an extended statistics object.
1651 : */
1652 : static char *
1653 718 : pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
1654 : {
1655 : Form_pg_statistic_ext statextrec;
1656 : HeapTuple statexttup;
1657 : StringInfoData buf;
1658 : int colno;
1659 : char *nsp;
1660 : ArrayType *arr;
1661 : char *enabled;
1662 : Datum datum;
1663 : bool ndistinct_enabled;
1664 : bool dependencies_enabled;
1665 : bool mcv_enabled;
1666 : int i;
1667 : List *context;
1668 : ListCell *lc;
1669 718 : List *exprs = NIL;
1670 : bool has_exprs;
1671 : int ncolumns;
1672 :
1673 718 : statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1674 :
1675 718 : if (!HeapTupleIsValid(statexttup))
1676 : {
1677 6 : if (missing_ok)
1678 6 : return NULL;
1679 0 : elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1680 : }
1681 :
1682 : /* has the statistics expressions? */
1683 712 : has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1684 :
1685 712 : statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1686 :
1687 : /*
1688 : * Get the statistics expressions, if any. (NOTE: we do not use the
1689 : * relcache versions of the expressions, because we want to display
1690 : * non-const-folded expressions.)
1691 : */
1692 712 : if (has_exprs)
1693 : {
1694 : Datum exprsDatum;
1695 : char *exprsString;
1696 :
1697 164 : exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1698 : Anum_pg_statistic_ext_stxexprs);
1699 164 : exprsString = TextDatumGetCString(exprsDatum);
1700 164 : exprs = (List *) stringToNode(exprsString);
1701 164 : pfree(exprsString);
1702 : }
1703 : else
1704 548 : exprs = NIL;
1705 :
1706 : /* count the number of columns (attributes and expressions) */
1707 712 : ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1708 :
1709 712 : initStringInfo(&buf);
1710 :
1711 712 : if (!columns_only)
1712 : {
1713 298 : nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
1714 298 : appendStringInfo(&buf, "CREATE STATISTICS %s",
1715 : quote_qualified_identifier(nsp,
1716 298 : NameStr(statextrec->stxname)));
1717 :
1718 : /*
1719 : * Decode the stxkind column so that we know which stats types to
1720 : * print.
1721 : */
1722 298 : datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1723 : Anum_pg_statistic_ext_stxkind);
1724 298 : arr = DatumGetArrayTypeP(datum);
1725 298 : if (ARR_NDIM(arr) != 1 ||
1726 298 : ARR_HASNULL(arr) ||
1727 298 : ARR_ELEMTYPE(arr) != CHAROID)
1728 0 : elog(ERROR, "stxkind is not a 1-D char array");
1729 298 : enabled = (char *) ARR_DATA_PTR(arr);
1730 :
1731 298 : ndistinct_enabled = false;
1732 298 : dependencies_enabled = false;
1733 298 : mcv_enabled = false;
1734 :
1735 766 : for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1736 : {
1737 468 : if (enabled[i] == STATS_EXT_NDISTINCT)
1738 156 : ndistinct_enabled = true;
1739 312 : else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1740 98 : dependencies_enabled = true;
1741 214 : else if (enabled[i] == STATS_EXT_MCV)
1742 116 : mcv_enabled = true;
1743 :
1744 : /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1745 : }
1746 :
1747 : /*
1748 : * If any option is disabled, then we'll need to append the types
1749 : * clause to show which options are enabled. We omit the types clause
1750 : * on purpose when all options are enabled, so a pg_dump/pg_restore
1751 : * will create all statistics types on a newer postgres version, if
1752 : * the statistics had all options enabled on the original version.
1753 : *
1754 : * But if the statistics is defined on just a single column, it has to
1755 : * be an expression statistics. In that case we don't need to specify
1756 : * kinds.
1757 : */
1758 298 : if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1759 : (ncolumns > 1))
1760 : {
1761 130 : bool gotone = false;
1762 :
1763 130 : appendStringInfoString(&buf, " (");
1764 :
1765 130 : if (ndistinct_enabled)
1766 : {
1767 76 : appendStringInfoString(&buf, "ndistinct");
1768 76 : gotone = true;
1769 : }
1770 :
1771 130 : if (dependencies_enabled)
1772 : {
1773 18 : appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
1774 18 : gotone = true;
1775 : }
1776 :
1777 130 : if (mcv_enabled)
1778 36 : appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1779 :
1780 130 : appendStringInfoChar(&buf, ')');
1781 : }
1782 :
1783 298 : appendStringInfoString(&buf, " ON ");
1784 : }
1785 :
1786 : /* decode simple column references */
1787 1988 : for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1788 : {
1789 1276 : AttrNumber attnum = statextrec->stxkeys.values[colno];
1790 : char *attname;
1791 :
1792 1276 : if (colno > 0)
1793 716 : appendStringInfoString(&buf, ", ");
1794 :
1795 1276 : attname = get_attname(statextrec->stxrelid, attnum, false);
1796 :
1797 1276 : appendStringInfoString(&buf, quote_identifier(attname));
1798 : }
1799 :
1800 712 : context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1801 : statextrec->stxrelid);
1802 :
1803 962 : foreach(lc, exprs)
1804 : {
1805 250 : Node *expr = (Node *) lfirst(lc);
1806 : char *str;
1807 250 : int prettyFlags = PRETTYFLAG_PAREN;
1808 :
1809 250 : str = deparse_expression_pretty(expr, context, false, false,
1810 : prettyFlags, 0);
1811 :
1812 250 : if (colno > 0)
1813 98 : appendStringInfoString(&buf, ", ");
1814 :
1815 : /* Need parens if it's not a bare function call */
1816 250 : if (looks_like_function(expr))
1817 34 : appendStringInfoString(&buf, str);
1818 : else
1819 216 : appendStringInfo(&buf, "(%s)", str);
1820 :
1821 250 : colno++;
1822 : }
1823 :
1824 712 : if (!columns_only)
1825 298 : appendStringInfo(&buf, " FROM %s",
1826 : generate_relation_name(statextrec->stxrelid, NIL));
1827 :
1828 712 : ReleaseSysCache(statexttup);
1829 :
1830 712 : return buf.data;
1831 : }
1832 :
1833 : /*
1834 : * Generate text array of expressions for statistics object.
1835 : */
1836 : Datum
1837 24 : pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
1838 : {
1839 24 : Oid statextid = PG_GETARG_OID(0);
1840 : Form_pg_statistic_ext statextrec;
1841 : HeapTuple statexttup;
1842 : Datum datum;
1843 : List *context;
1844 : ListCell *lc;
1845 24 : List *exprs = NIL;
1846 : bool has_exprs;
1847 : char *tmp;
1848 24 : ArrayBuildState *astate = NULL;
1849 :
1850 24 : statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1851 :
1852 24 : if (!HeapTupleIsValid(statexttup))
1853 0 : PG_RETURN_NULL();
1854 :
1855 : /* Does the stats object have expressions? */
1856 24 : has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1857 :
1858 : /* no expressions? we're done */
1859 24 : if (!has_exprs)
1860 : {
1861 12 : ReleaseSysCache(statexttup);
1862 12 : PG_RETURN_NULL();
1863 : }
1864 :
1865 12 : statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1866 :
1867 : /*
1868 : * Get the statistics expressions, and deparse them into text values.
1869 : */
1870 12 : datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1871 : Anum_pg_statistic_ext_stxexprs);
1872 12 : tmp = TextDatumGetCString(datum);
1873 12 : exprs = (List *) stringToNode(tmp);
1874 12 : pfree(tmp);
1875 :
1876 12 : context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1877 : statextrec->stxrelid);
1878 :
1879 36 : foreach(lc, exprs)
1880 : {
1881 24 : Node *expr = (Node *) lfirst(lc);
1882 : char *str;
1883 24 : int prettyFlags = PRETTYFLAG_INDENT;
1884 :
1885 24 : str = deparse_expression_pretty(expr, context, false, false,
1886 : prettyFlags, 0);
1887 :
1888 24 : astate = accumArrayResult(astate,
1889 24 : PointerGetDatum(cstring_to_text(str)),
1890 : false,
1891 : TEXTOID,
1892 : CurrentMemoryContext);
1893 : }
1894 :
1895 12 : ReleaseSysCache(statexttup);
1896 :
1897 12 : PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
1898 : }
1899 :
1900 : /*
1901 : * pg_get_partkeydef
1902 : *
1903 : * Returns the partition key specification, ie, the following:
1904 : *
1905 : * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1906 : */
1907 : Datum
1908 1476 : pg_get_partkeydef(PG_FUNCTION_ARGS)
1909 : {
1910 1476 : Oid relid = PG_GETARG_OID(0);
1911 : char *res;
1912 :
1913 1476 : res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1914 :
1915 1476 : if (res == NULL)
1916 6 : PG_RETURN_NULL();
1917 :
1918 1470 : PG_RETURN_TEXT_P(string_to_text(res));
1919 : }
1920 :
1921 : /* Internal version that just reports the column definitions */
1922 : char *
1923 142 : pg_get_partkeydef_columns(Oid relid, bool pretty)
1924 : {
1925 : int prettyFlags;
1926 :
1927 142 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1928 :
1929 142 : return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1930 : }
1931 :
1932 : /*
1933 : * Internal workhorse to decompile a partition key definition.
1934 : */
1935 : static char *
1936 1618 : pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1937 : bool attrsOnly, bool missing_ok)
1938 : {
1939 : Form_pg_partitioned_table form;
1940 : HeapTuple tuple;
1941 : oidvector *partclass;
1942 : oidvector *partcollation;
1943 : List *partexprs;
1944 : ListCell *partexpr_item;
1945 : List *context;
1946 : Datum datum;
1947 : StringInfoData buf;
1948 : int keyno;
1949 : char *str;
1950 : char *sep;
1951 :
1952 1618 : tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1953 1618 : if (!HeapTupleIsValid(tuple))
1954 : {
1955 6 : if (missing_ok)
1956 6 : return NULL;
1957 0 : elog(ERROR, "cache lookup failed for partition key of %u", relid);
1958 : }
1959 :
1960 1612 : form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1961 :
1962 : Assert(form->partrelid == relid);
1963 :
1964 : /* Must get partclass and partcollation the hard way */
1965 1612 : datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1966 : Anum_pg_partitioned_table_partclass);
1967 1612 : partclass = (oidvector *) DatumGetPointer(datum);
1968 :
1969 1612 : datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1970 : Anum_pg_partitioned_table_partcollation);
1971 1612 : partcollation = (oidvector *) DatumGetPointer(datum);
1972 :
1973 :
1974 : /*
1975 : * Get the expressions, if any. (NOTE: we do not use the relcache
1976 : * versions of the expressions, because we want to display
1977 : * non-const-folded expressions.)
1978 : */
1979 1612 : if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1980 : {
1981 : Datum exprsDatum;
1982 : char *exprsString;
1983 :
1984 146 : exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1985 : Anum_pg_partitioned_table_partexprs);
1986 146 : exprsString = TextDatumGetCString(exprsDatum);
1987 146 : partexprs = (List *) stringToNode(exprsString);
1988 :
1989 146 : if (!IsA(partexprs, List))
1990 0 : elog(ERROR, "unexpected node type found in partexprs: %d",
1991 : (int) nodeTag(partexprs));
1992 :
1993 146 : pfree(exprsString);
1994 : }
1995 : else
1996 1466 : partexprs = NIL;
1997 :
1998 1612 : partexpr_item = list_head(partexprs);
1999 1612 : context = deparse_context_for(get_relation_name(relid), relid);
2000 :
2001 1612 : initStringInfo(&buf);
2002 :
2003 1612 : switch (form->partstrat)
2004 : {
2005 128 : case PARTITION_STRATEGY_HASH:
2006 128 : if (!attrsOnly)
2007 128 : appendStringInfoString(&buf, "HASH");
2008 128 : break;
2009 598 : case PARTITION_STRATEGY_LIST:
2010 598 : if (!attrsOnly)
2011 558 : appendStringInfoString(&buf, "LIST");
2012 598 : break;
2013 886 : case PARTITION_STRATEGY_RANGE:
2014 886 : if (!attrsOnly)
2015 784 : appendStringInfoString(&buf, "RANGE");
2016 886 : break;
2017 0 : default:
2018 0 : elog(ERROR, "unexpected partition strategy: %d",
2019 : (int) form->partstrat);
2020 : }
2021 :
2022 1612 : if (!attrsOnly)
2023 1470 : appendStringInfoString(&buf, " (");
2024 1612 : sep = "";
2025 3376 : for (keyno = 0; keyno < form->partnatts; keyno++)
2026 : {
2027 1764 : AttrNumber attnum = form->partattrs.values[keyno];
2028 : Oid keycoltype;
2029 : Oid keycolcollation;
2030 : Oid partcoll;
2031 :
2032 1764 : appendStringInfoString(&buf, sep);
2033 1764 : sep = ", ";
2034 1764 : if (attnum != 0)
2035 : {
2036 : /* Simple attribute reference */
2037 : char *attname;
2038 : int32 keycoltypmod;
2039 :
2040 1606 : attname = get_attname(relid, attnum, false);
2041 1606 : appendStringInfoString(&buf, quote_identifier(attname));
2042 1606 : get_atttypetypmodcoll(relid, attnum,
2043 : &keycoltype, &keycoltypmod,
2044 : &keycolcollation);
2045 : }
2046 : else
2047 : {
2048 : /* Expression */
2049 : Node *partkey;
2050 :
2051 158 : if (partexpr_item == NULL)
2052 0 : elog(ERROR, "too few entries in partexprs list");
2053 158 : partkey = (Node *) lfirst(partexpr_item);
2054 158 : partexpr_item = lnext(partexprs, partexpr_item);
2055 :
2056 : /* Deparse */
2057 158 : str = deparse_expression_pretty(partkey, context, false, false,
2058 : prettyFlags, 0);
2059 : /* Need parens if it's not a bare function call */
2060 158 : if (looks_like_function(partkey))
2061 56 : appendStringInfoString(&buf, str);
2062 : else
2063 102 : appendStringInfo(&buf, "(%s)", str);
2064 :
2065 158 : keycoltype = exprType(partkey);
2066 158 : keycolcollation = exprCollation(partkey);
2067 : }
2068 :
2069 : /* Add collation, if not default for column */
2070 1764 : partcoll = partcollation->values[keyno];
2071 1764 : if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
2072 6 : appendStringInfo(&buf, " COLLATE %s",
2073 : generate_collation_name((partcoll)));
2074 :
2075 : /* Add the operator class name, if not default */
2076 1764 : if (!attrsOnly)
2077 1568 : get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2078 : }
2079 :
2080 1612 : if (!attrsOnly)
2081 1470 : appendStringInfoChar(&buf, ')');
2082 :
2083 : /* Clean up */
2084 1612 : ReleaseSysCache(tuple);
2085 :
2086 1612 : return buf.data;
2087 : }
2088 :
2089 : /*
2090 : * pg_get_partition_constraintdef
2091 : *
2092 : * Returns partition constraint expression as a string for the input relation
2093 : */
2094 : Datum
2095 182 : pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
2096 : {
2097 182 : Oid relationId = PG_GETARG_OID(0);
2098 : Expr *constr_expr;
2099 : int prettyFlags;
2100 : List *context;
2101 : char *consrc;
2102 :
2103 182 : constr_expr = get_partition_qual_relid(relationId);
2104 :
2105 : /* Quick exit if no partition constraint */
2106 182 : if (constr_expr == NULL)
2107 18 : PG_RETURN_NULL();
2108 :
2109 : /*
2110 : * Deparse and return the constraint expression.
2111 : */
2112 164 : prettyFlags = PRETTYFLAG_INDENT;
2113 164 : context = deparse_context_for(get_relation_name(relationId), relationId);
2114 164 : consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2115 : false, prettyFlags, 0);
2116 :
2117 164 : PG_RETURN_TEXT_P(string_to_text(consrc));
2118 : }
2119 :
2120 : /*
2121 : * pg_get_partconstrdef_string
2122 : *
2123 : * Returns the partition constraint as a C-string for the input relation, with
2124 : * the given alias. No pretty-printing.
2125 : */
2126 : char *
2127 110 : pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
2128 : {
2129 : Expr *constr_expr;
2130 : List *context;
2131 :
2132 110 : constr_expr = get_partition_qual_relid(partitionId);
2133 110 : context = deparse_context_for(aliasname, partitionId);
2134 :
2135 110 : return deparse_expression((Node *) constr_expr, context, true, false);
2136 : }
2137 :
2138 : /*
2139 : * pg_get_constraintdef
2140 : *
2141 : * Returns the definition for the constraint, ie, everything that needs to
2142 : * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2143 : */
2144 : Datum
2145 2338 : pg_get_constraintdef(PG_FUNCTION_ARGS)
2146 : {
2147 2338 : Oid constraintId = PG_GETARG_OID(0);
2148 : int prettyFlags;
2149 : char *res;
2150 :
2151 2338 : prettyFlags = PRETTYFLAG_INDENT;
2152 :
2153 2338 : res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2154 :
2155 2338 : if (res == NULL)
2156 6 : PG_RETURN_NULL();
2157 :
2158 2332 : PG_RETURN_TEXT_P(string_to_text(res));
2159 : }
2160 :
2161 : Datum
2162 4858 : pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
2163 : {
2164 4858 : Oid constraintId = PG_GETARG_OID(0);
2165 4858 : bool pretty = PG_GETARG_BOOL(1);
2166 : int prettyFlags;
2167 : char *res;
2168 :
2169 4858 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2170 :
2171 4858 : res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2172 :
2173 4858 : if (res == NULL)
2174 0 : PG_RETURN_NULL();
2175 :
2176 4858 : PG_RETURN_TEXT_P(string_to_text(res));
2177 : }
2178 :
2179 : /*
2180 : * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2181 : */
2182 : char *
2183 608 : pg_get_constraintdef_command(Oid constraintId)
2184 : {
2185 608 : return pg_get_constraintdef_worker(constraintId, true, 0, false);
2186 : }
2187 :
2188 : /*
2189 : * As of 9.4, we now use an MVCC snapshot for this.
2190 : */
2191 : static char *
2192 7804 : pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
2193 : int prettyFlags, bool missing_ok)
2194 : {
2195 : HeapTuple tup;
2196 : Form_pg_constraint conForm;
2197 : StringInfoData buf;
2198 : SysScanDesc scandesc;
2199 : ScanKeyData scankey[1];
2200 7804 : Snapshot snapshot = RegisterSnapshot(GetTransactionSnapshot());
2201 7804 : Relation relation = table_open(ConstraintRelationId, AccessShareLock);
2202 :
2203 7804 : ScanKeyInit(&scankey[0],
2204 : Anum_pg_constraint_oid,
2205 : BTEqualStrategyNumber, F_OIDEQ,
2206 : ObjectIdGetDatum(constraintId));
2207 :
2208 7804 : scandesc = systable_beginscan(relation,
2209 : ConstraintOidIndexId,
2210 : true,
2211 : snapshot,
2212 : 1,
2213 : scankey);
2214 :
2215 : /*
2216 : * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2217 : * via SearchSysCache, which works fine.
2218 : */
2219 7804 : tup = systable_getnext(scandesc);
2220 :
2221 7804 : UnregisterSnapshot(snapshot);
2222 :
2223 7804 : if (!HeapTupleIsValid(tup))
2224 : {
2225 6 : if (missing_ok)
2226 : {
2227 6 : systable_endscan(scandesc);
2228 6 : table_close(relation, AccessShareLock);
2229 6 : return NULL;
2230 : }
2231 0 : elog(ERROR, "could not find tuple for constraint %u", constraintId);
2232 : }
2233 :
2234 7798 : conForm = (Form_pg_constraint) GETSTRUCT(tup);
2235 :
2236 7798 : initStringInfo(&buf);
2237 :
2238 7798 : if (fullCommand)
2239 : {
2240 608 : if (OidIsValid(conForm->conrelid))
2241 : {
2242 : /*
2243 : * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2244 : * constraints, and other types of constraints don't inherit
2245 : * anyway so it doesn't matter whether we say ONLY or not. Someday
2246 : * we might need to let callers specify whether to put ONLY in the
2247 : * command.
2248 : */
2249 594 : appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2250 : generate_qualified_relation_name(conForm->conrelid),
2251 594 : quote_identifier(NameStr(conForm->conname)));
2252 : }
2253 : else
2254 : {
2255 : /* Must be a domain constraint */
2256 : Assert(OidIsValid(conForm->contypid));
2257 14 : appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2258 : generate_qualified_type_name(conForm->contypid),
2259 14 : quote_identifier(NameStr(conForm->conname)));
2260 : }
2261 : }
2262 :
2263 7798 : switch (conForm->contype)
2264 : {
2265 760 : case CONSTRAINT_FOREIGN:
2266 : {
2267 : Datum val;
2268 : bool isnull;
2269 : const char *string;
2270 :
2271 : /* Start off the constraint definition */
2272 760 : appendStringInfoString(&buf, "FOREIGN KEY (");
2273 :
2274 : /* Fetch and build referencing-column list */
2275 760 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2276 : Anum_pg_constraint_conkey);
2277 :
2278 : /* If it is a temporal foreign key then it uses PERIOD. */
2279 760 : decompile_column_index_array(val, conForm->conrelid, conForm->conperiod, &buf);
2280 :
2281 : /* add foreign relation name */
2282 760 : appendStringInfo(&buf, ") REFERENCES %s(",
2283 : generate_relation_name(conForm->confrelid,
2284 : NIL));
2285 :
2286 : /* Fetch and build referenced-column list */
2287 760 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2288 : Anum_pg_constraint_confkey);
2289 :
2290 760 : decompile_column_index_array(val, conForm->confrelid, conForm->conperiod, &buf);
2291 :
2292 760 : appendStringInfoChar(&buf, ')');
2293 :
2294 : /* Add match type */
2295 760 : switch (conForm->confmatchtype)
2296 : {
2297 34 : case FKCONSTR_MATCH_FULL:
2298 34 : string = " MATCH FULL";
2299 34 : break;
2300 0 : case FKCONSTR_MATCH_PARTIAL:
2301 0 : string = " MATCH PARTIAL";
2302 0 : break;
2303 726 : case FKCONSTR_MATCH_SIMPLE:
2304 726 : string = "";
2305 726 : break;
2306 0 : default:
2307 0 : elog(ERROR, "unrecognized confmatchtype: %d",
2308 : conForm->confmatchtype);
2309 : string = ""; /* keep compiler quiet */
2310 : break;
2311 : }
2312 760 : appendStringInfoString(&buf, string);
2313 :
2314 : /* Add ON UPDATE and ON DELETE clauses, if needed */
2315 760 : switch (conForm->confupdtype)
2316 : {
2317 624 : case FKCONSTR_ACTION_NOACTION:
2318 624 : string = NULL; /* suppress default */
2319 624 : break;
2320 0 : case FKCONSTR_ACTION_RESTRICT:
2321 0 : string = "RESTRICT";
2322 0 : break;
2323 108 : case FKCONSTR_ACTION_CASCADE:
2324 108 : string = "CASCADE";
2325 108 : break;
2326 28 : case FKCONSTR_ACTION_SETNULL:
2327 28 : string = "SET NULL";
2328 28 : break;
2329 0 : case FKCONSTR_ACTION_SETDEFAULT:
2330 0 : string = "SET DEFAULT";
2331 0 : break;
2332 0 : default:
2333 0 : elog(ERROR, "unrecognized confupdtype: %d",
2334 : conForm->confupdtype);
2335 : string = NULL; /* keep compiler quiet */
2336 : break;
2337 : }
2338 760 : if (string)
2339 136 : appendStringInfo(&buf, " ON UPDATE %s", string);
2340 :
2341 760 : switch (conForm->confdeltype)
2342 : {
2343 628 : case FKCONSTR_ACTION_NOACTION:
2344 628 : string = NULL; /* suppress default */
2345 628 : break;
2346 0 : case FKCONSTR_ACTION_RESTRICT:
2347 0 : string = "RESTRICT";
2348 0 : break;
2349 108 : case FKCONSTR_ACTION_CASCADE:
2350 108 : string = "CASCADE";
2351 108 : break;
2352 18 : case FKCONSTR_ACTION_SETNULL:
2353 18 : string = "SET NULL";
2354 18 : break;
2355 6 : case FKCONSTR_ACTION_SETDEFAULT:
2356 6 : string = "SET DEFAULT";
2357 6 : break;
2358 0 : default:
2359 0 : elog(ERROR, "unrecognized confdeltype: %d",
2360 : conForm->confdeltype);
2361 : string = NULL; /* keep compiler quiet */
2362 : break;
2363 : }
2364 760 : if (string)
2365 132 : appendStringInfo(&buf, " ON DELETE %s", string);
2366 :
2367 : /*
2368 : * Add columns specified to SET NULL or SET DEFAULT if
2369 : * provided.
2370 : */
2371 760 : val = SysCacheGetAttr(CONSTROID, tup,
2372 : Anum_pg_constraint_confdelsetcols, &isnull);
2373 760 : if (!isnull)
2374 : {
2375 12 : appendStringInfoString(&buf, " (");
2376 12 : decompile_column_index_array(val, conForm->conrelid, false, &buf);
2377 12 : appendStringInfoChar(&buf, ')');
2378 : }
2379 :
2380 760 : break;
2381 : }
2382 4064 : case CONSTRAINT_PRIMARY:
2383 : case CONSTRAINT_UNIQUE:
2384 : {
2385 : Datum val;
2386 : Oid indexId;
2387 : int keyatts;
2388 : HeapTuple indtup;
2389 :
2390 : /* Start off the constraint definition */
2391 4064 : if (conForm->contype == CONSTRAINT_PRIMARY)
2392 3318 : appendStringInfoString(&buf, "PRIMARY KEY ");
2393 : else
2394 746 : appendStringInfoString(&buf, "UNIQUE ");
2395 :
2396 4064 : indexId = conForm->conindid;
2397 :
2398 4064 : indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2399 4064 : if (!HeapTupleIsValid(indtup))
2400 0 : elog(ERROR, "cache lookup failed for index %u", indexId);
2401 4064 : if (conForm->contype == CONSTRAINT_UNIQUE &&
2402 746 : ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2403 0 : appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2404 :
2405 4064 : appendStringInfoChar(&buf, '(');
2406 :
2407 : /* Fetch and build target column list */
2408 4064 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2409 : Anum_pg_constraint_conkey);
2410 :
2411 4064 : keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf);
2412 4064 : if (conForm->conperiod)
2413 406 : appendStringInfoString(&buf, " WITHOUT OVERLAPS");
2414 :
2415 4064 : appendStringInfoChar(&buf, ')');
2416 :
2417 : /* Build including column list (from pg_index.indkeys) */
2418 4064 : val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2419 : Anum_pg_index_indnatts);
2420 4064 : if (DatumGetInt32(val) > keyatts)
2421 : {
2422 : Datum cols;
2423 : Datum *keys;
2424 : int nKeys;
2425 : int j;
2426 :
2427 82 : appendStringInfoString(&buf, " INCLUDE (");
2428 :
2429 82 : cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2430 : Anum_pg_index_indkey);
2431 :
2432 82 : deconstruct_array_builtin(DatumGetArrayTypeP(cols), INT2OID,
2433 : &keys, NULL, &nKeys);
2434 :
2435 246 : for (j = keyatts; j < nKeys; j++)
2436 : {
2437 : char *colName;
2438 :
2439 164 : colName = get_attname(conForm->conrelid,
2440 164 : DatumGetInt16(keys[j]), false);
2441 164 : if (j > keyatts)
2442 82 : appendStringInfoString(&buf, ", ");
2443 164 : appendStringInfoString(&buf, quote_identifier(colName));
2444 : }
2445 :
2446 82 : appendStringInfoChar(&buf, ')');
2447 : }
2448 4064 : ReleaseSysCache(indtup);
2449 :
2450 : /* XXX why do we only print these bits if fullCommand? */
2451 4064 : if (fullCommand && OidIsValid(indexId))
2452 : {
2453 204 : char *options = flatten_reloptions(indexId);
2454 : Oid tblspc;
2455 :
2456 204 : if (options)
2457 : {
2458 0 : appendStringInfo(&buf, " WITH (%s)", options);
2459 0 : pfree(options);
2460 : }
2461 :
2462 : /*
2463 : * Print the tablespace, unless it's the database default.
2464 : * This is to help ALTER TABLE usage of this facility,
2465 : * which needs this behavior to recreate exact catalog
2466 : * state.
2467 : */
2468 204 : tblspc = get_rel_tablespace(indexId);
2469 204 : if (OidIsValid(tblspc))
2470 24 : appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2471 24 : quote_identifier(get_tablespace_name(tblspc)));
2472 : }
2473 :
2474 4064 : break;
2475 : }
2476 2402 : case CONSTRAINT_CHECK:
2477 : {
2478 : Datum val;
2479 : char *conbin;
2480 : char *consrc;
2481 : Node *expr;
2482 : List *context;
2483 :
2484 : /* Fetch constraint expression in parsetree form */
2485 2402 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2486 : Anum_pg_constraint_conbin);
2487 :
2488 2402 : conbin = TextDatumGetCString(val);
2489 2402 : expr = stringToNode(conbin);
2490 :
2491 : /* Set up deparsing context for Var nodes in constraint */
2492 2402 : if (conForm->conrelid != InvalidOid)
2493 : {
2494 : /* relation constraint */
2495 2138 : context = deparse_context_for(get_relation_name(conForm->conrelid),
2496 : conForm->conrelid);
2497 : }
2498 : else
2499 : {
2500 : /* domain constraint --- can't have Vars */
2501 264 : context = NIL;
2502 : }
2503 :
2504 2402 : consrc = deparse_expression_pretty(expr, context, false, false,
2505 : prettyFlags, 0);
2506 :
2507 : /*
2508 : * Now emit the constraint definition, adding NO INHERIT if
2509 : * necessary.
2510 : *
2511 : * There are cases where the constraint expression will be
2512 : * fully parenthesized and we don't need the outer parens ...
2513 : * but there are other cases where we do need 'em. Be
2514 : * conservative for now.
2515 : *
2516 : * Note that simply checking for leading '(' and trailing ')'
2517 : * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2518 : */
2519 2402 : appendStringInfo(&buf, "CHECK (%s)%s",
2520 : consrc,
2521 2402 : conForm->connoinherit ? " NO INHERIT" : "");
2522 2402 : break;
2523 : }
2524 468 : case CONSTRAINT_NOTNULL:
2525 : {
2526 468 : if (conForm->conrelid)
2527 : {
2528 : AttrNumber attnum;
2529 :
2530 344 : attnum = extractNotNullColumn(tup);
2531 :
2532 344 : appendStringInfo(&buf, "NOT NULL %s",
2533 344 : quote_identifier(get_attname(conForm->conrelid,
2534 : attnum, false)));
2535 344 : if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
2536 0 : appendStringInfoString(&buf, " NO INHERIT");
2537 : }
2538 124 : else if (conForm->contypid)
2539 : {
2540 : /* conkey is null for domain not-null constraints */
2541 124 : appendStringInfoString(&buf, "NOT NULL");
2542 : }
2543 468 : break;
2544 : }
2545 :
2546 0 : case CONSTRAINT_TRIGGER:
2547 :
2548 : /*
2549 : * There isn't an ALTER TABLE syntax for creating a user-defined
2550 : * constraint trigger, but it seems better to print something than
2551 : * throw an error; if we throw error then this function couldn't
2552 : * safely be applied to all rows of pg_constraint.
2553 : */
2554 0 : appendStringInfoString(&buf, "TRIGGER");
2555 0 : break;
2556 104 : case CONSTRAINT_EXCLUSION:
2557 : {
2558 104 : Oid indexOid = conForm->conindid;
2559 : Datum val;
2560 : Datum *elems;
2561 : int nElems;
2562 : int i;
2563 : Oid *operators;
2564 :
2565 : /* Extract operator OIDs from the pg_constraint tuple */
2566 104 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2567 : Anum_pg_constraint_conexclop);
2568 :
2569 104 : deconstruct_array_builtin(DatumGetArrayTypeP(val), OIDOID,
2570 : &elems, NULL, &nElems);
2571 :
2572 104 : operators = (Oid *) palloc(nElems * sizeof(Oid));
2573 228 : for (i = 0; i < nElems; i++)
2574 124 : operators[i] = DatumGetObjectId(elems[i]);
2575 :
2576 : /* pg_get_indexdef_worker does the rest */
2577 : /* suppress tablespace because pg_dump wants it that way */
2578 104 : appendStringInfoString(&buf,
2579 104 : pg_get_indexdef_worker(indexOid,
2580 : 0,
2581 : operators,
2582 : false,
2583 : false,
2584 : false,
2585 : false,
2586 : prettyFlags,
2587 : false));
2588 104 : break;
2589 : }
2590 0 : default:
2591 0 : elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2592 : break;
2593 : }
2594 :
2595 7798 : if (conForm->condeferrable)
2596 120 : appendStringInfoString(&buf, " DEFERRABLE");
2597 7798 : if (conForm->condeferred)
2598 48 : appendStringInfoString(&buf, " INITIALLY DEFERRED");
2599 :
2600 : /* Validated status is irrelevant when the constraint is NOT ENFORCED. */
2601 7798 : if (!conForm->conenforced)
2602 92 : appendStringInfoString(&buf, " NOT ENFORCED");
2603 7706 : else if (!conForm->convalidated)
2604 260 : appendStringInfoString(&buf, " NOT VALID");
2605 :
2606 : /* Cleanup */
2607 7798 : systable_endscan(scandesc);
2608 7798 : table_close(relation, AccessShareLock);
2609 :
2610 7798 : return buf.data;
2611 : }
2612 :
2613 :
2614 : /*
2615 : * Convert an int16[] Datum into a comma-separated list of column names
2616 : * for the indicated relation; append the list to buf. Returns the number
2617 : * of keys.
2618 : */
2619 : static int
2620 5596 : decompile_column_index_array(Datum column_index_array, Oid relId,
2621 : bool withPeriod, StringInfo buf)
2622 : {
2623 : Datum *keys;
2624 : int nKeys;
2625 : int j;
2626 :
2627 : /* Extract data from array of int16 */
2628 5596 : deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2629 : &keys, NULL, &nKeys);
2630 :
2631 13552 : for (j = 0; j < nKeys; j++)
2632 : {
2633 : char *colName;
2634 :
2635 7956 : colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2636 :
2637 7956 : if (j == 0)
2638 5596 : appendStringInfoString(buf, quote_identifier(colName));
2639 : else
2640 2588 : appendStringInfo(buf, ", %s%s",
2641 228 : (withPeriod && j == nKeys - 1) ? "PERIOD " : "",
2642 : quote_identifier(colName));
2643 : }
2644 :
2645 5596 : return nKeys;
2646 : }
2647 :
2648 :
2649 : /* ----------
2650 : * pg_get_expr - Decompile an expression tree
2651 : *
2652 : * Input: an expression tree in nodeToString form, and a relation OID
2653 : *
2654 : * Output: reverse-listed expression
2655 : *
2656 : * Currently, the expression can only refer to a single relation, namely
2657 : * the one specified by the second parameter. This is sufficient for
2658 : * partial indexes, column default expressions, etc. We also support
2659 : * Var-free expressions, for which the OID can be InvalidOid.
2660 : *
2661 : * If the OID is nonzero but not actually valid, don't throw an error,
2662 : * just return NULL. This is a bit questionable, but it's what we've
2663 : * done historically, and it can help avoid unwanted failures when
2664 : * examining catalog entries for just-deleted relations.
2665 : *
2666 : * We expect this function to work, or throw a reasonably clean error,
2667 : * for any node tree that can appear in a catalog pg_node_tree column.
2668 : * Query trees, such as those appearing in pg_rewrite.ev_action, are
2669 : * not supported. Nor are expressions in more than one relation, which
2670 : * can appear in places like pg_rewrite.ev_qual.
2671 : * ----------
2672 : */
2673 : Datum
2674 8900 : pg_get_expr(PG_FUNCTION_ARGS)
2675 : {
2676 8900 : text *expr = PG_GETARG_TEXT_PP(0);
2677 8900 : Oid relid = PG_GETARG_OID(1);
2678 : text *result;
2679 : int prettyFlags;
2680 :
2681 8900 : prettyFlags = PRETTYFLAG_INDENT;
2682 :
2683 8900 : result = pg_get_expr_worker(expr, relid, prettyFlags);
2684 8900 : if (result)
2685 8892 : PG_RETURN_TEXT_P(result);
2686 : else
2687 8 : PG_RETURN_NULL();
2688 : }
2689 :
2690 : Datum
2691 724 : pg_get_expr_ext(PG_FUNCTION_ARGS)
2692 : {
2693 724 : text *expr = PG_GETARG_TEXT_PP(0);
2694 724 : Oid relid = PG_GETARG_OID(1);
2695 724 : bool pretty = PG_GETARG_BOOL(2);
2696 : text *result;
2697 : int prettyFlags;
2698 :
2699 724 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2700 :
2701 724 : result = pg_get_expr_worker(expr, relid, prettyFlags);
2702 724 : if (result)
2703 724 : PG_RETURN_TEXT_P(result);
2704 : else
2705 0 : PG_RETURN_NULL();
2706 : }
2707 :
2708 : static text *
2709 9624 : pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
2710 : {
2711 : Node *node;
2712 : Node *tst;
2713 : Relids relids;
2714 : List *context;
2715 : char *exprstr;
2716 9624 : Relation rel = NULL;
2717 : char *str;
2718 :
2719 : /* Convert input pg_node_tree (really TEXT) object to C string */
2720 9624 : exprstr = text_to_cstring(expr);
2721 :
2722 : /* Convert expression to node tree */
2723 9624 : node = (Node *) stringToNode(exprstr);
2724 :
2725 9624 : pfree(exprstr);
2726 :
2727 : /*
2728 : * Throw error if the input is a querytree rather than an expression tree.
2729 : * While we could support queries here, there seems no very good reason
2730 : * to. In most such catalog columns, we'll see a List of Query nodes, or
2731 : * even nested Lists, so drill down to a non-List node before checking.
2732 : */
2733 9624 : tst = node;
2734 9624 : while (tst && IsA(tst, List))
2735 0 : tst = linitial((List *) tst);
2736 9624 : if (tst && IsA(tst, Query))
2737 0 : ereport(ERROR,
2738 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2739 : errmsg("input is a query, not an expression")));
2740 :
2741 : /*
2742 : * Throw error if the expression contains Vars we won't be able to
2743 : * deparse.
2744 : */
2745 9624 : relids = pull_varnos(NULL, node);
2746 9624 : if (OidIsValid(relid))
2747 : {
2748 9540 : if (!bms_is_subset(relids, bms_make_singleton(1)))
2749 0 : ereport(ERROR,
2750 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2751 : errmsg("expression contains variables of more than one relation")));
2752 : }
2753 : else
2754 : {
2755 84 : if (!bms_is_empty(relids))
2756 0 : ereport(ERROR,
2757 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2758 : errmsg("expression contains variables")));
2759 : }
2760 :
2761 : /*
2762 : * Prepare deparse context if needed. If we are deparsing with a relid,
2763 : * we need to transiently open and lock the rel, to make sure it won't go
2764 : * away underneath us. (set_relation_column_names would lock it anyway,
2765 : * so this isn't really introducing any new behavior.)
2766 : */
2767 9624 : if (OidIsValid(relid))
2768 : {
2769 9540 : rel = try_relation_open(relid, AccessShareLock);
2770 9540 : if (rel == NULL)
2771 8 : return NULL;
2772 9532 : context = deparse_context_for(RelationGetRelationName(rel), relid);
2773 : }
2774 : else
2775 84 : context = NIL;
2776 :
2777 : /* Deparse */
2778 9616 : str = deparse_expression_pretty(node, context, false, false,
2779 : prettyFlags, 0);
2780 :
2781 9616 : if (rel != NULL)
2782 9532 : relation_close(rel, AccessShareLock);
2783 :
2784 9616 : return string_to_text(str);
2785 : }
2786 :
2787 :
2788 : /* ----------
2789 : * pg_get_userbyid - Get a user name by roleid and
2790 : * fallback to 'unknown (OID=n)'
2791 : * ----------
2792 : */
2793 : Datum
2794 1734 : pg_get_userbyid(PG_FUNCTION_ARGS)
2795 : {
2796 1734 : Oid roleid = PG_GETARG_OID(0);
2797 : Name result;
2798 : HeapTuple roletup;
2799 : Form_pg_authid role_rec;
2800 :
2801 : /*
2802 : * Allocate space for the result
2803 : */
2804 1734 : result = (Name) palloc(NAMEDATALEN);
2805 1734 : memset(NameStr(*result), 0, NAMEDATALEN);
2806 :
2807 : /*
2808 : * Get the pg_authid entry and print the result
2809 : */
2810 1734 : roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2811 1734 : if (HeapTupleIsValid(roletup))
2812 : {
2813 1734 : role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2814 1734 : *result = role_rec->rolname;
2815 1734 : ReleaseSysCache(roletup);
2816 : }
2817 : else
2818 0 : sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2819 :
2820 1734 : PG_RETURN_NAME(result);
2821 : }
2822 :
2823 :
2824 : /*
2825 : * pg_get_serial_sequence
2826 : * Get the name of the sequence used by an identity or serial column,
2827 : * formatted suitably for passing to setval, nextval or currval.
2828 : * First parameter is not treated as double-quoted, second parameter
2829 : * is --- see documentation for reason.
2830 : */
2831 : Datum
2832 12 : pg_get_serial_sequence(PG_FUNCTION_ARGS)
2833 : {
2834 12 : text *tablename = PG_GETARG_TEXT_PP(0);
2835 12 : text *columnname = PG_GETARG_TEXT_PP(1);
2836 : RangeVar *tablerv;
2837 : Oid tableOid;
2838 : char *column;
2839 : AttrNumber attnum;
2840 12 : Oid sequenceId = InvalidOid;
2841 : Relation depRel;
2842 : ScanKeyData key[3];
2843 : SysScanDesc scan;
2844 : HeapTuple tup;
2845 :
2846 : /* Look up table name. Can't lock it - we might not have privileges. */
2847 12 : tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2848 12 : tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2849 :
2850 : /* Get the number of the column */
2851 12 : column = text_to_cstring(columnname);
2852 :
2853 12 : attnum = get_attnum(tableOid, column);
2854 12 : if (attnum == InvalidAttrNumber)
2855 0 : ereport(ERROR,
2856 : (errcode(ERRCODE_UNDEFINED_COLUMN),
2857 : errmsg("column \"%s\" of relation \"%s\" does not exist",
2858 : column, tablerv->relname)));
2859 :
2860 : /* Search the dependency table for the dependent sequence */
2861 12 : depRel = table_open(DependRelationId, AccessShareLock);
2862 :
2863 12 : ScanKeyInit(&key[0],
2864 : Anum_pg_depend_refclassid,
2865 : BTEqualStrategyNumber, F_OIDEQ,
2866 : ObjectIdGetDatum(RelationRelationId));
2867 12 : ScanKeyInit(&key[1],
2868 : Anum_pg_depend_refobjid,
2869 : BTEqualStrategyNumber, F_OIDEQ,
2870 : ObjectIdGetDatum(tableOid));
2871 12 : ScanKeyInit(&key[2],
2872 : Anum_pg_depend_refobjsubid,
2873 : BTEqualStrategyNumber, F_INT4EQ,
2874 : Int32GetDatum(attnum));
2875 :
2876 12 : scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2877 : NULL, 3, key);
2878 :
2879 30 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
2880 : {
2881 30 : Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2882 :
2883 : /*
2884 : * Look for an auto dependency (serial column) or internal dependency
2885 : * (identity column) of a sequence on a column. (We need the relkind
2886 : * test because indexes can also have auto dependencies on columns.)
2887 : */
2888 30 : if (deprec->classid == RelationRelationId &&
2889 12 : deprec->objsubid == 0 &&
2890 12 : (deprec->deptype == DEPENDENCY_AUTO ||
2891 18 : deprec->deptype == DEPENDENCY_INTERNAL) &&
2892 12 : get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2893 : {
2894 12 : sequenceId = deprec->objid;
2895 12 : break;
2896 : }
2897 : }
2898 :
2899 12 : systable_endscan(scan);
2900 12 : table_close(depRel, AccessShareLock);
2901 :
2902 12 : if (OidIsValid(sequenceId))
2903 : {
2904 : char *result;
2905 :
2906 12 : result = generate_qualified_relation_name(sequenceId);
2907 :
2908 12 : PG_RETURN_TEXT_P(string_to_text(result));
2909 : }
2910 :
2911 0 : PG_RETURN_NULL();
2912 : }
2913 :
2914 :
2915 : /*
2916 : * pg_get_functiondef
2917 : * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2918 : * the specified function.
2919 : *
2920 : * Note: if you change the output format of this function, be careful not
2921 : * to break psql's rules (in \ef and \sf) for identifying the start of the
2922 : * function body. To wit: the function body starts on a line that begins with
2923 : * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
2924 : */
2925 : Datum
2926 172 : pg_get_functiondef(PG_FUNCTION_ARGS)
2927 : {
2928 172 : Oid funcid = PG_GETARG_OID(0);
2929 : StringInfoData buf;
2930 : StringInfoData dq;
2931 : HeapTuple proctup;
2932 : Form_pg_proc proc;
2933 : bool isfunction;
2934 : Datum tmp;
2935 : bool isnull;
2936 : const char *prosrc;
2937 : const char *name;
2938 : const char *nsp;
2939 : float4 procost;
2940 : int oldlen;
2941 :
2942 172 : initStringInfo(&buf);
2943 :
2944 : /* Look up the function */
2945 172 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2946 172 : if (!HeapTupleIsValid(proctup))
2947 6 : PG_RETURN_NULL();
2948 :
2949 166 : proc = (Form_pg_proc) GETSTRUCT(proctup);
2950 166 : name = NameStr(proc->proname);
2951 :
2952 166 : if (proc->prokind == PROKIND_AGGREGATE)
2953 0 : ereport(ERROR,
2954 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2955 : errmsg("\"%s\" is an aggregate function", name)));
2956 :
2957 166 : isfunction = (proc->prokind != PROKIND_PROCEDURE);
2958 :
2959 : /*
2960 : * We always qualify the function name, to ensure the right function gets
2961 : * replaced.
2962 : */
2963 166 : nsp = get_namespace_name_or_temp(proc->pronamespace);
2964 166 : appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2965 : isfunction ? "FUNCTION" : "PROCEDURE",
2966 : quote_qualified_identifier(nsp, name));
2967 166 : (void) print_function_arguments(&buf, proctup, false, true);
2968 166 : appendStringInfoString(&buf, ")\n");
2969 166 : if (isfunction)
2970 : {
2971 146 : appendStringInfoString(&buf, " RETURNS ");
2972 146 : print_function_rettype(&buf, proctup);
2973 146 : appendStringInfoChar(&buf, '\n');
2974 : }
2975 :
2976 166 : print_function_trftypes(&buf, proctup);
2977 :
2978 166 : appendStringInfo(&buf, " LANGUAGE %s\n",
2979 166 : quote_identifier(get_language_name(proc->prolang, false)));
2980 :
2981 : /* Emit some miscellaneous options on one line */
2982 166 : oldlen = buf.len;
2983 :
2984 166 : if (proc->prokind == PROKIND_WINDOW)
2985 0 : appendStringInfoString(&buf, " WINDOW");
2986 166 : switch (proc->provolatile)
2987 : {
2988 12 : case PROVOLATILE_IMMUTABLE:
2989 12 : appendStringInfoString(&buf, " IMMUTABLE");
2990 12 : break;
2991 30 : case PROVOLATILE_STABLE:
2992 30 : appendStringInfoString(&buf, " STABLE");
2993 30 : break;
2994 124 : case PROVOLATILE_VOLATILE:
2995 124 : break;
2996 : }
2997 :
2998 166 : switch (proc->proparallel)
2999 : {
3000 28 : case PROPARALLEL_SAFE:
3001 28 : appendStringInfoString(&buf, " PARALLEL SAFE");
3002 28 : break;
3003 0 : case PROPARALLEL_RESTRICTED:
3004 0 : appendStringInfoString(&buf, " PARALLEL RESTRICTED");
3005 0 : break;
3006 138 : case PROPARALLEL_UNSAFE:
3007 138 : break;
3008 : }
3009 :
3010 166 : if (proc->proisstrict)
3011 50 : appendStringInfoString(&buf, " STRICT");
3012 166 : if (proc->prosecdef)
3013 6 : appendStringInfoString(&buf, " SECURITY DEFINER");
3014 166 : if (proc->proleakproof)
3015 0 : appendStringInfoString(&buf, " LEAKPROOF");
3016 :
3017 : /* This code for the default cost and rows should match functioncmds.c */
3018 166 : if (proc->prolang == INTERNALlanguageId ||
3019 166 : proc->prolang == ClanguageId)
3020 10 : procost = 1;
3021 : else
3022 156 : procost = 100;
3023 166 : if (proc->procost != procost)
3024 6 : appendStringInfo(&buf, " COST %g", proc->procost);
3025 :
3026 166 : if (proc->prorows > 0 && proc->prorows != 1000)
3027 0 : appendStringInfo(&buf, " ROWS %g", proc->prorows);
3028 :
3029 166 : if (proc->prosupport)
3030 : {
3031 : Oid argtypes[1];
3032 :
3033 : /*
3034 : * We should qualify the support function's name if it wouldn't be
3035 : * resolved by lookup in the current search path.
3036 : */
3037 0 : argtypes[0] = INTERNALOID;
3038 0 : appendStringInfo(&buf, " SUPPORT %s",
3039 : generate_function_name(proc->prosupport, 1,
3040 : NIL, argtypes,
3041 : false, NULL, false));
3042 : }
3043 :
3044 166 : if (oldlen != buf.len)
3045 64 : appendStringInfoChar(&buf, '\n');
3046 :
3047 : /* Emit any proconfig options, one per line */
3048 166 : tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
3049 166 : if (!isnull)
3050 : {
3051 6 : ArrayType *a = DatumGetArrayTypeP(tmp);
3052 : int i;
3053 :
3054 : Assert(ARR_ELEMTYPE(a) == TEXTOID);
3055 : Assert(ARR_NDIM(a) == 1);
3056 : Assert(ARR_LBOUND(a)[0] == 1);
3057 :
3058 36 : for (i = 1; i <= ARR_DIMS(a)[0]; i++)
3059 : {
3060 : Datum d;
3061 :
3062 30 : d = array_ref(a, 1, &i,
3063 : -1 /* varlenarray */ ,
3064 : -1 /* TEXT's typlen */ ,
3065 : false /* TEXT's typbyval */ ,
3066 : TYPALIGN_INT /* TEXT's typalign */ ,
3067 : &isnull);
3068 30 : if (!isnull)
3069 : {
3070 30 : char *configitem = TextDatumGetCString(d);
3071 : char *pos;
3072 :
3073 30 : pos = strchr(configitem, '=');
3074 30 : if (pos == NULL)
3075 0 : continue;
3076 30 : *pos++ = '\0';
3077 :
3078 30 : appendStringInfo(&buf, " SET %s TO ",
3079 : quote_identifier(configitem));
3080 :
3081 : /*
3082 : * Variables that are marked GUC_LIST_QUOTE were already fully
3083 : * quoted by flatten_set_variable_args() before they were put
3084 : * into the proconfig array. However, because the quoting
3085 : * rules used there aren't exactly like SQL's, we have to
3086 : * break the list value apart and then quote the elements as
3087 : * string literals. (The elements may be double-quoted as-is,
3088 : * but we can't just feed them to the SQL parser; it would do
3089 : * the wrong thing with elements that are zero-length or
3090 : * longer than NAMEDATALEN.)
3091 : *
3092 : * Variables that are not so marked should just be emitted as
3093 : * simple string literals. If the variable is not known to
3094 : * guc.c, we'll do that; this makes it unsafe to use
3095 : * GUC_LIST_QUOTE for extension variables.
3096 : */
3097 30 : if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3098 : {
3099 : List *namelist;
3100 : ListCell *lc;
3101 :
3102 : /* Parse string into list of identifiers */
3103 12 : if (!SplitGUCList(pos, ',', &namelist))
3104 : {
3105 : /* this shouldn't fail really */
3106 0 : elog(ERROR, "invalid list syntax in proconfig item");
3107 : }
3108 42 : foreach(lc, namelist)
3109 : {
3110 30 : char *curname = (char *) lfirst(lc);
3111 :
3112 30 : simple_quote_literal(&buf, curname);
3113 30 : if (lnext(namelist, lc))
3114 18 : appendStringInfoString(&buf, ", ");
3115 : }
3116 : }
3117 : else
3118 18 : simple_quote_literal(&buf, pos);
3119 30 : appendStringInfoChar(&buf, '\n');
3120 : }
3121 : }
3122 : }
3123 :
3124 : /* And finally the function definition ... */
3125 166 : (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3126 166 : if (proc->prolang == SQLlanguageId && !isnull)
3127 : {
3128 114 : print_function_sqlbody(&buf, proctup);
3129 : }
3130 : else
3131 : {
3132 52 : appendStringInfoString(&buf, "AS ");
3133 :
3134 52 : tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
3135 52 : if (!isnull)
3136 : {
3137 10 : simple_quote_literal(&buf, TextDatumGetCString(tmp));
3138 10 : appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3139 : }
3140 :
3141 52 : tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
3142 52 : prosrc = TextDatumGetCString(tmp);
3143 :
3144 : /*
3145 : * We always use dollar quoting. Figure out a suitable delimiter.
3146 : *
3147 : * Since the user is likely to be editing the function body string, we
3148 : * shouldn't use a short delimiter that he might easily create a
3149 : * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3150 : * if needed.
3151 : */
3152 52 : initStringInfo(&dq);
3153 52 : appendStringInfoChar(&dq, '$');
3154 52 : appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3155 52 : while (strstr(prosrc, dq.data) != NULL)
3156 0 : appendStringInfoChar(&dq, 'x');
3157 52 : appendStringInfoChar(&dq, '$');
3158 :
3159 52 : appendBinaryStringInfo(&buf, dq.data, dq.len);
3160 52 : appendStringInfoString(&buf, prosrc);
3161 52 : appendBinaryStringInfo(&buf, dq.data, dq.len);
3162 : }
3163 :
3164 166 : appendStringInfoChar(&buf, '\n');
3165 :
3166 166 : ReleaseSysCache(proctup);
3167 :
3168 166 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3169 : }
3170 :
3171 : /*
3172 : * pg_get_function_arguments
3173 : * Get a nicely-formatted list of arguments for a function.
3174 : * This is everything that would go between the parentheses in
3175 : * CREATE FUNCTION.
3176 : */
3177 : Datum
3178 4752 : pg_get_function_arguments(PG_FUNCTION_ARGS)
3179 : {
3180 4752 : Oid funcid = PG_GETARG_OID(0);
3181 : StringInfoData buf;
3182 : HeapTuple proctup;
3183 :
3184 4752 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3185 4752 : if (!HeapTupleIsValid(proctup))
3186 6 : PG_RETURN_NULL();
3187 :
3188 4746 : initStringInfo(&buf);
3189 :
3190 4746 : (void) print_function_arguments(&buf, proctup, false, true);
3191 :
3192 4746 : ReleaseSysCache(proctup);
3193 :
3194 4746 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3195 : }
3196 :
3197 : /*
3198 : * pg_get_function_identity_arguments
3199 : * Get a formatted list of arguments for a function.
3200 : * This is everything that would go between the parentheses in
3201 : * ALTER FUNCTION, etc. In particular, don't print defaults.
3202 : */
3203 : Datum
3204 4220 : pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
3205 : {
3206 4220 : Oid funcid = PG_GETARG_OID(0);
3207 : StringInfoData buf;
3208 : HeapTuple proctup;
3209 :
3210 4220 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3211 4220 : if (!HeapTupleIsValid(proctup))
3212 6 : PG_RETURN_NULL();
3213 :
3214 4214 : initStringInfo(&buf);
3215 :
3216 4214 : (void) print_function_arguments(&buf, proctup, false, false);
3217 :
3218 4214 : ReleaseSysCache(proctup);
3219 :
3220 4214 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3221 : }
3222 :
3223 : /*
3224 : * pg_get_function_result
3225 : * Get a nicely-formatted version of the result type of a function.
3226 : * This is what would appear after RETURNS in CREATE FUNCTION.
3227 : */
3228 : Datum
3229 4156 : pg_get_function_result(PG_FUNCTION_ARGS)
3230 : {
3231 4156 : Oid funcid = PG_GETARG_OID(0);
3232 : StringInfoData buf;
3233 : HeapTuple proctup;
3234 :
3235 4156 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3236 4156 : if (!HeapTupleIsValid(proctup))
3237 6 : PG_RETURN_NULL();
3238 :
3239 4150 : if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3240 : {
3241 250 : ReleaseSysCache(proctup);
3242 250 : PG_RETURN_NULL();
3243 : }
3244 :
3245 3900 : initStringInfo(&buf);
3246 :
3247 3900 : print_function_rettype(&buf, proctup);
3248 :
3249 3900 : ReleaseSysCache(proctup);
3250 :
3251 3900 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3252 : }
3253 :
3254 : /*
3255 : * Guts of pg_get_function_result: append the function's return type
3256 : * to the specified buffer.
3257 : */
3258 : static void
3259 4046 : print_function_rettype(StringInfo buf, HeapTuple proctup)
3260 : {
3261 4046 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3262 4046 : int ntabargs = 0;
3263 : StringInfoData rbuf;
3264 :
3265 4046 : initStringInfo(&rbuf);
3266 :
3267 4046 : if (proc->proretset)
3268 : {
3269 : /* It might be a table function; try to print the arguments */
3270 416 : appendStringInfoString(&rbuf, "TABLE(");
3271 416 : ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3272 416 : if (ntabargs > 0)
3273 76 : appendStringInfoChar(&rbuf, ')');
3274 : else
3275 340 : resetStringInfo(&rbuf);
3276 : }
3277 :
3278 4046 : if (ntabargs == 0)
3279 : {
3280 : /* Not a table function, so do the normal thing */
3281 3970 : if (proc->proretset)
3282 340 : appendStringInfoString(&rbuf, "SETOF ");
3283 3970 : appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3284 : }
3285 :
3286 4046 : appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3287 4046 : }
3288 :
3289 : /*
3290 : * Common code for pg_get_function_arguments and pg_get_function_result:
3291 : * append the desired subset of arguments to buf. We print only TABLE
3292 : * arguments when print_table_args is true, and all the others when it's false.
3293 : * We print argument defaults only if print_defaults is true.
3294 : * Function return value is the number of arguments printed.
3295 : */
3296 : static int
3297 9542 : print_function_arguments(StringInfo buf, HeapTuple proctup,
3298 : bool print_table_args, bool print_defaults)
3299 : {
3300 9542 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3301 : int numargs;
3302 : Oid *argtypes;
3303 : char **argnames;
3304 : char *argmodes;
3305 9542 : int insertorderbyat = -1;
3306 : int argsprinted;
3307 : int inputargno;
3308 : int nlackdefaults;
3309 9542 : List *argdefaults = NIL;
3310 9542 : ListCell *nextargdefault = NULL;
3311 : int i;
3312 :
3313 9542 : numargs = get_func_arg_info(proctup,
3314 : &argtypes, &argnames, &argmodes);
3315 :
3316 9542 : nlackdefaults = numargs;
3317 9542 : if (print_defaults && proc->pronargdefaults > 0)
3318 : {
3319 : Datum proargdefaults;
3320 : bool isnull;
3321 :
3322 38 : proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3323 : Anum_pg_proc_proargdefaults,
3324 : &isnull);
3325 38 : if (!isnull)
3326 : {
3327 : char *str;
3328 :
3329 38 : str = TextDatumGetCString(proargdefaults);
3330 38 : argdefaults = castNode(List, stringToNode(str));
3331 38 : pfree(str);
3332 38 : nextargdefault = list_head(argdefaults);
3333 : /* nlackdefaults counts only *input* arguments lacking defaults */
3334 38 : nlackdefaults = proc->pronargs - list_length(argdefaults);
3335 : }
3336 : }
3337 :
3338 : /* Check for special treatment of ordered-set aggregates */
3339 9542 : if (proc->prokind == PROKIND_AGGREGATE)
3340 : {
3341 : HeapTuple aggtup;
3342 : Form_pg_aggregate agg;
3343 :
3344 1194 : aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(proc->oid));
3345 1194 : if (!HeapTupleIsValid(aggtup))
3346 0 : elog(ERROR, "cache lookup failed for aggregate %u",
3347 : proc->oid);
3348 1194 : agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3349 1194 : if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3350 52 : insertorderbyat = agg->aggnumdirectargs;
3351 1194 : ReleaseSysCache(aggtup);
3352 : }
3353 :
3354 9542 : argsprinted = 0;
3355 9542 : inputargno = 0;
3356 19072 : for (i = 0; i < numargs; i++)
3357 : {
3358 9530 : Oid argtype = argtypes[i];
3359 9530 : char *argname = argnames ? argnames[i] : NULL;
3360 9530 : char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3361 : const char *modename;
3362 : bool isinput;
3363 :
3364 9530 : switch (argmode)
3365 : {
3366 7852 : case PROARGMODE_IN:
3367 :
3368 : /*
3369 : * For procedures, explicitly mark all argument modes, so as
3370 : * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3371 : */
3372 7852 : if (proc->prokind == PROKIND_PROCEDURE)
3373 556 : modename = "IN ";
3374 : else
3375 7296 : modename = "";
3376 7852 : isinput = true;
3377 7852 : break;
3378 100 : case PROARGMODE_INOUT:
3379 100 : modename = "INOUT ";
3380 100 : isinput = true;
3381 100 : break;
3382 956 : case PROARGMODE_OUT:
3383 956 : modename = "OUT ";
3384 956 : isinput = false;
3385 956 : break;
3386 178 : case PROARGMODE_VARIADIC:
3387 178 : modename = "VARIADIC ";
3388 178 : isinput = true;
3389 178 : break;
3390 444 : case PROARGMODE_TABLE:
3391 444 : modename = "";
3392 444 : isinput = false;
3393 444 : break;
3394 0 : default:
3395 0 : elog(ERROR, "invalid parameter mode '%c'", argmode);
3396 : modename = NULL; /* keep compiler quiet */
3397 : isinput = false;
3398 : break;
3399 : }
3400 9530 : if (isinput)
3401 8130 : inputargno++; /* this is a 1-based counter */
3402 :
3403 9530 : if (print_table_args != (argmode == PROARGMODE_TABLE))
3404 764 : continue;
3405 :
3406 8766 : if (argsprinted == insertorderbyat)
3407 : {
3408 52 : if (argsprinted)
3409 52 : appendStringInfoChar(buf, ' ');
3410 52 : appendStringInfoString(buf, "ORDER BY ");
3411 : }
3412 8714 : else if (argsprinted)
3413 2776 : appendStringInfoString(buf, ", ");
3414 :
3415 8766 : appendStringInfoString(buf, modename);
3416 8766 : if (argname && argname[0])
3417 3130 : appendStringInfo(buf, "%s ", quote_identifier(argname));
3418 8766 : appendStringInfoString(buf, format_type_be(argtype));
3419 8766 : if (print_defaults && isinput && inputargno > nlackdefaults)
3420 : {
3421 : Node *expr;
3422 :
3423 : Assert(nextargdefault != NULL);
3424 58 : expr = (Node *) lfirst(nextargdefault);
3425 58 : nextargdefault = lnext(argdefaults, nextargdefault);
3426 :
3427 58 : appendStringInfo(buf, " DEFAULT %s",
3428 : deparse_expression(expr, NIL, false, false));
3429 : }
3430 8766 : argsprinted++;
3431 :
3432 : /* nasty hack: print the last arg twice for variadic ordered-set agg */
3433 8766 : if (argsprinted == insertorderbyat && i == numargs - 1)
3434 : {
3435 26 : i--;
3436 : /* aggs shouldn't have defaults anyway, but just to be sure ... */
3437 26 : print_defaults = false;
3438 : }
3439 : }
3440 :
3441 9542 : return argsprinted;
3442 : }
3443 :
3444 : static bool
3445 96 : is_input_argument(int nth, const char *argmodes)
3446 : {
3447 : return (!argmodes
3448 42 : || argmodes[nth] == PROARGMODE_IN
3449 18 : || argmodes[nth] == PROARGMODE_INOUT
3450 138 : || argmodes[nth] == PROARGMODE_VARIADIC);
3451 : }
3452 :
3453 : /*
3454 : * Append used transformed types to specified buffer
3455 : */
3456 : static void
3457 166 : print_function_trftypes(StringInfo buf, HeapTuple proctup)
3458 : {
3459 : Oid *trftypes;
3460 : int ntypes;
3461 :
3462 166 : ntypes = get_func_trftypes(proctup, &trftypes);
3463 166 : if (ntypes > 0)
3464 : {
3465 : int i;
3466 :
3467 6 : appendStringInfoString(buf, " TRANSFORM ");
3468 16 : for (i = 0; i < ntypes; i++)
3469 : {
3470 10 : if (i != 0)
3471 4 : appendStringInfoString(buf, ", ");
3472 10 : appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3473 : }
3474 6 : appendStringInfoChar(buf, '\n');
3475 : }
3476 166 : }
3477 :
3478 : /*
3479 : * Get textual representation of a function argument's default value. The
3480 : * second argument of this function is the argument number among all arguments
3481 : * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3482 : * how information_schema.sql uses it.
3483 : */
3484 : Datum
3485 54 : pg_get_function_arg_default(PG_FUNCTION_ARGS)
3486 : {
3487 54 : Oid funcid = PG_GETARG_OID(0);
3488 54 : int32 nth_arg = PG_GETARG_INT32(1);
3489 : HeapTuple proctup;
3490 : Form_pg_proc proc;
3491 : int numargs;
3492 : Oid *argtypes;
3493 : char **argnames;
3494 : char *argmodes;
3495 : int i;
3496 : List *argdefaults;
3497 : Node *node;
3498 : char *str;
3499 : int nth_inputarg;
3500 : Datum proargdefaults;
3501 : bool isnull;
3502 : int nth_default;
3503 :
3504 54 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3505 54 : if (!HeapTupleIsValid(proctup))
3506 12 : PG_RETURN_NULL();
3507 :
3508 42 : numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3509 42 : if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3510 : {
3511 12 : ReleaseSysCache(proctup);
3512 12 : PG_RETURN_NULL();
3513 : }
3514 :
3515 30 : nth_inputarg = 0;
3516 84 : for (i = 0; i < nth_arg; i++)
3517 54 : if (is_input_argument(i, argmodes))
3518 48 : nth_inputarg++;
3519 :
3520 30 : proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3521 : Anum_pg_proc_proargdefaults,
3522 : &isnull);
3523 30 : if (isnull)
3524 : {
3525 0 : ReleaseSysCache(proctup);
3526 0 : PG_RETURN_NULL();
3527 : }
3528 :
3529 30 : str = TextDatumGetCString(proargdefaults);
3530 30 : argdefaults = castNode(List, stringToNode(str));
3531 30 : pfree(str);
3532 :
3533 30 : proc = (Form_pg_proc) GETSTRUCT(proctup);
3534 :
3535 : /*
3536 : * Calculate index into proargdefaults: proargdefaults corresponds to the
3537 : * last N input arguments, where N = pronargdefaults.
3538 : */
3539 30 : nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3540 :
3541 30 : if (nth_default < 0 || nth_default >= list_length(argdefaults))
3542 : {
3543 6 : ReleaseSysCache(proctup);
3544 6 : PG_RETURN_NULL();
3545 : }
3546 24 : node = list_nth(argdefaults, nth_default);
3547 24 : str = deparse_expression(node, NIL, false, false);
3548 :
3549 24 : ReleaseSysCache(proctup);
3550 :
3551 24 : PG_RETURN_TEXT_P(string_to_text(str));
3552 : }
3553 :
3554 : static void
3555 222 : print_function_sqlbody(StringInfo buf, HeapTuple proctup)
3556 : {
3557 : int numargs;
3558 : Oid *argtypes;
3559 : char **argnames;
3560 : char *argmodes;
3561 222 : deparse_namespace dpns = {0};
3562 : Datum tmp;
3563 : Node *n;
3564 :
3565 222 : dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3566 222 : numargs = get_func_arg_info(proctup,
3567 : &argtypes, &argnames, &argmodes);
3568 222 : dpns.numargs = numargs;
3569 222 : dpns.argnames = argnames;
3570 :
3571 222 : tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3572 222 : n = stringToNode(TextDatumGetCString(tmp));
3573 :
3574 222 : if (IsA(n, List))
3575 : {
3576 : List *stmts;
3577 : ListCell *lc;
3578 :
3579 176 : stmts = linitial(castNode(List, n));
3580 :
3581 176 : appendStringInfoString(buf, "BEGIN ATOMIC\n");
3582 :
3583 342 : foreach(lc, stmts)
3584 : {
3585 166 : Query *query = lfirst_node(Query, lc);
3586 :
3587 : /* It seems advisable to get at least AccessShareLock on rels */
3588 166 : AcquireRewriteLocks(query, false, false);
3589 166 : get_query_def(query, buf, list_make1(&dpns), NULL, false,
3590 : PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
3591 166 : appendStringInfoChar(buf, ';');
3592 166 : appendStringInfoChar(buf, '\n');
3593 : }
3594 :
3595 176 : appendStringInfoString(buf, "END");
3596 : }
3597 : else
3598 : {
3599 46 : Query *query = castNode(Query, n);
3600 :
3601 : /* It seems advisable to get at least AccessShareLock on rels */
3602 46 : AcquireRewriteLocks(query, false, false);
3603 46 : get_query_def(query, buf, list_make1(&dpns), NULL, false,
3604 : 0, WRAP_COLUMN_DEFAULT, 0);
3605 : }
3606 222 : }
3607 :
3608 : Datum
3609 3632 : pg_get_function_sqlbody(PG_FUNCTION_ARGS)
3610 : {
3611 3632 : Oid funcid = PG_GETARG_OID(0);
3612 : StringInfoData buf;
3613 : HeapTuple proctup;
3614 : bool isnull;
3615 :
3616 3632 : initStringInfo(&buf);
3617 :
3618 : /* Look up the function */
3619 3632 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3620 3632 : if (!HeapTupleIsValid(proctup))
3621 0 : PG_RETURN_NULL();
3622 :
3623 3632 : (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3624 3632 : if (isnull)
3625 : {
3626 3524 : ReleaseSysCache(proctup);
3627 3524 : PG_RETURN_NULL();
3628 : }
3629 :
3630 108 : print_function_sqlbody(&buf, proctup);
3631 :
3632 108 : ReleaseSysCache(proctup);
3633 :
3634 108 : PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
3635 : }
3636 :
3637 :
3638 : /*
3639 : * deparse_expression - General utility for deparsing expressions
3640 : *
3641 : * calls deparse_expression_pretty with all prettyPrinting disabled
3642 : */
3643 : char *
3644 73562 : deparse_expression(Node *expr, List *dpcontext,
3645 : bool forceprefix, bool showimplicit)
3646 : {
3647 73562 : return deparse_expression_pretty(expr, dpcontext, forceprefix,
3648 : showimplicit, 0, 0);
3649 : }
3650 :
3651 : /* ----------
3652 : * deparse_expression_pretty - General utility for deparsing expressions
3653 : *
3654 : * expr is the node tree to be deparsed. It must be a transformed expression
3655 : * tree (ie, not the raw output of gram.y).
3656 : *
3657 : * dpcontext is a list of deparse_namespace nodes representing the context
3658 : * for interpreting Vars in the node tree. It can be NIL if no Vars are
3659 : * expected.
3660 : *
3661 : * forceprefix is true to force all Vars to be prefixed with their table names.
3662 : *
3663 : * showimplicit is true to force all implicit casts to be shown explicitly.
3664 : *
3665 : * Tries to pretty up the output according to prettyFlags and startIndent.
3666 : *
3667 : * The result is a palloc'd string.
3668 : * ----------
3669 : */
3670 : static char *
3671 87344 : deparse_expression_pretty(Node *expr, List *dpcontext,
3672 : bool forceprefix, bool showimplicit,
3673 : int prettyFlags, int startIndent)
3674 : {
3675 : StringInfoData buf;
3676 : deparse_context context;
3677 :
3678 87344 : initStringInfo(&buf);
3679 87344 : context.buf = &buf;
3680 87344 : context.namespaces = dpcontext;
3681 87344 : context.resultDesc = NULL;
3682 87344 : context.targetList = NIL;
3683 87344 : context.windowClause = NIL;
3684 87344 : context.varprefix = forceprefix;
3685 87344 : context.prettyFlags = prettyFlags;
3686 87344 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
3687 87344 : context.indentLevel = startIndent;
3688 87344 : context.colNamesVisible = true;
3689 87344 : context.inGroupBy = false;
3690 87344 : context.varInOrderBy = false;
3691 87344 : context.appendparents = NULL;
3692 :
3693 87344 : get_rule_expr(expr, &context, showimplicit);
3694 :
3695 87344 : return buf.data;
3696 : }
3697 :
3698 : /* ----------
3699 : * deparse_context_for - Build deparse context for a single relation
3700 : *
3701 : * Given the reference name (alias) and OID of a relation, build deparsing
3702 : * context for an expression referencing only that relation (as varno 1,
3703 : * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3704 : * ----------
3705 : */
3706 : List *
3707 24452 : deparse_context_for(const char *aliasname, Oid relid)
3708 : {
3709 : deparse_namespace *dpns;
3710 : RangeTblEntry *rte;
3711 :
3712 24452 : dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3713 :
3714 : /* Build a minimal RTE for the rel */
3715 24452 : rte = makeNode(RangeTblEntry);
3716 24452 : rte->rtekind = RTE_RELATION;
3717 24452 : rte->relid = relid;
3718 24452 : rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3719 24452 : rte->rellockmode = AccessShareLock;
3720 24452 : rte->alias = makeAlias(aliasname, NIL);
3721 24452 : rte->eref = rte->alias;
3722 24452 : rte->lateral = false;
3723 24452 : rte->inh = false;
3724 24452 : rte->inFromCl = true;
3725 :
3726 : /* Build one-element rtable */
3727 24452 : dpns->rtable = list_make1(rte);
3728 24452 : dpns->subplans = NIL;
3729 24452 : dpns->ctes = NIL;
3730 24452 : dpns->appendrels = NULL;
3731 24452 : set_rtable_names(dpns, NIL, NULL);
3732 24452 : set_simple_column_names(dpns);
3733 :
3734 : /* Return a one-deep namespace stack */
3735 24452 : return list_make1(dpns);
3736 : }
3737 :
3738 : /*
3739 : * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3740 : *
3741 : * When deparsing an expression in a Plan tree, we use the plan's rangetable
3742 : * to resolve names of simple Vars. The initialization of column names for
3743 : * this is rather expensive if the rangetable is large, and it'll be the same
3744 : * for every expression in the Plan tree; so we do it just once and re-use
3745 : * the result of this function for each expression. (Note that the result
3746 : * is not usable until set_deparse_context_plan() is applied to it.)
3747 : *
3748 : * In addition to the PlannedStmt, pass the per-RTE alias names
3749 : * assigned by a previous call to select_rtable_names_for_explain.
3750 : */
3751 : List *
3752 24042 : deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
3753 : {
3754 : deparse_namespace *dpns;
3755 :
3756 24042 : dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3757 :
3758 : /* Initialize fields that stay the same across the whole plan tree */
3759 24042 : dpns->rtable = pstmt->rtable;
3760 24042 : dpns->rtable_names = rtable_names;
3761 24042 : dpns->subplans = pstmt->subplans;
3762 24042 : dpns->ctes = NIL;
3763 24042 : if (pstmt->appendRelations)
3764 : {
3765 : /* Set up the array, indexed by child relid */
3766 3840 : int ntables = list_length(dpns->rtable);
3767 : ListCell *lc;
3768 :
3769 3840 : dpns->appendrels = (AppendRelInfo **)
3770 3840 : palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3771 20846 : foreach(lc, pstmt->appendRelations)
3772 : {
3773 17006 : AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3774 17006 : Index crelid = appinfo->child_relid;
3775 :
3776 : Assert(crelid > 0 && crelid <= ntables);
3777 : Assert(dpns->appendrels[crelid] == NULL);
3778 17006 : dpns->appendrels[crelid] = appinfo;
3779 : }
3780 : }
3781 : else
3782 20202 : dpns->appendrels = NULL; /* don't need it */
3783 :
3784 : /*
3785 : * Set up column name aliases, ignoring any join RTEs; they don't matter
3786 : * because plan trees don't contain any join alias Vars.
3787 : */
3788 24042 : set_simple_column_names(dpns);
3789 :
3790 : /* Return a one-deep namespace stack */
3791 24042 : return list_make1(dpns);
3792 : }
3793 :
3794 : /*
3795 : * set_deparse_context_plan - Specify Plan node containing expression
3796 : *
3797 : * When deparsing an expression in a Plan tree, we might have to resolve
3798 : * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
3799 : * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
3800 : * can be resolved by drilling down into the left and right child plans.
3801 : * Similarly, INDEX_VAR references can be resolved by reference to the
3802 : * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3803 : * ForeignScan and CustomScan nodes. (Note that we don't currently support
3804 : * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3805 : * for those, we can only deparse the indexqualorig fields, which won't
3806 : * contain INDEX_VAR Vars.)
3807 : *
3808 : * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3809 : * the most-closely-nested first. This is needed to resolve PARAM_EXEC
3810 : * Params. Note we assume that all the Plan nodes share the same rtable.
3811 : *
3812 : * For a ModifyTable plan, we might also need to resolve references to OLD/NEW
3813 : * variables in the RETURNING list, so we copy the alias names of the OLD and
3814 : * NEW rows from the ModifyTable plan node.
3815 : *
3816 : * Once this function has been called, deparse_expression() can be called on
3817 : * subsidiary expression(s) of the specified Plan node. To deparse
3818 : * expressions of a different Plan node in the same Plan tree, re-call this
3819 : * function to identify the new parent Plan node.
3820 : *
3821 : * The result is the same List passed in; this is a notational convenience.
3822 : */
3823 : List *
3824 53970 : set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3825 : {
3826 : deparse_namespace *dpns;
3827 :
3828 : /* Should always have one-entry namespace list for Plan deparsing */
3829 : Assert(list_length(dpcontext) == 1);
3830 53970 : dpns = (deparse_namespace *) linitial(dpcontext);
3831 :
3832 : /* Set our attention on the specific plan node passed in */
3833 53970 : dpns->ancestors = ancestors;
3834 53970 : set_deparse_plan(dpns, plan);
3835 :
3836 : /* For ModifyTable, set aliases for OLD and NEW in RETURNING */
3837 53970 : if (IsA(plan, ModifyTable))
3838 : {
3839 210 : dpns->ret_old_alias = ((ModifyTable *) plan)->returningOldAlias;
3840 210 : dpns->ret_new_alias = ((ModifyTable *) plan)->returningNewAlias;
3841 : }
3842 :
3843 53970 : return dpcontext;
3844 : }
3845 :
3846 : /*
3847 : * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3848 : *
3849 : * Determine the relation aliases we'll use during an EXPLAIN operation.
3850 : * This is just a frontend to set_rtable_names. We have to expose the aliases
3851 : * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3852 : */
3853 : List *
3854 24042 : select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
3855 : {
3856 : deparse_namespace dpns;
3857 :
3858 24042 : memset(&dpns, 0, sizeof(dpns));
3859 24042 : dpns.rtable = rtable;
3860 24042 : dpns.subplans = NIL;
3861 24042 : dpns.ctes = NIL;
3862 24042 : dpns.appendrels = NULL;
3863 24042 : set_rtable_names(&dpns, NIL, rels_used);
3864 : /* We needn't bother computing column aliases yet */
3865 :
3866 24042 : return dpns.rtable_names;
3867 : }
3868 :
3869 : /*
3870 : * set_rtable_names: select RTE aliases to be used in printing a query
3871 : *
3872 : * We fill in dpns->rtable_names with a list of names that is one-for-one with
3873 : * the already-filled dpns->rtable list. Each RTE name is unique among those
3874 : * in the new namespace plus any ancestor namespaces listed in
3875 : * parent_namespaces.
3876 : *
3877 : * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3878 : *
3879 : * Note that this function is only concerned with relation names, not column
3880 : * names.
3881 : */
3882 : static void
3883 54688 : set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3884 : Bitmapset *rels_used)
3885 : {
3886 : HASHCTL hash_ctl;
3887 : HTAB *names_hash;
3888 : NameHashEntry *hentry;
3889 : bool found;
3890 : int rtindex;
3891 : ListCell *lc;
3892 :
3893 54688 : dpns->rtable_names = NIL;
3894 : /* nothing more to do if empty rtable */
3895 54688 : if (dpns->rtable == NIL)
3896 576 : return;
3897 :
3898 : /*
3899 : * We use a hash table to hold known names, so that this process is O(N)
3900 : * not O(N^2) for N names.
3901 : */
3902 54112 : hash_ctl.keysize = NAMEDATALEN;
3903 54112 : hash_ctl.entrysize = sizeof(NameHashEntry);
3904 54112 : hash_ctl.hcxt = CurrentMemoryContext;
3905 54112 : names_hash = hash_create("set_rtable_names names",
3906 54112 : list_length(dpns->rtable),
3907 : &hash_ctl,
3908 : HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3909 :
3910 : /* Preload the hash table with names appearing in parent_namespaces */
3911 55860 : foreach(lc, parent_namespaces)
3912 : {
3913 1748 : deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3914 : ListCell *lc2;
3915 :
3916 6310 : foreach(lc2, olddpns->rtable_names)
3917 : {
3918 4562 : char *oldname = (char *) lfirst(lc2);
3919 :
3920 4562 : if (oldname == NULL)
3921 336 : continue;
3922 4226 : hentry = (NameHashEntry *) hash_search(names_hash,
3923 : oldname,
3924 : HASH_ENTER,
3925 : &found);
3926 : /* we do not complain about duplicate names in parent namespaces */
3927 4226 : hentry->counter = 0;
3928 : }
3929 : }
3930 :
3931 : /* Now we can scan the rtable */
3932 54112 : rtindex = 1;
3933 155010 : foreach(lc, dpns->rtable)
3934 : {
3935 100898 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3936 : char *refname;
3937 :
3938 : /* Just in case this takes an unreasonable amount of time ... */
3939 100898 : CHECK_FOR_INTERRUPTS();
3940 :
3941 100898 : if (rels_used && !bms_is_member(rtindex, rels_used))
3942 : {
3943 : /* Ignore unreferenced RTE */
3944 17042 : refname = NULL;
3945 : }
3946 83856 : else if (rte->alias)
3947 : {
3948 : /* If RTE has a user-defined alias, prefer that */
3949 54620 : refname = rte->alias->aliasname;
3950 : }
3951 29236 : else if (rte->rtekind == RTE_RELATION)
3952 : {
3953 : /* Use the current actual name of the relation */
3954 22274 : refname = get_rel_name(rte->relid);
3955 : }
3956 6962 : else if (rte->rtekind == RTE_JOIN)
3957 : {
3958 : /* Unnamed join has no refname */
3959 1782 : refname = NULL;
3960 : }
3961 : else
3962 : {
3963 : /* Otherwise use whatever the parser assigned */
3964 5180 : refname = rte->eref->aliasname;
3965 : }
3966 :
3967 : /*
3968 : * If the selected name isn't unique, append digits to make it so, and
3969 : * make a new hash entry for it once we've got a unique name. For a
3970 : * very long input name, we might have to truncate to stay within
3971 : * NAMEDATALEN.
3972 : */
3973 100898 : if (refname)
3974 : {
3975 82074 : hentry = (NameHashEntry *) hash_search(names_hash,
3976 : refname,
3977 : HASH_ENTER,
3978 : &found);
3979 82074 : if (found)
3980 : {
3981 : /* Name already in use, must choose a new one */
3982 14700 : int refnamelen = strlen(refname);
3983 14700 : char *modname = (char *) palloc(refnamelen + 16);
3984 : NameHashEntry *hentry2;
3985 :
3986 : do
3987 : {
3988 14706 : hentry->counter++;
3989 : for (;;)
3990 : {
3991 14718 : memcpy(modname, refname, refnamelen);
3992 14718 : sprintf(modname + refnamelen, "_%d", hentry->counter);
3993 14718 : if (strlen(modname) < NAMEDATALEN)
3994 14706 : break;
3995 : /* drop chars from refname to keep all the digits */
3996 12 : refnamelen = pg_mbcliplen(refname, refnamelen,
3997 : refnamelen - 1);
3998 : }
3999 14706 : hentry2 = (NameHashEntry *) hash_search(names_hash,
4000 : modname,
4001 : HASH_ENTER,
4002 : &found);
4003 14706 : } while (found);
4004 14700 : hentry2->counter = 0; /* init new hash entry */
4005 14700 : refname = modname;
4006 : }
4007 : else
4008 : {
4009 : /* Name not previously used, need only initialize hentry */
4010 67374 : hentry->counter = 0;
4011 : }
4012 : }
4013 :
4014 100898 : dpns->rtable_names = lappend(dpns->rtable_names, refname);
4015 100898 : rtindex++;
4016 : }
4017 :
4018 54112 : hash_destroy(names_hash);
4019 : }
4020 :
4021 : /*
4022 : * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
4023 : *
4024 : * For convenience, this is defined to initialize the deparse_namespace struct
4025 : * from scratch.
4026 : */
4027 : static void
4028 6030 : set_deparse_for_query(deparse_namespace *dpns, Query *query,
4029 : List *parent_namespaces)
4030 : {
4031 : ListCell *lc;
4032 : ListCell *lc2;
4033 :
4034 : /* Initialize *dpns and fill rtable/ctes links */
4035 6030 : memset(dpns, 0, sizeof(deparse_namespace));
4036 6030 : dpns->rtable = query->rtable;
4037 6030 : dpns->subplans = NIL;
4038 6030 : dpns->ctes = query->cteList;
4039 6030 : dpns->appendrels = NULL;
4040 6030 : dpns->ret_old_alias = query->returningOldAlias;
4041 6030 : dpns->ret_new_alias = query->returningNewAlias;
4042 :
4043 : /* Assign a unique relation alias to each RTE */
4044 6030 : set_rtable_names(dpns, parent_namespaces, NULL);
4045 :
4046 : /* Initialize dpns->rtable_columns to contain zeroed structs */
4047 6030 : dpns->rtable_columns = NIL;
4048 16726 : while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4049 10696 : dpns->rtable_columns = lappend(dpns->rtable_columns,
4050 : palloc0(sizeof(deparse_columns)));
4051 :
4052 : /* If it's a utility query, it won't have a jointree */
4053 6030 : if (query->jointree)
4054 : {
4055 : /* Detect whether global uniqueness of USING names is needed */
4056 6014 : dpns->unique_using =
4057 6014 : has_dangerous_join_using(dpns, (Node *) query->jointree);
4058 :
4059 : /*
4060 : * Select names for columns merged by USING, via a recursive pass over
4061 : * the query jointree.
4062 : */
4063 6014 : set_using_names(dpns, (Node *) query->jointree, NIL);
4064 : }
4065 :
4066 : /*
4067 : * Now assign remaining column aliases for each RTE. We do this in a
4068 : * linear scan of the rtable, so as to process RTEs whether or not they
4069 : * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
4070 : * etc). JOIN RTEs must be processed after their children, but this is
4071 : * okay because they appear later in the rtable list than their children
4072 : * (cf Asserts in identify_join_columns()).
4073 : */
4074 16726 : forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4075 : {
4076 10696 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4077 10696 : deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4078 :
4079 10696 : if (rte->rtekind == RTE_JOIN)
4080 1498 : set_join_column_names(dpns, rte, colinfo);
4081 : else
4082 9198 : set_relation_column_names(dpns, rte, colinfo);
4083 : }
4084 6030 : }
4085 :
4086 : /*
4087 : * set_simple_column_names: fill in column aliases for non-query situations
4088 : *
4089 : * This handles EXPLAIN and cases where we only have relation RTEs. Without
4090 : * a join tree, we can't do anything smart about join RTEs, but we don't
4091 : * need to, because EXPLAIN should never see join alias Vars anyway.
4092 : * If we find a join RTE we'll just skip it, leaving its deparse_columns
4093 : * struct all-zero. If somehow we try to deparse a join alias Var, we'll
4094 : * error out cleanly because the struct's num_cols will be zero.
4095 : */
4096 : static void
4097 48658 : set_simple_column_names(deparse_namespace *dpns)
4098 : {
4099 : ListCell *lc;
4100 : ListCell *lc2;
4101 :
4102 : /* Initialize dpns->rtable_columns to contain zeroed structs */
4103 48658 : dpns->rtable_columns = NIL;
4104 138860 : while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4105 90202 : dpns->rtable_columns = lappend(dpns->rtable_columns,
4106 : palloc0(sizeof(deparse_columns)));
4107 :
4108 : /* Assign unique column aliases within each non-join RTE */
4109 138860 : forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4110 : {
4111 90202 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4112 90202 : deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4113 :
4114 90202 : if (rte->rtekind != RTE_JOIN)
4115 84416 : set_relation_column_names(dpns, rte, colinfo);
4116 : }
4117 48658 : }
4118 :
4119 : /*
4120 : * has_dangerous_join_using: search jointree for unnamed JOIN USING
4121 : *
4122 : * Merged columns of a JOIN USING may act differently from either of the input
4123 : * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4124 : * because an implicit coercion of the underlying input column is required.
4125 : * In such a case the column must be referenced as a column of the JOIN not as
4126 : * a column of either input. And this is problematic if the join is unnamed
4127 : * (alias-less): we cannot qualify the column's name with an RTE name, since
4128 : * there is none. (Forcibly assigning an alias to the join is not a solution,
4129 : * since that will prevent legal references to tables below the join.)
4130 : * To ensure that every column in the query is unambiguously referenceable,
4131 : * we must assign such merged columns names that are globally unique across
4132 : * the whole query, aliasing other columns out of the way as necessary.
4133 : *
4134 : * Because the ensuing re-aliasing is fairly damaging to the readability of
4135 : * the query, we don't do this unless we have to. So, we must pre-scan
4136 : * the join tree to see if we have to, before starting set_using_names().
4137 : */
4138 : static bool
4139 14158 : has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
4140 : {
4141 14158 : if (IsA(jtnode, RangeTblRef))
4142 : {
4143 : /* nothing to do here */
4144 : }
4145 7446 : else if (IsA(jtnode, FromExpr))
4146 : {
4147 6014 : FromExpr *f = (FromExpr *) jtnode;
4148 : ListCell *lc;
4149 :
4150 11366 : foreach(lc, f->fromlist)
4151 : {
4152 5424 : if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4153 72 : return true;
4154 : }
4155 : }
4156 1432 : else if (IsA(jtnode, JoinExpr))
4157 : {
4158 1432 : JoinExpr *j = (JoinExpr *) jtnode;
4159 :
4160 : /* Is it an unnamed JOIN with USING? */
4161 1432 : if (j->alias == NULL && j->usingClause)
4162 : {
4163 : /*
4164 : * Yes, so check each join alias var to see if any of them are not
4165 : * simple references to underlying columns. If so, we have a
4166 : * dangerous situation and must pick unique aliases.
4167 : */
4168 286 : RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4169 :
4170 : /* We need only examine the merged columns */
4171 596 : for (int i = 0; i < jrte->joinmergedcols; i++)
4172 : {
4173 382 : Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4174 :
4175 382 : if (!IsA(aliasvar, Var))
4176 72 : return true;
4177 : }
4178 : }
4179 :
4180 : /* Nope, but inspect children */
4181 1360 : if (has_dangerous_join_using(dpns, j->larg))
4182 0 : return true;
4183 1360 : if (has_dangerous_join_using(dpns, j->rarg))
4184 0 : return true;
4185 : }
4186 : else
4187 0 : elog(ERROR, "unrecognized node type: %d",
4188 : (int) nodeTag(jtnode));
4189 14014 : return false;
4190 : }
4191 :
4192 : /*
4193 : * set_using_names: select column aliases to be used for merged USING columns
4194 : *
4195 : * We do this during a recursive descent of the query jointree.
4196 : * dpns->unique_using must already be set to determine the global strategy.
4197 : *
4198 : * Column alias info is saved in the dpns->rtable_columns list, which is
4199 : * assumed to be filled with pre-zeroed deparse_columns structs.
4200 : *
4201 : * parentUsing is a list of all USING aliases assigned in parent joins of
4202 : * the current jointree node. (The passed-in list must not be modified.)
4203 : *
4204 : * Note that we do not use per-deparse_columns hash tables in this function.
4205 : * The number of names that need to be assigned should be small enough that
4206 : * we don't need to trouble with that.
4207 : */
4208 : static void
4209 14476 : set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4210 : {
4211 14476 : if (IsA(jtnode, RangeTblRef))
4212 : {
4213 : /* nothing to do now */
4214 : }
4215 7512 : else if (IsA(jtnode, FromExpr))
4216 : {
4217 6014 : FromExpr *f = (FromExpr *) jtnode;
4218 : ListCell *lc;
4219 :
4220 11480 : foreach(lc, f->fromlist)
4221 5466 : set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4222 : }
4223 1498 : else if (IsA(jtnode, JoinExpr))
4224 : {
4225 1498 : JoinExpr *j = (JoinExpr *) jtnode;
4226 1498 : RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4227 1498 : deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4228 : int *leftattnos;
4229 : int *rightattnos;
4230 : deparse_columns *leftcolinfo;
4231 : deparse_columns *rightcolinfo;
4232 : int i;
4233 : ListCell *lc;
4234 :
4235 : /* Get info about the shape of the join */
4236 1498 : identify_join_columns(j, rte, colinfo);
4237 1498 : leftattnos = colinfo->leftattnos;
4238 1498 : rightattnos = colinfo->rightattnos;
4239 :
4240 : /* Look up the not-yet-filled-in child deparse_columns structs */
4241 1498 : leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4242 1498 : rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4243 :
4244 : /*
4245 : * If this join is unnamed, then we cannot substitute new aliases at
4246 : * this level, so any name requirements pushed down to here must be
4247 : * pushed down again to the children.
4248 : */
4249 1498 : if (rte->alias == NULL)
4250 : {
4251 1528 : for (i = 0; i < colinfo->num_cols; i++)
4252 : {
4253 138 : char *colname = colinfo->colnames[i];
4254 :
4255 138 : if (colname == NULL)
4256 24 : continue;
4257 :
4258 : /* Push down to left column, unless it's a system column */
4259 114 : if (leftattnos[i] > 0)
4260 : {
4261 102 : expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4262 102 : leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4263 : }
4264 :
4265 : /* Same on the righthand side */
4266 114 : if (rightattnos[i] > 0)
4267 : {
4268 114 : expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4269 114 : rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4270 : }
4271 : }
4272 : }
4273 :
4274 : /*
4275 : * If there's a USING clause, select the USING column names and push
4276 : * those names down to the children. We have two strategies:
4277 : *
4278 : * If dpns->unique_using is true, we force all USING names to be
4279 : * unique across the whole query level. In principle we'd only need
4280 : * the names of dangerous USING columns to be globally unique, but to
4281 : * safely assign all USING names in a single pass, we have to enforce
4282 : * the same uniqueness rule for all of them. However, if a USING
4283 : * column's name has been pushed down from the parent, we should use
4284 : * it as-is rather than making a uniqueness adjustment. This is
4285 : * necessary when we're at an unnamed join, and it creates no risk of
4286 : * ambiguity. Also, if there's a user-written output alias for a
4287 : * merged column, we prefer to use that rather than the input name;
4288 : * this simplifies the logic and seems likely to lead to less aliasing
4289 : * overall.
4290 : *
4291 : * If dpns->unique_using is false, we only need USING names to be
4292 : * unique within their own join RTE. We still need to honor
4293 : * pushed-down names, though.
4294 : *
4295 : * Though significantly different in results, these two strategies are
4296 : * implemented by the same code, with only the difference of whether
4297 : * to put assigned names into dpns->using_names.
4298 : */
4299 1498 : if (j->usingClause)
4300 : {
4301 : /* Copy the input parentUsing list so we don't modify it */
4302 424 : parentUsing = list_copy(parentUsing);
4303 :
4304 : /* USING names must correspond to the first join output columns */
4305 424 : expand_colnames_array_to(colinfo, list_length(j->usingClause));
4306 424 : i = 0;
4307 1004 : foreach(lc, j->usingClause)
4308 : {
4309 580 : char *colname = strVal(lfirst(lc));
4310 :
4311 : /* Assert it's a merged column */
4312 : Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4313 :
4314 : /* Adopt passed-down name if any, else select unique name */
4315 580 : if (colinfo->colnames[i] != NULL)
4316 102 : colname = colinfo->colnames[i];
4317 : else
4318 : {
4319 : /* Prefer user-written output alias if any */
4320 478 : if (rte->alias && i < list_length(rte->alias->colnames))
4321 0 : colname = strVal(list_nth(rte->alias->colnames, i));
4322 : /* Make it appropriately unique */
4323 478 : colname = make_colname_unique(colname, dpns, colinfo);
4324 478 : if (dpns->unique_using)
4325 126 : dpns->using_names = lappend(dpns->using_names,
4326 : colname);
4327 : /* Save it as output column name, too */
4328 478 : colinfo->colnames[i] = colname;
4329 : }
4330 :
4331 : /* Remember selected names for use later */
4332 580 : colinfo->usingNames = lappend(colinfo->usingNames, colname);
4333 580 : parentUsing = lappend(parentUsing, colname);
4334 :
4335 : /* Push down to left column, unless it's a system column */
4336 580 : if (leftattnos[i] > 0)
4337 : {
4338 580 : expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4339 580 : leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4340 : }
4341 :
4342 : /* Same on the righthand side */
4343 580 : if (rightattnos[i] > 0)
4344 : {
4345 580 : expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4346 580 : rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4347 : }
4348 :
4349 580 : i++;
4350 : }
4351 : }
4352 :
4353 : /* Mark child deparse_columns structs with correct parentUsing info */
4354 1498 : leftcolinfo->parentUsing = parentUsing;
4355 1498 : rightcolinfo->parentUsing = parentUsing;
4356 :
4357 : /* Now recursively assign USING column names in children */
4358 1498 : set_using_names(dpns, j->larg, parentUsing);
4359 1498 : set_using_names(dpns, j->rarg, parentUsing);
4360 : }
4361 : else
4362 0 : elog(ERROR, "unrecognized node type: %d",
4363 : (int) nodeTag(jtnode));
4364 14476 : }
4365 :
4366 : /*
4367 : * set_relation_column_names: select column aliases for a non-join RTE
4368 : *
4369 : * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4370 : * If any colnames entries are already filled in, those override local
4371 : * choices.
4372 : */
4373 : static void
4374 93614 : set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4375 : deparse_columns *colinfo)
4376 : {
4377 : int ncolumns;
4378 : char **real_colnames;
4379 : bool changed_any;
4380 : int noldcolumns;
4381 : int i;
4382 : int j;
4383 :
4384 : /*
4385 : * Construct an array of the current "real" column names of the RTE.
4386 : * real_colnames[] will be indexed by physical column number, with NULL
4387 : * entries for dropped columns.
4388 : */
4389 93614 : if (rte->rtekind == RTE_RELATION)
4390 : {
4391 : /* Relation --- look to the system catalogs for up-to-date info */
4392 : Relation rel;
4393 : TupleDesc tupdesc;
4394 :
4395 79674 : rel = relation_open(rte->relid, AccessShareLock);
4396 79674 : tupdesc = RelationGetDescr(rel);
4397 :
4398 79674 : ncolumns = tupdesc->natts;
4399 79674 : real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4400 :
4401 507628 : for (i = 0; i < ncolumns; i++)
4402 : {
4403 427954 : Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4404 :
4405 427954 : if (attr->attisdropped)
4406 3208 : real_colnames[i] = NULL;
4407 : else
4408 424746 : real_colnames[i] = pstrdup(NameStr(attr->attname));
4409 : }
4410 79674 : relation_close(rel, AccessShareLock);
4411 : }
4412 : else
4413 : {
4414 : /* Otherwise get the column names from eref or expandRTE() */
4415 : List *colnames;
4416 : ListCell *lc;
4417 :
4418 : /*
4419 : * Functions returning composites have the annoying property that some
4420 : * of the composite type's columns might have been dropped since the
4421 : * query was parsed. If possible, use expandRTE() to handle that
4422 : * case, since it has the tedious logic needed to find out about
4423 : * dropped columns. However, if we're explaining a plan, then we
4424 : * don't have rte->functions because the planner thinks that won't be
4425 : * needed later, and that breaks expandRTE(). So in that case we have
4426 : * to rely on rte->eref, which may lead us to report a dropped
4427 : * column's old name; that seems close enough for EXPLAIN's purposes.
4428 : *
4429 : * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4430 : * which should be sufficiently up-to-date: no other RTE types can
4431 : * have columns get dropped from under them after parsing.
4432 : */
4433 13940 : if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4434 : {
4435 : /* Since we're not creating Vars, rtindex etc. don't matter */
4436 846 : expandRTE(rte, 1, 0, VAR_RETURNING_DEFAULT, -1,
4437 : true /* include dropped */ , &colnames, NULL);
4438 : }
4439 : else
4440 13094 : colnames = rte->eref->colnames;
4441 :
4442 13940 : ncolumns = list_length(colnames);
4443 13940 : real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4444 :
4445 13940 : i = 0;
4446 45990 : foreach(lc, colnames)
4447 : {
4448 : /*
4449 : * If the column name we find here is an empty string, then it's a
4450 : * dropped column, so change to NULL.
4451 : */
4452 32050 : char *cname = strVal(lfirst(lc));
4453 :
4454 32050 : if (cname[0] == '\0')
4455 54 : cname = NULL;
4456 32050 : real_colnames[i] = cname;
4457 32050 : i++;
4458 : }
4459 : }
4460 :
4461 : /*
4462 : * Ensure colinfo->colnames has a slot for each column. (It could be long
4463 : * enough already, if we pushed down a name for the last column.) Note:
4464 : * it's possible that there are now more columns than there were when the
4465 : * query was parsed, ie colnames could be longer than rte->eref->colnames.
4466 : * We must assign unique aliases to the new columns too, else there could
4467 : * be unresolved conflicts when the view/rule is reloaded.
4468 : */
4469 93614 : expand_colnames_array_to(colinfo, ncolumns);
4470 : Assert(colinfo->num_cols == ncolumns);
4471 :
4472 : /*
4473 : * Make sufficiently large new_colnames and is_new_col arrays, too.
4474 : *
4475 : * Note: because we leave colinfo->num_new_cols zero until after the loop,
4476 : * colname_is_unique will not consult that array, which is fine because it
4477 : * would only be duplicate effort.
4478 : */
4479 93614 : colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4480 93614 : colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4481 :
4482 : /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4483 93614 : build_colinfo_names_hash(colinfo);
4484 :
4485 : /*
4486 : * Scan the columns, select a unique alias for each one, and store it in
4487 : * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4488 : * entries for dropped columns, the latter omits them. Also mark
4489 : * new_colnames entries as to whether they are new since parse time; this
4490 : * is the case for entries beyond the length of rte->eref->colnames.
4491 : */
4492 93614 : noldcolumns = list_length(rte->eref->colnames);
4493 93614 : changed_any = false;
4494 93614 : j = 0;
4495 553618 : for (i = 0; i < ncolumns; i++)
4496 : {
4497 460004 : char *real_colname = real_colnames[i];
4498 460004 : char *colname = colinfo->colnames[i];
4499 :
4500 : /* Skip dropped columns */
4501 460004 : if (real_colname == NULL)
4502 : {
4503 : Assert(colname == NULL); /* colnames[i] is already NULL */
4504 3262 : continue;
4505 : }
4506 :
4507 : /* If alias already assigned, that's what to use */
4508 456742 : if (colname == NULL)
4509 : {
4510 : /* If user wrote an alias, prefer that over real column name */
4511 455684 : if (rte->alias && i < list_length(rte->alias->colnames))
4512 42910 : colname = strVal(list_nth(rte->alias->colnames, i));
4513 : else
4514 412774 : colname = real_colname;
4515 :
4516 : /* Unique-ify and insert into colinfo */
4517 455684 : colname = make_colname_unique(colname, dpns, colinfo);
4518 :
4519 455684 : colinfo->colnames[i] = colname;
4520 455684 : add_to_names_hash(colinfo, colname);
4521 : }
4522 :
4523 : /* Put names of non-dropped columns in new_colnames[] too */
4524 456742 : colinfo->new_colnames[j] = colname;
4525 : /* And mark them as new or not */
4526 456742 : colinfo->is_new_col[j] = (i >= noldcolumns);
4527 456742 : j++;
4528 :
4529 : /* Remember if any assigned aliases differ from "real" name */
4530 456742 : if (!changed_any && strcmp(colname, real_colname) != 0)
4531 1198 : changed_any = true;
4532 : }
4533 :
4534 : /* We're now done needing the colinfo's names_hash */
4535 93614 : destroy_colinfo_names_hash(colinfo);
4536 :
4537 : /*
4538 : * Set correct length for new_colnames[] array. (Note: if columns have
4539 : * been added, colinfo->num_cols includes them, which is not really quite
4540 : * right but is harmless, since any new columns must be at the end where
4541 : * they won't affect varattnos of pre-existing columns.)
4542 : */
4543 93614 : colinfo->num_new_cols = j;
4544 :
4545 : /*
4546 : * For a relation RTE, we need only print the alias column names if any
4547 : * are different from the underlying "real" names. For a function RTE,
4548 : * always emit a complete column alias list; this is to protect against
4549 : * possible instability of the default column names (eg, from altering
4550 : * parameter names). For tablefunc RTEs, we never print aliases, because
4551 : * the column names are part of the clause itself. For other RTE types,
4552 : * print if we changed anything OR if there were user-written column
4553 : * aliases (since the latter would be part of the underlying "reality").
4554 : */
4555 93614 : if (rte->rtekind == RTE_RELATION)
4556 79674 : colinfo->printaliases = changed_any;
4557 13940 : else if (rte->rtekind == RTE_FUNCTION)
4558 1424 : colinfo->printaliases = true;
4559 12516 : else if (rte->rtekind == RTE_TABLEFUNC)
4560 176 : colinfo->printaliases = false;
4561 12340 : else if (rte->alias && rte->alias->colnames != NIL)
4562 732 : colinfo->printaliases = true;
4563 : else
4564 11608 : colinfo->printaliases = changed_any;
4565 93614 : }
4566 :
4567 : /*
4568 : * set_join_column_names: select column aliases for a join RTE
4569 : *
4570 : * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4571 : * If any colnames entries are already filled in, those override local
4572 : * choices. Also, names for USING columns were already chosen by
4573 : * set_using_names(). We further expect that column alias selection has been
4574 : * completed for both input RTEs.
4575 : */
4576 : static void
4577 1498 : set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4578 : deparse_columns *colinfo)
4579 : {
4580 : deparse_columns *leftcolinfo;
4581 : deparse_columns *rightcolinfo;
4582 : bool changed_any;
4583 : int noldcolumns;
4584 : int nnewcolumns;
4585 1498 : Bitmapset *leftmerged = NULL;
4586 1498 : Bitmapset *rightmerged = NULL;
4587 : int i;
4588 : int j;
4589 : int ic;
4590 : int jc;
4591 :
4592 : /* Look up the previously-filled-in child deparse_columns structs */
4593 1498 : leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4594 1498 : rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4595 :
4596 : /*
4597 : * Ensure colinfo->colnames has a slot for each column. (It could be long
4598 : * enough already, if we pushed down a name for the last column.) Note:
4599 : * it's possible that one or both inputs now have more columns than there
4600 : * were when the query was parsed, but we'll deal with that below. We
4601 : * only need entries in colnames for pre-existing columns.
4602 : */
4603 1498 : noldcolumns = list_length(rte->eref->colnames);
4604 1498 : expand_colnames_array_to(colinfo, noldcolumns);
4605 : Assert(colinfo->num_cols == noldcolumns);
4606 :
4607 : /* If the RTE is wide enough, use a hash table to avoid O(N^2) costs */
4608 1498 : build_colinfo_names_hash(colinfo);
4609 :
4610 : /*
4611 : * Scan the join output columns, select an alias for each one, and store
4612 : * it in colinfo->colnames. If there are USING columns, set_using_names()
4613 : * already selected their names, so we can start the loop at the first
4614 : * non-merged column.
4615 : */
4616 1498 : changed_any = false;
4617 49840 : for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4618 : {
4619 48342 : char *colname = colinfo->colnames[i];
4620 : char *real_colname;
4621 :
4622 : /* Join column must refer to at least one input column */
4623 : Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4624 :
4625 : /* Get the child column name */
4626 48342 : if (colinfo->leftattnos[i] > 0)
4627 34042 : real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4628 14300 : else if (colinfo->rightattnos[i] > 0)
4629 14300 : real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4630 : else
4631 : {
4632 : /* We're joining system columns --- use eref name */
4633 0 : real_colname = strVal(list_nth(rte->eref->colnames, i));
4634 : }
4635 :
4636 : /* If child col has been dropped, no need to assign a join colname */
4637 48342 : if (real_colname == NULL)
4638 : {
4639 6 : colinfo->colnames[i] = NULL;
4640 6 : continue;
4641 : }
4642 :
4643 : /* In an unnamed join, just report child column names as-is */
4644 48336 : if (rte->alias == NULL)
4645 : {
4646 47958 : colinfo->colnames[i] = real_colname;
4647 47958 : add_to_names_hash(colinfo, real_colname);
4648 47958 : continue;
4649 : }
4650 :
4651 : /* If alias already assigned, that's what to use */
4652 378 : if (colname == NULL)
4653 : {
4654 : /* If user wrote an alias, prefer that over real column name */
4655 378 : if (rte->alias && i < list_length(rte->alias->colnames))
4656 96 : colname = strVal(list_nth(rte->alias->colnames, i));
4657 : else
4658 282 : colname = real_colname;
4659 :
4660 : /* Unique-ify and insert into colinfo */
4661 378 : colname = make_colname_unique(colname, dpns, colinfo);
4662 :
4663 378 : colinfo->colnames[i] = colname;
4664 378 : add_to_names_hash(colinfo, colname);
4665 : }
4666 :
4667 : /* Remember if any assigned aliases differ from "real" name */
4668 378 : if (!changed_any && strcmp(colname, real_colname) != 0)
4669 24 : changed_any = true;
4670 : }
4671 :
4672 : /*
4673 : * Calculate number of columns the join would have if it were re-parsed
4674 : * now, and create storage for the new_colnames and is_new_col arrays.
4675 : *
4676 : * Note: colname_is_unique will be consulting new_colnames[] during the
4677 : * loops below, so its not-yet-filled entries must be zeroes.
4678 : */
4679 2996 : nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4680 1498 : list_length(colinfo->usingNames);
4681 1498 : colinfo->num_new_cols = nnewcolumns;
4682 1498 : colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4683 1498 : colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4684 :
4685 : /*
4686 : * Generating the new_colnames array is a bit tricky since any new columns
4687 : * added since parse time must be inserted in the right places. This code
4688 : * must match the parser, which will order a join's columns as merged
4689 : * columns first (in USING-clause order), then non-merged columns from the
4690 : * left input (in attnum order), then non-merged columns from the right
4691 : * input (ditto). If one of the inputs is itself a join, its columns will
4692 : * be ordered according to the same rule, which means newly-added columns
4693 : * might not be at the end. We can figure out what's what by consulting
4694 : * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4695 : *
4696 : * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4697 : * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4698 : * meanings for the current child RTE.
4699 : */
4700 :
4701 : /* Handle merged columns; they are first and can't be new */
4702 1498 : i = j = 0;
4703 1498 : while (i < noldcolumns &&
4704 2078 : colinfo->leftattnos[i] != 0 &&
4705 2078 : colinfo->rightattnos[i] != 0)
4706 : {
4707 : /* column name is already determined and known unique */
4708 580 : colinfo->new_colnames[j] = colinfo->colnames[i];
4709 580 : colinfo->is_new_col[j] = false;
4710 :
4711 : /* build bitmapsets of child attnums of merged columns */
4712 580 : if (colinfo->leftattnos[i] > 0)
4713 580 : leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4714 580 : if (colinfo->rightattnos[i] > 0)
4715 580 : rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4716 :
4717 580 : i++, j++;
4718 : }
4719 :
4720 : /* Handle non-merged left-child columns */
4721 1498 : ic = 0;
4722 36606 : for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4723 : {
4724 35108 : char *child_colname = leftcolinfo->new_colnames[jc];
4725 :
4726 35108 : if (!leftcolinfo->is_new_col[jc])
4727 : {
4728 : /* Advance ic to next non-dropped old column of left child */
4729 34700 : while (ic < leftcolinfo->num_cols &&
4730 34700 : leftcolinfo->colnames[ic] == NULL)
4731 84 : ic++;
4732 : Assert(ic < leftcolinfo->num_cols);
4733 34616 : ic++;
4734 : /* If it is a merged column, we already processed it */
4735 34616 : if (bms_is_member(ic, leftmerged))
4736 580 : continue;
4737 : /* Else, advance i to the corresponding existing join column */
4738 34042 : while (i < colinfo->num_cols &&
4739 34042 : colinfo->colnames[i] == NULL)
4740 6 : i++;
4741 : Assert(i < colinfo->num_cols);
4742 : Assert(ic == colinfo->leftattnos[i]);
4743 : /* Use the already-assigned name of this column */
4744 34036 : colinfo->new_colnames[j] = colinfo->colnames[i];
4745 34036 : i++;
4746 : }
4747 : else
4748 : {
4749 : /*
4750 : * Unique-ify the new child column name and assign, unless we're
4751 : * in an unnamed join, in which case just copy
4752 : */
4753 492 : if (rte->alias != NULL)
4754 : {
4755 264 : colinfo->new_colnames[j] =
4756 132 : make_colname_unique(child_colname, dpns, colinfo);
4757 132 : if (!changed_any &&
4758 108 : strcmp(colinfo->new_colnames[j], child_colname) != 0)
4759 12 : changed_any = true;
4760 : }
4761 : else
4762 360 : colinfo->new_colnames[j] = child_colname;
4763 492 : add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4764 : }
4765 :
4766 34528 : colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4767 34528 : j++;
4768 : }
4769 :
4770 : /* Handle non-merged right-child columns in exactly the same way */
4771 1498 : ic = 0;
4772 16546 : for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4773 : {
4774 15048 : char *child_colname = rightcolinfo->new_colnames[jc];
4775 :
4776 15048 : if (!rightcolinfo->is_new_col[jc])
4777 : {
4778 : /* Advance ic to next non-dropped old column of right child */
4779 14880 : while (ic < rightcolinfo->num_cols &&
4780 14880 : rightcolinfo->colnames[ic] == NULL)
4781 0 : ic++;
4782 : Assert(ic < rightcolinfo->num_cols);
4783 14880 : ic++;
4784 : /* If it is a merged column, we already processed it */
4785 14880 : if (bms_is_member(ic, rightmerged))
4786 580 : continue;
4787 : /* Else, advance i to the corresponding existing join column */
4788 14300 : while (i < colinfo->num_cols &&
4789 14300 : colinfo->colnames[i] == NULL)
4790 0 : i++;
4791 : Assert(i < colinfo->num_cols);
4792 : Assert(ic == colinfo->rightattnos[i]);
4793 : /* Use the already-assigned name of this column */
4794 14300 : colinfo->new_colnames[j] = colinfo->colnames[i];
4795 14300 : i++;
4796 : }
4797 : else
4798 : {
4799 : /*
4800 : * Unique-ify the new child column name and assign, unless we're
4801 : * in an unnamed join, in which case just copy
4802 : */
4803 168 : if (rte->alias != NULL)
4804 : {
4805 48 : colinfo->new_colnames[j] =
4806 24 : make_colname_unique(child_colname, dpns, colinfo);
4807 24 : if (!changed_any &&
4808 24 : strcmp(colinfo->new_colnames[j], child_colname) != 0)
4809 12 : changed_any = true;
4810 : }
4811 : else
4812 144 : colinfo->new_colnames[j] = child_colname;
4813 168 : add_to_names_hash(colinfo, colinfo->new_colnames[j]);
4814 : }
4815 :
4816 14468 : colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4817 14468 : j++;
4818 : }
4819 :
4820 : /* Assert we processed the right number of columns */
4821 : #ifdef USE_ASSERT_CHECKING
4822 : while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4823 : i++;
4824 : Assert(i == colinfo->num_cols);
4825 : Assert(j == nnewcolumns);
4826 : #endif
4827 :
4828 : /* We're now done needing the colinfo's names_hash */
4829 1498 : destroy_colinfo_names_hash(colinfo);
4830 :
4831 : /*
4832 : * For a named join, print column aliases if we changed any from the child
4833 : * names. Unnamed joins cannot print aliases.
4834 : */
4835 1498 : if (rte->alias != NULL)
4836 108 : colinfo->printaliases = changed_any;
4837 : else
4838 1390 : colinfo->printaliases = false;
4839 1498 : }
4840 :
4841 : /*
4842 : * colname_is_unique: is colname distinct from already-chosen column names?
4843 : *
4844 : * dpns is query-wide info, colinfo is for the column's RTE
4845 : */
4846 : static bool
4847 459064 : colname_is_unique(const char *colname, deparse_namespace *dpns,
4848 : deparse_columns *colinfo)
4849 : {
4850 : int i;
4851 : ListCell *lc;
4852 :
4853 : /*
4854 : * If we have a hash table, consult that instead of linearly scanning the
4855 : * colinfo's strings.
4856 : */
4857 459064 : if (colinfo->names_hash)
4858 : {
4859 18386 : if (hash_search(colinfo->names_hash,
4860 : colname,
4861 : HASH_FIND,
4862 : NULL) != NULL)
4863 0 : return false;
4864 : }
4865 : else
4866 : {
4867 : /* Check against already-assigned column aliases within RTE */
4868 6079780 : for (i = 0; i < colinfo->num_cols; i++)
4869 : {
4870 5641398 : char *oldname = colinfo->colnames[i];
4871 :
4872 5641398 : if (oldname && strcmp(oldname, colname) == 0)
4873 2296 : return false;
4874 : }
4875 :
4876 : /*
4877 : * If we're building a new_colnames array, check that too (this will
4878 : * be partially but not completely redundant with the previous checks)
4879 : */
4880 439654 : for (i = 0; i < colinfo->num_new_cols; i++)
4881 : {
4882 1296 : char *oldname = colinfo->new_colnames[i];
4883 :
4884 1296 : if (oldname && strcmp(oldname, colname) == 0)
4885 24 : return false;
4886 : }
4887 :
4888 : /*
4889 : * Also check against names already assigned for parent-join USING
4890 : * cols
4891 : */
4892 440950 : foreach(lc, colinfo->parentUsing)
4893 : {
4894 2598 : char *oldname = (char *) lfirst(lc);
4895 :
4896 2598 : if (strcmp(oldname, colname) == 0)
4897 6 : return false;
4898 : }
4899 : }
4900 :
4901 : /*
4902 : * Also check against USING-column names that must be globally unique.
4903 : * These are not hashed, but there should be few of them.
4904 : */
4905 457578 : foreach(lc, dpns->using_names)
4906 : {
4907 882 : char *oldname = (char *) lfirst(lc);
4908 :
4909 882 : if (strcmp(oldname, colname) == 0)
4910 42 : return false;
4911 : }
4912 :
4913 456696 : return true;
4914 : }
4915 :
4916 : /*
4917 : * make_colname_unique: modify colname if necessary to make it unique
4918 : *
4919 : * dpns is query-wide info, colinfo is for the column's RTE
4920 : */
4921 : static char *
4922 456696 : make_colname_unique(char *colname, deparse_namespace *dpns,
4923 : deparse_columns *colinfo)
4924 : {
4925 : /*
4926 : * If the selected name isn't unique, append digits to make it so. For a
4927 : * very long input name, we might have to truncate to stay within
4928 : * NAMEDATALEN.
4929 : */
4930 456696 : if (!colname_is_unique(colname, dpns, colinfo))
4931 : {
4932 1644 : int colnamelen = strlen(colname);
4933 1644 : char *modname = (char *) palloc(colnamelen + 16);
4934 1644 : int i = 0;
4935 :
4936 : do
4937 : {
4938 2368 : i++;
4939 : for (;;)
4940 : {
4941 2368 : memcpy(modname, colname, colnamelen);
4942 2368 : sprintf(modname + colnamelen, "_%d", i);
4943 2368 : if (strlen(modname) < NAMEDATALEN)
4944 2368 : break;
4945 : /* drop chars from colname to keep all the digits */
4946 0 : colnamelen = pg_mbcliplen(colname, colnamelen,
4947 : colnamelen - 1);
4948 : }
4949 2368 : } while (!colname_is_unique(modname, dpns, colinfo));
4950 1644 : colname = modname;
4951 : }
4952 456696 : return colname;
4953 : }
4954 :
4955 : /*
4956 : * expand_colnames_array_to: make colinfo->colnames at least n items long
4957 : *
4958 : * Any added array entries are initialized to zero.
4959 : */
4960 : static void
4961 96912 : expand_colnames_array_to(deparse_columns *colinfo, int n)
4962 : {
4963 96912 : if (n > colinfo->num_cols)
4964 : {
4965 94260 : if (colinfo->colnames == NULL)
4966 92844 : colinfo->colnames = palloc0_array(char *, n);
4967 : else
4968 1416 : colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4969 94260 : colinfo->num_cols = n;
4970 : }
4971 96912 : }
4972 :
4973 : /*
4974 : * build_colinfo_names_hash: optionally construct a hash table for colinfo
4975 : */
4976 : static void
4977 95112 : build_colinfo_names_hash(deparse_columns *colinfo)
4978 : {
4979 : HASHCTL hash_ctl;
4980 : int i;
4981 : ListCell *lc;
4982 :
4983 : /*
4984 : * Use a hash table only for RTEs with at least 32 columns. (The cutoff
4985 : * is somewhat arbitrary, but let's choose it so that this code does get
4986 : * exercised in the regression tests.)
4987 : */
4988 95112 : if (colinfo->num_cols < 32)
4989 93772 : return;
4990 :
4991 : /*
4992 : * Set up the hash table. The entries are just strings with no other
4993 : * payload.
4994 : */
4995 1340 : hash_ctl.keysize = NAMEDATALEN;
4996 1340 : hash_ctl.entrysize = NAMEDATALEN;
4997 1340 : hash_ctl.hcxt = CurrentMemoryContext;
4998 2680 : colinfo->names_hash = hash_create("deparse_columns names",
4999 1340 : colinfo->num_cols + colinfo->num_new_cols,
5000 : &hash_ctl,
5001 : HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
5002 :
5003 : /*
5004 : * Preload the hash table with any names already present (these would have
5005 : * come from set_using_names).
5006 : */
5007 62914 : for (i = 0; i < colinfo->num_cols; i++)
5008 : {
5009 61574 : char *oldname = colinfo->colnames[i];
5010 :
5011 61574 : if (oldname)
5012 0 : add_to_names_hash(colinfo, oldname);
5013 : }
5014 :
5015 1340 : for (i = 0; i < colinfo->num_new_cols; i++)
5016 : {
5017 0 : char *oldname = colinfo->new_colnames[i];
5018 :
5019 0 : if (oldname)
5020 0 : add_to_names_hash(colinfo, oldname);
5021 : }
5022 :
5023 1340 : foreach(lc, colinfo->parentUsing)
5024 : {
5025 0 : char *oldname = (char *) lfirst(lc);
5026 :
5027 0 : add_to_names_hash(colinfo, oldname);
5028 : }
5029 : }
5030 :
5031 : /*
5032 : * add_to_names_hash: add a string to the names_hash, if we're using one
5033 : */
5034 : static void
5035 504680 : add_to_names_hash(deparse_columns *colinfo, const char *name)
5036 : {
5037 504680 : if (colinfo->names_hash)
5038 61574 : (void) hash_search(colinfo->names_hash,
5039 : name,
5040 : HASH_ENTER,
5041 : NULL);
5042 504680 : }
5043 :
5044 : /*
5045 : * destroy_colinfo_names_hash: destroy hash table when done with it
5046 : */
5047 : static void
5048 95112 : destroy_colinfo_names_hash(deparse_columns *colinfo)
5049 : {
5050 95112 : if (colinfo->names_hash)
5051 : {
5052 1340 : hash_destroy(colinfo->names_hash);
5053 1340 : colinfo->names_hash = NULL;
5054 : }
5055 95112 : }
5056 :
5057 : /*
5058 : * identify_join_columns: figure out where columns of a join come from
5059 : *
5060 : * Fills the join-specific fields of the colinfo struct, except for
5061 : * usingNames which is filled later.
5062 : */
5063 : static void
5064 1498 : identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
5065 : deparse_columns *colinfo)
5066 : {
5067 : int numjoincols;
5068 : int jcolno;
5069 : int rcolno;
5070 : ListCell *lc;
5071 :
5072 : /* Extract left/right child RT indexes */
5073 1498 : if (IsA(j->larg, RangeTblRef))
5074 952 : colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
5075 546 : else if (IsA(j->larg, JoinExpr))
5076 546 : colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
5077 : else
5078 0 : elog(ERROR, "unrecognized node type in jointree: %d",
5079 : (int) nodeTag(j->larg));
5080 1498 : if (IsA(j->rarg, RangeTblRef))
5081 1498 : colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
5082 0 : else if (IsA(j->rarg, JoinExpr))
5083 0 : colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
5084 : else
5085 0 : elog(ERROR, "unrecognized node type in jointree: %d",
5086 : (int) nodeTag(j->rarg));
5087 :
5088 : /* Assert children will be processed earlier than join in second pass */
5089 : Assert(colinfo->leftrti < j->rtindex);
5090 : Assert(colinfo->rightrti < j->rtindex);
5091 :
5092 : /* Initialize result arrays with zeroes */
5093 1498 : numjoincols = list_length(jrte->joinaliasvars);
5094 : Assert(numjoincols == list_length(jrte->eref->colnames));
5095 1498 : colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
5096 1498 : colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
5097 :
5098 : /*
5099 : * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
5100 : * Recall that the column(s) merged due to USING are the first column(s)
5101 : * of the join output. We need not do anything special while scanning
5102 : * joinleftcols, but while scanning joinrightcols we must distinguish
5103 : * merged from unmerged columns.
5104 : */
5105 1498 : jcolno = 0;
5106 36120 : foreach(lc, jrte->joinleftcols)
5107 : {
5108 34622 : int leftattno = lfirst_int(lc);
5109 :
5110 34622 : colinfo->leftattnos[jcolno++] = leftattno;
5111 : }
5112 1498 : rcolno = 0;
5113 16378 : foreach(lc, jrte->joinrightcols)
5114 : {
5115 14880 : int rightattno = lfirst_int(lc);
5116 :
5117 14880 : if (rcolno < jrte->joinmergedcols) /* merged column? */
5118 580 : colinfo->rightattnos[rcolno] = rightattno;
5119 : else
5120 14300 : colinfo->rightattnos[jcolno++] = rightattno;
5121 14880 : rcolno++;
5122 : }
5123 : Assert(jcolno == numjoincols);
5124 1498 : }
5125 :
5126 : /*
5127 : * get_rtable_name: convenience function to get a previously assigned RTE alias
5128 : *
5129 : * The RTE must belong to the topmost namespace level in "context".
5130 : */
5131 : static char *
5132 6810 : get_rtable_name(int rtindex, deparse_context *context)
5133 : {
5134 6810 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
5135 :
5136 : Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
5137 6810 : return (char *) list_nth(dpns->rtable_names, rtindex - 1);
5138 : }
5139 :
5140 : /*
5141 : * set_deparse_plan: set up deparse_namespace to parse subexpressions
5142 : * of a given Plan node
5143 : *
5144 : * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
5145 : * and index_tlist fields. Caller must already have adjusted the ancestors
5146 : * list if necessary. Note that the rtable, subplans, and ctes fields do
5147 : * not need to change when shifting attention to different plan nodes in a
5148 : * single plan tree.
5149 : */
5150 : static void
5151 129908 : set_deparse_plan(deparse_namespace *dpns, Plan *plan)
5152 : {
5153 129908 : dpns->plan = plan;
5154 :
5155 : /*
5156 : * We special-case Append and MergeAppend to pretend that the first child
5157 : * plan is the OUTER referent; we have to interpret OUTER Vars in their
5158 : * tlists according to one of the children, and the first one is the most
5159 : * natural choice.
5160 : */
5161 129908 : if (IsA(plan, Append))
5162 4090 : dpns->outer_plan = linitial(((Append *) plan)->appendplans);
5163 125818 : else if (IsA(plan, MergeAppend))
5164 528 : dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
5165 : else
5166 125290 : dpns->outer_plan = outerPlan(plan);
5167 :
5168 129908 : if (dpns->outer_plan)
5169 59678 : dpns->outer_tlist = dpns->outer_plan->targetlist;
5170 : else
5171 70230 : dpns->outer_tlist = NIL;
5172 :
5173 : /*
5174 : * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
5175 : * use OUTER because that could someday conflict with the normal meaning.)
5176 : * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
5177 : * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
5178 : * that as INNER referent.
5179 : *
5180 : * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
5181 : * INNER referent. This is the join from the target relation to the data
5182 : * source, and all INNER_VAR Vars in other parts of the query refer to its
5183 : * targetlist.
5184 : *
5185 : * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
5186 : * excluded expression's tlist. (Similar to the SubqueryScan we don't want
5187 : * to reuse OUTER, it's used for RETURNING in some modify table cases,
5188 : * although not INSERT .. CONFLICT).
5189 : */
5190 129908 : if (IsA(plan, SubqueryScan))
5191 680 : dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
5192 129228 : else if (IsA(plan, CteScan))
5193 552 : dpns->inner_plan = list_nth(dpns->subplans,
5194 552 : ((CteScan *) plan)->ctePlanId - 1);
5195 128676 : else if (IsA(plan, WorkTableScan))
5196 174 : dpns->inner_plan = find_recursive_union(dpns,
5197 : (WorkTableScan *) plan);
5198 128502 : else if (IsA(plan, ModifyTable))
5199 : {
5200 402 : if (((ModifyTable *) plan)->operation == CMD_MERGE)
5201 60 : dpns->inner_plan = outerPlan(plan);
5202 : else
5203 342 : dpns->inner_plan = plan;
5204 : }
5205 : else
5206 128100 : dpns->inner_plan = innerPlan(plan);
5207 :
5208 129908 : if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
5209 170 : dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5210 129738 : else if (dpns->inner_plan)
5211 22142 : dpns->inner_tlist = dpns->inner_plan->targetlist;
5212 : else
5213 107596 : dpns->inner_tlist = NIL;
5214 :
5215 : /* Set up referent for INDEX_VAR Vars, if needed */
5216 129908 : if (IsA(plan, IndexOnlyScan))
5217 3472 : dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5218 126436 : else if (IsA(plan, ForeignScan))
5219 3072 : dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5220 123364 : else if (IsA(plan, CustomScan))
5221 0 : dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5222 : else
5223 123364 : dpns->index_tlist = NIL;
5224 129908 : }
5225 :
5226 : /*
5227 : * Locate the ancestor plan node that is the RecursiveUnion generating
5228 : * the WorkTableScan's work table. We can match on wtParam, since that
5229 : * should be unique within the plan tree.
5230 : */
5231 : static Plan *
5232 174 : find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
5233 : {
5234 : ListCell *lc;
5235 :
5236 438 : foreach(lc, dpns->ancestors)
5237 : {
5238 438 : Plan *ancestor = (Plan *) lfirst(lc);
5239 :
5240 438 : if (IsA(ancestor, RecursiveUnion) &&
5241 174 : ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5242 174 : return ancestor;
5243 : }
5244 0 : elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5245 : wtscan->wtParam);
5246 : return NULL;
5247 : }
5248 :
5249 : /*
5250 : * push_child_plan: temporarily transfer deparsing attention to a child plan
5251 : *
5252 : * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5253 : * deparse context in case the referenced expression itself uses
5254 : * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5255 : * affecting levelsup issues (although in a Plan tree there really shouldn't
5256 : * be any).
5257 : *
5258 : * Caller must provide a local deparse_namespace variable to save the
5259 : * previous state for pop_child_plan.
5260 : */
5261 : static void
5262 71298 : push_child_plan(deparse_namespace *dpns, Plan *plan,
5263 : deparse_namespace *save_dpns)
5264 : {
5265 : /* Save state for restoration later */
5266 71298 : *save_dpns = *dpns;
5267 :
5268 : /* Link current plan node into ancestors list */
5269 71298 : dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5270 :
5271 : /* Set attention on selected child */
5272 71298 : set_deparse_plan(dpns, plan);
5273 71298 : }
5274 :
5275 : /*
5276 : * pop_child_plan: undo the effects of push_child_plan
5277 : */
5278 : static void
5279 71298 : pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5280 : {
5281 : List *ancestors;
5282 :
5283 : /* Get rid of ancestors list cell added by push_child_plan */
5284 71298 : ancestors = list_delete_first(dpns->ancestors);
5285 :
5286 : /* Restore fields changed by push_child_plan */
5287 71298 : *dpns = *save_dpns;
5288 :
5289 : /* Make sure dpns->ancestors is right (may be unnecessary) */
5290 71298 : dpns->ancestors = ancestors;
5291 71298 : }
5292 :
5293 : /*
5294 : * push_ancestor_plan: temporarily transfer deparsing attention to an
5295 : * ancestor plan
5296 : *
5297 : * When expanding a Param reference, we must adjust the deparse context
5298 : * to match the plan node that contains the expression being printed;
5299 : * otherwise we'd fail if that expression itself contains a Param or
5300 : * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5301 : *
5302 : * The target ancestor is conveniently identified by the ListCell holding it
5303 : * in dpns->ancestors.
5304 : *
5305 : * Caller must provide a local deparse_namespace variable to save the
5306 : * previous state for pop_ancestor_plan.
5307 : */
5308 : static void
5309 4640 : push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
5310 : deparse_namespace *save_dpns)
5311 : {
5312 4640 : Plan *plan = (Plan *) lfirst(ancestor_cell);
5313 :
5314 : /* Save state for restoration later */
5315 4640 : *save_dpns = *dpns;
5316 :
5317 : /* Build a new ancestor list with just this node's ancestors */
5318 4640 : dpns->ancestors =
5319 4640 : list_copy_tail(dpns->ancestors,
5320 4640 : list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5321 :
5322 : /* Set attention on selected ancestor */
5323 4640 : set_deparse_plan(dpns, plan);
5324 4640 : }
5325 :
5326 : /*
5327 : * pop_ancestor_plan: undo the effects of push_ancestor_plan
5328 : */
5329 : static void
5330 4640 : pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5331 : {
5332 : /* Free the ancestor list made in push_ancestor_plan */
5333 4640 : list_free(dpns->ancestors);
5334 :
5335 : /* Restore fields changed by push_ancestor_plan */
5336 4640 : *dpns = *save_dpns;
5337 4640 : }
5338 :
5339 :
5340 : /* ----------
5341 : * make_ruledef - reconstruct the CREATE RULE command
5342 : * for a given pg_rewrite tuple
5343 : * ----------
5344 : */
5345 : static void
5346 558 : make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5347 : int prettyFlags)
5348 : {
5349 : char *rulename;
5350 : char ev_type;
5351 : Oid ev_class;
5352 : bool is_instead;
5353 : char *ev_qual;
5354 : char *ev_action;
5355 : List *actions;
5356 : Relation ev_relation;
5357 558 : TupleDesc viewResultDesc = NULL;
5358 : int fno;
5359 : Datum dat;
5360 : bool isnull;
5361 :
5362 : /*
5363 : * Get the attribute values from the rules tuple
5364 : */
5365 558 : fno = SPI_fnumber(rulettc, "rulename");
5366 558 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5367 : Assert(!isnull);
5368 558 : rulename = NameStr(*(DatumGetName(dat)));
5369 :
5370 558 : fno = SPI_fnumber(rulettc, "ev_type");
5371 558 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5372 : Assert(!isnull);
5373 558 : ev_type = DatumGetChar(dat);
5374 :
5375 558 : fno = SPI_fnumber(rulettc, "ev_class");
5376 558 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5377 : Assert(!isnull);
5378 558 : ev_class = DatumGetObjectId(dat);
5379 :
5380 558 : fno = SPI_fnumber(rulettc, "is_instead");
5381 558 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5382 : Assert(!isnull);
5383 558 : is_instead = DatumGetBool(dat);
5384 :
5385 558 : fno = SPI_fnumber(rulettc, "ev_qual");
5386 558 : ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5387 : Assert(ev_qual != NULL);
5388 :
5389 558 : fno = SPI_fnumber(rulettc, "ev_action");
5390 558 : ev_action = SPI_getvalue(ruletup, rulettc, fno);
5391 : Assert(ev_action != NULL);
5392 558 : actions = (List *) stringToNode(ev_action);
5393 558 : if (actions == NIL)
5394 0 : elog(ERROR, "invalid empty ev_action list");
5395 :
5396 558 : ev_relation = table_open(ev_class, AccessShareLock);
5397 :
5398 : /*
5399 : * Build the rules definition text
5400 : */
5401 558 : appendStringInfo(buf, "CREATE RULE %s AS",
5402 : quote_identifier(rulename));
5403 :
5404 558 : if (prettyFlags & PRETTYFLAG_INDENT)
5405 558 : appendStringInfoString(buf, "\n ON ");
5406 : else
5407 0 : appendStringInfoString(buf, " ON ");
5408 :
5409 : /* The event the rule is fired for */
5410 558 : switch (ev_type)
5411 : {
5412 6 : case '1':
5413 6 : appendStringInfoString(buf, "SELECT");
5414 6 : viewResultDesc = RelationGetDescr(ev_relation);
5415 6 : break;
5416 :
5417 154 : case '2':
5418 154 : appendStringInfoString(buf, "UPDATE");
5419 154 : break;
5420 :
5421 294 : case '3':
5422 294 : appendStringInfoString(buf, "INSERT");
5423 294 : break;
5424 :
5425 104 : case '4':
5426 104 : appendStringInfoString(buf, "DELETE");
5427 104 : break;
5428 :
5429 0 : default:
5430 0 : ereport(ERROR,
5431 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5432 : errmsg("rule \"%s\" has unsupported event type %d",
5433 : rulename, ev_type)));
5434 : break;
5435 : }
5436 :
5437 : /* The relation the rule is fired on */
5438 558 : appendStringInfo(buf, " TO %s",
5439 558 : (prettyFlags & PRETTYFLAG_SCHEMA) ?
5440 114 : generate_relation_name(ev_class, NIL) :
5441 444 : generate_qualified_relation_name(ev_class));
5442 :
5443 : /* If the rule has an event qualification, add it */
5444 558 : if (strcmp(ev_qual, "<>") != 0)
5445 : {
5446 : Node *qual;
5447 : Query *query;
5448 : deparse_context context;
5449 : deparse_namespace dpns;
5450 :
5451 122 : if (prettyFlags & PRETTYFLAG_INDENT)
5452 122 : appendStringInfoString(buf, "\n ");
5453 122 : appendStringInfoString(buf, " WHERE ");
5454 :
5455 122 : qual = stringToNode(ev_qual);
5456 :
5457 : /*
5458 : * We need to make a context for recognizing any Vars in the qual
5459 : * (which can only be references to OLD and NEW). Use the rtable of
5460 : * the first query in the action list for this purpose.
5461 : */
5462 122 : query = (Query *) linitial(actions);
5463 :
5464 : /*
5465 : * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5466 : * into the SELECT, and that's what we need to look at. (Ugly kluge
5467 : * ... try to fix this when we redesign querytrees.)
5468 : */
5469 122 : query = getInsertSelectQuery(query, NULL);
5470 :
5471 : /* Must acquire locks right away; see notes in get_query_def() */
5472 122 : AcquireRewriteLocks(query, false, false);
5473 :
5474 122 : context.buf = buf;
5475 122 : context.namespaces = list_make1(&dpns);
5476 122 : context.resultDesc = NULL;
5477 122 : context.targetList = NIL;
5478 122 : context.windowClause = NIL;
5479 122 : context.varprefix = (list_length(query->rtable) != 1);
5480 122 : context.prettyFlags = prettyFlags;
5481 122 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
5482 122 : context.indentLevel = PRETTYINDENT_STD;
5483 122 : context.colNamesVisible = true;
5484 122 : context.inGroupBy = false;
5485 122 : context.varInOrderBy = false;
5486 122 : context.appendparents = NULL;
5487 :
5488 122 : set_deparse_for_query(&dpns, query, NIL);
5489 :
5490 122 : get_rule_expr(qual, &context, false);
5491 : }
5492 :
5493 558 : appendStringInfoString(buf, " DO ");
5494 :
5495 : /* The INSTEAD keyword (if so) */
5496 558 : if (is_instead)
5497 330 : appendStringInfoString(buf, "INSTEAD ");
5498 :
5499 : /* Finally the rules actions */
5500 558 : if (list_length(actions) > 1)
5501 : {
5502 : ListCell *action;
5503 : Query *query;
5504 :
5505 20 : appendStringInfoChar(buf, '(');
5506 60 : foreach(action, actions)
5507 : {
5508 40 : query = (Query *) lfirst(action);
5509 40 : get_query_def(query, buf, NIL, viewResultDesc, true,
5510 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5511 40 : if (prettyFlags)
5512 40 : appendStringInfoString(buf, ";\n");
5513 : else
5514 0 : appendStringInfoString(buf, "; ");
5515 : }
5516 20 : appendStringInfoString(buf, ");");
5517 : }
5518 : else
5519 : {
5520 : Query *query;
5521 :
5522 538 : query = (Query *) linitial(actions);
5523 538 : get_query_def(query, buf, NIL, viewResultDesc, true,
5524 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5525 538 : appendStringInfoChar(buf, ';');
5526 : }
5527 :
5528 558 : table_close(ev_relation, AccessShareLock);
5529 558 : }
5530 :
5531 :
5532 : /* ----------
5533 : * make_viewdef - reconstruct the SELECT part of a
5534 : * view rewrite rule
5535 : * ----------
5536 : */
5537 : static void
5538 3674 : make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5539 : int prettyFlags, int wrapColumn)
5540 : {
5541 : Query *query;
5542 : char ev_type;
5543 : Oid ev_class;
5544 : bool is_instead;
5545 : char *ev_qual;
5546 : char *ev_action;
5547 : List *actions;
5548 : Relation ev_relation;
5549 : int fno;
5550 : Datum dat;
5551 : bool isnull;
5552 :
5553 : /*
5554 : * Get the attribute values from the rules tuple
5555 : */
5556 3674 : fno = SPI_fnumber(rulettc, "ev_type");
5557 3674 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5558 : Assert(!isnull);
5559 3674 : ev_type = DatumGetChar(dat);
5560 :
5561 3674 : fno = SPI_fnumber(rulettc, "ev_class");
5562 3674 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5563 : Assert(!isnull);
5564 3674 : ev_class = DatumGetObjectId(dat);
5565 :
5566 3674 : fno = SPI_fnumber(rulettc, "is_instead");
5567 3674 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5568 : Assert(!isnull);
5569 3674 : is_instead = DatumGetBool(dat);
5570 :
5571 3674 : fno = SPI_fnumber(rulettc, "ev_qual");
5572 3674 : ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5573 : Assert(ev_qual != NULL);
5574 :
5575 3674 : fno = SPI_fnumber(rulettc, "ev_action");
5576 3674 : ev_action = SPI_getvalue(ruletup, rulettc, fno);
5577 : Assert(ev_action != NULL);
5578 3674 : actions = (List *) stringToNode(ev_action);
5579 :
5580 3674 : if (list_length(actions) != 1)
5581 : {
5582 : /* keep output buffer empty and leave */
5583 0 : return;
5584 : }
5585 :
5586 3674 : query = (Query *) linitial(actions);
5587 :
5588 3674 : if (ev_type != '1' || !is_instead ||
5589 3674 : strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5590 : {
5591 : /* keep output buffer empty and leave */
5592 0 : return;
5593 : }
5594 :
5595 3674 : ev_relation = table_open(ev_class, AccessShareLock);
5596 :
5597 3674 : get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5598 : prettyFlags, wrapColumn, 0);
5599 3674 : appendStringInfoChar(buf, ';');
5600 :
5601 3674 : table_close(ev_relation, AccessShareLock);
5602 : }
5603 :
5604 :
5605 : /* ----------
5606 : * get_query_def - Parse back one query parsetree
5607 : *
5608 : * query: parsetree to be displayed
5609 : * buf: output text is appended to buf
5610 : * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5611 : * resultDesc: if not NULL, the output tuple descriptor for the view
5612 : * represented by a SELECT query. We use the column names from it
5613 : * to label SELECT output columns, in preference to names in the query
5614 : * colNamesVisible: true if the surrounding context cares about the output
5615 : * column names at all (as, for example, an EXISTS() context does not);
5616 : * when false, we can suppress dummy column labels such as "?column?"
5617 : * prettyFlags: bitmask of PRETTYFLAG_XXX options
5618 : * wrapColumn: maximum line length, or -1 to disable wrapping
5619 : * startIndent: initial indentation amount
5620 : * ----------
5621 : */
5622 : static void
5623 5872 : get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5624 : TupleDesc resultDesc, bool colNamesVisible,
5625 : int prettyFlags, int wrapColumn, int startIndent)
5626 : {
5627 : deparse_context context;
5628 : deparse_namespace dpns;
5629 : int rtable_size;
5630 :
5631 : /* Guard against excessively long or deeply-nested queries */
5632 5872 : CHECK_FOR_INTERRUPTS();
5633 5872 : check_stack_depth();
5634 :
5635 11744 : rtable_size = query->hasGroupRTE ?
5636 5872 : list_length(query->rtable) - 1 :
5637 5628 : list_length(query->rtable);
5638 :
5639 : /*
5640 : * Replace any Vars in the query's targetlist and havingQual that
5641 : * reference GROUP outputs with the underlying grouping expressions.
5642 : */
5643 5872 : if (query->hasGroupRTE)
5644 : {
5645 244 : query->targetList = (List *)
5646 244 : flatten_group_exprs(NULL, query, (Node *) query->targetList);
5647 244 : query->havingQual =
5648 244 : flatten_group_exprs(NULL, query, query->havingQual);
5649 : }
5650 :
5651 : /*
5652 : * Before we begin to examine the query, acquire locks on referenced
5653 : * relations, and fix up deleted columns in JOIN RTEs. This ensures
5654 : * consistent results. Note we assume it's OK to scribble on the passed
5655 : * querytree!
5656 : *
5657 : * We are only deparsing the query (we are not about to execute it), so we
5658 : * only need AccessShareLock on the relations it mentions.
5659 : */
5660 5872 : AcquireRewriteLocks(query, false, false);
5661 :
5662 5872 : context.buf = buf;
5663 5872 : context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5664 5872 : context.resultDesc = NULL;
5665 5872 : context.targetList = NIL;
5666 5872 : context.windowClause = NIL;
5667 5872 : context.varprefix = (parentnamespace != NIL ||
5668 : rtable_size != 1);
5669 5872 : context.prettyFlags = prettyFlags;
5670 5872 : context.wrapColumn = wrapColumn;
5671 5872 : context.indentLevel = startIndent;
5672 5872 : context.colNamesVisible = colNamesVisible;
5673 5872 : context.inGroupBy = false;
5674 5872 : context.varInOrderBy = false;
5675 5872 : context.appendparents = NULL;
5676 :
5677 5872 : set_deparse_for_query(&dpns, query, parentnamespace);
5678 :
5679 5872 : switch (query->commandType)
5680 : {
5681 5232 : case CMD_SELECT:
5682 : /* We set context.resultDesc only if it's a SELECT */
5683 5232 : context.resultDesc = resultDesc;
5684 5232 : get_select_query_def(query, &context);
5685 5232 : break;
5686 :
5687 154 : case CMD_UPDATE:
5688 154 : get_update_query_def(query, &context);
5689 154 : break;
5690 :
5691 340 : case CMD_INSERT:
5692 340 : get_insert_query_def(query, &context);
5693 340 : break;
5694 :
5695 76 : case CMD_DELETE:
5696 76 : get_delete_query_def(query, &context);
5697 76 : break;
5698 :
5699 12 : case CMD_MERGE:
5700 12 : get_merge_query_def(query, &context);
5701 12 : break;
5702 :
5703 42 : case CMD_NOTHING:
5704 42 : appendStringInfoString(buf, "NOTHING");
5705 42 : break;
5706 :
5707 16 : case CMD_UTILITY:
5708 16 : get_utility_query_def(query, &context);
5709 16 : break;
5710 :
5711 0 : default:
5712 0 : elog(ERROR, "unrecognized query command type: %d",
5713 : query->commandType);
5714 : break;
5715 : }
5716 5872 : }
5717 :
5718 : /* ----------
5719 : * get_values_def - Parse back a VALUES list
5720 : * ----------
5721 : */
5722 : static void
5723 272 : get_values_def(List *values_lists, deparse_context *context)
5724 : {
5725 272 : StringInfo buf = context->buf;
5726 272 : bool first_list = true;
5727 : ListCell *vtl;
5728 :
5729 272 : appendStringInfoString(buf, "VALUES ");
5730 :
5731 778 : foreach(vtl, values_lists)
5732 : {
5733 506 : List *sublist = (List *) lfirst(vtl);
5734 506 : bool first_col = true;
5735 : ListCell *lc;
5736 :
5737 506 : if (first_list)
5738 272 : first_list = false;
5739 : else
5740 234 : appendStringInfoString(buf, ", ");
5741 :
5742 506 : appendStringInfoChar(buf, '(');
5743 1958 : foreach(lc, sublist)
5744 : {
5745 1452 : Node *col = (Node *) lfirst(lc);
5746 :
5747 1452 : if (first_col)
5748 506 : first_col = false;
5749 : else
5750 946 : appendStringInfoChar(buf, ',');
5751 :
5752 : /*
5753 : * Print the value. Whole-row Vars need special treatment.
5754 : */
5755 1452 : get_rule_expr_toplevel(col, context, false);
5756 : }
5757 506 : appendStringInfoChar(buf, ')');
5758 : }
5759 272 : }
5760 :
5761 : /* ----------
5762 : * get_with_clause - Parse back a WITH clause
5763 : * ----------
5764 : */
5765 : static void
5766 5814 : get_with_clause(Query *query, deparse_context *context)
5767 : {
5768 5814 : StringInfo buf = context->buf;
5769 : const char *sep;
5770 : ListCell *l;
5771 :
5772 5814 : if (query->cteList == NIL)
5773 5718 : return;
5774 :
5775 96 : if (PRETTY_INDENT(context))
5776 : {
5777 96 : context->indentLevel += PRETTYINDENT_STD;
5778 96 : appendStringInfoChar(buf, ' ');
5779 : }
5780 :
5781 96 : if (query->hasRecursive)
5782 56 : sep = "WITH RECURSIVE ";
5783 : else
5784 40 : sep = "WITH ";
5785 242 : foreach(l, query->cteList)
5786 : {
5787 146 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5788 :
5789 146 : appendStringInfoString(buf, sep);
5790 146 : appendStringInfoString(buf, quote_identifier(cte->ctename));
5791 146 : if (cte->aliascolnames)
5792 : {
5793 56 : bool first = true;
5794 : ListCell *col;
5795 :
5796 56 : appendStringInfoChar(buf, '(');
5797 148 : foreach(col, cte->aliascolnames)
5798 : {
5799 92 : if (first)
5800 56 : first = false;
5801 : else
5802 36 : appendStringInfoString(buf, ", ");
5803 92 : appendStringInfoString(buf,
5804 92 : quote_identifier(strVal(lfirst(col))));
5805 : }
5806 56 : appendStringInfoChar(buf, ')');
5807 : }
5808 146 : appendStringInfoString(buf, " AS ");
5809 146 : switch (cte->ctematerialized)
5810 : {
5811 128 : case CTEMaterializeDefault:
5812 128 : break;
5813 18 : case CTEMaterializeAlways:
5814 18 : appendStringInfoString(buf, "MATERIALIZED ");
5815 18 : break;
5816 0 : case CTEMaterializeNever:
5817 0 : appendStringInfoString(buf, "NOT MATERIALIZED ");
5818 0 : break;
5819 : }
5820 146 : appendStringInfoChar(buf, '(');
5821 146 : if (PRETTY_INDENT(context))
5822 146 : appendContextKeyword(context, "", 0, 0, 0);
5823 146 : get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5824 : true,
5825 : context->prettyFlags, context->wrapColumn,
5826 : context->indentLevel);
5827 146 : if (PRETTY_INDENT(context))
5828 146 : appendContextKeyword(context, "", 0, 0, 0);
5829 146 : appendStringInfoChar(buf, ')');
5830 :
5831 146 : if (cte->search_clause)
5832 : {
5833 6 : bool first = true;
5834 : ListCell *lc;
5835 :
5836 6 : appendStringInfo(buf, " SEARCH %s FIRST BY ",
5837 6 : cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5838 :
5839 18 : foreach(lc, cte->search_clause->search_col_list)
5840 : {
5841 12 : if (first)
5842 6 : first = false;
5843 : else
5844 6 : appendStringInfoString(buf, ", ");
5845 12 : appendStringInfoString(buf,
5846 12 : quote_identifier(strVal(lfirst(lc))));
5847 : }
5848 :
5849 6 : appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5850 : }
5851 :
5852 146 : if (cte->cycle_clause)
5853 : {
5854 12 : bool first = true;
5855 : ListCell *lc;
5856 :
5857 12 : appendStringInfoString(buf, " CYCLE ");
5858 :
5859 36 : foreach(lc, cte->cycle_clause->cycle_col_list)
5860 : {
5861 24 : if (first)
5862 12 : first = false;
5863 : else
5864 12 : appendStringInfoString(buf, ", ");
5865 24 : appendStringInfoString(buf,
5866 24 : quote_identifier(strVal(lfirst(lc))));
5867 : }
5868 :
5869 12 : appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5870 :
5871 : {
5872 12 : Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5873 12 : Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5874 :
5875 18 : if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5876 6 : cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5877 : {
5878 6 : appendStringInfoString(buf, " TO ");
5879 6 : get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5880 6 : appendStringInfoString(buf, " DEFAULT ");
5881 6 : get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5882 : }
5883 : }
5884 :
5885 12 : appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5886 : }
5887 :
5888 146 : sep = ", ";
5889 : }
5890 :
5891 96 : if (PRETTY_INDENT(context))
5892 : {
5893 96 : context->indentLevel -= PRETTYINDENT_STD;
5894 96 : appendContextKeyword(context, "", 0, 0, 0);
5895 : }
5896 : else
5897 0 : appendStringInfoChar(buf, ' ');
5898 : }
5899 :
5900 : /* ----------
5901 : * get_select_query_def - Parse back a SELECT parsetree
5902 : * ----------
5903 : */
5904 : static void
5905 5232 : get_select_query_def(Query *query, deparse_context *context)
5906 : {
5907 5232 : StringInfo buf = context->buf;
5908 : bool force_colno;
5909 : ListCell *l;
5910 :
5911 : /* Insert the WITH clause if given */
5912 5232 : get_with_clause(query, context);
5913 :
5914 : /* Subroutines may need to consult the SELECT targetlist and windowClause */
5915 5232 : context->targetList = query->targetList;
5916 5232 : context->windowClause = query->windowClause;
5917 :
5918 : /*
5919 : * If the Query node has a setOperations tree, then it's the top level of
5920 : * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5921 : * fields are interesting in the top query itself.
5922 : */
5923 5232 : if (query->setOperations)
5924 : {
5925 164 : get_setop_query(query->setOperations, query, context);
5926 : /* ORDER BY clauses must be simple in this case */
5927 164 : force_colno = true;
5928 : }
5929 : else
5930 : {
5931 5068 : get_basic_select_query(query, context);
5932 5068 : force_colno = false;
5933 : }
5934 :
5935 : /* Add the ORDER BY clause if given */
5936 5232 : if (query->sortClause != NIL)
5937 : {
5938 180 : appendContextKeyword(context, " ORDER BY ",
5939 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5940 180 : get_rule_orderby(query->sortClause, query->targetList,
5941 : force_colno, context);
5942 : }
5943 :
5944 : /*
5945 : * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5946 : * standard spelling of LIMIT.
5947 : */
5948 5232 : if (query->limitOffset != NULL)
5949 : {
5950 32 : appendContextKeyword(context, " OFFSET ",
5951 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5952 32 : get_rule_expr(query->limitOffset, context, false);
5953 : }
5954 5232 : if (query->limitCount != NULL)
5955 : {
5956 86 : if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5957 : {
5958 : /*
5959 : * The limitCount arg is a c_expr, so it needs parens. Simple
5960 : * literals and function expressions would not need parens, but
5961 : * unfortunately it's hard to tell if the expression will be
5962 : * printed as a simple literal like 123 or as a typecast
5963 : * expression, like '-123'::int4. The grammar accepts the former
5964 : * without quoting, but not the latter.
5965 : */
5966 48 : appendContextKeyword(context, " FETCH FIRST ",
5967 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5968 48 : appendStringInfoChar(buf, '(');
5969 48 : get_rule_expr(query->limitCount, context, false);
5970 48 : appendStringInfoChar(buf, ')');
5971 48 : appendStringInfoString(buf, " ROWS WITH TIES");
5972 : }
5973 : else
5974 : {
5975 38 : appendContextKeyword(context, " LIMIT ",
5976 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5977 38 : if (IsA(query->limitCount, Const) &&
5978 16 : ((Const *) query->limitCount)->constisnull)
5979 16 : appendStringInfoString(buf, "ALL");
5980 : else
5981 22 : get_rule_expr(query->limitCount, context, false);
5982 : }
5983 : }
5984 :
5985 : /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5986 5232 : if (query->hasForUpdate)
5987 : {
5988 12 : foreach(l, query->rowMarks)
5989 : {
5990 6 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5991 :
5992 : /* don't print implicit clauses */
5993 6 : if (rc->pushedDown)
5994 0 : continue;
5995 :
5996 6 : switch (rc->strength)
5997 : {
5998 0 : case LCS_NONE:
5999 : /* we intentionally throw an error for LCS_NONE */
6000 0 : elog(ERROR, "unrecognized LockClauseStrength %d",
6001 : (int) rc->strength);
6002 : break;
6003 0 : case LCS_FORKEYSHARE:
6004 0 : appendContextKeyword(context, " FOR KEY SHARE",
6005 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6006 0 : break;
6007 0 : case LCS_FORSHARE:
6008 0 : appendContextKeyword(context, " FOR SHARE",
6009 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6010 0 : break;
6011 0 : case LCS_FORNOKEYUPDATE:
6012 0 : appendContextKeyword(context, " FOR NO KEY UPDATE",
6013 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6014 0 : break;
6015 6 : case LCS_FORUPDATE:
6016 6 : appendContextKeyword(context, " FOR UPDATE",
6017 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6018 6 : break;
6019 : }
6020 :
6021 6 : appendStringInfo(buf, " OF %s",
6022 6 : quote_identifier(get_rtable_name(rc->rti,
6023 : context)));
6024 6 : if (rc->waitPolicy == LockWaitError)
6025 0 : appendStringInfoString(buf, " NOWAIT");
6026 6 : else if (rc->waitPolicy == LockWaitSkip)
6027 0 : appendStringInfoString(buf, " SKIP LOCKED");
6028 : }
6029 : }
6030 5232 : }
6031 :
6032 : /*
6033 : * Detect whether query looks like SELECT ... FROM VALUES(),
6034 : * with no need to rename the output columns of the VALUES RTE.
6035 : * If so, return the VALUES RTE. Otherwise return NULL.
6036 : */
6037 : static RangeTblEntry *
6038 5068 : get_simple_values_rte(Query *query, TupleDesc resultDesc)
6039 : {
6040 5068 : RangeTblEntry *result = NULL;
6041 : ListCell *lc;
6042 :
6043 : /*
6044 : * We want to detect a match even if the Query also contains OLD or NEW
6045 : * rule RTEs. So the idea is to scan the rtable and see if there is only
6046 : * one inFromCl RTE that is a VALUES RTE.
6047 : */
6048 5440 : foreach(lc, query->rtable)
6049 : {
6050 4618 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
6051 :
6052 4618 : if (rte->rtekind == RTE_VALUES && rte->inFromCl)
6053 : {
6054 228 : if (result)
6055 4246 : return NULL; /* multiple VALUES (probably not possible) */
6056 228 : result = rte;
6057 : }
6058 4390 : else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
6059 144 : continue; /* ignore rule entries */
6060 : else
6061 4246 : return NULL; /* something else -> not simple VALUES */
6062 : }
6063 :
6064 : /*
6065 : * We don't need to check the targetlist in any great detail, because
6066 : * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
6067 : * appear inside auto-generated sub-queries with very restricted
6068 : * structure. However, DefineView might have modified the tlist by
6069 : * injecting new column aliases, or we might have some other column
6070 : * aliases forced by a resultDesc. We can only simplify if the RTE's
6071 : * column names match the names that get_target_list() would select.
6072 : */
6073 822 : if (result)
6074 : {
6075 : ListCell *lcn;
6076 : int colno;
6077 :
6078 228 : if (list_length(query->targetList) != list_length(result->eref->colnames))
6079 0 : return NULL; /* this probably cannot happen */
6080 228 : colno = 0;
6081 842 : forboth(lc, query->targetList, lcn, result->eref->colnames)
6082 : {
6083 626 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
6084 626 : char *cname = strVal(lfirst(lcn));
6085 : char *colname;
6086 :
6087 626 : if (tle->resjunk)
6088 12 : return NULL; /* this probably cannot happen */
6089 :
6090 : /* compute name that get_target_list would use for column */
6091 626 : colno++;
6092 626 : if (resultDesc && colno <= resultDesc->natts)
6093 30 : colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6094 : else
6095 596 : colname = tle->resname;
6096 :
6097 : /* does it match the VALUES RTE? */
6098 626 : if (colname == NULL || strcmp(colname, cname) != 0)
6099 12 : return NULL; /* column name has been changed */
6100 : }
6101 : }
6102 :
6103 810 : return result;
6104 : }
6105 :
6106 : static void
6107 5068 : get_basic_select_query(Query *query, deparse_context *context)
6108 : {
6109 5068 : StringInfo buf = context->buf;
6110 : RangeTblEntry *values_rte;
6111 : char *sep;
6112 : ListCell *l;
6113 :
6114 5068 : if (PRETTY_INDENT(context))
6115 : {
6116 5022 : context->indentLevel += PRETTYINDENT_STD;
6117 5022 : appendStringInfoChar(buf, ' ');
6118 : }
6119 :
6120 : /*
6121 : * If the query looks like SELECT * FROM (VALUES ...), then print just the
6122 : * VALUES part. This reverses what transformValuesClause() did at parse
6123 : * time.
6124 : */
6125 5068 : values_rte = get_simple_values_rte(query, context->resultDesc);
6126 5068 : if (values_rte)
6127 : {
6128 216 : get_values_def(values_rte->values_lists, context);
6129 216 : return;
6130 : }
6131 :
6132 : /*
6133 : * Build up the query string - first we say SELECT
6134 : */
6135 4852 : if (query->isReturn)
6136 52 : appendStringInfoString(buf, "RETURN");
6137 : else
6138 4800 : appendStringInfoString(buf, "SELECT");
6139 :
6140 : /* Add the DISTINCT clause if given */
6141 4852 : if (query->distinctClause != NIL)
6142 : {
6143 0 : if (query->hasDistinctOn)
6144 : {
6145 0 : appendStringInfoString(buf, " DISTINCT ON (");
6146 0 : sep = "";
6147 0 : foreach(l, query->distinctClause)
6148 : {
6149 0 : SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6150 :
6151 0 : appendStringInfoString(buf, sep);
6152 0 : get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
6153 : false, context);
6154 0 : sep = ", ";
6155 : }
6156 0 : appendStringInfoChar(buf, ')');
6157 : }
6158 : else
6159 0 : appendStringInfoString(buf, " DISTINCT");
6160 : }
6161 :
6162 : /* Then we tell what to select (the targetlist) */
6163 4852 : get_target_list(query->targetList, context);
6164 :
6165 : /* Add the FROM clause if needed */
6166 4852 : get_from_clause(query, " FROM ", context);
6167 :
6168 : /* Add the WHERE clause if given */
6169 4852 : if (query->jointree->quals != NULL)
6170 : {
6171 1470 : appendContextKeyword(context, " WHERE ",
6172 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6173 1470 : get_rule_expr(query->jointree->quals, context, false);
6174 : }
6175 :
6176 : /* Add the GROUP BY clause if given */
6177 4852 : if (query->groupClause != NULL || query->groupingSets != NULL)
6178 : {
6179 : bool save_ingroupby;
6180 :
6181 244 : appendContextKeyword(context, " GROUP BY ",
6182 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6183 244 : if (query->groupDistinct)
6184 0 : appendStringInfoString(buf, "DISTINCT ");
6185 :
6186 244 : save_ingroupby = context->inGroupBy;
6187 244 : context->inGroupBy = true;
6188 :
6189 244 : if (query->groupByAll)
6190 6 : appendStringInfoString(buf, "ALL");
6191 238 : else if (query->groupingSets == NIL)
6192 : {
6193 232 : sep = "";
6194 522 : foreach(l, query->groupClause)
6195 : {
6196 290 : SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6197 :
6198 290 : appendStringInfoString(buf, sep);
6199 290 : get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
6200 : false, context);
6201 290 : sep = ", ";
6202 : }
6203 : }
6204 : else
6205 : {
6206 6 : sep = "";
6207 12 : foreach(l, query->groupingSets)
6208 : {
6209 6 : GroupingSet *grp = lfirst(l);
6210 :
6211 6 : appendStringInfoString(buf, sep);
6212 6 : get_rule_groupingset(grp, query->targetList, true, context);
6213 6 : sep = ", ";
6214 : }
6215 : }
6216 :
6217 244 : context->inGroupBy = save_ingroupby;
6218 : }
6219 :
6220 : /* Add the HAVING clause if given */
6221 4852 : if (query->havingQual != NULL)
6222 : {
6223 10 : appendContextKeyword(context, " HAVING ",
6224 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
6225 10 : get_rule_expr(query->havingQual, context, false);
6226 : }
6227 :
6228 : /* Add the WINDOW clause if needed */
6229 4852 : if (query->windowClause != NIL)
6230 42 : get_rule_windowclause(query, context);
6231 : }
6232 :
6233 : /* ----------
6234 : * get_target_list - Parse back a SELECT target list
6235 : *
6236 : * This is also used for RETURNING lists in INSERT/UPDATE/DELETE/MERGE.
6237 : * ----------
6238 : */
6239 : static void
6240 4998 : get_target_list(List *targetList, deparse_context *context)
6241 : {
6242 4998 : StringInfo buf = context->buf;
6243 : StringInfoData targetbuf;
6244 4998 : bool last_was_multiline = false;
6245 : char *sep;
6246 : int colno;
6247 : ListCell *l;
6248 :
6249 : /* we use targetbuf to hold each TLE's text temporarily */
6250 4998 : initStringInfo(&targetbuf);
6251 :
6252 4998 : sep = " ";
6253 4998 : colno = 0;
6254 25270 : foreach(l, targetList)
6255 : {
6256 20272 : TargetEntry *tle = (TargetEntry *) lfirst(l);
6257 : char *colname;
6258 : char *attname;
6259 :
6260 20272 : if (tle->resjunk)
6261 34 : continue; /* ignore junk entries */
6262 :
6263 20238 : appendStringInfoString(buf, sep);
6264 20238 : sep = ", ";
6265 20238 : colno++;
6266 :
6267 : /*
6268 : * Put the new field text into targetbuf so we can decide after we've
6269 : * got it whether or not it needs to go on a new line.
6270 : */
6271 20238 : resetStringInfo(&targetbuf);
6272 20238 : context->buf = &targetbuf;
6273 :
6274 : /*
6275 : * We special-case Var nodes rather than using get_rule_expr. This is
6276 : * needed because get_rule_expr will display a whole-row Var as
6277 : * "foo.*", which is the preferred notation in most contexts, but at
6278 : * the top level of a SELECT list it's not right (the parser will
6279 : * expand that notation into multiple columns, yielding behavior
6280 : * different from a whole-row Var). We need to call get_variable
6281 : * directly so that we can tell it to do the right thing, and so that
6282 : * we can get the attribute name which is the default AS label.
6283 : */
6284 20238 : if (tle->expr && (IsA(tle->expr, Var)))
6285 : {
6286 15684 : attname = get_variable((Var *) tle->expr, 0, true, context);
6287 : }
6288 : else
6289 : {
6290 4554 : get_rule_expr((Node *) tle->expr, context, true);
6291 :
6292 : /*
6293 : * When colNamesVisible is true, we should always show the
6294 : * assigned column name explicitly. Otherwise, show it only if
6295 : * it's not FigureColname's fallback.
6296 : */
6297 4554 : attname = context->colNamesVisible ? NULL : "?column?";
6298 : }
6299 :
6300 : /*
6301 : * Figure out what the result column should be called. In the context
6302 : * of a view, use the view's tuple descriptor (so as to pick up the
6303 : * effects of any column RENAME that's been done on the view).
6304 : * Otherwise, just use what we can find in the TLE.
6305 : */
6306 20238 : if (context->resultDesc && colno <= context->resultDesc->natts)
6307 18402 : colname = NameStr(TupleDescAttr(context->resultDesc,
6308 : colno - 1)->attname);
6309 : else
6310 1836 : colname = tle->resname;
6311 :
6312 : /* Show AS unless the column's name is correct as-is */
6313 20238 : if (colname) /* resname could be NULL */
6314 : {
6315 20186 : if (attname == NULL || strcmp(attname, colname) != 0)
6316 6476 : appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6317 : }
6318 :
6319 : /* Restore context's output buffer */
6320 20238 : context->buf = buf;
6321 :
6322 : /* Consider line-wrapping if enabled */
6323 20238 : if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6324 : {
6325 : int leading_nl_pos;
6326 :
6327 : /* Does the new field start with a new line? */
6328 20192 : if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6329 474 : leading_nl_pos = 0;
6330 : else
6331 19718 : leading_nl_pos = -1;
6332 :
6333 : /* If so, we shouldn't add anything */
6334 20192 : if (leading_nl_pos >= 0)
6335 : {
6336 : /* instead, remove any trailing spaces currently in buf */
6337 474 : removeStringInfoSpaces(buf);
6338 : }
6339 : else
6340 : {
6341 : char *trailing_nl;
6342 :
6343 : /* Locate the start of the current line in the output buffer */
6344 19718 : trailing_nl = strrchr(buf->data, '\n');
6345 19718 : if (trailing_nl == NULL)
6346 6090 : trailing_nl = buf->data;
6347 : else
6348 13628 : trailing_nl++;
6349 :
6350 : /*
6351 : * Add a newline, plus some indentation, if the new field is
6352 : * not the first and either the new field would cause an
6353 : * overflow or the last field used more than one line.
6354 : */
6355 19718 : if (colno > 1 &&
6356 14782 : ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6357 : last_was_multiline))
6358 14782 : appendContextKeyword(context, "", -PRETTYINDENT_STD,
6359 : PRETTYINDENT_STD, PRETTYINDENT_VAR);
6360 : }
6361 :
6362 : /* Remember this field's multiline status for next iteration */
6363 20192 : last_was_multiline =
6364 20192 : (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6365 : }
6366 :
6367 : /* Add the new field */
6368 20238 : appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6369 : }
6370 :
6371 : /* clean up */
6372 4998 : pfree(targetbuf.data);
6373 4998 : }
6374 :
6375 : static void
6376 146 : get_returning_clause(Query *query, deparse_context *context)
6377 : {
6378 146 : StringInfo buf = context->buf;
6379 :
6380 146 : if (query->returningList)
6381 : {
6382 146 : bool have_with = false;
6383 :
6384 146 : appendContextKeyword(context, " RETURNING",
6385 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6386 :
6387 : /* Add WITH (OLD/NEW) options, if they're not the defaults */
6388 146 : if (query->returningOldAlias && strcmp(query->returningOldAlias, "old") != 0)
6389 : {
6390 18 : appendStringInfo(buf, " WITH (OLD AS %s",
6391 18 : quote_identifier(query->returningOldAlias));
6392 18 : have_with = true;
6393 : }
6394 146 : if (query->returningNewAlias && strcmp(query->returningNewAlias, "new") != 0)
6395 : {
6396 18 : if (have_with)
6397 12 : appendStringInfo(buf, ", NEW AS %s",
6398 12 : quote_identifier(query->returningNewAlias));
6399 : else
6400 : {
6401 6 : appendStringInfo(buf, " WITH (NEW AS %s",
6402 6 : quote_identifier(query->returningNewAlias));
6403 6 : have_with = true;
6404 : }
6405 : }
6406 146 : if (have_with)
6407 24 : appendStringInfoChar(buf, ')');
6408 :
6409 : /* Add the returning expressions themselves */
6410 146 : get_target_list(query->returningList, context);
6411 : }
6412 146 : }
6413 :
6414 : static void
6415 756 : get_setop_query(Node *setOp, Query *query, deparse_context *context)
6416 : {
6417 756 : StringInfo buf = context->buf;
6418 : bool need_paren;
6419 :
6420 : /* Guard against excessively long or deeply-nested queries */
6421 756 : CHECK_FOR_INTERRUPTS();
6422 756 : check_stack_depth();
6423 :
6424 756 : if (IsA(setOp, RangeTblRef))
6425 : {
6426 460 : RangeTblRef *rtr = (RangeTblRef *) setOp;
6427 460 : RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6428 460 : Query *subquery = rte->subquery;
6429 :
6430 : Assert(subquery != NULL);
6431 :
6432 : /*
6433 : * We need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y.
6434 : * Also add parens if the leaf query contains its own set operations.
6435 : * (That shouldn't happen unless one of the other clauses is also
6436 : * present, see transformSetOperationTree; but let's be safe.)
6437 : */
6438 1380 : need_paren = (subquery->cteList ||
6439 460 : subquery->sortClause ||
6440 460 : subquery->rowMarks ||
6441 460 : subquery->limitOffset ||
6442 1380 : subquery->limitCount ||
6443 460 : subquery->setOperations);
6444 460 : if (need_paren)
6445 0 : appendStringInfoChar(buf, '(');
6446 460 : get_query_def(subquery, buf, context->namespaces,
6447 460 : context->resultDesc, context->colNamesVisible,
6448 : context->prettyFlags, context->wrapColumn,
6449 : context->indentLevel);
6450 460 : if (need_paren)
6451 0 : appendStringInfoChar(buf, ')');
6452 : }
6453 296 : else if (IsA(setOp, SetOperationStmt))
6454 : {
6455 296 : SetOperationStmt *op = (SetOperationStmt *) setOp;
6456 : int subindent;
6457 : bool save_colnamesvisible;
6458 :
6459 : /*
6460 : * We force parens when nesting two SetOperationStmts, except when the
6461 : * lefthand input is another setop of the same kind. Syntactically,
6462 : * we could omit parens in rather more cases, but it seems best to use
6463 : * parens to flag cases where the setop operator changes. If we use
6464 : * parens, we also increase the indentation level for the child query.
6465 : *
6466 : * There are some cases in which parens are needed around a leaf query
6467 : * too, but those are more easily handled at the next level down (see
6468 : * code above).
6469 : */
6470 296 : if (IsA(op->larg, SetOperationStmt))
6471 : {
6472 132 : SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6473 :
6474 132 : if (op->op == lop->op && op->all == lop->all)
6475 132 : need_paren = false;
6476 : else
6477 0 : need_paren = true;
6478 : }
6479 : else
6480 164 : need_paren = false;
6481 :
6482 296 : if (need_paren)
6483 : {
6484 0 : appendStringInfoChar(buf, '(');
6485 0 : subindent = PRETTYINDENT_STD;
6486 0 : appendContextKeyword(context, "", subindent, 0, 0);
6487 : }
6488 : else
6489 296 : subindent = 0;
6490 :
6491 296 : get_setop_query(op->larg, query, context);
6492 :
6493 296 : if (need_paren)
6494 0 : appendContextKeyword(context, ") ", -subindent, 0, 0);
6495 296 : else if (PRETTY_INDENT(context))
6496 296 : appendContextKeyword(context, "", -subindent, 0, 0);
6497 : else
6498 0 : appendStringInfoChar(buf, ' ');
6499 :
6500 296 : switch (op->op)
6501 : {
6502 296 : case SETOP_UNION:
6503 296 : appendStringInfoString(buf, "UNION ");
6504 296 : break;
6505 0 : case SETOP_INTERSECT:
6506 0 : appendStringInfoString(buf, "INTERSECT ");
6507 0 : break;
6508 0 : case SETOP_EXCEPT:
6509 0 : appendStringInfoString(buf, "EXCEPT ");
6510 0 : break;
6511 0 : default:
6512 0 : elog(ERROR, "unrecognized set op: %d",
6513 : (int) op->op);
6514 : }
6515 296 : if (op->all)
6516 284 : appendStringInfoString(buf, "ALL ");
6517 :
6518 : /* Always parenthesize if RHS is another setop */
6519 296 : need_paren = IsA(op->rarg, SetOperationStmt);
6520 :
6521 : /*
6522 : * The indentation code here is deliberately a bit different from that
6523 : * for the lefthand input, because we want the line breaks in
6524 : * different places.
6525 : */
6526 296 : if (need_paren)
6527 : {
6528 0 : appendStringInfoChar(buf, '(');
6529 0 : subindent = PRETTYINDENT_STD;
6530 : }
6531 : else
6532 296 : subindent = 0;
6533 296 : appendContextKeyword(context, "", subindent, 0, 0);
6534 :
6535 : /*
6536 : * The output column names of the RHS sub-select don't matter.
6537 : */
6538 296 : save_colnamesvisible = context->colNamesVisible;
6539 296 : context->colNamesVisible = false;
6540 :
6541 296 : get_setop_query(op->rarg, query, context);
6542 :
6543 296 : context->colNamesVisible = save_colnamesvisible;
6544 :
6545 296 : if (PRETTY_INDENT(context))
6546 296 : context->indentLevel -= subindent;
6547 296 : if (need_paren)
6548 0 : appendContextKeyword(context, ")", 0, 0, 0);
6549 : }
6550 : else
6551 : {
6552 0 : elog(ERROR, "unrecognized node type: %d",
6553 : (int) nodeTag(setOp));
6554 : }
6555 756 : }
6556 :
6557 : /*
6558 : * Display a sort/group clause.
6559 : *
6560 : * Also returns the expression tree, so caller need not find it again.
6561 : */
6562 : static Node *
6563 684 : get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
6564 : deparse_context *context)
6565 : {
6566 684 : StringInfo buf = context->buf;
6567 : TargetEntry *tle;
6568 : Node *expr;
6569 :
6570 684 : tle = get_sortgroupref_tle(ref, tlist);
6571 684 : expr = (Node *) tle->expr;
6572 :
6573 : /*
6574 : * Use column-number form if requested by caller. Otherwise, if
6575 : * expression is a constant, force it to be dumped with an explicit cast
6576 : * as decoration --- this is because a simple integer constant is
6577 : * ambiguous (and will be misinterpreted by findTargetlistEntrySQL92()) if
6578 : * we dump it without any decoration. Similarly, if it's just a Var,
6579 : * there is risk of misinterpretation if the column name is reassigned in
6580 : * the SELECT list, so we may need to force table qualification. And, if
6581 : * it's anything more complex than a simple Var, then force extra parens
6582 : * around it, to ensure it can't be misinterpreted as a cube() or rollup()
6583 : * construct.
6584 : */
6585 684 : if (force_colno)
6586 : {
6587 : Assert(!tle->resjunk);
6588 12 : appendStringInfo(buf, "%d", tle->resno);
6589 : }
6590 672 : else if (!expr)
6591 : /* do nothing, probably can't happen */ ;
6592 672 : else if (IsA(expr, Const))
6593 0 : get_const_expr((Const *) expr, context, 1);
6594 672 : else if (IsA(expr, Var))
6595 : {
6596 : /* Tell get_variable to check for name conflict */
6597 644 : bool save_varinorderby = context->varInOrderBy;
6598 :
6599 644 : context->varInOrderBy = true;
6600 644 : (void) get_variable((Var *) expr, 0, false, context);
6601 644 : context->varInOrderBy = save_varinorderby;
6602 : }
6603 : else
6604 : {
6605 : /*
6606 : * We must force parens for function-like expressions even if
6607 : * PRETTY_PAREN is off, since those are the ones in danger of
6608 : * misparsing. For other expressions we need to force them only if
6609 : * PRETTY_PAREN is on, since otherwise the expression will output them
6610 : * itself. (We can't skip the parens.)
6611 : */
6612 56 : bool need_paren = (PRETTY_PAREN(context)
6613 28 : || IsA(expr, FuncExpr)
6614 24 : || IsA(expr, Aggref)
6615 24 : || IsA(expr, WindowFunc)
6616 56 : || IsA(expr, JsonConstructorExpr));
6617 :
6618 28 : if (need_paren)
6619 4 : appendStringInfoChar(context->buf, '(');
6620 28 : get_rule_expr(expr, context, true);
6621 28 : if (need_paren)
6622 4 : appendStringInfoChar(context->buf, ')');
6623 : }
6624 :
6625 684 : return expr;
6626 : }
6627 :
6628 : /*
6629 : * Display a GroupingSet
6630 : */
6631 : static void
6632 18 : get_rule_groupingset(GroupingSet *gset, List *targetlist,
6633 : bool omit_parens, deparse_context *context)
6634 : {
6635 : ListCell *l;
6636 18 : StringInfo buf = context->buf;
6637 18 : bool omit_child_parens = true;
6638 18 : char *sep = "";
6639 :
6640 18 : switch (gset->kind)
6641 : {
6642 0 : case GROUPING_SET_EMPTY:
6643 0 : appendStringInfoString(buf, "()");
6644 0 : return;
6645 :
6646 12 : case GROUPING_SET_SIMPLE:
6647 : {
6648 12 : if (!omit_parens || list_length(gset->content) != 1)
6649 12 : appendStringInfoChar(buf, '(');
6650 :
6651 42 : foreach(l, gset->content)
6652 : {
6653 30 : Index ref = lfirst_int(l);
6654 :
6655 30 : appendStringInfoString(buf, sep);
6656 30 : get_rule_sortgroupclause(ref, targetlist,
6657 : false, context);
6658 30 : sep = ", ";
6659 : }
6660 :
6661 12 : if (!omit_parens || list_length(gset->content) != 1)
6662 12 : appendStringInfoChar(buf, ')');
6663 : }
6664 12 : return;
6665 :
6666 6 : case GROUPING_SET_ROLLUP:
6667 6 : appendStringInfoString(buf, "ROLLUP(");
6668 6 : break;
6669 0 : case GROUPING_SET_CUBE:
6670 0 : appendStringInfoString(buf, "CUBE(");
6671 0 : break;
6672 0 : case GROUPING_SET_SETS:
6673 0 : appendStringInfoString(buf, "GROUPING SETS (");
6674 0 : omit_child_parens = false;
6675 0 : break;
6676 : }
6677 :
6678 18 : foreach(l, gset->content)
6679 : {
6680 12 : appendStringInfoString(buf, sep);
6681 12 : get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6682 12 : sep = ", ";
6683 : }
6684 :
6685 6 : appendStringInfoChar(buf, ')');
6686 : }
6687 :
6688 : /*
6689 : * Display an ORDER BY list.
6690 : */
6691 : static void
6692 332 : get_rule_orderby(List *orderList, List *targetList,
6693 : bool force_colno, deparse_context *context)
6694 : {
6695 332 : StringInfo buf = context->buf;
6696 : const char *sep;
6697 : ListCell *l;
6698 :
6699 332 : sep = "";
6700 696 : foreach(l, orderList)
6701 : {
6702 364 : SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6703 : Node *sortexpr;
6704 : Oid sortcoltype;
6705 : TypeCacheEntry *typentry;
6706 :
6707 364 : appendStringInfoString(buf, sep);
6708 364 : sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6709 : force_colno, context);
6710 364 : sortcoltype = exprType(sortexpr);
6711 : /* See whether operator is default < or > for datatype */
6712 364 : typentry = lookup_type_cache(sortcoltype,
6713 : TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
6714 364 : if (srt->sortop == typentry->lt_opr)
6715 : {
6716 : /* ASC is default, so emit nothing for it */
6717 336 : if (srt->nulls_first)
6718 0 : appendStringInfoString(buf, " NULLS FIRST");
6719 : }
6720 28 : else if (srt->sortop == typentry->gt_opr)
6721 : {
6722 10 : appendStringInfoString(buf, " DESC");
6723 : /* DESC defaults to NULLS FIRST */
6724 10 : if (!srt->nulls_first)
6725 2 : appendStringInfoString(buf, " NULLS LAST");
6726 : }
6727 : else
6728 : {
6729 18 : appendStringInfo(buf, " USING %s",
6730 : generate_operator_name(srt->sortop,
6731 : sortcoltype,
6732 : sortcoltype));
6733 : /* be specific to eliminate ambiguity */
6734 18 : if (srt->nulls_first)
6735 0 : appendStringInfoString(buf, " NULLS FIRST");
6736 : else
6737 18 : appendStringInfoString(buf, " NULLS LAST");
6738 : }
6739 364 : sep = ", ";
6740 : }
6741 332 : }
6742 :
6743 : /*
6744 : * Display a WINDOW clause.
6745 : *
6746 : * Note that the windowClause list might contain only anonymous window
6747 : * specifications, in which case we should print nothing here.
6748 : */
6749 : static void
6750 42 : get_rule_windowclause(Query *query, deparse_context *context)
6751 : {
6752 42 : StringInfo buf = context->buf;
6753 : const char *sep;
6754 : ListCell *l;
6755 :
6756 42 : sep = NULL;
6757 84 : foreach(l, query->windowClause)
6758 : {
6759 42 : WindowClause *wc = (WindowClause *) lfirst(l);
6760 :
6761 42 : if (wc->name == NULL)
6762 42 : continue; /* ignore anonymous windows */
6763 :
6764 0 : if (sep == NULL)
6765 0 : appendContextKeyword(context, " WINDOW ",
6766 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6767 : else
6768 0 : appendStringInfoString(buf, sep);
6769 :
6770 0 : appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6771 :
6772 0 : get_rule_windowspec(wc, query->targetList, context);
6773 :
6774 0 : sep = ", ";
6775 : }
6776 42 : }
6777 :
6778 : /*
6779 : * Display a window definition
6780 : */
6781 : static void
6782 42 : get_rule_windowspec(WindowClause *wc, List *targetList,
6783 : deparse_context *context)
6784 : {
6785 42 : StringInfo buf = context->buf;
6786 42 : bool needspace = false;
6787 : const char *sep;
6788 : ListCell *l;
6789 :
6790 42 : appendStringInfoChar(buf, '(');
6791 42 : if (wc->refname)
6792 : {
6793 0 : appendStringInfoString(buf, quote_identifier(wc->refname));
6794 0 : needspace = true;
6795 : }
6796 : /* partition clauses are always inherited, so only print if no refname */
6797 42 : if (wc->partitionClause && !wc->refname)
6798 : {
6799 0 : if (needspace)
6800 0 : appendStringInfoChar(buf, ' ');
6801 0 : appendStringInfoString(buf, "PARTITION BY ");
6802 0 : sep = "";
6803 0 : foreach(l, wc->partitionClause)
6804 : {
6805 0 : SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6806 :
6807 0 : appendStringInfoString(buf, sep);
6808 0 : get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6809 : false, context);
6810 0 : sep = ", ";
6811 : }
6812 0 : needspace = true;
6813 : }
6814 : /* print ordering clause only if not inherited */
6815 42 : if (wc->orderClause && !wc->copiedOrder)
6816 : {
6817 42 : if (needspace)
6818 0 : appendStringInfoChar(buf, ' ');
6819 42 : appendStringInfoString(buf, "ORDER BY ");
6820 42 : get_rule_orderby(wc->orderClause, targetList, false, context);
6821 42 : needspace = true;
6822 : }
6823 : /* framing clause is never inherited, so print unless it's default */
6824 42 : if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
6825 : {
6826 42 : if (needspace)
6827 42 : appendStringInfoChar(buf, ' ');
6828 42 : get_window_frame_options(wc->frameOptions,
6829 : wc->startOffset, wc->endOffset,
6830 : context);
6831 : }
6832 42 : appendStringInfoChar(buf, ')');
6833 42 : }
6834 :
6835 : /*
6836 : * Append the description of a window's framing options to context->buf
6837 : */
6838 : static void
6839 232 : get_window_frame_options(int frameOptions,
6840 : Node *startOffset, Node *endOffset,
6841 : deparse_context *context)
6842 : {
6843 232 : StringInfo buf = context->buf;
6844 :
6845 232 : if (frameOptions & FRAMEOPTION_NONDEFAULT)
6846 : {
6847 232 : if (frameOptions & FRAMEOPTION_RANGE)
6848 20 : appendStringInfoString(buf, "RANGE ");
6849 212 : else if (frameOptions & FRAMEOPTION_ROWS)
6850 200 : appendStringInfoString(buf, "ROWS ");
6851 12 : else if (frameOptions & FRAMEOPTION_GROUPS)
6852 12 : appendStringInfoString(buf, "GROUPS ");
6853 : else
6854 : Assert(false);
6855 232 : if (frameOptions & FRAMEOPTION_BETWEEN)
6856 92 : appendStringInfoString(buf, "BETWEEN ");
6857 232 : if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
6858 146 : appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6859 86 : else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW)
6860 26 : appendStringInfoString(buf, "CURRENT ROW ");
6861 60 : else if (frameOptions & FRAMEOPTION_START_OFFSET)
6862 : {
6863 60 : get_rule_expr(startOffset, context, false);
6864 60 : if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
6865 60 : appendStringInfoString(buf, " PRECEDING ");
6866 0 : else if (frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
6867 0 : appendStringInfoString(buf, " FOLLOWING ");
6868 : else
6869 : Assert(false);
6870 : }
6871 : else
6872 : Assert(false);
6873 232 : if (frameOptions & FRAMEOPTION_BETWEEN)
6874 : {
6875 92 : appendStringInfoString(buf, "AND ");
6876 92 : if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
6877 20 : appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6878 72 : else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
6879 6 : appendStringInfoString(buf, "CURRENT ROW ");
6880 66 : else if (frameOptions & FRAMEOPTION_END_OFFSET)
6881 : {
6882 66 : get_rule_expr(endOffset, context, false);
6883 66 : if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
6884 0 : appendStringInfoString(buf, " PRECEDING ");
6885 66 : else if (frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
6886 66 : appendStringInfoString(buf, " FOLLOWING ");
6887 : else
6888 : Assert(false);
6889 : }
6890 : else
6891 : Assert(false);
6892 : }
6893 232 : if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
6894 6 : appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6895 226 : else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6896 6 : appendStringInfoString(buf, "EXCLUDE GROUP ");
6897 220 : else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6898 6 : appendStringInfoString(buf, "EXCLUDE TIES ");
6899 : /* we will now have a trailing space; remove it */
6900 232 : buf->data[--(buf->len)] = '\0';
6901 : }
6902 232 : }
6903 :
6904 : /*
6905 : * Return the description of a window's framing options as a palloc'd string
6906 : */
6907 : char *
6908 190 : get_window_frame_options_for_explain(int frameOptions,
6909 : Node *startOffset, Node *endOffset,
6910 : List *dpcontext, bool forceprefix)
6911 : {
6912 : StringInfoData buf;
6913 : deparse_context context;
6914 :
6915 190 : initStringInfo(&buf);
6916 190 : context.buf = &buf;
6917 190 : context.namespaces = dpcontext;
6918 190 : context.resultDesc = NULL;
6919 190 : context.targetList = NIL;
6920 190 : context.windowClause = NIL;
6921 190 : context.varprefix = forceprefix;
6922 190 : context.prettyFlags = 0;
6923 190 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
6924 190 : context.indentLevel = 0;
6925 190 : context.colNamesVisible = true;
6926 190 : context.inGroupBy = false;
6927 190 : context.varInOrderBy = false;
6928 190 : context.appendparents = NULL;
6929 :
6930 190 : get_window_frame_options(frameOptions, startOffset, endOffset, &context);
6931 :
6932 190 : return buf.data;
6933 : }
6934 :
6935 : /* ----------
6936 : * get_insert_query_def - Parse back an INSERT parsetree
6937 : * ----------
6938 : */
6939 : static void
6940 340 : get_insert_query_def(Query *query, deparse_context *context)
6941 : {
6942 340 : StringInfo buf = context->buf;
6943 340 : RangeTblEntry *select_rte = NULL;
6944 340 : RangeTblEntry *values_rte = NULL;
6945 : RangeTblEntry *rte;
6946 : char *sep;
6947 : ListCell *l;
6948 : List *strippedexprs;
6949 :
6950 : /* Insert the WITH clause if given */
6951 340 : get_with_clause(query, context);
6952 :
6953 : /*
6954 : * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6955 : * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6956 : */
6957 1322 : foreach(l, query->rtable)
6958 : {
6959 982 : rte = (RangeTblEntry *) lfirst(l);
6960 :
6961 982 : if (rte->rtekind == RTE_SUBQUERY)
6962 : {
6963 50 : if (select_rte)
6964 0 : elog(ERROR, "too many subquery RTEs in INSERT");
6965 50 : select_rte = rte;
6966 : }
6967 :
6968 982 : if (rte->rtekind == RTE_VALUES)
6969 : {
6970 44 : if (values_rte)
6971 0 : elog(ERROR, "too many values RTEs in INSERT");
6972 44 : values_rte = rte;
6973 : }
6974 : }
6975 340 : if (select_rte && values_rte)
6976 0 : elog(ERROR, "both subquery and values RTEs in INSERT");
6977 :
6978 : /*
6979 : * Start the query with INSERT INTO relname
6980 : */
6981 340 : rte = rt_fetch(query->resultRelation, query->rtable);
6982 : Assert(rte->rtekind == RTE_RELATION);
6983 :
6984 340 : if (PRETTY_INDENT(context))
6985 : {
6986 340 : context->indentLevel += PRETTYINDENT_STD;
6987 340 : appendStringInfoChar(buf, ' ');
6988 : }
6989 340 : appendStringInfo(buf, "INSERT INTO %s",
6990 : generate_relation_name(rte->relid, NIL));
6991 :
6992 : /* Print the relation alias, if needed; INSERT requires explicit AS */
6993 340 : get_rte_alias(rte, query->resultRelation, true, context);
6994 :
6995 : /* always want a space here */
6996 340 : appendStringInfoChar(buf, ' ');
6997 :
6998 : /*
6999 : * Add the insert-column-names list. Any indirection decoration needed on
7000 : * the column names can be inferred from the top targetlist.
7001 : */
7002 340 : strippedexprs = NIL;
7003 340 : sep = "";
7004 340 : if (query->targetList)
7005 340 : appendStringInfoChar(buf, '(');
7006 1242 : foreach(l, query->targetList)
7007 : {
7008 902 : TargetEntry *tle = (TargetEntry *) lfirst(l);
7009 :
7010 902 : if (tle->resjunk)
7011 0 : continue; /* ignore junk entries */
7012 :
7013 902 : appendStringInfoString(buf, sep);
7014 902 : sep = ", ";
7015 :
7016 : /*
7017 : * Put out name of target column; look in the catalogs, not at
7018 : * tle->resname, since resname will fail to track RENAME.
7019 : */
7020 902 : appendStringInfoString(buf,
7021 902 : quote_identifier(get_attname(rte->relid,
7022 902 : tle->resno,
7023 : false)));
7024 :
7025 : /*
7026 : * Print any indirection needed (subfields or subscripts), and strip
7027 : * off the top-level nodes representing the indirection assignments.
7028 : * Add the stripped expressions to strippedexprs. (If it's a
7029 : * single-VALUES statement, the stripped expressions are the VALUES to
7030 : * print below. Otherwise they're just Vars and not really
7031 : * interesting.)
7032 : */
7033 902 : strippedexprs = lappend(strippedexprs,
7034 902 : processIndirection((Node *) tle->expr,
7035 : context));
7036 : }
7037 340 : if (query->targetList)
7038 340 : appendStringInfoString(buf, ") ");
7039 :
7040 340 : if (query->override)
7041 : {
7042 0 : if (query->override == OVERRIDING_SYSTEM_VALUE)
7043 0 : appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
7044 0 : else if (query->override == OVERRIDING_USER_VALUE)
7045 0 : appendStringInfoString(buf, "OVERRIDING USER VALUE ");
7046 : }
7047 :
7048 340 : if (select_rte)
7049 : {
7050 : /* Add the SELECT */
7051 50 : get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
7052 : false,
7053 : context->prettyFlags, context->wrapColumn,
7054 : context->indentLevel);
7055 : }
7056 290 : else if (values_rte)
7057 : {
7058 : /* Add the multi-VALUES expression lists */
7059 44 : get_values_def(values_rte->values_lists, context);
7060 : }
7061 246 : else if (strippedexprs)
7062 : {
7063 : /* Add the single-VALUES expression list */
7064 246 : appendContextKeyword(context, "VALUES (",
7065 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7066 246 : get_rule_list_toplevel(strippedexprs, context, false);
7067 246 : appendStringInfoChar(buf, ')');
7068 : }
7069 : else
7070 : {
7071 : /* No expressions, so it must be DEFAULT VALUES */
7072 0 : appendStringInfoString(buf, "DEFAULT VALUES");
7073 : }
7074 :
7075 : /* Add ON CONFLICT if present */
7076 340 : if (query->onConflict)
7077 : {
7078 30 : OnConflictExpr *confl = query->onConflict;
7079 :
7080 30 : appendStringInfoString(buf, " ON CONFLICT");
7081 :
7082 30 : if (confl->arbiterElems)
7083 : {
7084 : /* Add the single-VALUES expression list */
7085 24 : appendStringInfoChar(buf, '(');
7086 24 : get_rule_expr((Node *) confl->arbiterElems, context, false);
7087 24 : appendStringInfoChar(buf, ')');
7088 :
7089 : /* Add a WHERE clause (for partial indexes) if given */
7090 24 : if (confl->arbiterWhere != NULL)
7091 : {
7092 : bool save_varprefix;
7093 :
7094 : /*
7095 : * Force non-prefixing of Vars, since parser assumes that they
7096 : * belong to target relation. WHERE clause does not use
7097 : * InferenceElem, so this is separately required.
7098 : */
7099 12 : save_varprefix = context->varprefix;
7100 12 : context->varprefix = false;
7101 :
7102 12 : appendContextKeyword(context, " WHERE ",
7103 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7104 12 : get_rule_expr(confl->arbiterWhere, context, false);
7105 :
7106 12 : context->varprefix = save_varprefix;
7107 : }
7108 : }
7109 6 : else if (OidIsValid(confl->constraint))
7110 : {
7111 0 : char *constraint = get_constraint_name(confl->constraint);
7112 :
7113 0 : if (!constraint)
7114 0 : elog(ERROR, "cache lookup failed for constraint %u",
7115 : confl->constraint);
7116 0 : appendStringInfo(buf, " ON CONSTRAINT %s",
7117 : quote_identifier(constraint));
7118 : }
7119 :
7120 30 : if (confl->action == ONCONFLICT_NOTHING)
7121 : {
7122 18 : appendStringInfoString(buf, " DO NOTHING");
7123 : }
7124 : else
7125 : {
7126 12 : appendStringInfoString(buf, " DO UPDATE SET ");
7127 : /* Deparse targetlist */
7128 12 : get_update_query_targetlist_def(query, confl->onConflictSet,
7129 : context, rte);
7130 :
7131 : /* Add a WHERE clause if given */
7132 12 : if (confl->onConflictWhere != NULL)
7133 : {
7134 12 : appendContextKeyword(context, " WHERE ",
7135 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7136 12 : get_rule_expr(confl->onConflictWhere, context, false);
7137 : }
7138 : }
7139 : }
7140 :
7141 : /* Add RETURNING if present */
7142 340 : if (query->returningList)
7143 78 : get_returning_clause(query, context);
7144 340 : }
7145 :
7146 :
7147 : /* ----------
7148 : * get_update_query_def - Parse back an UPDATE parsetree
7149 : * ----------
7150 : */
7151 : static void
7152 154 : get_update_query_def(Query *query, deparse_context *context)
7153 : {
7154 154 : StringInfo buf = context->buf;
7155 : RangeTblEntry *rte;
7156 :
7157 : /* Insert the WITH clause if given */
7158 154 : get_with_clause(query, context);
7159 :
7160 : /*
7161 : * Start the query with UPDATE relname SET
7162 : */
7163 154 : rte = rt_fetch(query->resultRelation, query->rtable);
7164 : Assert(rte->rtekind == RTE_RELATION);
7165 154 : if (PRETTY_INDENT(context))
7166 : {
7167 154 : appendStringInfoChar(buf, ' ');
7168 154 : context->indentLevel += PRETTYINDENT_STD;
7169 : }
7170 308 : appendStringInfo(buf, "UPDATE %s%s",
7171 154 : only_marker(rte),
7172 : generate_relation_name(rte->relid, NIL));
7173 :
7174 : /* Print the relation alias, if needed */
7175 154 : get_rte_alias(rte, query->resultRelation, false, context);
7176 :
7177 154 : appendStringInfoString(buf, " SET ");
7178 :
7179 : /* Deparse targetlist */
7180 154 : get_update_query_targetlist_def(query, query->targetList, context, rte);
7181 :
7182 : /* Add the FROM clause if needed */
7183 154 : get_from_clause(query, " FROM ", context);
7184 :
7185 : /* Add a WHERE clause if given */
7186 154 : if (query->jointree->quals != NULL)
7187 : {
7188 114 : appendContextKeyword(context, " WHERE ",
7189 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7190 114 : get_rule_expr(query->jointree->quals, context, false);
7191 : }
7192 :
7193 : /* Add RETURNING if present */
7194 154 : if (query->returningList)
7195 46 : get_returning_clause(query, context);
7196 154 : }
7197 :
7198 :
7199 : /* ----------
7200 : * get_update_query_targetlist_def - Parse back an UPDATE targetlist
7201 : * ----------
7202 : */
7203 : static void
7204 190 : get_update_query_targetlist_def(Query *query, List *targetList,
7205 : deparse_context *context, RangeTblEntry *rte)
7206 : {
7207 190 : StringInfo buf = context->buf;
7208 : ListCell *l;
7209 : ListCell *next_ma_cell;
7210 : int remaining_ma_columns;
7211 : const char *sep;
7212 : SubLink *cur_ma_sublink;
7213 : List *ma_sublinks;
7214 :
7215 : /*
7216 : * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
7217 : * into a list. We expect them to appear, in ID order, in resjunk tlist
7218 : * entries.
7219 : */
7220 190 : ma_sublinks = NIL;
7221 190 : if (query->hasSubLinks) /* else there can't be any */
7222 : {
7223 42 : foreach(l, targetList)
7224 : {
7225 30 : TargetEntry *tle = (TargetEntry *) lfirst(l);
7226 :
7227 30 : if (tle->resjunk && IsA(tle->expr, SubLink))
7228 : {
7229 6 : SubLink *sl = (SubLink *) tle->expr;
7230 :
7231 6 : if (sl->subLinkType == MULTIEXPR_SUBLINK)
7232 : {
7233 6 : ma_sublinks = lappend(ma_sublinks, sl);
7234 : Assert(sl->subLinkId == list_length(ma_sublinks));
7235 : }
7236 : }
7237 : }
7238 : }
7239 190 : next_ma_cell = list_head(ma_sublinks);
7240 190 : cur_ma_sublink = NULL;
7241 190 : remaining_ma_columns = 0;
7242 :
7243 : /* Add the comma separated list of 'attname = value' */
7244 190 : sep = "";
7245 488 : foreach(l, targetList)
7246 : {
7247 298 : TargetEntry *tle = (TargetEntry *) lfirst(l);
7248 : Node *expr;
7249 :
7250 298 : if (tle->resjunk)
7251 6 : continue; /* ignore junk entries */
7252 :
7253 : /* Emit separator (OK whether we're in multiassignment or not) */
7254 292 : appendStringInfoString(buf, sep);
7255 292 : sep = ", ";
7256 :
7257 : /*
7258 : * Check to see if we're starting a multiassignment group: if so,
7259 : * output a left paren.
7260 : */
7261 292 : if (next_ma_cell != NULL && cur_ma_sublink == NULL)
7262 : {
7263 : /*
7264 : * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
7265 : * Param. That could be buried under FieldStores and
7266 : * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
7267 : * and underneath those there could be an implicit type coercion.
7268 : * Because we would ignore implicit type coercions anyway, we
7269 : * don't need to be as careful as processIndirection() is about
7270 : * descending past implicit CoerceToDomains.
7271 : */
7272 6 : expr = (Node *) tle->expr;
7273 12 : while (expr)
7274 : {
7275 12 : if (IsA(expr, FieldStore))
7276 : {
7277 0 : FieldStore *fstore = (FieldStore *) expr;
7278 :
7279 0 : expr = (Node *) linitial(fstore->newvals);
7280 : }
7281 12 : else if (IsA(expr, SubscriptingRef))
7282 : {
7283 6 : SubscriptingRef *sbsref = (SubscriptingRef *) expr;
7284 :
7285 6 : if (sbsref->refassgnexpr == NULL)
7286 0 : break;
7287 :
7288 6 : expr = (Node *) sbsref->refassgnexpr;
7289 : }
7290 6 : else if (IsA(expr, CoerceToDomain))
7291 : {
7292 0 : CoerceToDomain *cdomain = (CoerceToDomain *) expr;
7293 :
7294 0 : if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
7295 0 : break;
7296 0 : expr = (Node *) cdomain->arg;
7297 : }
7298 : else
7299 6 : break;
7300 : }
7301 6 : expr = strip_implicit_coercions(expr);
7302 :
7303 6 : if (expr && IsA(expr, Param) &&
7304 6 : ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
7305 : {
7306 6 : cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
7307 6 : next_ma_cell = lnext(ma_sublinks, next_ma_cell);
7308 6 : remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
7309 : Assert(((Param *) expr)->paramid ==
7310 : ((cur_ma_sublink->subLinkId << 16) | 1));
7311 6 : appendStringInfoChar(buf, '(');
7312 : }
7313 : }
7314 :
7315 : /*
7316 : * Put out name of target column; look in the catalogs, not at
7317 : * tle->resname, since resname will fail to track RENAME.
7318 : */
7319 292 : appendStringInfoString(buf,
7320 292 : quote_identifier(get_attname(rte->relid,
7321 292 : tle->resno,
7322 : false)));
7323 :
7324 : /*
7325 : * Print any indirection needed (subfields or subscripts), and strip
7326 : * off the top-level nodes representing the indirection assignments.
7327 : */
7328 292 : expr = processIndirection((Node *) tle->expr, context);
7329 :
7330 : /*
7331 : * If we're in a multiassignment, skip printing anything more, unless
7332 : * this is the last column; in which case, what we print should be the
7333 : * sublink, not the Param.
7334 : */
7335 292 : if (cur_ma_sublink != NULL)
7336 : {
7337 18 : if (--remaining_ma_columns > 0)
7338 12 : continue; /* not the last column of multiassignment */
7339 6 : appendStringInfoChar(buf, ')');
7340 6 : expr = (Node *) cur_ma_sublink;
7341 6 : cur_ma_sublink = NULL;
7342 : }
7343 :
7344 280 : appendStringInfoString(buf, " = ");
7345 :
7346 280 : get_rule_expr(expr, context, false);
7347 : }
7348 190 : }
7349 :
7350 :
7351 : /* ----------
7352 : * get_delete_query_def - Parse back a DELETE parsetree
7353 : * ----------
7354 : */
7355 : static void
7356 76 : get_delete_query_def(Query *query, deparse_context *context)
7357 : {
7358 76 : StringInfo buf = context->buf;
7359 : RangeTblEntry *rte;
7360 :
7361 : /* Insert the WITH clause if given */
7362 76 : get_with_clause(query, context);
7363 :
7364 : /*
7365 : * Start the query with DELETE FROM relname
7366 : */
7367 76 : rte = rt_fetch(query->resultRelation, query->rtable);
7368 : Assert(rte->rtekind == RTE_RELATION);
7369 76 : if (PRETTY_INDENT(context))
7370 : {
7371 76 : appendStringInfoChar(buf, ' ');
7372 76 : context->indentLevel += PRETTYINDENT_STD;
7373 : }
7374 152 : appendStringInfo(buf, "DELETE FROM %s%s",
7375 76 : only_marker(rte),
7376 : generate_relation_name(rte->relid, NIL));
7377 :
7378 : /* Print the relation alias, if needed */
7379 76 : get_rte_alias(rte, query->resultRelation, false, context);
7380 :
7381 : /* Add the USING clause if given */
7382 76 : get_from_clause(query, " USING ", context);
7383 :
7384 : /* Add a WHERE clause if given */
7385 76 : if (query->jointree->quals != NULL)
7386 : {
7387 76 : appendContextKeyword(context, " WHERE ",
7388 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7389 76 : get_rule_expr(query->jointree->quals, context, false);
7390 : }
7391 :
7392 : /* Add RETURNING if present */
7393 76 : if (query->returningList)
7394 16 : get_returning_clause(query, context);
7395 76 : }
7396 :
7397 :
7398 : /* ----------
7399 : * get_merge_query_def - Parse back a MERGE parsetree
7400 : * ----------
7401 : */
7402 : static void
7403 12 : get_merge_query_def(Query *query, deparse_context *context)
7404 : {
7405 12 : StringInfo buf = context->buf;
7406 : RangeTblEntry *rte;
7407 : ListCell *lc;
7408 : bool haveNotMatchedBySource;
7409 :
7410 : /* Insert the WITH clause if given */
7411 12 : get_with_clause(query, context);
7412 :
7413 : /*
7414 : * Start the query with MERGE INTO relname
7415 : */
7416 12 : rte = rt_fetch(query->resultRelation, query->rtable);
7417 : Assert(rte->rtekind == RTE_RELATION);
7418 12 : if (PRETTY_INDENT(context))
7419 : {
7420 12 : appendStringInfoChar(buf, ' ');
7421 12 : context->indentLevel += PRETTYINDENT_STD;
7422 : }
7423 24 : appendStringInfo(buf, "MERGE INTO %s%s",
7424 12 : only_marker(rte),
7425 : generate_relation_name(rte->relid, NIL));
7426 :
7427 : /* Print the relation alias, if needed */
7428 12 : get_rte_alias(rte, query->resultRelation, false, context);
7429 :
7430 : /* Print the source relation and join clause */
7431 12 : get_from_clause(query, " USING ", context);
7432 12 : appendContextKeyword(context, " ON ",
7433 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7434 12 : get_rule_expr(query->mergeJoinCondition, context, false);
7435 :
7436 : /*
7437 : * Test for any NOT MATCHED BY SOURCE actions. If there are none, then
7438 : * any NOT MATCHED BY TARGET actions are output as "WHEN NOT MATCHED", per
7439 : * SQL standard. Otherwise, we have a non-SQL-standard query, so output
7440 : * "BY SOURCE" / "BY TARGET" qualifiers for all NOT MATCHED actions, to be
7441 : * more explicit.
7442 : */
7443 12 : haveNotMatchedBySource = false;
7444 84 : foreach(lc, query->mergeActionList)
7445 : {
7446 78 : MergeAction *action = lfirst_node(MergeAction, lc);
7447 :
7448 78 : if (action->matchKind == MERGE_WHEN_NOT_MATCHED_BY_SOURCE)
7449 : {
7450 6 : haveNotMatchedBySource = true;
7451 6 : break;
7452 : }
7453 : }
7454 :
7455 : /* Print each merge action */
7456 90 : foreach(lc, query->mergeActionList)
7457 : {
7458 78 : MergeAction *action = lfirst_node(MergeAction, lc);
7459 :
7460 78 : appendContextKeyword(context, " WHEN ",
7461 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
7462 78 : switch (action->matchKind)
7463 : {
7464 36 : case MERGE_WHEN_MATCHED:
7465 36 : appendStringInfoString(buf, "MATCHED");
7466 36 : break;
7467 6 : case MERGE_WHEN_NOT_MATCHED_BY_SOURCE:
7468 6 : appendStringInfoString(buf, "NOT MATCHED BY SOURCE");
7469 6 : break;
7470 36 : case MERGE_WHEN_NOT_MATCHED_BY_TARGET:
7471 36 : if (haveNotMatchedBySource)
7472 6 : appendStringInfoString(buf, "NOT MATCHED BY TARGET");
7473 : else
7474 30 : appendStringInfoString(buf, "NOT MATCHED");
7475 36 : break;
7476 0 : default:
7477 0 : elog(ERROR, "unrecognized matchKind: %d",
7478 : (int) action->matchKind);
7479 : }
7480 :
7481 78 : if (action->qual)
7482 : {
7483 48 : appendContextKeyword(context, " AND ",
7484 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 3);
7485 48 : get_rule_expr(action->qual, context, false);
7486 : }
7487 78 : appendContextKeyword(context, " THEN ",
7488 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 3);
7489 :
7490 78 : if (action->commandType == CMD_INSERT)
7491 : {
7492 : /* This generally matches get_insert_query_def() */
7493 36 : List *strippedexprs = NIL;
7494 36 : const char *sep = "";
7495 : ListCell *lc2;
7496 :
7497 36 : appendStringInfoString(buf, "INSERT");
7498 :
7499 36 : if (action->targetList)
7500 30 : appendStringInfoString(buf, " (");
7501 102 : foreach(lc2, action->targetList)
7502 : {
7503 66 : TargetEntry *tle = (TargetEntry *) lfirst(lc2);
7504 :
7505 : Assert(!tle->resjunk);
7506 :
7507 66 : appendStringInfoString(buf, sep);
7508 66 : sep = ", ";
7509 :
7510 66 : appendStringInfoString(buf,
7511 66 : quote_identifier(get_attname(rte->relid,
7512 66 : tle->resno,
7513 : false)));
7514 66 : strippedexprs = lappend(strippedexprs,
7515 66 : processIndirection((Node *) tle->expr,
7516 : context));
7517 : }
7518 36 : if (action->targetList)
7519 30 : appendStringInfoChar(buf, ')');
7520 :
7521 36 : if (action->override)
7522 : {
7523 6 : if (action->override == OVERRIDING_SYSTEM_VALUE)
7524 0 : appendStringInfoString(buf, " OVERRIDING SYSTEM VALUE");
7525 6 : else if (action->override == OVERRIDING_USER_VALUE)
7526 6 : appendStringInfoString(buf, " OVERRIDING USER VALUE");
7527 : }
7528 :
7529 36 : if (strippedexprs)
7530 : {
7531 30 : appendContextKeyword(context, " VALUES (",
7532 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 4);
7533 30 : get_rule_list_toplevel(strippedexprs, context, false);
7534 30 : appendStringInfoChar(buf, ')');
7535 : }
7536 : else
7537 6 : appendStringInfoString(buf, " DEFAULT VALUES");
7538 : }
7539 42 : else if (action->commandType == CMD_UPDATE)
7540 : {
7541 24 : appendStringInfoString(buf, "UPDATE SET ");
7542 24 : get_update_query_targetlist_def(query, action->targetList,
7543 : context, rte);
7544 : }
7545 18 : else if (action->commandType == CMD_DELETE)
7546 12 : appendStringInfoString(buf, "DELETE");
7547 6 : else if (action->commandType == CMD_NOTHING)
7548 6 : appendStringInfoString(buf, "DO NOTHING");
7549 : }
7550 :
7551 : /* Add RETURNING if present */
7552 12 : if (query->returningList)
7553 6 : get_returning_clause(query, context);
7554 12 : }
7555 :
7556 :
7557 : /* ----------
7558 : * get_utility_query_def - Parse back a UTILITY parsetree
7559 : * ----------
7560 : */
7561 : static void
7562 16 : get_utility_query_def(Query *query, deparse_context *context)
7563 : {
7564 16 : StringInfo buf = context->buf;
7565 :
7566 16 : if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7567 16 : {
7568 16 : NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7569 :
7570 16 : appendContextKeyword(context, "",
7571 : 0, PRETTYINDENT_STD, 1);
7572 16 : appendStringInfo(buf, "NOTIFY %s",
7573 16 : quote_identifier(stmt->conditionname));
7574 16 : if (stmt->payload)
7575 : {
7576 0 : appendStringInfoString(buf, ", ");
7577 0 : simple_quote_literal(buf, stmt->payload);
7578 : }
7579 : }
7580 : else
7581 : {
7582 : /* Currently only NOTIFY utility commands can appear in rules */
7583 0 : elog(ERROR, "unexpected utility statement type");
7584 : }
7585 16 : }
7586 :
7587 : /*
7588 : * Display a Var appropriately.
7589 : *
7590 : * In some cases (currently only when recursing into an unnamed join)
7591 : * the Var's varlevelsup has to be interpreted with respect to a context
7592 : * above the current one; levelsup indicates the offset.
7593 : *
7594 : * If istoplevel is true, the Var is at the top level of a SELECT's
7595 : * targetlist, which means we need special treatment of whole-row Vars.
7596 : * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
7597 : * dirty hack to prevent "tab.*" from being expanded into multiple columns.
7598 : * (The parser will strip the useless coercion, so no inefficiency is added in
7599 : * dump and reload.) We used to print just "tab" in such cases, but that is
7600 : * ambiguous and will yield the wrong result if "tab" is also a plain column
7601 : * name in the query.
7602 : *
7603 : * Returns the attname of the Var, or NULL if the Var has no attname (because
7604 : * it is a whole-row Var or a subplan output reference).
7605 : */
7606 : static char *
7607 174284 : get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
7608 : {
7609 174284 : StringInfo buf = context->buf;
7610 : RangeTblEntry *rte;
7611 : AttrNumber attnum;
7612 : int netlevelsup;
7613 : deparse_namespace *dpns;
7614 : int varno;
7615 : AttrNumber varattno;
7616 : deparse_columns *colinfo;
7617 : char *refname;
7618 : char *attname;
7619 : bool need_prefix;
7620 :
7621 : /* Find appropriate nesting depth */
7622 174284 : netlevelsup = var->varlevelsup + levelsup;
7623 174284 : if (netlevelsup >= list_length(context->namespaces))
7624 0 : elog(ERROR, "bogus varlevelsup: %d offset %d",
7625 : var->varlevelsup, levelsup);
7626 174284 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7627 : netlevelsup);
7628 :
7629 : /*
7630 : * If we have a syntactic referent for the Var, and we're working from a
7631 : * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7632 : * on the semantic referent. (Forcing use of the semantic referent when
7633 : * printing plan trees is a design choice that's perhaps more motivated by
7634 : * backwards compatibility than anything else. But it does have the
7635 : * advantage of making plans more explicit.)
7636 : */
7637 174284 : if (var->varnosyn > 0 && dpns->plan == NULL)
7638 : {
7639 38386 : varno = var->varnosyn;
7640 38386 : varattno = var->varattnosyn;
7641 : }
7642 : else
7643 : {
7644 135898 : varno = var->varno;
7645 135898 : varattno = var->varattno;
7646 : }
7647 :
7648 : /*
7649 : * Try to find the relevant RTE in this rtable. In a plan tree, it's
7650 : * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7651 : * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7652 : * find the aliases previously assigned for this RTE.
7653 : */
7654 174284 : if (varno >= 1 && varno <= list_length(dpns->rtable))
7655 : {
7656 : /*
7657 : * We might have been asked to map child Vars to some parent relation.
7658 : */
7659 130276 : if (context->appendparents && dpns->appendrels)
7660 : {
7661 3816 : int pvarno = varno;
7662 3816 : AttrNumber pvarattno = varattno;
7663 3816 : AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7664 3816 : bool found = false;
7665 :
7666 : /* Only map up to inheritance parents, not UNION ALL appendrels */
7667 7706 : while (appinfo &&
7668 4240 : rt_fetch(appinfo->parent_relid,
7669 4240 : dpns->rtable)->rtekind == RTE_RELATION)
7670 : {
7671 3890 : found = false;
7672 3890 : if (pvarattno > 0) /* system columns stay as-is */
7673 : {
7674 3612 : if (pvarattno > appinfo->num_child_cols)
7675 0 : break; /* safety check */
7676 3612 : pvarattno = appinfo->parent_colnos[pvarattno - 1];
7677 3612 : if (pvarattno == 0)
7678 0 : break; /* Var is local to child */
7679 : }
7680 :
7681 3890 : pvarno = appinfo->parent_relid;
7682 3890 : found = true;
7683 :
7684 : /* If the parent is itself a child, continue up. */
7685 : Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7686 3890 : appinfo = dpns->appendrels[pvarno];
7687 : }
7688 :
7689 : /*
7690 : * If we found an ancestral rel, and that rel is included in
7691 : * appendparents, print that column not the original one.
7692 : */
7693 3816 : if (found && bms_is_member(pvarno, context->appendparents))
7694 : {
7695 3100 : varno = pvarno;
7696 3100 : varattno = pvarattno;
7697 : }
7698 : }
7699 :
7700 130276 : rte = rt_fetch(varno, dpns->rtable);
7701 :
7702 : /* might be returning old/new column value */
7703 130276 : if (var->varreturningtype == VAR_RETURNING_OLD)
7704 416 : refname = dpns->ret_old_alias;
7705 129860 : else if (var->varreturningtype == VAR_RETURNING_NEW)
7706 414 : refname = dpns->ret_new_alias;
7707 : else
7708 129446 : refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7709 :
7710 130276 : colinfo = deparse_columns_fetch(varno, dpns);
7711 130276 : attnum = varattno;
7712 : }
7713 : else
7714 : {
7715 44008 : resolve_special_varno((Node *) var, context,
7716 : get_special_variable, NULL);
7717 44008 : return NULL;
7718 : }
7719 :
7720 : /*
7721 : * The planner will sometimes emit Vars referencing resjunk elements of a
7722 : * subquery's target list (this is currently only possible if it chooses
7723 : * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7724 : * Although we prefer to print subquery-referencing Vars using the
7725 : * subquery's alias, that's not possible for resjunk items since they have
7726 : * no alias. So in that case, drill down to the subplan and print the
7727 : * contents of the referenced tlist item. This works because in a plan
7728 : * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7729 : * we'll have set dpns->inner_plan to reference the child plan node.
7730 : */
7731 134518 : if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7732 4242 : attnum > list_length(rte->eref->colnames) &&
7733 2 : dpns->inner_plan)
7734 : {
7735 : TargetEntry *tle;
7736 : deparse_namespace save_dpns;
7737 :
7738 2 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7739 2 : if (!tle)
7740 0 : elog(ERROR, "invalid attnum %d for relation \"%s\"",
7741 : attnum, rte->eref->aliasname);
7742 :
7743 : Assert(netlevelsup == 0);
7744 2 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7745 :
7746 : /*
7747 : * Force parentheses because our caller probably assumed a Var is a
7748 : * simple expression.
7749 : */
7750 2 : if (!IsA(tle->expr, Var))
7751 0 : appendStringInfoChar(buf, '(');
7752 2 : get_rule_expr((Node *) tle->expr, context, true);
7753 2 : if (!IsA(tle->expr, Var))
7754 0 : appendStringInfoChar(buf, ')');
7755 :
7756 2 : pop_child_plan(dpns, &save_dpns);
7757 2 : return NULL;
7758 : }
7759 :
7760 : /*
7761 : * If it's an unnamed join, look at the expansion of the alias variable.
7762 : * If it's a simple reference to one of the input vars, then recursively
7763 : * print the name of that var instead. When it's not a simple reference,
7764 : * we have to just print the unqualified join column name. (This can only
7765 : * happen with "dangerous" merged columns in a JOIN USING; we took pains
7766 : * previously to make the unqualified column name unique in such cases.)
7767 : *
7768 : * This wouldn't work in decompiling plan trees, because we don't store
7769 : * joinaliasvars lists after planning; but a plan tree should never
7770 : * contain a join alias variable.
7771 : */
7772 130274 : if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7773 : {
7774 96 : if (rte->joinaliasvars == NIL)
7775 0 : elog(ERROR, "cannot decompile join alias var in plan tree");
7776 96 : if (attnum > 0)
7777 : {
7778 : Var *aliasvar;
7779 :
7780 96 : aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7781 : /* we intentionally don't strip implicit coercions here */
7782 96 : if (aliasvar && IsA(aliasvar, Var))
7783 : {
7784 0 : return get_variable(aliasvar, var->varlevelsup + levelsup,
7785 : istoplevel, context);
7786 : }
7787 : }
7788 :
7789 : /*
7790 : * Unnamed join has no refname. (Note: since it's unnamed, there is
7791 : * no way the user could have referenced it to create a whole-row Var
7792 : * for it. So we don't have to cover that case below.)
7793 : */
7794 : Assert(refname == NULL);
7795 : }
7796 :
7797 130274 : if (attnum == InvalidAttrNumber)
7798 1014 : attname = NULL;
7799 129260 : else if (attnum > 0)
7800 : {
7801 : /* Get column name to use from the colinfo struct */
7802 127386 : if (attnum > colinfo->num_cols)
7803 0 : elog(ERROR, "invalid attnum %d for relation \"%s\"",
7804 : attnum, rte->eref->aliasname);
7805 127386 : attname = colinfo->colnames[attnum - 1];
7806 :
7807 : /*
7808 : * If we find a Var referencing a dropped column, it seems better to
7809 : * print something (anything) than to fail. In general this should
7810 : * not happen, but it used to be possible for some cases involving
7811 : * functions returning named composite types, and perhaps there are
7812 : * still bugs out there.
7813 : */
7814 127386 : if (attname == NULL)
7815 6 : attname = "?dropped?column?";
7816 : }
7817 : else
7818 : {
7819 : /* System column - name is fixed, get it from the catalog */
7820 1874 : attname = get_rte_attribute_name(rte, attnum);
7821 : }
7822 :
7823 195182 : need_prefix = (context->varprefix || attname == NULL ||
7824 64908 : var->varreturningtype != VAR_RETURNING_DEFAULT);
7825 :
7826 : /*
7827 : * If we're considering a plain Var in an ORDER BY (but not GROUP BY)
7828 : * clause, we may need to add a table-name prefix to prevent
7829 : * findTargetlistEntrySQL92 from misinterpreting the name as an
7830 : * output-column name. To avoid cluttering the output with unnecessary
7831 : * prefixes, do so only if there is a name match to a SELECT tlist item
7832 : * that is different from the Var.
7833 : */
7834 130274 : if (context->varInOrderBy && !context->inGroupBy && !need_prefix)
7835 : {
7836 240 : int colno = 0;
7837 :
7838 922 : foreach_node(TargetEntry, tle, context->targetList)
7839 : {
7840 : char *colname;
7841 :
7842 454 : if (tle->resjunk)
7843 0 : continue; /* ignore junk entries */
7844 454 : colno++;
7845 :
7846 : /* This must match colname-choosing logic in get_target_list() */
7847 454 : if (context->resultDesc && colno <= context->resultDesc->natts)
7848 454 : colname = NameStr(TupleDescAttr(context->resultDesc,
7849 : colno - 1)->attname);
7850 : else
7851 0 : colname = tle->resname;
7852 :
7853 454 : if (colname && strcmp(colname, attname) == 0 &&
7854 168 : !equal(var, tle->expr))
7855 : {
7856 12 : need_prefix = true;
7857 12 : break;
7858 : }
7859 : }
7860 : }
7861 :
7862 130274 : if (refname && need_prefix)
7863 : {
7864 65310 : appendStringInfoString(buf, quote_identifier(refname));
7865 65310 : appendStringInfoChar(buf, '.');
7866 : }
7867 130274 : if (attname)
7868 129260 : appendStringInfoString(buf, quote_identifier(attname));
7869 : else
7870 : {
7871 1014 : appendStringInfoChar(buf, '*');
7872 1014 : if (istoplevel)
7873 84 : appendStringInfo(buf, "::%s",
7874 : format_type_with_typemod(var->vartype,
7875 : var->vartypmod));
7876 : }
7877 :
7878 130274 : return attname;
7879 : }
7880 :
7881 : /*
7882 : * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
7883 : * routine is actually a callback for resolve_special_varno, which handles
7884 : * finding the correct TargetEntry. We get the expression contained in that
7885 : * TargetEntry and just need to deparse it, a job we can throw back on
7886 : * get_rule_expr.
7887 : */
7888 : static void
7889 44008 : get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7890 : {
7891 44008 : StringInfo buf = context->buf;
7892 :
7893 : /*
7894 : * For a non-Var referent, force parentheses because our caller probably
7895 : * assumed a Var is a simple expression.
7896 : */
7897 44008 : if (!IsA(node, Var))
7898 3834 : appendStringInfoChar(buf, '(');
7899 44008 : get_rule_expr(node, context, true);
7900 44008 : if (!IsA(node, Var))
7901 3834 : appendStringInfoChar(buf, ')');
7902 44008 : }
7903 :
7904 : /*
7905 : * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7906 : * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7907 : * invoke the callback provided.
7908 : */
7909 : static void
7910 120958 : resolve_special_varno(Node *node, deparse_context *context,
7911 : rsv_callback callback, void *callback_arg)
7912 : {
7913 : Var *var;
7914 : deparse_namespace *dpns;
7915 :
7916 : /* This function is recursive, so let's be paranoid. */
7917 120958 : check_stack_depth();
7918 :
7919 : /* If it's not a Var, invoke the callback. */
7920 120958 : if (!IsA(node, Var))
7921 : {
7922 4094 : (*callback) (node, context, callback_arg);
7923 4094 : return;
7924 : }
7925 :
7926 : /* Find appropriate nesting depth */
7927 116864 : var = (Var *) node;
7928 116864 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7929 116864 : var->varlevelsup);
7930 :
7931 : /*
7932 : * If varno is special, recurse. (Don't worry about varnosyn; if we're
7933 : * here, we already decided not to use that.)
7934 : */
7935 116864 : if (var->varno == OUTER_VAR && dpns->outer_tlist)
7936 : {
7937 : TargetEntry *tle;
7938 : deparse_namespace save_dpns;
7939 : Bitmapset *save_appendparents;
7940 :
7941 57068 : tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7942 57068 : if (!tle)
7943 0 : elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7944 :
7945 : /*
7946 : * If we're descending to the first child of an Append or MergeAppend,
7947 : * update appendparents. This will affect deparsing of all Vars
7948 : * appearing within the eventually-resolved subexpression.
7949 : */
7950 57068 : save_appendparents = context->appendparents;
7951 :
7952 57068 : if (IsA(dpns->plan, Append))
7953 4132 : context->appendparents = bms_union(context->appendparents,
7954 4132 : ((Append *) dpns->plan)->apprelids);
7955 52936 : else if (IsA(dpns->plan, MergeAppend))
7956 608 : context->appendparents = bms_union(context->appendparents,
7957 608 : ((MergeAppend *) dpns->plan)->apprelids);
7958 :
7959 57068 : push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7960 57068 : resolve_special_varno((Node *) tle->expr, context,
7961 : callback, callback_arg);
7962 57068 : pop_child_plan(dpns, &save_dpns);
7963 57068 : context->appendparents = save_appendparents;
7964 57068 : return;
7965 : }
7966 59796 : else if (var->varno == INNER_VAR && dpns->inner_tlist)
7967 : {
7968 : TargetEntry *tle;
7969 : deparse_namespace save_dpns;
7970 :
7971 14096 : tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7972 14096 : if (!tle)
7973 0 : elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7974 :
7975 14096 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7976 14096 : resolve_special_varno((Node *) tle->expr, context,
7977 : callback, callback_arg);
7978 14096 : pop_child_plan(dpns, &save_dpns);
7979 14096 : return;
7980 : }
7981 45700 : else if (var->varno == INDEX_VAR && dpns->index_tlist)
7982 : {
7983 : TargetEntry *tle;
7984 :
7985 5526 : tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7986 5526 : if (!tle)
7987 0 : elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7988 :
7989 5526 : resolve_special_varno((Node *) tle->expr, context,
7990 : callback, callback_arg);
7991 5526 : return;
7992 : }
7993 40174 : else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7994 0 : elog(ERROR, "bogus varno: %d", var->varno);
7995 :
7996 : /* Not special. Just invoke the callback. */
7997 40174 : (*callback) (node, context, callback_arg);
7998 : }
7999 :
8000 : /*
8001 : * Get the name of a field of an expression of composite type. The
8002 : * expression is usually a Var, but we handle other cases too.
8003 : *
8004 : * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
8005 : *
8006 : * This is fairly straightforward when the expression has a named composite
8007 : * type; we need only look up the type in the catalogs. However, the type
8008 : * could also be RECORD. Since no actual table or view column is allowed to
8009 : * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
8010 : * or to a subquery output. We drill down to find the ultimate defining
8011 : * expression and attempt to infer the field name from it. We ereport if we
8012 : * can't determine the name.
8013 : *
8014 : * Similarly, a PARAM of type RECORD has to refer to some expression of
8015 : * a determinable composite type.
8016 : */
8017 : static const char *
8018 1340 : get_name_for_var_field(Var *var, int fieldno,
8019 : int levelsup, deparse_context *context)
8020 : {
8021 : RangeTblEntry *rte;
8022 : AttrNumber attnum;
8023 : int netlevelsup;
8024 : deparse_namespace *dpns;
8025 : int varno;
8026 : AttrNumber varattno;
8027 : TupleDesc tupleDesc;
8028 : Node *expr;
8029 :
8030 : /*
8031 : * If it's a RowExpr that was expanded from a whole-row Var, use the
8032 : * column names attached to it. (We could let get_expr_result_tupdesc()
8033 : * handle this, but it's much cheaper to just pull out the name we need.)
8034 : */
8035 1340 : if (IsA(var, RowExpr))
8036 : {
8037 36 : RowExpr *r = (RowExpr *) var;
8038 :
8039 36 : if (fieldno > 0 && fieldno <= list_length(r->colnames))
8040 36 : return strVal(list_nth(r->colnames, fieldno - 1));
8041 : }
8042 :
8043 : /*
8044 : * If it's a Param of type RECORD, try to find what the Param refers to.
8045 : */
8046 1304 : if (IsA(var, Param))
8047 : {
8048 18 : Param *param = (Param *) var;
8049 : ListCell *ancestor_cell;
8050 :
8051 18 : expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8052 18 : if (expr)
8053 : {
8054 : /* Found a match, so recurse to decipher the field name */
8055 : deparse_namespace save_dpns;
8056 : const char *result;
8057 :
8058 18 : push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8059 18 : result = get_name_for_var_field((Var *) expr, fieldno,
8060 : 0, context);
8061 18 : pop_ancestor_plan(dpns, &save_dpns);
8062 18 : return result;
8063 : }
8064 : }
8065 :
8066 : /*
8067 : * If it's a Var of type RECORD, we have to find what the Var refers to;
8068 : * if not, we can use get_expr_result_tupdesc().
8069 : */
8070 1286 : if (!IsA(var, Var) ||
8071 1206 : var->vartype != RECORDOID)
8072 : {
8073 1040 : tupleDesc = get_expr_result_tupdesc((Node *) var, false);
8074 : /* Got the tupdesc, so we can extract the field name */
8075 : Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8076 1040 : return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8077 : }
8078 :
8079 : /* Find appropriate nesting depth */
8080 246 : netlevelsup = var->varlevelsup + levelsup;
8081 246 : if (netlevelsup >= list_length(context->namespaces))
8082 0 : elog(ERROR, "bogus varlevelsup: %d offset %d",
8083 : var->varlevelsup, levelsup);
8084 246 : dpns = (deparse_namespace *) list_nth(context->namespaces,
8085 : netlevelsup);
8086 :
8087 : /*
8088 : * If we have a syntactic referent for the Var, and we're working from a
8089 : * parse tree, prefer to use the syntactic referent. Otherwise, fall back
8090 : * on the semantic referent. (See comments in get_variable().)
8091 : */
8092 246 : if (var->varnosyn > 0 && dpns->plan == NULL)
8093 : {
8094 96 : varno = var->varnosyn;
8095 96 : varattno = var->varattnosyn;
8096 : }
8097 : else
8098 : {
8099 150 : varno = var->varno;
8100 150 : varattno = var->varattno;
8101 : }
8102 :
8103 : /*
8104 : * Try to find the relevant RTE in this rtable. In a plan tree, it's
8105 : * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
8106 : * down into the subplans, or INDEX_VAR, which is resolved similarly.
8107 : *
8108 : * Note: unlike get_variable and resolve_special_varno, we need not worry
8109 : * about inheritance mapping: a child Var should have the same datatype as
8110 : * its parent, and here we're really only interested in the Var's type.
8111 : */
8112 246 : if (varno >= 1 && varno <= list_length(dpns->rtable))
8113 : {
8114 168 : rte = rt_fetch(varno, dpns->rtable);
8115 168 : attnum = varattno;
8116 : }
8117 78 : else if (varno == OUTER_VAR && dpns->outer_tlist)
8118 : {
8119 : TargetEntry *tle;
8120 : deparse_namespace save_dpns;
8121 : const char *result;
8122 :
8123 60 : tle = get_tle_by_resno(dpns->outer_tlist, varattno);
8124 60 : if (!tle)
8125 0 : elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
8126 :
8127 : Assert(netlevelsup == 0);
8128 60 : push_child_plan(dpns, dpns->outer_plan, &save_dpns);
8129 :
8130 60 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
8131 : levelsup, context);
8132 :
8133 60 : pop_child_plan(dpns, &save_dpns);
8134 60 : return result;
8135 : }
8136 18 : else if (varno == INNER_VAR && dpns->inner_tlist)
8137 : {
8138 : TargetEntry *tle;
8139 : deparse_namespace save_dpns;
8140 : const char *result;
8141 :
8142 18 : tle = get_tle_by_resno(dpns->inner_tlist, varattno);
8143 18 : if (!tle)
8144 0 : elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
8145 :
8146 : Assert(netlevelsup == 0);
8147 18 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8148 :
8149 18 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
8150 : levelsup, context);
8151 :
8152 18 : pop_child_plan(dpns, &save_dpns);
8153 18 : return result;
8154 : }
8155 0 : else if (varno == INDEX_VAR && dpns->index_tlist)
8156 : {
8157 : TargetEntry *tle;
8158 : const char *result;
8159 :
8160 0 : tle = get_tle_by_resno(dpns->index_tlist, varattno);
8161 0 : if (!tle)
8162 0 : elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
8163 :
8164 : Assert(netlevelsup == 0);
8165 :
8166 0 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
8167 : levelsup, context);
8168 :
8169 0 : return result;
8170 : }
8171 : else
8172 : {
8173 0 : elog(ERROR, "bogus varno: %d", varno);
8174 : return NULL; /* keep compiler quiet */
8175 : }
8176 :
8177 168 : if (attnum == InvalidAttrNumber)
8178 : {
8179 : /* Var is whole-row reference to RTE, so select the right field */
8180 24 : return get_rte_attribute_name(rte, fieldno);
8181 : }
8182 :
8183 : /*
8184 : * This part has essentially the same logic as the parser's
8185 : * expandRecordVariable() function, but we are dealing with a different
8186 : * representation of the input context, and we only need one field name
8187 : * not a TupleDesc. Also, we need special cases for finding subquery and
8188 : * CTE subplans when deparsing Plan trees.
8189 : */
8190 144 : expr = (Node *) var; /* default if we can't drill down */
8191 :
8192 144 : switch (rte->rtekind)
8193 : {
8194 0 : case RTE_RELATION:
8195 : case RTE_VALUES:
8196 : case RTE_NAMEDTUPLESTORE:
8197 : case RTE_RESULT:
8198 :
8199 : /*
8200 : * This case should not occur: a column of a table, values list,
8201 : * or ENR shouldn't have type RECORD. Fall through and fail (most
8202 : * likely) at the bottom.
8203 : */
8204 0 : break;
8205 72 : case RTE_SUBQUERY:
8206 : /* Subselect-in-FROM: examine sub-select's output expr */
8207 : {
8208 72 : if (rte->subquery)
8209 : {
8210 42 : TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
8211 : attnum);
8212 :
8213 42 : if (ste == NULL || ste->resjunk)
8214 0 : elog(ERROR, "subquery %s does not have attribute %d",
8215 : rte->eref->aliasname, attnum);
8216 42 : expr = (Node *) ste->expr;
8217 42 : if (IsA(expr, Var))
8218 : {
8219 : /*
8220 : * Recurse into the sub-select to see what its Var
8221 : * refers to. We have to build an additional level of
8222 : * namespace to keep in step with varlevelsup in the
8223 : * subselect; furthermore, the subquery RTE might be
8224 : * from an outer query level, in which case the
8225 : * namespace for the subselect must have that outer
8226 : * level as parent namespace.
8227 : */
8228 18 : List *save_nslist = context->namespaces;
8229 : List *parent_namespaces;
8230 : deparse_namespace mydpns;
8231 : const char *result;
8232 :
8233 18 : parent_namespaces = list_copy_tail(context->namespaces,
8234 : netlevelsup);
8235 :
8236 18 : set_deparse_for_query(&mydpns, rte->subquery,
8237 : parent_namespaces);
8238 :
8239 18 : context->namespaces = lcons(&mydpns, parent_namespaces);
8240 :
8241 18 : result = get_name_for_var_field((Var *) expr, fieldno,
8242 : 0, context);
8243 :
8244 18 : context->namespaces = save_nslist;
8245 :
8246 18 : return result;
8247 : }
8248 : /* else fall through to inspect the expression */
8249 : }
8250 : else
8251 : {
8252 : /*
8253 : * We're deparsing a Plan tree so we don't have complete
8254 : * RTE entries (in particular, rte->subquery is NULL). But
8255 : * the only place we'd normally see a Var directly
8256 : * referencing a SUBQUERY RTE is in a SubqueryScan plan
8257 : * node, and we can look into the child plan's tlist
8258 : * instead. An exception occurs if the subquery was
8259 : * proven empty and optimized away: then we'd find such a
8260 : * Var in a childless Result node, and there's nothing in
8261 : * the plan tree that would let us figure out what it had
8262 : * originally referenced. In that case, fall back on
8263 : * printing "fN", analogously to the default column names
8264 : * for RowExprs.
8265 : */
8266 : TargetEntry *tle;
8267 : deparse_namespace save_dpns;
8268 : const char *result;
8269 :
8270 30 : if (!dpns->inner_plan)
8271 : {
8272 12 : char *dummy_name = palloc(32);
8273 :
8274 : Assert(dpns->plan && IsA(dpns->plan, Result));
8275 12 : snprintf(dummy_name, 32, "f%d", fieldno);
8276 12 : return dummy_name;
8277 : }
8278 : Assert(dpns->plan && IsA(dpns->plan, SubqueryScan));
8279 :
8280 18 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8281 18 : if (!tle)
8282 0 : elog(ERROR, "bogus varattno for subquery var: %d",
8283 : attnum);
8284 : Assert(netlevelsup == 0);
8285 18 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8286 :
8287 18 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
8288 : levelsup, context);
8289 :
8290 18 : pop_child_plan(dpns, &save_dpns);
8291 18 : return result;
8292 : }
8293 : }
8294 24 : break;
8295 0 : case RTE_JOIN:
8296 : /* Join RTE --- recursively inspect the alias variable */
8297 0 : if (rte->joinaliasvars == NIL)
8298 0 : elog(ERROR, "cannot decompile join alias var in plan tree");
8299 : Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
8300 0 : expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
8301 : Assert(expr != NULL);
8302 : /* we intentionally don't strip implicit coercions here */
8303 0 : if (IsA(expr, Var))
8304 0 : return get_name_for_var_field((Var *) expr, fieldno,
8305 0 : var->varlevelsup + levelsup,
8306 : context);
8307 : /* else fall through to inspect the expression */
8308 0 : break;
8309 0 : case RTE_FUNCTION:
8310 : case RTE_TABLEFUNC:
8311 :
8312 : /*
8313 : * We couldn't get here unless a function is declared with one of
8314 : * its result columns as RECORD, which is not allowed.
8315 : */
8316 0 : break;
8317 72 : case RTE_CTE:
8318 : /* CTE reference: examine subquery's output expr */
8319 : {
8320 72 : CommonTableExpr *cte = NULL;
8321 : Index ctelevelsup;
8322 : ListCell *lc;
8323 :
8324 : /*
8325 : * Try to find the referenced CTE using the namespace stack.
8326 : */
8327 72 : ctelevelsup = rte->ctelevelsup + netlevelsup;
8328 72 : if (ctelevelsup >= list_length(context->namespaces))
8329 12 : lc = NULL;
8330 : else
8331 : {
8332 : deparse_namespace *ctedpns;
8333 :
8334 : ctedpns = (deparse_namespace *)
8335 60 : list_nth(context->namespaces, ctelevelsup);
8336 66 : foreach(lc, ctedpns->ctes)
8337 : {
8338 36 : cte = (CommonTableExpr *) lfirst(lc);
8339 36 : if (strcmp(cte->ctename, rte->ctename) == 0)
8340 30 : break;
8341 : }
8342 : }
8343 72 : if (lc != NULL)
8344 : {
8345 30 : Query *ctequery = (Query *) cte->ctequery;
8346 30 : TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
8347 : attnum);
8348 :
8349 30 : if (ste == NULL || ste->resjunk)
8350 0 : elog(ERROR, "CTE %s does not have attribute %d",
8351 : rte->eref->aliasname, attnum);
8352 30 : expr = (Node *) ste->expr;
8353 30 : if (IsA(expr, Var))
8354 : {
8355 : /*
8356 : * Recurse into the CTE to see what its Var refers to.
8357 : * We have to build an additional level of namespace
8358 : * to keep in step with varlevelsup in the CTE;
8359 : * furthermore it could be an outer CTE (compare
8360 : * SUBQUERY case above).
8361 : */
8362 18 : List *save_nslist = context->namespaces;
8363 : List *parent_namespaces;
8364 : deparse_namespace mydpns;
8365 : const char *result;
8366 :
8367 18 : parent_namespaces = list_copy_tail(context->namespaces,
8368 : ctelevelsup);
8369 :
8370 18 : set_deparse_for_query(&mydpns, ctequery,
8371 : parent_namespaces);
8372 :
8373 18 : context->namespaces = lcons(&mydpns, parent_namespaces);
8374 :
8375 18 : result = get_name_for_var_field((Var *) expr, fieldno,
8376 : 0, context);
8377 :
8378 18 : context->namespaces = save_nslist;
8379 :
8380 18 : return result;
8381 : }
8382 : /* else fall through to inspect the expression */
8383 : }
8384 : else
8385 : {
8386 : /*
8387 : * We're deparsing a Plan tree so we don't have a CTE
8388 : * list. But the only places we'd normally see a Var
8389 : * directly referencing a CTE RTE are in CteScan or
8390 : * WorkTableScan plan nodes. For those cases,
8391 : * set_deparse_plan arranged for dpns->inner_plan to be
8392 : * the plan node that emits the CTE or RecursiveUnion
8393 : * result, and we can look at its tlist instead. As
8394 : * above, this can fail if the CTE has been proven empty,
8395 : * in which case fall back to "fN".
8396 : */
8397 : TargetEntry *tle;
8398 : deparse_namespace save_dpns;
8399 : const char *result;
8400 :
8401 42 : if (!dpns->inner_plan)
8402 : {
8403 6 : char *dummy_name = palloc(32);
8404 :
8405 : Assert(dpns->plan && IsA(dpns->plan, Result));
8406 6 : snprintf(dummy_name, 32, "f%d", fieldno);
8407 6 : return dummy_name;
8408 : }
8409 : Assert(dpns->plan && (IsA(dpns->plan, CteScan) ||
8410 : IsA(dpns->plan, WorkTableScan)));
8411 :
8412 36 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
8413 36 : if (!tle)
8414 0 : elog(ERROR, "bogus varattno for subquery var: %d",
8415 : attnum);
8416 : Assert(netlevelsup == 0);
8417 36 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
8418 :
8419 36 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
8420 : levelsup, context);
8421 :
8422 36 : pop_child_plan(dpns, &save_dpns);
8423 36 : return result;
8424 : }
8425 : }
8426 12 : break;
8427 0 : case RTE_GROUP:
8428 :
8429 : /*
8430 : * We couldn't get here: any Vars that reference the RTE_GROUP RTE
8431 : * should have been replaced with the underlying grouping
8432 : * expressions.
8433 : */
8434 0 : break;
8435 : }
8436 :
8437 : /*
8438 : * We now have an expression we can't expand any more, so see if
8439 : * get_expr_result_tupdesc() can do anything with it.
8440 : */
8441 36 : tupleDesc = get_expr_result_tupdesc(expr, false);
8442 : /* Got the tupdesc, so we can extract the field name */
8443 : Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
8444 36 : return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
8445 : }
8446 :
8447 : /*
8448 : * Try to find the referenced expression for a PARAM_EXEC Param that might
8449 : * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
8450 : *
8451 : * If successful, return the expression and set *dpns_p and *ancestor_cell_p
8452 : * appropriately for calling push_ancestor_plan(). If no referent can be
8453 : * found, return NULL.
8454 : */
8455 : static Node *
8456 7192 : find_param_referent(Param *param, deparse_context *context,
8457 : deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
8458 : {
8459 : /* Initialize output parameters to prevent compiler warnings */
8460 7192 : *dpns_p = NULL;
8461 7192 : *ancestor_cell_p = NULL;
8462 :
8463 : /*
8464 : * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
8465 : * SubPlan argument. This will necessarily be in some ancestor of the
8466 : * current expression's Plan node.
8467 : */
8468 7192 : if (param->paramkind == PARAM_EXEC)
8469 : {
8470 : deparse_namespace *dpns;
8471 : Plan *child_plan;
8472 : ListCell *lc;
8473 :
8474 6300 : dpns = (deparse_namespace *) linitial(context->namespaces);
8475 6300 : child_plan = dpns->plan;
8476 :
8477 11168 : foreach(lc, dpns->ancestors)
8478 : {
8479 9508 : Node *ancestor = (Node *) lfirst(lc);
8480 : ListCell *lc2;
8481 :
8482 : /*
8483 : * NestLoops transmit params to their inner child only.
8484 : */
8485 9508 : if (IsA(ancestor, NestLoop) &&
8486 4332 : child_plan == innerPlan(ancestor))
8487 : {
8488 4152 : NestLoop *nl = (NestLoop *) ancestor;
8489 :
8490 5138 : foreach(lc2, nl->nestParams)
8491 : {
8492 4964 : NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
8493 :
8494 4964 : if (nlp->paramno == param->paramid)
8495 : {
8496 : /* Found a match, so return it */
8497 3978 : *dpns_p = dpns;
8498 3978 : *ancestor_cell_p = lc;
8499 3978 : return (Node *) nlp->paramval;
8500 : }
8501 : }
8502 : }
8503 :
8504 : /*
8505 : * If ancestor is a SubPlan, check the arguments it provides.
8506 : */
8507 5530 : if (IsA(ancestor, SubPlan))
8508 366 : {
8509 1028 : SubPlan *subplan = (SubPlan *) ancestor;
8510 : ListCell *lc3;
8511 : ListCell *lc4;
8512 :
8513 1370 : forboth(lc3, subplan->parParam, lc4, subplan->args)
8514 : {
8515 1004 : int paramid = lfirst_int(lc3);
8516 1004 : Node *arg = (Node *) lfirst(lc4);
8517 :
8518 1004 : if (paramid == param->paramid)
8519 : {
8520 : /*
8521 : * Found a match, so return it. But, since Vars in
8522 : * the arg are to be evaluated in the surrounding
8523 : * context, we have to point to the next ancestor item
8524 : * that is *not* a SubPlan.
8525 : */
8526 : ListCell *rest;
8527 :
8528 662 : for_each_cell(rest, dpns->ancestors,
8529 : lnext(dpns->ancestors, lc))
8530 : {
8531 662 : Node *ancestor2 = (Node *) lfirst(rest);
8532 :
8533 662 : if (!IsA(ancestor2, SubPlan))
8534 : {
8535 662 : *dpns_p = dpns;
8536 662 : *ancestor_cell_p = rest;
8537 662 : return arg;
8538 : }
8539 : }
8540 0 : elog(ERROR, "SubPlan cannot be outermost ancestor");
8541 : }
8542 : }
8543 :
8544 : /* SubPlan isn't a kind of Plan, so skip the rest */
8545 366 : continue;
8546 : }
8547 :
8548 : /*
8549 : * We need not consider the ancestor's initPlan list, since
8550 : * initplans never have any parParams.
8551 : */
8552 :
8553 : /* No luck, crawl up to next ancestor */
8554 4502 : child_plan = (Plan *) ancestor;
8555 : }
8556 : }
8557 :
8558 : /* No referent found */
8559 2552 : return NULL;
8560 : }
8561 :
8562 : /*
8563 : * Try to find a subplan/initplan that emits the value for a PARAM_EXEC Param.
8564 : *
8565 : * If successful, return the generating subplan/initplan and set *column_p
8566 : * to the subplan's 0-based output column number.
8567 : * Otherwise, return NULL.
8568 : */
8569 : static SubPlan *
8570 2552 : find_param_generator(Param *param, deparse_context *context, int *column_p)
8571 : {
8572 : /* Initialize output parameter to prevent compiler warnings */
8573 2552 : *column_p = 0;
8574 :
8575 : /*
8576 : * If it's a PARAM_EXEC parameter, search the current plan node as well as
8577 : * ancestor nodes looking for a subplan or initplan that emits the value
8578 : * for the Param. It could appear in the setParams of an initplan or
8579 : * MULTIEXPR_SUBLINK subplan, or in the paramIds of an ancestral SubPlan.
8580 : */
8581 2552 : if (param->paramkind == PARAM_EXEC)
8582 : {
8583 : SubPlan *result;
8584 : deparse_namespace *dpns;
8585 : ListCell *lc;
8586 :
8587 1660 : dpns = (deparse_namespace *) linitial(context->namespaces);
8588 :
8589 : /* First check the innermost plan node's initplans */
8590 1660 : result = find_param_generator_initplan(param, dpns->plan, column_p);
8591 1660 : if (result)
8592 500 : return result;
8593 :
8594 : /*
8595 : * The plan's targetlist might contain MULTIEXPR_SUBLINK SubPlans,
8596 : * which can be referenced by Params elsewhere in the targetlist.
8597 : * (Such Params should always be in the same targetlist, so there's no
8598 : * need to do this work at upper plan nodes.)
8599 : */
8600 5944 : foreach_node(TargetEntry, tle, dpns->plan->targetlist)
8601 : {
8602 3728 : if (tle->expr && IsA(tle->expr, SubPlan))
8603 : {
8604 100 : SubPlan *subplan = (SubPlan *) tle->expr;
8605 :
8606 100 : if (subplan->subLinkType == MULTIEXPR_SUBLINK)
8607 : {
8608 78 : foreach_int(paramid, subplan->setParam)
8609 : {
8610 78 : if (paramid == param->paramid)
8611 : {
8612 : /* Found a match, so return it. */
8613 52 : *column_p = foreach_current_index(paramid);
8614 52 : return subplan;
8615 : }
8616 : }
8617 : }
8618 : }
8619 : }
8620 :
8621 : /* No luck, so check the ancestor nodes */
8622 1462 : foreach(lc, dpns->ancestors)
8623 : {
8624 1462 : Node *ancestor = (Node *) lfirst(lc);
8625 :
8626 : /*
8627 : * If ancestor is a SubPlan, check the paramIds it provides.
8628 : */
8629 1462 : if (IsA(ancestor, SubPlan))
8630 0 : {
8631 210 : SubPlan *subplan = (SubPlan *) ancestor;
8632 :
8633 236 : foreach_int(paramid, subplan->paramIds)
8634 : {
8635 236 : if (paramid == param->paramid)
8636 : {
8637 : /* Found a match, so return it. */
8638 210 : *column_p = foreach_current_index(paramid);
8639 210 : return subplan;
8640 : }
8641 : }
8642 :
8643 : /* SubPlan isn't a kind of Plan, so skip the rest */
8644 0 : continue;
8645 : }
8646 :
8647 : /*
8648 : * Otherwise, it's some kind of Plan node, so check its initplans.
8649 : */
8650 1252 : result = find_param_generator_initplan(param, (Plan *) ancestor,
8651 : column_p);
8652 1252 : if (result)
8653 898 : return result;
8654 :
8655 : /* No luck, crawl up to next ancestor */
8656 : }
8657 : }
8658 :
8659 : /* No generator found */
8660 892 : return NULL;
8661 : }
8662 :
8663 : /*
8664 : * Subroutine for find_param_generator: search one Plan node's initplans
8665 : */
8666 : static SubPlan *
8667 2912 : find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
8668 : {
8669 4566 : foreach_node(SubPlan, subplan, plan->initPlan)
8670 : {
8671 1824 : foreach_int(paramid, subplan->setParam)
8672 : {
8673 1544 : if (paramid == param->paramid)
8674 : {
8675 : /* Found a match, so return it. */
8676 1398 : *column_p = foreach_current_index(paramid);
8677 1398 : return subplan;
8678 : }
8679 : }
8680 : }
8681 1514 : return NULL;
8682 : }
8683 :
8684 : /*
8685 : * Display a Param appropriately.
8686 : */
8687 : static void
8688 7174 : get_parameter(Param *param, deparse_context *context)
8689 : {
8690 : Node *expr;
8691 : deparse_namespace *dpns;
8692 : ListCell *ancestor_cell;
8693 : SubPlan *subplan;
8694 : int column;
8695 :
8696 : /*
8697 : * If it's a PARAM_EXEC parameter, try to locate the expression from which
8698 : * the parameter was computed. This stanza handles only cases in which
8699 : * the Param represents an input to the subplan we are currently in.
8700 : */
8701 7174 : expr = find_param_referent(param, context, &dpns, &ancestor_cell);
8702 7174 : if (expr)
8703 : {
8704 : /* Found a match, so print it */
8705 : deparse_namespace save_dpns;
8706 : bool save_varprefix;
8707 : bool need_paren;
8708 :
8709 : /* Switch attention to the ancestor plan node */
8710 4622 : push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8711 :
8712 : /*
8713 : * Force prefixing of Vars, since they won't belong to the relation
8714 : * being scanned in the original plan node.
8715 : */
8716 4622 : save_varprefix = context->varprefix;
8717 4622 : context->varprefix = true;
8718 :
8719 : /*
8720 : * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8721 : * upper-level Param, which wouldn't need extra parentheses.
8722 : * Otherwise, insert parens to ensure the expression looks atomic.
8723 : */
8724 4640 : need_paren = !(IsA(expr, Var) ||
8725 18 : IsA(expr, Aggref) ||
8726 18 : IsA(expr, GroupingFunc) ||
8727 12 : IsA(expr, Param));
8728 4622 : if (need_paren)
8729 0 : appendStringInfoChar(context->buf, '(');
8730 :
8731 4622 : get_rule_expr(expr, context, false);
8732 :
8733 4622 : if (need_paren)
8734 0 : appendStringInfoChar(context->buf, ')');
8735 :
8736 4622 : context->varprefix = save_varprefix;
8737 :
8738 4622 : pop_ancestor_plan(dpns, &save_dpns);
8739 :
8740 4622 : return;
8741 : }
8742 :
8743 : /*
8744 : * Alternatively, maybe it's a subplan output, which we print as a
8745 : * reference to the subplan. (We could drill down into the subplan and
8746 : * print the relevant targetlist expression, but that has been deemed too
8747 : * confusing since it would violate normal SQL scope rules. Also, we're
8748 : * relying on this reference to show that the testexpr containing the
8749 : * Param has anything to do with that subplan at all.)
8750 : */
8751 2552 : subplan = find_param_generator(param, context, &column);
8752 2552 : if (subplan)
8753 : {
8754 1660 : appendStringInfo(context->buf, "(%s%s).col%d",
8755 1660 : subplan->useHashTable ? "hashed " : "",
8756 : subplan->plan_name, column + 1);
8757 :
8758 1660 : return;
8759 : }
8760 :
8761 : /*
8762 : * If it's an external parameter, see if the outermost namespace provides
8763 : * function argument names.
8764 : */
8765 892 : if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8766 : {
8767 892 : dpns = llast(context->namespaces);
8768 892 : if (dpns->argnames &&
8769 68 : param->paramid > 0 &&
8770 68 : param->paramid <= dpns->numargs)
8771 : {
8772 68 : char *argname = dpns->argnames[param->paramid - 1];
8773 :
8774 68 : if (argname)
8775 : {
8776 68 : bool should_qualify = false;
8777 : ListCell *lc;
8778 :
8779 : /*
8780 : * Qualify the parameter name if there are any other deparse
8781 : * namespaces with range tables. This avoids qualifying in
8782 : * trivial cases like "RETURN a + b", but makes it safe in all
8783 : * other cases.
8784 : */
8785 156 : foreach(lc, context->namespaces)
8786 : {
8787 118 : deparse_namespace *depns = lfirst(lc);
8788 :
8789 118 : if (depns->rtable_names != NIL)
8790 : {
8791 30 : should_qualify = true;
8792 30 : break;
8793 : }
8794 : }
8795 68 : if (should_qualify)
8796 : {
8797 30 : appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
8798 30 : appendStringInfoChar(context->buf, '.');
8799 : }
8800 :
8801 68 : appendStringInfoString(context->buf, quote_identifier(argname));
8802 68 : return;
8803 : }
8804 : }
8805 : }
8806 :
8807 : /*
8808 : * Not PARAM_EXEC, or couldn't find referent: just print $N.
8809 : *
8810 : * It's a bug if we get here for anything except PARAM_EXTERN Params, but
8811 : * in production builds printing $N seems more useful than failing.
8812 : */
8813 : Assert(param->paramkind == PARAM_EXTERN);
8814 :
8815 824 : appendStringInfo(context->buf, "$%d", param->paramid);
8816 : }
8817 :
8818 : /*
8819 : * get_simple_binary_op_name
8820 : *
8821 : * helper function for isSimpleNode
8822 : * will return single char binary operator name, or NULL if it's not
8823 : */
8824 : static const char *
8825 150 : get_simple_binary_op_name(OpExpr *expr)
8826 : {
8827 150 : List *args = expr->args;
8828 :
8829 150 : if (list_length(args) == 2)
8830 : {
8831 : /* binary operator */
8832 150 : Node *arg1 = (Node *) linitial(args);
8833 150 : Node *arg2 = (Node *) lsecond(args);
8834 : const char *op;
8835 :
8836 150 : op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8837 150 : if (strlen(op) == 1)
8838 150 : return op;
8839 : }
8840 0 : return NULL;
8841 : }
8842 :
8843 :
8844 : /*
8845 : * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
8846 : *
8847 : * true : simple in the context of parent node's type
8848 : * false : not simple
8849 : */
8850 : static bool
8851 5598 : isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
8852 : {
8853 5598 : if (!node)
8854 0 : return false;
8855 :
8856 5598 : switch (nodeTag(node))
8857 : {
8858 4694 : case T_Var:
8859 : case T_Const:
8860 : case T_Param:
8861 : case T_CoerceToDomainValue:
8862 : case T_SetToDefault:
8863 : case T_CurrentOfExpr:
8864 : /* single words: always simple */
8865 4694 : return true;
8866 :
8867 490 : case T_SubscriptingRef:
8868 : case T_ArrayExpr:
8869 : case T_RowExpr:
8870 : case T_CoalesceExpr:
8871 : case T_MinMaxExpr:
8872 : case T_SQLValueFunction:
8873 : case T_XmlExpr:
8874 : case T_NextValueExpr:
8875 : case T_NullIfExpr:
8876 : case T_Aggref:
8877 : case T_GroupingFunc:
8878 : case T_WindowFunc:
8879 : case T_MergeSupportFunc:
8880 : case T_FuncExpr:
8881 : case T_JsonConstructorExpr:
8882 : case T_JsonExpr:
8883 : /* function-like: name(..) or name[..] */
8884 490 : return true;
8885 :
8886 : /* CASE keywords act as parentheses */
8887 0 : case T_CaseExpr:
8888 0 : return true;
8889 :
8890 66 : case T_FieldSelect:
8891 :
8892 : /*
8893 : * appears simple since . has top precedence, unless parent is
8894 : * T_FieldSelect itself!
8895 : */
8896 66 : return !IsA(parentNode, FieldSelect);
8897 :
8898 0 : case T_FieldStore:
8899 :
8900 : /*
8901 : * treat like FieldSelect (probably doesn't matter)
8902 : */
8903 0 : return !IsA(parentNode, FieldStore);
8904 :
8905 0 : case T_CoerceToDomain:
8906 : /* maybe simple, check args */
8907 0 : return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8908 : node, prettyFlags);
8909 18 : case T_RelabelType:
8910 18 : return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8911 : node, prettyFlags);
8912 0 : case T_CoerceViaIO:
8913 0 : return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8914 : node, prettyFlags);
8915 0 : case T_ArrayCoerceExpr:
8916 0 : return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8917 : node, prettyFlags);
8918 0 : case T_ConvertRowtypeExpr:
8919 0 : return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8920 : node, prettyFlags);
8921 0 : case T_ReturningExpr:
8922 0 : return isSimpleNode((Node *) ((ReturningExpr *) node)->retexpr,
8923 : node, prettyFlags);
8924 :
8925 276 : case T_OpExpr:
8926 : {
8927 : /* depends on parent node type; needs further checking */
8928 276 : if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8929 : {
8930 : const char *op;
8931 : const char *parentOp;
8932 : bool is_lopriop;
8933 : bool is_hipriop;
8934 : bool is_lopriparent;
8935 : bool is_hipriparent;
8936 :
8937 78 : op = get_simple_binary_op_name((OpExpr *) node);
8938 78 : if (!op)
8939 0 : return false;
8940 :
8941 : /* We know only the basic operators + - and * / % */
8942 78 : is_lopriop = (strchr("+-", *op) != NULL);
8943 78 : is_hipriop = (strchr("*/%", *op) != NULL);
8944 78 : if (!(is_lopriop || is_hipriop))
8945 6 : return false;
8946 :
8947 72 : parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8948 72 : if (!parentOp)
8949 0 : return false;
8950 :
8951 72 : is_lopriparent = (strchr("+-", *parentOp) != NULL);
8952 72 : is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8953 72 : if (!(is_lopriparent || is_hipriparent))
8954 0 : return false;
8955 :
8956 72 : if (is_hipriop && is_lopriparent)
8957 12 : return true; /* op binds tighter than parent */
8958 :
8959 60 : if (is_lopriop && is_hipriparent)
8960 48 : return false;
8961 :
8962 : /*
8963 : * Operators are same priority --- can skip parens only if
8964 : * we have (a - b) - c, not a - (b - c).
8965 : */
8966 12 : if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8967 6 : return true;
8968 :
8969 6 : return false;
8970 : }
8971 : /* else do the same stuff as for T_SubLink et al. */
8972 : }
8973 : /* FALLTHROUGH */
8974 :
8975 : case T_SubLink:
8976 : case T_NullTest:
8977 : case T_BooleanTest:
8978 : case T_DistinctExpr:
8979 : case T_JsonIsPredicate:
8980 228 : switch (nodeTag(parentNode))
8981 : {
8982 36 : case T_FuncExpr:
8983 : {
8984 : /* special handling for casts and COERCE_SQL_SYNTAX */
8985 36 : CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8986 :
8987 36 : if (type == COERCE_EXPLICIT_CAST ||
8988 6 : type == COERCE_IMPLICIT_CAST ||
8989 : type == COERCE_SQL_SYNTAX)
8990 36 : return false;
8991 0 : return true; /* own parentheses */
8992 : }
8993 162 : case T_BoolExpr: /* lower precedence */
8994 : case T_SubscriptingRef: /* other separators */
8995 : case T_ArrayExpr: /* other separators */
8996 : case T_RowExpr: /* other separators */
8997 : case T_CoalesceExpr: /* own parentheses */
8998 : case T_MinMaxExpr: /* own parentheses */
8999 : case T_XmlExpr: /* own parentheses */
9000 : case T_NullIfExpr: /* other separators */
9001 : case T_Aggref: /* own parentheses */
9002 : case T_GroupingFunc: /* own parentheses */
9003 : case T_WindowFunc: /* own parentheses */
9004 : case T_CaseExpr: /* other separators */
9005 162 : return true;
9006 30 : default:
9007 30 : return false;
9008 : }
9009 :
9010 18 : case T_BoolExpr:
9011 18 : switch (nodeTag(parentNode))
9012 : {
9013 18 : case T_BoolExpr:
9014 18 : if (prettyFlags & PRETTYFLAG_PAREN)
9015 : {
9016 : BoolExprType type;
9017 : BoolExprType parentType;
9018 :
9019 18 : type = ((BoolExpr *) node)->boolop;
9020 18 : parentType = ((BoolExpr *) parentNode)->boolop;
9021 : switch (type)
9022 : {
9023 12 : case NOT_EXPR:
9024 : case AND_EXPR:
9025 12 : if (parentType == AND_EXPR || parentType == OR_EXPR)
9026 12 : return true;
9027 0 : break;
9028 6 : case OR_EXPR:
9029 6 : if (parentType == OR_EXPR)
9030 0 : return true;
9031 6 : break;
9032 : }
9033 : }
9034 6 : return false;
9035 0 : case T_FuncExpr:
9036 : {
9037 : /* special handling for casts and COERCE_SQL_SYNTAX */
9038 0 : CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
9039 :
9040 0 : if (type == COERCE_EXPLICIT_CAST ||
9041 0 : type == COERCE_IMPLICIT_CAST ||
9042 : type == COERCE_SQL_SYNTAX)
9043 0 : return false;
9044 0 : return true; /* own parentheses */
9045 : }
9046 0 : case T_SubscriptingRef: /* other separators */
9047 : case T_ArrayExpr: /* other separators */
9048 : case T_RowExpr: /* other separators */
9049 : case T_CoalesceExpr: /* own parentheses */
9050 : case T_MinMaxExpr: /* own parentheses */
9051 : case T_XmlExpr: /* own parentheses */
9052 : case T_NullIfExpr: /* other separators */
9053 : case T_Aggref: /* own parentheses */
9054 : case T_GroupingFunc: /* own parentheses */
9055 : case T_WindowFunc: /* own parentheses */
9056 : case T_CaseExpr: /* other separators */
9057 : case T_JsonExpr: /* own parentheses */
9058 0 : return true;
9059 0 : default:
9060 0 : return false;
9061 : }
9062 :
9063 0 : case T_JsonValueExpr:
9064 : /* maybe simple, check args */
9065 0 : return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
9066 : node, prettyFlags);
9067 :
9068 6 : default:
9069 6 : break;
9070 : }
9071 : /* those we don't know: in dubio complexo */
9072 6 : return false;
9073 : }
9074 :
9075 :
9076 : /*
9077 : * appendContextKeyword - append a keyword to buffer
9078 : *
9079 : * If prettyPrint is enabled, perform a line break, and adjust indentation.
9080 : * Otherwise, just append the keyword.
9081 : */
9082 : static void
9083 29960 : appendContextKeyword(deparse_context *context, const char *str,
9084 : int indentBefore, int indentAfter, int indentPlus)
9085 : {
9086 29960 : StringInfo buf = context->buf;
9087 :
9088 29960 : if (PRETTY_INDENT(context))
9089 : {
9090 : int indentAmount;
9091 :
9092 29044 : context->indentLevel += indentBefore;
9093 :
9094 : /* remove any trailing spaces currently in the buffer ... */
9095 29044 : removeStringInfoSpaces(buf);
9096 : /* ... then add a newline and some spaces */
9097 29044 : appendStringInfoChar(buf, '\n');
9098 :
9099 29044 : if (context->indentLevel < PRETTYINDENT_LIMIT)
9100 29044 : indentAmount = Max(context->indentLevel, 0) + indentPlus;
9101 : else
9102 : {
9103 : /*
9104 : * If we're indented more than PRETTYINDENT_LIMIT characters, try
9105 : * to conserve horizontal space by reducing the per-level
9106 : * indentation. For best results the scale factor here should
9107 : * divide all the indent amounts that get added to indentLevel
9108 : * (PRETTYINDENT_STD, etc). It's important that the indentation
9109 : * not grow unboundedly, else deeply-nested trees use O(N^2)
9110 : * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
9111 : */
9112 0 : indentAmount = PRETTYINDENT_LIMIT +
9113 0 : (context->indentLevel - PRETTYINDENT_LIMIT) /
9114 : (PRETTYINDENT_STD / 2);
9115 0 : indentAmount %= PRETTYINDENT_LIMIT;
9116 : /* scale/wrap logic affects indentLevel, but not indentPlus */
9117 0 : indentAmount += indentPlus;
9118 : }
9119 29044 : appendStringInfoSpaces(buf, indentAmount);
9120 :
9121 29044 : appendStringInfoString(buf, str);
9122 :
9123 29044 : context->indentLevel += indentAfter;
9124 29044 : if (context->indentLevel < 0)
9125 0 : context->indentLevel = 0;
9126 : }
9127 : else
9128 916 : appendStringInfoString(buf, str);
9129 29960 : }
9130 :
9131 : /*
9132 : * removeStringInfoSpaces - delete trailing spaces from a buffer.
9133 : *
9134 : * Possibly this should move to stringinfo.c at some point.
9135 : */
9136 : static void
9137 29518 : removeStringInfoSpaces(StringInfo str)
9138 : {
9139 46134 : while (str->len > 0 && str->data[str->len - 1] == ' ')
9140 16616 : str->data[--(str->len)] = '\0';
9141 29518 : }
9142 :
9143 :
9144 : /*
9145 : * get_rule_expr_paren - deparse expr using get_rule_expr,
9146 : * embracing the string with parentheses if necessary for prettyPrint.
9147 : *
9148 : * Never embrace if prettyFlags=0, because it's done in the calling node.
9149 : *
9150 : * Any node that does *not* embrace its argument node by sql syntax (with
9151 : * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
9152 : * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
9153 : * added.
9154 : */
9155 : static void
9156 162334 : get_rule_expr_paren(Node *node, deparse_context *context,
9157 : bool showimplicit, Node *parentNode)
9158 : {
9159 : bool need_paren;
9160 :
9161 167914 : need_paren = PRETTY_PAREN(context) &&
9162 5580 : !isSimpleNode(node, parentNode, context->prettyFlags);
9163 :
9164 162334 : if (need_paren)
9165 138 : appendStringInfoChar(context->buf, '(');
9166 :
9167 162334 : get_rule_expr(node, context, showimplicit);
9168 :
9169 162334 : if (need_paren)
9170 138 : appendStringInfoChar(context->buf, ')');
9171 162334 : }
9172 :
9173 : static void
9174 84 : get_json_behavior(JsonBehavior *behavior, deparse_context *context,
9175 : const char *on)
9176 : {
9177 : /*
9178 : * The order of array elements must correspond to the order of
9179 : * JsonBehaviorType members.
9180 : */
9181 84 : const char *behavior_names[] =
9182 : {
9183 : " NULL",
9184 : " ERROR",
9185 : " EMPTY",
9186 : " TRUE",
9187 : " FALSE",
9188 : " UNKNOWN",
9189 : " EMPTY ARRAY",
9190 : " EMPTY OBJECT",
9191 : " DEFAULT "
9192 : };
9193 :
9194 84 : if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
9195 0 : elog(ERROR, "invalid json behavior type: %d", behavior->btype);
9196 :
9197 84 : appendStringInfoString(context->buf, behavior_names[behavior->btype]);
9198 :
9199 84 : if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
9200 18 : get_rule_expr(behavior->expr, context, false);
9201 :
9202 84 : appendStringInfo(context->buf, " ON %s", on);
9203 84 : }
9204 :
9205 : /*
9206 : * get_json_expr_options
9207 : *
9208 : * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
9209 : * JSON_TABLE columns.
9210 : */
9211 : static void
9212 456 : get_json_expr_options(JsonExpr *jsexpr, deparse_context *context,
9213 : JsonBehaviorType default_behavior)
9214 : {
9215 456 : if (jsexpr->op == JSON_QUERY_OP)
9216 : {
9217 210 : if (jsexpr->wrapper == JSW_CONDITIONAL)
9218 12 : appendStringInfoString(context->buf, " WITH CONDITIONAL WRAPPER");
9219 198 : else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
9220 30 : appendStringInfoString(context->buf, " WITH UNCONDITIONAL WRAPPER");
9221 : /* The default */
9222 168 : else if (jsexpr->wrapper == JSW_NONE || jsexpr->wrapper == JSW_UNSPEC)
9223 168 : appendStringInfoString(context->buf, " WITHOUT WRAPPER");
9224 :
9225 210 : if (jsexpr->omit_quotes)
9226 42 : appendStringInfoString(context->buf, " OMIT QUOTES");
9227 : /* The default */
9228 : else
9229 168 : appendStringInfoString(context->buf, " KEEP QUOTES");
9230 : }
9231 :
9232 456 : if (jsexpr->on_empty && jsexpr->on_empty->btype != default_behavior)
9233 30 : get_json_behavior(jsexpr->on_empty, context, "EMPTY");
9234 :
9235 456 : if (jsexpr->on_error && jsexpr->on_error->btype != default_behavior)
9236 48 : get_json_behavior(jsexpr->on_error, context, "ERROR");
9237 456 : }
9238 :
9239 : /* ----------
9240 : * get_rule_expr - Parse back an expression
9241 : *
9242 : * Note: showimplicit determines whether we display any implicit cast that
9243 : * is present at the top of the expression tree. It is a passed argument,
9244 : * not a field of the context struct, because we change the value as we
9245 : * recurse down into the expression. In general we suppress implicit casts
9246 : * when the result type is known with certainty (eg, the arguments of an
9247 : * OR must be boolean). We display implicit casts for arguments of functions
9248 : * and operators, since this is needed to be certain that the same function
9249 : * or operator will be chosen when the expression is re-parsed.
9250 : * ----------
9251 : */
9252 : static void
9253 336860 : get_rule_expr(Node *node, deparse_context *context,
9254 : bool showimplicit)
9255 : {
9256 336860 : StringInfo buf = context->buf;
9257 :
9258 336860 : if (node == NULL)
9259 90 : return;
9260 :
9261 : /* Guard against excessively long or deeply-nested queries */
9262 336770 : CHECK_FOR_INTERRUPTS();
9263 336770 : check_stack_depth();
9264 :
9265 : /*
9266 : * Each level of get_rule_expr must emit an indivisible term
9267 : * (parenthesized if necessary) to ensure result is reparsed into the same
9268 : * expression tree. The only exception is that when the input is a List,
9269 : * we emit the component items comma-separated with no surrounding
9270 : * decoration; this is convenient for most callers.
9271 : */
9272 336770 : switch (nodeTag(node))
9273 : {
9274 156742 : case T_Var:
9275 156742 : (void) get_variable((Var *) node, 0, false, context);
9276 156742 : break;
9277 :
9278 62186 : case T_Const:
9279 62186 : get_const_expr((Const *) node, context, 0);
9280 62186 : break;
9281 :
9282 7174 : case T_Param:
9283 7174 : get_parameter((Param *) node, context);
9284 7174 : break;
9285 :
9286 1734 : case T_Aggref:
9287 1734 : get_agg_expr((Aggref *) node, context, (Aggref *) node);
9288 1734 : break;
9289 :
9290 112 : case T_GroupingFunc:
9291 : {
9292 112 : GroupingFunc *gexpr = (GroupingFunc *) node;
9293 :
9294 112 : appendStringInfoString(buf, "GROUPING(");
9295 112 : get_rule_expr((Node *) gexpr->args, context, true);
9296 112 : appendStringInfoChar(buf, ')');
9297 : }
9298 112 : break;
9299 :
9300 306 : case T_WindowFunc:
9301 306 : get_windowfunc_expr((WindowFunc *) node, context);
9302 306 : break;
9303 :
9304 6 : case T_MergeSupportFunc:
9305 6 : appendStringInfoString(buf, "MERGE_ACTION()");
9306 6 : break;
9307 :
9308 328 : case T_SubscriptingRef:
9309 : {
9310 328 : SubscriptingRef *sbsref = (SubscriptingRef *) node;
9311 : bool need_parens;
9312 :
9313 : /*
9314 : * If the argument is a CaseTestExpr, we must be inside a
9315 : * FieldStore, ie, we are assigning to an element of an array
9316 : * within a composite column. Since we already punted on
9317 : * displaying the FieldStore's target information, just punt
9318 : * here too, and display only the assignment source
9319 : * expression.
9320 : */
9321 328 : if (IsA(sbsref->refexpr, CaseTestExpr))
9322 : {
9323 : Assert(sbsref->refassgnexpr);
9324 0 : get_rule_expr((Node *) sbsref->refassgnexpr,
9325 : context, showimplicit);
9326 0 : break;
9327 : }
9328 :
9329 : /*
9330 : * Parenthesize the argument unless it's a simple Var or a
9331 : * FieldSelect. (In particular, if it's another
9332 : * SubscriptingRef, we *must* parenthesize to avoid
9333 : * confusion.)
9334 : */
9335 482 : need_parens = !IsA(sbsref->refexpr, Var) &&
9336 154 : !IsA(sbsref->refexpr, FieldSelect);
9337 328 : if (need_parens)
9338 94 : appendStringInfoChar(buf, '(');
9339 328 : get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
9340 328 : if (need_parens)
9341 94 : appendStringInfoChar(buf, ')');
9342 :
9343 : /*
9344 : * If there's a refassgnexpr, we want to print the node in the
9345 : * format "container[subscripts] := refassgnexpr". This is
9346 : * not legal SQL, so decompilation of INSERT or UPDATE
9347 : * statements should always use processIndirection as part of
9348 : * the statement-level syntax. We should only see this when
9349 : * EXPLAIN tries to print the targetlist of a plan resulting
9350 : * from such a statement.
9351 : */
9352 328 : if (sbsref->refassgnexpr)
9353 : {
9354 : Node *refassgnexpr;
9355 :
9356 : /*
9357 : * Use processIndirection to print this node's subscripts
9358 : * as well as any additional field selections or
9359 : * subscripting in immediate descendants. It returns the
9360 : * RHS expr that is actually being "assigned".
9361 : */
9362 12 : refassgnexpr = processIndirection(node, context);
9363 12 : appendStringInfoString(buf, " := ");
9364 12 : get_rule_expr(refassgnexpr, context, showimplicit);
9365 : }
9366 : else
9367 : {
9368 : /* Just an ordinary container fetch, so print subscripts */
9369 316 : printSubscripts(sbsref, context);
9370 : }
9371 : }
9372 328 : break;
9373 :
9374 12598 : case T_FuncExpr:
9375 12598 : get_func_expr((FuncExpr *) node, context, showimplicit);
9376 12598 : break;
9377 :
9378 30 : case T_NamedArgExpr:
9379 : {
9380 30 : NamedArgExpr *na = (NamedArgExpr *) node;
9381 :
9382 30 : appendStringInfo(buf, "%s => ", quote_identifier(na->name));
9383 30 : get_rule_expr((Node *) na->arg, context, showimplicit);
9384 : }
9385 30 : break;
9386 :
9387 60610 : case T_OpExpr:
9388 60610 : get_oper_expr((OpExpr *) node, context);
9389 60610 : break;
9390 :
9391 18 : case T_DistinctExpr:
9392 : {
9393 18 : DistinctExpr *expr = (DistinctExpr *) node;
9394 18 : List *args = expr->args;
9395 18 : Node *arg1 = (Node *) linitial(args);
9396 18 : Node *arg2 = (Node *) lsecond(args);
9397 :
9398 18 : if (!PRETTY_PAREN(context))
9399 12 : appendStringInfoChar(buf, '(');
9400 18 : get_rule_expr_paren(arg1, context, true, node);
9401 18 : appendStringInfoString(buf, " IS DISTINCT FROM ");
9402 18 : get_rule_expr_paren(arg2, context, true, node);
9403 18 : if (!PRETTY_PAREN(context))
9404 12 : appendStringInfoChar(buf, ')');
9405 : }
9406 18 : break;
9407 :
9408 160 : case T_NullIfExpr:
9409 : {
9410 160 : NullIfExpr *nullifexpr = (NullIfExpr *) node;
9411 :
9412 160 : appendStringInfoString(buf, "NULLIF(");
9413 160 : get_rule_expr((Node *) nullifexpr->args, context, true);
9414 160 : appendStringInfoChar(buf, ')');
9415 : }
9416 160 : break;
9417 :
9418 3030 : case T_ScalarArrayOpExpr:
9419 : {
9420 3030 : ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
9421 3030 : List *args = expr->args;
9422 3030 : Node *arg1 = (Node *) linitial(args);
9423 3030 : Node *arg2 = (Node *) lsecond(args);
9424 :
9425 3030 : if (!PRETTY_PAREN(context))
9426 3018 : appendStringInfoChar(buf, '(');
9427 3030 : get_rule_expr_paren(arg1, context, true, node);
9428 3030 : appendStringInfo(buf, " %s %s (",
9429 : generate_operator_name(expr->opno,
9430 : exprType(arg1),
9431 : get_base_element_type(exprType(arg2))),
9432 3030 : expr->useOr ? "ANY" : "ALL");
9433 3030 : get_rule_expr_paren(arg2, context, true, node);
9434 :
9435 : /*
9436 : * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
9437 : * a bare sub-SELECT. Since we're here, the sub-SELECT must
9438 : * be meant as a scalar sub-SELECT yielding an array value to
9439 : * be used in ScalarArrayOpExpr; but the grammar will
9440 : * preferentially interpret such a construct as an ANY/ALL
9441 : * SubLink. To prevent misparsing the output that way, insert
9442 : * a dummy coercion (which will be stripped by parse analysis,
9443 : * so no inefficiency is added in dump and reload). This is
9444 : * indeed most likely what the user wrote to get the construct
9445 : * accepted in the first place.
9446 : */
9447 3030 : if (IsA(arg2, SubLink) &&
9448 6 : ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
9449 6 : appendStringInfo(buf, "::%s",
9450 : format_type_with_typemod(exprType(arg2),
9451 : exprTypmod(arg2)));
9452 3030 : appendStringInfoChar(buf, ')');
9453 3030 : if (!PRETTY_PAREN(context))
9454 3018 : appendStringInfoChar(buf, ')');
9455 : }
9456 3030 : break;
9457 :
9458 11196 : case T_BoolExpr:
9459 : {
9460 11196 : BoolExpr *expr = (BoolExpr *) node;
9461 11196 : Node *first_arg = linitial(expr->args);
9462 : ListCell *arg;
9463 :
9464 11196 : switch (expr->boolop)
9465 : {
9466 8918 : case AND_EXPR:
9467 8918 : if (!PRETTY_PAREN(context))
9468 8852 : appendStringInfoChar(buf, '(');
9469 8918 : get_rule_expr_paren(first_arg, context,
9470 : false, node);
9471 20340 : for_each_from(arg, expr->args, 1)
9472 : {
9473 11422 : appendStringInfoString(buf, " AND ");
9474 11422 : get_rule_expr_paren((Node *) lfirst(arg), context,
9475 : false, node);
9476 : }
9477 8918 : if (!PRETTY_PAREN(context))
9478 8852 : appendStringInfoChar(buf, ')');
9479 8918 : break;
9480 :
9481 1912 : case OR_EXPR:
9482 1912 : if (!PRETTY_PAREN(context))
9483 1900 : appendStringInfoChar(buf, '(');
9484 1912 : get_rule_expr_paren(first_arg, context,
9485 : false, node);
9486 4538 : for_each_from(arg, expr->args, 1)
9487 : {
9488 2626 : appendStringInfoString(buf, " OR ");
9489 2626 : get_rule_expr_paren((Node *) lfirst(arg), context,
9490 : false, node);
9491 : }
9492 1912 : if (!PRETTY_PAREN(context))
9493 1900 : appendStringInfoChar(buf, ')');
9494 1912 : break;
9495 :
9496 366 : case NOT_EXPR:
9497 366 : if (!PRETTY_PAREN(context))
9498 354 : appendStringInfoChar(buf, '(');
9499 366 : appendStringInfoString(buf, "NOT ");
9500 366 : get_rule_expr_paren(first_arg, context,
9501 : false, node);
9502 366 : if (!PRETTY_PAREN(context))
9503 354 : appendStringInfoChar(buf, ')');
9504 366 : break;
9505 :
9506 0 : default:
9507 0 : elog(ERROR, "unrecognized boolop: %d",
9508 : (int) expr->boolop);
9509 : }
9510 : }
9511 11196 : break;
9512 :
9513 460 : case T_SubLink:
9514 460 : get_sublink_expr((SubLink *) node, context);
9515 460 : break;
9516 :
9517 724 : case T_SubPlan:
9518 : {
9519 724 : SubPlan *subplan = (SubPlan *) node;
9520 :
9521 : /*
9522 : * We cannot see an already-planned subplan in rule deparsing,
9523 : * only while EXPLAINing a query plan. We don't try to
9524 : * reconstruct the original SQL, just reference the subplan
9525 : * that appears elsewhere in EXPLAIN's result. It does seem
9526 : * useful to show the subLinkType and testexpr (if any), and
9527 : * we also note whether the subplan will be hashed.
9528 : */
9529 724 : switch (subplan->subLinkType)
9530 : {
9531 96 : case EXISTS_SUBLINK:
9532 96 : appendStringInfoString(buf, "EXISTS(");
9533 : Assert(subplan->testexpr == NULL);
9534 96 : break;
9535 6 : case ALL_SUBLINK:
9536 6 : appendStringInfoString(buf, "(ALL ");
9537 : Assert(subplan->testexpr != NULL);
9538 6 : break;
9539 166 : case ANY_SUBLINK:
9540 166 : appendStringInfoString(buf, "(ANY ");
9541 : Assert(subplan->testexpr != NULL);
9542 166 : break;
9543 6 : case ROWCOMPARE_SUBLINK:
9544 : /* Parenthesizing the testexpr seems sufficient */
9545 6 : appendStringInfoChar(buf, '(');
9546 : Assert(subplan->testexpr != NULL);
9547 6 : break;
9548 412 : case EXPR_SUBLINK:
9549 : /* No need to decorate these subplan references */
9550 412 : appendStringInfoChar(buf, '(');
9551 : Assert(subplan->testexpr == NULL);
9552 412 : break;
9553 26 : case MULTIEXPR_SUBLINK:
9554 : /* MULTIEXPR isn't executed in the normal way */
9555 26 : appendStringInfoString(buf, "(rescan ");
9556 : Assert(subplan->testexpr == NULL);
9557 26 : break;
9558 12 : case ARRAY_SUBLINK:
9559 12 : appendStringInfoString(buf, "ARRAY(");
9560 : Assert(subplan->testexpr == NULL);
9561 12 : break;
9562 0 : case CTE_SUBLINK:
9563 : /* This case is unreachable within expressions */
9564 0 : appendStringInfoString(buf, "CTE(");
9565 : Assert(subplan->testexpr == NULL);
9566 0 : break;
9567 : }
9568 :
9569 724 : if (subplan->testexpr != NULL)
9570 : {
9571 : deparse_namespace *dpns;
9572 :
9573 : /*
9574 : * Push SubPlan into ancestors list while deparsing
9575 : * testexpr, so that we can handle PARAM_EXEC references
9576 : * to the SubPlan's paramIds. (This makes it look like
9577 : * the SubPlan is an "ancestor" of the current plan node,
9578 : * which is a little weird, but it does no harm.) In this
9579 : * path, we don't need to mention the SubPlan explicitly,
9580 : * because the referencing Params will show its existence.
9581 : */
9582 178 : dpns = (deparse_namespace *) linitial(context->namespaces);
9583 178 : dpns->ancestors = lcons(subplan, dpns->ancestors);
9584 :
9585 178 : get_rule_expr(subplan->testexpr, context, showimplicit);
9586 178 : appendStringInfoChar(buf, ')');
9587 :
9588 178 : dpns->ancestors = list_delete_first(dpns->ancestors);
9589 : }
9590 : else
9591 : {
9592 : /* No referencing Params, so show the SubPlan's name */
9593 546 : if (subplan->useHashTable)
9594 0 : appendStringInfo(buf, "hashed %s)", subplan->plan_name);
9595 : else
9596 546 : appendStringInfo(buf, "%s)", subplan->plan_name);
9597 : }
9598 : }
9599 724 : break;
9600 :
9601 0 : case T_AlternativeSubPlan:
9602 : {
9603 0 : AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
9604 : ListCell *lc;
9605 :
9606 : /*
9607 : * This case cannot be reached in normal usage, since no
9608 : * AlternativeSubPlan can appear either in parsetrees or
9609 : * finished plan trees. We keep it just in case somebody
9610 : * wants to use this code to print planner data structures.
9611 : */
9612 0 : appendStringInfoString(buf, "(alternatives: ");
9613 0 : foreach(lc, asplan->subplans)
9614 : {
9615 0 : SubPlan *splan = lfirst_node(SubPlan, lc);
9616 :
9617 0 : if (splan->useHashTable)
9618 0 : appendStringInfo(buf, "hashed %s", splan->plan_name);
9619 : else
9620 0 : appendStringInfoString(buf, splan->plan_name);
9621 0 : if (lnext(asplan->subplans, lc))
9622 0 : appendStringInfoString(buf, " or ");
9623 : }
9624 0 : appendStringInfoChar(buf, ')');
9625 : }
9626 0 : break;
9627 :
9628 1154 : case T_FieldSelect:
9629 : {
9630 1154 : FieldSelect *fselect = (FieldSelect *) node;
9631 1154 : Node *arg = (Node *) fselect->arg;
9632 1154 : int fno = fselect->fieldnum;
9633 : const char *fieldname;
9634 : bool need_parens;
9635 :
9636 : /*
9637 : * Parenthesize the argument unless it's an SubscriptingRef or
9638 : * another FieldSelect. Note in particular that it would be
9639 : * WRONG to not parenthesize a Var argument; simplicity is not
9640 : * the issue here, having the right number of names is.
9641 : */
9642 2272 : need_parens = !IsA(arg, SubscriptingRef) &&
9643 1118 : !IsA(arg, FieldSelect);
9644 1154 : if (need_parens)
9645 1118 : appendStringInfoChar(buf, '(');
9646 1154 : get_rule_expr(arg, context, true);
9647 1154 : if (need_parens)
9648 1118 : appendStringInfoChar(buf, ')');
9649 :
9650 : /*
9651 : * Get and print the field name.
9652 : */
9653 1154 : fieldname = get_name_for_var_field((Var *) arg, fno,
9654 : 0, context);
9655 1154 : appendStringInfo(buf, ".%s", quote_identifier(fieldname));
9656 : }
9657 1154 : break;
9658 :
9659 6 : case T_FieldStore:
9660 : {
9661 6 : FieldStore *fstore = (FieldStore *) node;
9662 : bool need_parens;
9663 :
9664 : /*
9665 : * There is no good way to represent a FieldStore as real SQL,
9666 : * so decompilation of INSERT or UPDATE statements should
9667 : * always use processIndirection as part of the
9668 : * statement-level syntax. We should only get here when
9669 : * EXPLAIN tries to print the targetlist of a plan resulting
9670 : * from such a statement. The plan case is even harder than
9671 : * ordinary rules would be, because the planner tries to
9672 : * collapse multiple assignments to the same field or subfield
9673 : * into one FieldStore; so we can see a list of target fields
9674 : * not just one, and the arguments could be FieldStores
9675 : * themselves. We don't bother to try to print the target
9676 : * field names; we just print the source arguments, with a
9677 : * ROW() around them if there's more than one. This isn't
9678 : * terribly complete, but it's probably good enough for
9679 : * EXPLAIN's purposes; especially since anything more would be
9680 : * either hopelessly confusing or an even poorer
9681 : * representation of what the plan is actually doing.
9682 : */
9683 6 : need_parens = (list_length(fstore->newvals) != 1);
9684 6 : if (need_parens)
9685 6 : appendStringInfoString(buf, "ROW(");
9686 6 : get_rule_expr((Node *) fstore->newvals, context, showimplicit);
9687 6 : if (need_parens)
9688 6 : appendStringInfoChar(buf, ')');
9689 : }
9690 6 : break;
9691 :
9692 2616 : case T_RelabelType:
9693 : {
9694 2616 : RelabelType *relabel = (RelabelType *) node;
9695 2616 : Node *arg = (Node *) relabel->arg;
9696 :
9697 2616 : if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
9698 2416 : !showimplicit)
9699 : {
9700 : /* don't show the implicit cast */
9701 74 : get_rule_expr_paren(arg, context, false, node);
9702 : }
9703 : else
9704 : {
9705 2542 : get_coercion_expr(arg, context,
9706 : relabel->resulttype,
9707 : relabel->resulttypmod,
9708 : node);
9709 : }
9710 : }
9711 2616 : break;
9712 :
9713 668 : case T_CoerceViaIO:
9714 : {
9715 668 : CoerceViaIO *iocoerce = (CoerceViaIO *) node;
9716 668 : Node *arg = (Node *) iocoerce->arg;
9717 :
9718 668 : if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9719 24 : !showimplicit)
9720 : {
9721 : /* don't show the implicit cast */
9722 24 : get_rule_expr_paren(arg, context, false, node);
9723 : }
9724 : else
9725 : {
9726 644 : get_coercion_expr(arg, context,
9727 : iocoerce->resulttype,
9728 : -1,
9729 : node);
9730 : }
9731 : }
9732 668 : break;
9733 :
9734 52 : case T_ArrayCoerceExpr:
9735 : {
9736 52 : ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
9737 52 : Node *arg = (Node *) acoerce->arg;
9738 :
9739 52 : if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
9740 52 : !showimplicit)
9741 : {
9742 : /* don't show the implicit cast */
9743 0 : get_rule_expr_paren(arg, context, false, node);
9744 : }
9745 : else
9746 : {
9747 52 : get_coercion_expr(arg, context,
9748 : acoerce->resulttype,
9749 : acoerce->resulttypmod,
9750 : node);
9751 : }
9752 : }
9753 52 : break;
9754 :
9755 88 : case T_ConvertRowtypeExpr:
9756 : {
9757 88 : ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
9758 88 : Node *arg = (Node *) convert->arg;
9759 :
9760 88 : if (convert->convertformat == COERCE_IMPLICIT_CAST &&
9761 82 : !showimplicit)
9762 : {
9763 : /* don't show the implicit cast */
9764 24 : get_rule_expr_paren(arg, context, false, node);
9765 : }
9766 : else
9767 : {
9768 64 : get_coercion_expr(arg, context,
9769 : convert->resulttype, -1,
9770 : node);
9771 : }
9772 : }
9773 88 : break;
9774 :
9775 90 : case T_CollateExpr:
9776 : {
9777 90 : CollateExpr *collate = (CollateExpr *) node;
9778 90 : Node *arg = (Node *) collate->arg;
9779 :
9780 90 : if (!PRETTY_PAREN(context))
9781 84 : appendStringInfoChar(buf, '(');
9782 90 : get_rule_expr_paren(arg, context, showimplicit, node);
9783 90 : appendStringInfo(buf, " COLLATE %s",
9784 : generate_collation_name(collate->collOid));
9785 90 : if (!PRETTY_PAREN(context))
9786 84 : appendStringInfoChar(buf, ')');
9787 : }
9788 90 : break;
9789 :
9790 606 : case T_CaseExpr:
9791 : {
9792 606 : CaseExpr *caseexpr = (CaseExpr *) node;
9793 : ListCell *temp;
9794 :
9795 606 : appendContextKeyword(context, "CASE",
9796 : 0, PRETTYINDENT_VAR, 0);
9797 606 : if (caseexpr->arg)
9798 : {
9799 186 : appendStringInfoChar(buf, ' ');
9800 186 : get_rule_expr((Node *) caseexpr->arg, context, true);
9801 : }
9802 2662 : foreach(temp, caseexpr->args)
9803 : {
9804 2056 : CaseWhen *when = (CaseWhen *) lfirst(temp);
9805 2056 : Node *w = (Node *) when->expr;
9806 :
9807 2056 : if (caseexpr->arg)
9808 : {
9809 : /*
9810 : * The parser should have produced WHEN clauses of the
9811 : * form "CaseTestExpr = RHS", possibly with an
9812 : * implicit coercion inserted above the CaseTestExpr.
9813 : * For accurate decompilation of rules it's essential
9814 : * that we show just the RHS. However in an
9815 : * expression that's been through the optimizer, the
9816 : * WHEN clause could be almost anything (since the
9817 : * equality operator could have been expanded into an
9818 : * inline function). If we don't recognize the form
9819 : * of the WHEN clause, just punt and display it as-is.
9820 : */
9821 772 : if (IsA(w, OpExpr))
9822 : {
9823 772 : List *args = ((OpExpr *) w)->args;
9824 :
9825 772 : if (list_length(args) == 2 &&
9826 772 : IsA(strip_implicit_coercions(linitial(args)),
9827 : CaseTestExpr))
9828 772 : w = (Node *) lsecond(args);
9829 : }
9830 : }
9831 :
9832 2056 : if (!PRETTY_INDENT(context))
9833 118 : appendStringInfoChar(buf, ' ');
9834 2056 : appendContextKeyword(context, "WHEN ",
9835 : 0, 0, 0);
9836 2056 : get_rule_expr(w, context, false);
9837 2056 : appendStringInfoString(buf, " THEN ");
9838 2056 : get_rule_expr((Node *) when->result, context, true);
9839 : }
9840 606 : if (!PRETTY_INDENT(context))
9841 108 : appendStringInfoChar(buf, ' ');
9842 606 : appendContextKeyword(context, "ELSE ",
9843 : 0, 0, 0);
9844 606 : get_rule_expr((Node *) caseexpr->defresult, context, true);
9845 606 : if (!PRETTY_INDENT(context))
9846 108 : appendStringInfoChar(buf, ' ');
9847 606 : appendContextKeyword(context, "END",
9848 : -PRETTYINDENT_VAR, 0, 0);
9849 : }
9850 606 : break;
9851 :
9852 0 : case T_CaseTestExpr:
9853 : {
9854 : /*
9855 : * Normally we should never get here, since for expressions
9856 : * that can contain this node type we attempt to avoid
9857 : * recursing to it. But in an optimized expression we might
9858 : * be unable to avoid that (see comments for CaseExpr). If we
9859 : * do see one, print it as CASE_TEST_EXPR.
9860 : */
9861 0 : appendStringInfoString(buf, "CASE_TEST_EXPR");
9862 : }
9863 0 : break;
9864 :
9865 560 : case T_ArrayExpr:
9866 : {
9867 560 : ArrayExpr *arrayexpr = (ArrayExpr *) node;
9868 :
9869 560 : appendStringInfoString(buf, "ARRAY[");
9870 560 : get_rule_expr((Node *) arrayexpr->elements, context, true);
9871 560 : appendStringInfoChar(buf, ']');
9872 :
9873 : /*
9874 : * If the array isn't empty, we assume its elements are
9875 : * coerced to the desired type. If it's empty, though, we
9876 : * need an explicit coercion to the array type.
9877 : */
9878 560 : if (arrayexpr->elements == NIL)
9879 6 : appendStringInfo(buf, "::%s",
9880 : format_type_with_typemod(arrayexpr->array_typeid, -1));
9881 : }
9882 560 : break;
9883 :
9884 192 : case T_RowExpr:
9885 : {
9886 192 : RowExpr *rowexpr = (RowExpr *) node;
9887 192 : TupleDesc tupdesc = NULL;
9888 : ListCell *arg;
9889 : int i;
9890 : char *sep;
9891 :
9892 : /*
9893 : * If it's a named type and not RECORD, we may have to skip
9894 : * dropped columns and/or claim there are NULLs for added
9895 : * columns.
9896 : */
9897 192 : if (rowexpr->row_typeid != RECORDOID)
9898 : {
9899 54 : tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9900 : Assert(list_length(rowexpr->args) <= tupdesc->natts);
9901 : }
9902 :
9903 : /*
9904 : * SQL99 allows "ROW" to be omitted when there is more than
9905 : * one column, but for simplicity we always print it.
9906 : */
9907 192 : appendStringInfoString(buf, "ROW(");
9908 192 : sep = "";
9909 192 : i = 0;
9910 570 : foreach(arg, rowexpr->args)
9911 : {
9912 378 : Node *e = (Node *) lfirst(arg);
9913 :
9914 378 : if (tupdesc == NULL ||
9915 120 : !TupleDescAttr(tupdesc, i)->attisdropped)
9916 : {
9917 378 : appendStringInfoString(buf, sep);
9918 : /* Whole-row Vars need special treatment here */
9919 378 : get_rule_expr_toplevel(e, context, true);
9920 378 : sep = ", ";
9921 : }
9922 378 : i++;
9923 : }
9924 192 : if (tupdesc != NULL)
9925 : {
9926 54 : while (i < tupdesc->natts)
9927 : {
9928 0 : if (!TupleDescAttr(tupdesc, i)->attisdropped)
9929 : {
9930 0 : appendStringInfoString(buf, sep);
9931 0 : appendStringInfoString(buf, "NULL");
9932 0 : sep = ", ";
9933 : }
9934 0 : i++;
9935 : }
9936 :
9937 54 : ReleaseTupleDesc(tupdesc);
9938 : }
9939 192 : appendStringInfoChar(buf, ')');
9940 192 : if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9941 36 : appendStringInfo(buf, "::%s",
9942 : format_type_with_typemod(rowexpr->row_typeid, -1));
9943 : }
9944 192 : break;
9945 :
9946 114 : case T_RowCompareExpr:
9947 : {
9948 114 : RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9949 :
9950 : /*
9951 : * SQL99 allows "ROW" to be omitted when there is more than
9952 : * one column, but for simplicity we always print it. Within
9953 : * a ROW expression, whole-row Vars need special treatment, so
9954 : * use get_rule_list_toplevel.
9955 : */
9956 114 : appendStringInfoString(buf, "(ROW(");
9957 114 : get_rule_list_toplevel(rcexpr->largs, context, true);
9958 :
9959 : /*
9960 : * We assume that the name of the first-column operator will
9961 : * do for all the rest too. This is definitely open to
9962 : * failure, eg if some but not all operators were renamed
9963 : * since the construct was parsed, but there seems no way to
9964 : * be perfect.
9965 : */
9966 114 : appendStringInfo(buf, ") %s ROW(",
9967 114 : generate_operator_name(linitial_oid(rcexpr->opnos),
9968 114 : exprType(linitial(rcexpr->largs)),
9969 114 : exprType(linitial(rcexpr->rargs))));
9970 114 : get_rule_list_toplevel(rcexpr->rargs, context, true);
9971 114 : appendStringInfoString(buf, "))");
9972 : }
9973 114 : break;
9974 :
9975 1200 : case T_CoalesceExpr:
9976 : {
9977 1200 : CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
9978 :
9979 1200 : appendStringInfoString(buf, "COALESCE(");
9980 1200 : get_rule_expr((Node *) coalesceexpr->args, context, true);
9981 1200 : appendStringInfoChar(buf, ')');
9982 : }
9983 1200 : break;
9984 :
9985 36 : case T_MinMaxExpr:
9986 : {
9987 36 : MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9988 :
9989 36 : switch (minmaxexpr->op)
9990 : {
9991 6 : case IS_GREATEST:
9992 6 : appendStringInfoString(buf, "GREATEST(");
9993 6 : break;
9994 30 : case IS_LEAST:
9995 30 : appendStringInfoString(buf, "LEAST(");
9996 30 : break;
9997 : }
9998 36 : get_rule_expr((Node *) minmaxexpr->args, context, true);
9999 36 : appendStringInfoChar(buf, ')');
10000 : }
10001 36 : break;
10002 :
10003 716 : case T_SQLValueFunction:
10004 : {
10005 716 : SQLValueFunction *svf = (SQLValueFunction *) node;
10006 :
10007 : /*
10008 : * Note: this code knows that typmod for time, timestamp, and
10009 : * timestamptz just prints as integer.
10010 : */
10011 716 : switch (svf->op)
10012 : {
10013 104 : case SVFOP_CURRENT_DATE:
10014 104 : appendStringInfoString(buf, "CURRENT_DATE");
10015 104 : break;
10016 12 : case SVFOP_CURRENT_TIME:
10017 12 : appendStringInfoString(buf, "CURRENT_TIME");
10018 12 : break;
10019 12 : case SVFOP_CURRENT_TIME_N:
10020 12 : appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
10021 12 : break;
10022 12 : case SVFOP_CURRENT_TIMESTAMP:
10023 12 : appendStringInfoString(buf, "CURRENT_TIMESTAMP");
10024 12 : break;
10025 126 : case SVFOP_CURRENT_TIMESTAMP_N:
10026 126 : appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
10027 : svf->typmod);
10028 126 : break;
10029 12 : case SVFOP_LOCALTIME:
10030 12 : appendStringInfoString(buf, "LOCALTIME");
10031 12 : break;
10032 12 : case SVFOP_LOCALTIME_N:
10033 12 : appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
10034 12 : break;
10035 30 : case SVFOP_LOCALTIMESTAMP:
10036 30 : appendStringInfoString(buf, "LOCALTIMESTAMP");
10037 30 : break;
10038 18 : case SVFOP_LOCALTIMESTAMP_N:
10039 18 : appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
10040 : svf->typmod);
10041 18 : break;
10042 12 : case SVFOP_CURRENT_ROLE:
10043 12 : appendStringInfoString(buf, "CURRENT_ROLE");
10044 12 : break;
10045 296 : case SVFOP_CURRENT_USER:
10046 296 : appendStringInfoString(buf, "CURRENT_USER");
10047 296 : break;
10048 12 : case SVFOP_USER:
10049 12 : appendStringInfoString(buf, "USER");
10050 12 : break;
10051 34 : case SVFOP_SESSION_USER:
10052 34 : appendStringInfoString(buf, "SESSION_USER");
10053 34 : break;
10054 12 : case SVFOP_CURRENT_CATALOG:
10055 12 : appendStringInfoString(buf, "CURRENT_CATALOG");
10056 12 : break;
10057 12 : case SVFOP_CURRENT_SCHEMA:
10058 12 : appendStringInfoString(buf, "CURRENT_SCHEMA");
10059 12 : break;
10060 : }
10061 : }
10062 716 : break;
10063 :
10064 176 : case T_XmlExpr:
10065 : {
10066 176 : XmlExpr *xexpr = (XmlExpr *) node;
10067 176 : bool needcomma = false;
10068 : ListCell *arg;
10069 : ListCell *narg;
10070 : Const *con;
10071 :
10072 176 : switch (xexpr->op)
10073 : {
10074 16 : case IS_XMLCONCAT:
10075 16 : appendStringInfoString(buf, "XMLCONCAT(");
10076 16 : break;
10077 32 : case IS_XMLELEMENT:
10078 32 : appendStringInfoString(buf, "XMLELEMENT(");
10079 32 : break;
10080 16 : case IS_XMLFOREST:
10081 16 : appendStringInfoString(buf, "XMLFOREST(");
10082 16 : break;
10083 16 : case IS_XMLPARSE:
10084 16 : appendStringInfoString(buf, "XMLPARSE(");
10085 16 : break;
10086 16 : case IS_XMLPI:
10087 16 : appendStringInfoString(buf, "XMLPI(");
10088 16 : break;
10089 16 : case IS_XMLROOT:
10090 16 : appendStringInfoString(buf, "XMLROOT(");
10091 16 : break;
10092 64 : case IS_XMLSERIALIZE:
10093 64 : appendStringInfoString(buf, "XMLSERIALIZE(");
10094 64 : break;
10095 0 : case IS_DOCUMENT:
10096 0 : break;
10097 : }
10098 176 : if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
10099 : {
10100 80 : if (xexpr->xmloption == XMLOPTION_DOCUMENT)
10101 32 : appendStringInfoString(buf, "DOCUMENT ");
10102 : else
10103 48 : appendStringInfoString(buf, "CONTENT ");
10104 : }
10105 176 : if (xexpr->name)
10106 : {
10107 48 : appendStringInfo(buf, "NAME %s",
10108 48 : quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
10109 48 : needcomma = true;
10110 : }
10111 176 : if (xexpr->named_args)
10112 : {
10113 32 : if (xexpr->op != IS_XMLFOREST)
10114 : {
10115 16 : if (needcomma)
10116 16 : appendStringInfoString(buf, ", ");
10117 16 : appendStringInfoString(buf, "XMLATTRIBUTES(");
10118 16 : needcomma = false;
10119 : }
10120 112 : forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
10121 : {
10122 80 : Node *e = (Node *) lfirst(arg);
10123 80 : char *argname = strVal(lfirst(narg));
10124 :
10125 80 : if (needcomma)
10126 48 : appendStringInfoString(buf, ", ");
10127 80 : get_rule_expr((Node *) e, context, true);
10128 80 : appendStringInfo(buf, " AS %s",
10129 80 : quote_identifier(map_xml_name_to_sql_identifier(argname)));
10130 80 : needcomma = true;
10131 : }
10132 32 : if (xexpr->op != IS_XMLFOREST)
10133 16 : appendStringInfoChar(buf, ')');
10134 : }
10135 176 : if (xexpr->args)
10136 : {
10137 160 : if (needcomma)
10138 48 : appendStringInfoString(buf, ", ");
10139 160 : switch (xexpr->op)
10140 : {
10141 128 : case IS_XMLCONCAT:
10142 : case IS_XMLELEMENT:
10143 : case IS_XMLFOREST:
10144 : case IS_XMLPI:
10145 : case IS_XMLSERIALIZE:
10146 : /* no extra decoration needed */
10147 128 : get_rule_expr((Node *) xexpr->args, context, true);
10148 128 : break;
10149 16 : case IS_XMLPARSE:
10150 : Assert(list_length(xexpr->args) == 2);
10151 :
10152 16 : get_rule_expr((Node *) linitial(xexpr->args),
10153 : context, true);
10154 :
10155 16 : con = lsecond_node(Const, xexpr->args);
10156 : Assert(!con->constisnull);
10157 16 : if (DatumGetBool(con->constvalue))
10158 0 : appendStringInfoString(buf,
10159 : " PRESERVE WHITESPACE");
10160 : else
10161 16 : appendStringInfoString(buf,
10162 : " STRIP WHITESPACE");
10163 16 : break;
10164 16 : case IS_XMLROOT:
10165 : Assert(list_length(xexpr->args) == 3);
10166 :
10167 16 : get_rule_expr((Node *) linitial(xexpr->args),
10168 : context, true);
10169 :
10170 16 : appendStringInfoString(buf, ", VERSION ");
10171 16 : con = (Const *) lsecond(xexpr->args);
10172 16 : if (IsA(con, Const) &&
10173 16 : con->constisnull)
10174 16 : appendStringInfoString(buf, "NO VALUE");
10175 : else
10176 0 : get_rule_expr((Node *) con, context, false);
10177 :
10178 16 : con = lthird_node(Const, xexpr->args);
10179 16 : if (con->constisnull)
10180 : /* suppress STANDALONE NO VALUE */ ;
10181 : else
10182 : {
10183 16 : switch (DatumGetInt32(con->constvalue))
10184 : {
10185 16 : case XML_STANDALONE_YES:
10186 16 : appendStringInfoString(buf,
10187 : ", STANDALONE YES");
10188 16 : break;
10189 0 : case XML_STANDALONE_NO:
10190 0 : appendStringInfoString(buf,
10191 : ", STANDALONE NO");
10192 0 : break;
10193 0 : case XML_STANDALONE_NO_VALUE:
10194 0 : appendStringInfoString(buf,
10195 : ", STANDALONE NO VALUE");
10196 0 : break;
10197 0 : default:
10198 0 : break;
10199 : }
10200 : }
10201 16 : break;
10202 0 : case IS_DOCUMENT:
10203 0 : get_rule_expr_paren((Node *) xexpr->args, context, false, node);
10204 0 : break;
10205 : }
10206 : }
10207 176 : if (xexpr->op == IS_XMLSERIALIZE)
10208 : {
10209 64 : appendStringInfo(buf, " AS %s",
10210 : format_type_with_typemod(xexpr->type,
10211 : xexpr->typmod));
10212 64 : if (xexpr->indent)
10213 16 : appendStringInfoString(buf, " INDENT");
10214 : else
10215 48 : appendStringInfoString(buf, " NO INDENT");
10216 : }
10217 :
10218 176 : if (xexpr->op == IS_DOCUMENT)
10219 0 : appendStringInfoString(buf, " IS DOCUMENT");
10220 : else
10221 176 : appendStringInfoChar(buf, ')');
10222 : }
10223 176 : break;
10224 :
10225 2646 : case T_NullTest:
10226 : {
10227 2646 : NullTest *ntest = (NullTest *) node;
10228 :
10229 2646 : if (!PRETTY_PAREN(context))
10230 2580 : appendStringInfoChar(buf, '(');
10231 2646 : get_rule_expr_paren((Node *) ntest->arg, context, true, node);
10232 :
10233 : /*
10234 : * For scalar inputs, we prefer to print as IS [NOT] NULL,
10235 : * which is shorter and traditional. If it's a rowtype input
10236 : * but we're applying a scalar test, must print IS [NOT]
10237 : * DISTINCT FROM NULL to be semantically correct.
10238 : */
10239 2646 : if (ntest->argisrow ||
10240 2584 : !type_is_rowtype(exprType((Node *) ntest->arg)))
10241 : {
10242 5256 : switch (ntest->nulltesttype)
10243 : {
10244 822 : case IS_NULL:
10245 822 : appendStringInfoString(buf, " IS NULL");
10246 822 : break;
10247 1806 : case IS_NOT_NULL:
10248 1806 : appendStringInfoString(buf, " IS NOT NULL");
10249 1806 : break;
10250 0 : default:
10251 0 : elog(ERROR, "unrecognized nulltesttype: %d",
10252 : (int) ntest->nulltesttype);
10253 : }
10254 : }
10255 : else
10256 : {
10257 18 : switch (ntest->nulltesttype)
10258 : {
10259 6 : case IS_NULL:
10260 6 : appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
10261 6 : break;
10262 12 : case IS_NOT_NULL:
10263 12 : appendStringInfoString(buf, " IS DISTINCT FROM NULL");
10264 12 : break;
10265 0 : default:
10266 0 : elog(ERROR, "unrecognized nulltesttype: %d",
10267 : (int) ntest->nulltesttype);
10268 : }
10269 : }
10270 2646 : if (!PRETTY_PAREN(context))
10271 2580 : appendStringInfoChar(buf, ')');
10272 : }
10273 2646 : break;
10274 :
10275 306 : case T_BooleanTest:
10276 : {
10277 306 : BooleanTest *btest = (BooleanTest *) node;
10278 :
10279 306 : if (!PRETTY_PAREN(context))
10280 306 : appendStringInfoChar(buf, '(');
10281 306 : get_rule_expr_paren((Node *) btest->arg, context, false, node);
10282 306 : switch (btest->booltesttype)
10283 : {
10284 36 : case IS_TRUE:
10285 36 : appendStringInfoString(buf, " IS TRUE");
10286 36 : break;
10287 138 : case IS_NOT_TRUE:
10288 138 : appendStringInfoString(buf, " IS NOT TRUE");
10289 138 : break;
10290 0 : case IS_FALSE:
10291 0 : appendStringInfoString(buf, " IS FALSE");
10292 0 : break;
10293 54 : case IS_NOT_FALSE:
10294 54 : appendStringInfoString(buf, " IS NOT FALSE");
10295 54 : break;
10296 24 : case IS_UNKNOWN:
10297 24 : appendStringInfoString(buf, " IS UNKNOWN");
10298 24 : break;
10299 54 : case IS_NOT_UNKNOWN:
10300 54 : appendStringInfoString(buf, " IS NOT UNKNOWN");
10301 54 : break;
10302 0 : default:
10303 0 : elog(ERROR, "unrecognized booltesttype: %d",
10304 : (int) btest->booltesttype);
10305 : }
10306 306 : if (!PRETTY_PAREN(context))
10307 306 : appendStringInfoChar(buf, ')');
10308 : }
10309 306 : break;
10310 :
10311 98 : case T_CoerceToDomain:
10312 : {
10313 98 : CoerceToDomain *ctest = (CoerceToDomain *) node;
10314 98 : Node *arg = (Node *) ctest->arg;
10315 :
10316 98 : if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
10317 48 : !showimplicit)
10318 : {
10319 : /* don't show the implicit cast */
10320 32 : get_rule_expr(arg, context, false);
10321 : }
10322 : else
10323 : {
10324 66 : get_coercion_expr(arg, context,
10325 : ctest->resulttype,
10326 : ctest->resulttypmod,
10327 : node);
10328 : }
10329 : }
10330 98 : break;
10331 :
10332 462 : case T_CoerceToDomainValue:
10333 462 : appendStringInfoString(buf, "VALUE");
10334 462 : break;
10335 :
10336 76 : case T_SetToDefault:
10337 76 : appendStringInfoString(buf, "DEFAULT");
10338 76 : break;
10339 :
10340 24 : case T_CurrentOfExpr:
10341 : {
10342 24 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
10343 :
10344 24 : if (cexpr->cursor_name)
10345 24 : appendStringInfo(buf, "CURRENT OF %s",
10346 24 : quote_identifier(cexpr->cursor_name));
10347 : else
10348 0 : appendStringInfo(buf, "CURRENT OF $%d",
10349 : cexpr->cursor_param);
10350 : }
10351 24 : break;
10352 :
10353 0 : case T_NextValueExpr:
10354 : {
10355 0 : NextValueExpr *nvexpr = (NextValueExpr *) node;
10356 :
10357 : /*
10358 : * This isn't exactly nextval(), but that seems close enough
10359 : * for EXPLAIN's purposes.
10360 : */
10361 0 : appendStringInfoString(buf, "nextval(");
10362 0 : simple_quote_literal(buf,
10363 0 : generate_relation_name(nvexpr->seqid,
10364 : NIL));
10365 0 : appendStringInfoChar(buf, ')');
10366 : }
10367 0 : break;
10368 :
10369 24 : case T_InferenceElem:
10370 : {
10371 24 : InferenceElem *iexpr = (InferenceElem *) node;
10372 : bool save_varprefix;
10373 : bool need_parens;
10374 :
10375 : /*
10376 : * InferenceElem can only refer to target relation, so a
10377 : * prefix is not useful, and indeed would cause parse errors.
10378 : */
10379 24 : save_varprefix = context->varprefix;
10380 24 : context->varprefix = false;
10381 :
10382 : /*
10383 : * Parenthesize the element unless it's a simple Var or a bare
10384 : * function call. Follows pg_get_indexdef_worker().
10385 : */
10386 24 : need_parens = !IsA(iexpr->expr, Var);
10387 24 : if (IsA(iexpr->expr, FuncExpr) &&
10388 0 : ((FuncExpr *) iexpr->expr)->funcformat ==
10389 : COERCE_EXPLICIT_CALL)
10390 0 : need_parens = false;
10391 :
10392 24 : if (need_parens)
10393 0 : appendStringInfoChar(buf, '(');
10394 24 : get_rule_expr((Node *) iexpr->expr,
10395 : context, false);
10396 24 : if (need_parens)
10397 0 : appendStringInfoChar(buf, ')');
10398 :
10399 24 : context->varprefix = save_varprefix;
10400 :
10401 24 : if (iexpr->infercollid)
10402 12 : appendStringInfo(buf, " COLLATE %s",
10403 : generate_collation_name(iexpr->infercollid));
10404 :
10405 : /* Add the operator class name, if not default */
10406 24 : if (iexpr->inferopclass)
10407 : {
10408 12 : Oid inferopclass = iexpr->inferopclass;
10409 12 : Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
10410 :
10411 12 : get_opclass_name(inferopclass, inferopcinputtype, buf);
10412 : }
10413 : }
10414 24 : break;
10415 :
10416 12 : case T_ReturningExpr:
10417 : {
10418 12 : ReturningExpr *retExpr = (ReturningExpr *) node;
10419 :
10420 : /*
10421 : * We cannot see a ReturningExpr in rule deparsing, only while
10422 : * EXPLAINing a query plan (ReturningExpr nodes are only ever
10423 : * adding during query rewriting). Just display the expression
10424 : * returned (an expanded view column).
10425 : */
10426 12 : get_rule_expr((Node *) retExpr->retexpr, context, showimplicit);
10427 : }
10428 12 : break;
10429 :
10430 4236 : case T_PartitionBoundSpec:
10431 : {
10432 4236 : PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
10433 : ListCell *cell;
10434 : char *sep;
10435 :
10436 4236 : if (spec->is_default)
10437 : {
10438 156 : appendStringInfoString(buf, "DEFAULT");
10439 156 : break;
10440 : }
10441 :
10442 4080 : switch (spec->strategy)
10443 : {
10444 330 : case PARTITION_STRATEGY_HASH:
10445 : Assert(spec->modulus > 0 && spec->remainder >= 0);
10446 : Assert(spec->modulus > spec->remainder);
10447 :
10448 330 : appendStringInfoString(buf, "FOR VALUES");
10449 330 : appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
10450 : spec->modulus, spec->remainder);
10451 330 : break;
10452 :
10453 1404 : case PARTITION_STRATEGY_LIST:
10454 : Assert(spec->listdatums != NIL);
10455 :
10456 1404 : appendStringInfoString(buf, "FOR VALUES IN (");
10457 1404 : sep = "";
10458 3714 : foreach(cell, spec->listdatums)
10459 : {
10460 2310 : Const *val = lfirst_node(Const, cell);
10461 :
10462 2310 : appendStringInfoString(buf, sep);
10463 2310 : get_const_expr(val, context, -1);
10464 2310 : sep = ", ";
10465 : }
10466 :
10467 1404 : appendStringInfoChar(buf, ')');
10468 1404 : break;
10469 :
10470 2346 : case PARTITION_STRATEGY_RANGE:
10471 : Assert(spec->lowerdatums != NIL &&
10472 : spec->upperdatums != NIL &&
10473 : list_length(spec->lowerdatums) ==
10474 : list_length(spec->upperdatums));
10475 :
10476 2346 : appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
10477 : get_range_partbound_string(spec->lowerdatums),
10478 : get_range_partbound_string(spec->upperdatums));
10479 2346 : break;
10480 :
10481 0 : default:
10482 0 : elog(ERROR, "unrecognized partition strategy: %d",
10483 : (int) spec->strategy);
10484 : break;
10485 : }
10486 : }
10487 4080 : break;
10488 :
10489 150 : case T_JsonValueExpr:
10490 : {
10491 150 : JsonValueExpr *jve = (JsonValueExpr *) node;
10492 :
10493 150 : get_rule_expr((Node *) jve->raw_expr, context, false);
10494 150 : get_json_format(jve->format, context->buf);
10495 : }
10496 150 : break;
10497 :
10498 186 : case T_JsonConstructorExpr:
10499 186 : get_json_constructor((JsonConstructorExpr *) node, context, false);
10500 186 : break;
10501 :
10502 60 : case T_JsonIsPredicate:
10503 : {
10504 60 : JsonIsPredicate *pred = (JsonIsPredicate *) node;
10505 :
10506 60 : if (!PRETTY_PAREN(context))
10507 30 : appendStringInfoChar(context->buf, '(');
10508 :
10509 60 : get_rule_expr_paren(pred->expr, context, true, node);
10510 :
10511 60 : appendStringInfoString(context->buf, " IS JSON");
10512 :
10513 : /* TODO: handle FORMAT clause */
10514 :
10515 60 : switch (pred->item_type)
10516 : {
10517 12 : case JS_TYPE_SCALAR:
10518 12 : appendStringInfoString(context->buf, " SCALAR");
10519 12 : break;
10520 12 : case JS_TYPE_ARRAY:
10521 12 : appendStringInfoString(context->buf, " ARRAY");
10522 12 : break;
10523 12 : case JS_TYPE_OBJECT:
10524 12 : appendStringInfoString(context->buf, " OBJECT");
10525 12 : break;
10526 24 : default:
10527 24 : break;
10528 : }
10529 :
10530 60 : if (pred->unique_keys)
10531 12 : appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
10532 :
10533 60 : if (!PRETTY_PAREN(context))
10534 30 : appendStringInfoChar(context->buf, ')');
10535 : }
10536 60 : break;
10537 :
10538 60 : case T_JsonExpr:
10539 : {
10540 60 : JsonExpr *jexpr = (JsonExpr *) node;
10541 :
10542 60 : switch (jexpr->op)
10543 : {
10544 12 : case JSON_EXISTS_OP:
10545 12 : appendStringInfoString(buf, "JSON_EXISTS(");
10546 12 : break;
10547 36 : case JSON_QUERY_OP:
10548 36 : appendStringInfoString(buf, "JSON_QUERY(");
10549 36 : break;
10550 12 : case JSON_VALUE_OP:
10551 12 : appendStringInfoString(buf, "JSON_VALUE(");
10552 12 : break;
10553 0 : default:
10554 0 : elog(ERROR, "unrecognized JsonExpr op: %d",
10555 : (int) jexpr->op);
10556 : }
10557 :
10558 60 : get_rule_expr(jexpr->formatted_expr, context, showimplicit);
10559 :
10560 60 : appendStringInfoString(buf, ", ");
10561 :
10562 60 : get_json_path_spec(jexpr->path_spec, context, showimplicit);
10563 :
10564 60 : if (jexpr->passing_values)
10565 : {
10566 : ListCell *lc1,
10567 : *lc2;
10568 12 : bool needcomma = false;
10569 :
10570 12 : appendStringInfoString(buf, " PASSING ");
10571 :
10572 48 : forboth(lc1, jexpr->passing_names,
10573 : lc2, jexpr->passing_values)
10574 : {
10575 36 : if (needcomma)
10576 24 : appendStringInfoString(buf, ", ");
10577 36 : needcomma = true;
10578 :
10579 36 : get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
10580 36 : appendStringInfo(buf, " AS %s",
10581 36 : quote_identifier(lfirst_node(String, lc1)->sval));
10582 : }
10583 : }
10584 :
10585 60 : if (jexpr->op != JSON_EXISTS_OP ||
10586 12 : jexpr->returning->typid != BOOLOID)
10587 48 : get_json_returning(jexpr->returning, context->buf,
10588 48 : jexpr->op == JSON_QUERY_OP);
10589 :
10590 60 : get_json_expr_options(jexpr, context,
10591 60 : jexpr->op != JSON_EXISTS_OP ?
10592 : JSON_BEHAVIOR_NULL :
10593 : JSON_BEHAVIOR_FALSE);
10594 :
10595 60 : appendStringInfoChar(buf, ')');
10596 : }
10597 60 : break;
10598 :
10599 2670 : case T_List:
10600 : {
10601 : char *sep;
10602 : ListCell *l;
10603 :
10604 2670 : sep = "";
10605 7556 : foreach(l, (List *) node)
10606 : {
10607 4886 : appendStringInfoString(buf, sep);
10608 4886 : get_rule_expr((Node *) lfirst(l), context, showimplicit);
10609 4886 : sep = ", ";
10610 : }
10611 : }
10612 2670 : break;
10613 :
10614 72 : case T_TableFunc:
10615 72 : get_tablefunc((TableFunc *) node, context, showimplicit);
10616 72 : break;
10617 :
10618 0 : default:
10619 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
10620 : break;
10621 : }
10622 : }
10623 :
10624 : /*
10625 : * get_rule_expr_toplevel - Parse back a toplevel expression
10626 : *
10627 : * Same as get_rule_expr(), except that if the expr is just a Var, we pass
10628 : * istoplevel = true not false to get_variable(). This causes whole-row Vars
10629 : * to get printed with decoration that will prevent expansion of "*".
10630 : * We need to use this in contexts such as ROW() and VALUES(), where the
10631 : * parser would expand "foo.*" appearing at top level. (In principle we'd
10632 : * use this in get_target_list() too, but that has additional worries about
10633 : * whether to print AS, so it needs to invoke get_variable() directly anyway.)
10634 : */
10635 : static void
10636 3044 : get_rule_expr_toplevel(Node *node, deparse_context *context,
10637 : bool showimplicit)
10638 : {
10639 3044 : if (node && IsA(node, Var))
10640 1214 : (void) get_variable((Var *) node, 0, true, context);
10641 : else
10642 1830 : get_rule_expr(node, context, showimplicit);
10643 3044 : }
10644 :
10645 : /*
10646 : * get_rule_list_toplevel - Parse back a list of toplevel expressions
10647 : *
10648 : * Apply get_rule_expr_toplevel() to each element of a List.
10649 : *
10650 : * This adds commas between the expressions, but caller is responsible
10651 : * for printing surrounding decoration.
10652 : */
10653 : static void
10654 504 : get_rule_list_toplevel(List *lst, deparse_context *context,
10655 : bool showimplicit)
10656 : {
10657 : const char *sep;
10658 : ListCell *lc;
10659 :
10660 504 : sep = "";
10661 1718 : foreach(lc, lst)
10662 : {
10663 1214 : Node *e = (Node *) lfirst(lc);
10664 :
10665 1214 : appendStringInfoString(context->buf, sep);
10666 1214 : get_rule_expr_toplevel(e, context, showimplicit);
10667 1214 : sep = ", ";
10668 : }
10669 504 : }
10670 :
10671 : /*
10672 : * get_rule_expr_funccall - Parse back a function-call expression
10673 : *
10674 : * Same as get_rule_expr(), except that we guarantee that the output will
10675 : * look like a function call, or like one of the things the grammar treats as
10676 : * equivalent to a function call (see the func_expr_windowless production).
10677 : * This is needed in places where the grammar uses func_expr_windowless and
10678 : * you can't substitute a parenthesized a_expr. If what we have isn't going
10679 : * to look like a function call, wrap it in a dummy CAST() expression, which
10680 : * will satisfy the grammar --- and, indeed, is likely what the user wrote to
10681 : * produce such a thing.
10682 : */
10683 : static void
10684 864 : get_rule_expr_funccall(Node *node, deparse_context *context,
10685 : bool showimplicit)
10686 : {
10687 864 : if (looks_like_function(node))
10688 852 : get_rule_expr(node, context, showimplicit);
10689 : else
10690 : {
10691 12 : StringInfo buf = context->buf;
10692 :
10693 12 : appendStringInfoString(buf, "CAST(");
10694 : /* no point in showing any top-level implicit cast */
10695 12 : get_rule_expr(node, context, false);
10696 12 : appendStringInfo(buf, " AS %s)",
10697 : format_type_with_typemod(exprType(node),
10698 : exprTypmod(node)));
10699 : }
10700 864 : }
10701 :
10702 : /*
10703 : * Helper function to identify node types that satisfy func_expr_windowless.
10704 : * If in doubt, "false" is always a safe answer.
10705 : */
10706 : static bool
10707 2114 : looks_like_function(Node *node)
10708 : {
10709 2114 : if (node == NULL)
10710 0 : return false; /* probably shouldn't happen */
10711 2114 : switch (nodeTag(node))
10712 : {
10713 892 : case T_FuncExpr:
10714 : /* OK, unless it's going to deparse as a cast */
10715 910 : return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
10716 18 : ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
10717 108 : case T_NullIfExpr:
10718 : case T_CoalesceExpr:
10719 : case T_MinMaxExpr:
10720 : case T_SQLValueFunction:
10721 : case T_XmlExpr:
10722 : case T_JsonExpr:
10723 : /* these are all accepted by func_expr_common_subexpr */
10724 108 : return true;
10725 1114 : default:
10726 1114 : break;
10727 : }
10728 1114 : return false;
10729 : }
10730 :
10731 :
10732 : /*
10733 : * get_oper_expr - Parse back an OpExpr node
10734 : */
10735 : static void
10736 60610 : get_oper_expr(OpExpr *expr, deparse_context *context)
10737 : {
10738 60610 : StringInfo buf = context->buf;
10739 60610 : Oid opno = expr->opno;
10740 60610 : List *args = expr->args;
10741 :
10742 60610 : if (!PRETTY_PAREN(context))
10743 58312 : appendStringInfoChar(buf, '(');
10744 60610 : if (list_length(args) == 2)
10745 : {
10746 : /* binary operator */
10747 60580 : Node *arg1 = (Node *) linitial(args);
10748 60580 : Node *arg2 = (Node *) lsecond(args);
10749 :
10750 60580 : get_rule_expr_paren(arg1, context, true, (Node *) expr);
10751 60580 : appendStringInfo(buf, " %s ",
10752 : generate_operator_name(opno,
10753 : exprType(arg1),
10754 : exprType(arg2)));
10755 60580 : get_rule_expr_paren(arg2, context, true, (Node *) expr);
10756 : }
10757 : else
10758 : {
10759 : /* prefix operator */
10760 30 : Node *arg = (Node *) linitial(args);
10761 :
10762 30 : appendStringInfo(buf, "%s ",
10763 : generate_operator_name(opno,
10764 : InvalidOid,
10765 : exprType(arg)));
10766 30 : get_rule_expr_paren(arg, context, true, (Node *) expr);
10767 : }
10768 60610 : if (!PRETTY_PAREN(context))
10769 58312 : appendStringInfoChar(buf, ')');
10770 60610 : }
10771 :
10772 : /*
10773 : * get_func_expr - Parse back a FuncExpr node
10774 : */
10775 : static void
10776 12598 : get_func_expr(FuncExpr *expr, deparse_context *context,
10777 : bool showimplicit)
10778 : {
10779 12598 : StringInfo buf = context->buf;
10780 12598 : Oid funcoid = expr->funcid;
10781 : Oid argtypes[FUNC_MAX_ARGS];
10782 : int nargs;
10783 : List *argnames;
10784 : bool use_variadic;
10785 : ListCell *l;
10786 :
10787 : /*
10788 : * If the function call came from an implicit coercion, then just show the
10789 : * first argument --- unless caller wants to see implicit coercions.
10790 : */
10791 12598 : if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
10792 : {
10793 1386 : get_rule_expr_paren((Node *) linitial(expr->args), context,
10794 : false, (Node *) expr);
10795 3332 : return;
10796 : }
10797 :
10798 : /*
10799 : * If the function call came from a cast, then show the first argument
10800 : * plus an explicit cast operation.
10801 : */
10802 11212 : if (expr->funcformat == COERCE_EXPLICIT_CAST ||
10803 10520 : expr->funcformat == COERCE_IMPLICIT_CAST)
10804 : {
10805 1772 : Node *arg = linitial(expr->args);
10806 1772 : Oid rettype = expr->funcresulttype;
10807 : int32 coercedTypmod;
10808 :
10809 : /* Get the typmod if this is a length-coercion function */
10810 1772 : (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
10811 :
10812 1772 : get_coercion_expr(arg, context,
10813 : rettype, coercedTypmod,
10814 : (Node *) expr);
10815 :
10816 1772 : return;
10817 : }
10818 :
10819 : /*
10820 : * If the function was called using one of the SQL spec's random special
10821 : * syntaxes, try to reproduce that. If we don't recognize the function,
10822 : * fall through.
10823 : */
10824 9440 : if (expr->funcformat == COERCE_SQL_SYNTAX)
10825 : {
10826 180 : if (get_func_sql_syntax(expr, context))
10827 174 : return;
10828 : }
10829 :
10830 : /*
10831 : * Normal function: display as proname(args). First we need to extract
10832 : * the argument datatypes.
10833 : */
10834 9266 : if (list_length(expr->args) > FUNC_MAX_ARGS)
10835 0 : ereport(ERROR,
10836 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10837 : errmsg("too many arguments")));
10838 9266 : nargs = 0;
10839 9266 : argnames = NIL;
10840 19144 : foreach(l, expr->args)
10841 : {
10842 9878 : Node *arg = (Node *) lfirst(l);
10843 :
10844 9878 : if (IsA(arg, NamedArgExpr))
10845 30 : argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10846 9878 : argtypes[nargs] = exprType(arg);
10847 9878 : nargs++;
10848 : }
10849 :
10850 9266 : appendStringInfo(buf, "%s(",
10851 : generate_function_name(funcoid, nargs,
10852 : argnames, argtypes,
10853 9266 : expr->funcvariadic,
10854 : &use_variadic,
10855 9266 : context->inGroupBy));
10856 9266 : nargs = 0;
10857 19144 : foreach(l, expr->args)
10858 : {
10859 9878 : if (nargs++ > 0)
10860 1798 : appendStringInfoString(buf, ", ");
10861 9878 : if (use_variadic && lnext(expr->args, l) == NULL)
10862 12 : appendStringInfoString(buf, "VARIADIC ");
10863 9878 : get_rule_expr((Node *) lfirst(l), context, true);
10864 : }
10865 9266 : appendStringInfoChar(buf, ')');
10866 : }
10867 :
10868 : /*
10869 : * get_agg_expr - Parse back an Aggref node
10870 : */
10871 : static void
10872 1994 : get_agg_expr(Aggref *aggref, deparse_context *context,
10873 : Aggref *original_aggref)
10874 : {
10875 1994 : get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
10876 : false);
10877 1994 : }
10878 :
10879 : /*
10880 : * get_agg_expr_helper - subroutine for get_agg_expr and
10881 : * get_json_agg_constructor
10882 : */
10883 : static void
10884 2048 : get_agg_expr_helper(Aggref *aggref, deparse_context *context,
10885 : Aggref *original_aggref, const char *funcname,
10886 : const char *options, bool is_json_objectagg)
10887 : {
10888 2048 : StringInfo buf = context->buf;
10889 : Oid argtypes[FUNC_MAX_ARGS];
10890 : int nargs;
10891 2048 : bool use_variadic = false;
10892 :
10893 : /*
10894 : * For a combining aggregate, we look up and deparse the corresponding
10895 : * partial aggregate instead. This is necessary because our input
10896 : * argument list has been replaced; the new argument list always has just
10897 : * one element, which will point to a partial Aggref that supplies us with
10898 : * transition states to combine.
10899 : */
10900 2048 : if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
10901 : {
10902 : TargetEntry *tle;
10903 :
10904 : Assert(list_length(aggref->args) == 1);
10905 260 : tle = linitial_node(TargetEntry, aggref->args);
10906 260 : resolve_special_varno((Node *) tle->expr, context,
10907 : get_agg_combine_expr, original_aggref);
10908 260 : return;
10909 : }
10910 :
10911 : /*
10912 : * Mark as PARTIAL, if appropriate. We look to the original aggref so as
10913 : * to avoid printing this when recursing from the code just above.
10914 : */
10915 1788 : if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
10916 60 : appendStringInfoString(buf, "PARTIAL ");
10917 :
10918 : /* Extract the argument types as seen by the parser */
10919 1788 : nargs = get_aggregate_argtypes(aggref, argtypes);
10920 :
10921 1788 : if (!funcname)
10922 1734 : funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
10923 1734 : argtypes, aggref->aggvariadic,
10924 : &use_variadic,
10925 1734 : context->inGroupBy);
10926 :
10927 : /* Print the aggregate name, schema-qualified if needed */
10928 1788 : appendStringInfo(buf, "%s(%s", funcname,
10929 1788 : (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
10930 :
10931 1788 : if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
10932 : {
10933 : /*
10934 : * Ordered-set aggregates do not use "*" syntax. Also, we needn't
10935 : * worry about inserting VARIADIC. So we can just dump the direct
10936 : * args as-is.
10937 : */
10938 : Assert(!aggref->aggvariadic);
10939 28 : get_rule_expr((Node *) aggref->aggdirectargs, context, true);
10940 : Assert(aggref->aggorder != NIL);
10941 28 : appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
10942 28 : get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10943 : }
10944 : else
10945 : {
10946 : /* aggstar can be set only in zero-argument aggregates */
10947 1760 : if (aggref->aggstar)
10948 280 : appendStringInfoChar(buf, '*');
10949 : else
10950 : {
10951 : ListCell *l;
10952 : int i;
10953 :
10954 1480 : i = 0;
10955 3148 : foreach(l, aggref->args)
10956 : {
10957 1668 : TargetEntry *tle = (TargetEntry *) lfirst(l);
10958 1668 : Node *arg = (Node *) tle->expr;
10959 :
10960 : Assert(!IsA(arg, NamedArgExpr));
10961 1668 : if (tle->resjunk)
10962 50 : continue;
10963 1618 : if (i++ > 0)
10964 : {
10965 138 : if (is_json_objectagg)
10966 : {
10967 : /*
10968 : * the ABSENT ON NULL and WITH UNIQUE args are printed
10969 : * separately, so ignore them here
10970 : */
10971 30 : if (i > 2)
10972 0 : break;
10973 :
10974 30 : appendStringInfoString(buf, " : ");
10975 : }
10976 : else
10977 108 : appendStringInfoString(buf, ", ");
10978 : }
10979 1618 : if (use_variadic && i == nargs)
10980 8 : appendStringInfoString(buf, "VARIADIC ");
10981 1618 : get_rule_expr(arg, context, true);
10982 : }
10983 : }
10984 :
10985 1760 : if (aggref->aggorder != NIL)
10986 : {
10987 82 : appendStringInfoString(buf, " ORDER BY ");
10988 82 : get_rule_orderby(aggref->aggorder, aggref->args, false, context);
10989 : }
10990 : }
10991 :
10992 1788 : if (options)
10993 54 : appendStringInfoString(buf, options);
10994 :
10995 1788 : if (aggref->aggfilter != NULL)
10996 : {
10997 46 : appendStringInfoString(buf, ") FILTER (WHERE ");
10998 46 : get_rule_expr((Node *) aggref->aggfilter, context, false);
10999 : }
11000 :
11001 1788 : appendStringInfoChar(buf, ')');
11002 : }
11003 :
11004 : /*
11005 : * This is a helper function for get_agg_expr(). It's used when we deparse
11006 : * a combining Aggref; resolve_special_varno locates the corresponding partial
11007 : * Aggref and then calls this.
11008 : */
11009 : static void
11010 260 : get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
11011 : {
11012 : Aggref *aggref;
11013 260 : Aggref *original_aggref = callback_arg;
11014 :
11015 260 : if (!IsA(node, Aggref))
11016 0 : elog(ERROR, "combining Aggref does not point to an Aggref");
11017 :
11018 260 : aggref = (Aggref *) node;
11019 260 : get_agg_expr(aggref, context, original_aggref);
11020 260 : }
11021 :
11022 : /*
11023 : * get_windowfunc_expr - Parse back a WindowFunc node
11024 : */
11025 : static void
11026 306 : get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
11027 : {
11028 306 : get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
11029 306 : }
11030 :
11031 :
11032 : /*
11033 : * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
11034 : * get_json_agg_constructor
11035 : */
11036 : static void
11037 318 : get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
11038 : const char *funcname, const char *options,
11039 : bool is_json_objectagg)
11040 : {
11041 318 : StringInfo buf = context->buf;
11042 : Oid argtypes[FUNC_MAX_ARGS];
11043 : int nargs;
11044 : List *argnames;
11045 : ListCell *l;
11046 :
11047 318 : if (list_length(wfunc->args) > FUNC_MAX_ARGS)
11048 0 : ereport(ERROR,
11049 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
11050 : errmsg("too many arguments")));
11051 318 : nargs = 0;
11052 318 : argnames = NIL;
11053 534 : foreach(l, wfunc->args)
11054 : {
11055 216 : Node *arg = (Node *) lfirst(l);
11056 :
11057 216 : if (IsA(arg, NamedArgExpr))
11058 0 : argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
11059 216 : argtypes[nargs] = exprType(arg);
11060 216 : nargs++;
11061 : }
11062 :
11063 318 : if (!funcname)
11064 306 : funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
11065 : argtypes, false, NULL,
11066 306 : context->inGroupBy);
11067 :
11068 318 : appendStringInfo(buf, "%s(", funcname);
11069 :
11070 : /* winstar can be set only in zero-argument aggregates */
11071 318 : if (wfunc->winstar)
11072 24 : appendStringInfoChar(buf, '*');
11073 : else
11074 : {
11075 294 : if (is_json_objectagg)
11076 : {
11077 6 : get_rule_expr((Node *) linitial(wfunc->args), context, false);
11078 6 : appendStringInfoString(buf, " : ");
11079 6 : get_rule_expr((Node *) lsecond(wfunc->args), context, false);
11080 : }
11081 : else
11082 288 : get_rule_expr((Node *) wfunc->args, context, true);
11083 : }
11084 :
11085 318 : if (options)
11086 12 : appendStringInfoString(buf, options);
11087 :
11088 318 : if (wfunc->aggfilter != NULL)
11089 : {
11090 0 : appendStringInfoString(buf, ") FILTER (WHERE ");
11091 0 : get_rule_expr((Node *) wfunc->aggfilter, context, false);
11092 : }
11093 :
11094 318 : appendStringInfoString(buf, ") OVER ");
11095 :
11096 318 : if (context->windowClause)
11097 : {
11098 : /* Query-decompilation case: search the windowClause list */
11099 42 : foreach(l, context->windowClause)
11100 : {
11101 42 : WindowClause *wc = (WindowClause *) lfirst(l);
11102 :
11103 42 : if (wc->winref == wfunc->winref)
11104 : {
11105 42 : if (wc->name)
11106 0 : appendStringInfoString(buf, quote_identifier(wc->name));
11107 : else
11108 42 : get_rule_windowspec(wc, context->targetList, context);
11109 42 : break;
11110 : }
11111 : }
11112 42 : if (l == NULL)
11113 0 : elog(ERROR, "could not find window clause for winref %u",
11114 : wfunc->winref);
11115 : }
11116 : else
11117 : {
11118 : /*
11119 : * In EXPLAIN, search the namespace stack for a matching WindowAgg
11120 : * node (probably it's always the first entry), and print winname.
11121 : */
11122 276 : foreach(l, context->namespaces)
11123 : {
11124 276 : deparse_namespace *dpns = (deparse_namespace *) lfirst(l);
11125 :
11126 276 : if (dpns->plan && IsA(dpns->plan, WindowAgg))
11127 : {
11128 276 : WindowAgg *wagg = (WindowAgg *) dpns->plan;
11129 :
11130 276 : if (wagg->winref == wfunc->winref)
11131 : {
11132 276 : appendStringInfoString(buf, quote_identifier(wagg->winname));
11133 276 : break;
11134 : }
11135 : }
11136 : }
11137 276 : if (l == NULL)
11138 0 : elog(ERROR, "could not find window clause for winref %u",
11139 : wfunc->winref);
11140 : }
11141 318 : }
11142 :
11143 : /*
11144 : * get_func_sql_syntax - Parse back a SQL-syntax function call
11145 : *
11146 : * Returns true if we successfully deparsed, false if we did not
11147 : * recognize the function.
11148 : */
11149 : static bool
11150 180 : get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
11151 : {
11152 180 : StringInfo buf = context->buf;
11153 180 : Oid funcoid = expr->funcid;
11154 :
11155 180 : switch (funcoid)
11156 : {
11157 24 : case F_TIMEZONE_INTERVAL_TIMESTAMP:
11158 : case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
11159 : case F_TIMEZONE_INTERVAL_TIMETZ:
11160 : case F_TIMEZONE_TEXT_TIMESTAMP:
11161 : case F_TIMEZONE_TEXT_TIMESTAMPTZ:
11162 : case F_TIMEZONE_TEXT_TIMETZ:
11163 : /* AT TIME ZONE ... note reversed argument order */
11164 24 : appendStringInfoChar(buf, '(');
11165 24 : get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
11166 : (Node *) expr);
11167 24 : appendStringInfoString(buf, " AT TIME ZONE ");
11168 24 : get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11169 : (Node *) expr);
11170 24 : appendStringInfoChar(buf, ')');
11171 24 : return true;
11172 :
11173 18 : case F_TIMEZONE_TIMESTAMP:
11174 : case F_TIMEZONE_TIMESTAMPTZ:
11175 : case F_TIMEZONE_TIMETZ:
11176 : /* AT LOCAL */
11177 18 : appendStringInfoChar(buf, '(');
11178 18 : get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11179 : (Node *) expr);
11180 18 : appendStringInfoString(buf, " AT LOCAL)");
11181 18 : return true;
11182 :
11183 6 : case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
11184 : case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
11185 : case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
11186 : case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
11187 : case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
11188 : case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
11189 : case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
11190 : case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
11191 : case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
11192 : case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
11193 : case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
11194 : case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
11195 : case F_OVERLAPS_TIME_TIME_TIME_TIME:
11196 : /* (x1, x2) OVERLAPS (y1, y2) */
11197 6 : appendStringInfoString(buf, "((");
11198 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
11199 6 : appendStringInfoString(buf, ", ");
11200 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11201 6 : appendStringInfoString(buf, ") OVERLAPS (");
11202 6 : get_rule_expr((Node *) lthird(expr->args), context, false);
11203 6 : appendStringInfoString(buf, ", ");
11204 6 : get_rule_expr((Node *) lfourth(expr->args), context, false);
11205 6 : appendStringInfoString(buf, "))");
11206 6 : return true;
11207 :
11208 18 : case F_EXTRACT_TEXT_DATE:
11209 : case F_EXTRACT_TEXT_TIME:
11210 : case F_EXTRACT_TEXT_TIMETZ:
11211 : case F_EXTRACT_TEXT_TIMESTAMP:
11212 : case F_EXTRACT_TEXT_TIMESTAMPTZ:
11213 : case F_EXTRACT_TEXT_INTERVAL:
11214 : /* EXTRACT (x FROM y) */
11215 18 : appendStringInfoString(buf, "EXTRACT(");
11216 : {
11217 18 : Const *con = (Const *) linitial(expr->args);
11218 :
11219 : Assert(IsA(con, Const) &&
11220 : con->consttype == TEXTOID &&
11221 : !con->constisnull);
11222 18 : appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
11223 : }
11224 18 : appendStringInfoString(buf, " FROM ");
11225 18 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11226 18 : appendStringInfoChar(buf, ')');
11227 18 : return true;
11228 :
11229 12 : case F_IS_NORMALIZED:
11230 : /* IS xxx NORMALIZED */
11231 12 : appendStringInfoChar(buf, '(');
11232 12 : get_rule_expr_paren((Node *) linitial(expr->args), context, false,
11233 : (Node *) expr);
11234 12 : appendStringInfoString(buf, " IS");
11235 12 : if (list_length(expr->args) == 2)
11236 : {
11237 6 : Const *con = (Const *) lsecond(expr->args);
11238 :
11239 : Assert(IsA(con, Const) &&
11240 : con->consttype == TEXTOID &&
11241 : !con->constisnull);
11242 6 : appendStringInfo(buf, " %s",
11243 6 : TextDatumGetCString(con->constvalue));
11244 : }
11245 12 : appendStringInfoString(buf, " NORMALIZED)");
11246 12 : return true;
11247 :
11248 6 : case F_PG_COLLATION_FOR:
11249 : /* COLLATION FOR */
11250 6 : appendStringInfoString(buf, "COLLATION FOR (");
11251 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
11252 6 : appendStringInfoChar(buf, ')');
11253 6 : return true;
11254 :
11255 12 : case F_NORMALIZE:
11256 : /* NORMALIZE() */
11257 12 : appendStringInfoString(buf, "NORMALIZE(");
11258 12 : get_rule_expr((Node *) linitial(expr->args), context, false);
11259 12 : if (list_length(expr->args) == 2)
11260 : {
11261 6 : Const *con = (Const *) lsecond(expr->args);
11262 :
11263 : Assert(IsA(con, Const) &&
11264 : con->consttype == TEXTOID &&
11265 : !con->constisnull);
11266 6 : appendStringInfo(buf, ", %s",
11267 6 : TextDatumGetCString(con->constvalue));
11268 : }
11269 12 : appendStringInfoChar(buf, ')');
11270 12 : return true;
11271 :
11272 12 : case F_OVERLAY_BIT_BIT_INT4:
11273 : case F_OVERLAY_BIT_BIT_INT4_INT4:
11274 : case F_OVERLAY_BYTEA_BYTEA_INT4:
11275 : case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
11276 : case F_OVERLAY_TEXT_TEXT_INT4:
11277 : case F_OVERLAY_TEXT_TEXT_INT4_INT4:
11278 : /* OVERLAY() */
11279 12 : appendStringInfoString(buf, "OVERLAY(");
11280 12 : get_rule_expr((Node *) linitial(expr->args), context, false);
11281 12 : appendStringInfoString(buf, " PLACING ");
11282 12 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11283 12 : appendStringInfoString(buf, " FROM ");
11284 12 : get_rule_expr((Node *) lthird(expr->args), context, false);
11285 12 : if (list_length(expr->args) == 4)
11286 : {
11287 6 : appendStringInfoString(buf, " FOR ");
11288 6 : get_rule_expr((Node *) lfourth(expr->args), context, false);
11289 : }
11290 12 : appendStringInfoChar(buf, ')');
11291 12 : return true;
11292 :
11293 6 : case F_POSITION_BIT_BIT:
11294 : case F_POSITION_BYTEA_BYTEA:
11295 : case F_POSITION_TEXT_TEXT:
11296 : /* POSITION() ... extra parens since args are b_expr not a_expr */
11297 6 : appendStringInfoString(buf, "POSITION((");
11298 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11299 6 : appendStringInfoString(buf, ") IN (");
11300 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
11301 6 : appendStringInfoString(buf, "))");
11302 6 : return true;
11303 :
11304 6 : case F_SUBSTRING_BIT_INT4:
11305 : case F_SUBSTRING_BIT_INT4_INT4:
11306 : case F_SUBSTRING_BYTEA_INT4:
11307 : case F_SUBSTRING_BYTEA_INT4_INT4:
11308 : case F_SUBSTRING_TEXT_INT4:
11309 : case F_SUBSTRING_TEXT_INT4_INT4:
11310 : /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
11311 6 : appendStringInfoString(buf, "SUBSTRING(");
11312 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
11313 6 : appendStringInfoString(buf, " FROM ");
11314 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11315 6 : if (list_length(expr->args) == 3)
11316 : {
11317 6 : appendStringInfoString(buf, " FOR ");
11318 6 : get_rule_expr((Node *) lthird(expr->args), context, false);
11319 : }
11320 6 : appendStringInfoChar(buf, ')');
11321 6 : return true;
11322 :
11323 6 : case F_SUBSTRING_TEXT_TEXT_TEXT:
11324 : /* SUBSTRING SIMILAR/ESCAPE */
11325 6 : appendStringInfoString(buf, "SUBSTRING(");
11326 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
11327 6 : appendStringInfoString(buf, " SIMILAR ");
11328 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11329 6 : appendStringInfoString(buf, " ESCAPE ");
11330 6 : get_rule_expr((Node *) lthird(expr->args), context, false);
11331 6 : appendStringInfoChar(buf, ')');
11332 6 : return true;
11333 :
11334 12 : case F_BTRIM_BYTEA_BYTEA:
11335 : case F_BTRIM_TEXT:
11336 : case F_BTRIM_TEXT_TEXT:
11337 : /* TRIM() */
11338 12 : appendStringInfoString(buf, "TRIM(BOTH");
11339 12 : if (list_length(expr->args) == 2)
11340 : {
11341 12 : appendStringInfoChar(buf, ' ');
11342 12 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11343 : }
11344 12 : appendStringInfoString(buf, " FROM ");
11345 12 : get_rule_expr((Node *) linitial(expr->args), context, false);
11346 12 : appendStringInfoChar(buf, ')');
11347 12 : return true;
11348 :
11349 12 : case F_LTRIM_BYTEA_BYTEA:
11350 : case F_LTRIM_TEXT:
11351 : case F_LTRIM_TEXT_TEXT:
11352 : /* TRIM() */
11353 12 : appendStringInfoString(buf, "TRIM(LEADING");
11354 12 : if (list_length(expr->args) == 2)
11355 : {
11356 12 : appendStringInfoChar(buf, ' ');
11357 12 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11358 : }
11359 12 : appendStringInfoString(buf, " FROM ");
11360 12 : get_rule_expr((Node *) linitial(expr->args), context, false);
11361 12 : appendStringInfoChar(buf, ')');
11362 12 : return true;
11363 :
11364 12 : case F_RTRIM_BYTEA_BYTEA:
11365 : case F_RTRIM_TEXT:
11366 : case F_RTRIM_TEXT_TEXT:
11367 : /* TRIM() */
11368 12 : appendStringInfoString(buf, "TRIM(TRAILING");
11369 12 : if (list_length(expr->args) == 2)
11370 : {
11371 6 : appendStringInfoChar(buf, ' ');
11372 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11373 : }
11374 12 : appendStringInfoString(buf, " FROM ");
11375 12 : get_rule_expr((Node *) linitial(expr->args), context, false);
11376 12 : appendStringInfoChar(buf, ')');
11377 12 : return true;
11378 :
11379 12 : case F_SYSTEM_USER:
11380 12 : appendStringInfoString(buf, "SYSTEM_USER");
11381 12 : return true;
11382 :
11383 0 : case F_XMLEXISTS:
11384 : /* XMLEXISTS ... extra parens because args are c_expr */
11385 0 : appendStringInfoString(buf, "XMLEXISTS((");
11386 0 : get_rule_expr((Node *) linitial(expr->args), context, false);
11387 0 : appendStringInfoString(buf, ") PASSING (");
11388 0 : get_rule_expr((Node *) lsecond(expr->args), context, false);
11389 0 : appendStringInfoString(buf, "))");
11390 0 : return true;
11391 : }
11392 6 : return false;
11393 : }
11394 :
11395 : /* ----------
11396 : * get_coercion_expr
11397 : *
11398 : * Make a string representation of a value coerced to a specific type
11399 : * ----------
11400 : */
11401 : static void
11402 5140 : get_coercion_expr(Node *arg, deparse_context *context,
11403 : Oid resulttype, int32 resulttypmod,
11404 : Node *parentNode)
11405 : {
11406 5140 : StringInfo buf = context->buf;
11407 :
11408 : /*
11409 : * Since parse_coerce.c doesn't immediately collapse application of
11410 : * length-coercion functions to constants, what we'll typically see in
11411 : * such cases is a Const with typmod -1 and a length-coercion function
11412 : * right above it. Avoid generating redundant output. However, beware of
11413 : * suppressing casts when the user actually wrote something like
11414 : * 'foo'::text::char(3).
11415 : *
11416 : * Note: it might seem that we are missing the possibility of needing to
11417 : * print a COLLATE clause for such a Const. However, a Const could only
11418 : * have nondefault collation in a post-constant-folding tree, in which the
11419 : * length coercion would have been folded too. See also the special
11420 : * handling of CollateExpr in coerce_to_target_type(): any collation
11421 : * marking will be above the coercion node, not below it.
11422 : */
11423 5140 : if (arg && IsA(arg, Const) &&
11424 606 : ((Const *) arg)->consttype == resulttype &&
11425 24 : ((Const *) arg)->consttypmod == -1)
11426 : {
11427 : /* Show the constant without normal ::typename decoration */
11428 24 : get_const_expr((Const *) arg, context, -1);
11429 : }
11430 : else
11431 : {
11432 5116 : if (!PRETTY_PAREN(context))
11433 4734 : appendStringInfoChar(buf, '(');
11434 5116 : get_rule_expr_paren(arg, context, false, parentNode);
11435 5116 : if (!PRETTY_PAREN(context))
11436 4734 : appendStringInfoChar(buf, ')');
11437 : }
11438 :
11439 : /*
11440 : * Never emit resulttype(arg) functional notation. A pg_proc entry could
11441 : * take precedence, and a resulttype in pg_temp would require schema
11442 : * qualification that format_type_with_typemod() would usually omit. We've
11443 : * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
11444 : * would work fine.
11445 : */
11446 5140 : appendStringInfo(buf, "::%s",
11447 : format_type_with_typemod(resulttype, resulttypmod));
11448 5140 : }
11449 :
11450 : /* ----------
11451 : * get_const_expr
11452 : *
11453 : * Make a string representation of a Const
11454 : *
11455 : * showtype can be -1 to never show "::typename" decoration, or +1 to always
11456 : * show it, or 0 to show it only if the constant wouldn't be assumed to be
11457 : * the right type by default.
11458 : *
11459 : * If the Const's collation isn't default for its type, show that too.
11460 : * We mustn't do this when showtype is -1 (since that means the caller will
11461 : * print "::typename", and we can't put a COLLATE clause in between). It's
11462 : * caller's responsibility that collation isn't missed in such cases.
11463 : * ----------
11464 : */
11465 : static void
11466 70322 : get_const_expr(Const *constval, deparse_context *context, int showtype)
11467 : {
11468 70322 : StringInfo buf = context->buf;
11469 : Oid typoutput;
11470 : bool typIsVarlena;
11471 : char *extval;
11472 70322 : bool needlabel = false;
11473 :
11474 70322 : if (constval->constisnull)
11475 : {
11476 : /*
11477 : * Always label the type of a NULL constant to prevent misdecisions
11478 : * about type when reparsing.
11479 : */
11480 1162 : appendStringInfoString(buf, "NULL");
11481 1162 : if (showtype >= 0)
11482 : {
11483 1108 : appendStringInfo(buf, "::%s",
11484 : format_type_with_typemod(constval->consttype,
11485 : constval->consttypmod));
11486 1108 : get_const_collation(constval, context);
11487 : }
11488 9244 : return;
11489 : }
11490 :
11491 69160 : getTypeOutputInfo(constval->consttype,
11492 : &typoutput, &typIsVarlena);
11493 :
11494 69160 : extval = OidOutputFunctionCall(typoutput, constval->constvalue);
11495 :
11496 69160 : switch (constval->consttype)
11497 : {
11498 39878 : case INT4OID:
11499 :
11500 : /*
11501 : * INT4 can be printed without any decoration, unless it is
11502 : * negative; in that case print it as '-nnn'::integer to ensure
11503 : * that the output will re-parse as a constant, not as a constant
11504 : * plus operator. In most cases we could get away with printing
11505 : * (-nnn) instead, because of the way that gram.y handles negative
11506 : * literals; but that doesn't work for INT_MIN, and it doesn't
11507 : * seem that much prettier anyway.
11508 : */
11509 39878 : if (extval[0] != '-')
11510 39314 : appendStringInfoString(buf, extval);
11511 : else
11512 : {
11513 564 : appendStringInfo(buf, "'%s'", extval);
11514 564 : needlabel = true; /* we must attach a cast */
11515 : }
11516 39878 : break;
11517 :
11518 1084 : case NUMERICOID:
11519 :
11520 : /*
11521 : * NUMERIC can be printed without quotes if it looks like a float
11522 : * constant (not an integer, and not Infinity or NaN) and doesn't
11523 : * have a leading sign (for the same reason as for INT4).
11524 : */
11525 1084 : if (isdigit((unsigned char) extval[0]) &&
11526 1084 : strcspn(extval, "eE.") != strlen(extval))
11527 : {
11528 380 : appendStringInfoString(buf, extval);
11529 : }
11530 : else
11531 : {
11532 704 : appendStringInfo(buf, "'%s'", extval);
11533 704 : needlabel = true; /* we must attach a cast */
11534 : }
11535 1084 : break;
11536 :
11537 1702 : case BOOLOID:
11538 1702 : if (strcmp(extval, "t") == 0)
11539 824 : appendStringInfoString(buf, "true");
11540 : else
11541 878 : appendStringInfoString(buf, "false");
11542 1702 : break;
11543 :
11544 26496 : default:
11545 26496 : simple_quote_literal(buf, extval);
11546 26496 : break;
11547 : }
11548 :
11549 69160 : pfree(extval);
11550 :
11551 69160 : if (showtype < 0)
11552 8082 : return;
11553 :
11554 : /*
11555 : * For showtype == 0, append ::typename unless the constant will be
11556 : * implicitly typed as the right type when it is read in.
11557 : *
11558 : * XXX this code has to be kept in sync with the behavior of the parser,
11559 : * especially make_const.
11560 : */
11561 61078 : switch (constval->consttype)
11562 : {
11563 1770 : case BOOLOID:
11564 : case UNKNOWNOID:
11565 : /* These types can be left unlabeled */
11566 1770 : needlabel = false;
11567 1770 : break;
11568 35376 : case INT4OID:
11569 : /* We determined above whether a label is needed */
11570 35376 : break;
11571 1084 : case NUMERICOID:
11572 :
11573 : /*
11574 : * Float-looking constants will be typed as numeric, which we
11575 : * checked above; but if there's a nondefault typmod we need to
11576 : * show it.
11577 : */
11578 1084 : needlabel |= (constval->consttypmod >= 0);
11579 1084 : break;
11580 22848 : default:
11581 22848 : needlabel = true;
11582 22848 : break;
11583 : }
11584 61078 : if (needlabel || showtype > 0)
11585 24102 : appendStringInfo(buf, "::%s",
11586 : format_type_with_typemod(constval->consttype,
11587 : constval->consttypmod));
11588 :
11589 61078 : get_const_collation(constval, context);
11590 : }
11591 :
11592 : /*
11593 : * helper for get_const_expr: append COLLATE if needed
11594 : */
11595 : static void
11596 62186 : get_const_collation(Const *constval, deparse_context *context)
11597 : {
11598 62186 : StringInfo buf = context->buf;
11599 :
11600 62186 : if (OidIsValid(constval->constcollid))
11601 : {
11602 8878 : Oid typcollation = get_typcollation(constval->consttype);
11603 :
11604 8878 : if (constval->constcollid != typcollation)
11605 : {
11606 74 : appendStringInfo(buf, " COLLATE %s",
11607 : generate_collation_name(constval->constcollid));
11608 : }
11609 : }
11610 62186 : }
11611 :
11612 : /*
11613 : * get_json_path_spec - Parse back a JSON path specification
11614 : */
11615 : static void
11616 456 : get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
11617 : {
11618 456 : if (IsA(path_spec, Const))
11619 456 : get_const_expr((Const *) path_spec, context, -1);
11620 : else
11621 0 : get_rule_expr(path_spec, context, showimplicit);
11622 456 : }
11623 :
11624 : /*
11625 : * get_json_format - Parse back a JsonFormat node
11626 : */
11627 : static void
11628 186 : get_json_format(JsonFormat *format, StringInfo buf)
11629 : {
11630 186 : if (format->format_type == JS_FORMAT_DEFAULT)
11631 108 : return;
11632 :
11633 78 : appendStringInfoString(buf,
11634 78 : format->format_type == JS_FORMAT_JSONB ?
11635 : " FORMAT JSONB" : " FORMAT JSON");
11636 :
11637 78 : if (format->encoding != JS_ENC_DEFAULT)
11638 : {
11639 : const char *encoding;
11640 :
11641 6 : encoding =
11642 12 : format->encoding == JS_ENC_UTF16 ? "UTF16" :
11643 6 : format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
11644 :
11645 6 : appendStringInfo(buf, " ENCODING %s", encoding);
11646 : }
11647 : }
11648 :
11649 : /*
11650 : * get_json_returning - Parse back a JsonReturning structure
11651 : */
11652 : static void
11653 180 : get_json_returning(JsonReturning *returning, StringInfo buf,
11654 : bool json_format_by_default)
11655 : {
11656 180 : if (!OidIsValid(returning->typid))
11657 0 : return;
11658 :
11659 180 : appendStringInfo(buf, " RETURNING %s",
11660 : format_type_with_typemod(returning->typid,
11661 : returning->typmod));
11662 :
11663 348 : if (!json_format_by_default ||
11664 168 : returning->format->format_type !=
11665 168 : (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
11666 36 : get_json_format(returning->format, buf);
11667 : }
11668 :
11669 : /*
11670 : * get_json_constructor - Parse back a JsonConstructorExpr node
11671 : */
11672 : static void
11673 186 : get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
11674 : bool showimplicit)
11675 : {
11676 186 : StringInfo buf = context->buf;
11677 : const char *funcname;
11678 : bool is_json_object;
11679 : int curridx;
11680 : ListCell *lc;
11681 :
11682 186 : if (ctor->type == JSCTOR_JSON_OBJECTAGG)
11683 : {
11684 36 : get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
11685 36 : return;
11686 : }
11687 150 : else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
11688 : {
11689 30 : get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
11690 30 : return;
11691 : }
11692 :
11693 120 : switch (ctor->type)
11694 : {
11695 30 : case JSCTOR_JSON_OBJECT:
11696 30 : funcname = "JSON_OBJECT";
11697 30 : break;
11698 24 : case JSCTOR_JSON_ARRAY:
11699 24 : funcname = "JSON_ARRAY";
11700 24 : break;
11701 42 : case JSCTOR_JSON_PARSE:
11702 42 : funcname = "JSON";
11703 42 : break;
11704 12 : case JSCTOR_JSON_SCALAR:
11705 12 : funcname = "JSON_SCALAR";
11706 12 : break;
11707 12 : case JSCTOR_JSON_SERIALIZE:
11708 12 : funcname = "JSON_SERIALIZE";
11709 12 : break;
11710 0 : default:
11711 0 : elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
11712 : }
11713 :
11714 120 : appendStringInfo(buf, "%s(", funcname);
11715 :
11716 120 : is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
11717 318 : foreach(lc, ctor->args)
11718 : {
11719 198 : curridx = foreach_current_index(lc);
11720 198 : if (curridx > 0)
11721 : {
11722 : const char *sep;
11723 :
11724 78 : sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
11725 78 : appendStringInfoString(buf, sep);
11726 : }
11727 :
11728 198 : get_rule_expr((Node *) lfirst(lc), context, true);
11729 : }
11730 :
11731 120 : get_json_constructor_options(ctor, buf);
11732 120 : appendStringInfoChar(buf, ')');
11733 : }
11734 :
11735 : /*
11736 : * Append options, if any, to the JSON constructor being deparsed
11737 : */
11738 : static void
11739 186 : get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
11740 : {
11741 186 : if (ctor->absent_on_null)
11742 : {
11743 36 : if (ctor->type == JSCTOR_JSON_OBJECT ||
11744 36 : ctor->type == JSCTOR_JSON_OBJECTAGG)
11745 0 : appendStringInfoString(buf, " ABSENT ON NULL");
11746 : }
11747 : else
11748 : {
11749 150 : if (ctor->type == JSCTOR_JSON_ARRAY ||
11750 150 : ctor->type == JSCTOR_JSON_ARRAYAGG)
11751 18 : appendStringInfoString(buf, " NULL ON NULL");
11752 : }
11753 :
11754 186 : if (ctor->unique)
11755 24 : appendStringInfoString(buf, " WITH UNIQUE KEYS");
11756 :
11757 : /*
11758 : * Append RETURNING clause if needed; JSON() and JSON_SCALAR() don't
11759 : * support one.
11760 : */
11761 186 : if (ctor->type != JSCTOR_JSON_PARSE && ctor->type != JSCTOR_JSON_SCALAR)
11762 132 : get_json_returning(ctor->returning, buf, true);
11763 186 : }
11764 :
11765 : /*
11766 : * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
11767 : */
11768 : static void
11769 66 : get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
11770 : const char *funcname, bool is_json_objectagg)
11771 : {
11772 : StringInfoData options;
11773 :
11774 66 : initStringInfo(&options);
11775 66 : get_json_constructor_options(ctor, &options);
11776 :
11777 66 : if (IsA(ctor->func, Aggref))
11778 54 : get_agg_expr_helper((Aggref *) ctor->func, context,
11779 54 : (Aggref *) ctor->func,
11780 54 : funcname, options.data, is_json_objectagg);
11781 12 : else if (IsA(ctor->func, WindowFunc))
11782 12 : get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
11783 12 : funcname, options.data,
11784 : is_json_objectagg);
11785 : else
11786 0 : elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
11787 : nodeTag(ctor->func));
11788 66 : }
11789 :
11790 : /*
11791 : * simple_quote_literal - Format a string as a SQL literal, append to buf
11792 : */
11793 : static void
11794 27332 : simple_quote_literal(StringInfo buf, const char *val)
11795 : {
11796 : const char *valptr;
11797 :
11798 : /*
11799 : * We form the string literal according to the prevailing setting of
11800 : * standard_conforming_strings; we never use E''. User is responsible for
11801 : * making sure result is used correctly.
11802 : */
11803 27332 : appendStringInfoChar(buf, '\'');
11804 281464 : for (valptr = val; *valptr; valptr++)
11805 : {
11806 254132 : char ch = *valptr;
11807 :
11808 254132 : if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
11809 306 : appendStringInfoChar(buf, ch);
11810 254132 : appendStringInfoChar(buf, ch);
11811 : }
11812 27332 : appendStringInfoChar(buf, '\'');
11813 27332 : }
11814 :
11815 :
11816 : /* ----------
11817 : * get_sublink_expr - Parse back a sublink
11818 : * ----------
11819 : */
11820 : static void
11821 460 : get_sublink_expr(SubLink *sublink, deparse_context *context)
11822 : {
11823 460 : StringInfo buf = context->buf;
11824 460 : Query *query = (Query *) (sublink->subselect);
11825 460 : char *opname = NULL;
11826 : bool need_paren;
11827 :
11828 460 : if (sublink->subLinkType == ARRAY_SUBLINK)
11829 24 : appendStringInfoString(buf, "ARRAY(");
11830 : else
11831 436 : appendStringInfoChar(buf, '(');
11832 :
11833 : /*
11834 : * Note that we print the name of only the first operator, when there are
11835 : * multiple combining operators. This is an approximation that could go
11836 : * wrong in various scenarios (operators in different schemas, renamed
11837 : * operators, etc) but there is not a whole lot we can do about it, since
11838 : * the syntax allows only one operator to be shown.
11839 : */
11840 460 : if (sublink->testexpr)
11841 : {
11842 18 : if (IsA(sublink->testexpr, OpExpr))
11843 : {
11844 : /* single combining operator */
11845 6 : OpExpr *opexpr = (OpExpr *) sublink->testexpr;
11846 :
11847 6 : get_rule_expr(linitial(opexpr->args), context, true);
11848 6 : opname = generate_operator_name(opexpr->opno,
11849 6 : exprType(linitial(opexpr->args)),
11850 6 : exprType(lsecond(opexpr->args)));
11851 : }
11852 12 : else if (IsA(sublink->testexpr, BoolExpr))
11853 : {
11854 : /* multiple combining operators, = or <> cases */
11855 : char *sep;
11856 : ListCell *l;
11857 :
11858 6 : appendStringInfoChar(buf, '(');
11859 6 : sep = "";
11860 18 : foreach(l, ((BoolExpr *) sublink->testexpr)->args)
11861 : {
11862 12 : OpExpr *opexpr = lfirst_node(OpExpr, l);
11863 :
11864 12 : appendStringInfoString(buf, sep);
11865 12 : get_rule_expr(linitial(opexpr->args), context, true);
11866 12 : if (!opname)
11867 6 : opname = generate_operator_name(opexpr->opno,
11868 6 : exprType(linitial(opexpr->args)),
11869 6 : exprType(lsecond(opexpr->args)));
11870 12 : sep = ", ";
11871 : }
11872 6 : appendStringInfoChar(buf, ')');
11873 : }
11874 6 : else if (IsA(sublink->testexpr, RowCompareExpr))
11875 : {
11876 : /* multiple combining operators, < <= > >= cases */
11877 6 : RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
11878 :
11879 6 : appendStringInfoChar(buf, '(');
11880 6 : get_rule_expr((Node *) rcexpr->largs, context, true);
11881 6 : opname = generate_operator_name(linitial_oid(rcexpr->opnos),
11882 6 : exprType(linitial(rcexpr->largs)),
11883 6 : exprType(linitial(rcexpr->rargs)));
11884 6 : appendStringInfoChar(buf, ')');
11885 : }
11886 : else
11887 0 : elog(ERROR, "unrecognized testexpr type: %d",
11888 : (int) nodeTag(sublink->testexpr));
11889 : }
11890 :
11891 460 : need_paren = true;
11892 :
11893 460 : switch (sublink->subLinkType)
11894 : {
11895 176 : case EXISTS_SUBLINK:
11896 176 : appendStringInfoString(buf, "EXISTS ");
11897 176 : break;
11898 :
11899 12 : case ANY_SUBLINK:
11900 12 : if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
11901 6 : appendStringInfoString(buf, " IN ");
11902 : else
11903 6 : appendStringInfo(buf, " %s ANY ", opname);
11904 12 : break;
11905 :
11906 6 : case ALL_SUBLINK:
11907 6 : appendStringInfo(buf, " %s ALL ", opname);
11908 6 : break;
11909 :
11910 0 : case ROWCOMPARE_SUBLINK:
11911 0 : appendStringInfo(buf, " %s ", opname);
11912 0 : break;
11913 :
11914 266 : case EXPR_SUBLINK:
11915 : case MULTIEXPR_SUBLINK:
11916 : case ARRAY_SUBLINK:
11917 266 : need_paren = false;
11918 266 : break;
11919 :
11920 0 : case CTE_SUBLINK: /* shouldn't occur in a SubLink */
11921 : default:
11922 0 : elog(ERROR, "unrecognized sublink type: %d",
11923 : (int) sublink->subLinkType);
11924 : break;
11925 : }
11926 :
11927 460 : if (need_paren)
11928 194 : appendStringInfoChar(buf, '(');
11929 :
11930 460 : get_query_def(query, buf, context->namespaces, NULL, false,
11931 : context->prettyFlags, context->wrapColumn,
11932 : context->indentLevel);
11933 :
11934 460 : if (need_paren)
11935 194 : appendStringInfoString(buf, "))");
11936 : else
11937 266 : appendStringInfoChar(buf, ')');
11938 460 : }
11939 :
11940 :
11941 : /* ----------
11942 : * get_xmltable - Parse back a XMLTABLE function
11943 : * ----------
11944 : */
11945 : static void
11946 62 : get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
11947 : {
11948 62 : StringInfo buf = context->buf;
11949 :
11950 62 : appendStringInfoString(buf, "XMLTABLE(");
11951 :
11952 62 : if (tf->ns_uris != NIL)
11953 : {
11954 : ListCell *lc1,
11955 : *lc2;
11956 16 : bool first = true;
11957 :
11958 16 : appendStringInfoString(buf, "XMLNAMESPACES (");
11959 32 : forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
11960 : {
11961 16 : Node *expr = (Node *) lfirst(lc1);
11962 16 : String *ns_node = lfirst_node(String, lc2);
11963 :
11964 16 : if (!first)
11965 0 : appendStringInfoString(buf, ", ");
11966 : else
11967 16 : first = false;
11968 :
11969 16 : if (ns_node != NULL)
11970 : {
11971 16 : get_rule_expr(expr, context, showimplicit);
11972 16 : appendStringInfo(buf, " AS %s",
11973 16 : quote_identifier(strVal(ns_node)));
11974 : }
11975 : else
11976 : {
11977 0 : appendStringInfoString(buf, "DEFAULT ");
11978 0 : get_rule_expr(expr, context, showimplicit);
11979 : }
11980 : }
11981 16 : appendStringInfoString(buf, "), ");
11982 : }
11983 :
11984 62 : appendStringInfoChar(buf, '(');
11985 62 : get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
11986 62 : appendStringInfoString(buf, ") PASSING (");
11987 62 : get_rule_expr((Node *) tf->docexpr, context, showimplicit);
11988 62 : appendStringInfoChar(buf, ')');
11989 :
11990 62 : if (tf->colexprs != NIL)
11991 : {
11992 : ListCell *l1;
11993 : ListCell *l2;
11994 : ListCell *l3;
11995 : ListCell *l4;
11996 : ListCell *l5;
11997 62 : int colnum = 0;
11998 :
11999 62 : appendStringInfoString(buf, " COLUMNS ");
12000 374 : forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
12001 : l4, tf->colexprs, l5, tf->coldefexprs)
12002 : {
12003 312 : char *colname = strVal(lfirst(l1));
12004 312 : Oid typid = lfirst_oid(l2);
12005 312 : int32 typmod = lfirst_int(l3);
12006 312 : Node *colexpr = (Node *) lfirst(l4);
12007 312 : Node *coldefexpr = (Node *) lfirst(l5);
12008 312 : bool ordinality = (tf->ordinalitycol == colnum);
12009 312 : bool notnull = bms_is_member(colnum, tf->notnulls);
12010 :
12011 312 : if (colnum > 0)
12012 250 : appendStringInfoString(buf, ", ");
12013 312 : colnum++;
12014 :
12015 590 : appendStringInfo(buf, "%s %s", quote_identifier(colname),
12016 : ordinality ? "FOR ORDINALITY" :
12017 278 : format_type_with_typemod(typid, typmod));
12018 312 : if (ordinality)
12019 34 : continue;
12020 :
12021 278 : if (coldefexpr != NULL)
12022 : {
12023 34 : appendStringInfoString(buf, " DEFAULT (");
12024 34 : get_rule_expr((Node *) coldefexpr, context, showimplicit);
12025 34 : appendStringInfoChar(buf, ')');
12026 : }
12027 278 : if (colexpr != NULL)
12028 : {
12029 254 : appendStringInfoString(buf, " PATH (");
12030 254 : get_rule_expr((Node *) colexpr, context, showimplicit);
12031 254 : appendStringInfoChar(buf, ')');
12032 : }
12033 278 : if (notnull)
12034 34 : appendStringInfoString(buf, " NOT NULL");
12035 : }
12036 : }
12037 :
12038 62 : appendStringInfoChar(buf, ')');
12039 62 : }
12040 :
12041 : /*
12042 : * get_json_table_nested_columns - Parse back nested JSON_TABLE columns
12043 : */
12044 : static void
12045 102 : get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
12046 : deparse_context *context, bool showimplicit,
12047 : bool needcomma)
12048 : {
12049 102 : if (IsA(plan, JsonTablePathScan))
12050 : {
12051 72 : JsonTablePathScan *scan = castNode(JsonTablePathScan, plan);
12052 :
12053 72 : if (needcomma)
12054 48 : appendStringInfoChar(context->buf, ',');
12055 :
12056 72 : appendStringInfoChar(context->buf, ' ');
12057 72 : appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
12058 72 : get_const_expr(scan->path->value, context, -1);
12059 72 : appendStringInfo(context->buf, " AS %s", quote_identifier(scan->path->name));
12060 72 : get_json_table_columns(tf, scan, context, showimplicit);
12061 : }
12062 30 : else if (IsA(plan, JsonTableSiblingJoin))
12063 : {
12064 30 : JsonTableSiblingJoin *join = (JsonTableSiblingJoin *) plan;
12065 :
12066 30 : get_json_table_nested_columns(tf, join->lplan, context, showimplicit,
12067 : needcomma);
12068 30 : get_json_table_nested_columns(tf, join->rplan, context, showimplicit,
12069 : true);
12070 : }
12071 102 : }
12072 :
12073 : /*
12074 : * get_json_table_columns - Parse back JSON_TABLE columns
12075 : */
12076 : static void
12077 180 : get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan,
12078 : deparse_context *context,
12079 : bool showimplicit)
12080 : {
12081 180 : StringInfo buf = context->buf;
12082 : ListCell *lc_colname;
12083 : ListCell *lc_coltype;
12084 : ListCell *lc_coltypmod;
12085 : ListCell *lc_colvalexpr;
12086 180 : int colnum = 0;
12087 :
12088 180 : appendStringInfoChar(buf, ' ');
12089 180 : appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
12090 :
12091 180 : if (PRETTY_INDENT(context))
12092 138 : context->indentLevel += PRETTYINDENT_VAR;
12093 :
12094 858 : forfour(lc_colname, tf->colnames,
12095 : lc_coltype, tf->coltypes,
12096 : lc_coltypmod, tf->coltypmods,
12097 : lc_colvalexpr, tf->colvalexprs)
12098 : {
12099 726 : char *colname = strVal(lfirst(lc_colname));
12100 : JsonExpr *colexpr;
12101 : Oid typid;
12102 : int32 typmod;
12103 : bool ordinality;
12104 : JsonBehaviorType default_behavior;
12105 :
12106 726 : typid = lfirst_oid(lc_coltype);
12107 726 : typmod = lfirst_int(lc_coltypmod);
12108 726 : colexpr = castNode(JsonExpr, lfirst(lc_colvalexpr));
12109 :
12110 : /* Skip columns that don't belong to this scan. */
12111 726 : if (scan->colMin < 0 || colnum < scan->colMin)
12112 : {
12113 264 : colnum++;
12114 264 : continue;
12115 : }
12116 462 : if (colnum > scan->colMax)
12117 48 : break;
12118 :
12119 414 : if (colnum > scan->colMin)
12120 258 : appendStringInfoString(buf, ", ");
12121 :
12122 414 : colnum++;
12123 :
12124 414 : ordinality = !colexpr;
12125 :
12126 414 : appendContextKeyword(context, "", 0, 0, 0);
12127 :
12128 810 : appendStringInfo(buf, "%s %s", quote_identifier(colname),
12129 : ordinality ? "FOR ORDINALITY" :
12130 396 : format_type_with_typemod(typid, typmod));
12131 414 : if (ordinality)
12132 18 : continue;
12133 :
12134 : /*
12135 : * Set default_behavior to guide get_json_expr_options() on whether to
12136 : * emit the ON ERROR / EMPTY clauses.
12137 : */
12138 396 : if (colexpr->op == JSON_EXISTS_OP)
12139 : {
12140 36 : appendStringInfoString(buf, " EXISTS");
12141 36 : default_behavior = JSON_BEHAVIOR_FALSE;
12142 : }
12143 : else
12144 : {
12145 360 : if (colexpr->op == JSON_QUERY_OP)
12146 : {
12147 : char typcategory;
12148 : bool typispreferred;
12149 :
12150 174 : get_type_category_preferred(typid, &typcategory, &typispreferred);
12151 :
12152 174 : if (typcategory == TYPCATEGORY_STRING)
12153 36 : appendStringInfoString(buf,
12154 36 : colexpr->format->format_type == JS_FORMAT_JSONB ?
12155 : " FORMAT JSONB" : " FORMAT JSON");
12156 : }
12157 :
12158 360 : default_behavior = JSON_BEHAVIOR_NULL;
12159 : }
12160 :
12161 396 : appendStringInfoString(buf, " PATH ");
12162 :
12163 396 : get_json_path_spec(colexpr->path_spec, context, showimplicit);
12164 :
12165 396 : get_json_expr_options(colexpr, context, default_behavior);
12166 : }
12167 :
12168 180 : if (scan->child)
12169 42 : get_json_table_nested_columns(tf, scan->child, context, showimplicit,
12170 42 : scan->colMin >= 0);
12171 :
12172 180 : if (PRETTY_INDENT(context))
12173 138 : context->indentLevel -= PRETTYINDENT_VAR;
12174 :
12175 180 : appendContextKeyword(context, ")", 0, 0, 0);
12176 180 : }
12177 :
12178 : /* ----------
12179 : * get_json_table - Parse back a JSON_TABLE function
12180 : * ----------
12181 : */
12182 : static void
12183 108 : get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
12184 : {
12185 108 : StringInfo buf = context->buf;
12186 108 : JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
12187 108 : JsonTablePathScan *root = castNode(JsonTablePathScan, tf->plan);
12188 :
12189 108 : appendStringInfoString(buf, "JSON_TABLE(");
12190 :
12191 108 : if (PRETTY_INDENT(context))
12192 66 : context->indentLevel += PRETTYINDENT_VAR;
12193 :
12194 108 : appendContextKeyword(context, "", 0, 0, 0);
12195 :
12196 108 : get_rule_expr(jexpr->formatted_expr, context, showimplicit);
12197 :
12198 108 : appendStringInfoString(buf, ", ");
12199 :
12200 108 : get_const_expr(root->path->value, context, -1);
12201 :
12202 108 : appendStringInfo(buf, " AS %s", quote_identifier(root->path->name));
12203 :
12204 108 : if (jexpr->passing_values)
12205 : {
12206 : ListCell *lc1,
12207 : *lc2;
12208 84 : bool needcomma = false;
12209 :
12210 84 : appendStringInfoChar(buf, ' ');
12211 84 : appendContextKeyword(context, "PASSING ", 0, 0, 0);
12212 :
12213 84 : if (PRETTY_INDENT(context))
12214 42 : context->indentLevel += PRETTYINDENT_VAR;
12215 :
12216 252 : forboth(lc1, jexpr->passing_names,
12217 : lc2, jexpr->passing_values)
12218 : {
12219 168 : if (needcomma)
12220 84 : appendStringInfoString(buf, ", ");
12221 168 : needcomma = true;
12222 :
12223 168 : appendContextKeyword(context, "", 0, 0, 0);
12224 :
12225 168 : get_rule_expr((Node *) lfirst(lc2), context, false);
12226 168 : appendStringInfo(buf, " AS %s",
12227 168 : quote_identifier((lfirst_node(String, lc1))->sval)
12228 : );
12229 : }
12230 :
12231 84 : if (PRETTY_INDENT(context))
12232 42 : context->indentLevel -= PRETTYINDENT_VAR;
12233 : }
12234 :
12235 108 : get_json_table_columns(tf, castNode(JsonTablePathScan, tf->plan), context,
12236 : showimplicit);
12237 :
12238 108 : if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY_ARRAY)
12239 6 : get_json_behavior(jexpr->on_error, context, "ERROR");
12240 :
12241 108 : if (PRETTY_INDENT(context))
12242 66 : context->indentLevel -= PRETTYINDENT_VAR;
12243 :
12244 108 : appendContextKeyword(context, ")", 0, 0, 0);
12245 108 : }
12246 :
12247 : /* ----------
12248 : * get_tablefunc - Parse back a table function
12249 : * ----------
12250 : */
12251 : static void
12252 170 : get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
12253 : {
12254 : /* XMLTABLE and JSON_TABLE are the only existing implementations. */
12255 :
12256 170 : if (tf->functype == TFT_XMLTABLE)
12257 62 : get_xmltable(tf, context, showimplicit);
12258 108 : else if (tf->functype == TFT_JSON_TABLE)
12259 108 : get_json_table(tf, context, showimplicit);
12260 170 : }
12261 :
12262 : /* ----------
12263 : * get_from_clause - Parse back a FROM clause
12264 : *
12265 : * "prefix" is the keyword that denotes the start of the list of FROM
12266 : * elements. It is FROM when used to parse back SELECT and UPDATE, but
12267 : * is USING when parsing back DELETE.
12268 : * ----------
12269 : */
12270 : static void
12271 5094 : get_from_clause(Query *query, const char *prefix, deparse_context *context)
12272 : {
12273 5094 : StringInfo buf = context->buf;
12274 5094 : bool first = true;
12275 : ListCell *l;
12276 :
12277 : /*
12278 : * We use the query's jointree as a guide to what to print. However, we
12279 : * must ignore auto-added RTEs that are marked not inFromCl. (These can
12280 : * only appear at the top level of the jointree, so it's sufficient to
12281 : * check here.) This check also ensures we ignore the rule pseudo-RTEs
12282 : * for NEW and OLD.
12283 : */
12284 10110 : foreach(l, query->jointree->fromlist)
12285 : {
12286 5016 : Node *jtnode = (Node *) lfirst(l);
12287 :
12288 5016 : if (IsA(jtnode, RangeTblRef))
12289 : {
12290 4064 : int varno = ((RangeTblRef *) jtnode)->rtindex;
12291 4064 : RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12292 :
12293 4064 : if (!rte->inFromCl)
12294 400 : continue;
12295 : }
12296 :
12297 4616 : if (first)
12298 : {
12299 4270 : appendContextKeyword(context, prefix,
12300 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
12301 4270 : first = false;
12302 :
12303 4270 : get_from_clause_item(jtnode, query, context);
12304 : }
12305 : else
12306 : {
12307 : StringInfoData itembuf;
12308 :
12309 346 : appendStringInfoString(buf, ", ");
12310 :
12311 : /*
12312 : * Put the new FROM item's text into itembuf so we can decide
12313 : * after we've got it whether or not it needs to go on a new line.
12314 : */
12315 346 : initStringInfo(&itembuf);
12316 346 : context->buf = &itembuf;
12317 :
12318 346 : get_from_clause_item(jtnode, query, context);
12319 :
12320 : /* Restore context's output buffer */
12321 346 : context->buf = buf;
12322 :
12323 : /* Consider line-wrapping if enabled */
12324 346 : if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
12325 : {
12326 : /* Does the new item start with a new line? */
12327 346 : if (itembuf.len > 0 && itembuf.data[0] == '\n')
12328 : {
12329 : /* If so, we shouldn't add anything */
12330 : /* instead, remove any trailing spaces currently in buf */
12331 0 : removeStringInfoSpaces(buf);
12332 : }
12333 : else
12334 : {
12335 : char *trailing_nl;
12336 :
12337 : /* Locate the start of the current line in the buffer */
12338 346 : trailing_nl = strrchr(buf->data, '\n');
12339 346 : if (trailing_nl == NULL)
12340 0 : trailing_nl = buf->data;
12341 : else
12342 346 : trailing_nl++;
12343 :
12344 : /*
12345 : * Add a newline, plus some indentation, if the new item
12346 : * would cause an overflow.
12347 : */
12348 346 : if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
12349 346 : appendContextKeyword(context, "", -PRETTYINDENT_STD,
12350 : PRETTYINDENT_STD,
12351 : PRETTYINDENT_VAR);
12352 : }
12353 : }
12354 :
12355 : /* Add the new item */
12356 346 : appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
12357 :
12358 : /* clean up */
12359 346 : pfree(itembuf.data);
12360 : }
12361 : }
12362 5094 : }
12363 :
12364 : static void
12365 7612 : get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
12366 : {
12367 7612 : StringInfo buf = context->buf;
12368 7612 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12369 :
12370 7612 : if (IsA(jtnode, RangeTblRef))
12371 : {
12372 6114 : int varno = ((RangeTblRef *) jtnode)->rtindex;
12373 6114 : RangeTblEntry *rte = rt_fetch(varno, query->rtable);
12374 6114 : deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12375 6114 : RangeTblFunction *rtfunc1 = NULL;
12376 :
12377 6114 : if (rte->lateral)
12378 112 : appendStringInfoString(buf, "LATERAL ");
12379 :
12380 : /* Print the FROM item proper */
12381 6114 : switch (rte->rtekind)
12382 : {
12383 4682 : case RTE_RELATION:
12384 : /* Normal relation RTE */
12385 9364 : appendStringInfo(buf, "%s%s",
12386 4682 : only_marker(rte),
12387 : generate_relation_name(rte->relid,
12388 : context->namespaces));
12389 4682 : break;
12390 292 : case RTE_SUBQUERY:
12391 : /* Subquery RTE */
12392 292 : appendStringInfoChar(buf, '(');
12393 292 : get_query_def(rte->subquery, buf, context->namespaces, NULL,
12394 : true,
12395 : context->prettyFlags, context->wrapColumn,
12396 : context->indentLevel);
12397 292 : appendStringInfoChar(buf, ')');
12398 292 : break;
12399 846 : case RTE_FUNCTION:
12400 : /* Function RTE */
12401 846 : rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
12402 :
12403 : /*
12404 : * Omit ROWS FROM() syntax for just one function, unless it
12405 : * has both a coldeflist and WITH ORDINALITY. If it has both,
12406 : * we must use ROWS FROM() syntax to avoid ambiguity about
12407 : * whether the coldeflist includes the ordinality column.
12408 : */
12409 846 : if (list_length(rte->functions) == 1 &&
12410 816 : (rtfunc1->funccolnames == NIL || !rte->funcordinality))
12411 : {
12412 816 : get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
12413 : /* we'll print the coldeflist below, if it has one */
12414 : }
12415 : else
12416 : {
12417 : bool all_unnest;
12418 : ListCell *lc;
12419 :
12420 : /*
12421 : * If all the function calls in the list are to unnest,
12422 : * and none need a coldeflist, then collapse the list back
12423 : * down to UNNEST(args). (If we had more than one
12424 : * built-in unnest function, this would get more
12425 : * difficult.)
12426 : *
12427 : * XXX This is pretty ugly, since it makes not-terribly-
12428 : * future-proof assumptions about what the parser would do
12429 : * with the output; but the alternative is to emit our
12430 : * nonstandard ROWS FROM() notation for what might have
12431 : * been a perfectly spec-compliant multi-argument
12432 : * UNNEST().
12433 : */
12434 30 : all_unnest = true;
12435 78 : foreach(lc, rte->functions)
12436 : {
12437 66 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12438 :
12439 66 : if (!IsA(rtfunc->funcexpr, FuncExpr) ||
12440 66 : ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
12441 48 : rtfunc->funccolnames != NIL)
12442 : {
12443 18 : all_unnest = false;
12444 18 : break;
12445 : }
12446 : }
12447 :
12448 30 : if (all_unnest)
12449 : {
12450 12 : List *allargs = NIL;
12451 :
12452 48 : foreach(lc, rte->functions)
12453 : {
12454 36 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12455 36 : List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
12456 :
12457 36 : allargs = list_concat(allargs, args);
12458 : }
12459 :
12460 12 : appendStringInfoString(buf, "UNNEST(");
12461 12 : get_rule_expr((Node *) allargs, context, true);
12462 12 : appendStringInfoChar(buf, ')');
12463 : }
12464 : else
12465 : {
12466 18 : int funcno = 0;
12467 :
12468 18 : appendStringInfoString(buf, "ROWS FROM(");
12469 66 : foreach(lc, rte->functions)
12470 : {
12471 48 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
12472 :
12473 48 : if (funcno > 0)
12474 30 : appendStringInfoString(buf, ", ");
12475 48 : get_rule_expr_funccall(rtfunc->funcexpr, context, true);
12476 48 : if (rtfunc->funccolnames != NIL)
12477 : {
12478 : /* Reconstruct the column definition list */
12479 6 : appendStringInfoString(buf, " AS ");
12480 6 : get_from_clause_coldeflist(rtfunc,
12481 : NULL,
12482 : context);
12483 : }
12484 48 : funcno++;
12485 : }
12486 18 : appendStringInfoChar(buf, ')');
12487 : }
12488 : /* prevent printing duplicate coldeflist below */
12489 30 : rtfunc1 = NULL;
12490 : }
12491 846 : if (rte->funcordinality)
12492 18 : appendStringInfoString(buf, " WITH ORDINALITY");
12493 846 : break;
12494 98 : case RTE_TABLEFUNC:
12495 98 : get_tablefunc(rte->tablefunc, context, true);
12496 98 : break;
12497 12 : case RTE_VALUES:
12498 : /* Values list RTE */
12499 12 : appendStringInfoChar(buf, '(');
12500 12 : get_values_def(rte->values_lists, context);
12501 12 : appendStringInfoChar(buf, ')');
12502 12 : break;
12503 184 : case RTE_CTE:
12504 184 : appendStringInfoString(buf, quote_identifier(rte->ctename));
12505 184 : break;
12506 0 : default:
12507 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
12508 : break;
12509 : }
12510 :
12511 : /* Print the relation alias, if needed */
12512 6114 : get_rte_alias(rte, varno, false, context);
12513 :
12514 : /* Print the column definitions or aliases, if needed */
12515 6114 : if (rtfunc1 && rtfunc1->funccolnames != NIL)
12516 : {
12517 : /* Reconstruct the columndef list, which is also the aliases */
12518 0 : get_from_clause_coldeflist(rtfunc1, colinfo, context);
12519 : }
12520 : else
12521 : {
12522 : /* Else print column aliases as needed */
12523 6114 : get_column_alias_list(colinfo, context);
12524 : }
12525 :
12526 : /* Tablesample clause must go after any alias */
12527 6114 : if (rte->rtekind == RTE_RELATION && rte->tablesample)
12528 32 : get_tablesample_def(rte->tablesample, context);
12529 : }
12530 1498 : else if (IsA(jtnode, JoinExpr))
12531 : {
12532 1498 : JoinExpr *j = (JoinExpr *) jtnode;
12533 1498 : deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
12534 : bool need_paren_on_right;
12535 :
12536 3434 : need_paren_on_right = PRETTY_PAREN(context) &&
12537 1498 : !IsA(j->rarg, RangeTblRef) &&
12538 0 : !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
12539 :
12540 1498 : if (!PRETTY_PAREN(context) || j->alias != NULL)
12541 1168 : appendStringInfoChar(buf, '(');
12542 :
12543 1498 : get_from_clause_item(j->larg, query, context);
12544 :
12545 1498 : switch (j->jointype)
12546 : {
12547 820 : case JOIN_INNER:
12548 820 : if (j->quals)
12549 778 : appendContextKeyword(context, " JOIN ",
12550 : -PRETTYINDENT_STD,
12551 : PRETTYINDENT_STD,
12552 : PRETTYINDENT_JOIN);
12553 : else
12554 42 : appendContextKeyword(context, " CROSS JOIN ",
12555 : -PRETTYINDENT_STD,
12556 : PRETTYINDENT_STD,
12557 : PRETTYINDENT_JOIN);
12558 820 : break;
12559 576 : case JOIN_LEFT:
12560 576 : appendContextKeyword(context, " LEFT JOIN ",
12561 : -PRETTYINDENT_STD,
12562 : PRETTYINDENT_STD,
12563 : PRETTYINDENT_JOIN);
12564 576 : break;
12565 102 : case JOIN_FULL:
12566 102 : appendContextKeyword(context, " FULL JOIN ",
12567 : -PRETTYINDENT_STD,
12568 : PRETTYINDENT_STD,
12569 : PRETTYINDENT_JOIN);
12570 102 : break;
12571 0 : case JOIN_RIGHT:
12572 0 : appendContextKeyword(context, " RIGHT JOIN ",
12573 : -PRETTYINDENT_STD,
12574 : PRETTYINDENT_STD,
12575 : PRETTYINDENT_JOIN);
12576 0 : break;
12577 0 : default:
12578 0 : elog(ERROR, "unrecognized join type: %d",
12579 : (int) j->jointype);
12580 : }
12581 :
12582 1498 : if (need_paren_on_right)
12583 0 : appendStringInfoChar(buf, '(');
12584 1498 : get_from_clause_item(j->rarg, query, context);
12585 1498 : if (need_paren_on_right)
12586 0 : appendStringInfoChar(buf, ')');
12587 :
12588 1498 : if (j->usingClause)
12589 : {
12590 : ListCell *lc;
12591 424 : bool first = true;
12592 :
12593 424 : appendStringInfoString(buf, " USING (");
12594 : /* Use the assigned names, not what's in usingClause */
12595 1004 : foreach(lc, colinfo->usingNames)
12596 : {
12597 580 : char *colname = (char *) lfirst(lc);
12598 :
12599 580 : if (first)
12600 424 : first = false;
12601 : else
12602 156 : appendStringInfoString(buf, ", ");
12603 580 : appendStringInfoString(buf, quote_identifier(colname));
12604 : }
12605 424 : appendStringInfoChar(buf, ')');
12606 :
12607 424 : if (j->join_using_alias)
12608 12 : appendStringInfo(buf, " AS %s",
12609 12 : quote_identifier(j->join_using_alias->aliasname));
12610 : }
12611 1074 : else if (j->quals)
12612 : {
12613 1026 : appendStringInfoString(buf, " ON ");
12614 1026 : if (!PRETTY_PAREN(context))
12615 1020 : appendStringInfoChar(buf, '(');
12616 1026 : get_rule_expr(j->quals, context, false);
12617 1026 : if (!PRETTY_PAREN(context))
12618 1020 : appendStringInfoChar(buf, ')');
12619 : }
12620 48 : else if (j->jointype != JOIN_INNER)
12621 : {
12622 : /* If we didn't say CROSS JOIN above, we must provide an ON */
12623 6 : appendStringInfoString(buf, " ON TRUE");
12624 : }
12625 :
12626 1498 : if (!PRETTY_PAREN(context) || j->alias != NULL)
12627 1168 : appendStringInfoChar(buf, ')');
12628 :
12629 : /* Yes, it's correct to put alias after the right paren ... */
12630 1498 : if (j->alias != NULL)
12631 : {
12632 : /*
12633 : * Note that it's correct to emit an alias clause if and only if
12634 : * there was one originally. Otherwise we'd be converting a named
12635 : * join to unnamed or vice versa, which creates semantic
12636 : * subtleties we don't want. However, we might print a different
12637 : * alias name than was there originally.
12638 : */
12639 108 : appendStringInfo(buf, " %s",
12640 108 : quote_identifier(get_rtable_name(j->rtindex,
12641 : context)));
12642 108 : get_column_alias_list(colinfo, context);
12643 : }
12644 : }
12645 : else
12646 0 : elog(ERROR, "unrecognized node type: %d",
12647 : (int) nodeTag(jtnode));
12648 7612 : }
12649 :
12650 : /*
12651 : * get_rte_alias - print the relation's alias, if needed
12652 : *
12653 : * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
12654 : */
12655 : static void
12656 6696 : get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
12657 : deparse_context *context)
12658 : {
12659 6696 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
12660 6696 : char *refname = get_rtable_name(varno, context);
12661 6696 : deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
12662 6696 : bool printalias = false;
12663 :
12664 6696 : if (rte->alias != NULL)
12665 : {
12666 : /* Always print alias if user provided one */
12667 3034 : printalias = true;
12668 : }
12669 3662 : else if (colinfo->printaliases)
12670 : {
12671 : /* Always print alias if we need to print column aliases */
12672 330 : printalias = true;
12673 : }
12674 3332 : else if (rte->rtekind == RTE_RELATION)
12675 : {
12676 : /*
12677 : * No need to print alias if it's same as relation name (this would
12678 : * normally be the case, but not if set_rtable_names had to resolve a
12679 : * conflict).
12680 : */
12681 3060 : if (strcmp(refname, get_relation_name(rte->relid)) != 0)
12682 80 : printalias = true;
12683 : }
12684 272 : else if (rte->rtekind == RTE_FUNCTION)
12685 : {
12686 : /*
12687 : * For a function RTE, always print alias. This covers possible
12688 : * renaming of the function and/or instability of the FigureColname
12689 : * rules for things that aren't simple functions. Note we'd need to
12690 : * force it anyway for the columndef list case.
12691 : */
12692 0 : printalias = true;
12693 : }
12694 272 : else if (rte->rtekind == RTE_SUBQUERY ||
12695 248 : rte->rtekind == RTE_VALUES)
12696 : {
12697 : /*
12698 : * For a subquery, always print alias. This makes the output
12699 : * SQL-spec-compliant, even though we allow such aliases to be omitted
12700 : * on input.
12701 : */
12702 36 : printalias = true;
12703 : }
12704 236 : else if (rte->rtekind == RTE_CTE)
12705 : {
12706 : /*
12707 : * No need to print alias if it's same as CTE name (this would
12708 : * normally be the case, but not if set_rtable_names had to resolve a
12709 : * conflict).
12710 : */
12711 144 : if (strcmp(refname, rte->ctename) != 0)
12712 22 : printalias = true;
12713 : }
12714 :
12715 6696 : if (printalias)
12716 3502 : appendStringInfo(context->buf, "%s%s",
12717 : use_as ? " AS " : " ",
12718 : quote_identifier(refname));
12719 6696 : }
12720 :
12721 : /*
12722 : * get_column_alias_list - print column alias list for an RTE
12723 : *
12724 : * Caller must already have printed the relation's alias name.
12725 : */
12726 : static void
12727 6222 : get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
12728 : {
12729 6222 : StringInfo buf = context->buf;
12730 : int i;
12731 6222 : bool first = true;
12732 :
12733 : /* Don't print aliases if not needed */
12734 6222 : if (!colinfo->printaliases)
12735 5016 : return;
12736 :
12737 9696 : for (i = 0; i < colinfo->num_new_cols; i++)
12738 : {
12739 8490 : char *colname = colinfo->new_colnames[i];
12740 :
12741 8490 : if (first)
12742 : {
12743 1206 : appendStringInfoChar(buf, '(');
12744 1206 : first = false;
12745 : }
12746 : else
12747 7284 : appendStringInfoString(buf, ", ");
12748 8490 : appendStringInfoString(buf, quote_identifier(colname));
12749 : }
12750 1206 : if (!first)
12751 1206 : appendStringInfoChar(buf, ')');
12752 : }
12753 :
12754 : /*
12755 : * get_from_clause_coldeflist - reproduce FROM clause coldeflist
12756 : *
12757 : * When printing a top-level coldeflist (which is syntactically also the
12758 : * relation's column alias list), use column names from colinfo. But when
12759 : * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
12760 : * original coldeflist's names, which are available in rtfunc->funccolnames.
12761 : * Pass NULL for colinfo to select the latter behavior.
12762 : *
12763 : * The coldeflist is appended immediately (no space) to buf. Caller is
12764 : * responsible for ensuring that an alias or AS is present before it.
12765 : */
12766 : static void
12767 6 : get_from_clause_coldeflist(RangeTblFunction *rtfunc,
12768 : deparse_columns *colinfo,
12769 : deparse_context *context)
12770 : {
12771 6 : StringInfo buf = context->buf;
12772 : ListCell *l1;
12773 : ListCell *l2;
12774 : ListCell *l3;
12775 : ListCell *l4;
12776 : int i;
12777 :
12778 6 : appendStringInfoChar(buf, '(');
12779 :
12780 6 : i = 0;
12781 24 : forfour(l1, rtfunc->funccoltypes,
12782 : l2, rtfunc->funccoltypmods,
12783 : l3, rtfunc->funccolcollations,
12784 : l4, rtfunc->funccolnames)
12785 : {
12786 18 : Oid atttypid = lfirst_oid(l1);
12787 18 : int32 atttypmod = lfirst_int(l2);
12788 18 : Oid attcollation = lfirst_oid(l3);
12789 : char *attname;
12790 :
12791 18 : if (colinfo)
12792 0 : attname = colinfo->colnames[i];
12793 : else
12794 18 : attname = strVal(lfirst(l4));
12795 :
12796 : Assert(attname); /* shouldn't be any dropped columns here */
12797 :
12798 18 : if (i > 0)
12799 12 : appendStringInfoString(buf, ", ");
12800 18 : appendStringInfo(buf, "%s %s",
12801 : quote_identifier(attname),
12802 : format_type_with_typemod(atttypid, atttypmod));
12803 24 : if (OidIsValid(attcollation) &&
12804 6 : attcollation != get_typcollation(atttypid))
12805 0 : appendStringInfo(buf, " COLLATE %s",
12806 : generate_collation_name(attcollation));
12807 :
12808 18 : i++;
12809 : }
12810 :
12811 6 : appendStringInfoChar(buf, ')');
12812 6 : }
12813 :
12814 : /*
12815 : * get_tablesample_def - print a TableSampleClause
12816 : */
12817 : static void
12818 32 : get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
12819 : {
12820 32 : StringInfo buf = context->buf;
12821 : Oid argtypes[1];
12822 : int nargs;
12823 : ListCell *l;
12824 :
12825 : /*
12826 : * We should qualify the handler's function name if it wouldn't be
12827 : * resolved by lookup in the current search path.
12828 : */
12829 32 : argtypes[0] = INTERNALOID;
12830 32 : appendStringInfo(buf, " TABLESAMPLE %s (",
12831 : generate_function_name(tablesample->tsmhandler, 1,
12832 : NIL, argtypes,
12833 : false, NULL, false));
12834 :
12835 32 : nargs = 0;
12836 64 : foreach(l, tablesample->args)
12837 : {
12838 32 : if (nargs++ > 0)
12839 0 : appendStringInfoString(buf, ", ");
12840 32 : get_rule_expr((Node *) lfirst(l), context, false);
12841 : }
12842 32 : appendStringInfoChar(buf, ')');
12843 :
12844 32 : if (tablesample->repeatable != NULL)
12845 : {
12846 16 : appendStringInfoString(buf, " REPEATABLE (");
12847 16 : get_rule_expr((Node *) tablesample->repeatable, context, false);
12848 16 : appendStringInfoChar(buf, ')');
12849 : }
12850 32 : }
12851 :
12852 : /*
12853 : * get_opclass_name - fetch name of an index operator class
12854 : *
12855 : * The opclass name is appended (after a space) to buf.
12856 : *
12857 : * Output is suppressed if the opclass is the default for the given
12858 : * actual_datatype. (If you don't want this behavior, just pass
12859 : * InvalidOid for actual_datatype.)
12860 : */
12861 : static void
12862 13086 : get_opclass_name(Oid opclass, Oid actual_datatype,
12863 : StringInfo buf)
12864 : {
12865 : HeapTuple ht_opc;
12866 : Form_pg_opclass opcrec;
12867 : char *opcname;
12868 : char *nspname;
12869 :
12870 13086 : ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
12871 13086 : if (!HeapTupleIsValid(ht_opc))
12872 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
12873 13086 : opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
12874 :
12875 26132 : if (!OidIsValid(actual_datatype) ||
12876 13046 : GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
12877 : {
12878 : /* Okay, we need the opclass name. Do we need to qualify it? */
12879 558 : opcname = NameStr(opcrec->opcname);
12880 558 : if (OpclassIsVisible(opclass))
12881 558 : appendStringInfo(buf, " %s", quote_identifier(opcname));
12882 : else
12883 : {
12884 0 : nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
12885 0 : appendStringInfo(buf, " %s.%s",
12886 : quote_identifier(nspname),
12887 : quote_identifier(opcname));
12888 : }
12889 : }
12890 13086 : ReleaseSysCache(ht_opc);
12891 13086 : }
12892 :
12893 : /*
12894 : * generate_opclass_name
12895 : * Compute the name to display for an opclass specified by OID
12896 : *
12897 : * The result includes all necessary quoting and schema-prefixing.
12898 : */
12899 : char *
12900 6 : generate_opclass_name(Oid opclass)
12901 : {
12902 : StringInfoData buf;
12903 :
12904 6 : initStringInfo(&buf);
12905 6 : get_opclass_name(opclass, InvalidOid, &buf);
12906 :
12907 6 : return &buf.data[1]; /* get_opclass_name() prepends space */
12908 : }
12909 :
12910 : /*
12911 : * processIndirection - take care of array and subfield assignment
12912 : *
12913 : * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
12914 : * appear in the input, printing them as decoration for the base column
12915 : * name (which we assume the caller just printed). We might also need to
12916 : * strip CoerceToDomain nodes, but only ones that appear above assignment
12917 : * nodes.
12918 : *
12919 : * Returns the subexpression that's to be assigned.
12920 : */
12921 : static Node *
12922 1272 : processIndirection(Node *node, deparse_context *context)
12923 : {
12924 1272 : StringInfo buf = context->buf;
12925 1272 : CoerceToDomain *cdomain = NULL;
12926 :
12927 : for (;;)
12928 : {
12929 1578 : if (node == NULL)
12930 0 : break;
12931 1578 : if (IsA(node, FieldStore))
12932 : {
12933 108 : FieldStore *fstore = (FieldStore *) node;
12934 : Oid typrelid;
12935 : char *fieldname;
12936 :
12937 : /* lookup tuple type */
12938 108 : typrelid = get_typ_typrelid(fstore->resulttype);
12939 108 : if (!OidIsValid(typrelid))
12940 0 : elog(ERROR, "argument type %s of FieldStore is not a tuple type",
12941 : format_type_be(fstore->resulttype));
12942 :
12943 : /*
12944 : * Print the field name. There should only be one target field in
12945 : * stored rules. There could be more than that in executable
12946 : * target lists, but this function cannot be used for that case.
12947 : */
12948 : Assert(list_length(fstore->fieldnums) == 1);
12949 108 : fieldname = get_attname(typrelid,
12950 108 : linitial_int(fstore->fieldnums), false);
12951 108 : appendStringInfo(buf, ".%s", quote_identifier(fieldname));
12952 :
12953 : /*
12954 : * We ignore arg since it should be an uninteresting reference to
12955 : * the target column or subcolumn.
12956 : */
12957 108 : node = (Node *) linitial(fstore->newvals);
12958 : }
12959 1470 : else if (IsA(node, SubscriptingRef))
12960 : {
12961 138 : SubscriptingRef *sbsref = (SubscriptingRef *) node;
12962 :
12963 138 : if (sbsref->refassgnexpr == NULL)
12964 0 : break;
12965 :
12966 138 : printSubscripts(sbsref, context);
12967 :
12968 : /*
12969 : * We ignore refexpr since it should be an uninteresting reference
12970 : * to the target column or subcolumn.
12971 : */
12972 138 : node = (Node *) sbsref->refassgnexpr;
12973 : }
12974 1332 : else if (IsA(node, CoerceToDomain))
12975 : {
12976 60 : cdomain = (CoerceToDomain *) node;
12977 : /* If it's an explicit domain coercion, we're done */
12978 60 : if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
12979 0 : break;
12980 : /* Tentatively descend past the CoerceToDomain */
12981 60 : node = (Node *) cdomain->arg;
12982 : }
12983 : else
12984 1272 : break;
12985 : }
12986 :
12987 : /*
12988 : * If we descended past a CoerceToDomain whose argument turned out not to
12989 : * be a FieldStore or array assignment, back up to the CoerceToDomain.
12990 : * (This is not enough to be fully correct if there are nested implicit
12991 : * CoerceToDomains, but such cases shouldn't ever occur.)
12992 : */
12993 1272 : if (cdomain && node == (Node *) cdomain->arg)
12994 0 : node = (Node *) cdomain;
12995 :
12996 1272 : return node;
12997 : }
12998 :
12999 : static void
13000 454 : printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
13001 : {
13002 454 : StringInfo buf = context->buf;
13003 : ListCell *lowlist_item;
13004 : ListCell *uplist_item;
13005 :
13006 454 : lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
13007 908 : foreach(uplist_item, sbsref->refupperindexpr)
13008 : {
13009 454 : appendStringInfoChar(buf, '[');
13010 454 : if (lowlist_item)
13011 : {
13012 : /* If subexpression is NULL, get_rule_expr prints nothing */
13013 0 : get_rule_expr((Node *) lfirst(lowlist_item), context, false);
13014 0 : appendStringInfoChar(buf, ':');
13015 0 : lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
13016 : }
13017 : /* If subexpression is NULL, get_rule_expr prints nothing */
13018 454 : get_rule_expr((Node *) lfirst(uplist_item), context, false);
13019 454 : appendStringInfoChar(buf, ']');
13020 : }
13021 454 : }
13022 :
13023 : /*
13024 : * quote_identifier - Quote an identifier only if needed
13025 : *
13026 : * When quotes are needed, we palloc the required space; slightly
13027 : * space-wasteful but well worth it for notational simplicity.
13028 : */
13029 : const char *
13030 2542996 : quote_identifier(const char *ident)
13031 : {
13032 : /*
13033 : * Can avoid quoting if ident starts with a lowercase letter or underscore
13034 : * and contains only lowercase letters, digits, and underscores, *and* is
13035 : * not any SQL keyword. Otherwise, supply quotes.
13036 : */
13037 2542996 : int nquotes = 0;
13038 : bool safe;
13039 : const char *ptr;
13040 : char *result;
13041 : char *optr;
13042 :
13043 : /*
13044 : * would like to use <ctype.h> macros here, but they might yield unwanted
13045 : * locale-specific results...
13046 : */
13047 2542996 : safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
13048 :
13049 21995236 : for (ptr = ident; *ptr; ptr++)
13050 : {
13051 19452240 : char ch = *ptr;
13052 :
13053 19452240 : if ((ch >= 'a' && ch <= 'z') ||
13054 2319342 : (ch >= '0' && ch <= '9') ||
13055 : (ch == '_'))
13056 : {
13057 : /* okay */
13058 : }
13059 : else
13060 : {
13061 64138 : safe = false;
13062 64138 : if (ch == '"')
13063 188 : nquotes++;
13064 : }
13065 : }
13066 :
13067 2542996 : if (quote_all_identifiers)
13068 13110 : safe = false;
13069 :
13070 2542996 : if (safe)
13071 : {
13072 : /*
13073 : * Check for keyword. We quote keywords except for unreserved ones.
13074 : * (In some cases we could avoid quoting a col_name or type_func_name
13075 : * keyword, but it seems much harder than it's worth to tell that.)
13076 : *
13077 : * Note: ScanKeywordLookup() does case-insensitive comparison, but
13078 : * that's fine, since we already know we have all-lower-case.
13079 : */
13080 2503558 : int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
13081 :
13082 2503558 : if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
13083 3466 : safe = false;
13084 : }
13085 :
13086 2542996 : if (safe)
13087 2500092 : return ident; /* no change needed */
13088 :
13089 42904 : result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
13090 :
13091 42904 : optr = result;
13092 42904 : *optr++ = '"';
13093 252570 : for (ptr = ident; *ptr; ptr++)
13094 : {
13095 209666 : char ch = *ptr;
13096 :
13097 209666 : if (ch == '"')
13098 188 : *optr++ = '"';
13099 209666 : *optr++ = ch;
13100 : }
13101 42904 : *optr++ = '"';
13102 42904 : *optr = '\0';
13103 :
13104 42904 : return result;
13105 : }
13106 :
13107 : /*
13108 : * quote_qualified_identifier - Quote a possibly-qualified identifier
13109 : *
13110 : * Return a name of the form qualifier.ident, or just ident if qualifier
13111 : * is NULL, quoting each component if necessary. The result is palloc'd.
13112 : */
13113 : char *
13114 1262030 : quote_qualified_identifier(const char *qualifier,
13115 : const char *ident)
13116 : {
13117 : StringInfoData buf;
13118 :
13119 1262030 : initStringInfo(&buf);
13120 1262030 : if (qualifier)
13121 453510 : appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
13122 1262030 : appendStringInfoString(&buf, quote_identifier(ident));
13123 1262030 : return buf.data;
13124 : }
13125 :
13126 : /*
13127 : * get_relation_name
13128 : * Get the unqualified name of a relation specified by OID
13129 : *
13130 : * This differs from the underlying get_rel_name() function in that it will
13131 : * throw error instead of silently returning NULL if the OID is bad.
13132 : */
13133 : static char *
13134 16920 : get_relation_name(Oid relid)
13135 : {
13136 16920 : char *relname = get_rel_name(relid);
13137 :
13138 16920 : if (!relname)
13139 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
13140 16920 : return relname;
13141 : }
13142 :
13143 : /*
13144 : * generate_relation_name
13145 : * Compute the name to display for a relation specified by OID
13146 : *
13147 : * The result includes all necessary quoting and schema-prefixing.
13148 : *
13149 : * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
13150 : * We will forcibly qualify the relation name if it equals any CTE name
13151 : * visible in the namespace list.
13152 : */
13153 : static char *
13154 8106 : generate_relation_name(Oid relid, List *namespaces)
13155 : {
13156 : HeapTuple tp;
13157 : Form_pg_class reltup;
13158 : bool need_qual;
13159 : ListCell *nslist;
13160 : char *relname;
13161 : char *nspname;
13162 : char *result;
13163 :
13164 8106 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13165 8106 : if (!HeapTupleIsValid(tp))
13166 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
13167 8106 : reltup = (Form_pg_class) GETSTRUCT(tp);
13168 8106 : relname = NameStr(reltup->relname);
13169 :
13170 : /* Check for conflicting CTE name */
13171 8106 : need_qual = false;
13172 14026 : foreach(nslist, namespaces)
13173 : {
13174 5920 : deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
13175 : ListCell *ctlist;
13176 :
13177 6052 : foreach(ctlist, dpns->ctes)
13178 : {
13179 132 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
13180 :
13181 132 : if (strcmp(cte->ctename, relname) == 0)
13182 : {
13183 0 : need_qual = true;
13184 0 : break;
13185 : }
13186 : }
13187 5920 : if (need_qual)
13188 0 : break;
13189 : }
13190 :
13191 : /* Otherwise, qualify the name if not visible in search path */
13192 8106 : if (!need_qual)
13193 8106 : need_qual = !RelationIsVisible(relid);
13194 :
13195 8106 : if (need_qual)
13196 2482 : nspname = get_namespace_name_or_temp(reltup->relnamespace);
13197 : else
13198 5624 : nspname = NULL;
13199 :
13200 8106 : result = quote_qualified_identifier(nspname, relname);
13201 :
13202 8106 : ReleaseSysCache(tp);
13203 :
13204 8106 : return result;
13205 : }
13206 :
13207 : /*
13208 : * generate_qualified_relation_name
13209 : * Compute the name to display for a relation specified by OID
13210 : *
13211 : * As above, but unconditionally schema-qualify the name.
13212 : */
13213 : static char *
13214 8392 : generate_qualified_relation_name(Oid relid)
13215 : {
13216 : HeapTuple tp;
13217 : Form_pg_class reltup;
13218 : char *relname;
13219 : char *nspname;
13220 : char *result;
13221 :
13222 8392 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13223 8392 : if (!HeapTupleIsValid(tp))
13224 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
13225 8392 : reltup = (Form_pg_class) GETSTRUCT(tp);
13226 8392 : relname = NameStr(reltup->relname);
13227 :
13228 8392 : nspname = get_namespace_name_or_temp(reltup->relnamespace);
13229 8392 : if (!nspname)
13230 0 : elog(ERROR, "cache lookup failed for namespace %u",
13231 : reltup->relnamespace);
13232 :
13233 8392 : result = quote_qualified_identifier(nspname, relname);
13234 :
13235 8392 : ReleaseSysCache(tp);
13236 :
13237 8392 : return result;
13238 : }
13239 :
13240 : /*
13241 : * generate_function_name
13242 : * Compute the name to display for a function specified by OID,
13243 : * given that it is being called with the specified actual arg names and
13244 : * types. (Those matter because of ambiguous-function resolution rules.)
13245 : *
13246 : * If we're dealing with a potentially variadic function (in practice, this
13247 : * means a FuncExpr or Aggref, not some other way of calling a function), then
13248 : * has_variadic must specify whether variadic arguments have been merged,
13249 : * and *use_variadic_p will be set to indicate whether to print VARIADIC in
13250 : * the output. For non-FuncExpr cases, has_variadic should be false and
13251 : * use_variadic_p can be NULL.
13252 : *
13253 : * inGroupBy must be true if we're deparsing a GROUP BY clause.
13254 : *
13255 : * The result includes all necessary quoting and schema-prefixing.
13256 : */
13257 : static char *
13258 12746 : generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
13259 : bool has_variadic, bool *use_variadic_p,
13260 : bool inGroupBy)
13261 : {
13262 : char *result;
13263 : HeapTuple proctup;
13264 : Form_pg_proc procform;
13265 : char *proname;
13266 : bool use_variadic;
13267 : char *nspname;
13268 : FuncDetailCode p_result;
13269 : int fgc_flags;
13270 : Oid p_funcid;
13271 : Oid p_rettype;
13272 : bool p_retset;
13273 : int p_nvargs;
13274 : Oid p_vatype;
13275 : Oid *p_true_typeids;
13276 12746 : bool force_qualify = false;
13277 :
13278 12746 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
13279 12746 : if (!HeapTupleIsValid(proctup))
13280 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
13281 12746 : procform = (Form_pg_proc) GETSTRUCT(proctup);
13282 12746 : proname = NameStr(procform->proname);
13283 :
13284 : /*
13285 : * Due to parser hacks to avoid needing to reserve CUBE, we need to force
13286 : * qualification of some function names within GROUP BY.
13287 : */
13288 12746 : if (inGroupBy)
13289 : {
13290 0 : if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
13291 0 : force_qualify = true;
13292 : }
13293 :
13294 : /*
13295 : * Determine whether VARIADIC should be printed. We must do this first
13296 : * since it affects the lookup rules in func_get_detail().
13297 : *
13298 : * We always print VARIADIC if the function has a merged variadic-array
13299 : * argument. Note that this is always the case for functions taking a
13300 : * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
13301 : * and printed the array elements as separate arguments, the call could
13302 : * match a newer non-VARIADIC function.
13303 : */
13304 12746 : if (use_variadic_p)
13305 : {
13306 : /* Parser should not have set funcvariadic unless fn is variadic */
13307 : Assert(!has_variadic || OidIsValid(procform->provariadic));
13308 11000 : use_variadic = has_variadic;
13309 11000 : *use_variadic_p = use_variadic;
13310 : }
13311 : else
13312 : {
13313 : Assert(!has_variadic);
13314 1746 : use_variadic = false;
13315 : }
13316 :
13317 : /*
13318 : * The idea here is to schema-qualify only if the parser would fail to
13319 : * resolve the correct function given the unqualified func name with the
13320 : * specified argtypes and VARIADIC flag. But if we already decided to
13321 : * force qualification, then we can skip the lookup and pretend we didn't
13322 : * find it.
13323 : */
13324 12746 : if (!force_qualify)
13325 12746 : p_result = func_get_detail(list_make1(makeString(proname)),
13326 : NIL, argnames, nargs, argtypes,
13327 12746 : !use_variadic, true, false,
13328 : &fgc_flags,
13329 : &p_funcid, &p_rettype,
13330 : &p_retset, &p_nvargs, &p_vatype,
13331 12746 : &p_true_typeids, NULL);
13332 : else
13333 : {
13334 0 : p_result = FUNCDETAIL_NOTFOUND;
13335 0 : p_funcid = InvalidOid;
13336 : }
13337 :
13338 12746 : if ((p_result == FUNCDETAIL_NORMAL ||
13339 1310 : p_result == FUNCDETAIL_AGGREGATE ||
13340 11544 : p_result == FUNCDETAIL_WINDOWFUNC) &&
13341 11544 : p_funcid == funcid)
13342 11544 : nspname = NULL;
13343 : else
13344 1202 : nspname = get_namespace_name_or_temp(procform->pronamespace);
13345 :
13346 12746 : result = quote_qualified_identifier(nspname, proname);
13347 :
13348 12746 : ReleaseSysCache(proctup);
13349 :
13350 12746 : return result;
13351 : }
13352 :
13353 : /*
13354 : * generate_operator_name
13355 : * Compute the name to display for an operator specified by OID,
13356 : * given that it is being called with the specified actual arg types.
13357 : * (Arg types matter because of ambiguous-operator resolution rules.
13358 : * Pass InvalidOid for unused arg of a unary operator.)
13359 : *
13360 : * The result includes all necessary quoting and schema-prefixing,
13361 : * plus the OPERATOR() decoration needed to use a qualified operator name
13362 : * in an expression.
13363 : */
13364 : static char *
13365 64064 : generate_operator_name(Oid operid, Oid arg1, Oid arg2)
13366 : {
13367 : StringInfoData buf;
13368 : HeapTuple opertup;
13369 : Form_pg_operator operform;
13370 : char *oprname;
13371 : char *nspname;
13372 : Operator p_result;
13373 :
13374 64064 : initStringInfo(&buf);
13375 :
13376 64064 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
13377 64064 : if (!HeapTupleIsValid(opertup))
13378 0 : elog(ERROR, "cache lookup failed for operator %u", operid);
13379 64064 : operform = (Form_pg_operator) GETSTRUCT(opertup);
13380 64064 : oprname = NameStr(operform->oprname);
13381 :
13382 : /*
13383 : * The idea here is to schema-qualify only if the parser would fail to
13384 : * resolve the correct operator given the unqualified op name with the
13385 : * specified argtypes.
13386 : */
13387 64064 : switch (operform->oprkind)
13388 : {
13389 64034 : case 'b':
13390 64034 : p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
13391 : true, -1);
13392 64034 : break;
13393 30 : case 'l':
13394 30 : p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
13395 : true, -1);
13396 30 : break;
13397 0 : default:
13398 0 : elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
13399 : p_result = NULL; /* keep compiler quiet */
13400 : break;
13401 : }
13402 :
13403 64064 : if (p_result != NULL && oprid(p_result) == operid)
13404 64054 : nspname = NULL;
13405 : else
13406 : {
13407 10 : nspname = get_namespace_name_or_temp(operform->oprnamespace);
13408 10 : appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
13409 : }
13410 :
13411 64064 : appendStringInfoString(&buf, oprname);
13412 :
13413 64064 : if (nspname)
13414 10 : appendStringInfoChar(&buf, ')');
13415 :
13416 64064 : if (p_result != NULL)
13417 64054 : ReleaseSysCache(p_result);
13418 :
13419 64064 : ReleaseSysCache(opertup);
13420 :
13421 64064 : return buf.data;
13422 : }
13423 :
13424 : /*
13425 : * generate_operator_clause --- generate a binary-operator WHERE clause
13426 : *
13427 : * This is used for internally-generated-and-executed SQL queries, where
13428 : * precision is essential and readability is secondary. The basic
13429 : * requirement is to append "leftop op rightop" to buf, where leftop and
13430 : * rightop are given as strings and are assumed to yield types leftoptype
13431 : * and rightoptype; the operator is identified by OID. The complexity
13432 : * comes from needing to be sure that the parser will select the desired
13433 : * operator when the query is parsed. We always name the operator using
13434 : * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
13435 : * We have to emit casts too, if either input isn't already the input type
13436 : * of the operator; else we are at the mercy of the parser's heuristics for
13437 : * ambiguous-operator resolution. The caller must ensure that leftop and
13438 : * rightop are suitable arguments for a cast operation; it's best to insert
13439 : * parentheses if they aren't just variables or parameters.
13440 : */
13441 : void
13442 6562 : generate_operator_clause(StringInfo buf,
13443 : const char *leftop, Oid leftoptype,
13444 : Oid opoid,
13445 : const char *rightop, Oid rightoptype)
13446 : {
13447 : HeapTuple opertup;
13448 : Form_pg_operator operform;
13449 : char *oprname;
13450 : char *nspname;
13451 :
13452 6562 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
13453 6562 : if (!HeapTupleIsValid(opertup))
13454 0 : elog(ERROR, "cache lookup failed for operator %u", opoid);
13455 6562 : operform = (Form_pg_operator) GETSTRUCT(opertup);
13456 : Assert(operform->oprkind == 'b');
13457 6562 : oprname = NameStr(operform->oprname);
13458 :
13459 6562 : nspname = get_namespace_name(operform->oprnamespace);
13460 :
13461 6562 : appendStringInfoString(buf, leftop);
13462 6562 : if (leftoptype != operform->oprleft)
13463 1210 : add_cast_to(buf, operform->oprleft);
13464 6562 : appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
13465 6562 : appendStringInfoString(buf, oprname);
13466 6562 : appendStringInfo(buf, ") %s", rightop);
13467 6562 : if (rightoptype != operform->oprright)
13468 978 : add_cast_to(buf, operform->oprright);
13469 :
13470 6562 : ReleaseSysCache(opertup);
13471 6562 : }
13472 :
13473 : /*
13474 : * Add a cast specification to buf. We spell out the type name the hard way,
13475 : * intentionally not using format_type_be(). This is to avoid corner cases
13476 : * for CHARACTER, BIT, and perhaps other types, where specifying the type
13477 : * using SQL-standard syntax results in undesirable data truncation. By
13478 : * doing it this way we can be certain that the cast will have default (-1)
13479 : * target typmod.
13480 : */
13481 : static void
13482 2188 : add_cast_to(StringInfo buf, Oid typid)
13483 : {
13484 : HeapTuple typetup;
13485 : Form_pg_type typform;
13486 : char *typname;
13487 : char *nspname;
13488 :
13489 2188 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13490 2188 : if (!HeapTupleIsValid(typetup))
13491 0 : elog(ERROR, "cache lookup failed for type %u", typid);
13492 2188 : typform = (Form_pg_type) GETSTRUCT(typetup);
13493 :
13494 2188 : typname = NameStr(typform->typname);
13495 2188 : nspname = get_namespace_name_or_temp(typform->typnamespace);
13496 :
13497 2188 : appendStringInfo(buf, "::%s.%s",
13498 : quote_identifier(nspname), quote_identifier(typname));
13499 :
13500 2188 : ReleaseSysCache(typetup);
13501 2188 : }
13502 :
13503 : /*
13504 : * generate_qualified_type_name
13505 : * Compute the name to display for a type specified by OID
13506 : *
13507 : * This is different from format_type_be() in that we unconditionally
13508 : * schema-qualify the name. That also means no special syntax for
13509 : * SQL-standard type names ... although in current usage, this should
13510 : * only get used for domains, so such cases wouldn't occur anyway.
13511 : */
13512 : static char *
13513 14 : generate_qualified_type_name(Oid typid)
13514 : {
13515 : HeapTuple tp;
13516 : Form_pg_type typtup;
13517 : char *typname;
13518 : char *nspname;
13519 : char *result;
13520 :
13521 14 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
13522 14 : if (!HeapTupleIsValid(tp))
13523 0 : elog(ERROR, "cache lookup failed for type %u", typid);
13524 14 : typtup = (Form_pg_type) GETSTRUCT(tp);
13525 14 : typname = NameStr(typtup->typname);
13526 :
13527 14 : nspname = get_namespace_name_or_temp(typtup->typnamespace);
13528 14 : if (!nspname)
13529 0 : elog(ERROR, "cache lookup failed for namespace %u",
13530 : typtup->typnamespace);
13531 :
13532 14 : result = quote_qualified_identifier(nspname, typname);
13533 :
13534 14 : ReleaseSysCache(tp);
13535 :
13536 14 : return result;
13537 : }
13538 :
13539 : /*
13540 : * generate_collation_name
13541 : * Compute the name to display for a collation specified by OID
13542 : *
13543 : * The result includes all necessary quoting and schema-prefixing.
13544 : */
13545 : char *
13546 294 : generate_collation_name(Oid collid)
13547 : {
13548 : HeapTuple tp;
13549 : Form_pg_collation colltup;
13550 : char *collname;
13551 : char *nspname;
13552 : char *result;
13553 :
13554 294 : tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
13555 294 : if (!HeapTupleIsValid(tp))
13556 0 : elog(ERROR, "cache lookup failed for collation %u", collid);
13557 294 : colltup = (Form_pg_collation) GETSTRUCT(tp);
13558 294 : collname = NameStr(colltup->collname);
13559 :
13560 294 : if (!CollationIsVisible(collid))
13561 0 : nspname = get_namespace_name_or_temp(colltup->collnamespace);
13562 : else
13563 294 : nspname = NULL;
13564 :
13565 294 : result = quote_qualified_identifier(nspname, collname);
13566 :
13567 294 : ReleaseSysCache(tp);
13568 :
13569 294 : return result;
13570 : }
13571 :
13572 : /*
13573 : * Given a C string, produce a TEXT datum.
13574 : *
13575 : * We assume that the input was palloc'd and may be freed.
13576 : */
13577 : static text *
13578 45666 : string_to_text(char *str)
13579 : {
13580 : text *result;
13581 :
13582 45666 : result = cstring_to_text(str);
13583 45666 : pfree(str);
13584 45666 : return result;
13585 : }
13586 :
13587 : /*
13588 : * Generate a C string representing a relation options from text[] datum.
13589 : */
13590 : static void
13591 244 : get_reloptions(StringInfo buf, Datum reloptions)
13592 : {
13593 : Datum *options;
13594 : int noptions;
13595 : int i;
13596 :
13597 244 : deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
13598 : &options, NULL, &noptions);
13599 :
13600 508 : for (i = 0; i < noptions; i++)
13601 : {
13602 264 : char *option = TextDatumGetCString(options[i]);
13603 : char *name;
13604 : char *separator;
13605 : char *value;
13606 :
13607 : /*
13608 : * Each array element should have the form name=value. If the "=" is
13609 : * missing for some reason, treat it like an empty value.
13610 : */
13611 264 : name = option;
13612 264 : separator = strchr(option, '=');
13613 264 : if (separator)
13614 : {
13615 264 : *separator = '\0';
13616 264 : value = separator + 1;
13617 : }
13618 : else
13619 0 : value = "";
13620 :
13621 264 : if (i > 0)
13622 20 : appendStringInfoString(buf, ", ");
13623 264 : appendStringInfo(buf, "%s=", quote_identifier(name));
13624 :
13625 : /*
13626 : * In general we need to quote the value; but to avoid unnecessary
13627 : * clutter, do not quote if it is an identifier that would not need
13628 : * quoting. (We could also allow numbers, but that is a bit trickier
13629 : * than it looks --- for example, are leading zeroes significant? We
13630 : * don't want to assume very much here about what custom reloptions
13631 : * might mean.)
13632 : */
13633 264 : if (quote_identifier(value) == value)
13634 8 : appendStringInfoString(buf, value);
13635 : else
13636 256 : simple_quote_literal(buf, value);
13637 :
13638 264 : pfree(option);
13639 : }
13640 244 : }
13641 :
13642 : /*
13643 : * Generate a C string representing a relation's reloptions, or NULL if none.
13644 : */
13645 : static char *
13646 7912 : flatten_reloptions(Oid relid)
13647 : {
13648 7912 : char *result = NULL;
13649 : HeapTuple tuple;
13650 : Datum reloptions;
13651 : bool isnull;
13652 :
13653 7912 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
13654 7912 : if (!HeapTupleIsValid(tuple))
13655 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
13656 :
13657 7912 : reloptions = SysCacheGetAttr(RELOID, tuple,
13658 : Anum_pg_class_reloptions, &isnull);
13659 7912 : if (!isnull)
13660 : {
13661 : StringInfoData buf;
13662 :
13663 210 : initStringInfo(&buf);
13664 210 : get_reloptions(&buf, reloptions);
13665 :
13666 210 : result = buf.data;
13667 : }
13668 :
13669 7912 : ReleaseSysCache(tuple);
13670 :
13671 7912 : return result;
13672 : }
13673 :
13674 : /*
13675 : * get_range_partbound_string
13676 : * A C string representation of one range partition bound
13677 : */
13678 : char *
13679 4716 : get_range_partbound_string(List *bound_datums)
13680 : {
13681 : deparse_context context;
13682 4716 : StringInfo buf = makeStringInfo();
13683 : ListCell *cell;
13684 : char *sep;
13685 :
13686 4716 : memset(&context, 0, sizeof(deparse_context));
13687 4716 : context.buf = buf;
13688 :
13689 4716 : appendStringInfoChar(buf, '(');
13690 4716 : sep = "";
13691 10224 : foreach(cell, bound_datums)
13692 : {
13693 5508 : PartitionRangeDatum *datum =
13694 : lfirst_node(PartitionRangeDatum, cell);
13695 :
13696 5508 : appendStringInfoString(buf, sep);
13697 5508 : if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
13698 222 : appendStringInfoString(buf, "MINVALUE");
13699 5286 : else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
13700 120 : appendStringInfoString(buf, "MAXVALUE");
13701 : else
13702 : {
13703 5166 : Const *val = castNode(Const, datum->value);
13704 :
13705 5166 : get_const_expr(val, &context, -1);
13706 : }
13707 5508 : sep = ", ";
13708 : }
13709 4716 : appendStringInfoChar(buf, ')');
13710 :
13711 4716 : return buf->data;
13712 : }
|