TLA 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-2023, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : *
11 : * IDENTIFICATION
12 : * src/backend/utils/adt/ruleutils.c
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 : #include "postgres.h"
17 :
18 : #include <ctype.h>
19 : #include <unistd.h>
20 : #include <fcntl.h>
21 :
22 : #include "access/amapi.h"
23 : #include "access/htup_details.h"
24 : #include "access/relation.h"
25 : #include "access/sysattr.h"
26 : #include "access/table.h"
27 : #include "catalog/pg_aggregate.h"
28 : #include "catalog/pg_am.h"
29 : #include "catalog/pg_authid.h"
30 : #include "catalog/pg_collation.h"
31 : #include "catalog/pg_constraint.h"
32 : #include "catalog/pg_depend.h"
33 : #include "catalog/pg_language.h"
34 : #include "catalog/pg_opclass.h"
35 : #include "catalog/pg_operator.h"
36 : #include "catalog/pg_partitioned_table.h"
37 : #include "catalog/pg_proc.h"
38 : #include "catalog/pg_statistic_ext.h"
39 : #include "catalog/pg_trigger.h"
40 : #include "catalog/pg_type.h"
41 : #include "commands/defrem.h"
42 : #include "commands/tablespace.h"
43 : #include "common/keywords.h"
44 : #include "executor/spi.h"
45 : #include "funcapi.h"
46 : #include "mb/pg_wchar.h"
47 : #include "miscadmin.h"
48 : #include "nodes/makefuncs.h"
49 : #include "nodes/nodeFuncs.h"
50 : #include "nodes/pathnodes.h"
51 : #include "optimizer/optimizer.h"
52 : #include "parser/parse_agg.h"
53 : #include "parser/parse_func.h"
54 : #include "parser/parse_node.h"
55 : #include "parser/parse_oper.h"
56 : #include "parser/parse_relation.h"
57 : #include "parser/parser.h"
58 : #include "parser/parsetree.h"
59 : #include "rewrite/rewriteHandler.h"
60 : #include "rewrite/rewriteManip.h"
61 : #include "rewrite/rewriteSupport.h"
62 : #include "utils/array.h"
63 : #include "utils/builtins.h"
64 : #include "utils/fmgroids.h"
65 : #include "utils/guc.h"
66 : #include "utils/hsearch.h"
67 : #include "utils/lsyscache.h"
68 : #include "utils/partcache.h"
69 : #include "utils/rel.h"
70 : #include "utils/ruleutils.h"
71 : #include "utils/snapmgr.h"
72 : #include "utils/syscache.h"
73 : #include "utils/typcache.h"
74 : #include "utils/varlena.h"
75 : #include "utils/xml.h"
76 :
77 : /* ----------
78 : * Pretty formatting constants
79 : * ----------
80 : */
81 :
82 : /* Indent counts */
83 : #define PRETTYINDENT_STD 8
84 : #define PRETTYINDENT_JOIN 4
85 : #define PRETTYINDENT_VAR 4
86 :
87 : #define PRETTYINDENT_LIMIT 40 /* wrap limit */
88 :
89 : /* Pretty flags */
90 : #define PRETTYFLAG_PAREN 0x0001
91 : #define PRETTYFLAG_INDENT 0x0002
92 : #define PRETTYFLAG_SCHEMA 0x0004
93 :
94 : /* Standard conversion of a "bool pretty" option to detailed flags */
95 : #define GET_PRETTY_FLAGS(pretty) \
96 : ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
97 : : PRETTYFLAG_INDENT)
98 :
99 : /* Default line length for pretty-print wrapping: 0 means wrap always */
100 : #define WRAP_COLUMN_DEFAULT 0
101 :
102 : /* macros to test if pretty action needed */
103 : #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
104 : #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
105 : #define PRETTY_SCHEMA(context) ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
106 :
107 :
108 : /* ----------
109 : * Local data types
110 : * ----------
111 : */
112 :
113 : /* Context info needed for invoking a recursive querytree display routine */
114 : typedef struct
115 : {
116 : StringInfo buf; /* output buffer to append to */
117 : List *namespaces; /* List of deparse_namespace nodes */
118 : List *windowClause; /* Current query level's WINDOW clause */
119 : List *windowTList; /* targetlist for resolving WINDOW clause */
120 : int prettyFlags; /* enabling of pretty-print functions */
121 : int wrapColumn; /* max line length, or -1 for no limit */
122 : int indentLevel; /* current indent level for pretty-print */
123 : bool varprefix; /* true to print prefixes on Vars */
124 : ParseExprKind special_exprkind; /* set only for exprkinds needing special
125 : * handling */
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 : /* Workspace for column alias assignment: */
171 : bool unique_using; /* Are we making USING names globally unique */
172 : List *using_names; /* List of assigned names for USING columns */
173 : /* Remaining fields are used only when deparsing a Plan tree: */
174 : Plan *plan; /* immediate parent of current expression */
175 : List *ancestors; /* ancestors of plan */
176 : Plan *outer_plan; /* outer subnode, or NULL if none */
177 : Plan *inner_plan; /* inner subnode, or NULL if none */
178 : List *outer_tlist; /* referent for OUTER_VAR Vars */
179 : List *inner_tlist; /* referent for INNER_VAR Vars */
180 : List *index_tlist; /* referent for INDEX_VAR Vars */
181 : /* Special namespace representing a function signature: */
182 : char *funcname;
183 : int numargs;
184 : char **argnames;
185 : } deparse_namespace;
186 :
187 : /*
188 : * Per-relation data about column alias names.
189 : *
190 : * Selecting aliases is unreasonably complicated because of the need to dump
191 : * rules/views whose underlying tables may have had columns added, deleted, or
192 : * renamed since the query was parsed. We must nonetheless print the rule/view
193 : * in a form that can be reloaded and will produce the same results as before.
194 : *
195 : * For each RTE used in the query, we must assign column aliases that are
196 : * unique within that RTE. SQL does not require this of the original query,
197 : * but due to factors such as *-expansion we need to be able to uniquely
198 : * reference every column in a decompiled query. As long as we qualify all
199 : * column references, per-RTE uniqueness is sufficient for that.
200 : *
201 : * However, we can't ensure per-column name uniqueness for unnamed join RTEs,
202 : * since they just inherit column names from their input RTEs, and we can't
203 : * rename the columns at the join level. Most of the time this isn't an issue
204 : * because we don't need to reference the join's output columns as such; we
205 : * can reference the input columns instead. That approach can fail for merged
206 : * JOIN USING columns, however, so when we have one of those in an unnamed
207 : * join, we have to make that column's alias globally unique across the whole
208 : * query to ensure it can be referenced unambiguously.
209 : *
210 : * Another problem is that a JOIN USING clause requires the columns to be
211 : * merged to have the same aliases in both input RTEs, and that no other
212 : * columns in those RTEs or their children conflict with the USING names.
213 : * To handle that, we do USING-column alias assignment in a recursive
214 : * traversal of the query's jointree. When descending through a JOIN with
215 : * USING, we preassign the USING column names to the child columns, overriding
216 : * other rules for column alias assignment. We also mark each RTE with a list
217 : * of all USING column names selected for joins containing that RTE, so that
218 : * when we assign other columns' aliases later, we can avoid conflicts.
219 : *
220 : * Another problem is that if a JOIN's input tables have had columns added or
221 : * deleted since the query was parsed, we must generate a column alias list
222 : * for the join that matches the current set of input columns --- otherwise, a
223 : * change in the number of columns in the left input would throw off matching
224 : * of aliases to columns of the right input. Thus, positions in the printable
225 : * column alias list are not necessarily one-for-one with varattnos of the
226 : * JOIN, so we need a separate new_colnames[] array for printing purposes.
227 : */
228 : typedef struct
229 : {
230 : /*
231 : * colnames is an array containing column aliases to use for columns that
232 : * existed when the query was parsed. Dropped columns have NULL entries.
233 : * This array can be directly indexed by varattno to get a Var's name.
234 : *
235 : * Non-NULL entries are guaranteed unique within the RTE, *except* when
236 : * this is for an unnamed JOIN RTE. In that case we merely copy up names
237 : * from the two input RTEs.
238 : *
239 : * During the recursive descent in set_using_names(), forcible assignment
240 : * of a child RTE's column name is represented by pre-setting that element
241 : * of the child's colnames array. So at that stage, NULL entries in this
242 : * array just mean that no name has been preassigned, not necessarily that
243 : * the column is dropped.
244 : */
245 : int num_cols; /* length of colnames[] array */
246 : char **colnames; /* array of C strings and NULLs */
247 :
248 : /*
249 : * new_colnames is an array containing column aliases to use for columns
250 : * that would exist if the query was re-parsed against the current
251 : * definitions of its base tables. This is what to print as the column
252 : * alias list for the RTE. This array does not include dropped columns,
253 : * but it will include columns added since original parsing. Indexes in
254 : * it therefore have little to do with current varattno values. As above,
255 : * entries are unique unless this is for an unnamed JOIN RTE. (In such an
256 : * RTE, we never actually print this array, but we must compute it anyway
257 : * for possible use in computing column names of upper joins.) The
258 : * parallel array is_new_col marks which of these columns are new since
259 : * original parsing. Entries with is_new_col false must match the
260 : * non-NULL colnames entries one-for-one.
261 : */
262 : int num_new_cols; /* length of new_colnames[] array */
263 : char **new_colnames; /* array of C strings */
264 : bool *is_new_col; /* array of bool flags */
265 :
266 : /* This flag tells whether we should actually print a column alias list */
267 : bool printaliases;
268 :
269 : /* This list has all names used as USING names in joins above this RTE */
270 : List *parentUsing; /* names assigned to parent merged columns */
271 :
272 : /*
273 : * If this struct is for a JOIN RTE, we fill these fields during the
274 : * set_using_names() pass to describe its relationship to its child RTEs.
275 : *
276 : * leftattnos and rightattnos are arrays with one entry per existing
277 : * output column of the join (hence, indexable by join varattno). For a
278 : * simple reference to a column of the left child, leftattnos[i] is the
279 : * child RTE's attno and rightattnos[i] is zero; and conversely for a
280 : * column of the right child. But for merged columns produced by JOIN
281 : * USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
282 : * Note that a simple reference might be to a child RTE column that's been
283 : * dropped; but that's OK since the column could not be used in the query.
284 : *
285 : * If it's a JOIN USING, usingNames holds the alias names selected for the
286 : * merged columns (these might be different from the original USING list,
287 : * if we had to modify names to achieve uniqueness).
288 : */
289 : int leftrti; /* rangetable index of left child */
290 : int rightrti; /* rangetable index of right child */
291 : int *leftattnos; /* left-child varattnos of join cols, or 0 */
292 : int *rightattnos; /* right-child varattnos of join cols, or 0 */
293 : List *usingNames; /* names assigned to merged columns */
294 : } deparse_columns;
295 :
296 : /* This macro is analogous to rt_fetch(), but for deparse_columns structs */
297 : #define deparse_columns_fetch(rangetable_index, dpns) \
298 : ((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
299 :
300 : /*
301 : * Entry in set_rtable_names' hash table
302 : */
303 : typedef struct
304 : {
305 : char name[NAMEDATALEN]; /* Hash key --- must be first */
306 : int counter; /* Largest addition used so far for name */
307 : } NameHashEntry;
308 :
309 : /* Callback signature for resolve_special_varno() */
310 : typedef void (*rsv_callback) (Node *node, deparse_context *context,
311 : void *callback_arg);
312 :
313 :
314 : /* ----------
315 : * Global data
316 : * ----------
317 : */
318 : static SPIPlanPtr plan_getrulebyoid = NULL;
319 : static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
320 : static SPIPlanPtr plan_getviewrule = NULL;
321 : static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
322 :
323 : /* GUC parameters */
324 : bool quote_all_identifiers = false;
325 :
326 :
327 : /* ----------
328 : * Local functions
329 : *
330 : * Most of these functions used to use fixed-size buffers to build their
331 : * results. Now, they take an (already initialized) StringInfo object
332 : * as a parameter, and append their text output to its contents.
333 : * ----------
334 : */
335 : static char *deparse_expression_pretty(Node *expr, List *dpcontext,
336 : bool forceprefix, bool showimplicit,
337 : int prettyFlags, int startIndent);
338 : static char *pg_get_viewdef_worker(Oid viewoid,
339 : int prettyFlags, int wrapColumn);
340 : static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
341 : static int decompile_column_index_array(Datum column_index_array, Oid relId,
342 : StringInfo buf);
343 : static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
344 : static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
345 : const Oid *excludeOps,
346 : bool attrsOnly, bool keysOnly,
347 : bool showTblSpc, bool inherits,
348 : int prettyFlags, bool missing_ok);
349 : static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
350 : bool missing_ok);
351 : static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
352 : bool attrsOnly, bool missing_ok);
353 : static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
354 : int prettyFlags, bool missing_ok);
355 : static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
356 : int prettyFlags);
357 : static int print_function_arguments(StringInfo buf, HeapTuple proctup,
358 : bool print_table_args, bool print_defaults);
359 : static void print_function_rettype(StringInfo buf, HeapTuple proctup);
360 : static void print_function_trftypes(StringInfo buf, HeapTuple proctup);
361 : static void print_function_sqlbody(StringInfo buf, HeapTuple proctup);
362 : static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
363 : Bitmapset *rels_used);
364 : static void set_deparse_for_query(deparse_namespace *dpns, Query *query,
365 : List *parent_namespaces);
366 : static void set_simple_column_names(deparse_namespace *dpns);
367 : static bool has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode);
368 : static void set_using_names(deparse_namespace *dpns, Node *jtnode,
369 : List *parentUsing);
370 : static void set_relation_column_names(deparse_namespace *dpns,
371 : RangeTblEntry *rte,
372 : deparse_columns *colinfo);
373 : static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
374 : deparse_columns *colinfo);
375 : static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
376 : deparse_columns *colinfo);
377 : static char *make_colname_unique(char *colname, deparse_namespace *dpns,
378 : deparse_columns *colinfo);
379 : static void expand_colnames_array_to(deparse_columns *colinfo, int n);
380 : static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
381 : deparse_columns *colinfo);
382 : static char *get_rtable_name(int rtindex, deparse_context *context);
383 : static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
384 : static Plan *find_recursive_union(deparse_namespace *dpns,
385 : WorkTableScan *wtscan);
386 : static void push_child_plan(deparse_namespace *dpns, Plan *plan,
387 : deparse_namespace *save_dpns);
388 : static void pop_child_plan(deparse_namespace *dpns,
389 : deparse_namespace *save_dpns);
390 : static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
391 : deparse_namespace *save_dpns);
392 : static void pop_ancestor_plan(deparse_namespace *dpns,
393 : deparse_namespace *save_dpns);
394 : static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
395 : int prettyFlags);
396 : static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
397 : int prettyFlags, int wrapColumn);
398 : static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
399 : TupleDesc resultDesc, bool colNamesVisible,
400 : int prettyFlags, int wrapColumn, int startIndent);
401 : static void get_values_def(List *values_lists, deparse_context *context);
402 : static void get_with_clause(Query *query, deparse_context *context);
403 : static void get_select_query_def(Query *query, deparse_context *context,
404 : TupleDesc resultDesc, bool colNamesVisible);
405 : static void get_insert_query_def(Query *query, deparse_context *context,
406 : bool colNamesVisible);
407 : static void get_update_query_def(Query *query, deparse_context *context,
408 : bool colNamesVisible);
409 : static void get_update_query_targetlist_def(Query *query, List *targetList,
410 : deparse_context *context,
411 : RangeTblEntry *rte);
412 : static void get_delete_query_def(Query *query, deparse_context *context,
413 : bool colNamesVisible);
414 : static void get_utility_query_def(Query *query, deparse_context *context);
415 : static void get_basic_select_query(Query *query, deparse_context *context,
416 : TupleDesc resultDesc, bool colNamesVisible);
417 : static void get_target_list(List *targetList, deparse_context *context,
418 : TupleDesc resultDesc, bool colNamesVisible);
419 : static void get_setop_query(Node *setOp, Query *query,
420 : deparse_context *context,
421 : TupleDesc resultDesc, bool colNamesVisible);
422 : static Node *get_rule_sortgroupclause(Index ref, List *tlist,
423 : bool force_colno,
424 : deparse_context *context);
425 : static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
426 : bool omit_parens, deparse_context *context);
427 : static void get_rule_orderby(List *orderList, List *targetList,
428 : bool force_colno, deparse_context *context);
429 : static void get_rule_windowclause(Query *query, deparse_context *context);
430 : static void get_rule_windowspec(WindowClause *wc, List *targetList,
431 : deparse_context *context);
432 : static char *get_variable(Var *var, int levelsup, bool istoplevel,
433 : deparse_context *context);
434 : static void get_special_variable(Node *node, deparse_context *context,
435 : void *callback_arg);
436 : static void resolve_special_varno(Node *node, deparse_context *context,
437 : rsv_callback callback, void *callback_arg);
438 : static Node *find_param_referent(Param *param, deparse_context *context,
439 : deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
440 : static void get_parameter(Param *param, deparse_context *context);
441 : static const char *get_simple_binary_op_name(OpExpr *expr);
442 : static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
443 : static void appendContextKeyword(deparse_context *context, const char *str,
444 : int indentBefore, int indentAfter, int indentPlus);
445 : static void removeStringInfoSpaces(StringInfo str);
446 : static void get_rule_expr(Node *node, deparse_context *context,
447 : bool showimplicit);
448 : static void get_rule_expr_toplevel(Node *node, deparse_context *context,
449 : bool showimplicit);
450 : static void get_rule_list_toplevel(List *lst, deparse_context *context,
451 : bool showimplicit);
452 : static void get_rule_expr_funccall(Node *node, deparse_context *context,
453 : bool showimplicit);
454 : static bool looks_like_function(Node *node);
455 : static void get_oper_expr(OpExpr *expr, deparse_context *context);
456 : static void get_func_expr(FuncExpr *expr, deparse_context *context,
457 : bool showimplicit);
458 : static void get_agg_expr(Aggref *aggref, deparse_context *context,
459 : Aggref *original_aggref);
460 : static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
461 : Aggref *original_aggref, const char *funcname,
462 : const char *options, bool is_json_objectagg);
463 : static void get_agg_combine_expr(Node *node, deparse_context *context,
464 : void *callback_arg);
465 : static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
466 : static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
467 : const char *funcname, const char *options,
468 : bool is_json_objectagg);
469 : static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
470 : static void get_coercion_expr(Node *arg, deparse_context *context,
471 : Oid resulttype, int32 resulttypmod,
472 : Node *parentNode);
473 : static void get_const_expr(Const *constval, deparse_context *context,
474 : int showtype);
475 : static void get_const_collation(Const *constval, deparse_context *context);
476 : static void get_json_format(JsonFormat *format, StringInfo buf);
477 : static void get_json_constructor(JsonConstructorExpr *ctor,
478 : deparse_context *context, bool showimplicit);
479 : static void get_json_constructor_options(JsonConstructorExpr *ctor,
480 : StringInfo buf);
481 : static void get_json_agg_constructor(JsonConstructorExpr *ctor,
482 : deparse_context *context,
483 : const char *funcname,
484 : bool is_json_objectagg);
485 : static void simple_quote_literal(StringInfo buf, const char *val);
486 : static void get_sublink_expr(SubLink *sublink, deparse_context *context);
487 : static void get_tablefunc(TableFunc *tf, deparse_context *context,
488 : bool showimplicit);
489 : static void get_from_clause(Query *query, const char *prefix,
490 : deparse_context *context);
491 : static void get_from_clause_item(Node *jtnode, Query *query,
492 : deparse_context *context);
493 : static void get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
494 : deparse_context *context);
495 : static void get_column_alias_list(deparse_columns *colinfo,
496 : deparse_context *context);
497 : static void get_from_clause_coldeflist(RangeTblFunction *rtfunc,
498 : deparse_columns *colinfo,
499 : deparse_context *context);
500 : static void get_tablesample_def(TableSampleClause *tablesample,
501 : deparse_context *context);
502 : static void get_opclass_name(Oid opclass, Oid actual_datatype,
503 : StringInfo buf);
504 : static Node *processIndirection(Node *node, deparse_context *context);
505 : static void printSubscripts(SubscriptingRef *sbsref, deparse_context *context);
506 : static char *get_relation_name(Oid relid);
507 : static char *generate_relation_name(Oid relid, List *namespaces);
508 : static char *generate_qualified_relation_name(Oid relid);
509 : static char *generate_function_name(Oid funcid, int nargs,
510 : List *argnames, Oid *argtypes,
511 : bool has_variadic, bool *use_variadic_p,
512 : ParseExprKind special_exprkind);
513 : static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
514 : static void add_cast_to(StringInfo buf, Oid typid);
515 : static char *generate_qualified_type_name(Oid typid);
516 : static text *string_to_text(char *str);
517 : static char *flatten_reloptions(Oid relid);
518 : static void get_reloptions(StringInfo buf, Datum reloptions);
519 :
520 : #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
521 :
522 :
523 : /* ----------
524 : * pg_get_ruledef - Do it all and return a text
525 : * that could be used as a statement
526 : * to recreate the rule
527 : * ----------
528 : */
529 : Datum
530 GIC 219 : pg_get_ruledef(PG_FUNCTION_ARGS)
531 : {
532 219 : Oid ruleoid = PG_GETARG_OID(0);
533 : int prettyFlags;
534 : char *res;
535 :
536 219 : prettyFlags = PRETTYFLAG_INDENT;
537 :
538 219 : res = pg_get_ruledef_worker(ruleoid, prettyFlags);
539 :
540 219 : if (res == NULL)
541 3 : PG_RETURN_NULL();
542 :
543 216 : PG_RETURN_TEXT_P(string_to_text(res));
544 : }
545 ECB :
546 :
547 : Datum
548 GIC 48 : pg_get_ruledef_ext(PG_FUNCTION_ARGS)
549 : {
550 48 : Oid ruleoid = PG_GETARG_OID(0);
551 CBC 48 : bool pretty = PG_GETARG_BOOL(1);
552 : int prettyFlags;
553 ECB : char *res;
554 :
555 CBC 48 : prettyFlags = GET_PRETTY_FLAGS(pretty);
556 ECB :
557 GIC 48 : res = pg_get_ruledef_worker(ruleoid, prettyFlags);
558 ECB :
559 GIC 48 : if (res == NULL)
560 UIC 0 : PG_RETURN_NULL();
561 :
562 GIC 48 : PG_RETURN_TEXT_P(string_to_text(res));
563 ECB : }
564 :
565 :
566 : static char *
567 GIC 267 : pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
568 : {
569 : Datum args[1];
570 ECB : char nulls[1];
571 : int spirc;
572 : HeapTuple ruletup;
573 : TupleDesc rulettc;
574 : StringInfoData buf;
575 EUB :
576 : /*
577 ECB : * Do this first so that string is alloc'd in outer context not SPI's.
578 : */
579 GIC 267 : initStringInfo(&buf);
580 :
581 : /*
582 ECB : * Connect to SPI manager
583 : */
584 GIC 267 : if (SPI_connect() != SPI_OK_CONNECT)
585 UIC 0 : elog(ERROR, "SPI_connect failed");
586 :
587 : /*
588 : * On the first call prepare the plan to lookup pg_rewrite. We read
589 : * pg_rewrite over the SPI manager instead of using the syscache to be
590 : * checked for read access on pg_rewrite.
591 : */
592 GIC 267 : if (plan_getrulebyoid == NULL)
593 : {
594 ECB : Oid argtypes[1];
595 : SPIPlanPtr plan;
596 :
597 GIC 17 : argtypes[0] = OIDOID;
598 17 : plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
599 CBC 17 : if (plan == NULL)
600 UBC 0 : elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
601 GIC 17 : SPI_keepplan(plan);
602 17 : plan_getrulebyoid = plan;
603 : }
604 :
605 : /*
606 : * Get the pg_rewrite tuple for this rule
607 ECB : */
608 GIC 267 : args[0] = ObjectIdGetDatum(ruleoid);
609 267 : nulls[0] = ' ';
610 267 : spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 0);
611 267 : if (spirc != SPI_OK_SELECT)
612 LBC 0 : elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
613 CBC 267 : if (SPI_processed != 1)
614 ECB : {
615 EUB : /*
616 ECB : * There is no tuple data available here, just keep the output buffer
617 : * empty.
618 : */
619 : }
620 : else
621 : {
622 : /*
623 : * Get the rule's definition and put it into executor's memory
624 : */
625 CBC 264 : ruletup = SPI_tuptable->vals[0];
626 264 : rulettc = SPI_tuptable->tupdesc;
627 GBC 264 : make_ruledef(&buf, ruletup, rulettc, prettyFlags);
628 ECB : }
629 :
630 : /*
631 : * Disconnect from SPI manager
632 : */
633 GIC 267 : if (SPI_finish() != SPI_OK_FINISH)
634 UIC 0 : elog(ERROR, "SPI_finish failed");
635 :
636 GIC 267 : if (buf.len == 0)
637 3 : return NULL;
638 :
639 264 : return buf.data;
640 ECB : }
641 :
642 :
643 : /* ----------
644 : * pg_get_viewdef - Mainly the same thing, but we
645 : * only return the SELECT part of a view
646 : * ----------
647 : */
648 : Datum
649 GBC 947 : pg_get_viewdef(PG_FUNCTION_ARGS)
650 : {
651 ECB : /* By OID */
652 CBC 947 : Oid viewoid = PG_GETARG_OID(0);
653 : int prettyFlags;
654 ECB : char *res;
655 :
656 GIC 947 : prettyFlags = PRETTYFLAG_INDENT;
657 :
658 947 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
659 :
660 947 : if (res == NULL)
661 3 : PG_RETURN_NULL();
662 :
663 944 : PG_RETURN_TEXT_P(string_to_text(res));
664 ECB : }
665 :
666 :
667 : Datum
668 GIC 233 : pg_get_viewdef_ext(PG_FUNCTION_ARGS)
669 : {
670 : /* By OID */
671 CBC 233 : Oid viewoid = PG_GETARG_OID(0);
672 GIC 233 : bool pretty = PG_GETARG_BOOL(1);
673 ECB : int prettyFlags;
674 : char *res;
675 :
676 CBC 233 : prettyFlags = GET_PRETTY_FLAGS(pretty);
677 :
678 233 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
679 :
680 GIC 233 : if (res == NULL)
681 UIC 0 : PG_RETURN_NULL();
682 :
683 CBC 233 : PG_RETURN_TEXT_P(string_to_text(res));
684 : }
685 :
686 ECB : Datum
687 CBC 3 : pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
688 : {
689 : /* By OID */
690 GIC 3 : Oid viewoid = PG_GETARG_OID(0);
691 CBC 3 : int wrap = PG_GETARG_INT32(1);
692 : int prettyFlags;
693 ECB : char *res;
694 :
695 : /* calling this implies we want pretty printing */
696 GBC 3 : prettyFlags = GET_PRETTY_FLAGS(true);
697 :
698 CBC 3 : res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
699 :
700 GIC 3 : if (res == NULL)
701 UIC 0 : PG_RETURN_NULL();
702 ECB :
703 GIC 3 : PG_RETURN_TEXT_P(string_to_text(res));
704 : }
705 ECB :
706 : Datum
707 GIC 36 : pg_get_viewdef_name(PG_FUNCTION_ARGS)
708 : {
709 : /* By qualified name */
710 36 : text *viewname = PG_GETARG_TEXT_PP(0);
711 ECB : int prettyFlags;
712 : RangeVar *viewrel;
713 : Oid viewoid;
714 : char *res;
715 :
716 GBC 36 : prettyFlags = PRETTYFLAG_INDENT;
717 :
718 ECB : /* Look up view name. Can't lock it - we might not have privileges. */
719 GIC 36 : viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
720 36 : viewoid = RangeVarGetRelid(viewrel, NoLock, false);
721 :
722 CBC 36 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
723 :
724 GIC 36 : if (res == NULL)
725 LBC 0 : PG_RETURN_NULL();
726 :
727 GIC 36 : PG_RETURN_TEXT_P(string_to_text(res));
728 : }
729 :
730 :
731 ECB : Datum
732 GIC 192 : pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
733 : {
734 ECB : /* By qualified name */
735 CBC 192 : text *viewname = PG_GETARG_TEXT_PP(0);
736 GIC 192 : bool pretty = PG_GETARG_BOOL(1);
737 ECB : int prettyFlags;
738 : RangeVar *viewrel;
739 : Oid viewoid;
740 EUB : char *res;
741 :
742 CBC 192 : prettyFlags = GET_PRETTY_FLAGS(pretty);
743 :
744 : /* Look up view name. Can't lock it - we might not have privileges. */
745 GIC 192 : viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
746 192 : viewoid = RangeVarGetRelid(viewrel, NoLock, false);
747 ECB :
748 GIC 192 : res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
749 :
750 CBC 192 : if (res == NULL)
751 LBC 0 : PG_RETURN_NULL();
752 :
753 GIC 192 : PG_RETURN_TEXT_P(string_to_text(res));
754 : }
755 :
756 : /*
757 ECB : * Common code for by-OID and by-name variants of pg_get_viewdef
758 : */
759 : static char *
760 CBC 1411 : pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
761 ECB : {
762 : Datum args[2];
763 : char nulls[2];
764 : int spirc;
765 : HeapTuple ruletup;
766 EUB : TupleDesc rulettc;
767 : StringInfoData buf;
768 ECB :
769 : /*
770 : * Do this first so that string is alloc'd in outer context not SPI's.
771 : */
772 GIC 1411 : initStringInfo(&buf);
773 :
774 : /*
775 ECB : * Connect to SPI manager
776 : */
777 GIC 1411 : if (SPI_connect() != SPI_OK_CONNECT)
778 UIC 0 : elog(ERROR, "SPI_connect failed");
779 :
780 : /*
781 : * On the first call prepare the plan to lookup pg_rewrite. We read
782 : * pg_rewrite over the SPI manager instead of using the syscache to be
783 : * checked for read access on pg_rewrite.
784 : */
785 GIC 1411 : if (plan_getviewrule == NULL)
786 : {
787 ECB : Oid argtypes[2];
788 : SPIPlanPtr plan;
789 :
790 GIC 108 : argtypes[0] = OIDOID;
791 108 : argtypes[1] = NAMEOID;
792 CBC 108 : plan = SPI_prepare(query_getviewrule, 2, argtypes);
793 GBC 108 : if (plan == NULL)
794 UIC 0 : elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
795 GIC 108 : SPI_keepplan(plan);
796 108 : plan_getviewrule = plan;
797 : }
798 :
799 : /*
800 ECB : * Get the pg_rewrite tuple for the view's SELECT rule
801 : */
802 GIC 1411 : args[0] = ObjectIdGetDatum(viewoid);
803 1411 : args[1] = DirectFunctionCall1(namein, CStringGetDatum(ViewSelectRuleName));
804 1411 : nulls[0] = ' ';
805 CBC 1411 : nulls[1] = ' ';
806 1411 : spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 0);
807 1411 : if (spirc != SPI_OK_SELECT)
808 LBC 0 : elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
809 GBC 1411 : if (SPI_processed != 1)
810 ECB : {
811 : /*
812 : * There is no tuple data available here, just keep the output buffer
813 : * empty.
814 : */
815 : }
816 : else
817 : {
818 : /*
819 : * Get the rule's definition and put it into executor's memory
820 : */
821 CBC 1408 : ruletup = SPI_tuptable->vals[0];
822 1408 : rulettc = SPI_tuptable->tupdesc;
823 GBC 1408 : make_viewdef(&buf, ruletup, rulettc, prettyFlags, wrapColumn);
824 ECB : }
825 :
826 : /*
827 : * Disconnect from SPI manager
828 : */
829 GIC 1411 : if (SPI_finish() != SPI_OK_FINISH)
830 UIC 0 : elog(ERROR, "SPI_finish failed");
831 :
832 GIC 1411 : if (buf.len == 0)
833 3 : return NULL;
834 :
835 1408 : return buf.data;
836 ECB : }
837 :
838 : /* ----------
839 : * pg_get_triggerdef - Get the definition of a trigger
840 : * ----------
841 : */
842 : Datum
843 GIC 102 : pg_get_triggerdef(PG_FUNCTION_ARGS)
844 ECB : {
845 GBC 102 : Oid trigid = PG_GETARG_OID(0);
846 : char *res;
847 ECB :
848 CBC 102 : res = pg_get_triggerdef_worker(trigid, false);
849 :
850 102 : if (res == NULL)
851 GIC 3 : PG_RETURN_NULL();
852 :
853 99 : PG_RETURN_TEXT_P(string_to_text(res));
854 : }
855 :
856 : Datum
857 576 : pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
858 ECB : {
859 GIC 576 : Oid trigid = PG_GETARG_OID(0);
860 CBC 576 : bool pretty = PG_GETARG_BOOL(1);
861 : char *res;
862 :
863 576 : res = pg_get_triggerdef_worker(trigid, pretty);
864 :
865 576 : if (res == NULL)
866 LBC 0 : PG_RETURN_NULL();
867 :
868 CBC 576 : PG_RETURN_TEXT_P(string_to_text(res));
869 : }
870 :
871 : static char *
872 678 : pg_get_triggerdef_worker(Oid trigid, bool pretty)
873 : {
874 ECB : HeapTuple ht_trig;
875 : Form_pg_trigger trigrec;
876 : StringInfoData buf;
877 : Relation tgrel;
878 : ScanKeyData skey[1];
879 : SysScanDesc tgscan;
880 CBC 678 : int findx = 0;
881 EUB : char *tgname;
882 : char *tgoldtable;
883 ECB : char *tgnewtable;
884 : Datum value;
885 : bool isnull;
886 :
887 : /*
888 : * Fetch the pg_trigger tuple by the Oid of the trigger
889 : */
890 GIC 678 : tgrel = table_open(TriggerRelationId, AccessShareLock);
891 :
892 678 : ScanKeyInit(&skey[0],
893 : Anum_pg_trigger_oid,
894 : BTEqualStrategyNumber, F_OIDEQ,
895 ECB : ObjectIdGetDatum(trigid));
896 :
897 GIC 678 : tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
898 : NULL, 1, skey);
899 :
900 678 : ht_trig = systable_getnext(tgscan);
901 :
902 678 : if (!HeapTupleIsValid(ht_trig))
903 : {
904 3 : systable_endscan(tgscan);
905 CBC 3 : table_close(tgrel, AccessShareLock);
906 GIC 3 : return NULL;
907 ECB : }
908 :
909 GIC 675 : trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
910 :
911 : /*
912 ECB : * Start the trigger definition. Note that the trigger's name should never
913 : * be schema-qualified, but the trigger rel's name may be.
914 : */
915 CBC 675 : initStringInfo(&buf);
916 :
917 675 : tgname = NameStr(trigrec->tgname);
918 GIC 1350 : appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
919 CBC 675 : OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
920 ECB : quote_identifier(tgname));
921 :
922 GIC 675 : if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
923 259 : appendStringInfoString(&buf, "BEFORE");
924 CBC 416 : else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
925 GIC 404 : appendStringInfoString(&buf, "AFTER");
926 12 : else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
927 12 : appendStringInfoString(&buf, "INSTEAD OF");
928 : else
929 UIC 0 : elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
930 ECB :
931 GIC 675 : if (TRIGGER_FOR_INSERT(trigrec->tgtype))
932 ECB : {
933 CBC 443 : appendStringInfoString(&buf, " INSERT");
934 443 : findx++;
935 : }
936 GIC 675 : if (TRIGGER_FOR_DELETE(trigrec->tgtype))
937 ECB : {
938 CBC 113 : if (findx > 0)
939 45 : appendStringInfoString(&buf, " OR DELETE");
940 ECB : else
941 CBC 68 : appendStringInfoString(&buf, " DELETE");
942 113 : findx++;
943 : }
944 GBC 675 : if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
945 : {
946 CBC 324 : if (findx > 0)
947 GIC 160 : appendStringInfoString(&buf, " OR UPDATE");
948 ECB : else
949 CBC 164 : appendStringInfoString(&buf, " UPDATE");
950 GIC 324 : findx++;
951 ECB : /* tgattr is first var-width field, so OK to access directly */
952 GIC 324 : if (trigrec->tgattr.dim1 > 0)
953 ECB : {
954 : int i;
955 :
956 CBC 38 : appendStringInfoString(&buf, " OF ");
957 84 : for (i = 0; i < trigrec->tgattr.dim1; i++)
958 : {
959 ECB : char *attname;
960 :
961 CBC 46 : if (i > 0)
962 8 : appendStringInfoString(&buf, ", ");
963 GIC 46 : attname = get_attname(trigrec->tgrelid,
964 CBC 46 : trigrec->tgattr.values[i], false);
965 46 : appendStringInfoString(&buf, quote_identifier(attname));
966 : }
967 ECB : }
968 : }
969 GIC 675 : if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
970 : {
971 LBC 0 : if (findx > 0)
972 0 : appendStringInfoString(&buf, " OR TRUNCATE");
973 : else
974 UIC 0 : appendStringInfoString(&buf, " TRUNCATE");
975 0 : findx++;
976 ECB : }
977 :
978 : /*
979 : * In non-pretty mode, always schema-qualify the target table name for
980 : * safety. In pretty mode, schema-qualify only if not visible.
981 : */
982 GIC 1350 : appendStringInfo(&buf, " ON %s ",
983 : pretty ?
984 CBC 69 : generate_relation_name(trigrec->tgrelid, NIL) :
985 GIC 606 : generate_qualified_relation_name(trigrec->tgrelid));
986 EUB :
987 GBC 675 : if (OidIsValid(trigrec->tgconstraint))
988 : {
989 UBC 0 : if (OidIsValid(trigrec->tgconstrrelid))
990 0 : appendStringInfo(&buf, "FROM %s ",
991 : generate_relation_name(trigrec->tgconstrrelid, NIL));
992 UIC 0 : if (!trigrec->tgdeferrable)
993 0 : appendStringInfoString(&buf, "NOT ");
994 0 : appendStringInfoString(&buf, "DEFERRABLE INITIALLY ");
995 0 : if (trigrec->tginitdeferred)
996 0 : appendStringInfoString(&buf, "DEFERRED ");
997 ECB : else
998 UIC 0 : appendStringInfoString(&buf, "IMMEDIATE ");
999 ECB : }
1000 :
1001 GIC 675 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
1002 ECB : tgrel->rd_att, &isnull);
1003 GIC 675 : if (!isnull)
1004 GBC 49 : tgoldtable = NameStr(*DatumGetName(value));
1005 EUB : else
1006 GIC 626 : tgoldtable = NULL;
1007 GBC 675 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
1008 EUB : tgrel->rd_att, &isnull);
1009 GBC 675 : if (!isnull)
1010 54 : tgnewtable = NameStr(*DatumGetName(value));
1011 EUB : else
1012 GIC 621 : tgnewtable = NULL;
1013 GBC 675 : if (tgoldtable != NULL || tgnewtable != NULL)
1014 : {
1015 GIC 76 : appendStringInfoString(&buf, "REFERENCING ");
1016 CBC 76 : if (tgoldtable != NULL)
1017 GIC 49 : appendStringInfo(&buf, "OLD TABLE AS %s ",
1018 ECB : quote_identifier(tgoldtable));
1019 CBC 76 : if (tgnewtable != NULL)
1020 GIC 54 : appendStringInfo(&buf, "NEW TABLE AS %s ",
1021 ECB : quote_identifier(tgnewtable));
1022 : }
1023 :
1024 CBC 675 : if (TRIGGER_FOR_ROW(trigrec->tgtype))
1025 520 : appendStringInfoString(&buf, "FOR EACH ROW ");
1026 : else
1027 155 : appendStringInfoString(&buf, "FOR EACH STATEMENT ");
1028 ECB :
1029 : /* If the trigger has a WHEN qualification, add that */
1030 CBC 675 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
1031 ECB : tgrel->rd_att, &isnull);
1032 CBC 675 : if (!isnull)
1033 : {
1034 ECB : Node *qual;
1035 : char relkind;
1036 : deparse_context context;
1037 : deparse_namespace dpns;
1038 : RangeTblEntry *oldrte;
1039 : RangeTblEntry *newrte;
1040 :
1041 GIC 72 : appendStringInfoString(&buf, "WHEN (");
1042 ECB :
1043 GIC 72 : qual = stringToNode(TextDatumGetCString(value));
1044 :
1045 CBC 72 : relkind = get_rel_relkind(trigrec->tgrelid);
1046 :
1047 ECB : /* Build minimal OLD and NEW RTEs for the rel */
1048 GIC 72 : oldrte = makeNode(RangeTblEntry);
1049 72 : oldrte->rtekind = RTE_RELATION;
1050 72 : oldrte->relid = trigrec->tgrelid;
1051 72 : oldrte->relkind = relkind;
1052 72 : oldrte->rellockmode = AccessShareLock;
1053 72 : oldrte->alias = makeAlias("old", NIL);
1054 72 : oldrte->eref = oldrte->alias;
1055 72 : oldrte->lateral = false;
1056 CBC 72 : oldrte->inh = false;
1057 GIC 72 : oldrte->inFromCl = true;
1058 ECB :
1059 GIC 72 : newrte = makeNode(RangeTblEntry);
1060 CBC 72 : newrte->rtekind = RTE_RELATION;
1061 GIC 72 : newrte->relid = trigrec->tgrelid;
1062 72 : newrte->relkind = relkind;
1063 CBC 72 : newrte->rellockmode = AccessShareLock;
1064 72 : newrte->alias = makeAlias("new", NIL);
1065 72 : newrte->eref = newrte->alias;
1066 72 : newrte->lateral = false;
1067 72 : newrte->inh = false;
1068 72 : newrte->inFromCl = true;
1069 ECB :
1070 : /* Build two-element rtable */
1071 CBC 72 : memset(&dpns, 0, sizeof(dpns));
1072 72 : dpns.rtable = list_make2(oldrte, newrte);
1073 GIC 72 : dpns.subplans = NIL;
1074 CBC 72 : dpns.ctes = NIL;
1075 72 : dpns.appendrels = NULL;
1076 72 : set_rtable_names(&dpns, NIL, NULL);
1077 72 : set_simple_column_names(&dpns);
1078 ECB :
1079 : /* Set up context with one-deep namespace stack */
1080 CBC 72 : context.buf = &buf;
1081 72 : context.namespaces = list_make1(&dpns);
1082 72 : context.windowClause = NIL;
1083 72 : context.windowTList = NIL;
1084 GIC 72 : context.varprefix = true;
1085 72 : context.prettyFlags = GET_PRETTY_FLAGS(pretty);
1086 CBC 72 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
1087 72 : context.indentLevel = PRETTYINDENT_STD;
1088 72 : context.special_exprkind = EXPR_KIND_NONE;
1089 72 : context.appendparents = NULL;
1090 ECB :
1091 CBC 72 : get_rule_expr(qual, &context, false);
1092 ECB :
1093 GIC 72 : appendStringInfoString(&buf, ") ");
1094 : }
1095 ECB :
1096 CBC 675 : appendStringInfo(&buf, "EXECUTE FUNCTION %s(",
1097 ECB : generate_function_name(trigrec->tgfoid, 0,
1098 : NIL, NULL,
1099 : false, NULL, EXPR_KIND_NONE));
1100 :
1101 CBC 675 : if (trigrec->tgnargs > 0)
1102 ECB : {
1103 : char *p;
1104 : int i;
1105 :
1106 CBC 225 : value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
1107 : tgrel->rd_att, &isnull);
1108 225 : if (isnull)
1109 UIC 0 : elog(ERROR, "tgargs is null for trigger %u", trigid);
1110 GIC 225 : p = (char *) VARDATA_ANY(DatumGetByteaPP(value));
1111 CBC 598 : for (i = 0; i < trigrec->tgnargs; i++)
1112 : {
1113 GIC 373 : if (i > 0)
1114 148 : appendStringInfoString(&buf, ", ");
1115 373 : simple_quote_literal(&buf, p);
1116 ECB : /* advance p to next string embedded in tgargs */
1117 GIC 3378 : while (*p)
1118 3005 : p++;
1119 373 : p++;
1120 : }
1121 ECB : }
1122 :
1123 : /* We deliberately do not put semi-colon at end */
1124 GBC 675 : appendStringInfoChar(&buf, ')');
1125 ECB :
1126 : /* Clean up */
1127 GIC 675 : systable_endscan(tgscan);
1128 ECB :
1129 CBC 675 : table_close(tgrel, AccessShareLock);
1130 ECB :
1131 GIC 675 : return buf.data;
1132 ECB : }
1133 :
1134 : /* ----------
1135 : * pg_get_indexdef - Get the definition of an index
1136 : *
1137 : * In the extended version, there is a colno argument as well as pretty bool.
1138 : * if colno == 0, we want a complete index definition.
1139 : * if colno > 0, we only want the Nth index key's variable or expression.
1140 : *
1141 : * Note that the SQL-function versions of this omit any info about the
1142 : * index tablespace; this is intentional because pg_dump wants it that way.
1143 : * However pg_get_indexdef_string() includes the index tablespace.
1144 : * ----------
1145 : */
1146 : Datum
1147 GIC 2088 : pg_get_indexdef(PG_FUNCTION_ARGS)
1148 : {
1149 2088 : Oid indexrelid = PG_GETARG_OID(0);
1150 : int prettyFlags;
1151 : char *res;
1152 :
1153 2088 : prettyFlags = PRETTYFLAG_INDENT;
1154 :
1155 2088 : res = pg_get_indexdef_worker(indexrelid, 0, NULL,
1156 : false, false,
1157 : false, false,
1158 : prettyFlags, true);
1159 :
1160 2088 : if (res == NULL)
1161 3 : PG_RETURN_NULL();
1162 ECB :
1163 GIC 2085 : PG_RETURN_TEXT_P(string_to_text(res));
1164 ECB : }
1165 :
1166 : Datum
1167 GIC 850 : pg_get_indexdef_ext(PG_FUNCTION_ARGS)
1168 ECB : {
1169 GIC 850 : Oid indexrelid = PG_GETARG_OID(0);
1170 CBC 850 : int32 colno = PG_GETARG_INT32(1);
1171 GIC 850 : bool pretty = PG_GETARG_BOOL(2);
1172 : int prettyFlags;
1173 : char *res;
1174 :
1175 CBC 850 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1176 ECB :
1177 GIC 850 : res = pg_get_indexdef_worker(indexrelid, colno, NULL,
1178 ECB : colno != 0, false,
1179 : false, false,
1180 : prettyFlags, true);
1181 :
1182 CBC 850 : if (res == NULL)
1183 UIC 0 : PG_RETURN_NULL();
1184 ECB :
1185 CBC 850 : PG_RETURN_TEXT_P(string_to_text(res));
1186 ECB : }
1187 :
1188 : /*
1189 : * Internal version for use by ALTER TABLE.
1190 : * Includes a tablespace clause in the result.
1191 : * Returns a palloc'd C string; no pretty-printing.
1192 : */
1193 : char *
1194 GIC 97 : pg_get_indexdef_string(Oid indexrelid)
1195 : {
1196 97 : return pg_get_indexdef_worker(indexrelid, 0, NULL,
1197 ECB : false, false,
1198 EUB : true, true,
1199 : 0, false);
1200 ECB : }
1201 :
1202 : /* Internal version that just reports the key-column definitions */
1203 : char *
1204 GIC 550 : pg_get_indexdef_columns(Oid indexrelid, bool pretty)
1205 : {
1206 : int prettyFlags;
1207 :
1208 550 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1209 ECB :
1210 GIC 550 : return pg_get_indexdef_worker(indexrelid, 0, NULL,
1211 ECB : true, true,
1212 : false, false,
1213 : prettyFlags, false);
1214 : }
1215 :
1216 : /*
1217 : * Internal workhorse to decompile an index definition.
1218 : *
1219 : * This is now used for exclusion constraints as well: if excludeOps is not
1220 : * NULL then it points to an array of exclusion operator OIDs.
1221 : */
1222 : static char *
1223 CBC 3637 : pg_get_indexdef_worker(Oid indexrelid, int colno,
1224 : const Oid *excludeOps,
1225 ECB : bool attrsOnly, bool keysOnly,
1226 : bool showTblSpc, bool inherits,
1227 : int prettyFlags, bool missing_ok)
1228 : {
1229 : /* might want a separate isConstraint parameter later */
1230 GIC 3637 : bool isConstraint = (excludeOps != NULL);
1231 : HeapTuple ht_idx;
1232 : HeapTuple ht_idxrel;
1233 : HeapTuple ht_am;
1234 : Form_pg_index idxrec;
1235 : Form_pg_class idxrelrec;
1236 : Form_pg_am amrec;
1237 : IndexAmRoutine *amroutine;
1238 ECB : List *indexprs;
1239 : ListCell *indexpr_item;
1240 : List *context;
1241 : Oid indrelid;
1242 : int keyno;
1243 : Datum indcollDatum;
1244 : Datum indclassDatum;
1245 : Datum indoptionDatum;
1246 : oidvector *indcollation;
1247 : oidvector *indclass;
1248 : int2vector *indoption;
1249 : StringInfoData buf;
1250 : char *str;
1251 : char *sep;
1252 :
1253 : /*
1254 : * Fetch the pg_index tuple by the Oid of the index
1255 : */
1256 GIC 3637 : ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
1257 3637 : if (!HeapTupleIsValid(ht_idx))
1258 : {
1259 3 : if (missing_ok)
1260 3 : return NULL;
1261 UIC 0 : elog(ERROR, "cache lookup failed for index %u", indexrelid);
1262 : }
1263 GIC 3634 : idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1264 :
1265 3634 : indrelid = idxrec->indrelid;
1266 3634 : Assert(indexrelid == idxrec->indexrelid);
1267 :
1268 : /* Must get indcollation, indclass, and indoption the hard way */
1269 GNC 3634 : indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1270 : Anum_pg_index_indcollation);
1271 GIC 3634 : indcollation = (oidvector *) DatumGetPointer(indcollDatum);
1272 ECB :
1273 GNC 3634 : indclassDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1274 : Anum_pg_index_indclass);
1275 CBC 3634 : indclass = (oidvector *) DatumGetPointer(indclassDatum);
1276 :
1277 GNC 3634 : indoptionDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1278 : Anum_pg_index_indoption);
1279 GIC 3634 : indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1280 ECB :
1281 : /*
1282 : * Fetch the pg_class tuple of the index relation
1283 : */
1284 CBC 3634 : ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
1285 GIC 3634 : if (!HeapTupleIsValid(ht_idxrel))
1286 LBC 0 : elog(ERROR, "cache lookup failed for relation %u", indexrelid);
1287 GIC 3634 : idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1288 ECB :
1289 : /*
1290 : * Fetch the pg_am tuple of the index' access method
1291 : */
1292 GIC 3634 : ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1293 3634 : if (!HeapTupleIsValid(ht_am))
1294 UIC 0 : elog(ERROR, "cache lookup failed for access method %u",
1295 ECB : idxrelrec->relam);
1296 CBC 3634 : amrec = (Form_pg_am) GETSTRUCT(ht_am);
1297 EUB :
1298 ECB : /* Fetch the index AM's API struct */
1299 GIC 3634 : amroutine = GetIndexAmRoutine(amrec->amhandler);
1300 :
1301 : /*
1302 : * Get the index expressions, if any. (NOTE: we do not use the relcache
1303 ECB : * versions of the expressions and predicate, because we want to display
1304 : * non-const-folded expressions.)
1305 EUB : */
1306 GIC 3634 : if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL))
1307 ECB : {
1308 : Datum exprsDatum;
1309 : char *exprsString;
1310 :
1311 GNC 276 : exprsDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1312 : Anum_pg_index_indexprs);
1313 GIC 276 : exprsString = TextDatumGetCString(exprsDatum);
1314 276 : indexprs = (List *) stringToNode(exprsString);
1315 CBC 276 : pfree(exprsString);
1316 : }
1317 : else
1318 GIC 3358 : indexprs = NIL;
1319 :
1320 CBC 3634 : indexpr_item = list_head(indexprs);
1321 :
1322 3634 : context = deparse_context_for(get_relation_name(indrelid), indrelid);
1323 ECB :
1324 : /*
1325 : * Start the index definition. Note that the index's name should never be
1326 : * schema-qualified, but the indexed rel's name may be.
1327 : */
1328 GIC 3634 : initStringInfo(&buf);
1329 ECB :
1330 GIC 3634 : if (!attrsOnly)
1331 ECB : {
1332 GIC 2859 : if (!isConstraint)
1333 5614 : appendStringInfo(&buf, "CREATE %sINDEX %s ON %s%s USING %s (",
1334 2807 : idxrec->indisunique ? "UNIQUE " : "",
1335 2807 : quote_identifier(NameStr(idxrelrec->relname)),
1336 2807 : idxrelrec->relkind == RELKIND_PARTITIONED_INDEX
1337 CBC 318 : && !inherits ? "ONLY " : "",
1338 GIC 2807 : (prettyFlags & PRETTYFLAG_SCHEMA) ?
1339 CBC 625 : generate_relation_name(indrelid, NIL) :
1340 GIC 2182 : generate_qualified_relation_name(indrelid),
1341 CBC 2807 : quote_identifier(NameStr(amrec->amname)));
1342 ECB : else /* currently, must be EXCLUDE constraint */
1343 CBC 52 : appendStringInfo(&buf, "EXCLUDE USING %s (",
1344 52 : quote_identifier(NameStr(amrec->amname)));
1345 ECB : }
1346 :
1347 : /*
1348 : * Report the indexed attributes
1349 : */
1350 CBC 3634 : sep = "";
1351 GIC 8973 : for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1352 ECB : {
1353 CBC 5387 : AttrNumber attnum = idxrec->indkey.values[keyno];
1354 : Oid keycoltype;
1355 : Oid keycolcollation;
1356 :
1357 : /*
1358 : * Ignore non-key attributes if told to.
1359 ECB : */
1360 CBC 5387 : if (keysOnly && keyno >= idxrec->indnkeyatts)
1361 GIC 48 : break;
1362 ECB :
1363 : /* Otherwise, print INCLUDE to divide key and non-key attrs. */
1364 GIC 5339 : if (!colno && keyno == idxrec->indnkeyatts)
1365 : {
1366 124 : appendStringInfoString(&buf, ") INCLUDE (");
1367 124 : sep = "";
1368 : }
1369 ECB :
1370 CBC 5339 : if (!colno)
1371 GIC 5024 : appendStringInfoString(&buf, sep);
1372 5339 : sep = ", ";
1373 ECB :
1374 GIC 5339 : if (attnum != 0)
1375 ECB : {
1376 : /* Simple index column */
1377 : char *attname;
1378 : int32 keycoltypmod;
1379 :
1380 CBC 4984 : attname = get_attname(indrelid, attnum, false);
1381 4984 : if (!colno || colno == keyno + 1)
1382 GIC 4900 : appendStringInfoString(&buf, quote_identifier(attname));
1383 CBC 4984 : get_atttypetypmodcoll(indrelid, attnum,
1384 : &keycoltype, &keycoltypmod,
1385 : &keycolcollation);
1386 : }
1387 : else
1388 : {
1389 ECB : /* expressional index */
1390 : Node *indexkey;
1391 :
1392 CBC 355 : if (indexpr_item == NULL)
1393 UIC 0 : elog(ERROR, "too few entries in indexprs list");
1394 GIC 355 : indexkey = (Node *) lfirst(indexpr_item);
1395 355 : indexpr_item = lnext(indexprs, indexpr_item);
1396 : /* Deparse */
1397 355 : str = deparse_expression_pretty(indexkey, context, false, false,
1398 : prettyFlags, 0);
1399 355 : if (!colno || colno == keyno + 1)
1400 : {
1401 ECB : /* Need parens if it's not a bare function call */
1402 GBC 349 : if (looks_like_function(indexkey))
1403 CBC 26 : appendStringInfoString(&buf, str);
1404 ECB : else
1405 GIC 323 : appendStringInfo(&buf, "(%s)", str);
1406 ECB : }
1407 GIC 355 : keycoltype = exprType(indexkey);
1408 CBC 355 : keycolcollation = exprCollation(indexkey);
1409 : }
1410 :
1411 ECB : /* Print additional decoration for (selected) key columns */
1412 CBC 5339 : if (!attrsOnly && keyno < idxrec->indnkeyatts &&
1413 UIC 0 : (!colno || colno == keyno + 1))
1414 ECB : {
1415 GIC 4169 : int16 opt = indoption->values[keyno];
1416 CBC 4169 : Oid indcoll = indcollation->values[keyno];
1417 4169 : Datum attoptions = get_attoptions(indexrelid, keyno + 1);
1418 GIC 4169 : bool has_options = attoptions != (Datum) 0;
1419 :
1420 : /* Add collation, if not default for column */
1421 CBC 4169 : if (OidIsValid(indcoll) && indcoll != keycolcollation)
1422 GBC 54 : appendStringInfo(&buf, " COLLATE %s",
1423 : generate_collation_name((indcoll)));
1424 ECB :
1425 : /* Add the operator class name, if not default */
1426 CBC 4169 : get_opclass_name(indclass->values[keyno],
1427 ECB : has_options ? InvalidOid : keycoltype, &buf);
1428 :
1429 GIC 4169 : if (has_options)
1430 ECB : {
1431 CBC 15 : appendStringInfoString(&buf, " (");
1432 GIC 15 : get_reloptions(&buf, attoptions);
1433 15 : appendStringInfoChar(&buf, ')');
1434 : }
1435 ECB :
1436 : /* Add options if relevant */
1437 GIC 4169 : if (amroutine->amcanorder)
1438 ECB : {
1439 : /* if it supports sort ordering, report DESC and NULLS opts */
1440 CBC 3520 : if (opt & INDOPTION_DESC)
1441 ECB : {
1442 LBC 0 : appendStringInfoString(&buf, " DESC");
1443 : /* NULLS FIRST is the default in this case */
1444 UIC 0 : if (!(opt & INDOPTION_NULLS_FIRST))
1445 0 : appendStringInfoString(&buf, " NULLS LAST");
1446 ECB : }
1447 : else
1448 : {
1449 CBC 3520 : if (opt & INDOPTION_NULLS_FIRST)
1450 UIC 0 : appendStringInfoString(&buf, " NULLS FIRST");
1451 EUB : }
1452 : }
1453 :
1454 : /* Add the exclusion operator if relevant */
1455 GIC 4169 : if (excludeOps != NULL)
1456 62 : appendStringInfo(&buf, " WITH %s",
1457 62 : generate_operator_name(excludeOps[keyno],
1458 ECB : keycoltype,
1459 EUB : keycoltype));
1460 : }
1461 : }
1462 :
1463 GIC 3634 : if (!attrsOnly)
1464 ECB : {
1465 CBC 2859 : appendStringInfoChar(&buf, ')');
1466 ECB :
1467 GIC 2859 : if (idxrec->indnullsnotdistinct)
1468 GNC 6 : appendStringInfoString(&buf, " NULLS NOT DISTINCT");
1469 :
1470 : /*
1471 : * If it has options, append "WITH (options)"
1472 ECB : */
1473 GIC 2859 : str = flatten_reloptions(indexrelid);
1474 CBC 2859 : if (str)
1475 : {
1476 105 : appendStringInfo(&buf, " WITH (%s)", str);
1477 105 : pfree(str);
1478 : }
1479 :
1480 : /*
1481 : * Print tablespace, but only if requested
1482 ECB : */
1483 CBC 2859 : if (showTblSpc)
1484 : {
1485 ECB : Oid tblspc;
1486 :
1487 GIC 97 : tblspc = get_rel_tablespace(indexrelid);
1488 97 : if (OidIsValid(tblspc))
1489 : {
1490 27 : if (isConstraint)
1491 UIC 0 : appendStringInfoString(&buf, " USING INDEX");
1492 CBC 27 : appendStringInfo(&buf, " TABLESPACE %s",
1493 GIC 27 : quote_identifier(get_tablespace_name(tblspc)));
1494 : }
1495 : }
1496 ECB :
1497 : /*
1498 : * If it's a partial index, decompile and append the predicate
1499 : */
1500 GBC 2859 : if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
1501 ECB : {
1502 : Node *node;
1503 : Datum predDatum;
1504 : char *predString;
1505 :
1506 : /* Convert text string to node tree */
1507 GNC 154 : predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
1508 : Anum_pg_index_indpred);
1509 GIC 154 : predString = TextDatumGetCString(predDatum);
1510 154 : node = (Node *) stringToNode(predString);
1511 154 : pfree(predString);
1512 :
1513 : /* Deparse */
1514 CBC 154 : str = deparse_expression_pretty(node, context, false, false,
1515 : prettyFlags, 0);
1516 154 : if (isConstraint)
1517 21 : appendStringInfo(&buf, " WHERE (%s)", str);
1518 ECB : else
1519 GIC 133 : appendStringInfo(&buf, " WHERE %s", str);
1520 : }
1521 ECB : }
1522 :
1523 : /* Clean up */
1524 CBC 3634 : ReleaseSysCache(ht_idx);
1525 GIC 3634 : ReleaseSysCache(ht_idxrel);
1526 CBC 3634 : ReleaseSysCache(ht_am);
1527 :
1528 GIC 3634 : return buf.data;
1529 : }
1530 :
1531 ECB : /* ----------
1532 : * pg_get_querydef
1533 : *
1534 : * Public entry point to deparse one query parsetree.
1535 : * The pretty flags are determined by GET_PRETTY_FLAGS(pretty).
1536 : *
1537 : * The result is a palloc'd C string.
1538 : * ----------
1539 : */
1540 : char *
1541 UIC 0 : pg_get_querydef(Query *query, bool pretty)
1542 : {
1543 : StringInfoData buf;
1544 : int prettyFlags;
1545 :
1546 0 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1547 :
1548 UBC 0 : initStringInfo(&buf);
1549 :
1550 UIC 0 : get_query_def(query, &buf, NIL, NULL, true,
1551 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
1552 :
1553 UBC 0 : return buf.data;
1554 : }
1555 EUB :
1556 : /*
1557 : * pg_get_statisticsobjdef
1558 : * Get the definition of an extended statistics object
1559 : */
1560 : Datum
1561 GIC 134 : pg_get_statisticsobjdef(PG_FUNCTION_ARGS)
1562 : {
1563 134 : Oid statextid = PG_GETARG_OID(0);
1564 : char *res;
1565 :
1566 134 : res = pg_get_statisticsobj_worker(statextid, false, true);
1567 :
1568 CBC 134 : if (res == NULL)
1569 GIC 3 : PG_RETURN_NULL();
1570 ECB :
1571 GIC 131 : PG_RETURN_TEXT_P(string_to_text(res));
1572 : }
1573 ECB :
1574 : /*
1575 : * Internal version for use by ALTER TABLE.
1576 : * Includes a tablespace clause in the result.
1577 : * Returns a palloc'd C string; no pretty-printing.
1578 : */
1579 : char *
1580 GIC 7 : pg_get_statisticsobjdef_string(Oid statextid)
1581 : {
1582 7 : return pg_get_statisticsobj_worker(statextid, false, false);
1583 : }
1584 :
1585 : /*
1586 : * pg_get_statisticsobjdef_columns
1587 ECB : * Get columns and expressions for an extended statistics object
1588 : */
1589 : Datum
1590 GIC 198 : pg_get_statisticsobjdef_columns(PG_FUNCTION_ARGS)
1591 : {
1592 198 : Oid statextid = PG_GETARG_OID(0);
1593 : char *res;
1594 :
1595 198 : res = pg_get_statisticsobj_worker(statextid, true, true);
1596 :
1597 CBC 198 : if (res == NULL)
1598 UIC 0 : PG_RETURN_NULL();
1599 ECB :
1600 GIC 198 : PG_RETURN_TEXT_P(string_to_text(res));
1601 : }
1602 ECB :
1603 : /*
1604 : * Internal workhorse to decompile an extended statistics object.
1605 EUB : */
1606 : static char *
1607 CBC 339 : pg_get_statisticsobj_worker(Oid statextid, bool columns_only, bool missing_ok)
1608 : {
1609 : Form_pg_statistic_ext statextrec;
1610 : HeapTuple statexttup;
1611 : StringInfoData buf;
1612 : int colno;
1613 : char *nsp;
1614 ECB : ArrayType *arr;
1615 : char *enabled;
1616 : Datum datum;
1617 : bool ndistinct_enabled;
1618 : bool dependencies_enabled;
1619 : bool mcv_enabled;
1620 : int i;
1621 : List *context;
1622 : ListCell *lc;
1623 GIC 339 : List *exprs = NIL;
1624 : bool has_exprs;
1625 : int ncolumns;
1626 :
1627 339 : statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1628 :
1629 CBC 339 : if (!HeapTupleIsValid(statexttup))
1630 : {
1631 GIC 3 : if (missing_ok)
1632 3 : return NULL;
1633 LBC 0 : elog(ERROR, "cache lookup failed for statistics object %u", statextid);
1634 : }
1635 ECB :
1636 : /* has the statistics expressions? */
1637 CBC 336 : has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1638 ECB :
1639 GBC 336 : statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1640 :
1641 : /*
1642 : * Get the statistics expressions, if any. (NOTE: we do not use the
1643 ECB : * relcache versions of the expressions, because we want to display
1644 : * non-const-folded expressions.)
1645 : */
1646 GIC 336 : if (has_exprs)
1647 : {
1648 : Datum exprsDatum;
1649 : char *exprsString;
1650 :
1651 GNC 71 : exprsDatum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1652 : Anum_pg_statistic_ext_stxexprs);
1653 GIC 71 : exprsString = TextDatumGetCString(exprsDatum);
1654 71 : exprs = (List *) stringToNode(exprsString);
1655 CBC 71 : pfree(exprsString);
1656 : }
1657 ECB : else
1658 CBC 265 : exprs = NIL;
1659 ECB :
1660 : /* count the number of columns (attributes and expressions) */
1661 GIC 336 : ncolumns = statextrec->stxkeys.dim1 + list_length(exprs);
1662 ECB :
1663 GIC 336 : initStringInfo(&buf);
1664 :
1665 CBC 336 : if (!columns_only)
1666 : {
1667 138 : nsp = get_namespace_name_or_temp(statextrec->stxnamespace);
1668 GIC 138 : appendStringInfo(&buf, "CREATE STATISTICS %s",
1669 ECB : quote_qualified_identifier(nsp,
1670 GIC 138 : NameStr(statextrec->stxname)));
1671 ECB :
1672 : /*
1673 : * Decode the stxkind column so that we know which stats types to
1674 : * print.
1675 : */
1676 GNC 138 : datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1677 : Anum_pg_statistic_ext_stxkind);
1678 GIC 138 : arr = DatumGetArrayTypeP(datum);
1679 CBC 138 : if (ARR_NDIM(arr) != 1 ||
1680 GIC 138 : ARR_HASNULL(arr) ||
1681 CBC 138 : ARR_ELEMTYPE(arr) != CHAROID)
1682 LBC 0 : elog(ERROR, "stxkind is not a 1-D char array");
1683 CBC 138 : enabled = (char *) ARR_DATA_PTR(arr);
1684 ECB :
1685 GBC 138 : ndistinct_enabled = false;
1686 CBC 138 : dependencies_enabled = false;
1687 GIC 138 : mcv_enabled = false;
1688 ECB :
1689 CBC 359 : for (i = 0; i < ARR_DIMS(arr)[0]; i++)
1690 ECB : {
1691 GIC 221 : if (enabled[i] == STATS_EXT_NDISTINCT)
1692 CBC 75 : ndistinct_enabled = true;
1693 GIC 146 : else if (enabled[i] == STATS_EXT_DEPENDENCIES)
1694 CBC 48 : dependencies_enabled = true;
1695 98 : else if (enabled[i] == STATS_EXT_MCV)
1696 57 : mcv_enabled = true;
1697 ECB :
1698 : /* ignore STATS_EXT_EXPRESSIONS (it's built automatically) */
1699 : }
1700 :
1701 : /*
1702 : * If any option is disabled, then we'll need to append the types
1703 : * clause to show which options are enabled. We omit the types clause
1704 : * on purpose when all options are enabled, so a pg_dump/pg_restore
1705 : * will create all statistics types on a newer postgres version, if
1706 : * the statistics had all options enabled on the original version.
1707 : *
1708 : * But if the statistics is defined on just a single column, it has to
1709 : * be an expression statistics. In that case we don't need to specify
1710 : * kinds.
1711 : */
1712 GIC 138 : if ((!ndistinct_enabled || !dependencies_enabled || !mcv_enabled) &&
1713 : (ncolumns > 1))
1714 : {
1715 CBC 63 : bool gotone = false;
1716 :
1717 GIC 63 : appendStringInfoString(&buf, " (");
1718 ECB :
1719 GIC 63 : if (ndistinct_enabled)
1720 ECB : {
1721 GIC 36 : appendStringInfoString(&buf, "ndistinct");
1722 CBC 36 : gotone = true;
1723 : }
1724 ECB :
1725 CBC 63 : if (dependencies_enabled)
1726 : {
1727 GIC 9 : appendStringInfo(&buf, "%sdependencies", gotone ? ", " : "");
1728 CBC 9 : gotone = true;
1729 : }
1730 ECB :
1731 CBC 63 : if (mcv_enabled)
1732 GIC 18 : appendStringInfo(&buf, "%smcv", gotone ? ", " : "");
1733 :
1734 CBC 63 : appendStringInfoChar(&buf, ')');
1735 ECB : }
1736 :
1737 CBC 138 : appendStringInfoString(&buf, " ON ");
1738 : }
1739 :
1740 ECB : /* decode simple column references */
1741 GIC 956 : for (colno = 0; colno < statextrec->stxkeys.dim1; colno++)
1742 : {
1743 620 : AttrNumber attnum = statextrec->stxkeys.values[colno];
1744 ECB : char *attname;
1745 :
1746 CBC 620 : if (colno > 0)
1747 GIC 349 : appendStringInfoString(&buf, ", ");
1748 :
1749 CBC 620 : attname = get_attname(statextrec->stxrelid, attnum, false);
1750 ECB :
1751 GIC 620 : appendStringInfoString(&buf, quote_identifier(attname));
1752 ECB : }
1753 :
1754 CBC 336 : context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1755 : statextrec->stxrelid);
1756 :
1757 450 : foreach(lc, exprs)
1758 : {
1759 GIC 114 : Node *expr = (Node *) lfirst(lc);
1760 ECB : char *str;
1761 GIC 114 : int prettyFlags = PRETTYFLAG_PAREN;
1762 ECB :
1763 GIC 114 : str = deparse_expression_pretty(expr, context, false, false,
1764 ECB : prettyFlags, 0);
1765 :
1766 CBC 114 : if (colno > 0)
1767 GIC 49 : appendStringInfoString(&buf, ", ");
1768 :
1769 ECB : /* Need parens if it's not a bare function call */
1770 CBC 114 : if (looks_like_function(expr))
1771 GIC 17 : appendStringInfoString(&buf, str);
1772 : else
1773 CBC 97 : appendStringInfo(&buf, "(%s)", str);
1774 ECB :
1775 GIC 114 : colno++;
1776 ECB : }
1777 :
1778 CBC 336 : if (!columns_only)
1779 GIC 138 : appendStringInfo(&buf, " FROM %s",
1780 : generate_relation_name(statextrec->stxrelid, NIL));
1781 ECB :
1782 CBC 336 : ReleaseSysCache(statexttup);
1783 :
1784 GIC 336 : return buf.data;
1785 ECB : }
1786 :
1787 : /*
1788 : * Generate text array of expressions for statistics object.
1789 : */
1790 : Datum
1791 UIC 0 : pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
1792 : {
1793 0 : Oid statextid = PG_GETARG_OID(0);
1794 EUB : Form_pg_statistic_ext statextrec;
1795 : HeapTuple statexttup;
1796 : Datum datum;
1797 : List *context;
1798 : ListCell *lc;
1799 UIC 0 : List *exprs = NIL;
1800 : bool has_exprs;
1801 EUB : char *tmp;
1802 UIC 0 : ArrayBuildState *astate = NULL;
1803 :
1804 UBC 0 : statexttup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statextid));
1805 :
1806 0 : if (!HeapTupleIsValid(statexttup))
1807 UIC 0 : PG_RETURN_NULL();
1808 EUB :
1809 : /* Does the stats object have expressions? */
1810 UIC 0 : has_exprs = !heap_attisnull(statexttup, Anum_pg_statistic_ext_stxexprs, NULL);
1811 :
1812 EUB : /* no expressions? we're done */
1813 UIC 0 : if (!has_exprs)
1814 : {
1815 UBC 0 : ReleaseSysCache(statexttup);
1816 UIC 0 : PG_RETURN_NULL();
1817 EUB : }
1818 :
1819 UIC 0 : statextrec = (Form_pg_statistic_ext) GETSTRUCT(statexttup);
1820 :
1821 EUB : /*
1822 : * Get the statistics expressions, and deparse them into text values.
1823 : */
1824 UNC 0 : datum = SysCacheGetAttrNotNull(STATEXTOID, statexttup,
1825 : Anum_pg_statistic_ext_stxexprs);
1826 UBC 0 : tmp = TextDatumGetCString(datum);
1827 0 : exprs = (List *) stringToNode(tmp);
1828 0 : pfree(tmp);
1829 :
1830 0 : context = deparse_context_for(get_relation_name(statextrec->stxrelid),
1831 : statextrec->stxrelid);
1832 :
1833 0 : foreach(lc, exprs)
1834 : {
1835 0 : Node *expr = (Node *) lfirst(lc);
1836 : char *str;
1837 0 : int prettyFlags = PRETTYFLAG_INDENT;
1838 :
1839 0 : str = deparse_expression_pretty(expr, context, false, false,
1840 : prettyFlags, 0);
1841 :
1842 0 : astate = accumArrayResult(astate,
1843 0 : PointerGetDatum(cstring_to_text(str)),
1844 : false,
1845 : TEXTOID,
1846 : CurrentMemoryContext);
1847 : }
1848 :
1849 0 : ReleaseSysCache(statexttup);
1850 :
1851 0 : PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
1852 : }
1853 :
1854 : /*
1855 : * pg_get_partkeydef
1856 : *
1857 : * Returns the partition key specification, ie, the following:
1858 : *
1859 : * { RANGE | LIST | HASH } (column opt_collation opt_opclass [, ...])
1860 : */
1861 : Datum
1862 CBC 586 : pg_get_partkeydef(PG_FUNCTION_ARGS)
1863 : {
1864 586 : Oid relid = PG_GETARG_OID(0);
1865 : char *res;
1866 :
1867 586 : res = pg_get_partkeydef_worker(relid, PRETTYFLAG_INDENT, false, true);
1868 :
1869 586 : if (res == NULL)
1870 3 : PG_RETURN_NULL();
1871 :
1872 583 : PG_RETURN_TEXT_P(string_to_text(res));
1873 : }
1874 :
1875 : /* Internal version that just reports the column definitions */
1876 : char *
1877 68 : pg_get_partkeydef_columns(Oid relid, bool pretty)
1878 : {
1879 : int prettyFlags;
1880 :
1881 68 : prettyFlags = GET_PRETTY_FLAGS(pretty);
1882 :
1883 68 : return pg_get_partkeydef_worker(relid, prettyFlags, true, false);
1884 : }
1885 :
1886 : /*
1887 : * Internal workhorse to decompile a partition key definition.
1888 : */
1889 : static char *
1890 654 : pg_get_partkeydef_worker(Oid relid, int prettyFlags,
1891 : bool attrsOnly, bool missing_ok)
1892 : {
1893 : Form_pg_partitioned_table form;
1894 : HeapTuple tuple;
1895 : oidvector *partclass;
1896 : oidvector *partcollation;
1897 : List *partexprs;
1898 : ListCell *partexpr_item;
1899 : List *context;
1900 : Datum datum;
1901 : StringInfoData buf;
1902 : int keyno;
1903 : char *str;
1904 : char *sep;
1905 ECB :
1906 CBC 654 : tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid));
1907 GIC 654 : if (!HeapTupleIsValid(tuple))
1908 ECB : {
1909 CBC 3 : if (missing_ok)
1910 GBC 3 : return NULL;
1911 UIC 0 : elog(ERROR, "cache lookup failed for partition key of %u", relid);
1912 : }
1913 ECB :
1914 GIC 651 : form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
1915 ECB :
1916 GIC 651 : Assert(form->partrelid == relid);
1917 :
1918 ECB : /* Must get partclass and partcollation the hard way */
1919 GNC 651 : datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1920 : Anum_pg_partitioned_table_partclass);
1921 CBC 651 : partclass = (oidvector *) DatumGetPointer(datum);
1922 :
1923 GNC 651 : datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1924 : Anum_pg_partitioned_table_partcollation);
1925 GIC 651 : partcollation = (oidvector *) DatumGetPointer(datum);
1926 :
1927 :
1928 : /*
1929 : * Get the expressions, if any. (NOTE: we do not use the relcache
1930 ECB : * versions of the expressions, because we want to display
1931 : * non-const-folded expressions.)
1932 : */
1933 GIC 651 : if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
1934 : {
1935 ECB : Datum exprsDatum;
1936 : char *exprsString;
1937 :
1938 GNC 73 : exprsDatum = SysCacheGetAttrNotNull(PARTRELID, tuple,
1939 : Anum_pg_partitioned_table_partexprs);
1940 GIC 73 : exprsString = TextDatumGetCString(exprsDatum);
1941 73 : partexprs = (List *) stringToNode(exprsString);
1942 ECB :
1943 GIC 73 : if (!IsA(partexprs, List))
1944 UIC 0 : elog(ERROR, "unexpected node type found in partexprs: %d",
1945 ECB : (int) nodeTag(partexprs));
1946 :
1947 CBC 73 : pfree(exprsString);
1948 ECB : }
1949 : else
1950 CBC 578 : partexprs = NIL;
1951 :
1952 651 : partexpr_item = list_head(partexprs);
1953 GIC 651 : context = deparse_context_for(get_relation_name(relid), relid);
1954 ECB :
1955 CBC 651 : initStringInfo(&buf);
1956 ECB :
1957 CBC 651 : switch (form->partstrat)
1958 ECB : {
1959 CBC 27 : case PARTITION_STRATEGY_HASH:
1960 27 : if (!attrsOnly)
1961 27 : appendStringInfoString(&buf, "HASH");
1962 27 : break;
1963 220 : case PARTITION_STRATEGY_LIST:
1964 220 : if (!attrsOnly)
1965 200 : appendStringInfoString(&buf, "LIST");
1966 GBC 220 : break;
1967 404 : case PARTITION_STRATEGY_RANGE:
1968 GIC 404 : if (!attrsOnly)
1969 356 : appendStringInfoString(&buf, "RANGE");
1970 404 : break;
1971 LBC 0 : default:
1972 0 : elog(ERROR, "unexpected partition strategy: %d",
1973 ECB : (int) form->partstrat);
1974 : }
1975 :
1976 CBC 651 : if (!attrsOnly)
1977 GIC 583 : appendStringInfoString(&buf, " (");
1978 651 : sep = "";
1979 1378 : for (keyno = 0; keyno < form->partnatts; keyno++)
1980 : {
1981 CBC 727 : AttrNumber attnum = form->partattrs.values[keyno];
1982 ECB : Oid keycoltype;
1983 : Oid keycolcollation;
1984 : Oid partcoll;
1985 :
1986 GIC 727 : appendStringInfoString(&buf, sep);
1987 727 : sep = ", ";
1988 727 : if (attnum != 0)
1989 ECB : {
1990 : /* Simple attribute reference */
1991 : char *attname;
1992 : int32 keycoltypmod;
1993 :
1994 GIC 648 : attname = get_attname(relid, attnum, false);
1995 648 : appendStringInfoString(&buf, quote_identifier(attname));
1996 648 : get_atttypetypmodcoll(relid, attnum,
1997 : &keycoltype, &keycoltypmod,
1998 : &keycolcollation);
1999 : }
2000 ECB : else
2001 EUB : {
2002 ECB : /* Expression */
2003 : Node *partkey;
2004 :
2005 GIC 79 : if (partexpr_item == NULL)
2006 LBC 0 : elog(ERROR, "too few entries in partexprs list");
2007 GIC 79 : partkey = (Node *) lfirst(partexpr_item);
2008 79 : partexpr_item = lnext(partexprs, partexpr_item);
2009 ECB :
2010 : /* Deparse */
2011 GIC 79 : str = deparse_expression_pretty(partkey, context, false, false,
2012 ECB : prettyFlags, 0);
2013 : /* Need parens if it's not a bare function call */
2014 CBC 79 : if (looks_like_function(partkey))
2015 28 : appendStringInfoString(&buf, str);
2016 : else
2017 GIC 51 : appendStringInfo(&buf, "(%s)", str);
2018 :
2019 CBC 79 : keycoltype = exprType(partkey);
2020 79 : keycolcollation = exprCollation(partkey);
2021 ECB : }
2022 :
2023 : /* Add collation, if not default for column */
2024 GIC 727 : partcoll = partcollation->values[keyno];
2025 CBC 727 : if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
2026 3 : appendStringInfo(&buf, " COLLATE %s",
2027 : generate_collation_name((partcoll)));
2028 :
2029 ECB : /* Add the operator class name, if not default */
2030 CBC 727 : if (!attrsOnly)
2031 GIC 632 : get_opclass_name(partclass->values[keyno], keycoltype, &buf);
2032 : }
2033 ECB :
2034 GIC 651 : if (!attrsOnly)
2035 CBC 583 : appendStringInfoChar(&buf, ')');
2036 :
2037 : /* Clean up */
2038 GIC 651 : ReleaseSysCache(tuple);
2039 :
2040 651 : return buf.data;
2041 : }
2042 :
2043 : /*
2044 ECB : * pg_get_partition_constraintdef
2045 : *
2046 : * Returns partition constraint expression as a string for the input relation
2047 : */
2048 : Datum
2049 GIC 78 : pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
2050 : {
2051 78 : Oid relationId = PG_GETARG_OID(0);
2052 ECB : Expr *constr_expr;
2053 : int prettyFlags;
2054 : List *context;
2055 : char *consrc;
2056 :
2057 GIC 78 : constr_expr = get_partition_qual_relid(relationId);
2058 :
2059 : /* Quick exit if no partition constraint */
2060 78 : if (constr_expr == NULL)
2061 CBC 9 : PG_RETURN_NULL();
2062 ECB :
2063 : /*
2064 : * Deparse and return the constraint expression.
2065 : */
2066 CBC 69 : prettyFlags = PRETTYFLAG_INDENT;
2067 GIC 69 : context = deparse_context_for(get_relation_name(relationId), relationId);
2068 69 : consrc = deparse_expression_pretty((Node *) constr_expr, context, false,
2069 : false, prettyFlags, 0);
2070 :
2071 69 : PG_RETURN_TEXT_P(string_to_text(consrc));
2072 : }
2073 :
2074 : /*
2075 : * pg_get_partconstrdef_string
2076 ECB : *
2077 : * Returns the partition constraint as a C-string for the input relation, with
2078 : * the given alias. No pretty-printing.
2079 : */
2080 : char *
2081 CBC 43 : pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
2082 ECB : {
2083 : Expr *constr_expr;
2084 : List *context;
2085 :
2086 GIC 43 : constr_expr = get_partition_qual_relid(partitionId);
2087 43 : context = deparse_context_for(aliasname, partitionId);
2088 :
2089 43 : return deparse_expression((Node *) constr_expr, context, true, false);
2090 : }
2091 :
2092 : /*
2093 : * pg_get_constraintdef
2094 ECB : *
2095 : * Returns the definition for the constraint, ie, everything that needs to
2096 : * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
2097 : */
2098 : Datum
2099 GIC 843 : pg_get_constraintdef(PG_FUNCTION_ARGS)
2100 ECB : {
2101 GIC 843 : Oid constraintId = PG_GETARG_OID(0);
2102 ECB : int prettyFlags;
2103 : char *res;
2104 :
2105 CBC 843 : prettyFlags = PRETTYFLAG_INDENT;
2106 :
2107 843 : res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2108 :
2109 GIC 843 : if (res == NULL)
2110 3 : PG_RETURN_NULL();
2111 ECB :
2112 GIC 840 : PG_RETURN_TEXT_P(string_to_text(res));
2113 ECB : }
2114 :
2115 : Datum
2116 GIC 1521 : pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
2117 : {
2118 CBC 1521 : Oid constraintId = PG_GETARG_OID(0);
2119 GIC 1521 : bool pretty = PG_GETARG_BOOL(1);
2120 ECB : int prettyFlags;
2121 : char *res;
2122 :
2123 GBC 1521 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2124 :
2125 CBC 1521 : res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true);
2126 :
2127 GIC 1521 : if (res == NULL)
2128 UIC 0 : PG_RETURN_NULL();
2129 :
2130 GIC 1521 : PG_RETURN_TEXT_P(string_to_text(res));
2131 : }
2132 ECB :
2133 : /*
2134 : * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command
2135 : */
2136 : char *
2137 GIC 202 : pg_get_constraintdef_command(Oid constraintId)
2138 : {
2139 202 : return pg_get_constraintdef_worker(constraintId, true, 0, false);
2140 : }
2141 ECB :
2142 : /*
2143 : * As of 9.4, we now use an MVCC snapshot for this.
2144 : */
2145 : static char *
2146 GIC 2566 : pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
2147 : int prettyFlags, bool missing_ok)
2148 : {
2149 ECB : HeapTuple tup;
2150 : Form_pg_constraint conForm;
2151 : StringInfoData buf;
2152 : SysScanDesc scandesc;
2153 : ScanKeyData scankey[1];
2154 GIC 2566 : Snapshot snapshot = RegisterSnapshot(GetTransactionSnapshot());
2155 2566 : Relation relation = table_open(ConstraintRelationId, AccessShareLock);
2156 :
2157 CBC 2566 : ScanKeyInit(&scankey[0],
2158 : Anum_pg_constraint_oid,
2159 : BTEqualStrategyNumber, F_OIDEQ,
2160 : ObjectIdGetDatum(constraintId));
2161 :
2162 GIC 2566 : scandesc = systable_beginscan(relation,
2163 : ConstraintOidIndexId,
2164 : true,
2165 : snapshot,
2166 : 1,
2167 : scankey);
2168 ECB :
2169 : /*
2170 : * We later use the tuple with SysCacheGetAttr() as if we had obtained it
2171 : * via SearchSysCache, which works fine.
2172 : */
2173 GIC 2566 : tup = systable_getnext(scandesc);
2174 ECB :
2175 GIC 2566 : UnregisterSnapshot(snapshot);
2176 ECB :
2177 CBC 2566 : if (!HeapTupleIsValid(tup))
2178 ECB : {
2179 GIC 3 : if (missing_ok)
2180 EUB : {
2181 GIC 3 : systable_endscan(scandesc);
2182 3 : table_close(relation, AccessShareLock);
2183 CBC 3 : return NULL;
2184 : }
2185 LBC 0 : elog(ERROR, "could not find tuple for constraint %u", constraintId);
2186 : }
2187 ECB :
2188 GIC 2563 : conForm = (Form_pg_constraint) GETSTRUCT(tup);
2189 ECB :
2190 GIC 2563 : initStringInfo(&buf);
2191 :
2192 2563 : if (fullCommand)
2193 : {
2194 202 : if (OidIsValid(conForm->conrelid))
2195 : {
2196 : /*
2197 : * Currently, callers want ALTER TABLE (without ONLY) for CHECK
2198 ECB : * constraints, and other types of constraints don't inherit
2199 : * anyway so it doesn't matter whether we say ONLY or not. Someday
2200 : * we might need to let callers specify whether to put ONLY in the
2201 : * command.
2202 : */
2203 GIC 195 : appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
2204 : generate_qualified_relation_name(conForm->conrelid),
2205 CBC 195 : quote_identifier(NameStr(conForm->conname)));
2206 ECB : }
2207 : else
2208 : {
2209 : /* Must be a domain constraint */
2210 GIC 7 : Assert(OidIsValid(conForm->contypid));
2211 7 : appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
2212 ECB : generate_qualified_type_name(conForm->contypid),
2213 GIC 7 : quote_identifier(NameStr(conForm->conname)));
2214 ECB : }
2215 : }
2216 :
2217 GIC 2563 : switch (conForm->contype)
2218 : {
2219 314 : case CONSTRAINT_FOREIGN:
2220 : {
2221 ECB : Datum val;
2222 : bool isnull;
2223 : const char *string;
2224 :
2225 : /* Start off the constraint definition */
2226 GIC 314 : appendStringInfoString(&buf, "FOREIGN KEY (");
2227 ECB :
2228 : /* Fetch and build referencing-column list */
2229 GNC 314 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2230 : Anum_pg_constraint_conkey);
2231 :
2232 CBC 314 : decompile_column_index_array(val, conForm->conrelid, &buf);
2233 :
2234 : /* add foreign relation name */
2235 314 : appendStringInfo(&buf, ") REFERENCES %s(",
2236 : generate_relation_name(conForm->confrelid,
2237 ECB : NIL));
2238 :
2239 : /* Fetch and build referenced-column list */
2240 GNC 314 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2241 : Anum_pg_constraint_confkey);
2242 EUB :
2243 GBC 314 : decompile_column_index_array(val, conForm->confrelid, &buf);
2244 EUB :
2245 CBC 314 : appendStringInfoChar(&buf, ')');
2246 ECB :
2247 : /* Add match type */
2248 GBC 314 : switch (conForm->confmatchtype)
2249 EUB : {
2250 GIC 17 : case FKCONSTR_MATCH_FULL:
2251 17 : string = " MATCH FULL";
2252 17 : break;
2253 UIC 0 : case FKCONSTR_MATCH_PARTIAL:
2254 LBC 0 : string = " MATCH PARTIAL";
2255 UIC 0 : break;
2256 GIC 297 : case FKCONSTR_MATCH_SIMPLE:
2257 CBC 297 : string = "";
2258 GIC 297 : break;
2259 LBC 0 : default:
2260 0 : elog(ERROR, "unrecognized confmatchtype: %d",
2261 ECB : conForm->confmatchtype);
2262 EUB : string = ""; /* keep compiler quiet */
2263 : break;
2264 : }
2265 CBC 314 : appendStringInfoString(&buf, string);
2266 ECB :
2267 : /* Add ON UPDATE and ON DELETE clauses, if needed */
2268 CBC 314 : switch (conForm->confupdtype)
2269 ECB : {
2270 CBC 252 : case FKCONSTR_ACTION_NOACTION:
2271 GBC 252 : string = NULL; /* suppress default */
2272 252 : break;
2273 UBC 0 : case FKCONSTR_ACTION_RESTRICT:
2274 0 : string = "RESTRICT";
2275 0 : break;
2276 GIC 48 : case FKCONSTR_ACTION_CASCADE:
2277 48 : string = "CASCADE";
2278 48 : break;
2279 14 : case FKCONSTR_ACTION_SETNULL:
2280 CBC 14 : string = "SET NULL";
2281 14 : break;
2282 UIC 0 : case FKCONSTR_ACTION_SETDEFAULT:
2283 LBC 0 : string = "SET DEFAULT";
2284 UIC 0 : break;
2285 LBC 0 : default:
2286 0 : elog(ERROR, "unrecognized confupdtype: %d",
2287 ECB : conForm->confupdtype);
2288 EUB : string = NULL; /* keep compiler quiet */
2289 : break;
2290 : }
2291 CBC 314 : if (string)
2292 62 : appendStringInfo(&buf, " ON UPDATE %s", string);
2293 ECB :
2294 CBC 314 : switch (conForm->confdeltype)
2295 ECB : {
2296 CBC 254 : case FKCONSTR_ACTION_NOACTION:
2297 254 : string = NULL; /* suppress default */
2298 254 : break;
2299 LBC 0 : case FKCONSTR_ACTION_RESTRICT:
2300 UBC 0 : string = "RESTRICT";
2301 0 : break;
2302 GIC 48 : case FKCONSTR_ACTION_CASCADE:
2303 48 : string = "CASCADE";
2304 48 : break;
2305 9 : case FKCONSTR_ACTION_SETNULL:
2306 CBC 9 : string = "SET NULL";
2307 9 : break;
2308 GIC 3 : case FKCONSTR_ACTION_SETDEFAULT:
2309 3 : string = "SET DEFAULT";
2310 3 : break;
2311 UIC 0 : default:
2312 0 : elog(ERROR, "unrecognized confdeltype: %d",
2313 ECB : conForm->confdeltype);
2314 : string = NULL; /* keep compiler quiet */
2315 : break;
2316 : }
2317 CBC 314 : if (string)
2318 60 : appendStringInfo(&buf, " ON DELETE %s", string);
2319 ECB :
2320 : /*
2321 : * Add columns specified to SET NULL or SET DEFAULT if
2322 : * provided.
2323 : */
2324 CBC 314 : val = SysCacheGetAttr(CONSTROID, tup,
2325 : Anum_pg_constraint_confdelsetcols, &isnull);
2326 GIC 314 : if (!isnull)
2327 : {
2328 GNC 6 : appendStringInfoString(&buf, " (");
2329 GIC 6 : decompile_column_index_array(val, conForm->conrelid, &buf);
2330 GNC 6 : appendStringInfoChar(&buf, ')');
2331 : }
2332 :
2333 CBC 314 : break;
2334 ECB : }
2335 GIC 1199 : case CONSTRAINT_PRIMARY:
2336 ECB : case CONSTRAINT_UNIQUE:
2337 : {
2338 : Datum val;
2339 : Oid indexId;
2340 : int keyatts;
2341 EUB : HeapTuple indtup;
2342 ECB :
2343 : /* Start off the constraint definition */
2344 GBC 1199 : if (conForm->contype == CONSTRAINT_PRIMARY)
2345 GIC 1047 : appendStringInfoString(&buf, "PRIMARY KEY ");
2346 ECB : else
2347 GIC 152 : appendStringInfoString(&buf, "UNIQUE ");
2348 :
2349 CBC 1199 : indexId = conForm->conindid;
2350 :
2351 GIC 1199 : indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
2352 CBC 1199 : if (!HeapTupleIsValid(indtup))
2353 UIC 0 : elog(ERROR, "cache lookup failed for index %u", indexId);
2354 CBC 1199 : if (conForm->contype == CONSTRAINT_UNIQUE &&
2355 GIC 152 : ((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
2356 UIC 0 : appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
2357 ECB :
2358 GNC 1199 : appendStringInfoChar(&buf, '(');
2359 ECB :
2360 : /* Fetch and build target column list */
2361 GNC 1199 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2362 : Anum_pg_constraint_conkey);
2363 ECB :
2364 GIC 1199 : keyatts = decompile_column_index_array(val, conForm->conrelid, &buf);
2365 ECB :
2366 GIC 1199 : appendStringInfoChar(&buf, ')');
2367 :
2368 ECB : /* Build including column list (from pg_index.indkeys) */
2369 GNC 1199 : val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2370 : Anum_pg_index_indnatts);
2371 GIC 1199 : if (DatumGetInt32(val) > keyatts)
2372 : {
2373 ECB : Datum cols;
2374 : Datum *keys;
2375 : int nKeys;
2376 : int j;
2377 :
2378 GIC 41 : appendStringInfoString(&buf, " INCLUDE (");
2379 :
2380 GNC 41 : cols = SysCacheGetAttrNotNull(INDEXRELID, indtup,
2381 : Anum_pg_index_indkey);
2382 :
2383 41 : deconstruct_array_builtin(DatumGetArrayTypeP(cols), INT2OID,
2384 : &keys, NULL, &nKeys);
2385 :
2386 GIC 123 : for (j = keyatts; j < nKeys; j++)
2387 ECB : {
2388 : char *colName;
2389 EUB :
2390 GBC 82 : colName = get_attname(conForm->conrelid,
2391 GIC 82 : DatumGetInt16(keys[j]), false);
2392 82 : if (j > keyatts)
2393 41 : appendStringInfoString(&buf, ", ");
2394 82 : appendStringInfoString(&buf, quote_identifier(colName));
2395 : }
2396 :
2397 41 : appendStringInfoChar(&buf, ')');
2398 : }
2399 CBC 1199 : ReleaseSysCache(indtup);
2400 ECB :
2401 : /* XXX why do we only print these bits if fullCommand? */
2402 CBC 1199 : if (fullCommand && OidIsValid(indexId))
2403 : {
2404 GIC 90 : char *options = flatten_reloptions(indexId);
2405 ECB : Oid tblspc;
2406 :
2407 CBC 90 : if (options)
2408 : {
2409 UIC 0 : appendStringInfo(&buf, " WITH (%s)", options);
2410 0 : pfree(options);
2411 : }
2412 :
2413 : /*
2414 : * Print the tablespace, unless it's the database default.
2415 : * This is to help ALTER TABLE usage of this facility,
2416 ECB : * which needs this behavior to recreate exact catalog
2417 : * state.
2418 : */
2419 CBC 90 : tblspc = get_rel_tablespace(indexId);
2420 90 : if (OidIsValid(tblspc))
2421 GIC 12 : appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
2422 12 : quote_identifier(get_tablespace_name(tblspc)));
2423 ECB : }
2424 :
2425 GIC 1199 : break;
2426 ECB : }
2427 GIC 971 : case CONSTRAINT_CHECK:
2428 : {
2429 : Datum val;
2430 : char *conbin;
2431 ECB : char *consrc;
2432 : Node *expr;
2433 : List *context;
2434 :
2435 : /* Fetch constraint expression in parsetree form */
2436 GNC 971 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2437 : Anum_pg_constraint_conbin);
2438 :
2439 GIC 971 : conbin = TextDatumGetCString(val);
2440 971 : expr = stringToNode(conbin);
2441 :
2442 : /* Set up deparsing context for Var nodes in constraint */
2443 971 : if (conForm->conrelid != InvalidOid)
2444 : {
2445 : /* relation constraint */
2446 CBC 880 : context = deparse_context_for(get_relation_name(conForm->conrelid),
2447 : conForm->conrelid);
2448 ECB : }
2449 : else
2450 : {
2451 : /* domain constraint --- can't have Vars */
2452 GIC 91 : context = NIL;
2453 : }
2454 :
2455 CBC 971 : consrc = deparse_expression_pretty(expr, context, false, false,
2456 : prettyFlags, 0);
2457 ECB :
2458 : /*
2459 : * Now emit the constraint definition, adding NO INHERIT if
2460 : * necessary.
2461 EUB : *
2462 ECB : * There are cases where the constraint expression will be
2463 : * fully parenthesized and we don't need the outer parens ...
2464 : * but there are other cases where we do need 'em. Be
2465 EUB : * conservative for now.
2466 : *
2467 : * Note that simply checking for leading '(' and trailing ')'
2468 : * would NOT be good enough, consider "(x > 0) AND (y > 0)".
2469 : */
2470 GIC 971 : appendStringInfo(&buf, "CHECK (%s)%s",
2471 : consrc,
2472 971 : conForm->connoinherit ? " NO INHERIT" : "");
2473 GBC 971 : break;
2474 EUB : }
2475 GNC 27 : case CONSTRAINT_NOTNULL:
2476 : {
2477 : AttrNumber attnum;
2478 :
2479 27 : attnum = extractNotNullColumn(tup);
2480 :
2481 27 : appendStringInfo(&buf, "NOT NULL %s",
2482 27 : quote_identifier(get_attname(conForm->conrelid,
2483 : attnum, false)));
2484 27 : if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
2485 UNC 0 : appendStringInfoString(&buf, " NO INHERIT");
2486 GNC 27 : break;
2487 : }
2488 :
2489 LBC 0 : case CONSTRAINT_TRIGGER:
2490 :
2491 ECB : /*
2492 : * There isn't an ALTER TABLE syntax for creating a user-defined
2493 : * constraint trigger, but it seems better to print something than
2494 : * throw an error; if we throw error then this function couldn't
2495 : * safely be applied to all rows of pg_constraint.
2496 : */
2497 UIC 0 : appendStringInfoString(&buf, "TRIGGER");
2498 0 : break;
2499 CBC 52 : case CONSTRAINT_EXCLUSION:
2500 : {
2501 GIC 52 : Oid indexOid = conForm->conindid;
2502 ECB : Datum val;
2503 : Datum *elems;
2504 : int nElems;
2505 : int i;
2506 : Oid *operators;
2507 :
2508 : /* Extract operator OIDs from the pg_constraint tuple */
2509 GNC 52 : val = SysCacheGetAttrNotNull(CONSTROID, tup,
2510 : Anum_pg_constraint_conexclop);
2511 :
2512 52 : deconstruct_array_builtin(DatumGetArrayTypeP(val), OIDOID,
2513 : &elems, NULL, &nElems);
2514 :
2515 CBC 52 : operators = (Oid *) palloc(nElems * sizeof(Oid));
2516 GIC 114 : for (i = 0; i < nElems; i++)
2517 GBC 62 : operators[i] = DatumGetObjectId(elems[i]);
2518 EUB :
2519 : /* pg_get_indexdef_worker does the rest */
2520 : /* suppress tablespace because pg_dump wants it that way */
2521 GIC 52 : appendStringInfoString(&buf,
2522 CBC 52 : pg_get_indexdef_worker(indexOid,
2523 ECB : 0,
2524 : operators,
2525 EUB : false,
2526 ECB : false,
2527 : false,
2528 : false,
2529 : prettyFlags,
2530 : false));
2531 CBC 52 : break;
2532 : }
2533 LBC 0 : default:
2534 UIC 0 : elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
2535 : break;
2536 : }
2537 :
2538 GIC 2563 : if (conForm->condeferrable)
2539 20 : appendStringInfoString(&buf, " DEFERRABLE");
2540 2563 : if (conForm->condeferred)
2541 UIC 0 : appendStringInfoString(&buf, " INITIALLY DEFERRED");
2542 GIC 2563 : if (!conForm->convalidated)
2543 CBC 47 : appendStringInfoString(&buf, " NOT VALID");
2544 :
2545 : /* Cleanup */
2546 GIC 2563 : systable_endscan(scandesc);
2547 2563 : table_close(relation, AccessShareLock);
2548 :
2549 2563 : return buf.data;
2550 : }
2551 ECB :
2552 :
2553 : /*
2554 : * Convert an int16[] Datum into a comma-separated list of column names
2555 : * for the indicated relation; append the list to buf. Returns the number
2556 : * of keys.
2557 : */
2558 : static int
2559 GIC 1833 : decompile_column_index_array(Datum column_index_array, Oid relId,
2560 ECB : StringInfo buf)
2561 : {
2562 : Datum *keys;
2563 : int nKeys;
2564 : int j;
2565 :
2566 : /* Extract data from array of int16 */
2567 GNC 1833 : deconstruct_array_builtin(DatumGetArrayTypeP(column_index_array), INT2OID,
2568 : &keys, NULL, &nKeys);
2569 :
2570 GIC 4229 : for (j = 0; j < nKeys; j++)
2571 : {
2572 : char *colName;
2573 :
2574 2396 : colName = get_attname(relId, DatumGetInt16(keys[j]), false);
2575 :
2576 2396 : if (j == 0)
2577 1833 : appendStringInfoString(buf, quote_identifier(colName));
2578 : else
2579 563 : appendStringInfo(buf, ", %s", quote_identifier(colName));
2580 : }
2581 :
2582 1833 : return nKeys;
2583 : }
2584 :
2585 :
2586 : /* ----------
2587 : * pg_get_expr - Decompile an expression tree
2588 : *
2589 ECB : * Input: an expression tree in nodeToString form, and a relation OID
2590 : *
2591 : * Output: reverse-listed expression
2592 : *
2593 : * Currently, the expression can only refer to a single relation, namely
2594 : * the one specified by the second parameter. This is sufficient for
2595 : * partial indexes, column default expressions, etc. We also support
2596 : * Var-free expressions, for which the OID can be InvalidOid.
2597 : *
2598 : * We expect this function to work, or throw a reasonably clean error,
2599 : * for any node tree that can appear in a catalog pg_node_tree column.
2600 : * Query trees, such as those appearing in pg_rewrite.ev_action, are
2601 : * not supported. Nor are expressions in more than one relation, which
2602 : * can appear in places like pg_rewrite.ev_qual.
2603 : * ----------
2604 : */
2605 : Datum
2606 GIC 3353 : pg_get_expr(PG_FUNCTION_ARGS)
2607 : {
2608 3353 : text *expr = PG_GETARG_TEXT_PP(0);
2609 CBC 3353 : Oid relid = PG_GETARG_OID(1);
2610 EUB : int prettyFlags;
2611 : char *relname;
2612 :
2613 GBC 3353 : prettyFlags = PRETTYFLAG_INDENT;
2614 :
2615 CBC 3353 : if (OidIsValid(relid))
2616 : {
2617 : /* Get the name for the relation */
2618 GIC 3353 : relname = get_rel_name(relid);
2619 ECB :
2620 : /*
2621 : * If the OID isn't actually valid, don't throw an error, just return
2622 : * NULL. This is a bit questionable, but it's what we've done
2623 : * historically, and it can help avoid unwanted failures when
2624 : * examining catalog entries for just-deleted relations.
2625 : */
2626 GIC 3353 : if (relname == NULL)
2627 LBC 0 : PG_RETURN_NULL();
2628 : }
2629 ECB : else
2630 UIC 0 : relname = NULL;
2631 :
2632 CBC 3353 : PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2633 : }
2634 ECB :
2635 EUB : Datum
2636 GIC 203 : pg_get_expr_ext(PG_FUNCTION_ARGS)
2637 : {
2638 GBC 203 : text *expr = PG_GETARG_TEXT_PP(0);
2639 GIC 203 : Oid relid = PG_GETARG_OID(1);
2640 CBC 203 : bool pretty = PG_GETARG_BOOL(2);
2641 : int prettyFlags;
2642 : char *relname;
2643 :
2644 203 : prettyFlags = GET_PRETTY_FLAGS(pretty);
2645 :
2646 GIC 203 : if (OidIsValid(relid))
2647 : {
2648 : /* Get the name for the relation */
2649 203 : relname = get_rel_name(relid);
2650 : /* See notes above */
2651 203 : if (relname == NULL)
2652 UIC 0 : PG_RETURN_NULL();
2653 : }
2654 ECB : else
2655 UIC 0 : relname = NULL;
2656 :
2657 CBC 203 : PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
2658 : }
2659 ECB :
2660 : static text *
2661 GIC 3556 : pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
2662 : {
2663 : Node *node;
2664 : Node *tst;
2665 : Relids relids;
2666 : List *context;
2667 ECB : char *exprstr;
2668 : char *str;
2669 EUB :
2670 ECB : /* Convert input pg_node_tree (really TEXT) object to C string */
2671 GBC 3556 : exprstr = text_to_cstring(expr);
2672 :
2673 : /* Convert expression to node tree */
2674 GIC 3556 : node = (Node *) stringToNode(exprstr);
2675 :
2676 3556 : pfree(exprstr);
2677 :
2678 : /*
2679 ECB : * Throw error if the input is a querytree rather than an expression tree.
2680 : * While we could support queries here, there seems no very good reason
2681 : * to. In most such catalog columns, we'll see a List of Query nodes, or
2682 : * even nested Lists, so drill down to a non-List node before checking.
2683 EUB : */
2684 GIC 3556 : tst = node;
2685 3556 : while (tst && IsA(tst, List))
2686 UIC 0 : tst = linitial((List *) tst);
2687 GIC 3556 : if (tst && IsA(tst, Query))
2688 UIC 0 : ereport(ERROR,
2689 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2690 : errmsg("input is a query, not an expression")));
2691 :
2692 : /*
2693 : * Throw error if the expression contains Vars we won't be able to
2694 : * deparse.
2695 : */
2696 CBC 3556 : relids = pull_varnos(NULL, node);
2697 3556 : if (OidIsValid(relid))
2698 : {
2699 GBC 3556 : if (!bms_is_subset(relids, bms_make_singleton(1)))
2700 UIC 0 : ereport(ERROR,
2701 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2702 ECB : errmsg("expression contains variables of more than one relation")));
2703 : }
2704 : else
2705 : {
2706 UIC 0 : if (!bms_is_empty(relids))
2707 0 : ereport(ERROR,
2708 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2709 : errmsg("expression contains variables")));
2710 : }
2711 :
2712 : /* Prepare deparse context if needed */
2713 GIC 3556 : if (OidIsValid(relid))
2714 3556 : context = deparse_context_for(relname, relid);
2715 ECB : else
2716 UIC 0 : context = NIL;
2717 ECB :
2718 : /* Deparse */
2719 GIC 3556 : str = deparse_expression_pretty(node, context, false, false,
2720 : prettyFlags, 0);
2721 :
2722 3556 : return string_to_text(str);
2723 : }
2724 :
2725 ECB :
2726 : /* ----------
2727 : * pg_get_userbyid - Get a user name by roleid and
2728 : * fallback to 'unknown (OID=n)'
2729 : * ----------
2730 : */
2731 : Datum
2732 CBC 774 : pg_get_userbyid(PG_FUNCTION_ARGS)
2733 : {
2734 774 : Oid roleid = PG_GETARG_OID(0);
2735 ECB : Name result;
2736 : HeapTuple roletup;
2737 : Form_pg_authid role_rec;
2738 :
2739 EUB : /*
2740 : * Allocate space for the result
2741 ECB : */
2742 GIC 774 : result = (Name) palloc(NAMEDATALEN);
2743 774 : memset(NameStr(*result), 0, NAMEDATALEN);
2744 :
2745 : /*
2746 : * Get the pg_authid entry and print the result
2747 : */
2748 774 : roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
2749 774 : if (HeapTupleIsValid(roletup))
2750 : {
2751 774 : role_rec = (Form_pg_authid) GETSTRUCT(roletup);
2752 774 : *result = role_rec->rolname;
2753 CBC 774 : ReleaseSysCache(roletup);
2754 : }
2755 ECB : else
2756 LBC 0 : sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
2757 :
2758 GIC 774 : PG_RETURN_NAME(result);
2759 : }
2760 :
2761 ECB :
2762 : /*
2763 : * pg_get_serial_sequence
2764 : * Get the name of the sequence used by an identity or serial column,
2765 : * formatted suitably for passing to setval, nextval or currval.
2766 : * First parameter is not treated as double-quoted, second parameter
2767 : * is --- see documentation for reason.
2768 : */
2769 : Datum
2770 GIC 6 : pg_get_serial_sequence(PG_FUNCTION_ARGS)
2771 : {
2772 CBC 6 : text *tablename = PG_GETARG_TEXT_PP(0);
2773 GIC 6 : text *columnname = PG_GETARG_TEXT_PP(1);
2774 ECB : RangeVar *tablerv;
2775 : Oid tableOid;
2776 EUB : char *column;
2777 : AttrNumber attnum;
2778 GIC 6 : Oid sequenceId = InvalidOid;
2779 : Relation depRel;
2780 : ScanKeyData key[3];
2781 : SysScanDesc scan;
2782 ECB : HeapTuple tup;
2783 :
2784 : /* Look up table name. Can't lock it - we might not have privileges. */
2785 GIC 6 : tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
2786 6 : tableOid = RangeVarGetRelid(tablerv, NoLock, false);
2787 :
2788 ECB : /* Get the number of the column */
2789 GIC 6 : column = text_to_cstring(columnname);
2790 :
2791 6 : attnum = get_attnum(tableOid, column);
2792 CBC 6 : if (attnum == InvalidAttrNumber)
2793 UIC 0 : ereport(ERROR,
2794 : (errcode(ERRCODE_UNDEFINED_COLUMN),
2795 : errmsg("column \"%s\" of relation \"%s\" does not exist",
2796 : column, tablerv->relname)));
2797 ECB :
2798 : /* Search the dependency table for the dependent sequence */
2799 GIC 6 : depRel = table_open(DependRelationId, AccessShareLock);
2800 ECB :
2801 GIC 6 : ScanKeyInit(&key[0],
2802 ECB : Anum_pg_depend_refclassid,
2803 : BTEqualStrategyNumber, F_OIDEQ,
2804 : ObjectIdGetDatum(RelationRelationId));
2805 GIC 6 : ScanKeyInit(&key[1],
2806 : Anum_pg_depend_refobjid,
2807 : BTEqualStrategyNumber, F_OIDEQ,
2808 : ObjectIdGetDatum(tableOid));
2809 CBC 6 : ScanKeyInit(&key[2],
2810 ECB : Anum_pg_depend_refobjsubid,
2811 : BTEqualStrategyNumber, F_INT4EQ,
2812 : Int32GetDatum(attnum));
2813 :
2814 GIC 6 : scan = systable_beginscan(depRel, DependReferenceIndexId, true,
2815 ECB : NULL, 3, key);
2816 :
2817 GIC 15 : while (HeapTupleIsValid(tup = systable_getnext(scan)))
2818 : {
2819 15 : Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
2820 ECB :
2821 : /*
2822 : * Look for an auto dependency (serial column) or internal dependency
2823 : * (identity column) of a sequence on a column. (We need the relkind
2824 : * test because indexes can also have auto dependencies on columns.)
2825 : */
2826 GIC 15 : if (deprec->classid == RelationRelationId &&
2827 CBC 6 : deprec->objsubid == 0 &&
2828 GIC 6 : (deprec->deptype == DEPENDENCY_AUTO ||
2829 CBC 9 : deprec->deptype == DEPENDENCY_INTERNAL) &&
2830 GIC 6 : get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
2831 : {
2832 GBC 6 : sequenceId = deprec->objid;
2833 GIC 6 : break;
2834 : }
2835 : }
2836 :
2837 6 : systable_endscan(scan);
2838 6 : table_close(depRel, AccessShareLock);
2839 :
2840 6 : if (OidIsValid(sequenceId))
2841 : {
2842 : char *result;
2843 :
2844 6 : result = generate_qualified_relation_name(sequenceId);
2845 :
2846 6 : PG_RETURN_TEXT_P(string_to_text(result));
2847 ECB : }
2848 :
2849 LBC 0 : PG_RETURN_NULL();
2850 : }
2851 :
2852 :
2853 : /*
2854 : * pg_get_functiondef
2855 : * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
2856 : * the specified function.
2857 : *
2858 : * Note: if you change the output format of this function, be careful not
2859 : * to break psql's rules (in \ef and \sf) for identifying the start of the
2860 : * function body. To wit: the function body starts on a line that begins with
2861 : * "AS ", "BEGIN ", or "RETURN ", and no preceding line will look like that.
2862 : */
2863 ECB : Datum
2864 GIC 73 : pg_get_functiondef(PG_FUNCTION_ARGS)
2865 : {
2866 CBC 73 : Oid funcid = PG_GETARG_OID(0);
2867 ECB : StringInfoData buf;
2868 : StringInfoData dq;
2869 : HeapTuple proctup;
2870 : Form_pg_proc proc;
2871 : bool isfunction;
2872 : Datum tmp;
2873 : bool isnull;
2874 EUB : const char *prosrc;
2875 : const char *name;
2876 : const char *nsp;
2877 : float4 procost;
2878 ECB : int oldlen;
2879 :
2880 GIC 73 : initStringInfo(&buf);
2881 :
2882 : /* Look up the function */
2883 73 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2884 CBC 73 : if (!HeapTupleIsValid(proctup))
2885 3 : PG_RETURN_NULL();
2886 :
2887 GIC 70 : proc = (Form_pg_proc) GETSTRUCT(proctup);
2888 CBC 70 : name = NameStr(proc->proname);
2889 ECB :
2890 CBC 70 : if (proc->prokind == PROKIND_AGGREGATE)
2891 UIC 0 : ereport(ERROR,
2892 ECB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2893 : errmsg("\"%s\" is an aggregate function", name)));
2894 :
2895 GIC 70 : isfunction = (proc->prokind != PROKIND_PROCEDURE);
2896 :
2897 ECB : /*
2898 : * We always qualify the function name, to ensure the right function gets
2899 : * replaced.
2900 : */
2901 GIC 70 : nsp = get_namespace_name_or_temp(proc->pronamespace);
2902 70 : appendStringInfo(&buf, "CREATE OR REPLACE %s %s(",
2903 ECB : isfunction ? "FUNCTION" : "PROCEDURE",
2904 : quote_qualified_identifier(nsp, name));
2905 CBC 70 : (void) print_function_arguments(&buf, proctup, false, true);
2906 GBC 70 : appendStringInfoString(&buf, ")\n");
2907 CBC 70 : if (isfunction)
2908 : {
2909 61 : appendStringInfoString(&buf, " RETURNS ");
2910 61 : print_function_rettype(&buf, proctup);
2911 61 : appendStringInfoChar(&buf, '\n');
2912 ECB : }
2913 :
2914 CBC 70 : print_function_trftypes(&buf, proctup);
2915 ECB :
2916 CBC 70 : appendStringInfo(&buf, " LANGUAGE %s\n",
2917 GIC 70 : quote_identifier(get_language_name(proc->prolang, false)));
2918 :
2919 ECB : /* Emit some miscellaneous options on one line */
2920 GIC 70 : oldlen = buf.len;
2921 ECB :
2922 CBC 70 : if (proc->prokind == PROKIND_WINDOW)
2923 LBC 0 : appendStringInfoString(&buf, " WINDOW");
2924 GBC 70 : switch (proc->provolatile)
2925 EUB : {
2926 GBC 12 : case PROVOLATILE_IMMUTABLE:
2927 CBC 12 : appendStringInfoString(&buf, " IMMUTABLE");
2928 12 : break;
2929 GIC 9 : case PROVOLATILE_STABLE:
2930 9 : appendStringInfoString(&buf, " STABLE");
2931 CBC 9 : break;
2932 49 : case PROVOLATILE_VOLATILE:
2933 49 : break;
2934 ECB : }
2935 :
2936 GBC 70 : switch (proc->proparallel)
2937 : {
2938 GIC 19 : case PROPARALLEL_SAFE:
2939 CBC 19 : appendStringInfoString(&buf, " PARALLEL SAFE");
2940 19 : break;
2941 LBC 0 : case PROPARALLEL_RESTRICTED:
2942 UIC 0 : appendStringInfoString(&buf, " PARALLEL RESTRICTED");
2943 LBC 0 : break;
2944 CBC 51 : case PROPARALLEL_UNSAFE:
2945 51 : break;
2946 : }
2947 ECB :
2948 GBC 70 : if (proc->proisstrict)
2949 GIC 24 : appendStringInfoString(&buf, " STRICT");
2950 CBC 70 : if (proc->prosecdef)
2951 GIC 3 : appendStringInfoString(&buf, " SECURITY DEFINER");
2952 70 : if (proc->proleakproof)
2953 UIC 0 : appendStringInfoString(&buf, " LEAKPROOF");
2954 :
2955 : /* This code for the default cost and rows should match functioncmds.c */
2956 GIC 70 : if (proc->prolang == INTERNALlanguageId ||
2957 70 : proc->prolang == ClanguageId)
2958 GBC 4 : procost = 1;
2959 EUB : else
2960 GIC 66 : procost = 100;
2961 70 : if (proc->procost != procost)
2962 3 : appendStringInfo(&buf, " COST %g", proc->procost);
2963 :
2964 70 : if (proc->prorows > 0 && proc->prorows != 1000)
2965 LBC 0 : appendStringInfo(&buf, " ROWS %g", proc->prorows);
2966 ECB :
2967 GIC 70 : if (proc->prosupport)
2968 : {
2969 ECB : Oid argtypes[1];
2970 :
2971 : /*
2972 : * We should qualify the support function's name if it wouldn't be
2973 : * resolved by lookup in the current search path.
2974 : */
2975 LBC 0 : argtypes[0] = INTERNALOID;
2976 0 : appendStringInfo(&buf, " SUPPORT %s",
2977 ECB : generate_function_name(proc->prosupport, 1,
2978 : NIL, argtypes,
2979 : false, NULL, EXPR_KIND_NONE));
2980 : }
2981 :
2982 GIC 70 : if (oldlen != buf.len)
2983 CBC 31 : appendStringInfoChar(&buf, '\n');
2984 :
2985 : /* Emit any proconfig options, one per line */
2986 GIC 70 : tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
2987 70 : if (!isnull)
2988 : {
2989 CBC 3 : ArrayType *a = DatumGetArrayTypeP(tmp);
2990 : int i;
2991 ECB :
2992 GIC 3 : Assert(ARR_ELEMTYPE(a) == TEXTOID);
2993 3 : Assert(ARR_NDIM(a) == 1);
2994 CBC 3 : Assert(ARR_LBOUND(a)[0] == 1);
2995 ECB :
2996 GBC 18 : for (i = 1; i <= ARR_DIMS(a)[0]; i++)
2997 ECB : {
2998 : Datum d;
2999 :
3000 GIC 15 : d = array_ref(a, 1, &i,
3001 : -1 /* varlenarray */ ,
3002 : -1 /* TEXT's typlen */ ,
3003 : false /* TEXT's typbyval */ ,
3004 : TYPALIGN_INT /* TEXT's typalign */ ,
3005 : &isnull);
3006 15 : if (!isnull)
3007 : {
3008 15 : char *configitem = TextDatumGetCString(d);
3009 : char *pos;
3010 :
3011 15 : pos = strchr(configitem, '=');
3012 15 : if (pos == NULL)
3013 UIC 0 : continue;
3014 GIC 15 : *pos++ = '\0';
3015 :
3016 15 : appendStringInfo(&buf, " SET %s TO ",
3017 : quote_identifier(configitem));
3018 ECB :
3019 : /*
3020 : * Variables that are marked GUC_LIST_QUOTE were already fully
3021 : * quoted by flatten_set_variable_args() before they were put
3022 : * into the proconfig array. However, because the quoting
3023 : * rules used there aren't exactly like SQL's, we have to
3024 : * break the list value apart and then quote the elements as
3025 : * string literals. (The elements may be double-quoted as-is,
3026 : * but we can't just feed them to the SQL parser; it would do
3027 EUB : * the wrong thing with elements that are zero-length or
3028 : * longer than NAMEDATALEN.)
3029 ECB : *
3030 : * Variables that are not so marked should just be emitted as
3031 : * simple string literals. If the variable is not known to
3032 : * guc.c, we'll do that; this makes it unsafe to use
3033 : * GUC_LIST_QUOTE for extension variables.
3034 : */
3035 CBC 15 : if (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
3036 : {
3037 : List *namelist;
3038 : ListCell *lc;
3039 ECB :
3040 : /* Parse string into list of identifiers */
3041 GIC 6 : if (!SplitGUCList(pos, ',', &namelist))
3042 : {
3043 : /* this shouldn't fail really */
3044 UIC 0 : elog(ERROR, "invalid list syntax in proconfig item");
3045 : }
3046 CBC 21 : foreach(lc, namelist)
3047 ECB : {
3048 GIC 15 : char *curname = (char *) lfirst(lc);
3049 ECB :
3050 GIC 15 : simple_quote_literal(&buf, curname);
3051 15 : if (lnext(namelist, lc))
3052 9 : appendStringInfoString(&buf, ", ");
3053 ECB : }
3054 : }
3055 : else
3056 CBC 9 : simple_quote_literal(&buf, pos);
3057 GIC 15 : appendStringInfoChar(&buf, '\n');
3058 ECB : }
3059 : }
3060 : }
3061 :
3062 : /* And finally the function definition ... */
3063 CBC 70 : (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3064 GIC 70 : if (proc->prolang == SQLlanguageId && !isnull)
3065 : {
3066 39 : print_function_sqlbody(&buf, proctup);
3067 : }
3068 : else
3069 : {
3070 31 : appendStringInfoString(&buf, "AS ");
3071 :
3072 31 : tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
3073 CBC 31 : if (!isnull)
3074 ECB : {
3075 CBC 4 : simple_quote_literal(&buf, TextDatumGetCString(tmp));
3076 4 : appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
3077 EUB : }
3078 ECB :
3079 GNC 31 : tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosrc);
3080 CBC 31 : prosrc = TextDatumGetCString(tmp);
3081 :
3082 : /*
3083 ECB : * We always use dollar quoting. Figure out a suitable delimiter.
3084 : *
3085 : * Since the user is likely to be editing the function body string, we
3086 : * shouldn't use a short delimiter that he might easily create a
3087 : * conflict with. Hence prefer "$function$"/"$procedure$", but extend
3088 : * if needed.
3089 : */
3090 GIC 31 : initStringInfo(&dq);
3091 31 : appendStringInfoChar(&dq, '$');
3092 31 : appendStringInfoString(&dq, (isfunction ? "function" : "procedure"));
3093 31 : while (strstr(prosrc, dq.data) != NULL)
3094 UIC 0 : appendStringInfoChar(&dq, 'x');
3095 GIC 31 : appendStringInfoChar(&dq, '$');
3096 :
3097 CBC 31 : appendBinaryStringInfo(&buf, dq.data, dq.len);
3098 GIC 31 : appendStringInfoString(&buf, prosrc);
3099 CBC 31 : appendBinaryStringInfo(&buf, dq.data, dq.len);
3100 : }
3101 :
3102 GIC 70 : appendStringInfoChar(&buf, '\n');
3103 ECB :
3104 CBC 70 : ReleaseSysCache(proctup);
3105 ECB :
3106 GIC 70 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3107 ECB : }
3108 :
3109 : /*
3110 : * pg_get_function_arguments
3111 : * Get a nicely-formatted list of arguments for a function.
3112 : * This is everything that would go between the parentheses in
3113 : * CREATE FUNCTION.
3114 : */
3115 : Datum
3116 GIC 2234 : pg_get_function_arguments(PG_FUNCTION_ARGS)
3117 : {
3118 2234 : Oid funcid = PG_GETARG_OID(0);
3119 : StringInfoData buf;
3120 : HeapTuple proctup;
3121 :
3122 2234 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3123 CBC 2234 : if (!HeapTupleIsValid(proctup))
3124 GIC 3 : PG_RETURN_NULL();
3125 ECB :
3126 GIC 2231 : initStringInfo(&buf);
3127 :
3128 2231 : (void) print_function_arguments(&buf, proctup, false, true);
3129 ECB :
3130 CBC 2231 : ReleaseSysCache(proctup);
3131 ECB :
3132 GIC 2231 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3133 ECB : }
3134 :
3135 : /*
3136 : * pg_get_function_identity_arguments
3137 : * Get a formatted list of arguments for a function.
3138 : * This is everything that would go between the parentheses in
3139 : * ALTER FUNCTION, etc. In particular, don't print defaults.
3140 : */
3141 : Datum
3142 GIC 1977 : pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
3143 : {
3144 1977 : Oid funcid = PG_GETARG_OID(0);
3145 : StringInfoData buf;
3146 : HeapTuple proctup;
3147 :
3148 CBC 1977 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3149 GIC 1977 : if (!HeapTupleIsValid(proctup))
3150 CBC 3 : PG_RETURN_NULL();
3151 :
3152 GIC 1974 : initStringInfo(&buf);
3153 :
3154 CBC 1974 : (void) print_function_arguments(&buf, proctup, false, false);
3155 ECB :
3156 CBC 1974 : ReleaseSysCache(proctup);
3157 :
3158 1974 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3159 : }
3160 ECB :
3161 : /*
3162 : * pg_get_function_result
3163 : * Get a nicely-formatted version of the result type of a function.
3164 : * This is what would appear after RETURNS in CREATE FUNCTION.
3165 : */
3166 : Datum
3167 GIC 1939 : pg_get_function_result(PG_FUNCTION_ARGS)
3168 ECB : {
3169 GIC 1939 : Oid funcid = PG_GETARG_OID(0);
3170 ECB : StringInfoData buf;
3171 : HeapTuple proctup;
3172 :
3173 GIC 1939 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3174 1939 : if (!HeapTupleIsValid(proctup))
3175 3 : PG_RETURN_NULL();
3176 :
3177 1936 : if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
3178 ECB : {
3179 GIC 105 : ReleaseSysCache(proctup);
3180 CBC 105 : PG_RETURN_NULL();
3181 ECB : }
3182 :
3183 GIC 1831 : initStringInfo(&buf);
3184 ECB :
3185 GIC 1831 : print_function_rettype(&buf, proctup);
3186 ECB :
3187 GIC 1831 : ReleaseSysCache(proctup);
3188 :
3189 CBC 1831 : PG_RETURN_TEXT_P(string_to_text(buf.data));
3190 ECB : }
3191 :
3192 : /*
3193 : * Guts of pg_get_function_result: append the function's return type
3194 : * to the specified buffer.
3195 : */
3196 : static void
3197 CBC 1892 : print_function_rettype(StringInfo buf, HeapTuple proctup)
3198 : {
3199 GIC 1892 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3200 CBC 1892 : int ntabargs = 0;
3201 ECB : StringInfoData rbuf;
3202 :
3203 GIC 1892 : initStringInfo(&rbuf);
3204 :
3205 CBC 1892 : if (proc->proretset)
3206 ECB : {
3207 : /* It might be a table function; try to print the arguments */
3208 GIC 173 : appendStringInfoString(&rbuf, "TABLE(");
3209 173 : ntabargs = print_function_arguments(&rbuf, proctup, true, false);
3210 173 : if (ntabargs > 0)
3211 35 : appendStringInfoChar(&rbuf, ')');
3212 : else
3213 138 : resetStringInfo(&rbuf);
3214 : }
3215 :
3216 CBC 1892 : if (ntabargs == 0)
3217 : {
3218 : /* Not a table function, so do the normal thing */
3219 1857 : if (proc->proretset)
3220 GIC 138 : appendStringInfoString(&rbuf, "SETOF ");
3221 1857 : appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
3222 : }
3223 :
3224 CBC 1892 : appendBinaryStringInfo(buf, rbuf.data, rbuf.len);
3225 GIC 1892 : }
3226 :
3227 : /*
3228 ECB : * Common code for pg_get_function_arguments and pg_get_function_result:
3229 : * append the desired subset of arguments to buf. We print only TABLE
3230 : * arguments when print_table_args is true, and all the others when it's false.
3231 : * We print argument defaults only if print_defaults is true.
3232 : * Function return value is the number of arguments printed.
3233 : */
3234 : static int
3235 CBC 4448 : print_function_arguments(StringInfo buf, HeapTuple proctup,
3236 ECB : bool print_table_args, bool print_defaults)
3237 : {
3238 GIC 4448 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
3239 : int numargs;
3240 : Oid *argtypes;
3241 ECB : char **argnames;
3242 : char *argmodes;
3243 GIC 4448 : int insertorderbyat = -1;
3244 ECB : int argsprinted;
3245 : int inputargno;
3246 : int nlackdefaults;
3247 GIC 4448 : List *argdefaults = NIL;
3248 CBC 4448 : ListCell *nextargdefault = NULL;
3249 ECB : int i;
3250 :
3251 CBC 4448 : numargs = get_func_arg_info(proctup,
3252 : &argtypes, &argnames, &argmodes);
3253 ECB :
3254 GIC 4448 : nlackdefaults = numargs;
3255 4448 : if (print_defaults && proc->pronargdefaults > 0)
3256 : {
3257 : Datum proargdefaults;
3258 ECB : bool isnull;
3259 :
3260 GIC 18 : proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3261 : Anum_pg_proc_proargdefaults,
3262 : &isnull);
3263 CBC 18 : if (!isnull)
3264 ECB : {
3265 EUB : char *str;
3266 :
3267 CBC 18 : str = TextDatumGetCString(proargdefaults);
3268 18 : argdefaults = castNode(List, stringToNode(str));
3269 18 : pfree(str);
3270 18 : nextargdefault = list_head(argdefaults);
3271 : /* nlackdefaults counts only *input* arguments lacking defaults */
3272 GIC 18 : nlackdefaults = proc->pronargs - list_length(argdefaults);
3273 ECB : }
3274 : }
3275 :
3276 : /* Check for special treatment of ordered-set aggregates */
3277 CBC 4448 : if (proc->prokind == PROKIND_AGGREGATE)
3278 ECB : {
3279 : HeapTuple aggtup;
3280 : Form_pg_aggregate agg;
3281 :
3282 GIC 591 : aggtup = SearchSysCache1(AGGFNOID, proc->oid);
3283 CBC 591 : if (!HeapTupleIsValid(aggtup))
3284 UIC 0 : elog(ERROR, "cache lookup failed for aggregate %u",
3285 ECB : proc->oid);
3286 GIC 591 : agg = (Form_pg_aggregate) GETSTRUCT(aggtup);
3287 591 : if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
3288 26 : insertorderbyat = agg->aggnumdirectargs;
3289 591 : ReleaseSysCache(aggtup);
3290 : }
3291 ECB :
3292 CBC 4448 : argsprinted = 0;
3293 GIC 4448 : inputargno = 0;
3294 CBC 9039 : for (i = 0; i < numargs; i++)
3295 ECB : {
3296 CBC 4591 : Oid argtype = argtypes[i];
3297 4591 : char *argname = argnames ? argnames[i] : NULL;
3298 4591 : char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
3299 ECB : const char *modename;
3300 : bool isinput;
3301 :
3302 CBC 4591 : switch (argmode)
3303 ECB : {
3304 CBC 3860 : case PROARGMODE_IN:
3305 ECB :
3306 : /*
3307 : * For procedures, explicitly mark all argument modes, so as
3308 : * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
3309 : */
3310 CBC 3860 : if (proc->prokind == PROKIND_PROCEDURE)
3311 263 : modename = "IN ";
3312 ECB : else
3313 GBC 3597 : modename = "";
3314 3860 : isinput = true;
3315 GIC 3860 : break;
3316 20 : case PROARGMODE_INOUT:
3317 20 : modename = "INOUT ";
3318 20 : isinput = true;
3319 CBC 20 : break;
3320 472 : case PROARGMODE_OUT:
3321 GIC 472 : modename = "OUT ";
3322 CBC 472 : isinput = false;
3323 472 : break;
3324 GIC 89 : case PROARGMODE_VARIADIC:
3325 CBC 89 : modename = "VARIADIC ";
3326 GIC 89 : isinput = true;
3327 CBC 89 : break;
3328 150 : case PROARGMODE_TABLE:
3329 150 : modename = "";
3330 GIC 150 : isinput = false;
3331 CBC 150 : break;
3332 LBC 0 : default:
3333 UIC 0 : elog(ERROR, "invalid parameter mode '%c'", argmode);
3334 ECB : modename = NULL; /* keep compiler quiet */
3335 : isinput = false;
3336 : break;
3337 : }
3338 CBC 4591 : if (isinput)
3339 GIC 3969 : inputargno++; /* this is a 1-based counter */
3340 :
3341 4591 : if (print_table_args != (argmode == PROARGMODE_TABLE))
3342 CBC 364 : continue;
3343 ECB :
3344 CBC 4227 : if (argsprinted == insertorderbyat)
3345 : {
3346 26 : if (argsprinted)
3347 GIC 26 : appendStringInfoChar(buf, ' ');
3348 26 : appendStringInfoString(buf, "ORDER BY ");
3349 ECB : }
3350 GIC 4201 : else if (argsprinted)
3351 1314 : appendStringInfoString(buf, ", ");
3352 ECB :
3353 GIC 4227 : appendStringInfoString(buf, modename);
3354 CBC 4227 : if (argname && argname[0])
3355 GIC 1446 : appendStringInfo(buf, "%s ", quote_identifier(argname));
3356 CBC 4227 : appendStringInfoString(buf, format_type_be(argtype));
3357 GIC 4227 : if (print_defaults && isinput && inputargno > nlackdefaults)
3358 : {
3359 : Node *expr;
3360 ECB :
3361 GIC 25 : Assert(nextargdefault != NULL);
3362 25 : expr = (Node *) lfirst(nextargdefault);
3363 25 : nextargdefault = lnext(argdefaults, nextargdefault);
3364 ECB :
3365 GIC 25 : appendStringInfo(buf, " DEFAULT %s",
3366 : deparse_expression(expr, NIL, false, false));
3367 ECB : }
3368 CBC 4227 : argsprinted++;
3369 ECB :
3370 : /* nasty hack: print the last arg twice for variadic ordered-set agg */
3371 GIC 4227 : if (argsprinted == insertorderbyat && i == numargs - 1)
3372 : {
3373 13 : i--;
3374 : /* aggs shouldn't have defaults anyway, but just to be sure ... */
3375 13 : print_defaults = false;
3376 ECB : }
3377 : }
3378 :
3379 GIC 4448 : return argsprinted;
3380 : }
3381 ECB :
3382 : static bool
3383 GIC 48 : is_input_argument(int nth, const char *argmodes)
3384 : {
3385 : return (!argmodes
3386 CBC 21 : || argmodes[nth] == PROARGMODE_IN
3387 9 : || argmodes[nth] == PROARGMODE_INOUT
3388 GIC 69 : || argmodes[nth] == PROARGMODE_VARIADIC);
3389 ECB : }
3390 :
3391 : /*
3392 : * Append used transformed types to specified buffer
3393 : */
3394 : static void
3395 CBC 70 : print_function_trftypes(StringInfo buf, HeapTuple proctup)
3396 : {
3397 : Oid *trftypes;
3398 : int ntypes;
3399 :
3400 GIC 70 : ntypes = get_func_trftypes(proctup, &trftypes);
3401 70 : if (ntypes > 0)
3402 : {
3403 : int i;
3404 ECB :
3405 GIC 3 : appendStringInfoString(buf, " TRANSFORM ");
3406 CBC 8 : for (i = 0; i < ntypes; i++)
3407 ECB : {
3408 GIC 5 : if (i != 0)
3409 2 : appendStringInfoString(buf, ", ");
3410 5 : appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
3411 : }
3412 3 : appendStringInfoChar(buf, '\n');
3413 : }
3414 70 : }
3415 :
3416 : /*
3417 : * Get textual representation of a function argument's default value. The
3418 : * second argument of this function is the argument number among all arguments
3419 : * (i.e. proallargtypes, *not* proargtypes), starting with 1, because that's
3420 : * how information_schema.sql uses it.
3421 : */
3422 : Datum
3423 CBC 27 : pg_get_function_arg_default(PG_FUNCTION_ARGS)
3424 ECB : {
3425 CBC 27 : Oid funcid = PG_GETARG_OID(0);
3426 GIC 27 : int32 nth_arg = PG_GETARG_INT32(1);
3427 ECB : HeapTuple proctup;
3428 : Form_pg_proc proc;
3429 : int numargs;
3430 : Oid *argtypes;
3431 : char **argnames;
3432 : char *argmodes;
3433 : int i;
3434 : List *argdefaults;
3435 : Node *node;
3436 : char *str;
3437 : int nth_inputarg;
3438 : Datum proargdefaults;
3439 : bool isnull;
3440 : int nth_default;
3441 :
3442 CBC 27 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3443 GIC 27 : if (!HeapTupleIsValid(proctup))
3444 GBC 6 : PG_RETURN_NULL();
3445 EUB :
3446 GIC 21 : numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
3447 21 : if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
3448 ECB : {
3449 CBC 6 : ReleaseSysCache(proctup);
3450 6 : PG_RETURN_NULL();
3451 : }
3452 ECB :
3453 GIC 15 : nth_inputarg = 0;
3454 42 : for (i = 0; i < nth_arg; i++)
3455 27 : if (is_input_argument(i, argmodes))
3456 24 : nth_inputarg++;
3457 :
3458 CBC 15 : proargdefaults = SysCacheGetAttr(PROCOID, proctup,
3459 : Anum_pg_proc_proargdefaults,
3460 ECB : &isnull);
3461 GIC 15 : if (isnull)
3462 ECB : {
3463 LBC 0 : ReleaseSysCache(proctup);
3464 UIC 0 : PG_RETURN_NULL();
3465 ECB : }
3466 :
3467 GIC 15 : str = TextDatumGetCString(proargdefaults);
3468 CBC 15 : argdefaults = castNode(List, stringToNode(str));
3469 GIC 15 : pfree(str);
3470 ECB :
3471 GIC 15 : proc = (Form_pg_proc) GETSTRUCT(proctup);
3472 :
3473 : /*
3474 ECB : * Calculate index into proargdefaults: proargdefaults corresponds to the
3475 : * last N input arguments, where N = pronargdefaults.
3476 : */
3477 GIC 15 : nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
3478 :
3479 15 : if (nth_default < 0 || nth_default >= list_length(argdefaults))
3480 ECB : {
3481 GIC 3 : ReleaseSysCache(proctup);
3482 3 : PG_RETURN_NULL();
3483 : }
3484 CBC 12 : node = list_nth(argdefaults, nth_default);
3485 12 : str = deparse_expression(node, NIL, false, false);
3486 :
3487 12 : ReleaseSysCache(proctup);
3488 ECB :
3489 GIC 12 : PG_RETURN_TEXT_P(string_to_text(str));
3490 ECB : }
3491 :
3492 : static void
3493 CBC 54 : print_function_sqlbody(StringInfo buf, HeapTuple proctup)
3494 : {
3495 : int numargs;
3496 : Oid *argtypes;
3497 : char **argnames;
3498 ECB : char *argmodes;
3499 GIC 54 : deparse_namespace dpns = {0};
3500 ECB : Datum tmp;
3501 : Node *n;
3502 :
3503 CBC 54 : dpns.funcname = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname));
3504 GIC 54 : numargs = get_func_arg_info(proctup,
3505 : &argtypes, &argnames, &argmodes);
3506 CBC 54 : dpns.numargs = numargs;
3507 54 : dpns.argnames = argnames;
3508 :
3509 GNC 54 : tmp = SysCacheGetAttrNotNull(PROCOID, proctup, Anum_pg_proc_prosqlbody);
3510 GIC 54 : n = stringToNode(TextDatumGetCString(tmp));
3511 :
3512 CBC 54 : if (IsA(n, List))
3513 : {
3514 : List *stmts;
3515 : ListCell *lc;
3516 ECB :
3517 GIC 32 : stmts = linitial(castNode(List, n));
3518 :
3519 CBC 32 : appendStringInfoString(buf, "BEGIN ATOMIC\n");
3520 ECB :
3521 GIC 59 : foreach(lc, stmts)
3522 : {
3523 CBC 27 : Query *query = lfirst_node(Query, lc);
3524 :
3525 : /* It seems advisable to get at least AccessShareLock on rels */
3526 27 : AcquireRewriteLocks(query, false, false);
3527 GIC 27 : get_query_def(query, buf, list_make1(&dpns), NULL, false,
3528 ECB : PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
3529 GIC 27 : appendStringInfoChar(buf, ';');
3530 27 : appendStringInfoChar(buf, '\n');
3531 : }
3532 :
3533 CBC 32 : appendStringInfoString(buf, "END");
3534 : }
3535 : else
3536 ECB : {
3537 CBC 22 : Query *query = castNode(Query, n);
3538 EUB :
3539 : /* It seems advisable to get at least AccessShareLock on rels */
3540 CBC 22 : AcquireRewriteLocks(query, false, false);
3541 22 : get_query_def(query, buf, list_make1(&dpns), NULL, false,
3542 : 0, WRAP_COLUMN_DEFAULT, 0);
3543 ECB : }
3544 CBC 54 : }
3545 :
3546 : Datum
3547 1686 : pg_get_function_sqlbody(PG_FUNCTION_ARGS)
3548 : {
3549 1686 : Oid funcid = PG_GETARG_OID(0);
3550 : StringInfoData buf;
3551 ECB : HeapTuple proctup;
3552 : bool isnull;
3553 :
3554 GIC 1686 : initStringInfo(&buf);
3555 :
3556 : /* Look up the function */
3557 1686 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
3558 1686 : if (!HeapTupleIsValid(proctup))
3559 UIC 0 : PG_RETURN_NULL();
3560 :
3561 CBC 1686 : (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosqlbody, &isnull);
3562 GIC 1686 : if (isnull)
3563 : {
3564 CBC 1671 : ReleaseSysCache(proctup);
3565 GIC 1671 : PG_RETURN_NULL();
3566 : }
3567 :
3568 15 : print_function_sqlbody(&buf, proctup);
3569 :
3570 15 : ReleaseSysCache(proctup);
3571 :
3572 GNC 15 : PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
3573 : }
3574 :
3575 :
3576 : /*
3577 : * deparse_expression - General utility for deparsing expressions
3578 : *
3579 : * calls deparse_expression_pretty with all prettyPrinting disabled
3580 : */
3581 : char *
3582 GIC 28781 : deparse_expression(Node *expr, List *dpcontext,
3583 : bool forceprefix, bool showimplicit)
3584 : {
3585 28781 : return deparse_expression_pretty(expr, dpcontext, forceprefix,
3586 : showimplicit, 0, 0);
3587 : }
3588 ECB :
3589 : /* ----------
3590 : * deparse_expression_pretty - General utility for deparsing expressions
3591 : *
3592 : * expr is the node tree to be deparsed. It must be a transformed expression
3593 : * tree (ie, not the raw output of gram.y).
3594 : *
3595 : * dpcontext is a list of deparse_namespace nodes representing the context
3596 : * for interpreting Vars in the node tree. It can be NIL if no Vars are
3597 : * expected.
3598 : *
3599 : * forceprefix is true to force all Vars to be prefixed with their table names.
3600 : *
3601 : * showimplicit is true to force all implicit casts to be shown explicitly.
3602 : *
3603 : * Tries to pretty up the output according to prettyFlags and startIndent.
3604 : *
3605 : * The result is a palloc'd string.
3606 : * ----------
3607 : */
3608 : static char *
3609 CBC 34079 : deparse_expression_pretty(Node *expr, List *dpcontext,
3610 : bool forceprefix, bool showimplicit,
3611 : int prettyFlags, int startIndent)
3612 : {
3613 : StringInfoData buf;
3614 : deparse_context context;
3615 :
3616 GIC 34079 : initStringInfo(&buf);
3617 34079 : context.buf = &buf;
3618 34079 : context.namespaces = dpcontext;
3619 34079 : context.windowClause = NIL;
3620 34079 : context.windowTList = NIL;
3621 CBC 34079 : context.varprefix = forceprefix;
3622 GIC 34079 : context.prettyFlags = prettyFlags;
3623 34079 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
3624 34079 : context.indentLevel = startIndent;
3625 34079 : context.special_exprkind = EXPR_KIND_NONE;
3626 CBC 34079 : context.appendparents = NULL;
3627 :
3628 GIC 34079 : get_rule_expr(expr, &context, showimplicit);
3629 ECB :
3630 CBC 34079 : return buf.data;
3631 ECB : }
3632 :
3633 : /* ----------
3634 : * deparse_context_for - Build deparse context for a single relation
3635 : *
3636 : * Given the reference name (alias) and OID of a relation, build deparsing
3637 : * context for an expression referencing only that relation (as varno 1,
3638 : * varlevelsup 0). This is sufficient for many uses of deparse_expression.
3639 : * ----------
3640 : */
3641 : List *
3642 CBC 9629 : deparse_context_for(const char *aliasname, Oid relid)
3643 ECB : {
3644 : deparse_namespace *dpns;
3645 : RangeTblEntry *rte;
3646 :
3647 GIC 9629 : dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3648 :
3649 ECB : /* Build a minimal RTE for the rel */
3650 GIC 9629 : rte = makeNode(RangeTblEntry);
3651 9629 : rte->rtekind = RTE_RELATION;
3652 9629 : rte->relid = relid;
3653 9629 : rte->relkind = RELKIND_RELATION; /* no need for exactness here */
3654 9629 : rte->rellockmode = AccessShareLock;
3655 9629 : rte->alias = makeAlias(aliasname, NIL);
3656 9629 : rte->eref = rte->alias;
3657 9629 : rte->lateral = false;
3658 9629 : rte->inh = false;
3659 9629 : rte->inFromCl = true;
3660 :
3661 : /* Build one-element rtable */
3662 9629 : dpns->rtable = list_make1(rte);
3663 9629 : dpns->subplans = NIL;
3664 9629 : dpns->ctes = NIL;
3665 9629 : dpns->appendrels = NULL;
3666 CBC 9629 : set_rtable_names(dpns, NIL, NULL);
3667 GIC 9629 : set_simple_column_names(dpns);
3668 :
3669 : /* Return a one-deep namespace stack */
3670 CBC 9629 : return list_make1(dpns);
3671 : }
3672 :
3673 ECB : /*
3674 : * deparse_context_for_plan_tree - Build deparse context for a Plan tree
3675 : *
3676 : * When deparsing an expression in a Plan tree, we use the plan's rangetable
3677 : * to resolve names of simple Vars. The initialization of column names for
3678 : * this is rather expensive if the rangetable is large, and it'll be the same
3679 : * for every expression in the Plan tree; so we do it just once and re-use
3680 : * the result of this function for each expression. (Note that the result
3681 : * is not usable until set_deparse_context_plan() is applied to it.)
3682 : *
3683 : * In addition to the PlannedStmt, pass the per-RTE alias names
3684 : * assigned by a previous call to select_rtable_names_for_explain.
3685 : */
3686 : List *
3687 CBC 9874 : deparse_context_for_plan_tree(PlannedStmt *pstmt, List *rtable_names)
3688 ECB : {
3689 : deparse_namespace *dpns;
3690 :
3691 CBC 9874 : dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
3692 ECB :
3693 : /* Initialize fields that stay the same across the whole plan tree */
3694 GIC 9874 : dpns->rtable = pstmt->rtable;
3695 9874 : dpns->rtable_names = rtable_names;
3696 CBC 9874 : dpns->subplans = pstmt->subplans;
3697 GIC 9874 : dpns->ctes = NIL;
3698 9874 : if (pstmt->appendRelations)
3699 : {
3700 : /* Set up the array, indexed by child relid */
3701 1637 : int ntables = list_length(dpns->rtable);
3702 : ListCell *lc;
3703 ECB :
3704 GIC 1637 : dpns->appendrels = (AppendRelInfo **)
3705 1637 : palloc0((ntables + 1) * sizeof(AppendRelInfo *));
3706 CBC 9266 : foreach(lc, pstmt->appendRelations)
3707 : {
3708 GIC 7629 : AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
3709 7629 : Index crelid = appinfo->child_relid;
3710 :
3711 7629 : Assert(crelid > 0 && crelid <= ntables);
3712 7629 : Assert(dpns->appendrels[crelid] == NULL);
3713 7629 : dpns->appendrels[crelid] = appinfo;
3714 : }
3715 : }
3716 : else
3717 8237 : dpns->appendrels = NULL; /* don't need it */
3718 :
3719 : /*
3720 : * Set up column name aliases. We will get rather bogus results for join
3721 : * RTEs, but that doesn't matter because plan trees don't contain any join
3722 : * alias Vars.
3723 : */
3724 9874 : set_simple_column_names(dpns);
3725 :
3726 : /* Return a one-deep namespace stack */
3727 9874 : return list_make1(dpns);
3728 : }
3729 :
3730 : /*
3731 : * set_deparse_context_plan - Specify Plan node containing expression
3732 : *
3733 : * When deparsing an expression in a Plan tree, we might have to resolve
3734 : * OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
3735 ECB : * provide the parent Plan node. Then OUTER_VAR and INNER_VAR references
3736 : * can be resolved by drilling down into the left and right child plans.
3737 : * Similarly, INDEX_VAR references can be resolved by reference to the
3738 : * indextlist given in a parent IndexOnlyScan node, or to the scan tlist in
3739 : * ForeignScan and CustomScan nodes. (Note that we don't currently support
3740 : * deparsing of indexquals in regular IndexScan or BitmapIndexScan nodes;
3741 : * for those, we can only deparse the indexqualorig fields, which won't
3742 : * contain INDEX_VAR Vars.)
3743 : *
3744 : * The ancestors list is a list of the Plan's parent Plan and SubPlan nodes,
3745 : * the most-closely-nested first. This is needed to resolve PARAM_EXEC
3746 : * Params. Note we assume that all the Plan nodes share the same rtable.
3747 : *
3748 : * Once this function has been called, deparse_expression() can be called on
3749 : * subsidiary expression(s) of the specified Plan node. To deparse
3750 : * expressions of a different Plan node in the same Plan tree, re-call this
3751 : * function to identify the new parent Plan node.
3752 : *
3753 : * The result is the same List passed in; this is a notational convenience.
3754 : */
3755 : List *
3756 GIC 21439 : set_deparse_context_plan(List *dpcontext, Plan *plan, List *ancestors)
3757 : {
3758 ECB : deparse_namespace *dpns;
3759 :
3760 : /* Should always have one-entry namespace list for Plan deparsing */
3761 GIC 21439 : Assert(list_length(dpcontext) == 1);
3762 CBC 21439 : dpns = (deparse_namespace *) linitial(dpcontext);
3763 ECB :
3764 : /* Set our attention on the specific plan node passed in */
3765 CBC 21439 : dpns->ancestors = ancestors;
3766 21439 : set_deparse_plan(dpns, plan);
3767 ECB :
3768 GIC 21439 : return dpcontext;
3769 : }
3770 ECB :
3771 : /*
3772 : * select_rtable_names_for_explain - Select RTE aliases for EXPLAIN
3773 : *
3774 : * Determine the relation aliases we'll use during an EXPLAIN operation.
3775 : * This is just a frontend to set_rtable_names. We have to expose the aliases
3776 : * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
3777 : */
3778 : List *
3779 GIC 9874 : select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
3780 : {
3781 : deparse_namespace dpns;
3782 :
3783 9874 : memset(&dpns, 0, sizeof(dpns));
3784 9874 : dpns.rtable = rtable;
3785 9874 : dpns.subplans = NIL;
3786 9874 : dpns.ctes = NIL;
3787 CBC 9874 : dpns.appendrels = NULL;
3788 GIC 9874 : set_rtable_names(&dpns, NIL, rels_used);
3789 : /* We needn't bother computing column aliases yet */
3790 :
3791 9874 : return dpns.rtable_names;
3792 : }
3793 :
3794 : /*
3795 : * set_rtable_names: select RTE aliases to be used in printing a query
3796 : *
3797 ECB : * We fill in dpns->rtable_names with a list of names that is one-for-one with
3798 : * the already-filled dpns->rtable list. Each RTE name is unique among those
3799 : * in the new namespace plus any ancestor namespaces listed in
3800 : * parent_namespaces.
3801 : *
3802 : * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
3803 : *
3804 : * Note that this function is only concerned with relation names, not column
3805 : * names.
3806 : */
3807 : static void
3808 CBC 21939 : set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
3809 ECB : Bitmapset *rels_used)
3810 : {
3811 : HASHCTL hash_ctl;
3812 : HTAB *names_hash;
3813 : NameHashEntry *hentry;
3814 : bool found;
3815 : int rtindex;
3816 : ListCell *lc;
3817 :
3818 GIC 21939 : dpns->rtable_names = NIL;
3819 : /* nothing more to do if empty rtable */
3820 CBC 21939 : if (dpns->rtable == NIL)
3821 GIC 232 : return;
3822 ECB :
3823 : /*
3824 : * We use a hash table to hold known names, so that this process is O(N)
3825 : * not O(N^2) for N names.
3826 : */
3827 GIC 21707 : hash_ctl.keysize = NAMEDATALEN;
3828 21707 : hash_ctl.entrysize = sizeof(NameHashEntry);
3829 21707 : hash_ctl.hcxt = CurrentMemoryContext;
3830 21707 : names_hash = hash_create("set_rtable_names names",
3831 CBC 21707 : list_length(dpns->rtable),
3832 : &hash_ctl,
3833 : HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
3834 :
3835 : /* Preload the hash table with names appearing in parent_namespaces */
3836 22365 : foreach(lc, parent_namespaces)
3837 ECB : {
3838 GIC 658 : deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
3839 ECB : ListCell *lc2;
3840 :
3841 GIC 2189 : foreach(lc2, olddpns->rtable_names)
3842 : {
3843 CBC 1531 : char *oldname = (char *) lfirst(lc2);
3844 :
3845 1531 : if (oldname == NULL)
3846 GIC 114 : continue;
3847 1417 : hentry = (NameHashEntry *) hash_search(names_hash,
3848 ECB : oldname,
3849 : HASH_ENTER,
3850 : &found);
3851 : /* we do not complain about duplicate names in parent namespaces */
3852 GIC 1417 : hentry->counter = 0;
3853 ECB : }
3854 : }
3855 :
3856 : /* Now we can scan the rtable */
3857 GIC 21707 : rtindex = 1;
3858 CBC 60652 : foreach(lc, dpns->rtable)
3859 : {
3860 38945 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
3861 : char *refname;
3862 :
3863 ECB : /* Just in case this takes an unreasonable amount of time ... */
3864 GIC 38945 : CHECK_FOR_INTERRUPTS();
3865 :
3866 38945 : if (rels_used && !bms_is_member(rtindex, rels_used))
3867 : {
3868 ECB : /* Ignore unreferenced RTE */
3869 GIC 5831 : refname = NULL;
3870 : }
3871 33114 : else if (rte->alias)
3872 : {
3873 : /* If RTE has a user-defined alias, prefer that */
3874 21727 : refname = rte->alias->aliasname;
3875 : }
3876 11387 : else if (rte->rtekind == RTE_RELATION)
3877 ECB : {
3878 : /* Use the current actual name of the relation */
3879 CBC 9798 : refname = get_rel_name(rte->relid);
3880 : }
3881 GIC 1589 : else if (rte->rtekind == RTE_JOIN)
3882 : {
3883 ECB : /* Unnamed join has no refname */
3884 GIC 630 : refname = NULL;
3885 : }
3886 ECB : else
3887 : {
3888 : /* Otherwise use whatever the parser assigned */
3889 GIC 959 : refname = rte->eref->aliasname;
3890 : }
3891 :
3892 ECB : /*
3893 : * If the selected name isn't unique, append digits to make it so, and
3894 : * make a new hash entry for it once we've got a unique name. For a
3895 : * very long input name, we might have to truncate to stay within
3896 : * NAMEDATALEN.
3897 : */
3898 CBC 38945 : if (refname)
3899 : {
3900 32484 : hentry = (NameHashEntry *) hash_search(names_hash,
3901 : refname,
3902 : HASH_ENTER,
3903 ECB : &found);
3904 GIC 32484 : if (found)
3905 : {
3906 : /* Name already in use, must choose a new one */
3907 CBC 6241 : int refnamelen = strlen(refname);
3908 6241 : char *modname = (char *) palloc(refnamelen + 16);
3909 ECB : NameHashEntry *hentry2;
3910 :
3911 : do
3912 : {
3913 GIC 6244 : hentry->counter++;
3914 ECB : for (;;)
3915 : {
3916 GIC 6250 : memcpy(modname, refname, refnamelen);
3917 6250 : sprintf(modname + refnamelen, "_%d", hentry->counter);
3918 CBC 6250 : if (strlen(modname) < NAMEDATALEN)
3919 6244 : break;
3920 : /* drop chars from refname to keep all the digits */
3921 GIC 6 : refnamelen = pg_mbcliplen(refname, refnamelen,
3922 ECB : refnamelen - 1);
3923 : }
3924 GIC 6244 : hentry2 = (NameHashEntry *) hash_search(names_hash,
3925 : modname,
3926 : HASH_ENTER,
3927 : &found);
3928 6244 : } while (found);
3929 6241 : hentry2->counter = 0; /* init new hash entry */
3930 6241 : refname = modname;
3931 : }
3932 ECB : else
3933 : {
3934 : /* Name not previously used, need only initialize hentry */
3935 GIC 26243 : hentry->counter = 0;
3936 : }
3937 : }
3938 :
3939 CBC 38945 : dpns->rtable_names = lappend(dpns->rtable_names, refname);
3940 38945 : rtindex++;
3941 ECB : }
3942 :
3943 CBC 21707 : hash_destroy(names_hash);
3944 : }
3945 :
3946 ECB : /*
3947 : * set_deparse_for_query: set up deparse_namespace for deparsing a Query tree
3948 : *
3949 : * For convenience, this is defined to initialize the deparse_namespace struct
3950 : * from scratch.
3951 : */
3952 : static void
3953 GIC 2364 : set_deparse_for_query(deparse_namespace *dpns, Query *query,
3954 : List *parent_namespaces)
3955 ECB : {
3956 : ListCell *lc;
3957 : ListCell *lc2;
3958 :
3959 : /* Initialize *dpns and fill rtable/ctes links */
3960 GIC 2364 : memset(dpns, 0, sizeof(deparse_namespace));
3961 2364 : dpns->rtable = query->rtable;
3962 2364 : dpns->subplans = NIL;
3963 2364 : dpns->ctes = query->cteList;
3964 2364 : dpns->appendrels = NULL;
3965 ECB :
3966 : /* Assign a unique relation alias to each RTE */
3967 GIC 2364 : set_rtable_names(dpns, parent_namespaces, NULL);
3968 :
3969 : /* Initialize dpns->rtable_columns to contain zeroed structs */
3970 2364 : dpns->rtable_columns = NIL;
3971 6395 : while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
3972 4031 : dpns->rtable_columns = lappend(dpns->rtable_columns,
3973 : palloc0(sizeof(deparse_columns)));
3974 :
3975 : /* If it's a utility query, it won't have a jointree */
3976 CBC 2364 : if (query->jointree)
3977 : {
3978 ECB : /* Detect whether global uniqueness of USING names is needed */
3979 CBC 2356 : dpns->unique_using =
3980 GIC 2356 : has_dangerous_join_using(dpns, (Node *) query->jointree);
3981 ECB :
3982 : /*
3983 : * Select names for columns merged by USING, via a recursive pass over
3984 : * the query jointree.
3985 : */
3986 CBC 2356 : set_using_names(dpns, (Node *) query->jointree, NIL);
3987 : }
3988 :
3989 : /*
3990 : * Now assign remaining column aliases for each RTE. We do this in a
3991 : * linear scan of the rtable, so as to process RTEs whether or not they
3992 : * are in the jointree (we mustn't miss NEW.*, INSERT target relations,
3993 : * etc). JOIN RTEs must be processed after their children, but this is
3994 : * okay because they appear later in the rtable list than their children
3995 : * (cf Asserts in identify_join_columns()).
3996 : */
3997 6395 : forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
3998 : {
3999 GIC 4031 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4000 4031 : deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4001 :
4002 4031 : if (rte->rtekind == RTE_JOIN)
4003 CBC 500 : set_join_column_names(dpns, rte, colinfo);
4004 ECB : else
4005 CBC 3531 : set_relation_column_names(dpns, rte, colinfo);
4006 : }
4007 GIC 2364 : }
4008 :
4009 ECB : /*
4010 : * set_simple_column_names: fill in column aliases for non-query situations
4011 : *
4012 : * This handles EXPLAIN and cases where we only have relation RTEs. Without
4013 : * a join tree, we can't do anything smart about join RTEs, but we don't
4014 : * need to (note that EXPLAIN should never see join alias Vars anyway).
4015 : * If we do hit a join RTE we'll just process it like a non-table base RTE.
4016 : */
4017 : static void
4018 GIC 19575 : set_simple_column_names(deparse_namespace *dpns)
4019 : {
4020 : ListCell *lc;
4021 : ListCell *lc2;
4022 :
4023 : /* Initialize dpns->rtable_columns to contain zeroed structs */
4024 19575 : dpns->rtable_columns = NIL;
4025 54489 : while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
4026 34914 : dpns->rtable_columns = lappend(dpns->rtable_columns,
4027 : palloc0(sizeof(deparse_columns)));
4028 :
4029 : /* Assign unique column aliases within each RTE */
4030 54489 : forboth(lc, dpns->rtable, lc2, dpns->rtable_columns)
4031 : {
4032 34914 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
4033 34914 : deparse_columns *colinfo = (deparse_columns *) lfirst(lc2);
4034 :
4035 34914 : set_relation_column_names(dpns, rte, colinfo);
4036 : }
4037 19575 : }
4038 ECB :
4039 : /*
4040 : * has_dangerous_join_using: search jointree for unnamed JOIN USING
4041 : *
4042 : * Merged columns of a JOIN USING may act differently from either of the input
4043 : * columns, either because they are merged with COALESCE (in a FULL JOIN) or
4044 : * because an implicit coercion of the underlying input column is required.
4045 : * In such a case the column must be referenced as a column of the JOIN not as
4046 : * a column of either input. And this is problematic if the join is unnamed
4047 : * (alias-less): we cannot qualify the column's name with an RTE name, since
4048 : * there is none. (Forcibly assigning an alias to the join is not a solution,
4049 : * since that will prevent legal references to tables below the join.)
4050 : * To ensure that every column in the query is unambiguously referenceable,
4051 : * we must assign such merged columns names that are globally unique across
4052 : * the whole query, aliasing other columns out of the way as necessary.
4053 : *
4054 : * Because the ensuing re-aliasing is fairly damaging to the readability of
4055 : * the query, we don't do this unless we have to. So, we must pre-scan
4056 : * the join tree to see if we have to, before starting set_using_names().
4057 : */
4058 : static bool
4059 GIC 5335 : has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
4060 ECB : {
4061 GIC 5335 : if (IsA(jtnode, RangeTblRef))
4062 : {
4063 : /* nothing to do here */
4064 : }
4065 2823 : else if (IsA(jtnode, FromExpr))
4066 : {
4067 CBC 2356 : FromExpr *f = (FromExpr *) jtnode;
4068 : ListCell *lc;
4069 :
4070 4437 : foreach(lc, f->fromlist)
4071 : {
4072 2117 : if (has_dangerous_join_using(dpns, (Node *) lfirst(lc)))
4073 GIC 36 : return true;
4074 ECB : }
4075 : }
4076 GIC 467 : else if (IsA(jtnode, JoinExpr))
4077 : {
4078 467 : JoinExpr *j = (JoinExpr *) jtnode;
4079 :
4080 ECB : /* Is it an unnamed JOIN with USING? */
4081 GBC 467 : if (j->alias == NULL && j->usingClause)
4082 ECB : {
4083 EUB : /*
4084 : * Yes, so check each join alias var to see if any of them are not
4085 : * simple references to underlying columns. If so, we have a
4086 : * dangerous situation and must pick unique aliases.
4087 : */
4088 CBC 143 : RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
4089 :
4090 : /* We need only examine the merged columns */
4091 GIC 298 : for (int i = 0; i < jrte->joinmergedcols; i++)
4092 : {
4093 191 : Node *aliasvar = list_nth(jrte->joinaliasvars, i);
4094 :
4095 191 : if (!IsA(aliasvar, Var))
4096 36 : return true;
4097 : }
4098 : }
4099 :
4100 : /* Nope, but inspect children */
4101 431 : if (has_dangerous_join_using(dpns, j->larg))
4102 UIC 0 : return true;
4103 GIC 431 : if (has_dangerous_join_using(dpns, j->rarg))
4104 LBC 0 : return true;
4105 : }
4106 ECB : else
4107 UIC 0 : elog(ERROR, "unrecognized node type: %d",
4108 : (int) nodeTag(jtnode));
4109 GIC 5263 : return false;
4110 ECB : }
4111 :
4112 : /*
4113 : * set_using_names: select column aliases to be used for merged USING columns
4114 : *
4115 : * We do this during a recursive descent of the query jointree.
4116 : * dpns->unique_using must already be set to determine the global strategy.
4117 : *
4118 : * Column alias info is saved in the dpns->rtable_columns list, which is
4119 : * assumed to be filled with pre-zeroed deparse_columns structs.
4120 : *
4121 : * parentUsing is a list of all USING aliases assigned in parent joins of
4122 : * the current jointree node. (The passed-in list must not be modified.)
4123 : */
4124 : static void
4125 GIC 5494 : set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
4126 : {
4127 5494 : if (IsA(jtnode, RangeTblRef))
4128 : {
4129 : /* nothing to do now */
4130 : }
4131 CBC 2856 : else if (IsA(jtnode, FromExpr))
4132 ECB : {
4133 CBC 2356 : FromExpr *f = (FromExpr *) jtnode;
4134 : ListCell *lc;
4135 :
4136 4494 : foreach(lc, f->fromlist)
4137 2138 : set_using_names(dpns, (Node *) lfirst(lc), parentUsing);
4138 : }
4139 GIC 500 : else if (IsA(jtnode, JoinExpr))
4140 : {
4141 500 : JoinExpr *j = (JoinExpr *) jtnode;
4142 500 : RangeTblEntry *rte = rt_fetch(j->rtindex, dpns->rtable);
4143 500 : deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
4144 ECB : int *leftattnos;
4145 : int *rightattnos;
4146 : deparse_columns *leftcolinfo;
4147 : deparse_columns *rightcolinfo;
4148 : int i;
4149 : ListCell *lc;
4150 :
4151 : /* Get info about the shape of the join */
4152 GIC 500 : identify_join_columns(j, rte, colinfo);
4153 500 : leftattnos = colinfo->leftattnos;
4154 CBC 500 : rightattnos = colinfo->rightattnos;
4155 :
4156 ECB : /* Look up the not-yet-filled-in child deparse_columns structs */
4157 CBC 500 : leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4158 GIC 500 : rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4159 :
4160 : /*
4161 ECB : * If this join is unnamed, then we cannot substitute new aliases at
4162 : * this level, so any name requirements pushed down to here must be
4163 : * pushed down again to the children.
4164 : */
4165 GIC 500 : if (rte->alias == NULL)
4166 : {
4167 515 : for (i = 0; i < colinfo->num_cols; i++)
4168 : {
4169 69 : char *colname = colinfo->colnames[i];
4170 :
4171 69 : if (colname == NULL)
4172 12 : continue;
4173 :
4174 : /* Push down to left column, unless it's a system column */
4175 57 : if (leftattnos[i] > 0)
4176 : {
4177 51 : expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4178 51 : leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4179 : }
4180 :
4181 : /* Same on the righthand side */
4182 57 : if (rightattnos[i] > 0)
4183 : {
4184 57 : expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4185 57 : rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4186 : }
4187 : }
4188 : }
4189 :
4190 : /*
4191 : * If there's a USING clause, select the USING column names and push
4192 : * those names down to the children. We have two strategies:
4193 : *
4194 ECB : * If dpns->unique_using is true, we force all USING names to be
4195 : * unique across the whole query level. In principle we'd only need
4196 : * the names of dangerous USING columns to be globally unique, but to
4197 : * safely assign all USING names in a single pass, we have to enforce
4198 : * the same uniqueness rule for all of them. However, if a USING
4199 : * column's name has been pushed down from the parent, we should use
4200 : * it as-is rather than making a uniqueness adjustment. This is
4201 : * necessary when we're at an unnamed join, and it creates no risk of
4202 : * ambiguity. Also, if there's a user-written output alias for a
4203 : * merged column, we prefer to use that rather than the input name;
4204 : * this simplifies the logic and seems likely to lead to less aliasing
4205 : * overall.
4206 : *
4207 : * If dpns->unique_using is false, we only need USING names to be
4208 : * unique within their own join RTE. We still need to honor
4209 : * pushed-down names, though.
4210 : *
4211 : * Though significantly different in results, these two strategies are
4212 : * implemented by the same code, with only the difference of whether
4213 : * to put assigned names into dpns->using_names.
4214 : */
4215 CBC 500 : if (j->usingClause)
4216 EUB : {
4217 : /* Copy the input parentUsing list so we don't modify it */
4218 CBC 212 : parentUsing = list_copy(parentUsing);
4219 ECB :
4220 : /* USING names must correspond to the first join output columns */
4221 GIC 212 : expand_colnames_array_to(colinfo, list_length(j->usingClause));
4222 212 : i = 0;
4223 CBC 502 : foreach(lc, j->usingClause)
4224 : {
4225 GIC 290 : char *colname = strVal(lfirst(lc));
4226 :
4227 ECB : /* Assert it's a merged column */
4228 CBC 290 : Assert(leftattnos[i] != 0 && rightattnos[i] != 0);
4229 :
4230 : /* Adopt passed-down name if any, else select unique name */
4231 290 : if (colinfo->colnames[i] != NULL)
4232 GIC 51 : colname = colinfo->colnames[i];
4233 ECB : else
4234 : {
4235 : /* Prefer user-written output alias if any */
4236 GIC 239 : if (rte->alias && i < list_length(rte->alias->colnames))
4237 UIC 0 : colname = strVal(list_nth(rte->alias->colnames, i));
4238 ECB : /* Make it appropriately unique */
4239 GIC 239 : colname = make_colname_unique(colname, dpns, colinfo);
4240 CBC 239 : if (dpns->unique_using)
4241 63 : dpns->using_names = lappend(dpns->using_names,
4242 : colname);
4243 : /* Save it as output column name, too */
4244 239 : colinfo->colnames[i] = colname;
4245 : }
4246 :
4247 : /* Remember selected names for use later */
4248 GIC 290 : colinfo->usingNames = lappend(colinfo->usingNames, colname);
4249 CBC 290 : parentUsing = lappend(parentUsing, colname);
4250 ECB :
4251 : /* Push down to left column, unless it's a system column */
4252 GIC 290 : if (leftattnos[i] > 0)
4253 ECB : {
4254 CBC 290 : expand_colnames_array_to(leftcolinfo, leftattnos[i]);
4255 GIC 290 : leftcolinfo->colnames[leftattnos[i] - 1] = colname;
4256 : }
4257 EUB :
4258 : /* Same on the righthand side */
4259 CBC 290 : if (rightattnos[i] > 0)
4260 : {
4261 GIC 290 : expand_colnames_array_to(rightcolinfo, rightattnos[i]);
4262 290 : rightcolinfo->colnames[rightattnos[i] - 1] = colname;
4263 : }
4264 :
4265 290 : i++;
4266 : }
4267 : }
4268 :
4269 ECB : /* Mark child deparse_columns structs with correct parentUsing info */
4270 GIC 500 : leftcolinfo->parentUsing = parentUsing;
4271 500 : rightcolinfo->parentUsing = parentUsing;
4272 :
4273 : /* Now recursively assign USING column names in children */
4274 500 : set_using_names(dpns, j->larg, parentUsing);
4275 500 : set_using_names(dpns, j->rarg, parentUsing);
4276 : }
4277 : else
4278 UIC 0 : elog(ERROR, "unrecognized node type: %d",
4279 : (int) nodeTag(jtnode));
4280 GIC 5494 : }
4281 :
4282 : /*
4283 : * set_relation_column_names: select column aliases for a non-join RTE
4284 ECB : *
4285 : * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4286 : * If any colnames entries are already filled in, those override local
4287 : * choices.
4288 : */
4289 : static void
4290 CBC 38445 : set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4291 ECB : deparse_columns *colinfo)
4292 : {
4293 : int ncolumns;
4294 : char **real_colnames;
4295 : bool changed_any;
4296 : int noldcolumns;
4297 : int i;
4298 : int j;
4299 :
4300 : /*
4301 : * Construct an array of the current "real" column names of the RTE.
4302 : * real_colnames[] will be indexed by physical column number, with NULL
4303 : * entries for dropped columns.
4304 : */
4305 CBC 38445 : if (rte->rtekind == RTE_RELATION)
4306 : {
4307 : /* Relation --- look to the system catalogs for up-to-date info */
4308 : Relation rel;
4309 : TupleDesc tupdesc;
4310 :
4311 GIC 32179 : rel = relation_open(rte->relid, AccessShareLock);
4312 32179 : tupdesc = RelationGetDescr(rel);
4313 :
4314 32179 : ncolumns = tupdesc->natts;
4315 32179 : real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4316 :
4317 207091 : for (i = 0; i < ncolumns; i++)
4318 : {
4319 174912 : Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
4320 :
4321 174912 : if (attr->attisdropped)
4322 1498 : real_colnames[i] = NULL;
4323 : else
4324 173414 : real_colnames[i] = pstrdup(NameStr(attr->attname));
4325 : }
4326 32179 : relation_close(rel, AccessShareLock);
4327 : }
4328 ECB : else
4329 : {
4330 : /* Otherwise get the column names from eref or expandRTE() */
4331 : List *colnames;
4332 : ListCell *lc;
4333 :
4334 : /*
4335 : * Functions returning composites have the annoying property that some
4336 : * of the composite type's columns might have been dropped since the
4337 : * query was parsed. If possible, use expandRTE() to handle that
4338 : * case, since it has the tedious logic needed to find out about
4339 : * dropped columns. However, if we're explaining a plan, then we
4340 : * don't have rte->functions because the planner thinks that won't be
4341 : * needed later, and that breaks expandRTE(). So in that case we have
4342 : * to rely on rte->eref, which may lead us to report a dropped
4343 : * column's old name; that seems close enough for EXPLAIN's purposes.
4344 : *
4345 : * For non-RELATION, non-FUNCTION RTEs, we can just look at rte->eref,
4346 : * which should be sufficiently up-to-date: no other RTE types can
4347 : * have columns get dropped from under them after parsing.
4348 : */
4349 CBC 6266 : if (rte->rtekind == RTE_FUNCTION && rte->functions != NIL)
4350 ECB : {
4351 : /* Since we're not creating Vars, rtindex etc. don't matter */
4352 CBC 267 : expandRTE(rte, 1, 0, -1, true /* include dropped */ ,
4353 : &colnames, NULL);
4354 : }
4355 : else
4356 GIC 5999 : colnames = rte->eref->colnames;
4357 :
4358 6266 : ncolumns = list_length(colnames);
4359 6266 : real_colnames = (char **) palloc(ncolumns * sizeof(char *));
4360 :
4361 6266 : i = 0;
4362 33471 : foreach(lc, colnames)
4363 : {
4364 ECB : /*
4365 : * If the column name we find here is an empty string, then it's a
4366 : * dropped column, so change to NULL.
4367 : */
4368 GIC 27205 : char *cname = strVal(lfirst(lc));
4369 :
4370 27205 : if (cname[0] == '\0')
4371 27 : cname = NULL;
4372 27205 : real_colnames[i] = cname;
4373 27205 : i++;
4374 ECB : }
4375 : }
4376 :
4377 : /*
4378 : * Ensure colinfo->colnames has a slot for each column. (It could be long
4379 : * enough already, if we pushed down a name for the last column.) Note:
4380 : * it's possible that there are now more columns than there were when the
4381 : * query was parsed, ie colnames could be longer than rte->eref->colnames.
4382 : * We must assign unique aliases to the new columns too, else there could
4383 : * be unresolved conflicts when the view/rule is reloaded.
4384 : */
4385 CBC 38445 : expand_colnames_array_to(colinfo, ncolumns);
4386 38445 : Assert(colinfo->num_cols == ncolumns);
4387 ECB :
4388 : /*
4389 : * Make sufficiently large new_colnames and is_new_col arrays, too.
4390 : *
4391 : * Note: because we leave colinfo->num_new_cols zero until after the loop,
4392 : * colname_is_unique will not consult that array, which is fine because it
4393 : * would only be duplicate effort.
4394 : */
4395 CBC 38445 : colinfo->new_colnames = (char **) palloc(ncolumns * sizeof(char *));
4396 38445 : colinfo->is_new_col = (bool *) palloc(ncolumns * sizeof(bool));
4397 :
4398 : /*
4399 : * Scan the columns, select a unique alias for each one, and store it in
4400 ECB : * colinfo->colnames and colinfo->new_colnames. The former array has NULL
4401 : * entries for dropped columns, the latter omits them. Also mark
4402 : * new_colnames entries as to whether they are new since parse time; this
4403 : * is the case for entries beyond the length of rte->eref->colnames.
4404 : */
4405 GIC 38445 : noldcolumns = list_length(rte->eref->colnames);
4406 CBC 38445 : changed_any = false;
4407 GIC 38445 : j = 0;
4408 240562 : for (i = 0; i < ncolumns; i++)
4409 ECB : {
4410 GIC 202117 : char *real_colname = real_colnames[i];
4411 CBC 202117 : char *colname = colinfo->colnames[i];
4412 :
4413 : /* Skip dropped columns */
4414 GIC 202117 : if (real_colname == NULL)
4415 ECB : {
4416 GIC 1525 : Assert(colname == NULL); /* colnames[i] is already NULL */
4417 CBC 1525 : continue;
4418 ECB : }
4419 :
4420 : /* If alias already assigned, that's what to use */
4421 CBC 200592 : if (colname == NULL)
4422 ECB : {
4423 : /* If user wrote an alias, prefer that over real column name */
4424 GIC 200063 : if (rte->alias && i < list_length(rte->alias->colnames))
4425 19190 : colname = strVal(list_nth(rte->alias->colnames, i));
4426 : else
4427 180873 : colname = real_colname;
4428 :
4429 : /* Unique-ify and insert into colinfo */
4430 200063 : colname = make_colname_unique(colname, dpns, colinfo);
4431 ECB :
4432 GIC 200063 : colinfo->colnames[i] = colname;
4433 : }
4434 :
4435 : /* Put names of non-dropped columns in new_colnames[] too */
4436 200592 : colinfo->new_colnames[j] = colname;
4437 : /* And mark them as new or not */
4438 200592 : colinfo->is_new_col[j] = (i >= noldcolumns);
4439 200592 : j++;
4440 :
4441 : /* Remember if any assigned aliases differ from "real" name */
4442 200592 : if (!changed_any && strcmp(colname, real_colname) != 0)
4443 CBC 1641 : changed_any = true;
4444 ECB : }
4445 :
4446 : /*
4447 : * Set correct length for new_colnames[] array. (Note: if columns have
4448 : * been added, colinfo->num_cols includes them, which is not really quite
4449 : * right but is harmless, since any new columns must be at the end where
4450 : * they won't affect varattnos of pre-existing columns.)
4451 : */
4452 CBC 38445 : colinfo->num_new_cols = j;
4453 ECB :
4454 : /*
4455 : * For a relation RTE, we need only print the alias column names if any
4456 : * are different from the underlying "real" names. For a function RTE,
4457 : * always emit a complete column alias list; this is to protect against
4458 : * possible instability of the default column names (eg, from altering
4459 : * parameter names). For tablefunc RTEs, we never print aliases, because
4460 : * the column names are part of the clause itself. For other RTE types,
4461 : * print if we changed anything OR if there were user-written column
4462 : * aliases (since the latter would be part of the underlying "reality").
4463 : */
4464 GIC 38445 : if (rte->rtekind == RTE_RELATION)
4465 CBC 32179 : colinfo->printaliases = changed_any;
4466 GIC 6266 : else if (rte->rtekind == RTE_FUNCTION)
4467 453 : colinfo->printaliases = true;
4468 5813 : else if (rte->rtekind == RTE_TABLEFUNC)
4469 28 : colinfo->printaliases = false;
4470 5785 : else if (rte->alias && rte->alias->colnames != NIL)
4471 336 : colinfo->printaliases = true;
4472 : else
4473 CBC 5449 : colinfo->printaliases = changed_any;
4474 38445 : }
4475 :
4476 : /*
4477 : * set_join_column_names: select column aliases for a join RTE
4478 : *
4479 : * Column alias info is saved in *colinfo, which is assumed to be pre-zeroed.
4480 : * If any colnames entries are already filled in, those override local
4481 ECB : * choices. Also, names for USING columns were already chosen by
4482 : * set_using_names(). We further expect that column alias selection has been
4483 : * completed for both input RTEs.
4484 : */
4485 : static void
4486 GIC 500 : set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
4487 : deparse_columns *colinfo)
4488 : {
4489 : deparse_columns *leftcolinfo;
4490 : deparse_columns *rightcolinfo;
4491 ECB : bool changed_any;
4492 : int noldcolumns;
4493 : int nnewcolumns;
4494 GIC 500 : Bitmapset *leftmerged = NULL;
4495 500 : Bitmapset *rightmerged = NULL;
4496 : int i;
4497 : int j;
4498 : int ic;
4499 : int jc;
4500 :
4501 ECB : /* Look up the previously-filled-in child deparse_columns structs */
4502 CBC 500 : leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
4503 GIC 500 : rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
4504 ECB :
4505 : /*
4506 : * Ensure colinfo->colnames has a slot for each column. (It could be long
4507 : * enough already, if we pushed down a name for the last column.) Note:
4508 : * it's possible that one or both inputs now have more columns than there
4509 : * were when the query was parsed, but we'll deal with that below. We
4510 : * only need entries in colnames for pre-existing columns.
4511 : */
4512 CBC 500 : noldcolumns = list_length(rte->eref->colnames);
4513 500 : expand_colnames_array_to(colinfo, noldcolumns);
4514 500 : Assert(colinfo->num_cols == noldcolumns);
4515 :
4516 : /*
4517 : * Scan the join output columns, select an alias for each one, and store
4518 EUB : * it in colinfo->colnames. If there are USING columns, set_using_names()
4519 : * already selected their names, so we can start the loop at the first
4520 : * non-merged column.
4521 : */
4522 CBC 500 : changed_any = false;
4523 GIC 12818 : for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
4524 ECB : {
4525 CBC 12318 : char *colname = colinfo->colnames[i];
4526 : char *real_colname;
4527 :
4528 : /* Join column must refer to at least one input column */
4529 12318 : Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
4530 :
4531 ECB : /* Get the child column name */
4532 CBC 12318 : if (colinfo->leftattnos[i] > 0)
4533 GIC 8558 : real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1];
4534 3760 : else if (colinfo->rightattnos[i] > 0)
4535 3760 : real_colname = rightcolinfo->colnames[colinfo->rightattnos[i] - 1];
4536 ECB : else
4537 : {
4538 : /* We're joining system columns --- use eref name */
4539 LBC 0 : real_colname = strVal(list_nth(rte->eref->colnames, i));
4540 ECB : }
4541 :
4542 : /* If child col has been dropped, no need to assign a join colname */
4543 GIC 12318 : if (real_colname == NULL)
4544 : {
4545 CBC 3 : colinfo->colnames[i] = NULL;
4546 GIC 3 : continue;
4547 ECB : }
4548 :
4549 : /* In an unnamed join, just report child column names as-is */
4550 GIC 12315 : if (rte->alias == NULL)
4551 ECB : {
4552 CBC 12126 : colinfo->colnames[i] = real_colname;
4553 GIC 12126 : continue;
4554 : }
4555 :
4556 : /* If alias already assigned, that's what to use */
4557 189 : if (colname == NULL)
4558 : {
4559 : /* If user wrote an alias, prefer that over real column name */
4560 189 : if (rte->alias && i < list_length(rte->alias->colnames))
4561 48 : colname = strVal(list_nth(rte->alias->colnames, i));
4562 ECB : else
4563 CBC 141 : colname = real_colname;
4564 ECB :
4565 : /* Unique-ify and insert into colinfo */
4566 CBC 189 : colname = make_colname_unique(colname, dpns, colinfo);
4567 :
4568 GIC 189 : colinfo->colnames[i] = colname;
4569 : }
4570 :
4571 : /* Remember if any assigned aliases differ from "real" name */
4572 189 : if (!changed_any && strcmp(colname, real_colname) != 0)
4573 12 : changed_any = true;
4574 : }
4575 :
4576 : /*
4577 : * Calculate number of columns the join would have if it were re-parsed
4578 : * now, and create storage for the new_colnames and is_new_col arrays.
4579 : *
4580 : * Note: colname_is_unique will be consulting new_colnames[] during the
4581 : * loops below, so its not-yet-filled entries must be zeroes.
4582 : */
4583 1000 : nnewcolumns = leftcolinfo->num_new_cols + rightcolinfo->num_new_cols -
4584 500 : list_length(colinfo->usingNames);
4585 CBC 500 : colinfo->num_new_cols = nnewcolumns;
4586 500 : colinfo->new_colnames = (char **) palloc0(nnewcolumns * sizeof(char *));
4587 500 : colinfo->is_new_col = (bool *) palloc0(nnewcolumns * sizeof(bool));
4588 ECB :
4589 : /*
4590 : * Generating the new_colnames array is a bit tricky since any new columns
4591 : * added since parse time must be inserted in the right places. This code
4592 : * must match the parser, which will order a join's columns as merged
4593 : * columns first (in USING-clause order), then non-merged columns from the
4594 : * left input (in attnum order), then non-merged columns from the right
4595 : * input (ditto). If one of the inputs is itself a join, its columns will
4596 : * be ordered according to the same rule, which means newly-added columns
4597 : * might not be at the end. We can figure out what's what by consulting
4598 : * the leftattnos and rightattnos arrays plus the input is_new_col arrays.
4599 : *
4600 : * In these loops, i indexes leftattnos/rightattnos (so it's join varattno
4601 : * less one), j indexes new_colnames/is_new_col, and ic/jc have similar
4602 : * meanings for the current child RTE.
4603 : */
4604 :
4605 : /* Handle merged columns; they are first and can't be new */
4606 GIC 500 : i = j = 0;
4607 CBC 500 : while (i < noldcolumns &&
4608 GIC 790 : colinfo->leftattnos[i] != 0 &&
4609 CBC 790 : colinfo->rightattnos[i] != 0)
4610 : {
4611 : /* column name is already determined and known unique */
4612 290 : colinfo->new_colnames[j] = colinfo->colnames[i];
4613 290 : colinfo->is_new_col[j] = false;
4614 ECB :
4615 : /* build bitmapsets of child attnums of merged columns */
4616 CBC 290 : if (colinfo->leftattnos[i] > 0)
4617 GIC 290 : leftmerged = bms_add_member(leftmerged, colinfo->leftattnos[i]);
4618 CBC 290 : if (colinfo->rightattnos[i] > 0)
4619 290 : rightmerged = bms_add_member(rightmerged, colinfo->rightattnos[i]);
4620 :
4621 290 : i++, j++;
4622 ECB : }
4623 :
4624 : /* Handle non-merged left-child columns */
4625 CBC 500 : ic = 0;
4626 GIC 9591 : for (jc = 0; jc < leftcolinfo->num_new_cols; jc++)
4627 ECB : {
4628 CBC 9091 : char *child_colname = leftcolinfo->new_colnames[jc];
4629 :
4630 GIC 9091 : if (!leftcolinfo->is_new_col[jc])
4631 : {
4632 : /* Advance ic to next non-dropped old column of left child */
4633 8887 : while (ic < leftcolinfo->num_cols &&
4634 8887 : leftcolinfo->colnames[ic] == NULL)
4635 42 : ic++;
4636 CBC 8845 : Assert(ic < leftcolinfo->num_cols);
4637 GIC 8845 : ic++;
4638 ECB : /* If it is a merged column, we already processed it */
4639 CBC 8845 : if (bms_is_member(ic, leftmerged))
4640 290 : continue;
4641 ECB : /* Else, advance i to the corresponding existing join column */
4642 CBC 8558 : while (i < colinfo->num_cols &&
4643 GIC 8558 : colinfo->colnames[i] == NULL)
4644 3 : i++;
4645 CBC 8555 : Assert(i < colinfo->num_cols);
4646 GIC 8555 : Assert(ic == colinfo->leftattnos[i]);
4647 : /* Use the already-assigned name of this column */
4648 CBC 8555 : colinfo->new_colnames[j] = colinfo->colnames[i];
4649 8555 : i++;
4650 : }
4651 : else
4652 : {
4653 ECB : /*
4654 : * Unique-ify the new child column name and assign, unless we're
4655 : * in an unnamed join, in which case just copy
4656 : */
4657 GIC 246 : if (rte->alias != NULL)
4658 ECB : {
4659 GIC 132 : colinfo->new_colnames[j] =
4660 66 : make_colname_unique(child_colname, dpns, colinfo);
4661 CBC 66 : if (!changed_any &&
4662 54 : strcmp(colinfo->new_colnames[j], child_colname) != 0)
4663 GBC 6 : changed_any = true;
4664 ECB : }
4665 : else
4666 GIC 180 : colinfo->new_colnames[j] = child_colname;
4667 ECB : }
4668 :
4669 GIC 8801 : colinfo->is_new_col[j] = leftcolinfo->is_new_col[jc];
4670 CBC 8801 : j++;
4671 ECB : }
4672 EUB :
4673 ECB : /* Handle non-merged right-child columns in exactly the same way */
4674 CBC 500 : ic = 0;
4675 GIC 4634 : for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
4676 ECB : {
4677 CBC 4134 : char *child_colname = rightcolinfo->new_colnames[jc];
4678 :
4679 GIC 4134 : if (!rightcolinfo->is_new_col[jc])
4680 : {
4681 : /* Advance ic to next non-dropped old column of right child */
4682 4050 : while (ic < rightcolinfo->num_cols &&
4683 4050 : rightcolinfo->colnames[ic] == NULL)
4684 UIC 0 : ic++;
4685 CBC 4050 : Assert(ic < rightcolinfo->num_cols);
4686 GIC 4050 : ic++;
4687 ECB : /* If it is a merged column, we already processed it */
4688 CBC 4050 : if (bms_is_member(ic, rightmerged))
4689 290 : continue;
4690 ECB : /* Else, advance i to the corresponding existing join column */
4691 CBC 3760 : while (i < colinfo->num_cols &&
4692 GIC 3760 : colinfo->colnames[i] == NULL)
4693 UIC 0 : i++;
4694 CBC 3760 : Assert(i < colinfo->num_cols);
4695 GIC 3760 : Assert(ic == colinfo->rightattnos[i]);
4696 : /* Use the already-assigned name of this column */
4697 CBC 3760 : colinfo->new_colnames[j] = colinfo->colnames[i];
4698 3760 : i++;
4699 : }
4700 : else
4701 : {
4702 : /*
4703 ECB : * Unique-ify the new child column name and assign, unless we're
4704 EUB : * in an unnamed join, in which case just copy
4705 ECB : */
4706 CBC 84 : if (rte->alias != NULL)
4707 : {
4708 GIC 24 : colinfo->new_colnames[j] =
4709 12 : make_colname_unique(child_colname, dpns, colinfo);
4710 12 : if (!changed_any &&
4711 12 : strcmp(colinfo->new_colnames[j], child_colname) != 0)
4712 6 : changed_any = true;
4713 ECB : }
4714 : else
4715 GIC 72 : colinfo->new_colnames[j] = child_colname;
4716 ECB : }
4717 :
4718 GIC 3844 : colinfo->is_new_col[j] = rightcolinfo->is_new_col[jc];
4719 3844 : j++;
4720 : }
4721 :
4722 : /* Assert we processed the right number of columns */
4723 : #ifdef USE_ASSERT_CHECKING
4724 500 : while (i < colinfo->num_cols && colinfo->colnames[i] == NULL)
4725 LBC 0 : i++;
4726 GIC 500 : Assert(i == colinfo->num_cols);
4727 500 : Assert(j == nnewcolumns);
4728 : #endif
4729 :
4730 : /*
4731 : * For a named join, print column aliases if we changed any from the child
4732 ECB : * names. Unnamed joins cannot print aliases.
4733 : */
4734 CBC 500 : if (rte->alias != NULL)
4735 GIC 54 : colinfo->printaliases = changed_any;
4736 ECB : else
4737 CBC 446 : colinfo->printaliases = false;
4738 GIC 500 : }
4739 :
4740 : /*
4741 : * colname_is_unique: is colname distinct from already-chosen column names?
4742 : *
4743 : * dpns is query-wide info, colinfo is for the column's RTE
4744 ECB : */
4745 : static bool
4746 CBC 209077 : colname_is_unique(const char *colname, deparse_namespace *dpns,
4747 : deparse_columns *colinfo)
4748 ECB : {
4749 : int i;
4750 : ListCell *lc;
4751 :
4752 : /* Check against already-assigned column aliases within RTE */
4753 CBC 3170987 : for (i = 0; i < colinfo->num_cols; i++)
4754 : {
4755 2970382 : char *oldname = colinfo->colnames[i];
4756 :
4757 2970382 : if (oldname && strcmp(oldname, colname) == 0)
4758 8472 : return false;
4759 : }
4760 :
4761 : /*
4762 ECB : * If we're building a new_colnames array, check that too (this will be
4763 : * partially but not completely redundant with the previous checks)
4764 : */
4765 GIC 201241 : for (i = 0; i < colinfo->num_new_cols; i++)
4766 ECB : {
4767 CBC 648 : char *oldname = colinfo->new_colnames[i];
4768 :
4769 GIC 648 : if (oldname && strcmp(oldname, colname) == 0)
4770 CBC 12 : return false;
4771 : }
4772 :
4773 : /* Also check against USING-column names that must be globally unique */
4774 GIC 201013 : foreach(lc, dpns->using_names)
4775 : {
4776 441 : char *oldname = (char *) lfirst(lc);
4777 :
4778 441 : if (strcmp(oldname, colname) == 0)
4779 CBC 21 : return false;
4780 : }
4781 :
4782 : /* Also check against names already assigned for parent-join USING cols */
4783 GIC 201868 : foreach(lc, colinfo->parentUsing)
4784 : {
4785 1299 : char *oldname = (char *) lfirst(lc);
4786 :
4787 CBC 1299 : if (strcmp(oldname, colname) == 0)
4788 GIC 3 : return false;
4789 ECB : }
4790 :
4791 CBC 200569 : return true;
4792 : }
4793 :
4794 : /*
4795 ECB : * make_colname_unique: modify colname if necessary to make it unique
4796 : *
4797 : * dpns is query-wide info, colinfo is for the column's RTE
4798 : */
4799 : static char *
4800 CBC 200569 : make_colname_unique(char *colname, deparse_namespace *dpns,
4801 ECB : deparse_columns *colinfo)
4802 : {
4803 EUB : /*
4804 : * If the selected name isn't unique, append digits to make it so. For a
4805 : * very long input name, we might have to truncate to stay within
4806 ECB : * NAMEDATALEN.
4807 : */
4808 GIC 200569 : if (!colname_is_unique(colname, dpns, colinfo))
4809 ECB : {
4810 GIC 7412 : int colnamelen = strlen(colname);
4811 7412 : char *modname = (char *) palloc(colnamelen + 16);
4812 7412 : int i = 0;
4813 :
4814 : do
4815 : {
4816 8508 : i++;
4817 : for (;;)
4818 ECB : {
4819 GIC 8508 : memcpy(modname, colname, colnamelen);
4820 CBC 8508 : sprintf(modname + colnamelen, "_%d", i);
4821 GIC 8508 : if (strlen(modname) < NAMEDATALEN)
4822 CBC 8508 : break;
4823 ECB : /* drop chars from colname to keep all the digits */
4824 UIC 0 : colnamelen = pg_mbcliplen(colname, colnamelen,
4825 ECB : colnamelen - 1);
4826 : }
4827 GIC 8508 : } while (!colname_is_unique(modname, dpns, colinfo));
4828 CBC 7412 : colname = modname;
4829 : }
4830 GIC 200569 : return colname;
4831 : }
4832 :
4833 : /*
4834 : * expand_colnames_array_to: make colinfo->colnames at least n items long
4835 : *
4836 : * Any added array entries are initialized to zero.
4837 ECB : */
4838 : static void
4839 GIC 39845 : expand_colnames_array_to(deparse_columns *colinfo, int n)
4840 : {
4841 39845 : if (n > colinfo->num_cols)
4842 : {
4843 38860 : if (colinfo->colnames == NULL)
4844 GNC 38152 : colinfo->colnames = palloc0_array(char *, n);
4845 : else
4846 708 : colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
4847 GIC 38860 : colinfo->num_cols = n;
4848 ECB : }
4849 CBC 39845 : }
4850 EUB :
4851 : /*
4852 : * identify_join_columns: figure out where columns of a join come from
4853 : *
4854 : * Fills the join-specific fields of the colinfo struct, except for
4855 : * usingNames which is filled later.
4856 : */
4857 ECB : static void
4858 CBC 500 : identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
4859 : deparse_columns *colinfo)
4860 : {
4861 ECB : int numjoincols;
4862 : int jcolno;
4863 : int rcolno;
4864 : ListCell *lc;
4865 :
4866 : /* Extract left/right child RT indexes */
4867 GIC 500 : if (IsA(j->larg, RangeTblRef))
4868 335 : colinfo->leftrti = ((RangeTblRef *) j->larg)->rtindex;
4869 165 : else if (IsA(j->larg, JoinExpr))
4870 165 : colinfo->leftrti = ((JoinExpr *) j->larg)->rtindex;
4871 : else
4872 UIC 0 : elog(ERROR, "unrecognized node type in jointree: %d",
4873 ECB : (int) nodeTag(j->larg));
4874 CBC 500 : if (IsA(j->rarg, RangeTblRef))
4875 GIC 500 : colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex;
4876 LBC 0 : else if (IsA(j->rarg, JoinExpr))
4877 UIC 0 : colinfo->rightrti = ((JoinExpr *) j->rarg)->rtindex;
4878 ECB : else
4879 UIC 0 : elog(ERROR, "unrecognized node type in jointree: %d",
4880 ECB : (int) nodeTag(j->rarg));
4881 :
4882 : /* Assert children will be processed earlier than join in second pass */
4883 CBC 500 : Assert(colinfo->leftrti < j->rtindex);
4884 GIC 500 : Assert(colinfo->rightrti < j->rtindex);
4885 ECB :
4886 : /* Initialize result arrays with zeroes */
4887 GIC 500 : numjoincols = list_length(jrte->joinaliasvars);
4888 CBC 500 : Assert(numjoincols == list_length(jrte->eref->colnames));
4889 500 : colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
4890 GIC 500 : colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
4891 ECB :
4892 : /*
4893 : * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
4894 : * Recall that the column(s) merged due to USING are the first column(s)
4895 : * of the join output. We need not do anything special while scanning
4896 : * joinleftcols, but while scanning joinrightcols we must distinguish
4897 : * merged from unmerged columns.
4898 : */
4899 GIC 500 : jcolno = 0;
4900 CBC 9348 : foreach(lc, jrte->joinleftcols)
4901 : {
4902 8848 : int leftattno = lfirst_int(lc);
4903 :
4904 8848 : colinfo->leftattnos[jcolno++] = leftattno;
4905 ECB : }
4906 GIC 500 : rcolno = 0;
4907 4550 : foreach(lc, jrte->joinrightcols)
4908 : {
4909 4050 : int rightattno = lfirst_int(lc);
4910 :
4911 4050 : if (rcolno < jrte->joinmergedcols) /* merged column? */
4912 290 : colinfo->rightattnos[rcolno] = rightattno;
4913 : else
4914 3760 : colinfo->rightattnos[jcolno++] = rightattno;
4915 4050 : rcolno++;
4916 : }
4917 500 : Assert(jcolno == numjoincols);
4918 500 : }
4919 ECB :
4920 : /*
4921 : * get_rtable_name: convenience function to get a previously assigned RTE alias
4922 : *
4923 : * The RTE must belong to the topmost namespace level in "context".
4924 : */
4925 : static char *
4926 GIC 2564 : get_rtable_name(int rtindex, deparse_context *context)
4927 : {
4928 2564 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
4929 ECB :
4930 CBC 2564 : Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
4931 2564 : return (char *) list_nth(dpns->rtable_names, rtindex - 1);
4932 ECB : }
4933 :
4934 : /*
4935 : * set_deparse_plan: set up deparse_namespace to parse subexpressions
4936 : * of a given Plan node
4937 : *
4938 : * This sets the plan, outer_plan, inner_plan, outer_tlist, inner_tlist,
4939 : * and index_tlist fields. Caller must already have adjusted the ancestors
4940 : * list if necessary. Note that the rtable, subplans, and ctes fields do
4941 : * not need to change when shifting attention to different plan nodes in a
4942 : * single plan tree.
4943 : */
4944 : static void
4945 GIC 49052 : set_deparse_plan(deparse_namespace *dpns, Plan *plan)
4946 : {
4947 49052 : dpns->plan = plan;
4948 :
4949 : /*
4950 : * We special-case Append and MergeAppend to pretend that the first child
4951 : * plan is the OUTER referent; we have to interpret OUTER Vars in their
4952 : * tlists according to one of the children, and the first one is the most
4953 : * natural choice.
4954 : */
4955 CBC 49052 : if (IsA(plan, Append))
4956 1924 : dpns->outer_plan = linitial(((Append *) plan)->appendplans);
4957 47128 : else if (IsA(plan, MergeAppend))
4958 213 : dpns->outer_plan = linitial(((MergeAppend *) plan)->mergeplans);
4959 ECB : else
4960 CBC 46915 : dpns->outer_plan = outerPlan(plan);
4961 ECB :
4962 GIC 49052 : if (dpns->outer_plan)
4963 CBC 21939 : dpns->outer_tlist = dpns->outer_plan->targetlist;
4964 ECB : else
4965 GIC 27113 : dpns->outer_tlist = NIL;
4966 ECB :
4967 : /*
4968 : * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
4969 : * use OUTER because that could someday conflict with the normal meaning.)
4970 : * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
4971 : * For a WorkTableScan, locate the parent RecursiveUnion plan node and use
4972 : * that as INNER referent.
4973 : *
4974 : * For MERGE, make the inner tlist point to the merge source tlist, which
4975 : * is same as the targetlist that the ModifyTable's source plan provides.
4976 : * For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
4977 : * excluded expression's tlist. (Similar to the SubqueryScan we don't want
4978 : * to reuse OUTER, it's used for RETURNING in some modify table cases,
4979 : * although not INSERT .. CONFLICT).
4980 : */
4981 CBC 49052 : if (IsA(plan, SubqueryScan))
4982 238 : dpns->inner_plan = ((SubqueryScan *) plan)->subplan;
4983 48814 : else if (IsA(plan, CteScan))
4984 240 : dpns->inner_plan = list_nth(dpns->subplans,
4985 240 : ((CteScan *) plan)->ctePlanId - 1);
4986 GBC 48574 : else if (IsA(plan, WorkTableScan))
4987 GIC 87 : dpns->inner_plan = find_recursive_union(dpns,
4988 ECB : (WorkTableScan *) plan);
4989 CBC 48487 : else if (IsA(plan, ModifyTable))
4990 GIC 107 : dpns->inner_plan = plan;
4991 : else
4992 48380 : dpns->inner_plan = innerPlan(plan);
4993 :
4994 49052 : if (IsA(plan, ModifyTable))
4995 : {
4996 107 : if (((ModifyTable *) plan)->operation == CMD_MERGE)
4997 CBC 3 : dpns->inner_tlist = dpns->outer_tlist;
4998 : else
4999 GIC 104 : dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
5000 : }
5001 CBC 48945 : else if (dpns->inner_plan)
5002 GIC 7593 : dpns->inner_tlist = dpns->inner_plan->targetlist;
5003 ECB : else
5004 GIC 41352 : dpns->inner_tlist = NIL;
5005 ECB :
5006 : /* Set up referent for INDEX_VAR Vars, if needed */
5007 CBC 49052 : if (IsA(plan, IndexOnlyScan))
5008 GIC 1229 : dpns->index_tlist = ((IndexOnlyScan *) plan)->indextlist;
5009 GBC 47823 : else if (IsA(plan, ForeignScan))
5010 GIC 1360 : dpns->index_tlist = ((ForeignScan *) plan)->fdw_scan_tlist;
5011 46463 : else if (IsA(plan, CustomScan))
5012 UIC 0 : dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist;
5013 : else
5014 GIC 46463 : dpns->index_tlist = NIL;
5015 49052 : }
5016 :
5017 : /*
5018 : * Locate the ancestor plan node that is the RecursiveUnion generating
5019 : * the WorkTableScan's work table. We can match on wtParam, since that
5020 : * should be unique within the plan tree.
5021 : */
5022 : static Plan *
5023 87 : find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan)
5024 : {
5025 : ListCell *lc;
5026 :
5027 CBC 219 : foreach(lc, dpns->ancestors)
5028 : {
5029 GIC 219 : Plan *ancestor = (Plan *) lfirst(lc);
5030 :
5031 CBC 219 : if (IsA(ancestor, RecursiveUnion) &&
5032 GIC 87 : ((RecursiveUnion *) ancestor)->wtParam == wtscan->wtParam)
5033 87 : return ancestor;
5034 ECB : }
5035 UIC 0 : elog(ERROR, "could not find RecursiveUnion for WorkTableScan with wtParam %d",
5036 : wtscan->wtParam);
5037 ECB : return NULL;
5038 : }
5039 :
5040 : /*
5041 : * push_child_plan: temporarily transfer deparsing attention to a child plan
5042 : *
5043 : * When expanding an OUTER_VAR or INNER_VAR reference, we must adjust the
5044 : * deparse context in case the referenced expression itself uses
5045 : * OUTER_VAR/INNER_VAR. We modify the top stack entry in-place to avoid
5046 : * affecting levelsup issues (although in a Plan tree there really shouldn't
5047 : * be any).
5048 : *
5049 : * Caller must provide a local deparse_namespace variable to save the
5050 : * previous state for pop_child_plan.
5051 : */
5052 : static void
5053 GIC 26217 : push_child_plan(deparse_namespace *dpns, Plan *plan,
5054 : deparse_namespace *save_dpns)
5055 ECB : {
5056 : /* Save state for restoration later */
5057 GIC 26217 : *save_dpns = *dpns;
5058 :
5059 : /* Link current plan node into ancestors list */
5060 26217 : dpns->ancestors = lcons(dpns->plan, dpns->ancestors);
5061 :
5062 : /* Set attention on selected child */
5063 26217 : set_deparse_plan(dpns, plan);
5064 26217 : }
5065 :
5066 : /*
5067 : * pop_child_plan: undo the effects of push_child_plan
5068 : */
5069 : static void
5070 26217 : pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5071 : {
5072 : List *ancestors;
5073 :
5074 ECB : /* Get rid of ancestors list cell added by push_child_plan */
5075 GIC 26217 : ancestors = list_delete_first(dpns->ancestors);
5076 :
5077 ECB : /* Restore fields changed by push_child_plan */
5078 GIC 26217 : *dpns = *save_dpns;
5079 :
5080 ECB : /* Make sure dpns->ancestors is right (may be unnecessary) */
5081 GIC 26217 : dpns->ancestors = ancestors;
5082 26217 : }
5083 ECB :
5084 : /*
5085 : * push_ancestor_plan: temporarily transfer deparsing attention to an
5086 : * ancestor plan
5087 : *
5088 : * When expanding a Param reference, we must adjust the deparse context
5089 : * to match the plan node that contains the expression being printed;
5090 : * otherwise we'd fail if that expression itself contains a Param or
5091 : * OUTER_VAR/INNER_VAR/INDEX_VAR variable.
5092 : *
5093 : * The target ancestor is conveniently identified by the ListCell holding it
5094 : * in dpns->ancestors.
5095 : *
5096 : * Caller must provide a local deparse_namespace variable to save the
5097 : * previous state for pop_ancestor_plan.
5098 : */
5099 : static void
5100 GIC 1396 : push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
5101 ECB : deparse_namespace *save_dpns)
5102 : {
5103 GIC 1396 : Plan *plan = (Plan *) lfirst(ancestor_cell);
5104 :
5105 : /* Save state for restoration later */
5106 1396 : *save_dpns = *dpns;
5107 :
5108 : /* Build a new ancestor list with just this node's ancestors */
5109 1396 : dpns->ancestors =
5110 1396 : list_copy_tail(dpns->ancestors,
5111 CBC 1396 : list_cell_number(dpns->ancestors, ancestor_cell) + 1);
5112 :
5113 : /* Set attention on selected ancestor */
5114 GIC 1396 : set_deparse_plan(dpns, plan);
5115 1396 : }
5116 :
5117 : /*
5118 : * pop_ancestor_plan: undo the effects of push_ancestor_plan
5119 : */
5120 : static void
5121 1396 : pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
5122 ECB : {
5123 : /* Free the ancestor list made in push_ancestor_plan */
5124 GIC 1396 : list_free(dpns->ancestors);
5125 :
5126 : /* Restore fields changed by push_ancestor_plan */
5127 1396 : *dpns = *save_dpns;
5128 1396 : }
5129 :
5130 ECB :
5131 : /* ----------
5132 : * make_ruledef - reconstruct the CREATE RULE command
5133 : * for a given pg_rewrite tuple
5134 : * ----------
5135 : */
5136 : static void
5137 CBC 264 : make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5138 ECB : int prettyFlags)
5139 : {
5140 : char *rulename;
5141 : char ev_type;
5142 : Oid ev_class;
5143 : bool is_instead;
5144 : char *ev_qual;
5145 : char *ev_action;
5146 : List *actions;
5147 : Relation ev_relation;
5148 CBC 264 : TupleDesc viewResultDesc = NULL;
5149 : int fno;
5150 ECB : Datum dat;
5151 : bool isnull;
5152 :
5153 : /*
5154 : * Get the attribute values from the rules tuple
5155 : */
5156 CBC 264 : fno = SPI_fnumber(rulettc, "rulename");
5157 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5158 264 : Assert(!isnull);
5159 GBC 264 : rulename = NameStr(*(DatumGetName(dat)));
5160 :
5161 CBC 264 : fno = SPI_fnumber(rulettc, "ev_type");
5162 GIC 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5163 264 : Assert(!isnull);
5164 264 : ev_type = DatumGetChar(dat);
5165 :
5166 CBC 264 : fno = SPI_fnumber(rulettc, "ev_class");
5167 GIC 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5168 264 : Assert(!isnull);
5169 CBC 264 : ev_class = DatumGetObjectId(dat);
5170 ECB :
5171 GIC 264 : fno = SPI_fnumber(rulettc, "is_instead");
5172 GBC 264 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5173 GIC 264 : Assert(!isnull);
5174 264 : is_instead = DatumGetBool(dat);
5175 ECB :
5176 GIC 264 : fno = SPI_fnumber(rulettc, "ev_qual");
5177 CBC 264 : ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5178 264 : Assert(ev_qual != NULL);
5179 ECB :
5180 CBC 264 : fno = SPI_fnumber(rulettc, "ev_action");
5181 GIC 264 : ev_action = SPI_getvalue(ruletup, rulettc, fno);
5182 CBC 264 : Assert(ev_action != NULL);
5183 264 : actions = (List *) stringToNode(ev_action);
5184 264 : if (actions == NIL)
5185 UIC 0 : elog(ERROR, "invalid empty ev_action list");
5186 ECB :
5187 CBC 264 : ev_relation = table_open(ev_class, AccessShareLock);
5188 ECB :
5189 : /*
5190 : * Build the rules definition text
5191 : */
5192 CBC 264 : appendStringInfo(buf, "CREATE RULE %s AS",
5193 : quote_identifier(rulename));
5194 EUB :
5195 GBC 264 : if (prettyFlags & PRETTYFLAG_INDENT)
5196 GIC 264 : appendStringInfoString(buf, "\n ON ");
5197 : else
5198 UIC 0 : appendStringInfoString(buf, " ON ");
5199 :
5200 : /* The event the rule is fired for */
5201 GIC 264 : switch (ev_type)
5202 : {
5203 CBC 3 : case '1':
5204 3 : appendStringInfoString(buf, "SELECT");
5205 3 : viewResultDesc = RelationGetDescr(ev_relation);
5206 3 : break;
5207 :
5208 GIC 71 : case '2':
5209 CBC 71 : appendStringInfoString(buf, "UPDATE");
5210 GIC 71 : break;
5211 :
5212 138 : case '3':
5213 138 : appendStringInfoString(buf, "INSERT");
5214 138 : break;
5215 :
5216 CBC 52 : case '4':
5217 52 : appendStringInfoString(buf, "DELETE");
5218 52 : break;
5219 :
5220 LBC 0 : default:
5221 UIC 0 : ereport(ERROR,
5222 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5223 : errmsg("rule \"%s\" has unsupported event type %d",
5224 : rulename, ev_type)));
5225 : break;
5226 : }
5227 ECB :
5228 : /* The relation the rule is fired on */
5229 GIC 264 : appendStringInfo(buf, " TO %s",
5230 264 : (prettyFlags & PRETTYFLAG_SCHEMA) ?
5231 48 : generate_relation_name(ev_class, NIL) :
5232 216 : generate_qualified_relation_name(ev_class));
5233 :
5234 ECB : /* If the rule has an event qualification, add it */
5235 GIC 264 : if (strcmp(ev_qual, "<>") != 0)
5236 : {
5237 ECB : Node *qual;
5238 : Query *query;
5239 : deparse_context context;
5240 : deparse_namespace dpns;
5241 :
5242 CBC 58 : if (prettyFlags & PRETTYFLAG_INDENT)
5243 58 : appendStringInfoString(buf, "\n ");
5244 58 : appendStringInfoString(buf, " WHERE ");
5245 ECB :
5246 CBC 58 : qual = stringToNode(ev_qual);
5247 ECB :
5248 : /*
5249 : * We need to make a context for recognizing any Vars in the qual
5250 : * (which can only be references to OLD and NEW). Use the rtable of
5251 : * the first query in the action list for this purpose.
5252 : */
5253 GIC 58 : query = (Query *) linitial(actions);
5254 :
5255 ECB : /*
5256 : * If the action is INSERT...SELECT, OLD/NEW have been pushed down
5257 : * into the SELECT, and that's what we need to look at. (Ugly kluge
5258 : * ... try to fix this when we redesign querytrees.)
5259 : */
5260 GIC 58 : query = getInsertSelectQuery(query, NULL);
5261 :
5262 ECB : /* Must acquire locks right away; see notes in get_query_def() */
5263 GIC 58 : AcquireRewriteLocks(query, false, false);
5264 :
5265 58 : context.buf = buf;
5266 58 : context.namespaces = list_make1(&dpns);
5267 CBC 58 : context.windowClause = NIL;
5268 58 : context.windowTList = NIL;
5269 GIC 58 : context.varprefix = (list_length(query->rtable) != 1);
5270 CBC 58 : context.prettyFlags = prettyFlags;
5271 58 : context.wrapColumn = WRAP_COLUMN_DEFAULT;
5272 GIC 58 : context.indentLevel = PRETTYINDENT_STD;
5273 CBC 58 : context.special_exprkind = EXPR_KIND_NONE;
5274 58 : context.appendparents = NULL;
5275 :
5276 GBC 58 : set_deparse_for_query(&dpns, query, NIL);
5277 :
5278 CBC 58 : get_rule_expr(qual, &context, false);
5279 : }
5280 :
5281 GIC 264 : appendStringInfoString(buf, " DO ");
5282 :
5283 : /* The INSTEAD keyword (if so) */
5284 CBC 264 : if (is_instead)
5285 162 : appendStringInfoString(buf, "INSTEAD ");
5286 :
5287 ECB : /* Finally the rules actions */
5288 GIC 264 : if (list_length(actions) > 1)
5289 : {
5290 ECB : ListCell *action;
5291 : Query *query;
5292 :
5293 GIC 10 : appendStringInfoChar(buf, '(');
5294 30 : foreach(action, actions)
5295 : {
5296 20 : query = (Query *) lfirst(action);
5297 20 : get_query_def(query, buf, NIL, viewResultDesc, true,
5298 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5299 20 : if (prettyFlags)
5300 CBC 20 : appendStringInfoString(buf, ";\n");
5301 : else
5302 UIC 0 : appendStringInfoString(buf, "; ");
5303 : }
5304 GIC 10 : appendStringInfoString(buf, ");");
5305 : }
5306 : else
5307 : {
5308 : Query *query;
5309 :
5310 254 : query = (Query *) linitial(actions);
5311 254 : get_query_def(query, buf, NIL, viewResultDesc, true,
5312 : prettyFlags, WRAP_COLUMN_DEFAULT, 0);
5313 254 : appendStringInfoChar(buf, ';');
5314 : }
5315 :
5316 264 : table_close(ev_relation, AccessShareLock);
5317 264 : }
5318 ECB :
5319 :
5320 : /* ----------
5321 : * make_viewdef - reconstruct the SELECT part of a
5322 : * view rewrite rule
5323 : * ----------
5324 : */
5325 : static void
5326 CBC 1408 : make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
5327 : int prettyFlags, int wrapColumn)
5328 ECB : {
5329 : Query *query;
5330 : char ev_type;
5331 : Oid ev_class;
5332 : bool is_instead;
5333 : char *ev_qual;
5334 : char *ev_action;
5335 : List *actions;
5336 : Relation ev_relation;
5337 : int fno;
5338 : Datum dat;
5339 : bool isnull;
5340 :
5341 : /*
5342 : * Get the attribute values from the rules tuple
5343 : */
5344 GIC 1408 : fno = SPI_fnumber(rulettc, "ev_type");
5345 GBC 1408 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5346 GIC 1408 : Assert(!isnull);
5347 1408 : ev_type = DatumGetChar(dat);
5348 ECB :
5349 GIC 1408 : fno = SPI_fnumber(rulettc, "ev_class");
5350 CBC 1408 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5351 1408 : Assert(!isnull);
5352 GIC 1408 : ev_class = DatumGetObjectId(dat);
5353 :
5354 GBC 1408 : fno = SPI_fnumber(rulettc, "is_instead");
5355 GIC 1408 : dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
5356 1408 : Assert(!isnull);
5357 CBC 1408 : is_instead = DatumGetBool(dat);
5358 :
5359 1408 : fno = SPI_fnumber(rulettc, "ev_qual");
5360 GIC 1408 : ev_qual = SPI_getvalue(ruletup, rulettc, fno);
5361 CBC 1408 : Assert(ev_qual != NULL);
5362 :
5363 1408 : fno = SPI_fnumber(rulettc, "ev_action");
5364 GIC 1408 : ev_action = SPI_getvalue(ruletup, rulettc, fno);
5365 1408 : Assert(ev_action != NULL);
5366 1408 : actions = (List *) stringToNode(ev_action);
5367 :
5368 1408 : if (list_length(actions) != 1)
5369 : {
5370 : /* keep output buffer empty and leave */
5371 UIC 0 : return;
5372 : }
5373 :
5374 GIC 1408 : query = (Query *) linitial(actions);
5375 :
5376 1408 : if (ev_type != '1' || !is_instead ||
5377 1408 : strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
5378 : {
5379 : /* keep output buffer empty and leave */
5380 UIC 0 : return;
5381 : }
5382 :
5383 GIC 1408 : ev_relation = table_open(ev_class, AccessShareLock);
5384 :
5385 CBC 1408 : get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
5386 : prettyFlags, wrapColumn, 0);
5387 GIC 1408 : appendStringInfoChar(buf, ';');
5388 :
5389 1408 : table_close(ev_relation, AccessShareLock);
5390 : }
5391 :
5392 :
5393 ECB : /* ----------
5394 : * get_query_def - Parse back one query parsetree
5395 : *
5396 : * query: parsetree to be displayed
5397 : * buf: output text is appended to buf
5398 : * parentnamespace: list (initially empty) of outer-level deparse_namespace's
5399 : * resultDesc: if not NULL, the output tuple descriptor for the view
5400 : * represented by a SELECT query. We use the column names from it
5401 : * to label SELECT output columns, in preference to names in the query
5402 : * colNamesVisible: true if the surrounding context cares about the output
5403 : * column names at all (as, for example, an EXISTS() context does not);
5404 : * when false, we can suppress dummy column labels such as "?column?"
5405 : * prettyFlags: bitmask of PRETTYFLAG_XXX options
5406 : * wrapColumn: maximum line length, or -1 to disable wrapping
5407 : * startIndent: initial indentation amount
5408 : * ----------
5409 : */
5410 : static void
5411 CBC 2294 : get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5412 ECB : TupleDesc resultDesc, bool colNamesVisible,
5413 : int prettyFlags, int wrapColumn, int startIndent)
5414 : {
5415 : deparse_context context;
5416 : deparse_namespace dpns;
5417 :
5418 : /* Guard against excessively long or deeply-nested queries */
5419 CBC 2294 : CHECK_FOR_INTERRUPTS();
5420 GIC 2294 : check_stack_depth();
5421 ECB :
5422 : /*
5423 : * Before we begin to examine the query, acquire locks on referenced
5424 : * relations, and fix up deleted columns in JOIN RTEs. This ensures
5425 : * consistent results. Note we assume it's OK to scribble on the passed
5426 : * querytree!
5427 : *
5428 : * We are only deparsing the query (we are not about to execute it), so we
5429 : * only need AccessShareLock on the relations it mentions.
5430 : */
5431 CBC 2294 : AcquireRewriteLocks(query, false, false);
5432 ECB :
5433 CBC 2294 : context.buf = buf;
5434 GIC 2294 : context.namespaces = lcons(&dpns, list_copy(parentnamespace));
5435 CBC 2294 : context.windowClause = NIL;
5436 2294 : context.windowTList = NIL;
5437 3976 : context.varprefix = (parentnamespace != NIL ||
5438 GIC 1682 : list_length(query->rtable) != 1);
5439 CBC 2294 : context.prettyFlags = prettyFlags;
5440 2294 : context.wrapColumn = wrapColumn;
5441 2294 : context.indentLevel = startIndent;
5442 GIC 2294 : context.special_exprkind = EXPR_KIND_NONE;
5443 CBC 2294 : context.appendparents = NULL;
5444 ECB :
5445 CBC 2294 : set_deparse_for_query(&dpns, query, parentnamespace);
5446 :
5447 GBC 2294 : switch (query->commandType)
5448 EUB : {
5449 GIC 2004 : case CMD_SELECT:
5450 2004 : get_select_query_def(query, &context, resultDesc, colNamesVisible);
5451 2004 : break;
5452 ECB :
5453 GIC 65 : case CMD_UPDATE:
5454 65 : get_update_query_def(query, &context, colNamesVisible);
5455 65 : break;
5456 :
5457 161 : case CMD_INSERT:
5458 161 : get_insert_query_def(query, &context, colNamesVisible);
5459 CBC 161 : break;
5460 :
5461 38 : case CMD_DELETE:
5462 38 : get_delete_query_def(query, &context, colNamesVisible);
5463 GIC 38 : break;
5464 :
5465 CBC 18 : case CMD_NOTHING:
5466 GIC 18 : appendStringInfoString(buf, "NOTHING");
5467 CBC 18 : break;
5468 :
5469 8 : case CMD_UTILITY:
5470 8 : get_utility_query_def(query, &context);
5471 GIC 8 : break;
5472 :
5473 LBC 0 : default:
5474 0 : elog(ERROR, "unrecognized query command type: %d",
5475 : query->commandType);
5476 ECB : break;
5477 : }
5478 CBC 2294 : }
5479 ECB :
5480 : /* ----------
5481 : * get_values_def - Parse back a VALUES list
5482 : * ----------
5483 : */
5484 : static void
5485 GIC 130 : get_values_def(List *values_lists, deparse_context *context)
5486 ECB : {
5487 GIC 130 : StringInfo buf = context->buf;
5488 130 : bool first_list = true;
5489 : ListCell *vtl;
5490 :
5491 CBC 130 : appendStringInfoString(buf, "VALUES ");
5492 :
5493 374 : foreach(vtl, values_lists)
5494 : {
5495 244 : List *sublist = (List *) lfirst(vtl);
5496 GIC 244 : bool first_col = true;
5497 : ListCell *lc;
5498 :
5499 244 : if (first_list)
5500 130 : first_list = false;
5501 : else
5502 CBC 114 : appendStringInfoString(buf, ", ");
5503 :
5504 244 : appendStringInfoChar(buf, '(');
5505 GIC 955 : foreach(lc, sublist)
5506 : {
5507 711 : Node *col = (Node *) lfirst(lc);
5508 ECB :
5509 CBC 711 : if (first_col)
5510 GIC 244 : first_col = false;
5511 ECB : else
5512 GIC 467 : appendStringInfoChar(buf, ',');
5513 ECB :
5514 : /*
5515 : * Print the value. Whole-row Vars need special treatment.
5516 : */
5517 CBC 711 : get_rule_expr_toplevel(col, context, false);
5518 ECB : }
5519 GIC 244 : appendStringInfoChar(buf, ')');
5520 ECB : }
5521 CBC 130 : }
5522 :
5523 ECB : /* ----------
5524 : * get_with_clause - Parse back a WITH clause
5525 : * ----------
5526 : */
5527 : static void
5528 GIC 2268 : get_with_clause(Query *query, deparse_context *context)
5529 ECB : {
5530 GIC 2268 : StringInfo buf = context->buf;
5531 : const char *sep;
5532 ECB : ListCell *l;
5533 :
5534 GIC 2268 : if (query->cteList == NIL)
5535 CBC 2226 : return;
5536 ECB :
5537 GIC 42 : if (PRETTY_INDENT(context))
5538 ECB : {
5539 CBC 42 : context->indentLevel += PRETTYINDENT_STD;
5540 42 : appendStringInfoChar(buf, ' ');
5541 : }
5542 ECB :
5543 GIC 42 : if (query->hasRecursive)
5544 CBC 28 : sep = "WITH RECURSIVE ";
5545 ECB : else
5546 GIC 14 : sep = "WITH ";
5547 CBC 100 : foreach(l, query->cteList)
5548 ECB : {
5549 CBC 58 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
5550 ECB :
5551 CBC 58 : appendStringInfoString(buf, sep);
5552 GBC 58 : appendStringInfoString(buf, quote_identifier(cte->ctename));
5553 58 : if (cte->aliascolnames)
5554 EUB : {
5555 GIC 22 : bool first = true;
5556 ECB : ListCell *col;
5557 :
5558 CBC 22 : appendStringInfoChar(buf, '(');
5559 62 : foreach(col, cte->aliascolnames)
5560 : {
5561 GIC 40 : if (first)
5562 22 : first = false;
5563 ECB : else
5564 CBC 18 : appendStringInfoString(buf, ", ");
5565 40 : appendStringInfoString(buf,
5566 GIC 40 : quote_identifier(strVal(lfirst(col))));
5567 ECB : }
5568 GIC 22 : appendStringInfoChar(buf, ')');
5569 ECB : }
5570 GIC 58 : appendStringInfoString(buf, " AS ");
5571 58 : switch (cte->ctematerialized)
5572 ECB : {
5573 CBC 52 : case CTEMaterializeDefault:
5574 GIC 52 : break;
5575 CBC 6 : case CTEMaterializeAlways:
5576 GIC 6 : appendStringInfoString(buf, "MATERIALIZED ");
5577 CBC 6 : break;
5578 LBC 0 : case CTEMaterializeNever:
5579 UIC 0 : appendStringInfoString(buf, "NOT MATERIALIZED ");
5580 LBC 0 : break;
5581 ECB : }
5582 CBC 58 : appendStringInfoChar(buf, '(');
5583 GIC 58 : if (PRETTY_INDENT(context))
5584 58 : appendContextKeyword(context, "", 0, 0, 0);
5585 CBC 58 : get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5586 : true,
5587 : context->prettyFlags, context->wrapColumn,
5588 ECB : context->indentLevel);
5589 GIC 58 : if (PRETTY_INDENT(context))
5590 CBC 58 : appendContextKeyword(context, "", 0, 0, 0);
5591 GIC 58 : appendStringInfoChar(buf, ')');
5592 :
5593 CBC 58 : if (cte->search_clause)
5594 : {
5595 3 : bool first = true;
5596 : ListCell *lc;
5597 ECB :
5598 CBC 3 : appendStringInfo(buf, " SEARCH %s FIRST BY ",
5599 GIC 3 : cte->search_clause->search_breadth_first ? "BREADTH" : "DEPTH");
5600 ECB :
5601 CBC 9 : foreach(lc, cte->search_clause->search_col_list)
5602 ECB : {
5603 GIC 6 : if (first)
5604 3 : first = false;
5605 ECB : else
5606 GIC 3 : appendStringInfoString(buf, ", ");
5607 6 : appendStringInfoString(buf,
5608 CBC 6 : quote_identifier(strVal(lfirst(lc))));
5609 ECB : }
5610 :
5611 CBC 3 : appendStringInfo(buf, " SET %s", quote_identifier(cte->search_clause->search_seq_column));
5612 ECB : }
5613 :
5614 CBC 58 : if (cte->cycle_clause)
5615 ECB : {
5616 CBC 6 : bool first = true;
5617 ECB : ListCell *lc;
5618 :
5619 GIC 6 : appendStringInfoString(buf, " CYCLE ");
5620 :
5621 CBC 18 : foreach(lc, cte->cycle_clause->cycle_col_list)
5622 : {
5623 GIC 12 : if (first)
5624 CBC 6 : first = false;
5625 : else
5626 GIC 6 : appendStringInfoString(buf, ", ");
5627 CBC 12 : appendStringInfoString(buf,
5628 GIC 12 : quote_identifier(strVal(lfirst(lc))));
5629 ECB : }
5630 :
5631 GIC 6 : appendStringInfo(buf, " SET %s", quote_identifier(cte->cycle_clause->cycle_mark_column));
5632 :
5633 EUB : {
5634 GIC 6 : Const *cmv = castNode(Const, cte->cycle_clause->cycle_mark_value);
5635 6 : Const *cmd = castNode(Const, cte->cycle_clause->cycle_mark_default);
5636 :
5637 9 : if (!(cmv->consttype == BOOLOID && !cmv->constisnull && DatumGetBool(cmv->constvalue) == true &&
5638 3 : cmd->consttype == BOOLOID && !cmd->constisnull && DatumGetBool(cmd->constvalue) == false))
5639 : {
5640 3 : appendStringInfoString(buf, " TO ");
5641 CBC 3 : get_rule_expr(cte->cycle_clause->cycle_mark_value, context, false);
5642 GIC 3 : appendStringInfoString(buf, " DEFAULT ");
5643 3 : get_rule_expr(cte->cycle_clause->cycle_mark_default, context, false);
5644 ECB : }
5645 : }
5646 :
5647 GIC 6 : appendStringInfo(buf, " USING %s", quote_identifier(cte->cycle_clause->cycle_path_column));
5648 : }
5649 :
5650 58 : sep = ", ";
5651 ECB : }
5652 :
5653 GIC 42 : if (PRETTY_INDENT(context))
5654 ECB : {
5655 CBC 42 : context->indentLevel -= PRETTYINDENT_STD;
5656 42 : appendContextKeyword(context, "", 0, 0, 0);
5657 ECB : }
5658 : else
5659 UIC 0 : appendStringInfoChar(buf, ' ');
5660 : }
5661 :
5662 : /* ----------
5663 : * get_select_query_def - Parse back a SELECT parsetree
5664 ECB : * ----------
5665 : */
5666 : static void
5667 GIC 2004 : get_select_query_def(Query *query, deparse_context *context,
5668 : TupleDesc resultDesc, bool colNamesVisible)
5669 ECB : {
5670 GIC 2004 : StringInfo buf = context->buf;
5671 : List *save_windowclause;
5672 : List *save_windowtlist;
5673 ECB : bool force_colno;
5674 : ListCell *l;
5675 :
5676 : /* Insert the WITH clause if given */
5677 GIC 2004 : get_with_clause(query, context);
5678 ECB :
5679 : /* Set up context for possible window functions */
5680 CBC 2004 : save_windowclause = context->windowClause;
5681 GIC 2004 : context->windowClause = query->windowClause;
5682 CBC 2004 : save_windowtlist = context->windowTList;
5683 GIC 2004 : context->windowTList = query->targetList;
5684 :
5685 : /*
5686 : * If the Query node has a setOperations tree, then it's the top level of
5687 : * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
5688 : * fields are interesting in the top query itself.
5689 : */
5690 CBC 2004 : if (query->setOperations)
5691 : {
5692 70 : get_setop_query(query->setOperations, query, context, resultDesc,
5693 : colNamesVisible);
5694 ECB : /* ORDER BY clauses must be simple in this case */
5695 GIC 70 : force_colno = true;
5696 ECB : }
5697 : else
5698 : {
5699 GIC 1934 : get_basic_select_query(query, context, resultDesc, colNamesVisible);
5700 CBC 1934 : force_colno = false;
5701 : }
5702 ECB :
5703 : /* Add the ORDER BY clause if given */
5704 GIC 2004 : if (query->sortClause != NIL)
5705 : {
5706 64 : appendContextKeyword(context, " ORDER BY ",
5707 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5708 GIC 64 : get_rule_orderby(query->sortClause, query->targetList,
5709 ECB : force_colno, context);
5710 : }
5711 :
5712 : /*
5713 : * Add the LIMIT/OFFSET clauses if given. If non-default options, use the
5714 : * standard spelling of LIMIT.
5715 : */
5716 GIC 2004 : if (query->limitOffset != NULL)
5717 : {
5718 CBC 16 : appendContextKeyword(context, " OFFSET ",
5719 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5720 16 : get_rule_expr(query->limitOffset, context, false);
5721 : }
5722 2004 : if (query->limitCount != NULL)
5723 : {
5724 GIC 35 : if (query->limitOption == LIMIT_OPTION_WITH_TIES)
5725 ECB : {
5726 GBC 16 : appendContextKeyword(context, " FETCH FIRST ",
5727 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5728 CBC 16 : get_rule_expr(query->limitCount, context, false);
5729 GIC 16 : appendStringInfoString(buf, " ROWS WITH TIES");
5730 EUB : }
5731 : else
5732 : {
5733 GIC 19 : appendContextKeyword(context, " LIMIT ",
5734 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5735 GBC 19 : if (IsA(query->limitCount, Const) &&
5736 8 : ((Const *) query->limitCount)->constisnull)
5737 GIC 8 : appendStringInfoString(buf, "ALL");
5738 EUB : else
5739 GBC 11 : get_rule_expr(query->limitCount, context, false);
5740 EUB : }
5741 : }
5742 :
5743 : /* Add FOR [KEY] UPDATE/SHARE clauses if present */
5744 GBC 2004 : if (query->hasForUpdate)
5745 : {
5746 6 : foreach(l, query->rowMarks)
5747 ECB : {
5748 CBC 3 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
5749 :
5750 ECB : /* don't print implicit clauses */
5751 GIC 3 : if (rc->pushedDown)
5752 UIC 0 : continue;
5753 ECB :
5754 CBC 3 : switch (rc->strength)
5755 : {
5756 LBC 0 : case LCS_NONE:
5757 EUB : /* we intentionally throw an error for LCS_NONE */
5758 LBC 0 : elog(ERROR, "unrecognized LockClauseStrength %d",
5759 EUB : (int) rc->strength);
5760 : break;
5761 UIC 0 : case LCS_FORKEYSHARE:
5762 0 : appendContextKeyword(context, " FOR KEY SHARE",
5763 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5764 LBC 0 : break;
5765 0 : case LCS_FORSHARE:
5766 UIC 0 : appendContextKeyword(context, " FOR SHARE",
5767 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5768 0 : break;
5769 0 : case LCS_FORNOKEYUPDATE:
5770 0 : appendContextKeyword(context, " FOR NO KEY UPDATE",
5771 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5772 0 : break;
5773 CBC 3 : case LCS_FORUPDATE:
5774 GIC 3 : appendContextKeyword(context, " FOR UPDATE",
5775 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5776 GIC 3 : break;
5777 : }
5778 :
5779 3 : appendStringInfo(buf, " OF %s",
5780 3 : quote_identifier(get_rtable_name(rc->rti,
5781 : context)));
5782 3 : if (rc->waitPolicy == LockWaitError)
5783 LBC 0 : appendStringInfoString(buf, " NOWAIT");
5784 GIC 3 : else if (rc->waitPolicy == LockWaitSkip)
5785 LBC 0 : appendStringInfoString(buf, " SKIP LOCKED");
5786 : }
5787 ECB : }
5788 :
5789 CBC 2004 : context->windowClause = save_windowclause;
5790 2004 : context->windowTList = save_windowtlist;
5791 2004 : }
5792 :
5793 ECB : /*
5794 : * Detect whether query looks like SELECT ... FROM VALUES(),
5795 : * with no need to rename the output columns of the VALUES RTE.
5796 : * If so, return the VALUES RTE. Otherwise return NULL.
5797 : */
5798 : static RangeTblEntry *
5799 GIC 1934 : get_simple_values_rte(Query *query, TupleDesc resultDesc)
5800 : {
5801 1934 : RangeTblEntry *result = NULL;
5802 : ListCell *lc;
5803 :
5804 : /*
5805 : * We want to detect a match even if the Query also contains OLD or NEW
5806 : * rule RTEs. So the idea is to scan the rtable and see if there is only
5807 : * one inFromCl RTE that is a VALUES RTE.
5808 ECB : */
5809 GIC 2105 : foreach(lc, query->rtable)
5810 : {
5811 1756 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
5812 :
5813 CBC 1756 : if (rte->rtekind == RTE_VALUES && rte->inFromCl)
5814 EUB : {
5815 CBC 111 : if (result)
5816 1585 : return NULL; /* multiple VALUES (probably not possible) */
5817 GIC 111 : result = rte;
5818 ECB : }
5819 CBC 1645 : else if (rte->rtekind == RTE_RELATION && !rte->inFromCl)
5820 GIC 60 : continue; /* ignore rule entries */
5821 : else
5822 CBC 1585 : return NULL; /* something else -> not simple VALUES */
5823 ECB : }
5824 :
5825 : /*
5826 : * We don't need to check the targetlist in any great detail, because
5827 : * parser/analyze.c will never generate a "bare" VALUES RTE --- they only
5828 : * appear inside auto-generated sub-queries with very restricted
5829 : * structure. However, DefineView might have modified the tlist by
5830 : * injecting new column aliases, or we might have some other column
5831 : * aliases forced by a resultDesc. We can only simplify if the RTE's
5832 : * column names match the names that get_target_list() would select.
5833 : */
5834 CBC 349 : if (result)
5835 : {
5836 : ListCell *lcn;
5837 : int colno;
5838 ECB :
5839 GIC 111 : if (list_length(query->targetList) != list_length(result->eref->colnames))
5840 UIC 0 : return NULL; /* this probably cannot happen */
5841 GIC 111 : colno = 0;
5842 CBC 415 : forboth(lc, query->targetList, lcn, result->eref->colnames)
5843 : {
5844 GIC 310 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
5845 CBC 310 : char *cname = strVal(lfirst(lcn));
5846 : char *colname;
5847 :
5848 GIC 310 : if (tle->resjunk)
5849 6 : return NULL; /* this probably cannot happen */
5850 ECB :
5851 : /* compute name that get_target_list would use for column */
5852 CBC 310 : colno++;
5853 310 : if (resultDesc && colno <= resultDesc->natts)
5854 GIC 15 : colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
5855 : else
5856 295 : colname = tle->resname;
5857 :
5858 : /* does it match the VALUES RTE? */
5859 310 : if (colname == NULL || strcmp(colname, cname) != 0)
5860 6 : return NULL; /* column name has been changed */
5861 ECB : }
5862 : }
5863 :
5864 CBC 343 : return result;
5865 ECB : }
5866 :
5867 : static void
5868 GIC 1934 : get_basic_select_query(Query *query, deparse_context *context,
5869 : TupleDesc resultDesc, bool colNamesVisible)
5870 : {
5871 CBC 1934 : StringInfo buf = context->buf;
5872 ECB : RangeTblEntry *values_rte;
5873 : char *sep;
5874 : ListCell *l;
5875 :
5876 GIC 1934 : if (PRETTY_INDENT(context))
5877 ECB : {
5878 GIC 1912 : context->indentLevel += PRETTYINDENT_STD;
5879 GBC 1912 : appendStringInfoChar(buf, ' ');
5880 : }
5881 EUB :
5882 : /*
5883 : * If the query looks like SELECT * FROM (VALUES ...), then print just the
5884 : * VALUES part. This reverses what transformValuesClause() did at parse
5885 : * time.
5886 : */
5887 GBC 1934 : values_rte = get_simple_values_rte(query, resultDesc);
5888 1934 : if (values_rte)
5889 : {
5890 105 : get_values_def(values_rte->values_lists, context);
5891 GIC 105 : return;
5892 EUB : }
5893 :
5894 : /*
5895 : * Build up the query string - first we say SELECT
5896 : */
5897 GIC 1829 : if (query->isReturn)
5898 25 : appendStringInfoString(buf, "RETURN");
5899 ECB : else
5900 GIC 1804 : appendStringInfoString(buf, "SELECT");
5901 :
5902 ECB : /* Add the DISTINCT clause if given */
5903 GIC 1829 : if (query->distinctClause != NIL)
5904 : {
5905 LBC 0 : if (query->hasDistinctOn)
5906 : {
5907 0 : appendStringInfoString(buf, " DISTINCT ON (");
5908 UIC 0 : sep = "";
5909 LBC 0 : foreach(l, query->distinctClause)
5910 : {
5911 UIC 0 : SortGroupClause *srt = (SortGroupClause *) lfirst(l);
5912 :
5913 LBC 0 : appendStringInfoString(buf, sep);
5914 UIC 0 : get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList,
5915 : false, context);
5916 0 : sep = ", ";
5917 ECB : }
5918 UIC 0 : appendStringInfoChar(buf, ')');
5919 ECB : }
5920 EUB : else
5921 UIC 0 : appendStringInfoString(buf, " DISTINCT");
5922 ECB : }
5923 :
5924 : /* Then we tell what to select (the targetlist) */
5925 CBC 1829 : get_target_list(query->targetList, context, resultDesc, colNamesVisible);
5926 :
5927 ECB : /* Add the FROM clause if needed */
5928 CBC 1829 : get_from_clause(query, " FROM ", context);
5929 :
5930 ECB : /* Add the WHERE clause if given */
5931 GIC 1829 : if (query->jointree->quals != NULL)
5932 ECB : {
5933 CBC 534 : appendContextKeyword(context, " WHERE ",
5934 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5935 534 : get_rule_expr(query->jointree->quals, context, false);
5936 : }
5937 :
5938 : /* Add the GROUP BY clause if given */
5939 GIC 1829 : if (query->groupClause != NULL || query->groupingSets != NULL)
5940 ECB : {
5941 : ParseExprKind save_exprkind;
5942 :
5943 CBC 37 : appendContextKeyword(context, " GROUP BY ",
5944 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
5945 37 : if (query->groupDistinct)
5946 LBC 0 : appendStringInfoString(buf, "DISTINCT ");
5947 ECB :
5948 GIC 37 : save_exprkind = context->special_exprkind;
5949 37 : context->special_exprkind = EXPR_KIND_GROUP_BY;
5950 :
5951 CBC 37 : if (query->groupingSets == NIL)
5952 : {
5953 GIC 34 : sep = "";
5954 85 : foreach(l, query->groupClause)
5955 ECB : {
5956 GIC 51 : SortGroupClause *grp = (SortGroupClause *) lfirst(l);
5957 ECB :
5958 GIC 51 : appendStringInfoString(buf, sep);
5959 CBC 51 : get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList,
5960 : false, context);
5961 GIC 51 : sep = ", ";
5962 : }
5963 ECB : }
5964 : else
5965 : {
5966 GIC 3 : sep = "";
5967 6 : foreach(l, query->groupingSets)
5968 : {
5969 3 : GroupingSet *grp = lfirst(l);
5970 :
5971 3 : appendStringInfoString(buf, sep);
5972 3 : get_rule_groupingset(grp, query->targetList, true, context);
5973 3 : sep = ", ";
5974 : }
5975 : }
5976 ECB :
5977 GIC 37 : context->special_exprkind = save_exprkind;
5978 : }
5979 ECB :
5980 : /* Add the HAVING clause if given */
5981 CBC 1829 : if (query->havingQual != NULL)
5982 : {
5983 GIC 5 : appendContextKeyword(context, " HAVING ",
5984 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
5985 5 : get_rule_expr(query->havingQual, context, false);
5986 : }
5987 ECB :
5988 : /* Add the WINDOW clause if needed */
5989 CBC 1829 : if (query->windowClause != NIL)
5990 21 : get_rule_windowclause(query, context);
5991 ECB : }
5992 :
5993 : /* ----------
5994 : * get_target_list - Parse back a SELECT target list
5995 : *
5996 : * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
5997 : *
5998 : * resultDesc and colNamesVisible are as for get_query_def()
5999 : * ----------
6000 : */
6001 : static void
6002 CBC 1887 : get_target_list(List *targetList, deparse_context *context,
6003 : TupleDesc resultDesc, bool colNamesVisible)
6004 : {
6005 GIC 1887 : StringInfo buf = context->buf;
6006 : StringInfoData targetbuf;
6007 1887 : bool last_was_multiline = false;
6008 ECB : char *sep;
6009 : int colno;
6010 : ListCell *l;
6011 :
6012 : /* we use targetbuf to hold each TLE's text temporarily */
6013 GIC 1887 : initStringInfo(&targetbuf);
6014 :
6015 1887 : sep = " ";
6016 1887 : colno = 0;
6017 8180 : foreach(l, targetList)
6018 : {
6019 6293 : TargetEntry *tle = (TargetEntry *) lfirst(l);
6020 : char *colname;
6021 ECB : char *attname;
6022 :
6023 CBC 6293 : if (tle->resjunk)
6024 GIC 20 : continue; /* ignore junk entries */
6025 :
6026 6273 : appendStringInfoString(buf, sep);
6027 CBC 6273 : sep = ", ";
6028 GIC 6273 : colno++;
6029 :
6030 : /*
6031 : * Put the new field text into targetbuf so we can decide after we've
6032 : * got it whether or not it needs to go on a new line.
6033 : */
6034 CBC 6273 : resetStringInfo(&targetbuf);
6035 GIC 6273 : context->buf = &targetbuf;
6036 :
6037 : /*
6038 : * We special-case Var nodes rather than using get_rule_expr. This is
6039 : * needed because get_rule_expr will display a whole-row Var as
6040 : * "foo.*", which is the preferred notation in most contexts, but at
6041 : * the top level of a SELECT list it's not right (the parser will
6042 : * expand that notation into multiple columns, yielding behavior
6043 ECB : * different from a whole-row Var). We need to call get_variable
6044 : * directly so that we can tell it to do the right thing, and so that
6045 : * we can get the attribute name which is the default AS label.
6046 : */
6047 GIC 6273 : if (tle->expr && (IsA(tle->expr, Var)))
6048 : {
6049 CBC 4813 : attname = get_variable((Var *) tle->expr, 0, true, context);
6050 : }
6051 ECB : else
6052 : {
6053 GIC 1460 : get_rule_expr((Node *) tle->expr, context, true);
6054 :
6055 : /*
6056 ECB : * When colNamesVisible is true, we should always show the
6057 : * assigned column name explicitly. Otherwise, show it only if
6058 : * it's not FigureColname's fallback.
6059 : */
6060 GIC 1460 : attname = colNamesVisible ? NULL : "?column?";
6061 : }
6062 :
6063 : /*
6064 ECB : * Figure out what the result column should be called. In the context
6065 : * of a view, use the view's tuple descriptor (so as to pick up the
6066 : * effects of any column RENAME that's been done on the view).
6067 : * Otherwise, just use what we can find in the TLE.
6068 : */
6069 GIC 6273 : if (resultDesc && colno <= resultDesc->natts)
6070 CBC 5681 : colname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname);
6071 : else
6072 GIC 592 : colname = tle->resname;
6073 ECB :
6074 : /* Show AS unless the column's name is correct as-is */
6075 GIC 6273 : if (colname) /* resname could be NULL */
6076 : {
6077 6248 : if (attname == NULL || strcmp(attname, colname) != 0)
6078 1941 : appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname));
6079 : }
6080 ECB :
6081 : /* Restore context's output buffer */
6082 CBC 6273 : context->buf = buf;
6083 :
6084 ECB : /* Consider line-wrapping if enabled */
6085 GIC 6273 : if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
6086 : {
6087 : int leading_nl_pos;
6088 :
6089 : /* Does the new field start with a new line? */
6090 6251 : if (targetbuf.len > 0 && targetbuf.data[0] == '\n')
6091 CBC 111 : leading_nl_pos = 0;
6092 ECB : else
6093 GIC 6140 : leading_nl_pos = -1;
6094 ECB :
6095 : /* If so, we shouldn't add anything */
6096 GIC 6251 : if (leading_nl_pos >= 0)
6097 : {
6098 : /* instead, remove any trailing spaces currently in buf */
6099 CBC 111 : removeStringInfoSpaces(buf);
6100 ECB : }
6101 : else
6102 : {
6103 : char *trailing_nl;
6104 :
6105 : /* Locate the start of the current line in the output buffer */
6106 GIC 6140 : trailing_nl = strrchr(buf->data, '\n');
6107 6140 : if (trailing_nl == NULL)
6108 CBC 2229 : trailing_nl = buf->data;
6109 ECB : else
6110 GIC 3911 : trailing_nl++;
6111 :
6112 ECB : /*
6113 : * Add a newline, plus some indentation, if the new field is
6114 : * not the first and either the new field would cause an
6115 : * overflow or the last field used more than one line.
6116 : */
6117 GIC 6140 : if (colno > 1 &&
6118 4283 : ((strlen(trailing_nl) + targetbuf.len > context->wrapColumn) ||
6119 ECB : last_was_multiline))
6120 CBC 4283 : appendContextKeyword(context, "", -PRETTYINDENT_STD,
6121 : PRETTYINDENT_STD, PRETTYINDENT_VAR);
6122 ECB : }
6123 :
6124 : /* Remember this field's multiline status for next iteration */
6125 CBC 6251 : last_was_multiline =
6126 6251 : (strchr(targetbuf.data + leading_nl_pos + 1, '\n') != NULL);
6127 : }
6128 ECB :
6129 : /* Add the new field */
6130 GIC 6273 : appendBinaryStringInfo(buf, targetbuf.data, targetbuf.len);
6131 ECB : }
6132 :
6133 : /* clean up */
6134 CBC 1887 : pfree(targetbuf.data);
6135 1887 : }
6136 ECB :
6137 EUB : static void
6138 CBC 276 : get_setop_query(Node *setOp, Query *query, deparse_context *context,
6139 : TupleDesc resultDesc, bool colNamesVisible)
6140 : {
6141 GIC 276 : StringInfo buf = context->buf;
6142 ECB : bool need_paren;
6143 EUB :
6144 : /* Guard against excessively long or deeply-nested queries */
6145 CBC 276 : CHECK_FOR_INTERRUPTS();
6146 GIC 276 : check_stack_depth();
6147 ECB :
6148 GIC 276 : if (IsA(setOp, RangeTblRef))
6149 : {
6150 173 : RangeTblRef *rtr = (RangeTblRef *) setOp;
6151 173 : RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
6152 173 : Query *subquery = rte->subquery;
6153 :
6154 173 : Assert(subquery != NULL);
6155 173 : Assert(subquery->setOperations == NULL);
6156 : /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
6157 519 : need_paren = (subquery->cteList ||
6158 173 : subquery->sortClause ||
6159 173 : subquery->rowMarks ||
6160 519 : subquery->limitOffset ||
6161 CBC 173 : subquery->limitCount);
6162 GIC 173 : if (need_paren)
6163 LBC 0 : appendStringInfoChar(buf, '(');
6164 GIC 173 : get_query_def(subquery, buf, context->namespaces, resultDesc,
6165 ECB : colNamesVisible,
6166 : context->prettyFlags, context->wrapColumn,
6167 : context->indentLevel);
6168 GBC 173 : if (need_paren)
6169 UIC 0 : appendStringInfoChar(buf, ')');
6170 : }
6171 CBC 103 : else if (IsA(setOp, SetOperationStmt))
6172 : {
6173 103 : SetOperationStmt *op = (SetOperationStmt *) setOp;
6174 : int subindent;
6175 EUB :
6176 : /*
6177 : * We force parens when nesting two SetOperationStmts, except when the
6178 : * lefthand input is another setop of the same kind. Syntactically,
6179 : * we could omit parens in rather more cases, but it seems best to use
6180 ECB : * parens to flag cases where the setop operator changes. If we use
6181 : * parens, we also increase the indentation level for the child query.
6182 : *
6183 : * There are some cases in which parens are needed around a leaf query
6184 : * too, but those are more easily handled at the next level down (see
6185 EUB : * code above).
6186 ECB : */
6187 CBC 103 : if (IsA(op->larg, SetOperationStmt))
6188 : {
6189 GBC 33 : SetOperationStmt *lop = (SetOperationStmt *) op->larg;
6190 :
6191 CBC 33 : if (op->op == lop->op && op->all == lop->all)
6192 GIC 33 : need_paren = false;
6193 ECB : else
6194 LBC 0 : need_paren = true;
6195 ECB : }
6196 EUB : else
6197 GBC 70 : need_paren = false;
6198 EUB :
6199 GBC 103 : if (need_paren)
6200 EUB : {
6201 UBC 0 : appendStringInfoChar(buf, '(');
6202 0 : subindent = PRETTYINDENT_STD;
6203 0 : appendContextKeyword(context, "", subindent, 0, 0);
6204 : }
6205 : else
6206 CBC 103 : subindent = 0;
6207 ECB :
6208 GIC 103 : get_setop_query(op->larg, query, context, resultDesc, colNamesVisible);
6209 :
6210 CBC 103 : if (need_paren)
6211 UIC 0 : appendContextKeyword(context, ") ", -subindent, 0, 0);
6212 GIC 103 : else if (PRETTY_INDENT(context))
6213 103 : appendContextKeyword(context, "", -subindent, 0, 0);
6214 : else
6215 UIC 0 : appendStringInfoChar(buf, ' ');
6216 :
6217 CBC 103 : switch (op->op)
6218 : {
6219 GBC 103 : case SETOP_UNION:
6220 103 : appendStringInfoString(buf, "UNION ");
6221 GIC 103 : break;
6222 UIC 0 : case SETOP_INTERSECT:
6223 LBC 0 : appendStringInfoString(buf, "INTERSECT ");
6224 0 : break;
6225 UIC 0 : case SETOP_EXCEPT:
6226 LBC 0 : appendStringInfoString(buf, "EXCEPT ");
6227 UIC 0 : break;
6228 LBC 0 : default:
6229 0 : elog(ERROR, "unrecognized set op: %d",
6230 ECB : (int) op->op);
6231 EUB : }
6232 GIC 103 : if (op->all)
6233 97 : appendStringInfoString(buf, "ALL ");
6234 :
6235 EUB : /* Always parenthesize if RHS is another setop */
6236 GIC 103 : need_paren = IsA(op->rarg, SetOperationStmt);
6237 :
6238 ECB : /*
6239 : * The indentation code here is deliberately a bit different from that
6240 : * for the lefthand input, because we want the line breaks in
6241 : * different places.
6242 : */
6243 GIC 103 : if (need_paren)
6244 : {
6245 UIC 0 : appendStringInfoChar(buf, '(');
6246 LBC 0 : subindent = PRETTYINDENT_STD;
6247 : }
6248 : else
6249 CBC 103 : subindent = 0;
6250 GIC 103 : appendContextKeyword(context, "", subindent, 0, 0);
6251 :
6252 103 : get_setop_query(op->rarg, query, context, resultDesc, false);
6253 ECB :
6254 CBC 103 : if (PRETTY_INDENT(context))
6255 GIC 103 : context->indentLevel -= subindent;
6256 103 : if (need_paren)
6257 UIC 0 : appendContextKeyword(context, ")", 0, 0, 0);
6258 : }
6259 : else
6260 : {
6261 0 : elog(ERROR, "unrecognized node type: %d",
6262 : (int) nodeTag(setOp));
6263 : }
6264 GIC 276 : }
6265 ECB :
6266 : /*
6267 EUB : * Display a sort/group clause.
6268 : *
6269 : * Also returns the expression tree, so caller need not find it again.
6270 ECB : */
6271 EUB : static Node *
6272 CBC 216 : get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
6273 ECB : deparse_context *context)
6274 : {
6275 GIC 216 : StringInfo buf = context->buf;
6276 : TargetEntry *tle;
6277 : Node *expr;
6278 :
6279 216 : tle = get_sortgroupref_tle(ref, tlist);
6280 216 : expr = (Node *) tle->expr;
6281 :
6282 : /*
6283 ECB : * Use column-number form if requested by caller. Otherwise, if
6284 : * expression is a constant, force it to be dumped with an explicit cast
6285 : * as decoration --- this is because a simple integer constant is
6286 : * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
6287 : * dump it without any decoration. If it's anything more complex than a
6288 : * simple Var, then force extra parens around it, to ensure it can't be
6289 : * misinterpreted as a cube() or rollup() construct.
6290 : */
6291 CBC 216 : if (force_colno)
6292 ECB : {
6293 LBC 0 : Assert(!tle->resjunk);
6294 UIC 0 : appendStringInfo(buf, "%d", tle->resno);
6295 : }
6296 CBC 216 : else if (expr && IsA(expr, Const))
6297 UIC 0 : get_const_expr((Const *) expr, context, 1);
6298 GIC 216 : else if (!expr || IsA(expr, Var))
6299 199 : get_rule_expr(expr, context, true);
6300 : else
6301 : {
6302 : /*
6303 ECB : * We must force parens for function-like expressions even if
6304 : * PRETTY_PAREN is off, since those are the ones in danger of
6305 : * misparsing. For other expressions we need to force them only if
6306 : * PRETTY_PAREN is on, since otherwise the expression will output them
6307 : * itself. (We can't skip the parens.)
6308 : */
6309 CBC 34 : bool need_paren = (PRETTY_PAREN(context)
6310 GIC 17 : || IsA(expr, FuncExpr)
6311 CBC 15 : || IsA(expr, Aggref)
6312 GNC 15 : || IsA(expr, WindowFunc)
6313 34 : || IsA(expr, JsonConstructorExpr));
6314 EUB :
6315 GBC 17 : if (need_paren)
6316 2 : appendStringInfoChar(context->buf, '(');
6317 GIC 17 : get_rule_expr(expr, context, true);
6318 CBC 17 : if (need_paren)
6319 GIC 2 : appendStringInfoChar(context->buf, ')');
6320 ECB : }
6321 :
6322 GIC 216 : return expr;
6323 ECB : }
6324 :
6325 : /*
6326 : * Display a GroupingSet
6327 : */
6328 : static void
6329 GIC 9 : get_rule_groupingset(GroupingSet *gset, List *targetlist,
6330 ECB : bool omit_parens, deparse_context *context)
6331 : {
6332 : ListCell *l;
6333 CBC 9 : StringInfo buf = context->buf;
6334 9 : bool omit_child_parens = true;
6335 GIC 9 : char *sep = "";
6336 ECB :
6337 GIC 9 : switch (gset->kind)
6338 ECB : {
6339 LBC 0 : case GROUPING_SET_EMPTY:
6340 0 : appendStringInfoString(buf, "()");
6341 UBC 0 : return;
6342 EUB :
6343 GBC 6 : case GROUPING_SET_SIMPLE:
6344 EUB : {
6345 GBC 6 : if (!omit_parens || list_length(gset->content) != 1)
6346 6 : appendStringInfoChar(buf, '(');
6347 EUB :
6348 GIC 21 : foreach(l, gset->content)
6349 : {
6350 CBC 15 : Index ref = lfirst_int(l);
6351 :
6352 15 : appendStringInfoString(buf, sep);
6353 15 : get_rule_sortgroupclause(ref, targetlist,
6354 ECB : false, context);
6355 GIC 15 : sep = ", ";
6356 : }
6357 ECB :
6358 GIC 6 : if (!omit_parens || list_length(gset->content) != 1)
6359 6 : appendStringInfoChar(buf, ')');
6360 : }
6361 6 : return;
6362 :
6363 3 : case GROUPING_SET_ROLLUP:
6364 CBC 3 : appendStringInfoString(buf, "ROLLUP(");
6365 GIC 3 : break;
6366 UIC 0 : case GROUPING_SET_CUBE:
6367 LBC 0 : appendStringInfoString(buf, "CUBE(");
6368 UIC 0 : break;
6369 0 : case GROUPING_SET_SETS:
6370 0 : appendStringInfoString(buf, "GROUPING SETS (");
6371 LBC 0 : omit_child_parens = false;
6372 0 : break;
6373 : }
6374 ECB :
6375 GIC 9 : foreach(l, gset->content)
6376 : {
6377 6 : appendStringInfoString(buf, sep);
6378 6 : get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context);
6379 CBC 6 : sep = ", ";
6380 ECB : }
6381 :
6382 CBC 3 : appendStringInfoChar(buf, ')');
6383 : }
6384 ECB :
6385 : /*
6386 : * Display an ORDER BY list.
6387 : */
6388 : static void
6389 CBC 134 : get_rule_orderby(List *orderList, List *targetList,
6390 EUB : bool force_colno, deparse_context *context)
6391 : {
6392 CBC 134 : StringInfo buf = context->buf;
6393 : const char *sep;
6394 ECB : ListCell *l;
6395 :
6396 CBC 134 : sep = "";
6397 284 : foreach(l, orderList)
6398 : {
6399 GIC 150 : SortGroupClause *srt = (SortGroupClause *) lfirst(l);
6400 : Node *sortexpr;
6401 ECB : Oid sortcoltype;
6402 : TypeCacheEntry *typentry;
6403 :
6404 GIC 150 : appendStringInfoString(buf, sep);
6405 150 : sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList,
6406 ECB : force_colno, context);
6407 GBC 150 : sortcoltype = exprType(sortexpr);
6408 : /* See whether operator is default < or > for datatype */
6409 CBC 150 : typentry = lookup_type_cache(sortcoltype,
6410 : TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
6411 150 : if (srt->sortop == typentry->lt_opr)
6412 : {
6413 ECB : /* ASC is default, so emit nothing for it */
6414 GIC 136 : if (srt->nulls_first)
6415 UIC 0 : appendStringInfoString(buf, " NULLS FIRST");
6416 : }
6417 GIC 14 : else if (srt->sortop == typentry->gt_opr)
6418 : {
6419 5 : appendStringInfoString(buf, " DESC");
6420 : /* DESC defaults to NULLS FIRST */
6421 5 : if (!srt->nulls_first)
6422 CBC 1 : appendStringInfoString(buf, " NULLS LAST");
6423 : }
6424 ECB : else
6425 : {
6426 GIC 9 : appendStringInfo(buf, " USING %s",
6427 : generate_operator_name(srt->sortop,
6428 ECB : sortcoltype,
6429 : sortcoltype));
6430 : /* be specific to eliminate ambiguity */
6431 CBC 9 : if (srt->nulls_first)
6432 UIC 0 : appendStringInfoString(buf, " NULLS FIRST");
6433 ECB : else
6434 CBC 9 : appendStringInfoString(buf, " NULLS LAST");
6435 : }
6436 GBC 150 : sep = ", ";
6437 EUB : }
6438 GIC 134 : }
6439 :
6440 EUB : /*
6441 : * Display a WINDOW clause.
6442 : *
6443 : * Note that the windowClause list might contain only anonymous window
6444 : * specifications, in which case we should print nothing here.
6445 : */
6446 : static void
6447 GIC 21 : get_rule_windowclause(Query *query, deparse_context *context)
6448 ECB : {
6449 GIC 21 : StringInfo buf = context->buf;
6450 : const char *sep;
6451 : ListCell *l;
6452 :
6453 21 : sep = NULL;
6454 CBC 42 : foreach(l, query->windowClause)
6455 : {
6456 GIC 21 : WindowClause *wc = (WindowClause *) lfirst(l);
6457 ECB :
6458 CBC 21 : if (wc->name == NULL)
6459 GIC 21 : continue; /* ignore anonymous windows */
6460 :
6461 UIC 0 : if (sep == NULL)
6462 LBC 0 : appendContextKeyword(context, " WINDOW ",
6463 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6464 : else
6465 UBC 0 : appendStringInfoString(buf, sep);
6466 EUB :
6467 UIC 0 : appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
6468 :
6469 LBC 0 : get_rule_windowspec(wc, query->targetList, context);
6470 :
6471 UBC 0 : sep = ", ";
6472 EUB : }
6473 GBC 21 : }
6474 EUB :
6475 : /*
6476 : * Display a window definition
6477 : */
6478 : static void
6479 GBC 21 : get_rule_windowspec(WindowClause *wc, List *targetList,
6480 EUB : deparse_context *context)
6481 : {
6482 GBC 21 : StringInfo buf = context->buf;
6483 GIC 21 : bool needspace = false;
6484 EUB : const char *sep;
6485 : ListCell *l;
6486 :
6487 CBC 21 : appendStringInfoChar(buf, '(');
6488 GIC 21 : if (wc->refname)
6489 ECB : {
6490 UBC 0 : appendStringInfoString(buf, quote_identifier(wc->refname));
6491 LBC 0 : needspace = true;
6492 ECB : }
6493 : /* partition clauses are always inherited, so only print if no refname */
6494 GIC 21 : if (wc->partitionClause && !wc->refname)
6495 : {
6496 LBC 0 : if (needspace)
6497 UIC 0 : appendStringInfoChar(buf, ' ');
6498 LBC 0 : appendStringInfoString(buf, "PARTITION BY ");
6499 0 : sep = "";
6500 0 : foreach(l, wc->partitionClause)
6501 ECB : {
6502 LBC 0 : SortGroupClause *grp = (SortGroupClause *) lfirst(l);
6503 ECB :
6504 LBC 0 : appendStringInfoString(buf, sep);
6505 0 : get_rule_sortgroupclause(grp->tleSortGroupRef, targetList,
6506 : false, context);
6507 UBC 0 : sep = ", ";
6508 ECB : }
6509 LBC 0 : needspace = true;
6510 ECB : }
6511 EUB : /* print ordering clause only if not inherited */
6512 CBC 21 : if (wc->orderClause && !wc->copiedOrder)
6513 EUB : {
6514 CBC 21 : if (needspace)
6515 UIC 0 : appendStringInfoChar(buf, ' ');
6516 CBC 21 : appendStringInfoString(buf, "ORDER BY ");
6517 21 : get_rule_orderby(wc->orderClause, targetList, false, context);
6518 21 : needspace = true;
6519 EUB : }
6520 : /* framing clause is never inherited, so print unless it's default */
6521 GIC 21 : if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
6522 EUB : {
6523 GIC 21 : if (needspace)
6524 21 : appendStringInfoChar(buf, ' ');
6525 GBC 21 : if (wc->frameOptions & FRAMEOPTION_RANGE)
6526 CBC 3 : appendStringInfoString(buf, "RANGE ");
6527 GIC 18 : else if (wc->frameOptions & FRAMEOPTION_ROWS)
6528 CBC 15 : appendStringInfoString(buf, "ROWS ");
6529 3 : else if (wc->frameOptions & FRAMEOPTION_GROUPS)
6530 GBC 3 : appendStringInfoString(buf, "GROUPS ");
6531 ECB : else
6532 UBC 0 : Assert(false);
6533 CBC 21 : if (wc->frameOptions & FRAMEOPTION_BETWEEN)
6534 GIC 21 : appendStringInfoString(buf, "BETWEEN ");
6535 CBC 21 : if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
6536 LBC 0 : appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
6537 GBC 21 : else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
6538 LBC 0 : appendStringInfoString(buf, "CURRENT ROW ");
6539 CBC 21 : else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
6540 : {
6541 GBC 21 : get_rule_expr(wc->startOffset, context, false);
6542 GIC 21 : if (wc->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
6543 21 : appendStringInfoString(buf, " PRECEDING ");
6544 UBC 0 : else if (wc->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
6545 UIC 0 : appendStringInfoString(buf, " FOLLOWING ");
6546 ECB : else
6547 LBC 0 : Assert(false);
6548 ECB : }
6549 : else
6550 LBC 0 : Assert(false);
6551 CBC 21 : if (wc->frameOptions & FRAMEOPTION_BETWEEN)
6552 : {
6553 21 : appendStringInfoString(buf, "AND ");
6554 GIC 21 : if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
6555 LBC 0 : appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
6556 CBC 21 : else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
6557 UIC 0 : appendStringInfoString(buf, "CURRENT ROW ");
6558 GIC 21 : else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
6559 : {
6560 21 : get_rule_expr(wc->endOffset, context, false);
6561 21 : if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
6562 UIC 0 : appendStringInfoString(buf, " PRECEDING ");
6563 CBC 21 : else if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
6564 GIC 21 : appendStringInfoString(buf, " FOLLOWING ");
6565 : else
6566 LBC 0 : Assert(false);
6567 ECB : }
6568 : else
6569 UIC 0 : Assert(false);
6570 : }
6571 GIC 21 : if (wc->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
6572 3 : appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
6573 18 : else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
6574 3 : appendStringInfoString(buf, "EXCLUDE GROUP ");
6575 CBC 15 : else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
6576 GIC 3 : appendStringInfoString(buf, "EXCLUDE TIES ");
6577 : /* we will now have a trailing space; remove it */
6578 21 : buf->len--;
6579 : }
6580 21 : appendStringInfoChar(buf, ')');
6581 CBC 21 : }
6582 :
6583 ECB : /* ----------
6584 : * get_insert_query_def - Parse back an INSERT parsetree
6585 : * ----------
6586 : */
6587 : static void
6588 GBC 161 : get_insert_query_def(Query *query, deparse_context *context,
6589 ECB : bool colNamesVisible)
6590 : {
6591 GIC 161 : StringInfo buf = context->buf;
6592 CBC 161 : RangeTblEntry *select_rte = NULL;
6593 GIC 161 : RangeTblEntry *values_rte = NULL;
6594 ECB : RangeTblEntry *rte;
6595 EUB : char *sep;
6596 ECB : ListCell *l;
6597 : List *strippedexprs;
6598 :
6599 : /* Insert the WITH clause if given */
6600 GBC 161 : get_with_clause(query, context);
6601 :
6602 : /*
6603 : * If it's an INSERT ... SELECT or multi-row VALUES, there will be a
6604 : * single RTE for the SELECT or VALUES. Plain VALUES has neither.
6605 ECB : */
6606 CBC 625 : foreach(l, query->rtable)
6607 : {
6608 464 : rte = (RangeTblEntry *) lfirst(l);
6609 :
6610 464 : if (rte->rtekind == RTE_SUBQUERY)
6611 ECB : {
6612 GIC 22 : if (select_rte)
6613 LBC 0 : elog(ERROR, "too many subquery RTEs in INSERT");
6614 GIC 22 : select_rte = rte;
6615 : }
6616 :
6617 CBC 464 : if (rte->rtekind == RTE_VALUES)
6618 : {
6619 GIC 19 : if (values_rte)
6620 LBC 0 : elog(ERROR, "too many values RTEs in INSERT");
6621 GIC 19 : values_rte = rte;
6622 : }
6623 : }
6624 161 : if (select_rte && values_rte)
6625 UIC 0 : elog(ERROR, "both subquery and values RTEs in INSERT");
6626 ECB :
6627 : /*
6628 : * Start the query with INSERT INTO relname
6629 : */
6630 CBC 161 : rte = rt_fetch(query->resultRelation, query->rtable);
6631 GIC 161 : Assert(rte->rtekind == RTE_RELATION);
6632 ECB :
6633 GIC 161 : if (PRETTY_INDENT(context))
6634 ECB : {
6635 GBC 161 : context->indentLevel += PRETTYINDENT_STD;
6636 GIC 161 : appendStringInfoChar(buf, ' ');
6637 ECB : }
6638 CBC 161 : appendStringInfo(buf, "INSERT INTO %s",
6639 : generate_relation_name(rte->relid, NIL));
6640 :
6641 : /* Print the relation alias, if needed; INSERT requires explicit AS */
6642 GIC 161 : get_rte_alias(rte, query->resultRelation, true, context);
6643 :
6644 ECB : /* always want a space here */
6645 CBC 161 : appendStringInfoChar(buf, ' ');
6646 ECB :
6647 : /*
6648 : * Add the insert-column-names list. Any indirection decoration needed on
6649 : * the column names can be inferred from the top targetlist.
6650 : */
6651 GIC 161 : strippedexprs = NIL;
6652 161 : sep = "";
6653 161 : if (query->targetList)
6654 161 : appendStringInfoChar(buf, '(');
6655 594 : foreach(l, query->targetList)
6656 : {
6657 CBC 433 : TargetEntry *tle = (TargetEntry *) lfirst(l);
6658 ECB :
6659 GIC 433 : if (tle->resjunk)
6660 UIC 0 : continue; /* ignore junk entries */
6661 ECB :
6662 CBC 433 : appendStringInfoString(buf, sep);
6663 GIC 433 : sep = ", ";
6664 ECB :
6665 : /*
6666 EUB : * Put out name of target column; look in the catalogs, not at
6667 : * tle->resname, since resname will fail to track RENAME.
6668 : */
6669 GBC 433 : appendStringInfoString(buf,
6670 GIC 433 : quote_identifier(get_attname(rte->relid,
6671 433 : tle->resno,
6672 ECB : false)));
6673 :
6674 : /*
6675 : * Print any indirection needed (subfields or subscripts), and strip
6676 : * off the top-level nodes representing the indirection assignments.
6677 : * Add the stripped expressions to strippedexprs. (If it's a
6678 : * single-VALUES statement, the stripped expressions are the VALUES to
6679 : * print below. Otherwise they're just Vars and not really
6680 : * interesting.)
6681 : */
6682 GIC 433 : strippedexprs = lappend(strippedexprs,
6683 CBC 433 : processIndirection((Node *) tle->expr,
6684 : context));
6685 ECB : }
6686 GIC 161 : if (query->targetList)
6687 161 : appendStringInfoString(buf, ") ");
6688 ECB :
6689 GIC 161 : if (query->override)
6690 ECB : {
6691 LBC 0 : if (query->override == OVERRIDING_SYSTEM_VALUE)
6692 UIC 0 : appendStringInfoString(buf, "OVERRIDING SYSTEM VALUE ");
6693 0 : else if (query->override == OVERRIDING_USER_VALUE)
6694 0 : appendStringInfoString(buf, "OVERRIDING USER VALUE ");
6695 : }
6696 EUB :
6697 GIC 161 : if (select_rte)
6698 : {
6699 : /* Add the SELECT */
6700 CBC 22 : get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
6701 : false,
6702 ECB : context->prettyFlags, context->wrapColumn,
6703 : context->indentLevel);
6704 : }
6705 GIC 139 : else if (values_rte)
6706 ECB : {
6707 : /* Add the multi-VALUES expression lists */
6708 GIC 19 : get_values_def(values_rte->values_lists, context);
6709 ECB : }
6710 CBC 120 : else if (strippedexprs)
6711 ECB : {
6712 : /* Add the single-VALUES expression list */
6713 GIC 120 : appendContextKeyword(context, "VALUES (",
6714 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
6715 GIC 120 : get_rule_list_toplevel(strippedexprs, context, false);
6716 120 : appendStringInfoChar(buf, ')');
6717 : }
6718 : else
6719 : {
6720 : /* No expressions, so it must be DEFAULT VALUES */
6721 UIC 0 : appendStringInfoString(buf, "DEFAULT VALUES");
6722 : }
6723 ECB :
6724 : /* Add ON CONFLICT if present */
6725 GIC 161 : if (query->onConflict)
6726 ECB : {
6727 GIC 15 : OnConflictExpr *confl = query->onConflict;
6728 ECB :
6729 GIC 15 : appendStringInfoString(buf, " ON CONFLICT");
6730 ECB :
6731 GIC 15 : if (confl->arbiterElems)
6732 : {
6733 ECB : /* Add the single-VALUES expression list */
6734 GIC 12 : appendStringInfoChar(buf, '(');
6735 GBC 12 : get_rule_expr((Node *) confl->arbiterElems, context, false);
6736 GIC 12 : appendStringInfoChar(buf, ')');
6737 EUB :
6738 : /* Add a WHERE clause (for partial indexes) if given */
6739 GIC 12 : if (confl->arbiterWhere != NULL)
6740 EUB : {
6741 : bool save_varprefix;
6742 :
6743 : /*
6744 ECB : * Force non-prefixing of Vars, since parser assumes that they
6745 : * belong to target relation. WHERE clause does not use
6746 : * InferenceElem, so this is separately required.
6747 : */
6748 GIC 6 : save_varprefix = context->varprefix;
6749 6 : context->varprefix = false;
6750 ECB :
6751 GIC 6 : appendContextKeyword(context, " WHERE ",
6752 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6753 GIC 6 : get_rule_expr(confl->arbiterWhere, context, false);
6754 :
6755 6 : context->varprefix = save_varprefix;
6756 ECB : }
6757 : }
6758 CBC 3 : else if (OidIsValid(confl->constraint))
6759 : {
6760 LBC 0 : char *constraint = get_constraint_name(confl->constraint);
6761 :
6762 UIC 0 : if (!constraint)
6763 0 : elog(ERROR, "cache lookup failed for constraint %u",
6764 : confl->constraint);
6765 0 : appendStringInfo(buf, " ON CONSTRAINT %s",
6766 ECB : quote_identifier(constraint));
6767 : }
6768 :
6769 GIC 15 : if (confl->action == ONCONFLICT_NOTHING)
6770 ECB : {
6771 GIC 9 : appendStringInfoString(buf, " DO NOTHING");
6772 ECB : }
6773 : else
6774 : {
6775 GIC 6 : appendStringInfoString(buf, " DO UPDATE SET ");
6776 : /* Deparse targetlist */
6777 6 : get_update_query_targetlist_def(query, confl->onConflictSet,
6778 : context, rte);
6779 :
6780 ECB : /* Add a WHERE clause if given */
6781 GIC 6 : if (confl->onConflictWhere != NULL)
6782 : {
6783 CBC 6 : appendContextKeyword(context, " WHERE ",
6784 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6785 GIC 6 : get_rule_expr(confl->onConflictWhere, context, false);
6786 : }
6787 ECB : }
6788 : }
6789 :
6790 : /* Add RETURNING if present */
6791 GIC 161 : if (query->returningList)
6792 ECB : {
6793 CBC 39 : appendContextKeyword(context, " RETURNING",
6794 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6795 GIC 39 : get_target_list(query->returningList, context, NULL, colNamesVisible);
6796 ECB : }
6797 CBC 161 : }
6798 :
6799 ECB :
6800 : /* ----------
6801 : * get_update_query_def - Parse back an UPDATE parsetree
6802 : * ----------
6803 : */
6804 : static void
6805 GIC 65 : get_update_query_def(Query *query, deparse_context *context,
6806 ECB : bool colNamesVisible)
6807 : {
6808 GIC 65 : StringInfo buf = context->buf;
6809 ECB : RangeTblEntry *rte;
6810 :
6811 : /* Insert the WITH clause if given */
6812 CBC 65 : get_with_clause(query, context);
6813 :
6814 : /*
6815 ECB : * Start the query with UPDATE relname SET
6816 : */
6817 CBC 65 : rte = rt_fetch(query->resultRelation, query->rtable);
6818 GIC 65 : Assert(rte->rtekind == RTE_RELATION);
6819 CBC 65 : if (PRETTY_INDENT(context))
6820 : {
6821 GIC 65 : appendStringInfoChar(buf, ' ');
6822 65 : context->indentLevel += PRETTYINDENT_STD;
6823 ECB : }
6824 GIC 130 : appendStringInfo(buf, "UPDATE %s%s",
6825 CBC 65 : only_marker(rte),
6826 : generate_relation_name(rte->relid, NIL));
6827 ECB :
6828 : /* Print the relation alias, if needed */
6829 CBC 65 : get_rte_alias(rte, query->resultRelation, false, context);
6830 :
6831 GIC 65 : appendStringInfoString(buf, " SET ");
6832 :
6833 : /* Deparse targetlist */
6834 65 : get_update_query_targetlist_def(query, query->targetList, context, rte);
6835 :
6836 : /* Add the FROM clause if needed */
6837 CBC 65 : get_from_clause(query, " FROM ", context);
6838 :
6839 : /* Add a WHERE clause if given */
6840 65 : if (query->jointree->quals != NULL)
6841 : {
6842 GIC 57 : appendContextKeyword(context, " WHERE ",
6843 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6844 57 : get_rule_expr(query->jointree->quals, context, false);
6845 : }
6846 :
6847 : /* Add RETURNING if present */
6848 65 : if (query->returningList)
6849 : {
6850 11 : appendContextKeyword(context, " RETURNING",
6851 : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6852 11 : get_target_list(query->returningList, context, NULL, colNamesVisible);
6853 ECB : }
6854 CBC 65 : }
6855 :
6856 ECB :
6857 : /* ----------
6858 : * get_update_query_targetlist_def - Parse back an UPDATE targetlist
6859 : * ----------
6860 : */
6861 : static void
6862 CBC 71 : get_update_query_targetlist_def(Query *query, List *targetList,
6863 : deparse_context *context, RangeTblEntry *rte)
6864 ECB : {
6865 GIC 71 : StringInfo buf = context->buf;
6866 ECB : ListCell *l;
6867 : ListCell *next_ma_cell;
6868 : int remaining_ma_columns;
6869 : const char *sep;
6870 : SubLink *cur_ma_sublink;
6871 : List *ma_sublinks;
6872 :
6873 : /*
6874 : * Prepare to deal with MULTIEXPR assignments: collect the source SubLinks
6875 : * into a list. We expect them to appear, in ID order, in resjunk tlist
6876 : * entries.
6877 : */
6878 CBC 71 : ma_sublinks = NIL;
6879 GIC 71 : if (query->hasSubLinks) /* else there can't be any */
6880 ECB : {
6881 GIC 15 : foreach(l, targetList)
6882 : {
6883 CBC 12 : TargetEntry *tle = (TargetEntry *) lfirst(l);
6884 ECB :
6885 GIC 12 : if (tle->resjunk && IsA(tle->expr, SubLink))
6886 : {
6887 CBC 3 : SubLink *sl = (SubLink *) tle->expr;
6888 ECB :
6889 GIC 3 : if (sl->subLinkType == MULTIEXPR_SUBLINK)
6890 : {
6891 3 : ma_sublinks = lappend(ma_sublinks, sl);
6892 3 : Assert(sl->subLinkId == list_length(ma_sublinks));
6893 : }
6894 ECB : }
6895 : }
6896 : }
6897 GIC 71 : next_ma_cell = list_head(ma_sublinks);
6898 71 : cur_ma_sublink = NULL;
6899 71 : remaining_ma_columns = 0;
6900 :
6901 : /* Add the comma separated list of 'attname = value' */
6902 71 : sep = "";
6903 193 : foreach(l, targetList)
6904 : {
6905 CBC 122 : TargetEntry *tle = (TargetEntry *) lfirst(l);
6906 ECB : Node *expr;
6907 :
6908 CBC 122 : if (tle->resjunk)
6909 GIC 3 : continue; /* ignore junk entries */
6910 EUB :
6911 : /* Emit separator (OK whether we're in multiassignment or not) */
6912 GBC 119 : appendStringInfoString(buf, sep);
6913 GIC 119 : sep = ", ";
6914 ECB :
6915 : /*
6916 : * Check to see if we're starting a multiassignment group: if so,
6917 : * output a left paren.
6918 : */
6919 GBC 119 : if (next_ma_cell != NULL && cur_ma_sublink == NULL)
6920 : {
6921 ECB : /*
6922 : * We must dig down into the expr to see if it's a PARAM_MULTIEXPR
6923 : * Param. That could be buried under FieldStores and
6924 : * SubscriptingRefs and CoerceToDomains (cf processIndirection()),
6925 EUB : * and underneath those there could be an implicit type coercion.
6926 : * Because we would ignore implicit type coercions anyway, we
6927 : * don't need to be as careful as processIndirection() is about
6928 : * descending past implicit CoerceToDomains.
6929 : */
6930 GIC 3 : expr = (Node *) tle->expr;
6931 6 : while (expr)
6932 ECB : {
6933 GIC 6 : if (IsA(expr, FieldStore))
6934 ECB : {
6935 UIC 0 : FieldStore *fstore = (FieldStore *) expr;
6936 ECB :
6937 LBC 0 : expr = (Node *) linitial(fstore->newvals);
6938 : }
6939 CBC 6 : else if (IsA(expr, SubscriptingRef))
6940 ECB : {
6941 CBC 3 : SubscriptingRef *sbsref = (SubscriptingRef *) expr;
6942 ECB :
6943 GIC 3 : if (sbsref->refassgnexpr == NULL)
6944 LBC 0 : break;
6945 :
6946 GIC 3 : expr = (Node *) sbsref->refassgnexpr;
6947 : }
6948 3 : else if (IsA(expr, CoerceToDomain))
6949 : {
6950 UIC 0 : CoerceToDomain *cdomain = (CoerceToDomain *) expr;
6951 :
6952 LBC 0 : if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
6953 0 : break;
6954 0 : expr = (Node *) cdomain->arg;
6955 : }
6956 : else
6957 GIC 3 : break;
6958 : }
6959 3 : expr = strip_implicit_coercions(expr);
6960 :
6961 CBC 3 : if (expr && IsA(expr, Param) &&
6962 GIC 3 : ((Param *) expr)->paramkind == PARAM_MULTIEXPR)
6963 : {
6964 3 : cur_ma_sublink = (SubLink *) lfirst(next_ma_cell);
6965 3 : next_ma_cell = lnext(ma_sublinks, next_ma_cell);
6966 3 : remaining_ma_columns = count_nonjunk_tlist_entries(((Query *) cur_ma_sublink->subselect)->targetList);
6967 3 : Assert(((Param *) expr)->paramid ==
6968 ECB : ((cur_ma_sublink->subLinkId << 16) | 1));
6969 GIC 3 : appendStringInfoChar(buf, '(');
6970 ECB : }
6971 : }
6972 :
6973 : /*
6974 : * Put out name of target column; look in the catalogs, not at
6975 : * tle->resname, since resname will fail to track RENAME.
6976 : */
6977 CBC 119 : appendStringInfoString(buf,
6978 GIC 119 : quote_identifier(get_attname(rte->relid,
6979 CBC 119 : tle->resno,
6980 : false)));
6981 ECB :
6982 : /*
6983 : * Print any indirection needed (subfields or subscripts), and strip
6984 : * off the top-level nodes representing the indirection assignments.
6985 : */
6986 GIC 119 : expr = processIndirection((Node *) tle->expr, context);
6987 :
6988 : /*
6989 ECB : * If we're in a multiassignment, skip printing anything more, unless
6990 : * this is the last column; in which case, what we print should be the
6991 : * sublink, not the Param.
6992 : */
6993 GIC 119 : if (cur_ma_sublink != NULL)
6994 : {
6995 9 : if (--remaining_ma_columns > 0)
6996 CBC 6 : continue; /* not the last column of multiassignment */
6997 GIC 3 : appendStringInfoChar(buf, ')');
6998 3 : expr = (Node *) cur_ma_sublink;
6999 3 : cur_ma_sublink = NULL;
7000 : }
7001 ECB :
7002 CBC 113 : appendStringInfoString(buf, " = ");
7003 ECB :
7004 GIC 113 : get_rule_expr(expr, context, false);
7005 ECB : }
7006 CBC 71 : }
7007 :
7008 ECB :
7009 : /* ----------
7010 : * get_delete_query_def - Parse back a DELETE parsetree
7011 : * ----------
7012 : */
7013 : static void
7014 GIC 38 : get_delete_query_def(Query *query, deparse_context *context,
7015 : bool colNamesVisible)
7016 ECB : {
7017 GIC 38 : StringInfo buf = context->buf;
7018 : RangeTblEntry *rte;
7019 ECB :
7020 : /* Insert the WITH clause if given */
7021 CBC 38 : get_with_clause(query, context);
7022 :
7023 ECB : /*
7024 : * Start the query with DELETE FROM relname
7025 : */
7026 GIC 38 : rte = rt_fetch(query->resultRelation, query->rtable);
7027 CBC 38 : Assert(rte->rtekind == RTE_RELATION);
7028 GIC 38 : if (PRETTY_INDENT(context))
7029 ECB : {
7030 GIC 38 : appendStringInfoChar(buf, ' ');
7031 CBC 38 : context->indentLevel += PRETTYINDENT_STD;
7032 : }
7033 76 : appendStringInfo(buf, "DELETE FROM %s%s",
7034 GIC 38 : only_marker(rte),
7035 : generate_relation_name(rte->relid, NIL));
7036 :
7037 : /* Print the relation alias, if needed */
7038 38 : get_rte_alias(rte, query->resultRelation, false, context);
7039 :
7040 : /* Add the USING clause if given */
7041 CBC 38 : get_from_clause(query, " USING ", context);
7042 :
7043 ECB : /* Add a WHERE clause if given */
7044 GIC 38 : if (query->jointree->quals != NULL)
7045 ECB : {
7046 CBC 38 : appendContextKeyword(context, " WHERE ",
7047 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7048 GIC 38 : get_rule_expr(query->jointree->quals, context, false);
7049 ECB : }
7050 :
7051 : /* Add RETURNING if present */
7052 CBC 38 : if (query->returningList)
7053 ECB : {
7054 GIC 8 : appendContextKeyword(context, " RETURNING",
7055 EUB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
7056 GBC 8 : get_target_list(query->returningList, context, NULL, colNamesVisible);
7057 : }
7058 GIC 38 : }
7059 :
7060 :
7061 : /* ----------
7062 EUB : * get_utility_query_def - Parse back a UTILITY parsetree
7063 : * ----------
7064 ECB : */
7065 : static void
7066 GIC 8 : get_utility_query_def(Query *query, deparse_context *context)
7067 : {
7068 8 : StringInfo buf = context->buf;
7069 :
7070 8 : if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
7071 8 : {
7072 8 : NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
7073 :
7074 8 : appendContextKeyword(context, "",
7075 : 0, PRETTYINDENT_STD, 1);
7076 8 : appendStringInfo(buf, "NOTIFY %s",
7077 8 : quote_identifier(stmt->conditionname));
7078 8 : if (stmt->payload)
7079 : {
7080 UIC 0 : appendStringInfoString(buf, ", ");
7081 0 : simple_quote_literal(buf, stmt->payload);
7082 : }
7083 : }
7084 : else
7085 : {
7086 ECB : /* Currently only NOTIFY utility commands can appear in rules */
7087 UIC 0 : elog(ERROR, "unexpected utility statement type");
7088 ECB : }
7089 GIC 8 : }
7090 :
7091 : /*
7092 : * Display a Var appropriately.
7093 : *
7094 : * In some cases (currently only when recursing into an unnamed join)
7095 : * the Var's varlevelsup has to be interpreted with respect to a context
7096 : * above the current one; levelsup indicates the offset.
7097 : *
7098 : * If istoplevel is true, the Var is at the top level of a SELECT's
7099 : * targetlist, which means we need special treatment of whole-row Vars.
7100 ECB : * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
7101 : * dirty hack to prevent "tab.*" from being expanded into multiple columns.
7102 EUB : * (The parser will strip the useless coercion, so no inefficiency is added in
7103 : * dump and reload.) We used to print just "tab" in such cases, but that is
7104 ECB : * ambiguous and will yield the wrong result if "tab" is also a plain column
7105 : * name in the query.
7106 : *
7107 : * Returns the attname of the Var, or NULL if the Var has no attname (because
7108 : * it is a whole-row Var or a subplan output reference).
7109 : */
7110 : static char *
7111 GIC 64306 : get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
7112 : {
7113 64306 : StringInfo buf = context->buf;
7114 : RangeTblEntry *rte;
7115 ECB : AttrNumber attnum;
7116 : int netlevelsup;
7117 : deparse_namespace *dpns;
7118 : int varno;
7119 : AttrNumber varattno;
7120 : deparse_columns *colinfo;
7121 : char *refname;
7122 : char *attname;
7123 :
7124 : /* Find appropriate nesting depth */
7125 GIC 64306 : netlevelsup = var->varlevelsup + levelsup;
7126 64306 : if (netlevelsup >= list_length(context->namespaces))
7127 UIC 0 : elog(ERROR, "bogus varlevelsup: %d offset %d",
7128 : var->varlevelsup, levelsup);
7129 GIC 64306 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7130 : netlevelsup);
7131 :
7132 ECB : /*
7133 : * If we have a syntactic referent for the Var, and we're working from a
7134 : * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7135 : * on the semantic referent. (Forcing use of the semantic referent when
7136 : * printing plan trees is a design choice that's perhaps more motivated by
7137 : * backwards compatibility than anything else. But it does have the
7138 : * advantage of making plans more explicit.)
7139 : */
7140 CBC 64306 : if (var->varnosyn > 0 && dpns->plan == NULL)
7141 ECB : {
7142 CBC 12577 : varno = var->varnosyn;
7143 GIC 12577 : varattno = var->varattnosyn;
7144 : }
7145 ECB : else
7146 : {
7147 CBC 51729 : varno = var->varno;
7148 GIC 51729 : varattno = var->varattno;
7149 ECB : }
7150 :
7151 : /*
7152 : * Try to find the relevant RTE in this rtable. In a plan tree, it's
7153 EUB : * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7154 ECB : * down into the subplans, or INDEX_VAR, which is resolved similarly. Also
7155 : * find the aliases previously assigned for this RTE.
7156 EUB : */
7157 GIC 64306 : if (varno >= 1 && varno <= list_length(dpns->rtable))
7158 : {
7159 ECB : /*
7160 : * We might have been asked to map child Vars to some parent relation.
7161 : */
7162 GIC 48323 : if (context->appendparents && dpns->appendrels)
7163 ECB : {
7164 CBC 1741 : int pvarno = varno;
7165 GIC 1741 : AttrNumber pvarattno = varattno;
7166 1741 : AppendRelInfo *appinfo = dpns->appendrels[pvarno];
7167 1741 : bool found = false;
7168 :
7169 : /* Only map up to inheritance parents, not UNION ALL appendrels */
7170 3539 : while (appinfo &&
7171 CBC 1935 : rt_fetch(appinfo->parent_relid,
7172 GIC 1935 : dpns->rtable)->rtekind == RTE_RELATION)
7173 ECB : {
7174 CBC 1798 : found = false;
7175 GIC 1798 : if (pvarattno > 0) /* system columns stay as-is */
7176 : {
7177 1661 : if (pvarattno > appinfo->num_child_cols)
7178 LBC 0 : break; /* safety check */
7179 CBC 1661 : pvarattno = appinfo->parent_colnos[pvarattno - 1];
7180 1661 : if (pvarattno == 0)
7181 LBC 0 : break; /* Var is local to child */
7182 : }
7183 :
7184 GIC 1798 : pvarno = appinfo->parent_relid;
7185 CBC 1798 : found = true;
7186 :
7187 ECB : /* If the parent is itself a child, continue up. */
7188 GIC 1798 : Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
7189 1798 : appinfo = dpns->appendrels[pvarno];
7190 : }
7191 :
7192 : /*
7193 : * If we found an ancestral rel, and that rel is included in
7194 : * appendparents, print that column not the original one.
7195 : */
7196 1741 : if (found && bms_is_member(pvarno, context->appendparents))
7197 : {
7198 1439 : varno = pvarno;
7199 1439 : varattno = pvarattno;
7200 : }
7201 ECB : }
7202 :
7203 CBC 48323 : rte = rt_fetch(varno, dpns->rtable);
7204 GIC 48323 : refname = (char *) list_nth(dpns->rtable_names, varno - 1);
7205 48323 : colinfo = deparse_columns_fetch(varno, dpns);
7206 48323 : attnum = varattno;
7207 : }
7208 ECB : else
7209 : {
7210 GBC 15983 : resolve_special_varno((Node *) var, context,
7211 : get_special_variable, NULL);
7212 GIC 15983 : return NULL;
7213 ECB : }
7214 :
7215 : /*
7216 : * The planner will sometimes emit Vars referencing resjunk elements of a
7217 : * subquery's target list (this is currently only possible if it chooses
7218 : * to generate a "physical tlist" for a SubqueryScan or CteScan node).
7219 : * Although we prefer to print subquery-referencing Vars using the
7220 : * subquery's alias, that's not possible for resjunk items since they have
7221 EUB : * no alias. So in that case, drill down to the subplan and print the
7222 ECB : * contents of the referenced tlist item. This works because in a plan
7223 : * tree, such Vars can only occur in a SubqueryScan or CteScan node, and
7224 EUB : * we'll have set dpns->inner_plan to reference the child plan node.
7225 : */
7226 CBC 49913 : if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
7227 1590 : attnum > list_length(rte->eref->colnames) &&
7228 GIC 1 : dpns->inner_plan)
7229 : {
7230 : TargetEntry *tle;
7231 : deparse_namespace save_dpns;
7232 :
7233 1 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7234 1 : if (!tle)
7235 UIC 0 : elog(ERROR, "invalid attnum %d for relation \"%s\"",
7236 : attnum, rte->eref->aliasname);
7237 :
7238 GIC 1 : Assert(netlevelsup == 0);
7239 1 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7240 :
7241 : /*
7242 ECB : * Force parentheses because our caller probably assumed a Var is a
7243 : * simple expression.
7244 : */
7245 GBC 1 : if (!IsA(tle->expr, Var))
7246 LBC 0 : appendStringInfoChar(buf, '(');
7247 GIC 1 : get_rule_expr((Node *) tle->expr, context, true);
7248 1 : if (!IsA(tle->expr, Var))
7249 UIC 0 : appendStringInfoChar(buf, ')');
7250 ECB :
7251 GIC 1 : pop_child_plan(dpns, &save_dpns);
7252 CBC 1 : return NULL;
7253 : }
7254 EUB :
7255 : /*
7256 : * If it's an unnamed join, look at the expansion of the alias variable.
7257 : * If it's a simple reference to one of the input vars, then recursively
7258 : * print the name of that var instead. When it's not a simple reference,
7259 : * we have to just print the unqualified join column name. (This can only
7260 : * happen with "dangerous" merged columns in a JOIN USING; we took pains
7261 : * previously to make the unqualified column name unique in such cases.)
7262 : *
7263 : * This wouldn't work in decompiling plan trees, because we don't store
7264 ECB : * joinaliasvars lists after planning; but a plan tree should never
7265 : * contain a join alias variable.
7266 : */
7267 CBC 48322 : if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
7268 ECB : {
7269 CBC 48 : if (rte->joinaliasvars == NIL)
7270 UIC 0 : elog(ERROR, "cannot decompile join alias var in plan tree");
7271 GIC 48 : if (attnum > 0)
7272 ECB : {
7273 EUB : Var *aliasvar;
7274 :
7275 CBC 48 : aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
7276 : /* we intentionally don't strip implicit coercions here */
7277 GIC 48 : if (aliasvar && IsA(aliasvar, Var))
7278 : {
7279 UIC 0 : return get_variable(aliasvar, var->varlevelsup + levelsup,
7280 : istoplevel, context);
7281 : }
7282 : }
7283 :
7284 ECB : /*
7285 : * Unnamed join has no refname. (Note: since it's unnamed, there is
7286 : * no way the user could have referenced it to create a whole-row Var
7287 : * for it. So we don't have to cover that case below.)
7288 : */
7289 GIC 48 : Assert(refname == NULL);
7290 ECB : }
7291 :
7292 GIC 48322 : if (attnum == InvalidAttrNumber)
7293 CBC 379 : attname = NULL;
7294 GIC 47943 : else if (attnum > 0)
7295 ECB : {
7296 : /* Get column name to use from the colinfo struct */
7297 GIC 47342 : if (attnum > colinfo->num_cols)
7298 LBC 0 : elog(ERROR, "invalid attnum %d for relation \"%s\"",
7299 ECB : attnum, rte->eref->aliasname);
7300 GIC 47342 : attname = colinfo->colnames[attnum - 1];
7301 :
7302 ECB : /*
7303 : * If we find a Var referencing a dropped column, it seems better to
7304 : * print something (anything) than to fail. In general this should
7305 : * not happen, but it used to be possible for some cases involving
7306 : * functions returning named composite types, and perhaps there are
7307 : * still bugs out there.
7308 : */
7309 CBC 47342 : if (attname == NULL)
7310 GIC 3 : attname = "?dropped?column?";
7311 : }
7312 : else
7313 : {
7314 : /* System column - name is fixed, get it from the catalog */
7315 601 : attname = get_rte_attribute_name(rte, attnum);
7316 : }
7317 :
7318 48322 : if (refname && (context->varprefix || attname == NULL))
7319 : {
7320 CBC 22198 : appendStringInfoString(buf, quote_identifier(refname));
7321 GIC 22198 : appendStringInfoChar(buf, '.');
7322 ECB : }
7323 GIC 48322 : if (attname)
7324 47943 : appendStringInfoString(buf, quote_identifier(attname));
7325 : else
7326 : {
7327 379 : appendStringInfoChar(buf, '*');
7328 CBC 379 : if (istoplevel)
7329 36 : appendStringInfo(buf, "::%s",
7330 ECB : format_type_with_typemod(var->vartype,
7331 : var->vartypmod));
7332 : }
7333 :
7334 GIC 48322 : return attname;
7335 : }
7336 :
7337 : /*
7338 : * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
7339 : * routine is actually a callback for resolve_special_varno, which handles
7340 : * finding the correct TargetEntry. We get the expression contained in that
7341 ECB : * TargetEntry and just need to deparse it, a job we can throw back on
7342 : * get_rule_expr.
7343 : */
7344 : static void
7345 GIC 15983 : get_special_variable(Node *node, deparse_context *context, void *callback_arg)
7346 : {
7347 15983 : StringInfo buf = context->buf;
7348 ECB :
7349 : /*
7350 : * For a non-Var referent, force parentheses because our caller probably
7351 : * assumed a Var is a simple expression.
7352 : */
7353 CBC 15983 : if (!IsA(node, Var))
7354 1506 : appendStringInfoChar(buf, '(');
7355 GIC 15983 : get_rule_expr(node, context, true);
7356 15983 : if (!IsA(node, Var))
7357 1506 : appendStringInfoChar(buf, ')');
7358 CBC 15983 : }
7359 ECB :
7360 : /*
7361 : * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
7362 : * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
7363 : * invoke the callback provided.
7364 : */
7365 : static void
7366 CBC 44201 : resolve_special_varno(Node *node, deparse_context *context,
7367 : rsv_callback callback, void *callback_arg)
7368 : {
7369 : Var *var;
7370 : deparse_namespace *dpns;
7371 :
7372 ECB : /* This function is recursive, so let's be paranoid. */
7373 CBC 44201 : check_stack_depth();
7374 EUB :
7375 : /* If it's not a Var, invoke the callback. */
7376 GIC 44201 : if (!IsA(node, Var))
7377 : {
7378 1636 : (*callback) (node, context, callback_arg);
7379 1636 : return;
7380 : }
7381 ECB :
7382 : /* Find appropriate nesting depth */
7383 CBC 42565 : var = (Var *) node;
7384 42565 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7385 42565 : var->varlevelsup);
7386 ECB :
7387 : /*
7388 : * If varno is special, recurse. (Don't worry about varnosyn; if we're
7389 : * here, we already decided not to use that.)
7390 : */
7391 CBC 42565 : if (var->varno == OUTER_VAR && dpns->outer_tlist)
7392 : {
7393 ECB : TargetEntry *tle;
7394 : deparse_namespace save_dpns;
7395 : Bitmapset *save_appendparents;
7396 :
7397 CBC 21079 : tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
7398 GIC 21079 : if (!tle)
7399 UIC 0 : elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
7400 :
7401 : /*
7402 ECB : * If we're descending to the first child of an Append or MergeAppend,
7403 : * update appendparents. This will affect deparsing of all Vars
7404 EUB : * appearing within the eventually-resolved subexpression.
7405 : */
7406 CBC 21079 : save_appendparents = context->appendparents;
7407 ECB :
7408 GIC 21079 : if (IsA(dpns->plan, Append))
7409 CBC 1948 : context->appendparents = bms_union(context->appendparents,
7410 1948 : ((Append *) dpns->plan)->apprelids);
7411 GIC 19131 : else if (IsA(dpns->plan, MergeAppend))
7412 CBC 243 : context->appendparents = bms_union(context->appendparents,
7413 GIC 243 : ((MergeAppend *) dpns->plan)->apprelids);
7414 :
7415 21079 : push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7416 CBC 21079 : resolve_special_varno((Node *) tle->expr, context,
7417 ECB : callback, callback_arg);
7418 GBC 21079 : pop_child_plan(dpns, &save_dpns);
7419 GIC 21079 : context->appendparents = save_appendparents;
7420 CBC 21079 : return;
7421 : }
7422 21486 : else if (var->varno == INNER_VAR && dpns->inner_tlist)
7423 : {
7424 ECB : TargetEntry *tle;
7425 EUB : deparse_namespace save_dpns;
7426 :
7427 GIC 5083 : tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
7428 CBC 5083 : if (!tle)
7429 UIC 0 : elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
7430 :
7431 GIC 5083 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7432 5083 : resolve_special_varno((Node *) tle->expr, context,
7433 : callback, callback_arg);
7434 5083 : pop_child_plan(dpns, &save_dpns);
7435 5083 : return;
7436 : }
7437 16403 : else if (var->varno == INDEX_VAR && dpns->index_tlist)
7438 : {
7439 : TargetEntry *tle;
7440 :
7441 1926 : tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
7442 1926 : if (!tle)
7443 UIC 0 : elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
7444 :
7445 GIC 1926 : resolve_special_varno((Node *) tle->expr, context,
7446 : callback, callback_arg);
7447 1926 : return;
7448 : }
7449 CBC 14477 : else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
7450 UIC 0 : elog(ERROR, "bogus varno: %d", var->varno);
7451 :
7452 : /* Not special. Just invoke the callback. */
7453 GIC 14477 : (*callback) (node, context, callback_arg);
7454 : }
7455 :
7456 : /*
7457 : * Get the name of a field of an expression of composite type. The
7458 : * expression is usually a Var, but we handle other cases too.
7459 : *
7460 : * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
7461 : *
7462 : * This is fairly straightforward when the expression has a named composite
7463 : * type; we need only look up the type in the catalogs. However, the type
7464 : * could also be RECORD. Since no actual table or view column is allowed to
7465 : * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
7466 ECB : * or to a subquery output. We drill down to find the ultimate defining
7467 : * expression and attempt to infer the field name from it. We ereport if we
7468 : * can't determine the name.
7469 : *
7470 : * Similarly, a PARAM of type RECORD has to refer to some expression of
7471 : * a determinable composite type.
7472 : */
7473 : static const char *
7474 GIC 376 : get_name_for_var_field(Var *var, int fieldno,
7475 : int levelsup, deparse_context *context)
7476 : {
7477 ECB : RangeTblEntry *rte;
7478 : AttrNumber attnum;
7479 : int netlevelsup;
7480 : deparse_namespace *dpns;
7481 : int varno;
7482 : AttrNumber varattno;
7483 : TupleDesc tupleDesc;
7484 : Node *expr;
7485 :
7486 : /*
7487 : * If it's a RowExpr that was expanded from a whole-row Var, use the
7488 : * column names attached to it. (We could let get_expr_result_tupdesc()
7489 : * handle this, but it's much cheaper to just pull out the name we need.)
7490 : */
7491 GIC 376 : if (IsA(var, RowExpr))
7492 ECB : {
7493 CBC 18 : RowExpr *r = (RowExpr *) var;
7494 :
7495 GIC 18 : if (fieldno > 0 && fieldno <= list_length(r->colnames))
7496 18 : return strVal(list_nth(r->colnames, fieldno - 1));
7497 : }
7498 :
7499 : /*
7500 : * If it's a Param of type RECORD, try to find what the Param refers to.
7501 ECB : */
7502 CBC 358 : if (IsA(var, Param))
7503 : {
7504 6 : Param *param = (Param *) var;
7505 : ListCell *ancestor_cell;
7506 ECB :
7507 CBC 6 : expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7508 GIC 6 : if (expr)
7509 : {
7510 : /* Found a match, so recurse to decipher the field name */
7511 ECB : deparse_namespace save_dpns;
7512 : const char *result;
7513 EUB :
7514 GIC 6 : push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
7515 CBC 6 : result = get_name_for_var_field((Var *) expr, fieldno,
7516 : 0, context);
7517 GIC 6 : pop_ancestor_plan(dpns, &save_dpns);
7518 6 : return result;
7519 : }
7520 : }
7521 :
7522 : /*
7523 ECB : * If it's a Var of type RECORD, we have to find what the Var refers to;
7524 : * if not, we can use get_expr_result_tupdesc().
7525 : */
7526 CBC 352 : if (!IsA(var, Var) ||
7527 GIC 324 : var->vartype != RECORDOID)
7528 : {
7529 271 : tupleDesc = get_expr_result_tupdesc((Node *) var, false);
7530 ECB : /* Got the tupdesc, so we can extract the field name */
7531 CBC 271 : Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7532 GIC 271 : return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7533 : }
7534 :
7535 : /* Find appropriate nesting depth */
7536 81 : netlevelsup = var->varlevelsup + levelsup;
7537 81 : if (netlevelsup >= list_length(context->namespaces))
7538 UIC 0 : elog(ERROR, "bogus varlevelsup: %d offset %d",
7539 : var->varlevelsup, levelsup);
7540 GIC 81 : dpns = (deparse_namespace *) list_nth(context->namespaces,
7541 : netlevelsup);
7542 :
7543 ECB : /*
7544 : * If we have a syntactic referent for the Var, and we're working from a
7545 : * parse tree, prefer to use the syntactic referent. Otherwise, fall back
7546 : * on the semantic referent. (See comments in get_variable().)
7547 : */
7548 CBC 81 : if (var->varnosyn > 0 && dpns->plan == NULL)
7549 : {
7550 GIC 27 : varno = var->varnosyn;
7551 27 : varattno = var->varattnosyn;
7552 : }
7553 : else
7554 ECB : {
7555 CBC 54 : varno = var->varno;
7556 GBC 54 : varattno = var->varattno;
7557 : }
7558 ECB :
7559 : /*
7560 : * Try to find the relevant RTE in this rtable. In a plan tree, it's
7561 : * likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
7562 : * down into the subplans, or INDEX_VAR, which is resolved similarly.
7563 : *
7564 : * Note: unlike get_variable and resolve_special_varno, we need not worry
7565 : * about inheritance mapping: a child Var should have the same datatype as
7566 : * its parent, and here we're really only interested in the Var's type.
7567 : */
7568 GIC 81 : if (varno >= 1 && varno <= list_length(dpns->rtable))
7569 : {
7570 42 : rte = rt_fetch(varno, dpns->rtable);
7571 42 : attnum = varattno;
7572 : }
7573 CBC 39 : else if (varno == OUTER_VAR && dpns->outer_tlist)
7574 ECB : {
7575 EUB : TargetEntry *tle;
7576 : deparse_namespace save_dpns;
7577 ECB : const char *result;
7578 :
7579 GIC 30 : tle = get_tle_by_resno(dpns->outer_tlist, varattno);
7580 CBC 30 : if (!tle)
7581 UIC 0 : elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
7582 :
7583 CBC 30 : Assert(netlevelsup == 0);
7584 30 : push_child_plan(dpns, dpns->outer_plan, &save_dpns);
7585 :
7586 GBC 30 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7587 : levelsup, context);
7588 :
7589 GIC 30 : pop_child_plan(dpns, &save_dpns);
7590 30 : return result;
7591 EUB : }
7592 GBC 9 : else if (varno == INNER_VAR && dpns->inner_tlist)
7593 EUB : {
7594 : TargetEntry *tle;
7595 : deparse_namespace save_dpns;
7596 : const char *result;
7597 :
7598 GIC 9 : tle = get_tle_by_resno(dpns->inner_tlist, varattno);
7599 9 : if (!tle)
7600 UBC 0 : elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
7601 :
7602 GIC 9 : Assert(netlevelsup == 0);
7603 9 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7604 EUB :
7605 GIC 9 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7606 : levelsup, context);
7607 :
7608 CBC 9 : pop_child_plan(dpns, &save_dpns);
7609 GIC 9 : return result;
7610 : }
7611 LBC 0 : else if (varno == INDEX_VAR && dpns->index_tlist)
7612 : {
7613 : TargetEntry *tle;
7614 : const char *result;
7615 :
7616 UIC 0 : tle = get_tle_by_resno(dpns->index_tlist, varattno);
7617 0 : if (!tle)
7618 0 : elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
7619 :
7620 0 : Assert(netlevelsup == 0);
7621 ECB :
7622 UIC 0 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7623 ECB : levelsup, context);
7624 :
7625 UBC 0 : return result;
7626 : }
7627 : else
7628 : {
7629 UIC 0 : elog(ERROR, "bogus varno: %d", varno);
7630 : return NULL; /* keep compiler quiet */
7631 : }
7632 :
7633 GIC 42 : if (attnum == InvalidAttrNumber)
7634 : {
7635 EUB : /* Var is whole-row reference to RTE, so select the right field */
7636 CBC 12 : return get_rte_attribute_name(rte, fieldno);
7637 : }
7638 :
7639 ECB : /*
7640 : * This part has essentially the same logic as the parser's
7641 : * expandRecordVariable() function, but we are dealing with a different
7642 : * representation of the input context, and we only need one field name
7643 : * not a TupleDesc. Also, we need special cases for finding subquery and
7644 : * CTE subplans when deparsing Plan trees.
7645 EUB : */
7646 GIC 30 : expr = (Node *) var; /* default if we can't drill down */
7647 ECB :
7648 CBC 30 : switch (rte->rtekind)
7649 : {
7650 UIC 0 : case RTE_RELATION:
7651 : case RTE_VALUES:
7652 : case RTE_NAMEDTUPLESTORE:
7653 : case RTE_RESULT:
7654 :
7655 : /*
7656 : * This case should not occur: a column of a table, values list,
7657 : * or ENR shouldn't have type RECORD. Fall through and fail (most
7658 : * likely) at the bottom.
7659 ECB : */
7660 UIC 0 : break;
7661 GIC 9 : case RTE_SUBQUERY:
7662 ECB : /* Subselect-in-FROM: examine sub-select's output expr */
7663 : {
7664 GIC 9 : if (rte->subquery)
7665 ECB : {
7666 GIC 6 : TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
7667 : attnum);
7668 ECB :
7669 CBC 6 : if (ste == NULL || ste->resjunk)
7670 UIC 0 : elog(ERROR, "subquery %s does not have attribute %d",
7671 ECB : rte->eref->aliasname, attnum);
7672 GIC 6 : expr = (Node *) ste->expr;
7673 6 : if (IsA(expr, Var))
7674 : {
7675 : /*
7676 : * Recurse into the sub-select to see what its Var
7677 : * refers to. We have to build an additional level of
7678 : * namespace to keep in step with varlevelsup in the
7679 : * subselect.
7680 : */
7681 : deparse_namespace mydpns;
7682 : const char *result;
7683 :
7684 6 : set_deparse_for_query(&mydpns, rte->subquery,
7685 : context->namespaces);
7686 :
7687 6 : context->namespaces = lcons(&mydpns,
7688 ECB : context->namespaces);
7689 EUB :
7690 GIC 6 : result = get_name_for_var_field((Var *) expr, fieldno,
7691 ECB : 0, context);
7692 :
7693 GBC 6 : context->namespaces =
7694 GIC 6 : list_delete_first(context->namespaces);
7695 ECB :
7696 CBC 6 : return result;
7697 : }
7698 ECB : /* else fall through to inspect the expression */
7699 : }
7700 : else
7701 : {
7702 : /*
7703 : * We're deparsing a Plan tree so we don't have complete
7704 : * RTE entries (in particular, rte->subquery is NULL). But
7705 EUB : * the only place we'd see a Var directly referencing a
7706 : * SUBQUERY RTE is in a SubqueryScan plan node, and we can
7707 : * look into the child plan's tlist instead.
7708 : */
7709 : TargetEntry *tle;
7710 : deparse_namespace save_dpns;
7711 : const char *result;
7712 :
7713 GIC 3 : if (!dpns->inner_plan)
7714 UBC 0 : elog(ERROR, "failed to find plan for subquery %s",
7715 EUB : rte->eref->aliasname);
7716 GBC 3 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7717 GIC 3 : if (!tle)
7718 UIC 0 : elog(ERROR, "bogus varattno for subquery var: %d",
7719 EUB : attnum);
7720 GBC 3 : Assert(netlevelsup == 0);
7721 GIC 3 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7722 :
7723 3 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7724 : levelsup, context);
7725 :
7726 3 : pop_child_plan(dpns, &save_dpns);
7727 GBC 3 : return result;
7728 ECB : }
7729 : }
7730 UIC 0 : break;
7731 LBC 0 : case RTE_JOIN:
7732 : /* Join RTE --- recursively inspect the alias variable */
7733 UIC 0 : if (rte->joinaliasvars == NIL)
7734 0 : elog(ERROR, "cannot decompile join alias var in plan tree");
7735 0 : Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
7736 0 : expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
7737 0 : Assert(expr != NULL);
7738 ECB : /* we intentionally don't strip implicit coercions here */
7739 LBC 0 : if (IsA(expr, Var))
7740 0 : return get_name_for_var_field((Var *) expr, fieldno,
7741 UIC 0 : var->varlevelsup + levelsup,
7742 : context);
7743 : /* else fall through to inspect the expression */
7744 0 : break;
7745 0 : case RTE_FUNCTION:
7746 ECB : case RTE_TABLEFUNC:
7747 :
7748 : /*
7749 : * We couldn't get here unless a function is declared with one of
7750 : * its result columns as RECORD, which is not allowed.
7751 : */
7752 UIC 0 : break;
7753 GIC 21 : case RTE_CTE:
7754 ECB : /* CTE reference: examine subquery's output expr */
7755 : {
7756 CBC 21 : CommonTableExpr *cte = NULL;
7757 ECB : Index ctelevelsup;
7758 : ListCell *lc;
7759 :
7760 : /*
7761 EUB : * Try to find the referenced CTE using the namespace stack.
7762 : */
7763 CBC 21 : ctelevelsup = rte->ctelevelsup + netlevelsup;
7764 21 : if (ctelevelsup >= list_length(context->namespaces))
7765 GIC 6 : lc = NULL;
7766 : else
7767 : {
7768 : deparse_namespace *ctedpns;
7769 :
7770 : ctedpns = (deparse_namespace *)
7771 15 : list_nth(context->namespaces, ctelevelsup);
7772 15 : foreach(lc, ctedpns->ctes)
7773 ECB : {
7774 GIC 9 : cte = (CommonTableExpr *) lfirst(lc);
7775 9 : if (strcmp(cte->ctename, rte->ctename) == 0)
7776 9 : break;
7777 : }
7778 ECB : }
7779 GIC 21 : if (lc != NULL)
7780 : {
7781 CBC 9 : Query *ctequery = (Query *) cte->ctequery;
7782 GIC 9 : TargetEntry *ste = get_tle_by_resno(GetCTETargetList(cte),
7783 ECB : attnum);
7784 :
7785 CBC 9 : if (ste == NULL || ste->resjunk)
7786 UIC 0 : elog(ERROR, "subquery %s does not have attribute %d",
7787 : rte->eref->aliasname, attnum);
7788 CBC 9 : expr = (Node *) ste->expr;
7789 GIC 9 : if (IsA(expr, Var))
7790 ECB : {
7791 : /*
7792 : * Recurse into the CTE to see what its Var refers to.
7793 : * We have to build an additional level of namespace
7794 : * to keep in step with varlevelsup in the CTE.
7795 : * Furthermore it could be an outer CTE, so we may
7796 : * have to delete some levels of namespace.
7797 : */
7798 GIC 6 : List *save_nslist = context->namespaces;
7799 : List *new_nslist;
7800 : deparse_namespace mydpns;
7801 : const char *result;
7802 :
7803 6 : set_deparse_for_query(&mydpns, ctequery,
7804 : context->namespaces);
7805 :
7806 6 : new_nslist = list_copy_tail(context->namespaces,
7807 : ctelevelsup);
7808 6 : context->namespaces = lcons(&mydpns, new_nslist);
7809 ECB :
7810 GBC 6 : result = get_name_for_var_field((Var *) expr, fieldno,
7811 : 0, context);
7812 ECB :
7813 CBC 6 : context->namespaces = save_nslist;
7814 EUB :
7815 GIC 6 : return result;
7816 ECB : }
7817 : /* else fall through to inspect the expression */
7818 : }
7819 : else
7820 : {
7821 : /*
7822 : * We're deparsing a Plan tree so we don't have a CTE
7823 : * list. But the only places we'd see a Var directly
7824 : * referencing a CTE RTE are in CteScan or WorkTableScan
7825 : * plan nodes. For those cases, set_deparse_plan arranged
7826 : * for dpns->inner_plan to be the plan node that emits the
7827 : * CTE or RecursiveUnion result, and we can look at its
7828 : * tlist instead.
7829 : */
7830 : TargetEntry *tle;
7831 : deparse_namespace save_dpns;
7832 : const char *result;
7833 :
7834 GIC 12 : if (!dpns->inner_plan)
7835 LBC 0 : elog(ERROR, "failed to find plan for CTE %s",
7836 ECB : rte->eref->aliasname);
7837 GIC 12 : tle = get_tle_by_resno(dpns->inner_tlist, attnum);
7838 12 : if (!tle)
7839 UIC 0 : elog(ERROR, "bogus varattno for subquery var: %d",
7840 : attnum);
7841 GIC 12 : Assert(netlevelsup == 0);
7842 12 : push_child_plan(dpns, dpns->inner_plan, &save_dpns);
7843 :
7844 12 : result = get_name_for_var_field((Var *) tle->expr, fieldno,
7845 : levelsup, context);
7846 :
7847 12 : pop_child_plan(dpns, &save_dpns);
7848 CBC 12 : return result;
7849 : }
7850 : }
7851 GIC 3 : break;
7852 ECB : }
7853 :
7854 : /*
7855 : * We now have an expression we can't expand any more, so see if
7856 : * get_expr_result_tupdesc() can do anything with it.
7857 : */
7858 GIC 3 : tupleDesc = get_expr_result_tupdesc(expr, false);
7859 : /* Got the tupdesc, so we can extract the field name */
7860 CBC 3 : Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
7861 GIC 3 : return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
7862 : }
7863 :
7864 : /*
7865 : * Try to find the referenced expression for a PARAM_EXEC Param that might
7866 ECB : * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
7867 : *
7868 : * If successful, return the expression and set *dpns_p and *ancestor_cell_p
7869 : * appropriately for calling push_ancestor_plan(). If no referent can be
7870 : * found, return NULL.
7871 : */
7872 : static Node *
7873 GIC 2425 : find_param_referent(Param *param, deparse_context *context,
7874 : deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
7875 : {
7876 : /* Initialize output parameters to prevent compiler warnings */
7877 CBC 2425 : *dpns_p = NULL;
7878 2425 : *ancestor_cell_p = NULL;
7879 :
7880 ECB : /*
7881 : * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
7882 : * SubPlan argument. This will necessarily be in some ancestor of the
7883 : * current expression's Plan node.
7884 : */
7885 GIC 2425 : if (param->paramkind == PARAM_EXEC)
7886 ECB : {
7887 : deparse_namespace *dpns;
7888 : Plan *child_plan;
7889 : ListCell *lc;
7890 :
7891 GIC 2012 : dpns = (deparse_namespace *) linitial(context->namespaces);
7892 2012 : child_plan = dpns->plan;
7893 :
7894 3811 : foreach(lc, dpns->ancestors)
7895 : {
7896 3195 : Node *ancestor = (Node *) lfirst(lc);
7897 ECB : ListCell *lc2;
7898 :
7899 : /*
7900 : * NestLoops transmit params to their inner child only.
7901 : */
7902 GIC 3195 : if (IsA(ancestor, NestLoop) &&
7903 GNC 1287 : child_plan == innerPlan(ancestor))
7904 : {
7905 CBC 1248 : NestLoop *nl = (NestLoop *) ancestor;
7906 :
7907 GIC 1528 : foreach(lc2, nl->nestParams)
7908 : {
7909 1483 : NestLoopParam *nlp = (NestLoopParam *) lfirst(lc2);
7910 :
7911 1483 : if (nlp->paramno == param->paramid)
7912 : {
7913 : /* Found a match, so return it */
7914 1203 : *dpns_p = dpns;
7915 CBC 1203 : *ancestor_cell_p = lc;
7916 GIC 1203 : return (Node *) nlp->paramval;
7917 : }
7918 ECB : }
7919 : }
7920 :
7921 : /*
7922 : * If ancestor is a SubPlan, check the arguments it provides.
7923 : */
7924 CBC 1992 : if (IsA(ancestor, SubPlan))
7925 GIC 33 : {
7926 226 : SubPlan *subplan = (SubPlan *) ancestor;
7927 EUB : ListCell *lc3;
7928 : ListCell *lc4;
7929 :
7930 GIC 254 : forboth(lc3, subplan->parParam, lc4, subplan->args)
7931 : {
7932 CBC 221 : int paramid = lfirst_int(lc3);
7933 GIC 221 : Node *arg = (Node *) lfirst(lc4);
7934 :
7935 221 : if (paramid == param->paramid)
7936 : {
7937 : /*
7938 : * Found a match, so return it. But, since Vars in
7939 : * the arg are to be evaluated in the surrounding
7940 : * context, we have to point to the next ancestor item
7941 ECB : * that is *not* a SubPlan.
7942 : */
7943 : ListCell *rest;
7944 :
7945 GIC 193 : for_each_cell(rest, dpns->ancestors,
7946 ECB : lnext(dpns->ancestors, lc))
7947 : {
7948 GIC 193 : Node *ancestor2 = (Node *) lfirst(rest);
7949 :
7950 193 : if (!IsA(ancestor2, SubPlan))
7951 : {
7952 193 : *dpns_p = dpns;
7953 CBC 193 : *ancestor_cell_p = rest;
7954 GIC 193 : return arg;
7955 : }
7956 : }
7957 UIC 0 : elog(ERROR, "SubPlan cannot be outermost ancestor");
7958 : }
7959 : }
7960 :
7961 : /* SubPlan isn't a kind of Plan, so skip the rest */
7962 CBC 33 : continue;
7963 ECB : }
7964 :
7965 : /*
7966 : * We need not consider the ancestor's initPlan list, since
7967 : * initplans never have any parParams.
7968 : */
7969 :
7970 : /* No luck, crawl up to next ancestor */
7971 GBC 1766 : child_plan = (Plan *) ancestor;
7972 ECB : }
7973 EUB : }
7974 :
7975 ECB : /* No referent found */
7976 GIC 1029 : return NULL;
7977 ECB : }
7978 EUB :
7979 : /*
7980 ECB : * Display a Param appropriately.
7981 : */
7982 : static void
7983 GIC 2419 : get_parameter(Param *param, deparse_context *context)
7984 ECB : {
7985 : Node *expr;
7986 : deparse_namespace *dpns;
7987 : ListCell *ancestor_cell;
7988 :
7989 : /*
7990 : * If it's a PARAM_EXEC parameter, try to locate the expression from which
7991 : * the parameter was computed. Note that failing to find a referent isn't
7992 : * an error, since the Param might well be a subplan output rather than an
7993 : * input.
7994 : */
7995 CBC 2419 : expr = find_param_referent(param, context, &dpns, &ancestor_cell);
7996 2419 : if (expr)
7997 : {
7998 ECB : /* Found a match, so print it */
7999 : deparse_namespace save_dpns;
8000 : bool save_varprefix;
8001 : bool need_paren;
8002 :
8003 : /* Switch attention to the ancestor plan node */
8004 GIC 1390 : push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
8005 :
8006 : /*
8007 : * Force prefixing of Vars, since they won't belong to the relation
8008 : * being scanned in the original plan node.
8009 : */
8010 1390 : save_varprefix = context->varprefix;
8011 CBC 1390 : context->varprefix = true;
8012 :
8013 ECB : /*
8014 : * A Param's expansion is typically a Var, Aggref, GroupingFunc, or
8015 : * upper-level Param, which wouldn't need extra parentheses.
8016 : * Otherwise, insert parens to ensure the expression looks atomic.
8017 : */
8018 CBC 1393 : need_paren = !(IsA(expr, Var) ||
8019 GIC 3 : IsA(expr, Aggref) ||
8020 3 : IsA(expr, GroupingFunc) ||
8021 LBC 0 : IsA(expr, Param));
8022 GIC 1390 : if (need_paren)
8023 LBC 0 : appendStringInfoChar(context->buf, '(');
8024 ECB :
8025 GIC 1390 : get_rule_expr(expr, context, false);
8026 :
8027 CBC 1390 : if (need_paren)
8028 LBC 0 : appendStringInfoChar(context->buf, ')');
8029 :
8030 GIC 1390 : context->varprefix = save_varprefix;
8031 :
8032 1390 : pop_ancestor_plan(dpns, &save_dpns);
8033 :
8034 1390 : return;
8035 : }
8036 ECB :
8037 : /*
8038 : * If it's an external parameter, see if the outermost namespace provides
8039 : * function argument names.
8040 : */
8041 GIC 1029 : if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
8042 : {
8043 413 : dpns = llast(context->namespaces);
8044 413 : if (dpns->argnames &&
8045 33 : param->paramid > 0 &&
8046 CBC 33 : param->paramid <= dpns->numargs)
8047 : {
8048 33 : char *argname = dpns->argnames[param->paramid - 1];
8049 :
8050 33 : if (argname)
8051 : {
8052 GIC 33 : bool should_qualify = false;
8053 ECB : ListCell *lc;
8054 :
8055 : /*
8056 : * Qualify the parameter name if there are any other deparse
8057 : * namespaces with range tables. This avoids qualifying in
8058 : * trivial cases like "RETURN a + b", but makes it safe in all
8059 : * other cases.
8060 : */
8061 GBC 75 : foreach(lc, context->namespaces)
8062 : {
8063 GNC 57 : deparse_namespace *depns = lfirst(lc);
8064 :
8065 57 : if (depns->rtable_names != NIL)
8066 : {
8067 GIC 15 : should_qualify = true;
8068 15 : break;
8069 : }
8070 : }
8071 33 : if (should_qualify)
8072 ECB : {
8073 GIC 15 : appendStringInfoString(context->buf, quote_identifier(dpns->funcname));
8074 CBC 15 : appendStringInfoChar(context->buf, '.');
8075 EUB : }
8076 :
8077 CBC 33 : appendStringInfoString(context->buf, quote_identifier(argname));
8078 GIC 33 : return;
8079 ECB : }
8080 : }
8081 : }
8082 :
8083 : /*
8084 : * Not PARAM_EXEC, or couldn't find referent: just print $N.
8085 : */
8086 CBC 996 : appendStringInfo(context->buf, "$%d", param->paramid);
8087 : }
8088 ECB :
8089 : /*
8090 : * get_simple_binary_op_name
8091 : *
8092 : * helper function for isSimpleNode
8093 : * will return single char binary operator name, or NULL if it's not
8094 : */
8095 : static const char *
8096 GIC 57 : get_simple_binary_op_name(OpExpr *expr)
8097 : {
8098 57 : List *args = expr->args;
8099 :
8100 57 : if (list_length(args) == 2)
8101 : {
8102 ECB : /* binary operator */
8103 GIC 57 : Node *arg1 = (Node *) linitial(args);
8104 57 : Node *arg2 = (Node *) lsecond(args);
8105 EUB : const char *op;
8106 :
8107 GIC 57 : op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
8108 CBC 57 : if (strlen(op) == 1)
8109 GIC 57 : return op;
8110 : }
8111 UIC 0 : return NULL;
8112 : }
8113 :
8114 ECB :
8115 : /*
8116 EUB : * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
8117 : *
8118 : * true : simple in the context of parent node's type
8119 : * false : not simple
8120 : */
8121 : static bool
8122 GIC 2212 : isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
8123 EUB : {
8124 GIC 2212 : if (!node)
8125 UBC 0 : return false;
8126 :
8127 CBC 2212 : switch (nodeTag(node))
8128 ECB : {
8129 GIC 1852 : case T_Var:
8130 EUB : case T_Const:
8131 : case T_Param:
8132 : case T_CoerceToDomainValue:
8133 : case T_SetToDefault:
8134 : case T_CurrentOfExpr:
8135 : /* single words: always simple */
8136 GBC 1852 : return true;
8137 EUB :
8138 GIC 186 : case T_SubscriptingRef:
8139 : case T_ArrayExpr:
8140 ECB : case T_RowExpr:
8141 : case T_CoalesceExpr:
8142 : case T_MinMaxExpr:
8143 : case T_XmlExpr:
8144 : case T_NextValueExpr:
8145 : case T_NullIfExpr:
8146 : case T_Aggref:
8147 : case T_GroupingFunc:
8148 : case T_WindowFunc:
8149 : case T_FuncExpr:
8150 : case T_JsonConstructorExpr:
8151 : /* function-like: name(..) or name[..] */
8152 CBC 186 : return true;
8153 ECB :
8154 EUB : /* CASE keywords act as parentheses */
8155 UIC 0 : case T_CaseExpr:
8156 0 : return true;
8157 ECB :
8158 CBC 24 : case T_FieldSelect:
8159 ECB :
8160 : /*
8161 : * appears simple since . has top precedence, unless parent is
8162 : * T_FieldSelect itself!
8163 : */
8164 GBC 24 : return !IsA(parentNode, FieldSelect);
8165 :
8166 LBC 0 : case T_FieldStore:
8167 ECB :
8168 : /*
8169 EUB : * treat like FieldSelect (probably doesn't matter)
8170 : */
8171 LBC 0 : return !IsA(parentNode, FieldStore);
8172 ECB :
8173 UIC 0 : case T_CoerceToDomain:
8174 ECB : /* maybe simple, check args */
8175 LBC 0 : return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
8176 : node, prettyFlags);
8177 GIC 3 : case T_RelabelType:
8178 3 : return isSimpleNode((Node *) ((RelabelType *) node)->arg,
8179 : node, prettyFlags);
8180 UIC 0 : case T_CoerceViaIO:
8181 LBC 0 : return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
8182 ECB : node, prettyFlags);
8183 UIC 0 : case T_ArrayCoerceExpr:
8184 LBC 0 : return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
8185 : node, prettyFlags);
8186 UIC 0 : case T_ConvertRowtypeExpr:
8187 0 : return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
8188 : node, prettyFlags);
8189 :
8190 GIC 126 : case T_OpExpr:
8191 : {
8192 : /* depends on parent node type; needs further checking */
8193 126 : if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
8194 : {
8195 ECB : const char *op;
8196 : const char *parentOp;
8197 : bool is_lopriop;
8198 : bool is_hipriop;
8199 : bool is_lopriparent;
8200 : bool is_hipriparent;
8201 :
8202 CBC 30 : op = get_simple_binary_op_name((OpExpr *) node);
8203 30 : if (!op)
8204 UIC 0 : return false;
8205 ECB :
8206 EUB : /* We know only the basic operators + - and * / % */
8207 GIC 30 : is_lopriop = (strchr("+-", *op) != NULL);
8208 CBC 30 : is_hipriop = (strchr("*/%", *op) != NULL);
8209 GIC 30 : if (!(is_lopriop || is_hipriop))
8210 3 : return false;
8211 :
8212 27 : parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
8213 27 : if (!parentOp)
8214 UIC 0 : return false;
8215 :
8216 GIC 27 : is_lopriparent = (strchr("+-", *parentOp) != NULL);
8217 27 : is_hipriparent = (strchr("*/%", *parentOp) != NULL);
8218 27 : if (!(is_lopriparent || is_hipriparent))
8219 UIC 0 : return false;
8220 ECB :
8221 CBC 27 : if (is_hipriop && is_lopriparent)
8222 6 : return true; /* op binds tighter than parent */
8223 :
8224 GIC 21 : if (is_lopriop && is_hipriparent)
8225 CBC 15 : return false;
8226 ECB :
8227 : /*
8228 : * Operators are same priority --- can skip parens only if
8229 : * we have (a - b) - c, not a - (b - c).
8230 : */
8231 GIC 6 : if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
8232 3 : return true;
8233 :
8234 CBC 3 : return false;
8235 ECB : }
8236 : /* else do the same stuff as for T_SubLink et al. */
8237 : }
8238 : /* FALLTHROUGH */
8239 :
8240 : case T_SubLink:
8241 : case T_NullTest:
8242 EUB : case T_BooleanTest:
8243 ECB : case T_DistinctExpr:
8244 : case T_JsonIsPredicate:
8245 CBC 108 : switch (nodeTag(parentNode))
8246 EUB : {
8247 CBC 15 : case T_FuncExpr:
8248 : {
8249 : /* special handling for casts and COERCE_SQL_SYNTAX */
8250 15 : CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8251 EUB :
8252 GIC 15 : if (type == COERCE_EXPLICIT_CAST ||
8253 3 : type == COERCE_IMPLICIT_CAST ||
8254 EUB : type == COERCE_SQL_SYNTAX)
8255 GIC 15 : return false;
8256 UBC 0 : return true; /* own parentheses */
8257 EUB : }
8258 GIC 81 : case T_BoolExpr: /* lower precedence */
8259 EUB : case T_SubscriptingRef: /* other separators */
8260 : case T_ArrayExpr: /* other separators */
8261 : case T_RowExpr: /* other separators */
8262 : case T_CoalesceExpr: /* own parentheses */
8263 : case T_MinMaxExpr: /* own parentheses */
8264 : case T_XmlExpr: /* own parentheses */
8265 : case T_NullIfExpr: /* other separators */
8266 : case T_Aggref: /* own parentheses */
8267 : case T_GroupingFunc: /* own parentheses */
8268 : case T_WindowFunc: /* own parentheses */
8269 : case T_CaseExpr: /* other separators */
8270 GIC 81 : return true;
8271 12 : default:
8272 12 : return false;
8273 EUB : }
8274 :
8275 GBC 9 : case T_BoolExpr:
8276 GIC 9 : switch (nodeTag(parentNode))
8277 : {
8278 GBC 9 : case T_BoolExpr:
8279 GIC 9 : if (prettyFlags & PRETTYFLAG_PAREN)
8280 EUB : {
8281 : BoolExprType type;
8282 : BoolExprType parentType;
8283 :
8284 GBC 9 : type = ((BoolExpr *) node)->boolop;
8285 GIC 9 : parentType = ((BoolExpr *) parentNode)->boolop;
8286 : switch (type)
8287 EUB : {
8288 GIC 6 : case NOT_EXPR:
8289 : case AND_EXPR:
8290 6 : if (parentType == AND_EXPR || parentType == OR_EXPR)
8291 6 : return true;
8292 UIC 0 : break;
8293 GIC 3 : case OR_EXPR:
8294 3 : if (parentType == OR_EXPR)
8295 UIC 0 : return true;
8296 GIC 3 : break;
8297 : }
8298 ECB : }
8299 GIC 3 : return false;
8300 UIC 0 : case T_FuncExpr:
8301 ECB : {
8302 : /* special handling for casts and COERCE_SQL_SYNTAX */
8303 LBC 0 : CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
8304 :
8305 UIC 0 : if (type == COERCE_EXPLICIT_CAST ||
8306 0 : type == COERCE_IMPLICIT_CAST ||
8307 ECB : type == COERCE_SQL_SYNTAX)
8308 UIC 0 : return false;
8309 0 : return true; /* own parentheses */
8310 ECB : }
8311 UIC 0 : case T_SubscriptingRef: /* other separators */
8312 ECB : case T_ArrayExpr: /* other separators */
8313 : case T_RowExpr: /* other separators */
8314 : case T_CoalesceExpr: /* own parentheses */
8315 : case T_MinMaxExpr: /* own parentheses */
8316 : case T_XmlExpr: /* own parentheses */
8317 : case T_NullIfExpr: /* other separators */
8318 : case T_Aggref: /* own parentheses */
8319 : case T_GroupingFunc: /* own parentheses */
8320 : case T_WindowFunc: /* own parentheses */
8321 : case T_CaseExpr: /* other separators */
8322 UIC 0 : return true;
8323 0 : default:
8324 0 : return false;
8325 : }
8326 :
8327 UNC 0 : case T_JsonValueExpr:
8328 : /* maybe simple, check args */
8329 0 : return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
8330 : node, prettyFlags);
8331 :
8332 UBC 0 : default:
8333 0 : break;
8334 : }
8335 EUB : /* those we don't know: in dubio complexo */
8336 UIC 0 : return false;
8337 EUB : }
8338 :
8339 ECB :
8340 : /*
8341 : * appendContextKeyword - append a keyword to buffer
8342 : *
8343 : * If prettyPrint is enabled, perform a line break, and adjust indentation.
8344 : * Otherwise, just append the keyword.
8345 EUB : */
8346 : static void
8347 GIC 8815 : appendContextKeyword(deparse_context *context, const char *str,
8348 ECB : int indentBefore, int indentAfter, int indentPlus)
8349 : {
8350 GIC 8815 : StringInfo buf = context->buf;
8351 :
8352 8815 : if (PRETTY_INDENT(context))
8353 : {
8354 : int indentAmount;
8355 :
8356 8666 : context->indentLevel += indentBefore;
8357 ECB :
8358 : /* remove any trailing spaces currently in the buffer ... */
8359 CBC 8666 : removeStringInfoSpaces(buf);
8360 ECB : /* ... then add a newline and some spaces */
8361 CBC 8666 : appendStringInfoChar(buf, '\n');
8362 :
8363 GIC 8666 : if (context->indentLevel < PRETTYINDENT_LIMIT)
8364 8666 : indentAmount = Max(context->indentLevel, 0) + indentPlus;
8365 : else
8366 : {
8367 : /*
8368 : * If we're indented more than PRETTYINDENT_LIMIT characters, try
8369 : * to conserve horizontal space by reducing the per-level
8370 : * indentation. For best results the scale factor here should
8371 : * divide all the indent amounts that get added to indentLevel
8372 : * (PRETTYINDENT_STD, etc). It's important that the indentation
8373 : * not grow unboundedly, else deeply-nested trees use O(N^2)
8374 : * whitespace; so we also wrap modulo PRETTYINDENT_LIMIT.
8375 : */
8376 LBC 0 : indentAmount = PRETTYINDENT_LIMIT +
8377 UIC 0 : (context->indentLevel - PRETTYINDENT_LIMIT) /
8378 : (PRETTYINDENT_STD / 2);
8379 0 : indentAmount %= PRETTYINDENT_LIMIT;
8380 : /* scale/wrap logic affects indentLevel, but not indentPlus */
8381 LBC 0 : indentAmount += indentPlus;
8382 ECB : }
8383 GIC 8666 : appendStringInfoSpaces(buf, indentAmount);
8384 ECB :
8385 CBC 8666 : appendStringInfoString(buf, str);
8386 :
8387 8666 : context->indentLevel += indentAfter;
8388 GIC 8666 : if (context->indentLevel < 0)
8389 LBC 0 : context->indentLevel = 0;
8390 ECB : }
8391 : else
8392 GIC 149 : appendStringInfoString(buf, str);
8393 8815 : }
8394 :
8395 : /*
8396 : * removeStringInfoSpaces - delete trailing spaces from a buffer.
8397 : *
8398 : * Possibly this should move to stringinfo.c at some point.
8399 : */
8400 : static void
8401 8777 : removeStringInfoSpaces(StringInfo str)
8402 : {
8403 13554 : while (str->len > 0 && str->data[str->len - 1] == ' ')
8404 4777 : str->data[--(str->len)] = '\0';
8405 8777 : }
8406 :
8407 :
8408 ECB : /*
8409 : * get_rule_expr_paren - deparse expr using get_rule_expr,
8410 : * embracing the string with parentheses if necessary for prettyPrint.
8411 : *
8412 : * Never embrace if prettyFlags=0, because it's done in the calling node.
8413 : *
8414 : * Any node that does *not* embrace its argument node by sql syntax (with
8415 : * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
8416 : * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
8417 : * added.
8418 : */
8419 : static void
8420 GIC 66059 : get_rule_expr_paren(Node *node, deparse_context *context,
8421 : bool showimplicit, Node *parentNode)
8422 : {
8423 : bool need_paren;
8424 :
8425 68268 : need_paren = PRETTY_PAREN(context) &&
8426 2209 : !isSimpleNode(node, parentNode, context->prettyFlags);
8427 ECB :
8428 GIC 66059 : if (need_paren)
8429 CBC 51 : appendStringInfoChar(context->buf, '(');
8430 ECB :
8431 CBC 66059 : get_rule_expr(node, context, showimplicit);
8432 :
8433 66059 : if (need_paren)
8434 51 : appendStringInfoChar(context->buf, ')');
8435 66059 : }
8436 :
8437 ECB :
8438 : /* ----------
8439 : * get_rule_expr - Parse back an expression
8440 : *
8441 : * Note: showimplicit determines whether we display any implicit cast that
8442 : * is present at the top of the expression tree. It is a passed argument,
8443 : * not a field of the context struct, because we change the value as we
8444 : * recurse down into the expression. In general we suppress implicit casts
8445 : * when the result type is known with certainty (eg, the arguments of an
8446 : * OR must be boolean). We display implicit casts for arguments of functions
8447 : * and operators, since this is needed to be certain that the same function
8448 : * or operator will be chosen when the expression is re-parsed.
8449 : * ----------
8450 : */
8451 : static void
8452 GIC 131463 : get_rule_expr(Node *node, deparse_context *context,
8453 ECB : bool showimplicit)
8454 : {
8455 CBC 131463 : StringInfo buf = context->buf;
8456 ECB :
8457 CBC 131463 : if (node == NULL)
8458 GIC 48 : return;
8459 ECB :
8460 : /* Guard against excessively long or deeply-nested queries */
8461 CBC 131415 : CHECK_FOR_INTERRUPTS();
8462 GIC 131415 : check_stack_depth();
8463 :
8464 : /*
8465 : * Each level of get_rule_expr must emit an indivisible term
8466 : * (parenthesized if necessary) to ensure result is reparsed into the same
8467 : * expression tree. The only exception is that when the input is a List,
8468 : * we emit the component items comma-separated with no surrounding
8469 : * decoration; this is convenient for most callers.
8470 : */
8471 131415 : switch (nodeTag(node))
8472 ECB : {
8473 GIC 58979 : case T_Var:
8474 GBC 58979 : (void) get_variable((Var *) node, 0, false, context);
8475 58979 : break;
8476 :
8477 25743 : case T_Const:
8478 GIC 25743 : get_const_expr((Const *) node, context, 0);
8479 25743 : break;
8480 :
8481 2419 : case T_Param:
8482 2419 : get_parameter((Param *) node, context);
8483 2419 : break;
8484 :
8485 762 : case T_Aggref:
8486 CBC 762 : get_agg_expr((Aggref *) node, context, (Aggref *) node);
8487 762 : break;
8488 ECB :
8489 CBC 26 : case T_GroupingFunc:
8490 ECB : {
8491 CBC 26 : GroupingFunc *gexpr = (GroupingFunc *) node;
8492 ECB :
8493 GIC 26 : appendStringInfoString(buf, "GROUPING(");
8494 26 : get_rule_expr((Node *) gexpr->args, context, true);
8495 26 : appendStringInfoChar(buf, ')');
8496 : }
8497 26 : break;
8498 :
8499 117 : case T_WindowFunc:
8500 117 : get_windowfunc_expr((WindowFunc *) node, context);
8501 117 : break;
8502 :
8503 CBC 98 : case T_SubscriptingRef:
8504 : {
8505 GIC 98 : SubscriptingRef *sbsref = (SubscriptingRef *) node;
8506 : bool need_parens;
8507 :
8508 : /*
8509 : * If the argument is a CaseTestExpr, we must be inside a
8510 : * FieldStore, ie, we are assigning to an element of an array
8511 : * within a composite column. Since we already punted on
8512 : * displaying the FieldStore's target information, just punt
8513 ECB : * here too, and display only the assignment source
8514 : * expression.
8515 : */
8516 GIC 98 : if (IsA(sbsref->refexpr, CaseTestExpr))
8517 : {
8518 UIC 0 : Assert(sbsref->refassgnexpr);
8519 0 : get_rule_expr((Node *) sbsref->refassgnexpr,
8520 ECB : context, showimplicit);
8521 UIC 0 : break;
8522 : }
8523 ECB :
8524 : /*
8525 : * Parenthesize the argument unless it's a simple Var or a
8526 : * FieldSelect. (In particular, if it's another
8527 : * SubscriptingRef, we *must* parenthesize to avoid
8528 : * confusion.)
8529 : */
8530 GIC 154 : need_parens = !IsA(sbsref->refexpr, Var) &&
8531 CBC 56 : !IsA(sbsref->refexpr, FieldSelect);
8532 GIC 98 : if (need_parens)
8533 CBC 41 : appendStringInfoChar(buf, '(');
8534 98 : get_rule_expr((Node *) sbsref->refexpr, context, showimplicit);
8535 GIC 98 : if (need_parens)
8536 CBC 41 : appendStringInfoChar(buf, ')');
8537 :
8538 ECB : /*
8539 : * If there's a refassgnexpr, we want to print the node in the
8540 : * format "container[subscripts] := refassgnexpr". This is
8541 : * not legal SQL, so decompilation of INSERT or UPDATE
8542 : * statements should always use processIndirection as part of
8543 : * the statement-level syntax. We should only see this when
8544 : * EXPLAIN tries to print the targetlist of a plan resulting
8545 : * from such a statement.
8546 : */
8547 CBC 98 : if (sbsref->refassgnexpr)
8548 : {
8549 ECB : Node *refassgnexpr;
8550 :
8551 : /*
8552 : * Use processIndirection to print this node's subscripts
8553 : * as well as any additional field selections or
8554 : * subscripting in immediate descendants. It returns the
8555 : * RHS expr that is actually being "assigned".
8556 : */
8557 CBC 6 : refassgnexpr = processIndirection(node, context);
8558 GIC 6 : appendStringInfoString(buf, " := ");
8559 CBC 6 : get_rule_expr(refassgnexpr, context, showimplicit);
8560 : }
8561 ECB : else
8562 : {
8563 : /* Just an ordinary container fetch, so print subscripts */
8564 CBC 92 : printSubscripts(sbsref, context);
8565 ECB : }
8566 : }
8567 CBC 98 : break;
8568 :
8569 5662 : case T_FuncExpr:
8570 GIC 5662 : get_func_expr((FuncExpr *) node, context, showimplicit);
8571 CBC 5662 : break;
8572 ECB :
8573 CBC 9 : case T_NamedArgExpr:
8574 ECB : {
8575 GIC 9 : NamedArgExpr *na = (NamedArgExpr *) node;
8576 ECB :
8577 CBC 9 : appendStringInfo(buf, "%s => ", quote_identifier(na->name));
8578 9 : get_rule_expr((Node *) na->arg, context, showimplicit);
8579 ECB : }
8580 GIC 9 : break;
8581 :
8582 24672 : case T_OpExpr:
8583 CBC 24672 : get_oper_expr((OpExpr *) node, context);
8584 24672 : break;
8585 :
8586 GIC 9 : case T_DistinctExpr:
8587 : {
8588 9 : DistinctExpr *expr = (DistinctExpr *) node;
8589 9 : List *args = expr->args;
8590 9 : Node *arg1 = (Node *) linitial(args);
8591 9 : Node *arg2 = (Node *) lsecond(args);
8592 :
8593 9 : if (!PRETTY_PAREN(context))
8594 6 : appendStringInfoChar(buf, '(');
8595 9 : get_rule_expr_paren(arg1, context, true, node);
8596 9 : appendStringInfoString(buf, " IS DISTINCT FROM ");
8597 9 : get_rule_expr_paren(arg2, context, true, node);
8598 CBC 9 : if (!PRETTY_PAREN(context))
8599 6 : appendStringInfoChar(buf, ')');
8600 ECB : }
8601 GIC 9 : break;
8602 :
8603 CBC 10 : case T_NullIfExpr:
8604 ECB : {
8605 CBC 10 : NullIfExpr *nullifexpr = (NullIfExpr *) node;
8606 :
8607 10 : appendStringInfoString(buf, "NULLIF(");
8608 GIC 10 : get_rule_expr((Node *) nullifexpr->args, context, true);
8609 CBC 10 : appendStringInfoChar(buf, ')');
8610 : }
8611 10 : break;
8612 ECB :
8613 GIC 1186 : case T_ScalarArrayOpExpr:
8614 : {
8615 CBC 1186 : ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
8616 GIC 1186 : List *args = expr->args;
8617 CBC 1186 : Node *arg1 = (Node *) linitial(args);
8618 1186 : Node *arg2 = (Node *) lsecond(args);
8619 ECB :
8620 CBC 1186 : if (!PRETTY_PAREN(context))
8621 GIC 1180 : appendStringInfoChar(buf, '(');
8622 CBC 1186 : get_rule_expr_paren(arg1, context, true, node);
8623 GIC 1186 : appendStringInfo(buf, " %s %s (",
8624 ECB : generate_operator_name(expr->opno,
8625 : exprType(arg1),
8626 : get_base_element_type(exprType(arg2))),
8627 GIC 1186 : expr->useOr ? "ANY" : "ALL");
8628 CBC 1186 : get_rule_expr_paren(arg2, context, true, node);
8629 ECB :
8630 : /*
8631 : * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
8632 : * a bare sub-SELECT. Since we're here, the sub-SELECT must
8633 : * be meant as a scalar sub-SELECT yielding an array value to
8634 : * be used in ScalarArrayOpExpr; but the grammar will
8635 : * preferentially interpret such a construct as an ANY/ALL
8636 : * SubLink. To prevent misparsing the output that way, insert
8637 : * a dummy coercion (which will be stripped by parse analysis,
8638 : * so no inefficiency is added in dump and reload). This is
8639 : * indeed most likely what the user wrote to get the construct
8640 : * accepted in the first place.
8641 : */
8642 GIC 1186 : if (IsA(arg2, SubLink) &&
8643 CBC 3 : ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
8644 3 : appendStringInfo(buf, "::%s",
8645 ECB : format_type_with_typemod(exprType(arg2),
8646 : exprTypmod(arg2)));
8647 CBC 1186 : appendStringInfoChar(buf, ')');
8648 1186 : if (!PRETTY_PAREN(context))
8649 1180 : appendStringInfoChar(buf, ')');
8650 ECB : }
8651 CBC 1186 : break;
8652 :
8653 4632 : case T_BoolExpr:
8654 ECB : {
8655 CBC 4632 : BoolExpr *expr = (BoolExpr *) node;
8656 GIC 4632 : Node *first_arg = linitial(expr->args);
8657 EUB : ListCell *arg;
8658 :
8659 GIC 4632 : switch (expr->boolop)
8660 : {
8661 3772 : case AND_EXPR:
8662 CBC 3772 : if (!PRETTY_PAREN(context))
8663 GIC 3739 : appendStringInfoChar(buf, '(');
8664 CBC 3772 : get_rule_expr_paren(first_arg, context,
8665 ECB : false, node);
8666 CBC 8553 : for_each_from(arg, expr->args, 1)
8667 : {
8668 4781 : appendStringInfoString(buf, " AND ");
8669 GIC 4781 : get_rule_expr_paren((Node *) lfirst(arg), context,
8670 ECB : false, node);
8671 : }
8672 GIC 3772 : if (!PRETTY_PAREN(context))
8673 3739 : appendStringInfoChar(buf, ')');
8674 3772 : break;
8675 :
8676 737 : case OR_EXPR:
8677 737 : if (!PRETTY_PAREN(context))
8678 CBC 731 : appendStringInfoChar(buf, '(');
8679 737 : get_rule_expr_paren(first_arg, context,
8680 : false, node);
8681 1759 : for_each_from(arg, expr->args, 1)
8682 : {
8683 1022 : appendStringInfoString(buf, " OR ");
8684 GIC 1022 : get_rule_expr_paren((Node *) lfirst(arg), context,
8685 EUB : false, node);
8686 : }
8687 GBC 737 : if (!PRETTY_PAREN(context))
8688 GIC 731 : appendStringInfoChar(buf, ')');
8689 737 : break;
8690 :
8691 123 : case NOT_EXPR:
8692 123 : if (!PRETTY_PAREN(context))
8693 117 : appendStringInfoChar(buf, '(');
8694 123 : appendStringInfoString(buf, "NOT ");
8695 123 : get_rule_expr_paren(first_arg, context,
8696 EUB : false, node);
8697 GBC 123 : if (!PRETTY_PAREN(context))
8698 GIC 117 : appendStringInfoChar(buf, ')');
8699 GBC 123 : break;
8700 :
8701 UBC 0 : default:
8702 0 : elog(ERROR, "unrecognized boolop: %d",
8703 : (int) expr->boolop);
8704 EUB : }
8705 : }
8706 GBC 4632 : break;
8707 :
8708 191 : case T_SubLink:
8709 GIC 191 : get_sublink_expr((SubLink *) node, context);
8710 GBC 191 : break;
8711 :
8712 CBC 230 : case T_SubPlan:
8713 : {
8714 230 : SubPlan *subplan = (SubPlan *) node;
8715 ECB :
8716 : /*
8717 : * We cannot see an already-planned subplan in rule deparsing,
8718 : * only while EXPLAINing a query plan. We don't try to
8719 : * reconstruct the original SQL, just reference the subplan
8720 : * that appears elsewhere in EXPLAIN's result.
8721 : */
8722 GIC 230 : if (subplan->useHashTable)
8723 58 : appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
8724 : else
8725 172 : appendStringInfo(buf, "(%s)", subplan->plan_name);
8726 ECB : }
8727 CBC 230 : break;
8728 ECB :
8729 LBC 0 : case T_AlternativeSubPlan:
8730 ECB : {
8731 LBC 0 : AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
8732 ECB : ListCell *lc;
8733 :
8734 : /*
8735 : * This case cannot be reached in normal usage, since no
8736 : * AlternativeSubPlan can appear either in parsetrees or
8737 : * finished plan trees. We keep it just in case somebody
8738 : * wants to use this code to print planner data structures.
8739 : */
8740 UIC 0 : appendStringInfoString(buf, "(alternatives: ");
8741 LBC 0 : foreach(lc, asplan->subplans)
8742 : {
8743 0 : SubPlan *splan = lfirst_node(SubPlan, lc);
8744 :
8745 0 : if (splan->useHashTable)
8746 UIC 0 : appendStringInfo(buf, "hashed %s", splan->plan_name);
8747 : else
8748 0 : appendStringInfoString(buf, splan->plan_name);
8749 0 : if (lnext(asplan->subplans, lc))
8750 0 : appendStringInfoString(buf, " or ");
8751 : }
8752 0 : appendStringInfoChar(buf, ')');
8753 : }
8754 0 : break;
8755 :
8756 GIC 304 : case T_FieldSelect:
8757 : {
8758 304 : FieldSelect *fselect = (FieldSelect *) node;
8759 304 : Node *arg = (Node *) fselect->arg;
8760 304 : int fno = fselect->fieldnum;
8761 : const char *fieldname;
8762 : bool need_parens;
8763 :
8764 : /*
8765 : * Parenthesize the argument unless it's an SubscriptingRef or
8766 : * another FieldSelect. Note in particular that it would be
8767 ECB : * WRONG to not parenthesize a Var argument; simplicity is not
8768 : * the issue here, having the right number of names is.
8769 : */
8770 CBC 590 : need_parens = !IsA(arg, SubscriptingRef) &&
8771 286 : !IsA(arg, FieldSelect);
8772 304 : if (need_parens)
8773 GIC 286 : appendStringInfoChar(buf, '(');
8774 CBC 304 : get_rule_expr(arg, context, true);
8775 GIC 304 : if (need_parens)
8776 CBC 286 : appendStringInfoChar(buf, ')');
8777 :
8778 ECB : /*
8779 : * Get and print the field name.
8780 : */
8781 CBC 304 : fieldname = get_name_for_var_field((Var *) arg, fno,
8782 ECB : 0, context);
8783 GIC 304 : appendStringInfo(buf, ".%s", quote_identifier(fieldname));
8784 : }
8785 CBC 304 : break;
8786 :
8787 GIC 3 : case T_FieldStore:
8788 : {
8789 CBC 3 : FieldStore *fstore = (FieldStore *) node;
8790 : bool need_parens;
8791 :
8792 : /*
8793 : * There is no good way to represent a FieldStore as real SQL,
8794 : * so decompilation of INSERT or UPDATE statements should
8795 ECB : * always use processIndirection as part of the
8796 : * statement-level syntax. We should only get here when
8797 : * EXPLAIN tries to print the targetlist of a plan resulting
8798 : * from such a statement. The plan case is even harder than
8799 : * ordinary rules would be, because the planner tries to
8800 : * collapse multiple assignments to the same field or subfield
8801 : * into one FieldStore; so we can see a list of target fields
8802 : * not just one, and the arguments could be FieldStores
8803 : * themselves. We don't bother to try to print the target
8804 : * field names; we just print the source arguments, with a
8805 : * ROW() around them if there's more than one. This isn't
8806 : * terribly complete, but it's probably good enough for
8807 : * EXPLAIN's purposes; especially since anything more would be
8808 : * either hopelessly confusing or an even poorer
8809 : * representation of what the plan is actually doing.
8810 : */
8811 GIC 3 : need_parens = (list_length(fstore->newvals) != 1);
8812 3 : if (need_parens)
8813 3 : appendStringInfoString(buf, "ROW(");
8814 3 : get_rule_expr((Node *) fstore->newvals, context, showimplicit);
8815 3 : if (need_parens)
8816 CBC 3 : appendStringInfoChar(buf, ')');
8817 : }
8818 3 : break;
8819 :
8820 1064 : case T_RelabelType:
8821 ECB : {
8822 GIC 1064 : RelabelType *relabel = (RelabelType *) node;
8823 CBC 1064 : Node *arg = (Node *) relabel->arg;
8824 ECB :
8825 GIC 1064 : if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
8826 1001 : !showimplicit)
8827 EUB : {
8828 : /* don't show the implicit cast */
8829 GIC 30 : get_rule_expr_paren(arg, context, false, node);
8830 : }
8831 ECB : else
8832 : {
8833 GIC 1034 : get_coercion_expr(arg, context,
8834 : relabel->resulttype,
8835 : relabel->resulttypmod,
8836 : node);
8837 ECB : }
8838 : }
8839 CBC 1064 : break;
8840 :
8841 262 : case T_CoerceViaIO:
8842 ECB : {
8843 GIC 262 : CoerceViaIO *iocoerce = (CoerceViaIO *) node;
8844 CBC 262 : Node *arg = (Node *) iocoerce->arg;
8845 ECB :
8846 GIC 262 : if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
8847 6 : !showimplicit)
8848 ECB : {
8849 : /* don't show the implicit cast */
8850 GIC 6 : get_rule_expr_paren(arg, context, false, node);
8851 : }
8852 ECB : else
8853 : {
8854 GIC 256 : get_coercion_expr(arg, context,
8855 : iocoerce->resulttype,
8856 : -1,
8857 ECB : node);
8858 : }
8859 : }
8860 GIC 262 : break;
8861 ECB :
8862 CBC 15 : case T_ArrayCoerceExpr:
8863 : {
8864 15 : ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
8865 15 : Node *arg = (Node *) acoerce->arg;
8866 ECB :
8867 CBC 15 : if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
8868 GIC 15 : !showimplicit)
8869 ECB : {
8870 : /* don't show the implicit cast */
8871 UIC 0 : get_rule_expr_paren(arg, context, false, node);
8872 ECB : }
8873 : else
8874 : {
8875 GIC 15 : get_coercion_expr(arg, context,
8876 ECB : acoerce->resulttype,
8877 : acoerce->resulttypmod,
8878 : node);
8879 : }
8880 : }
8881 CBC 15 : break;
8882 :
8883 45 : case T_ConvertRowtypeExpr:
8884 ECB : {
8885 GIC 45 : ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
8886 CBC 45 : Node *arg = (Node *) convert->arg;
8887 :
8888 45 : if (convert->convertformat == COERCE_IMPLICIT_CAST &&
8889 42 : !showimplicit)
8890 : {
8891 ECB : /* don't show the implicit cast */
8892 GIC 12 : get_rule_expr_paren(arg, context, false, node);
8893 : }
8894 : else
8895 : {
8896 33 : get_coercion_expr(arg, context,
8897 : convert->resulttype, -1,
8898 : node);
8899 : }
8900 : }
8901 45 : break;
8902 :
8903 48 : case T_CollateExpr:
8904 : {
8905 CBC 48 : CollateExpr *collate = (CollateExpr *) node;
8906 GIC 48 : Node *arg = (Node *) collate->arg;
8907 ECB :
8908 GIC 48 : if (!PRETTY_PAREN(context))
8909 CBC 48 : appendStringInfoChar(buf, '(');
8910 48 : get_rule_expr_paren(arg, context, showimplicit, node);
8911 GIC 48 : appendStringInfo(buf, " COLLATE %s",
8912 ECB : generate_collation_name(collate->collOid));
8913 GIC 48 : if (!PRETTY_PAREN(context))
8914 48 : appendStringInfoChar(buf, ')');
8915 : }
8916 CBC 48 : break;
8917 ECB :
8918 CBC 153 : case T_CaseExpr:
8919 : {
8920 153 : CaseExpr *caseexpr = (CaseExpr *) node;
8921 ECB : ListCell *temp;
8922 :
8923 GIC 153 : appendContextKeyword(context, "CASE",
8924 ECB : 0, PRETTYINDENT_VAR, 0);
8925 CBC 153 : if (caseexpr->arg)
8926 ECB : {
8927 GIC 51 : appendStringInfoChar(buf, ' ');
8928 CBC 51 : get_rule_expr((Node *) caseexpr->arg, context, true);
8929 ECB : }
8930 CBC 632 : foreach(temp, caseexpr->args)
8931 ECB : {
8932 GIC 479 : CaseWhen *when = (CaseWhen *) lfirst(temp);
8933 479 : Node *w = (Node *) when->expr;
8934 ECB :
8935 GIC 479 : if (caseexpr->arg)
8936 EUB : {
8937 : /*
8938 : * The parser should have produced WHEN clauses of the
8939 : * form "CaseTestExpr = RHS", possibly with an
8940 : * implicit coercion inserted above the CaseTestExpr.
8941 : * For accurate decompilation of rules it's essential
8942 : * that we show just the RHS. However in an
8943 : * expression that's been through the optimizer, the
8944 : * WHEN clause could be almost anything (since the
8945 : * equality operator could have been expanded into an
8946 : * inline function). If we don't recognize the form
8947 : * of the WHEN clause, just punt and display it as-is.
8948 : */
8949 CBC 197 : if (IsA(w, OpExpr))
8950 : {
8951 197 : List *args = ((OpExpr *) w)->args;
8952 :
8953 197 : if (list_length(args) == 2 &&
8954 197 : IsA(strip_implicit_coercions(linitial(args)),
8955 ECB : CaseTestExpr))
8956 GIC 197 : w = (Node *) lsecond(args);
8957 : }
8958 : }
8959 :
8960 479 : if (!PRETTY_INDENT(context))
8961 41 : appendStringInfoChar(buf, ' ');
8962 CBC 479 : appendContextKeyword(context, "WHEN ",
8963 ECB : 0, 0, 0);
8964 GIC 479 : get_rule_expr(w, context, false);
8965 479 : appendStringInfoString(buf, " THEN ");
8966 CBC 479 : get_rule_expr((Node *) when->result, context, true);
8967 : }
8968 153 : if (!PRETTY_INDENT(context))
8969 GIC 36 : appendStringInfoChar(buf, ' ');
8970 CBC 153 : appendContextKeyword(context, "ELSE ",
8971 ECB : 0, 0, 0);
8972 GIC 153 : get_rule_expr((Node *) caseexpr->defresult, context, true);
8973 153 : if (!PRETTY_INDENT(context))
8974 36 : appendStringInfoChar(buf, ' ');
8975 153 : appendContextKeyword(context, "END",
8976 : -PRETTYINDENT_VAR, 0, 0);
8977 : }
8978 153 : break;
8979 :
8980 UIC 0 : case T_CaseTestExpr:
8981 ECB : {
8982 : /*
8983 : * Normally we should never get here, since for expressions
8984 : * that can contain this node type we attempt to avoid
8985 : * recursing to it. But in an optimized expression we might
8986 : * be unable to avoid that (see comments for CaseExpr). If we
8987 : * do see one, print it as CASE_TEST_EXPR.
8988 : */
8989 UIC 0 : appendStringInfoString(buf, "CASE_TEST_EXPR");
8990 : }
8991 LBC 0 : break;
8992 ECB :
8993 CBC 181 : case T_ArrayExpr:
8994 ECB : {
8995 GIC 181 : ArrayExpr *arrayexpr = (ArrayExpr *) node;
8996 ECB :
8997 GIC 181 : appendStringInfoString(buf, "ARRAY[");
8998 CBC 181 : get_rule_expr((Node *) arrayexpr->elements, context, true);
8999 181 : appendStringInfoChar(buf, ']');
9000 :
9001 ECB : /*
9002 : * If the array isn't empty, we assume its elements are
9003 : * coerced to the desired type. If it's empty, though, we
9004 : * need an explicit coercion to the array type.
9005 : */
9006 CBC 181 : if (arrayexpr->elements == NIL)
9007 GIC 3 : appendStringInfo(buf, "::%s",
9008 ECB : format_type_with_typemod(arrayexpr->array_typeid, -1));
9009 : }
9010 CBC 181 : break;
9011 :
9012 GBC 90 : case T_RowExpr:
9013 : {
9014 90 : RowExpr *rowexpr = (RowExpr *) node;
9015 90 : TupleDesc tupdesc = NULL;
9016 EUB : ListCell *arg;
9017 : int i;
9018 : char *sep;
9019 :
9020 : /*
9021 ECB : * If it's a named type and not RECORD, we may have to skip
9022 : * dropped columns and/or claim there are NULLs for added
9023 : * columns.
9024 : */
9025 CBC 90 : if (rowexpr->row_typeid != RECORDOID)
9026 : {
9027 GIC 24 : tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
9028 CBC 24 : Assert(list_length(rowexpr->args) <= tupdesc->natts);
9029 : }
9030 ECB :
9031 : /*
9032 : * SQL99 allows "ROW" to be omitted when there is more than
9033 : * one column, but for simplicity we always print it.
9034 : */
9035 GIC 90 : appendStringInfoString(buf, "ROW(");
9036 90 : sep = "";
9037 90 : i = 0;
9038 258 : foreach(arg, rowexpr->args)
9039 : {
9040 CBC 168 : Node *e = (Node *) lfirst(arg);
9041 ECB :
9042 GIC 168 : if (tupdesc == NULL ||
9043 45 : !TupleDescAttr(tupdesc, i)->attisdropped)
9044 : {
9045 168 : appendStringInfoString(buf, sep);
9046 : /* Whole-row Vars need special treatment here */
9047 168 : get_rule_expr_toplevel(e, context, true);
9048 168 : sep = ", ";
9049 : }
9050 CBC 168 : i++;
9051 ECB : }
9052 CBC 90 : if (tupdesc != NULL)
9053 ECB : {
9054 CBC 24 : while (i < tupdesc->natts)
9055 ECB : {
9056 UIC 0 : if (!TupleDescAttr(tupdesc, i)->attisdropped)
9057 ECB : {
9058 UIC 0 : appendStringInfoString(buf, sep);
9059 LBC 0 : appendStringInfoString(buf, "NULL");
9060 UIC 0 : sep = ", ";
9061 ECB : }
9062 UIC 0 : i++;
9063 ECB : }
9064 :
9065 CBC 24 : ReleaseTupleDesc(tupdesc);
9066 : }
9067 90 : appendStringInfoChar(buf, ')');
9068 GIC 90 : if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
9069 CBC 18 : appendStringInfo(buf, "::%s",
9070 : format_type_with_typemod(rowexpr->row_typeid, -1));
9071 ECB : }
9072 GIC 90 : break;
9073 ECB :
9074 GIC 33 : case T_RowCompareExpr:
9075 ECB : {
9076 CBC 33 : RowCompareExpr *rcexpr = (RowCompareExpr *) node;
9077 ECB :
9078 : /*
9079 : * SQL99 allows "ROW" to be omitted when there is more than
9080 : * one column, but for simplicity we always print it. Within
9081 : * a ROW expression, whole-row Vars need special treatment, so
9082 : * use get_rule_list_toplevel.
9083 : */
9084 GIC 33 : appendStringInfoString(buf, "(ROW(");
9085 CBC 33 : get_rule_list_toplevel(rcexpr->largs, context, true);
9086 :
9087 ECB : /*
9088 : * We assume that the name of the first-column operator will
9089 : * do for all the rest too. This is definitely open to
9090 : * failure, eg if some but not all operators were renamed
9091 : * since the construct was parsed, but there seems no way to
9092 : * be perfect.
9093 : */
9094 GIC 33 : appendStringInfo(buf, ") %s ROW(",
9095 CBC 33 : generate_operator_name(linitial_oid(rcexpr->opnos),
9096 GIC 33 : exprType(linitial(rcexpr->largs)),
9097 CBC 33 : exprType(linitial(rcexpr->rargs))));
9098 33 : get_rule_list_toplevel(rcexpr->rargs, context, true);
9099 33 : appendStringInfoString(buf, "))");
9100 ECB : }
9101 CBC 33 : break;
9102 ECB :
9103 CBC 489 : case T_CoalesceExpr:
9104 ECB : {
9105 CBC 489 : CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
9106 ECB :
9107 CBC 489 : appendStringInfoString(buf, "COALESCE(");
9108 489 : get_rule_expr((Node *) coalesceexpr->args, context, true);
9109 489 : appendStringInfoChar(buf, ')');
9110 ECB : }
9111 CBC 489 : break;
9112 ECB :
9113 CBC 18 : case T_MinMaxExpr:
9114 ECB : {
9115 CBC 18 : MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
9116 ECB :
9117 CBC 18 : switch (minmaxexpr->op)
9118 EUB : {
9119 GBC 3 : case IS_GREATEST:
9120 GIC 3 : appendStringInfoString(buf, "GREATEST(");
9121 CBC 3 : break;
9122 GIC 15 : case IS_LEAST:
9123 CBC 15 : appendStringInfoString(buf, "LEAST(");
9124 GBC 15 : break;
9125 : }
9126 CBC 18 : get_rule_expr((Node *) minmaxexpr->args, context, true);
9127 GIC 18 : appendStringInfoChar(buf, ')');
9128 ECB : }
9129 GIC 18 : break;
9130 ECB :
9131 GIC 72 : case T_XmlExpr:
9132 ECB : {
9133 CBC 72 : XmlExpr *xexpr = (XmlExpr *) node;
9134 72 : bool needcomma = false;
9135 ECB : ListCell *arg;
9136 : ListCell *narg;
9137 : Const *con;
9138 EUB :
9139 GIC 72 : switch (xexpr->op)
9140 ECB : {
9141 CBC 8 : case IS_XMLCONCAT:
9142 GIC 8 : appendStringInfoString(buf, "XMLCONCAT(");
9143 8 : break;
9144 16 : case IS_XMLELEMENT:
9145 CBC 16 : appendStringInfoString(buf, "XMLELEMENT(");
9146 GIC 16 : break;
9147 CBC 8 : case IS_XMLFOREST:
9148 8 : appendStringInfoString(buf, "XMLFOREST(");
9149 GIC 8 : break;
9150 CBC 8 : case IS_XMLPARSE:
9151 GBC 8 : appendStringInfoString(buf, "XMLPARSE(");
9152 8 : break;
9153 GIC 8 : case IS_XMLPI:
9154 GBC 8 : appendStringInfoString(buf, "XMLPI(");
9155 8 : break;
9156 8 : case IS_XMLROOT:
9157 GIC 8 : appendStringInfoString(buf, "XMLROOT(");
9158 GBC 8 : break;
9159 16 : case IS_XMLSERIALIZE:
9160 16 : appendStringInfoString(buf, "XMLSERIALIZE(");
9161 GIC 16 : break;
9162 UIC 0 : case IS_DOCUMENT:
9163 LBC 0 : break;
9164 EUB : }
9165 GBC 72 : if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
9166 EUB : {
9167 GIC 24 : if (xexpr->xmloption == XMLOPTION_DOCUMENT)
9168 UIC 0 : appendStringInfoString(buf, "DOCUMENT ");
9169 ECB : else
9170 CBC 24 : appendStringInfoString(buf, "CONTENT ");
9171 : }
9172 GIC 72 : if (xexpr->name)
9173 ECB : {
9174 GBC 24 : appendStringInfo(buf, "NAME %s",
9175 GIC 24 : quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
9176 CBC 24 : needcomma = true;
9177 : }
9178 72 : if (xexpr->named_args)
9179 : {
9180 16 : if (xexpr->op != IS_XMLFOREST)
9181 : {
9182 8 : if (needcomma)
9183 GIC 8 : appendStringInfoString(buf, ", ");
9184 CBC 8 : appendStringInfoString(buf, "XMLATTRIBUTES(");
9185 8 : needcomma = false;
9186 ECB : }
9187 GIC 56 : forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
9188 : {
9189 40 : Node *e = (Node *) lfirst(arg);
9190 40 : char *argname = strVal(lfirst(narg));
9191 :
9192 40 : if (needcomma)
9193 24 : appendStringInfoString(buf, ", ");
9194 CBC 40 : get_rule_expr((Node *) e, context, true);
9195 40 : appendStringInfo(buf, " AS %s",
9196 GIC 40 : quote_identifier(map_xml_name_to_sql_identifier(argname)));
9197 CBC 40 : needcomma = true;
9198 : }
9199 16 : if (xexpr->op != IS_XMLFOREST)
9200 8 : appendStringInfoChar(buf, ')');
9201 ECB : }
9202 CBC 72 : if (xexpr->args)
9203 ECB : {
9204 CBC 64 : if (needcomma)
9205 GBC 24 : appendStringInfoString(buf, ", ");
9206 64 : switch (xexpr->op)
9207 : {
9208 GIC 48 : case IS_XMLCONCAT:
9209 : case IS_XMLELEMENT:
9210 : case IS_XMLFOREST:
9211 : case IS_XMLPI:
9212 ECB : case IS_XMLSERIALIZE:
9213 : /* no extra decoration needed */
9214 CBC 48 : get_rule_expr((Node *) xexpr->args, context, true);
9215 48 : break;
9216 8 : case IS_XMLPARSE:
9217 8 : Assert(list_length(xexpr->args) == 2);
9218 ECB :
9219 CBC 8 : get_rule_expr((Node *) linitial(xexpr->args),
9220 EUB : context, true);
9221 :
9222 GIC 8 : con = lsecond_node(Const, xexpr->args);
9223 8 : Assert(!con->constisnull);
9224 8 : if (DatumGetBool(con->constvalue))
9225 LBC 0 : appendStringInfoString(buf,
9226 ECB : " PRESERVE WHITESPACE");
9227 : else
9228 CBC 8 : appendStringInfoString(buf,
9229 : " STRIP WHITESPACE");
9230 8 : break;
9231 GIC 8 : case IS_XMLROOT:
9232 CBC 8 : Assert(list_length(xexpr->args) == 3);
9233 :
9234 8 : get_rule_expr((Node *) linitial(xexpr->args),
9235 ECB : context, true);
9236 :
9237 CBC 8 : appendStringInfoString(buf, ", VERSION ");
9238 GIC 8 : con = (Const *) lsecond(xexpr->args);
9239 CBC 8 : if (IsA(con, Const) &&
9240 8 : con->constisnull)
9241 8 : appendStringInfoString(buf, "NO VALUE");
9242 ECB : else
9243 LBC 0 : get_rule_expr((Node *) con, context, false);
9244 ECB :
9245 GBC 8 : con = lthird_node(Const, xexpr->args);
9246 8 : if (con->constisnull)
9247 EUB : /* suppress STANDALONE NO VALUE */ ;
9248 : else
9249 : {
9250 GBC 8 : switch (DatumGetInt32(con->constvalue))
9251 ECB : {
9252 CBC 8 : case XML_STANDALONE_YES:
9253 8 : appendStringInfoString(buf,
9254 ECB : ", STANDALONE YES");
9255 CBC 8 : break;
9256 LBC 0 : case XML_STANDALONE_NO:
9257 UBC 0 : appendStringInfoString(buf,
9258 EUB : ", STANDALONE NO");
9259 UIC 0 : break;
9260 0 : case XML_STANDALONE_NO_VALUE:
9261 LBC 0 : appendStringInfoString(buf,
9262 ECB : ", STANDALONE NO VALUE");
9263 UIC 0 : break;
9264 LBC 0 : default:
9265 UIC 0 : break;
9266 ECB : }
9267 : }
9268 CBC 8 : break;
9269 LBC 0 : case IS_DOCUMENT:
9270 UIC 0 : get_rule_expr_paren((Node *) xexpr->args, context, false, node);
9271 LBC 0 : break;
9272 ECB : }
9273 : }
9274 GIC 72 : if (xexpr->op == IS_XMLSERIALIZE)
9275 CBC 16 : appendStringInfo(buf, " AS %s",
9276 : format_type_with_typemod(xexpr->type,
9277 : xexpr->typmod));
9278 GIC 72 : if (xexpr->op == IS_DOCUMENT)
9279 LBC 0 : appendStringInfoString(buf, " IS DOCUMENT");
9280 : else
9281 GIC 72 : appendStringInfoChar(buf, ')');
9282 : }
9283 72 : break;
9284 :
9285 CBC 897 : case T_NullTest:
9286 : {
9287 897 : NullTest *ntest = (NullTest *) node;
9288 ECB :
9289 CBC 897 : if (!PRETTY_PAREN(context))
9290 GIC 873 : appendStringInfoChar(buf, '(');
9291 CBC 897 : get_rule_expr_paren((Node *) ntest->arg, context, true, node);
9292 ECB :
9293 : /*
9294 : * For scalar inputs, we prefer to print as IS [NOT] NULL,
9295 : * which is shorter and traditional. If it's a rowtype input
9296 : * but we're applying a scalar test, must print IS [NOT]
9297 : * DISTINCT FROM NULL to be semantically correct.
9298 : */
9299 CBC 897 : if (ntest->argisrow ||
9300 888 : !type_is_rowtype(exprType((Node *) ntest->arg)))
9301 ECB : {
9302 GIC 1776 : switch (ntest->nulltesttype)
9303 EUB : {
9304 GIC 264 : case IS_NULL:
9305 264 : appendStringInfoString(buf, " IS NULL");
9306 CBC 264 : break;
9307 GIC 624 : case IS_NOT_NULL:
9308 GBC 624 : appendStringInfoString(buf, " IS NOT NULL");
9309 GIC 624 : break;
9310 UBC 0 : default:
9311 UIC 0 : elog(ERROR, "unrecognized nulltesttype: %d",
9312 : (int) ntest->nulltesttype);
9313 : }
9314 : }
9315 : else
9316 EUB : {
9317 GBC 9 : switch (ntest->nulltesttype)
9318 EUB : {
9319 GIC 3 : case IS_NULL:
9320 GBC 3 : appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL");
9321 GIC 3 : break;
9322 GBC 6 : case IS_NOT_NULL:
9323 GIC 6 : appendStringInfoString(buf, " IS DISTINCT FROM NULL");
9324 CBC 6 : break;
9325 UIC 0 : default:
9326 LBC 0 : elog(ERROR, "unrecognized nulltesttype: %d",
9327 : (int) ntest->nulltesttype);
9328 : }
9329 : }
9330 GIC 897 : if (!PRETTY_PAREN(context))
9331 873 : appendStringInfoChar(buf, ')');
9332 : }
9333 897 : break;
9334 ECB :
9335 CBC 36 : case T_BooleanTest:
9336 : {
9337 GIC 36 : BooleanTest *btest = (BooleanTest *) node;
9338 :
9339 36 : if (!PRETTY_PAREN(context))
9340 36 : appendStringInfoChar(buf, '(');
9341 CBC 36 : get_rule_expr_paren((Node *) btest->arg, context, false, node);
9342 36 : switch (btest->booltesttype)
9343 EUB : {
9344 GIC 6 : case IS_TRUE:
9345 GBC 6 : appendStringInfoString(buf, " IS TRUE");
9346 GIC 6 : break;
9347 CBC 12 : case IS_NOT_TRUE:
9348 GBC 12 : appendStringInfoString(buf, " IS NOT TRUE");
9349 CBC 12 : break;
9350 UIC 0 : case IS_FALSE:
9351 LBC 0 : appendStringInfoString(buf, " IS FALSE");
9352 UBC 0 : break;
9353 UIC 0 : case IS_NOT_FALSE:
9354 LBC 0 : appendStringInfoString(buf, " IS NOT FALSE");
9355 UIC 0 : break;
9356 CBC 9 : case IS_UNKNOWN:
9357 9 : appendStringInfoString(buf, " IS UNKNOWN");
9358 GIC 9 : break;
9359 9 : case IS_NOT_UNKNOWN:
9360 9 : appendStringInfoString(buf, " IS NOT UNKNOWN");
9361 CBC 9 : break;
9362 UIC 0 : default:
9363 LBC 0 : elog(ERROR, "unrecognized booltesttype: %d",
9364 ECB : (int) btest->booltesttype);
9365 : }
9366 CBC 36 : if (!PRETTY_PAREN(context))
9367 GIC 36 : appendStringInfoChar(buf, ')');
9368 : }
9369 CBC 36 : break;
9370 :
9371 16 : case T_CoerceToDomain:
9372 : {
9373 16 : CoerceToDomain *ctest = (CoerceToDomain *) node;
9374 GIC 16 : Node *arg = (Node *) ctest->arg;
9375 :
9376 16 : if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
9377 CBC 11 : !showimplicit)
9378 : {
9379 ECB : /* don't show the implicit cast */
9380 CBC 11 : get_rule_expr(arg, context, false);
9381 : }
9382 : else
9383 ECB : {
9384 GIC 5 : get_coercion_expr(arg, context,
9385 ECB : ctest->resulttype,
9386 : ctest->resulttypmod,
9387 : node);
9388 : }
9389 : }
9390 CBC 16 : break;
9391 :
9392 140 : case T_CoerceToDomainValue:
9393 GIC 140 : appendStringInfoString(buf, "VALUE");
9394 CBC 140 : break;
9395 ECB :
9396 GIC 32 : case T_SetToDefault:
9397 CBC 32 : appendStringInfoString(buf, "DEFAULT");
9398 32 : break;
9399 ECB :
9400 GIC 9 : case T_CurrentOfExpr:
9401 ECB : {
9402 GIC 9 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
9403 ECB :
9404 CBC 9 : if (cexpr->cursor_name)
9405 9 : appendStringInfo(buf, "CURRENT OF %s",
9406 GIC 9 : quote_identifier(cexpr->cursor_name));
9407 : else
9408 LBC 0 : appendStringInfo(buf, "CURRENT OF $%d",
9409 ECB : cexpr->cursor_param);
9410 : }
9411 CBC 9 : break;
9412 ECB :
9413 UIC 0 : case T_NextValueExpr:
9414 : {
9415 0 : NextValueExpr *nvexpr = (NextValueExpr *) node;
9416 :
9417 ECB : /*
9418 : * This isn't exactly nextval(), but that seems close enough
9419 : * for EXPLAIN's purposes.
9420 : */
9421 UIC 0 : appendStringInfoString(buf, "nextval(");
9422 UBC 0 : simple_quote_literal(buf,
9423 0 : generate_relation_name(nvexpr->seqid,
9424 : NIL));
9425 UIC 0 : appendStringInfoChar(buf, ')');
9426 : }
9427 0 : break;
9428 ECB :
9429 GIC 12 : case T_InferenceElem:
9430 ECB : {
9431 GIC 12 : InferenceElem *iexpr = (InferenceElem *) node;
9432 ECB : bool save_varprefix;
9433 : bool need_parens;
9434 :
9435 : /*
9436 : * InferenceElem can only refer to target relation, so a
9437 : * prefix is not useful, and indeed would cause parse errors.
9438 : */
9439 CBC 12 : save_varprefix = context->varprefix;
9440 12 : context->varprefix = false;
9441 ECB :
9442 : /*
9443 : * Parenthesize the element unless it's a simple Var or a bare
9444 : * function call. Follows pg_get_indexdef_worker().
9445 : */
9446 GIC 12 : need_parens = !IsA(iexpr->expr, Var);
9447 CBC 12 : if (IsA(iexpr->expr, FuncExpr) &&
9448 LBC 0 : ((FuncExpr *) iexpr->expr)->funcformat ==
9449 : COERCE_EXPLICIT_CALL)
9450 0 : need_parens = false;
9451 :
9452 CBC 12 : if (need_parens)
9453 UIC 0 : appendStringInfoChar(buf, '(');
9454 GIC 12 : get_rule_expr((Node *) iexpr->expr,
9455 : context, false);
9456 CBC 12 : if (need_parens)
9457 UIC 0 : appendStringInfoChar(buf, ')');
9458 ECB :
9459 CBC 12 : context->varprefix = save_varprefix;
9460 ECB :
9461 CBC 12 : if (iexpr->infercollid)
9462 6 : appendStringInfo(buf, " COLLATE %s",
9463 ECB : generate_collation_name(iexpr->infercollid));
9464 :
9465 : /* Add the operator class name, if not default */
9466 CBC 12 : if (iexpr->inferopclass)
9467 ECB : {
9468 CBC 6 : Oid inferopclass = iexpr->inferopclass;
9469 GIC 6 : Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
9470 :
9471 CBC 6 : get_opclass_name(inferopclass, inferopcinputtype, buf);
9472 ECB : }
9473 : }
9474 CBC 12 : break;
9475 ECB :
9476 GIC 1715 : case T_PartitionBoundSpec:
9477 ECB : {
9478 GIC 1715 : PartitionBoundSpec *spec = (PartitionBoundSpec *) node;
9479 ECB : ListCell *cell;
9480 : char *sep;
9481 :
9482 GIC 1715 : if (spec->is_default)
9483 : {
9484 CBC 76 : appendStringInfoString(buf, "DEFAULT");
9485 76 : break;
9486 : }
9487 ECB :
9488 CBC 1639 : switch (spec->strategy)
9489 ECB : {
9490 GIC 91 : case PARTITION_STRATEGY_HASH:
9491 91 : Assert(spec->modulus > 0 && spec->remainder >= 0);
9492 CBC 91 : Assert(spec->modulus > spec->remainder);
9493 :
9494 91 : appendStringInfoString(buf, "FOR VALUES");
9495 91 : appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
9496 ECB : spec->modulus, spec->remainder);
9497 GIC 91 : break;
9498 EUB :
9499 GBC 537 : case PARTITION_STRATEGY_LIST:
9500 GIC 537 : Assert(spec->listdatums != NIL);
9501 :
9502 537 : appendStringInfoString(buf, "FOR VALUES IN (");
9503 537 : sep = "";
9504 1483 : foreach(cell, spec->listdatums)
9505 : {
9506 946 : Const *val = lfirst_node(Const, cell);
9507 :
9508 946 : appendStringInfoString(buf, sep);
9509 946 : get_const_expr(val, context, -1);
9510 946 : sep = ", ";
9511 : }
9512 :
9513 537 : appendStringInfoChar(buf, ')');
9514 537 : break;
9515 :
9516 CBC 1011 : case PARTITION_STRATEGY_RANGE:
9517 GIC 1011 : Assert(spec->lowerdatums != NIL &&
9518 : spec->upperdatums != NIL &&
9519 ECB : list_length(spec->lowerdatums) ==
9520 : list_length(spec->upperdatums));
9521 :
9522 CBC 1011 : appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
9523 ECB : get_range_partbound_string(spec->lowerdatums),
9524 : get_range_partbound_string(spec->upperdatums));
9525 GIC 1011 : break;
9526 :
9527 UIC 0 : default:
9528 0 : elog(ERROR, "unrecognized partition strategy: %d",
9529 : (int) spec->strategy);
9530 : break;
9531 : }
9532 : }
9533 GIC 1639 : break;
9534 ECB :
9535 GNC 24 : case T_JsonValueExpr:
9536 : {
9537 24 : JsonValueExpr *jve = (JsonValueExpr *) node;
9538 :
9539 24 : get_rule_expr((Node *) jve->raw_expr, context, false);
9540 24 : get_json_format(jve->format, context->buf);
9541 : }
9542 24 : break;
9543 :
9544 36 : case T_JsonConstructorExpr:
9545 36 : get_json_constructor((JsonConstructorExpr *) node, context, false);
9546 36 : break;
9547 :
9548 24 : case T_JsonIsPredicate:
9549 : {
9550 24 : JsonIsPredicate *pred = (JsonIsPredicate *) node;
9551 :
9552 24 : if (!PRETTY_PAREN(context))
9553 12 : appendStringInfoChar(context->buf, '(');
9554 :
9555 24 : get_rule_expr_paren(pred->expr, context, true, node);
9556 :
9557 24 : appendStringInfoString(context->buf, " IS JSON");
9558 :
9559 : /* TODO: handle FORMAT clause */
9560 :
9561 24 : switch (pred->item_type)
9562 : {
9563 6 : case JS_TYPE_SCALAR:
9564 6 : appendStringInfoString(context->buf, " SCALAR");
9565 6 : break;
9566 6 : case JS_TYPE_ARRAY:
9567 6 : appendStringInfoString(context->buf, " ARRAY");
9568 6 : break;
9569 6 : case JS_TYPE_OBJECT:
9570 6 : appendStringInfoString(context->buf, " OBJECT");
9571 6 : break;
9572 6 : default:
9573 6 : break;
9574 : }
9575 :
9576 24 : if (pred->unique_keys)
9577 6 : appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
9578 :
9579 24 : if (!PRETTY_PAREN(context))
9580 12 : appendStringInfoChar(context->buf, ')');
9581 : }
9582 24 : break;
9583 :
9584 GIC 940 : case T_List:
9585 : {
9586 : char *sep;
9587 : ListCell *l;
9588 :
9589 CBC 940 : sep = "";
9590 2658 : foreach(l, (List *) node)
9591 : {
9592 1718 : appendStringInfoString(buf, sep);
9593 GIC 1718 : get_rule_expr((Node *) lfirst(l), context, showimplicit);
9594 CBC 1718 : sep = ", ";
9595 ECB : }
9596 : }
9597 GIC 940 : break;
9598 ECB :
9599 GIC 12 : case T_TableFunc:
9600 12 : get_tablefunc((TableFunc *) node, context, showimplicit);
9601 12 : break;
9602 :
9603 UIC 0 : default:
9604 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
9605 : break;
9606 : }
9607 : }
9608 :
9609 : /*
9610 : * get_rule_expr_toplevel - Parse back a toplevel expression
9611 : *
9612 : * Same as get_rule_expr(), except that if the expr is just a Var, we pass
9613 ECB : * istoplevel = true not false to get_variable(). This causes whole-row Vars
9614 : * to get printed with decoration that will prevent expansion of "*".
9615 : * We need to use this in contexts such as ROW() and VALUES(), where the
9616 : * parser would expand "foo.*" appearing at top level. (In principle we'd
9617 : * use this in get_target_list() too, but that has additional worries about
9618 : * whether to print AS, so it needs to invoke get_variable() directly anyway.)
9619 : */
9620 : static void
9621 GIC 1351 : get_rule_expr_toplevel(Node *node, deparse_context *context,
9622 ECB : bool showimplicit)
9623 : {
9624 CBC 1351 : if (node && IsA(node, Var))
9625 514 : (void) get_variable((Var *) node, 0, true, context);
9626 : else
9627 GIC 837 : get_rule_expr(node, context, showimplicit);
9628 1351 : }
9629 ECB :
9630 : /*
9631 : * get_rule_list_toplevel - Parse back a list of toplevel expressions
9632 : *
9633 : * Apply get_rule_expr_toplevel() to each element of a List.
9634 : *
9635 : * This adds commas between the expressions, but caller is responsible
9636 : * for printing surrounding decoration.
9637 : */
9638 : static void
9639 GBC 186 : get_rule_list_toplevel(List *lst, deparse_context *context,
9640 ECB : bool showimplicit)
9641 : {
9642 : const char *sep;
9643 : ListCell *lc;
9644 :
9645 CBC 186 : sep = "";
9646 658 : foreach(lc, lst)
9647 : {
9648 GIC 472 : Node *e = (Node *) lfirst(lc);
9649 :
9650 472 : appendStringInfoString(context->buf, sep);
9651 CBC 472 : get_rule_expr_toplevel(e, context, showimplicit);
9652 472 : sep = ", ";
9653 ECB : }
9654 GIC 186 : }
9655 ECB :
9656 : /*
9657 : * get_rule_expr_funccall - Parse back a function-call expression
9658 : *
9659 : * Same as get_rule_expr(), except that we guarantee that the output will
9660 : * look like a function call, or like one of the things the grammar treats as
9661 : * equivalent to a function call (see the func_expr_windowless production).
9662 : * This is needed in places where the grammar uses func_expr_windowless and
9663 : * you can't substitute a parenthesized a_expr. If what we have isn't going
9664 : * to look like a function call, wrap it in a dummy CAST() expression, which
9665 : * will satisfy the grammar --- and, indeed, is likely what the user wrote to
9666 : * produce such a thing.
9667 : */
9668 : static void
9669 CBC 276 : get_rule_expr_funccall(Node *node, deparse_context *context,
9670 ECB : bool showimplicit)
9671 : {
9672 GIC 276 : if (looks_like_function(node))
9673 270 : get_rule_expr(node, context, showimplicit);
9674 ECB : else
9675 : {
9676 GIC 6 : StringInfo buf = context->buf;
9677 ECB :
9678 CBC 6 : appendStringInfoString(buf, "CAST(");
9679 : /* no point in showing any top-level implicit cast */
9680 GIC 6 : get_rule_expr(node, context, false);
9681 6 : appendStringInfo(buf, " AS %s)",
9682 ECB : format_type_with_typemod(exprType(node),
9683 : exprTypmod(node)));
9684 : }
9685 GIC 276 : }
9686 :
9687 ECB : /*
9688 : * Helper function to identify node types that satisfy func_expr_windowless.
9689 : * If in doubt, "false" is always a safe answer.
9690 : */
9691 : static bool
9692 GIC 818 : looks_like_function(Node *node)
9693 ECB : {
9694 GIC 818 : if (node == NULL)
9695 LBC 0 : return false; /* probably shouldn't happen */
9696 CBC 818 : switch (nodeTag(node))
9697 ECB : {
9698 GIC 341 : case T_FuncExpr:
9699 : /* OK, unless it's going to deparse as a cast */
9700 401 : return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
9701 60 : ((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
9702 3 : case T_NullIfExpr:
9703 ECB : case T_CoalesceExpr:
9704 : case T_MinMaxExpr:
9705 : case T_XmlExpr:
9706 : /* these are all accepted by func_expr_common_subexpr */
9707 GIC 3 : return true;
9708 474 : default:
9709 474 : break;
9710 : }
9711 474 : return false;
9712 : }
9713 :
9714 :
9715 : /*
9716 : * get_oper_expr - Parse back an OpExpr node
9717 ECB : */
9718 : static void
9719 CBC 24672 : get_oper_expr(OpExpr *expr, deparse_context *context)
9720 : {
9721 24672 : StringInfo buf = context->buf;
9722 GIC 24672 : Oid opno = expr->opno;
9723 24672 : List *args = expr->args;
9724 :
9725 24672 : if (!PRETTY_PAREN(context))
9726 23770 : appendStringInfoChar(buf, '(');
9727 24672 : if (list_length(args) == 2)
9728 ECB : {
9729 : /* binary operator */
9730 GIC 24657 : Node *arg1 = (Node *) linitial(args);
9731 CBC 24657 : Node *arg2 = (Node *) lsecond(args);
9732 ECB :
9733 GIC 24657 : get_rule_expr_paren(arg1, context, true, (Node *) expr);
9734 24657 : appendStringInfo(buf, " %s ",
9735 : generate_operator_name(opno,
9736 ECB : exprType(arg1),
9737 : exprType(arg2)));
9738 CBC 24657 : get_rule_expr_paren(arg2, context, true, (Node *) expr);
9739 : }
9740 : else
9741 : {
9742 ECB : /* prefix operator */
9743 GIC 15 : Node *arg = (Node *) linitial(args);
9744 :
9745 15 : appendStringInfo(buf, "%s ",
9746 : generate_operator_name(opno,
9747 : InvalidOid,
9748 : exprType(arg)));
9749 15 : get_rule_expr_paren(arg, context, true, (Node *) expr);
9750 ECB : }
9751 GIC 24672 : if (!PRETTY_PAREN(context))
9752 CBC 23770 : appendStringInfoChar(buf, ')');
9753 24672 : }
9754 :
9755 : /*
9756 : * get_func_expr - Parse back a FuncExpr node
9757 : */
9758 : static void
9759 GIC 5662 : get_func_expr(FuncExpr *expr, deparse_context *context,
9760 ECB : bool showimplicit)
9761 EUB : {
9762 GIC 5662 : StringInfo buf = context->buf;
9763 5662 : Oid funcoid = expr->funcid;
9764 ECB : Oid argtypes[FUNC_MAX_ARGS];
9765 : int nargs;
9766 : List *argnames;
9767 : bool use_variadic;
9768 : ListCell *l;
9769 :
9770 : /*
9771 : * If the function call came from an implicit coercion, then just show the
9772 : * first argument --- unless caller wants to see implicit coercions.
9773 : */
9774 GIC 5662 : if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
9775 : {
9776 CBC 847 : get_rule_expr_paren((Node *) linitial(expr->args), context,
9777 : false, (Node *) expr);
9778 GIC 2125 : return;
9779 ECB : }
9780 :
9781 : /*
9782 : * If the function call came from a cast, then show the first argument
9783 : * plus an explicit cast operation.
9784 : */
9785 CBC 4815 : if (expr->funcformat == COERCE_EXPLICIT_CAST ||
9786 4560 : expr->funcformat == COERCE_IMPLICIT_CAST)
9787 ECB : {
9788 CBC 656 : Node *arg = linitial(expr->args);
9789 656 : Oid rettype = expr->funcresulttype;
9790 : int32 coercedTypmod;
9791 ECB :
9792 : /* Get the typmod if this is a length-coercion function */
9793 GIC 656 : (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
9794 :
9795 656 : get_coercion_expr(arg, context,
9796 : rettype, coercedTypmod,
9797 : (Node *) expr);
9798 ECB :
9799 GIC 656 : return;
9800 : }
9801 ECB :
9802 : /*
9803 : * If the function was called using one of the SQL spec's random special
9804 : * syntaxes, try to reproduce that. If we don't recognize the function,
9805 : * fall through.
9806 : */
9807 GIC 4159 : if (expr->funcformat == COERCE_SQL_SYNTAX)
9808 : {
9809 625 : if (get_func_sql_syntax(expr, context))
9810 CBC 622 : return;
9811 : }
9812 :
9813 : /*
9814 ECB : * Normal function: display as proname(args). First we need to extract
9815 : * the argument datatypes.
9816 : */
9817 CBC 3537 : if (list_length(expr->args) > FUNC_MAX_ARGS)
9818 UIC 0 : ereport(ERROR,
9819 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
9820 : errmsg("too many arguments")));
9821 GIC 3537 : nargs = 0;
9822 3537 : argnames = NIL;
9823 7563 : foreach(l, expr->args)
9824 : {
9825 4026 : Node *arg = (Node *) lfirst(l);
9826 ECB :
9827 GIC 4026 : if (IsA(arg, NamedArgExpr))
9828 9 : argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
9829 4026 : argtypes[nargs] = exprType(arg);
9830 CBC 4026 : nargs++;
9831 ECB : }
9832 :
9833 GIC 3537 : appendStringInfo(buf, "%s(",
9834 ECB : generate_function_name(funcoid, nargs,
9835 : argnames, argtypes,
9836 GIC 3537 : expr->funcvariadic,
9837 : &use_variadic,
9838 : context->special_exprkind));
9839 3537 : nargs = 0;
9840 7563 : foreach(l, expr->args)
9841 ECB : {
9842 CBC 4026 : if (nargs++ > 0)
9843 GIC 809 : appendStringInfoString(buf, ", ");
9844 4026 : if (use_variadic && lnext(expr->args, l) == NULL)
9845 CBC 3 : appendStringInfoString(buf, "VARIADIC ");
9846 GIC 4026 : get_rule_expr((Node *) lfirst(l), context, true);
9847 ECB : }
9848 CBC 3537 : appendStringInfoChar(buf, ')');
9849 ECB : }
9850 :
9851 : /*
9852 : * get_agg_expr - Parse back an Aggref node
9853 : */
9854 : static void
9855 CBC 892 : get_agg_expr(Aggref *aggref, deparse_context *context,
9856 : Aggref *original_aggref)
9857 : {
9858 GNC 892 : get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
9859 : false);
9860 892 : }
9861 :
9862 : /*
9863 : * get_agg_expr_helper - subroutine for get_agg_expr and
9864 : * get_json_agg_constructor
9865 : */
9866 : static void
9867 910 : get_agg_expr_helper(Aggref *aggref, deparse_context *context,
9868 : Aggref *original_aggref, const char *funcname,
9869 : const char *options, bool is_json_objectagg)
9870 ECB : {
9871 GIC 910 : StringInfo buf = context->buf;
9872 : Oid argtypes[FUNC_MAX_ARGS];
9873 : int nargs;
9874 GNC 910 : bool use_variadic = false;
9875 :
9876 : /*
9877 ECB : * For a combining aggregate, we look up and deparse the corresponding
9878 : * partial aggregate instead. This is necessary because our input
9879 : * argument list has been replaced; the new argument list always has just
9880 : * one element, which will point to a partial Aggref that supplies us with
9881 : * transition states to combine.
9882 : */
9883 GIC 910 : if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
9884 : {
9885 : TargetEntry *tle;
9886 ECB :
9887 CBC 130 : Assert(list_length(aggref->args) == 1);
9888 GIC 130 : tle = linitial_node(TargetEntry, aggref->args);
9889 130 : resolve_special_varno((Node *) tle->expr, context,
9890 : get_agg_combine_expr, original_aggref);
9891 130 : return;
9892 : }
9893 ECB :
9894 : /*
9895 : * Mark as PARTIAL, if appropriate. We look to the original aggref so as
9896 : * to avoid printing this when recursing from the code just above.
9897 : */
9898 GIC 780 : if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
9899 CBC 30 : appendStringInfoString(buf, "PARTIAL ");
9900 ECB :
9901 : /* Extract the argument types as seen by the parser */
9902 CBC 780 : nargs = get_aggregate_argtypes(aggref, argtypes);
9903 :
9904 GNC 780 : if (!funcname)
9905 762 : funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
9906 762 : argtypes, aggref->aggvariadic,
9907 : &use_variadic,
9908 : context->special_exprkind);
9909 :
9910 ECB : /* Print the aggregate name, schema-qualified if needed */
9911 GNC 780 : appendStringInfo(buf, "%s(%s", funcname,
9912 GBC 780 : (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
9913 :
9914 CBC 780 : if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
9915 : {
9916 : /*
9917 ECB : * Ordered-set aggregates do not use "*" syntax. Also, we needn't
9918 : * worry about inserting VARIADIC. So we can just dump the direct
9919 : * args as-is.
9920 : */
9921 CBC 14 : Assert(!aggref->aggvariadic);
9922 GIC 14 : get_rule_expr((Node *) aggref->aggdirectargs, context, true);
9923 14 : Assert(aggref->aggorder != NIL);
9924 14 : appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
9925 CBC 14 : get_rule_orderby(aggref->aggorder, aggref->args, false, context);
9926 : }
9927 ECB : else
9928 : {
9929 : /* aggstar can be set only in zero-argument aggregates */
9930 GIC 766 : if (aggref->aggstar)
9931 112 : appendStringInfoChar(buf, '*');
9932 ECB : else
9933 : {
9934 : ListCell *l;
9935 : int i;
9936 :
9937 CBC 654 : i = 0;
9938 1387 : foreach(l, aggref->args)
9939 : {
9940 GIC 733 : TargetEntry *tle = (TargetEntry *) lfirst(l);
9941 CBC 733 : Node *arg = (Node *) tle->expr;
9942 :
9943 GIC 733 : Assert(!IsA(arg, NamedArgExpr));
9944 733 : if (tle->resjunk)
9945 19 : continue;
9946 714 : if (i++ > 0)
9947 : {
9948 GNC 60 : if (is_json_objectagg)
9949 : {
9950 : /*
9951 : * the ABSENT ON NULL and WITH UNIQUE args are printed
9952 : * separately, so ignore them here
9953 : */
9954 6 : if (i > 2)
9955 UNC 0 : break;
9956 :
9957 GNC 6 : appendStringInfoString(buf, " : ");
9958 : }
9959 : else
9960 54 : appendStringInfoString(buf, ", ");
9961 : }
9962 GIC 714 : if (use_variadic && i == nargs)
9963 4 : appendStringInfoString(buf, "VARIADIC ");
9964 CBC 714 : get_rule_expr(arg, context, true);
9965 : }
9966 : }
9967 ECB :
9968 GIC 766 : if (aggref->aggorder != NIL)
9969 ECB : {
9970 GBC 35 : appendStringInfoString(buf, " ORDER BY ");
9971 GIC 35 : get_rule_orderby(aggref->aggorder, aggref->args, false, context);
9972 ECB : }
9973 : }
9974 :
9975 GNC 780 : if (options)
9976 18 : appendStringInfoString(buf, options);
9977 :
9978 GIC 780 : if (aggref->aggfilter != NULL)
9979 : {
9980 23 : appendStringInfoString(buf, ") FILTER (WHERE ");
9981 23 : get_rule_expr((Node *) aggref->aggfilter, context, false);
9982 : }
9983 ECB :
9984 GIC 780 : appendStringInfoChar(buf, ')');
9985 ECB : }
9986 :
9987 : /*
9988 : * This is a helper function for get_agg_expr(). It's used when we deparse
9989 : * a combining Aggref; resolve_special_varno locates the corresponding partial
9990 : * Aggref and then calls this.
9991 : */
9992 : static void
9993 GIC 130 : get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
9994 ECB : {
9995 : Aggref *aggref;
9996 GIC 130 : Aggref *original_aggref = callback_arg;
9997 :
9998 CBC 130 : if (!IsA(node, Aggref))
9999 UIC 0 : elog(ERROR, "combining Aggref does not point to an Aggref");
10000 :
10001 GIC 130 : aggref = (Aggref *) node;
10002 130 : get_agg_expr(aggref, context, original_aggref);
10003 130 : }
10004 ECB :
10005 EUB : /*
10006 : * get_windowfunc_expr - Parse back a WindowFunc node
10007 : */
10008 ECB : static void
10009 CBC 117 : get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
10010 : {
10011 GNC 117 : get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
10012 117 : }
10013 :
10014 :
10015 : /*
10016 : * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
10017 : * get_json_agg_constructor
10018 : */
10019 : static void
10020 123 : get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
10021 : const char *funcname, const char *options,
10022 : bool is_json_objectagg)
10023 ECB : {
10024 GIC 123 : StringInfo buf = context->buf;
10025 ECB : Oid argtypes[FUNC_MAX_ARGS];
10026 : int nargs;
10027 : List *argnames;
10028 EUB : ListCell *l;
10029 ECB :
10030 CBC 123 : if (list_length(wfunc->args) > FUNC_MAX_ARGS)
10031 UIC 0 : ereport(ERROR,
10032 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
10033 ECB : errmsg("too many arguments")));
10034 CBC 123 : nargs = 0;
10035 GIC 123 : argnames = NIL;
10036 192 : foreach(l, wfunc->args)
10037 : {
10038 CBC 69 : Node *arg = (Node *) lfirst(l);
10039 :
10040 GIC 69 : if (IsA(arg, NamedArgExpr))
10041 LBC 0 : argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
10042 CBC 69 : argtypes[nargs] = exprType(arg);
10043 GIC 69 : nargs++;
10044 : }
10045 ECB :
10046 GNC 123 : if (!funcname)
10047 117 : funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
10048 : argtypes, false, NULL,
10049 : context->special_exprkind);
10050 :
10051 123 : appendStringInfo(buf, "%s(", funcname);
10052 :
10053 : /* winstar can be set only in zero-argument aggregates */
10054 CBC 123 : if (wfunc->winstar)
10055 GIC 12 : appendStringInfoChar(buf, '*');
10056 : else
10057 : {
10058 GNC 111 : if (is_json_objectagg)
10059 : {
10060 3 : get_rule_expr((Node *) linitial(wfunc->args), context, false);
10061 3 : appendStringInfoString(buf, " : ");
10062 3 : get_rule_expr((Node *) lsecond(wfunc->args), context, false);
10063 : }
10064 : else
10065 108 : get_rule_expr((Node *) wfunc->args, context, true);
10066 : }
10067 :
10068 123 : if (options)
10069 6 : appendStringInfoString(buf, options);
10070 ECB :
10071 GIC 123 : if (wfunc->aggfilter != NULL)
10072 ECB : {
10073 UIC 0 : appendStringInfoString(buf, ") FILTER (WHERE ");
10074 UBC 0 : get_rule_expr((Node *) wfunc->aggfilter, context, false);
10075 EUB : }
10076 :
10077 GIC 123 : appendStringInfoString(buf, ") OVER ");
10078 ECB :
10079 GIC 123 : foreach(l, context->windowClause)
10080 ECB : {
10081 GIC 21 : WindowClause *wc = (WindowClause *) lfirst(l);
10082 ECB :
10083 GIC 21 : if (wc->winref == wfunc->winref)
10084 ECB : {
10085 GIC 21 : if (wc->name)
10086 LBC 0 : appendStringInfoString(buf, quote_identifier(wc->name));
10087 EUB : else
10088 GIC 21 : get_rule_windowspec(wc, context->windowTList, context);
10089 CBC 21 : break;
10090 ECB : }
10091 : }
10092 GIC 123 : if (l == NULL)
10093 ECB : {
10094 GIC 102 : if (context->windowClause)
10095 LBC 0 : elog(ERROR, "could not find window clause for winref %u",
10096 EUB : wfunc->winref);
10097 :
10098 : /*
10099 : * In EXPLAIN, we don't have window context information available, so
10100 : * we have to settle for this:
10101 : */
10102 GIC 102 : appendStringInfoString(buf, "(?)");
10103 ECB : }
10104 GIC 123 : }
10105 ECB :
10106 : /*
10107 : * get_func_sql_syntax_time
10108 : *
10109 : * Parse back argument of SQL-syntax function call related to a time or a
10110 : * timestamp. These require a specific handling when their typmod is given
10111 : * by the function caller through their SQL keyword.
10112 : */
10113 : static void
10114 GNC 366 : get_func_sql_syntax_time(List *args, deparse_context *context)
10115 : {
10116 366 : StringInfo buf = context->buf;
10117 : Const *cons;
10118 :
10119 366 : if (list_length(args) != 1)
10120 24 : return;
10121 :
10122 342 : cons = (Const *) linitial(args);
10123 342 : Assert(IsA(cons, Const));
10124 :
10125 342 : if (!cons->constisnull)
10126 : {
10127 333 : appendStringInfoString(buf, "(");
10128 333 : get_rule_expr((Node *) cons, context, false);
10129 333 : appendStringInfoString(buf, ")");
10130 : }
10131 : }
10132 :
10133 : /*
10134 : * get_func_sql_syntax - Parse back a SQL-syntax function call
10135 : *
10136 : * Returns true if we successfully deparsed, false if we did not
10137 : * recognize the function.
10138 : */
10139 : static bool
10140 GIC 625 : get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
10141 : {
10142 CBC 625 : StringInfo buf = context->buf;
10143 GIC 625 : Oid funcoid = expr->funcid;
10144 ECB :
10145 GIC 625 : switch (funcoid)
10146 : {
10147 CBC 6 : case F_TIMEZONE_INTERVAL_TIMESTAMP:
10148 ECB : case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
10149 : case F_TIMEZONE_INTERVAL_TIMETZ:
10150 : case F_TIMEZONE_TEXT_TIMESTAMP:
10151 : case F_TIMEZONE_TEXT_TIMESTAMPTZ:
10152 : case F_TIMEZONE_TEXT_TIMETZ:
10153 : /* AT TIME ZONE ... note reversed argument order */
10154 GIC 6 : appendStringInfoChar(buf, '(');
10155 CBC 6 : get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
10156 ECB : (Node *) expr);
10157 CBC 6 : appendStringInfoString(buf, " AT TIME ZONE ");
10158 GIC 6 : get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10159 : (Node *) expr);
10160 6 : appendStringInfoChar(buf, ')');
10161 6 : return true;
10162 :
10163 3 : case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
10164 : case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
10165 : case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
10166 : case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
10167 : case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
10168 ECB : case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
10169 : case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
10170 : case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
10171 : case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
10172 : case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
10173 : case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
10174 : case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
10175 : case F_OVERLAPS_TIME_TIME_TIME_TIME:
10176 : /* (x1, x2) OVERLAPS (y1, y2) */
10177 GIC 3 : appendStringInfoString(buf, "((");
10178 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10179 3 : appendStringInfoString(buf, ", ");
10180 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10181 3 : appendStringInfoString(buf, ") OVERLAPS (");
10182 CBC 3 : get_rule_expr((Node *) lthird(expr->args), context, false);
10183 3 : appendStringInfoString(buf, ", ");
10184 GIC 3 : get_rule_expr((Node *) lfourth(expr->args), context, false);
10185 CBC 3 : appendStringInfoString(buf, "))");
10186 3 : return true;
10187 :
10188 3 : case F_EXTRACT_TEXT_DATE:
10189 ECB : case F_EXTRACT_TEXT_TIME:
10190 : case F_EXTRACT_TEXT_TIMETZ:
10191 : case F_EXTRACT_TEXT_TIMESTAMP:
10192 : case F_EXTRACT_TEXT_TIMESTAMPTZ:
10193 : case F_EXTRACT_TEXT_INTERVAL:
10194 : /* EXTRACT (x FROM y) */
10195 GIC 3 : appendStringInfoString(buf, "EXTRACT(");
10196 : {
10197 3 : Const *con = (Const *) linitial(expr->args);
10198 :
10199 3 : Assert(IsA(con, Const) &&
10200 : con->consttype == TEXTOID &&
10201 : !con->constisnull);
10202 3 : appendStringInfoString(buf, TextDatumGetCString(con->constvalue));
10203 : }
10204 3 : appendStringInfoString(buf, " FROM ");
10205 CBC 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10206 3 : appendStringInfoChar(buf, ')');
10207 3 : return true;
10208 ECB :
10209 CBC 6 : case F_IS_NORMALIZED:
10210 ECB : /* IS xxx NORMALIZED */
10211 CBC 6 : appendStringInfoString(buf, "(");
10212 6 : get_rule_expr_paren((Node *) linitial(expr->args), context, false,
10213 ECB : (Node *) expr);
10214 CBC 6 : appendStringInfoString(buf, " IS");
10215 GIC 6 : if (list_length(expr->args) == 2)
10216 ECB : {
10217 GIC 3 : Const *con = (Const *) lsecond(expr->args);
10218 :
10219 3 : Assert(IsA(con, Const) &&
10220 : con->consttype == TEXTOID &&
10221 : !con->constisnull);
10222 3 : appendStringInfo(buf, " %s",
10223 CBC 3 : TextDatumGetCString(con->constvalue));
10224 : }
10225 6 : appendStringInfoString(buf, " NORMALIZED)");
10226 GIC 6 : return true;
10227 ECB :
10228 GIC 3 : case F_PG_COLLATION_FOR:
10229 : /* COLLATION FOR */
10230 CBC 3 : appendStringInfoString(buf, "COLLATION FOR (");
10231 GIC 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10232 CBC 3 : appendStringInfoChar(buf, ')');
10233 3 : return true;
10234 ECB :
10235 CBC 6 : case F_NORMALIZE:
10236 : /* NORMALIZE() */
10237 6 : appendStringInfoString(buf, "NORMALIZE(");
10238 GIC 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
10239 CBC 6 : if (list_length(expr->args) == 2)
10240 ECB : {
10241 GIC 3 : Const *con = (Const *) lsecond(expr->args);
10242 ECB :
10243 CBC 3 : Assert(IsA(con, Const) &&
10244 : con->consttype == TEXTOID &&
10245 ECB : !con->constisnull);
10246 GIC 3 : appendStringInfo(buf, ", %s",
10247 CBC 3 : TextDatumGetCString(con->constvalue));
10248 : }
10249 GIC 6 : appendStringInfoChar(buf, ')');
10250 CBC 6 : return true;
10251 ECB :
10252 GIC 6 : case F_OVERLAY_BIT_BIT_INT4:
10253 ECB : case F_OVERLAY_BIT_BIT_INT4_INT4:
10254 : case F_OVERLAY_BYTEA_BYTEA_INT4:
10255 : case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
10256 : case F_OVERLAY_TEXT_TEXT_INT4:
10257 : case F_OVERLAY_TEXT_TEXT_INT4_INT4:
10258 : /* OVERLAY() */
10259 CBC 6 : appendStringInfoString(buf, "OVERLAY(");
10260 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
10261 6 : appendStringInfoString(buf, " PLACING ");
10262 GIC 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10263 CBC 6 : appendStringInfoString(buf, " FROM ");
10264 GIC 6 : get_rule_expr((Node *) lthird(expr->args), context, false);
10265 CBC 6 : if (list_length(expr->args) == 4)
10266 ECB : {
10267 CBC 3 : appendStringInfoString(buf, " FOR ");
10268 GIC 3 : get_rule_expr((Node *) lfourth(expr->args), context, false);
10269 ECB : }
10270 GIC 6 : appendStringInfoChar(buf, ')');
10271 CBC 6 : return true;
10272 :
10273 GIC 3 : case F_POSITION_BIT_BIT:
10274 ECB : case F_POSITION_BYTEA_BYTEA:
10275 : case F_POSITION_TEXT_TEXT:
10276 : /* POSITION() ... extra parens since args are b_expr not a_expr */
10277 CBC 3 : appendStringInfoString(buf, "POSITION((");
10278 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10279 GIC 3 : appendStringInfoString(buf, ") IN (");
10280 CBC 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10281 GIC 3 : appendStringInfoString(buf, "))");
10282 3 : return true;
10283 :
10284 3 : case F_SUBSTRING_BIT_INT4:
10285 : case F_SUBSTRING_BIT_INT4_INT4:
10286 : case F_SUBSTRING_BYTEA_INT4:
10287 ECB : case F_SUBSTRING_BYTEA_INT4_INT4:
10288 : case F_SUBSTRING_TEXT_INT4:
10289 : case F_SUBSTRING_TEXT_INT4_INT4:
10290 : /* SUBSTRING FROM/FOR (i.e., integer-position variants) */
10291 CBC 3 : appendStringInfoString(buf, "SUBSTRING(");
10292 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10293 3 : appendStringInfoString(buf, " FROM ");
10294 GIC 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10295 CBC 3 : if (list_length(expr->args) == 3)
10296 ECB : {
10297 GIC 3 : appendStringInfoString(buf, " FOR ");
10298 CBC 3 : get_rule_expr((Node *) lthird(expr->args), context, false);
10299 ECB : }
10300 GIC 3 : appendStringInfoChar(buf, ')');
10301 CBC 3 : return true;
10302 :
10303 GIC 3 : case F_SUBSTRING_TEXT_TEXT_TEXT:
10304 : /* SUBSTRING SIMILAR/ESCAPE */
10305 CBC 3 : appendStringInfoString(buf, "SUBSTRING(");
10306 3 : get_rule_expr((Node *) linitial(expr->args), context, false);
10307 3 : appendStringInfoString(buf, " SIMILAR ");
10308 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10309 3 : appendStringInfoString(buf, " ESCAPE ");
10310 3 : get_rule_expr((Node *) lthird(expr->args), context, false);
10311 GIC 3 : appendStringInfoChar(buf, ')');
10312 CBC 3 : return true;
10313 :
10314 GIC 6 : case F_BTRIM_BYTEA_BYTEA:
10315 : case F_BTRIM_TEXT:
10316 : case F_BTRIM_TEXT_TEXT:
10317 : /* TRIM() */
10318 6 : appendStringInfoString(buf, "TRIM(BOTH");
10319 CBC 6 : if (list_length(expr->args) == 2)
10320 ECB : {
10321 CBC 6 : appendStringInfoChar(buf, ' ');
10322 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10323 ECB : }
10324 GIC 6 : appendStringInfoString(buf, " FROM ");
10325 CBC 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
10326 6 : appendStringInfoChar(buf, ')');
10327 GIC 6 : return true;
10328 ECB :
10329 CBC 6 : case F_LTRIM_BYTEA_BYTEA:
10330 : case F_LTRIM_TEXT:
10331 ECB : case F_LTRIM_TEXT_TEXT:
10332 : /* TRIM() */
10333 CBC 6 : appendStringInfoString(buf, "TRIM(LEADING");
10334 6 : if (list_length(expr->args) == 2)
10335 ECB : {
10336 CBC 6 : appendStringInfoChar(buf, ' ');
10337 6 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10338 ECB : }
10339 CBC 6 : appendStringInfoString(buf, " FROM ");
10340 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
10341 GIC 6 : appendStringInfoChar(buf, ')');
10342 CBC 6 : return true;
10343 :
10344 GIC 6 : case F_RTRIM_BYTEA_BYTEA:
10345 : case F_RTRIM_TEXT:
10346 ECB : case F_RTRIM_TEXT_TEXT:
10347 : /* TRIM() */
10348 GIC 6 : appendStringInfoString(buf, "TRIM(TRAILING");
10349 CBC 6 : if (list_length(expr->args) == 2)
10350 ECB : {
10351 GIC 3 : appendStringInfoChar(buf, ' ');
10352 CBC 3 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10353 ECB : }
10354 CBC 6 : appendStringInfoString(buf, " FROM ");
10355 6 : get_rule_expr((Node *) linitial(expr->args), context, false);
10356 GIC 6 : appendStringInfoChar(buf, ')');
10357 CBC 6 : return true;
10358 :
10359 GNC 6 : case F_CURRENT_CATALOG:
10360 6 : appendStringInfoString(buf, "CURRENT_CATALOG");
10361 6 : return true;
10362 6 : case F_CURRENT_ROLE:
10363 6 : appendStringInfoString(buf, "CURRENT_ROLE");
10364 6 : return true;
10365 6 : case F_CURRENT_SCHEMA:
10366 6 : appendStringInfoString(buf, "CURRENT_SCHEMA");
10367 6 : return true;
10368 141 : case F_CURRENT_USER:
10369 141 : appendStringInfoString(buf, "CURRENT_USER");
10370 141 : return true;
10371 6 : case F_USER:
10372 6 : appendStringInfoString(buf, "USER");
10373 6 : return true;
10374 16 : case F_SESSION_USER:
10375 16 : appendStringInfoString(buf, "SESSION_USER");
10376 16 : return true;
10377 6 : case F_SYSTEM_USER:
10378 6 : appendStringInfoString(buf, "SYSTEM_USER");
10379 6 : return true;
10380 :
10381 9 : case F_CURRENT_DATE:
10382 9 : appendStringInfoString(buf, "CURRENT_DATE");
10383 9 : return true;
10384 12 : case F_CURRENT_TIME:
10385 12 : appendStringInfoString(buf, "CURRENT_TIME");
10386 12 : get_func_sql_syntax_time(expr->args, context);
10387 12 : return true;
10388 318 : case F_CURRENT_TIMESTAMP:
10389 318 : appendStringInfoString(buf, "CURRENT_TIMESTAMP");
10390 318 : get_func_sql_syntax_time(expr->args, context);
10391 318 : return true;
10392 12 : case F_LOCALTIME:
10393 12 : appendStringInfoString(buf, "LOCALTIME");
10394 12 : get_func_sql_syntax_time(expr->args, context);
10395 12 : return true;
10396 24 : case F_LOCALTIMESTAMP:
10397 24 : appendStringInfoString(buf, "LOCALTIMESTAMP");
10398 24 : get_func_sql_syntax_time(expr->args, context);
10399 24 : return true;
10400 :
10401 UIC 0 : case F_XMLEXISTS:
10402 : /* XMLEXISTS ... extra parens because args are c_expr */
10403 LBC 0 : appendStringInfoString(buf, "XMLEXISTS((");
10404 0 : get_rule_expr((Node *) linitial(expr->args), context, false);
10405 UIC 0 : appendStringInfoString(buf, ") PASSING (");
10406 LBC 0 : get_rule_expr((Node *) lsecond(expr->args), context, false);
10407 0 : appendStringInfoString(buf, "))");
10408 UIC 0 : return true;
10409 ECB : }
10410 CBC 3 : return false;
10411 ECB : }
10412 :
10413 : /* ----------
10414 : * get_coercion_expr
10415 : *
10416 : * Make a string representation of a value coerced to a specific type
10417 : * ----------
10418 : */
10419 : static void
10420 GIC 1999 : get_coercion_expr(Node *arg, deparse_context *context,
10421 ECB : Oid resulttype, int32 resulttypmod,
10422 : Node *parentNode)
10423 : {
10424 CBC 1999 : StringInfo buf = context->buf;
10425 ECB :
10426 : /*
10427 : * Since parse_coerce.c doesn't immediately collapse application of
10428 : * length-coercion functions to constants, what we'll typically see in
10429 : * such cases is a Const with typmod -1 and a length-coercion function
10430 : * right above it. Avoid generating redundant output. However, beware of
10431 : * suppressing casts when the user actually wrote something like
10432 : * 'foo'::text::char(3).
10433 : *
10434 : * Note: it might seem that we are missing the possibility of needing to
10435 : * print a COLLATE clause for such a Const. However, a Const could only
10436 : * have nondefault collation in a post-constant-folding tree, in which the
10437 : * length coercion would have been folded too. See also the special
10438 : * handling of CollateExpr in coerce_to_target_type(): any collation
10439 : * marking will be above the coercion node, not below it.
10440 : */
10441 CBC 1999 : if (arg && IsA(arg, Const) &&
10442 225 : ((Const *) arg)->consttype == resulttype &&
10443 12 : ((Const *) arg)->consttypmod == -1)
10444 ECB : {
10445 : /* Show the constant without normal ::typename decoration */
10446 CBC 12 : get_const_expr((Const *) arg, context, -1);
10447 ECB : }
10448 : else
10449 : {
10450 GIC 1987 : if (!PRETTY_PAREN(context))
10451 CBC 1823 : appendStringInfoChar(buf, '(');
10452 1987 : get_rule_expr_paren(arg, context, false, parentNode);
10453 1987 : if (!PRETTY_PAREN(context))
10454 1823 : appendStringInfoChar(buf, ')');
10455 ECB : }
10456 :
10457 : /*
10458 : * Never emit resulttype(arg) functional notation. A pg_proc entry could
10459 : * take precedence, and a resulttype in pg_temp would require schema
10460 : * qualification that format_type_with_typemod() would usually omit. We've
10461 : * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
10462 : * would work fine.
10463 : */
10464 CBC 1999 : appendStringInfo(buf, "::%s",
10465 ECB : format_type_with_typemod(resulttype, resulttypmod));
10466 CBC 1999 : }
10467 ECB :
10468 : /* ----------
10469 : * get_const_expr
10470 : *
10471 EUB : * Make a string representation of a Const
10472 : *
10473 : * showtype can be -1 to never show "::typename" decoration, or +1 to always
10474 : * show it, or 0 to show it only if the constant wouldn't be assumed to be
10475 : * the right type by default.
10476 : *
10477 : * If the Const's collation isn't default for its type, show that too.
10478 : * We mustn't do this when showtype is -1 (since that means the caller will
10479 : * print "::typename", and we can't put a COLLATE clause in between). It's
10480 ECB : * caller's responsibility that collation isn't missed in such cases.
10481 : * ----------
10482 : */
10483 : static void
10484 GIC 28960 : get_const_expr(Const *constval, deparse_context *context, int showtype)
10485 : {
10486 28960 : StringInfo buf = context->buf;
10487 : Oid typoutput;
10488 : bool typIsVarlena;
10489 : char *extval;
10490 CBC 28960 : bool needlabel = false;
10491 :
10492 GIC 28960 : if (constval->constisnull)
10493 : {
10494 ECB : /*
10495 : * Always label the type of a NULL constant to prevent misdecisions
10496 : * about type when reparsing.
10497 : */
10498 GIC 360 : appendStringInfoString(buf, "NULL");
10499 360 : if (showtype >= 0)
10500 : {
10501 338 : appendStringInfo(buf, "::%s",
10502 : format_type_with_typemod(constval->consttype,
10503 : constval->consttypmod));
10504 338 : get_const_collation(constval, context);
10505 : }
10506 3555 : return;
10507 : }
10508 :
10509 28600 : getTypeOutputInfo(constval->consttype,
10510 : &typoutput, &typIsVarlena);
10511 ECB :
10512 CBC 28600 : extval = OidOutputFunctionCall(typoutput, constval->constvalue);
10513 ECB :
10514 GIC 28600 : switch (constval->consttype)
10515 : {
10516 CBC 16499 : case INT4OID:
10517 :
10518 : /*
10519 : * INT4 can be printed without any decoration, unless it is
10520 ECB : * negative; in that case print it as '-nnn'::integer to ensure
10521 : * that the output will re-parse as a constant, not as a constant
10522 : * plus operator. In most cases we could get away with printing
10523 : * (-nnn) instead, because of the way that gram.y handles negative
10524 : * literals; but that doesn't work for INT_MIN, and it doesn't
10525 : * seem that much prettier anyway.
10526 : */
10527 GIC 16499 : if (extval[0] != '-')
10528 16243 : appendStringInfoString(buf, extval);
10529 : else
10530 : {
10531 256 : appendStringInfo(buf, "'%s'", extval);
10532 256 : needlabel = true; /* we must attach a cast */
10533 : }
10534 CBC 16499 : break;
10535 :
10536 508 : case NUMERICOID:
10537 :
10538 : /*
10539 : * NUMERIC can be printed without quotes if it looks like a float
10540 : * constant (not an integer, and not Infinity or NaN) and doesn't
10541 : * have a leading sign (for the same reason as for INT4).
10542 : */
10543 GIC 508 : if (isdigit((unsigned char) extval[0]) &&
10544 508 : strcspn(extval, "eE.") != strlen(extval))
10545 : {
10546 180 : appendStringInfoString(buf, extval);
10547 : }
10548 : else
10549 : {
10550 328 : appendStringInfo(buf, "'%s'", extval);
10551 328 : needlabel = true; /* we must attach a cast */
10552 : }
10553 508 : break;
10554 ECB :
10555 GIC 669 : case BOOLOID:
10556 CBC 669 : if (strcmp(extval, "t") == 0)
10557 GIC 354 : appendStringInfoString(buf, "true");
10558 : else
10559 315 : appendStringInfoString(buf, "false");
10560 CBC 669 : break;
10561 :
10562 10924 : default:
10563 GIC 10924 : simple_quote_literal(buf, extval);
10564 10924 : break;
10565 : }
10566 :
10567 28600 : pfree(extval);
10568 ECB :
10569 CBC 28600 : if (showtype < 0)
10570 GIC 3195 : return;
10571 ECB :
10572 : /*
10573 : * For showtype == 0, append ::typename unless the constant will be
10574 : * implicitly typed as the right type when it is read in.
10575 : *
10576 : * XXX this code has to be kept in sync with the behavior of the parser,
10577 : * especially make_const.
10578 : */
10579 CBC 25405 : switch (constval->consttype)
10580 : {
10581 GIC 685 : case BOOLOID:
10582 ECB : case UNKNOWNOID:
10583 : /* These types can be left unlabeled */
10584 CBC 685 : needlabel = false;
10585 GIC 685 : break;
10586 CBC 14466 : case INT4OID:
10587 : /* We determined above whether a label is needed */
10588 GIC 14466 : break;
10589 508 : case NUMERICOID:
10590 :
10591 : /*
10592 : * Float-looking constants will be typed as numeric, which we
10593 : * checked above; but if there's a nondefault typmod we need to
10594 : * show it.
10595 : */
10596 508 : needlabel |= (constval->consttypmod >= 0);
10597 CBC 508 : break;
10598 9746 : default:
10599 GIC 9746 : needlabel = true;
10600 9746 : break;
10601 ECB : }
10602 CBC 25405 : if (needlabel || showtype > 0)
10603 GIC 10323 : appendStringInfo(buf, "::%s",
10604 ECB : format_type_with_typemod(constval->consttype,
10605 : constval->consttypmod));
10606 :
10607 GIC 25405 : get_const_collation(constval, context);
10608 : }
10609 :
10610 : /*
10611 : * helper for get_const_expr: append COLLATE if needed
10612 : */
10613 ECB : static void
10614 CBC 25743 : get_const_collation(Const *constval, deparse_context *context)
10615 : {
10616 25743 : StringInfo buf = context->buf;
10617 :
10618 GIC 25743 : if (OidIsValid(constval->constcollid))
10619 : {
10620 CBC 3672 : Oid typcollation = get_typcollation(constval->consttype);
10621 ECB :
10622 GIC 3672 : if (constval->constcollid != typcollation)
10623 ECB : {
10624 GIC 35 : appendStringInfo(buf, " COLLATE %s",
10625 ECB : generate_collation_name(constval->constcollid));
10626 : }
10627 : }
10628 GIC 25743 : }
10629 ECB :
10630 : /*
10631 : * get_json_format - Parse back a JsonFormat node
10632 : */
10633 : static void
10634 GNC 24 : get_json_format(JsonFormat *format, StringInfo buf)
10635 : {
10636 24 : if (format->format_type == JS_FORMAT_DEFAULT)
10637 UNC 0 : return;
10638 :
10639 GNC 24 : appendStringInfoString(buf,
10640 24 : format->format_type == JS_FORMAT_JSONB ?
10641 : " FORMAT JSONB" : " FORMAT JSON");
10642 :
10643 24 : if (format->encoding != JS_ENC_DEFAULT)
10644 : {
10645 : const char *encoding;
10646 :
10647 UNC 0 : encoding =
10648 0 : format->encoding == JS_ENC_UTF16 ? "UTF16" :
10649 0 : format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
10650 :
10651 0 : appendStringInfo(buf, " ENCODING %s", encoding);
10652 : }
10653 : }
10654 :
10655 : /*
10656 : * get_json_returning - Parse back a JsonReturning structure
10657 : */
10658 : static void
10659 GNC 36 : get_json_returning(JsonReturning *returning, StringInfo buf,
10660 : bool json_format_by_default)
10661 : {
10662 36 : if (!OidIsValid(returning->typid))
10663 UNC 0 : return;
10664 :
10665 GNC 36 : appendStringInfo(buf, " RETURNING %s",
10666 : format_type_with_typemod(returning->typid,
10667 : returning->typmod));
10668 :
10669 72 : if (!json_format_by_default ||
10670 36 : returning->format->format_type !=
10671 36 : (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
10672 UNC 0 : get_json_format(returning->format, buf);
10673 : }
10674 :
10675 : /*
10676 : * get_json_constructor - Parse back a JsonConstructorExpr node
10677 : */
10678 : static void
10679 GNC 36 : get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
10680 : bool showimplicit)
10681 : {
10682 36 : StringInfo buf = context->buf;
10683 : const char *funcname;
10684 : bool is_json_object;
10685 : int curridx;
10686 : ListCell *lc;
10687 :
10688 36 : if (ctor->type == JSCTOR_JSON_OBJECTAGG)
10689 : {
10690 9 : get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
10691 9 : return;
10692 : }
10693 27 : else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
10694 : {
10695 15 : get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
10696 15 : return;
10697 : }
10698 :
10699 12 : switch (ctor->type)
10700 : {
10701 6 : case JSCTOR_JSON_OBJECT:
10702 6 : funcname = "JSON_OBJECT";
10703 6 : break;
10704 6 : case JSCTOR_JSON_ARRAY:
10705 6 : funcname = "JSON_ARRAY";
10706 6 : break;
10707 UNC 0 : default:
10708 0 : elog(ERROR, "invalid JsonConstructorType %d", ctor->type);
10709 : }
10710 :
10711 GNC 12 : appendStringInfo(buf, "%s(", funcname);
10712 :
10713 12 : is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
10714 48 : foreach(lc, ctor->args)
10715 : {
10716 36 : curridx = foreach_current_index(lc);
10717 36 : if (curridx > 0)
10718 : {
10719 : const char *sep;
10720 :
10721 24 : sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
10722 24 : appendStringInfoString(buf, sep);
10723 : }
10724 :
10725 36 : get_rule_expr((Node *) lfirst(lc), context, true);
10726 : }
10727 :
10728 12 : get_json_constructor_options(ctor, buf);
10729 12 : appendStringInfo(buf, ")");
10730 : }
10731 :
10732 : /*
10733 : * Append options, if any, to the JSON constructor being deparsed
10734 : */
10735 : static void
10736 36 : get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
10737 : {
10738 36 : if (ctor->absent_on_null)
10739 : {
10740 12 : if (ctor->type == JSCTOR_JSON_OBJECT ||
10741 12 : ctor->type == JSCTOR_JSON_OBJECTAGG)
10742 UNC 0 : appendStringInfoString(buf, " ABSENT ON NULL");
10743 : }
10744 : else
10745 : {
10746 GNC 24 : if (ctor->type == JSCTOR_JSON_ARRAY ||
10747 24 : ctor->type == JSCTOR_JSON_ARRAYAGG)
10748 9 : appendStringInfoString(buf, " NULL ON NULL");
10749 : }
10750 :
10751 36 : if (ctor->unique)
10752 9 : appendStringInfoString(buf, " WITH UNIQUE KEYS");
10753 :
10754 36 : get_json_returning(ctor->returning, buf, true);
10755 36 : }
10756 :
10757 : /*
10758 : * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
10759 : */
10760 : static void
10761 24 : get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
10762 : const char *funcname, bool is_json_objectagg)
10763 : {
10764 : StringInfoData options;
10765 :
10766 24 : initStringInfo(&options);
10767 24 : get_json_constructor_options(ctor, &options);
10768 :
10769 24 : if (IsA(ctor->func, Aggref))
10770 18 : get_agg_expr_helper((Aggref *) ctor->func, context,
10771 18 : (Aggref *) ctor->func,
10772 18 : funcname, options.data, is_json_objectagg);
10773 6 : else if (IsA(ctor->func, WindowFunc))
10774 6 : get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
10775 6 : funcname, options.data,
10776 : is_json_objectagg);
10777 : else
10778 UNC 0 : elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
10779 : nodeTag(ctor->func));
10780 GNC 24 : }
10781 :
10782 ECB : /*
10783 : * simple_quote_literal - Format a string as a SQL literal, append to buf
10784 : */
10785 : static void
10786 CBC 11451 : simple_quote_literal(StringInfo buf, const char *val)
10787 : {
10788 : const char *valptr;
10789 ECB :
10790 : /*
10791 : * We form the string literal according to the prevailing setting of
10792 : * standard_conforming_strings; we never use E''. User is responsible for
10793 : * making sure result is used correctly.
10794 : */
10795 GIC 11451 : appendStringInfoChar(buf, '\'');
10796 118056 : for (valptr = val; *valptr; valptr++)
10797 : {
10798 106605 : char ch = *valptr;
10799 :
10800 106605 : if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
10801 CBC 153 : appendStringInfoChar(buf, ch);
10802 GIC 106605 : appendStringInfoChar(buf, ch);
10803 ECB : }
10804 GIC 11451 : appendStringInfoChar(buf, '\'');
10805 11451 : }
10806 ECB :
10807 :
10808 : /* ----------
10809 : * get_sublink_expr - Parse back a sublink
10810 : * ----------
10811 : */
10812 : static void
10813 GIC 191 : get_sublink_expr(SubLink *sublink, deparse_context *context)
10814 : {
10815 191 : StringInfo buf = context->buf;
10816 191 : Query *query = (Query *) (sublink->subselect);
10817 191 : char *opname = NULL;
10818 ECB : bool need_paren;
10819 :
10820 CBC 191 : if (sublink->subLinkType == ARRAY_SUBLINK)
10821 6 : appendStringInfoString(buf, "ARRAY(");
10822 ECB : else
10823 GIC 185 : appendStringInfoChar(buf, '(');
10824 ECB :
10825 : /*
10826 : * Note that we print the name of only the first operator, when there are
10827 : * multiple combining operators. This is an approximation that could go
10828 : * wrong in various scenarios (operators in different schemas, renamed
10829 : * operators, etc) but there is not a whole lot we can do about it, since
10830 : * the syntax allows only one operator to be shown.
10831 : */
10832 GIC 191 : if (sublink->testexpr)
10833 : {
10834 9 : if (IsA(sublink->testexpr, OpExpr))
10835 : {
10836 ECB : /* single combining operator */
10837 GIC 3 : OpExpr *opexpr = (OpExpr *) sublink->testexpr;
10838 ECB :
10839 GIC 3 : get_rule_expr(linitial(opexpr->args), context, true);
10840 CBC 3 : opname = generate_operator_name(opexpr->opno,
10841 GIC 3 : exprType(linitial(opexpr->args)),
10842 CBC 3 : exprType(lsecond(opexpr->args)));
10843 : }
10844 6 : else if (IsA(sublink->testexpr, BoolExpr))
10845 : {
10846 ECB : /* multiple combining operators, = or <> cases */
10847 : char *sep;
10848 : ListCell *l;
10849 :
10850 CBC 3 : appendStringInfoChar(buf, '(');
10851 GIC 3 : sep = "";
10852 9 : foreach(l, ((BoolExpr *) sublink->testexpr)->args)
10853 : {
10854 6 : OpExpr *opexpr = lfirst_node(OpExpr, l);
10855 :
10856 CBC 6 : appendStringInfoString(buf, sep);
10857 GIC 6 : get_rule_expr(linitial(opexpr->args), context, true);
10858 CBC 6 : if (!opname)
10859 GBC 3 : opname = generate_operator_name(opexpr->opno,
10860 GIC 3 : exprType(linitial(opexpr->args)),
10861 CBC 3 : exprType(lsecond(opexpr->args)));
10862 6 : sep = ", ";
10863 : }
10864 GIC 3 : appendStringInfoChar(buf, ')');
10865 ECB : }
10866 GIC 3 : else if (IsA(sublink->testexpr, RowCompareExpr))
10867 : {
10868 : /* multiple combining operators, < <= > >= cases */
10869 GBC 3 : RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
10870 EUB :
10871 GBC 3 : appendStringInfoChar(buf, '(');
10872 GIC 3 : get_rule_expr((Node *) rcexpr->largs, context, true);
10873 GBC 3 : opname = generate_operator_name(linitial_oid(rcexpr->opnos),
10874 GIC 3 : exprType(linitial(rcexpr->largs)),
10875 3 : exprType(linitial(rcexpr->rargs)));
10876 3 : appendStringInfoChar(buf, ')');
10877 : }
10878 : else
10879 UIC 0 : elog(ERROR, "unrecognized testexpr type: %d",
10880 : (int) nodeTag(sublink->testexpr));
10881 ECB : }
10882 :
10883 GIC 191 : need_paren = true;
10884 ECB :
10885 GBC 191 : switch (sublink->subLinkType)
10886 : {
10887 CBC 85 : case EXISTS_SUBLINK:
10888 GIC 85 : appendStringInfoString(buf, "EXISTS ");
10889 85 : break;
10890 :
10891 CBC 6 : case ANY_SUBLINK:
10892 6 : if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
10893 3 : appendStringInfoString(buf, " IN ");
10894 EUB : else
10895 GIC 3 : appendStringInfo(buf, " %s ANY ", opname);
10896 6 : break;
10897 :
10898 3 : case ALL_SUBLINK:
10899 3 : appendStringInfo(buf, " %s ALL ", opname);
10900 3 : break;
10901 ECB :
10902 UIC 0 : case ROWCOMPARE_SUBLINK:
10903 0 : appendStringInfo(buf, " %s ", opname);
10904 LBC 0 : break;
10905 :
10906 GIC 97 : case EXPR_SUBLINK:
10907 : case MULTIEXPR_SUBLINK:
10908 : case ARRAY_SUBLINK:
10909 97 : need_paren = false;
10910 CBC 97 : break;
10911 :
10912 LBC 0 : case CTE_SUBLINK: /* shouldn't occur in a SubLink */
10913 ECB : default:
10914 UIC 0 : elog(ERROR, "unrecognized sublink type: %d",
10915 ECB : (int) sublink->subLinkType);
10916 : break;
10917 : }
10918 :
10919 GIC 191 : if (need_paren)
10920 94 : appendStringInfoChar(buf, '(');
10921 ECB :
10922 GIC 191 : get_query_def(query, buf, context->namespaces, NULL, false,
10923 ECB : context->prettyFlags, context->wrapColumn,
10924 : context->indentLevel);
10925 :
10926 CBC 191 : if (need_paren)
10927 94 : appendStringInfoString(buf, "))");
10928 ECB : else
10929 GBC 97 : appendStringInfoChar(buf, ')');
10930 191 : }
10931 :
10932 :
10933 ECB : /* ----------
10934 : * get_tablefunc - Parse back a table function
10935 : * ----------
10936 : */
10937 : static void
10938 CBC 25 : get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
10939 ECB : {
10940 GIC 25 : StringInfo buf = context->buf;
10941 :
10942 : /* XMLTABLE is the only existing implementation. */
10943 ECB :
10944 CBC 25 : appendStringInfoString(buf, "XMLTABLE(");
10945 :
10946 GIC 25 : if (tf->ns_uris != NIL)
10947 ECB : {
10948 : ListCell *lc1,
10949 : *lc2;
10950 CBC 5 : bool first = true;
10951 ECB :
10952 GIC 5 : appendStringInfoString(buf, "XMLNAMESPACES (");
10953 10 : forboth(lc1, tf->ns_uris, lc2, tf->ns_names)
10954 : {
10955 5 : Node *expr = (Node *) lfirst(lc1);
10956 5 : String *ns_node = lfirst_node(String, lc2);
10957 :
10958 CBC 5 : if (!first)
10959 UIC 0 : appendStringInfoString(buf, ", ");
10960 ECB : else
10961 GIC 5 : first = false;
10962 ECB :
10963 CBC 5 : if (ns_node != NULL)
10964 EUB : {
10965 GIC 5 : get_rule_expr(expr, context, showimplicit);
10966 5 : appendStringInfo(buf, " AS %s", strVal(ns_node));
10967 : }
10968 ECB : else
10969 : {
10970 LBC 0 : appendStringInfoString(buf, "DEFAULT ");
10971 UIC 0 : get_rule_expr(expr, context, showimplicit);
10972 : }
10973 ECB : }
10974 CBC 5 : appendStringInfoString(buf, "), ");
10975 : }
10976 ECB :
10977 CBC 25 : appendStringInfoChar(buf, '(');
10978 GIC 25 : get_rule_expr((Node *) tf->rowexpr, context, showimplicit);
10979 25 : appendStringInfoString(buf, ") PASSING (");
10980 25 : get_rule_expr((Node *) tf->docexpr, context, showimplicit);
10981 25 : appendStringInfoChar(buf, ')');
10982 :
10983 CBC 25 : if (tf->colexprs != NIL)
10984 : {
10985 : ListCell *l1;
10986 : ListCell *l2;
10987 : ListCell *l3;
10988 ECB : ListCell *l4;
10989 : ListCell *l5;
10990 GIC 25 : int colnum = 0;
10991 ECB :
10992 CBC 25 : appendStringInfoString(buf, " COLUMNS ");
10993 172 : forfive(l1, tf->colnames, l2, tf->coltypes, l3, tf->coltypmods,
10994 ECB : l4, tf->colexprs, l5, tf->coldefexprs)
10995 : {
10996 CBC 147 : char *colname = strVal(lfirst(l1));
10997 147 : Oid typid = lfirst_oid(l2);
10998 GIC 147 : int32 typmod = lfirst_int(l3);
10999 147 : Node *colexpr = (Node *) lfirst(l4);
11000 GBC 147 : Node *coldefexpr = (Node *) lfirst(l5);
11001 GIC 147 : bool ordinality = (tf->ordinalitycol == colnum);
11002 CBC 147 : bool notnull = bms_is_member(colnum, tf->notnulls);
11003 :
11004 GIC 147 : if (colnum > 0)
11005 122 : appendStringInfoString(buf, ", ");
11006 147 : colnum++;
11007 :
11008 CBC 277 : appendStringInfo(buf, "%s %s", quote_identifier(colname),
11009 : ordinality ? "FOR ORDINALITY" :
11010 GIC 130 : format_type_with_typemod(typid, typmod));
11011 147 : if (ordinality)
11012 17 : continue;
11013 :
11014 130 : if (coldefexpr != NULL)
11015 : {
11016 17 : appendStringInfoString(buf, " DEFAULT (");
11017 CBC 17 : get_rule_expr((Node *) coldefexpr, context, showimplicit);
11018 17 : appendStringInfoChar(buf, ')');
11019 : }
11020 130 : if (colexpr != NULL)
11021 : {
11022 124 : appendStringInfoString(buf, " PATH (");
11023 124 : get_rule_expr((Node *) colexpr, context, showimplicit);
11024 124 : appendStringInfoChar(buf, ')');
11025 : }
11026 130 : if (notnull)
11027 17 : appendStringInfoString(buf, " NOT NULL");
11028 : }
11029 : }
11030 :
11031 GIC 25 : appendStringInfoChar(buf, ')');
11032 25 : }
11033 :
11034 : /* ----------
11035 ECB : * get_from_clause - Parse back a FROM clause
11036 : *
11037 : * "prefix" is the keyword that denotes the start of the list of FROM
11038 : * elements. It is FROM when used to parse back SELECT and UPDATE, but
11039 : * is USING when parsing back DELETE.
11040 : * ----------
11041 : */
11042 : static void
11043 CBC 1932 : get_from_clause(Query *query, const char *prefix, deparse_context *context)
11044 : {
11045 1932 : StringInfo buf = context->buf;
11046 GIC 1932 : bool first = true;
11047 : ListCell *l;
11048 :
11049 : /*
11050 : * We use the query's jointree as a guide to what to print. However, we
11051 : * must ignore auto-added RTEs that are marked not inFromCl. (These can
11052 : * only appear at the top level of the jointree, so it's sufficient to
11053 : * check here.) This check also ensures we ignore the rule pseudo-RTEs
11054 ECB : * for NEW and OLD.
11055 : */
11056 CBC 3860 : foreach(l, query->jointree->fromlist)
11057 : {
11058 GIC 1928 : Node *jtnode = (Node *) lfirst(l);
11059 ECB :
11060 GIC 1928 : if (IsA(jtnode, RangeTblRef))
11061 ECB : {
11062 CBC 1593 : int varno = ((RangeTblRef *) jtnode)->rtindex;
11063 1593 : RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11064 ECB :
11065 GIC 1593 : if (!rte->inFromCl)
11066 CBC 185 : continue;
11067 : }
11068 :
11069 GIC 1743 : if (first)
11070 : {
11071 1591 : appendContextKeyword(context, prefix,
11072 ECB : -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
11073 CBC 1591 : first = false;
11074 ECB :
11075 GIC 1591 : get_from_clause_item(jtnode, query, context);
11076 ECB : }
11077 : else
11078 : {
11079 : StringInfoData itembuf;
11080 :
11081 CBC 152 : appendStringInfoString(buf, ", ");
11082 ECB :
11083 : /*
11084 : * Put the new FROM item's text into itembuf so we can decide
11085 : * after we've got it whether or not it needs to go on a new line.
11086 : */
11087 GIC 152 : initStringInfo(&itembuf);
11088 CBC 152 : context->buf = &itembuf;
11089 :
11090 GIC 152 : get_from_clause_item(jtnode, query, context);
11091 ECB :
11092 : /* Restore context's output buffer */
11093 CBC 152 : context->buf = buf;
11094 ECB :
11095 : /* Consider line-wrapping if enabled */
11096 CBC 152 : if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
11097 ECB : {
11098 : /* Does the new item start with a new line? */
11099 GIC 152 : if (itembuf.len > 0 && itembuf.data[0] == '\n')
11100 : {
11101 EUB : /* If so, we shouldn't add anything */
11102 : /* instead, remove any trailing spaces currently in buf */
11103 UIC 0 : removeStringInfoSpaces(buf);
11104 : }
11105 ECB : else
11106 : {
11107 : char *trailing_nl;
11108 :
11109 : /* Locate the start of the current line in the buffer */
11110 CBC 152 : trailing_nl = strrchr(buf->data, '\n');
11111 152 : if (trailing_nl == NULL)
11112 UIC 0 : trailing_nl = buf->data;
11113 ECB : else
11114 CBC 152 : trailing_nl++;
11115 ECB :
11116 : /*
11117 : * Add a newline, plus some indentation, if the new item
11118 : * would cause an overflow.
11119 : */
11120 CBC 152 : if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
11121 152 : appendContextKeyword(context, "", -PRETTYINDENT_STD,
11122 ECB : PRETTYINDENT_STD,
11123 : PRETTYINDENT_VAR);
11124 EUB : }
11125 : }
11126 :
11127 : /* Add the new item */
11128 CBC 152 : appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
11129 :
11130 : /* clean up */
11131 152 : pfree(itembuf.data);
11132 ECB : }
11133 : }
11134 GBC 1932 : }
11135 :
11136 EUB : static void
11137 GIC 2743 : get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
11138 : {
11139 2743 : StringInfo buf = context->buf;
11140 2743 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
11141 ECB :
11142 CBC 2743 : if (IsA(jtnode, RangeTblRef))
11143 : {
11144 2243 : int varno = ((RangeTblRef *) jtnode)->rtindex;
11145 GIC 2243 : RangeTblEntry *rte = rt_fetch(varno, query->rtable);
11146 2243 : deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11147 2243 : RangeTblFunction *rtfunc1 = NULL;
11148 ECB :
11149 CBC 2243 : if (rte->lateral)
11150 GIC 32 : appendStringInfoString(buf, "LATERAL ");
11151 ECB :
11152 : /* Print the FROM item proper */
11153 GIC 2243 : switch (rte->rtekind)
11154 : {
11155 1752 : case RTE_RELATION:
11156 : /* Normal relation RTE */
11157 3504 : appendStringInfo(buf, "%s%s",
11158 1752 : only_marker(rte),
11159 : generate_relation_name(rte->relid,
11160 ECB : context->namespaces));
11161 GIC 1752 : break;
11162 CBC 119 : case RTE_SUBQUERY:
11163 : /* Subquery RTE */
11164 GIC 119 : appendStringInfoChar(buf, '(');
11165 119 : get_query_def(rte->subquery, buf, context->namespaces, NULL,
11166 ECB : true,
11167 : context->prettyFlags, context->wrapColumn,
11168 : context->indentLevel);
11169 GIC 119 : appendStringInfoChar(buf, ')');
11170 119 : break;
11171 267 : case RTE_FUNCTION:
11172 ECB : /* Function RTE */
11173 GIC 267 : rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
11174 ECB :
11175 : /*
11176 : * Omit ROWS FROM() syntax for just one function, unless it
11177 : * has both a coldeflist and WITH ORDINALITY. If it has both,
11178 : * we must use ROWS FROM() syntax to avoid ambiguity about
11179 : * whether the coldeflist includes the ordinality column.
11180 : */
11181 GBC 267 : if (list_length(rte->functions) == 1 &&
11182 GIC 252 : (rtfunc1->funccolnames == NIL || !rte->funcordinality))
11183 ECB : {
11184 GIC 252 : get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
11185 ECB : /* we'll print the coldeflist below, if it has one */
11186 : }
11187 : else
11188 : {
11189 : bool all_unnest;
11190 : ListCell *lc;
11191 :
11192 EUB : /*
11193 : * If all the function calls in the list are to unnest,
11194 : * and none need a coldeflist, then collapse the list back
11195 : * down to UNNEST(args). (If we had more than one
11196 ECB : * built-in unnest function, this would get more
11197 : * difficult.)
11198 : *
11199 : * XXX This is pretty ugly, since it makes not-terribly-
11200 : * future-proof assumptions about what the parser would do
11201 : * with the output; but the alternative is to emit our
11202 : * nonstandard ROWS FROM() notation for what might have
11203 : * been a perfectly spec-compliant multi-argument
11204 : * UNNEST().
11205 : */
11206 GIC 15 : all_unnest = true;
11207 39 : foreach(lc, rte->functions)
11208 : {
11209 33 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11210 :
11211 33 : if (!IsA(rtfunc->funcexpr, FuncExpr) ||
11212 CBC 33 : ((FuncExpr *) rtfunc->funcexpr)->funcid != F_UNNEST_ANYARRAY ||
11213 GIC 24 : rtfunc->funccolnames != NIL)
11214 ECB : {
11215 CBC 9 : all_unnest = false;
11216 GIC 9 : break;
11217 : }
11218 ECB : }
11219 :
11220 CBC 15 : if (all_unnest)
11221 ECB : {
11222 CBC 6 : List *allargs = NIL;
11223 ECB :
11224 CBC 24 : foreach(lc, rte->functions)
11225 : {
11226 18 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11227 18 : List *args = ((FuncExpr *) rtfunc->funcexpr)->args;
11228 ECB :
11229 GIC 18 : allargs = list_concat(allargs, args);
11230 ECB : }
11231 :
11232 CBC 6 : appendStringInfoString(buf, "UNNEST(");
11233 6 : get_rule_expr((Node *) allargs, context, true);
11234 6 : appendStringInfoChar(buf, ')');
11235 : }
11236 ECB : else
11237 : {
11238 CBC 9 : int funcno = 0;
11239 ECB :
11240 CBC 9 : appendStringInfoString(buf, "ROWS FROM(");
11241 GIC 33 : foreach(lc, rte->functions)
11242 ECB : {
11243 GIC 24 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
11244 ECB :
11245 CBC 24 : if (funcno > 0)
11246 15 : appendStringInfoString(buf, ", ");
11247 GIC 24 : get_rule_expr_funccall(rtfunc->funcexpr, context, true);
11248 CBC 24 : if (rtfunc->funccolnames != NIL)
11249 ECB : {
11250 : /* Reconstruct the column definition list */
11251 GIC 3 : appendStringInfoString(buf, " AS ");
11252 3 : get_from_clause_coldeflist(rtfunc,
11253 ECB : NULL,
11254 : context);
11255 : }
11256 GIC 24 : funcno++;
11257 : }
11258 9 : appendStringInfoChar(buf, ')');
11259 : }
11260 : /* prevent printing duplicate coldeflist below */
11261 15 : rtfunc1 = NULL;
11262 : }
11263 267 : if (rte->funcordinality)
11264 9 : appendStringInfoString(buf, " WITH ORDINALITY");
11265 CBC 267 : break;
11266 GIC 13 : case RTE_TABLEFUNC:
11267 CBC 13 : get_tablefunc(rte->tablefunc, context, true);
11268 13 : break;
11269 GIC 6 : case RTE_VALUES:
11270 : /* Values list RTE */
11271 6 : appendStringInfoChar(buf, '(');
11272 6 : get_values_def(rte->values_lists, context);
11273 6 : appendStringInfoChar(buf, ')');
11274 6 : break;
11275 86 : case RTE_CTE:
11276 86 : appendStringInfoString(buf, quote_identifier(rte->ctename));
11277 86 : break;
11278 LBC 0 : default:
11279 UIC 0 : elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
11280 ECB : break;
11281 : }
11282 :
11283 : /* Print the relation alias, if needed */
11284 CBC 2243 : get_rte_alias(rte, varno, false, context);
11285 ECB :
11286 : /* Print the column definitions or aliases, if needed */
11287 CBC 2243 : if (rtfunc1 && rtfunc1->funccolnames != NIL)
11288 ECB : {
11289 : /* Reconstruct the columndef list, which is also the aliases */
11290 UIC 0 : get_from_clause_coldeflist(rtfunc1, colinfo, context);
11291 ECB : }
11292 : else
11293 : {
11294 : /* Else print column aliases as needed */
11295 CBC 2243 : get_column_alias_list(colinfo, context);
11296 : }
11297 ECB :
11298 : /* Tablesample clause must go after any alias */
11299 GIC 2243 : if (rte->rtekind == RTE_RELATION && rte->tablesample)
11300 16 : get_tablesample_def(rte->tablesample, context);
11301 : }
11302 500 : else if (IsA(jtnode, JoinExpr))
11303 ECB : {
11304 GIC 500 : JoinExpr *j = (JoinExpr *) jtnode;
11305 500 : deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns);
11306 : bool need_paren_on_right;
11307 :
11308 1219 : need_paren_on_right = PRETTY_PAREN(context) &&
11309 CBC 500 : !IsA(j->rarg, RangeTblRef) &&
11310 LBC 0 : !(IsA(j->rarg, JoinExpr) && ((JoinExpr *) j->rarg)->alias != NULL);
11311 :
11312 CBC 500 : if (!PRETTY_PAREN(context) || j->alias != NULL)
11313 GIC 335 : appendStringInfoChar(buf, '(');
11314 :
11315 CBC 500 : get_from_clause_item(j->larg, query, context);
11316 :
11317 GIC 500 : switch (j->jointype)
11318 ECB : {
11319 GIC 302 : case JOIN_INNER:
11320 302 : if (j->quals)
11321 CBC 281 : appendContextKeyword(context, " JOIN ",
11322 : -PRETTYINDENT_STD,
11323 : PRETTYINDENT_STD,
11324 : PRETTYINDENT_JOIN);
11325 EUB : else
11326 GIC 21 : appendContextKeyword(context, " CROSS JOIN ",
11327 : -PRETTYINDENT_STD,
11328 : PRETTYINDENT_STD,
11329 : PRETTYINDENT_JOIN);
11330 302 : break;
11331 147 : case JOIN_LEFT:
11332 CBC 147 : appendContextKeyword(context, " LEFT JOIN ",
11333 ECB : -PRETTYINDENT_STD,
11334 EUB : PRETTYINDENT_STD,
11335 : PRETTYINDENT_JOIN);
11336 CBC 147 : break;
11337 GIC 51 : case JOIN_FULL:
11338 51 : appendContextKeyword(context, " FULL JOIN ",
11339 : -PRETTYINDENT_STD,
11340 : PRETTYINDENT_STD,
11341 : PRETTYINDENT_JOIN);
11342 CBC 51 : break;
11343 LBC 0 : case JOIN_RIGHT:
11344 UIC 0 : appendContextKeyword(context, " RIGHT JOIN ",
11345 : -PRETTYINDENT_STD,
11346 : PRETTYINDENT_STD,
11347 : PRETTYINDENT_JOIN);
11348 0 : break;
11349 0 : default:
11350 LBC 0 : elog(ERROR, "unrecognized join type: %d",
11351 : (int) j->jointype);
11352 : }
11353 ECB :
11354 GIC 500 : if (need_paren_on_right)
11355 UIC 0 : appendStringInfoChar(buf, '(');
11356 CBC 500 : get_from_clause_item(j->rarg, query, context);
11357 GIC 500 : if (need_paren_on_right)
11358 UIC 0 : appendStringInfoChar(buf, ')');
11359 ECB :
11360 GIC 500 : if (j->usingClause)
11361 ECB : {
11362 : ListCell *lc;
11363 GIC 212 : bool first = true;
11364 ECB :
11365 GIC 212 : appendStringInfoString(buf, " USING (");
11366 ECB : /* Use the assigned names, not what's in usingClause */
11367 CBC 502 : foreach(lc, colinfo->usingNames)
11368 ECB : {
11369 CBC 290 : char *colname = (char *) lfirst(lc);
11370 :
11371 290 : if (first)
11372 212 : first = false;
11373 : else
11374 GIC 78 : appendStringInfoString(buf, ", ");
11375 CBC 290 : appendStringInfoString(buf, quote_identifier(colname));
11376 : }
11377 212 : appendStringInfoChar(buf, ')');
11378 :
11379 212 : if (j->join_using_alias)
11380 6 : appendStringInfo(buf, " AS %s",
11381 GIC 6 : quote_identifier(j->join_using_alias->aliasname));
11382 : }
11383 CBC 288 : else if (j->quals)
11384 ECB : {
11385 GIC 264 : appendStringInfoString(buf, " ON ");
11386 CBC 264 : if (!PRETTY_PAREN(context))
11387 261 : appendStringInfoChar(buf, '(');
11388 GIC 264 : get_rule_expr(j->quals, context, false);
11389 264 : if (!PRETTY_PAREN(context))
11390 261 : appendStringInfoChar(buf, ')');
11391 ECB : }
11392 CBC 24 : else if (j->jointype != JOIN_INNER)
11393 ECB : {
11394 : /* If we didn't say CROSS JOIN above, we must provide an ON */
11395 CBC 3 : appendStringInfoString(buf, " ON TRUE");
11396 : }
11397 :
11398 GIC 500 : if (!PRETTY_PAREN(context) || j->alias != NULL)
11399 335 : appendStringInfoChar(buf, ')');
11400 :
11401 : /* Yes, it's correct to put alias after the right paren ... */
11402 500 : if (j->alias != NULL)
11403 ECB : {
11404 : /*
11405 : * Note that it's correct to emit an alias clause if and only if
11406 : * there was one originally. Otherwise we'd be converting a named
11407 : * join to unnamed or vice versa, which creates semantic
11408 : * subtleties we don't want. However, we might print a different
11409 : * alias name than was there originally.
11410 : */
11411 GIC 54 : appendStringInfo(buf, " %s",
11412 54 : quote_identifier(get_rtable_name(j->rtindex,
11413 : context)));
11414 54 : get_column_alias_list(colinfo, context);
11415 : }
11416 : }
11417 : else
11418 UIC 0 : elog(ERROR, "unrecognized node type: %d",
11419 : (int) nodeTag(jtnode));
11420 GIC 2743 : }
11421 :
11422 : /*
11423 : * get_rte_alias - print the relation's alias, if needed
11424 : *
11425 : * If printed, the alias is preceded by a space, or by " AS " if use_as is true.
11426 : */
11427 : static void
11428 CBC 2507 : get_rte_alias(RangeTblEntry *rte, int varno, bool use_as,
11429 ECB : deparse_context *context)
11430 : {
11431 CBC 2507 : deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
11432 GIC 2507 : char *refname = get_rtable_name(varno, context);
11433 CBC 2507 : deparse_columns *colinfo = deparse_columns_fetch(varno, dpns);
11434 2507 : bool printalias = false;
11435 ECB :
11436 GIC 2507 : if (rte->alias != NULL)
11437 ECB : {
11438 : /* Always print alias if user provided one */
11439 GIC 1007 : printalias = true;
11440 : }
11441 1500 : else if (colinfo->printaliases)
11442 ECB : {
11443 : /* Always print alias if we need to print column aliases */
11444 CBC 126 : printalias = true;
11445 : }
11446 1374 : else if (rte->rtekind == RTE_RELATION)
11447 : {
11448 ECB : /*
11449 : * No need to print alias if it's same as relation name (this would
11450 : * normally be the case, but not if set_rtable_names had to resolve a
11451 : * conflict).
11452 : */
11453 GIC 1274 : if (strcmp(refname, get_relation_name(rte->relid)) != 0)
11454 CBC 19 : printalias = true;
11455 ECB : }
11456 CBC 100 : else if (rte->rtekind == RTE_FUNCTION)
11457 : {
11458 : /*
11459 : * For a function RTE, always print alias. This covers possible
11460 ECB : * renaming of the function and/or instability of the FigureColname
11461 : * rules for things that aren't simple functions. Note we'd need to
11462 : * force it anyway for the columndef list case.
11463 : */
11464 UIC 0 : printalias = true;
11465 ECB : }
11466 GIC 100 : else if (rte->rtekind == RTE_SUBQUERY ||
11467 CBC 88 : rte->rtekind == RTE_VALUES)
11468 ECB : {
11469 : /*
11470 : * For a subquery, always print alias. This makes the output
11471 : * SQL-spec-compliant, even though we allow such aliases to be omitted
11472 : * on input.
11473 : */
11474 CBC 18 : printalias = true;
11475 : }
11476 GIC 82 : else if (rte->rtekind == RTE_CTE)
11477 ECB : {
11478 : /*
11479 : * No need to print alias if it's same as CTE name (this would
11480 : * normally be the case, but not if set_rtable_names had to resolve a
11481 : * conflict).
11482 : */
11483 GIC 69 : if (strcmp(refname, rte->ctename) != 0)
11484 CBC 11 : printalias = true;
11485 : }
11486 :
11487 2507 : if (printalias)
11488 GIC 1181 : appendStringInfo(context->buf, "%s%s",
11489 ECB : use_as ? " AS " : " ",
11490 : quote_identifier(refname));
11491 CBC 2507 : }
11492 ECB :
11493 : /*
11494 : * get_column_alias_list - print column alias list for an RTE
11495 : *
11496 : * Caller must already have printed the relation's alias name.
11497 : */
11498 : static void
11499 CBC 2297 : get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
11500 ECB : {
11501 CBC 2297 : StringInfo buf = context->buf;
11502 ECB : int i;
11503 CBC 2297 : bool first = true;
11504 EUB :
11505 : /* Don't print aliases if not needed */
11506 GIC 2297 : if (!colinfo->printaliases)
11507 1853 : return;
11508 :
11509 2898 : for (i = 0; i < colinfo->num_new_cols; i++)
11510 ECB : {
11511 GIC 2454 : char *colname = colinfo->new_colnames[i];
11512 :
11513 CBC 2454 : if (first)
11514 : {
11515 GIC 444 : appendStringInfoChar(buf, '(');
11516 GBC 444 : first = false;
11517 : }
11518 : else
11519 GIC 2010 : appendStringInfoString(buf, ", ");
11520 2454 : appendStringInfoString(buf, quote_identifier(colname));
11521 ECB : }
11522 GIC 444 : if (!first)
11523 444 : appendStringInfoChar(buf, ')');
11524 : }
11525 ECB :
11526 : /*
11527 : * get_from_clause_coldeflist - reproduce FROM clause coldeflist
11528 : *
11529 : * When printing a top-level coldeflist (which is syntactically also the
11530 : * relation's column alias list), use column names from colinfo. But when
11531 : * printing a coldeflist embedded inside ROWS FROM(), we prefer to use the
11532 : * original coldeflist's names, which are available in rtfunc->funccolnames.
11533 : * Pass NULL for colinfo to select the latter behavior.
11534 : *
11535 : * The coldeflist is appended immediately (no space) to buf. Caller is
11536 EUB : * responsible for ensuring that an alias or AS is present before it.
11537 : */
11538 ECB : static void
11539 CBC 3 : get_from_clause_coldeflist(RangeTblFunction *rtfunc,
11540 : deparse_columns *colinfo,
11541 ECB : deparse_context *context)
11542 : {
11543 CBC 3 : StringInfo buf = context->buf;
11544 : ListCell *l1;
11545 ECB : ListCell *l2;
11546 : ListCell *l3;
11547 : ListCell *l4;
11548 : int i;
11549 :
11550 GIC 3 : appendStringInfoChar(buf, '(');
11551 :
11552 CBC 3 : i = 0;
11553 GIC 12 : forfour(l1, rtfunc->funccoltypes,
11554 : l2, rtfunc->funccoltypmods,
11555 : l3, rtfunc->funccolcollations,
11556 ECB : l4, rtfunc->funccolnames)
11557 : {
11558 CBC 9 : Oid atttypid = lfirst_oid(l1);
11559 GIC 9 : int32 atttypmod = lfirst_int(l2);
11560 9 : Oid attcollation = lfirst_oid(l3);
11561 : char *attname;
11562 ECB :
11563 CBC 9 : if (colinfo)
11564 LBC 0 : attname = colinfo->colnames[i];
11565 : else
11566 GIC 9 : attname = strVal(lfirst(l4));
11567 :
11568 CBC 9 : Assert(attname); /* shouldn't be any dropped columns here */
11569 EUB :
11570 GBC 9 : if (i > 0)
11571 GIC 6 : appendStringInfoString(buf, ", ");
11572 9 : appendStringInfo(buf, "%s %s",
11573 : quote_identifier(attname),
11574 EUB : format_type_with_typemod(atttypid, atttypmod));
11575 GBC 12 : if (OidIsValid(attcollation) &&
11576 3 : attcollation != get_typcollation(atttypid))
11577 UIC 0 : appendStringInfo(buf, " COLLATE %s",
11578 : generate_collation_name(attcollation));
11579 :
11580 CBC 9 : i++;
11581 EUB : }
11582 ECB :
11583 CBC 3 : appendStringInfoChar(buf, ')');
11584 GBC 3 : }
11585 :
11586 ECB : /*
11587 : * get_tablesample_def - print a TableSampleClause
11588 : */
11589 : static void
11590 GIC 16 : get_tablesample_def(TableSampleClause *tablesample, deparse_context *context)
11591 ECB : {
11592 GIC 16 : StringInfo buf = context->buf;
11593 ECB : Oid argtypes[1];
11594 : int nargs;
11595 : ListCell *l;
11596 :
11597 : /*
11598 : * We should qualify the handler's function name if it wouldn't be
11599 : * resolved by lookup in the current search path.
11600 : */
11601 CBC 16 : argtypes[0] = INTERNALOID;
11602 GIC 16 : appendStringInfo(buf, " TABLESAMPLE %s (",
11603 ECB : generate_function_name(tablesample->tsmhandler, 1,
11604 : NIL, argtypes,
11605 : false, NULL, EXPR_KIND_NONE));
11606 :
11607 CBC 16 : nargs = 0;
11608 GIC 32 : foreach(l, tablesample->args)
11609 ECB : {
11610 GIC 16 : if (nargs++ > 0)
11611 LBC 0 : appendStringInfoString(buf, ", ");
11612 CBC 16 : get_rule_expr((Node *) lfirst(l), context, false);
11613 ECB : }
11614 CBC 16 : appendStringInfoChar(buf, ')');
11615 ECB :
11616 CBC 16 : if (tablesample->repeatable != NULL)
11617 : {
11618 8 : appendStringInfoString(buf, " REPEATABLE (");
11619 GIC 8 : get_rule_expr((Node *) tablesample->repeatable, context, false);
11620 8 : appendStringInfoChar(buf, ')');
11621 ECB : }
11622 GIC 16 : }
11623 :
11624 ECB : /*
11625 : * get_opclass_name - fetch name of an index operator class
11626 : *
11627 : * The opclass name is appended (after a space) to buf.
11628 : *
11629 : * Output is suppressed if the opclass is the default for the given
11630 : * actual_datatype. (If you don't want this behavior, just pass
11631 : * InvalidOid for actual_datatype.)
11632 : */
11633 : static void
11634 GIC 4810 : get_opclass_name(Oid opclass, Oid actual_datatype,
11635 : StringInfo buf)
11636 : {
11637 ECB : HeapTuple ht_opc;
11638 : Form_pg_opclass opcrec;
11639 : char *opcname;
11640 : char *nspname;
11641 :
11642 GIC 4810 : ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
11643 4810 : if (!HeapTupleIsValid(ht_opc))
11644 UBC 0 : elog(ERROR, "cache lookup failed for opclass %u", opclass);
11645 GIC 4810 : opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
11646 ECB :
11647 GIC 9602 : if (!OidIsValid(actual_datatype) ||
11648 4792 : GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
11649 : {
11650 : /* Okay, we need the opclass name. Do we need to qualify it? */
11651 277 : opcname = NameStr(opcrec->opcname);
11652 277 : if (OpclassIsVisible(opclass))
11653 277 : appendStringInfo(buf, " %s", quote_identifier(opcname));
11654 ECB : else
11655 : {
11656 UIC 0 : nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
11657 LBC 0 : appendStringInfo(buf, " %s.%s",
11658 ECB : quote_identifier(nspname),
11659 : quote_identifier(opcname));
11660 : }
11661 : }
11662 CBC 4810 : ReleaseSysCache(ht_opc);
11663 GIC 4810 : }
11664 :
11665 ECB : /*
11666 : * generate_opclass_name
11667 : * Compute the name to display for an opclass specified by OID
11668 : *
11669 : * The result includes all necessary quoting and schema-prefixing.
11670 : */
11671 : char *
11672 CBC 3 : generate_opclass_name(Oid opclass)
11673 : {
11674 : StringInfoData buf;
11675 :
11676 GIC 3 : initStringInfo(&buf);
11677 3 : get_opclass_name(opclass, InvalidOid, &buf);
11678 :
11679 CBC 3 : return &buf.data[1]; /* get_opclass_name() prepends space */
11680 ECB : }
11681 :
11682 : /*
11683 : * processIndirection - take care of array and subfield assignment
11684 : *
11685 : * We strip any top-level FieldStore or assignment SubscriptingRef nodes that
11686 : * appear in the input, printing them as decoration for the base column
11687 : * name (which we assume the caller just printed). We might also need to
11688 : * strip CoerceToDomain nodes, but only ones that appear above assignment
11689 : * nodes.
11690 EUB : *
11691 : * Returns the subexpression that's to be assigned.
11692 ECB : */
11693 : static Node *
11694 GIC 558 : processIndirection(Node *node, deparse_context *context)
11695 : {
11696 558 : StringInfo buf = context->buf;
11697 558 : CoerceToDomain *cdomain = NULL;
11698 :
11699 : for (;;)
11700 ECB : {
11701 GIC 645 : if (node == NULL)
11702 LBC 0 : break;
11703 GIC 645 : if (IsA(node, FieldStore))
11704 : {
11705 36 : FieldStore *fstore = (FieldStore *) node;
11706 : Oid typrelid;
11707 : char *fieldname;
11708 :
11709 ECB : /* lookup tuple type */
11710 CBC 36 : typrelid = get_typ_typrelid(fstore->resulttype);
11711 GIC 36 : if (!OidIsValid(typrelid))
11712 UIC 0 : elog(ERROR, "argument type %s of FieldStore is not a tuple type",
11713 ECB : format_type_be(fstore->resulttype));
11714 :
11715 : /*
11716 : * Print the field name. There should only be one target field in
11717 : * stored rules. There could be more than that in executable
11718 : * target lists, but this function cannot be used for that case.
11719 : */
11720 GIC 36 : Assert(list_length(fstore->fieldnums) == 1);
11721 36 : fieldname = get_attname(typrelid,
11722 36 : linitial_int(fstore->fieldnums), false);
11723 36 : appendStringInfo(buf, ".%s", quote_identifier(fieldname));
11724 :
11725 ECB : /*
11726 : * We ignore arg since it should be an uninteresting reference to
11727 : * the target column or subcolumn.
11728 : */
11729 CBC 36 : node = (Node *) linitial(fstore->newvals);
11730 : }
11731 GIC 609 : else if (IsA(node, SubscriptingRef))
11732 ECB : {
11733 CBC 39 : SubscriptingRef *sbsref = (SubscriptingRef *) node;
11734 :
11735 39 : if (sbsref->refassgnexpr == NULL)
11736 UIC 0 : break;
11737 ECB :
11738 GIC 39 : printSubscripts(sbsref, context);
11739 ECB :
11740 : /*
11741 : * We ignore refexpr since it should be an uninteresting reference
11742 : * to the target column or subcolumn.
11743 : */
11744 GIC 39 : node = (Node *) sbsref->refassgnexpr;
11745 ECB : }
11746 CBC 570 : else if (IsA(node, CoerceToDomain))
11747 : {
11748 12 : cdomain = (CoerceToDomain *) node;
11749 ECB : /* If it's an explicit domain coercion, we're done */
11750 GIC 12 : if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
11751 UIC 0 : break;
11752 : /* Tentatively descend past the CoerceToDomain */
11753 GIC 12 : node = (Node *) cdomain->arg;
11754 : }
11755 : else
11756 558 : break;
11757 : }
11758 :
11759 : /*
11760 : * If we descended past a CoerceToDomain whose argument turned out not to
11761 : * be a FieldStore or array assignment, back up to the CoerceToDomain.
11762 : * (This is not enough to be fully correct if there are nested implicit
11763 : * CoerceToDomains, but such cases shouldn't ever occur.)
11764 : */
11765 CBC 558 : if (cdomain && node == (Node *) cdomain->arg)
11766 UIC 0 : node = (Node *) cdomain;
11767 :
11768 GIC 558 : return node;
11769 ECB : }
11770 :
11771 : static void
11772 GIC 131 : printSubscripts(SubscriptingRef *sbsref, deparse_context *context)
11773 : {
11774 131 : StringInfo buf = context->buf;
11775 : ListCell *lowlist_item;
11776 ECB : ListCell *uplist_item;
11777 :
11778 CBC 131 : lowlist_item = list_head(sbsref->reflowerindexpr); /* could be NULL */
11779 262 : foreach(uplist_item, sbsref->refupperindexpr)
11780 : {
11781 GIC 131 : appendStringInfoChar(buf, '[');
11782 131 : if (lowlist_item)
11783 : {
11784 ECB : /* If subexpression is NULL, get_rule_expr prints nothing */
11785 LBC 0 : get_rule_expr((Node *) lfirst(lowlist_item), context, false);
11786 0 : appendStringInfoChar(buf, ':');
11787 UIC 0 : lowlist_item = lnext(sbsref->reflowerindexpr, lowlist_item);
11788 : }
11789 ECB : /* If subexpression is NULL, get_rule_expr prints nothing */
11790 GBC 131 : get_rule_expr((Node *) lfirst(uplist_item), context, false);
11791 GIC 131 : appendStringInfoChar(buf, ']');
11792 ECB : }
11793 GIC 131 : }
11794 ECB :
11795 : /*
11796 : * quote_identifier - Quote an identifier only if needed
11797 : *
11798 : * When quotes are needed, we palloc the required space; slightly
11799 : * space-wasteful but well worth it for notational simplicity.
11800 : */
11801 : const char *
11802 CBC 1056314 : quote_identifier(const char *ident)
11803 EUB : {
11804 : /*
11805 : * Can avoid quoting if ident starts with a lowercase letter or underscore
11806 ECB : * and contains only lowercase letters, digits, and underscores, *and* is
11807 : * not any SQL keyword. Otherwise, supply quotes.
11808 : */
11809 CBC 1056314 : int nquotes = 0;
11810 ECB : bool safe;
11811 : const char *ptr;
11812 : char *result;
11813 : char *optr;
11814 :
11815 : /*
11816 : * would like to use <ctype.h> macros here, but they might yield unwanted
11817 : * locale-specific results...
11818 : */
11819 GIC 1056314 : safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
11820 :
11821 8625457 : for (ptr = ident; *ptr; ptr++)
11822 : {
11823 7569143 : char ch = *ptr;
11824 :
11825 7569143 : if ((ch >= 'a' && ch <= 'z') ||
11826 843761 : (ch >= '0' && ch <= '9') ||
11827 ECB : (ch == '_'))
11828 : {
11829 : /* okay */
11830 : }
11831 : else
11832 : {
11833 CBC 23897 : safe = false;
11834 23897 : if (ch == '"')
11835 GIC 6 : nquotes++;
11836 ECB : }
11837 EUB : }
11838 ECB :
11839 GIC 1056314 : if (quote_all_identifiers)
11840 CBC 5564 : safe = false;
11841 :
11842 1056314 : if (safe)
11843 : {
11844 ECB : /*
11845 : * Check for keyword. We quote keywords except for unreserved ones.
11846 : * (In some cases we could avoid quoting a col_name or type_func_name
11847 : * keyword, but it seems much harder than it's worth to tell that.)
11848 : *
11849 : * Note: ScanKeywordLookup() does case-insensitive comparison, but
11850 : * that's fine, since we already know we have all-lower-case.
11851 : */
11852 GIC 1041297 : int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
11853 :
11854 1041297 : if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
11855 1046 : safe = false;
11856 : }
11857 :
11858 1056314 : if (safe)
11859 1040251 : return ident; /* no change needed */
11860 ECB :
11861 GIC 16063 : result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
11862 :
11863 16063 : optr = result;
11864 16063 : *optr++ = '"';
11865 97533 : for (ptr = ident; *ptr; ptr++)
11866 : {
11867 81470 : char ch = *ptr;
11868 ECB :
11869 CBC 81470 : if (ch == '"')
11870 GBC 6 : *optr++ = '"';
11871 CBC 81470 : *optr++ = ch;
11872 : }
11873 16063 : *optr++ = '"';
11874 16063 : *optr = '\0';
11875 :
11876 GIC 16063 : return result;
11877 ECB : }
11878 :
11879 : /*
11880 : * quote_qualified_identifier - Quote a possibly-qualified identifier
11881 : *
11882 EUB : * Return a name of the form qualifier.ident, or just ident if qualifier
11883 : * is NULL, quoting each component if necessary. The result is palloc'd.
11884 : */
11885 : char *
11886 GIC 488282 : quote_qualified_identifier(const char *qualifier,
11887 : const char *ident)
11888 ECB : {
11889 : StringInfoData buf;
11890 :
11891 GIC 488282 : initStringInfo(&buf);
11892 488282 : if (qualifier)
11893 200798 : appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
11894 488282 : appendStringInfoString(&buf, quote_identifier(ident));
11895 488282 : return buf.data;
11896 : }
11897 :
11898 ECB : /*
11899 : * get_relation_name
11900 : * Get the unqualified name of a relation specified by OID
11901 : *
11902 : * This differs from the underlying get_rel_name() function in that it will
11903 : * throw error instead of silently returning NULL if the OID is bad.
11904 : */
11905 : static char *
11906 GIC 6844 : get_relation_name(Oid relid)
11907 : {
11908 6844 : char *relname = get_rel_name(relid);
11909 :
11910 6844 : if (!relname)
11911 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
11912 GIC 6844 : return relname;
11913 : }
11914 :
11915 : /*
11916 : * generate_relation_name
11917 : * Compute the name to display for a relation specified by OID
11918 : *
11919 : * The result includes all necessary quoting and schema-prefixing.
11920 ECB : *
11921 : * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
11922 : * We will forcibly qualify the relation name if it equals any CTE name
11923 : * visible in the namespace list.
11924 : */
11925 : static char *
11926 GIC 3210 : generate_relation_name(Oid relid, List *namespaces)
11927 ECB : {
11928 EUB : HeapTuple tp;
11929 ECB : Form_pg_class reltup;
11930 : bool need_qual;
11931 : ListCell *nslist;
11932 : char *relname;
11933 : char *nspname;
11934 : char *result;
11935 :
11936 CBC 3210 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11937 3210 : if (!HeapTupleIsValid(tp))
11938 UBC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
11939 GIC 3210 : reltup = (Form_pg_class) GETSTRUCT(tp);
11940 3210 : relname = NameStr(reltup->relname);
11941 :
11942 : /* Check for conflicting CTE name */
11943 3210 : need_qual = false;
11944 5383 : foreach(nslist, namespaces)
11945 : {
11946 CBC 2173 : deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
11947 ECB : ListCell *ctlist;
11948 :
11949 CBC 2203 : foreach(ctlist, dpns->ctes)
11950 : {
11951 GIC 30 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
11952 :
11953 30 : if (strcmp(cte->ctename, relname) == 0)
11954 : {
11955 LBC 0 : need_qual = true;
11956 UIC 0 : break;
11957 ECB : }
11958 : }
11959 CBC 2173 : if (need_qual)
11960 UIC 0 : break;
11961 ECB : }
11962 EUB :
11963 : /* Otherwise, qualify the name if not visible in search path */
11964 CBC 3210 : if (!need_qual)
11965 GIC 3210 : need_qual = !RelationIsVisible(relid);
11966 :
11967 3210 : if (need_qual)
11968 1079 : nspname = get_namespace_name_or_temp(reltup->relnamespace);
11969 : else
11970 CBC 2131 : nspname = NULL;
11971 :
11972 3210 : result = quote_qualified_identifier(nspname, relname);
11973 :
11974 3210 : ReleaseSysCache(tp);
11975 :
11976 3210 : return result;
11977 EUB : }
11978 :
11979 ECB : /*
11980 : * generate_qualified_relation_name
11981 : * Compute the name to display for a relation specified by OID
11982 : *
11983 : * As above, but unconditionally schema-qualify the name.
11984 : */
11985 : static char *
11986 GIC 3205 : generate_qualified_relation_name(Oid relid)
11987 : {
11988 : HeapTuple tp;
11989 : Form_pg_class reltup;
11990 : char *relname;
11991 ECB : char *nspname;
11992 EUB : char *result;
11993 :
11994 CBC 3205 : tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
11995 GIC 3205 : if (!HeapTupleIsValid(tp))
11996 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
11997 GIC 3205 : reltup = (Form_pg_class) GETSTRUCT(tp);
11998 CBC 3205 : relname = NameStr(reltup->relname);
11999 :
12000 3205 : nspname = get_namespace_name_or_temp(reltup->relnamespace);
12001 GIC 3205 : if (!nspname)
12002 UIC 0 : elog(ERROR, "cache lookup failed for namespace %u",
12003 : reltup->relnamespace);
12004 ECB :
12005 CBC 3205 : result = quote_qualified_identifier(nspname, relname);
12006 :
12007 3205 : ReleaseSysCache(tp);
12008 ECB :
12009 GIC 3205 : return result;
12010 : }
12011 EUB :
12012 : /*
12013 : * generate_function_name
12014 : * Compute the name to display for a function specified by OID,
12015 : * given that it is being called with the specified actual arg names and
12016 ECB : * types. (Those matter because of ambiguous-function resolution rules.)
12017 : *
12018 : * If we're dealing with a potentially variadic function (in practice, this
12019 : * means a FuncExpr or Aggref, not some other way of calling a function), then
12020 : * has_variadic must specify whether variadic arguments have been merged,
12021 : * and *use_variadic_p will be set to indicate whether to print VARIADIC in
12022 : * the output. For non-FuncExpr cases, has_variadic should be false and
12023 : * use_variadic_p can be NULL.
12024 : *
12025 : * The result includes all necessary quoting and schema-prefixing.
12026 : */
12027 : static char *
12028 CBC 5107 : generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
12029 : bool has_variadic, bool *use_variadic_p,
12030 : ParseExprKind special_exprkind)
12031 : {
12032 : char *result;
12033 : HeapTuple proctup;
12034 : Form_pg_proc procform;
12035 ECB : char *proname;
12036 : bool use_variadic;
12037 : char *nspname;
12038 : FuncDetailCode p_result;
12039 : Oid p_funcid;
12040 : Oid p_rettype;
12041 : bool p_retset;
12042 : int p_nvargs;
12043 : Oid p_vatype;
12044 : Oid *p_true_typeids;
12045 CBC 5107 : bool force_qualify = false;
12046 :
12047 5107 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
12048 GIC 5107 : if (!HeapTupleIsValid(proctup))
12049 LBC 0 : elog(ERROR, "cache lookup failed for function %u", funcid);
12050 GIC 5107 : procform = (Form_pg_proc) GETSTRUCT(proctup);
12051 CBC 5107 : proname = NameStr(procform->proname);
12052 ECB :
12053 : /*
12054 : * Due to parser hacks to avoid needing to reserve CUBE, we need to force
12055 : * qualification in some special cases.
12056 : */
12057 GIC 5107 : if (special_exprkind == EXPR_KIND_GROUP_BY)
12058 : {
12059 LBC 0 : if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0)
12060 0 : force_qualify = true;
12061 ECB : }
12062 :
12063 : /*
12064 : * Determine whether VARIADIC should be printed. We must do this first
12065 : * since it affects the lookup rules in func_get_detail().
12066 : *
12067 : * We always print VARIADIC if the function has a merged variadic-array
12068 : * argument. Note that this is always the case for functions taking a
12069 : * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
12070 : * and printed the array elements as separate arguments, the call could
12071 : * match a newer non-VARIADIC function.
12072 : */
12073 GIC 5107 : if (use_variadic_p)
12074 : {
12075 : /* Parser should not have set funcvariadic unless fn is variadic */
12076 4299 : Assert(!has_variadic || OidIsValid(procform->provariadic));
12077 4299 : use_variadic = has_variadic;
12078 CBC 4299 : *use_variadic_p = use_variadic;
12079 : }
12080 ECB : else
12081 : {
12082 GIC 808 : Assert(!has_variadic);
12083 808 : use_variadic = false;
12084 ECB : }
12085 :
12086 : /*
12087 : * The idea here is to schema-qualify only if the parser would fail to
12088 : * resolve the correct function given the unqualified func name with the
12089 : * specified argtypes and VARIADIC flag. But if we already decided to
12090 : * force qualification, then we can skip the lookup and pretend we didn't
12091 : * find it.
12092 : */
12093 CBC 5107 : if (!force_qualify)
12094 GIC 5107 : p_result = func_get_detail(list_make1(makeString(proname)),
12095 ECB : NIL, argnames, nargs, argtypes,
12096 CBC 5107 : !use_variadic, true, false,
12097 ECB : &p_funcid, &p_rettype,
12098 : &p_retset, &p_nvargs, &p_vatype,
12099 CBC 5107 : &p_true_typeids, NULL);
12100 ECB : else
12101 : {
12102 LBC 0 : p_result = FUNCDETAIL_NOTFOUND;
12103 UIC 0 : p_funcid = InvalidOid;
12104 : }
12105 :
12106 GIC 5107 : if ((p_result == FUNCDETAIL_NORMAL ||
12107 589 : p_result == FUNCDETAIL_AGGREGATE ||
12108 4569 : p_result == FUNCDETAIL_WINDOWFUNC) &&
12109 4569 : p_funcid == funcid)
12110 4569 : nspname = NULL;
12111 : else
12112 CBC 538 : nspname = get_namespace_name_or_temp(procform->pronamespace);
12113 :
12114 GIC 5107 : result = quote_qualified_identifier(nspname, proname);
12115 :
12116 5107 : ReleaseSysCache(proctup);
12117 ECB :
12118 CBC 5107 : return result;
12119 ECB : }
12120 :
12121 : /*
12122 : * generate_operator_name
12123 : * Compute the name to display for an operator specified by OID,
12124 : * given that it is being called with the specified actual arg types.
12125 : * (Arg types matter because of ambiguous-operator resolution rules.
12126 : * Pass InvalidOid for unused arg of a unary operator.)
12127 : *
12128 : * The result includes all necessary quoting and schema-prefixing,
12129 : * plus the OPERATOR() decoration needed to use a qualified operator name
12130 : * in an expression.
12131 : */
12132 : static char *
12133 GIC 26028 : generate_operator_name(Oid operid, Oid arg1, Oid arg2)
12134 ECB : {
12135 : StringInfoData buf;
12136 : HeapTuple opertup;
12137 EUB : Form_pg_operator operform;
12138 ECB : char *oprname;
12139 : char *nspname;
12140 : Operator p_result;
12141 :
12142 GIC 26028 : initStringInfo(&buf);
12143 :
12144 26028 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
12145 26028 : if (!HeapTupleIsValid(opertup))
12146 UIC 0 : elog(ERROR, "cache lookup failed for operator %u", operid);
12147 GIC 26028 : operform = (Form_pg_operator) GETSTRUCT(opertup);
12148 26028 : oprname = NameStr(operform->oprname);
12149 :
12150 : /*
12151 : * The idea here is to schema-qualify only if the parser would fail to
12152 ECB : * resolve the correct operator given the unqualified op name with the
12153 : * specified argtypes.
12154 : */
12155 GIC 26028 : switch (operform->oprkind)
12156 : {
12157 26013 : case 'b':
12158 26013 : p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
12159 : true, -1);
12160 26013 : break;
12161 15 : case 'l':
12162 CBC 15 : p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
12163 ECB : true, -1);
12164 GBC 15 : break;
12165 LBC 0 : default:
12166 0 : elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
12167 : p_result = NULL; /* keep compiler quiet */
12168 : break;
12169 ECB : }
12170 :
12171 GIC 26028 : if (p_result != NULL && oprid(p_result) == operid)
12172 CBC 26023 : nspname = NULL;
12173 : else
12174 : {
12175 5 : nspname = get_namespace_name_or_temp(operform->oprnamespace);
12176 GIC 5 : appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
12177 ECB : }
12178 :
12179 CBC 26028 : appendStringInfoString(&buf, oprname);
12180 :
12181 GBC 26028 : if (nspname)
12182 5 : appendStringInfoChar(&buf, ')');
12183 :
12184 GIC 26028 : if (p_result != NULL)
12185 CBC 26023 : ReleaseSysCache(p_result);
12186 EUB :
12187 GIC 26028 : ReleaseSysCache(opertup);
12188 :
12189 26028 : return buf.data;
12190 ECB : }
12191 :
12192 : /*
12193 : * generate_operator_clause --- generate a binary-operator WHERE clause
12194 : *
12195 : * This is used for internally-generated-and-executed SQL queries, where
12196 : * precision is essential and readability is secondary. The basic
12197 : * requirement is to append "leftop op rightop" to buf, where leftop and
12198 : * rightop are given as strings and are assumed to yield types leftoptype
12199 : * and rightoptype; the operator is identified by OID. The complexity
12200 : * comes from needing to be sure that the parser will select the desired
12201 : * operator when the query is parsed. We always name the operator using
12202 : * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties.
12203 : * We have to emit casts too, if either input isn't already the input type
12204 : * of the operator; else we are at the mercy of the parser's heuristics for
12205 : * ambiguous-operator resolution. The caller must ensure that leftop and
12206 : * rightop are suitable arguments for a cast operation; it's best to insert
12207 : * parentheses if they aren't just variables or parameters.
12208 : */
12209 : void
12210 GIC 2508 : generate_operator_clause(StringInfo buf,
12211 : const char *leftop, Oid leftoptype,
12212 ECB : Oid opoid,
12213 : const char *rightop, Oid rightoptype)
12214 : {
12215 : HeapTuple opertup;
12216 : Form_pg_operator operform;
12217 : char *oprname;
12218 : char *nspname;
12219 :
12220 CBC 2508 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
12221 2508 : if (!HeapTupleIsValid(opertup))
12222 UBC 0 : elog(ERROR, "cache lookup failed for operator %u", opoid);
12223 CBC 2508 : operform = (Form_pg_operator) GETSTRUCT(opertup);
12224 2508 : Assert(operform->oprkind == 'b');
12225 GIC 2508 : oprname = NameStr(operform->oprname);
12226 ECB :
12227 CBC 2508 : nspname = get_namespace_name(operform->oprnamespace);
12228 EUB :
12229 GIC 2508 : appendStringInfoString(buf, leftop);
12230 2508 : if (leftoptype != operform->oprleft)
12231 CBC 21 : add_cast_to(buf, operform->oprleft);
12232 GIC 2508 : appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
12233 CBC 2508 : appendStringInfoString(buf, oprname);
12234 GIC 2508 : appendStringInfo(buf, ") %s", rightop);
12235 CBC 2508 : if (rightoptype != operform->oprright)
12236 GIC 30 : add_cast_to(buf, operform->oprright);
12237 :
12238 2508 : ReleaseSysCache(opertup);
12239 2508 : }
12240 :
12241 : /*
12242 : * Add a cast specification to buf. We spell out the type name the hard way,
12243 : * intentionally not using format_type_be(). This is to avoid corner cases
12244 : * for CHARACTER, BIT, and perhaps other types, where specifying the type
12245 : * using SQL-standard syntax results in undesirable data truncation. By
12246 : * doing it this way we can be certain that the cast will have default (-1)
12247 : * target typmod.
12248 : */
12249 : static void
12250 51 : add_cast_to(StringInfo buf, Oid typid)
12251 : {
12252 : HeapTuple typetup;
12253 : Form_pg_type typform;
12254 ECB : char *typname;
12255 : char *nspname;
12256 :
12257 GIC 51 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
12258 51 : if (!HeapTupleIsValid(typetup))
12259 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
12260 GIC 51 : typform = (Form_pg_type) GETSTRUCT(typetup);
12261 :
12262 51 : typname = NameStr(typform->typname);
12263 51 : nspname = get_namespace_name_or_temp(typform->typnamespace);
12264 :
12265 51 : appendStringInfo(buf, "::%s.%s",
12266 : quote_identifier(nspname), quote_identifier(typname));
12267 :
12268 51 : ReleaseSysCache(typetup);
12269 51 : }
12270 :
12271 ECB : /*
12272 : * generate_qualified_type_name
12273 : * Compute the name to display for a type specified by OID
12274 : *
12275 EUB : * This is different from format_type_be() in that we unconditionally
12276 ECB : * schema-qualify the name. That also means no special syntax for
12277 : * SQL-standard type names ... although in current usage, this should
12278 : * only get used for domains, so such cases wouldn't occur anyway.
12279 : */
12280 : static char *
12281 GIC 7 : generate_qualified_type_name(Oid typid)
12282 : {
12283 ECB : HeapTuple tp;
12284 : Form_pg_type typtup;
12285 EUB : char *typname;
12286 : char *nspname;
12287 : char *result;
12288 :
12289 GIC 7 : tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
12290 7 : if (!HeapTupleIsValid(tp))
12291 UIC 0 : elog(ERROR, "cache lookup failed for type %u", typid);
12292 GIC 7 : typtup = (Form_pg_type) GETSTRUCT(tp);
12293 7 : typname = NameStr(typtup->typname);
12294 :
12295 7 : nspname = get_namespace_name_or_temp(typtup->typnamespace);
12296 7 : if (!nspname)
12297 UIC 0 : elog(ERROR, "cache lookup failed for namespace %u",
12298 : typtup->typnamespace);
12299 ECB :
12300 GIC 7 : result = quote_qualified_identifier(nspname, typname);
12301 :
12302 CBC 7 : ReleaseSysCache(tp);
12303 ECB :
12304 CBC 7 : return result;
12305 : }
12306 :
12307 : /*
12308 ECB : * generate_collation_name
12309 : * Compute the name to display for a collation specified by OID
12310 : *
12311 : * The result includes all necessary quoting and schema-prefixing.
12312 : */
12313 : char *
12314 GIC 155 : generate_collation_name(Oid collid)
12315 : {
12316 : HeapTuple tp;
12317 : Form_pg_collation colltup;
12318 : char *collname;
12319 ECB : char *nspname;
12320 : char *result;
12321 :
12322 CBC 155 : tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
12323 GIC 155 : if (!HeapTupleIsValid(tp))
12324 UIC 0 : elog(ERROR, "cache lookup failed for collation %u", collid);
12325 CBC 155 : colltup = (Form_pg_collation) GETSTRUCT(tp);
12326 GIC 155 : collname = NameStr(colltup->collname);
12327 :
12328 GBC 155 : if (!CollationIsVisible(collid))
12329 UBC 0 : nspname = get_namespace_name_or_temp(colltup->collnamespace);
12330 : else
12331 GIC 155 : nspname = NULL;
12332 ECB :
12333 CBC 155 : result = quote_qualified_identifier(nspname, collname);
12334 ECB :
12335 CBC 155 : ReleaseSysCache(tp);
12336 ECB :
12337 GIC 155 : return result;
12338 ECB : }
12339 :
12340 : /*
12341 : * Given a C string, produce a TEXT datum.
12342 : *
12343 : * We assume that the input was palloc'd and may be freed.
12344 : */
12345 : static text *
12346 GIC 18304 : string_to_text(char *str)
12347 : {
12348 : text *result;
12349 :
12350 18304 : result = cstring_to_text(str);
12351 18304 : pfree(str);
12352 18304 : return result;
12353 : }
12354 :
12355 : /*
12356 : * Generate a C string representing a relation options from text[] datum.
12357 : */
12358 : static void
12359 CBC 120 : get_reloptions(StringInfo buf, Datum reloptions)
12360 : {
12361 : Datum *options;
12362 : int noptions;
12363 : int i;
12364 :
12365 GNC 120 : deconstruct_array_builtin(DatumGetArrayTypeP(reloptions), TEXTOID,
12366 : &options, NULL, &noptions);
12367 ECB :
12368 GIC 250 : for (i = 0; i < noptions; i++)
12369 ECB : {
12370 CBC 130 : char *option = TextDatumGetCString(options[i]);
12371 EUB : char *name;
12372 ECB : char *separator;
12373 : char *value;
12374 :
12375 : /*
12376 : * Each array element should have the form name=value. If the "=" is
12377 : * missing for some reason, treat it like an empty value.
12378 : */
12379 GIC 130 : name = option;
12380 CBC 130 : separator = strchr(option, '=');
12381 GIC 130 : if (separator)
12382 ECB : {
12383 CBC 130 : *separator = '\0';
12384 GIC 130 : value = separator + 1;
12385 ECB : }
12386 : else
12387 LBC 0 : value = "";
12388 :
12389 CBC 130 : if (i > 0)
12390 GBC 10 : appendStringInfoString(buf, ", ");
12391 130 : appendStringInfo(buf, "%s=", quote_identifier(name));
12392 :
12393 : /*
12394 : * In general we need to quote the value; but to avoid unnecessary
12395 : * clutter, do not quote if it is an identifier that would not need
12396 ECB : * quoting. (We could also allow numbers, but that is a bit trickier
12397 : * than it looks --- for example, are leading zeroes significant? We
12398 : * don't want to assume very much here about what custom reloptions
12399 : * might mean.)
12400 : */
12401 CBC 130 : if (quote_identifier(value) == value)
12402 GIC 4 : appendStringInfoString(buf, value);
12403 : else
12404 CBC 126 : simple_quote_literal(buf, value);
12405 :
12406 130 : pfree(option);
12407 ECB : }
12408 GIC 120 : }
12409 ECB :
12410 : /*
12411 : * Generate a C string representing a relation's reloptions, or NULL if none.
12412 : */
12413 : static char *
12414 CBC 2949 : flatten_reloptions(Oid relid)
12415 : {
12416 GIC 2949 : char *result = NULL;
12417 : HeapTuple tuple;
12418 : Datum reloptions;
12419 : bool isnull;
12420 :
12421 2949 : tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
12422 2949 : if (!HeapTupleIsValid(tuple))
12423 UIC 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
12424 :
12425 GIC 2949 : reloptions = SysCacheGetAttr(RELOID, tuple,
12426 : Anum_pg_class_reloptions, &isnull);
12427 2949 : if (!isnull)
12428 : {
12429 : StringInfoData buf;
12430 :
12431 105 : initStringInfo(&buf);
12432 105 : get_reloptions(&buf, reloptions);
12433 :
12434 105 : result = buf.data;
12435 ECB : }
12436 :
12437 GIC 2949 : ReleaseSysCache(tuple);
12438 :
12439 2949 : return result;
12440 : }
12441 :
12442 : /*
12443 : * get_range_partbound_string
12444 : * A C string representation of one range partition bound
12445 ECB : */
12446 : char *
12447 GBC 2034 : get_range_partbound_string(List *bound_datums)
12448 ECB : {
12449 : deparse_context context;
12450 CBC 2034 : StringInfo buf = makeStringInfo();
12451 : ListCell *cell;
12452 ECB : char *sep;
12453 :
12454 CBC 2034 : memset(&context, 0, sizeof(deparse_context));
12455 2034 : context.buf = buf;
12456 ECB :
12457 CBC 2034 : appendStringInfoChar(buf, '(');
12458 2034 : sep = "";
12459 4464 : foreach(cell, bound_datums)
12460 ECB : {
12461 : PartitionRangeDatum *datum =
12462 GIC 2430 : lfirst_node(PartitionRangeDatum, cell);
12463 ECB :
12464 CBC 2430 : appendStringInfoString(buf, sep);
12465 GIC 2430 : if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
12466 111 : appendStringInfoString(buf, "MINVALUE");
12467 2319 : else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
12468 60 : appendStringInfoString(buf, "MAXVALUE");
12469 : else
12470 : {
12471 2259 : Const *val = castNode(Const, datum->value);
12472 :
12473 2259 : get_const_expr(val, &context, -1);
12474 : }
12475 CBC 2430 : sep = ", ";
12476 : }
12477 GIC 2034 : appendStringInfoChar(buf, ')');
12478 :
12479 2034 : return buf->data;
12480 : }
|